You can use a global counter to track input and setCursorPos(stdout, x, y) from it. Keeping track of the text in memory and setting the cursor position based on that text would give a better backspace experience. Probably. This shows how the counter could work, without any extra effort.
import std/terminal
type
CarteseanCoordinate = tuple[x: int, y: int]
# Global counter to track position
var inputCounter: int
proc getCursorPosition(): CarteseanCoordinate =
## Calculate the x,y coordinates from the global counter
## Returns a tuple(x: int, y: int)
let lineLength = terminalWidth()
if inputCounter <= lineLength: return (inputCounter, 0)
result = (inputCounter mod lineLength, (inputCounter / lineLength).int)
proc processBackspace() =
## Handle a backspace input and update global counters
let cursorPosition = getCursorPosition()
# Handle First Column
if cursorPosition.x == 0:
if cursorPosition.y == 0: return # Nothing to delete
dec inputCounter
stdout.setCursorPos(terminalWidth() - 1, cursorPosition.y - 1)
write(stdout, ' ')
stdout.setCursorPos(terminalWidth() - 1, cursorPosition.y - 1)
return
# Handle all other columns
dec inputCounter
stdout.setCursorPos(cursorPosition.x - 1, cursorPosition.y)
write(stdout, ' ')
stdout.setCursorPos(cursorPosition.x - 1, cursorPosition.y)
proc processReturn() =
## Handle a return input and update global counters
let cursorPosition = getCursorPosition()
# Global counter to include all the empty space the terminal inserts
inputCounter += terminalWidth() - cursorPosition.x
write(stdout, '\n')
proc processProblemInput(input: char): bool =
## Analyze input for special conditions
if input == '\b':
processBackspace()
return true
if input == '\r':
processReturn()
return true
eraseScreen(stdout)
stdout.setCursorPos(0,0)
while true:
let input = getch()
if not processProblemInput(input):
stdout.styledWrite(fgRed, $input)
inc inputCounter
showCursor(stdout)