diff --git a/muppet/breadcrumbs.py b/muppet/breadcrumbs.py index ae88d3c172eb9eb13d2d0920813c462075296017..70e6d4bc06c68aa34121a67608be1a347a41df71 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 8c52eb44e562c10e9670770b8cf47aeb685c5d28..bf107adc490aca9352d43913a97908de0b1543ee 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 1d3fc48e482606514838a7b6a60852ffae7c0c01..4795553d44524f42c6a145fc907aa7ee39dcd8b8 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 df54feebc89f4a18c504dd2ee13f76b457681704..dd7e1eab8f3a6d4aa5429c479e9e782e8f2a1a81 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 7e2266b7924e96112e0eb1a22a43d97de50bcd8d..727fe37d651b6f937616fbfa696b461a10c891c7 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 5ab7e1b509230559834186d9b51a0b1ac85ba9f4..d1f95c60c3cfb9a0b99978f3570f3b4fba806acc 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 2f0fba28433875709336fde1bcc1850ff05bab12..a4846ba8d38111c5bdbb24905283b82591b3532c 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 c2187179699af3ae1e2739dffd15b16161dc7f98..c9cbb888670e64515756a64f51551d7d41c5db5a 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 0b588ccc0fde2da1c235d517cdbc5c26502ae3a9..989fc5a7b2cd95d549ff1c6e092974ac8f4e21a4 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>