From f8ba899b8734db7dcf3ae57cc34939db18a1a414 Mon Sep 17 00:00:00 2001 From: Joel Baranick Date: Thu, 1 Sep 2022 11:25:41 -0700 Subject: [PATCH] Initial addition of support for worktrees --- .gitignore | 2 + pkg/cheatsheet/generate.go | 1 + pkg/commands/git.go | 3 + pkg/commands/git_commands/branch_loader.go | 12 ++ pkg/commands/git_commands/worktree_loader.go | 80 ++++++++ pkg/commands/models/worktree.go | 21 ++ pkg/gui/context/context.go | 4 + pkg/gui/context/setup.go | 1 + pkg/gui/context/worktrees_context.go | 52 +++++ pkg/gui/controllers.go | 6 + pkg/gui/controllers/helpers/refresh_helper.go | 17 ++ pkg/gui/controllers/worktrees_controller.go | 186 ++++++++++++++++++ pkg/gui/gui.go | 4 + pkg/gui/presentation/icons/git_icons.go | 5 + pkg/gui/presentation/worktrees.go | 35 ++++ pkg/gui/types/common.go | 1 + pkg/gui/types/refresh.go | 1 + pkg/gui/types/views.go | 1 + pkg/gui/views.go | 3 + pkg/i18n/english.go | 4 + 20 files changed, 439 insertions(+) create mode 100644 pkg/commands/git_commands/worktree_loader.go create mode 100644 pkg/commands/models/worktree.go create mode 100644 pkg/gui/context/worktrees_context.go create mode 100644 pkg/gui/controllers/worktrees_controller.go create mode 100644 pkg/gui/presentation/worktrees.go diff --git a/.gitignore b/.gitignore index 09b2235f1..548902f7b 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ test/results/** oryxBuildBinary __debug_bin + +.worktrees \ No newline at end of file diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index f1e8a3487..112e4c4d5 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -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] diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 3a2349fd5..6e74daa52 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -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, }, diff --git a/pkg/commands/git_commands/branch_loader.go b/pkg/commands/git_commands/branch_loader.go index cb284f67f..bab24bfa7 100644 --- a/pkg/commands/git_commands/branch_loader.go +++ b/pkg/commands/git_commands/branch_loader.go @@ -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() diff --git a/pkg/commands/git_commands/worktree_loader.go b/pkg/commands/git_commands/worktree_loader.go new file mode 100644 index 000000000..905754540 --- /dev/null +++ b/pkg/commands/git_commands/worktree_loader.go @@ -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 +} diff --git a/pkg/commands/models/worktree.go b/pkg/commands/models/worktree.go new file mode 100644 index 000000000..f38c67e07 --- /dev/null +++ b/pkg/commands/models/worktree.go @@ -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() +} diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index ab188d761..12fc285ae 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -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, diff --git a/pkg/gui/context/setup.go b/pkg/gui/context/setup.go index 775803884..ecb47d3f8 100644 --- a/pkg/gui/context/setup.go +++ b/pkg/gui/context/setup.go @@ -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, diff --git a/pkg/gui/context/worktrees_context.go b/pkg/gui/context/worktrees_context.go new file mode 100644 index 000000000..6ce8f8a80 --- /dev/null +++ b/pkg/gui/context/worktrees_context.go @@ -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() +} diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index d2ee837ae..328620d48 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -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, ) diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index c8fbe8627..8431ae4cf 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -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()) diff --git a/pkg/gui/controllers/worktrees_controller.go b/pkg/gui/controllers/worktrees_controller.go new file mode 100644 index 000000000..f3b5ed60b --- /dev/null +++ b/pkg/gui/controllers/worktrees_controller.go @@ -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 +} diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 9a8d96712..0de209fd1 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -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": { { diff --git a/pkg/gui/presentation/icons/git_icons.go b/pkg/gui/presentation/icons/git_icons.go index 6fd8bfb57..0111ca2b5 100644 --- a/pkg/gui/presentation/icons/git_icons.go +++ b/pkg/gui/presentation/icons/git_icons.go @@ -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 +} diff --git a/pkg/gui/presentation/worktrees.go b/pkg/gui/presentation/worktrees.go new file mode 100644 index 000000000..4bb778944 --- /dev/null +++ b/pkg/gui/presentation/worktrees.go @@ -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 +} diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index e485fbceb..b0944fb92 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -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 diff --git a/pkg/gui/types/refresh.go b/pkg/gui/types/refresh.go index 6d6c6f8a4..552bfae04 100644 --- a/pkg/gui/types/refresh.go +++ b/pkg/gui/types/refresh.go @@ -13,6 +13,7 @@ const ( REFLOG TAGS REMOTES + WORKTREES STATUS SUBMODULES STAGING diff --git a/pkg/gui/types/views.go b/pkg/gui/types/views.go index 8b8a62e61..69a79f8a0 100644 --- a/pkg/gui/types/views.go +++ b/pkg/gui/types/views.go @@ -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 diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 8567af797..594ca5fb3 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -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 diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 34f9e66e0..a47056b55 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -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",