work on multiline, horizontal scroll
This commit is contained in:
parent
d2001bb458
commit
2fffb11a69
|
@ -49,8 +49,10 @@ proc read*(ed: EditorState): (EditorResult, string) =
|
||||||
ed.history.add(ed.textBuffer)
|
ed.history.add(ed.textBuffer)
|
||||||
ed.historyIndex = ed.history.high()
|
ed.historyIndex = ed.history.high()
|
||||||
|
|
||||||
|
var scroll: Scroll = new(Scroll)
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
render(ed.textBuffer, ed.termBuffer, ed.prompt)
|
render(ed.textBuffer, ed.termBuffer, ed.prompt, scroll)
|
||||||
let (getKeyResult, key) = getKey()
|
let (getKeyResult, key) = getKey()
|
||||||
case getKeyResult:
|
case getKeyResult:
|
||||||
of gkChar:
|
of gkChar:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import editor
|
import editor
|
||||||
|
import terminal
|
||||||
|
|
||||||
let e = newEditor(">>> ")
|
let e = newEditor(">>> ")
|
||||||
|
|
||||||
|
@ -6,5 +7,9 @@ while true:
|
||||||
let (res, text) = e.read()
|
let (res, text) = e.read()
|
||||||
if res in {erCtrlC, erCtrlD} or text == "quit":
|
if res in {erCtrlC, erCtrlD} or text == "quit":
|
||||||
break
|
break
|
||||||
|
elif text == "clear":
|
||||||
|
eraseScreen()
|
||||||
|
setCursorPos(0, 0)
|
||||||
|
continue
|
||||||
if text.len() > 0:
|
if text.len() > 0:
|
||||||
echo text
|
echo text
|
54
renderer.nim
54
renderer.nim
|
@ -2,26 +2,66 @@
|
||||||
# when render() is called, rewrites the terminal buffer completely as a function of
|
# when render() is called, rewrites the terminal buffer completely as a function of
|
||||||
# of the text buffer
|
# of the text buffer
|
||||||
|
|
||||||
|
import strutils
|
||||||
|
|
||||||
import textBuffer
|
import textBuffer
|
||||||
import terminalUtils/buffer
|
import terminalUtils/buffer
|
||||||
import terminalUtils/terminalGetInfo
|
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
|
# we are free to "redraw" everything everytime
|
||||||
# since termBuffer double buffers
|
# since termBuffer double buffers
|
||||||
|
|
||||||
# resizing the buffer if needed
|
# resizing the buffer if needed
|
||||||
let lineCount = textBuffer.getLineCount()
|
let lineCount = textBuffer.getLineCount()
|
||||||
let termWidth = termGetWidth()
|
let termWidth = termGetWidth()
|
||||||
let termHeight = termGetHeight() # TODO
|
let termHeight = termGetHeight()
|
||||||
|
|
||||||
let (bufWidth, bufHeight) = termBuffer.getSize()
|
let (bufWidth, bufHeight) = termBuffer.getSize()
|
||||||
|
|
||||||
|
|
||||||
termBuffer.clearLine()
|
if bufWidth != termWidth or bufHeight != min(lineCount, termHeight):
|
||||||
termBuffer.write(prompt)
|
termBuffer.resize(termWidth, min(lineCount, termHeight))
|
||||||
termBuffer.write(textBuffer.getLine())
|
|
||||||
|
termBuffer.clear()
|
||||||
|
|
||||||
let (x, y) = textBuffer.getCursorPos()
|
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()
|
termBuffer.redraw()
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,9 @@ proc write*(buf: Buffer, text: string) =
|
||||||
let runes = text.toRunes()
|
let runes = text.toRunes()
|
||||||
buf.write(runes)
|
buf.write(runes)
|
||||||
|
|
||||||
|
proc newLine*(buf: Buffer) =
|
||||||
|
buf.bufferY += 1
|
||||||
|
buf.bufferX = 0
|
||||||
|
|
||||||
proc redraw*(buf: Buffer, force: bool = false) =
|
proc redraw*(buf: Buffer, force: bool = false) =
|
||||||
var toPrint = ""
|
var toPrint = ""
|
||||||
|
@ -144,17 +147,36 @@ proc redraw*(buf: Buffer, force: bool = false) =
|
||||||
func getSize*(buf: Buffer): (int, int) =
|
func getSize*(buf: Buffer): (int, int) =
|
||||||
(buf.width, buf.height)
|
(buf.width, buf.height)
|
||||||
|
|
||||||
proc resize*(buf: Buffer, newX, newY: int) =
|
proc resize*(buf: Buffer, newWidth, newHeight: int) =
|
||||||
# shrinking X
|
# shrinking X
|
||||||
if newX < buf.width:
|
if newWidth < buf.width:
|
||||||
# dropping cells outside the screen
|
# dropping cells outside the screen
|
||||||
var i = 0
|
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.width = newWidth
|
||||||
buf.height = newY
|
buf.height = newHeight
|
||||||
|
|
||||||
func getPosition*(buf: Buffer): (int, int) =
|
func getPosition*(buf: Buffer): (int, int) =
|
||||||
(buf.positionX, buf.positionY)
|
(buf.positionX, buf.positionY)
|
||||||
|
|
|
@ -67,6 +67,10 @@ proc moveCursor*(buf: TextBuffer, dx, dy: int) =
|
||||||
buf.cursorY = 0
|
buf.cursorY = 0
|
||||||
elif buf.cursorY > buf.content.high():
|
elif buf.cursorY > buf.content.high():
|
||||||
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) =
|
proc getCursorPos*(buf: TextBuffer): (int, int) =
|
||||||
(buf.cursorX, buf.cursorY)
|
(buf.cursorX, buf.cursorY)
|
||||||
|
@ -98,4 +102,7 @@ proc newLine*(buf: TextBuffer) =
|
||||||
buf.cursorX = 0
|
buf.cursorX = 0
|
||||||
|
|
||||||
proc getLineCount*(buf: TextBuffer): int =
|
proc getLineCount*(buf: TextBuffer): int =
|
||||||
buf.content.len()
|
buf.content.len()
|
||||||
|
|
||||||
|
proc lines*(buf: TextBuffer): seq[seq[Rune]] =
|
||||||
|
buf.content
|
Loading…
Reference in New Issue