Added horizontal scrolling (for single/all line)

This commit is contained in:
Productive2 2021-02-21 00:44:56 +01:00
parent 0d8a66b57e
commit 36b32c5a23
3 changed files with 51 additions and 16 deletions

View File

@ -22,6 +22,7 @@ e.bindKey("ctrl+s"):
e.prompt = ""
e.populateDefaults(enterSubmits = false, ctrlForVerticalMove = false)
e.scrollMode = sbAllScroll
let result = e.read()
if save and paramCount() > 0:
writeFile(paramStr(1), result)

View File

@ -16,11 +16,15 @@ type
EditorState = enum
esOutside, esTyping, esFinishing, esQuitting
ScrollBehavior* = enum
sbSingleScroll, sbAllScroll, sbWrap
LineEditor* = ref object
# permanents
keystrokes*: Event[int]
events*: Event[JaleEvent]
prompt*: string
scrollMode*: ScrollBehavior
# permanent internals: none
@ -31,6 +35,7 @@ type
state: EditorState
rendered: int # how many lines were printed last full refresh
forceRedraw: bool
hscroll: int
# getter/setter sorts
@ -61,6 +66,8 @@ proc newLineEditor*: LineEditor =
result.lastKeystroke = -1
result.forceRedraw = false
result.state = esOutside
result.scrollMode = sbSingleScroll
result.hscroll = 0
# priv/pub methods
@ -72,20 +79,31 @@ proc reset(editor: LineEditor) =
editor.content = newMultiline()
editor.lastKeystroke = -1
editor.forceRedraw = false
editor.hscroll = 0
proc render(editor: LineEditor, line: int = -1, hscroll: bool = true) =
proc render(editor: LineEditor, line: int = -1) =
## Assumes that the cursor is already on the right line then
## proceeds to render the line-th line of the editor (if -1, will check
## the y).
var y = line
if y == -1:
y = editor.content.Y
# the prompt's length is assumed to be always padded
let prompt = if y == 0: editor.prompt else: " ".repeat(editor.prompt.len())
renderLine(prompt, editor.content.getLine(y), 0)
let content = editor.content.getLine(y)
if editor.scrollMode == sbAllScroll or
(editor.scrollMode == sbSingleScroll and y == editor.content.Y):
renderLine(prompt, content, editor.hscroll)
else:
renderLine(prompt, content, 0)
proc fullRender(editor: LineEditor) =
# from the top cursor pos, it draws the entire multiline prompt, then
# moves cursor to current y
for i in countup(0, editor.content.high()):
editor.render(i, false)
editor.render(i)
if i < editor.rendered:
cursorDown(1)
else:
@ -118,7 +136,7 @@ proc read*(editor: LineEditor): string =
while editor.state == esTyping:
# refresh current line every time
setCursorXPos(editor.content.X + editor.prompt.len())
setCursorXPos(editor.content.X - editor.hscroll + editor.prompt.len())
# get key (with escapes)
let key = getKey()
# record y pos
@ -127,6 +145,20 @@ proc read*(editor: LineEditor): string =
editor.lastKeystroke = key
editor.keystrokes.call(key)
editor.events.call(jeKeypress)
# autoscroll horizontally based on current scroll and x pos
# last x rendered
let lastX = terminalWidth() - editor.prompt.len() + editor.hscroll - 1
# first x rendered
let firstX = editor.hscroll
# x squished into boundaries
let boundX = min(max(firstX, editor.content.X), lastX)
if editor.content.X != boundX:
editor.hscroll += editor.content.X - boundX
if editor.scrollMode == sbAllScroll:
editor.forceRedraw = true
# redraw everything if y changed
if editor.forceRedraw or preY != editor.content.Y:
# move to the top

View File

@ -5,16 +5,18 @@
import strutils
import terminal
proc renderLine*(prompt: string, content: string, hscroll: int = 0) =
proc renderLine*(prompt: string, text: string, hscroll: int = 0) =
eraseLine()
setCursorXPos(0)
var content = prompt & content
if content.len() < terminalWidth():
content &= " ".repeat(terminalWidth() - content.len() - 1)
if content.len() > terminalWidth():
var lower = hscroll
var upper = hscroll + terminalWidth() - 1
if upper > content.high():
upper = content.high()
content = content[lower..upper]
write stdout, content
var lower = hscroll
var upper = hscroll + terminalWidth() - prompt.len() - 1
if upper > text.high():
upper = text.high()
if lower < -1:
raise newException(Defect, "negative hscroll submitted to renderLine")
if lower > text.high():
write stdout, prompt
else:
let content = prompt & text[lower..upper]
write stdout, content