From 77348c2188eac472124b85f35d2ed213ba78b6af Mon Sep 17 00:00:00 2001 From: rrrooommmaaa Date: Mon, 11 Feb 2019 23:27:08 +0300 Subject: [PATCH] implemented 'area scrolling' (#202) * implemented 'area scrolling' * bug fix: area scroll down boundary check * bug fix: ReverseIndex activates scroll down correctly --- buffer/buffer.go | 92 ++++++++++++++-------------------------- buffer/terminal_state.go | 12 ++++++ gui/mouse.go | 4 +- terminal/csi.go | 4 +- terminal/scr_state.go | 2 +- terminal/terminal.go | 49 +++++++++++++++++---- 6 files changed, 91 insertions(+), 72 deletions(-) diff --git a/buffer/buffer.go b/buffer/buffer.go index 4d21979..f5c657b 100644 --- a/buffer/buffer.go +++ b/buffer/buffer.go @@ -326,10 +326,6 @@ func (buffer *Buffer) IsDirty() bool { return true } -func (buffer *Buffer) GetScrollOffset() uint { - return buffer.terminalState.scrollLinesFromBottom -} - func (buffer *Buffer) HasScrollableRegion() bool { return buffer.terminalState.topMargin > 0 || buffer.terminalState.bottomMargin < uint(buffer.ViewHeight())-1 } @@ -338,46 +334,48 @@ func (buffer *Buffer) InScrollableRegion() bool { return buffer.HasScrollableRegion() && uint(buffer.terminalState.cursorY) >= buffer.terminalState.topMargin && uint(buffer.terminalState.cursorY) <= buffer.terminalState.bottomMargin } -func (buffer *Buffer) ScrollDown(lines uint16) { +// NOTE: bottom is exclusive +func (buffer *Buffer) getAreaScrollRange() (top uint64, bottom uint64) { + top = buffer.convertViewLineToRawLine(uint16(buffer.terminalState.topMargin)) + bottom = buffer.convertViewLineToRawLine(uint16(buffer.terminalState.bottomMargin)) + 1 + if bottom > uint64(len(buffer.lines)) { + bottom = uint64(len(buffer.lines)) + } + return top, bottom +} +func (buffer *Buffer) AreaScrollDown(lines uint16) { defer buffer.emitDisplayChange() - if buffer.Height() < int(buffer.ViewHeight()) { - return - } + // NOTE: bottom is exclusive + top, bottom := buffer.getAreaScrollRange() - if uint(lines) > buffer.terminalState.scrollLinesFromBottom { - lines = uint16(buffer.terminalState.scrollLinesFromBottom) + for i := bottom; i > top; { + i-- + if i >= top+uint64(lines) { + buffer.lines[i] = buffer.lines[i-uint64(lines)] + } else { + buffer.lines[i] = newLine() + } } - buffer.terminalState.scrollLinesFromBottom -= uint(lines) } -func (buffer *Buffer) ScrollUp(lines uint16) { - +func (buffer *Buffer) AreaScrollUp(lines uint16) { defer buffer.emitDisplayChange() - if buffer.Height() < int(buffer.ViewHeight()) { - return - } + // NOTE: bottom is exclusive + top, bottom := buffer.getAreaScrollRange() - if uint(lines)+buffer.terminalState.scrollLinesFromBottom >= (uint(buffer.Height()) - uint(buffer.ViewHeight())) { - buffer.terminalState.scrollLinesFromBottom = uint(buffer.Height()) - uint(buffer.ViewHeight()) - } else { - buffer.terminalState.scrollLinesFromBottom += uint(lines) + for i := top; i < bottom; i++ { + from := i + uint64(lines) + if from < bottom { + buffer.lines[i] = buffer.lines[from] + } else { + buffer.lines[i] = newLine() + } } } -func (buffer *Buffer) ScrollPageDown() { - buffer.ScrollDown(buffer.terminalState.viewHeight) -} -func (buffer *Buffer) ScrollPageUp() { - buffer.ScrollUp(buffer.terminalState.viewHeight) -} -func (buffer *Buffer) ScrollToEnd() { - defer buffer.emitDisplayChange() - buffer.terminalState.scrollLinesFromBottom = 0 -} - func (buffer *Buffer) SaveCursor() { copiedAttr := buffer.terminalState.CursorAttr buffer.savedCursorAttr = &copiedAttr @@ -595,15 +593,7 @@ func (buffer *Buffer) Index() { if uint(buffer.terminalState.cursorY) < buffer.terminalState.bottomMargin { buffer.terminalState.cursorY++ } else { - - topIndex := buffer.convertViewLineToRawLine(uint16(buffer.terminalState.topMargin)) - bottomIndex := buffer.convertViewLineToRawLine(uint16(buffer.terminalState.bottomMargin)) - - for i := topIndex; i < bottomIndex; i++ { - buffer.lines[i] = buffer.lines[i+1] - } - - buffer.lines[bottomIndex] = newLine() + buffer.AreaScrollUp(1) } return @@ -625,25 +615,9 @@ func (buffer *Buffer) ReverseIndex() { defer buffer.emitDisplayChange() - if buffer.InScrollableRegion() { - - if uint(buffer.terminalState.cursorY) > buffer.terminalState.topMargin { - buffer.terminalState.cursorY-- - } else { - - topIndex := buffer.convertViewLineToRawLine(uint16(buffer.terminalState.topMargin)) - bottomIndex := buffer.convertViewLineToRawLine(uint16(buffer.terminalState.bottomMargin)) - - for i := bottomIndex; i > topIndex; i-- { - buffer.lines[i] = buffer.lines[i-1] - } - - buffer.lines[topIndex] = newLine() - } - return - } - - if buffer.terminalState.cursorY > 0 { + if uint(buffer.terminalState.cursorY) == buffer.terminalState.topMargin { + buffer.AreaScrollDown(1) + } else if buffer.terminalState.cursorY > 0 { buffer.terminalState.cursorY-- } } diff --git a/buffer/terminal_state.go b/buffer/terminal_state.go index 4883b81..38b9972 100644 --- a/buffer/terminal_state.go +++ b/buffer/terminal_state.go @@ -110,3 +110,15 @@ func (terminalState *TerminalState) TabReset() { i += TabStep } } + +func (terminalState *TerminalState) ViewHeight() uint16 { + return terminalState.viewHeight +} + +func (terminalState *TerminalState) GetScrollOffset() uint { + return terminalState.scrollLinesFromBottom +} + +func (terminalState *TerminalState) SetScrollOffset(offset uint) { + terminalState.scrollLinesFromBottom = offset +} diff --git a/gui/mouse.go b/gui/mouse.go index bbdd39a..b29987b 100644 --- a/gui/mouse.go +++ b/gui/mouse.go @@ -13,9 +13,9 @@ import ( func (gui *GUI) glfwScrollCallback(w *glfw.Window, xoff float64, yoff float64) { if yoff > 0 { - gui.terminal.ScrollUp(1) + gui.terminal.ScreenScrollUp(1) } else { - gui.terminal.ScrollDown(1) + gui.terminal.ScreenScrollDown(1) } } diff --git a/terminal/csi.go b/terminal/csi.go index bac472b..c749951 100644 --- a/terminal/csi.go +++ b/terminal/csi.go @@ -299,7 +299,7 @@ func csiScrollUpHandler(params []string, terminal *Terminal) error { } } terminal.logger.Debugf("Scrolling up %d", distance) - terminal.ScrollUp(uint16(distance)) + terminal.AreaScrollUp(uint16(distance)) return nil } @@ -370,7 +370,7 @@ func csiScrollDownHandler(params []string, terminal *Terminal) error { } } terminal.logger.Debugf("Scrolling down %d", distance) - terminal.ScrollDown(uint16(distance)) + terminal.AreaScrollDown(uint16(distance)) return nil } diff --git a/terminal/scr_state.go b/terminal/scr_state.go index ff64c83..ae1a346 100644 --- a/terminal/scr_state.go +++ b/terminal/scr_state.go @@ -9,7 +9,7 @@ func screenStateHandler(pty chan rune, terminal *Terminal) error { // hide cursor? buffer := terminal.ActiveBuffer() terminal.ResetVerticalMargins() - buffer.ScrollToEnd() + terminal.ScrollToEnd() // Fill the whole screen with E's count := buffer.ViewHeight() * buffer.ViewWidth() diff --git a/terminal/terminal.go b/terminal/terminal.go index 67ab419..3469636 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -154,12 +154,22 @@ func (terminal *Terminal) UsingMainBuffer() bool { } func (terminal *Terminal) GetScrollOffset() uint { - return terminal.ActiveBuffer().GetScrollOffset() + return terminal.terminalState.GetScrollOffset() } -func (terminal *Terminal) ScrollDown(lines uint16) { - terminal.ActiveBuffer().ScrollDown(lines) +func (terminal *Terminal) ScreenScrollDown(lines uint16) { + defer terminal.SetDirty() + buffer := terminal.ActiveBuffer() + if buffer.Height() < int(buffer.ViewHeight()) { + return + } + + offset := terminal.terminalState.GetScrollOffset() + if uint(lines) > offset { + lines = uint16(offset) + } + terminal.terminalState.SetScrollOffset(offset - uint(lines)) } func (terminal *Terminal) SetCharSize(w float32, h float32) { @@ -167,18 +177,41 @@ func (terminal *Terminal) SetCharSize(w float32, h float32) { terminal.charHeight = h } -func (terminal *Terminal) ScrollUp(lines uint16) { - terminal.ActiveBuffer().ScrollUp(lines) +func (terminal *Terminal) AreaScrollUp(lines uint16) { + terminal.ActiveBuffer().AreaScrollUp(lines) +} + +func (terminal *Terminal) AreaScrollDown(lines uint16) { + terminal.ActiveBuffer().AreaScrollDown(lines) +} + +func (terminal *Terminal) ScreenScrollUp(lines uint16) { + defer terminal.SetDirty() + buffer := terminal.ActiveBuffer() + + if buffer.Height() < int(buffer.ViewHeight()) { + return + } + + offset := terminal.terminalState.GetScrollOffset() + + if uint(lines)+offset >= (uint(buffer.Height()) - uint(buffer.ViewHeight())) { + terminal.terminalState.SetScrollOffset(uint(buffer.Height()) - uint(buffer.ViewHeight())) + } else { + terminal.terminalState.SetScrollOffset(offset + uint(lines)) + } } func (terminal *Terminal) ScrollPageDown() { - terminal.ActiveBuffer().ScrollPageDown() + terminal.ScreenScrollDown(terminal.terminalState.ViewHeight()) } func (terminal *Terminal) ScrollPageUp() { - terminal.ActiveBuffer().ScrollPageUp() + terminal.ScreenScrollUp(terminal.terminalState.ViewHeight()) } + func (terminal *Terminal) ScrollToEnd() { - terminal.ActiveBuffer().ScrollToEnd() + defer terminal.SetDirty() + terminal.terminalState.SetScrollOffset(0) } func (terminal *Terminal) GetVisibleLines() []buffer.Line {