From 20d0b4316d01fe523cff0cd78b61ba583e36026e Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 18 Jan 2025 20:03:57 +0100 Subject: [PATCH] Only avoid the blank line at end of view if view is not editable For editable views it is important to actually show the blank line so that we can put the cursor there for typing. This fixes problems with adding blank lines at the end of longer commit messages. --- .../helpers/confirmation_helper.go | 15 +++--- pkg/gui/patch_exploring/state.go | 2 +- pkg/utils/lines.go | 6 ++- pkg/utils/lines_test.go | 47 ++++++++++++++++++- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/pkg/gui/controllers/helpers/confirmation_helper.go b/pkg/gui/controllers/helpers/confirmation_helper.go index f7f6f8720c4..7a53f924382 100644 --- a/pkg/gui/controllers/helpers/confirmation_helper.go +++ b/pkg/gui/controllers/helpers/confirmation_helper.go @@ -56,8 +56,8 @@ func (self *ConfirmationHelper) DeactivateConfirmationPrompt() { self.clearConfirmationViewKeyBindings() } -func getMessageHeight(wrap bool, message string, width int) int { - wrappedLines, _, _ := utils.WrapViewLinesToWidth(wrap, message, width) +func getMessageHeight(wrap bool, editable bool, message string, width int) int { + wrappedLines, _, _ := utils.WrapViewLinesToWidth(wrap, editable, message, width) return len(wrappedLines) } @@ -265,7 +265,7 @@ func (self *ConfirmationHelper) resizeMenu(parentPopupContext types.Context) { if selectedItem != nil { tooltip = self.TooltipForMenuItem(selectedItem) } - tooltipHeight := getMessageHeight(true, tooltip, contentWidth) + 2 // plus 2 for the frame + tooltipHeight := getMessageHeight(true, false, tooltip, contentWidth) + 2 // plus 2 for the frame _, _ = self.c.GocuiGui().SetView(self.c.Views().Tooltip.Name(), x0, tooltipTop, x1, tooltipTop+tooltipHeight-1, 0) } @@ -276,7 +276,7 @@ func (self *ConfirmationHelper) layoutMenuPrompt(contentWidth int) int { var promptLines []string prompt := self.c.Contexts().Menu.GetPrompt() if len(prompt) > 0 { - promptLines, _, _ = utils.WrapViewLinesToWidth(true, prompt, contentWidth) + promptLines, _, _ = utils.WrapViewLinesToWidth(true, false, prompt, contentWidth) promptLines = append(promptLines, "") } self.c.Contexts().Menu.SetPromptLines(promptLines) @@ -307,11 +307,12 @@ func (self *ConfirmationHelper) resizeConfirmationPanel(parentPopupContext types contentWidth := panelWidth - 2 // minus 2 for the frame prompt := self.c.Views().Confirmation.Buffer() wrap := true - if self.c.Views().Confirmation.Editable { + editable := self.c.Views().Confirmation.Editable + if editable { prompt = self.c.Views().Confirmation.TextArea.GetContent() wrap = false } - panelHeight := getMessageHeight(wrap, prompt, contentWidth) + suggestionsViewHeight + panelHeight := getMessageHeight(wrap, editable, prompt, contentWidth) + suggestionsViewHeight x0, y0, x1, y1 := self.getPopupPanelDimensionsAux(panelWidth, panelHeight, parentPopupContext) confirmationViewBottom := y1 - suggestionsViewHeight _, _ = self.c.GocuiGui().SetView(self.c.Views().Confirmation.Name(), x0, y0, x1, confirmationViewBottom, 0) @@ -324,7 +325,7 @@ func (self *ConfirmationHelper) ResizeCommitMessagePanels(parentPopupContext typ panelWidth := self.getPopupPanelWidth() content := self.c.Views().CommitDescription.TextArea.GetContent() summaryViewHeight := 3 - panelHeight := getMessageHeight(false, content, panelWidth) + panelHeight := getMessageHeight(false, true, content, panelWidth) minHeight := 7 if panelHeight < minHeight { panelHeight = minHeight diff --git a/pkg/gui/patch_exploring/state.go b/pkg/gui/patch_exploring/state.go index 40b2e870620..2b32d1e7f91 100644 --- a/pkg/gui/patch_exploring/state.go +++ b/pkg/gui/patch_exploring/state.go @@ -323,6 +323,6 @@ func (s *State) CalculateOrigin(currentOrigin int, bufferHeight int, numLines in func wrapPatchLines(diff string, view *gocui.View) ([]int, []int) { _, viewLineIndices, patchLineIndices := utils.WrapViewLinesToWidth( - view.Wrap, strings.TrimSuffix(diff, "\n"), view.InnerWidth()) + view.Wrap, view.Editable, strings.TrimSuffix(diff, "\n"), view.InnerWidth()) return viewLineIndices, patchLineIndices } diff --git a/pkg/utils/lines.go b/pkg/utils/lines.go index d2ce7fdc60d..ebb131c1c22 100644 --- a/pkg/utils/lines.go +++ b/pkg/utils/lines.go @@ -109,8 +109,10 @@ func ScanLinesAndTruncateWhenLongerThanBuffer(maxBufferSize int) func(data []byt // - the line indices of the original lines, indexed by the wrapped line indices // If wrap is false, the text is returned as is. // This code needs to behave the same as `gocui.lineWrap` does. -func WrapViewLinesToWidth(wrap bool, text string, width int) ([]string, []int, []int) { - text = strings.TrimSuffix(text, "\n") +func WrapViewLinesToWidth(wrap bool, editable bool, text string, width int) ([]string, []int, []int) { + if !editable { + text = strings.TrimSuffix(text, "\n") + } lines := strings.Split(text, "\n") if !wrap { indices := make([]int, len(lines)) diff --git a/pkg/utils/lines_test.go b/pkg/utils/lines_test.go index c2b90356f91..6011cf1fdcc 100644 --- a/pkg/utils/lines_test.go +++ b/pkg/utils/lines_test.go @@ -170,6 +170,7 @@ func TestWrapViewLinesToWidth(t *testing.T) { tests := []struct { name string wrap bool + editable bool text string width int expectedWrappedLines []string @@ -378,10 +379,53 @@ func TestWrapViewLinesToWidth(t *testing.T) { expectedWrappedLinesIndices: []int{0, 2, 6}, expectedOriginalLinesIndices: []int{0, 0, 1, 1, 1, 1, 2, 2}, }, + { + name: "Avoid blank line at end if not editable", + wrap: true, + editable: false, + text: "First\nSecond\nThird\n", + width: 10, + expectedWrappedLines: []string{ + "First", + "Second", + "Third", + }, + expectedWrappedLinesIndices: []int{0, 1, 2}, + expectedOriginalLinesIndices: []int{0, 1, 2}, + }, + { + name: "Avoid blank line at end if not editable", + wrap: true, + editable: false, + text: "First\nSecond\nThird\n", + width: 10, + expectedWrappedLines: []string{ + "First", + "Second", + "Third", + }, + expectedWrappedLinesIndices: []int{0, 1, 2}, + expectedOriginalLinesIndices: []int{0, 1, 2}, + }, + { + name: "Keep blank line at end if editable", + wrap: true, + editable: true, + text: "First\nSecond\nThird\n", + width: 10, + expectedWrappedLines: []string{ + "First", + "Second", + "Third", + "", + }, + expectedWrappedLinesIndices: []int{0, 1, 2, 3}, + expectedOriginalLinesIndices: []int{0, 1, 2, 3}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - wrappedLines, wrappedLinesIndices, originalLinesIndices := WrapViewLinesToWidth(tt.wrap, tt.text, tt.width) + wrappedLines, wrappedLinesIndices, originalLinesIndices := WrapViewLinesToWidth(tt.wrap, tt.editable, tt.text, tt.width) assert.Equal(t, tt.expectedWrappedLines, wrappedLines) if tt.expectedWrappedLinesIndices != nil { assert.Equal(t, tt.expectedWrappedLinesIndices, wrappedLinesIndices) @@ -394,6 +438,7 @@ func TestWrapViewLinesToWidth(t *testing.T) { view := gocui.NewView("", 0, 0, tt.width+1, 1000, gocui.OutputNormal) assert.Equal(t, tt.width, view.InnerWidth()) view.Wrap = tt.wrap + view.Editable = tt.editable view.SetContent(tt.text) assert.Equal(t, wrappedLines, view.ViewBufferLines()) })