Skip to content

proposal: text/template: add ability to send executed content to a pipeline #54748

Open
@bvisness

Description

@bvisness

I propose adding an apply function to text/template which would execute a template and send its output to a pipeline:

{{ apply markdown | highlight "html" }}
    Hello, **Gopher**!
{{ end }}
<pre class="code">
    Hello, <span class="tag">&lt;strong&gt;</span>Gopher<span class="tag">&lt;/strong&gt;</span>!
</pre>

The motivation for this feature is essentially the same as the motivation for Hugo's shortcodes. When authoring content in Go templates, it is often desirable to run templated content through a template function for post-processing - for example, for syntax highlighting, processing markdown, creating "accordion" sections, etc.

Different flavors of this behavior have been proposed before (see below), and have been rejected with workarounds. Unfortunately, the best workaround available today is to add an eval "template name" . function and then use named templates, which is too cumbersome in practice:

{{ template "base.html" . }}

{{ define "content 1" }}
    Hello, **{{ .Name }}**!

    Watch this _sweet_ video to get started:
{{ end }}
{{ define "content 2" }}
    Don't forget to [like and subscribe](https://video.com/gopher)!
{{ end }}

{{ define "some block from base.html" }}
    {{ eval "content 1" . | markdown }}
    <iframe src="https://video.com/gopher/123456/embed"></iframe>
    {{ eval "content 2" . | markdown }}
{{ end }}

I propose for apply to simply be sugar for this workaround, albeit without defining a named template. With the proposed feature, this example would look like:

{{ template "base.html" . }}

{{ define "some block from base.html" }}
    {{ apply markdown }}
        Hello, **{{ .Name }}**!

        Watch this _sweet_ video to get started:
    {{ end }}
    <iframe src="https://video.com/gopher/123456/embed"></iframe>
    {{ apply markdown }}
        Don't forget to [like and subscribe](https://video.com/gopher)!
    {{ end }}
{{ end }}

I have created a prototype implementation of this feature.

Prior proposals

Open questions

Is this API sufficient? It may be wise to additionally expose APIs like the following, but I will leave that for further discussion.

  • eval "template name" .: evaluates a template by name and returns the output as a string. This behavior is implicitly present in apply, and is part of the commonly-suggested workaround, so it may be worth exposing explicitly. Example:

    {{ define "greet" }}Hello, {{ . }}!{{ end }}
    {{ $greeting := eval "greet" .Name }}
    {{ urlquery $greeting }}
    
    // Output (when executed with Name = "Gopher"):
    Hello%2C+Gopher!
    

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions