]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Add try
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 19 Apr 2022 14:56:49 +0000 (16:56 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sun, 5 Jan 2025 14:32:21 +0000 (15:32 +0100)
Updates #9737

tpl/internal/go_templates/texttemplate/hugo_template.go
tpl/partials/init.go
tpl/safe/init.go
tpl/templates/templates_integration_test.go

index 12dbe041217f2e4bf6dcfd8849ee26fd69a4c87f..0dbee02f73384c44c69f18324bc7d9aced38b71e 100644 (file)
@@ -15,6 +15,7 @@ package template
 
 import (
        "context"
+       "fmt"
        "io"
        "reflect"
 
@@ -255,10 +256,32 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
        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.
        }
@@ -371,6 +394,11 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
                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
 }
 
index e9d901bbf63432d74c838fcae3a0bf58c900fdff..6f7c0ffc1e78f53e568e1320bb6df4fa7271d447 100644 (file)
@@ -38,7 +38,7 @@ func init() {
                        },
                )
 
-               // 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"},
index 3b498e6dfb00283fb2baef945b52b6dee71f0a3d..ea1469e8047adb9971ade9f1e65b1743fa77f504 100644 (file)
@@ -70,6 +70,13 @@ func init() {
                        },
                )
 
+               ns.AddMethodMapping(func(v any) (any, error) {
+                       return v, nil
+               },
+                       []string{"try"},
+                       [][2]string{},
+               )
+
                return ns
        }
 
index 301f783a573f2557f900b4e49e18c6dcb0ba84d3..aa5540862fe856349b30745819a26648d7e2dd0e 100644 (file)
@@ -93,3 +93,37 @@ Home: true
 
 `)
 }
+
+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",
+       )
+}