mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-03-29 22:07:13 +02:00
Initial addition of support for worktrees
This commit is contained in:
parent
52447e5d46
commit
f8ba899b87
2
.gitignore
vendored
2
.gitignore
vendored
@ -39,3 +39,5 @@ test/results/**
|
||||
|
||||
oryxBuildBinary
|
||||
__debug_bin
|
||||
|
||||
.worktrees
|
@ -116,6 +116,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string {
|
||||
"stash": tr.StashTitle,
|
||||
"suggestions": tr.SuggestionsCheatsheetTitle,
|
||||
"extras": tr.ExtrasTitle,
|
||||
"worktrees": tr.WorktreesTitle,
|
||||
}
|
||||
|
||||
title, ok := contextTitleMap[str]
|
||||
|
@ -50,6 +50,7 @@ type Loaders struct {
|
||||
RemoteLoader *git_commands.RemoteLoader
|
||||
StashLoader *git_commands.StashLoader
|
||||
TagLoader *git_commands.TagLoader
|
||||
Worktrees *git_commands.WorktreeLoader
|
||||
}
|
||||
|
||||
func NewGitCommand(
|
||||
@ -133,6 +134,7 @@ func NewGitCommandAux(
|
||||
commitLoader := git_commands.NewCommitLoader(cmn, cmd, dotGitDir, statusCommands.RebaseMode, gitCommon)
|
||||
reflogCommitLoader := git_commands.NewReflogCommitLoader(cmn, cmd)
|
||||
remoteLoader := git_commands.NewRemoteLoader(cmn, cmd, repo.Remotes)
|
||||
worktreeLoader := git_commands.NewWorktreeLoader(cmn, cmd)
|
||||
stashLoader := git_commands.NewStashLoader(cmn, cmd)
|
||||
tagLoader := git_commands.NewTagLoader(cmn, cmd)
|
||||
|
||||
@ -161,6 +163,7 @@ func NewGitCommandAux(
|
||||
FileLoader: fileLoader,
|
||||
ReflogCommitLoader: reflogCommitLoader,
|
||||
RemoteLoader: remoteLoader,
|
||||
Worktrees: worktreeLoader,
|
||||
StashLoader: stashLoader,
|
||||
TagLoader: tagLoader,
|
||||
},
|
||||
|
@ -2,6 +2,7 @@ package git_commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@ -117,6 +118,11 @@ outer:
|
||||
}
|
||||
|
||||
func (self *BranchLoader) obtainBranches() []*models.Branch {
|
||||
currentDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
output, err := self.getRawBranches()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -138,6 +144,11 @@ func (self *BranchLoader) obtainBranches() []*models.Branch {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if len(split[6]) > 0 && split[6] != currentDir {
|
||||
// Ignore line because it is a branch checked out in a different worktree
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return obtainBranch(split), true
|
||||
})
|
||||
}
|
||||
@ -166,6 +177,7 @@ var branchFields = []string{
|
||||
"upstream:track",
|
||||
"subject",
|
||||
fmt.Sprintf("objectname:short=%d", utils.COMMIT_HASH_SHORT_SIZE),
|
||||
"worktreepath",
|
||||
}
|
||||
|
||||
// Obtain branch information from parsed line output of getRawBranches()
|
||||
|
80
pkg/commands/git_commands/worktree_loader.go
Normal file
80
pkg/commands/git_commands/worktree_loader.go
Normal file
@ -0,0 +1,80 @@
|
||||
package git_commands
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
||||
"github.com/jesseduffield/lazygit/pkg/common"
|
||||
)
|
||||
|
||||
type WorktreeLoader struct {
|
||||
*common.Common
|
||||
cmd oscommands.ICmdObjBuilder
|
||||
}
|
||||
|
||||
func NewWorktreeLoader(
|
||||
common *common.Common,
|
||||
cmd oscommands.ICmdObjBuilder,
|
||||
) *WorktreeLoader {
|
||||
return &WorktreeLoader{
|
||||
Common: common,
|
||||
cmd: cmd,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *WorktreeLoader) GetWorktrees() ([]*models.Worktree, error) {
|
||||
currentDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmdArgs := NewGitCmd("worktree").Arg("list", "--porcelain", "-z").ToArgv()
|
||||
worktreesOutput, err := self.cmd.New(cmdArgs).DontLog().RunWithOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
splitLines := strings.Split(worktreesOutput, "\x00")
|
||||
|
||||
var worktrees []*models.Worktree
|
||||
var currentWorktree *models.Worktree
|
||||
for _, splitLine := range splitLines {
|
||||
if len(splitLine) == 0 && currentWorktree != nil {
|
||||
|
||||
worktrees = append(worktrees, currentWorktree)
|
||||
currentWorktree = nil
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(splitLine, "worktree ") {
|
||||
main := false
|
||||
name := "main"
|
||||
path := strings.SplitN(splitLine, " ", 2)[1]
|
||||
if len(worktrees) == 0 {
|
||||
main = true
|
||||
} else {
|
||||
name = filepath.Base(path)
|
||||
}
|
||||
currentWorktree = &models.Worktree{
|
||||
Name: name,
|
||||
Path: path,
|
||||
Main: main,
|
||||
Current: path == currentDir,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
worktree /Users/jbaranick/Source/lazygit
|
||||
HEAD f6d6b5dec0432ffa953611700ab9b1ff0089f948
|
||||
branch refs/heads/worktree_support
|
||||
|
||||
worktree /Users/jbaranick/Source/lazygit/.worktrees/worktree_tests
|
||||
HEAD f6d6b5dec0432ffa953611700ab9b1ff0089f948
|
||||
branch refs/heads/worktree_tests
|
||||
*/
|
||||
|
||||
return worktrees, nil
|
||||
}
|
21
pkg/commands/models/worktree.go
Normal file
21
pkg/commands/models/worktree.go
Normal file
@ -0,0 +1,21 @@
|
||||
package models
|
||||
|
||||
// Worktree : A git worktree
|
||||
type Worktree struct {
|
||||
Name string
|
||||
Main bool
|
||||
Current bool
|
||||
Path string
|
||||
}
|
||||
|
||||
func (w *Worktree) RefName() string {
|
||||
return w.Name
|
||||
}
|
||||
|
||||
func (w *Worktree) ID() string {
|
||||
return w.RefName()
|
||||
}
|
||||
|
||||
func (w *Worktree) Description() string {
|
||||
return w.RefName()
|
||||
}
|
@ -11,6 +11,7 @@ const (
|
||||
FILES_CONTEXT_KEY types.ContextKey = "files"
|
||||
LOCAL_BRANCHES_CONTEXT_KEY types.ContextKey = "localBranches"
|
||||
REMOTES_CONTEXT_KEY types.ContextKey = "remotes"
|
||||
WORKTREES_CONTEXT_KEY types.ContextKey = "worktrees"
|
||||
REMOTE_BRANCHES_CONTEXT_KEY types.ContextKey = "remoteBranches"
|
||||
TAGS_CONTEXT_KEY types.ContextKey = "tags"
|
||||
LOCAL_COMMITS_CONTEXT_KEY types.ContextKey = "commits"
|
||||
@ -49,6 +50,7 @@ var AllContextKeys = []types.ContextKey{
|
||||
FILES_CONTEXT_KEY,
|
||||
LOCAL_BRANCHES_CONTEXT_KEY,
|
||||
REMOTES_CONTEXT_KEY,
|
||||
WORKTREES_CONTEXT_KEY,
|
||||
REMOTE_BRANCHES_CONTEXT_KEY,
|
||||
TAGS_CONTEXT_KEY,
|
||||
LOCAL_COMMITS_CONTEXT_KEY,
|
||||
@ -84,6 +86,7 @@ type ContextTree struct {
|
||||
LocalCommits *LocalCommitsContext
|
||||
CommitFiles *CommitFilesContext
|
||||
Remotes *RemotesContext
|
||||
Worktrees *WorktreesContext
|
||||
Submodules *SubmodulesContext
|
||||
RemoteBranches *RemoteBranchesContext
|
||||
ReflogCommits *ReflogCommitsContext
|
||||
@ -121,6 +124,7 @@ func (self *ContextTree) Flatten() []types.Context {
|
||||
self.Files,
|
||||
self.SubCommits,
|
||||
self.Remotes,
|
||||
self.Worktrees,
|
||||
self.RemoteBranches,
|
||||
self.Tags,
|
||||
self.Branches,
|
||||
|
@ -29,6 +29,7 @@ func NewContextTree(c *ContextCommon) *ContextTree {
|
||||
Submodules: NewSubmodulesContext(c),
|
||||
Menu: NewMenuContext(c),
|
||||
Remotes: NewRemotesContext(c),
|
||||
Worktrees: NewWorktreesContext(c),
|
||||
RemoteBranches: NewRemoteBranchesContext(c),
|
||||
LocalCommits: NewLocalCommitsContext(c),
|
||||
CommitFiles: commitFilesContext,
|
||||
|
52
pkg/gui/context/worktrees_context.go
Normal file
52
pkg/gui/context/worktrees_context.go
Normal file
@ -0,0 +1,52 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
type WorktreesContext struct {
|
||||
*FilteredListViewModel[*models.Worktree]
|
||||
*ListContextTrait
|
||||
}
|
||||
|
||||
var _ types.IListContext = (*WorktreesContext)(nil)
|
||||
|
||||
func NewWorktreesContext(c *ContextCommon) *WorktreesContext {
|
||||
viewModel := NewFilteredListViewModel(
|
||||
func() []*models.Worktree { return c.Model().Worktrees },
|
||||
func(Worktree *models.Worktree) []string {
|
||||
return []string{Worktree.Name}
|
||||
},
|
||||
)
|
||||
|
||||
getDisplayStrings := func(startIdx int, length int) [][]string {
|
||||
return presentation.GetWorktreeListDisplayStrings(c.Model().Worktrees)
|
||||
}
|
||||
|
||||
return &WorktreesContext{
|
||||
FilteredListViewModel: viewModel,
|
||||
ListContextTrait: &ListContextTrait{
|
||||
Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{
|
||||
View: c.Views().Worktrees,
|
||||
WindowName: "branches",
|
||||
Key: WORKTREES_CONTEXT_KEY,
|
||||
Kind: types.SIDE_CONTEXT,
|
||||
Focusable: true,
|
||||
})),
|
||||
list: viewModel,
|
||||
getDisplayStrings: getDisplayStrings,
|
||||
c: c,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (self *WorktreesContext) GetSelectedItemId() string {
|
||||
item := self.GetSelected()
|
||||
if item == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return item.ID()
|
||||
}
|
@ -138,6 +138,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
||||
common,
|
||||
func(branches []*models.RemoteBranch) { gui.State.Model.RemoteBranches = branches },
|
||||
)
|
||||
worktreesController := controllers.NewWorktreesController(common)
|
||||
undoController := controllers.NewUndoController(common)
|
||||
globalController := controllers.NewGlobalController(common)
|
||||
contextLinesController := controllers.NewContextLinesController(common)
|
||||
@ -177,6 +178,7 @@ func (gui *Gui) resetHelpersAndControllers() {
|
||||
for _, context := range []types.Context{
|
||||
gui.State.Contexts.Status,
|
||||
gui.State.Contexts.Remotes,
|
||||
gui.State.Contexts.Worktrees,
|
||||
gui.State.Contexts.Tags,
|
||||
gui.State.Contexts.Branches,
|
||||
gui.State.Contexts.RemoteBranches,
|
||||
@ -298,6 +300,10 @@ func (gui *Gui) resetHelpersAndControllers() {
|
||||
remotesController,
|
||||
)
|
||||
|
||||
controllers.AttachControllers(gui.State.Contexts.Worktrees,
|
||||
worktreesController,
|
||||
)
|
||||
|
||||
controllers.AttachControllers(gui.State.Contexts.Stash,
|
||||
stashController,
|
||||
)
|
||||
|
@ -83,6 +83,7 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
||||
types.REFLOG,
|
||||
types.TAGS,
|
||||
types.REMOTES,
|
||||
types.WORKTREES,
|
||||
types.STATUS,
|
||||
types.BISECT_INFO,
|
||||
types.STAGING,
|
||||
@ -150,6 +151,10 @@ func (self *RefreshHelper) Refresh(options types.RefreshOptions) error {
|
||||
refresh("remotes", func() { _ = self.refreshRemotes() })
|
||||
}
|
||||
|
||||
if scopeSet.Includes(types.WORKTREES) {
|
||||
refresh("worktrees", func() { _ = self.refreshWorktrees() })
|
||||
}
|
||||
|
||||
if scopeSet.Includes(types.STAGING) {
|
||||
refresh("staging", func() {
|
||||
fileWg.Wait()
|
||||
@ -197,6 +202,7 @@ func getScopeNames(scopes []types.RefreshableView) []string {
|
||||
types.REFLOG: "reflog",
|
||||
types.TAGS: "tags",
|
||||
types.REMOTES: "remotes",
|
||||
types.WORKTREES: "worktrees",
|
||||
types.STATUS: "status",
|
||||
types.BISECT_INFO: "bisect",
|
||||
types.STAGING: "staging",
|
||||
@ -589,6 +595,17 @@ func (self *RefreshHelper) refreshRemotes() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshWorktrees() error {
|
||||
worktrees, err := self.c.Git().Loaders.Worktrees.GetWorktrees()
|
||||
if err != nil {
|
||||
return self.c.Error(err)
|
||||
}
|
||||
|
||||
self.c.Model().Worktrees = worktrees
|
||||
|
||||
return self.c.PostRefreshUpdate(self.c.Contexts().Worktrees)
|
||||
}
|
||||
|
||||
func (self *RefreshHelper) refreshStashEntries() error {
|
||||
self.c.Model().StashEntries = self.c.Git().Loaders.StashLoader.
|
||||
GetStashEntries(self.c.Modes().Filtering.GetPath())
|
||||
|
186
pkg/gui/controllers/worktrees_controller.go
Normal file
186
pkg/gui/controllers/worktrees_controller.go
Normal file
@ -0,0 +1,186 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/context"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||
)
|
||||
|
||||
type WorktreesController struct {
|
||||
baseController
|
||||
c *ControllerCommon
|
||||
}
|
||||
|
||||
var _ types.IController = &WorktreesController{}
|
||||
|
||||
func NewWorktreesController(
|
||||
common *ControllerCommon,
|
||||
) *WorktreesController {
|
||||
return &WorktreesController{
|
||||
baseController: baseController{},
|
||||
c: common,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *WorktreesController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding {
|
||||
bindings := []*types.Binding{
|
||||
{
|
||||
Key: opts.GetKey(opts.Config.Universal.Select),
|
||||
Handler: self.checkSelected(self.enter),
|
||||
Description: self.c.Tr.EnterWorktree,
|
||||
},
|
||||
//{
|
||||
// Key: opts.GetKey(opts.Config.Universal.Remove),
|
||||
// Handler: self.withSelectedTag(self.delete),
|
||||
// Description: self.c.Tr.LcDeleteTag,
|
||||
//},
|
||||
//{
|
||||
// Key: opts.GetKey(opts.Config.Branches.PushTag),
|
||||
// Handler: self.withSelectedTag(self.push),
|
||||
// Description: self.c.Tr.LcPushTag,
|
||||
//},
|
||||
//{
|
||||
// Key: opts.GetKey(opts.Config.Universal.New),
|
||||
// Handler: self.create,
|
||||
// Description: self.c.Tr.LcCreateTag,
|
||||
//},
|
||||
//{
|
||||
// Key: opts.GetKey(opts.Config.Commits.ViewResetOptions),
|
||||
// Handler: self.withSelectedTag(self.createResetMenu),
|
||||
// Description: self.c.Tr.LcViewResetOptions,
|
||||
// OpensMenu: true,
|
||||
//},
|
||||
}
|
||||
|
||||
return bindings
|
||||
}
|
||||
|
||||
func (self *WorktreesController) GetOnRenderToMain() func() error {
|
||||
return func() error {
|
||||
var task types.UpdateTask
|
||||
worktree := self.context().GetSelected()
|
||||
if worktree == nil {
|
||||
task = types.NewRenderStringTask("No worktrees")
|
||||
} else {
|
||||
task = types.NewRenderStringTask(fmt.Sprintf("%s\nPath: %s", style.FgGreen.Sprint(worktree.Name), worktree.Path))
|
||||
}
|
||||
|
||||
return self.c.RenderToMainViews(types.RefreshMainOpts{
|
||||
Pair: self.c.MainViewPairs().Normal,
|
||||
Main: &types.ViewUpdateOpts{
|
||||
Title: "Worktree",
|
||||
Task: task,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//func (self *WorktreesController) switchToWorktree(worktree *models.Worktree) error {
|
||||
// //self.c.LogAction(self.c.Tr.Actions.CheckoutTag)
|
||||
// //if err := self.helpers.Refs.CheckoutRef(tag.Name, types.CheckoutRefOptions{}); err != nil {
|
||||
// // return err
|
||||
// //}
|
||||
// //return self.c.PushContext(self.contexts.Branches)
|
||||
//
|
||||
// wd, err := os.Getwd()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// gui.RepoPathStack.Push(wd)
|
||||
//
|
||||
// return gui.dispatchSwitchToRepo(submodule.Path, true)
|
||||
//}
|
||||
|
||||
// func (self *WorktreesController) delete(tag *models.Tag) error {
|
||||
// prompt := utils.ResolvePlaceholderString(
|
||||
// self.c.Tr.DeleteTagPrompt,
|
||||
// map[string]string{
|
||||
// "tagName": tag.Name,
|
||||
// },
|
||||
// )
|
||||
//
|
||||
// return self.c.Confirm(types.ConfirmOpts{
|
||||
// Title: self.c.Tr.DeleteTagTitle,
|
||||
// Prompt: prompt,
|
||||
// HandleConfirm: func() error {
|
||||
// self.c.LogAction(self.c.Tr.Actions.DeleteTag)
|
||||
// if err := self.git.Tag.Delete(tag.Name); err != nil {
|
||||
// return self.c.Error(err)
|
||||
// }
|
||||
// return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// func (self *WorktreesController) push(tag *models.Tag) error {
|
||||
// title := utils.ResolvePlaceholderString(
|
||||
// self.c.Tr.PushTagTitle,
|
||||
// map[string]string{
|
||||
// "tagName": tag.Name,
|
||||
// },
|
||||
// )
|
||||
//
|
||||
// return self.c.Prompt(types.PromptOpts{
|
||||
// Title: title,
|
||||
// InitialContent: "origin",
|
||||
// FindSuggestionsFunc: self.helpers.Suggestions.GetRemoteSuggestionsFunc(),
|
||||
// HandleConfirm: func(response string) error {
|
||||
// return self.c.WithWaitingStatus(self.c.Tr.PushingTagStatus, func() error {
|
||||
// self.c.LogAction(self.c.Tr.Actions.PushTag)
|
||||
// err := self.git.Tag.Push(response, tag.Name)
|
||||
// if err != nil {
|
||||
// _ = self.c.Error(err)
|
||||
// }
|
||||
//
|
||||
// return nil
|
||||
// })
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// func (self *WorktreesController) createResetMenu(tag *models.Tag) error {
|
||||
// return self.helpers.Refs.CreateGitResetMenu(tag.Name)
|
||||
// }
|
||||
//
|
||||
// func (self *WorktreesController) create() error {
|
||||
// // leaving commit SHA blank so that we're just creating the tag for the current commit
|
||||
// return self.helpers.Tags.CreateTagMenu("", func() { self.context().SetSelectedLineIdx(0) })
|
||||
// }
|
||||
|
||||
func (self *WorktreesController) GetOnClick() func() error {
|
||||
return self.checkSelected(self.enter)
|
||||
}
|
||||
|
||||
func (self *WorktreesController) enter(worktree *models.Worktree) error {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.c.State().GetRepoPathStack().Push(wd)
|
||||
|
||||
return self.c.Helpers().Repos.DispatchSwitchToRepo(worktree.Path, true)
|
||||
}
|
||||
|
||||
func (self *WorktreesController) checkSelected(callback func(worktree *models.Worktree) error) func() error {
|
||||
return func() error {
|
||||
worktree := self.context().GetSelected()
|
||||
if worktree == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return callback(worktree)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *WorktreesController) Context() types.Context {
|
||||
return self.context()
|
||||
}
|
||||
|
||||
func (self *WorktreesController) context() *context.WorktreesContext {
|
||||
return self.c.Contexts().Worktrees
|
||||
}
|
@ -569,6 +569,10 @@ func (gui *Gui) viewTabMap() map[string][]context.TabView {
|
||||
Tab: gui.c.Tr.TagsTitle,
|
||||
ViewName: "tags",
|
||||
},
|
||||
{
|
||||
Tab: gui.c.Tr.WorktreesTitle,
|
||||
ViewName: "worktrees",
|
||||
},
|
||||
},
|
||||
"commits": {
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ var (
|
||||
MERGE_COMMIT_ICON = "\U000f062d" //
|
||||
DEFAULT_REMOTE_ICON = "\uf02a2" //
|
||||
STASH_ICON = "\uf01c" //
|
||||
WORKTREE_ICON = "\uf02b" //
|
||||
)
|
||||
|
||||
var remoteIcons = map[string]string{
|
||||
@ -68,3 +69,7 @@ func IconForRemote(remote *models.Remote) string {
|
||||
func IconForStash(stash *models.StashEntry) string {
|
||||
return STASH_ICON
|
||||
}
|
||||
|
||||
func IconForWorktree(tag *models.Worktree) string {
|
||||
return WORKTREE_ICON
|
||||
}
|
||||
|
35
pkg/gui/presentation/worktrees.go
Normal file
35
pkg/gui/presentation/worktrees.go
Normal file
@ -0,0 +1,35 @@
|
||||
package presentation
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/generics/slices"
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/presentation/icons"
|
||||
"github.com/jesseduffield/lazygit/pkg/gui/style"
|
||||
"github.com/jesseduffield/lazygit/pkg/theme"
|
||||
)
|
||||
|
||||
func GetWorktreeListDisplayStrings(worktrees []*models.Worktree) [][]string {
|
||||
return slices.Map(worktrees, func(worktree *models.Worktree) []string {
|
||||
return getWorktreeDisplayStrings(worktree)
|
||||
})
|
||||
}
|
||||
|
||||
// getWorktreeDisplayStrings returns the display string of branch
|
||||
func getWorktreeDisplayStrings(w *models.Worktree) []string {
|
||||
textStyle := theme.DefaultTextColor
|
||||
|
||||
current := ""
|
||||
currentColor := style.FgCyan
|
||||
if w.Current {
|
||||
current = " *"
|
||||
currentColor = style.FgGreen
|
||||
}
|
||||
|
||||
res := make([]string, 0, 3)
|
||||
res = append(res, currentColor.Sprint(current))
|
||||
if icons.IsIconEnabled() {
|
||||
res = append(res, textStyle.Sprint(icons.IconForWorktree(w)))
|
||||
}
|
||||
res = append(res, textStyle.Sprint(w.Name))
|
||||
return res
|
||||
}
|
@ -201,6 +201,7 @@ type Model struct {
|
||||
StashEntries []*models.StashEntry
|
||||
SubCommits []*models.Commit
|
||||
Remotes []*models.Remote
|
||||
Worktrees []*models.Worktree
|
||||
|
||||
// FilteredReflogCommits are the ones that appear in the reflog panel.
|
||||
// when in filtering mode we only include the ones that match the given path
|
||||
|
@ -13,6 +13,7 @@ const (
|
||||
REFLOG
|
||||
TAGS
|
||||
REMOTES
|
||||
WORKTREES
|
||||
STATUS
|
||||
SUBMODULES
|
||||
STAGING
|
||||
|
@ -8,6 +8,7 @@ type Views struct {
|
||||
Files *gocui.View
|
||||
Branches *gocui.View
|
||||
Remotes *gocui.View
|
||||
Worktrees *gocui.View
|
||||
Tags *gocui.View
|
||||
RemoteBranches *gocui.View
|
||||
ReflogCommits *gocui.View
|
||||
|
@ -29,6 +29,7 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping {
|
||||
{viewPtr: &gui.Views.Files, name: "files"},
|
||||
{viewPtr: &gui.Views.Tags, name: "tags"},
|
||||
{viewPtr: &gui.Views.Remotes, name: "remotes"},
|
||||
{viewPtr: &gui.Views.Worktrees, name: "worktrees"},
|
||||
{viewPtr: &gui.Views.Branches, name: "localBranches"},
|
||||
{viewPtr: &gui.Views.RemoteBranches, name: "remoteBranches"},
|
||||
{viewPtr: &gui.Views.ReflogCommits, name: "reflogCommits"},
|
||||
@ -113,6 +114,8 @@ func (gui *Gui) createAllViews() error {
|
||||
|
||||
gui.Views.Remotes.Title = gui.c.Tr.RemotesTitle
|
||||
|
||||
gui.Views.Worktrees.Title = gui.c.Tr.WorktreesTitle
|
||||
|
||||
gui.Views.Tags.Title = gui.c.Tr.TagsTitle
|
||||
|
||||
gui.Views.Files.Title = gui.c.Tr.FilesTitle
|
||||
|
@ -200,6 +200,7 @@ type TranslationSet struct {
|
||||
TagsTitle string
|
||||
MenuTitle string
|
||||
RemotesTitle string
|
||||
WorktreesTitle string
|
||||
RemoteBranchesTitle string
|
||||
PatchBuildingTitle string
|
||||
InformationTitle string
|
||||
@ -541,6 +542,7 @@ type TranslationSet struct {
|
||||
FilterPrefix string
|
||||
ExitSearchMode string
|
||||
ExitTextFilterMode string
|
||||
EnterWorktree string
|
||||
Actions Actions
|
||||
Bisect Bisect
|
||||
}
|
||||
@ -897,6 +899,7 @@ func EnglishTranslationSet() TranslationSet {
|
||||
TagsTitle: "Tags",
|
||||
MenuTitle: "Menu",
|
||||
RemotesTitle: "Remotes",
|
||||
WorktreesTitle: "Worktrees",
|
||||
RemoteBranchesTitle: "Remote branches",
|
||||
PatchBuildingTitle: "Main panel (patch building)",
|
||||
InformationTitle: "Information",
|
||||
@ -1239,6 +1242,7 @@ func EnglishTranslationSet() TranslationSet {
|
||||
SearchKeybindings: "%s: Next match, %s: Previous match, %s: Exit search mode",
|
||||
SearchPrefix: "Search: ",
|
||||
FilterPrefix: "Filter: ",
|
||||
EnterWorktree: "Enter worktree",
|
||||
Actions: Actions{
|
||||
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
|
||||
CheckoutCommit: "Checkout commit",
|
||||
|
Loading…
x
Reference in New Issue
Block a user