diff --git a/cell/cell.go b/cell/cell.go index c3eb6df..8088b94 100644 --- a/cell/cell.go +++ b/cell/cell.go @@ -23,8 +23,12 @@ type Option interface { // Options stores the provided options. type Options struct { - FgColor Color - BgColor Color + FgColor Color + BgColor Color + Bold bool + Italic bool + Underline bool + Strikethrough bool } // Set allows existing options to be passed as an option. @@ -62,3 +66,31 @@ func BgColor(color Color) Option { co.BgColor = color }) } + +// Bold makes cell's text bold. +func Bold() Option { + return option(func(co *Options) { + co.Bold = true + }) +} + +// Italic makes cell's text italic. Only works when using the tcell backend. +func Italic() Option { + return option(func(co *Options) { + co.Italic = true + }) +} + +// Underline makes cell's text underlined. +func Underline() Option { + return option(func(co *Options) { + co.Underline = true + }) +} + +// Strikethrough strikes through the cell's text. Currently a no-op until tcell is updated to >= v2.0.0 +func Strikethrough() Option { + return option(func(co *Options) { + co.Strikethrough = true + }) +} diff --git a/go.mod b/go.mod index 3a81b32..e007d5e 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/mum4k/termdash go 1.14 require ( - github.com/gdamore/tcell v1.3.0 + github.com/gdamore/tcell v1.4.0 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-runewidth v0.0.9 github.com/nsf/termbox-go v0.0.0-20200204031403-4d2b513ad8be diff --git a/go.sum b/go.sum index 5e34e27..1a5c516 100644 --- a/go.sum +++ b/go.sum @@ -4,11 +4,16 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM= github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= +github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU= +github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lucasb-eyer/go-colorful v1.0.2 h1:mCMFu6PgSozg9tDNMMK3g18oJBX7oYGrC09mS6CXfO4= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= +github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= +github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/nsf/termbox-go v0.0.0-20200204031403-4d2b513ad8be h1:yzmWtPyxEUIKdZg4RcPq64MfS8NA6A5fNOJgYhpR9EQ= diff --git a/terminal/tcell/cell_options.go b/terminal/tcell/cell_options.go index e0357a9..7195181 100644 --- a/terminal/tcell/cell_options.go +++ b/terminal/tcell/cell_options.go @@ -57,6 +57,7 @@ func cellOptsToStyle(opts *cell.Options, colorMode terminalapi.ColorMode) tcell. fg = fixColor(fg, colorMode) bg = fixColor(bg, colorMode) - st = st.Foreground(fg).Background(bg) + // FIXME: tcell doesn't have a strikethrough style option + st = st.Foreground(fg).Background(bg).Bold(opts.Bold).Italic(opts.Italic).Underline(opts.Underline) return st } diff --git a/terminal/tcell/cell_options_test.go b/terminal/tcell/cell_options_test.go index b3df570..7c747b2 100644 --- a/terminal/tcell/cell_options_test.go +++ b/terminal/tcell/cell_options_test.go @@ -141,6 +141,21 @@ func TestCellOptsToStyle(t *testing.T) { opts: cell.Options{FgColor: cell.ColorWhite, BgColor: cell.ColorBlack}, want: tcell.StyleDefault.Foreground(tcell.Color23).Background(tcell.Color16), }, + { + colorMode: terminalapi.ColorModeNormal, + opts: cell.Options{Bold: true}, + want: tcell.StyleDefault.Bold(true), + }, + { + colorMode: terminalapi.ColorModeNormal, + opts: cell.Options{Italic: true}, + want: tcell.StyleDefault.Italic(true), + }, + { + colorMode: terminalapi.ColorModeNormal, + opts: cell.Options{Underline: true}, + want: tcell.StyleDefault.Underline(true), + }, } for _, tc := range tests { diff --git a/terminal/termbox/cell_options.go b/terminal/termbox/cell_options.go index 41ee760..9f2a638 100644 --- a/terminal/termbox/cell_options.go +++ b/terminal/termbox/cell_options.go @@ -17,6 +17,8 @@ package termbox // cell_options.go converts termdash cell options to the termbox format. import ( + "errors" + "github.com/mum4k/termdash/cell" tbx "github.com/nsf/termbox-go" ) @@ -27,8 +29,24 @@ func cellColor(c cell.Color) tbx.Attribute { } // cellOptsToFg converts the cell options to the termbox foreground attribute. -func cellOptsToFg(opts *cell.Options) tbx.Attribute { - return cellColor(opts.FgColor) +func cellOptsToFg(opts *cell.Options) (tbx.Attribute, error) { + a := cellColor(opts.FgColor) + var err error + if opts.Bold { + a |= tbx.AttrBold + } + // FIXME: Termbox doesn't have an italics attribute + if opts.Italic { + err = errors.New("Termbox: Unsupported attribute: Italic") + } + if opts.Underline { + a |= tbx.AttrUnderline + } + // FIXME: Termbox doesn't have a strikethrough attribute + if opts.Strikethrough { + err = errors.New("Termbox: Unsupported attribute: Strikethrough") + } + return a, err } // cellOptsToBg converts the cell options to the termbox background attribute. diff --git a/terminal/termbox/cell_options_test.go b/terminal/termbox/cell_options_test.go index f74e9bb..66d9e1d 100644 --- a/terminal/termbox/cell_options_test.go +++ b/terminal/termbox/cell_options_test.go @@ -15,6 +15,7 @@ package termbox import ( + "fmt" "testing" "github.com/mum4k/termdash/cell" @@ -48,3 +49,25 @@ func TestCellColor(t *testing.T) { }) } } + +func TestCellFontModifier(t *testing.T) { + tests := []struct { + opt cell.Options + want tbx.Attribute + }{ + {cell.Options{Bold: true}, tbx.AttrBold}, + {cell.Options{Underline: true}, tbx.AttrUnderline}, + } + + for _, tc := range tests { + t.Run(fmt.Sprintf("%v", tc.opt), func(t *testing.T) { + got, err := cellOptsToFg(&tc.opt) + if err != nil { + t.Errorf("cellOptsToFg(%v) failed: %s", tc.opt, err) + } + if got != tc.want { + t.Errorf("cellOptsToFg(%v) => got %v, want %v", tc.opt, got, tc.want) + } + }) + } +} diff --git a/terminal/termbox/termbox.go b/terminal/termbox/termbox.go index 4329e46..2d88c87 100644 --- a/terminal/termbox/termbox.go +++ b/terminal/termbox/termbox.go @@ -105,7 +105,11 @@ func (t *Terminal) Size() image.Point { // Clear implements terminalapi.Terminal.Clear. func (t *Terminal) Clear(opts ...cell.Option) error { o := cell.NewOptions(opts...) - return tbx.Clear(cellOptsToFg(o), cellOptsToBg(o)) + fg, err := cellOptsToFg(o) + if err != nil { + return err + } + return tbx.Clear(fg, cellOptsToBg(o)) } // Flush implements terminalapi.Terminal.Flush. @@ -126,7 +130,11 @@ func (t *Terminal) HideCursor() { // SetCell implements terminalapi.Terminal.SetCell. func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error { o := cell.NewOptions(opts...) - tbx.SetCell(p.X, p.Y, r, cellOptsToFg(o), cellOptsToBg(o)) + fg, err := cellOptsToFg(o) + if err != nil { + return err + } + tbx.SetCell(p.X, p.Y, r, fg, cellOptsToBg(o)) return nil } diff --git a/widgets/text/textdemo/textdemo.go b/widgets/text/textdemo/textdemo.go index ede5368..cf30ea9 100644 --- a/widgets/text/textdemo/textdemo.go +++ b/widgets/text/textdemo/textdemo.go @@ -22,11 +22,12 @@ import ( "math/rand" "time" + "github.com/mum4k/termdash/terminal/tcell" + "github.com/mum4k/termdash" "github.com/mum4k/termdash/cell" "github.com/mum4k/termdash/container" "github.com/mum4k/termdash/linestyle" - "github.com/mum4k/termdash/terminal/termbox" "github.com/mum4k/termdash/terminal/terminalapi" "github.com/mum4k/termdash/widgets/text" ) @@ -67,7 +68,7 @@ func writeLines(ctx context.Context, t *text.Text, delay time.Duration) { } func main() { - t, err := termbox.New() + t, err := tcell.New() if err != nil { panic(err) } @@ -108,6 +109,15 @@ func main() { if err := wrapped.Write(" colors", text.WriteCellOpts(cell.FgColor(cell.ColorBlue))); err != nil { panic(err) } + if err := wrapped.Write(" and"); err != nil { + panic(err) + } + if err := wrapped.Write(" font ", text.WriteCellOpts(cell.Bold(), cell.Italic())); err != nil { + panic(err) + } + if err := wrapped.Write("modifiers", text.WriteCellOpts(cell.Underline(), cell.Italic())); err != nil { + panic(err) + } if err := wrapped.Write(". Wraps long lines at rune boundaries if the WrapAtRunes() option is provided.\nSupports newline character to\ncreate\nnewlines\nmanually.\nTrims the content if it is too long.\n\n\n\nToo long."); err != nil { panic(err) }