diff options
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) } } |