From a1841d21e2cda9adaac68854afc3fe7cbcad7445 Mon Sep 17 00:00:00 2001 From: Jan De Dobbeleer Date: Fri, 25 Aug 2023 11:36:09 +0200 Subject: [PATCH] fix(template): support all numbers for trunc resolves #4184 --- src/template/func_map.go | 1 + src/template/round.go | 12 +++++---- src/template/strings.go | 18 ++++++++++++++ src/template/strings_test.go | 47 ++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 src/template/strings.go create mode 100644 src/template/strings_test.go diff --git a/src/template/func_map.go b/src/template/func_map.go index c2437e1a..82149afb 100644 --- a/src/template/func_map.go +++ b/src/template/func_map.go @@ -18,6 +18,7 @@ func funcMap() template.FuncMap { "lt": lt, "reason": GetReasonFromStatus, "hresult": hresult, + "trunc": trunc, } for key, fun := range sprig.TxtFuncMap() { if _, ok := funcMap[key]; !ok { diff --git a/src/template/round.go b/src/template/round.go index 79a828f2..7dce2772 100644 --- a/src/template/round.go +++ b/src/template/round.go @@ -6,23 +6,25 @@ import ( "strings" ) -func parseSeconds(seconds interface{}) (int, error) { - switch seconds := seconds.(type) { +func toInt(integer any) (int, error) { + switch seconds := integer.(type) { default: - return 0, errors.New("invalid seconds type") + return 0, errors.New("invalid integer type") case string: return strconv.Atoi(seconds) case int: return seconds, nil case int64: return int(seconds), nil + case uint64: + return int(seconds), nil case float64: return int(seconds), nil } } -func secondsRound(seconds interface{}) string { - s, err := parseSeconds(seconds) +func secondsRound(seconds any) string { + s, err := toInt(seconds) if err != nil { return err.Error() } diff --git a/src/template/strings.go b/src/template/strings.go new file mode 100644 index 00000000..2526986a --- /dev/null +++ b/src/template/strings.go @@ -0,0 +1,18 @@ +package template + +func trunc(length any, s string) string { + c, err := toInt(length) + if err != nil { + panic(err) + } + + if c < 0 && len(s)+c > 0 { + return s[len(s)+c:] + } + + if c >= 0 && len(s) > c { + return s[:c] + } + + return s +} diff --git a/src/template/strings_test.go b/src/template/strings_test.go new file mode 100644 index 00000000..b5cfadce --- /dev/null +++ b/src/template/strings_test.go @@ -0,0 +1,47 @@ +package template + +import ( + "testing" + + "github.com/jandedobbeleer/oh-my-posh/src/mock" + "github.com/jandedobbeleer/oh-my-posh/src/platform" + + "github.com/stretchr/testify/assert" + mock2 "github.com/stretchr/testify/mock" +) + +func TestTrunc(t *testing.T) { + cases := []struct { + Case string + Expected string + Template string + ShouldError bool + }{ + {Case: "5 length integer", Expected: "Hello", Template: `{{ trunc 5 "Hello World" }}`}, + {Case: "5 length stringteger", Expected: "Hello", Template: `{{ trunc "5" "Hello World" }}`}, + {Case: "5 length float", Expected: "Hello", Template: `{{ trunc 5.0 "Hello World" }}`}, + {Case: "invalid", ShouldError: true, Template: `{{ trunc "foo" "Hello World" }}`}, + {Case: "smaller than length", Expected: "Hello World", Template: `{{ trunc 20 "Hello World" }}`}, + {Case: "negative", Expected: "ld", Template: `{{ trunc -2 "Hello World" }}`}, + } + + env := &mock.MockedEnvironment{} + env.On("TemplateCache").Return(&platform.TemplateCache{ + Env: make(map[string]string), + }) + env.On("Error", mock2.Anything) + env.On("Debug", mock2.Anything) + for _, tc := range cases { + tmpl := &Text{ + Template: tc.Template, + Context: nil, + Env: env, + } + text, err := tmpl.Render() + if tc.ShouldError { + assert.Error(t, err) + continue + } + assert.Equal(t, tc.Expected, text, tc.Case) + } +}