Diffstat (limited to 'filters')
| -rwxr-xr-x | filters/ci-jenkins.sh | 58 | ||||
| -rwxr-xr-x | filters/html-converters/md2html | 89 | ||||
| -rwxr-xr-x | filters/syntax-highlighting.py | 45 | ||||
| -rwxr-xr-x | filters/syntax-highlighting.sh | 14 |
4 files changed, 172 insertions, 34 deletions
diff --git a/filters/ci-jenkins.sh b/filters/ci-jenkins.sh new file mode 100755 index 0000000..842af21 --- /dev/null +++ b/filters/ci-jenkins.sh @@ -0,0 +1,58 @@ +#!/bin/sh +# This script may be used with the ci-filter or repo.ci-filter setting in +# cgitrc to hide the "ci" tab for refs which have no pipeline on a Jenkins +# instance. +# +# Arguments: +# $1 the name of the branch or tag being viewed +# $2 "branch" or "tag" +# $3 the ci url which the "ci" tab would redirect to +# +# Exit with a zero status to show the tab, non-zero to hide it. This script +# must not write anything to standard output, as that would end up in the +# middle of the page cgit is rendering. +# +# The filter is consulted while rendering every repository page, so the +# verdict is cached on disk to keep Jenkins from being hammered, and the +# probe is given a short timeout so that an unreachable Jenkins degrades +# into a missing tab rather than a hanging web server. +# +# Set CI_NETRC to a netrc(5) file if the Jenkins instance requires +# authentication; without it a private job answers 403 and the tab is +# hidden even though the pipeline exists. + +CI_CACHE_DIR="${CI_CACHE_DIR:-/var/cache/cgit/ci-filter}" +CI_CACHE_TTL_MINUTES="${CI_CACHE_TTL_MINUTES:-5}" +CI_TIMEOUT="${CI_TIMEOUT:-2}" + +url="$3" +test -n "$url" || exit 1 + +# Jenkins job pages are often not readable anonymously, so query the REST +# API rather than the page the tab points at. +probe="$url/api/json?tree=name" + +key="$(printf '%s' "$url" | cksum | tr -cd '0-9')" +cache="$CI_CACHE_DIR/$key" + +mkdir -p "$CI_CACHE_DIR" 2>/dev/null + +if test -f "$cache" && + test -z "$(find "$cache" -mmin "+$CI_CACHE_TTL_MINUTES" 2>/dev/null)" +then + exit "$(cat "$cache")" +fi + +status=0 +curl --silent --fail --head --output /dev/null \ + --max-time "$CI_TIMEOUT" \ + ${CI_NETRC:+--netrc-file "$CI_NETRC"} \ + "$probe" >/dev/null 2>&1 || status=1 + +if test -d "$CI_CACHE_DIR" +then + printf '%s\n' "$status" >"$cache.$$" 2>/dev/null && + mv "$cache.$$" "$cache" 2>/dev/null +fi + +exit "$status" diff --git a/filters/html-converters/md2html b/filters/html-converters/md2html index dc20f42..4f6ad37 100755 --- a/filters/html-converters/md2html +++ b/filters/html-converters/md2html @@ -2,8 +2,46 @@ import markdown import sys import io -from pygments.formatters import HtmlFormatter from markdown.extensions.toc import TocExtension + +# Pygments' token classes, mapped onto the --syn-* custom properties that +# cgit.css defines. The fallbacks are the palette those properties default to, +# so that the output stays readable under a stylesheet without them. +SYNTAX_COLORS = ( + (('k', 'kc', 'kd', 'kn', 'kr'), '--syn-keyword', '#000', + 'font-weight: bold'), + (('kp',), '--syn-keyword', '#000', None), + (('kt',), '--syn-type', '#010181', None), + (('nc', 'nf', 'nn', 'ne'), '--syn-keyword-alt', '#0057ae', None), + (('s', 'sa', 'sb', 'sc', 'dl', 'sd', 's2', 'sh', 'sx', 'sr', 's1', 'ss'), + '--syn-string', '#bf0303', None), + (('se',), '--syn-escape', '#f0f', None), + (('si',), '--syn-interpolation', '#0057ae', None), + (('c', 'ch', 'cm', 'c1', 'cs'), '--syn-comment', '#838183', + 'font-style: italic'), + (('cp', 'cpf'), '--syn-preproc', '#008200', None), + (('m', 'mb', 'mf', 'mh', 'mi', 'mo', 'il'), '--syn-number', '#b07e00', + None), + (('o', 'ow', 'p'), '--syn-operator', '#000', None), + (('err',), '--syn-error', '#bf0303', None), + (('gd',), '--red', 'red', None), + (('gi',), '--green', 'green', None), + (('lineno', 'linenos'), '--syn-linenum', '#555', None), +) + + +def style_defs(prefix='.highlight'): + rules = [] + for classes, prop, fallback, extra in SYNTAX_COLORS: + selector = ', '.join('%s .%s' % (prefix, c) for c in classes) + decls = 'color: var(%s, %s)' % (prop, fallback) + if extra: + decls += '; ' + extra + rules.append('%s { %s }' % (selector, decls)) + rules.append('%s .hll { background-color: var(--syn-mark-bg, #ffb) }' + % prefix) + return '\n'.join(rules) + '\n' + sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stdout.write(''' @@ -20,7 +58,7 @@ sys.stdout.write(''' margin-bottom: 0 !important; } .markdown-body a.absent { - color: #c00; + color: var(--red-mid, #c00); } .markdown-body a.anchor { display: block; @@ -42,7 +80,7 @@ sys.stdout.write(''' } .markdown-body h1 .mini-icon-link, .markdown-body h2 .mini-icon-link, .markdown-body h3 .mini-icon-link, .markdown-body h4 .mini-icon-link, .markdown-body h5 .mini-icon-link, .markdown-body h6 .mini-icon-link { display: none; - color: #000; + color: var(--fg-strong, #000); } .markdown-body h1:hover a.anchor, .markdown-body h2:hover a.anchor, .markdown-body h3:hover a.anchor, .markdown-body h4:hover a.anchor, .markdown-body h5:hover a.anchor, .markdown-body h6:hover a.anchor { text-decoration: none; @@ -55,19 +93,19 @@ sys.stdout.write(''' display: inline-block; } div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div#cgit .markdown-body h3 a.toclink, div#cgit .markdown-body h4 a.toclink, div#cgit .markdown-body h5 a.toclink, div#cgit .markdown-body h6 a.toclink { - color: black; + color: var(--fg-strong, #000); } .markdown-body h1 tt, .markdown-body h1 code, .markdown-body h2 tt, .markdown-body h2 code, .markdown-body h3 tt, .markdown-body h3 code, .markdown-body h4 tt, .markdown-body h4 code, .markdown-body h5 tt, .markdown-body h5 code, .markdown-body h6 tt, .markdown-body h6 code { font-size: inherit; } .markdown-body h1 { font-size: 28px; - color: #000; + color: var(--fg-strong, #000); } .markdown-body h2 { font-size: 24px; - border-bottom: 1px solid #ccc; - color: #000; + border-bottom: 1px solid var(--border, #ccc); + color: var(--fg-strong, #000); } .markdown-body h3 { font-size: 18px; @@ -79,18 +117,14 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# font-size: 14px; } .markdown-body h6 { - color: #777; + color: var(--fg-mute, #777); font-size: 14px; } .markdown-body p, .markdown-body blockquote, .markdown-body ul, .markdown-body ol, .markdown-body dl, .markdown-body table, .markdown-body pre { margin: 15px 0; } .markdown-body hr { - background: transparent url("/dirty-shade.png") repeat-x 0 0; - border: 0 none; - color: #ccc; - height: 4px; - padding: 0; + border: 2px solid var(--border, #ccc); } .markdown-body>h2:first-child, .markdown-body>h1:first-child, .markdown-body>h1:first-child+h2, .markdown-body>h3:first-child, .markdown-body>h4:first-child, .markdown-body>h5:first-child, .markdown-body>h6:first-child { margin-top: 0; @@ -152,9 +186,9 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# margin-bottom: 0px; } .markdown-body blockquote { - border-left: 4px solid #DDD; + border-left: 4px solid var(--border, #ddd); padding: 0 15px; - color: #777; + color: var(--fg-mute, #777); } .markdown-body blockquote>:first-child { margin-top: 0px; @@ -166,15 +200,15 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# font-weight: bold; } .markdown-body table th, .markdown-body table td { - border: 1px solid #ccc; + border: 1px solid var(--border, #ccc); padding: 6px 13px; } .markdown-body table tr { - border-top: 1px solid #ccc; - background-color: #fff; + border-top: 1px solid var(--border, #ccc); + background-color: var(--bg, #fff); } .markdown-body table tr:nth-child(2n) { - background-color: #f8f8f8; + background-color: var(--bg-zebra, #f8f8f8); } .markdown-body img { max-width: 100%; @@ -186,7 +220,7 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# overflow: hidden; } .markdown-body span.frame>span { - border: 1px solid #ddd; + border: 1px solid var(--border, #ddd); display: block; float: left; overflow: hidden; @@ -200,7 +234,7 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# } .markdown-body span.frame span span { clear: both; - color: #333; + color: var(--fg, #333); display: block; padding: 5px 0 0; } @@ -258,8 +292,8 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# .markdown-body code, .markdown-body tt { margin: 0 2px; padding: 0px 5px; - border: 1px solid #eaeaea; - background-color: #f8f8f8; + border: 1px solid var(--border, #eaeaea); + background-color: var(--bg-zebra, #f8f8f8); border-radius: 3px; } .markdown-body code { @@ -273,8 +307,8 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# background: transparent; } .markdown-body .highlight pre, .markdown-body pre { - background-color: #f8f8f8; - border: 1px solid #ccc; + background-color: var(--bg-zebra, #f8f8f8); + border: 1px solid var(--border, #ccc); font-size: 13px; line-height: 19px; overflow: auto; @@ -288,9 +322,9 @@ div#cgit .markdown-body h1 a.toclink, div#cgit .markdown-body h2 a.toclink, div# border: none; } ''') -sys.stdout.write(HtmlFormatter(style='pastie').get_style_defs('.highlight')) +sys.stdout.write(style_defs('.highlight')) sys.stdout.write(''' -</style> +</style> ''') sys.stdout.write("<div class='markdown-body'>") sys.stdout.flush() @@ -301,6 +335,7 @@ markdown.markdownFromFile( "markdown.extensions.fenced_code", "markdown.extensions.codehilite", "markdown.extensions.tables", + "markdown.extensions.sane_lists", TocExtension(anchorlink=True)], extension_configs={ "markdown.extensions.codehilite":{"css_class":"highlight"}}) diff --git a/filters/syntax-highlighting.py b/filters/syntax-highlighting.py index e912594..d757e2d 100755 --- a/filters/syntax-highlighting.py +++ b/filters/syntax-highlighting.py @@ -30,11 +30,50 @@ from pygments.lexers import guess_lexer_for_filename from pygments.formatters import HtmlFormatter +# Pygments' token classes, mapped onto the --syn-* custom properties that +# cgit.css defines. The fallbacks are the palette those properties default to, +# so that the output stays readable under a stylesheet without them. +SYNTAX_COLORS = ( + (('k', 'kc', 'kd', 'kn', 'kr'), '--syn-keyword', '#000', + 'font-weight: bold'), + (('kp',), '--syn-keyword', '#000', None), + (('kt',), '--syn-type', '#010181', None), + (('nc', 'nf', 'nn', 'ne'), '--syn-keyword-alt', '#0057ae', None), + (('s', 'sa', 'sb', 'sc', 'dl', 'sd', 's2', 'sh', 'sx', 'sr', 's1', 'ss'), + '--syn-string', '#bf0303', None), + (('se',), '--syn-escape', '#f0f', None), + (('si',), '--syn-interpolation', '#0057ae', None), + (('c', 'ch', 'cm', 'c1', 'cs'), '--syn-comment', '#838183', + 'font-style: italic'), + (('cp', 'cpf'), '--syn-preproc', '#008200', None), + (('m', 'mb', 'mf', 'mh', 'mi', 'mo', 'il'), '--syn-number', '#b07e00', + None), + (('o', 'ow', 'p'), '--syn-operator', '#000', None), + (('err',), '--syn-error', '#bf0303', None), + (('gd',), '--red', 'red', None), + (('gi',), '--green', 'green', None), + (('lineno', 'linenos'), '--syn-linenum', '#555', None), +) + + +def style_defs(prefix='.highlight'): + rules = [] + for classes, prop, fallback, extra in SYNTAX_COLORS: + selector = ', '.join('%s .%s' % (prefix, c) for c in classes) + decls = 'color: var(%s, %s)' % (prop, fallback) + if extra: + decls += '; ' + extra + rules.append('%s { %s }' % (selector, decls)) + rules.append('%s .hll { background-color: var(--syn-mark-bg, #ffb) }' + % prefix) + return '\n'.join(rules) + '\n' + + sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8', errors='replace') sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') data = sys.stdin.read() filename = sys.argv[1] -formatter = HtmlFormatter(style='pastie', nobackground=True) +formatter = HtmlFormatter(nobackground=True) try: lexer = guess_lexer_for_filename(filename, data) @@ -48,8 +87,8 @@ except TypeError: lexer = TextLexer() # highlight! :-) -# printout pygments' css definitions as well +# printout the css definitions for pygments' token classes as well sys.stdout.write('<style>') -sys.stdout.write(formatter.get_style_defs('.highlight')) +sys.stdout.write(style_defs('.highlight')) sys.stdout.write('</style>') sys.stdout.write(highlight(data, lexer, formatter, outfile=None)) diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh index 840bc34..bb8d60c 100755 --- a/filters/syntax-highlighting.sh +++ b/filters/syntax-highlighting.sh @@ -8,8 +8,10 @@ # might have to use an external call to sed instead. # # Note: the highlight command (http://www.andre-simon.de/) uses css for syntax -# highlighting, so you'll probably want something like the following included -# in your css file: +# highlighting. cgit.css defines these classes in terms of its --syn-* custom +# properties, so nothing has to be added when using the default stylesheet. +# The palette below, from highlight 3.13, is what those properties default to; +# a custom stylesheet wanting the same colors can use it directly: # # Style definition file generated by highlight 2.4.8, http://www.andre-simon.de/ # @@ -114,8 +116,12 @@ EXTENSION="${BASENAME##*.}" # Version 2 can be found (for example) on EPEL 5, while version 3 can be # found (for example) on EPEL 6. # +# Note that -I (--include-style) is not used: the stylesheet it embeds in the +# output would override the .hl rules in cgit.css and with them any theming +# done through the --syn-* custom properties. +# # This is for version 2 -exec highlight --force -f -I -X -S "$EXTENSION" 2>/dev/null +exec highlight --force -f -X -S "$EXTENSION" 2>/dev/null # This is for version 3 -#exec highlight --force -f -I -O xhtml -S "$EXTENSION" 2>/dev/null +#exec highlight --force -f -O xhtml -S "$EXTENSION" 2>/dev/null |