aboutsummaryrefslogtreecommitdiff
path: root/muppet
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2023-07-01 09:41:03 +0200
committerHugo Hörnquist <hugo@lysator.liu.se>2023-07-01 13:50:13 +0200
commit5f05951e9ba1ff51f4f6542bf1cddff7c9efa7ef (patch)
tree2072d7a3c693884af59fd61d0dcc779d42538b13 /muppet
parentSwitch to scss. (diff)
downloadmuppet-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__.py3
-rw-r--r--muppet/format.py9
-rw-r--r--muppet/output.py12
-rw-r--r--muppet/syntax_highlight/__init__.py39
-rw-r--r--muppet/syntax_highlight/andre_simon.py36
-rw-r--r--muppet/syntax_highlight/plain.py14
-rw-r--r--muppet/syntax_highlight/pygments.py24
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}
+ """