fix: measure hyperlinks correctly

This commit is contained in:
Jan De Dobbeleer 2022-04-03 20:38:02 +02:00 committed by Jan De Dobbeleer
parent 8db4d47e45
commit ba94d5b584
4 changed files with 60 additions and 8 deletions

View file

@ -67,7 +67,7 @@ func (a *Ansi) Init(shellName string) {
a.escapeLeft = "%{"
a.escapeRight = "%}"
a.hyperlink = "%%{\x1b]8;;%s\x1b\\\\%%}%s%%{\x1b]8;;\x1b\\\\%%}"
a.hyperlinkRegex = `(?P<STR>\x1b]8;;(.+)\x1b\\\\(?P<TEXT>.+)\x1b]8;;\x1b\\\\)`
a.hyperlinkRegex = `(?P<STR>%{\x1b]8;;(.+)\x1b\\\\%}(?P<TEXT>.+)%{\x1b]8;;\x1b\\\\%})`
a.osc99 = "%%{\x1b]9;9;\"%s\"\x1b\\%%}"
a.bold = "%%{\x1b[1m%%}%s%%{\x1b[22m%%}"
a.italic = "%%{\x1b[3m%%}%s%%{\x1b[23m%%}"
@ -93,7 +93,7 @@ func (a *Ansi) Init(shellName string) {
a.escapeLeft = "\\["
a.escapeRight = "\\]"
a.hyperlink = "\\[\x1b]8;;%s\x1b\\\\\\]%s\\[\x1b]8;;\x1b\\\\\\]"
a.hyperlinkRegex = `(?P<STR>\x1b]8;;(.+)\x1b\\\\(?P<TEXT>.+)\x1b]8;;\x1b\\\\)`
a.hyperlinkRegex = `(?P<STR>\\\[\x1b\]8;;(.+)\x1b\\\\\\\](?P<TEXT>.+)\\\[\x1b\]8;;\x1b\\\\\\\])`
a.osc99 = "\\[\x1b]9;9;\"%s\"\x1b\\\\\\]"
a.bold = "\\[\x1b[1m\\]%s\\[\x1b[22m\\]"
a.italic = "\\[\x1b[3m\\]%s\\[\x1b[23m\\]"
@ -119,7 +119,9 @@ func (a *Ansi) Init(shellName string) {
a.escapeLeft = ""
a.escapeRight = ""
a.hyperlink = "\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\"
a.hyperlinkRegex = `(?P<STR>\x1b]8;;(.+)\x1b\\(?P<TEXT>.+)\x1b]8;;\x1b\\)`
// a.hyperlinkRegex = "(?P<STR>\x1b]8;;(.+)\x1b\\(?P<TEXT>.+)\x1b]8;;\x1b\\)"
// \x1b]8;;https://ohmyposh.dev\x1b\\link\x1b]8;;\x1b\\
a.hyperlinkRegex = "(?P<STR>\x1b]8;;(.+)\x1b\\\\\\\\?(?P<TEXT>.+)\x1b]8;;\x1b\\\\)"
a.osc99 = "\x1b]9;9;\"%s\"\x1b\\"
a.bold = "\x1b[1m%s\x1b[22m"
a.italic = "\x1b[3m%s\x1b[23m"
@ -224,7 +226,7 @@ func (a *Ansi) initEscapeSequences(shellName string) {
}
}
func (a *Ansi) generateHyperlink(text string) string {
func (a *Ansi) GenerateHyperlink(text string) string {
// hyperlink matching
results := regex.FindNamedRegexMatch("(?P<all>(?:\\[(?P<name>.+)\\])(?:\\((?P<url>.*)\\)))", text)
if len(results) != 3 {

View file

@ -20,7 +20,7 @@ func TestGenerateHyperlinkNoUrl(t *testing.T) {
for _, tc := range cases {
a := Ansi{}
a.Init(tc.ShellName)
hyperlinkText := a.generateHyperlink(tc.Text)
hyperlinkText := a.GenerateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText)
}
}
@ -38,7 +38,7 @@ func TestGenerateHyperlinkWithUrl(t *testing.T) {
for _, tc := range cases {
a := Ansi{}
a.Init(tc.ShellName)
hyperlinkText := a.generateHyperlink(tc.Text)
hyperlinkText := a.GenerateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText)
}
}
@ -56,7 +56,7 @@ func TestGenerateHyperlinkWithUrlNoName(t *testing.T) {
for _, tc := range cases {
a := Ansi{}
a.Init(tc.ShellName)
hyperlinkText := a.generateHyperlink(tc.Text)
hyperlinkText := a.GenerateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText)
}
}

50
src/color/text_test.go Normal file
View file

@ -0,0 +1,50 @@
package color
import (
"fmt"
"oh-my-posh/environment"
"oh-my-posh/mock"
"oh-my-posh/shell"
"oh-my-posh/template"
"testing"
"github.com/stretchr/testify/assert"
)
func TestMeasureText(t *testing.T) {
cases := []struct {
Case string
Template string
Expected int
}{
{
Case: "Simple text",
Template: "src",
Expected: 3,
},
{
Case: "Hyperlink",
Template: `{{ url "link" "https://ohmyposh.dev" }}`,
Expected: 4,
},
}
env := new(mock.MockedEnvironment)
env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string),
})
shells := []string{shell.BASH, shell.ZSH, shell.PLAIN}
for _, shell := range shells {
for _, tc := range cases {
ansi := &Ansi{}
ansi.Init(shell)
tmpl := &template.Text{
Template: tc.Template,
Env: env,
}
text, _ := tmpl.Render()
text = ansi.GenerateHyperlink(text)
got := ansi.MeasureText(text)
assert.Equal(t, tc.Expected, got, fmt.Sprintf("%s: %s", shell, tc.Case))
}
}
}

View file

@ -141,7 +141,7 @@ func (a *AnsiWriter) Write(background, foreground, text string) {
bgAnsi, fgAnsi := a.asAnsiColors(background, foreground)
text = a.Ansi.formatText(text)
text = a.Ansi.generateHyperlink(text)
text = a.Ansi.GenerateHyperlink(text)
text = a.Ansi.EscapeText(text)
// first we match for any potentially valid colors enclosed in <>