diff --git a/CHANGELOG.md b/CHANGELOG.md index c255026..5cb3776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- the `Text` widget now allows user to specify custom scroll marker runes. + ### Fixed - coveralls again triggers and reports on PRs. diff --git a/README.md b/README.md index 8ecd1fd..466df32 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,7 @@ Termdash uses [this branching model](https://nvie.com/posts/a-successful-git-bra - [datadash](https://github.com/keithknott26/datadash): Visualize streaming or tabular data inside the terminal. - [grafterm](https://github.com/slok/grafterm): Metrics dashboards visualization on the terminal. - [perfstat](https://github.com/flaviostutz/perfstat): Analyze and show tips about possible bottlenecks in Linux systems. +- [gex](https://github.com/Tosch110/gex): Cosmos SDK explorer in-terminal. # Disclaimer diff --git a/widgets/text/options.go b/widgets/text/options.go index b91cec8..1896d69 100644 --- a/widgets/text/options.go +++ b/widgets/text/options.go @@ -32,6 +32,8 @@ type Option interface { // options stores the provided options. type options struct { + scrollUp rune + scrollDown rune wrapMode wrap.Mode rollContent bool disableScrolling bool @@ -46,6 +48,8 @@ type options struct { // newOptions returns a new options instance. func newOptions(opts ...Option) *options { opt := &options{ + scrollUp: DefaultScrollUpRune, + scrollDown: DefaultScrollDownRune, mouseUpButton: DefaultScrollMouseButtonUp, mouseDownButton: DefaultScrollMouseButtonDown, keyUp: DefaultScrollKeyUp, @@ -84,6 +88,22 @@ func (o option) set(opts *options) { o(opts) } +// ScrollRunes configures the text widgets scroll runes, shown at the top and +// bottom of a scrollable text widget. If not provided, the default scroll +// runes will be used. +func ScrollRunes(up, down rune) Option { + return option(func(opts *options) { + opts.scrollUp = up + opts.scrollDown = down + }) +} + +// The default scroll runes for content scrolling +const ( + DefaultScrollUpRune = '⇧' + DefaultScrollDownRune = '⇩' +) + // WrapAtWords configures the text widget so that it automatically wraps lines // that are longer than the width of the widget at word boundaries. If not // provided, long lines are trimmed instead. diff --git a/widgets/text/text.go b/widgets/text/text.go index 0712cbc..645a3db 100644 --- a/widgets/text/text.go +++ b/widgets/text/text.go @@ -125,7 +125,7 @@ const minLinesForMarkers = 3 func (t *Text) drawScrollUp(cvs *canvas.Canvas, cur image.Point, fromLine int) (bool, error) { height := cvs.Area().Dy() if cur.Y == 0 && height >= minLinesForMarkers && fromLine > 0 { - cells, err := cvs.SetCell(cur, '⇧') + cells, err := cvs.SetCell(cur, t.opts.scrollUp) if err != nil { return false, err } @@ -144,7 +144,7 @@ func (t *Text) drawScrollDown(cvs *canvas.Canvas, cur image.Point, fromLine int) height := cvs.Area().Dy() lines := len(t.wrapped) if cur.Y == height-1 && height >= minLinesForMarkers && height < lines-fromLine { - cells, err := cvs.SetCell(cur, '⇩') + cells, err := cvs.SetCell(cur, t.opts.scrollDown) if err != nil { return false, err } diff --git a/widgets/text/text_test.go b/widgets/text/text_test.go index 784db8d..b6b9111 100644 --- a/widgets/text/text_test.go +++ b/widgets/text/text_test.go @@ -281,6 +281,26 @@ func TestTextDraws(t *testing.T) { return ft }, }, + { + desc: "trims content when longer than canvas and draws a custom bottom scroll marker", + canvas: image.Rect(0, 0, 10, 3), + opts: []Option{ + ScrollRunes('^', '.'), + }, + writes: func(widget *Text) error { + return widget.Write("line0\nline1\nline2\nline3") + }, + want: func(size image.Point) *faketerm.Terminal { + ft := faketerm.MustNew(size) + c := testcanvas.MustNew(ft.Area()) + + testdraw.MustText(c, "line0", image.Point{0, 0}) + testdraw.MustText(c, "line1", image.Point{0, 1}) + testdraw.MustText(c, ".", image.Point{0, 2}) + testcanvas.MustApply(c, ft) + return ft + }, + }, { desc: "scrolls down on mouse wheel down a line at a time", canvas: image.Rect(0, 0, 10, 3), @@ -571,6 +591,27 @@ func TestTextDraws(t *testing.T) { return ft }, }, + { + desc: "rolls content upwards and draws a custom up scroll marker", + canvas: image.Rect(0, 0, 10, 3), + opts: []Option{ + RollContent(), + ScrollRunes('^', '.'), + }, + writes: func(widget *Text) error { + return widget.Write("line0\nline1\nline2\nline3") + }, + want: func(size image.Point) *faketerm.Terminal { + ft := faketerm.MustNew(size) + c := testcanvas.MustNew(ft.Area()) + + testdraw.MustText(c, "^", image.Point{0, 0}) + testdraw.MustText(c, "line2", image.Point{0, 1}) + testdraw.MustText(c, "line3", image.Point{0, 2}) + testcanvas.MustApply(c, ft) + return ft + }, + }, { desc: "rolls content upwards and wraps lines at rune boundaries", canvas: image.Rect(0, 0, 10, 2),