edit/ui: Add renderer for content with vertical scrollbar.

This commit is contained in:
Qi Xiao 2019-01-31 14:29:29 -08:00
parent 0cb066d326
commit 686e944cb1
3 changed files with 74 additions and 7 deletions

View File

@ -21,16 +21,27 @@ func Render(r Renderer, width int) *Buffer {
return bb.Buffer()
}
// NewStringRenderer returns a Renderer that shows the given string unstyled,
// possibly trimmed to fit whatever width is available.
// NewStringRenderer returns a Renderer that shows the given strings unstyled,
// trimmed to fit whatever width is available.
func NewStringRenderer(s string) Renderer {
return stringRenderer{s}
return NewLinesRenderer(s)
}
type stringRenderer struct{ s string }
// NewLinesRenderer returns a Renderer that shows the given lines unstyled,
// each trimmed to fit whatever width is available.
func NewLinesRenderer(lines ...string) Renderer {
return linesRenderer{lines}
}
func (r stringRenderer) Render(bb *BufferBuilder) {
bb.WriteString(util.TrimWcwidth(r.s, bb.Width), "")
type linesRenderer struct{ lines []string }
func (r linesRenderer) Render(bb *BufferBuilder) {
for i, line := range r.lines {
if i > 0 {
bb.Newline()
}
bb.WriteString(util.TrimWcwidth(line, bb.Width), "")
}
}
// NewModeLineRenderer returns a Renderer for a mode line.
@ -47,7 +58,7 @@ func (ml modeLineRenderer) Render(bb *BufferBuilder) {
bb.WriteString(ml.title, styleForMode.String())
bb.WriteSpaces(1, "")
bb.WriteString(ml.filter, styleForFilter.String())
bb.Dot = bb.Cursor()
bb.SetDotToCursor()
}
// NewModeLineWithScrollBarRenderer returns a Renderer for a mode line with a
@ -72,3 +83,21 @@ func (ml modeLineWithScrollBarRenderer) Render(bb *BufferBuilder) {
writeHorizontalScrollbar(bb, ml.n, ml.low, ml.high, scrollbarWidth)
}
}
// NewRendererWithVerticalScrollbar returns a Renderer that renders the given
// base plus a vertical scrollbar at the right-hand side.
func NewRendererWithVerticalScrollbar(base Renderer, n, low, high int) Renderer {
return rendererWithVerticalScrollbar{base, n, low, high}
}
type rendererWithVerticalScrollbar struct {
base Renderer
n, low, high int
}
func (r rendererWithVerticalScrollbar) Render(bb *BufferBuilder) {
bufBase := Render(r.base, bb.Width-1)
bb.ExtendRight(bufBase, 0)
bufScrollbar := renderVerticalScrollbar(r.n, r.low, r.high, len(bufBase.Lines))
bb.ExtendRight(bufScrollbar, bb.Width-1)
}

View File

@ -22,6 +22,15 @@ func TestRender(t *testing.T) {
Args(NewStringRenderer("string"), 3).
Rets(NewBufferBuilder(3).WriteString("str", "").Buffer()),
Args(NewLinesRenderer("line 1", "line 2"), 10).
Rets(
NewBufferBuilder(10).WriteString("line 1", "").Newline().
WriteString("line 2", "").Buffer()),
Args(NewLinesRenderer("line 1", "line 2"), 3).
Rets(
NewBufferBuilder(3).WriteString("lin", "").Newline().
WriteString("lin", "").Buffer()),
Args(NewModeLineRenderer("M", "f"), 10).
Rets(
NewBufferBuilder(10).
@ -43,5 +52,18 @@ func TestRender(t *testing.T) {
Write(' ', styleForScrollBarThumb.String()).
WriteString("━━━━", styleForScrollBarArea.String()).
Buffer()),
Args(NewRendererWithVerticalScrollbar(NewLinesRenderer("1", "2", "3"), 3, 0, 1), 5).
Rets(
NewBufferBuilder(5).
WriteString("1 ", "").
Write(' ', styleForScrollBarThumb.String()).
Newline().
WriteString("2 ", "").
Write('│', styleForScrollBarArea.String()).
Newline().
WriteString("3 ", "").
Write('│', styleForScrollBarArea.String()).
Buffer()),
})
}

View File

@ -11,6 +11,22 @@ func writeHorizontalScrollbar(bb *BufferBuilder, n, low, high, width int) {
}
}
func renderVerticalScrollbar(n, low, high, height int) *Buffer {
slow, shigh := findScrollInterval(n, low, high, height)
bb := NewBufferBuilder(1)
for i := 0; i < height; i++ {
if i > 0 {
bb.Newline()
}
if slow <= i && i < shigh {
bb.Write(' ', styleForScrollBarThumb.String())
} else {
bb.Write('│', styleForScrollBarArea.String())
}
}
return bb.Buffer()
}
func findScrollInterval(n, low, high, height int) (int, int) {
f := func(i int) int {
return int(float64(i)/float64(n)*float64(height) + 0.5)