New Upstream Release - easygen

Ready changes

Summary

Merged new upstream version: 5.2.1 (was: 5.1.9).

Resulting package

Built on 2022-12-14T13:58 (took 4m4s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases easygenapt install -t fresh-releases golang-github-go-easygen-easygen-dev

Lintian Result

Diff

diff --git a/.all-contributorsrc b/.all-contributorsrc
index abc924f..d151d6b 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -2,7 +2,7 @@
   "files": [
     "README.md",
     "README.beg.e.md",
-    "README.end.e.md"
+    "README.end2.e.md"
   ],
   "imageSize": 100,
   "commit": false,
diff --git a/.gitignore b/.gitignore
index 76b5f2c..f9f78f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,4 @@ _testmain.go
 *.prof
 
 *~
+.idea/
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 0320726..3444ff0 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -19,6 +19,9 @@ builds:
     goarch:
       - amd64
       - arm64
+    ignore:
+      - goos: windows
+        goarch: arm64
 
     # Path to main.go file or main package.
     # Notice: when used with `gomod.proxy`, this must be a package.
diff --git a/README.end.e.md b/README.end.e.md
index 425a493..1f34563 100644
--- a/README.end.e.md
+++ b/README.end.e.md
@@ -29,7 +29,7 @@ rmdir -v {{.Name}}_*_linux_amd64
 
 ### Distro package
 
-- Packages available for Linux distros are
+- [Packages available for Linux distros](https://cloudsmith.io/~suntong/repos/repo/packages/) are
   * [Alpine Linux](https://cloudsmith.io/~suntong/repos/repo/setup/#formats-alpine)
   * [Debian](https://cloudsmith.io/~suntong/repos/repo/setup/#formats-deb)
   * [RedHat](https://cloudsmith.io/~suntong/repos/repo/setup/#formats-rpm)
@@ -69,29 +69,3 @@ Tong SUN
 _Powered by_ [**WireFrame**](https://github.com/go-easygen/wireframe)  
 [![PoweredBy WireFrame](https://github.com/go-easygen/wireframe/blob/master/PoweredBy-WireFrame-Y.svg)](http://godoc.org/github.com/go-easygen/wireframe)  
 the _one-stop wire-framing solution_ for Go cli based projects, from _init_ to _deploy_.
-
-## Contributors ✨
-
-Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
-
-<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
-<!-- prettier-ignore-start -->
-<!-- markdownlint-disable -->
-<table>
-  <tr>
-    <td align="center"><a href="https://github.com/suntong"><img src="https://avatars.githubusercontent.com/u/422244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>suntong</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/commits?author=suntong" title="Code">πŸ’»</a> <a href="#ideas-suntong" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="#design-suntong" title="Design">🎨</a> <a href="#data-suntong" title="Data">πŸ”£</a> <a href="https://github.com/go-easygen/easygen/commits?author=suntong" title="Tests">⚠️</a> <a href="https://github.com/go-easygen/easygen/issues?q=author%3Asuntong" title="Bug reports">πŸ›</a> <a href="https://github.com/go-easygen/easygen/commits?author=suntong" title="Documentation">πŸ“–</a> <a href="#blog-suntong" title="Blogposts">πŸ“</a> <a href="#example-suntong" title="Examples">πŸ’‘</a> <a href="#tutorial-suntong" title="Tutorials">βœ…</a> <a href="#tool-suntong" title="Tools">πŸ”§</a> <a href="#platform-suntong" title="Packaging/porting to new platform">πŸ“¦</a> <a href="https://github.com/go-easygen/easygen/pulls?q=is%3Apr+reviewed-by%3Asuntong" title="Reviewed Pull Requests">πŸ‘€</a> <a href="#question-suntong" title="Answering Questions">πŸ’¬</a> <a href="#maintenance-suntong" title="Maintenance">🚧</a> <a href="#infra-suntong" title="Infrastructure (Hosting, Build-Tools, etc)">πŸš‡</a></td>
-    <td align="center"><a href="http://gerrit.sdf.org/"><img src="https://avatars.githubusercontent.com/u/5132989?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gerrit Renker</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/commits?author=grrtrr" title="Code">πŸ’»</a> <a href="#ideas-grrtrr" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/go-easygen/easygen/issues?q=author%3Agrrtrr" title="Bug reports">πŸ›</a> <a href="#userTesting-grrtrr" title="User Testing">πŸ““</a> <a href="#talk-grrtrr" title="Talks">πŸ“’</a> <a href="#content-grrtrr" title="Content">πŸ–‹</a> <a href="#blog-grrtrr" title="Blogposts">πŸ“</a></td>
-    <td align="center"><a href="https://github.com/bruston"><img src="https://avatars.githubusercontent.com/u/3519911?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benjamin Ruston</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/commits?author=bruston" title="Code">πŸ’»</a> <a href="https://github.com/go-easygen/easygen/issues?q=author%3Abruston" title="Bug reports">πŸ›</a> <a href="#userTesting-bruston" title="User Testing">πŸ““</a></td>
-    <td align="center"><a href="https://github.com/sanjaymsh"><img src="https://avatars.githubusercontent.com/u/66668807?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sanjaymsh</b></sub></a><br /><a href="#platform-sanjaymsh" title="Packaging/porting to new platform">πŸ“¦</a></td>
-    <td align="center"><a href="https://wiki.debian.org/AnthonyFok"><img src="https://avatars.githubusercontent.com/u/1274764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anthony Fok</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/issues?q=author%3Aanthonyfok" title="Bug reports">πŸ›</a> <a href="https://github.com/go-easygen/easygen/pulls?q=is%3Apr+reviewed-by%3Aanthonyfok" title="Reviewed Pull Requests">πŸ‘€</a> <a href="#maintenance-anthonyfok" title="Maintenance">🚧</a> <a href="#userTesting-anthonyfok" title="User Testing">πŸ““</a></td>
-    <td align="center"><a href="https://github.com/ghost"><img src="https://avatars.githubusercontent.com/u/10137?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Deleted user</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/issues?q=author%3Aghost" title="Bug reports">πŸ›</a> <a href="#ideas-ghost" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="#userTesting-ghost" title="User Testing">πŸ““</a></td>
-    <td align="center"><a href="https://github.com/romz-pl"><img src="https://avatars.githubusercontent.com/u/32552206?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zbigniew Romanowski</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/issues?q=author%3Aromz-pl" title="Bug reports">πŸ›</a> <a href="#ideas-romz-pl" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="#userTesting-romz-pl" title="User Testing">πŸ““</a></td>
-  </tr>
-</table>
-
-<!-- markdownlint-restore -->
-<!-- prettier-ignore-end -->
-
-<!-- ALL-CONTRIBUTORS-LIST:END -->
-
-This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
diff --git a/README.end2.e.md b/README.end2.e.md
new file mode 100644
index 0000000..62e2c1b
--- /dev/null
+++ b/README.end2.e.md
@@ -0,0 +1,26 @@
+
+## Contributors ✨
+
+Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
+
+<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
+<!-- prettier-ignore-start -->
+<!-- markdownlint-disable -->
+<table>
+  <tr>
+    <td align="center"><a href="https://github.com/suntong"><img src="https://avatars.githubusercontent.com/u/422244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>suntong</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/commits?author=suntong" title="Code">πŸ’»</a> <a href="#ideas-suntong" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="#design-suntong" title="Design">🎨</a> <a href="#data-suntong" title="Data">πŸ”£</a> <a href="https://github.com/go-easygen/easygen/commits?author=suntong" title="Tests">⚠️</a> <a href="https://github.com/go-easygen/easygen/issues?q=author%3Asuntong" title="Bug reports">πŸ›</a> <a href="https://github.com/go-easygen/easygen/commits?author=suntong" title="Documentation">πŸ“–</a> <a href="#blog-suntong" title="Blogposts">πŸ“</a> <a href="#example-suntong" title="Examples">πŸ’‘</a> <a href="#tutorial-suntong" title="Tutorials">βœ…</a> <a href="#tool-suntong" title="Tools">πŸ”§</a> <a href="#platform-suntong" title="Packaging/porting to new platform">πŸ“¦</a> <a href="https://github.com/go-easygen/easygen/pulls?q=is%3Apr+reviewed-by%3Asuntong" title="Reviewed Pull Requests">πŸ‘€</a> <a href="#question-suntong" title="Answering Questions">πŸ’¬</a> <a href="#maintenance-suntong" title="Maintenance">🚧</a> <a href="#infra-suntong" title="Infrastructure (Hosting, Build-Tools, etc)">πŸš‡</a></td>
+    <td align="center"><a href="http://gerrit.sdf.org/"><img src="https://avatars.githubusercontent.com/u/5132989?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gerrit Renker</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/commits?author=grrtrr" title="Code">πŸ’»</a> <a href="#ideas-grrtrr" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="https://github.com/go-easygen/easygen/issues?q=author%3Agrrtrr" title="Bug reports">πŸ›</a> <a href="#userTesting-grrtrr" title="User Testing">πŸ““</a> <a href="#talk-grrtrr" title="Talks">πŸ“’</a> <a href="#content-grrtrr" title="Content">πŸ–‹</a> <a href="#blog-grrtrr" title="Blogposts">πŸ“</a></td>
+    <td align="center"><a href="https://github.com/bruston"><img src="https://avatars.githubusercontent.com/u/3519911?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benjamin Ruston</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/commits?author=bruston" title="Code">πŸ’»</a> <a href="https://github.com/go-easygen/easygen/issues?q=author%3Abruston" title="Bug reports">πŸ›</a> <a href="#userTesting-bruston" title="User Testing">πŸ““</a></td>
+    <td align="center"><a href="https://github.com/sanjaymsh"><img src="https://avatars.githubusercontent.com/u/66668807?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sanjaymsh</b></sub></a><br /><a href="#platform-sanjaymsh" title="Packaging/porting to new platform">πŸ“¦</a></td>
+    <td align="center"><a href="https://wiki.debian.org/AnthonyFok"><img src="https://avatars.githubusercontent.com/u/1274764?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Anthony Fok</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/issues?q=author%3Aanthonyfok" title="Bug reports">πŸ›</a> <a href="https://github.com/go-easygen/easygen/pulls?q=is%3Apr+reviewed-by%3Aanthonyfok" title="Reviewed Pull Requests">πŸ‘€</a> <a href="#maintenance-anthonyfok" title="Maintenance">🚧</a> <a href="#userTesting-anthonyfok" title="User Testing">πŸ““</a></td>
+    <td align="center"><a href="https://github.com/ghost"><img src="https://avatars.githubusercontent.com/u/10137?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Deleted user</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/issues?q=author%3Aghost" title="Bug reports">πŸ›</a> <a href="#ideas-ghost" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="#userTesting-ghost" title="User Testing">πŸ““</a></td>
+    <td align="center"><a href="https://github.com/romz-pl"><img src="https://avatars.githubusercontent.com/u/32552206?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zbigniew Romanowski</b></sub></a><br /><a href="https://github.com/go-easygen/easygen/issues?q=author%3Aromz-pl" title="Bug reports">πŸ›</a> <a href="#ideas-romz-pl" title="Ideas, Planning, & Feedback">πŸ€”</a> <a href="#userTesting-romz-pl" title="User Testing">πŸ““</a></td>
+  </tr>
+</table>
+
+<!-- markdownlint-restore -->
+<!-- prettier-ignore-end -->
+
+<!-- ALL-CONTRIBUTORS-LIST:END -->
+
+This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
diff --git a/README.md b/README.md
index 031c21a..d0642a1 100644
--- a/README.md
+++ b/README.md
@@ -136,7 +136,7 @@ rmdir -v easygen_*_linux_amd64
 
 ### Distro package
 
-- Packages available for Linux distros are
+- [Packages available for Linux distros](https://cloudsmith.io/~suntong/repos/repo/packages/) are
   * [Alpine Linux](https://cloudsmith.io/~suntong/repos/repo/setup/#formats-alpine)
   * [Debian](https://cloudsmith.io/~suntong/repos/repo/setup/#formats-deb)
   * [RedHat](https://cloudsmith.io/~suntong/repos/repo/setup/#formats-rpm)
diff --git a/cmd/easygen/main.go b/cmd/easygen/main.go
index 265c876..70a001a 100644
--- a/cmd/easygen/main.go
+++ b/cmd/easygen/main.go
@@ -41,8 +41,8 @@ import (
 
 var (
 	progname = "easygen"
-	version  = "5.1.9"
-	date     = "2021-12-31"
+	version  = "5.2.1"
+	date     = "2022-07-10"
 )
 
 ////////////////////////////////////////////////////////////////////////////
diff --git a/cmd/easygen/main_test.go b/cmd/easygen/main_test.go
index dff19c5..15306b8 100644
--- a/cmd/easygen/main_test.go
+++ b/cmd/easygen/main_test.go
@@ -72,6 +72,7 @@ func TestExec(t *testing.T) {
 	testEasygen(t, "list1", "list1")
 	testEasygen(t, "listfunc1", "listfunc1")
 	testEasygen(t, "listfunc2", "listfunc2")
+	testEasygen(t, "tf-calc", "tf-calc")
 
 	//Test Basic Json Functions
 	testEasygen(t, "list0j", "list0j")
diff --git a/debian/changelog b/debian/changelog
index 3e00428..c03be88 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+easygen (5.2.1-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 14 Dec 2022 13:55:10 -0000
+
 easygen (5.1.9-2) unstable; urgency=medium
 
   * Team Upload.
diff --git a/t_strings_test.go b/t_strings_test.go
index dabaf6a..57f872c 100644
--- a/t_strings_test.go
+++ b/t_strings_test.go
@@ -183,6 +183,22 @@ func TestStringManipulation(t *testing.T) {
 		// 	"a PEACH",
 		// },
 		// == my added strings functions
+		{
+			`{{ indent 2 "a" }}`,
+			"a",
+		},
+		{
+			`{{ indent 2 "a\nb\nc" }}`,
+			"a\n  b\n  c",
+		},
+		{
+			`{{ pindent 2 "a" }}`,
+			"  a",
+		},
+		{
+			`{{ pindent 2 "a\nb\nc" }}`,
+			"  a\n  b\n  c",
+		},
 		{
 			`{{ coalesce "a" }}`,
 			"a",
@@ -211,6 +227,11 @@ func TestStringManipulation(t *testing.T) {
 			`{{ coalesce .StrEmpty "Something else" }}`,
 			"Something else",
 		},
+		// The following failed the template.Execute before but now fixed
+		{
+			`{{ coalesce .StrNone "Not exist" }}`,
+			"Not exist",
+		},
 	}
 
 	testStringManipulation(t, testData)
diff --git a/template.go b/template.go
index da9fc3c..b56afd6 100644
--- a/template.go
+++ b/template.go
@@ -156,8 +156,8 @@ var egFuncMap = FuncMap{
 	"stringsTrimSpace":      strings.TrimSpace,
 	"stringsTrimSuffix":     strings.TrimSuffix,
 	// aliases
-	"eqf":   strings.EqualFold,
-	"split": strings.Fields,
+	"eqf":     strings.EqualFold,
+	"split":   strings.Fields,
 	"sprintf": fmt.Sprintf,
 
 	// == standard regexp function definitions
@@ -178,12 +178,16 @@ var egFuncMap = FuncMap{
 	// == my added functions
 	"ENV":         os.Getenv,
 	"substr":      Substr,
+	"indent":      Indent,
+	"pindent":     PIndent,
 	"coalesce":    Coalesce,
 	"quote4shell": Quote4shell,
 
 	"iterate":   Iterate,
 	"argsa":     ArgsA,
 	"argsm":     ArgsM,
+	"add":       Add,
+	"minus":     Minus,
 	"minus1":    Minus1,
 	"date":      Date,
 	"timestamp": Timestamp,
diff --git a/test/commandlineEnv.ref b/test/commandlineEnv.ref
new file mode 100644
index 0000000..4214664
--- /dev/null
+++ b/test/commandlineEnv.ref
@@ -0,0 +1,36 @@
+package main
+
+// import "github.com/caarlos0/env"
+
+//////////////////////////////////////////////////////////////////////////
+// Constant and data type/structure definitions
+
+
+/*
+
+Custom environment settings:
+
+- **EVD_HOST**: Host address (string="localhost")
+- **EVD_PORT**: Listening port (int="80")
+- **EVD_FRCE**: Force start (bool)
+- **EVD_VERB**: Verbose mode (higher numbers increase the verbosity) (int)
+
+*/
+
+type envConfig struct {
+	Host	string	`env:"EVD_HOST" envDefault:"localhost"`	// Host address
+	Port	int	`env:"EVD_PORT" envDefault:"80"`	// Listening port
+	Force	bool	`env:"EVD_FRCE"`	// Force start
+	Verbose	int	`env:"EVD_VERB"`	// Verbose mode (higher numbers increase the verbosity)
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Global variables definitions
+
+//  var (
+//          progname  = "evdemo"
+//          version   = "0.1.0"
+//          date = "2022-01-30"
+
+//          e envConfig
+//  )
diff --git a/test/commandlineEnv.tmpl b/test/commandlineEnv.tmpl
new file mode 100644
index 0000000..26630d1
--- /dev/null
+++ b/test/commandlineEnv.tmpl
@@ -0,0 +1,39 @@
+package {{$.PackageName}}
+
+// import "github.com/caarlos0/env"
+
+//////////////////////////////////////////////////////////////////////////
+// Constant and data type/structure definitions
+
+
+/*{{- $prefix := .Prefix}}
+
+Custom environment settings:
+{{range .Options}}
+- **{{$prefix}}
+{{- if .EVar}}{{.EVar}}
+{{- else}}{{clk2ss .Name}}
+{{- end}}**: {{.Usage}} ({{.Type}}{{- if .Value}}="{{.Value}}"{{end}})
+{{- end}}
+
+*/
+
+type envConfig struct { {{- range .Options}}
+	{{.Name}}	{{.Type}}	`env:"{{$prefix}}
+{{- if .EVar}}{{.EVar}}
+{{- else}}{{clk2ss .Name}}
+{{- end}}"
+{{- if .Value}} envDefault:"{{.Value}}"{{end}}`	// {{.Usage}}
+{{- end}}
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Global variables definitions
+
+//  var (
+//          progname  = "{{.Name}}"
+//          version   = "0.1.0"
+//          date = "{{ date "I" }}"
+
+//          e envConfig
+//  )
diff --git a/test/commandlineEnv.yaml b/test/commandlineEnv.yaml
new file mode 100644
index 0000000..af8e38c
--- /dev/null
+++ b/test/commandlineEnv.yaml
@@ -0,0 +1,35 @@
+# program name, name for the executable
+# ProgramName: redo
+# Authors: Myself <me@mine.org>
+
+#
+PackageName: main
+
+Name: evdemo
+# Desc: "global option redo"
+# Text: Redo global option via automatic code-gen
+
+# prefix string before every environment variable
+Prefix: EVD_
+
+Options:
+  - Name: Host
+    Type: string
+    Usage: Host address
+    Value: localhost
+
+  - Name: Port
+    Type: int
+    Usage: Listening port
+    Value: 80
+
+  - Name: Force
+    Type: bool
+    EVar: FRCE
+    Usage: Force start
+
+  - Name: Verbose
+    Type: int
+    EVar: VERB
+    Usage: Verbose mode (higher numbers increase the verbosity)
+    Value: 0
diff --git a/test/commandlineGoFlags.header.tmpl b/test/commandlineGoFlags.header.tmpl
new file mode 100644
index 0000000..66cb210
--- /dev/null
+++ b/test/commandlineGoFlags.header.tmpl
@@ -0,0 +1,7 @@
+{{- define "header" -}}
+////////////////////////////////////////////////////////////////////////////
+// Program: {{.Name}}
+// Purpose: {{.Desc}}
+// Authors: {{or .Authors "Author"}} (c) {{date "Y4"}}, All rights reserved
+////////////////////////////////////////////////////////////////////////////
+{{- end}}
diff --git a/test/commandlineGoFlags.ityped.tmpl b/test/commandlineGoFlags.ityped.tmpl
new file mode 100644
index 0000000..90bbc81
--- /dev/null
+++ b/test/commandlineGoFlags.ityped.tmpl
@@ -0,0 +1,27 @@
+{{- define "type_struct" -}} 
+// The {{.typeName}} type defines all the configurable options from cli.
+{{.Prefix}}type {{.typeName}} struct { {{- range .Options}}
+{{- if eq .Name "Args" }}
+{{$.Prefix}}
+{{$.Prefix}}	{{.Args}}
+{{- else }}{{$f := stringsSplit .Flag ","}}{{ $flen := len $f }}
+{{$.Prefix}}	{{.Name}}	{{.Type}}	`
+{{- if gt $flen 1}}short:"{{index $f 0}}" long:"{{index $f 1}}"
+{{- else}}
+ {{- if le ((index $f 0) | len) 1 }}short:"{{index $f 0}}"
+ {{- else}}long:"{{index $f 0}}"{{end}}
+{{- end}}
+{{- if .EnvV}} env:"{{printf "%s_%s" (clk2ss $.ProgramName) (clk2ss .Name)}}"{{end}} description:"{{.Usage}}"
+{{- if .Value}} default:"{{.Value}}"{{end}}
+{{- if .Choices}}{{range .Choices}} choice:"{{.}}"{{end}}{{end}}
+{{- if .Required}} required:"true"{{end}}`{{end}}
+{{- end}}
+{{- if .Verbose}}
+{{$.Prefix}}	Verbflg func()  `short:"v" long:"verbose" description:"Verbose mode (Multiple -v options increase the verbosity)"`
+{{$.Prefix}}	Verbose int
+{{- end}}
+{{- if .Version}}
+{{$.Prefix}}	Version func()  `short:"V" long:"version" description:"Show program version and exit"`
+{{- end}}
+{{$.Prefix -}} }
+{{- end}}
diff --git a/test/commandlineGoFlags.ref b/test/commandlineGoFlags.ref
new file mode 100644
index 0000000..b6ec334
--- /dev/null
+++ b/test/commandlineGoFlags.ref
@@ -0,0 +1,263 @@
+
+
+// redo - global option redo
+// 
+// Redo global option via automatic code-gen
+
+package main
+
+////////////////////////////////////////////////////////////////////////////
+// Program: redo
+// Purpose: global option redo
+// Authors: Myself <me@mine.org> (c) 2022, All rights reserved
+////////////////////////////////////////////////////////////////////////////
+
+import (
+//  	"fmt"
+//  	"os"
+
+//  	"github.com/go-easygen/go-flags"
+)
+
+// Template for main starts here
+
+//////////////////////////////////////////////////////////////////////////
+// Constant and data type/structure definitions
+
+////////////////////////////////////////////////////////////////////////////
+// Global variables definitions
+
+//  var (
+//          progname  = "redo"
+//          version   = "0.1.0"
+//          date = "2022-02-07"
+
+//  	// opts store all the configurable options
+//  	opts optsT
+//  )
+//  
+//  var parser = flags.NewParser(&opts, flags.Default)
+
+////////////////////////////////////////////////////////////////////////////
+// Function definitions
+
+// Function main
+//  func main() {
+//  	opts.Version = showVersion
+//  	opts.Verbflg = func() {
+//  		opts.Verbose++
+//  	}
+//  
+//  	if _, err := parser.Parse(); err != nil {
+//  		fmt.Println()
+//  		parser.WriteHelp(os.Stdout)
+//  		os.Exit(1)
+//  	}
+//  	fmt.Println()
+//  	//DoRedo()
+//  }
+//
+//  func showVersion() {
+//   	fmt.Fprintf(os.Stderr, "redo - global option redo, version %s\n", version)
+//  	fmt.Fprintf(os.Stderr, "Built on %s\n", date)
+//   	fmt.Fprintf(os.Stderr, "Copyright (C) 2022, Myself <me@mine.org>\n\n")
+//  	fmt.Fprintf(os.Stderr, "Redo global option via automatic code-gen\n")
+//  	os.Exit(0)
+//  }
+// Template for main ends here
+
+// DoRedo implements the business logic of command `redo`
+//  func DoRedo() error {
+//  	return nil
+//  }
+
+// Template for type define starts here
+
+// The optsT type defines all the configurable options from cli.
+type optsT struct {
+	Host	string	`short:"H" long:"host" env:"REDO_HOST" description:"Host address" default:"localhost"`
+	Port	int	`short:"p" long:"port" env:"REDO_PORT" description:"Listening port" default:"80"`
+	Force	bool	`short:"f" long:"force" env:"REDO_FORCE" description:"Force start"`
+	Verbflg func()  `short:"v" long:"verbose" description:"Verbose mode (Multiple -v options increase the verbosity)"`
+	Verbose int
+	Version func()  `short:"V" long:"version" description:"Show program version and exit"`
+}
+// Template for type define ends here
+
+
+// Template for "build" CLI handling starts here
+////////////////////////////////////////////////////////////////////////////
+// Program: redo
+// Purpose: global option redo
+// Authors: Myself <me@mine.org> (c) 2022, All rights reserved
+////////////////////////////////////////////////////////////////////////////
+
+//  package main
+
+//  import (
+//  	"fmt"
+//  	"os"
+//
+//  	"github.com/go-easygen/go-flags/clis"
+//  )
+
+// *** Sub-command: build ***
+
+////////////////////////////////////////////////////////////////////////////
+// Constant and data type/structure definitions
+
+// The BuildCommand type defines all the configurable options from cli.
+//  type BuildCommand struct {
+//  	Dir	string	`long:"dir" description:"source code root dir" default:"./"`
+//  }
+
+//  
+//  var buildCommand BuildCommand
+//  
+//  func init() {
+//  	parser.AddCommand("build",
+//  		"Build the network application",
+//  		"Usage:\n  redo build [Options] Arch(i386|amd64)",
+//  		&buildCommand)
+//  }
+//
+//  func (x *BuildCommand) Execute(args []string) error {
+//   	fmt.Fprintf(os.Stderr, "Build the network application\n")
+//   	// fmt.Fprintf(os.Stderr, "Copyright (C) 2022, Myself <me@mine.org>\n\n")
+//   	clis.Setup("redo::build", opts.Verbose)
+//   	clis.Verbose(1, "Doing Build, with %+v, %+v", opts, args)
+//   	fmt.Println(x.Dir)
+//  	return x.Exec(args)
+//  }
+//  
+// Exec implements the business logic of command `build`
+// func (x *BuildCommand) Exec(args []string) error {
+// 	// err := ...
+// 	// clis.WarnOn("Build, Exec", err)
+// 	// or,
+// 	// clis.AbortOn("Build, Exec", err)
+// 	return nil
+// }
+// Template for "build" CLI handling ends here
+
+// Template for "install" CLI handling starts here
+////////////////////////////////////////////////////////////////////////////
+// Program: redo
+// Purpose: global option redo
+// Authors: Myself <me@mine.org> (c) 2022, All rights reserved
+////////////////////////////////////////////////////////////////////////////
+
+//  package main
+
+//  import (
+//  	"fmt"
+//  	"os"
+//
+//  	"github.com/go-easygen/go-flags/clis"
+//  )
+
+// *** Sub-command: install ***
+
+////////////////////////////////////////////////////////////////////////////
+// Constant and data type/structure definitions
+
+// The InstallCommand type defines all the configurable options from cli.
+//  type InstallCommand struct {
+//  	Dir	string	`short:"d" description:"source code root dir" default:"./"`
+//  	Suffix	string	`long:"suffix" description:"source file suffix" default:".go,.c,.s"`
+//  }
+
+//  
+//  var installCommand InstallCommand
+//  
+//  func init() {
+//  	parser.AddCommand("install",
+//  		"Install the network application",
+//  		"The add command adds a file to the repository. Use -a to add all files",
+//  		&installCommand)
+//  }
+//
+//  func (x *InstallCommand) Execute(args []string) error {
+//   	fmt.Fprintf(os.Stderr, "Install the network application\n")
+//   	// fmt.Fprintf(os.Stderr, "Copyright (C) 2022, Myself <me@mine.org>\n\n")
+//   	clis.Setup("redo::install", opts.Verbose)
+//   	clis.Verbose(1, "Doing Install, with %+v, %+v", opts, args)
+//   	fmt.Println(x.Dir, x.Suffix)
+//  	return x.Exec(args)
+//  }
+//  
+// Exec implements the business logic of command `install`
+// func (x *InstallCommand) Exec(args []string) error {
+// 	// err := ...
+// 	// clis.WarnOn("Install, Exec", err)
+// 	// or,
+// 	// clis.AbortOn("Install, Exec", err)
+// 	return nil
+// }
+// Template for "install" CLI handling ends here
+
+// Template for "publish" CLI handling starts here
+////////////////////////////////////////////////////////////////////////////
+// Program: redo
+// Purpose: global option redo
+// Authors: Myself <me@mine.org> (c) 2022, All rights reserved
+////////////////////////////////////////////////////////////////////////////
+
+//  package main
+
+//  import (
+//  	"fmt"
+//  	"os"
+//
+//  	"github.com/go-easygen/go-flags/clis"
+//  )
+
+// *** Sub-command: publish ***
+
+////////////////////////////////////////////////////////////////////////////
+// Constant and data type/structure definitions
+
+// The PublishCommand type defines all the configurable options from cli.
+//  type PublishCommand struct {
+//  	Dir	string	`short:"d" long:"dir" description:"publish dir" required:"true"`
+//  	Suffix	[]string	`short:"s" long:"suffix" description:"source file suffix for publish" choice:".go" choice:".c" choice:".h"`
+//  	Out	string	`short:"o" long:"out" description:"output filename"`
+//  
+//  	// Example of positional arguments
+//  	Args struct {
+//  	  ID   string
+//  	  Num  int
+//  	  Rest []string
+//  	} `positional-args:"yes" required:"yes"`
+//  }
+
+//  
+//  var publishCommand PublishCommand
+//  
+//  func init() {
+//  	parser.AddCommand("publish",
+//  		"Publish the network application",
+//  		"Publish the built network application to central repo",
+//  		&publishCommand)
+//  }
+//
+//  func (x *PublishCommand) Execute(args []string) error {
+//   	fmt.Fprintf(os.Stderr, "Publish the network application\n")
+//   	// fmt.Fprintf(os.Stderr, "Copyright (C) 2022, Myself <me@mine.org>\n\n")
+//   	clis.Setup("redo::publish", opts.Verbose)
+//   	clis.Verbose(1, "Doing Publish, with %+v, %+v", opts, args)
+//   	fmt.Println(x.Dir, x.Suffix, x.Out, x.Args)
+//  	return x.Exec(args)
+//  }
+//  
+// Exec implements the business logic of command `publish`
+// func (x *PublishCommand) Exec(args []string) error {
+// 	// err := ...
+// 	// clis.WarnOn("Publish, Exec", err)
+// 	// or,
+// 	// clis.AbortOn("Publish, Exec", err)
+// 	return nil
+// }
+// Template for "publish" CLI handling ends here
+
+
diff --git a/test/commandlineGoFlags.tmpl b/test/commandlineGoFlags.tmpl
new file mode 100644
index 0000000..7a5d2f4
--- /dev/null
+++ b/test/commandlineGoFlags.tmpl
@@ -0,0 +1,128 @@
+// {{.Name}} - {{.Desc}}
+// 
+// {{.Text}}
+
+package {{$.PackageName}}
+
+{{template "header" $ }}
+
+import (
+//  	"fmt"
+//  	"os"
+
+//  	"github.com/go-easygen/go-flags"
+)
+
+// Template for main starts here
+
+//////////////////////////////////////////////////////////////////////////
+// Constant and data type/structure definitions
+
+////////////////////////////////////////////////////////////////////////////
+// Global variables definitions
+
+//  var (
+//          progname  = "{{.Name}}"
+//          version   = "0.1.0"
+//          date = "{{ date "I" }}"
+
+//  	// opts store all the configurable options
+//  	opts optsT
+//  )
+//  
+//  var parser = flags.NewParser(&opts, flags.Default)
+
+////////////////////////////////////////////////////////////////////////////
+// Function definitions
+
+// Function main
+//  func main() {
+{{- if .Version }}
+//  	opts.Version = showVersion
+{{- end }}
+{{- if .Verbose }}
+//  	opts.Verbflg = func() {
+//  		opts.Verbose++
+//  	}
+{{- end }}
+//  
+//  	if _, err := parser.Parse(); err != nil {
+//  		fmt.Println()
+//  		parser.WriteHelp(os.Stdout)
+//  		os.Exit(1)
+//  	}
+//  	fmt.Println()
+//  	//Do{{stringsTitle .Name}}()
+//  }
+//  
+{{- if .Version }}
+//  func showVersion() {
+//   	fmt.Fprintf(os.Stderr, "{{.Name}} - {{.Desc}}, version %s\n", version)
+//  	fmt.Fprintf(os.Stderr, "Built on %s\n", date)
+//   	fmt.Fprintf(os.Stderr, "Copyright (C) {{ date "Y4" }}, {{or $.Authors "The Author(s) <they@their.org>"}}\n\n")
+//  	fmt.Fprintf(os.Stderr, "{{.Text}}\n")
+//  	os.Exit(0)
+//  }
+{{- end }}
+// Template for main ends here
+
+// Do{{stringsTitle .Name}} implements the business logic of command `{{.Name}}`
+//  func Do{{stringsTitle .Name}}() error {
+//  	return nil
+//  }
+
+// Template for type define starts here
+
+{{template "type_struct" argsm "ProgramName" .ProgramName "Options" .Options "Verbose" .Verbose "Version" .Version "typeName" "optsT" "Prefix" "" }}
+// Template for type define ends here
+
+{{range .Command}}
+// Template for "{{.Name}}" CLI handling starts here
+{{template "header" $ }}
+
+//  package {{$.PackageName}}
+
+//  import (
+//  	"fmt"
+//  	"os"
+//
+//  	"github.com/go-easygen/go-flags/clis"
+//  )
+
+// *** Sub-command: {{.Name}} ***
+
+////////////////////////////////////////////////////////////////////////////
+// Constant and data type/structure definitions
+
+{{template "type_struct" argsm "ProgramName" $.ProgramName "Options" .Options "typeName" (print (stringsTitle .Name) "Command") "Prefix" "//  " }}
+
+//  
+//  var {{.Name}}Command {{stringsTitle .Name}}Command
+//  
+//  func init() {
+//  	parser.AddCommand("{{.Name}}",
+//  		"{{.Desc}}",
+//  		"{{.Text}}",
+//  		&{{.Name}}Command)
+//  }
+//
+//  func (x *{{stringsTitle .Name}}Command) Execute(args []string) error {
+//   	fmt.Fprintf(os.Stderr, "{{.Desc}}\n")
+//   	// fmt.Fprintf(os.Stderr, "Copyright (C) {{ date "Y4" }}, {{or $.Authors "The Author(s) <they@their.org>"}}\n\n")
+//   	clis.Setup("{{$.Name}}::{{.Name}}", opts.Verbose)
+//   	clis.Verbose(1, "Doing {{stringsTitle .Name}}, with %+v, %+v", opts, args)
+//   	{{$opts := .Options}}fmt.Println({{range $i, $opt := .Options}}x.{{$opt.Name}}{{if lt $i ($opts | len | minus1)}}, {{end}}{{end}})
+//  	return x.Exec(args)
+//  }
+//  
+// Exec implements the business logic of command `{{.Name}}`
+// func (x *{{stringsTitle .Name}}Command) Exec(args []string) error {
+// 	// err := ...
+// 	// clis.WarnOn("{{stringsTitle .Name}}, Exec", err)
+// 	// or,
+// 	// clis.AbortOn("{{stringsTitle .Name}}, Exec", err)
+// 	return nil
+// }
+// Template for "{{.Name}}" CLI handling ends here
+{{end}}
+
diff --git a/test/commandlineGoFlags.yaml b/test/commandlineGoFlags.yaml
new file mode 100644
index 0000000..8ff2642
--- /dev/null
+++ b/test/commandlineGoFlags.yaml
@@ -0,0 +1,102 @@
+# program name, name for the executable
+ProgramName: redo
+Authors: Myself <me@mine.org>
+
+# For the complete demo, refer to the finished code at
+#   https://github.com/suntong/lang/tree/master/lang/Go/src/sys/go-flags/wireframed
+#  and the wiki at
+#   https://github.com/go-easygen/easygen/issues/46
+#
+PackageName: main
+
+Name: redo
+Desc: "global option redo"
+Text: Redo global option via automatic code-gen
+Verbose: true
+Version: true
+
+Options:
+  - Name: Host
+    Type: string
+    Flag: H,host
+    EnvV: true
+    Usage: Host address
+    Value: localhost
+
+  - Name: Port
+    Type: int
+    Flag: p,port
+    EnvV: true
+    Usage: Listening port
+    Value: 80
+
+  - Name: Force
+    Type: bool
+    Flag: f,force
+    EnvV: true
+    Usage: Force start
+
+
+Command:
+
+  - Name: build
+    Desc: "Build the network application"
+    Text: 'Usage:\n  redo build [Options] Arch(i386|amd64)'
+    
+    Options:
+      - Name: Dir
+        Type: string
+        Flag: dir
+        Value: "./"
+        Usage: source code root dir
+
+  - Name: install
+    Desc: "Install the network application"
+    Text: 'The add command adds a file to the repository. Use -a to add all files'
+    
+    Options:
+      - Name: Dir
+        Type: string
+        Flag: d
+        Value: "./"
+        Usage: source code root dir
+
+      - Name: Suffix
+        Type: string
+        Flag: suffix
+        Value: ".go,.c,.s"
+        Usage: "source file suffix"
+
+  - Name: publish
+    Desc: Publish the network application
+    Text: Publish the built network application to central repo
+
+    Options:
+      - Name: Dir
+        Type: string
+        Flag: 'd,dir'
+        Usage: publish dir
+        Required: true
+
+      - Name: Suffix
+        Type: '[]string'
+        Flag: s,suffix
+        Usage: "source file suffix for publish"
+        Choices:
+          - .go
+          - .c
+          - .h
+
+      - Name: Out
+        Type: string
+        Flag: o,out
+        Usage: "output filename"
+
+      - Name: Args
+        Args: |-
+          // Example of positional arguments
+          //  	Args struct {
+          //  	  ID   string
+          //  	  Num  int
+          //  	  Rest []string
+          //  	} `positional-args:"yes" required:"yes"`
diff --git a/test/nested_demo_argsm_opt.tmpl b/test/nested_demo_argsm_opt.tmpl
new file mode 100644
index 0000000..682db92
--- /dev/null
+++ b/test/nested_demo_argsm_opt.tmpl
@@ -0,0 +1,23 @@
+{{define "type_struct" -}} 
+
+// The {{.typeName}} type defines all the configurable options from cli.
+type {{.typeName}} struct { {{- range .Options}}
+{{- if eq .Name "Args" }}
+
+	{{.Args}}
+{{- else }}{{$f := stringsSplit .Flag ","}}{{ $flen := len $f }}
+	{{.Name}}	{{.Type}}	`short:"{{index $f 0}}"{{if gt $flen 1}} long:"{{index $f 1}}"{{end}}{{if .EnvV}} env:"{{printf "%s_%s" (clk2ss $.ProgramName) (clk2ss .Name)}}"{{end}} description:"{{.Usage}}"{{if .Value}} default:"{{.Value}}"{{end}}`{{end}}
+{{- end}}
+{{- if .Verbose}}
+	Verbflg func()  `short:"v" long:"verbose" description:"Verbose mode (Multiple -v options increase the verbosity)"`
+	Verbose uint
+{{end}}
+{{- end -}}
+
+{{range .Command}}
+////////////////////////////////////////////////////////////////////////////
+// {{.Name}}
+
+{{template "type_struct" argsm "Options" .Options "typeName" (print (stringsTitle .Name) "Command")  }}
+}
+{{end}}
diff --git a/test/nested_demo_argsm_opt.yaml b/test/nested_demo_argsm_opt.yaml
new file mode 100644
index 0000000..85ec7aa
--- /dev/null
+++ b/test/nested_demo_argsm_opt.yaml
@@ -0,0 +1,36 @@
+Command:
+
+  - Name: publish
+    Desc: "Publish application"
+    Text: 'Publish the network application"'    
+
+    Options:
+      - Name: Dir
+        Type: string
+        Flag: '*d,dir'
+        Usage: publish dir
+
+      - Name: Suffix
+        Type: string
+        Flag: suffix
+        Value: ".go,.c,.s"
+        Usage: "source file suffix"
+
+      - Name: Out
+        Type: string
+        Flag: o,out
+        Usage: "output filename"
+
+      - Name: List
+        Type: bool
+        Flag: l,list
+        Usage: "list all sub commands"
+
+      - Name: Args
+        Args: |
+          // Example of positional arguments
+          Args struct {
+            ID   string
+            Num  int
+            Rest []string
+          "} `positional-args:"yes" required:"yes"`"
diff --git a/test/tf-calc.ref b/test/tf-calc.ref
new file mode 100644
index 0000000..be3a1f4
--- /dev/null
+++ b/test/tf-calc.ref
@@ -0,0 +1,5 @@
+some-init-method
+5 5
+5 5
+3 3 2 2
+8
diff --git a/test/tf-calc.tmpl b/test/tf-calc.tmpl
new file mode 100644
index 0000000..60fabb5
--- /dev/null
+++ b/test/tf-calc.tmpl
@@ -0,0 +1,5 @@
+{{.Name}}
+{{6 | minus1}} {{minus1 6}}
+{{6 | minus 1}} {{minus 1 6}}
+{{5 | minus 2}} {{minus 2 5}} {{5 | minus 3}} {{minus 3 5}}
+{{add 2 6}}
diff --git a/test/tf-calc.yaml b/test/tf-calc.yaml
new file mode 120000
index 0000000..042f49b
--- /dev/null
+++ b/test/tf-calc.yaml
@@ -0,0 +1 @@
+listfunc2.yaml
\ No newline at end of file
diff --git a/tf-calc.go b/tf-calc.go
index 5f23e9d..78db730 100644
--- a/tf-calc.go
+++ b/tf-calc.go
@@ -45,6 +45,9 @@ func ArgsM(kvs ...interface{}) (map[string]interface{}, error) {
 //==========================================================================
 // template function for calculations
 
+func Add(b, a int) int   { return a + b }
+func Minus(b, a int) int { return a - b }
+
 // By Caleb Spare @gmail.com
 // https://groups.google.com/d/msg/golang-nuts/gzAyBLAeUbU/LwgomgxcjQ8J
 
diff --git a/tf-strings.go b/tf-strings.go
index fdf4a3a..3e48f0e 100644
--- a/tf-strings.go
+++ b/tf-strings.go
@@ -150,11 +150,25 @@ func RegexpSplit(s string, regExp string, n int) []string {
 ////////////////////////////////////////////////////////////////////////////
 // Misc
 
+// Indent will indent the following lines according to the specified spaces
+func Indent(spaces int, v string) string {
+	pad := strings.Repeat(" ", spaces)
+	return strings.Replace(v, "\n", "\n"+pad, -1)
+}
+
+// PIndent will indent all lines according to the specified spaces
+func PIndent(spaces int, v string) string {
+	pad := strings.Repeat(" ", spaces)
+	return pad + Indent(spaces, v)
+}
+
 // Coalesce function takes two or more string arguments and returns the first argument that is not empty.
 // The result is empty only if all the arguments are empty.
-func Coalesce(s ...string) string {
-	for _, str := range s {
-		if len(str) != 0 && str != "<no value>" {
+func Coalesce(s ...interface{}) string {
+	// https://go.dev/play/p/C2-f7B0eCwx
+	for _, v := range s {
+		str := fmt.Sprint(v)
+		if len(str) != 0 && str != "<nil>" {
 			return str
 		}
 	}

More details

Full run details