fix(hyperlink): parse links correctly

resolves #3082
This commit is contained in:
Jan De Dobbeleer 2022-11-15 21:11:29 +01:00 committed by Jan De Dobbeleer
parent 0ae2725481
commit f1e699f5b3
2 changed files with 74 additions and 16 deletions

View file

@ -140,20 +140,59 @@ func (a *Ansi) InitPlain() {
}
func (a *Ansi) GenerateHyperlink(text string) string {
parts := strings.SplitAfter(text, ")")
var buffer strings.Builder
var part string
for i := range parts {
part += parts[i]
if strings.Contains(parts[i], "[") && !strings.Contains(parts[i], "]") {
const (
LINK = "link"
TEXT = "text"
OTHER = "plain"
)
var result, hyperlink strings.Builder
var squareIndex, roundCount int
state := OTHER
for i, s := range text {
if s == '[' && state == OTHER {
state = TEXT
hyperlink.WriteRune(s)
continue
}
buffer.WriteString(a.replaceHyperlink(part))
part = ""
if state == OTHER {
result.WriteRune(s)
continue
}
hyperlink.WriteRune(s)
switch s {
case ']':
// potential end of text part of hyperlink
squareIndex = i
case '(':
// split into link part
if squareIndex == i-1 {
state = LINK
}
if state == LINK {
roundCount++
}
case ')':
if state != LINK {
continue
}
roundCount--
if roundCount != 0 {
continue
}
// end of link part
result.WriteString(a.replaceHyperlink(hyperlink.String()))
hyperlink.Reset()
state = OTHER
}
}
// when we did not process any parts, we return the original text
buffer.WriteString(part)
return buffer.String()
result.WriteString(hyperlink.String())
return result.String()
}
func (a *Ansi) replaceHyperlink(text string) string {

View file

@ -31,16 +31,16 @@ func TestGenerateHyperlinkWithUrl(t *testing.T) {
ShellName string
Expected string
}{
{
Text: "in <accent>\x1b[1mpwsh \x1b[22m</> ",
ShellName: shell.PWSH,
Expected: "in <accent>\x1b[1mpwsh \x1b[22m</> ",
},
{
Text: "[google](http://www.google.be) [maps (2/2)](http://maps.google.be)",
ShellName: shell.FISH,
Expected: "\x1b]8;;http://www.google.be\x1b\\google\x1b]8;;\x1b\\ \x1b]8;;http://maps.google.be\x1b\\maps (2/2)\x1b]8;;\x1b\\",
},
{
Text: "in <accent>\x1b[1mpwsh \x1b[22m</> ",
ShellName: shell.PWSH,
Expected: "in <accent>\x1b[1mpwsh \x1b[22m</> ",
},
{Text: "[google](http://www.google.be)", ShellName: shell.ZSH, Expected: "%{\x1b]8;;http://www.google.be\x1b\\%}google%{\x1b]8;;\x1b\\%}"},
{Text: "[google](http://www.google.be)", ShellName: shell.PWSH, Expected: "\x1b]8;;http://www.google.be\x1b\\google\x1b]8;;\x1b\\"},
{Text: "[google](http://www.google.be)", ShellName: shell.BASH, Expected: "\\[\x1b]8;;http://www.google.be\x1b\\\\\\]google\\[\x1b]8;;\x1b\\\\\\]"},
@ -100,3 +100,22 @@ func TestFormatText(t *testing.T) {
assert.Equal(t, tc.Expected, formattedText, tc.Case)
}
}
func TestGenerateFileLink(t *testing.T) {
cases := []struct {
Text string
Expected string
}{
{
Text: `[Posh](file:C:/Program Files (x86)/Common Files/Microsoft Shared/Posh)`,
Expected: "\x1b]8;;file:C:/Program Files (x86)/Common Files/Microsoft Shared/Posh\x1b\\Posh\x1b]8;;\x1b\\",
},
{Text: `[Windows](file:C:/Windows)`, Expected: "\x1b]8;;file:C:/Windows\x1b\\Windows\x1b]8;;\x1b\\"},
}
for _, tc := range cases {
a := Ansi{}
a.Init(shell.PWSH)
hyperlinkText := a.GenerateHyperlink(tc.Text)
assert.Equal(t, tc.Expected, hyperlinkText)
}
}