diff --git a/pkg/commands/models/submodule_config.go b/pkg/commands/models/submodule_config.go index c6481bbd1..f52576921 100644 --- a/pkg/commands/models/submodule_config.go +++ b/pkg/commands/models/submodule_config.go @@ -5,3 +5,15 @@ type SubmoduleConfig struct { Path string Url string } + +func (r *SubmoduleConfig) RefName() string { + return r.Name +} + +func (r *SubmoduleConfig) ID() string { + return r.RefName() +} + +func (r *SubmoduleConfig) Description() string { + return r.RefName() +} diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 585838505..3119065a5 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -34,6 +34,7 @@ const ( CONFIRMATION_CONTEXT_KEY = "confirmation" SEARCH_CONTEXT_KEY = "search" COMMIT_MESSAGE_CONTEXT_KEY = "commitMessage" + SUBMODULES_CONTEXT_KEY = "submodules" ) var allContextKeys = []string{ @@ -57,6 +58,64 @@ var allContextKeys = []string{ CONFIRMATION_CONTEXT_KEY, SEARCH_CONTEXT_KEY, COMMIT_MESSAGE_CONTEXT_KEY, + SUBMODULES_CONTEXT_KEY, +} + +type SimpleContextNode struct { + Context Context +} + +type RemotesContextNode struct { + Context Context + Branches SimpleContextNode +} + +type ContextTree struct { + Status SimpleContextNode + Files SimpleContextNode + Submodules SimpleContextNode + Menu SimpleContextNode + Branches SimpleContextNode + Remotes RemotesContextNode + Tags SimpleContextNode + BranchCommits SimpleContextNode + CommitFiles SimpleContextNode + ReflogCommits SimpleContextNode + SubCommits SimpleContextNode + Stash SimpleContextNode + Normal SimpleContextNode + Staging SimpleContextNode + PatchBuilding SimpleContextNode + Merging SimpleContextNode + Credentials SimpleContextNode + Confirmation SimpleContextNode + CommitMessage SimpleContextNode + Search SimpleContextNode +} + +func (gui *Gui) allContexts() []Context { + return []Context{ + gui.Contexts.Status.Context, + gui.Contexts.Files.Context, + gui.Contexts.Submodules.Context, + gui.Contexts.Branches.Context, + gui.Contexts.Remotes.Context, + gui.Contexts.Remotes.Branches.Context, + gui.Contexts.Tags.Context, + gui.Contexts.BranchCommits.Context, + gui.Contexts.CommitFiles.Context, + gui.Contexts.ReflogCommits.Context, + gui.Contexts.Stash.Context, + gui.Contexts.Menu.Context, + gui.Contexts.Confirmation.Context, + gui.Contexts.Credentials.Context, + gui.Contexts.CommitMessage.Context, + gui.Contexts.Normal.Context, + gui.Contexts.Staging.Context, + gui.Contexts.Merging.Context, + gui.Contexts.PatchBuilding.Context, + gui.Contexts.SubCommits.Context, + } } type Context interface { @@ -139,61 +198,6 @@ func (c BasicContext) GetKey() string { return c.Key } -type SimpleContextNode struct { - Context Context -} - -type RemotesContextNode struct { - Context Context - Branches SimpleContextNode -} - -type ContextTree struct { - Status SimpleContextNode - Files SimpleContextNode - Menu SimpleContextNode - Branches SimpleContextNode - Remotes RemotesContextNode - Tags SimpleContextNode - BranchCommits SimpleContextNode - CommitFiles SimpleContextNode - ReflogCommits SimpleContextNode - SubCommits SimpleContextNode - Stash SimpleContextNode - Normal SimpleContextNode - Staging SimpleContextNode - PatchBuilding SimpleContextNode - Merging SimpleContextNode - Credentials SimpleContextNode - Confirmation SimpleContextNode - CommitMessage SimpleContextNode - Search SimpleContextNode -} - -func (gui *Gui) allContexts() []Context { - return []Context{ - gui.Contexts.Status.Context, - gui.Contexts.Files.Context, - gui.Contexts.Branches.Context, - gui.Contexts.Remotes.Context, - gui.Contexts.Remotes.Branches.Context, - gui.Contexts.Tags.Context, - gui.Contexts.BranchCommits.Context, - gui.Contexts.CommitFiles.Context, - gui.Contexts.ReflogCommits.Context, - gui.Contexts.Stash.Context, - gui.Contexts.Menu.Context, - gui.Contexts.Confirmation.Context, - gui.Contexts.Credentials.Context, - gui.Contexts.CommitMessage.Context, - gui.Contexts.Normal.Context, - gui.Contexts.Staging.Context, - gui.Contexts.Merging.Context, - gui.Contexts.PatchBuilding.Context, - gui.Contexts.SubCommits.Context, - } -} - func (gui *Gui) contextTree() ContextTree { return ContextTree{ Status: SimpleContextNode{ @@ -207,6 +211,9 @@ func (gui *Gui) contextTree() ContextTree { Files: SimpleContextNode{ Context: gui.filesListContext(), }, + Submodules: SimpleContextNode{ + Context: gui.submodulesListContext(), + }, Menu: SimpleContextNode{ Context: gui.menuListContext(), }, @@ -365,6 +372,18 @@ func (gui *Gui) viewTabContextMap() map[string][]tabContext { }, }, }, + "files": { + { + tab: "Files", + contexts: []Context{gui.Contexts.Files.Context}, + }, + { + tab: "Submodules", + contexts: []Context{ + gui.Contexts.Submodules.Context, + }, + }, + }, } } diff --git a/pkg/gui/diffing.go b/pkg/gui/diffing.go index 7da33dee0..58a549d62 100644 --- a/pkg/gui/diffing.go +++ b/pkg/gui/diffing.go @@ -34,7 +34,8 @@ func (gui *Gui) currentDiffTerminals() []string { switch gui.currentContext().GetKey() { case "": return nil - case FILES_CONTEXT_KEY: + case FILES_CONTEXT_KEY, SUBMODULES_CONTEXT_KEY: + // TODO: should we just return nil here? return []string{""} case COMMIT_FILES_CONTEXT_KEY: return []string{gui.State.Panels.CommitFiles.refName} diff --git a/pkg/gui/discard_changes_menu_panel.go b/pkg/gui/discard_changes_menu_panel.go index 8c761a3e9..6805187c4 100644 --- a/pkg/gui/discard_changes_menu_panel.go +++ b/pkg/gui/discard_changes_menu_panel.go @@ -6,7 +6,7 @@ import ( ) func (gui *Gui) submoduleFromFile(file *models.File) *models.SubmoduleConfig { - for _, config := range gui.State.SubmoduleConfigs { + for _, config := range gui.State.Submodules { if config.Name == file.Name { return config } @@ -23,7 +23,7 @@ func (gui *Gui) handleCreateDiscardMenu(g *gocui.Gui, v *gocui.View) error { var menuItems []*menuItem - submoduleConfigs := gui.State.SubmoduleConfigs + submoduleConfigs := gui.State.Submodules if file.IsSubmodule(submoduleConfigs) { submoduleConfig := file.SubmoduleConfig(submoduleConfigs) diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 157b75599..d70309a6a 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -8,7 +8,6 @@ import ( // "strings" "fmt" - "os" "regexp" "strings" @@ -80,7 +79,7 @@ func (gui *Gui) selectFile(alreadySelected bool) error { return gui.refreshMainViews(refreshOpts) } -func (gui *Gui) refreshFiles() error { +func (gui *Gui) refreshFilesAndSubmodules() error { gui.State.RefreshingFilesMutex.Lock() gui.State.IsRefreshingFiles = true defer func() { @@ -103,15 +102,25 @@ func (gui *Gui) refreshFiles() error { } gui.g.Update(func(g *gocui.Gui) error { - if err := gui.Contexts.Files.Context.HandleRender(); err != nil { - return err + if err := gui.postRefreshUpdate(gui.Contexts.Submodules.Context); err != nil { + gui.Log.Error(err) } - if g.CurrentView() == filesView || (g.CurrentView() == gui.getMainView() && g.CurrentView().Context == MAIN_MERGING_CONTEXT_KEY) { + if gui.getFilesView().Context == FILES_CONTEXT_KEY { + // doing this a little custom (as opposed to using gui.postRefreshUpdate) because we handle selecting the file explicitly below + if err := gui.Contexts.Files.Context.HandleRender(); err != nil { + return err + } + } + + if gui.currentContext().GetKey() == FILES_CONTEXT_KEY || (g.CurrentView() == gui.getMainView() && g.CurrentView().Context == MAIN_MERGING_CONTEXT_KEY) { newSelectedFile := gui.getSelectedFile() alreadySelected := selectedFile != nil && newSelectedFile != nil && newSelectedFile.Name == selectedFile.Name - return gui.selectFile(alreadySelected) + if err := gui.selectFile(alreadySelected); err != nil { + return err + } } + return nil }) @@ -161,15 +170,10 @@ func (gui *Gui) enterFile(forceSecondaryFocused bool, selectedLineIdx int) error return nil } - submoduleConfigs := gui.State.SubmoduleConfigs + submoduleConfigs := gui.State.Submodules if file.IsSubmodule(submoduleConfigs) { - wd, err := os.Getwd() - if err != nil { - return err - } - gui.State.RepoPathStack = append(gui.State.RepoPathStack, wd) submoduleConfig := file.SubmoduleConfig(submoduleConfigs) - return gui.dispatchSwitchToRepo(submoduleConfig.Path) + return gui.enterSubmodule(submoduleConfig) } if file.HasInlineMergeConflicts { @@ -325,7 +329,7 @@ func (gui *Gui) promptToStageAllAndRetry(retry func() error) error { if err := gui.GitCommand.StageAll(); err != nil { return gui.surfaceError(err) } - if err := gui.refreshFiles(); err != nil { + if err := gui.refreshFilesAndSubmodules(); err != nil { return gui.surfaceError(err) } @@ -448,7 +452,7 @@ func (gui *Gui) refreshStateSubmoduleConfigs() error { return err } - gui.State.SubmoduleConfigs = configs + gui.State.Submodules = configs return nil } diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 57d450f8a..06d79e12d 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -209,6 +209,10 @@ type commitFilesPanelState struct { canRebase bool } +type submodulePanelState struct { + listPanelState +} + type panelStates struct { Files *filePanelState Branches *branchPanelState @@ -223,6 +227,7 @@ type panelStates struct { LineByLine *lineByLinePanelState Merging *mergingPanelState CommitFiles *commitFilesPanelState + Submodules *submodulePanelState } type searchingState struct { @@ -273,12 +278,12 @@ type Modes struct { } type guiState struct { - Files []*models.File - SubmoduleConfigs []*models.SubmoduleConfig - Branches []*models.Branch - Commits []*models.Commit - StashEntries []*models.StashEntry - CommitFiles []*models.CommitFile + Files []*models.File + Submodules []*models.SubmoduleConfig + Branches []*models.Branch + Commits []*models.Commit + StashEntries []*models.StashEntry + CommitFiles []*models.CommitFile // FilteredReflogCommits are the ones that appear in the reflog panel. // when in filtering mode we only include the ones that match the given path FilteredReflogCommits []*models.Commit @@ -358,6 +363,7 @@ func (gui *Gui) resetState() { Panels: &panelStates{ // TODO: work out why some of these are -1 and some are 0. Last time I checked there was a good reason but I'm less certain now Files: &filePanelState{listPanelState{SelectedLineIdx: -1}}, + Submodules: &submodulePanelState{listPanelState{SelectedLineIdx: -1}}, Branches: &branchPanelState{listPanelState{SelectedLineIdx: 0}}, Remotes: &remotePanelState{listPanelState{SelectedLineIdx: 0}}, RemoteBranches: &remoteBranchesState{listPanelState{SelectedLineIdx: -1}}, @@ -456,7 +462,7 @@ func (gui *Gui) Run() error { go gui.startBackgroundFetch() } - gui.goEvery(time.Second*10, gui.stopChan, gui.refreshFiles) + gui.goEvery(time.Second*10, gui.stopChan, gui.refreshFilesAndSubmodules) g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout())) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 5abe3d989..b08f3df92 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -363,102 +363,119 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.commitChanges"), Handler: gui.wrappedHandler(gui.handleCommitPress), Description: gui.Tr.SLocalize("CommitChanges"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.commitChangesWithoutHook"), Handler: gui.handleWIPCommitPress, Description: gui.Tr.SLocalize("commitChangesWithoutHook"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.amendLastCommit"), Handler: gui.wrappedHandler(gui.handleAmendCommitPress), Description: gui.Tr.SLocalize("AmendLastCommit"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.commitChangesWithEditor"), Handler: gui.wrappedHandler(gui.handleCommitEditorPress), Description: gui.Tr.SLocalize("CommitChangesWithEditor"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("universal.select"), Handler: gui.wrappedHandler(gui.handleFilePress), Description: gui.Tr.SLocalize("toggleStaged"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("universal.remove"), Handler: gui.handleCreateDiscardMenu, Description: gui.Tr.SLocalize("viewDiscardOptions"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("universal.edit"), Handler: gui.handleFileEdit, Description: gui.Tr.SLocalize("editFile"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("universal.openFile"), Handler: gui.handleFileOpen, Description: gui.Tr.SLocalize("openFile"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.ignoreFile"), Handler: gui.handleIgnoreFile, Description: gui.Tr.SLocalize("ignoreFile"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.refreshFiles"), Handler: gui.handleRefreshFiles, Description: gui.Tr.SLocalize("refreshFiles"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.stashAllChanges"), Handler: gui.handleStashChanges, Description: gui.Tr.SLocalize("stashAllChanges"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.viewStashOptions"), Handler: gui.handleCreateStashMenu, Description: gui.Tr.SLocalize("viewStashOptions"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.toggleStagedAll"), Handler: gui.handleStageAll, Description: gui.Tr.SLocalize("toggleStagedAll"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.viewResetOptions"), Handler: gui.handleCreateResetMenu, Description: gui.Tr.SLocalize("viewResetOptions"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("universal.goInto"), Handler: gui.handleEnterFile, Description: gui.Tr.SLocalize("StageLines"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("files.fetch"), Handler: gui.handleGitFetch, Description: gui.Tr.SLocalize("fetch"), }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("universal.copyToClipboard"), Handler: gui.wrappedHandler(gui.handleCopySelectedSideContextItemToClipboard), Description: gui.Tr.SLocalize("copyFileNameToClipboard"), @@ -471,6 +488,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { }, { ViewName: "files", + Contexts: []string{FILES_CONTEXT_KEY}, Key: gui.getKey("commits.viewResetOptions"), Handler: gui.handleCreateResetToUpstreamMenu, Description: gui.Tr.SLocalize("viewResetToUpstreamOptions"), @@ -1542,6 +1560,32 @@ func (gui *Gui) GetInitialKeybindings() []*Binding { Modifier: gocui.ModNone, Handler: gui.wrappedHandler(gui.onMenuPress), }, + { + ViewName: "files", + Contexts: []string{SUBMODULES_CONTEXT_KEY}, + Key: gui.getKey("universal.goInto"), + Handler: gui.wrappedHandler(gui.handleSubmoduleEnter), + Description: gui.Tr.SLocalize("enterSubmodule"), + }, + { + ViewName: "files", + Key: gui.getKey("universal.nextTab"), + Handler: gui.handleNextTab, + Description: gui.Tr.SLocalize("nextTab"), + }, + { + ViewName: "files", + Key: gui.getKey("universal.prevTab"), + Handler: gui.handlePrevTab, + Description: gui.Tr.SLocalize("prevTab"), + }, + { + ViewName: "files", + Contexts: []string{SUBMODULES_CONTEXT_KEY}, + Key: gui.getKey("universal.copyToClipboard"), + Handler: gui.wrappedHandler(gui.handleCopySelectedSideContextItemToClipboard), + Description: gui.Tr.SLocalize("copySubmoduleNameToClipboard"), + }, } for _, viewName := range []string{"status", "branches", "files", "commits", "commitFiles", "stash", "menu"} { diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 2aa01c6a7..e27a46457 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -285,8 +285,10 @@ func (gui *Gui) layout(g *gocui.Gui) error { listContext *ListContext } + // TODO: don't we already have the view included in the context object itself? Or might that change in a way we don't want reflected here? listContextStates := []listContextState{ {view: filesView, listContext: gui.filesListContext()}, + {view: filesView, listContext: gui.submodulesListContext()}, {view: branchesView, listContext: gui.branchesListContext()}, {view: branchesView, listContext: gui.remotesListContext()}, {view: branchesView, listContext: gui.remoteBranchesListContext()}, diff --git a/pkg/gui/list_context.go b/pkg/gui/list_context.go index e2dec2a96..c360b2f2a 100644 --- a/pkg/gui/list_context.go +++ b/pkg/gui/list_context.go @@ -270,7 +270,7 @@ func (gui *Gui) filesListContext() *ListContext { ResetMainViewOriginOnFocus: false, Kind: SIDE_CONTEXT, GetDisplayStrings: func() [][]string { - return presentation.GetFileListDisplayStrings(gui.State.Files, gui.State.Modes.Diffing.Ref, gui.State.SubmoduleConfigs) + return presentation.GetFileListDisplayStrings(gui.State.Files, gui.State.Modes.Diffing.Ref, gui.State.Submodules) }, SelectedItem: func() (ListItem, bool) { item := gui.getSelectedFile() @@ -462,6 +462,27 @@ func (gui *Gui) commitFilesListContext() *ListContext { } } +func (gui *Gui) submodulesListContext() *ListContext { + return &ListContext{ + ViewName: "files", + WindowName: "files", + ContextKey: SUBMODULES_CONTEXT_KEY, + GetItemsLength: func() int { return len(gui.State.Submodules) }, + GetPanelState: func() IListPanelState { return gui.State.Panels.Submodules }, + OnFocus: gui.handleSubmoduleSelect, + Gui: gui, + ResetMainViewOriginOnFocus: true, + Kind: SIDE_CONTEXT, + GetDisplayStrings: func() [][]string { + return presentation.GetSubmoduleListDisplayStrings(gui.State.Submodules) + }, + SelectedItem: func() (ListItem, bool) { + item := gui.getSelectedSubmodule() + return item, item != nil + }, + } +} + func (gui *Gui) getListContexts() []*ListContext { return []*ListContext{ gui.menuListContext(), @@ -475,6 +496,7 @@ func (gui *Gui) getListContexts() []*ListContext { gui.subCommitsListContext(), gui.stashListContext(), gui.commitFilesListContext(), + gui.submodulesListContext(), } } diff --git a/pkg/gui/presentation/submodules.go b/pkg/gui/presentation/submodules.go new file mode 100644 index 000000000..6b42d76f0 --- /dev/null +++ b/pkg/gui/presentation/submodules.go @@ -0,0 +1,21 @@ +package presentation + +import ( + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/theme" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +func GetSubmoduleListDisplayStrings(submodules []*models.SubmoduleConfig) [][]string { + lines := make([][]string, len(submodules)) + + for i := range submodules { + lines[i] = getSubmoduleDisplayStrings(submodules[i]) + } + + return lines +} + +func getSubmoduleDisplayStrings(s *models.SubmoduleConfig) []string { + return []string{utils.ColoredString(s.Name, theme.DefaultTextColor)} +} diff --git a/pkg/gui/submodules_panel.go b/pkg/gui/submodules_panel.go new file mode 100644 index 000000000..e956a30f4 --- /dev/null +++ b/pkg/gui/submodules_panel.go @@ -0,0 +1,135 @@ +package gui + +import ( + "fmt" + "os" + + "github.com/fatih/color" + "github.com/jesseduffield/lazygit/pkg/commands/models" + "github.com/jesseduffield/lazygit/pkg/utils" +) + +func (gui *Gui) getSelectedSubmodule() *models.SubmoduleConfig { + selectedLine := gui.State.Panels.Submodules.SelectedLineIdx + if selectedLine == -1 || len(gui.State.Submodules) == 0 { + return nil + } + + return gui.State.Submodules[selectedLine] +} + +func (gui *Gui) handleSubmoduleSelect() error { + var task updateTask + submodule := gui.getSelectedSubmodule() + if submodule == nil { + task = gui.createRenderStringTask("No submodules") + } else { + // TODO: we want to display the path, name, url, and a diff. We really need to be able to pipe commands together. We can always pipe commands together and just not do it asynchronously, but what if it's an expensive diff to obtain? I think that makes the most sense now though. + task = gui.createRenderStringTask( + fmt.Sprintf( + "Name: %s\nPath: %s\nUrl: %s\n", + utils.ColoredString(submodule.Name, color.FgGreen), + utils.ColoredString(submodule.Path, color.FgYellow), + utils.ColoredString(submodule.Url, color.FgCyan), + ), + ) + } + + return gui.refreshMainViews(refreshMainOpts{ + main: &viewUpdateOpts{ + title: "Submodule", + task: task, + }, + }) +} + +func (gui *Gui) handleSubmoduleEnter() error { + submodule := gui.getSelectedSubmodule() + if submodule == nil { + return nil + } + + return gui.enterSubmodule(submodule) +} + +func (gui *Gui) enterSubmodule(submodule *models.SubmoduleConfig) error { + wd, err := os.Getwd() + if err != nil { + return err + } + gui.State.RepoPathStack = append(gui.State.RepoPathStack, wd) + + return gui.dispatchSwitchToRepo(submodule.Path) +} + +// func (gui *Gui) handleAddRemote(g *gocui.Gui, v *gocui.View) error { +// return gui.prompt(gui.Tr.SLocalize("newRemoteName"), "", func(remoteName string) error { +// return gui.prompt(gui.Tr.SLocalize("newRemoteUrl"), "", func(remoteUrl string) error { +// if err := gui.GitCommand.AddRemote(remoteName, remoteUrl); err != nil { +// return err +// } +// return gui.refreshSidePanels(refreshOptions{scope: []int{REMOTES}}) +// }) +// }) +// } + +// func (gui *Gui) handleRemoveRemote(g *gocui.Gui, v *gocui.View) error { +// remote := gui.getSelectedSubmodule() +// if remote == nil { +// return nil +// } + +// return gui.ask(askOpts{ +// title: gui.Tr.SLocalize("removeRemote"), +// prompt: gui.Tr.SLocalize("removeRemotePrompt") + " '" + remote.Name + "'?", +// handleConfirm: func() error { +// if err := gui.GitCommand.RemoveRemote(remote.Name); err != nil { +// return err +// } + +// return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) +// }, +// }) +// } + +// func (gui *Gui) handleEditRemote(g *gocui.Gui, v *gocui.View) error { +// remote := gui.getSelectedSubmodule() +// if remote == nil { +// return nil +// } + +// editNameMessage := gui.Tr.TemplateLocalize( +// "editRemoteName", +// Teml{ +// "remoteName": remote.Name, +// }, +// ) + +// return gui.prompt(editNameMessage, remote.Name, func(updatedRemoteName string) error { +// if updatedRemoteName != remote.Name { +// if err := gui.GitCommand.RenameRemote(remote.Name, updatedRemoteName); err != nil { +// return gui.surfaceError(err) +// } +// } + +// editUrlMessage := gui.Tr.TemplateLocalize( +// "editRemoteUrl", +// Teml{ +// "remoteName": updatedRemoteName, +// }, +// ) + +// urls := remote.Urls +// url := "" +// if len(urls) > 0 { +// url = urls[0] +// } + +// return gui.prompt(editUrlMessage, url, func(updatedRemoteUrl string) error { +// if err := gui.GitCommand.UpdateRemoteUrl(updatedRemoteName, updatedRemoteUrl); err != nil { +// return gui.surfaceError(err) +// } +// return gui.refreshSidePanels(refreshOptions{scope: []int{BRANCHES, REMOTES}}) +// }) +// }) +// } diff --git a/pkg/gui/view_helpers.go b/pkg/gui/view_helpers.go index d7eab73ba..f2b5b6026 100644 --- a/pkg/gui/view_helpers.go +++ b/pkg/gui/view_helpers.go @@ -25,18 +25,20 @@ const ( TAGS REMOTES STATUS + SUBMODULES ) func getScopeNames(scopes []int) []string { scopeNameMap := map[int]string{ - COMMITS: "commits", - BRANCHES: "branches", - FILES: "files", - STASH: "stash", - REFLOG: "reflog", - TAGS: "tags", - REMOTES: "remotes", - STATUS: "status", + COMMITS: "commits", + BRANCHES: "branches", + FILES: "files", + SUBMODULES: "submodules", + STASH: "stash", + REFLOG: "reflog", + TAGS: "tags", + REMOTES: "remotes", + STATUS: "status", } scopeNames := make([]string, len(scopes)) @@ -116,13 +118,13 @@ func (gui *Gui) refreshSidePanels(options refreshOptions) error { }() } - if scopeMap[FILES] { + if scopeMap[FILES] || scopeMap[SUBMODULES] { wg.Add(1) func() { if options.mode == ASYNC { - go gui.refreshFiles() + go gui.refreshFilesAndSubmodules() } else { - gui.refreshFiles() + gui.refreshFilesAndSubmodules() } wg.Done() }() diff --git a/pkg/gui/workspace_reset_options_panel.go b/pkg/gui/workspace_reset_options_panel.go index 93b33f56e..6695c6cb5 100644 --- a/pkg/gui/workspace_reset_options_panel.go +++ b/pkg/gui/workspace_reset_options_panel.go @@ -11,7 +11,7 @@ func (gui *Gui) handleCreateResetMenu(g *gocui.Gui, v *gocui.View) error { red := color.New(color.FgRed) nukeStr := "reset --hard HEAD && git clean -fd" - if len(gui.State.SubmoduleConfigs) > 0 { + if len(gui.State.Submodules) > 0 { nukeStr = fmt.Sprintf("%s (%s)", nukeStr, gui.Tr.SLocalize("andResetSubmodules")) } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index afce1cffd..45a13647f 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -1197,6 +1197,12 @@ func addEnglish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "andResetSubmodules", Other: "and reset submodules", + }, &i18n.Message{ + ID: "enterSubmodule", + Other: "enter submodule", + }, &i18n.Message{ + ID: "copySubmoduleNameToClipboard", + Other: "copy submodule name to clipboard", }, ) }