From 557cd588fcd0c4f8715c39679a159603f01f2801 Mon Sep 17 00:00:00 2001 From: Noboru Saito Date: Tue, 17 Sep 2024 14:11:03 +0900 Subject: [PATCH] Improve column's overflow Add the start position to the COLUMN judgment. Make variable names easier to understand for refactoring. Add Comment. --- oviewer/convert_align.go | 41 +++++++++-------- oviewer/prepare_draw.go | 84 +++++++++++++++++++++++------------ oviewer/prepare_draw_test.go | 86 ++++++++++++++++++++---------------- 3 files changed, 126 insertions(+), 85 deletions(-) diff --git a/oviewer/convert_align.go b/oviewer/convert_align.go index 4fc1cdc5..d9b3a55b 100644 --- a/oviewer/convert_align.go +++ b/oviewer/convert_align.go @@ -129,47 +129,50 @@ func (a *align) convertDelm(src contents) contents { func (a *align) convertWidth(src contents) contents { dst := make(contents, 0, len(src)) - s := 0 + start := 0 for c := 0; c < len(a.orgWidths); c++ { - e := findColumnEnd(src, a.orgWidths, c) + 1 - e = min(e, len(src)) + end := findColumnEnd(src, a.orgWidths, c, start) + 1 + end = min(end, len(src)) if a.isShrink(c) { dst = appendShrink(dst, nil) dst = append(dst, SpaceContent) a.maxWidths[c] = runewidth.RuneWidth(Shrink) - s = e + start = end continue } - ss := countLeftSpaces(src, s) - ee := countRightSpaces(src, e) - if ss >= ee { - s = e + tStart := findStartWithTrim(src, start) + tEnd := findEndWidthTrim(src, end) + // If the column width is 0, skip. + if tStart >= tEnd { + start = end continue } - addSpace := 0 + + padding := 0 if c < len(a.maxWidths) { - addSpace = (a.maxWidths[c] - (ee - ss)) + padding = (a.maxWidths[c] - (tEnd - tStart)) } - s = e + start = end if a.isRightAlign(c) { // Add left space to align columns. - dst = appendSpaces(dst, addSpace) + dst = appendSpaces(dst, padding) // Add content. - dst = append(dst, src[ss:ee]...) + dst = append(dst, src[tStart:tEnd]...) } else { // Add content. - dst = append(dst, src[ss:ee]...) + dst = append(dst, src[tStart:tEnd]...) // Add right space to align columns. - dst = appendSpaces(dst, addSpace) + dst = appendSpaces(dst, padding) } dst = append(dst, SpaceContent) - } + + // Add the remaining content. if !a.isShrink(len(a.orgWidths)) { - dst = append(dst, src[s:]...) + dst = append(dst, src[start:]...) return dst } dst = appendShrink(dst, nil) @@ -206,13 +209,13 @@ func (a *align) isRightAlign(col int) bool { return false } -func countLeftSpaces(lc contents, s int) int { +func findStartWithTrim(lc contents, s int) int { for ; s < len(lc) && lc[s].mainc == ' '; s++ { } return s } -func countRightSpaces(lc contents, e int) int { +func findEndWidthTrim(lc contents, e int) int { for ; e > 0 && lc[e-1].mainc == ' '; e-- { } return e diff --git a/oviewer/prepare_draw.go b/oviewer/prepare_draw.go index cca8e4f2..6d438940 100644 --- a/oviewer/prepare_draw.go +++ b/oviewer/prepare_draw.go @@ -183,7 +183,7 @@ func maxWidthsWidth(lc contents, maxWidths []int, widths []int, rightCount []int } s := 0 for i := 0; i < len(widths); i++ { - e := findColumnEnd(lc, widths, i) + 1 + e := findColumnEnd(lc, widths, i, s) + 1 width, addRight := trimWidth(lc[s:e]) if len(maxWidths) <= i { maxWidths = append(maxWidths, width) @@ -470,10 +470,7 @@ func (root *Root) columnDelimiterHighlight(line LineC) { switch { case c == 0 && lStart == 0: iStart = lStart - iEnd = indexes[0][1] - len(m.ColumnDelimiter) - if iEnd < 0 { - iEnd = 0 - } + iEnd = max(indexes[0][1]-len(m.ColumnDelimiter), 0) case c < len(indexes): iStart = iEnd + 1 iEnd = indexes[c][0] @@ -504,13 +501,12 @@ func (root *Root) columnWidthHighlight(line LineC) { numC := len(root.StyleColumnRainbow) - start := 0 + start, end := 0, 0 for c := 0; c < len(indexes)+1; c++ { - end := 0 if m.Converter == convAlign { end = alignColumnEnd(line.lc, m.alignConv.maxWidths, c, start) } else { - end = findColumnEnd(line.lc, indexes, c) + end = findColumnEnd(line.lc, indexes, c, start) } if m.ColumnRainbow { @@ -524,41 +520,71 @@ func (root *Root) columnWidthHighlight(line LineC) { } // findColumnEnd returns the position of the end of a column. -func findColumnEnd(lc contents, indexes []int, n int) int { +func findColumnEnd(lc contents, indexes []int, n int, start int) int { + // If the column index is out of bounds, return the length of the contents. if len(indexes) <= n { return len(lc) } - width := indexes[n] - if width >= len(lc) { + + columnEnd := indexes[n] + // The end of the right end returns the length of the contents. + if columnEnd >= len(lc) { return len(lc) } - if lc[width].mainc == ' ' { - return width + // If the character at the end of the column is a space, return the end of the column. + if lc[columnEnd].mainc == ' ' { + return columnEnd } - f := width - for ; f < len(lc) && lc[f].mainc != ' '; f++ { - } - b := width - for ; b > 0 && lc[b].mainc != ' '; b-- { - } + // Column overflow. + lCount, lPos := countToNextSpaceLeft(lc, columnEnd) + rCount, rPos := countToNextSpaceRight(lc, columnEnd) - if b == indexes[n] { - return f + // Is the column omitted? + if lPos == columnEnd { + return rPos } + + // Check the position of the next column. if n < len(indexes)-1 { - if f == indexes[n+1] { - return b - } - if b == indexes[n] { - return f + // If the next column is reached, return the position shifted to the left. + if rPos == indexes[n+1] { + return lPos } - if b > indexes[n] && b < indexes[n+1] { - return b + // If the position is between the end of the column and the start of the next column, + // return the position shifted to the left. + if lPos > columnEnd && lPos < indexes[n+1] { + return lPos } } - return f + // It overflows on the left side. + if lPos > start && rCount > lCount { + return lPos + } + + // It overflows on the right side. + return rPos +} + +// countToNextSpaceLeft counts the number of positions to the next space character to the left. +func countToNextSpaceLeft(lc contents, start int) (int, int) { + count := 0 + i := start + for ; i >= 0 && lc[i].mainc != ' '; i-- { + count++ + } + return count, i +} + +// countToNextSpaceRight counts the number of positions to the next space character to the right. +func countToNextSpaceRight(lc contents, start int) (int, int) { + count := 0 + i := start + for ; i < len(lc) && lc[i].mainc != ' '; i++ { + count++ + } + return count, i } // alignColumnEnd returns the position of the end of a column. diff --git a/oviewer/prepare_draw_test.go b/oviewer/prepare_draw_test.go index 3dfd444b..f1b59865 100644 --- a/oviewer/prepare_draw_test.go +++ b/oviewer/prepare_draw_test.go @@ -850,9 +850,10 @@ func TestRoot_sectionNum(t *testing.T) { func Test_findColumnEnd(t *testing.T) { type args struct { - str string - pos []int - n int + str string + pos []int + n int + start int } tests := []struct { name string @@ -862,99 +863,110 @@ func Test_findColumnEnd(t *testing.T) { { name: "Test findColumnEnd1Over", args: args{ - str: "012345678901234567890123", - pos: []int{7, 15}, - n: 0, + str: "012345678901234567890123", + pos: []int{7, 15}, + n: 0, + start: 0, }, want: 24, }, { name: "Test findColumnEnd2", args: args{ - str: "header1 header2 header3", - pos: []int{7, 15}, - n: 0, + str: "header1 header2 header3", + pos: []int{7, 15}, + n: 0, + start: 0, }, want: 7, }, { name: "Test findColumnEnd3", args: args{ - str: "1 2 3", - pos: []int{7, 15}, - n: 0, + str: "1 2 3", + pos: []int{7, 15}, + n: 0, + start: 0, }, want: 7, }, { name: "Test findColumnEnd4", args: args{ - str: " 1 2 3", - pos: []int{7, 15}, - n: 0, + str: " 1 2 3", + pos: []int{7, 15}, + n: 0, + start: 0, }, want: 7, }, { name: "Test findColumnEnd6Over1", args: args{ - str: "123 456789012 345678901234", - pos: []int{7, 15}, - n: 0, + str: "123 456789012 345678901234", + pos: []int{7, 15}, + n: 0, + start: 0, }, want: 5, }, { name: "Test findColumnEnd6Over2", args: args{ - str: "123 456789012 345678901234", - pos: []int{7, 15}, - n: 1, + str: "123 456789012 345678901234", + pos: []int{7, 15}, + n: 1, + start: 6, }, want: 15, }, { name: "Test findColumnEnd7Over1", args: args{ - str: "abedefghi jkujik mnoopqr", - pos: []int{7, 15}, - n: 0, + str: "abedefghi jkujik mnoopqr", + pos: []int{7, 15}, + n: 0, + start: 0, }, want: 9, }, { name: "Test findColumnEnd7Over2", args: args{ - str: "abedefghi jkujikl mnoopqr", - pos: []int{7, 15}, - n: 1, + str: "abedefghi jkujikl mnoopqr", + pos: []int{7, 15}, + n: 1, + start: 0, }, want: 17, }, { name: "Test findColumnEnd8Over1", args: args{ - str: "abedefghi jkujikl mnoopqr", - pos: []int{7, 15}, - n: 0, + str: "abedefghi jkujikl mnoopqr", + pos: []int{7, 15}, + n: 0, + start: 0, }, want: 9, }, { name: "Test findColumnEnd8Over2", args: args{ - str: "あいうえお かきくけこ さしすせそ", - pos: []int{7, 15}, - n: 1, + str: "あいうえお かきくけこ さしすせそ", + pos: []int{10, 15}, + n: 1, + start: 10, }, want: 21, }, { name: "Test findColumnEnd9Over", args: args{ - str: "abedefg hijkujiklmnoopqrstuvxyz", - pos: []int{7, 15}, - n: 1, + str: "abedefg hijkujiklmnoopqrstuvxyz", + pos: []int{7, 15}, + n: 1, + start: 7, }, want: 31, }, @@ -962,7 +974,7 @@ func Test_findColumnEnd(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { lc := StrToContents(tt.args.str, 8) - if got := findColumnEnd(lc, tt.args.pos, tt.args.n); got != tt.want { + if got := findColumnEnd(lc, tt.args.pos, tt.args.n, tt.args.start); got != tt.want { t.Errorf("findColumnEnd() = %v, want %v", got, tt.want) } })