summaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorStefan Haller <stefan@haller-berlin.de>2024-06-23 12:35:50 +0200
committerGitHub <noreply@github.com>2024-06-23 12:35:50 +0200
commitc401f345302c96cb77b8c506ac74c6778d937e61 (patch)
treecdf795e48dcd61c35f2957ed9b12d52ce84da1a8 /pkg
parent6f8244e3fe23cc44019e2dee49fe67a365538e30 (diff)
parentddd6323aa5429908f712f7b7fe67760b15ed398c (diff)
Add prompt to the remote branch checkout menu (#3652)
- **PR Description** As a followup to [this discussion](https://github.com/jesseduffield/lazygit/pull/3388#issuecomment-2002308045), this PR adds a way to add a prompt text to menus. It is shown above the menu items, separated by a blank line. We use it to add a prompt to the remote branch checkout menu.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/gui/context/menu_context.go31
-rw-r--r--pkg/gui/controllers/helpers/confirmation_helper.go61
-rw-r--r--pkg/gui/controllers/helpers/refs_helper.go1
-rw-r--r--pkg/gui/menu_panel.go1
-rw-r--r--pkg/gui/types/common.go1
-rw-r--r--pkg/i18n/english.go2
6 files changed, 87 insertions, 10 deletions
diff --git a/pkg/gui/context/menu_context.go b/pkg/gui/context/menu_context.go
index a6b0e77cb..e4b26f884 100644
--- a/pkg/gui/context/menu_context.go
+++ b/pkg/gui/context/menu_context.go
@@ -50,6 +50,8 @@ func NewMenuContext(
type MenuViewModel struct {
c *ContextCommon
menuItems []*types.MenuItem
+ prompt string
+ promptLines []string
columnAlignment []utils.Alignment
*FilteredListViewModel[*types.MenuItem]
}
@@ -73,6 +75,23 @@ func (self *MenuViewModel) SetMenuItems(items []*types.MenuItem, columnAlignment
self.columnAlignment = columnAlignment
}
+func (self *MenuViewModel) GetPrompt() string {
+ return self.prompt
+}
+
+func (self *MenuViewModel) SetPrompt(prompt string) {
+ self.prompt = prompt
+ self.promptLines = nil
+}
+
+func (self *MenuViewModel) GetPromptLines() []string {
+ return self.promptLines
+}
+
+func (self *MenuViewModel) SetPromptLines(promptLines []string) {
+ self.promptLines = promptLines
+}
+
// TODO: move into presentation package
func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string {
menuItems := self.FilteredListViewModel.GetItems()
@@ -94,14 +113,22 @@ func (self *MenuViewModel) GetDisplayStrings(_ int, _ int) [][]string {
}
func (self *MenuViewModel) GetNonModelItems() []*NonModelItem {
+ result := []*NonModelItem{}
+ result = append(result, lo.Map(self.promptLines, func(line string, _ int) *NonModelItem {
+ return &NonModelItem{
+ Index: 0,
+ Column: 0,
+ Content: line,
+ }
+ })...)
+
// Don't display section headers when we are filtering, and the filter mode
// is fuzzy. The reason is that filtering changes the order of the items
// (they are sorted by best match), so all the sections would be messed up.
if self.FilteredListViewModel.IsFiltering() && self.c.UserConfig.Gui.UseFuzzySearch() {
- return []*NonModelItem{}
+ return result
}
- result := []*NonModelItem{}
menuItems := self.FilteredListViewModel.GetItems()
var prevSection *types.MenuSection = nil
for i, menuItem := range menuItems {
diff --git a/pkg/gui/controllers/helpers/confirmation_helper.go b/pkg/gui/controllers/helpers/confirmation_helper.go
index 1e60b5f08..8f7c60b5a 100644
--- a/pkg/gui/controllers/helpers/confirmation_helper.go
+++ b/pkg/gui/controllers/helpers/confirmation_helper.go
@@ -63,15 +63,20 @@ func (self *ConfirmationHelper) DeactivateConfirmationPrompt() {
// Temporary hack: we're just duplicating the logic in `gocui.lineWrap`
func getMessageHeight(wrap bool, message string, width int) int {
+ return len(wrapMessageToWidth(wrap, message, width))
+}
+
+func wrapMessageToWidth(wrap bool, message string, width int) []string {
+ lines := strings.Split(message, "\n")
if !wrap {
- return len(strings.Split(message, "\n"))
+ return lines
}
- lineCount := 0
- lines := strings.Split(message, "\n")
+ wrappedLines := make([]string, 0, len(lines))
for _, line := range lines {
n := 0
+ offset := 0
lastWhitespaceIndex := -1
for i, currChr := range line {
rw := runewidth.RuneWidth(currChr)
@@ -79,28 +84,38 @@ func getMessageHeight(wrap bool, message string, width int) int {
if n > width {
if currChr == ' ' {
+ wrappedLines = append(wrappedLines, line[offset:i])
+ offset = i + 1
n = 0
} else if currChr == '-' {
+ wrappedLines = append(wrappedLines, line[offset:i])
+ offset = i
n = rw
} else if lastWhitespaceIndex != -1 && lastWhitespaceIndex+1 != i {
if line[lastWhitespaceIndex] == '-' {
+ wrappedLines = append(wrappedLines, line[offset:lastWhitespaceIndex+1])
+ offset = lastWhitespaceIndex + 1
n = i - lastWhitespaceIndex
} else {
+ wrappedLines = append(wrappedLines, line[offset:lastWhitespaceIndex])
+ offset = lastWhitespaceIndex + 1
n = i - lastWhitespaceIndex + 1
}
} else {
+ wrappedLines = append(wrappedLines, line[offset:i])
+ offset = i
n = rw
}
- lineCount++
lastWhitespaceIndex = -1
} else if currChr == ' ' || currChr == '-' {
lastWhitespaceIndex = i
}
}
- lineCount++
+
+ wrappedLines = append(wrappedLines, line[offset:])
}
- return lineCount
+ return wrappedLines
}
func (self *ConfirmationHelper) getPopupPanelDimensions(wrap bool, prompt string) (int, int, int, int) {
@@ -358,7 +373,9 @@ func (self *ConfirmationHelper) resizeMenu() {
itemCount := self.c.Contexts().Menu.UnfilteredLen()
offset := 3
panelWidth := self.getPopupPanelWidth()
- x0, y0, x1, y1 := self.getPopupPanelDimensionsForContentHeight(panelWidth, itemCount+offset)
+ contentWidth := panelWidth - 2 // minus 2 for the frame
+ promptLinesCount := self.layoutMenuPrompt(contentWidth)
+ x0, y0, x1, y1 := self.getPopupPanelDimensionsForContentHeight(panelWidth, itemCount+offset+promptLinesCount)
menuBottom := y1 - offset
_, _ = self.c.GocuiGui().SetView(self.c.Views().Menu.Name(), x0, y0, x1, menuBottom, 0)
@@ -368,11 +385,39 @@ func (self *ConfirmationHelper) resizeMenu() {
if selectedItem != nil {
tooltip = self.TooltipForMenuItem(selectedItem)
}
- contentWidth := panelWidth - 2 // minus 2 for the frame
tooltipHeight := getMessageHeight(true, tooltip, contentWidth) + 2 // plus 2 for the frame
_, _ = self.c.GocuiGui().SetView(self.c.Views().Tooltip.Name(), x0, tooltipTop, x1, tooltipTop+tooltipHeight-1, 0)
}
+// Wraps the lines of the menu prompt to the available width and rerenders the
+// menu if neeeded. Returns the number of lines the prompt takes up.
+func (self *ConfirmationHelper) layoutMenuPrompt(contentWidth int) int {
+ oldPromptLines := self.c.Contexts().Menu.GetPromptLines()
+ var promptLines []string
+ prompt := self.c.Contexts().Menu.GetPrompt()
+ if len(prompt) > 0 {
+ promptLines = wrapMessageToWidth(true, prompt, contentWidth)
+ promptLines = append(promptLines, "")
+ }
+ self.c.Contexts().Menu.SetPromptLines(promptLines)
+ if len(oldPromptLines) != len(promptLines) {
+ // The number of lines in the prompt has changed; this happens either
+ // because we're now showing a menu that has a prompt, and the previous
+ // menu didn't (or vice versa), or because the user is resizing the
+ // terminal window while a menu with a prompt is open.
+
+ // We need to rerender to give the menu context a chance to update its
+ // non-model items, and reinitialize the data it uses for converting
+ // between view index and model index.
+ _ = self.c.Contexts().Menu.HandleRender()
+
+ // Then we need to refocus to ensure the cursor is in the right place in
+ // the view.
+ _ = self.c.Contexts().Menu.HandleFocus(types.OnFocusOpts{})
+ }
+ return len(promptLines)
+}
+
func (self *ConfirmationHelper) resizeConfirmationPanel() {
suggestionsViewHeight := 0
if self.c.Views().Suggestions.Visible {
diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go
index d837d8266..ccfe71799 100644
--- a/pkg/gui/controllers/helpers/refs_helper.go
+++ b/pkg/gui/controllers/helpers/refs_helper.go
@@ -130,6 +130,7 @@ func (self *RefsHelper) CheckoutRemoteBranch(fullBranchName string, localBranchN
Title: utils.ResolvePlaceholderString(self.c.Tr.RemoteBranchCheckoutTitle, map[string]string{
"branchName": fullBranchName,
}),
+ Prompt: self.c.Tr.RemoteBranchCheckoutPrompt,
Items: []*types.MenuItem{
{
Label: self.c.Tr.CheckoutTypeNewBranch,
diff --git a/pkg/gui/menu_panel.go b/pkg/gui/menu_panel.go
index b777536ee..ca03ea69e 100644
--- a/pkg/gui/menu_panel.go
+++ b/pkg/gui/menu_panel.go
@@ -42,6 +42,7 @@ func (gui *Gui) createMenu(opts types.CreateMenuOptions) error {
}
gui.State.Contexts.Menu.SetMenuItems(opts.Items, opts.ColumnAlignment)
+ gui.State.Contexts.Menu.SetPrompt(opts.Prompt)
gui.State.Contexts.Menu.SetSelection(0)
gui.Views.Menu.Title = opts.Title
diff --git a/pkg/gui/types/common.go b/pkg/gui/types/common.go
index 77f2f56eb..fc9168406 100644
--- a/pkg/gui/types/common.go
+++ b/pkg/gui/types/common.go
@@ -159,6 +159,7 @@ const (
type CreateMenuOptions struct {
Title string
+ Prompt string // a message that will be displayed above the menu options
Items []*MenuItem
HideCancel bool
ColumnAlignment []utils.Alignment
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index 7aabbbc2b..78b8b84cf 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -113,6 +113,7 @@ type TranslationSet struct {
CheckoutByName string
CheckoutByNameTooltip string
RemoteBranchCheckoutTitle string
+ RemoteBranchCheckoutPrompt string
CheckoutTypeNewBranch string
CheckoutTypeNewBranchTooltip string
CheckoutTypeDetachedHead string
@@ -1079,6 +1080,7 @@ func EnglishTranslationSet() TranslationSet {
CheckoutByName: "Checkout by name",
CheckoutByNameTooltip: "Checkout by name. In the input box you can enter '-' to switch to the last branch.",
RemoteBranchCheckoutTitle: "Checkout {{.branchName}}",
+ RemoteBranchCheckoutPrompt: "How would you like to check out this branch?",
CheckoutTypeNewBranch: "New local branch",
CheckoutTypeNewBranchTooltip: "Checkout the remote branch as a local branch, tracking the remote branch.",
CheckoutTypeDetachedHead: "Detached head",