Repository: JanDeDobbeleer/oh-my-posh
Pull request #3130 (2022-11-27 05:57:04)

feat: add osc51 support
OSC 51 is the working directory OSC for emacs-libvterm

It additionally wants the username, so support for passing that to the template was added.

### 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

This adds yet another OSC for path detection; this one is for [emacs-libvterm](https://github.com/akermu/emacs-libvterm#directory-tracking-and-prompt-tracking).

I mostly copied what I found for existing OSC support, with the addition that OSC 51 also wants the username. It seemed relatively straightforward, but please let me know if I should adjust anything.

Tests pass, and I tried it out to verify that it works before making the PR.

<!--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.

-->

[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/color/ansi.go b/src/color/ansi.go
index 0b3e45d3..f183a417 100644
--- a/src/color/ansi.go
+++ b/src/color/ansi.go
@@ -12,6 +12,7 @@ const (
 
 	OSC99 string = "osc99"
 	OSC7  string = "osc7"
+	OSC51 string = "osc51"
 )
 
 type Ansi struct {
@@ -34,6 +35,7 @@ type Ansi struct {
 	hyperlinkRegex        string
 	osc99                 string
 	osc7                  string
+	osc51                 string
 	bold                  string
 	italic                string
 	underline             string
@@ -68,6 +70,7 @@ func (a *Ansi) Init(shellName string) {
 		a.hyperlinkRegex = `(?P<STR>%{\x1b]8;;(.+)\x1b\\%}(?P<TEXT>.+)%{\x1b]8;;\x1b\\%})`
 		a.osc99 = "%%{\x1b]9;9;\"%s\"\x1b\\%%}"
 		a.osc7 = "%%{\x1b]7;file:\"//%s/%s\"\x1b\\%%}"
+		a.osc51 = "%%{\x1b]51;A%s@%s:%s\x1b\\%%}"
 		a.bold = "%%{\x1b[1m%%}%s%%{\x1b[22m%%}"
 		a.italic = "%%{\x1b[3m%%}%s%%{\x1b[23m%%}"
 		a.underline = "%%{\x1b[4m%%}%s%%{\x1b[24m%%}"
@@ -96,6 +99,7 @@ func (a *Ansi) Init(shellName string) {
 		a.hyperlinkRegex = `(?P<STR>\\\[\x1b\]8;;(.+)\x1b\\\\\\\](?P<TEXT>.+)\\\[\x1b\]8;;\x1b\\\\\\\])`
 		a.osc99 = "\\[\x1b]9;9;\"%s\"\x1b\\\\\\]"
 		a.osc7 = "\\[\x1b]7;\"file://%s/%s\"\x1b\\\\\\]"
+		a.osc51 = "\\[\x1b]51;A;%s@%s:%s\x1b\\\\\\]"
 		a.bold = "\\[\x1b[1m\\]%s\\[\x1b[22m\\]"
 		a.italic = "\\[\x1b[3m\\]%s\\[\x1b[23m\\]"
 		a.underline = "\\[\x1b[4m\\]%s\\[\x1b[24m\\]"
@@ -124,6 +128,7 @@ func (a *Ansi) Init(shellName string) {
 		a.hyperlinkRegex = "(?P<STR>\x1b]8;;(.+)\x1b\\\\\\\\?(?P<TEXT>.+)\x1b]8;;\x1b\\\\)"
 		a.osc99 = "\x1b]9;9;\"%s\"\x1b\\"
 		a.osc7 = "\x1b]7;\"file://%s/%s\"\x1b\\"
+		a.osc51 = "\x1b]51;A%s@%s:%s\x1b\\"
 		a.bold = "\x1b[1m%s\x1b[22m"
 		a.italic = "\x1b[3m%s\x1b[23m"
 		a.underline = "\x1b[4m%s\x1b[24m"
@@ -303,13 +308,15 @@ func (a *Ansi) ChangeLine(numberOfLines int) string {
 	return fmt.Sprintf(a.linechange, numberOfLines, position)
 }
 
-func (a *Ansi) ConsolePwd(pwdType, hostName, pwd string) string {
+func (a *Ansi) ConsolePwd(pwdType, userName, hostName, pwd string) string {
 	if strings.HasSuffix(pwd, ":") {
 		pwd += "\\"
 	}
 	switch pwdType {
 	case OSC7:
 		return fmt.Sprintf(a.osc7, hostName, pwd)
+	case OSC51:
+		return fmt.Sprintf(a.osc51, userName, hostName, pwd)
 	case OSC99:
 		fallthrough
 	default:
diff --git a/src/engine/engine.go b/src/engine/engine.go
index 06a4bc6a..dc46a81d 100644
--- a/src/engine/engine.go
+++ b/src/engine/engine.go
@@ -85,7 +85,7 @@ func (e *Engine) printPWD() {
 	cwd := e.Env.Pwd()
 	// Backwards compatibility for deprecated OSC99
 	if e.Config.OSC99 {
-		e.writeANSI(e.Ansi.ConsolePwd(color.OSC99, "", cwd))
+		e.writeANSI(e.Ansi.ConsolePwd(color.OSC99, "", "", cwd))
 		return
 	}
 	// Allow template logic to define when to enable the PWD (when supported)
@@ -97,8 +97,9 @@ func (e *Engine) printPWD() {
 	if err != nil || len(pwdType) == 0 {
 		return
 	}
+	user := e.Env.User()
 	host, _ := e.Env.Host()
-	e.writeANSI(e.Ansi.ConsolePwd(pwdType, host, cwd))
+	e.writeANSI(e.Ansi.ConsolePwd(pwdType, user, host, cwd))
 }
 
 func (e *Engine) newline() {
diff --git a/src/engine/image.go b/src/engine/image.go
index 45e22767..795e2edb 100644
--- a/src/engine/image.go
+++ b/src/engine/image.go
@@ -70,6 +70,7 @@ const (
 	left                = "left"
 	osc99               = "osc99"
 	osc7                = "osc7"
+	osc51               = "osc51"
 	lineChange          = "linechange"
 	consoleTitle        = "title"
 	link                = "link"
@@ -197,6 +198,7 @@ func (ir *ImageRenderer) Init(config string) {
 		left:                `^(?P<STR>\x1b\[(\d{1,3})D)`,
 		osc99:               `^(?P<STR>\x1b\]9;9;(.+)\x1b\\)`,
 		osc7:                `^(?P<STR>\x1b\]7;(.+)\x1b\\)`,
+		osc51:               `^(?P<STR>\x1b\]51;A(.+)\x1b\\)`,
 		lineChange:          `^(?P<STR>\x1b\[(\d)[FB])`,
 		consoleTitle:        `^(?P<STR>\x1b\]0;(.+)\007)`,
 		link:                fmt.Sprintf(`^%s`, regex.LINK),
@@ -504,7 +506,7 @@ func (ir *ImageRenderer) shouldPrint() bool {
 		case boldReset, italicReset, underlineReset, overlineReset:
 			ir.style = ""
 			return false
-		case strikethrough, strikethroughReset, left, osc99, osc7, lineChange, consoleTitle:
+		case strikethrough, strikethroughReset, left, osc99, osc7, osc51, lineChange, consoleTitle:
 			return false
 		case color16:
 			ir.setBase16Color(match[bc])
diff --git a/themes/schema.json b/themes/schema.json
index 1bb7b16c..63cf7e03 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -2869,7 +2869,7 @@
     },
     "pwd": {
       "type": "string",
-      "title": "Enable OSC99/7",
+      "title": "Enable OSC99/7/51",
       "description": "https://ohmyposh.dev/docs/configuration/overview#general-settings",
       "default": ""
     },
diff --git a/website/docs/configuration/overview.mdx b/website/docs/configuration/overview.mdx
index c68b8e8b..f6074c0e 100644
--- a/website/docs/configuration/overview.mdx
+++ b/website/docs/configuration/overview.mdx
@@ -129,7 +129,7 @@ For example, the following is a valid `--config` flag:
 | Name                  | Type      | Description                                                                                                                                                                           |
 | --------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | `final_space`         | `boolean` | when true adds a space at the end of the prompt                                                                                                                                       |
-| `pwd`                 | `string`  | notify terminal of current working directory, values can be `osc99` or `osc7` depending on your terminal                                                                              |
+| `pwd`                 | `string`  | notify terminal of current working directory, values can be `osc99`, `osc7`, or `osc51` depending on your terminal                                                                    |
 | `terminal_background` | `string`  | [color][colors] - terminal background color, set to your terminal's background color when you notice black elements in Windows Terminal or the Visual Studio Code integrated terminal |
 | `accent_color`        | `string`  | [color][colors] - accent color, used as a fallback when the `accent` [color][accent] is not supported                                                                                 |
 


Test patch:
diff --git a/src/engine/engine_test.go b/src/engine/engine_test.go
index 54c7f5e9..bd4e5434 100644
--- a/src/engine/engine_test.go
+++ b/src/engine/engine_test.go
@@ -54,6 +54,7 @@ func TestPrintPWD(t *testing.T) {
 		{Case: "Empty PWD"},
 		{Case: "OSC99", PWD: color.OSC99, Expected: "\x1b]9;9;\"pwd\"\x1b\\"},
 		{Case: "OSC7", PWD: color.OSC7, Expected: "\x1b]7;\"file://host/pwd\"\x1b\\"},
+		{Case: "OSC51", PWD: color.OSC51, Expected: "\x1b]51;Auser@host:pwd\x1b\\"},
 		{Case: "Deprecated OSC99", OSC99: true, Expected: "\x1b]9;9;\"pwd\"\x1b\\"},
 		{Case: "Template (empty)", PWD: "{{ if eq .Shell \"pwsh\" }}osc7{{ end }}"},
 		{Case: "Template (non empty)", PWD: "{{ if eq .Shell \"shell\" }}osc7{{ end }}", Expected: "\x1b]7;\"file://host/pwd\"\x1b\\"},
@@ -63,6 +64,7 @@ func TestPrintPWD(t *testing.T) {
 		env := new(mock.MockedEnvironment)
 		env.On("Pwd").Return("pwd")
 		env.On("Shell").Return("shell")
+		env.On("User").Return("user")
 		env.On("Host").Return("host", nil)
 		env.On("TemplateCache").Return(&platform.TemplateCache{
 			Env:   make(map[string]string),