From fab2e14b55455be370d8514871d60bc59adfbf30 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 1 Aug 2022 21:36:17 +1000 Subject: [PATCH 1/5] fix issue caused by opening a menu over a prompt --- pkg/gui/context.go | 40 +++++++++++++++++++++------------ pkg/gui/context/menu_context.go | 2 +- pkg/gui/gui_common.go | 2 +- pkg/gui/types/context.go | 14 ++++++++++-- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index d2a99d84b..89356d956 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -79,9 +79,10 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { gui.State.ContextManager.Lock() - // push onto stack - // if we are switching to a side context, remove all other contexts in the stack - if c.GetKind() == types.SIDE_CONTEXT { + if len(gui.State.ContextManager.ContextStack) == 0 { + gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack, c) + } else if c.GetKind() == types.SIDE_CONTEXT { + // if we are switching to a side context, remove all other contexts in the stack for _, stackContext := range gui.State.ContextManager.ContextStack { if stackContext.GetKey() != c.GetKey() { if err := gui.deactivateContext(stackContext); err != nil { @@ -91,12 +92,25 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { } } gui.State.ContextManager.ContextStack = []types.Context{c} - } else if len(gui.State.ContextManager.ContextStack) == 0 || gui.currentContextWithoutLock().GetKey() != c.GetKey() { - // Do not append if the one at the end is the same context (e.g. opening a menu from a menu) - // In that case we'll just close the menu entirely when the user hits escape. + } else { + topContext := gui.currentContextWithoutLock() - // TODO: think about other exceptional cases - gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack, c) + // if we're pushing the same context on, we do nothing. + if topContext.GetKey() != c.GetKey() { + // if top one is a temporary popup, we remove it. Ideally you'd be able to + // escape back to previous temporary popups, but because we're currently reusing + // views for this, you might not be able to get back to where you previously were. + if topContext.GetKind() == types.TEMPORARY_POPUP { + if err := gui.deactivateContext(topContext); err != nil { + gui.State.ContextManager.Unlock() + return err + } + + _, gui.State.ContextManager.ContextStack = slices.Pop(gui.State.ContextManager.ContextStack) + } + + gui.State.ContextManager.ContextStack = append(gui.State.ContextManager.ContextStack, c) + } } gui.State.ContextManager.Unlock() @@ -111,7 +125,7 @@ func (gui *Gui) pushContextWithView(viewName string) error { return gui.c.PushContext(gui.State.ViewContextMap.Get(viewName)) } -func (gui *Gui) returnFromContext() error { +func (gui *Gui) popContext() error { gui.State.ContextManager.Lock() if len(gui.State.ContextManager.ContextStack) == 1 { @@ -120,12 +134,10 @@ func (gui *Gui) returnFromContext() error { return nil } - n := len(gui.State.ContextManager.ContextStack) - 1 + var currentContext types.Context + currentContext, gui.State.ContextManager.ContextStack = slices.Pop(gui.State.ContextManager.ContextStack) - currentContext := gui.State.ContextManager.ContextStack[n] - newContext := gui.State.ContextManager.ContextStack[n-1] - - gui.State.ContextManager.ContextStack = gui.State.ContextManager.ContextStack[:n] + newContext := gui.State.ContextManager.ContextStack[len(gui.State.ContextManager.ContextStack)-1] gui.g.SetCurrentContext(string(newContext.GetKey())) diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go index 489f412f0..f71feaeae 100644 --- a/pkg/gui/context/menu_context.go +++ b/pkg/gui/context/menu_context.go @@ -36,7 +36,7 @@ func NewMenuContext( Context: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ ViewName: "menu", Key: "menu", - Kind: types.PERSISTENT_POPUP, + Kind: types.TEMPORARY_POPUP, OnGetOptionsMap: getOptionsMap, Focusable: true, }), ContextCallbackOpts{ diff --git a/pkg/gui/gui_common.go b/pkg/gui/gui_common.go index 7d8354bf6..89abe92ba 100644 --- a/pkg/gui/gui_common.go +++ b/pkg/gui/gui_common.go @@ -43,7 +43,7 @@ func (self *guiCommon) PushContext(context types.Context, opts ...types.OnFocusO } func (self *guiCommon) PopContext() error { - return self.gui.returnFromContext() + return self.gui.popContext() } func (self *guiCommon) CurrentContext() types.Context { diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 253bb62ef..7dec9b9db 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -8,12 +8,22 @@ import ( type ContextKind int const ( + // this is your files, branches, commits, contexts etc. They're all on the left hand side + // and you can cycle through them. SIDE_CONTEXT ContextKind = iota + // This is either the left or right 'main' contexts that appear to the right of the side contexts MAIN_CONTEXT - TEMPORARY_POPUP + // A persistent popup is one that has its own identity e.g. the commit message context. + // When you open a popup over it, we'll let you return to it upon pressing escape PERSISTENT_POPUP + // A temporary popup is one that could be used for various things (e.g. a generic menu or confirmation popup). + // Because we re-use these contexts, they're temporary in that you can't return to them after you've switched from them + // to some other context, because the context you switched to might actually be the same context but rendering different content. + // We should really be able to spawn new contexts for menus/prompts so that we can actually return to old ones. + TEMPORARY_POPUP + // This contains the command log, underneath the main contexts. EXTRAS_CONTEXT - // only used by the one global context + // only used by the one global context, purely for the sake of defining keybindings globally GLOBAL_CONTEXT ) From debc58b6c587e85716a0a176d3fd23f385803d84 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 1 Aug 2022 21:58:49 +1000 Subject: [PATCH 2/5] fix popup focus issue --- pkg/gui/confirmation_panel.go | 33 ++++++------------- pkg/gui/context_config.go | 4 +++ .../helpers/merge_and_rebase_helper.go | 9 ++--- pkg/gui/gui.go | 3 +- pkg/gui/popup/popup_handler.go | 23 +++++++------ pkg/gui/types/common.go | 4 --- 6 files changed, 31 insertions(+), 45 deletions(-) diff --git a/pkg/gui/confirmation_panel.go b/pkg/gui/confirmation_panel.go index 19f8745a8..4177a689b 100644 --- a/pkg/gui/confirmation_panel.go +++ b/pkg/gui/confirmation_panel.go @@ -16,9 +16,9 @@ import ( // This file is for the rendering of confirmation panels along with setting and handling associated // keybindings. -func (gui *Gui) wrappedConfirmationFunction(handlersManageFocus bool, function func() error) func() error { +func (gui *Gui) wrappedConfirmationFunction(function func() error) func() error { return func() error { - if err := gui.closeConfirmationPrompt(handlersManageFocus); err != nil { + if err := gui.c.PopContext(); err != nil { return err } @@ -32,9 +32,9 @@ func (gui *Gui) wrappedConfirmationFunction(handlersManageFocus bool, function f } } -func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, function func(string) error, getResponse func() string) func() error { +func (gui *Gui) wrappedPromptConfirmationFunction(function func(string) error, getResponse func() string) func() error { return func() error { - if err := gui.closeConfirmationPrompt(handlersManageFocus); err != nil { + if err := gui.c.PopContext(); err != nil { return err } @@ -48,27 +48,15 @@ func (gui *Gui) wrappedPromptConfirmationFunction(handlersManageFocus bool, func } } -func (gui *Gui) closeConfirmationPrompt(handlersManageFocus bool) error { +func (gui *Gui) deactivateConfirmationPrompt() { gui.Mutexes.PopupMutex.Lock() gui.State.CurrentPopupOpts = nil gui.Mutexes.PopupMutex.Unlock() - // we've already closed it so we can just return - if !gui.Views.Confirmation.Visible { - return nil - } - - if !handlersManageFocus { - if err := gui.c.PopContext(); err != nil { - return err - } - } - - gui.clearConfirmationViewKeyBindings() gui.Views.Confirmation.Visible = false gui.Views.Suggestions.Visible = false - return nil + gui.clearConfirmationViewKeyBindings() } func (gui *Gui) getMessageHeight(wrap bool, message string, width int) int { @@ -219,14 +207,13 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error { _ = gui.renderString(gui.Views.Options, actions) var onConfirm func() error if opts.HandleConfirmPrompt != nil { - onConfirm = gui.wrappedPromptConfirmationFunction(opts.HandlersManageFocus, opts.HandleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() }) + onConfirm = gui.wrappedPromptConfirmationFunction(opts.HandleConfirmPrompt, func() string { return gui.Views.Confirmation.TextArea.GetContent() }) } else { - onConfirm = gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleConfirm) + onConfirm = gui.wrappedConfirmationFunction(opts.HandleConfirm) } keybindingConfig := gui.c.UserConfig.Keybinding onSuggestionConfirm := gui.wrappedPromptConfirmationFunction( - opts.HandlersManageFocus, opts.HandleConfirmPrompt, gui.getSelectedSuggestionValue, ) @@ -248,7 +235,7 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error { ViewName: "confirmation", Contexts: []string{string(context.CONFIRMATION_CONTEXT_KEY)}, Key: gui.getKey(keybindingConfig.Universal.Return), - Handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose), + Handler: gui.wrappedConfirmationFunction(opts.HandleClose), }, { ViewName: "confirmation", @@ -277,7 +264,7 @@ func (gui *Gui) setKeyBindings(opts types.CreatePopupPanelOpts) error { ViewName: "suggestions", Contexts: []string{string(context.SUGGESTIONS_CONTEXT_KEY)}, Key: gui.getKey(keybindingConfig.Universal.Return), - Handler: gui.wrappedConfirmationFunction(opts.HandlersManageFocus, opts.HandleClose), + Handler: gui.wrappedConfirmationFunction(opts.HandleClose), }, { ViewName: "suggestions", diff --git a/pkg/gui/context_config.go b/pkg/gui/context_config.go index bc9df8ba4..a983ffdd5 100644 --- a/pkg/gui/context_config.go +++ b/pkg/gui/context_config.go @@ -124,6 +124,10 @@ func (gui *Gui) contextTree() *context.ContextTree { }), context.ContextCallbackOpts{ OnFocus: OnFocusWrapper(gui.handleAskFocused), + OnFocusLost: func() error { + gui.deactivateConfirmationPrompt() + return nil + }, }, ), CommitMessage: context.NewSimpleContext( diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index ef9dd76a2..6d2c680e3 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -149,17 +149,12 @@ func (self *MergeAndRebaseHelper) CheckMergeOrRebase(result error) error { return nil } else if isMergeConflictErr(result.Error()) { return self.c.Confirm(types.ConfirmOpts{ - Title: self.c.Tr.FoundConflictsTitle, - Prompt: self.c.Tr.FoundConflicts, - HandlersManageFocus: true, + Title: self.c.Tr.FoundConflictsTitle, + Prompt: self.c.Tr.FoundConflicts, HandleConfirm: func() error { return self.c.PushContext(self.contexts.Files) }, HandleClose: func() error { - if err := self.c.PopContext(); err != nil { - return err - } - return self.genericMergeCommand(REBASE_OPTION_ABORT) }, }) diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 04b53e074..e7f1e3499 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -424,7 +424,8 @@ func NewGui( cmn, gui.createPopupPanel, func() error { return gui.c.Refresh(types.RefreshOptions{Mode: types.ASYNC}) }, - func() error { return gui.closeConfirmationPrompt(false) }, + gui.popContext, + gui.currentContext, gui.createMenu, gui.withWaitingStatus, gui.toast, diff --git a/pkg/gui/popup/popup_handler.go b/pkg/gui/popup/popup_handler.go index 53c52c74e..de892437f 100644 --- a/pkg/gui/popup/popup_handler.go +++ b/pkg/gui/popup/popup_handler.go @@ -6,6 +6,7 @@ import ( "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/common" + "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" "github.com/jesseduffield/lazygit/pkg/utils" @@ -17,7 +18,8 @@ type PopupHandler struct { sync.Mutex createPopupPanelFn func(types.CreatePopupPanelOpts) error onErrorFn func() error - closePopupFn func() error + popContextFn func() error + currentContextFn func() types.Context createMenuFn func(types.CreateMenuOptions) error withWaitingStatusFn func(message string, f func() error) error toastFn func(message string) @@ -30,7 +32,8 @@ func NewPopupHandler( common *common.Common, createPopupPanelFn func(types.CreatePopupPanelOpts) error, onErrorFn func() error, - closePopupFn func() error, + popContextFn func() error, + currentContextFn func() types.Context, createMenuFn func(types.CreateMenuOptions) error, withWaitingStatusFn func(message string, f func() error) error, toastFn func(message string), @@ -41,7 +44,8 @@ func NewPopupHandler( index: 0, createPopupPanelFn: createPopupPanelFn, onErrorFn: onErrorFn, - closePopupFn: closePopupFn, + popContextFn: popContextFn, + currentContextFn: currentContextFn, createMenuFn: createMenuFn, withWaitingStatusFn: withWaitingStatusFn, toastFn: toastFn, @@ -93,11 +97,10 @@ func (self *PopupHandler) Confirm(opts types.ConfirmOpts) error { self.Unlock() return self.createPopupPanelFn(types.CreatePopupPanelOpts{ - Title: opts.Title, - Prompt: opts.Prompt, - HandleConfirm: opts.HandleConfirm, - HandleClose: opts.HandleClose, - HandlersManageFocus: opts.HandlersManageFocus, + Title: opts.Title, + Prompt: opts.Prompt, + HandleConfirm: opts.HandleConfirm, + HandleClose: opts.HandleClose, }) } @@ -139,8 +142,8 @@ func (self *PopupHandler) WithLoaderPanel(message string, f func() error) error } self.Lock() - if index == self.index { - _ = self.closePopupFn() + if index == self.index && self.currentContextFn().GetKey() == context.CONFIRMATION_CONTEXT_KEY { + _ = self.popContextFn() } self.Unlock() }) diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go index 21808705a..5bc0e5856 100644 --- a/pkg/gui/types/common.go +++ b/pkg/gui/types/common.go @@ -85,9 +85,6 @@ type CreatePopupPanelOpts struct { HandleConfirmPrompt func(string) error HandleClose func() error - // when HandlersManageFocus is true, do not return from the confirmation context automatically. It's expected that the handlers will manage focus, whether that means switching to another context, or manually returning the context. - HandlersManageFocus bool - FindSuggestionsFunc func(string) []*Suggestion Mask bool } @@ -97,7 +94,6 @@ type ConfirmOpts struct { Prompt string HandleConfirm func() error HandleClose func() error - HandlersManageFocus bool HasLoader bool FindSuggestionsFunc func(string) []*Suggestion Editable bool From 3ee2ad511eb279a2e5dfaec1b0a69c53c0043b01 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 1 Aug 2022 22:10:08 +1000 Subject: [PATCH 3/5] prevent crash when opening recent repos panel if no recent repos are present --- pkg/gui/recent_repos_panel.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 3b817fbca..edf3fe393 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -60,8 +60,12 @@ func (gui *Gui) getCurrentBranch(path string) string { } func (gui *Gui) handleCreateRecentReposMenu() error { - // we skip the first one because we're currently in it - recentRepoPaths := gui.c.GetAppState().RecentRepos[1:] + // we'll show an empty panel if there are no recent repos + recentRepoPaths := []string{} + if len(gui.c.GetAppState().RecentRepos) > 0 { + // we skip the first one because we're currently in it + recentRepoPaths = gui.c.GetAppState().RecentRepos[1:] + } currentBranches := sync.Map{} From 932b0b593ed3503da9004a4f1fb6b27a34dfb0df Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Mon, 1 Aug 2022 22:13:08 +1000 Subject: [PATCH 4/5] add integration test to ensure we don't run into issues with popup focus --- docs/Integration_Tests.md | 2 +- .../expected/repo/.git_keep/COMMIT_EDITMSG | 1 + .../expected/repo/.git_keep/FETCH_HEAD | 0 .../popupFocus/expected/repo/.git_keep/HEAD | 1 + .../popupFocus/expected/repo/.git_keep/config | 10 ++++++++++ .../expected/repo/.git_keep/description | 1 + .../popupFocus/expected/repo/.git_keep/index | Bin 0 -> 281 bytes .../expected/repo/.git_keep/info/exclude | 7 +++++++ .../expected/repo/.git_keep/logs/HEAD | 3 +++ .../repo/.git_keep/logs/refs/heads/master | 3 +++ .../04/78d727ea0ebf57ed9ca85acef9e60a324d86f0 | 3 +++ .../0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 | Bin 0 -> 52 bytes .../18/0cf8328022becee9aaa2577a8f84ea2b9f3827 | Bin 0 -> 21 bytes .../2b/173c861df433fa43ffad13f80c8b312c5c8bce | Bin 0 -> 103 bytes .../35/3cce986c61f361452f43522426c120b4ee9461 | 3 +++ .../6e/cdae79ff53548670039abee9008b6bb36cdf4f | 2 ++ .../a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 | Bin 0 -> 21 bytes .../a7/341a59f0ddeef969e69fb6368266d22b0f2416 | Bin 0 -> 77 bytes .../df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b | Bin 0 -> 21 bytes .../expected/repo/.git_keep/refs/heads/master | 1 + .../popupFocus/expected/repo/myfile1 | 1 + .../popupFocus/expected/repo/myfile2 | 1 + .../popupFocus/expected/repo/myfile3 | 1 + test/integration/popupFocus/recording.json | 1 + test/integration/popupFocus/setup.sh | 18 ++++++++++++++++++ test/integration/popupFocus/test.json | 1 + 26 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/COMMIT_EDITMSG create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/FETCH_HEAD create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/HEAD create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/config create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/description create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/index create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/info/exclude create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/logs/HEAD create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/logs/refs/heads/master create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/04/78d727ea0ebf57ed9ca85acef9e60a324d86f0 create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/0e/6cf0a6b79e8d44e186d812a1f74b43d64fac52 create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/18/0cf8328022becee9aaa2577a8f84ea2b9f3827 create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/35/3cce986c61f361452f43522426c120b4ee9461 create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/6e/cdae79ff53548670039abee9008b6bb36cdf4f create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b create mode 100644 test/integration/popupFocus/expected/repo/.git_keep/refs/heads/master create mode 100644 test/integration/popupFocus/expected/repo/myfile1 create mode 100644 test/integration/popupFocus/expected/repo/myfile2 create mode 100644 test/integration/popupFocus/expected/repo/myfile3 create mode 100644 test/integration/popupFocus/recording.json create mode 100644 test/integration/popupFocus/setup.sh create mode 100644 test/integration/popupFocus/test.json diff --git a/docs/Integration_Tests.md b/docs/Integration_Tests.md index 3532e2e93..2cbf8064a 100644 --- a/docs/Integration_Tests.md +++ b/docs/Integration_Tests.md @@ -7,7 +7,7 @@ Integration tests are located in `test/integration`. Each test will run a bash s An example of a `test.json` is: ``` -{ "description": "stage a file and commit the change", "speed": 20 } +{ "description": "Open a confirmation, then open a menu over that, then close the menu. Verify that the confirmation popup also closes automatically", "speed": 20 } ``` The `speed` key refers to the playback speed as a multiple of the original recording speed. So 20 means the test will run 20 times faster than the original recording speed. If a test fails for a given speed, it will drop the speed and re-test, until finally attempting the test at the original speed. If you omit the speed, it will default to 10. diff --git a/test/integration/popupFocus/expected/repo/.git_keep/COMMIT_EDITMSG b/test/integration/popupFocus/expected/repo/.git_keep/COMMIT_EDITMSG new file mode 100644 index 000000000..00d7bdd40 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/COMMIT_EDITMSG @@ -0,0 +1 @@ +WIP diff --git a/test/integration/popupFocus/expected/repo/.git_keep/FETCH_HEAD b/test/integration/popupFocus/expected/repo/.git_keep/FETCH_HEAD new file mode 100644 index 000000000..e69de29bb diff --git a/test/integration/popupFocus/expected/repo/.git_keep/HEAD b/test/integration/popupFocus/expected/repo/.git_keep/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/test/integration/popupFocus/expected/repo/.git_keep/config b/test/integration/popupFocus/expected/repo/.git_keep/config new file mode 100644 index 000000000..8ae104545 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/config @@ -0,0 +1,10 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[user] + email = CI@example.com + name = CI diff --git a/test/integration/popupFocus/expected/repo/.git_keep/description b/test/integration/popupFocus/expected/repo/.git_keep/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/test/integration/popupFocus/expected/repo/.git_keep/index b/test/integration/popupFocus/expected/repo/.git_keep/index new file mode 100644 index 0000000000000000000000000000000000000000..d74d35efa5b8b45bfb51d1b04e0f8526e5d98551 GIT binary patch literal 281 zcmZ?q402{*U|<4b=A`F`?kO^CRfExt3=FKyM{l2JU}#*zz`*zws73^c*_Q5k{8u&g z#+QiDD4u+$3jtm&-B%gdb1Ty_b5ad~3PAdmlvU@!Xs9{Q(an+I`C-(cwC~)@Rg1!_ z`deOU&$m#AnPUVsN7*?q3}g<7hMMye-JJW`yxM2Vp1t8erEo}Hz{_7_*AZ!$ImSS9 zLV{dffs`bJv4R1Ywzy53>=)x-&i~g6|KRC1)QRanw>O}4C0}5M;n`ZZlbt8kH+oMl G{0IQfWnokR literal 0 HcmV?d00001 diff --git a/test/integration/popupFocus/expected/repo/.git_keep/info/exclude b/test/integration/popupFocus/expected/repo/.git_keep/info/exclude new file mode 100644 index 000000000..8e9f2071f --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/info/exclude @@ -0,0 +1,7 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ +.DS_Store diff --git a/test/integration/popupFocus/expected/repo/.git_keep/logs/HEAD b/test/integration/popupFocus/expected/repo/.git_keep/logs/HEAD new file mode 100644 index 000000000..03b354937 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/logs/HEAD @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 353cce986c61f361452f43522426c120b4ee9461 CI 1659355870 +1000 commit (initial): myfile1 +353cce986c61f361452f43522426c120b4ee9461 6ecdae79ff53548670039abee9008b6bb36cdf4f CI 1659355870 +1000 commit: myfile2 +6ecdae79ff53548670039abee9008b6bb36cdf4f 0478d727ea0ebf57ed9ca85acef9e60a324d86f0 CI 1659355876 +1000 commit: WIP diff --git a/test/integration/popupFocus/expected/repo/.git_keep/logs/refs/heads/master b/test/integration/popupFocus/expected/repo/.git_keep/logs/refs/heads/master new file mode 100644 index 000000000..03b354937 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/logs/refs/heads/master @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 353cce986c61f361452f43522426c120b4ee9461 CI 1659355870 +1000 commit (initial): myfile1 +353cce986c61f361452f43522426c120b4ee9461 6ecdae79ff53548670039abee9008b6bb36cdf4f CI 1659355870 +1000 commit: myfile2 +6ecdae79ff53548670039abee9008b6bb36cdf4f 0478d727ea0ebf57ed9ca85acef9e60a324d86f0 CI 1659355876 +1000 commit: WIP diff --git a/test/integration/popupFocus/expected/repo/.git_keep/objects/04/78d727ea0ebf57ed9ca85acef9e60a324d86f0 b/test/integration/popupFocus/expected/repo/.git_keep/objects/04/78d727ea0ebf57ed9ca85acef9e60a324d86f0 new file mode 100644 index 000000000..1a59d8559 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/objects/04/78d727ea0ebf57ed9ca85acef9e60a324d86f0 @@ -0,0 +1,3 @@ +x +0E]+f/ȤӼ@D;w +Ɩ7pl`.C8zHy$ռX҈ ف]_] %$UGn> RE$!K!=&ca~ZE#08nZNMgRZ+ literal 0 HcmV?d00001 diff --git a/test/integration/popupFocus/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce b/test/integration/popupFocus/expected/repo/.git_keep/objects/2b/173c861df433fa43ffad13f80c8b312c5c8bce new file mode 100644 index 0000000000000000000000000000000000000000..0a734f98100d24e67455a3cfa8497adaccc7a422 GIT binary patch literal 103 zcmV-t0GR)H0V^p=O;s>7Fl8__FfcPQQOK=K%gjkNWLUcA@n6-{8($(qqj>V2E(CbB zbYDeLV#FZ9^TVh?Y2Ue*s}_Y<^|!pzo^PR!qQsctem1Z6nX+eZ_)jSuQWx;@*VuJL J8UTCqE3ZN5G4lWb literal 0 HcmV?d00001 diff --git a/test/integration/popupFocus/expected/repo/.git_keep/objects/35/3cce986c61f361452f43522426c120b4ee9461 b/test/integration/popupFocus/expected/repo/.git_keep/objects/35/3cce986c61f361452f43522426c120b4ee9461 new file mode 100644 index 000000000..a3e9d66fe --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/objects/35/3cce986c61f361452f43522426c120b4ee9461 @@ -0,0 +1,3 @@ +xA +0@ѮsʌN&\yL`H +~XKY˭*1c  /'Lw=`9/=C7}ZF CowwBDskOn74], \ No newline at end of file diff --git a/test/integration/popupFocus/expected/repo/.git_keep/objects/6e/cdae79ff53548670039abee9008b6bb36cdf4f b/test/integration/popupFocus/expected/repo/.git_keep/objects/6e/cdae79ff53548670039abee9008b6bb36cdf4f new file mode 100644 index 000000000..a23afd560 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/objects/6e/cdae79ff53548670039abee9008b6bb36cdf4f @@ -0,0 +1,2 @@ +xM +0@a9Ed~2퀈U,[J=ǷxyuiOm7#y6+*jeEf)d^SM{8baf.c00K^̓D.3QfrWey\+9> \ No newline at end of file diff --git a/test/integration/popupFocus/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 b/test/integration/popupFocus/expected/repo/.git_keep/objects/a5/bce3fd2565d8f458555a0c6f42d0504a848bd5 new file mode 100644 index 0000000000000000000000000000000000000000..285df3e5fbab12262e28d85e78af8a31cd0024c1 GIT binary patch literal 21 ccmb`~^A08nuUMF0Q* literal 0 HcmV?d00001 diff --git a/test/integration/popupFocus/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 b/test/integration/popupFocus/expected/repo/.git_keep/objects/a7/341a59f0ddeef969e69fb6368266d22b0f2416 new file mode 100644 index 0000000000000000000000000000000000000000..96d2e71a6af75cdd27ac5d9628a27faecc40fb66 GIT binary patch literal 77 zcmV-T0J8sh0V^p=O;s>AU@$Z=Ff%bx$gNDv%tB=N-?^8o7KK;!x4hDxZ=ntVWIZ01*pecg literal 0 HcmV?d00001 diff --git a/test/integration/popupFocus/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b b/test/integration/popupFocus/expected/repo/.git_keep/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b new file mode 100644 index 0000000000000000000000000000000000000000..9b771fc2f6f41f91b00976b4ff3f8f9935f7931e GIT binary patch literal 21 ccmb>`CU&08otwO#lD@ literal 0 HcmV?d00001 diff --git a/test/integration/popupFocus/expected/repo/.git_keep/refs/heads/master b/test/integration/popupFocus/expected/repo/.git_keep/refs/heads/master new file mode 100644 index 000000000..6ffdf61da --- /dev/null +++ b/test/integration/popupFocus/expected/repo/.git_keep/refs/heads/master @@ -0,0 +1 @@ +0478d727ea0ebf57ed9ca85acef9e60a324d86f0 diff --git a/test/integration/popupFocus/expected/repo/myfile1 b/test/integration/popupFocus/expected/repo/myfile1 new file mode 100644 index 000000000..a5bce3fd2 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/myfile1 @@ -0,0 +1 @@ +test1 diff --git a/test/integration/popupFocus/expected/repo/myfile2 b/test/integration/popupFocus/expected/repo/myfile2 new file mode 100644 index 000000000..180cf8328 --- /dev/null +++ b/test/integration/popupFocus/expected/repo/myfile2 @@ -0,0 +1 @@ +test2 diff --git a/test/integration/popupFocus/expected/repo/myfile3 b/test/integration/popupFocus/expected/repo/myfile3 new file mode 100644 index 000000000..df6b0d2bc --- /dev/null +++ b/test/integration/popupFocus/expected/repo/myfile3 @@ -0,0 +1 @@ +test3 diff --git a/test/integration/popupFocus/recording.json b/test/integration/popupFocus/recording.json new file mode 100644 index 000000000..e7f4f9d53 --- /dev/null +++ b/test/integration/popupFocus/recording.json @@ -0,0 +1 @@ +{"KeyEvents":[{"Timestamp":607,"Mod":0,"Key":259,"Ch":0},{"Timestamp":745,"Mod":0,"Key":259,"Ch":0},{"Timestamp":1304,"Mod":0,"Key":256,"Ch":82},{"Timestamp":2087,"Mod":2,"Key":18,"Ch":18},{"Timestamp":2894,"Mod":0,"Key":27,"Ch":0},{"Timestamp":3553,"Mod":0,"Key":260,"Ch":0},{"Timestamp":3697,"Mod":0,"Key":260,"Ch":0},{"Timestamp":4064,"Mod":0,"Key":256,"Ch":32},{"Timestamp":4376,"Mod":0,"Key":256,"Ch":119},{"Timestamp":4745,"Mod":0,"Key":13,"Ch":13},{"Timestamp":5200,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":238,"Height":61}]} \ No newline at end of file diff --git a/test/integration/popupFocus/setup.sh b/test/integration/popupFocus/setup.sh new file mode 100644 index 000000000..b22a9c241 --- /dev/null +++ b/test/integration/popupFocus/setup.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +cd $1 + +git init + +git config user.email "CI@example.com" +git config user.name "CI" + +echo test1 > myfile1 +git add . +git commit -am "myfile1" +echo test2 > myfile2 +git add . +git commit -am "myfile2" +echo test3 > myfile3 diff --git a/test/integration/popupFocus/test.json b/test/integration/popupFocus/test.json new file mode 100644 index 000000000..60bfe9319 --- /dev/null +++ b/test/integration/popupFocus/test.json @@ -0,0 +1 @@ +{ "description": "stage a file and commit the change", "speed": 15 } From c1c6e2fac24f8db618c8d895db272ca486b78300 Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Tue, 2 Aug 2022 09:16:01 +1000 Subject: [PATCH 5/5] make exception for searching from menu --- pkg/gui/context.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/gui/context.go b/pkg/gui/context.go index 89356d956..f08acec06 100644 --- a/pkg/gui/context.go +++ b/pkg/gui/context.go @@ -100,7 +100,8 @@ func (gui *Gui) pushContext(c types.Context, opts ...types.OnFocusOpts) error { // if top one is a temporary popup, we remove it. Ideally you'd be able to // escape back to previous temporary popups, but because we're currently reusing // views for this, you might not be able to get back to where you previously were. - if topContext.GetKind() == types.TEMPORARY_POPUP { + // The exception is when going to the search context e.g. for searching a menu. + if topContext.GetKind() == types.TEMPORARY_POPUP && c.GetKey() != context.SEARCH_CONTEXT_KEY { if err := gui.deactivateContext(topContext); err != nil { gui.State.ContextManager.Unlock() return err