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
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 event
import renderer
import uniterm
import terminal
type
JaleEvent* = enum
@ -73,56 +73,53 @@ proc reset(editor: LineEditor) =
editor.lastKeystroke = -1
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
if y == -1:
y = editor.content.Y
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
# moves cursor to current y
for i in countup(0, editor.content.high()):
editor.render(wr, i, false)
editor.render(i, false)
if i < editor.rendered:
wr.down(1)
cursorDown(1)
else:
wr.lf()
write stdout, "\n"
inc editor.rendered
var extraup = 0
while editor.content.len() < editor.rendered:
wr.clearLine()
wr.down(1)
eraseLine()
cursorDown(1)
dec editor.rendered
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
if editor.content.high() > editor.content.Y:
wr.down(editor.content.high() - editor.content.Y)
wr.lf()
cursorDown(editor.content.high() - editor.content.Y)
write stdout, "\n"
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(buffer)
editor.fullRender()
while editor.state == esTyping:
# refresh current line every time
buffer.setCursorX(editor.content.X + editor.prompt.len())
setCursorXPos(editor.content.X + editor.prompt.len())
# get key (with escapes)
buffer.flush()
let key = getKey()
# record y pos
let preY = editor.content.Y
@ -134,19 +131,18 @@ proc read*(editor: LineEditor): string =
if editor.forceRedraw or preY != editor.content.Y:
# move to the top
if preY > 0:
buffer.up(preY)
cursorUp(preY)
# move to the right y
editor.fullRender(buffer)
editor.fullRender()
if editor.forceRedraw:
editor.forceRedraw = false
else:
editor.render(buffer)
editor.render()
editor.events.call(jePostRead)
# move cursor to end
editor.moveCursorToEnd(buffer)
buffer.flush()
editor.moveCursorToEnd()
if editor.state == esFinishing:
result = editor.content.getContent()
editor.reset()

View File

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

View File

@ -25,51 +25,3 @@ else:
proc uniGetChr*: int =
## 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")
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]("")