diff --git a/pkg/gui/controllers/helpers/confirmation_helper.go b/pkg/gui/controllers/helpers/confirmation_helper.go index 7a53f9243..6e45087c0 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, editable bool, message string, width int) int { - wrappedLines, _, _ := utils.WrapViewLinesToWidth(wrap, editable, message, width) +func getMessageHeight(wrap bool, editable bool, message string, width int, tabWidth int) int { + wrappedLines, _, _ := utils.WrapViewLinesToWidth(wrap, editable, message, width, tabWidth) return len(wrappedLines) } @@ -265,7 +265,7 @@ func (self *ConfirmationHelper) resizeMenu(parentPopupContext types.Context) { if selectedItem != nil { tooltip = self.TooltipForMenuItem(selectedItem) } - tooltipHeight := getMessageHeight(true, false, tooltip, contentWidth) + 2 // plus 2 for the frame + tooltipHeight := getMessageHeight(true, false, tooltip, contentWidth, self.c.Views().Menu.TabWidth) + 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, false, prompt, contentWidth) + promptLines, _, _ = utils.WrapViewLinesToWidth(true, false, prompt, contentWidth, self.c.Views().Menu.TabWidth) promptLines = append(promptLines, "") } self.c.Contexts().Menu.SetPromptLines(promptLines) @@ -305,17 +305,18 @@ func (self *ConfirmationHelper) resizeConfirmationPanel(parentPopupContext types } panelWidth := self.getPopupPanelWidth() contentWidth := panelWidth - 2 // minus 2 for the frame - prompt := self.c.Views().Confirmation.Buffer() + confirmationView := self.c.Views().Confirmation + prompt := confirmationView.Buffer() wrap := true - editable := self.c.Views().Confirmation.Editable + editable := confirmationView.Editable if editable { - prompt = self.c.Views().Confirmation.TextArea.GetContent() + prompt = confirmationView.TextArea.GetContent() wrap = false } - panelHeight := getMessageHeight(wrap, editable, prompt, contentWidth) + suggestionsViewHeight + panelHeight := getMessageHeight(wrap, editable, prompt, contentWidth, confirmationView.TabWidth) + 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) + _, _ = self.c.GocuiGui().SetView(confirmationView.Name(), x0, y0, x1, confirmationViewBottom, 0) suggestionsViewTop := confirmationViewBottom + 1 _, _ = self.c.GocuiGui().SetView(self.c.Views().Suggestions.Name(), x0, suggestionsViewTop, x1, suggestionsViewTop+suggestionsViewHeight, 0) @@ -325,7 +326,7 @@ func (self *ConfirmationHelper) ResizeCommitMessagePanels(parentPopupContext typ panelWidth := self.getPopupPanelWidth() content := self.c.Views().CommitDescription.TextArea.GetContent() summaryViewHeight := 3 - panelHeight := getMessageHeight(false, true, content, panelWidth) + panelHeight := getMessageHeight(false, true, content, panelWidth, self.c.Views().CommitDescription.TabWidth) minHeight := 7 if panelHeight < minHeight { panelHeight = minHeight diff --git a/pkg/gui/patch_exploring/state.go b/pkg/gui/patch_exploring/state.go index 2b32d1e7f..074793f8e 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, view.Editable, strings.TrimSuffix(diff, "\n"), view.InnerWidth()) + view.Wrap, view.Editable, strings.TrimSuffix(diff, "\n"), view.InnerWidth(), view.TabWidth) return viewLineIndices, patchLineIndices } diff --git a/pkg/utils/lines.go b/pkg/utils/lines.go index ebb131c1c..c601bb806 100644 --- a/pkg/utils/lines.go +++ b/pkg/utils/lines.go @@ -109,7 +109,7 @@ 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, editable bool, text string, width int) ([]string, []int, []int) { +func WrapViewLinesToWidth(wrap bool, editable bool, text string, width int, tabWidth int) ([]string, []int, []int) { if !editable { text = strings.TrimSuffix(text, "\n") } @@ -126,14 +126,18 @@ func WrapViewLinesToWidth(wrap bool, editable bool, text string, width int) ([]s wrappedLineIndices := make([]int, 0, len(lines)) originalLineIndices := make([]int, 0, len(lines)) + if tabWidth < 1 { + tabWidth = 4 + } + for originalLineIdx, line := range lines { wrappedLineIndices = append(wrappedLineIndices, len(wrappedLines)) // convert tabs to spaces for i := 0; i < len(line); i++ { if line[i] == '\t' { - numSpaces := 4 - (i % 4) - line = line[:i] + " "[:numSpaces] + line[i+1:] + numSpaces := tabWidth - (i % tabWidth) + line = line[:i] + strings.Repeat(" ", numSpaces) + line[i+1:] i += numSpaces - 1 } } diff --git a/pkg/utils/lines_test.go b/pkg/utils/lines_test.go index 6011cf1fd..a67d59237 100644 --- a/pkg/utils/lines_test.go +++ b/pkg/utils/lines_test.go @@ -173,6 +173,7 @@ func TestWrapViewLinesToWidth(t *testing.T) { editable bool text string width int + tabWidth int expectedWrappedLines []string expectedWrappedLinesIndices []int expectedOriginalLinesIndices []int @@ -353,14 +354,25 @@ func TestWrapViewLinesToWidth(t *testing.T) { }, }, { - name: "Tabs", - wrap: true, - text: "\ta\tbb\tccc\tdddd\teeeee", - width: 50, + name: "Tabs, width 4", + wrap: true, + text: "\ta\tbb\tccc\tdddd\teeeee", + width: 50, + tabWidth: 4, expectedWrappedLines: []string{ " a bb ccc dddd eeeee", }, }, + { + name: "Tabs, width 8", + wrap: true, + text: "\ta\tbb\tccc\tdddddddd\teeeee", + width: 100, + tabWidth: 8, + expectedWrappedLines: []string{ + " a bb ccc dddddddd eeeee", + }, + }, { name: "Multiple lines", wrap: true, @@ -425,7 +437,11 @@ func TestWrapViewLinesToWidth(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - wrappedLines, wrappedLinesIndices, originalLinesIndices := WrapViewLinesToWidth(tt.wrap, tt.editable, tt.text, tt.width) + tabWidth := tt.tabWidth + if tabWidth == 0 { + tabWidth = 4 + } + wrappedLines, wrappedLinesIndices, originalLinesIndices := WrapViewLinesToWidth(tt.wrap, tt.editable, tt.text, tt.width, tabWidth) assert.Equal(t, tt.expectedWrappedLines, wrappedLines) if tt.expectedWrappedLinesIndices != nil { assert.Equal(t, tt.expectedWrappedLinesIndices, wrappedLinesIndices) @@ -436,6 +452,7 @@ func TestWrapViewLinesToWidth(t *testing.T) { // As a sanity check, also test that gocui's line wrapping behaves the same way view := gocui.NewView("", 0, 0, tt.width+1, 1000, gocui.OutputNormal) + view.TabWidth = tabWidth assert.Equal(t, tt.width, view.InnerWidth()) view.Wrap = tt.wrap view.Editable = tt.editable