diff --git a/src/block.go b/src/block.go index 32058eff..6f7d77f5 100644 --- a/src/block.go +++ b/src/block.go @@ -72,11 +72,10 @@ func (b *Block) setStringValues() { wg := sync.WaitGroup{} wg.Add(len(b.Segments)) defer wg.Wait() - cwd := b.env.getcwd() for _, segment := range b.Segments { go func(s *Segment) { defer wg.Done() - s.setStringValue(b.env, cwd) + s.setStringValue(b.env) }(segment) } } @@ -184,7 +183,7 @@ func (b *Block) debug() (int, []*SegmentTiming) { largestSegmentNameLength := 0 for _, segment := range b.Segments { err := segment.mapSegmentWithWriter(b.env) - if err != nil || !segment.shouldIncludeFolder(b.env.getcwd()) { + if err != nil || !segment.shouldIncludeFolder() { continue } var segmentTiming SegmentTiming diff --git a/src/regex.go b/src/regex.go index b151d4d4..524d987b 100644 --- a/src/regex.go +++ b/src/regex.go @@ -1,7 +1,9 @@ package main import ( + "fmt" "regexp" + "strings" "sync" ) @@ -77,3 +79,25 @@ func matchString(pattern, text string) bool { re := getCompiledRegex(pattern) return re.MatchString(text) } + +func dirMatchesOneOf(env environmentInfo, dir string, regexes []string) bool { + normalizedCwd := strings.ReplaceAll(dir, "\\", "/") + normalizedHomeDir := strings.ReplaceAll(env.homeDir(), "\\", "/") + + for _, element := range regexes { + normalizedElement := strings.ReplaceAll(element, "\\\\", "/") + if strings.HasPrefix(normalizedElement, "~") { + normalizedElement = normalizedHomeDir + normalizedElement[1:] + } + pattern := fmt.Sprintf("^%s$", normalizedElement) + goos := env.getRuntimeGOOS() + if goos == windowsPlatform || goos == darwinPlatform { + pattern = "(?i)" + pattern + } + matched := matchString(pattern, normalizedCwd) + if matched { + return true + } + } + return false +} diff --git a/src/regex_test.go b/src/regex_test.go new file mode 100644 index 00000000..8d609414 --- /dev/null +++ b/src/regex_test.go @@ -0,0 +1,40 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDirMatchesOneOf(t *testing.T) { + cases := []struct { + GOOS string + HomeDir string + Dir string + Pattern string + Expected bool + }{ + {GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill", Pattern: "/home/bill", Expected: true}, + {GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/foo", Expected: true}, + {GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/Foo", Expected: false}, + {GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~\\\\foo", Expected: true}, + {GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo/bar", Pattern: "~/fo.*", Expected: true}, + {GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/fo\\w", Expected: true}, + {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "C:\\\\Users\\\\Bill", Expected: true}, + {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "C:/Users/Bill", Expected: true}, + {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "c:/users/bill", Expected: true}, + {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "~", Expected: true}, + {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/Foo", Expected: true}, + {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/foo", Expected: true}, + {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo\\Bar", Pattern: "~/fo.*", Expected: true}, + {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/fo\\w", Expected: true}, + } + + for _, tc := range cases { + env := new(MockedEnvironment) + env.On("getRuntimeGOOS", nil).Return(tc.GOOS) + env.On("homeDir", nil).Return(tc.HomeDir) + got := dirMatchesOneOf(env, tc.Dir, []string{tc.Pattern}) + assert.Equal(t, tc.Expected, got) + } +} diff --git a/src/segment.go b/src/segment.go index 90a30977..f632e17d 100644 --- a/src/segment.go +++ b/src/segment.go @@ -3,7 +3,6 @@ package main import ( "errors" "fmt" - "strings" "time" ) @@ -146,13 +145,13 @@ func (segment *Segment) getValue(property Property, defaultValue string) string return defaultValue } -func (segment *Segment) shouldIncludeFolder(cwd string) bool { - cwdIncluded := segment.cwdIncluded(cwd) - cwdExcluded := segment.cwdExcluded(cwd) +func (segment *Segment) shouldIncludeFolder() bool { + cwdIncluded := segment.cwdIncluded() + cwdExcluded := segment.cwdExcluded() return (cwdIncluded && !cwdExcluded) } -func (segment *Segment) cwdIncluded(cwd string) bool { +func (segment *Segment) cwdIncluded() bool { value, ok := segment.Properties[IncludeFolders] if !ok { // IncludeFolders isn't specified, everything is included @@ -166,38 +165,16 @@ func (segment *Segment) cwdIncluded(cwd string) bool { return true } - return segment.cwdMatchesOneOf(cwd, list) + return dirMatchesOneOf(segment.env, segment.env.getcwd(), list) } -func (segment *Segment) cwdExcluded(cwd string) bool { +func (segment *Segment) cwdExcluded() bool { value, ok := segment.Properties[ExcludeFolders] if !ok { value = segment.Properties[IgnoreFolders] } list := parseStringArray(value) - return segment.cwdMatchesOneOf(cwd, list) -} - -func (segment *Segment) cwdMatchesOneOf(cwd string, regexes []string) bool { - normalizedCwd := strings.ReplaceAll(cwd, "\\", "/") - normalizedHomeDir := strings.ReplaceAll(segment.env.homeDir(), "\\", "/") - - for _, element := range regexes { - normalizedElement := strings.ReplaceAll(element, "\\\\", "/") - if strings.HasPrefix(normalizedElement, "~") { - normalizedElement = normalizedHomeDir + normalizedElement[1:] - } - pattern := fmt.Sprintf("^%s$", normalizedElement) - goos := segment.env.getRuntimeGOOS() - if goos == windowsPlatform || goos == darwinPlatform { - pattern = "(?i)" + pattern - } - matched := matchString(pattern, normalizedCwd) - if matched { - return true - } - } - return false + return dirMatchesOneOf(segment.env, segment.env.getcwd(), list) } func (segment *Segment) getColor(templates []string, defaultColor string) string { @@ -297,7 +274,7 @@ func (segment *Segment) mapSegmentWithWriter(env environmentInfo) error { return errors.New("unable to map writer") } -func (segment *Segment) setStringValue(env environmentInfo, cwd string) { +func (segment *Segment) setStringValue(env environmentInfo) { defer func() { err := recover() if err == nil { @@ -310,7 +287,7 @@ func (segment *Segment) setStringValue(env environmentInfo, cwd string) { segment.active = true }() err := segment.mapSegmentWithWriter(env) - if err != nil || !segment.shouldIncludeFolder(cwd) { + if err != nil || !segment.shouldIncludeFolder() { return } if segment.enabled() { diff --git a/src/segment_git.go b/src/segment_git.go index 516fe3e6..c932c813 100644 --- a/src/segment_git.go +++ b/src/segment_git.go @@ -135,6 +135,10 @@ func (g *git) enabled() bool { if err != nil { return false } + if g.shouldIgnoreRootRepository(gitdir.parentFolder) { + return false + } + g.repo = &gitRepo{} if gitdir.isDir { g.repo.gitWorkingFolder = gitdir.path @@ -159,6 +163,18 @@ func (g *git) enabled() bool { return false } +func (g *git) shouldIgnoreRootRepository(rootDir string) bool { + if g.props == nil || g.props.values == nil { + return false + } + value, ok := g.props.values[ExcludeFolders] + if !ok { + return false + } + excludedFolders := parseStringArray(value) + return dirMatchesOneOf(g.env, rootDir, excludedFolders) +} + func (g *git) string() string { statusColorsEnabled := g.props.getBool(StatusColorsEnabled, false) displayStatus := g.props.getBool(DisplayStatus, false) diff --git a/src/segment_git_test.go b/src/segment_git_test.go index 96507495..1ad7ff5b 100644 --- a/src/segment_git_test.go +++ b/src/segment_git_test.go @@ -925,3 +925,36 @@ func TestTruncateBranch(t *testing.T) { assert.Equal(t, tc.Expected, g.truncateBranch(tc.Branch), tc.Case) } } + +func TestShouldIgnoreRootRepository(t *testing.T) { + cases := []struct { + Case string + Dir string + Expected bool + }{ + {Case: "inside excluded", Dir: "/home/bill/repo"}, + {Case: "oustide excluded", Dir: "/home/melinda"}, + {Case: "excluded exact match", Dir: "/home/gates", Expected: true}, + {Case: "excluded inside match", Dir: "/home/gates/bill", Expected: true}, + } + + for _, tc := range cases { + props := map[Property]interface{}{ + ExcludeFolders: []string{ + "/home/bill", + "/home/gates.*", + }, + } + env := new(MockedEnvironment) + env.On("homeDir", nil).Return("/home/bill") + env.On("getRuntimeGOOS", nil).Return(windowsPlatform) + git := &git{ + props: &properties{ + values: props, + }, + env: env, + } + got := git.shouldIgnoreRootRepository(tc.Dir) + assert.Equal(t, tc.Expected, got, tc.Case) + } +} diff --git a/src/segment_test.go b/src/segment_test.go index 5cf71ae8..0807f0a6 100644 --- a/src/segment_test.go +++ b/src/segment_test.go @@ -84,6 +84,7 @@ func TestShouldIncludeFolder(t *testing.T) { env := new(MockedEnvironment) env.On("getRuntimeGOOS", nil).Return(linuxPlatform) env.On("homeDir", nil).Return("") + env.On("getcwd", nil).Return(cwd) segment := &Segment{ Properties: map[Property]interface{}{ IncludeFolders: tc.IncludeFolders, @@ -91,7 +92,7 @@ func TestShouldIncludeFolder(t *testing.T) { }, env: env, } - got := segment.shouldIncludeFolder(cwd) + got := segment.shouldIncludeFolder() assert.Equal(t, tc.Expected, got, tc.Case) } } @@ -100,6 +101,7 @@ func TestShouldIncludeFolderRegexInverted(t *testing.T) { env := new(MockedEnvironment) env.On("getRuntimeGOOS", nil).Return(linuxPlatform) env.On("homeDir", nil).Return("") + env.On("getcwd", nil).Return(cwd) segment := &Segment{ Properties: map[Property]interface{}{ ExcludeFolders: []string{"(?!Projects[\\/]).*"}, @@ -113,13 +115,14 @@ func TestShouldIncludeFolderRegexInverted(t *testing.T) { assert.Equal(t, "regexp: Compile(`^(?!Projects[\\/]).*$`): error parsing regexp: invalid or unsupported Perl syntax: `(?!`", err) } }() - segment.shouldIncludeFolder(cwd) + segment.shouldIncludeFolder() } func TestShouldIncludeFolderRegexInvertedNonEscaped(t *testing.T) { env := new(MockedEnvironment) env.On("getRuntimeGOOS", nil).Return(linuxPlatform) env.On("homeDir", nil).Return("") + env.On("getcwd", nil).Return(cwd) segment := &Segment{ Properties: map[Property]interface{}{ ExcludeFolders: []string{"(?!Projects/).*"}, @@ -133,7 +136,7 @@ func TestShouldIncludeFolderRegexInvertedNonEscaped(t *testing.T) { assert.Equal(t, "regexp: Compile(`^(?!Projects/).*$`): error parsing regexp: invalid or unsupported Perl syntax: `(?!`", err) } }() - segment.shouldIncludeFolder(cwd) + segment.shouldIncludeFolder() } func TestGetColors(t *testing.T) { @@ -208,39 +211,3 @@ func TestGetColors(t *testing.T) { assert.Equal(t, tc.ExpectedColor, color, tc.Case) } } - -func TestCwdMatchesOneOf(t *testing.T) { - cases := []struct { - GOOS string - HomeDir string - Cwd string - Pattern string - Expected bool - }{ - {GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill", Pattern: "/home/bill", Expected: true}, - {GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo", Pattern: "~/foo", Expected: true}, - {GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo", Pattern: "~/Foo", Expected: false}, - {GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo", Pattern: "~\\\\foo", Expected: true}, - {GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo/bar", Pattern: "~/fo.*", Expected: true}, - {GOOS: linuxPlatform, HomeDir: "/home/bill", Cwd: "/home/bill/foo", Pattern: "~/fo\\w", Expected: true}, - {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill", Pattern: "C:\\\\Users\\\\Bill", Expected: true}, - {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill", Pattern: "C:/Users/Bill", Expected: true}, - {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill", Pattern: "c:/users/bill", Expected: true}, - {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill", Pattern: "~", Expected: true}, - {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill\\Foo", Pattern: "~/Foo", Expected: true}, - {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill\\Foo", Pattern: "~/foo", Expected: true}, - {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill\\Foo\\Bar", Pattern: "~/fo.*", Expected: true}, - {GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Cwd: "C:\\Users\\Bill\\Foo", Pattern: "~/fo\\w", Expected: true}, - } - - for _, tc := range cases { - env := new(MockedEnvironment) - env.On("getRuntimeGOOS", nil).Return(tc.GOOS) - env.On("homeDir", nil).Return(tc.HomeDir) - segment := &Segment{ - env: env, - } - got := segment.cwdMatchesOneOf(tc.Cwd, []string{tc.Pattern}) - assert.Equal(t, tc.Expected, got) - } -}