Fix fullwidth rune handling.

This commit is contained in:
Brian Mattern 2019-06-04 14:21:13 -07:00
parent f3b451c887
commit 84a4bbd440
3 changed files with 99 additions and 11 deletions

24
src/utils/runes.go Normal file
View File

@ -0,0 +1,24 @@
package utils
import (
rw "github.com/mattn/go-runewidth"
)
func TruncateFront(s string, w int, prefix string) string {
if rw.StringWidth(s) <= w {
return s
}
r := []rune(s)
pw := rw.StringWidth(prefix)
w -= pw
width := 0
i := len(r) - 1
for ; i >= 0; i-- {
cw := rw.RuneWidth(r[i])
width += cw
if width > w {
break
}
}
return prefix + string(r[i+1:len(r)])
}

50
src/utils/runes_test.go Normal file
View File

@ -0,0 +1,50 @@
package utils
import "testing"
const (
ELLIPSIS = "…"
)
func TestTruncateFront(t *testing.T) {
tests := []struct {
s string
w int
prefix string
want string
}{
{"", 0, ELLIPSIS, ""},
{"", 1, ELLIPSIS, ""},
{"", 10, ELLIPSIS, ""},
{"abcdef", 0, ELLIPSIS, ELLIPSIS},
{"abcdef", 1, ELLIPSIS, ELLIPSIS},
{"abcdef", 2, ELLIPSIS, ELLIPSIS + "f"},
{"abcdef", 5, ELLIPSIS, ELLIPSIS + "cdef"},
{"abcdef", 6, ELLIPSIS, "abcdef"},
{"abcdef", 10, ELLIPSIS, "abcdef"},
{"abcdef", 0, "...", "..."},
{"abcdef", 1, "...", "..."},
{"abcdef", 3, "...", "..."},
{"abcdef", 4, "...", "...f"},
{"abcdef", 5, "...", "...ef"},
{"abcdef", 6, "...", "abcdef"},
{"abcdef", 10, "...", "abcdef"},
{"⦅fullwidth⦆", 15, ".", "⦅fullwidth⦆"},
{"⦅fullwidth⦆", 14, ".", ".fullwidth⦆"},
{"⦅fullwidth⦆", 13, ".", ".ullwidth⦆"},
{"⦅fullwidth⦆", 10, ".", ".width⦆"},
{"⦅fullwidth⦆", 9, ".", ".width⦆"},
{"⦅fullwidth⦆", 8, ".", ".width⦆"},
{"⦅fullwidth⦆", 3, ".", ".⦆"},
{"⦅fullwidth⦆", 2, ".", "."},
}
for _, test := range tests {
if got := TruncateFront(test.s, test.w, test.prefix); got != test.want {
t.Errorf("TruncateFront(%q, %d, %q) = %q; want %q", test.s, test.w, test.prefix, got, test.want)
}
}
}

View File

@ -16,6 +16,7 @@ import (
ui "github.com/cjbassi/gotop/src/termui"
"github.com/cjbassi/gotop/src/utils"
tui "github.com/gizak/termui/v3"
rw "github.com/mattn/go-runewidth"
)
const (
@ -123,7 +124,8 @@ func (self *ProcWidget) HandleEvent(e tui.Event) bool {
self.SetEditingFilter(false)
case "<Backspace>":
if self.filter != "" {
self.filter = self.filter[:len(self.filter)-1]
r := []rune(self.filter)
self.filter = string(r[:len(r)-1])
self.update()
}
case "<Space>":
@ -143,6 +145,8 @@ func (self *ProcWidget) Draw(buf *tui.Buffer) {
}
func (self *ProcWidget) drawFilter(buf *tui.Buffer) {
padding := 2
style := self.TitleStyle
label := " Filter: "
if self.editingFilter {
@ -151,24 +155,34 @@ func (self *ProcWidget) drawFilter(buf *tui.Buffer) {
}
cursorStyle := tui.NewStyle(style.Bg, style.Fg, tui.ModifierClear)
p := image.Pt(self.Min.X+2, self.Max.Y-1)
p := image.Pt(self.Min.X+padding, self.Max.Y-1)
buf.SetString(label, style, p)
p.X += utf8.RuneCountInString(label)
p.X += rw.StringWidth(label)
maxLen := self.Max.X - p.X - 5
filter := self.filter
if l := utf8.RuneCountInString(filter); l > maxLen {
filter = ELLIPSIS + filter[l-maxLen+1:]
tail := " "
if self.editingFilter {
tail = "] "
}
maxLen := self.Max.X - p.X - padding - rw.StringWidth(tail)
if self.editingFilter {
maxLen -= 1 // for cursor
}
filter := utils.TruncateFront(self.filter, maxLen, ELLIPSIS)
buf.SetString(filter, self.TitleStyle, p)
p.X += utf8.RuneCountInString(filter)
p.X += rw.StringWidth(filter)
if self.editingFilter {
buf.SetString(CURSOR, cursorStyle, p)
p.X += 1
remaining := self.Max.X - 2 - p.X
buf.SetString(fmt.Sprintf("%*s", remaining, "] "), style, p)
p.X += rw.StringWidth(CURSOR)
if remaining := maxLen - rw.StringWidth(filter); remaining > 0 {
buf.SetString(strings.Repeat(" ", remaining), self.TitleStyle, p)
p.X += remaining
}
}
buf.SetString(tail, style, p)
}
func (self *ProcWidget) filterProcs(procs []Proc) []Proc {