diff options
author | Hugo Hörnquist <hugo@lysator.liu.se> | 2023-07-01 09:41:03 +0200 |
---|---|---|
committer | Hugo Hörnquist <hugo@lysator.liu.se> | 2023-07-01 13:50:13 +0200 |
commit | 5f05951e9ba1ff51f4f6542bf1cddff7c9efa7ef (patch) | |
tree | 2072d7a3c693884af59fd61d0dcc779d42538b13 /muppet | |
parent | Switch to scss. (diff) | |
download | muppet-strings-5f05951e9ba1ff51f4f6542bf1cddff7c9efa7ef.tar.gz muppet-strings-5f05951e9ba1ff51f4f6542bf1cddff7c9efa7ef.tar.xz |
Rework how highlighting works.
See static-src/README.rst for details about how it works.
Diffstat (limited to 'muppet')
-rw-r--r-- | muppet/__main__.py | 3 | ||||
-rw-r--r-- | muppet/format.py | 9 | ||||
-rw-r--r-- | muppet/output.py | 12 | ||||
-rw-r--r-- | muppet/syntax_highlight/__init__.py | 39 | ||||
-rw-r--r-- | muppet/syntax_highlight/andre_simon.py | 36 | ||||
-rw-r--r-- | muppet/syntax_highlight/plain.py | 14 | ||||
-rw-r--r-- | muppet/syntax_highlight/pygments.py | 24 |
7 files changed, 130 insertions, 7 deletions
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} + """ |