1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-28 16:02:01 +03:00

Improve name handling

This commit is contained in:
Jesse Duffield
2023-07-16 13:43:20 +10:00
parent d19d89ea9d
commit c713d550c0
8 changed files with 189 additions and 19 deletions

View File

@ -81,7 +81,7 @@ func TestObtainBranch(t *testing.T) {
for _, s := range scenarios { for _, s := range scenarios {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
branch := obtainBranch(s.input) branch := obtainBranch(s.input, "current-dir")
assert.EqualValues(t, s.expectedBranch, branch) assert.EqualValues(t, s.expectedBranch, branch)
}) })
} }

View File

@ -20,8 +20,8 @@ func NewWorktreeCommands(gitCommon *GitCommon) *WorktreeCommands {
} }
} }
func (self *WorktreeCommands) New(worktreePath string) error { func (self *WorktreeCommands) New(worktreePath string, committish string) error {
cmdArgs := NewGitCmd("worktree").Arg("add", worktreePath).ToArgv() cmdArgs := NewGitCmd("worktree").Arg("add", worktreePath, committish).ToArgv()
return self.cmd.New(cmdArgs).Run() return self.cmd.New(cmdArgs).Run()
} }

View File

@ -1,12 +1,12 @@
package git_commands package git_commands
import ( import (
"path/filepath"
"strings" "strings"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands" "github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/common" "github.com/jesseduffield/lazygit/pkg/common"
"github.com/samber/lo"
) )
type WorktreeLoader struct { type WorktreeLoader struct {
@ -49,9 +49,115 @@ func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
} }
} else if strings.HasPrefix(splitLine, "branch ") { } else if strings.HasPrefix(splitLine, "branch ") {
branch := strings.SplitN(splitLine, " ", 2)[1] branch := strings.SplitN(splitLine, " ", 2)[1]
currentWorktree.Branch = filepath.Base(branch) currentWorktree.Branch = strings.TrimPrefix(branch, "refs/heads/")
} }
} }
names := getUniqueNamesFromPaths(lo.Map(worktrees, func(worktree *models.Worktree, _ int) string {
return worktree.Path
}))
for index, worktree := range worktrees {
worktree.NameField = names[index]
}
return worktrees, nil return worktrees, nil
} }
type pathWithIndexT struct {
path string
index int
}
type nameWithIndexT struct {
name string
index int
}
func getUniqueNamesFromPaths(paths []string) []string {
pathsWithIndex := lo.Map(paths, func(path string, index int) pathWithIndexT {
return pathWithIndexT{path, index}
})
namesWithIndex := getUniqueNamesFromPathsAux(pathsWithIndex, 0)
// now sort based on index
result := make([]string, len(namesWithIndex))
for _, nameWithIndex := range namesWithIndex {
result[nameWithIndex.index] = nameWithIndex.name
}
return result
}
func getUniqueNamesFromPathsAux(paths []pathWithIndexT, depth int) []nameWithIndexT {
// If we have no paths, return an empty array
if len(paths) == 0 {
return []nameWithIndexT{}
}
// If we have only one path, return the last segment of the path
if len(paths) == 1 {
path := paths[0]
return []nameWithIndexT{{index: path.index, name: sliceAtDepth(path.path, depth)}}
}
// group the paths by their value at the specified depth
groups := make(map[string][]pathWithIndexT)
for _, path := range paths {
value := valueAtDepth(path.path, depth)
groups[value] = append(groups[value], path)
}
result := []nameWithIndexT{}
for _, group := range groups {
if len(group) == 1 {
path := group[0]
result = append(result, nameWithIndexT{index: path.index, name: sliceAtDepth(path.path, depth)})
} else {
result = append(result, getUniqueNamesFromPathsAux(group, depth+1)...)
}
}
return result
}
// if the path is /a/b/c/d, and the depth is 0, the value is 'd'. If the depth is 1, the value is 'c', etc
func valueAtDepth(path string, depth int) string {
path = strings.TrimPrefix(path, "/")
path = strings.TrimSuffix(path, "/")
// Split the path into segments
segments := strings.Split(path, "/")
// Get the length of segments
length := len(segments)
// If the depth is greater than the length of segments, return an empty string
if depth >= length {
return ""
}
// Return the segment at the specified depth from the end of the path
return segments[length-1-depth]
}
// if the path is /a/b/c/d, and the depth is 0, the value is 'd'. If the depth is 1, the value is 'b/c', etc
func sliceAtDepth(path string, depth int) string {
path = strings.TrimPrefix(path, "/")
path = strings.TrimSuffix(path, "/")
// Split the path into segments
segments := strings.Split(path, "/")
// Get the length of segments
length := len(segments)
// If the depth is greater than or equal to the length of segments, return an empty string
if depth >= length {
return ""
}
// Join the segments from the specified depth till end of the path
return strings.Join(segments[length-1-depth:], "/")
}

View File

@ -0,0 +1,52 @@
package git_commands
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetUniqueNamesFromPaths(t *testing.T) {
for _, scenario := range []struct {
input []string
expected []string
}{
{
input: []string{},
expected: []string{},
},
{
input: []string{
"/my/path/feature/one",
},
expected: []string{
"one",
},
},
{
input: []string{
"/my/path/feature/one/",
},
expected: []string{
"one",
},
},
{
input: []string{
"/a/b/c/d",
"/a/b/c/e",
"/a/b/f/d",
"/a/e/c/d",
},
expected: []string{
"b/c/d",
"e",
"f/d",
"e/c/d",
},
},
} {
actual := getUniqueNamesFromPaths(scenario.input)
assert.EqualValues(t, scenario.expected, actual)
}
}

View File

@ -1,14 +1,13 @@
package models package models
import ( // A git worktree
"path/filepath"
)
// Worktree : A git worktree
type Worktree struct { type Worktree struct {
// if false, this is a linked worktree
IsMain bool IsMain bool
Path string Path string
Branch string Branch string
// based on the path, but uniquified
NameField string
} }
func (w *Worktree) RefName() string { func (w *Worktree) RefName() string {
@ -16,7 +15,7 @@ func (w *Worktree) RefName() string {
} }
func (w *Worktree) ID() string { func (w *Worktree) ID() string {
return w.RefName() return w.Path
} }
func (w *Worktree) Description() string { func (w *Worktree) Description() string {
@ -24,7 +23,7 @@ func (w *Worktree) Description() string {
} }
func (w *Worktree) Name() string { func (w *Worktree) Name() string {
return filepath.Base(w.Path) return w.NameField
} }
func (w *Worktree) Main() bool { func (w *Worktree) Main() bool {

View File

@ -58,12 +58,17 @@ func (self *WorktreeHelper) IsWorktreePathMissing(w *models.Worktree) bool {
func (self *WorktreeHelper) NewWorktree() error { func (self *WorktreeHelper) NewWorktree() error {
return self.c.Prompt(types.PromptOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.NewWorktreePath, Title: self.c.Tr.NewWorktreePath,
HandleConfirm: func(response string) error { HandleConfirm: func(path string) error {
self.c.LogAction(self.c.Tr.Actions.CreateWorktree) return self.c.Prompt(types.PromptOpts{
if err := self.c.Git().Worktree.New(sanitizedBranchName(response)); err != nil { Title: self.c.Tr.NewWorktreePath,
return err HandleConfirm: func(committish string) error {
} self.c.LogAction(self.c.Tr.Actions.CreateWorktree)
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) if err := self.c.Git().Worktree.New(sanitizedBranchName(path), committish); err != nil {
return err
}
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
},
})
}, },
}) })
} }

View File

@ -38,6 +38,12 @@ func GetWorktreeDisplayString(isCurrent bool, isPathMissing bool, worktree *mode
if icons.IsIconEnabled() { if icons.IsIconEnabled() {
res = append(res, textStyle.Sprint(icon)) res = append(res, textStyle.Sprint(icon))
} }
res = append(res, textStyle.Sprint(worktree.Name()))
name := worktree.Name()
if worktree.Main() {
// TODO: i18n
name += " (main worktree)"
}
res = append(res, textStyle.Sprint(name))
return res return res
} }

View File

@ -557,6 +557,7 @@ type TranslationSet struct {
MainWorktree string MainWorktree string
CreateWorktree string CreateWorktree string
NewWorktreePath string NewWorktreePath string
NewWorktreeBranch string
Name string Name string
Branch string Branch string
Path string Path string
@ -1276,6 +1277,7 @@ func EnglishTranslationSet() TranslationSet {
MainWorktree: "(main)", MainWorktree: "(main)",
CreateWorktree: "Create worktree", CreateWorktree: "Create worktree",
NewWorktreePath: "New worktree path", NewWorktreePath: "New worktree path",
NewWorktreeBranch: "New worktree branch (leave blank to use the current branch)",
Name: "Name", Name: "Name",
Branch: "Branch", Branch: "Branch",
Path: "Path", Path: "Path",