From 2453283ad9f3fda70169ad9e8e48037d5554ba19 Mon Sep 17 00:00:00 2001 From: Productive2 <48047721+Productive2@users.noreply.github.com> Date: Fri, 19 Feb 2021 14:11:25 +0100 Subject: [PATCH] added uniterm note: currently broken, download another commit if you're just testing --- src/jale/editor.nim | 44 ++++++++++++++++--------------- src/jale/plugin/defaults.nim | 12 ++++----- src/jale/renderer.nim | 15 ++++++----- src/jale/uniterm.nim | 50 +++++++++++++++++++++++++++++++++++- 4 files changed, 87 insertions(+), 34 deletions(-) diff --git a/src/jale/editor.nim b/src/jale/editor.nim index 5f6dadf..263557e 100644 --- a/src/jale/editor.nim +++ b/src/jale/editor.nim @@ -1,13 +1,13 @@ import strformat import strutils import tables -import terminal import line import multiline import keycodes import event import renderer +import uniterm type JaleEvent* = enum @@ -73,12 +73,12 @@ proc reset(editor: LineEditor) = editor.lastKeystroke = -1 editor.forceRedraw = false -proc render(editor: LineEditor, line: int = -1, hscroll: bool = true) = +proc render(editor: LineEditor, wr: var TermWriter, line: int = -1, hscroll: bool = true) = var y = line if y == -1: y = editor.content.Y - renderLine( + wr.renderLine( ( if y == 0: editor.prompt @@ -89,49 +89,52 @@ proc render(editor: LineEditor, line: int = -1, hscroll: bool = true) = 0 ) -proc clearLine = - write stdout, "\r" & " ".repeat(terminalWidth()) +proc clearLine(wr: var TermWriter) = + wr.clearLine() -proc fullRender(editor: LineEditor) = +proc fullRender(editor: LineEditor, wr: var TermWriter) = # from the top cursor pos, it draws the entire multiline prompt, then # moves cursor to current y for i in countup(0, editor.content.high()): - editor.render(i, false) + editor.render(wr, i, false) if i < editor.rendered: - cursorDown(1) + wr.down(1) else: write stdout, "\n" inc editor.rendered var extraup = 0 while editor.content.len() < editor.rendered: - clearLine() - cursorDown(1) + wr.clearLine() + wr.down(1) dec editor.rendered inc extraup - cursorUp(editor.content.len() - editor.content.Y + extraup) + wr.up(editor.content.len() - editor.content.Y + extraup) -proc moveCursorToEnd(editor: LineEditor) = +proc moveCursorToEnd(editor: LineEditor, wr: var TermWriter) = # only called when read finished if editor.content.high() > editor.content.Y: - cursorDown(editor.content.high() - editor.content.Y) - write stdout, "\n" + wr.down(editor.content.high() - editor.content.Y) + wr.lf() proc read*(editor: LineEditor): string = editor.state = esTyping editor.events.call(jePreRead) + var buffer: TermWriter + # starts at the top, full render moves it into the right y - editor.fullRender() + editor.fullRender(buffer) while editor.state == esTyping: # refresh current line every time - editor.render() - setCursorXPos(editor.content.X + editor.prompt.len()) + editor.render(buffer) + buffer.setCursorX(editor.content.X + editor.prompt.len()) # get key (with escapes) + buffer.flush() let key = getKey() # record y pos let preY = editor.content.Y @@ -143,16 +146,17 @@ proc read*(editor: LineEditor): string = if editor.forceRedraw or preY != editor.content.Y: # move to the top if preY > 0: - cursorUp(preY) + buffer.up(preY) # move to the right y - editor.fullRender() + editor.fullRender(buffer) if editor.forceRedraw: editor.forceRedraw = false editor.events.call(jePostRead) # move cursor to end - editor.moveCursorToEnd() + editor.moveCursorToEnd(buffer) + buffer.flush() if editor.state == esFinishing: result = editor.content.getContent() editor.reset() diff --git a/src/jale/plugin/defaults.nim b/src/jale/plugin/defaults.nim index 5c69c7e..7c37435 100644 --- a/src/jale/plugin/defaults.nim +++ b/src/jale/plugin/defaults.nim @@ -21,17 +21,19 @@ proc bindTerminate*(editor: LineEditor) = editor.quit() -proc populateDefaults*(editor: LineEditor, enterSubmits = true, shiftForVerticalMove = true) = +proc populateDefaults*(editor: LineEditor, enterSubmits = true, ctrlForVerticalMove = true) = editor.bindInput() editor.bindTerminate() editor.bindKey("left"): editor.content.left() editor.bindKey("right"): editor.content.right() - if shiftForVerticalMove: - editor.bindKey("shiftup"): + if ctrlForVerticalMove: + editor.bindKey("ctrlup"): editor.content.up() - editor.bindKey("shiftdown"): + editor.bindKey("ctrldown"): + if editor.content.Y() == editor.content.high(): + editor.content.insertline() editor.content.down() editor.bindKey("ctrlpageup"): editor.content.vhome() @@ -55,8 +57,6 @@ proc populateDefaults*(editor: LineEditor, enterSubmits = true, shiftForVertical editor.bindKey("delete"): editor.content.delete() if enterSubmits: - editor.bindKey("ctrldown"): - editor.content.enter() editor.bindKey("enter"): editor.finish() else: diff --git a/src/jale/renderer.nim b/src/jale/renderer.nim index e8c56b1..bc0d15d 100644 --- a/src/jale/renderer.nim +++ b/src/jale/renderer.nim @@ -2,20 +2,21 @@ # # a terminal renderer for readline-like libraries -import terminal import strutils +import uniterm -proc renderLine*(prompt: string, content: string, hscroll: int = 0) = +proc renderLine*(wr: var TermWriter, prompt: string, content: string, hscroll: int = 0) = + wr.cr() var content = prompt & content - if content.len() < terminalWidth(): - content &= " ".repeat(terminalWidth() - content.len()) - if content.len() > terminalWidth(): + if content.len() < wr.terminalWidth(): + content &= " ".repeat(wr.terminalWidth() - content.len()) + if content.len() > wr.terminalWidth(): var lower = hscroll - var upper = hscroll + terminalWidth() - 1 + var upper = hscroll + wr.terminalWidth() - 1 if upper > content.high(): upper = content.high() content = content[lower..upper] - write stdout, "\r" & content + wr &= content diff --git a/src/jale/uniterm.nim b/src/jale/uniterm.nim index 56f3ac6..4335539 100644 --- a/src/jale/uniterm.nim +++ b/src/jale/uniterm.nim @@ -3,6 +3,9 @@ # source: https://github.com/h3rald/nimline/blob/master/nimline.nim # lines 42-56 (modified) +import strutils +import terminal + when defined(windows): proc putchr(c: cint): cint {.discardable, header: "", importc: "_putch".} proc getchr(): cint {.header: "", importc: "_getch".} @@ -15,7 +18,6 @@ when defined(windows): getchr().int else: - import terminal proc uniPutChr*(c: char) = ## Prints an ASCII character to stdout. stdout.write(c) @@ -24,3 +26,49 @@ else: ## Retrieves an ASCII character from stdin. return getch().int +type TermWriter* = distinct string + +proc `&=`*(wr: var TermWriter, str: string) = + wr = TermWriter(string(wr) & str) + +proc lf*(wr: var TermWriter) = + wr &= "\n" + +proc cr*(wr: var TermWriter) = + when defined(windows): + wr &= ($27.char & "[0G") + else: + wr &= "\r" + +proc up*(wr: var TermWriter, count: int) = + if count == 0: + return + wr &= ($27.char & "[" & $count & "A") + +proc down*(wr: var TermWriter, count: int) = + if count == 0: + return + wr &= ($27.char & "[" & $count & "B") + +proc clearLine*(wr: var TermWriter) = + when defined(windows): + wr &= ($27.char & "[1M" & $27.char & "[1L") + else: + wr &= ($27.char & "[2K") + +proc setCursorX*(wr: var TermWriter, x: int) = + when defined(windows): + wr &= ($27.char & "[" & $x & "G") + else: + if x == 0: + wr &= "\r" + else: + wr &= ("\r" & $27.char & "[" & $x & "C") + +proc terminalWidth*(wr: var TermWriter): int = + terminalWidth() + +proc flush*(wr: var TermWriter) = + stdout.write(cast[string](wr)) + wr = cast[TermWriter]("") +