mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-31 14:24:25 +03:00
add submodules context
This commit is contained in:
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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.postRefreshUpdate(gui.Contexts.Submodules.Context); err != nil {
|
||||
gui.Log.Error(err)
|
||||
}
|
||||
|
||||
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 g.CurrentView() == filesView || (g.CurrentView() == gui.getMainView() && g.CurrentView().Context == MAIN_MERGING_CONTEXT_KEY) {
|
||||
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
|
||||
}
|
||||
|
@ -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 {
|
||||
@ -274,7 +279,7 @@ type Modes struct {
|
||||
|
||||
type guiState struct {
|
||||
Files []*models.File
|
||||
SubmoduleConfigs []*models.SubmoduleConfig
|
||||
Submodules []*models.SubmoduleConfig
|
||||
Branches []*models.Branch
|
||||
Commits []*models.Commit
|
||||
StashEntries []*models.StashEntry
|
||||
@ -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()))
|
||||
|
||||
|
@ -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"} {
|
||||
|
@ -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()},
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
21
pkg/gui/presentation/submodules.go
Normal file
21
pkg/gui/presentation/submodules.go
Normal file
@ -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)}
|
||||
}
|
135
pkg/gui/submodules_panel.go
Normal file
135
pkg/gui/submodules_panel.go
Normal file
@ -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}})
|
||||
// })
|
||||
// })
|
||||
// }
|
@ -25,6 +25,7 @@ const (
|
||||
TAGS
|
||||
REMOTES
|
||||
STATUS
|
||||
SUBMODULES
|
||||
)
|
||||
|
||||
func getScopeNames(scopes []int) []string {
|
||||
@ -32,6 +33,7 @@ func getScopeNames(scopes []int) []string {
|
||||
COMMITS: "commits",
|
||||
BRANCHES: "branches",
|
||||
FILES: "files",
|
||||
SUBMODULES: "submodules",
|
||||
STASH: "stash",
|
||||
REFLOG: "reflog",
|
||||
TAGS: "tags",
|
||||
@ -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()
|
||||
}()
|
||||
|
@ -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"))
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user