refactor: named regex captures

This commit is contained in:
Jan De Dobbeleer 2020-11-22 15:02:27 +01:00 committed by Jan De Dobbeleer
parent 56778276b2
commit fd84a469ef
6 changed files with 67 additions and 36 deletions

View file

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"regexp"
) )
// Property defines one property of a segment for context // 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 { if err == nil {
return colorString return colorString
} }
r := regexp.MustCompile(`(?P<color>#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})`) values := findNamedRegexMatch(`(?P<color>#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})`, colorString)
values := groupDict(r, colorString)
if values != nil && values["color"] != "" { if values != nil && values["color"] != "" {
return values["color"] return values["color"]
} }

45
regex.go Normal file
View file

@ -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)
}

View file

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"regexp"
"strings" "strings"
"github.com/gookit/color" "github.com/gookit/color"
@ -147,18 +146,16 @@ func (r *Renderer) writeAndRemoveText(background, foreground, text, textToRemove
func (r *Renderer) write(background, foreground, text string) { func (r *Renderer) write(background, foreground, text string) {
// first we match for any potentially valid colors enclosed in <> // first we match for any potentially valid colors enclosed in <>
rex := regexp.MustCompile(`<([#A-Za-z0-9]+)?(?:,([#A-Za-z0-9]+))?>(.*?)<\/>`) match := findAllNamedRegexMatch(`<(?P<foreground>[^,>]+)?,?(?P<background>[^>]+)?>(?P<content>[^<]*)<\/>`, text)
match := rex.FindAllStringSubmatch(text, -1)
for i := range match { for i := range match {
extractedForegroundColor := match[i][1] extractedForegroundColor := match[i]["foreground"]
extractedBackgroundColor := match[i][2] extractedBackgroundColor := match[i]["background"]
if col := r.getAnsiFromColorString(extractedForegroundColor, false); col == "" && extractedForegroundColor != Transparent && len(extractedBackgroundColor) == 0 { if col := r.getAnsiFromColorString(extractedForegroundColor, false); col == "" && extractedForegroundColor != Transparent && len(extractedBackgroundColor) == 0 {
continue // we skip invalid colors continue // we skip invalid colors
} }
if col := r.getAnsiFromColorString(extractedBackgroundColor, false); col == "" && extractedBackgroundColor != Transparent && len(extractedForegroundColor) == 0 { if col := r.getAnsiFromColorString(extractedBackgroundColor, false); col == "" && extractedBackgroundColor != Transparent && len(extractedForegroundColor) == 0 {
continue // we skip invalid colors continue // we skip invalid colors
} }
// reuse function colors if only one was specified // reuse function colors if only one was specified
if len(extractedBackgroundColor) == 0 { if len(extractedBackgroundColor) == 0 {
extractedBackgroundColor = background extractedBackgroundColor = background
@ -166,9 +163,8 @@ func (r *Renderer) write(background, foreground, text string) {
if len(extractedForegroundColor) == 0 { if len(extractedForegroundColor) == 0 {
extractedForegroundColor = foreground extractedForegroundColor = foreground
} }
escapedTextSegment := match[i]["text"]
escapedTextSegment := match[i][0] innerText := match[i]["content"]
innerText := match[i][3]
textBeforeColorOverride := strings.Split(text, escapedTextSegment)[0] textBeforeColorOverride := strings.Split(text, escapedTextSegment)[0]
text = r.writeAndRemoveText(background, foreground, textBeforeColorOverride, textBeforeColorOverride, text) text = r.writeAndRemoveText(background, foreground, textBeforeColorOverride, textBeforeColorOverride, text)
text = r.writeAndRemoveText(extractedBackgroundColor, extractedForegroundColor, innerText, escapedTextSegment, 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 { func (r *Renderer) lenWithoutANSI(str string) int {
re := regexp.MustCompile(r.formats.rANSI) stripped := replaceAllString(r.formats.rANSI, str, "")
stripped := re.ReplaceAllString(str, "")
switch r.shell { switch r.shell {
case zsh: case zsh:
stripped = strings.ReplaceAll(stripped, "%{", "") stripped = strings.ReplaceAll(stripped, "%{", "")

View file

@ -85,6 +85,17 @@ func TestWriteColorOverrideBoth16(t *testing.T) {
assert.NotContains(t, renderer.string(), "</>") 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) { func TestWriteColorTransparent(t *testing.T) {
renderer := &Renderer{ renderer := &Renderer{
Buffer: new(bytes.Buffer), Buffer: new(bytes.Buffer),

View file

@ -3,7 +3,6 @@ package main
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"regexp"
"strconv" "strconv"
"strings" "strings"
) )
@ -180,8 +179,7 @@ func (g *git) getStatusDetailString(status *gitStatus, color, icon Property, def
} }
func (g *git) getUpstreamSymbol() string { func (g *git) getUpstreamSymbol() string {
upstreamRegex := regexp.MustCompile("/.*") upstream := replaceAllString("/.*", g.repo.upstream, "")
upstream := upstreamRegex.ReplaceAllString(g.repo.upstream, "")
url := g.getGitCommandOutput("remote", "get-url", upstream) url := g.getGitCommandOutput("remote", "get-url", upstream)
if strings.Contains(url, "github") { if strings.Contains(url, "github") {
return g.props.getString(GithubIcon, "\uF408 ") return g.props.getString(GithubIcon, "\uF408 ")
@ -348,19 +346,6 @@ func (g *git) getStashContext() string {
} }
func (g *git) parseGitStatusInfo(branchInfo string) map[string]string { func (g *git) parseGitStatusInfo(branchInfo string) map[string]string {
var branchRegex = regexp.MustCompile(`^## (?P<local>\S+?)(\.{3}(?P<upstream>\S+?)( \[(?P<upstream_status>(ahead (?P<ahead>\d+)(, )?)?(behind (?P<behind>\d+))?(gone)?)])?)?$`) var branchRegex = `^## (?P<local>\S+?)(\.{3}(?P<upstream>\S+?)( \[(?P<upstream_status>(ahead (?P<ahead>\d+)(, )?)?(behind (?P<behind>\d+))?(gone)?)])?)?$`
return groupDict(branchRegex, branchInfo) return findNamedRegexMatch(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
} }

View file

@ -1,7 +1,5 @@
package main package main
import "regexp"
type language struct { type language struct {
props *properties props *properties
env environmentInfo env environmentInfo
@ -39,8 +37,7 @@ func (l *language) enabled() bool {
} }
} }
versionInfo, _ := l.env.runCommand(executable, l.versionParam) versionInfo, _ := l.env.runCommand(executable, l.versionParam)
r := regexp.MustCompile(l.versionRegex) values := findNamedRegexMatch(l.versionRegex, versionInfo)
values := groupDict(r, versionInfo)
l.version = values["version"] l.version = values["version"]
return true return true
} }