Skip to content

Commit 915caec

Browse files
rootBr1an67
authored andcommitted
fix(preview): expand tabs based on current line position
Tab characters are now expanded to reach the next tab stop based on the current display position in the line, rather than always expanding to exactly 4 spaces. This matches standard terminal behavior where tabs align to fixed column positions. For example, with TabWidth=4: - Position 1: tab expands to 3 spaces (reaches column 4) - Position 3: tab expands to 1 space (reaches column 4) - Position 4: tab expands to 4 spaces (reaches column 8)
1 parent c48efc3 commit 915caec

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

src/internal/common/string_function.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ func IsTextFile(filename string) (bool, error) {
228228
// This function should better not be broken into multiple functions
229229
func MakePrintableWithEscCheck(line string, allowEsc bool) string { //nolint: gocognit // See above
230230
var sb strings.Builder
231+
// Track current display width for proper tab expansion
232+
curWidth := 0
231233
for _, r := range line {
232234
if r == utf8.RuneError {
233235
continue
@@ -236,13 +238,17 @@ func MakePrintableWithEscCheck(line string, allowEsc bool) string { //nolint: go
236238
// It is multi-byte in UTF-8, But it has zero display width
237239
if r == NonBreakingSpace {
238240
sb.WriteRune(r)
241+
curWidth++
239242
continue
240243
}
241244
// It needs to be handled separately since considered a space,
242245
// Since we are using ansi.StringWidth() for truncation, and \t is
243246
// considered zero width
244247
if r == '\t' {
245-
sb.WriteString(" ")
248+
// Expand tab to reach next tab stop based on current position
249+
spacesNeeded := TabWidth - (curWidth % TabWidth)
250+
sb.WriteString(strings.Repeat(" ", spacesNeeded))
251+
curWidth += spacesNeeded
246252
continue
247253
}
248254
if r == EscapeChar {
@@ -259,10 +265,17 @@ func MakePrintableWithEscCheck(line string, allowEsc bool) string { //nolint: go
259265
r = ' '
260266
}
261267
sb.WriteRune(r)
268+
curWidth += ansi.StringWidth(string(r))
262269
continue
263270
}
264271
if unicode.IsGraphic(r) || r == rune('\n') {
265272
sb.WriteRune(r)
273+
if r != rune('\n') {
274+
curWidth++
275+
} else {
276+
// Reset width on newline
277+
curWidth = 0
278+
}
266279
}
267280
}
268281
return sb.String()

src/internal/common/string_function_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,13 @@ func TestMakePrintable(t *testing.T) {
176176
{"", ""},
177177
{"hello", "hello"},
178178
{"abcdABCD0123~!@#$%^&*()_+-={}|:\"<>?,./;'[]", "abcdABCD0123~!@#$%^&*()_+-={}|:\"<>?,./;'[]"},
179-
{"Horizontal Tab and NewLine\t\t\n\n", "Horizontal Tab and NewLine \n\n"},
179+
{"Horizontal Tab and NewLine\t\t\n\n", "Horizontal Tab and NewLine \n\n"},
180+
// Tab expansion tests - tabs should expand to reach next tab stop (TabWidth=4)
181+
{"a\tb", "a b"}, // Position 1: need 3 spaces to reach position 4
182+
{"ab\tc", "ab c"}, // Position 2: need 2 spaces to reach position 4
183+
{"abc\td", "abc d"}, // Position 3: need 1 space to reach position 4
184+
{"abcd\te", "abcd e"}, // Position 4: need 4 spaces to reach position 8
185+
{"a\tb\tc", "a b c"}, // Position 1: 3 spaces, then position 4: 4 spaces to reach 8
180186
{"(NBSP)\u00a0\u00a0\u00a0\u00a0;", "(NBSP)\u00a0\u00a0\u00a0\u00a0;"},
181187
{"\x0b(Vertical Tab)", "(Vertical Tab)"},
182188
{"\x0d(CR)", "(CR)"},

0 commit comments

Comments
 (0)