jal3/renderer.nim

109 lines
3.2 KiB
Nim

# takes a text buffer and a terminal buffer (terminalUtils/buffer)
# 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
type Scroll* = ref object
x, y: int
proc reset*(scroll: Scroll) =
scroll.x = 0
scroll.y = 0
proc render*(textBuffer: TextBuffer, termBuffer: Buffer, prompt: string, scroll: Scroll, width, height: int, edCursorY: int): int =
# we are free to "redraw" everything everytime
# since termBuffer double buffers
# returns how many lines were drawn
# GET INFO
let (x, y) = textBuffer.getCursorPos()
let lines = textBuffer.lines()
let lineCount = lines.len()
#let termWidth = termGetWidth()
let termWidth = width
#let termHeight = termGetHeight()
let termHeight = height
let promptLen = prompt.len()
let maxTextLen = termWidth - promptLen
# SCROLL
const scrollOffset = 2
# 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 on backspace - TODO IMPLEMENT
# vertical scroll
# scroll down - when it would be out of reach
# mode 1: by moving the location up
# this one is based on content, not y position
# if this one scrolls too much
block:
# in a block so positionY can't be used below, since it can change!
let (_, positionY) = termBuffer.getPosition()
if positionY > 0 and positionY + lineCount > termHeight:
termBuffer.scroll(min(positionY + lineCount - termHeight, positionY))
# scroll down
# mode 2 - only if positionY is 0, so mode 1 is already done
# this one is based on the cursor
block:
let (_, positionY) = termBuffer.getPosition()
if positionY == 0 and y - scroll.y > termHeight - 1:
scroll.y = y - termHeight + 1
# scroll up
if y < scroll.y:
scroll.y = y
# resizing the buffer if needed
block:
# in a block, so bufWidth and height can't be used below, since they get changed!
let (bufWidth, bufHeight) = termBuffer.getSize()
# prevent shrinking vertically to avoid uncleaned parts
let desiredBufHeight = min(max(lineCount, bufHeight), termHeight)
if bufWidth != termWidth or bufHeight != desiredBufHeight:
termBuffer.resize(termWidth, desiredBufHeight, termWidth, termHeight)
termBuffer.clear()
if maxTextLen < 1:
termBuffer.redraw()
return # nothing will fit anyways
let fromY = scroll.y
# assumes that the MODE 1 scroll up has happened
# and if lineCount doesn't fit in termheight
# then it has already been scrolled to pos 0
let toY = min(fromY+termHeight-1, lineCount-1)
for i in fromY..toY:
let line = lines[i]
if i == 0:
termBuffer.write(prompt)
elif i == y:
termBuffer.write(">" & " ".repeat(promptLen - 1))
else:
termBuffer.write(" ".repeat(promptLen))
# keep what's in range
let fromPos = scroll.x
let toPos = min(scroll.x+maxTextLen-2, line.high())
if fromPos <= line.high():
termBuffer.write(line[fromPos..toPos])
if i < toY:
termBuffer.newLine()
termBuffer.setCursorPos(x + promptLen - scroll.x, y - scroll.y)
termBuffer.redraw()
return termBuffer.getHeight()