Repository: JanDeDobbeleer/oh-my-posh
Pull request #1859 (2022-03-03 01:50:50)

feat(swift): add swift segment
### Prerequisites

- [x] I have read and understood the `CONTRIBUTING` guide
- [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

Adds a Swift language segment to display the currently active Swift version.

![swift-5 5 3](https://user-images.githubusercontent.com/85419773/156479847-a28fbfbc-3b13-4eb4-961b-4ff3b88e5ae9.PNG)
![swift-5 5](https://user-images.githubusercontent.com/85419773/156479852-30f608dd-9c1e-419b-a1c4-509f30c41f4b.PNG)
![swift-5 6-dev](https://user-images.githubusercontent.com/85419773/156479856-e859fccc-41bc-441d-9160-60f5070f4f07.PNG)

It should be noted that when using a dev version the `versionURLTemplate` is invalid as the tags vary signficantly
For example the release urls for `5.6-dev` and `5.7-dev`
<https://github.com/apple/swift/releases/tag/swift-5.6-DEVELOPMENT-SNAPSHOT-2022-02-11-a>
<https://github.com/apple/swift/releases/tag/swift-DEVELOPMENT-SNAPSHOT-2022-02-25-a>

Kind regards,
Jed

[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary



Patch:
diff --git a/docs/docs/segment-swift.md b/docs/docs/segment-swift.md
new file mode 100644
index 00000000..bcf707fd
--- /dev/null
+++ b/docs/docs/segment-swift.md
@@ -0,0 +1,57 @@
+---
+id: swift
+title: Swift
+sidebar_label: Swift
+---
+
+## What
+
+Display the currently active [Swift][swift] version.
+
+## Sample Configuration
+
+```json
+{
+  "type": "swift",
+  "style": "powerline",
+  "powerline_symbol": "\uE0B0",
+  "foreground": "#ffffff",
+  "background": "#f6553c",
+  "properties": {
+    "template": " \ue755 {{ .Full }} "
+  }
+}
+```
+
+## Properties
+
+- home_enabled: `boolean` - display the segment in the HOME folder or not - defaults to `false`
+- fetch_version: `boolean` - display the swift version - defaults to `true`
+- display_error: `boolean` - show the error context when failing to retrieve the version information - defaults to `true`
+- missing_command_text: `string` - text to display when the command is missing - defaults to empty
+- display_mode: `string` - determines when the segment is displayed
+  - `always`: the segment is always displayed
+  - `files`: the segment is only displayed when `*.swift` or `*.SWIFT` files are present (default)
+
+## Template ([info][templates])
+
+:::note default template
+
+``` template
+{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}
+```
+
+:::
+
+### Properties
+
+- `.Full`: `string` - the full version
+- `.Major`: `string` - major number
+- `.Minor`: `string` - minor number
+- `.Patch`: `string` - patch number
+- `.Prerelease`: `string` - prerelease info text
+- `.BuildMetadata`: `string` - build metadata
+- `.Error`: `string` - when fetching the version string errors
+
+[templates]: /docs/config-templates
+[swift]: https://www.swift.org/
diff --git a/docs/sidebars.js b/docs/sidebars.js
index d4cbe48a..0f431578 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -77,6 +77,7 @@ module.exports = {
         "shell",
         "spotify",
         "strava",
+        "swift",
         "sysinfo",
         "terraform",
         "text",
diff --git a/src/engine/segment.go b/src/engine/segment.go
index d7314577..de35a834 100644
--- a/src/engine/segment.go
+++ b/src/engine/segment.go
@@ -160,6 +160,8 @@ const (
 	CFTARGET SegmentType = "cftarget"
 	// KOTLIN writes the active kotlin version
 	KOTLIN SegmentType = "kotlin"
+	// SWIFT writes the active swift version
+	SWIFT SegmentType = "swift"
 )
 
 func (segment *Segment) shouldIncludeFolder() bool {
@@ -287,6 +289,7 @@ func (segment *Segment) mapSegmentWithWriter(env environment.Environment) error
 		CF:            &segments.Cf{},
 		CFTARGET:      &segments.CfTarget{},
 		KOTLIN:        &segments.Kotlin{},
+		SWIFT:         &segments.Swift{},
 	}
 	if segment.Properties == nil {
 		segment.Properties = make(properties.Map)
diff --git a/src/segments/swift.go b/src/segments/swift.go
new file mode 100644
index 00000000..ebb99f01
--- /dev/null
+++ b/src/segments/swift.go
@@ -0,0 +1,34 @@
+package segments
+
+import (
+	"oh-my-posh/environment"
+	"oh-my-posh/properties"
+)
+
+type Swift struct {
+	language
+}
+
+func (s *Swift) Template() string {
+	return languageTemplate
+}
+
+func (s *Swift) Init(props properties.Properties, env environment.Environment) {
+	s.language = language{
+		env:        env,
+		props:      props,
+		extensions: []string{"*.swift", "*.SWIFT"},
+		commands: []*cmd{
+			{
+				executable: "swift",
+				args:       []string{"--version"},
+				regex:      `Swift version (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+)((.|-)(?P<patch>[0-9]+|dev))?))`,
+			},
+		},
+		versionURLTemplate: "https://github.com/apple/swift/releases/tag/swift-{{ .Full }}-RELEASE",
+	}
+}
+
+func (s *Swift) Enabled() bool {
+	return s.language.Enabled()
+}
diff --git a/themes/schema.json b/themes/schema.json
index f0a96e42..e8ee56fa 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -197,7 +197,8 @@
             "ipify",
             "haskell",
             "ui5tooling",
-            "kotlin"
+            "kotlin",
+            "swift"
           ]
         },
         "style": {
@@ -2010,6 +2011,32 @@
               }
             }
           }
+        },
+        {
+          "if": {
+            "properties": {
+              "type": { "const": "swift" }
+            }
+          },
+          "then": {
+            "title": "Swift Segment",
+            "description": "https://ohmyposh.dev/docs/swift",
+            "properties": {
+              "properties": {
+                "properties": {
+                  "fetch_version": {
+                    "$ref": "#/definitions/fetch_version"
+                  },
+                  "display_mode": {
+                    "$ref": "#/definitions/display_mode"
+                  },
+                  "missing_command_text": {
+                    "$ref": "#/definitions/missing_command_text"
+                  }
+                }
+              }
+            }
+          }
         }
       ]
     }


Test patch:
diff --git a/src/segments/swift_test.go b/src/segments/swift_test.go
new file mode 100644
index 00000000..948334f3
--- /dev/null
+++ b/src/segments/swift_test.go
@@ -0,0 +1,35 @@
+package segments
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestSwift(t *testing.T) {
+	cases := []struct {
+		Case           string
+		ExpectedString string
+		Version        string
+	}{
+		{Case: "Swift 5.5.3", ExpectedString: "5.5.3", Version: "Swift version 5.5.3 (swift-5.5.3-RELEASE)"},
+		{Case: "Swift 5.5.3 on Windows", ExpectedString: "5.5.3", Version: "compnerd.org Swift version 5.5.3 (swift-5.5.3-RELEASE)"},
+		{Case: "Swift 5.5.3 on Mac", ExpectedString: "5.5.3", Version: "Apple Swift version 5.5.3 (swift-5.5.3-RELEASE)"},
+		{Case: "Swift 5.5", ExpectedString: "5.5", Version: "Swift version 5.5 (swift-5.5-RELEASE)"},
+		{Case: "Swift 5.6-dev", ExpectedString: "5.6-dev", Version: "Swift version 5.6-dev (LLVM 62b900d3d0d5be9, Swift ce64fe8867792d4)"},
+	}
+	for _, tc := range cases {
+		params := &mockedLanguageParams{
+			cmd:           "swift",
+			versionParam:  "--version",
+			versionOutput: tc.Version,
+			extension:     "*.swift",
+		}
+		env, props := getMockedLanguageEnv(params)
+		s := &Swift{}
+		s.Init(props, env)
+		assert.True(t, s.Enabled(), fmt.Sprintf("Failed in case: %s", tc.Case))
+		assert.Equal(t, tc.ExpectedString, renderTemplate(env, s.Template(), s), fmt.Sprintf("Failed in case: %s", tc.Case))
+	}
+}