diff --git a/properties.go b/properties.go index 1fd2af5d130b..021b7652f61f 100644 --- a/properties.go +++ b/properties.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "regexp" ) // Property defines one property of a segment for context @@ -62,8 +61,7 @@ func (p *properties) getColor(property Property, defaultValue string) string { if err == nil { return colorString } - r := regexp.MustCompile(`(?P#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})`) - values := groupDict(r, colorString) + values := findNamedRegexMatch(`(?P#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})`, colorString) if values != nil && values["color"] != "" { return values["color"] } diff --git a/regex.go b/regex.go new file mode 100644 index 000000000000..8dac1320a6bd --- /dev/null +++ b/regex.go @@ -0,0 +1,45 @@ +package main + +import "regexp" + +func findNamedRegexMatch(pattern, text string) map[string]string { + re := regexp.MustCompile(pattern) + match := re.FindStringSubmatch(text) + result := make(map[string]string) + if len(match) == 0 { + return result + } + for i, name := range re.SubexpNames() { + if i == 0 { + continue + } + result[name] = match[i] + } + return result +} + +func findAllNamedRegexMatch(pattern, text string) []map[string]string { + re := regexp.MustCompile(pattern) + match := re.FindAllStringSubmatch(text, -1) + var results []map[string]string + if len(match) == 0 { + return results + } + for _, set := range match { + result := make(map[string]string) + for i, name := range re.SubexpNames() { + if i == 0 { + result["text"] = set[i] + continue + } + result[name] = set[i] + } + results = append(results, result) + } + return results +} + +func replaceAllString(pattern, text, replaceText string) string { + re := regexp.MustCompile(pattern) + return re.ReplaceAllString(text, replaceText) +} diff --git a/renderer.go b/renderer.go index e2c26d9b3f66..9347e14d4773 100644 --- a/renderer.go +++ b/renderer.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "fmt" - "regexp" "strings" "github.com/gookit/color" @@ -147,18 +146,16 @@ func (r *Renderer) writeAndRemoveText(background, foreground, text, textToRemove func (r *Renderer) write(background, foreground, text string) { // first we match for any potentially valid colors enclosed in <> - rex := regexp.MustCompile(`<([#A-Za-z0-9]+)?(?:,([#A-Za-z0-9]+))?>(.*?)<\/>`) - match := rex.FindAllStringSubmatch(text, -1) + match := findAllNamedRegexMatch(`<(?P[^,>]+)?,?(?P[^>]+)?>(?P[^<]*)<\/>`, text) for i := range match { - extractedForegroundColor := match[i][1] - extractedBackgroundColor := match[i][2] + extractedForegroundColor := match[i]["foreground"] + extractedBackgroundColor := match[i]["background"] if col := r.getAnsiFromColorString(extractedForegroundColor, false); col == "" && extractedForegroundColor != Transparent && len(extractedBackgroundColor) == 0 { continue // we skip invalid colors } if col := r.getAnsiFromColorString(extractedBackgroundColor, false); col == "" && extractedBackgroundColor != Transparent && len(extractedForegroundColor) == 0 { continue // we skip invalid colors } - // reuse function colors if only one was specified if len(extractedBackgroundColor) == 0 { extractedBackgroundColor = background @@ -166,9 +163,8 @@ func (r *Renderer) write(background, foreground, text string) { if len(extractedForegroundColor) == 0 { extractedForegroundColor = foreground } - - escapedTextSegment := match[i][0] - innerText := match[i][3] + escapedTextSegment := match[i]["text"] + innerText := match[i]["content"] textBeforeColorOverride := strings.Split(text, escapedTextSegment)[0] text = r.writeAndRemoveText(background, foreground, textBeforeColorOverride, textBeforeColorOverride, text) text = r.writeAndRemoveText(extractedBackgroundColor, extractedForegroundColor, innerText, escapedTextSegment, text) @@ -178,8 +174,7 @@ func (r *Renderer) write(background, foreground, text string) { } func (r *Renderer) lenWithoutANSI(str string) int { - re := regexp.MustCompile(r.formats.rANSI) - stripped := re.ReplaceAllString(str, "") + stripped := replaceAllString(r.formats.rANSI, str, "") switch r.shell { case zsh: stripped = strings.ReplaceAll(stripped, "%{", "") diff --git a/renderer_test.go b/renderer_test.go index 16495b0891c1..0a4c4704e88f 100644 --- a/renderer_test.go +++ b/renderer_test.go @@ -85,6 +85,17 @@ func TestWriteColorOverrideBoth16(t *testing.T) { assert.NotContains(t, renderer.string(), "") } +func TestWriteColorOverrideDouble(t *testing.T) { + renderer := &Renderer{ + Buffer: new(bytes.Buffer), + } + text := "<#ffffff>jan@<#ffffff>Jans-MBP" + renderer.init("pwsh") + renderer.write("#193549", "#ff5733", text) + assert.NotContains(t, renderer.string(), "<#ffffff>") + assert.NotContains(t, renderer.string(), "") +} + func TestWriteColorTransparent(t *testing.T) { renderer := &Renderer{ Buffer: new(bytes.Buffer), diff --git a/segment_git.go b/segment_git.go index 8c9c2fd81191..6720688f9b05 100644 --- a/segment_git.go +++ b/segment_git.go @@ -3,7 +3,6 @@ package main import ( "bytes" "fmt" - "regexp" "strconv" "strings" ) @@ -180,8 +179,7 @@ func (g *git) getStatusDetailString(status *gitStatus, color, icon Property, def } func (g *git) getUpstreamSymbol() string { - upstreamRegex := regexp.MustCompile("/.*") - upstream := upstreamRegex.ReplaceAllString(g.repo.upstream, "") + upstream := replaceAllString("/.*", g.repo.upstream, "") url := g.getGitCommandOutput("remote", "get-url", upstream) if strings.Contains(url, "github") { return g.props.getString(GithubIcon, "\uF408 ") @@ -348,19 +346,6 @@ func (g *git) getStashContext() string { } func (g *git) parseGitStatusInfo(branchInfo string) map[string]string { - var branchRegex = regexp.MustCompile(`^## (?P\S+?)(\.{3}(?P\S+?)( \[(?P(ahead (?P\d+)(, )?)?(behind (?P\d+))?(gone)?)])?)?$`) - return groupDict(branchRegex, branchInfo) -} - -func groupDict(pattern *regexp.Regexp, haystack string) map[string]string { - match := pattern.FindStringSubmatch(haystack) - result := make(map[string]string) - if len(match) > 0 { - for i, name := range pattern.SubexpNames() { - if i != 0 { - result[name] = match[i] - } - } - } - return result + var branchRegex = `^## (?P\S+?)(\.{3}(?P\S+?)( \[(?P(ahead (?P\d+)(, )?)?(behind (?P\d+))?(gone)?)])?)?$` + return findNamedRegexMatch(branchRegex, branchInfo) } diff --git a/segment_language.go b/segment_language.go index c3fb14c31c25..f746d2a89390 100644 --- a/segment_language.go +++ b/segment_language.go @@ -1,7 +1,5 @@ package main -import "regexp" - type language struct { props *properties env environmentInfo @@ -39,8 +37,7 @@ func (l *language) enabled() bool { } } versionInfo, _ := l.env.runCommand(executable, l.versionParam) - r := regexp.MustCompile(l.versionRegex) - values := groupDict(r, versionInfo) + values := findNamedRegexMatch(l.versionRegex, versionInfo) l.version = values["version"] return true }