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.prompt = ""
e.populateDefaults(enterSubmits = false, ctrlForVerticalMove = false) e.populateDefaults(enterSubmits = false, ctrlForVerticalMove = false)
e.scrollMode = sbAllScroll
let result = e.read() let result = e.read()
if save and paramCount() > 0: if save and paramCount() > 0:
writeFile(paramStr(1), result) writeFile(paramStr(1), result)

View File

@ -16,11 +16,15 @@ type
EditorState = enum EditorState = enum
esOutside, esTyping, esFinishing, esQuitting esOutside, esTyping, esFinishing, esQuitting
ScrollBehavior* = enum
sbSingleScroll, sbAllScroll, sbWrap
LineEditor* = ref object LineEditor* = ref object
# permanents # permanents
keystrokes*: Event[int] keystrokes*: Event[int]
events*: Event[JaleEvent] events*: Event[JaleEvent]
prompt*: string prompt*: string
scrollMode*: ScrollBehavior
# permanent internals: none # permanent internals: none
@ -31,6 +35,7 @@ type
state: EditorState state: EditorState
rendered: int # how many lines were printed last full refresh rendered: int # how many lines were printed last full refresh
forceRedraw: bool forceRedraw: bool
hscroll: int
# getter/setter sorts # getter/setter sorts
@ -61,6 +66,8 @@ proc newLineEditor*: LineEditor =
result.lastKeystroke = -1 result.lastKeystroke = -1
result.forceRedraw = false result.forceRedraw = false
result.state = esOutside result.state = esOutside
result.scrollMode = sbSingleScroll
result.hscroll = 0
# priv/pub methods # priv/pub methods
@ -72,20 +79,31 @@ proc reset(editor: LineEditor) =
editor.content = newMultiline() editor.content = newMultiline()
editor.lastKeystroke = -1 editor.lastKeystroke = -1
editor.forceRedraw = false 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 var y = line
if y == -1: if y == -1:
y = editor.content.Y 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()) 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) = proc fullRender(editor: LineEditor) =
# from the top cursor pos, it draws the entire multiline prompt, then # from the top cursor pos, it draws the entire multiline prompt, then
# moves cursor to current y # moves cursor to current y
for i in countup(0, editor.content.high()): for i in countup(0, editor.content.high()):
editor.render(i, false) editor.render(i)
if i < editor.rendered: if i < editor.rendered:
cursorDown(1) cursorDown(1)
else: else:
@ -118,7 +136,7 @@ proc read*(editor: LineEditor): string =
while editor.state == esTyping: while editor.state == esTyping:
# refresh current line every time # 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) # get key (with escapes)
let key = getKey() let key = getKey()
# record y pos # record y pos
@ -127,6 +145,20 @@ proc read*(editor: LineEditor): string =
editor.lastKeystroke = key editor.lastKeystroke = key
editor.keystrokes.call(key) editor.keystrokes.call(key)
editor.events.call(jeKeypress) 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 # redraw everything if y changed
if editor.forceRedraw or preY != editor.content.Y: if editor.forceRedraw or preY != editor.content.Y:
# move to the top # move to the top

View File

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