Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve column's overflow #627

Merged
merged 1 commit into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 22 additions & 19 deletions oviewer/convert_align.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
84 changes: 55 additions & 29 deletions oviewer/prepare_draw.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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 {
Expand All @@ -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.
Expand Down
86 changes: 49 additions & 37 deletions oviewer/prepare_draw_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -862,107 +863,118 @@ 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,
},
}
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)
}
})
Expand Down