use terminal

This commit is contained in:
Productive2 2021-02-20 14:46:37 +01:00
parent 85cf1d0581
commit 82b18c1cd4
4 changed files with 38 additions and 79 deletions

View File

@ -9,3 +9,14 @@ srcDir = "src"
# Dependencies # Dependencies
requires "nim >= 1.0.0" requires "nim >= 1.0.0"
import os
task examples, "Builds examples":
for kind, path in walkDir("examples/"):
if path.splitFile().ext == ".nim":
let (oup, exitcode) = gorgeEx "nim c " & path
if exitcode != 0:
echo "Failed building example " & path
echo oup
else:
echo "Successfully built example " & path

View File

@ -7,7 +7,7 @@ import multiline
import keycodes import keycodes
import event import event
import renderer import renderer
import uniterm import terminal
type type
JaleEvent* = enum JaleEvent* = enum
@ -73,56 +73,53 @@ proc reset(editor: LineEditor) =
editor.lastKeystroke = -1 editor.lastKeystroke = -1
editor.forceRedraw = false editor.forceRedraw = false
proc render(editor: LineEditor, wr: var TermWriter, line: int = -1, hscroll: bool = true) = proc render(editor: LineEditor, line: int = -1, hscroll: bool = true) =
var y = line var y = line
if y == -1: if y == -1:
y = editor.content.Y y = editor.content.Y
let prompt = if y == 0: editor.prompt else: " ".repeat(editor.prompt.len()) let prompt = if y == 0: editor.prompt else: " ".repeat(editor.prompt.len())
wr.renderLine(prompt, editor.content.getLine(y), 0) renderLine(prompt, editor.content.getLine(y), 0)
proc fullRender(editor: LineEditor, wr: var TermWriter) = proc fullRender(editor: LineEditor) =
# from the top cursor pos, it draws the entire multiline prompt, then # from the top cursor pos, it draws the entire multiline prompt, then
# moves cursor to current y # moves cursor to current y
for i in countup(0, editor.content.high()): for i in countup(0, editor.content.high()):
editor.render(wr, i, false) editor.render(i, false)
if i < editor.rendered: if i < editor.rendered:
wr.down(1) cursorDown(1)
else: else:
wr.lf() write stdout, "\n"
inc editor.rendered inc editor.rendered
var extraup = 0 var extraup = 0
while editor.content.len() < editor.rendered: while editor.content.len() < editor.rendered:
wr.clearLine() eraseLine()
wr.down(1) cursorDown(1)
dec editor.rendered dec editor.rendered
inc extraup inc extraup
wr.up(editor.content.len() - editor.content.Y + extraup) cursorUp(editor.content.len() - editor.content.Y + extraup)
proc moveCursorToEnd(editor: LineEditor, wr: var TermWriter) = proc moveCursorToEnd(editor: LineEditor) =
# only called when read finished # only called when read finished
if editor.content.high() > editor.content.Y: if editor.content.high() > editor.content.Y:
wr.down(editor.content.high() - editor.content.Y) cursorDown(editor.content.high() - editor.content.Y)
wr.lf() write stdout, "\n"
proc read*(editor: LineEditor): string = proc read*(editor: LineEditor): string =
editor.state = esTyping editor.state = esTyping
editor.events.call(jePreRead) editor.events.call(jePreRead)
var buffer: TermWriter
# starts at the top, full render moves it into the right y # starts at the top, full render moves it into the right y
editor.fullRender(buffer) editor.fullRender()
while editor.state == esTyping: while editor.state == esTyping:
# refresh current line every time # refresh current line every time
buffer.setCursorX(editor.content.X + editor.prompt.len()) setCursorXPos(editor.content.X + editor.prompt.len())
# get key (with escapes) # get key (with escapes)
buffer.flush()
let key = getKey() let key = getKey()
# record y pos # record y pos
let preY = editor.content.Y let preY = editor.content.Y
@ -134,19 +131,18 @@ proc read*(editor: LineEditor): string =
if editor.forceRedraw or preY != editor.content.Y: if editor.forceRedraw or preY != editor.content.Y:
# move to the top # move to the top
if preY > 0: if preY > 0:
buffer.up(preY) cursorUp(preY)
# move to the right y # move to the right y
editor.fullRender(buffer) editor.fullRender()
if editor.forceRedraw: if editor.forceRedraw:
editor.forceRedraw = false editor.forceRedraw = false
else: else:
editor.render(buffer) editor.render()
editor.events.call(jePostRead) editor.events.call(jePostRead)
# move cursor to end # move cursor to end
editor.moveCursorToEnd(buffer) editor.moveCursorToEnd()
buffer.flush()
if editor.state == esFinishing: if editor.state == esFinishing:
result = editor.content.getContent() result = editor.content.getContent()
editor.reset() editor.reset()

View File

@ -3,18 +3,18 @@
# a terminal renderer for readline-like libraries # a terminal renderer for readline-like libraries
import strutils import strutils
import uniterm import terminal
proc renderLine*(wr: var TermWriter, prompt: string, content: string, hscroll: int = 0) = proc renderLine*(prompt: string, content: string, hscroll: int = 0) =
wr.cr() setCursorXPos(0)
var content = prompt & content var content = prompt & content
if content.len() < wr.terminalWidth(): if content.len() < terminalWidth():
content &= " ".repeat(wr.terminalWidth() - content.len()) content &= " ".repeat(terminalWidth() - content.len())
if content.len() > wr.terminalWidth(): if content.len() > terminalWidth():
var lower = hscroll var lower = hscroll
var upper = hscroll + wr.terminalWidth() - 1 var upper = hscroll + terminalWidth() - 1
if upper > content.high(): if upper > content.high():
upper = content.high() upper = content.high()
content = content[lower..upper] content = content[lower..upper]
wr &= content write stdout, content

View File

@ -25,51 +25,3 @@ else:
proc uniGetChr*: int = proc uniGetChr*: int =
## Retrieves an ASCII character from stdin. ## Retrieves an ASCII character from stdin.
return getch().int 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")
wr.cr()
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]("")