From 4dc6992767a1312aafa37d898e19ce7751968c63 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 17 Jun 2020 18:43:01 -0400 Subject: [PATCH] Cmds for scrolling + handle renderer msgs in a renderer method --- renderer.go | 171 +++++++++++++++++++++++++++++++++------------------- tea.go | 28 +-------- 2 files changed, 112 insertions(+), 87 deletions(-) diff --git a/renderer.go b/renderer.go index 79bbda2..2bb2065 100644 --- a/renderer.go +++ b/renderer.go @@ -14,62 +14,6 @@ const ( defaultFramerate = time.Second / 60 ) -// RendererIgnoreLinesMsg tells the renderer to skip rendering for the given -// range of lines. -type ignoreLinesMsg struct { - From int - To int -} - -// IgnoreLines produces command that sets a range of lines to be ignored -// by the renderer. The general use case here is that those lines would be -// rendered separately for performance reasons. -func IgnoreLines(from int, to int) Cmd { - return func() Msg { - return ignoreLinesMsg{From: from, To: to} - } -} - -type resetIgnoreLinesMsg struct { - from int - to int -} - -// ResetIngoredLines produces a command that clears any lines set to be ignored -// and the sets new ones by the renderer. This is probably a more common use -// case than the IgnoreLines command. -func ResetIgnoredLines(from int, to int) Cmd { - return func() Msg { - return resetIgnoreLinesMsg{from: from, to: to} - } -} - -// ClearIgnoredLinesMsg has the renderer allows the renderer to commence rendering -// any lines previously set to be ignored. -type clearIgnoredLinesMsg struct{} - -// RendererIgnoreLines is a command that sets a range of lines to be -// ignored by the renderer. -func ClearIgnoredLines() Msg { - return clearIgnoredLinesMsg{} -} - -// ScrollDownMsg is experiemental. There are no guarantees about it persisting -// in a future API. It's exposed for high performance scrolling. -type ScrollUpMsg struct { - NewLines []string - TopBoundary int - BottomBoundary int -} - -// ScrollDownMsg is experiemental. There are no guarantees about it persisting -// in a future API. It's exposed for high performance scrolling. -type ScrollDownMsg struct { - NewLines []string - TopBoundary int - BottomBoundary int -} - // renderer is a timer-based renderer, updating the view at a given framerate // to avoid overloading the terminal emulator. // @@ -239,6 +183,8 @@ func (r *renderer) clearIgnoredLines() { // area designated to be a scrollable region, pushing everything else down. // This is roughly how ncurses does it. // +// To call this function use command ScrollUp(). +// // For this to work renderer.ignoreLines must be set to ignore the scrollable // region since we are bypassing the normal Bubble Tea renderer here. // @@ -270,13 +216,12 @@ func (r *renderer) insertTop(lines []string, topBoundary, bottomBoundary int) { // insertBottom effectively scrolls down. It inserts lines at the bottom of // a given area designated to be a scrollable region, pushing everything else -// up. This is roughly how ncurses does it. +// up. This is roughly how ncurses does it. // -// For this to work renderer.ignoreLines must be set to ignore the scrollable -// region since we are bypassing the normal Bubble Tea renderer here. +// To call this function use the command ScrollDown(). // -// See note in insertTop() on how this function only makes sense for -// full-window applications and how it differs from the noraml way we do +// See note in insertTop() for caveats, how this function only makes sense for +// full-window applications, and how it differs from the noraml way we do // rendering in Bubble Tea. func (r *renderer) insertBottom(lines []string, topBoundary, bottomBoundary int) { r.mtx.Lock() @@ -293,3 +238,107 @@ func (r *renderer) insertBottom(lines []string, topBoundary, bottomBoundary int) r.out.Write(b.Bytes()) } + +// handleMessages handles internal messages for the renderer. It belongs in the +// main update loop at the program level. +func (r *renderer) handleMessages(msg Msg) { + switch msg := msg.(type) { + case WindowSizeMsg: + r.width = msg.Width + r.height = msg.Height + + case ignoreLinesMsg: + r.setIgnoredLines(msg.from, msg.to) + + case replaceIgnoredLinesMsg: + r.clearIgnoredLines() + r.setIgnoredLines(msg.from, msg.to) + + case clearIgnoredLinesMsg: + r.clearIgnoredLines() + + case scrollUpMsg: + r.insertTop(msg.lines, msg.topBoundary, msg.bottomBoundary) + + case scrollDownMsg: + r.insertTop(msg.lines, msg.topBoundary, msg.bottomBoundary) + } +} + +// HIGH-PERFORMANCE RENDERING STUFF + +// ignoreLinesMsg tells the renderer to skip rendering for the given +// range of lines. +type ignoreLinesMsg struct { + from int + to int +} + +// IgnoreLines produces command that sets a range of lines to be ignored +// by the renderer. The general use case here is that those lines would be +// rendered separately for performance reasons. +func IgnoreLines(from int, to int) Cmd { + return func() Msg { + return ignoreLinesMsg{from: from, to: to} + } +} + +type replaceIgnoredLinesMsg struct { + from int + to int +} + +// ReplaceIngoredLines produces a command that clears any lines set to be ignored +// and the sets new ones by the renderer. This is probably a more common use +// case than the IgnoreLines command. +func ReplaceIgnoredLines(from int, to int) Cmd { + return func() Msg { + return replaceIgnoredLinesMsg{from: from, to: to} + } +} + +// ClearIgnoredLinesMsg has the renderer allows the renderer to commence rendering +// any lines previously set to be ignored. +type clearIgnoredLinesMsg struct{} + +// RendererIgnoreLines is a command that sets a range of lines to be +// ignored by the renderer. +func ClearIgnoredLines() Msg { + return clearIgnoredLinesMsg{} +} + +// scrollDownMsg is experiemental. There are no guarantees about it persisting +// in a future API. It's exposed for high performance scrolling. +type scrollUpMsg struct { + lines []string + topBoundary int + bottomBoundary int +} + +func ScrollUp(newLines []string, topBoundary, bottomBoundary int) Cmd { + return func() Msg { + return scrollUpMsg{ + lines: newLines, + topBoundary: topBoundary, + bottomBoundary: bottomBoundary, + } + } +} + +// scrollDownMsg is experiemental. There are no guarantees about it persisting +// in a future API. It's exposed for high performance scrolling. +type scrollDownMsg struct { + lines []string + topBoundary int + bottomBoundary int +} + +func ScrollDown(newLines []string, topBoundary, bottomBoundary int) Cmd { + return func() Msg { + return scrollDownMsg{ + lines: newLines, + topBoundary: topBoundary, + bottomBoundary: bottomBoundary, + } + } +} diff --git a/tea.go b/tea.go index aa27bce..e18edd3 100644 --- a/tea.go +++ b/tea.go @@ -171,32 +171,8 @@ func (p *Program) Start() error { continue } - // Report resizes to the renderer. Only necessary for special, - // performance-based rendering. - if size, ok := msg.(WindowSizeMsg); ok { - mrRenderer.width = size.Width - mrRenderer.height = size.Height - } - - // Handle messages telling the main rendering routine to ignore - // ranges of lines. Useful for performance-based rendering. - if lineRange, ok := msg.(ignoreLinesMsg); ok { - mrRenderer.setIgnoredLines(lineRange.from, lineRange.to) - } - - // Handle messages telling the main rendering routine to clear - // ranges of lines previously ignored and set a new range of - // ignored lines. For use in high-performance rendering. - if lineRange, ok := msg.(resetIgnoreLinesMsg); ok { - mrRenderer.clearIgnoredLines() - mrRenderer.setIgnoredLines(lineRange.from, lineRange.to) - } - - // Handle messages telling the main rendering to stop ignoring - // lines. Useful when disabling any performance-based rendering. - if _, ok := msg.(clearIgnoredLinesMsg); ok { - mrRenderer.clearIgnoredLines() - } + // Process any internal messages for the renderer + mrRenderer.handleMessages(msg) model, cmd = p.update(msg, model) // run update cmds <- cmd // process command (if any)