Repository: JanDeDobbeleer/oh-my-posh
Pull request #1730 (2022-02-09 08:40:21)

wednesday issue time
### 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

<!--TemplateBody-->

<!---

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.

-->

[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary



Patch:
diff --git a/docs/docs/config-transient.mdx b/docs/docs/config-transient.mdx
index 86b2f738..98ba8084 100644
--- a/docs/docs/config-transient.mdx
+++ b/docs/docs/config-transient.mdx
@@ -73,12 +73,19 @@ properties below - defaults to `{{ .Shell }}> `
 <TabItem value="pwsh">
 
 
-Import/invoke Oh My Posh in your `$PROFILE` and add the following line below:
+Invoke Oh My Posh in your `$PROFILE` and add the following line below.
 
 ```powershell
+oh-my-posh --init --shell pwsh --config $env:POSH_THEMES_PATH/jandedobbeleer.omp.json | Invoke-Expression
+// highlight-start
 Enable-PoshTransientPrompt
+// highlight-end
 ```
 
+:::caution
+If you import **PSReadLine** separately, make sure to import it before the `Enable-PoshTransientPrompt` command.
+:::
+
 Restart your shell or reload your `$PROFILE` using `. $PROFILE` for the changes to take effect.
 
 </TabItem>
diff --git a/docs/docs/segment-path.md b/docs/docs/segment-path.md
index fd32ab5e..dfe8b5d4 100644
--- a/docs/docs/segment-path.md
+++ b/docs/docs/segment-path.md
@@ -78,6 +78,7 @@ Style sets the way the path is displayed. Based on previous experience and popul
 - folder
 - mixed
 - letter
+- unique
 
 ### Agnoster
 
@@ -121,6 +122,10 @@ starts with a symbol or icon.
 - `__pycache__` will be shortened to `__p`
 - `➼ folder` will be shortened to `➼ f`
 
+### Unique
+
+Works like `Letter`, but will make sure every folder name is the shortest unique value.
+
 ## Template ([info][templates])
 
 :::note default template
diff --git a/src/segments/path.go b/src/segments/path.go
index 9fce4f86..956e2f19 100644
--- a/src/segments/path.go
+++ b/src/segments/path.go
@@ -44,6 +44,8 @@ const (
 	Mixed string = "mixed"
 	// Letter like agnoster, but with the first letter of each folder name
 	Letter string = "letter"
+	// Unique like agnoster, but with the first unique letters of each folder name
+	Unique string = "unique"
 	// AgnosterLeft like agnoster, but keeps the left side of the path
 	AgnosterLeft string = "agnoster_left"
 	// MixedThreshold the threshold of the length of the path Mixed will display
@@ -73,6 +75,8 @@ func (pt *Path) Enabled() bool {
 		pt.Path = pt.getMixedPath()
 	case Letter:
 		pt.Path = pt.getLetterPath()
+	case Unique:
+		pt.Path = pt.getUniqueLettersPath()
 	case AgnosterLeft:
 		pt.Path = pt.getAgnosterLeftPath()
 	case Short:
@@ -171,6 +175,19 @@ func (pt *Path) getAgnosterLeftPath() string {
 	return buffer.String()
 }
 
+func (pt *Path) getRelevantLetter(folder string) string {
+	// check if there is at least a letter we can use
+	matches := regex.FindNamedRegexMatch(`(?P<letter>[\p{L}0-9]).*`, folder)
+	if matches == nil || matches["letter"] == "" {
+		// no letter found, keep the folder unchanged
+		return folder
+	}
+	letter := matches["letter"]
+	// handle non-letter characters before the first found letter
+	letter = folder[0:strings.Index(folder, letter)] + letter
+	return letter
+}
+
 func (pt *Path) getLetterPath() string {
 	var buffer strings.Builder
 	pwd := pt.getPwd()
@@ -181,20 +198,34 @@ func (pt *Path) getLetterPath() string {
 		if len(folder) == 0 {
 			continue
 		}
+		letter := pt.getRelevantLetter(folder)
+		buffer.WriteString(fmt.Sprintf("%s%s", letter, separator))
+	}
+	if len(splitted) > 0 {
+		buffer.WriteString(splitted[len(splitted)-1])
+	}
+	return buffer.String()
+}
 
-		// check if there is at least a letter we can use
-		matches := regex.FindNamedRegexMatch(`(?P<letter>[\p{L}0-9]).*`, folder)
-
-		if matches == nil || matches["letter"] == "" {
-			// no letter found, keep the folder unchanged
-			buffer.WriteString(fmt.Sprintf("%s%s", folder, separator))
+func (pt *Path) getUniqueLettersPath() string {
+	var buffer strings.Builder
+	pwd := pt.getPwd()
+	splitted := strings.Split(pwd, pt.env.PathSeperator())
+	separator := pt.props.GetString(FolderSeparatorIcon, pt.env.PathSeperator())
+	letters := make(map[string]bool, len(splitted))
+	for i := 0; i < len(splitted)-1; i++ {
+		folder := splitted[i]
+		if len(folder) == 0 {
 			continue
 		}
-
-		letter := matches["letter"]
-		// handle non-letter characters before the first found letter
-		letter = folder[0:strings.Index(folder, letter)] + letter
-
+		letter := pt.getRelevantLetter(folder)
+		for letters[letter] {
+			if letter == folder {
+				break
+			}
+			letter += folder[len(letter) : len(letter)+1]
+		}
+		letters[letter] = true
 		buffer.WriteString(fmt.Sprintf("%s%s", letter, separator))
 	}
 	if len(splitted) > 0 {
diff --git a/themes/schema.json b/themes/schema.json
index d5005d46..f6d37ff4 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -1114,7 +1114,8 @@
                       "full",
                       "folder",
                       "mixed",
-                      "letter"
+                      "letter",
+                      "unique"
                     ],
                     "default": "folder"
                   },


Test patch:
diff --git a/src/segments/path_test.go b/src/segments/path_test.go
index 50484140..bcdf33cc 100644
--- a/src/segments/path_test.go
+++ b/src/segments/path_test.go
@@ -238,6 +238,10 @@ func TestAgnosterPathStyles(t *testing.T) {
 		{Style: Letter, Expected: "u > .b > __p > .w > man", HomePath: "/usr/home", Pwd: "/usr/.burp/__pycache__/.whatever/man", PathSeperator: "/", FolderSeparatorIcon: " > "},
 		{Style: Letter, Expected: "➼ > .w > man", HomePath: "/usr/home", Pwd: "➼/.whatever/man", PathSeperator: "/", FolderSeparatorIcon: " > "},
 		{Style: Letter, Expected: "➼ s > .w > man", HomePath: "/usr/home", Pwd: "➼ something/.whatever/man", PathSeperator: "/", FolderSeparatorIcon: " > "},
+
+		{Style: Unique, Expected: "~ > a > ab > abcd", HomePath: "/usr/home", Pwd: "/usr/home/ab/abc/abcd", PathSeperator: "/", FolderSeparatorIcon: " > "},
+		{Style: Unique, Expected: "~ > a > .a > abcd", HomePath: "/usr/home", Pwd: "/usr/home/ab/.abc/abcd", PathSeperator: "/", FolderSeparatorIcon: " > "},
+		{Style: Unique, Expected: "~ > a > ab > abcd", HomePath: "/usr/home", Pwd: "/usr/home/ab/ab/abcd", PathSeperator: "/", FolderSeparatorIcon: " > "},
 	}
 	for _, tc := range cases {
 		env := new(mock.MockedEnvironment)