import posix import unicode import terminalUtils/buffer import terminalUtils/terminalGetInfo import terminalUtils/keycodes import textBuffer import renderer type EditorState* = ref object # config prompt: string # prompt to display textBuffer: TextBuffer # current text termBuffer: Buffer history: seq[TextBuffer] # past texts historyIndex: int # where are we in history EditorResult* = enum erEnter, erCtrlC, erCtrlD, erError # for editors var editors: seq[EditorState] # resize support onSignal(28): discard proc newEditor*(prompt: string = "> "): EditorState = new(result) result.prompt = prompt editors.add(result) proc destroyEditor*(oldEditor: EditorState) = for i in 0..editors.high(): let ed = editors[i] if ed == oldEditor: editors.del(i) return proc read*(ed: EditorState): (EditorResult, string) = var editorResult = erError let (_, cursorY) = termGetCursorPos(stdout) ed.termBuffer = newBuffer(0, cursorY, termGetWidth(), 1, stdout) ed.textBuffer = newTextBuffer() ed.history.add(ed.textBuffer) ed.historyIndex = ed.history.high() while true: render(ed.textBuffer, ed.termBuffer, ed.prompt) let (getKeyResult, key) = getKey() case getKeyResult: of gkChar: ed.textBuffer.insertRune(key.uint32().Rune()) of gkControl: let control = key.JaleKeycode() case control: of jkEnter: if ed.textBuffer.isCursorAtEnd(): editorResult = erEnter break else: ed.textBuffer.enter() of {jkBackspace, jkAltBackspace}: ed.textBuffer.backspace() of jkDelete: ed.textBuffer.delete() of jkCtrlC: # ctrl+c editorResult = erCtrlC break of jkCtrlD: # ctrl+d if ed.textBuffer.isEmpty(): editorResult = erCtrlD break of jkLeft: ed.textBuffer.moveCursor(-1, 0) of jkRight: ed.textBuffer.moveCursor(1, 0) of jkDown: ed.textBuffer.moveCursor(0, 1) of jkUp: ed.textBuffer.moveCursor(0, -1) of jkEnd: ed.textBuffer.moveToEnd(true) of jkHome: ed.textBuffer.moveToEnd(false) of jkCtrlDown: ed.textBuffer.newLine() else: discard # not implemented # return val result = (editorResult, ed.textBuffer.getContent()) # cleanup stdout.write("\n") ed.termBuffer = nil