From 859fd0bbefbba3db0cae9587287ebf49eb14a295 Mon Sep 17 00:00:00 2001 From: Jan De Dobbeleer Date: Wed, 13 Jul 2022 13:53:55 +0200 Subject: [PATCH] feat: add osc7 support resolves #2515 --- src/color/ansi.go | 22 ++++++++++---- src/engine/config.go | 5 +++- src/engine/engine.go | 26 ++++++++++++++--- src/engine/engine_test.go | 39 +++++++++++++++++++++++++ src/engine/image.go | 4 ++- themes/1_shell.omp.json | 1 - themes/atomic.omp.json | 1 - themes/atomicBit.omp.json | 1 - themes/blue-owl.omp.json | 1 - themes/clean-detailed.omp.json | 1 - themes/devious-diamonds.omp.yaml | 1 - themes/grandpa-style.omp.json | 1 - themes/hotstick.minimal.omp.json | 1 - themes/if_tea.omp.json | 1 - themes/jblab_2021.omp.json | 1 - themes/markbull.omp.json | 1 - themes/night-owl.omp.json | 1 - themes/schema.json | 8 ++--- themes/sonicboom_dark.omp.json | 1 - themes/sonicboom_light.omp.json | 1 - themes/stelbent.minimal.omp.json | 1 - themes/takuya.omp.json | 1 - themes/uew.omp.json | 3 +- themes/velvet.omp.json | 1 - website/docs/configuration/overview.mdx | 2 +- 25 files changed, 90 insertions(+), 36 deletions(-) diff --git a/src/color/ansi.go b/src/color/ansi.go index 307a598d..6ceb7cff 100644 --- a/src/color/ansi.go +++ b/src/color/ansi.go @@ -9,6 +9,9 @@ import ( const ( AnsiRegex = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))" + + OSC99 string = "osc99" + OSC7 string = "osc7" ) type Ansi struct { @@ -29,7 +32,7 @@ type Ansi struct { escapeRight string hyperlink string hyperlinkRegex string - osc99 string + pwd string bold string italic string underline string @@ -62,7 +65,7 @@ func (a *Ansi) Init(shellName string) { a.escapeRight = "%}" a.hyperlink = "%%{\x1b]8;;%s\x1b\\%%}%s%%{\x1b]8;;\x1b\\%%}" a.hyperlinkRegex = `(?P%{\x1b]8;;(.+)\x1b\\%}(?P.+)%{\x1b]8;;\x1b\\%})` - a.osc99 = "%%{\x1b]9;9;\"%s\"\x1b\\%%}" + a.pwd = "%%{\x1b]%s;\"%s\"\x1b\\%%}" a.bold = "%%{\x1b[1m%%}%s%%{\x1b[22m%%}" a.italic = "%%{\x1b[3m%%}%s%%{\x1b[23m%%}" a.underline = "%%{\x1b[4m%%}%s%%{\x1b[24m%%}" @@ -89,7 +92,7 @@ func (a *Ansi) Init(shellName string) { a.escapeRight = "\\]" a.hyperlink = "\\[\x1b]8;;%s\x1b\\\\\\]%s\\[\x1b]8;;\x1b\\\\\\]" a.hyperlinkRegex = `(?P\\\[\x1b\]8;;(.+)\x1b\\\\\\\](?P.+)\\\[\x1b\]8;;\x1b\\\\\\\])` - a.osc99 = "\\[\x1b]9;9;\"%s\"\x1b\\\\\\]" + a.pwd = "\\[\x1b]%s;\"%s\"\x1b\\\\\\]" a.bold = "\\[\x1b[1m\\]%s\\[\x1b[22m\\]" a.italic = "\\[\x1b[3m\\]%s\\[\x1b[23m\\]" a.underline = "\\[\x1b[4m\\]%s\\[\x1b[24m\\]" @@ -116,7 +119,7 @@ func (a *Ansi) Init(shellName string) { a.escapeRight = "" a.hyperlink = "\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\" a.hyperlinkRegex = "(?P\x1b]8;;(.+)\x1b\\\\\\\\?(?P.+)\x1b]8;;\x1b\\\\)" - a.osc99 = "\x1b]9;9;\"%s\"\x1b\\" + a.pwd = "\x1b]%s;\"%s\"\x1b\\" a.bold = "\x1b[1m%s\x1b[22m" a.italic = "\x1b[3m%s\x1b[23m" a.underline = "\x1b[4m%s\x1b[24m" @@ -240,11 +243,18 @@ func (a *Ansi) ChangeLine(numberOfLines int) string { return fmt.Sprintf(a.linechange, numberOfLines, position) } -func (a *Ansi) ConsolePwd(pwd string) string { +func (a *Ansi) ConsolePwd(pwdType, pwd string) string { if strings.HasSuffix(pwd, ":") { pwd += "\\" } - return fmt.Sprintf(a.osc99, pwd) + switch pwdType { + case OSC7: + return fmt.Sprintf(a.pwd, "7", pwd) + case OSC99: + fallthrough + default: + return fmt.Sprintf(a.pwd, "9;9", pwd) + } } func (a *Ansi) ClearAfter() string { diff --git a/src/engine/config.go b/src/engine/config.go index 76275073..aef61da4 100644 --- a/src/engine/config.go +++ b/src/engine/config.go @@ -32,7 +32,6 @@ const ( type Config struct { Version int `json:"version"` FinalSpace bool `json:"final_space,omitempty"` - OSC99 bool `json:"osc99,omitempty"` ConsoleTitleTemplate string `json:"console_title_template,omitempty"` TerminalBackground string `json:"terminal_background,omitempty"` AccentColor string `json:"accent_color,omitempty"` @@ -44,6 +43,10 @@ type Config struct { SecondaryPrompt *Segment `json:"secondary_prompt,omitempty"` DebugPrompt *Segment `json:"debug_prompt,omitempty"` Palette color.Palette `json:"palette,omitempty"` + PWD string `json:"pwd,omitempty"` + + // Deprecated + OSC99 bool `json:"osc99,omitempty"` Output string `json:"-"` diff --git a/src/engine/engine.go b/src/engine/engine.go index ea98a316..19cba427 100644 --- a/src/engine/engine.go +++ b/src/engine/engine.go @@ -74,12 +74,30 @@ func (e *Engine) PrintPrimary() string { if e.Config.FinalSpace { e.write(" ") } - if !e.Config.OSC99 { - return e.print() + e.printPWD() + return e.print() +} + +func (e *Engine) printPWD() { + if len(e.Config.PWD) == 0 && !e.Config.OSC99 { + return } cwd := e.Env.Pwd() - e.writeANSI(e.Ansi.ConsolePwd(cwd)) - return e.print() + // Backwards compatibility for deprecated OSC99 + if e.Config.OSC99 { + e.writeANSI(e.Ansi.ConsolePwd(color.OSC99, cwd)) + return + } + // Allow template logic to define when to enable the PWD (when supported) + tmpl := &template.Text{ + Template: e.Config.PWD, + Env: e.Env, + } + pwdType, err := tmpl.Render() + if err != nil || len(pwdType) == 0 { + return + } + e.writeANSI(e.Ansi.ConsolePwd(pwdType, cwd)) } func (e *Engine) newline() { diff --git a/src/engine/engine_test.go b/src/engine/engine_test.go index 710c21fa..9a230778 100644 --- a/src/engine/engine_test.go +++ b/src/engine/engine_test.go @@ -44,6 +44,45 @@ func TestCanWriteRPrompt(t *testing.T) { } } +func TestPrintPWD(t *testing.T) { + cases := []struct { + Case string + Expected string + PWD string + OSC99 bool + }{ + {Case: "Empty PWD"}, + {Case: "OSC99", PWD: color.OSC99, Expected: "\x1b]9;9;\"pwd\"\x1b\\"}, + {Case: "OSC7", PWD: color.OSC7, Expected: "\x1b]7;\"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;\"pwd\"\x1b\\"}, + } + + for _, tc := range cases { + env := new(mock.MockedEnvironment) + env.On("Pwd").Return("pwd") + env.On("Shell").Return("shell") + env.On("TemplateCache").Return(&environment.TemplateCache{ + Env: make(map[string]string), + Shell: "shell", + }) + ansi := &color.Ansi{} + ansi.InitPlain() + engine := &Engine{ + Env: env, + Config: &Config{ + PWD: tc.PWD, + OSC99: tc.OSC99, + }, + Ansi: ansi, + } + engine.printPWD() + got := engine.print() + assert.Equal(t, tc.Expected, got, tc.Case) + } +} + func BenchmarkEngineRender(b *testing.B) { for i := 0; i < b.N; i++ { engineRender() diff --git a/src/engine/image.go b/src/engine/image.go index b86f7995..45e22767 100644 --- a/src/engine/image.go +++ b/src/engine/image.go @@ -69,6 +69,7 @@ const ( color16 = "color16" left = "left" osc99 = "osc99" + osc7 = "osc7" lineChange = "linechange" consoleTitle = "title" link = "link" @@ -195,6 +196,7 @@ func (ir *ImageRenderer) Init(config string) { color16: `^(?P\x1b\[(?P[349][0-7]|10[0-7]|39)m)`, left: `^(?P\x1b\[(\d{1,3})D)`, osc99: `^(?P\x1b\]9;9;(.+)\x1b\\)`, + osc7: `^(?P\x1b\]7;(.+)\x1b\\)`, lineChange: `^(?P\x1b\[(\d)[FB])`, consoleTitle: `^(?P\x1b\]0;(.+)\007)`, link: fmt.Sprintf(`^%s`, regex.LINK), @@ -502,7 +504,7 @@ func (ir *ImageRenderer) shouldPrint() bool { case boldReset, italicReset, underlineReset, overlineReset: ir.style = "" return false - case strikethrough, strikethroughReset, left, osc99, lineChange, consoleTitle: + case strikethrough, strikethroughReset, left, osc99, osc7, lineChange, consoleTitle: return false case color16: ir.setBase16Color(match[bc]) diff --git a/themes/1_shell.omp.json b/themes/1_shell.omp.json index 1f6bf10e..069084ce 100644 --- a/themes/1_shell.omp.json +++ b/themes/1_shell.omp.json @@ -116,7 +116,6 @@ } ], "console_title_template": "{{ .Folder }}", - "osc99": true, "transient_prompt": { "background": "transparent", "foreground": "#FEF5ED", diff --git a/themes/atomic.omp.json b/themes/atomic.omp.json index ad45fe62..13494645 100644 --- a/themes/atomic.omp.json +++ b/themes/atomic.omp.json @@ -272,6 +272,5 @@ "type": "prompt" } ], - "osc99": true, "version": 2 } diff --git a/themes/atomicBit.omp.json b/themes/atomicBit.omp.json index ec13de68..739a30ca 100644 --- a/themes/atomicBit.omp.json +++ b/themes/atomicBit.omp.json @@ -189,6 +189,5 @@ "type": "prompt" } ], - "osc99": true, "version": 2 } diff --git a/themes/blue-owl.omp.json b/themes/blue-owl.omp.json index 578de71f..94fc1617 100644 --- a/themes/blue-owl.omp.json +++ b/themes/blue-owl.omp.json @@ -120,6 +120,5 @@ } ], "console_title_template": "{{if .Root}} \u26a1 {{end}}{{.Folder | replace \"~\" \"🏚\" }} @ {{.HostName}}", - "osc99": true, "version": 2 } diff --git a/themes/clean-detailed.omp.json b/themes/clean-detailed.omp.json index 1f0dada7..fe0012b8 100644 --- a/themes/clean-detailed.omp.json +++ b/themes/clean-detailed.omp.json @@ -134,7 +134,6 @@ } ], "console_title_template": "{{ .Folder }}", - "osc99": true, "transient_prompt": { "background": "transparent", "foreground": "#FEF5ED", diff --git a/themes/devious-diamonds.omp.yaml b/themes/devious-diamonds.omp.yaml index bc15a9a2..0040feef 100644 --- a/themes/devious-diamonds.omp.yaml +++ b/themes/devious-diamonds.omp.yaml @@ -218,7 +218,6 @@ blocks: root_icon:  template: "{{ if and .Root ( not .Segments.Path.Writable ) }} {{ end }}{{ if and .Root .Segments.Path.Writable }}  {{ end }} \b" console_title_template: "{{ .Folder }}" -osc99: true palette: black: "#1B1A23" blue: "#9580FF" diff --git a/themes/grandpa-style.omp.json b/themes/grandpa-style.omp.json index 842615d7..e04de502 100644 --- a/themes/grandpa-style.omp.json +++ b/themes/grandpa-style.omp.json @@ -120,6 +120,5 @@ } ], "console_title_template": "{{if .Root}} \u26a1 {{end}}{{.Folder | replace \"~\" \"🏚\" }} @ {{.HostName}}", - "osc99": true, "version": 2 } diff --git a/themes/hotstick.minimal.omp.json b/themes/hotstick.minimal.omp.json index 8c92a6e2..faea5dba 100644 --- a/themes/hotstick.minimal.omp.json +++ b/themes/hotstick.minimal.omp.json @@ -53,6 +53,5 @@ ], "console_title_template": "{{.Folder}}{{if .Root}} :: root{{end}} :: {{.Shell}}", "final_space": true, - "osc99": true, "version": 2 } diff --git a/themes/if_tea.omp.json b/themes/if_tea.omp.json index 679b9591..781bd3ce 100644 --- a/themes/if_tea.omp.json +++ b/themes/if_tea.omp.json @@ -166,7 +166,6 @@ "console_title_style": "template", "console_title_template": "{{ .Folder }}", - "osc99": true, "transient_prompt": { "background": "transparent", "foreground": "#FEF5ED", diff --git a/themes/jblab_2021.omp.json b/themes/jblab_2021.omp.json index aea93f71..071be516 100644 --- a/themes/jblab_2021.omp.json +++ b/themes/jblab_2021.omp.json @@ -96,6 +96,5 @@ ], "console_title_template": "{{if .Root}} \u26a1 {{end}}{{.Folder | replace \"~\" \"🏠\"}} @ {{.HostName}}", "final_space": true, - "osc99": true, "version": 2 } diff --git a/themes/markbull.omp.json b/themes/markbull.omp.json index 57285862..5014b51f 100644 --- a/themes/markbull.omp.json +++ b/themes/markbull.omp.json @@ -115,6 +115,5 @@ ], "console_title_template": "{{if .Root}}\u26a1 {{end}}{{.Folder}}", "final_space": true, - "osc99": true, "version": 2 } diff --git a/themes/night-owl.omp.json b/themes/night-owl.omp.json index 0c5f79d4..a832a62e 100644 --- a/themes/night-owl.omp.json +++ b/themes/night-owl.omp.json @@ -291,7 +291,6 @@ } ], "console_title_template": "{{ .Folder }}", - "osc99": true, "transient_prompt": { "background": "transparent", "foreground": "#d6deeb", diff --git a/themes/schema.json b/themes/schema.json index be09740a..de25111c 100644 --- a/themes/schema.json +++ b/themes/schema.json @@ -2601,11 +2601,11 @@ "description": "https://ohmyposh.dev/docs/configuration/overview#general-settings", "default": true }, - "osc99": { - "type": "boolean", - "title": "Enable OSC99", + "pwd": { + "type": "string", + "title": "Enable OSC99/7", "description": "https://ohmyposh.dev/docs/configuration/overview#general-settings", - "default": false + "default": "" }, "console_title_template": { "type": "string", diff --git a/themes/sonicboom_dark.omp.json b/themes/sonicboom_dark.omp.json index a35347b8..5c15215d 100644 --- a/themes/sonicboom_dark.omp.json +++ b/themes/sonicboom_dark.omp.json @@ -121,6 +121,5 @@ } ], "final_space": true, - "osc99": true, "version": 2 } diff --git a/themes/sonicboom_light.omp.json b/themes/sonicboom_light.omp.json index f2a98a8b..63c4718a 100644 --- a/themes/sonicboom_light.omp.json +++ b/themes/sonicboom_light.omp.json @@ -121,6 +121,5 @@ } ], "final_space": true, - "osc99": true, "version": 2 } diff --git a/themes/stelbent.minimal.omp.json b/themes/stelbent.minimal.omp.json index 454cbfce..ca37761a 100644 --- a/themes/stelbent.minimal.omp.json +++ b/themes/stelbent.minimal.omp.json @@ -118,6 +118,5 @@ } ], "final_space": true, - "osc99": true, "version": 2 } diff --git a/themes/takuya.omp.json b/themes/takuya.omp.json index 0e01fee0..948fb1cc 100644 --- a/themes/takuya.omp.json +++ b/themes/takuya.omp.json @@ -111,6 +111,5 @@ "type": "prompt" } ], - "osc99": true, "version": 2 } diff --git a/themes/uew.omp.json b/themes/uew.omp.json index 4477236d..8d125e8c 100644 --- a/themes/uew.omp.json +++ b/themes/uew.omp.json @@ -116,11 +116,10 @@ } ], "console_title_template": "{{ .Folder }}", - "osc99": true, "transient_prompt": { "background": "transparent", "foreground": "#FEF5ED", "template": "\ue285 " }, "version": 2 - } \ No newline at end of file + } diff --git a/themes/velvet.omp.json b/themes/velvet.omp.json index 3e39eb14..8188071b 100644 --- a/themes/velvet.omp.json +++ b/themes/velvet.omp.json @@ -166,6 +166,5 @@ ], "console_title_template": "{{ .Shell }} - {{ .Folder }}", "final_space": true, - "osc99": true, "version": 2 } diff --git a/website/docs/configuration/overview.mdx b/website/docs/configuration/overview.mdx index 84a9e8d0..4bc39123 100644 --- a/website/docs/configuration/overview.mdx +++ b/website/docs/configuration/overview.mdx @@ -124,7 +124,7 @@ For example, the following is a valid `--config` flag: ## General Settings - final_space: `boolean` - when true adds a space at the end of the prompt -- osc99: `boolean` - when true adds support for OSC9;9; (notify terminal of current working directory) +- pwd: `string` - notify terminal of current working directory, values can be `osc99` or `osc7` 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