work on multiline, horizontal scroll

This commit is contained in:
Art 2022-12-29 18:50:57 +01:00
parent d2001bb458
commit 2fffb11a69
Signed by: prod2
GPG Key ID: F3BB5A97A70A8DDE
5 changed files with 91 additions and 15 deletions

View File

@ -49,8 +49,10 @@ proc read*(ed: EditorState): (EditorResult, string) =
ed.history.add(ed.textBuffer)
ed.historyIndex = ed.history.high()
var scroll: Scroll = new(Scroll)
while true:
render(ed.textBuffer, ed.termBuffer, ed.prompt)
render(ed.textBuffer, ed.termBuffer, ed.prompt, scroll)
let (getKeyResult, key) = getKey()
case getKeyResult:
of gkChar:

View File

@ -1,4 +1,5 @@
import editor
import terminal
let e = newEditor(">>> ")
@ -6,5 +7,9 @@ while true:
let (res, text) = e.read()
if res in {erCtrlC, erCtrlD} or text == "quit":
break
elif text == "clear":
eraseScreen()
setCursorPos(0, 0)
continue
if text.len() > 0:
echo text

View File

@ -2,26 +2,66 @@
# when render() is called, rewrites the terminal buffer completely as a function of
# of the text buffer
import strutils
import textBuffer
import terminalUtils/buffer
import terminalUtils/terminalGetInfo
proc render*(textBuffer: TextBuffer, termBuffer: Buffer, prompt: string) =
type Scroll* = ref object
x, y: int
proc render*(textBuffer: TextBuffer, termBuffer: Buffer, prompt: string, scroll: Scroll) =
# we are free to "redraw" everything everytime
# since termBuffer double buffers
# resizing the buffer if needed
let lineCount = textBuffer.getLineCount()
let termWidth = termGetWidth()
let termHeight = termGetHeight() # TODO
let termHeight = termGetHeight()
let (bufWidth, bufHeight) = termBuffer.getSize()
termBuffer.clearLine()
termBuffer.write(prompt)
termBuffer.write(textBuffer.getLine())
if bufWidth != termWidth or bufHeight != min(lineCount, termHeight):
termBuffer.resize(termWidth, min(lineCount, termHeight))
termBuffer.clear()
let (x, y) = textBuffer.getCursorPos()
termBuffer.setCursorPos(x + prompt.len(), y)
let lines = textBuffer.lines()
let promptLen = prompt.len()
let maxTextLen = termWidth - promptLen
if maxTextLen < 1:
termBuffer.redraw()
return # nothing will fit anyways
for i in 0..lines.high():
let line = lines[i]
if i == 0:
termBuffer.write(prompt)
else:
termBuffer.write(" ".repeat(promptLen))
let lineLen = line.len()
if lineLen < maxTextLen - 1:
scroll.x = 0
termBuffer.write(line)
else:
const scrollOffset = 2
# horizontal scroll
# right scroll
if x - scroll.x >= maxTextLen - scrollOffset:
scroll.x = x - maxTextLen + scrollOffset
# left scroll
if x - scroll.x < 0:
scroll.x = x
# left scroll
# keep what's in range
let fromPos = scroll.x
let toPos = min(scroll.x+maxTextLen-2, line.high())
termBuffer.write(line[fromPos..toPos])
termBuffer.newLine()
termBuffer.setCursorPos(x + promptLen - scroll.x, y - scroll.y)
termBuffer.redraw()

View File

@ -104,6 +104,9 @@ proc write*(buf: Buffer, text: string) =
let runes = text.toRunes()
buf.write(runes)
proc newLine*(buf: Buffer) =
buf.bufferY += 1
buf.bufferX = 0
proc redraw*(buf: Buffer, force: bool = false) =
var toPrint = ""
@ -144,17 +147,36 @@ proc redraw*(buf: Buffer, force: bool = false) =
func getSize*(buf: Buffer): (int, int) =
(buf.width, buf.height)
proc resize*(buf: Buffer, newX, newY: int) =
proc resize*(buf: Buffer, newWidth, newHeight: int) =
# shrinking X
if newX < buf.width:
if newWidth < buf.width:
# dropping cells outside the screen
var i = 0
buf.buffered.keepItIf(i mod buf.width < newWidth)
i = 0
buf.displayed.keepItIf(i mod buf.width < newWidth)
# increasing X
elif newWidth > buf.width:
let extra = newWidth - buf.width
let extraCells = Cell(text: Rune(0)).repeat(extra)
for i in 0..buf.height-1:
let pos = i * newWidth + buf.width
buf.buffered.insert(extraCells, pos)
buf.displayed.insert(extraCells, pos)
# shrinking Y
if newHeight < buf.height:
buf.buffered.setLen(newHeight * newWidth)
buf.displayed.setLen(newHeight * newWidth)
# increasing Y
elif newHeight > buf.height:
let extra = newHeight - buf.height
let extraCells = Cell(text: Rune(0)).repeat(extra * newWidth)
buf.buffered &= extraCells
buf.displayed &= extraCells
buf.width = newX
buf.height = newY
buf.width = newWidth
buf.height = newHeight
func getPosition*(buf: Buffer): (int, int) =
(buf.positionX, buf.positionY)

View File

@ -67,6 +67,10 @@ proc moveCursor*(buf: TextBuffer, dx, dy: int) =
buf.cursorY = 0
elif buf.cursorY > buf.content.high():
buf.cursorY = buf.content.high()
if buf.cursorX > buf.cline().len():
buf.cursorX = buf.cline().len()
proc getCursorPos*(buf: TextBuffer): (int, int) =
(buf.cursorX, buf.cursorY)
@ -98,4 +102,7 @@ proc newLine*(buf: TextBuffer) =
buf.cursorX = 0
proc getLineCount*(buf: TextBuffer): int =
buf.content.len()
buf.content.len()
proc lines*(buf: TextBuffer): seq[seq[Rune]] =
buf.content