From 697f456becfcadd832944432f7a406bdbde02dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= <hugo@lysator.liu.se> Date: Sat, 1 Jul 2023 18:29:15 +0200 Subject: [PATCH] work --- muppet/breadcrumbs.py | 27 ++++++++++++++-- muppet/format.py | 36 ++++++++++++--------- muppet/gather.py | 3 +- muppet/markdown.py | 5 ++- muppet/output.py | 22 ++++++++++--- muppet/puppet/parser.py | 1 + static-src/style.scss | 68 ++++++++++++++++++++++++++++++++++++++-- templates/base.html | 3 +- templates/code_page.html | 4 ++- 9 files changed, 141 insertions(+), 28 deletions(-) diff --git a/muppet/breadcrumbs.py b/muppet/breadcrumbs.py index ae88d3c..70e6d4b 100644 --- a/muppet/breadcrumbs.py +++ b/muppet/breadcrumbs.py @@ -33,7 +33,21 @@ class Breadcrumb: text: str -def breadcrumbs(*items: str | Tuple[str, str]) -> list[Breadcrumb]: +@dataclass +class Breadcrumbs: + """ + A complete set of breadcrumbs. + + Basically a non-empty list, with the last item being guaranteed. + This since the trailing item shouldn't be a link, and with this we + have guaranteed correct data when rendering the template. + """ + + crumbs: list[Breadcrumb] + final: str + + +def breadcrumbs(*items: str | Tuple[str, str]) -> Breadcrumbs: """ Generate a breadcrumb trail. @@ -47,7 +61,7 @@ def breadcrumbs(*items: str | Tuple[str, str]) -> list[Breadcrumb]: """ url = '/' result = [] - for item in items: + for item in items[:-1]: if isinstance(item, str): url += item + '/' text = item @@ -56,4 +70,11 @@ def breadcrumbs(*items: str | Tuple[str, str]) -> list[Breadcrumb]: text = item[0] url = re.sub('/+', '/', url) result.append(Breadcrumb(ref=url, text=text)) - return result + + final = items[-1] + if isinstance(final, str): + finaltxt = final + else: + finaltxt = final[0] + + return Breadcrumbs(result, finaltxt) diff --git a/muppet/format.py b/muppet/format.py index 8c52eb4..bf107ad 100644 --- a/muppet/format.py +++ b/muppet/format.py @@ -1022,7 +1022,7 @@ def parse(form: Any, indent: int, context: list[str]) -> Tag: return tag(f'[|[{form}]|]', 'parse-error') -def print_docstring(name: str, docstring: dict[str, Any]) -> str: +def format_docstring(name: str, docstring: dict[str, Any]) -> Tuple[str, str]: """ Format docstrings as they appear in some puppet types. @@ -1049,8 +1049,6 @@ def print_docstring(name: str, docstring: dict[str, Any]) -> str: # param_defaults = d_type['defaults'] - out += f'<h2><code>{name}</code></h2>\n' - for t in tags: text = html.escape(t.get('text') or '') if t['tag_name'] == 'summary': @@ -1063,6 +1061,7 @@ def print_docstring(name: str, docstring: dict[str, Any]) -> str: if t['tag_name'] == 'example': if name := t.get('name'): out += f'<h3>{name}</h3>\n' + # TODO highlight? out += f'<pre class="example"><code class="puppet">{text}</code></pre>\n' # out += '<dl>' @@ -1081,9 +1080,10 @@ def print_docstring(name: str, docstring: dict[str, Any]) -> str: out += markdown(docstring['text']) out += '</div>' - return out + return (name, out) +# TODO @option tags def build_param_dict(docstring: dict[str, Any]) -> dict[str, str]: """ Extract all parameter documentation from a docstring dict. @@ -1112,7 +1112,7 @@ def build_param_dict(docstring: dict[str, Any]) -> dict[str, str]: return {} -def format_class(d_type: dict[str, Any]) -> str: +def format_class(d_type: dict[str, Any]) -> Tuple[str, str]: """Format Puppet class.""" t = parse_puppet(d_type['source']) data = parse(t, 0, ['root']) @@ -1120,12 +1120,13 @@ def format_class(d_type: dict[str, Any]) -> str: out = '' name = d_type['name'] # print(name, file=sys.stderr) - out += print_docstring(name, d_type['docstring']) + name, body = format_docstring(name, d_type['docstring']) + out += body out += '<pre class="highlight-muppet"><code class="puppet">' out += render(renderer, data) out += '</code></pre>' - return out + return name, out def format_type() -> str: @@ -1133,35 +1134,37 @@ def format_type() -> str: return 'TODO format_type not implemented' -def format_type_alias(d_type: dict[str, Any]) -> str: +def format_type_alias(d_type: dict[str, Any]) -> Tuple[str, str]: """Format Puppet type alias.""" renderer = HTMLRenderer() out = '' name = d_type['name'] # print(name, file=sys.stderr) - out += print_docstring(name, d_type['docstring']) + title, body = format_docstring(name, d_type['docstring']) + out += body out += '\n' out += '<pre class="highlight-muppet"><code class="puppet">' t = parse_puppet(d_type['alias_of']) data = parse(t, 0, ['root']) out += render(renderer, data) out += '</code></pre>\n' - return out + return title, out -def format_defined_type(d_type: dict[str, Any]) -> str: +def format_defined_type(d_type: dict[str, Any]) -> Tuple[str, str]: """Format Puppet defined type.""" renderer = HTMLRenderer(build_param_dict(d_type['docstring'])) out = '' name = d_type['name'] # print(name, file=sys.stderr) - out += print_docstring(name, d_type['docstring']) + title, body = format_docstring(name, d_type['docstring']) + out += body 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' - return out + return title, out def format_resource_type(r_type: dict[str, Any]) -> str: @@ -1206,8 +1209,11 @@ 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' + # TODO syntax highlighting + s = '<pre class="highlight-muppet"><code class="ruby">' + s += function["source"] + s += '</code></pre>\n' + out += s elif t == 'puppet': out += '<pre class="highlight-muppet"><code class="puppet">' try: diff --git a/muppet/gather.py b/muppet/gather.py index 1d3fc48..4795553 100644 --- a/muppet/gather.py +++ b/muppet/gather.py @@ -103,7 +103,8 @@ def get_module(cache: Cache, except FileNotFoundError: metadata = {} - doc_files = glob(os.path.join(os.path.abspath(path), '*.md')) + doc_files = glob(os.path.join(os.path.abspath(path), '*.md')) \ + + glob(os.path.join(os.path.abspath(path), 'LICENSE')) return ModuleEntry(name=name, path=path, diff --git a/muppet/markdown.py b/muppet/markdown.py index df54fee..dd7e1ea 100644 --- a/muppet/markdown.py +++ b/muppet/markdown.py @@ -43,7 +43,10 @@ def markdown(text: str) -> str: .enable('table') \ .enable('strikethrough') - return md.render(text) + output = md.render(text) + if not isinstance(output, str): + raise ValueError(f"Unexpected markdown output: expected str, got {type(output)}") + return output # header_text.downcase().replace(' ', '-') diff --git a/muppet/output.py b/muppet/output.py index 7e2266b..727fe37 100644 --- a/muppet/output.py +++ b/muppet/output.py @@ -298,9 +298,19 @@ def setup_module(base: str, module: ModuleEntry, *, path_base: str) -> None: with open(os.path.join(dir, 'source.pp.html'), 'w') as f: template = jinja.get_template('code_page.html') + crumbs = breadcrumbs( + ('Environment', ''), + module.name, + (puppet_class['name'], + 'manifests/' + '/'.join(puppet_class['name'].split('::')[1:])), + 'This', + ) + with open(module.file(puppet_class['file']), 'r') as g: - f.write(template.render(content=highlight(g.read(), 'puppet'), - path_base=path_base)) + f.write(template.render(title='', + content=highlight(g.read(), 'puppet'), + path_base=path_base, + breadcrumbs=crumbs)) with open(os.path.join(dir, 'source.json'), 'w') as f: json.dump(puppet_class, f, indent=2) @@ -316,7 +326,9 @@ def setup_module(base: str, module: ModuleEntry, *, path_base: str) -> None: (puppet_class['name'], 'manifests/' + '/'.join(puppet_class['name'].split('::')[1:])), ) - f.write(template.render(content=format_class(puppet_class), + title, body = format_class(puppet_class) + f.write(template.render(title=title, + content=body, path_base=path_base, breadcrumbs=crumbs)) @@ -336,7 +348,9 @@ def setup_module(base: str, module: ModuleEntry, *, path_base: str) -> None: template = jinja.get_template('code_page.html') with open(os.path.join(dir, 'index.html'), 'w') as f: - f.write(template.render(content=format_type_alias(type_alias), + title, body = format_type_alias(type_alias) + f.write(template.render(title=title, + content=body, path_base=path_base)) # data['data_type_aliases'] diff --git a/muppet/puppet/parser.py b/muppet/puppet/parser.py index 5ab7e1b..d1f95c6 100644 --- a/muppet/puppet/parser.py +++ b/muppet/puppet/parser.py @@ -13,6 +13,7 @@ from typing import Any, TypeAlias, Union from ..cache import Cache +# TODO cache path cache = Cache('/home/hugo/.cache/puppet-doc') diff --git a/static-src/style.scss b/static-src/style.scss index 2f0fba2..a4846ba 100644 --- a/static-src/style.scss +++ b/static-src/style.scss @@ -1,3 +1,5 @@ +$border-radius: 1ex; + /* -------------------------------------------------- */ .parse-error { @@ -9,6 +11,12 @@ $header-height: 2em; +h1 { + text-align: center; + margin: 0; + border-bottom: 1px solid black; +} + h2, h3 { position: sticky; background: white; @@ -72,18 +80,38 @@ code.json { .example { background: lightgray; padding: 1em; - border-radius: 1ex; + border-radius: $border-radius; } .comment { + /* border-left: 1ex; border-left-style: dotted; - display: inline-block; padding-left: 1em; + */ + display: inline-block; font-family: sans; font-size: 80%; + p { + $line-height: 1.2em; + + line-height: $line-height; + padding-left: 20px; + /* https://stackoverflow.com/questions/52748260/add-a-prefix-character-for-each-new-line-using-css */ + background: + repeating-linear-gradient( + to bottom, + transparent 0px, + transparent 5px, + #000 5px, + #000 calc(1.2em - 2px), + transparent calc(1.2em - 2px), + transparent 1.2em) + 4px 0/2px 100% no-repeat; + } + p:first-child { margin-top: 0; } @@ -93,6 +121,42 @@ code.json { } } +.alternatives { + display: flex; + align-items: center; + justify-content: center; + padding: 0; + margin-top: 0; + + li { + padding: 0; + display: inline-block; + background-color: lightgrey; + border-left: 1px solid black; + border-right: 1px solid black; + + &:first-child { + border-radius: 0 0 0 $border-radius; + border-left: none; + } + + &:last-child { + border-radius: 0 0 $border-radius 0; + border-right: none; + } + + a { + display: block; + padding: 1em; + color: black; + } + + .selected { + background-color: grey; + } + } +} + /* -------------------------------------------------- */ @import "colorscheme_default"; diff --git a/templates/base.html b/templates/base.html index c218717..c9cbb88 100644 --- a/templates/base.html +++ b/templates/base.html @@ -35,9 +35,10 @@ Parameters: <header> {% if breadcrumbs %} <ul class="breadcrumb"> - {%- for item in breadcrumbs -%} + {%- for item in breadcrumbs.crumbs -%} <li><a href="{{ path_base }}{{ item.ref }}">{{ item.text }}</a></li> {%- endfor -%} + <li>{{ breadcrumbs.final }}</li> </ul> {% endif %} </header> diff --git a/templates/code_page.html b/templates/code_page.html index 0b588cc..989fc5a 100644 --- a/templates/code_page.html +++ b/templates/code_page.html @@ -2,12 +2,14 @@ A page containing puppet code. Parameters: + title: content: Content of page #} {% extends "base.html" %} {% block content %} - <ul> + <h1><code>{{ title }}</code></h1> + <ul class="alternatives"> <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> -- GitLab