diff options
author | Tim Culverhouse <tim@timculverhouse.com> | 2024-02-12 06:26:27 -0600 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-02-12 13:49:14 +0100 |
commit | 6314e2dc67418141b12081bde846091e5e160702 (patch) | |
tree | f21798e32c9d43a9d7fc4d08b5f80c1da0ca9848 /lib/ui | |
parent | 57020e98b9ca22eaf2be73722abb79547674cd67 (diff) | |
download | aerc-6314e2dc67418141b12081bde846091e5e160702.tar.gz |
vaxis: update to v0.7.2 and update ansi parser
Update Vaxis to v0.7.2 to gain performance improvements and StyledString
parsing. The Vaxis parser fully accounts for the terminal's capability
to display wide characters.
Use the Vaxis StyledString parser to parse and style ansi-encoded
strings. Remove unneeded code and tests.
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'lib/ui')
-rw-r--r-- | lib/ui/context.go | 21 | ||||
-rw-r--r-- | lib/ui/string.go | 142 | ||||
-rw-r--r-- | lib/ui/table.go | 34 |
3 files changed, 167 insertions, 30 deletions
diff --git a/lib/ui/context.go b/lib/ui/context.go index 2ca0d310..8544abdb 100644 --- a/lib/ui/context.go +++ b/lib/ui/context.go @@ -3,7 +3,6 @@ package ui import ( "fmt" - "git.sr.ht/~rjarry/aerc/lib/parse" "git.sr.ht/~rockorager/vaxis" ) @@ -68,8 +67,8 @@ func (ctx *Context) Printf(x, y int, style vaxis.Style, str := fmt.Sprintf(format, a...) - buf := parse.ParseANSI(str) - buf.ApplyStyle(style) + buf := StyledString(str) + ApplyAttrs(buf, style) old_x := x @@ -78,22 +77,16 @@ func (ctx *Context) Printf(x, y int, style vaxis.Style, y++ return y < height } - for _, sr := range buf.Runes() { - switch sr.Value { - case '\n': + for _, sr := range buf.Cells { + switch sr.Grapheme { + case "\n": if !newline() { return buf.Len() } - case '\r': + case "\r": x = old_x default: - ctx.window.SetCell(x, y, vaxis.Cell{ - Character: vaxis.Character{ - Grapheme: string(sr.Value), - Width: sr.Width, - }, - Style: sr.Style, - }) + ctx.window.SetCell(x, y, sr) x += sr.Width if x == old_x+width { if !newline() { diff --git a/lib/ui/string.go b/lib/ui/string.go new file mode 100644 index 00000000..407c9963 --- /dev/null +++ b/lib/ui/string.go @@ -0,0 +1,142 @@ +package ui + +import ( + "git.sr.ht/~rockorager/vaxis" +) + +func StyledString(s string) *vaxis.StyledString { + return state.vx.NewStyledString(s, vaxis.Style{}) +} + +// Applies a style to a string. Any currently applied styles will not be overwritten +func ApplyStyle(style vaxis.Style, str string) string { + ss := StyledString(str) + d := vaxis.Style{} + for i, sr := range ss.Cells { + if sr.Style == d { + sr.Style = style + ss.Cells[i] = sr + } + } + return ss.Encode() +} + +// PadLeft inserts blank spaces at the beginning of the StyledString to produce +// a string of the provided width +func PadLeft(ss *vaxis.StyledString, width int) { + w := ss.Len() + if w >= width { + return + } + cell := vaxis.Cell{ + Character: vaxis.Character{ + Grapheme: " ", + Width: 1, + }, + } + w = width - w + cells := make([]vaxis.Cell, 0, len(ss.Cells)+w) + for w > 0 { + cells = append(cells, cell) + w -= 1 + } + cells = append(cells, ss.Cells...) + ss.Cells = cells +} + +// PadLeft inserts blank spaces at the end of the StyledString to produce +// a string of the provided width +func PadRight(ss *vaxis.StyledString, width int) { + w := ss.Len() + if w >= width { + return + } + cell := vaxis.Cell{ + Character: vaxis.Character{ + Grapheme: " ", + Width: 1, + }, + } + w = width - w + for w > 0 { + w -= 1 + ss.Cells = append(ss.Cells, cell) + } +} + +// ApplyAttrs applies the style, and if another style is present ORs the +// attributes +func ApplyAttrs(ss *vaxis.StyledString, style vaxis.Style) { + for i, cell := range ss.Cells { + if style.Foreground != 0 { + cell.Style.Foreground = style.Foreground + } + if style.Background != 0 { + cell.Style.Background = style.Background + } + cell.Style.Attribute |= style.Attribute + if style.UnderlineColor != 0 { + cell.Style.UnderlineColor = style.UnderlineColor + } + if style.UnderlineStyle != vaxis.UnderlineOff { + cell.Style.UnderlineStyle = style.UnderlineStyle + } + ss.Cells[i] = cell + } +} + +// Truncates the styled string on the right and inserts a '…' as the last +// character +func Truncate(ss *vaxis.StyledString, width int) { + if ss.Len() <= width { + return + } + cells := make([]vaxis.Cell, 0, len(ss.Cells)) + total := 0 + for _, cell := range ss.Cells { + if total+cell.Width >= width { + // we can't fit this cell so put in our truncator + cells = append(cells, vaxis.Cell{ + Character: vaxis.Character{ + Grapheme: "…", + Width: 1, + }, + Style: cell.Style, + }) + break + } + total += cell.Width + cells = append(cells, cell) + } + ss.Cells = cells +} + +// TruncateHead truncates the left side of the string and inserts '…' as the +// first character +func TruncateHead(ss *vaxis.StyledString, width int) { + l := ss.Len() + if l <= width { + return + } + offset := l - width + cells := make([]vaxis.Cell, 0, len(ss.Cells)) + cells = append(cells, vaxis.Cell{ + Character: vaxis.Character{ + Grapheme: "…", + Width: 1, + }, + }) + total := 0 + for _, cell := range ss.Cells { + total += cell.Width + if total < offset { + // we always have at least one for our truncator. We + // copy this cells style to it so that it retains the + // style information from the first printed cell + cells[0].Style = cell.Style + continue + } + cells = append(cells, cell) + } + ss.Cells = cells +} diff --git a/lib/ui/table.go b/lib/ui/table.go index ceb01c78..3f5fc4b3 100644 --- a/lib/ui/table.go +++ b/lib/ui/table.go @@ -5,7 +5,6 @@ import ( "regexp" "git.sr.ht/~rjarry/aerc/config" - "git.sr.ht/~rjarry/aerc/lib/parse" "git.sr.ht/~rockorager/vaxis" "github.com/mattn/go-runewidth" ) @@ -93,7 +92,7 @@ func (t *Table) computeWidths(width int) { if t.autoFitWidths { for _, row := range t.Rows { for c := range t.Columns { - buf := parse.ParseANSI(row.Cells[c]) + buf := StyledString(row.Cells[c]) if buf.Len() > contentMaxWidths[c] { contentMaxWidths[c] = buf.Len() } @@ -160,32 +159,35 @@ var metaCharsRegexp = regexp.MustCompile(`[\t\r\f\n\v]`) func (col *Column) alignCell(cell string) string { cell = metaCharsRegexp.ReplaceAllString(cell, " ") - buf := parse.ParseANSI(cell) + buf := StyledString(cell) width := buf.Len() switch { case col.Def.Flags.Has(config.ALIGN_LEFT): if width < col.Width { - buf.PadRight(col.Width, ' ', vaxis.Style{}) - cell = buf.String() + PadRight(buf, col.Width) + cell = buf.Encode() } else if width > col.Width { - cell = buf.Truncate(col.Width, '…') + Truncate(buf, col.Width) + cell = buf.Encode() } case col.Def.Flags.Has(config.ALIGN_CENTER): if width < col.Width { pad := col.Width - width - buf.PadLeft(col.Width-(pad/2), ' ', vaxis.Style{}) - buf.PadRight(col.Width, ' ', vaxis.Style{}) - cell = buf.String() + PadLeft(buf, col.Width-(pad/2)) + PadRight(buf, col.Width) + cell = buf.Encode() } else if width > col.Width { - cell = buf.Truncate(col.Width, '…') + Truncate(buf, col.Width) + cell = buf.Encode() } case col.Def.Flags.Has(config.ALIGN_RIGHT): if width < col.Width { - buf.PadLeft(col.Width, ' ', vaxis.Style{}) - cell = buf.String() + PadLeft(buf, col.Width) + cell = buf.Encode() } else if width > col.Width { - cell = buf.TruncateHead(col.Width, '…') + TruncateHead(buf, col.Width) + cell = buf.Encode() } } @@ -209,9 +211,9 @@ func (t *Table) Draw(ctx *Context) { cell := col.alignCell(row.Cells[c]) style := t.GetRowStyle(t, r) - buf := parse.ParseANSI(cell) - buf.ApplyAttrs(style) - cell = buf.String() + buf := StyledString(cell) + ApplyAttrs(buf, style) + cell = buf.Encode() ctx.Printf(col.Offset, r, style, "%s%s", cell, col.Separator) } } |