Repository: go
Issue: proposal: text/template: add ability to send executed content to a pipeline
Labels: Proposal

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](https://gohugo.io/content-management/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](https://github.com/golang/go/compare/master...bvisness:go:template-apply) of this feature.

## Prior proposals

- https://github.com/golang/go/issues/33273
    This issue proposed modifications to the behavior of `block` and `template` which were deemed unacceptable. A workaround was suggested where the user can supply an `eval` function to execute a named template and get its result as a value. Unfortunately this workaround is still too cumbersome for the workflows described in this proposal.
- https://github.com/golang/go/issues/44144
    This issue was, in my opinion, erroneously closed as a duplicate of the previous issue. However, it did not redefine any existing syntax, so it was not really proposing the same thing. I hope that my proposal is a more complete and thoughtful version of this idea.

## 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!
    ```