Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Goat and Mermaid diagrams (via Goldmark) code fences #9521

Closed
bep opened this issue Feb 17, 2022 · 12 comments
Closed

Add support for Goat and Mermaid diagrams (via Goldmark) code fences #9521

bep opened this issue Feb 17, 2022 · 12 comments

Comments

@bep
Copy link
Member

bep commented Feb 17, 2022

People will most likely want to adjust the template for this, so I will add some "hooks". I will add some built-in defaults for these, but I need some help with the naming; below _default/_markup:

render-diagram-goat.html
render-diagram-mermaid.html
render-diagram-mermaid-post.html

The render-diagram-mermaid-post.html would be invoked after all the Mermaid diagrams on a page has been rendered (inclusion of JS).

/cc @jmooring @regisphilibert

See #7765

@bep
Copy link
Member Author

bep commented Feb 17, 2022

Testing this now I would say that Goat (ascii) diagrams is something I'm going to use:

image

@jmooring
Copy link
Member

jmooring commented Feb 17, 2022

What first popped into my head was #6702 and #8520. Just wondering if there's a way to handle it with one render hook controlled by "lang" (e.g., "diagram-mermaid", "diagram-plantuml") or a passed attribute.

@bep
Copy link
Member Author

bep commented Feb 17, 2022

Hmm... It's a good idea.

As I have quickly implemented the diagrams is to check if the lang is goat or mermaid, else pass it on to the Chroma highlighter.

All the diagram types would need some kind of processing, but it's probably suboptimal to do that where we do it today (as we often end up with double implementation).

So, given the Goat example:

  1. Check if there is a template for the given lang.
  2. Pass Lang, Content (and Page) to the template:
{{ $svg := diagrams.Goat .Content }}
<div>
{{ $svg.Content }}
</div>

The above is just jotted down without much thought. But if we had:

render-codeblock-goat.html
render-codeblock-mermaid.html

Which should probably also have a fall back template for people wanting to handle all code highlighting via custom template:

render-codeblock-goat.html
render-codeblock-mermaid.html
render-codeblock-default.html

@jmooring
Copy link
Member

Perhaps irrelevant, but there's also the (undocumented) nohl attribute that seems to bypass Chroma.

@bep
Copy link
Member Author

bep commented Feb 17, 2022

Probably better:

render-codeblock-goat.html
render-codeblock-mermaid.html
render-codeblock-go.html
render-codeblock.html

@jmooring
Copy link
Member

jmooring commented Feb 17, 2022

I hijacked render-heading to figure out how I would naturally write a generic render-codeblock template. Interesting exercise...

Given these two markdown examples:

```bash {.my-class #my-id lineNos="table" hl_Lines="1" lineNoStart="42"}
declare x=1
```
```diagram-mermaid {.my-class #my-id width="600" height="300" borderWidth="1px" borderColor="#333"}
something
```

We would pass .Lang, .Attributes, and .Code to:

{{- $code := .Code }}
{{- $lang := or .Lang "text" }}
{{- $options := slice }}
{{- $attrs := slice }}

{{- if strings.HasPrefix (strings.ToLower $lang) "diagram" }}
    {{- $validOptions := slice
        "borderColor"
        "borderStyle"
        "borderWidth"
        "height"
        "width"
    }}
    {{- $validOptions = apply $validOptions "strings.ToLower" "." }}
    {{- range $k, $v := .Attributes }}
        {{- if in $validOptions (strings.ToLower $k) }}
            {{- $options = $options | append (printf "%s=%v" $k $v) }}
        {{- else }}
            {{- $attrs = $attrs | append (printf "%s=%q" $k $v) }}
        {{- end }}
    {{- end }}
    <div {{ delimit $attrs " " | safeHTMLAttr }}>{{- transform.Diagram $code $lang (delimit $options ",") }}</div>
{{- else }}
    {{- $validOptions := slice
        "anchorLineNos"
        "guessSyntax"
        "hl_Lines"
        "lineAnchors"
        "lineNos"
        "lineNoStart"
        "lineNumbersInTable"
        "noClasses"
        "style"
        "tabWidth"
    }}
    {{- $validOptions = apply $validOptions "strings.ToLower" "." }}
    {{- range $k, $v := .Attributes }}
        {{- if in $validOptions (strings.ToLower $k) }}
            {{- $options = $options | append (printf "%s=%v" $k $v) }}
        {{- else }}
            {{- $attrs = $attrs | append (printf "%s=%q" $k $v) }}
        {{- end }}
    {{- end }}
    <div {{ delimit $attrs " " | safeHTMLAttr }}>{{ transform.Highlight $code $lang (delimit $options ",") }}</div>
{{- end }}
{{- /**/ -}}

Key points:

  1. The call to transform.Diagram has the same signature as the call to transform.Highlight
  2. Prefixing the diagram languages with "diagram-" made for a simple conditional

Nice to have: an .Ordinal value like we have with shortcodes. When placing multiple code blocks on a single page, we could use the ordinal when setting lineAnchors. That would allow us to guarantee unique fragments when anchorLineNos is enabled.

@marshall007
Copy link
Contributor

marshall007 commented Feb 18, 2022

@bep the proposed codeblock hook templates would be very handy in terms of preserving the authoring experience and compatibility of native markdown. Two cases in particular come to mind:

  1. documenting configuration examples while presenting in multiple formats (just like this shortcode from the Hugo docs)
  2. presenting both the source code and evaluated result (like in the docs for a styleguide or data analysis from a python script)

The latter use case would pair really nicely with your exec proposal in #796.

Would also be good to normalize language aliases such that templates defined as render-codeblock-go.html and render-codeblock-golang.html are synonymous.

@bep
Copy link
Member Author

bep commented Feb 18, 2022

Would also be good to normalize language aliases such that templates defined

How would we mantain such a mapping? Have you seen the list of Chroma lexers?

We're going to do the above, but the prime use case will still be the diagram langs, I'm not going some extra thousand miles to maintain a database of all code formats of the world and their aliases...

@marshall007
Copy link
Contributor

How would we mantain such a mapping? Have you seen the list of Chroma lexers?

@bep right, the mappings are maintained by Chroma. I was thinking you could consistently map template filenames with the langs defined in the authored codeblock using this method:

https://github.com/alecthomas/chroma/blob/4bc19573451ad676d11efa7a8d5bf5a8d176a5b5/lexers/lexers.go#L33-L35

Otherwise you'd have to rely on content authors being consistent with the aliases they use.

@bep bep changed the title Add support for Goat and Mermaid diagrams (via Goldmark) code fences) Add support for Goat and Mermaid diagrams (via Goldmark) code fences Feb 19, 2022
@bep
Copy link
Member Author

bep commented Feb 19, 2022

@marshall007 thanks, I did not know about that API, will use it.

@bep
Copy link
Member Author

bep commented Feb 26, 2022

This is now merged.

@bep bep closed this as completed Feb 26, 2022
@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 20, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants