diff --git a/pkg/gui/commit_files_panel.go b/pkg/gui/commit_files_panel.go index 05f23374c..d4cef7b14 100644 --- a/pkg/gui/commit_files_panel.go +++ b/pkg/gui/commit_files_panel.go @@ -46,10 +46,16 @@ func (gui *Gui) commitFilesRenderToMain() error { cmdObj := gui.git.WorkingTree.ShowFileDiffCmdObj(from, to, reverse, node.GetPath(), false) task := NewRunPtyTask(cmdObj.GetCmd()) + mainContext := gui.State.Contexts.Normal + if node.File != nil { + mainContext = gui.State.Contexts.PatchBuilding + } + return gui.refreshMainViews(refreshMainOpts{ main: &viewUpdateOpts{ - title: "Patch", - task: task, + title: "Patch", + task: task, + context: mainContext, }, secondary: gui.secondaryPatchPanelUpdateOpts(), }) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 657274c1f..f8aa9134e 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -11,7 +11,7 @@ import ( func (gui *Gui) popupViewNames() []string { result := []string{} - for _, context := range gui.allContexts() { + for _, context := range gui.State.Contexts.Flatten() { if context.GetKind() == types.PERSISTENT_POPUP || context.GetKind() == types.TEMPORARY_POPUP { result = append(result, context.GetViewName()) } @@ -44,6 +44,10 @@ func (gui *Gui) replaceContext(c types.Context) error { gui.State.ContextManager.Lock() defer gui.State.ContextManager.Unlock() + if !c.IsFocusable() { + return nil + } + if len(gui.State.ContextManager.ContextStack) == 0 { gui.State.ContextManager.ContextStack = []types.Context{c} } else { @@ -60,8 +64,9 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { return errors.New("cannot pass multiple opts to pushContext") } - if c.GetKey() == context.GLOBAL_CONTEXT_KEY { - return errors.New("Cannot push global context") + if !c.IsFocusable() { + panic(c.GetKey()) + return nil } gui.State.ContextManager.Lock() @@ -97,7 +102,7 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { // want to switch to: you only know the view that you want to switch to. It will // look up the context currently active for that view and switch to that context func (gui *Gui) pushContextWithView(viewName string) error { - return gui.c.PushContext(gui.State.ViewContextMap[viewName]) + return gui.c.PushContext(gui.State.ViewContextMap.Get(viewName)) } func (gui *Gui) returnFromContext() error { @@ -152,7 +157,7 @@ func (gui *Gui) deactivateContext(c types.Context) error { // if the context's view is set to another context we do nothing. // if the context's view is the current view we trigger a focus; re-selecting the current item. func (gui *Gui) postRefreshUpdate(c types.Context) error { - if gui.State.ViewContextMap[c.GetViewName()].GetKey() != c.GetKey() { + if gui.State.ViewContextMap.Get(c.GetViewName()).GetKey() != c.GetKey() { return nil } @@ -175,7 +180,7 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro if err != nil { return err } - originalViewContextKey := gui.State.ViewContextMap[viewName].GetKey() + originalViewContextKey := gui.State.ViewContextMap.Get(viewName).GetKey() gui.setWindowContext(c) gui.setViewTabForContext(c) @@ -200,7 +205,7 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro } } - gui.State.ViewContextMap[viewName] = c + gui.ViewContextMapSet(viewName, c) gui.g.Cursor = v.Editable @@ -215,12 +220,19 @@ func (gui *Gui) activateContext(c types.Context, opts ...types.OnFocusOpts) erro return err } - // TODO: consider removing this and instead depending on the .Context field of views - gui.State.ViewContextMap[c.GetViewName()] = c - return nil } +// also setting context on view for now. We'll need to pick one of these two approaches to stick with. +func (gui *Gui) ViewContextMapSet(viewName string, c types.Context) { + gui.State.ViewContextMap.Set(viewName, c) + view, err := gui.g.View(viewName) + if err != nil { + panic(err) + } + view.Context = string(c.GetKey()) +} + // // currently unused // func (gui *Gui) renderContextStack() string { // result := "" @@ -369,8 +381,8 @@ func (gui *Gui) changeMainViewsContext(c types.Context) { switch c.GetKey() { case context.MAIN_NORMAL_CONTEXT_KEY, context.MAIN_PATCH_BUILDING_CONTEXT_KEY, context.MAIN_STAGING_CONTEXT_KEY, context.MAIN_MERGING_CONTEXT_KEY: - gui.State.ViewContextMap[gui.Views.Main.Name()] = c - gui.State.ViewContextMap[gui.Views.Secondary.Name()] = c + gui.ViewContextMapSet(gui.Views.Main.Name(), c) + gui.ViewContextMapSet(gui.Views.Secondary.Name(), c) default: panic(fmt.Sprintf("unknown context for main: %s", c.GetKey())) } @@ -416,18 +428,8 @@ func (gui *Gui) setViewTabForContext(c types.Context) { } } -func (gui *Gui) mustContextForContextKey(contextKey types.ContextKey) types.Context { - context, ok := gui.contextForContextKey(contextKey) - - if !ok { - panic(fmt.Sprintf("context not found for key %s", contextKey)) - } - - return context -} - func (gui *Gui) contextForContextKey(contextKey types.ContextKey) (types.Context, bool) { - for _, context := range gui.allContexts() { + for _, context := range gui.State.Contexts.Flatten() { if context.GetKey() == contextKey { return context, true } @@ -437,13 +439,7 @@ func (gui *Gui) contextForContextKey(contextKey types.ContextKey) (types.Context } func (gui *Gui) rerenderView(view *gocui.View) error { - context, ok := gui.State.ViewContextMap[view.Name()] - - if !ok { - panic("no context set against view " + view.Name()) - } - - return context.HandleRender() + return gui.State.ViewContextMap.Get(view.Name()).HandleRender() } func (gui *Gui) getSideContextSelectedItemId() string { @@ -456,7 +452,7 @@ func (gui *Gui) getSideContextSelectedItemId() string { } func (gui *Gui) isContextVisible(c types.Context) bool { - return gui.State.WindowViewNameMap[c.GetWindowName()] == c.GetViewName() && gui.State.ViewContextMap[c.GetViewName()].GetKey() == c.GetKey() + return gui.State.WindowViewNameMap[c.GetWindowName()] == c.GetViewName() && gui.State.ViewContextMap.Get(c.GetViewName()).GetKey() == c.GetKey() } // currently unused diff --git a/pkg/gui/context/base_context.go b/pkg/gui/context/base_context.go index 5dbc3cbf4..b4beb293d 100644 --- a/pkg/gui/context/base_context.go +++ b/pkg/gui/context/base_context.go @@ -15,6 +15,8 @@ type BaseContext struct { keybindingsFns []types.KeybindingsFn mouseKeybindingsFns []types.MouseKeybindingsFn + focusable bool + *ParentContextMgr } @@ -25,6 +27,7 @@ type NewBaseContextOpts struct { Key types.ContextKey ViewName string WindowName string + Focusable bool OnGetOptionsMap func() map[string]string } @@ -36,6 +39,7 @@ func NewBaseContext(opts NewBaseContextOpts) *BaseContext { ViewName: opts.ViewName, windowName: opts.WindowName, onGetOptionsMap: opts.OnGetOptionsMap, + focusable: opts.Focusable, ParentContextMgr: &ParentContextMgr{}, } } @@ -96,3 +100,7 @@ func (self *BaseContext) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocu return bindings } + +func (self *BaseContext) IsFocusable() bool { + return self.focusable +} diff --git a/pkg/gui/context/commit_files_context.go b/pkg/gui/context/commit_files_context.go index 49a9f34da..e729fb3c1 100644 --- a/pkg/gui/context/commit_files_context.go +++ b/pkg/gui/context/commit_files_context.go @@ -31,6 +31,7 @@ func NewCommitFilesContext( WindowName: "commits", Key: COMMIT_FILES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }) self := &CommitFilesContext{} diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index b45a089be..710e9a590 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -30,7 +30,7 @@ const ( ) var AllContextKeys = []types.ContextKey{ - GLOBAL_CONTEXT_KEY, + GLOBAL_CONTEXT_KEY, // not focusable STATUS_CONTEXT_KEY, FILES_CONTEXT_KEY, LOCAL_BRANCHES_CONTEXT_KEY, @@ -42,10 +42,10 @@ var AllContextKeys = []types.ContextKey{ SUB_COMMITS_CONTEXT_KEY, COMMIT_FILES_CONTEXT_KEY, STASH_CONTEXT_KEY, - MAIN_NORMAL_CONTEXT_KEY, + MAIN_NORMAL_CONTEXT_KEY, // not focusable MAIN_MERGING_CONTEXT_KEY, MAIN_PATCH_BUILDING_CONTEXT_KEY, - MAIN_STAGING_CONTEXT_KEY, + MAIN_STAGING_CONTEXT_KEY, // not focusable for secondary view MENU_CONTEXT_KEY, CREDENTIALS_CONTEXT_KEY, CONFIRMATION_CONTEXT_KEY, @@ -83,24 +83,50 @@ type ContextTree struct { CommandLog types.Context } -func (tree ContextTree) InitialViewContextMap() map[string]types.Context { - return map[string]types.Context{ - "status": tree.Status, - "files": tree.Files, - "branches": tree.Branches, - "commits": tree.BranchCommits, - "commitFiles": tree.CommitFiles, - "stash": tree.Stash, - "menu": tree.Menu, - "confirmation": tree.Confirmation, - "credentials": tree.Credentials, - "commitMessage": tree.CommitMessage, - "main": tree.Normal, - "secondary": tree.Normal, - "extras": tree.CommandLog, +func (self *ContextTree) Flatten() []types.Context { + return []types.Context{ + self.Global, + self.Status, + self.Files, + self.Submodules, + self.Branches, + self.Remotes, + self.RemoteBranches, + self.Tags, + self.BranchCommits, + self.CommitFiles, + self.ReflogCommits, + self.Stash, + self.Menu, + self.Confirmation, + self.Credentials, + self.CommitMessage, + self.Normal, + self.Staging, + self.Merging, + self.PatchBuilding, + self.SubCommits, + self.Suggestions, + self.CommandLog, } } +type ViewContextMap struct { + content map[string]types.Context +} + +func NewViewContextMap() *ViewContextMap { + return &ViewContextMap{content: map[string]types.Context{}} +} + +func (self *ViewContextMap) Get(viewName string) types.Context { + return self.content[viewName] +} + +func (self *ViewContextMap) Set(viewName string, context types.Context) { + self.content[viewName] = context +} + type TabContext struct { Tab string Contexts []types.Context diff --git a/pkg/gui/context/tags_context.go b/pkg/gui/context/tags_context.go index 8644b15dc..2f20c4363 100644 --- a/pkg/gui/context/tags_context.go +++ b/pkg/gui/context/tags_context.go @@ -31,6 +31,7 @@ func NewTagsContext( WindowName: "branches", Key: TAGS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }) self := &TagsContext{} diff --git a/pkg/gui/context/working_tree_context.go b/pkg/gui/context/working_tree_context.go index 8ab4a1403..6179e7270 100644 --- a/pkg/gui/context/working_tree_context.go +++ b/pkg/gui/context/working_tree_context.go @@ -31,6 +31,7 @@ func NewWorkingTreeContext( WindowName: "files", Key: FILES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }) self := &WorkingTreeContext{} diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index 4e5c241d0..d62f9f5e1 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -5,7 +5,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/types" ) -func (gui *Gui) allContexts() []types.Context { +func (gui *Gui) allContexts2() []types.Context { return []types.Context{ gui.State.Contexts.Global, gui.State.Contexts.Status, @@ -41,6 +41,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "", WindowName: "", Key: context.GLOBAL_CONTEXT_KEY, + Focusable: false, }), NewSimpleContextOpts{ OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), @@ -52,6 +53,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "status", WindowName: "status", Key: context.STATUS_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnRenderToMain: OnFocusWrapper(gui.statusRenderToMain), @@ -76,6 +78,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "main", WindowName: "main", Key: context.MAIN_NORMAL_CONTEXT_KEY, + Focusable: false, }), NewSimpleContextOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { @@ -89,6 +92,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "main", WindowName: "main", Key: context.MAIN_STAGING_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { @@ -112,6 +116,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "main", WindowName: "main", Key: context.MAIN_PATCH_BUILDING_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: func(opts ...types.OnFocusOpts) error { @@ -131,6 +136,7 @@ func (gui *Gui) contextTree() *context.ContextTree { WindowName: "main", Key: context.MAIN_MERGING_CONTEXT_KEY, OnGetOptionsMap: gui.getMergingOptions, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: OnFocusWrapper(func() error { return gui.renderConflictsWithLock(true) }), @@ -142,6 +148,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "credentials", WindowName: "credentials", Key: context.CREDENTIALS_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: OnFocusWrapper(gui.handleAskFocused), @@ -153,6 +160,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "confirmation", WindowName: "confirmation", Key: context.CONFIRMATION_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: OnFocusWrapper(gui.handleAskFocused), @@ -164,6 +172,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "commitMessage", WindowName: "commitMessage", Key: context.COMMIT_MESSAGE_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{ OnFocus: OnFocusWrapper(gui.handleCommitMessageFocused), @@ -175,6 +184,7 @@ func (gui *Gui) contextTree() *context.ContextTree { ViewName: "search", WindowName: "search", Key: context.SEARCH_CONTEXT_KEY, + Focusable: true, }), NewSimpleContextOpts{}, ), @@ -185,6 +195,7 @@ func (gui *Gui) contextTree() *context.ContextTree { WindowName: "extras", Key: context.COMMAND_LOG_CONTEXT_KEY, OnGetOptionsMap: gui.getMergingOptions, + Focusable: true, }), NewSimpleContextOpts{ OnFocusLost: func() error { diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 0ffdcfc6c..5d5d65c8f 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -55,9 +55,15 @@ func (gui *Gui) filesRenderToMain() error { cmdObj := gui.git.WorkingTree.WorktreeFileDiffCmdObj(node, false, !node.GetHasUnstagedChanges() && node.GetHasStagedChanges(), gui.IgnoreWhitespaceInDiffView) + mainContext := gui.State.Contexts.Normal + if node.File != nil { + mainContext = gui.State.Contexts.Staging + } + refreshOpts := refreshMainOpts{main: &viewUpdateOpts{ - title: gui.c.Tr.UnstagedChanges, - task: NewRunPtyTask(cmdObj.GetCmd()), + title: gui.c.Tr.UnstagedChanges, + task: NewRunPtyTask(cmdObj.GetCmd()), + context: mainContext, }} if node.GetHasUnstagedChanges() { @@ -65,8 +71,9 @@ func (gui *Gui) filesRenderToMain() error { cmdObj := gui.git.WorkingTree.WorktreeFileDiffCmdObj(node, false, true, gui.IgnoreWhitespaceInDiffView) refreshOpts.secondary = &viewUpdateOpts{ - title: gui.c.Tr.StagedChanges, - task: NewRunPtyTask(cmdObj.GetCmd()), + title: gui.c.Tr.StagedChanges, + task: NewRunPtyTask(cmdObj.GetCmd()), + context: mainContext, } } } else { diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index ccb032175..f8479c111 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -193,7 +193,7 @@ type GuiRepoState struct { MainContext types.ContextKey // used to keep the main and secondary views' contexts in sync ContextManager ContextManager Contexts *context.ContextTree - ViewContextMap map[string]types.Context + ViewContextMap *context.ViewContextMap ViewTabContextMap map[string][]context.TabContext // WindowViewNameMap is a mapping of windows to the current view of that window. @@ -417,13 +417,23 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { } } - contexts := gui.contextTree() + contextTree := gui.contextTree() screenMode := SCREEN_NORMAL - var initialContext types.IListContext = contexts.Files + var initialContext types.IListContext = contextTree.Files if filterPath != "" { screenMode = SCREEN_HALF - initialContext = contexts.BranchCommits + initialContext = contextTree.BranchCommits + } + + viewContextMap := context.NewViewContextMap() + for viewName, context := range initialViewContextMapping(contextTree) { + viewContextMap.Set(viewName, context) + view, err := gui.g.View(viewName) + if err != nil { + panic(err) + } + view.Context = string(context.GetKey()) } gui.State = &GuiRepoState{ @@ -461,17 +471,35 @@ func (gui *Gui) resetState(filterPath string, reuseState bool) { CherryPicking: cherrypicking.New(), Diffing: diffing.New(), }, - ViewContextMap: contexts.InitialViewContextMap(), - ViewTabContextMap: contexts.InitialViewTabContextMap(), + ViewContextMap: viewContextMap, + ViewTabContextMap: contextTree.InitialViewTabContextMap(), ScreenMode: screenMode, // TODO: put contexts in the context manager ContextManager: NewContextManager(initialContext), - Contexts: contexts, + Contexts: contextTree, } gui.RepoStateMap[Repo(currentDir)] = gui.State } +func initialViewContextMapping(contextTree *context.ContextTree) map[string]types.Context { + return map[string]types.Context{ + "status": contextTree.Status, + "files": contextTree.Files, + "branches": contextTree.Branches, + "commits": contextTree.BranchCommits, + "commitFiles": contextTree.CommitFiles, + "stash": contextTree.Stash, + "menu": contextTree.Menu, + "confirmation": contextTree.Confirmation, + "credentials": contextTree.Credentials, + "commitMessage": contextTree.CommitMessage, + "main": contextTree.Normal, + "secondary": contextTree.Normal, + "extras": contextTree.CommandLog, + } +} + // for now the split view will always be on // NewGui builds a new gui handler func NewGui( @@ -760,6 +788,10 @@ func (gui *Gui) Run(filterPath string) error { gui.g.SetManager(gocui.ManagerFunc(gui.layout), gocui.ManagerFunc(gui.getFocusLayout())) + if err := gui.createAllViews(); err != nil { + return err + } + // onNewRepo must be called after g.SetManager because SetManager deletes keybindings if err := gui.onNewRepo(filterPath, false); err != nil { return err @@ -777,6 +809,120 @@ func (gui *Gui) Run(filterPath string) error { return gui.g.MainLoop() } +func (gui *Gui) createAllViews() error { + viewNameMappings := []struct { + viewPtr **gocui.View + name string + }{ + {viewPtr: &gui.Views.Status, name: "status"}, + {viewPtr: &gui.Views.Files, name: "files"}, + {viewPtr: &gui.Views.Branches, name: "branches"}, + {viewPtr: &gui.Views.Commits, name: "commits"}, + {viewPtr: &gui.Views.Stash, name: "stash"}, + {viewPtr: &gui.Views.CommitFiles, name: "commitFiles"}, + {viewPtr: &gui.Views.Main, name: "main"}, + {viewPtr: &gui.Views.Secondary, name: "secondary"}, + {viewPtr: &gui.Views.Options, name: "options"}, + {viewPtr: &gui.Views.AppStatus, name: "appStatus"}, + {viewPtr: &gui.Views.Information, name: "information"}, + {viewPtr: &gui.Views.Search, name: "search"}, + {viewPtr: &gui.Views.SearchPrefix, name: "searchPrefix"}, + {viewPtr: &gui.Views.CommitMessage, name: "commitMessage"}, + {viewPtr: &gui.Views.Credentials, name: "credentials"}, + {viewPtr: &gui.Views.Menu, name: "menu"}, + {viewPtr: &gui.Views.Suggestions, name: "suggestions"}, + {viewPtr: &gui.Views.Confirmation, name: "confirmation"}, + {viewPtr: &gui.Views.Limit, name: "limit"}, + {viewPtr: &gui.Views.Extras, name: "extras"}, + } + + var err error + for _, mapping := range viewNameMappings { + *mapping.viewPtr, err = gui.prepareView(mapping.name) + if err != nil && err.Error() != UNKNOWN_VIEW_ERROR_MSG { + return err + } + } + + gui.Views.Options.Frame = false + gui.Views.Options.FgColor = theme.OptionsColor + + gui.Views.SearchPrefix.BgColor = gocui.ColorDefault + gui.Views.SearchPrefix.FgColor = gocui.ColorGreen + gui.Views.SearchPrefix.Frame = false + gui.setViewContent(gui.Views.SearchPrefix, SEARCH_PREFIX) + + gui.Views.Stash.Title = gui.c.Tr.StashTitle + gui.Views.Stash.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Commits.Title = gui.c.Tr.CommitsTitle + gui.Views.Commits.FgColor = theme.GocuiDefaultTextColor + + gui.Views.CommitFiles.Title = gui.c.Tr.CommitFiles + gui.Views.CommitFiles.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Branches.Title = gui.c.Tr.BranchesTitle + gui.Views.Branches.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Files.Highlight = true + gui.Views.Files.Title = gui.c.Tr.FilesTitle + gui.Views.Files.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Secondary.Title = gui.c.Tr.DiffTitle + gui.Views.Secondary.Wrap = true + gui.Views.Secondary.FgColor = theme.GocuiDefaultTextColor + gui.Views.Secondary.IgnoreCarriageReturns = true + + gui.Views.Main.Title = gui.c.Tr.DiffTitle + gui.Views.Main.Wrap = true + gui.Views.Main.FgColor = theme.GocuiDefaultTextColor + gui.Views.Main.IgnoreCarriageReturns = true + + gui.Views.Limit.Title = gui.c.Tr.NotEnoughSpace + gui.Views.Limit.Wrap = true + + gui.Views.Status.Title = gui.c.Tr.StatusTitle + gui.Views.Status.FgColor = theme.GocuiDefaultTextColor + + gui.Views.Search.BgColor = gocui.ColorDefault + gui.Views.Search.FgColor = gocui.ColorGreen + gui.Views.Search.Frame = false + gui.Views.Search.Editable = true + + gui.Views.AppStatus.BgColor = gocui.ColorDefault + gui.Views.AppStatus.FgColor = gocui.ColorCyan + gui.Views.AppStatus.Frame = false + gui.Views.AppStatus.Visible = false + + gui.Views.CommitMessage.Visible = false + gui.Views.CommitMessage.Title = gui.c.Tr.CommitMessage + gui.Views.CommitMessage.FgColor = theme.GocuiDefaultTextColor + gui.Views.CommitMessage.Editable = true + gui.Views.CommitMessage.Editor = gocui.EditorFunc(gui.commitMessageEditor) + + gui.Views.Confirmation.Visible = false + + gui.Views.Credentials.Visible = false + gui.Views.Credentials.Title = gui.c.Tr.CredentialsUsername + gui.Views.Credentials.FgColor = theme.GocuiDefaultTextColor + gui.Views.Credentials.Editable = true + + gui.Views.Suggestions.Visible = false + + gui.Views.Menu.Visible = false + + gui.Views.Information.BgColor = gocui.ColorDefault + gui.Views.Information.FgColor = gocui.ColorGreen + gui.Views.Information.Frame = false + + gui.Views.Extras.Title = gui.c.Tr.CommandLog + gui.Views.Extras.FgColor = theme.GocuiDefaultTextColor + gui.Views.Extras.Autoscroll = true + gui.Views.Extras.Wrap = true + + return nil +} + func (gui *Gui) RunAndHandleError(filterPath string) error { gui.stopChan = make(chan struct{}) return utils.SafeWithError(func() error { diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 50a8587ec..0083cd940 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -1348,7 +1348,7 @@ func (gui *Gui) GetInitialKeybindings() ([]*types.Binding, []*gocui.ViewMouseBin } mouseKeybindings := []*gocui.ViewMouseBinding{} - for _, c := range gui.allContexts() { + for _, c := range gui.State.Contexts.Flatten() { viewName := c.GetViewName() contextKey := c.GetKey() for _, binding := range c.GetKeybindings(keybindingsOpts) { diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 7f8e9edef..097625f4c 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -7,130 +7,12 @@ import ( const SEARCH_PREFIX = "search: " -func (gui *Gui) createAllViews() error { - viewNameMappings := []struct { - viewPtr **gocui.View - name string - }{ - {viewPtr: &gui.Views.Status, name: "status"}, - {viewPtr: &gui.Views.Files, name: "files"}, - {viewPtr: &gui.Views.Branches, name: "branches"}, - {viewPtr: &gui.Views.Commits, name: "commits"}, - {viewPtr: &gui.Views.Stash, name: "stash"}, - {viewPtr: &gui.Views.CommitFiles, name: "commitFiles"}, - {viewPtr: &gui.Views.Main, name: "main"}, - {viewPtr: &gui.Views.Secondary, name: "secondary"}, - {viewPtr: &gui.Views.Options, name: "options"}, - {viewPtr: &gui.Views.AppStatus, name: "appStatus"}, - {viewPtr: &gui.Views.Information, name: "information"}, - {viewPtr: &gui.Views.Search, name: "search"}, - {viewPtr: &gui.Views.SearchPrefix, name: "searchPrefix"}, - {viewPtr: &gui.Views.CommitMessage, name: "commitMessage"}, - {viewPtr: &gui.Views.Credentials, name: "credentials"}, - {viewPtr: &gui.Views.Menu, name: "menu"}, - {viewPtr: &gui.Views.Suggestions, name: "suggestions"}, - {viewPtr: &gui.Views.Confirmation, name: "confirmation"}, - {viewPtr: &gui.Views.Limit, name: "limit"}, - {viewPtr: &gui.Views.Extras, name: "extras"}, - } - - var err error - for _, mapping := range viewNameMappings { - *mapping.viewPtr, err = gui.prepareView(mapping.name) - if err != nil && err.Error() != UNKNOWN_VIEW_ERROR_MSG { - return err - } - } - - gui.Views.Options.Frame = false - gui.Views.Options.FgColor = theme.OptionsColor - - gui.Views.SearchPrefix.BgColor = gocui.ColorDefault - gui.Views.SearchPrefix.FgColor = gocui.ColorGreen - gui.Views.SearchPrefix.Frame = false - gui.setViewContent(gui.Views.SearchPrefix, SEARCH_PREFIX) - - gui.Views.Stash.Title = gui.c.Tr.StashTitle - gui.Views.Stash.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Commits.Title = gui.c.Tr.CommitsTitle - gui.Views.Commits.FgColor = theme.GocuiDefaultTextColor - - gui.Views.CommitFiles.Title = gui.c.Tr.CommitFiles - gui.Views.CommitFiles.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Branches.Title = gui.c.Tr.BranchesTitle - gui.Views.Branches.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Files.Highlight = true - gui.Views.Files.Title = gui.c.Tr.FilesTitle - gui.Views.Files.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Secondary.Title = gui.c.Tr.DiffTitle - gui.Views.Secondary.Wrap = true - gui.Views.Secondary.FgColor = theme.GocuiDefaultTextColor - gui.Views.Secondary.IgnoreCarriageReturns = true - - gui.Views.Main.Title = gui.c.Tr.DiffTitle - gui.Views.Main.Wrap = true - gui.Views.Main.FgColor = theme.GocuiDefaultTextColor - gui.Views.Main.IgnoreCarriageReturns = true - - gui.Views.Limit.Title = gui.c.Tr.NotEnoughSpace - gui.Views.Limit.Wrap = true - - gui.Views.Status.Title = gui.c.Tr.StatusTitle - gui.Views.Status.FgColor = theme.GocuiDefaultTextColor - - gui.Views.Search.BgColor = gocui.ColorDefault - gui.Views.Search.FgColor = gocui.ColorGreen - gui.Views.Search.Frame = false - gui.Views.Search.Editable = true - - gui.Views.AppStatus.BgColor = gocui.ColorDefault - gui.Views.AppStatus.FgColor = gocui.ColorCyan - gui.Views.AppStatus.Frame = false - gui.Views.AppStatus.Visible = false - - gui.Views.CommitMessage.Visible = false - gui.Views.CommitMessage.Title = gui.c.Tr.CommitMessage - gui.Views.CommitMessage.FgColor = theme.GocuiDefaultTextColor - gui.Views.CommitMessage.Editable = true - gui.Views.CommitMessage.Editor = gocui.EditorFunc(gui.commitMessageEditor) - - gui.Views.Confirmation.Visible = false - - gui.Views.Credentials.Visible = false - gui.Views.Credentials.Title = gui.c.Tr.CredentialsUsername - gui.Views.Credentials.FgColor = theme.GocuiDefaultTextColor - gui.Views.Credentials.Editable = true - - gui.Views.Suggestions.Visible = false - - gui.Views.Menu.Visible = false - - gui.Views.Information.BgColor = gocui.ColorDefault - gui.Views.Information.FgColor = gocui.ColorGreen - gui.Views.Information.Frame = false - - gui.Views.Extras.Title = gui.c.Tr.CommandLog - gui.Views.Extras.FgColor = theme.GocuiDefaultTextColor - gui.Views.Extras.Autoscroll = true - gui.Views.Extras.Wrap = true - - gui.printCommandLogHeader() - - if _, err := gui.g.SetCurrentView(gui.defaultSideContext().GetViewName()); err != nil { - return err - } - - return nil -} - // layout is called for every screen re-render e.g. when the screen is resized func (gui *Gui) layout(g *gocui.Gui) error { if !gui.ViewsSetup { - if err := gui.createAllViews(); err != nil { + gui.printCommandLogHeader() + + if _, err := gui.g.SetCurrentView(gui.defaultSideContext().GetViewName()); err != nil { return err } } diff --git a/pkg/gui/list_context_config.go b/pkg/gui/list_context_config.go index 704ffb4b4..dedcab4cc 100644 --- a/pkg/gui/list_context_config.go +++ b/pkg/gui/list_context_config.go @@ -19,6 +19,7 @@ func (gui *Gui) menuListContext() types.IListContext { Key: "menu", Kind: types.PERSISTENT_POPUP, OnGetOptionsMap: gui.getMenuOptions, + Focusable: true, }), GetItemsLength: func() int { return gui.Views.Menu.LinesHeight() }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Menu }, @@ -55,6 +56,7 @@ func (gui *Gui) branchesListContext() types.IListContext { WindowName: "branches", Key: context.LOCAL_BRANCHES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.Branches) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Branches }, @@ -80,6 +82,7 @@ func (gui *Gui) remotesListContext() types.IListContext { WindowName: "branches", Key: context.REMOTES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.Remotes) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Remotes }, @@ -105,6 +108,7 @@ func (gui *Gui) remoteBranchesListContext() types.IListContext { WindowName: "branches", Key: context.REMOTE_BRANCHES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.RemoteBranches) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.RemoteBranches }, @@ -155,6 +159,7 @@ func (gui *Gui) branchCommitsListContext() types.IListContext { WindowName: "commits", Key: context.BRANCH_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.Commits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Commits }, @@ -201,6 +206,7 @@ func (gui *Gui) subCommitsListContext() types.IListContext { WindowName: "branches", Key: context.SUB_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.SubCommits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.SubCommits }, @@ -265,6 +271,7 @@ func (gui *Gui) reflogCommitsListContext() types.IListContext { WindowName: "commits", Key: context.REFLOG_COMMITS_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.FilteredReflogCommits) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.ReflogCommits }, @@ -296,6 +303,7 @@ func (gui *Gui) stashListContext() types.IListContext { WindowName: "stash", Key: context.STASH_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.StashEntries) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Stash }, @@ -345,6 +353,7 @@ func (gui *Gui) submodulesListContext() types.IListContext { WindowName: "files", Key: context.SUBMODULES_CONTEXT_KEY, Kind: types.SIDE_CONTEXT, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Model.Submodules) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Submodules }, @@ -370,6 +379,7 @@ func (gui *Gui) suggestionsListContext() types.IListContext { WindowName: "suggestions", Key: context.SUGGESTIONS_CONTEXT_KEY, Kind: types.PERSISTENT_POPUP, + Focusable: true, }), GetItemsLength: func() int { return len(gui.State.Suggestions) }, OnGetPanelState: func() types.IListPanelState { return gui.State.Panels.Suggestions }, diff --git a/pkg/gui/main_panels.go b/pkg/gui/main_panels.go index bb0644585..cbb478446 100644 --- a/pkg/gui/main_panels.go +++ b/pkg/gui/main_panels.go @@ -4,6 +4,7 @@ import ( "os/exec" "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/types" ) type viewUpdateOpts struct { @@ -16,6 +17,8 @@ type viewUpdateOpts struct { highlight bool task updateTask + + context types.Context } type refreshMainOpts struct { @@ -100,6 +103,11 @@ func (gui *Gui) refreshMainView(opts *viewUpdateOpts, view *gocui.View) error { view.Title = opts.title view.Wrap = !opts.noWrap view.Highlight = opts.highlight + context := opts.context + if context == nil { + context = gui.State.Contexts.Normal + } + gui.ViewContextMapSet(view.Name(), context) if err := gui.runTaskForView(view, opts.task); err != nil { gui.c.Log.Error(err) diff --git a/pkg/gui/merge_panel.go b/pkg/gui/merge_panel.go index 54783e986..60aa93a17 100644 --- a/pkg/gui/merge_panel.go +++ b/pkg/gui/merge_panel.go @@ -153,9 +153,10 @@ func (gui *Gui) renderConflicts(hasFocus bool) error { return gui.refreshMainViews(refreshMainOpts{ main: &viewUpdateOpts{ - title: gui.c.Tr.MergeConflictsTitle, - task: NewRenderStringWithoutScrollTask(content), - noWrap: true, + title: gui.c.Tr.MergeConflictsTitle, + task: NewRenderStringWithoutScrollTask(content), + context: gui.State.Contexts.Merging, + noWrap: true, }, }) } diff --git a/pkg/gui/patch_building_panel.go b/pkg/gui/patch_building_panel.go index ac09a898c..fc41bd603 100644 --- a/pkg/gui/patch_building_panel.go +++ b/pkg/gui/patch_building_panel.go @@ -136,6 +136,7 @@ func (gui *Gui) secondaryPatchPanelUpdateOpts() *viewUpdateOpts { title: "Custom Patch", noWrap: true, highlight: true, + context: gui.State.Contexts.PatchBuilding, task: NewRenderStringWithoutScrollTask(patch), } } diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 381374adf..7b9f47001 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -31,6 +31,7 @@ type IBaseContext interface { GetWindowName() string SetWindowName(string) GetKey() ContextKey + IsFocusable() bool GetOptionsMap() map[string]string diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index b374c82c0..1c7829b57 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -1441,7 +1441,7 @@ func (g *Gui) matchView(v *View, kb *keybinding) bool { return true } for _, context := range kb.contexts { - if context == g.currentContext { + if context == v.Context { return true } } diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go index 9783d7637..1316ced2e 100644 --- a/vendor/github.com/jesseduffield/gocui/view.go +++ b/vendor/github.com/jesseduffield/gocui/view.go @@ -149,6 +149,8 @@ type View struct { // ParentView is the view which catches events bubbled up from the given view if there's no matching handler ParentView *View + Context string // this is for assigning keybindings to a view only in certain contexts + searcher *searcher // KeybindOnEdit should be set to true when you want to execute keybindings even when the view is editable