Repository: JanDeDobbeleer/oh-my-posh
Pull request #5844 (2024-11-07 10:43:41)

next minor release
### 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

Aggregation of multiple PR's

<!---

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/config/segment.go b/src/config/segment.go
index 28d0452c..7f92c8dc 100644
--- a/src/config/segment.go
+++ b/src/config/segment.go
@@ -115,18 +115,11 @@ func (segment *Segment) Execute(env runtime.Environment) {
 		return
 	}
 
-	if shouldHideForWidth(segment.env, segment.MinWidth, segment.MaxWidth) {
+	if shouldHideForWidth(env, segment.MinWidth, segment.MaxWidth) {
 		return
 	}
 
-	if len(segment.Templates) != 0 {
-		segment.Template = segment.Templates.Resolve(segment.writer, "", segment.TemplatesLogic)
-	}
-
-	if segment.writer.Enabled() {
-		segment.Enabled = true
-		env.TemplateCache().AddSegmentData(segment.Name(), segment.writer)
-	}
+	segment.Enabled = segment.writer.Enabled()
 }
 
 func (segment *Segment) Render() {
@@ -142,7 +135,8 @@ func (segment *Segment) Render() {
 		return
 	}
 
-	segment.writer.SetText(text)
+	segment.SetText(text)
+	segment.env.TemplateCache().AddSegmentData(segment.Name(), segment.writer)
 	segment.setCache()
 }
 
@@ -277,6 +271,11 @@ func (segment *Segment) folderKey() string {
 }
 
 func (segment *Segment) string() string {
+	result := segment.Templates.Resolve(segment.writer, "", segment.TemplatesLogic)
+	if len(result) != 0 {
+		return result
+	}
+
 	if len(segment.Template) == 0 {
 		segment.Template = segment.writer.Template()
 	}
@@ -328,6 +327,10 @@ func (segment *Segment) evaluateNeeds() {
 		value += strings.Join(segment.BackgroundTemplates, "")
 	}
 
+	if len(segment.Templates) != 0 {
+		value += strings.Join(segment.Templates, "")
+	}
+
 	if !strings.Contains(value, ".Segments.") {
 		return
 	}
diff --git a/src/config/segment_types.go b/src/config/segment_types.go
index 8821e42f..6d4193b8 100644
--- a/src/config/segment_types.go
+++ b/src/config/segment_types.go
@@ -33,6 +33,8 @@ const (
 	ANGULAR SegmentType = "angular"
 	// ARGOCD writes the current argocd context
 	ARGOCD SegmentType = "argocd"
+	// AURELIA writes which aurelia version is currently referenced in package.json
+	AURELIA SegmentType = "aurelia"
 	// AWS writes the active aws context
 	AWS SegmentType = "aws"
 	// AZ writes the Azure subscription info we're currently in
@@ -217,6 +219,8 @@ const (
 	YARN SegmentType = "yarn"
 	// YTM writes YouTube Music information and status
 	YTM SegmentType = "ytm"
+	// ZIG writes the active zig version
+	ZIG SegmentType = "zig"
 )
 
 // Segments contains all available prompt segment writers.
@@ -224,6 +228,7 @@ const (
 var Segments = map[SegmentType]func() SegmentWriter{
 	ANGULAR:         func() SegmentWriter { return &segments.Angular{} },
 	ARGOCD:          func() SegmentWriter { return &segments.Argocd{} },
+	AURELIA:         func() SegmentWriter { return &segments.Aurelia{} },
 	AWS:             func() SegmentWriter { return &segments.Aws{} },
 	AZ:              func() SegmentWriter { return &segments.Az{} },
 	AZD:             func() SegmentWriter { return &segments.Azd{} },
@@ -316,6 +321,7 @@ var Segments = map[SegmentType]func() SegmentWriter{
 	XMAKE:           func() SegmentWriter { return &segments.XMake{} },
 	YARN:            func() SegmentWriter { return &segments.Yarn{} },
 	YTM:             func() SegmentWriter { return &segments.Ytm{} },
+	ZIG:             func() SegmentWriter { return &segments.Zig{} },
 }
 
 func (segment *Segment) MapSegmentWithWriter(env runtime.Environment) error {
diff --git a/src/prompt/engine.go b/src/prompt/engine.go
index 532ac75b..20d8c2e8 100644
--- a/src/prompt/engine.go
+++ b/src/prompt/engine.go
@@ -154,6 +154,7 @@ func (e *Engine) shouldFill(filler string, padLength int) (string, bool) {
 	}
 
 	// allow for easy color overrides and templates
+	terminal.SetColors("default", "default")
 	terminal.Write("", "", filler)
 	filler, lenFiller := terminal.String()
 	if lenFiller == 0 {
diff --git a/src/prompt/segments.go b/src/prompt/segments.go
index 5d01912e..a959fd56 100644
--- a/src/prompt/segments.go
+++ b/src/prompt/segments.go
@@ -59,11 +59,6 @@ func (e *Engine) writeSegments(out chan result, block *config.Block) {
 
 			results[res.index] = res.segment
 
-			name := res.segment.Name()
-			if !slices.Contains(executed, name) {
-				executed = append(executed, name)
-			}
-
 			segment := results[current]
 
 			for segment != nil {
@@ -80,6 +75,11 @@ func (e *Engine) writeSegments(out chan result, block *config.Block) {
 
 				current++
 				segment = results[current]
+
+				name := res.segment.Name()
+				if !slices.Contains(executed, name) {
+					executed = append(executed, name)
+				}
 			}
 		default:
 			runtime.Gosched()
diff --git a/src/segments/angular.go b/src/segments/angular.go
index f7617a78..c56d709b 100644
--- a/src/segments/angular.go
+++ b/src/segments/angular.go
@@ -26,6 +26,5 @@ func (a *Angular) Enabled() bool {
 }
 
 func (a *Angular) getVersion() (string, error) {
-	// tested by nx_test.go
-	return getNodePackageVersion(a.language.env, filepath.Join("@angular", "core"))
+	return a.nodePackageVersion(filepath.Join("@angular", "core"))
 }
diff --git a/src/segments/aurelia.go b/src/segments/aurelia.go
new file mode 100644
index 00000000..49063eb1
--- /dev/null
+++ b/src/segments/aurelia.go
@@ -0,0 +1,30 @@
+package segments
+
+type Aurelia struct {
+	language
+}
+
+func (a *Aurelia) Template() string {
+	return languageTemplate
+}
+
+func (a *Aurelia) Enabled() bool {
+	a.extensions = []string{"package.json"}
+	a.commands = []*cmd{
+		{
+			regex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)(-(?P<prerelease>[a-z]+).(?P<buildmetadata>[0-9]+))?)))`,
+			getVersion: a.getVersion,
+		},
+	}
+	a.versionURLTemplate = "https://github.com/aurelia/aurelia/releases/tag/v{{ .Full }}"
+
+	if !a.hasNodePackage("aurelia") {
+		return false
+	}
+
+	return a.language.Enabled()
+}
+
+func (a *Aurelia) getVersion() (string, error) {
+	return a.nodePackageVersion("aurelia")
+}
diff --git a/src/segments/cds.go b/src/segments/cds.go
index afa3d243..df96b79a 100644
--- a/src/segments/cds.go
+++ b/src/segments/cds.go
@@ -1,9 +1,5 @@
 package segments
 
-import (
-	"encoding/json"
-)
-
 type Cds struct {
 	language
 	HasDependency bool
@@ -22,7 +18,6 @@ func (c *Cds) Enabled() bool {
 			regex:      `@sap/cds: (?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
 		},
 	}
-	//TODO: is this necessary?
 	c.language.loadContext = c.loadContext
 	c.language.inContext = c.inContext
 	c.displayMode = c.props.GetString(DisplayMode, DisplayModeContext)
@@ -31,29 +26,11 @@ func (c *Cds) Enabled() bool {
 }
 
 func (c *Cds) loadContext() {
-	if !c.language.env.HasFiles("package.json") {
-		return
-	}
-
-	content := c.language.env.FileContent("package.json")
-	objmap := map[string]json.RawMessage{}
-
-	if err := json.Unmarshal([]byte(content), &objmap); err != nil {
+	if !c.hasNodePackage("@sap/cds") {
 		return
 	}
 
-	dependencies := map[string]json.RawMessage{}
-
-	if err := json.Unmarshal(objmap["dependencies"], &dependencies); err != nil {
-		return
-	}
-
-	for d := range dependencies {
-		if d == "@sap/cds" {
-			c.HasDependency = true
-			break
-		}
-	}
+	c.HasDependency = true
 }
 
 func (c *Cds) inContext() bool {
diff --git a/src/segments/language.go b/src/segments/language.go
index 11327a91..e5b3855b 100644
--- a/src/segments/language.go
+++ b/src/segments/language.go
@@ -307,3 +307,42 @@ func (l *language) buildVersionURL() {
 
 	l.version.URL = url
 }
+
+func (l *language) hasNodePackage(name string) bool {
+	packageJSON := l.env.FileContent("package.json")
+
+	var packageData map[string]interface{}
+	if err := json.Unmarshal([]byte(packageJSON), &packageData); err != nil {
+		return false
+	}
+
+	dependencies, ok := packageData["dependencies"].(map[string]interface{})
+	if !ok {
+		return false
+	}
+
+	if _, exists := dependencies[name]; !exists {
+		return false
+	}
+
+	return true
+}
+
+func (l *language) nodePackageVersion(name string) (string, error) {
+	folder := filepath.Join(l.env.Pwd(), "node_modules", name)
+
+	const fileName string = "package.json"
+	if !l.env.HasFilesInDir(folder, fileName) {
+		return "", fmt.Errorf("%s not found in %s", fileName, folder)
+	}
+
+	content := l.env.FileContent(filepath.Join(folder, fileName))
+	var data ProjectData
+	err := json.Unmarshal([]byte(content), &data)
+
+	if err != nil {
+		return "", err
+	}
+
+	return data.Version, nil
+}
diff --git a/src/segments/nx.go b/src/segments/nx.go
index 2e538cab..5c29f20f 100644
--- a/src/segments/nx.go
+++ b/src/segments/nx.go
@@ -1,13 +1,5 @@
 package segments
 
-import (
-	"encoding/json"
-	"fmt"
-	"path/filepath"
-
-	"github.com/jandedobbeleer/oh-my-posh/src/runtime"
-)
-
 type Nx struct {
 	language
 }
@@ -30,20 +22,5 @@ func (a *Nx) Enabled() bool {
 }
 
 func (a *Nx) getVersion() (string, error) {
-	return getNodePackageVersion(a.language.env, "nx")
-}
-
-func getNodePackageVersion(env runtime.Environment, nodePackage string) (string, error) {
-	const fileName string = "package.json"
-	folder := filepath.Join(env.Pwd(), "node_modules", nodePackage)
-	if !env.HasFilesInDir(folder, fileName) {
-		return "", fmt.Errorf("%s not found in %s", fileName, folder)
-	}
-	content := env.FileContent(filepath.Join(folder, fileName))
-	var data ProjectData
-	err := json.Unmarshal([]byte(content), &data)
-	if err != nil {
-		return "", err
-	}
-	return data.Version, nil
+	return a.nodePackageVersion("nx")
 }
diff --git a/src/segments/react.go b/src/segments/react.go
index bd40b99a..19f6ca04 100644
--- a/src/segments/react.go
+++ b/src/segments/react.go
@@ -22,6 +22,5 @@ func (r *React) Enabled() bool {
 }
 
 func (r *React) getVersion() (string, error) {
-	// tested by nx_test.go
-	return getNodePackageVersion(r.language.env, "react")
+	return r.nodePackageVersion("react")
 }
diff --git a/src/segments/zig.go b/src/segments/zig.go
new file mode 100644
index 00000000..efebc100
--- /dev/null
+++ b/src/segments/zig.go
@@ -0,0 +1,29 @@
+package segments
+
+type Zig struct {
+	language
+}
+
+func (zig *Zig) Template() string {
+	return languageTemplate
+}
+
+func (zig *Zig) Enabled() bool {
+	zig.extensions = []string{"*.zig", "*.zon"}
+	zig.projectFiles = []string{"build.zig"}
+	zig.commands = []*cmd{
+		{
+			executable: "zig",
+			args:       []string{"version"},
+			regex:      `(?P<version>(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)`, //nolint:lll
+		},
+	}
+
+	zig.versionURLTemplate = "https://ziglang.org/download/{{ .Major }}.{{ .Minor }}.{{ .Patch }}/release-notes.html"
+
+	return zig.language.Enabled()
+}
+
+func (zig *Zig) InProjectDir() bool {
+	return zig.projectRoot != nil
+}
diff --git a/src/template/list.go b/src/template/list.go
index f018ffc1..4a893451 100644
--- a/src/template/list.go
+++ b/src/template/list.go
@@ -18,6 +18,10 @@ func (l List) Empty() bool {
 }
 
 func (l List) Resolve(context any, defaultValue string, logic Logic) string {
+	if l.Empty() {
+		return defaultValue
+	}
+
 	switch logic {
 	case FirstMatch:
 		return l.FirstMatch(context, defaultValue)
diff --git a/themes/atomic.omp.json b/themes/atomic.omp.json
index 1c810631..118e6c25 100644
--- a/themes/atomic.omp.json
+++ b/themes/atomic.omp.json
@@ -146,6 +146,15 @@
           "trailing_diamond": "\ue0b4 ",
           "type": "angular"
         },
+        {
+          "background": "#ffffff",
+          "foreground": "#de1f84",
+          "leading_diamond": " \ue0b6",
+          "style": "diamond",
+          "template": "\u03b1 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}",
+          "trailing_diamond": "\ue0b4 ",
+          "type": "aurelia"
+        },
         {
           "background": "#1e293b",
           "foreground": "#ffffff",
diff --git a/themes/atomicBit.omp.json b/themes/atomicBit.omp.json
index 893de3d2..73a5b768 100644
--- a/themes/atomicBit.omp.json
+++ b/themes/atomicBit.omp.json
@@ -80,6 +80,12 @@
           "template": "<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>",
           "type": "angular"
         },
+        {
+          "foreground": "#de1f84",
+          "style": "plain",
+          "template": "<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>",
+          "type": "aurelia"
+        },
         {
           "foreground": "#ffffff",
           "style": "plain",
diff --git a/themes/devious-diamonds.omp.yaml b/themes/devious-diamonds.omp.yaml
index 33d4db11..714e2b5e 100644
--- a/themes/devious-diamonds.omp.yaml
+++ b/themes/devious-diamonds.omp.yaml
@@ -51,6 +51,14 @@ blocks:
         properties:
           fetch_version: true
         template: " 󰚲 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} "
+      - type: aurelia
+        style: powerline
+        powerline_symbol: 
+        background: purple
+        foreground: white
+        properties:
+          fetch_version: true
+        template: " α {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} "
       - type: aws
         style: powerline
         powerline_symbol: 
@@ -252,7 +260,9 @@ palette:
   cyan: "#80FFEA"
   green: "#8AFF80"
   magenta-purple: "#FF80BF"
+  purple: "#DE1F84"
   red: "#FF9580"
+  white: "#FFFFFF"
   white-cursorColor-foreground: "#F8F8F2"
   yellow: "#FFCA80"
 version: 2
diff --git a/themes/froczh.omp.json b/themes/froczh.omp.json
index 0c14d807..41ae9be8 100644
--- a/themes/froczh.omp.json
+++ b/themes/froczh.omp.json
@@ -69,6 +69,14 @@
                     "foreground": "#ffffff",
                     "template": " \uE753 {{ if .Error }}<#FE4A49>?</>{{ else }}{{ .Full }}{{ end }} "
                 },
+                {
+                    "type": "aurelia",
+                    "style": "powerline",
+                    "powerline_symbol": "\uE0B0",
+                    "background": "#000000",
+                    "foreground": "#ffffff",
+                    "template": " \uE753 {{ if .Error }}<#DE1F84>?</>{{ else }}{{ .Full }}{{ end }} "
+                },
                 {
                     "type": "node",
                     "style": "powerline",
diff --git a/themes/night-owl.omp.json b/themes/night-owl.omp.json
index 6189b69d..722d4490 100644
--- a/themes/night-owl.omp.json
+++ b/themes/night-owl.omp.json
@@ -106,6 +106,15 @@
           "trailing_diamond": "<transparent,#ffffff>\ue0b2</>",
           "type": "angular"
         },
+        {
+          "background": "#ffffff",
+          "foreground": "#de1f84",
+          "leading_diamond": "\ue0b2",
+          "style": "diamond",
+          "template": "\u03b1 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} ",
+          "trailing_diamond": "<transparent,#ffffff>\ue0b2</>",
+          "type": "aurelia"
+        },
         {
           "background": "#565656",
           "foreground": "#faa029",
diff --git a/themes/schema.json b/themes/schema.json
index 1b42bbd0..11609d5c 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -147,6 +147,11 @@
       "description": "The duration for which the segment will be cached. This is parsed using the `time.ParseDuration` function from the Go standard library (see https://pkg.go.dev/time#ParseDuration for details).",
       "pattern": "^(infinite|([0-9]+(h|m|s))+)$"
     },
+    "filler": {
+      "type": "string",
+      "title": "Filler",
+      "description": "Right aligned filler text, will span the remaining width."
+    },
     "extra_prompt": {
       "type": "object",
       "default": {},
@@ -230,6 +235,10 @@
                   "hide"
                 ],
                 "default": ""
+              },
+              "filler": {
+                "$ref": "#/definitions/filler",
+                "description": "https://ohmyposh.dev/docs/configuration/block#filler"
               }
             }
           }
@@ -306,6 +315,7 @@
             "azfunc",
             "argocd",
             "angular",
+            "aurelia",
             "battery",
             "bazel",
             "brewfather",
@@ -3288,6 +3298,54 @@
             }
           }
         },
+        {
+          "if": {
+            "properties": {
+              "type": {
+                "const": "aurelia"
+              }
+            }
+          },
+          "then": {
+            "title": "Aurelia Segment",
+            "description": "https://ohmyposh.dev/docs/segments/cli/aurelia",
+            "properties": {
+              "properties": {
+                "properties": {
+                  "home_enabled": {
+                    "$ref": "#/definitions/home_enabled"
+                  },
+                  "fetch_version": {
+                    "$ref": "#/definitions/fetch_version"
+                  },
+                  "missing_command_text": {
+                    "$ref": "#/definitions/missing_command_text"
+                  },
+                  "display_mode": {
+                    "$ref": "#/definitions/display_mode"
+                  },
+                  "version_url_template": {
+                    "$ref": "#/definitions/version_url_template"
+                  },
+                  "extensions": {
+                    "type": "array",
+                    "title": "Extensions",
+                    "description": "The extensions to look for when determining if the current directory is an Aurelia project",
+                    "default": [
+                      "package.json"
+                    ],
+                    "items": {
+                      "type": "string"
+                    }
+                  },
+                  "folders": {
+                    "$ref": "#/definitions/folders"
+                  }
+                }
+              }
+            }
+          }
+        },
         {
           "if": {
             "properties": {
@@ -4642,6 +4700,55 @@
             "title": "Nix Shell",
             "description": "https://ohmyposh.dev/docs/segments/cli/nix-shell"
           }
+        },
+        {
+          "if": {
+            "properties": {
+              "type": {
+                "const": "zig"
+              }
+            }
+          },
+          "then": {
+            "title": "Zig Segment",
+            "description": "https://ohmyposh.dev/docs/segments/languages/zig",
+            "properties": {
+              "properties": {
+                "properties": {
+                  "home_enabled": {
+                    "$ref": "#/definitions/home_enabled"
+                  },
+                  "fetch_version": {
+                    "$ref": "#/definitions/fetch_version"
+                  },
+                  "display_mode": {
+                    "$ref": "#/definitions/display_mode"
+                  },
+                  "missing_command_text": {
+                    "$ref": "#/definitions/missing_command_text"
+                  },
+                  "version_url_template": {
+                    "$ref": "#/definitions/version_url_template"
+                  },
+                  "extensions": {
+                    "type": "array",
+                    "title": "Extensions",
+                    "description": "The extensions to look for when determining if the current directory is an zig project",
+                    "default": [
+                      "*.zig",
+                      "*.zon"
+                    ],
+                    "items": {
+                      "type": "string"
+                    }
+                  },
+                  "folders": {
+                    "$ref": "#/definitions/folders"
+                  }
+                }
+              }
+            }
+          }
         }
       ]
     }
@@ -4738,19 +4845,21 @@
       "$ref": "#/definitions/extra_prompt",
       "title": "Transient Prompt Setting",
       "description": "https://ohmyposh.dev/docs/configuration/transient",
-      "properties": {
-        "filler": {
-          "type": "string",
-          "title": "Filler",
-          "description": "Right aligned filler text, will span the remaining width"
-        },
-        "newline": {
-          "type": "boolean",
-          "title": "Newline",
-          "description": "Add a newline before the prompt",
-          "default": false
+      "anyOf": [
+        {
+          "properties": {
+            "filler": {
+              "$ref": "#/definitions/filler"
+            },
+            "newline": {
+              "type": "boolean",
+              "title": "Newline",
+              "description": "Add a newline before the prompt",
+              "default": false
+            }
+          }
         }
-      }
+      ]
     },
     "valid_line": {
       "$ref": "#/definitions/extra_prompt",
diff --git a/website/docs/segments/cli/aurelia.mdx b/website/docs/segments/cli/aurelia.mdx
new file mode 100644
index 00000000..77637895
--- /dev/null
+++ b/website/docs/segments/cli/aurelia.mdx
@@ -0,0 +1,61 @@
+---
+id: aurelia
+title: Aurelia
+sidebar_label: Aurelia
+---
+
+## What
+
+Display the currently active Aurelia version.
+
+## Sample Configuration
+
+import Config from "@site/src/components/Config.js";
+
+<Config
+  data={{
+    type: "aurelia",
+    style: "powerline",
+    powerline_symbol: "\uE0B0",
+    foreground: "#ffffff",
+    background: "#de1f84",
+    template: " \u03b1 {{ .Full }} ",
+  }}
+/>
+
+## Properties
+
+| Name                   | Type       | Default        | Description                                                                                                                                                                                                                          |
+| ---------------------- | :--------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `home_enabled`         | `boolean`  | `false`        | display the segment in the HOME folder or not                                                                                                                                                                                        |
+| `fetch_version`        | `boolean`  | `true`         | fetch the aurelia version                                                                                                                                                                                                            |
+| `missing_command_text` | `string`   |                | text to display when the command is missing                                                                                                                                                                                          |
+| `display_mode`         | `string`   | `context`      | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |
+| `version_url_template` | `string`   |                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |
+| `extensions`           | `[]string` | `package.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |
+| `folders`              | `[]string` |                | allows to override the list of folder names to validate                                                                                                                                                                              |
+
+## Template ([info][templates])
+
+:::note default template
+
+```template
+{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}
+```
+
+:::
+
+### Properties
+
+| Name     | Type     | Description                                        |
+| -------- | -------- | -------------------------------------------------- |
+| `.Full`  | `string` | the full version                                   |
+| `.Major` | `string` | major number                                       |
+| `.Minor` | `string` | minor number                                       |
+| `.Patch` | `string` | patch number                                       |
+| `.URL`   | `string` | URL of the version info / release notes            |
+| `.Error` | `string` | error encountered when fetching the version string |
+
+[go-text-template]: https://golang.org/pkg/text/template/
+[templates]: /docs/configuration/templates
+[aurelia]: https://docs.aurelia.io/
diff --git a/website/docs/segments/languages/zig.mdx b/website/docs/segments/languages/zig.mdx
new file mode 100644
index 00000000..e822e30e
--- /dev/null
+++ b/website/docs/segments/languages/zig.mdx
@@ -0,0 +1,64 @@
+---
+id: zig
+title: Zig
+sidebar_label: Zig
+---
+
+## What
+
+Display the currently active [zig][zig] version.
+
+## Sample Configuration
+
+import Config from "@site/src/components/Config.js";
+
+<Config
+  data={{
+    type: "zig",
+    style: "powerline",
+    powerline_symbol: "\ue0b0",
+    foreground: "#342311",
+    background: "#ffad55",
+    template: " \ue6a9 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} ",
+  }}
+/>
+
+## Properties
+
+| Name                   |    Type    |    Default     | Description                                                                                                                                                                                                                          |
+| ---------------------- | :--------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `home_enabled`         | `boolean`  |    `false`     | display the segment in the HOME folder or not                                                                                                                                                                                        |
+| `fetch_version`        | `boolean`  |     `true`     | fetch the zig version (`zig version`)                                                                                                                                                                                                |
+| `missing_command_text` |  `string`  |                | text to display when the command is missing                                                                                                                                                                                          |
+| `display_mode`         |  `string`  |   `context`    | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |
+| `version_url_template` |  `string`  |                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |
+| `extensions`           | `[]string` | `*.zig, *.zon` | allows to override the default list of file extensions to validate                                                                                                                                                                   |
+| `folders`              | `[]string` |                | allows to override the list of folder names to validate                                                                                                                                                                              |
+
+## Template ([info][templates])
+
+:::note default template
+
+```template
+{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}
+```
+
+:::
+
+### Properties
+
+| Name             | Type     | Description                                           |
+| ---------------- | -------- | ----------------------------------------------------- |
+| `.Full`          | `string` | the full version                                      |
+| `.Major`         | `string` | major number                                          |
+| `.Minor`         | `string` | minor number                                          |
+| `.Patch`         | `string` | patch number                                          |
+| `.Prerelease`    | `string` | prerelease identifier                                 |
+| `.BuildMetadata` | `string` | build identifier                                      |
+| `.URL`           | `string` | URL of the version info / release notes               |
+| `.InProjectDir`  | `bool`   | whether the working directory is within a Zig project |
+| `.Error`         | `string` | error encountered when fetching the version string    |
+
+[go-text-template]: https://golang.org/pkg/text/template/
+[templates]: /docs/configuration/templates
+[zig]: https://ziglang.org/
diff --git a/website/sidebars.js b/website/sidebars.js
index 536a1064..35557dde 100644
--- a/website/sidebars.js
+++ b/website/sidebars.js
@@ -62,6 +62,7 @@ module.exports = {
           items: [
             "segments/cli/angular",
             "segments/cli/argocd",
+            "segments/cli/aurelia",
             "segments/cli/bazel",
             "segments/cli/buf",
             "segments/cli/bun",
@@ -143,6 +144,7 @@ module.exports = {
             "segments/languages/rust",
             "segments/languages/swift",
             "segments/languages/vala",
+            "segments/languages/zig",
           ]
         },
         {


Test patch:
diff --git a/src/segments/cds_test.go b/src/segments/cds_test.go
index 035e35bc..8bc493c5 100644
--- a/src/segments/cds_test.go
+++ b/src/segments/cds_test.go
@@ -72,12 +72,8 @@ func TestCdsSegment(t *testing.T) {
 		}
 		props[DisplayMode] = tc.DisplayMode
 
-		if len(tc.PackageJSON) != 0 {
-			env.On("HasFiles", "package.json").Return(true)
-			env.On("FileContent", "package.json").Return(tc.PackageJSON)
-		} else {
-			env.On("HasFiles", "package.json").Return(false)
-		}
+		env.On("HasFiles", "package.json").Return(len(tc.PackageJSON) != 0)
+		env.On("FileContent", "package.json").Return(tc.PackageJSON)
 
 		cds := &Cds{}
 		cds.Init(props, env)
diff --git a/src/segments/language_test.go b/src/segments/language_test.go
index 08e55f7d..b34b16e0 100644
--- a/src/segments/language_test.go
+++ b/src/segments/language_test.go
@@ -1,6 +1,7 @@
 package segments
 
 import (
+	"path/filepath"
 	"testing"
 
 	cache_ "github.com/jandedobbeleer/oh-my-posh/src/cache/mock"
@@ -559,3 +560,38 @@ func getMockedLanguageEnv(params *mockedLanguageParams) (*mock.Environment, prop
 
 	return env, props
 }
+
+func TestNodePackageVersion(t *testing.T) {
+	cases := []struct {
+		Case        string
+		PackageJSON string
+		Version     string
+		ShouldFail  bool
+		NoFiles     bool
+	}{
+		{Case: "14.1.5", Version: "14.1.5", PackageJSON: "{ \"name\": \"nx\",\"version\": \"14.1.5\"}"},
+		{Case: "14.0.0", Version: "14.0.0", PackageJSON: "{ \"name\": \"nx\",\"version\": \"14.0.0\"}"},
+		{Case: "no files", NoFiles: true, ShouldFail: true},
+		{Case: "bad data", ShouldFail: true, PackageJSON: "bad data"},
+	}
+
+	for _, tc := range cases {
+		var env = new(mock.Environment)
+		env.On("Pwd").Return("posh")
+		path := filepath.Join("posh", "node_modules", "nx")
+		env.On("HasFilesInDir", path, "package.json").Return(!tc.NoFiles)
+		env.On("FileContent", filepath.Join(path, "package.json")).Return(tc.PackageJSON)
+
+		a := &language{}
+		a.Init(properties.Map{}, env)
+		got, err := a.nodePackageVersion("nx")
+
+		if tc.ShouldFail {
+			assert.Error(t, err, tc.Case)
+			return
+		}
+
+		assert.Nil(t, err, tc.Case)
+		assert.Equal(t, tc.Version, got, tc.Case)
+	}
+}
diff --git a/src/segments/nx_test.go b/src/segments/nx_test.go
deleted file mode 100644
index 9ffb1845..00000000
--- a/src/segments/nx_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package segments
-
-import (
-	"path/filepath"
-	"testing"
-
-	"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestGetNodePackageVersion(t *testing.T) {
-	cases := []struct {
-		Case        string
-		PackageJSON string
-		Version     string
-		ShouldFail  bool
-		NoFiles     bool
-	}{
-		{Case: "14.1.5", Version: "14.1.5", PackageJSON: "{ \"name\": \"nx\",\"version\": \"14.1.5\"}"},
-		{Case: "14.0.0", Version: "14.0.0", PackageJSON: "{ \"name\": \"nx\",\"version\": \"14.0.0\"}"},
-		{Case: "no files", NoFiles: true, ShouldFail: true},
-		{Case: "bad data", ShouldFail: true, PackageJSON: "bad data"},
-	}
-
-	for _, tc := range cases {
-		var env = new(mock.Environment)
-		env.On("Pwd").Return("posh")
-		path := filepath.Join("posh", "node_modules", "nx")
-		env.On("HasFilesInDir", path, "package.json").Return(!tc.NoFiles)
-		env.On("FileContent", filepath.Join(path, "package.json")).Return(tc.PackageJSON)
-
-		got, err := getNodePackageVersion(env, "nx")
-
-		if tc.ShouldFail {
-			assert.Error(t, err, tc.Case)
-			return
-		}
-
-		assert.Nil(t, err, tc.Case)
-		assert.Equal(t, tc.Version, got, tc.Case)
-	}
-}
diff --git a/src/segments/zig_test.go b/src/segments/zig_test.go
new file mode 100644
index 00000000..e70d2a9a
--- /dev/null
+++ b/src/segments/zig_test.go
@@ -0,0 +1,74 @@
+package segments
+
+import (
+	"errors"
+	"testing"
+
+	"github.com/jandedobbeleer/oh-my-posh/src/runtime"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestZig(t *testing.T) {
+	cases := []struct {
+		Case           string
+		Version        string
+		ExpectedString string
+		ExpectedURL    string
+		InProjectDir   bool
+	}{
+		{
+			Case:           "zig 0.13.0 - not in project dir",
+			Version:        "0.13.0",
+			InProjectDir:   false,
+			ExpectedString: "0.13.0",
+			ExpectedURL:    "https://ziglang.org/download/0.13.0/release-notes.html",
+		},
+		{
+			Case:           "zig 0.12.0-dev.2063+804cee3b9 - not in project dir",
+			Version:        "0.12.0-dev.2063+804cee3b9",
+			InProjectDir:   false,
+			ExpectedString: "0.12.0-dev.2063+804cee3b9",
+			ExpectedURL:    "https://ziglang.org/download/0.12.0/release-notes.html",
+		},
+		{
+			Case:           "zig 0.13.0 - in project dir",
+			Version:        "0.13.0",
+			InProjectDir:   true,
+			ExpectedString: "0.13.0",
+			ExpectedURL:    "https://ziglang.org/download/0.13.0/release-notes.html",
+		},
+		{
+			Case:           "zig 0.12.0-dev.2063+804cee3b9 - in project dir",
+			Version:        "0.12.0-dev.2063+804cee3b9",
+			InProjectDir:   true,
+			ExpectedString: "0.12.0-dev.2063+804cee3b9",
+			ExpectedURL:    "https://ziglang.org/download/0.12.0/release-notes.html",
+		},
+	}
+	for _, tc := range cases {
+		params := &mockedLanguageParams{
+			cmd:           "zig",
+			versionParam:  "version",
+			versionOutput: tc.Version,
+			extension:     "*.zig",
+		}
+
+		env, props := getMockedLanguageEnv(params)
+
+		dummyDir := &runtime.FileInfo{}
+
+		if tc.InProjectDir {
+			env.On("HasParentFilePath", "build.zig", false).Return(dummyDir, nil)
+		} else {
+			env.On("HasParentFilePath", "build.zig", false).Return(dummyDir, errors.New("build.zig not found"))
+		}
+
+		zig := &Zig{}
+		zig.Init(props, env)
+
+		assert.True(t, zig.Enabled(), tc.Case)
+		assert.Equal(t, tc.ExpectedString, renderTemplate(env, zig.Template(), zig), tc.Case)
+		assert.Equal(t, tc.ExpectedURL, renderTemplate(env, zig.URL, zig), tc.Case)
+		assert.Equal(t, tc.InProjectDir, zig.InProjectDir(), tc.Case)
+	}
+}