diff --git a/pkg/gui/types/views.go b/pkg/gui/types/views.go index c740ccb2e..1a48d170a 100644 --- a/pkg/gui/types/views.go +++ b/pkg/gui/types/views.go @@ -27,6 +27,8 @@ type Views struct { Confirmation *gocui.View Prompt *gocui.View Menu *gocui.View + MenuFilterFrame *gocui.View + MenuFilter *gocui.View CommitMessage *gocui.View CommitDescription *gocui.View CommitFiles *gocui.View diff --git a/pkg/gui/views.go b/pkg/gui/views.go index b47e76c5a..895260fd9 100644 --- a/pkg/gui/views.go +++ b/pkg/gui/views.go @@ -66,6 +66,12 @@ func (gui *Gui) orderedViewNameMappings() []viewNameMapping { {viewPtr: &gui.Views.CommitMessage, name: "commitMessage"}, {viewPtr: &gui.Views.CommitDescription, name: "commitDescription"}, {viewPtr: &gui.Views.Menu, name: "menu"}, + // the filter row of a menu that filters as you type: a frame that hangs off + // the bottom of the menu and shows the "Filter:" prompt, plus the input + // field that sits inside it. Both must come after the menu so that the row's + // top border is drawn over the menu's bottom border. + {viewPtr: &gui.Views.MenuFilterFrame, name: "menuFilterFrame"}, + {viewPtr: &gui.Views.MenuFilter, name: "menuFilter"}, {viewPtr: &gui.Views.Suggestions, name: "suggestions"}, {viewPtr: &gui.Views.Confirmation, name: "confirmation"}, {viewPtr: &gui.Views.Prompt, name: "prompt"}, @@ -139,6 +145,14 @@ func (gui *Gui) createAllViews() error { gui.Views.Menu.Visible = false + gui.Views.MenuFilterFrame.Visible = false + gui.Views.MenuFilter.Visible = false + gui.Views.MenuFilter.Frame = false + // The filter row belongs to the menu: it shares the menu's focus, and keys + // that the input field doesn't take are the menu's to handle. + gui.Views.MenuFilterFrame.ParentView = gui.Views.Menu + gui.Views.MenuFilter.ParentView = gui.Views.Menu + gui.Views.Tooltip.Visible = false gui.Views.Tooltip.AutoRenderHyperLinks = true @@ -155,17 +169,30 @@ func (gui *Gui) createAllViews() error { return nil } +// gocui expects a view's frame runes in this order: the horizontal and the +// vertical edge, then the top left, top right, bottom left and bottom right +// corner. +func frameRunesWithTopCorners(frameRunes []rune, topLeft rune, topRight rune) []rune { + return []rune{frameRunes[0], frameRunes[1], topLeft, topRight, frameRunes[4], frameRunes[5]} +} + func (gui *Gui) configureViewProperties() { frameRunes := []rune{'─', '│', '┌', '┐', '└', '┘'} + // The corners for a view that hangs off the bottom of another one, so that the + // border they share reads as a divider rather than as two frames touching. + teeLeft, teeRight := '├', '┤' switch gui.c.UserConfig().Gui.Border { case "double": frameRunes = []rune{'═', '║', '╔', '╗', '╚', '╝'} + teeLeft, teeRight = '╠', '╣' case "rounded": frameRunes = []rune{'─', '│', '╭', '╮', '╰', '╯'} case "hidden": frameRunes = []rune{' ', ' ', ' ', ' ', ' ', ' '} + teeLeft, teeRight = ' ', ' ' case "bold": frameRunes = []rune{'━', '┃', '┏', '┓', '┗', '┛'} + teeLeft, teeRight = '┣', '┫' } for _, mapping := range gui.orderedViewNameMappings() { @@ -177,6 +204,8 @@ func (gui *Gui) configureViewProperties() { (*mapping.viewPtr).InactiveViewSelBgColor = theme.GocuiInactiveViewSelectedLineBgColor } + gui.Views.MenuFilterFrame.FrameRunes = frameRunesWithTopCorners(frameRunes, teeLeft, teeRight) + gui.c.SetViewContent(gui.Views.SearchPrefix, gui.c.Tr.SearchPrefix) gui.Views.Stash.Title = gui.c.Tr.StashTitle