import (
"context"
+ "fmt"
"io"
"reflect"
panic("not reached")
}
+// TryValue is what gets returned when using the "try" keyword.
+type TryValue struct {
+ // Value is the value returned by the function or method wrapped with "try".
+ // This will always be nil if Err is set.
+ Value any
+ // Err is the error returned by the function or method wrapped with "try".
+ // This will always be nil if Value is set.
+ Err error
+}
+
// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
// as the function itself.
-func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value, first ...reflect.Value) reflect.Value {
+func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node, name string, args []parse.Node, final reflect.Value, first ...reflect.Value) (val reflect.Value) {
+ // Added for Hugo.
+ if name == "try" {
+ defer func() {
+ if r := recover(); r != nil {
+ if err, ok := r.(error); ok {
+ val = reflect.ValueOf(TryValue{nil, err})
+ } else {
+ val = reflect.ValueOf(TryValue{nil, fmt.Errorf("%v", r)})
+ }
+ }
+ }()
+ }
if args != nil {
args = args[1:] // Zeroth arg is function name/node; not passed to function.
}
s.helper.OnCalled(s.ctx, s.prep, name, argv, vv)
}
+ // Added for Hugo.
+ if name == "try" {
+ return reflect.ValueOf(TryValue{vv.Interface(), nil})
+ }
+
return vv
}
},
)
- // TODO(bep) we need the return to be a valid identifier, but
+ // TODO(bep) we need the return to be a valid identifiers, but
// should consider another way of adding it.
ns.AddMethodMapping(func() string { return "" },
[]string{"return"},
`)
}
+
+func TestTry(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- config.toml --
+baseURL = 'http://example.com/'
+-- layouts/index.html --
+Home.
+{{ $g := try ("hello = \"Hello Hugo\"" | transform.Unmarshal) }}
+{{ with $g.Err }}
+Err1: {{ . }}
+{{ else }}
+Value1: {{ $g.Value.hello | safeHTML }}|
+{{ end }}
+{{ $g := try ("hello != \"Hello Hugo\"" | transform.Unmarshal) }}
+{{ with $g.Err }}
+Err2: {{ . | safeHTML }}
+{{ else }}
+Value2: {{ $g.Value.hello | safeHTML }}|
+{{ end }}
+Try upper: {{ (try ("hello" | upper)).Value }}
+Try printf: {{ (try (printf "hello %s" "world")).Value }}
+`
+
+ b := hugolib.Test(t, files)
+
+ b.AssertFileContent("public/index.html",
+ "Value1: Hello Hugo|",
+ "Err2: template: index.html:",
+ "Try upper: HELLO",
+ "Try printf: hello world",
+ )
+}