From 5f05951e9ba1ff51f4f6542bf1cddff7c9efa7ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= <hugo@lysator.liu.se> Date: Sat, 1 Jul 2023 09:41:03 +0200 Subject: [PATCH] Rework how highlighting works. See static-src/README.rst for details about how it works. --- Makefile | 8 +- muppet/__main__.py | 3 +- muppet/format.py | 9 +- muppet/output.py | 12 +- muppet/syntax_highlight/__init__.py | 39 +++++++ muppet/syntax_highlight/andre_simon.py | 36 ++++++ muppet/syntax_highlight/plain.py | 14 +++ muppet/syntax_highlight/pygments.py | 24 ++++ static-src/.gitignore | 3 + static-src/Makefile | 58 +++++++++ static-src/README.rst | 109 +++++++++++++++++ static-src/_breadcrumb.scss | 155 ++----------------------- static-src/_breadcrumb.scss.map | 7 -- static-src/_highlight.scss | 49 -------- static-src/build_css.py | 146 +++++++++++++++++++++++ static-src/colorscheme/default.yaml | 23 ++++ static-src/highlight/andre_simon.yaml | 26 +++++ static-src/highlight/muppet.yaml | 25 ++++ static-src/highlight/pygments.yaml | 61 ++++++++++ static-src/style.scss | 20 +++- static/.gitignore | 1 - templates/code_page.html | 4 +- 22 files changed, 614 insertions(+), 218 deletions(-) create mode 100644 muppet/syntax_highlight/__init__.py create mode 100644 muppet/syntax_highlight/andre_simon.py create mode 100644 muppet/syntax_highlight/plain.py create mode 100644 muppet/syntax_highlight/pygments.py create mode 100644 static-src/.gitignore create mode 100644 static-src/Makefile create mode 100644 static-src/README.rst delete mode 100644 static-src/_breadcrumb.scss.map delete mode 100644 static-src/_highlight.scss create mode 100755 static-src/build_css.py create mode 100644 static-src/colorscheme/default.yaml create mode 100644 static-src/highlight/andre_simon.yaml create mode 100644 static-src/highlight/muppet.yaml create mode 100644 static-src/highlight/pygments.yaml delete mode 100644 static/.gitignore diff --git a/Makefile b/Makefile index 3000cef..b8cf57a 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ DOC_OUTPUT = doc.rendered OUTPUT_FLAGS = --path-base /code/muppet-strings/output \ --env ~/puppet/generated-environments/production/modules/ -SCSS = sass +SCSS = scss -output: static/style.css +output: static-src/style.css python -m muppet $(OUTPUT_FLAGS) check_style: @@ -37,5 +37,5 @@ documentation: $(DOC_OUTPUT)/index.html clean: -rm -r output -static/%.css: static-src/style.scss $(wildcard static-src/_*.scss) - $(SCSS) --sourcemap=auto -Istatic-src $< $@ +static-src/style.css: + $(MAKE) -C $(dir $@) $(notdir $@) diff --git a/muppet/__main__.py b/muppet/__main__.py index 943f9ae..b064cf1 100644 --- a/muppet/__main__.py +++ b/muppet/__main__.py @@ -47,7 +47,8 @@ def __main() -> None: # print(module) setup_module('output', module, path_base=args.path_base) - os.system("cp -r static output") + os.system('make -C static-src --silent install-full PREFIX=$PWD/output') + os.system("cp -r static/* output/static/") if __name__ == '__main__': diff --git a/muppet/format.py b/muppet/format.py index 97c38d1..870dfd3 100644 --- a/muppet/format.py +++ b/muppet/format.py @@ -1117,7 +1117,7 @@ def format_class(d_type: dict[str, Any]) -> str: # print(name, file=sys.stderr) out += print_docstring(name, d_type['docstring']) - out += '<pre><code class="puppet">' + out += '<pre class="highlight-muppet"><code class="puppet">' out += render(renderer, data) out += '</code></pre>' return out @@ -1136,7 +1136,7 @@ def format_type_alias(d_type: dict[str, Any]) -> str: # print(name, file=sys.stderr) out += print_docstring(name, d_type['docstring']) out += '\n' - out += '<pre><code class="puppet">' + out += '<pre class="highlight-muppet"><code class="puppet">' t = parse_puppet(d_type['alias_of']) data = parse(t, 0, ['root']) out += render(renderer, data) @@ -1152,7 +1152,7 @@ def format_defined_type(d_type: dict[str, Any]) -> str: # print(name, file=sys.stderr) out += print_docstring(name, d_type['docstring']) - out += '<pre><code class="puppet">' + out += '<pre class="highlight-muppet"><code class="puppet">' t = parse_puppet(d_type['source']) out += render(renderer, parse(t, 0, ['root'])) out += '</code></pre>\n' @@ -1201,9 +1201,10 @@ def format_puppet_function(function: dict[str, Any]) -> str: signature['signature'] signature['docstring'] if t in ['ruby3x', 'ruby4x']: + # TODO manual highlight here out += f'<pre><code class="ruby">{function["source"]}</code></pre>\n' elif t == 'puppet': - out += '<pre><code class="puppet">' + out += '<pre class="highlight-muppet"><code class="puppet">' try: t = parse_puppet(function['source']) out += str(parse(t, 0, ['root'])) diff --git a/muppet/output.py b/muppet/output.py index 0e83c58..7e2266b 100644 --- a/muppet/output.py +++ b/muppet/output.py @@ -30,6 +30,7 @@ from collections.abc import ( from .util import group_by from .puppet.strings import isprivate from .breadcrumbs import breadcrumbs +from .syntax_highlight import highlight # TODO replace 'output' with base, or put this somewhere else @@ -291,8 +292,15 @@ def setup_module(base: str, module: ModuleEntry, *, path_base: str) -> None: # TODO option to add .txt extension (for web serverse which # treat .pp as application/binary) - with open(os.path.join(dir, 'source.pp.txt'), 'w') as f: - f.write(puppet_class['source']) + with open(os.path.join(dir, 'source.pp.txt'), 'wb') as f: + with open(module.file(puppet_class['file']), 'rb') as g: + f.write(g.read()) + + with open(os.path.join(dir, 'source.pp.html'), 'w') as f: + template = jinja.get_template('code_page.html') + with open(module.file(puppet_class['file']), 'r') as g: + f.write(template.render(content=highlight(g.read(), 'puppet'), + path_base=path_base)) with open(os.path.join(dir, 'source.json'), 'w') as f: json.dump(puppet_class, f, indent=2) diff --git a/muppet/syntax_highlight/__init__.py b/muppet/syntax_highlight/__init__.py new file mode 100644 index 0000000..bcadf81 --- /dev/null +++ b/muppet/syntax_highlight/__init__.py @@ -0,0 +1,39 @@ +""" +Syntax highlight with the best available backend. + +Syntax highlight the given code by the best, available, syntax +highlighter, returning the result as HTML. The default highlighter +simply wraps the output in +``<pre><code class={language}>{code}</code></pre>`` +(with escaping). This means that it can still be handled by JavaScript if so desired. +""" + +from . import pygments +from . import andre_simon +from . import plain + +from typing import cast + + +for module in [pygments, andre_simon, plain]: + if module.available: + backend = module + break +else: + # This should never happen, since ``plain`` should always be + # available. + raise ValueError("No applicable highlight module") + + +def highlight(source: str, language: str) -> str: + """ + Highlight the given source as language, retuning HTML. + + :param source: + Source code to highlight. + :param language: + Language of the source code. + :returns: + An HTML string. + """ + return cast(str, backend.highlight(source, language)) diff --git a/muppet/syntax_highlight/andre_simon.py b/muppet/syntax_highlight/andre_simon.py new file mode 100644 index 0000000..7bbcd43 --- /dev/null +++ b/muppet/syntax_highlight/andre_simon.py @@ -0,0 +1,36 @@ +""" +Syntax highlighting through the highlight(1) command. + +The name "Andre Simon" is choosen based of the author, and that +"highlight" by itself it really non-descriptive. +""" + +import subprocess + +try: + subprocess.run(['highlight', '--version'], stdout=subprocess.DEVNULL) + available = True +except FileNotFoundError: + available = False + + +def highlight(code: str, language: str) -> str: + """Highlight code through the ``highlight`` command.""" + # TODO line- vs pygments line_ + cmd = subprocess.run(['highlight', + '--out-format', 'html', + '--fragment', + '--line-numbers', + '--anchors', + '--anchors-prefix=line', + '--class-name=NONE', + '--syntax', language, + '--enclose-pre'], + capture_output=True, + text=True, + input=code, + check=True) + return f""" + <!-- Generated through highlight(1), as language {language} --> + <div class="highlight-andre-simon">{cmd.stdout}</div> + """ diff --git a/muppet/syntax_highlight/plain.py b/muppet/syntax_highlight/plain.py new file mode 100644 index 0000000..0d1234f --- /dev/null +++ b/muppet/syntax_highlight/plain.py @@ -0,0 +1,14 @@ +"""Non-highlighter useful as a backup.""" + +import html + +available = True + + +def highlight(code: str, language: str) -> str: + """Return the code "highlighted" by wrapping it in <pre> tags.""" + out = f'<pre><code class="{language}">{html.escape(code)}</code></pre>' + return f""" + <!-- "Genererated" as plain output --> + <div class"highlight-plain">{out}</div> + """ diff --git a/muppet/syntax_highlight/pygments.py b/muppet/syntax_highlight/pygments.py new file mode 100644 index 0000000..05e8562 --- /dev/null +++ b/muppet/syntax_highlight/pygments.py @@ -0,0 +1,24 @@ +"""Syntax highlighting through pygments.""" + +try: + from pygments.formatters import HtmlFormatter + from pygments.lexers import get_lexer_by_name + import pygments + available = True +except ModuleNotFoundError: + available = False + + +def highlight(code: str, language: str) -> str: + """Highlight code through pygments.""" + out = pygments.highlight(code, get_lexer_by_name(language), + HtmlFormatter(cssclass='highlight-pygments', + lineanchors='line', + linenos='table', + # linenos='inline' + anchorlinenos=True, + )) + return f""" + <!-- Generated through pygments, as {language} --> + {out} + """ diff --git a/static-src/.gitignore b/static-src/.gitignore new file mode 100644 index 0000000..6de9d50 --- /dev/null +++ b/static-src/.gitignore @@ -0,0 +1,3 @@ +out/ +style.css +*.map diff --git a/static-src/Makefile b/static-src/Makefile new file mode 100644 index 0000000..e01aded --- /dev/null +++ b/static-src/Makefile @@ -0,0 +1,58 @@ +.PHONY: all clean install install-full install-bare + +SCSS = scss +OUT_DIR = out +TARGET = style.css + +DESTDIR = +PREFIX = /usr/local/share/muppet/ +# Path relative install root where the static files should end up +LOCAL_PATH = static + +# Highlighting files +highlights = $(wildcard highlight/*.yaml) +# Colorscheme files +colorschemes = $(wildcard colorscheme/*.yaml) +# Generated highlighting and colorscheme files +outputs = $(patsubst colorscheme/%.yaml,$(OUT_DIR)/_colorscheme_%.scss,$(colorschemes)) \ + $(patsubst highlight/%.yaml,$(OUT_DIR)/_highlight_%.scss,$(highlights)) + +# Included scss files +SCSS_FILES = $(wildcard _*.scss) + +all: style.css + +clean: + -rm $(outputs) + -rmdir $(OUT_DIR) + -rm $(TARGET) + -rm $(TARGET).map + +$(TARGET): style.scss $(SCSS_FILES) $(outputs) + $(SCSS) --sourcemap=auto -I. -Iout $< $@ + +$(OUT_DIR)/_highlight_%.scss: highlight/%.yaml $(OUT_DIR) + ./build_css.py highlight $< > $@ + +$(OUT_DIR)/_colorscheme_%.scss: colorscheme/%.yaml $(OUT_DIR) + ./build_css.py colorscheme $< > $@ + +$(OUT_DIR): + mkdir -p $@ + + +dest=$(abspath $(DESTDIR)/$(PREFIX)/$(LOCAL_PATH)) + +# Install generated files, along with most source files and the map +# file, to aid in debugging +install-full: $(TARGET) + install -d "$(dest)" + install -d "$(dest)/$(OUT_DIR)" + install -m644 $(outputs) "$(dest)/$(OUT_DIR)" + install -m644 "$(TARGET)" "$(TARGET).map" style.scss $(SCSS_FILES) "$(dest)" + +# Only install the generated files +install-bare: $(TARGET) + install -D -m644 -t "$(dest)" $(TARGET) + +install: install-full diff --git a/static-src/README.rst b/static-src/README.rst new file mode 100644 index 0000000..3d8b52f --- /dev/null +++ b/static-src/README.rst @@ -0,0 +1,109 @@ +.. _highlight-readme: + +.. Introduction + +Syntax highlighting in the HTML output is handled in a way to allow +easy changing of highlighting engine, and of colorschemes. +All syntax objects are grouped into one of the Abstract highlight +groups (see :ref:`abstract-highlight-groups`). Highlighting files maps +these groups onto distinct CSS classes depending on the highlighting +engine, and colorscheme files maps these into CSS styles. + + + +Colorschemes +============ + +Colorscheme files should be placed in ``colorscheme/*.yaml``, and +should contain a mapping for all (wanted) abstract highlight groups, +onto mappings containing (any of) the following keys: + +- ``color`` +- ``background`` +- ``font-style`` +- ``font-weight`` + +These will be mapped directly into the CSS. + +The special key *raw-append* also exists, which, if present, should +contain raw CSS code which will be appended to this colorscheme. +This is mainly useful to target highlighting specific classes not +exposed by the abstract highlight groups. + +.. TODO useful raw selectors + - ``:root`` + - ``.highlight-pygments`` + - ``.highlight-andre-simon`` + - ``.highlight-muppet`` + +Sample CSS +---------- + +The generated CSS code will have the following form detailed in +:ref:`sample-css`. Note that the selector (``.comment``) will depend +on the highlight file, while the variable names (``--hl-comment-*``) +depend on the abstract highlight group. + +.. code-block:: css + :name: sample-css + :caption: fragment of generated CSS for a colorscheme. + + .comment { + color: var(--hl-comment-color); + background-color: var(--hl-comment-background); + font-style: var(--hl-comment-font-style); + font-weight: var(--hl-comment-font-weight); + } + + +Highlight files +=============== + +Highlight files map ref:`abstract-highlight_group` to concrete CSS +classes. Each Yaml file (located in ``highlight/*.yaml``) should +contain a mapping from abstract highlight groups, to lists of css +classes. + + +.. _abstract-highlight-group: + +Abstract highlight groups +========================= + +The available Abstract highlight groups are as follows: + +``comment`` + Comments + +``error`` + TODO + +``escape`` + Escape sequences embedded in strings + +``interpolate`` + Variables interpolated in strings + +``keyword`` + Language reserved words (like ``class``, ...) + +``line`` + Line numbers (not part of the actual code) + +``number`` + Numeric literals + +``operator`` + operators (``+``, ``in``, ...) + +``regex`` + Regex literals + +``special`` + TODO + +``string`` + String literals + +``variable`` + Variables diff --git a/static-src/_breadcrumb.scss b/static-src/_breadcrumb.scss index 63534d6..6918af0 100644 --- a/static-src/_breadcrumb.scss +++ b/static-src/_breadcrumb.scss @@ -1,148 +1,11 @@ -@charset "UTF-8"; -/* -------------------------------------------------- */ -.parse-error { - background: red; - color: yellow; } - -/* -------------------------------------------------- */ -h2 { - position: sticky; - top: 0; - background: white; - display: block; - z-index: 100; } - -/* -------------------------------------------------- */ -.documentation { - display: none; } - -/* -.var { - position: relative; -} - -.var .documentation { - display: none; - position: absolute; - top: 2ch; - left: 0; - border: 1px solid black; - background: lightblue; - z-index: 10; -} - -.var:hover .documentation { - display: block; -} -*/ -.noscript { - display: none; } - -code.json { - font-size: 80%; } - -:target { - background-color: yellow; } - -.overview-list p { - display: inline; } - -.example { - background: lightgray; - padding: 1em; - border-radius: 1ex; } - -.comment { - border-left: 1ex; - border-left-style: dotted; - display: inline-block; - padding-left: 1em; - font-family: sans; - font-size: 80%; } - .comment p:first-child { - margin-top: 0; } - .comment p:last-child { - margin-bottom: 0; } - -/* -------------------------------------------------- */ .breadcrumb { - padding: 0; } - .breadcrumb li { - display: inline-block; - padding: 0; } - .breadcrumb li:not(:first-child)::before { - content: "»"; - padding: 1ex; } - -/* -.case { color: ; } -.splat { color: ; } -.array { color: ; } -.parse-error { color: ; } -.parameter { color: ; } -.string { color: ; } -.regex { color: ; } -.invoke { color: ; } -.default { color: ; } -.call { color: ; } -.qr { color: ; } -.lambda { color: ; } -.number { color: ; } -.regex-body { color: ; } -.call-method { color: ; } -*/ -.literal { - color: green; } - -.keyword { - color: orange; } - -.type { - color: darkgreen; } - -.qn { - color: darkgreen; } - -.var { - color: blue; } - -.str-var { - color: blue; } - -.name { - color: red; } - -.string { - color: olive; } - -.comment { - color: grey; } - -/* Style for tabgroups */ -.tabs { - display: grid; - grid-template-columns: 1fr; - grid-template-rows: auto 1fr; - border: 1px solid red; } - .tabs menu { - display: flex; - flex-direction: row; - padding: 0; - margin: 0; } - .tabs menu li { - display: block; } - -/* -.tabs menu li { - display: block; - background-color: lightgray; - border: 1px solid gray; + padding: 0; + li { + display: inline-block; + padding: 0; + &:not(:first-child)::before { + content: "»"; + padding: 1ex; + } + } } -*/ -.tab { - display: none; - border: 1px solid green; } - .tab.selected { - display: block !important; } - -/*# sourceMappingURL=_breadcrumb.scss.map */ diff --git a/static-src/_breadcrumb.scss.map b/static-src/_breadcrumb.scss.map deleted file mode 100644 index 5770a45..0000000 --- a/static-src/_breadcrumb.scss.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": ";AACA,wDAAwD;AAExD,YAAa;EACZ,UAAU,EAAE,GAAG;EACf,KAAK,EAAE,MAAM;;AAGd,wDAAwD;AAExD,EAAG;EACF,QAAQ,EAAE,MAAM;EAChB,GAAG,EAAE,CAAC;EACN,UAAU,EAAE,KAAK;EACjB,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,GAAG;;AAGb,wDAAwD;AAExD,cAAe;EACd,OAAO,EAAE,IAAI;;AAGd;;;;;;;;;;;;;;;;;;EAkBE;AAEF,SAAU;EACT,OAAO,EAAE,IAAI;;AAGd,SAAU;EACT,SAAS,EAAE,GAAG;;AAGf,OAAQ;EACP,gBAAgB,EAAE,MAAM;;AAGzB,gBAAiB;EAChB,OAAO,EAAE,MAAM;;AAGhB,QAAS;EACR,UAAU,EAAE,SAAS;EACrB,OAAO,EAAE,GAAG;EACZ,aAAa,EAAE,GAAG;;AAGnB,QAAS;EACR,WAAW,EAAE,GAAG;EAChB,iBAAiB,EAAE,MAAM;EACzB,OAAO,EAAE,YAAY;EACrB,YAAY,EAAE,GAAG;EACjB,WAAW,EAAE,IAAI;EACjB,SAAS,EAAE,GAAG;EAEd,sBAAc;IACb,UAAU,EAAE,CAAC;EAGd,qBAAa;IACZ,aAAa,EAAE,CAAC;;AAIlB,wDAAwD;ACnFxD,WAAY;EACX,OAAO,EAAE,CAAC;EAEV,cAAG;IACF,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,CAAC;EAGX,wCAA6B;IAC5B,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;;ACVd;;;;;;;;;;;;;;;;EAgBE;AAEF,QAAS;EAAE,KAAK,EAAE,KAAK;;AAKvB,QAAS;EAAE,KAAK,EAAE,MAAM;;AAWxB,KAAM;EAAE,KAAK,EAAE,SAAS;;AACxB,GAAI;EAAE,KAAK,EAAE,SAAS;;AAEtB,IAAK;EAAE,KAAK,EAAE,IAAI;;AAClB,QAAS;EAAE,KAAK,EAAE,IAAI;;AAEtB,KAAM;EAAE,KAAK,EAAE,GAAG;;AAElB,OAAQ;EACP,KAAK,EAAE,KAAK;;AAGb,QAAS;EACR,KAAK,EAAE,IAAI;;AC/CZ,yBAAyB;AACzB,KAAM;EACL,OAAO,EAAE,IAAI;EACb,qBAAqB,EAAE,GAAG;EAC1B,kBAAkB,EAAE,QAAQ;EAC5B,MAAM,EAAE,aAAa;EAErB,UAAK;IACJ,OAAO,EAAE,IAAI;IACb,cAAc,EAAE,GAAG;IACnB,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,CAAC;EAGV,aAAQ;IACP,OAAO,EAAE,KAAK;;AAKhB;;;;;;EAME;AAEF,IAAK;EACJ,OAAO,EAAE,IAAI;EACb,MAAM,EAAE,eAAe;EAEvB,aAAW;IACV,OAAO,EAAE,gBAAgB;;ACjC3B,EAAG;EAAE,KAAK,EAAE,OAAO;;AACnB,EAAG;EAAE,KAAK,EAAE,OAAO;;AACnB,EAAG;EAAE,KAAK,EAAE,OAAO;;AACnB,EAAG;EAAE,KAAK,EAAE,OAAO;;AACnB,EAAG;EAAE,KAAK,EAAE,OAAO;;AACnB,EAAG;EAAE,KAAK,EAAE,OAAO", -"sources": ["style.scss","_breadcrumb.scss","_highlight.scss","_tabset.scss","_color-headers.scss"], -"names": [], -"file": "_breadcrumb.scss" -} diff --git a/static-src/_highlight.scss b/static-src/_highlight.scss deleted file mode 100644 index b3aa5d0..0000000 --- a/static-src/_highlight.scss +++ /dev/null @@ -1,49 +0,0 @@ -/* -.case { color: ; } -.splat { color: ; } -.array { color: ; } -.parse-error { color: ; } -.parameter { color: ; } -.string { color: ; } -.regex { color: ; } -.invoke { color: ; } -.default { color: ; } -.call { color: ; } -.qr { color: ; } -.lambda { color: ; } -.number { color: ; } -.regex-body { color: ; } -.call-method { color: ; } -*/ - -.literal { color: green; } -.true {} -.false {} -.undef {} - -.keyword { color: orange; } -.class {} -.or {} -.define {} -.unless {} -.if {} -.else {} -.function {} -.and {} -.in {} - -.type { color: darkgreen; } -.qn { color: darkgreen; } - -.var { color: blue; } -.str-var { color: blue; } - -.name { color: red; } - -.string { - color: olive; -} - -.comment { - color: grey; -} diff --git a/static-src/build_css.py b/static-src/build_css.py new file mode 100755 index 0000000..38cb2c6 --- /dev/null +++ b/static-src/build_css.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 + +""" +(S)CSS generators for help with highlighting. + +:ref:`highlight-readme`. +""" + +import yaml +from datetime import datetime +import argparse + +CSS_RULES = ''' + color: var(--hl-{name}-color); + background-color: var(--hl-{name}-background); + font-style: var(--hl-{name}-font-style); + font-weight: var(--hl-{name}-font-weight); +''' + +HEADER = '''/* +* File autogenerated from {source}. +* Generated at {time} +*/ +''' + +HIGHLIGHT_GROUPS = [ + "comment", + "error", + "escape", + "interpolate", + "keyword", + "line", + "number", + "operator", + "regex", + "special", + "string", + "variable", +] + +HIGHLIGHT_VARIABLES = [ + 'color', + 'background', + 'font-style', + 'font-weight', +] + + +def build_highlight_map(source_file: str) -> str: + """ + Generate CSS rules from source file. + + :param source_file: + A yaml file containing mappings from our abstract highlight + groups, to concrete CSS classes. + :returns: + Generated CSS code, applicable to be written directly to a + file. + """ + with open(source_file) as f: + data = yaml.full_load(f) + result = '' + result += HEADER.format(source=source_file, + time=datetime.now()) + for name, classes in data.items(): + output: str = '\n' + output += ', '.join(f'.{c}' for c in classes) + output += ' {' + output += CSS_RULES.format(name=name) + output += '}' + + result += output + '\n' + + return result + + +def build_colorscheme(source_file: str, + selector: str = ':root') -> str: + """ + Build CSS colorscheme from source file. + + :param selector: + CSS selector to use for this group. + :param source_file: + Yaml file containing mapping from abrtract highlighting groups, + to CSS attributes. + :returns: + Generated CSS code, applicable to be written directly to a + file. + """ + with open(source_file) as f: + data = yaml.full_load(f) + + result = '' + result += HEADER.format(source=source_file, + time=datetime.now()) + result += f'{selector} {{\n' + for group_key in HIGHLIGHT_GROUPS: + if group := data.get(group_key): + for value_key in HIGHLIGHT_VARIABLES: + if value := group.get(value_key): + result += f' --hl-{group_key}-{value_key}: {value};\n' + if raw := group.get('raw-append'): + result += raw + '\n' + # Raw CSS rules, useful to capture something not handled by + # the abstract groups. + if raw := data.get('raw-append'): + result += raw + '\n' + + result += '}\n' + return result + + +def run_colorscheme(args: argparse.Namespace) -> None: + """Entry point when using the colorscheme mode.""" + print(build_colorscheme(selector=args.selector, + source_file=args.source)) + + +def run_highlight(args: argparse.Namespace) -> None: + """Entry point when using the highlight mode.""" + print(build_highlight_map(source_file=args.source)) + + +def main() -> None: + """Primary entry point of program.""" + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers() + + parser_hl = subparsers.add_parser('highlight') + parser_hl.set_defaults(func=run_highlight) + parser_hl.add_argument('source') + + parser_cs = subparsers.add_parser('colorscheme') + parser_cs.set_defaults(func=run_colorscheme) + parser_cs.add_argument('--selector', + default=':root') + parser_cs.add_argument('source') + + args = parser.parse_args() + + args.func(args) + + +if __name__ == '__main__': + main() diff --git a/static-src/colorscheme/default.yaml b/static-src/colorscheme/default.yaml new file mode 100644 index 0000000..5fa61d3 --- /dev/null +++ b/static-src/colorscheme/default.yaml @@ -0,0 +1,23 @@ +comment: + color: '#3D7B7B' + font-style: italic +error: +escape: + color: red +interpolate: +keyword: + color: green + font-weight: bold +line: +number: + color: green +operator: + color: '#666666' +regex: + color: green +special: + color: olive +string: + color: '#BA2121' +variable: + color: darkblue diff --git a/static-src/highlight/andre_simon.yaml b/static-src/highlight/andre_simon.yaml new file mode 100644 index 0000000..84dd00d --- /dev/null +++ b/static-src/highlight/andre_simon.yaml @@ -0,0 +1,26 @@ +# highlight(1) +comment: + - mlc +escape: + - esc +interpolate: + - ipl +keyword: + - kwa +line: + - lin +number: + - num +operator: + - sym +regex: + - kwc +string: + - sng +variable: + - kwb +error: + - err + - erm +special: + - kwd diff --git a/static-src/highlight/muppet.yaml b/static-src/highlight/muppet.yaml new file mode 100644 index 0000000..93491ad --- /dev/null +++ b/static-src/highlight/muppet.yaml @@ -0,0 +1,25 @@ +# Muppet's built in output +comment: + - comment +error: + - parse-error +interpolate: + - str-var +keyword: + - keyword + - literal +operator: + - and + - or +regex: + - regex +special: + - parameter + - qr +number: + - number +string: + - string +variable: + - qn + - var diff --git a/static-src/highlight/pygments.yaml b/static-src/highlight/pygments.yaml new file mode 100644 index 0000000..1f57a7a --- /dev/null +++ b/static-src/highlight/pygments.yaml @@ -0,0 +1,61 @@ +# Pygmentize(1) +comment: + - c + - ch + - cm + - cp + - cpf + - c1 + - cs +error: + - err +escape: + - se +interpolate: + - si +keyword: + - k + - kc + - kd + - kn + - kp + - kr + - kt +number: + - m + - mb + - mf + - mh + - mi + - mo +operator: + - o +regex: + - sr +string: + - s + - sa + - sb + - sc + - dl + - sd + - s2 + - sh + - sx + - sr + - s1 +variable: + - n + - nb + - nc + - 'no' + - nd + - ni + - ne + - nf + - nl + - nn + - nt + - nv +special: + - na diff --git a/static-src/style.scss b/static-src/style.scss index b5c4407..2f0fba2 100644 --- a/static-src/style.scss +++ b/static-src/style.scss @@ -1,4 +1,3 @@ - /* -------------------------------------------------- */ .parse-error { @@ -28,9 +27,11 @@ h3 { /* -------------------------------------------------- */ +/* .documentation { display: none; } +*/ /* .var { @@ -79,6 +80,7 @@ code.json { border-left-style: dotted; display: inline-block; padding-left: 1em; + font-family: sans; font-size: 80%; @@ -93,8 +95,20 @@ code.json { /* -------------------------------------------------- */ +@import "colorscheme_default"; + +.highlight-pygments { + @import "highlight_pygments"; +} + +.highlight-andre-simon { + @import "highlight_andre_simon"; +} + +.highlight-muppet { + @import "highlight_muppet"; +} + @import "breadcrumb"; -@import "highlight"; @import "tabset"; - @import "color-headers"; diff --git a/static/.gitignore b/static/.gitignore deleted file mode 100644 index b3a5267..0000000 --- a/static/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.css diff --git a/templates/code_page.html b/templates/code_page.html index 80ad037..0b588cc 100644 --- a/templates/code_page.html +++ b/templates/code_page.html @@ -8,7 +8,9 @@ Parameters: {% extends "base.html" %} {% block content %} <ul> - <li><a href="source.pp.txt">Raw Source code</a></li> + <li><a href="index.html">Rendered</a></li> + <li><a href="source.pp.html">Source</a></li> + <li><a href="source.pp.txt">Raw Source</a></li> <li><a href="source.json">JSON blob</a></li> </ul> {{ content }} -- GitLab