# 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()