From 4f14cdffbf165cb3a5b48f5bf5a1b58e515e2ec4 Mon Sep 17 00:00:00 2001 From: Tolmachev Igor Date: Tue, 6 Jan 2026 06:50:50 +0900 Subject: Add material highlight --- Dockerfile | 5 +- cgitrc | 2 +- responsive/cgit.css | 359 ++++++++++++++++++++++++++++++++++++++++-- responsive/md2html | 37 +++++ responsive/syntax-material.py | 37 +++++ 5 files changed, 423 insertions(+), 17 deletions(-) create mode 100755 responsive/md2html create mode 100755 responsive/syntax-material.py diff --git a/Dockerfile b/Dockerfile index 516f38a..df191eb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,11 +15,14 @@ RUN make install COPY cgitrc /app COPY responsive/head.html /app/www/static COPY responsive/cgit.css /app/www/static +COPY responsive/syntax-material.py /app/lib/filters +COPY responsive/md2html /app/lib/filters/html-converters/md2html FROM debian:latest AS cgit-run RUN apt-get update -RUN apt-get install -y python3 python3-pygments lighttpd +RUN apt-get install -y python3 python3-pygments python3-markdown python3-docutils +RUN apt-get install -y lighttpd WORKDIR /app COPY --from=cgit-build /app /app diff --git a/cgitrc b/cgitrc index 99ecefa..981ab64 100644 --- a/cgitrc +++ b/cgitrc @@ -5,6 +5,6 @@ favicon=/static/favicon.ico head-include=/app/www/static/head.html about-filter=/app/lib/filters/about-formatting.sh -source-filter=/app/lib/filters/syntax-highlighting.py +source-filter=/app/lib/filters/syntax-material.py include=/app/etc/cgitrc diff --git a/responsive/cgit.css b/responsive/cgit.css index f9e1b76..c69b01c 100644 --- a/responsive/cgit.css +++ b/responsive/cgit.css @@ -556,27 +556,356 @@ div#cgit div.error { } } -/* --- Fix Syntax Highlighting Alignment --- */ +/* Container override for highlighted code to handle font sizing */ +div#cgit table.blob pre { + font-family: "JetBrains Mono", "Fira Code", monospace; + font-size: 0.95em; + line-height: 1.4; +} -/* 1. Reset margins and padding added by syntax highlighting */ -div#cgit table.blob td.lines div.highlight { - margin: 0; - padding: 0; - border: none; +/* --- Syntax Highlighting Mapping to Material Variables --- */ + +/* Comments - Outline/Grey */ +.hl-c, +.hl-cm, +.hl-cp, +.hl-c1, +.hl-cs { + color: var(--color-outline); + font-style: italic; } -/* 2. Force alignment of line height and fonts */ -div#cgit table.blob td.linenumbers pre, -div#cgit table.blob td.lines pre { - font-family: monospace; - font-size: 14px; - line-height: 1.5 !important; +/* Keywords - Primary (Pinkish/Orange) */ +.hl-k, +.hl-kc, +.hl-kd, +.hl-kn, +.hl-kp, +.hl-kr, +.hl-kt { + color: var(--color-primary); + font-weight: bold; +} + +/* Names/Functions - Tertiary (Yellowish) */ +.hl-n, +.hl-na, +.hl-nb, +.hl-nc, +.hl-no, +.hl-nd, +.hl-ni, +.hl-ne, +.hl-nf, +.hl-nl, +.hl-nn, +.hl-nt, +.hl-nv, +.hl-nx { + color: var(--color-tertiary); +} + +/* Strings - Secondary (Reddish/Brownish) */ +.hl-s, +.hl-sa, +.hl-sb, +.hl-sc, +.hl-dl, +.hl-sd, +.hl-s2, +.hl-se, +.hl-sh, +.hl-si, +.hl-sx, +.hl-sr, +.hl-s1, +.hl-ss { + color: var(--color-secondary); +} + +/* Operators - On Surface (Main text color) */ +.hl-o, +.hl-ow { + color: var(--color-on-surface-variant); +} + +/* Numbers - Primary Container (Brighter accent) */ +.hl-m, +.hl-mb, +.hl-mf, +.hl-mh, +.hl-mi, +.hl-mo, +.hl-il { + color: var(--color-primary-fixed); +} + +/* Errors */ +.hl-err, +.hl-gr { + color: var(--color-error); + background-color: var(--color-error-container); +} + +/* Generic Deleted */ +.hl-gd { + color: var(--color-error); + background-color: var(--color-error-container); +} + +/* Generic Inserted */ +.hl-gi { + color: var(--color-tertiary); + background-color: var(--color-tertiary-container); +} + +/* --- Markdown Body Styles (Material Design) --- */ + +.markdown-body { + font-family: inherit; + font-size: 1rem; + line-height: 1.6; + color: var(--color-on-background); + word-wrap: break-word; +} + +/* Headers */ +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: 600; + line-height: 1.25; + color: var(--color-on-surface); +} + +.markdown-body h1 { + font-size: 2em; + border-bottom: 1px solid var(--color-outline-variant); + padding-bottom: 0.3em; +} +.markdown-body h2 { + font-size: 1.5em; + border-bottom: 1px solid var(--color-outline-variant); + padding-bottom: 0.3em; +} +.markdown-body h3 { + font-size: 1.25em; +} +.markdown-body h4 { + font-size: 1em; +} +.markdown-body h5 { + font-size: 0.875em; +} +.markdown-body h6 { + font-size: 0.85em; + color: var(--color-on-surface-variant); +} + +/* Links */ +.markdown-body a { + color: var(--color-primary); + text-decoration: none; +} +.markdown-body a:hover { + text-decoration: underline; +} + +/* Paragraphs & Lists */ +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body pre { margin-top: 0; + margin-bottom: 16px; } -/* 3. Remove impact of first
 */
-div#cgit table.blob td.lines > pre {
-    white-space: normal;
+.markdown-body hr {
+    height: 0.25em;
+    padding: 0;
+    margin: 24px 0;
+    background-color: var(--color-outline-variant);
+    border: 0;
+}
+
+/* Blockquotes */
+.markdown-body blockquote {
+    padding: 0 1em;
+    color: var(--color-on-surface-variant);
+    border-left: 0.25em solid var(--color-outline);
+    background-color: var(--color-surface-container-low);
+}
+
+/* Tables */
+.markdown-body table {
+    display: block;
+    width: 100%;
+    overflow: auto;
+    border-spacing: 0;
+    border-collapse: collapse;
+}
+
+.markdown-body table th {
+    font-weight: 600;
+    background-color: var(--color-surface-container);
+}
+
+.markdown-body table th,
+.markdown-body table td {
+    padding: 6px 13px;
+    border: 1px solid var(--color-outline-variant);
+}
+
+.markdown-body table tr {
+    background-color: var(--color-surface);
+    border-top: 1px solid var(--color-outline-variant);
+}
+
+.markdown-body table tr:nth-child(2n) {
+    background-color: var(--color-surface-container-lowest);
+}
+
+/* Images */
+.markdown-body img {
+    max-width: 100%;
+    box-sizing: border-box;
+    background-color: var(--color-surface);
+    border-radius: 4px;
+}
+
+/* Code Blocks & Inline Code */
+.markdown-body code,
+.markdown-body tt {
+    padding: 0.2em 0.4em;
     margin: 0;
+    font-size: 85%;
+    font-family: "JetBrains Mono", "Fira Code", monospace;
+    background-color: var(--color-surface-container-high);
+    border-radius: 6px;
+    color: var(--color-on-surface);
+}
+
+.markdown-body pre {
+    padding: 16px;
+    overflow: auto;
+    font-size: 85%;
+    line-height: 1.45;
+    background-color: var(--color-surface-container-lowest);
+    border-radius: 6px;
+    border: 1px solid var(--color-outline-variant);
+}
+
+.markdown-body pre code,
+.markdown-body pre tt {
+    display: inline;
+    max-width: auto;
     padding: 0;
+    margin: 0;
+    overflow: visible;
+    line-height: inherit;
+    word-wrap: normal;
+    background-color: transparent;
+    border: 0;
+}
+
+/* Anchors (Permalinks) */
+.markdown-body .headerlink {
+    float: left;
+    padding-right: 4px;
+    margin-left: -20px;
+    line-height: 1;
+    color: var(--color-primary);
+    text-decoration: none;
+    opacity: 0;
+    transition: opacity 0.2s;
+}
+
+.markdown-body h1:hover .headerlink,
+.markdown-body h2:hover .headerlink,
+.markdown-body h3:hover .headerlink,
+.markdown-body h4:hover .headerlink,
+.markdown-body h5:hover .headerlink,
+.markdown-body h6:hover .headerlink {
+    opacity: 1;
+}
+
+/* Pygments Syntax Highlighting within Markdown
+   (Mapping standard Pygments classes to Material Variables) */
+.markdown-body .highlight .c,
+.markdown-body .highlight .cm,
+.markdown-body .highlight .cp,
+.markdown-body .highlight .c1,
+.markdown-body .highlight .cs {
+    color: var(--color-outline);
+    font-style: italic;
+}
+.markdown-body .highlight .k,
+.markdown-body .highlight .kc,
+.markdown-body .highlight .kd,
+.markdown-body .highlight .kn,
+.markdown-body .highlight .kp,
+.markdown-body .highlight .kr,
+.markdown-body .highlight .kt {
+    color: var(--color-primary);
+    font-weight: bold;
+}
+.markdown-body .highlight .n,
+.markdown-body .highlight .na,
+.markdown-body .highlight .nb,
+.markdown-body .highlight .nc,
+.markdown-body .highlight .no,
+.markdown-body .highlight .nd,
+.markdown-body .highlight .ni,
+.markdown-body .highlight .ne,
+.markdown-body .highlight .nf,
+.markdown-body .highlight .nl,
+.markdown-body .highlight .nn,
+.markdown-body .highlight .nt,
+.markdown-body .highlight .nv,
+.markdown-body .highlight .nx {
+    color: var(--color-tertiary);
+}
+.markdown-body .highlight .s,
+.markdown-body .highlight .sa,
+.markdown-body .highlight .sb,
+.markdown-body .highlight .sc,
+.markdown-body .highlight .dl,
+.markdown-body .highlight .sd,
+.markdown-body .highlight .s2,
+.markdown-body .highlight .se,
+.markdown-body .highlight .sh,
+.markdown-body .highlight .si,
+.markdown-body .highlight .sx,
+.markdown-body .highlight .sr,
+.markdown-body .highlight .s1,
+.markdown-body .highlight .ss {
+    color: var(--color-secondary);
+}
+.markdown-body .highlight .m,
+.markdown-body .highlight .mb,
+.markdown-body .highlight .mf,
+.markdown-body .highlight .mh,
+.markdown-body .highlight .mi,
+.markdown-body .highlight .mo,
+.markdown-body .highlight .il {
+    color: var(--color-primary-fixed);
+}
+.markdown-body .highlight .o,
+.markdown-body .highlight .ow {
+    color: var(--color-on-surface-variant);
+}
+.markdown-body .highlight .g,
+.markdown-body .highlight .gh,
+.markdown-body .highlight .gu,
+.markdown-body .highlight .gd,
+.markdown-body .highlight .gi {
+    color: var(--color-on-surface);
 }
diff --git a/responsive/md2html b/responsive/md2html
new file mode 100755
index 0000000..571c8d7
--- /dev/null
+++ b/responsive/md2html
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+import io
+import sys
+
+import markdown
+from markdown.extensions.toc import TocExtension
+
+sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding="utf-8")
+sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
+
+sys.stdout.write("
") +sys.stdout.flush() + +try: + markdown.markdownFromFile( + output_format="html5", + extensions=[ + "markdown.extensions.fenced_code", + "markdown.extensions.codehilite", + "markdown.extensions.tables", + "markdown.extensions.sane_lists", + "markdown.extensions.admonition", + TocExtension(anchorlink=True, permalink=True), + ], + extension_configs={ + "markdown.extensions.codehilite": { + "css_class": "highlight", + "guess_lang": False, + } + }, + ) +except Exception as e: + sys.stdout.write(f"

Error rendering markdown: {e}

") + sys.stdin.seek(0) + sys.stdout.write(f"
{sys.stdin.read()}
") + +sys.stdout.write("
") diff --git a/responsive/syntax-material.py b/responsive/syntax-material.py new file mode 100755 index 0000000..3176691 --- /dev/null +++ b/responsive/syntax-material.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +import sys + +from pygments import highlight +from pygments.formatters import HtmlFormatter +from pygments.lexers import get_lexer_for_filename, guess_lexer +from pygments.util import ClassNotFound + + +def main(): + filename = sys.argv[-1] if len(sys.argv) > 1 else "stdin" + + try: + data = sys.stdin.read() + except Exception: + return + + try: + lexer = get_lexer_for_filename(filename) + except ClassNotFound: + try: + lexer = guess_lexer(data) + except ClassNotFound: + sys.stdout.write(f"
{data}
") + return + + formatter = HtmlFormatter(style="default", nowrap=True, classprefix="hl-") + + try: + sys.stdout.write("") + highlight(data, lexer, formatter, sys.stdout) + except BrokenPipeError: + pass + + +if __name__ == "__main__": + main() -- cgit v1.2.3