tdemin / gmnhg

Hugo-to-Gemini Markdown converter
GNU General Public License v3.0
29 stars 1 forks source link

Shortcode templates #4

Open mntn-xyz opened 3 years ago

mntn-xyz commented 3 years ago

Just wanted to put this out there for consideration... it would be helpful to have some kind of shortcode processing in gmnhg. Given the variety of shortcodes available, as well as the ability for people to define custom shortcodes, it would make sense to build this around the idea of user-defined templates.

Here's one approach:

tdemin commented 3 years ago

Allowing for custom templating code sure is nice, I never really thought about it. Can you please provide an usage example usage of this (not an existing one, just a short template pseudocode with how it would supposedly be processed)? I know Hugo already does shortcodes, but I've never really seen them in use to this day, and I'm having problems grasping the idea seeing no examples.

mntn-xyz commented 3 years ago

The simplest example, taken from Hugo's documentation, is the built-in "highlight" shortcode.

{{< highlight html >}}
<section id="main">
  <div>
   <h1 id="title">{{ .Title }}</h1>
    {{ range .Pages }}
        {{ .Render "summary"}}
    {{ end }}
  </div>
</section>
{{< /highlight >}}

For translation to Gemtext, the template function would just receive the inner text and format it as a code block:

```
<section id="main">
  <div>
   <h1 id="title">{{ .Title }}</h1>
    {{ range .Pages }}
        {{ .Render "summary"}}
    {{ end }}
  </div>
</section>
```

For an example that uses parameters, there's the built-in "figure" shortcode. This can have a number of parameters, including captions, alt text, image attribution text, and image attribution links.

{{< figure src="https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Sc_%28spreadsheet_calculator%29.png/300px-Sc_%28spreadsheet_calculator%29.png" width="300" height="153" link="https://en.wikipedia.org/wiki/File:Sc_(spreadsheet_calculator).png" title="sc" caption="spreadsheet calculator" alt="Sc (spreadsheet calculator).png" >}}

Here's a hypothetical output for this example:

=> https://upload.wikimedia.org/wikipedia/commons/thumb/7/70/Sc_%28spreadsheet_calculator%29.png/300px-Sc_%28spreadsheet_calculator%29.png sc
=> https://en.wikipedia.org/wiki/File:Sc_(spreadsheet_calculator).png Sc (spreadsheet calculator).png
spreadsheet calculator

In order to render this, the parser would need to parse any shortcode arguments and pass them to the rendering function in figure.go. Some may be ignored by the function (width/height). These are the parameters from that particular figure template:

This is an implementation detail, but in case it helps, I imagine a signature like this:

type param struct {
    name string
    value string
}

func render(innerText *string, params ...param) string {}
mntn-xyz commented 3 years ago

I'll add that the formatting function could get relatively complex and the output probably depends on the user's preference. For instance, in the figure example I gave, maybe the user would prefer to have the function output just the link and not the thumbnail if both are present. Maybe they would want the caption to have a "Caption: " prefix. With user-defined functions they can format this however they like, as long as they return a string.

mntn-xyz commented 3 years ago

I started looking into this more, thinking that there may be a way to use Hugo itself for preprocessing to fill out any shortcodes and inline {{ }} code blocks. At first I was looking into using the rendering internals directly, but it is enormously complicated and would be fragile.

This led me to look at Hugo output formats, and I wonder if you couldn't just have Hugo render markdown files using "text/plain" to fill out the shortcodes? Then you would just postprocess the generated files to translate them to Gemtext. https://gohugo.io/templates/output-formats/

I think this could be done in a way where users could provide Gemtext "override" templates that take precedence over any theme or built-in templates. I'll investigate this more when I have some time.

mntn-xyz commented 3 years ago

Investigated a little bit. I think this will be needed first (PR seems to be in progress): https://github.com/gohugoio/hugo/issues/7297

Adding this to config.toml got me most of the way there:

[mediaTypes]
[mediaTypes."text/gemini"]
suffixes = ["gmi"]

[outputFormats]
[outputFormats.gemini]
isPlainText = false
isHTML = false
mediaType = "text/gemini"
protocol = "gemini://"

[outputs]
page = ["gemini"]

I also needed to create layouts/_default/single.gmi:

{{ .RawContent }}

Current issues:

mntn-xyz commented 3 years ago

I found a straightforward way to build a template that includes both the front matter and the raw text output:

{{ .Params | jsonify }}
{{ .RawContent }}

So if that proposed ".RenderShortcodes" function were implemented in Hugo, you could use the following template:

{{ .Params | jsonify }}
{{ .RawContent | .RenderShortcodes }}

With the definition of a custom media type and output format, this template can then be used to pre-render all markdown files for processing with gmnhg, filling out {{ }} code blocks and shortcodes. In fact this can be done 100% on the user side with some clever scripting, no need for gmnhg changes... but if this change does eventually make it into Hugo, it would be useful to have this process automated!