diff --git a/pkg/cheatsheet/generate.go b/pkg/cheatsheet/generate.go index 004b13db1..3a5299062 100644 --- a/pkg/cheatsheet/generate.go +++ b/pkg/cheatsheet/generate.go @@ -116,6 +116,7 @@ func localisedTitle(tr *i18n.TranslationSet, str string) string { "commitDescription": tr.CommitDescriptionTitle, "commits": tr.CommitsTitle, "confirmation": tr.ConfirmationTitle, + "prompt": tr.PromptTitle, "information": tr.InformationTitle, "main": tr.NormalTitle, "patchBuilding": tr.PatchBuildingTitle, diff --git a/pkg/gui/context/context.go b/pkg/gui/context/context.go index a993cf253..8af05e36f 100644 --- a/pkg/gui/context/context.go +++ b/pkg/gui/context/context.go @@ -41,6 +41,7 @@ const ( MENU_CONTEXT_KEY types.ContextKey = "menu" CONFIRMATION_CONTEXT_KEY types.ContextKey = "confirmation" + PROMPT_CONTEXT_KEY types.ContextKey = "prompt" SEARCH_CONTEXT_KEY types.ContextKey = "search" COMMIT_MESSAGE_CONTEXT_KEY types.ContextKey = "commitMessage" COMMIT_DESCRIPTION_CONTEXT_KEY types.ContextKey = "commitDescription" @@ -73,6 +74,7 @@ var AllContextKeys = []types.ContextKey{ MENU_CONTEXT_KEY, CONFIRMATION_CONTEXT_KEY, + PROMPT_CONTEXT_KEY, SEARCH_CONTEXT_KEY, COMMIT_MESSAGE_CONTEXT_KEY, SUBMODULES_CONTEXT_KEY, @@ -106,6 +108,7 @@ type ContextTree struct { CustomPatchBuilderSecondary types.Context MergeConflicts *MergeConflictsContext Confirmation *ConfirmationContext + Prompt *PromptContext CommitMessage *CommitMessageContext CommitDescription types.Context CommandLog types.Context @@ -141,6 +144,7 @@ func (self *ContextTree) Flatten() []types.Context { self.Stash, self.Menu, self.Confirmation, + self.Prompt, self.CommitMessage, self.CommitDescription, diff --git a/pkg/gui/context/prompt_context.go b/pkg/gui/context/prompt_context.go new file mode 100644 index 000000000..c1def571c --- /dev/null +++ b/pkg/gui/context/prompt_context.go @@ -0,0 +1,30 @@ +package context + +import ( + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type PromptContext struct { + *SimpleContext + c *ContextCommon + + State ConfirmationContextState +} + +var _ types.Context = (*PromptContext)(nil) + +func NewPromptContext( + c *ContextCommon, +) *PromptContext { + return &PromptContext{ + c: c, + SimpleContext: NewSimpleContext(NewBaseContext(NewBaseContextOpts{ + View: c.Views().Prompt, + WindowName: "prompt", + Key: PROMPT_CONTEXT_KEY, + Kind: types.TEMPORARY_POPUP, + Focusable: true, + HasUncontrolledBounds: true, + })), + } +} diff --git a/pkg/gui/context/setup.go b/pkg/gui/context/setup.go index 3a87c100a..8f498e6a9 100644 --- a/pkg/gui/context/setup.go +++ b/pkg/gui/context/setup.go @@ -84,6 +84,7 @@ func NewContextTree(c *ContextCommon) *ContextTree { c, ), Confirmation: NewConfirmationContext(c), + Prompt: NewPromptContext(c), CommitMessage: NewCommitMessageContext(c), CommitDescription: NewSimpleContext( NewBaseContext(NewBaseContextOpts{ diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index 20b52b2cb..f3ea245cf 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -193,6 +193,7 @@ func (gui *Gui) resetHelpersAndControllers() { statusController := controllers.NewStatusController(common) commandLogController := controllers.NewCommandLogController(common) confirmationController := controllers.NewConfirmationController(common) + promptController := controllers.NewPromptController(common) suggestionsController := controllers.NewSuggestionsController(common) jumpToSideWindowController := controllers.NewJumpToSideWindowController(common, gui.handleNextTab) @@ -399,6 +400,10 @@ func (gui *Gui) resetHelpersAndControllers() { confirmationController, ) + controllers.AttachControllers(gui.State.Contexts.Prompt, + promptController, + ) + controllers.AttachControllers(gui.State.Contexts.Suggestions, suggestionsController, ) diff --git a/pkg/gui/controllers/confirmation_controller.go b/pkg/gui/controllers/confirmation_controller.go index 1e4e5cd46..206818f40 100644 --- a/pkg/gui/controllers/confirmation_controller.go +++ b/pkg/gui/controllers/confirmation_controller.go @@ -1,9 +1,6 @@ package controllers import ( - "fmt" - - "github.com/jesseduffield/gocui" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" ) @@ -39,45 +36,19 @@ func (self *ConfirmationController) GetKeybindings(opts types.KeybindingsOpts) [ DisplayOnScreen: true, }, { - Key: opts.GetKey(opts.Config.Universal.TogglePanel), - Handler: func() error { - if len(self.c.Contexts().Suggestions.State.Suggestions) > 0 { - self.switchToSuggestions() - } - return nil - }, - }, - { - Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), - Handler: self.handleCopyToClipboard, - Description: self.c.Tr.CopyToClipboardMenu, - DisplayOnScreen: true, - GetDisabledReason: self.copyToClipboardEnabled, + Key: opts.GetKey(opts.Config.Universal.CopyToClipboard), + Handler: self.handleCopyToClipboard, + Description: self.c.Tr.CopyToClipboardMenu, + DisplayOnScreen: true, }, } return bindings } -func (self *ConfirmationController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { - return []*gocui.ViewMouseBinding{ - { - ViewName: self.c.Contexts().Suggestions.GetViewName(), - FocusedView: self.c.Contexts().Confirmation.GetViewName(), - Key: gocui.MouseLeft, - Handler: func(gocui.ViewMouseBindingOpts) error { - self.switchToSuggestions() - // Let it fall through to the ListController's click handler so that - // the clicked line gets selected: - return gocui.ErrKeybindingNotHandled - }, - }, - } -} - func (self *ConfirmationController) GetOnFocusLost() func(types.OnFocusLostOpts) { return func(types.OnFocusLostOpts) { - self.c.Helpers().Confirmation.DeactivateConfirmationPrompt() + self.c.Helpers().Confirmation.DeactivateConfirmation() } } @@ -89,18 +60,6 @@ func (self *ConfirmationController) context() *context.ConfirmationContext { return self.c.Contexts().Confirmation } -func (self *ConfirmationController) switchToSuggestions() { - subtitle := "" - if self.c.State().GetRepoState().GetCurrentPopupOpts().HandleDeleteSuggestion != nil { - // We assume that whenever things are deletable, they - // are also editable, so we show both keybindings - subtitle = fmt.Sprintf(self.c.Tr.SuggestionsSubtitle, - self.c.UserConfig().Keybinding.Universal.Remove, self.c.UserConfig().Keybinding.Universal.Edit) - } - self.c.Views().Suggestions.Subtitle = subtitle - self.c.Context().Replace(self.c.Contexts().Suggestions) -} - func (self *ConfirmationController) handleCopyToClipboard() error { confirmationView := self.c.Views().Confirmation text := confirmationView.Buffer() @@ -111,12 +70,3 @@ func (self *ConfirmationController) handleCopyToClipboard() error { self.c.Toast(self.c.Tr.MessageCopiedToClipboard) return nil } - -func (self *ConfirmationController) copyToClipboardEnabled() *types.DisabledReason { - if self.c.Views().Confirmation.Editable { - // The empty text is intentional. We don't want to get a toast when invoking this, we only - // want to prevent it from showing up in the options bar. - return &types.DisabledReason{Text: ""} - } - return nil -} diff --git a/pkg/gui/controllers/helpers/confirmation_helper.go b/pkg/gui/controllers/helpers/confirmation_helper.go index c59275275..f8e25c47c 100644 --- a/pkg/gui/controllers/helpers/confirmation_helper.go +++ b/pkg/gui/controllers/helpers/confirmation_helper.go @@ -46,17 +46,27 @@ func (self *ConfirmationHelper) wrappedPromptConfirmationFunction(cancel goConte }) } -func (self *ConfirmationHelper) DeactivateConfirmationPrompt() { +func (self *ConfirmationHelper) DeactivateConfirmation() { self.c.Mutexes().PopupMutex.Lock() self.c.State().GetRepoState().SetCurrentPopupOpts(nil) self.c.Mutexes().PopupMutex.Unlock() self.c.Views().Confirmation.Visible = false - self.c.Views().Suggestions.Visible = false self.clearConfirmationViewKeyBindings() } +func (self *ConfirmationHelper) DeactivatePrompt() { + self.c.Mutexes().PopupMutex.Lock() + self.c.State().GetRepoState().SetCurrentPopupOpts(nil) + self.c.Mutexes().PopupMutex.Unlock() + + self.c.Views().Prompt.Visible = false + self.c.Views().Suggestions.Visible = false + + self.clearPromptViewKeyBindings() +} + func getMessageHeight(wrap bool, editable bool, message string, width int, tabWidth int) int { wrappedLines, _, _ := utils.WrapViewLinesToWidth(wrap, editable, message, width, tabWidth) return len(wrappedLines) @@ -105,15 +115,28 @@ func (self *ConfirmationHelper) prepareConfirmationPanel( opts types.ConfirmOpts, ) { self.c.Views().Confirmation.Title = opts.Title - // for now we do not support wrapping in our editor - self.c.Views().Confirmation.Wrap = !opts.Editable self.c.Views().Confirmation.FgColor = theme.GocuiDefaultTextColor - self.c.Views().Confirmation.Mask = runeForMask(opts.Mask) - self.c.Views().Confirmation.SetOrigin(0, 0) - suggestionsContext := self.c.Contexts().Suggestions - suggestionsContext.State.FindSuggestions = opts.FindSuggestionsFunc + self.c.ResetViewOrigin(self.c.Views().Confirmation) + self.c.SetViewContent(self.c.Views().Confirmation, style.AttrBold.Sprint(strings.TrimSpace(opts.Prompt))) +} + +func (self *ConfirmationHelper) preparePromptPanel( + opts types.ConfirmOpts, +) { + self.c.Views().Prompt.Title = opts.Title + self.c.Views().Prompt.FgColor = theme.GocuiDefaultTextColor + self.c.Views().Prompt.Mask = runeForMask(opts.Mask) + self.c.Views().Prompt.SetOrigin(0, 0) + + textArea := self.c.Views().Prompt.TextArea + textArea.Clear() + textArea.TypeString(opts.Prompt) + self.c.Views().Prompt.RenderTextArea() + if opts.FindSuggestionsFunc != nil { + suggestionsContext := self.c.Contexts().Suggestions + suggestionsContext.State.FindSuggestions = opts.FindSuggestionsFunc suggestionsView := self.c.Views().Suggestions suggestionsView.Wrap = false suggestionsView.FgColor = theme.GocuiDefaultTextColor @@ -150,44 +173,59 @@ func (self *ConfirmationHelper) CreatePopupPanel(ctx goContext.Context, opts typ // remove any previous keybindings self.clearConfirmationViewKeyBindings() + self.clearPromptViewKeyBindings() - self.prepareConfirmationPanel( - types.ConfirmOpts{ - Title: opts.Title, - Prompt: opts.Prompt, - FindSuggestionsFunc: opts.FindSuggestionsFunc, - Editable: opts.Editable, - Mask: opts.Mask, - }) - confirmationView := self.c.Views().Confirmation - confirmationView.Editable = opts.Editable - + var context types.Context if opts.Editable { - textArea := confirmationView.TextArea - textArea.Clear() - textArea.TypeString(opts.Prompt) - confirmationView.RenderTextArea() - } else { - self.c.ResetViewOrigin(confirmationView) - self.c.SetViewContent(confirmationView, style.AttrBold.Sprint(strings.TrimSpace(opts.Prompt))) - } + self.c.Contexts().Suggestions.State.FindSuggestions = opts.FindSuggestionsFunc - self.setKeyBindings(cancel, opts) + self.preparePromptPanel( + types.ConfirmOpts{ + Title: opts.Title, + Prompt: opts.Prompt, + FindSuggestionsFunc: opts.FindSuggestionsFunc, + Mask: opts.Mask, + }) + + context = self.c.Contexts().Prompt + + self.setPromptKeyBindings(cancel, opts) + } else { + if opts.FindSuggestionsFunc != nil { + panic("non-editable confirmation views do not support suggestions") + } + + self.c.Contexts().Suggestions.State.FindSuggestions = nil + + self.prepareConfirmationPanel( + types.ConfirmOpts{ + Title: opts.Title, + Prompt: opts.Prompt, + }) + + context = self.c.Contexts().Confirmation + + self.setConfirmationKeyBindings(cancel, opts) + } self.c.Contexts().Suggestions.State.AllowEditSuggestion = opts.AllowEditSuggestion self.c.State().GetRepoState().SetCurrentPopupOpts(&opts) - self.c.Context().Push(self.c.Contexts().Confirmation, types.OnFocusOpts{}) + self.c.Context().Push(context, types.OnFocusOpts{}) } -func (self *ConfirmationHelper) setKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) { - var onConfirm func() error - if opts.HandleConfirmPrompt != nil { - onConfirm = self.wrappedPromptConfirmationFunction(cancel, opts.HandleConfirmPrompt, func() string { return self.c.Views().Confirmation.TextArea.GetContent() }) - } else { - onConfirm = self.wrappedConfirmationFunction(cancel, opts.HandleConfirm) - } +func (self *ConfirmationHelper) setConfirmationKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) { + onConfirm := self.wrappedConfirmationFunction(cancel, opts.HandleConfirm) + onClose := self.wrappedConfirmationFunction(cancel, opts.HandleClose) + + self.c.Contexts().Confirmation.State.OnConfirm = onConfirm + self.c.Contexts().Confirmation.State.OnClose = onClose +} + +func (self *ConfirmationHelper) setPromptKeyBindings(cancel goContext.CancelFunc, opts types.CreatePopupPanelOpts) { + onConfirm := self.wrappedPromptConfirmationFunction(cancel, opts.HandleConfirmPrompt, + func() string { return self.c.Views().Prompt.TextArea.GetContent() }) onSuggestionConfirm := self.wrappedPromptConfirmationFunction( cancel, @@ -206,8 +244,8 @@ func (self *ConfirmationHelper) setKeyBindings(cancel goContext.CancelFunc, opts return opts.HandleDeleteSuggestion(idx) } - self.c.Contexts().Confirmation.State.OnConfirm = onConfirm - self.c.Contexts().Confirmation.State.OnClose = onClose + self.c.Contexts().Prompt.State.OnConfirm = onConfirm + self.c.Contexts().Prompt.State.OnClose = onClose self.c.Contexts().Suggestions.State.OnConfirm = onSuggestionConfirm self.c.Contexts().Suggestions.State.OnClose = onClose self.c.Contexts().Suggestions.State.OnDeleteSuggestion = onDeleteSuggestion @@ -217,6 +255,12 @@ func (self *ConfirmationHelper) clearConfirmationViewKeyBindings() { noop := func() error { return nil } self.c.Contexts().Confirmation.State.OnConfirm = noop self.c.Contexts().Confirmation.State.OnClose = noop +} + +func (self *ConfirmationHelper) clearPromptViewKeyBindings() { + noop := func() error { return nil } + self.c.Contexts().Prompt.State.OnConfirm = noop + self.c.Contexts().Prompt.State.OnClose = noop self.c.Contexts().Suggestions.State.OnConfirm = noop self.c.Contexts().Suggestions.State.OnClose = noop self.c.Contexts().Suggestions.State.OnDeleteSuggestion = noop @@ -238,8 +282,10 @@ func (self *ConfirmationHelper) ResizeCurrentPopupPanels() { switch c { case self.c.Contexts().Menu: self.resizeMenu(parentPopupContext) - case self.c.Contexts().Confirmation, self.c.Contexts().Suggestions: + case self.c.Contexts().Confirmation: self.resizeConfirmationPanel(parentPopupContext) + case self.c.Contexts().Prompt, self.c.Contexts().Suggestions: + self.resizePromptPanel(parentPopupContext) case self.c.Contexts().CommitMessage, self.c.Contexts().CommitDescription: self.ResizeCommitMessagePanels(parentPopupContext) } @@ -300,26 +346,30 @@ func (self *ConfirmationHelper) layoutMenuPrompt(contentWidth int) int { } func (self *ConfirmationHelper) resizeConfirmationPanel(parentPopupContext types.Context) { + panelWidth := self.getPopupPanelWidth() + contentWidth := panelWidth - 2 // minus 2 for the frame + confirmationView := self.c.Views().Confirmation + prompt := confirmationView.Buffer() + panelHeight := getMessageHeight(true, false, prompt, contentWidth, confirmationView.TabWidth) + x0, y0, x1, y1 := self.getPopupPanelDimensionsAux(panelWidth, panelHeight, parentPopupContext) + _, _ = self.c.GocuiGui().SetView(confirmationView.Name(), x0, y0, x1, y1, 0) +} + +func (self *ConfirmationHelper) resizePromptPanel(parentPopupContext types.Context) { suggestionsViewHeight := 0 if self.c.Views().Suggestions.Visible { suggestionsViewHeight = 11 } panelWidth := self.getPopupPanelWidth() contentWidth := panelWidth - 2 // minus 2 for the frame - confirmationView := self.c.Views().Confirmation - prompt := confirmationView.Buffer() - wrap := true - editable := confirmationView.Editable - if editable { - prompt = confirmationView.TextArea.GetContent() - wrap = false - } - panelHeight := getMessageHeight(wrap, editable, prompt, contentWidth, confirmationView.TabWidth) + suggestionsViewHeight + promptView := self.c.Views().Prompt + prompt := promptView.TextArea.GetContent() + panelHeight := getMessageHeight(false, true, prompt, contentWidth, promptView.TabWidth) + suggestionsViewHeight x0, y0, x1, y1 := self.getPopupPanelDimensionsAux(panelWidth, panelHeight, parentPopupContext) - confirmationViewBottom := y1 - suggestionsViewHeight - _, _ = self.c.GocuiGui().SetView(confirmationView.Name(), x0, y0, x1, confirmationViewBottom, 0) + promptViewBottom := y1 - suggestionsViewHeight + _, _ = self.c.GocuiGui().SetView(promptView.Name(), x0, y0, x1, promptViewBottom, 0) - suggestionsViewTop := confirmationViewBottom + 1 + suggestionsViewTop := promptViewBottom + 1 _, _ = self.c.GocuiGui().SetView(self.c.Views().Suggestions.Name(), x0, suggestionsViewTop, x1, suggestionsViewTop+suggestionsViewHeight, 0) } diff --git a/pkg/gui/controllers/prompt_controller.go b/pkg/gui/controllers/prompt_controller.go new file mode 100644 index 000000000..4d98e294f --- /dev/null +++ b/pkg/gui/controllers/prompt_controller.go @@ -0,0 +1,95 @@ +package controllers + +import ( + "fmt" + + "github.com/jesseduffield/gocui" + "github.com/jesseduffield/lazygit/pkg/gui/context" + "github.com/jesseduffield/lazygit/pkg/gui/types" +) + +type PromptController struct { + baseController + c *ControllerCommon +} + +var _ types.IController = &PromptController{} + +func NewPromptController( + c *ControllerCommon, +) *PromptController { + return &PromptController{ + baseController: baseController{}, + c: c, + } +} + +func (self *PromptController) GetKeybindings(opts types.KeybindingsOpts) []*types.Binding { + bindings := []*types.Binding{ + { + Key: opts.GetKey(opts.Config.Universal.Confirm), + Handler: func() error { return self.context().State.OnConfirm() }, + Description: self.c.Tr.Confirm, + DisplayOnScreen: true, + }, + { + Key: opts.GetKey(opts.Config.Universal.Return), + Handler: func() error { return self.context().State.OnClose() }, + Description: self.c.Tr.CloseCancel, + DisplayOnScreen: true, + }, + { + Key: opts.GetKey(opts.Config.Universal.TogglePanel), + Handler: func() error { + if len(self.c.Contexts().Suggestions.State.Suggestions) > 0 { + self.switchToSuggestions() + } + return nil + }, + }, + } + + return bindings +} + +func (self *PromptController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { + return []*gocui.ViewMouseBinding{ + { + ViewName: self.c.Contexts().Suggestions.GetViewName(), + FocusedView: self.c.Contexts().Prompt.GetViewName(), + Key: gocui.MouseLeft, + Handler: func(gocui.ViewMouseBindingOpts) error { + self.switchToSuggestions() + // Let it fall through to the ListController's click handler so that + // the clicked line gets selected: + return gocui.ErrKeybindingNotHandled + }, + }, + } +} + +func (self *PromptController) GetOnFocusLost() func(types.OnFocusLostOpts) { + return func(types.OnFocusLostOpts) { + self.c.Helpers().Confirmation.DeactivatePrompt() + } +} + +func (self *PromptController) Context() types.Context { + return self.context() +} + +func (self *PromptController) context() *context.PromptContext { + return self.c.Contexts().Prompt +} + +func (self *PromptController) switchToSuggestions() { + subtitle := "" + if self.c.State().GetRepoState().GetCurrentPopupOpts().HandleDeleteSuggestion != nil { + // We assume that whenever things are deletable, they + // are also editable, so we show both keybindings + subtitle = fmt.Sprintf(self.c.Tr.SuggestionsSubtitle, + self.c.UserConfig().Keybinding.Universal.Remove, self.c.UserConfig().Keybinding.Universal.Edit) + } + self.c.Views().Suggestions.Subtitle = subtitle + self.c.Context().Replace(self.c.Contexts().Suggestions) +} diff --git a/pkg/gui/controllers/suggestions_controller.go b/pkg/gui/controllers/suggestions_controller.go index d97e56289..01ec3a145 100644 --- a/pkg/gui/controllers/suggestions_controller.go +++ b/pkg/gui/controllers/suggestions_controller.go @@ -42,7 +42,7 @@ func (self *SuggestionsController) GetKeybindings(opts types.KeybindingsOpts) [] }, { Key: opts.GetKey(opts.Config.Universal.TogglePanel), - Handler: self.switchToConfirmation, + Handler: self.switchToPrompt, }, { Key: opts.GetKey(opts.Config.Universal.Remove), @@ -55,11 +55,11 @@ func (self *SuggestionsController) GetKeybindings(opts types.KeybindingsOpts) [] Handler: func() error { if self.context().State.AllowEditSuggestion { if selectedItem := self.c.Contexts().Suggestions.GetSelected(); selectedItem != nil { - self.c.Contexts().Confirmation.GetView().TextArea.Clear() - self.c.Contexts().Confirmation.GetView().TextArea.TypeString(selectedItem.Value) - self.c.Contexts().Confirmation.GetView().RenderTextArea() + self.c.Contexts().Prompt.GetView().TextArea.Clear() + self.c.Contexts().Prompt.GetView().TextArea.TypeString(selectedItem.Value) + self.c.Contexts().Prompt.GetView().RenderTextArea() self.c.Contexts().Suggestions.RefreshSuggestions() - return self.switchToConfirmation() + return self.switchToPrompt() } } return nil @@ -73,26 +73,26 @@ func (self *SuggestionsController) GetKeybindings(opts types.KeybindingsOpts) [] func (self *SuggestionsController) GetMouseKeybindings(opts types.KeybindingsOpts) []*gocui.ViewMouseBinding { return []*gocui.ViewMouseBinding{ { - ViewName: self.c.Contexts().Confirmation.GetViewName(), + ViewName: self.c.Contexts().Prompt.GetViewName(), FocusedView: self.c.Contexts().Suggestions.GetViewName(), Key: gocui.MouseLeft, Handler: func(gocui.ViewMouseBindingOpts) error { - return self.switchToConfirmation() + return self.switchToPrompt() }, }, } } -func (self *SuggestionsController) switchToConfirmation() error { +func (self *SuggestionsController) switchToPrompt() error { self.c.Views().Suggestions.Subtitle = "" self.c.Views().Suggestions.Highlight = false - self.c.Context().Replace(self.c.Contexts().Confirmation) + self.c.Context().Replace(self.c.Contexts().Prompt) return nil } func (self *SuggestionsController) GetOnFocusLost() func(types.OnFocusLostOpts) { return func(types.OnFocusLostOpts) { - self.c.Helpers().Confirmation.DeactivateConfirmationPrompt() + self.c.Helpers().Confirmation.DeactivatePrompt() } } diff --git a/pkg/gui/global_handlers.go b/pkg/gui/global_handlers.go index 9abadf4e0..9b6551d33 100644 --- a/pkg/gui/global_handlers.go +++ b/pkg/gui/global_handlers.go @@ -90,60 +90,36 @@ func (gui *Gui) scrollDownSecondary() error { } func (gui *Gui) scrollUpConfirmationPanel() error { - if gui.Views.Confirmation.Editable { - return nil - } - gui.scrollUpView(gui.Views.Confirmation) return nil } func (gui *Gui) scrollDownConfirmationPanel() error { - if gui.Views.Confirmation.Editable { - return nil - } - gui.scrollDownView(gui.Views.Confirmation) return nil } func (gui *Gui) pageUpConfirmationPanel() error { - if gui.Views.Confirmation.Editable { - return nil - } - gui.Views.Confirmation.ScrollUp(gui.Contexts().Confirmation.GetViewTrait().PageDelta()) return nil } func (gui *Gui) pageDownConfirmationPanel() error { - if gui.Views.Confirmation.Editable { - return nil - } - gui.Views.Confirmation.ScrollDown(gui.Contexts().Confirmation.GetViewTrait().PageDelta()) return nil } func (gui *Gui) goToConfirmationPanelTop() error { - if gui.Views.Confirmation.Editable { - return gocui.ErrKeybindingNotHandled - } - gui.Views.Confirmation.ScrollUp(gui.Views.Confirmation.ViewLinesHeight()) return nil } func (gui *Gui) goToConfirmationPanelBottom() error { - if gui.Views.Confirmation.Editable { - return gocui.ErrKeybindingNotHandled - } - gui.Views.Confirmation.ScrollDown(gui.Views.Confirmation.ViewLinesHeight()) return nil diff --git a/pkg/gui/gui.go b/pkg/gui/gui.go index 1bd5788f2..c9252e03d 100644 --- a/pkg/gui/gui.go +++ b/pkg/gui/gui.go @@ -697,7 +697,7 @@ func NewGui( return gui.helpers.AppStatus.WithWaitingStatusSync(message, f) }, func(message string, kind types.ToastKind) { gui.helpers.AppStatus.Toast(message, kind) }, - func() string { return gui.Views.Confirmation.TextArea.GetContent() }, + func() string { return gui.Views.Prompt.TextArea.GetContent() }, func() bool { return gui.c.InDemo() }, ) diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index c966b148a..084a25159 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -507,11 +507,11 @@ func (gui *Gui) SetMouseKeybinding(binding *gocui.ViewMouseBinding) error { !gocui.IsMouseScrollKey(opts.Key) { // we ignore click events on views that aren't popup panels, when a popup panel is focused. // Unless both the current view and the clicked-on view are either commit message or commit - // description, or a confirmation and the suggestions view, because we want to allow switching + // description, or a prompt and the suggestions view, because we want to allow switching // between those two views by clicking. isCommitMessageOrSuggestionsView := func(viewName string) bool { return viewName == "commitMessage" || viewName == "commitDescription" || - viewName == "confirmation" || viewName == "suggestions" + viewName == "prompt" || viewName == "suggestions" } if !isCommitMessageOrSuggestionsView(gui.currentViewName()) || !isCommitMessageOrSuggestionsView(binding.ViewName) { return nil diff --git a/pkg/gui/types/views.go b/pkg/gui/types/views.go index 867dff92e..46a67d23a 100644 --- a/pkg/gui/types/views.go +++ b/pkg/gui/types/views.go @@ -25,6 +25,7 @@ type Views struct { Options *gocui.View Confirmation *gocui.View + Prompt *gocui.View Menu *gocui.View CommitMessage *gocui.View CommitDescription *gocui.View diff --git a/pkg/gui/views.go b/pkg/gui/views.go index 8eb62c623..629f5e396 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -68,6 +68,7 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping { {viewPtr: &gui.Views.Menu, name: "menu"}, {viewPtr: &gui.Views.Suggestions, name: "suggestions"}, {viewPtr: &gui.Views.Confirmation, name: "confirmation"}, + {viewPtr: &gui.Views.Prompt, name: "prompt"}, {viewPtr: &gui.Views.Tooltip, name: "tooltip"}, // this guy will cover everything else when it appears @@ -127,9 +128,14 @@ func (gui *Gui) createAllViews() error { gui.Views.CommitDescription.Editor = gocui.EditorFunc(gui.commitDescriptionEditor) gui.Views.Confirmation.Visible = false - gui.Views.Confirmation.Editor = gocui.EditorFunc(gui.promptEditor) + gui.Views.Confirmation.Wrap = true gui.Views.Confirmation.AutoRenderHyperLinks = true + gui.Views.Prompt.Visible = false + gui.Views.Prompt.Wrap = false // We don't want wrapping in one-line prompts + gui.Views.Prompt.Editable = true + gui.Views.Prompt.Editor = gocui.EditorFunc(gui.promptEditor) + gui.Views.Suggestions.Visible = false gui.Views.Menu.Visible = false diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index ea9f805a2..9db91b7a8 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -611,6 +611,7 @@ type TranslationSet struct { MustStashWarning string MustStashTitle string ConfirmationTitle string + PromptTitle string PrevPage string NextPage string GotoTop string @@ -1692,6 +1693,7 @@ func EnglishTranslationSet() *TranslationSet { MustStashWarning: "Pulling a patch out into the index requires stashing and unstashing your changes. If something goes wrong, you'll be able to access your files from the stash. Continue?", MustStashTitle: "Must stash", ConfirmationTitle: "Confirmation panel", + PromptTitle: "Input prompt", PrevPage: "Previous page", NextPage: "Next page", GotoTop: "Scroll to top", diff --git a/pkg/integration/components/popup.go b/pkg/integration/components/popup.go index aa80770b2..3cdc4f1f2 100644 --- a/pkg/integration/components/popup.go +++ b/pkg/integration/components/popup.go @@ -13,7 +13,7 @@ func (self *Popup) Confirmation() *ConfirmationDriver { func (self *Popup) inConfirm() { self.t.assertWithRetries(func() (bool, string) { currentView := self.t.gui.CurrentContext().GetView() - return currentView.Name() == "confirmation" && !currentView.Editable, "Expected confirmation popup to be focused" + return currentView.Name() == "confirmation", "Expected confirmation popup to be focused" }) } @@ -26,7 +26,7 @@ func (self *Popup) Prompt() *PromptDriver { func (self *Popup) inPrompt() { self.t.assertWithRetries(func() (bool, string) { currentView := self.t.gui.CurrentContext().GetView() - return currentView.Name() == "confirmation" && currentView.Editable, "Expected prompt popup to be focused" + return currentView.Name() == "prompt", "Expected prompt popup to be focused" }) } @@ -45,7 +45,7 @@ func (self *Popup) inAlert() { // basically the same thing as a confirmation popup with the current implementation self.t.assertWithRetries(func() (bool, string) { currentView := self.t.gui.CurrentContext().GetView() - return currentView.Name() == "confirmation" && !currentView.Editable, "Expected alert popup to be focused" + return currentView.Name() == "confirmation", "Expected alert popup to be focused" }) } diff --git a/pkg/integration/components/prompt_driver.go b/pkg/integration/components/prompt_driver.go index a19c29aa4..34c07614b 100644 --- a/pkg/integration/components/prompt_driver.go +++ b/pkg/integration/components/prompt_driver.go @@ -6,7 +6,7 @@ type PromptDriver struct { } func (self *PromptDriver) getViewDriver() *ViewDriver { - return self.t.Views().Confirmation() + return self.t.Views().Prompt() } // asserts that the popup has the expected title diff --git a/pkg/integration/components/views.go b/pkg/integration/components/views.go index 873aca650..1d32f4828 100644 --- a/pkg/integration/components/views.go +++ b/pkg/integration/components/views.go @@ -128,6 +128,10 @@ func (self *Views) Confirmation() *ViewDriver { return self.regularView("confirmation") } +func (self *Views) Prompt() *ViewDriver { + return self.regularView("prompt") +} + func (self *Views) CommitMessage() *ViewDriver { return self.regularView("commitMessage") }