use terminal
This commit is contained in:
parent
85cf1d0581
commit
82b18c1cd4
11
jale.nimble
11
jale.nimble
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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]("")
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue