Repository: JanDeDobbeleer/oh-my-posh
Pull request #4104 (2023-07-29 12:52:37)

feat(template): add hresult function
### Prerequisites

- [x] I have read and understood the [contributing guide][CONTRIBUTING.md].
- [x] The commit message follows the [conventional commits][cc] guidelines.
- [x] Tests for the changes have been added (for bug fixes / features).
- [x] Docs have been added/updated (for bug fixes / features).

### Description

<!--
copilot:summary
-->
### <samp>🤖 Generated by Copilot at 8f502d0</samp>

This pull request adds a new template function `hresult` that converts integers to hexadecimal strings representing HRESULT values. The function is implemented, tested, and documented in `src/template/numbers.go`, `src/template/numbers_test.go`, and `website/docs/configuration/templates.mdx` respectively.

### How

<!--
copilot:walkthrough
-->
### <samp>🤖 Generated by Copilot at 8f502d0</samp>

*  Add a new template function `hresult` to convert integers to hexadecimal strings representing HRESULT values ([link](https://github.com/JanDeDobbeleer/oh-my-posh/pull/4104/files?diff=unified&w=0#diff-fb476f29de832fca91da97cc9d9f278b83db39959969543c1793a9e875340131R20), [link](https://github.com/JanDeDobbeleer/oh-my-posh/pull/4104/files?diff=unified&w=0#diff-460992fbdbf9b032d89a81f3d92437415d70d15636bd988c2396c2893b257394R1-R7), [link](https://github.com/JanDeDobbeleer/oh-my-posh/pull/4104/files?diff=unified&w=0#diff-398b34422872ecc5101ef1d16becc75269a1e389ed972d81a029503e77f7c03eR1-R43), [link](https://github.com/JanDeDobbeleer/oh-my-posh/pull/4104/files?diff=unified&w=0#diff-258349fd4a67f21d91c0fbbfd1e6f28a7ee422af8f1b445022bd8eb5cc4e2d48L163-R171))
  - Implement the function in `src/template/numbers.go` using the `fmt` package ([link](https://github.com/JanDeDobbeleer/oh-my-posh/pull/4104/files?diff=unified&w=0#diff-460992fbdbf9b032d89a81f3d92437415d70d15636bd988c2396c2893b257394R1-R7))
  - Add unit tests for the function in `src/template/numbers_test.go` using the `testing` and `assert` packages ([link](https://github.com/JanDeDobbeleer/oh-my-posh/pull/4104/files?diff=unified&w=0#diff-398b34422872ecc5101ef1d16becc75269a1e389ed972d81a029503e77f7c03eR1-R43))
  - Update the documentation for the template functions in `website/docs/configuration/templates.mdx` with an explanation and an example of the function ([link](https://github.com/JanDeDobbeleer/oh-my-posh/pull/4104/files?diff=unified&w=0#diff-258349fd4a67f21d91c0fbbfd1e6f28a7ee422af8f1b445022bd8eb5cc4e2d48L163-R171))

<!---

Tips:

If you're not comfortable with working with Git,
we're working a guide (https://ohmyposh.dev/docs/contributing_git) to help you out.
Oh My Posh advises GitKraken (https://www.gitkraken.com/invite/nQmDPR9D) as your preferred cross platform Git GUI power tool.

-->

[CONTRIBUTING.md]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md
[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary



Patch:
diff --git a/src/template/func_map.go b/src/template/func_map.go
index de3dd1c2..c2437e1a 100644
--- a/src/template/func_map.go
+++ b/src/template/func_map.go
@@ -17,6 +17,7 @@ func funcMap() template.FuncMap {
 		"gt":           gt,
 		"lt":           lt,
 		"reason":       GetReasonFromStatus,
+		"hresult":      hresult,
 	}
 	for key, fun := range sprig.TxtFuncMap() {
 		if _, ok := funcMap[key]; !ok {
diff --git a/src/template/numbers.go b/src/template/numbers.go
new file mode 100644
index 00000000..c1765321
--- /dev/null
+++ b/src/template/numbers.go
@@ -0,0 +1,7 @@
+package template
+
+import "fmt"
+
+func hresult(number int) string {
+	return fmt.Sprintf("0x%04X", uint32(number))
+}
diff --git a/website/docs/configuration/templates.mdx b/website/docs/configuration/templates.mdx
index 21335b36..3654d3dc 100644
--- a/website/docs/configuration/templates.mdx
+++ b/website/docs/configuration/templates.mdx
@@ -160,14 +160,15 @@ use them.
 
 <!-- markdownlint-disable MD013 -->
 
-| Template                                                       | Description                                                                                                        |
-| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
-| `{{ url .UpstreamIcon .UpstreamURL }}`                         | Create a hyperlink to a website to open your default browser (needs terminal [support][terminal-list-hyperlinks]). |
-| `{{ path .Path .Location }}`                                   | Create a link to a folder to open your file explorer (needs terminal [support][terminal-list-hyperlinks]).         |
-| `{{ secondsRound 3600 }}`                                      | Round seconds to a time indication. In this case the output is `1h`.                                               |
-| `{{ if glob "*.go" }}OK{{ else }}NOK{{ end }}`                 | Exposes [filepath.Glob][glob] as a boolean template function.                                                      |
-| `{{ if matchP "*.Repo" .Path }}Repo{{ else }}No Repo{{ end }}` | Exposes [regexp.MatchString][regexpms] as a boolean template function.                                             |
-| `{{ replaceP "c.t" "cut code cat" "dog" }}`                    | Exposes [regexp.ReplaceAllString][regexpra] as a string template function.                                         |
+| Template                                                       | Description                                                                                                            |
+| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
+| `{{ url .UpstreamIcon .UpstreamURL }}`                         | Create a hyperlink to a website to open your default browser (needs terminal [support][terminal-list-hyperlinks]).     |
+| `{{ path .Path .Location }}`                                   | Create a link to a folder to open your file explorer (needs terminal [support][terminal-list-hyperlinks]).             |
+| `{{ secondsRound 3600 }}`                                      | Round seconds to a time indication. In this case the output is `1h`.                                                   |
+| `{{ if glob "*.go" }}OK{{ else }}NOK{{ end }}`                 | Exposes [filepath.Glob][glob] as a boolean template function.                                                          |
+| `{{ if matchP "*.Repo" .Path }}Repo{{ else }}No Repo{{ end }}` | Exposes [regexp.MatchString][regexpms] as a boolean template function.                                                 |
+| `{{ replaceP "c.t" "cut code cat" "dog" }}`                    | Exposes [regexp.ReplaceAllString][regexpra] as a string template function.                                             |
+| <code>{{ .Code &vert; hresult }}</code>                        | Transform a status code to its HRESULT value for easy troubleshooting. For example `-1978335212` becomes `0x8A150014`. |
 
 <!-- markdownlint-enable MD013 -->
 


Test patch:
diff --git a/src/template/numbers_test.go b/src/template/numbers_test.go
new file mode 100644
index 00000000..7d2f809d
--- /dev/null
+++ b/src/template/numbers_test.go
@@ -0,0 +1,43 @@
+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 TestHResult(t *testing.T) {
+	cases := []struct {
+		Case        string
+		Expected    string
+		Template    string
+		ShouldError bool
+	}{
+		{Case: "Windows exit code", Expected: "0x8A150014", Template: `{{ hresult -1978335212 }}`},
+		{Case: "Not a number", Template: `{{ hresult "no number" }}`, ShouldError: true},
+	}
+
+	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)
+	}
+}