gohugoio / hugo

The world’s fastest framework for building websites.
https://gohugo.io
Apache License 2.0
74.62k stars 7.45k forks source link

Support for custom functions #10633

Open Yharimium opened 1 year ago

Yharimium commented 1 year ago

Sometimes we need custom functions to write hugo templates easier.

Here is my ideal example.

{{ func "subs" "s" "map" }}
    {{ $s := .s }}
    {{ range $key, $index := .map }}
        {{ $s = $s | replaceRE $key $index }}
    {{ end }}
    {{ return $s }}
{{ end }}

"subs" is the name of the function while "s" and "map" are input variables. So that i can use that function in my templates like this:

......
<span>{{ sub $s $map }}</span>
......

With this method, I can avoid using dict or .Scratch to pass variables to partials.

Personally, partial is more suitable for html templates than functions. Using partial to write functions is tedious. Customized functions will be more convenient to operate data logically or to write recursive programs.

Another example:

Using custom function:

{{ func "fib" "x" }}
    {{ if or (eq .x 1) (eq .x 2) }}
        {{ return 1 }}
    {{ end }}
    {{ return add (fib (sub .x 1)) (fib (sub .x 2))  }}
{{ end }}

{{ fib 4 }} <!-- return 3 -->

Using partial:

{{ define "partials/fib" }}
{{ $ans := 1 }}
{{ if and (ne .x 1) (ne .x 2) }}
    {{ $y := partial "fib" (dict "x" (sub .x 1)) }}
    {{ $z := partial "fib" (dict "x" (sub .x 2)) }}
    {{ $ans = add $y $z }}
{{ end }}
{{ return $ans }}
{{ end }}

{{ partial "fib" (dict "x" 4) }} <!-- return 3 -->

Sincerely hope you can read my issue. I would appreciate it if you could consider adding custom functions to Hugo.

bep commented 1 year ago

Personally, partial is more suitable for html templates than functions. Using partial to write functions is tedious.

It may not be ideal, but tedious? From your example above, there isn't much difference between the func and the partial example. I think that adding something new in this area should give us a little more than just cosmetics.

Note that I have thought about adding a proper scripting language "somehow" (e.g. https://github.com/bep/gojap), but that is a larger canvas to draw.

jmooring commented 1 year ago

There's also https://github.com/gohugoio/hugo/issues/10544 to simply the calling syntax, but I would put this in the "low priority" category.

xbc5 commented 1 year ago

Note that I have thought about adding a proper scripting language "somehow" (e.g. https://github.com/bep/gojap), but that is a larger canvas to draw.

@bep would en embedded JS engine drastically slow down compilation if the site is custom function heavy? Are there faster solutions other than JS?

xbc5 commented 1 year ago

Instead of a scripting engine, would it be possible to shell out to a go binary? These binaries could act like plugins, which accept and emit a standard interface. You could PATH these to a dedicated directory within the project:

{{ with plugin "my-plugin" (dict "data" $data "myKey" $myCustomData)  }}
  ...
{{ end }}

It would be a much smaller job to implement, and probably faster too.

ahelwer commented 1 year ago

I would be very interested in this feature to write my own renderer for code fences with certain language tags. Specifically I would like to integrate syntax highlighting with tree-sitter for a few languages.