mirror of https://github.com/japl-lang/jale.git
parent
c913d4657d
commit
ed00e87415
|
@ -1,3 +1,4 @@
|
||||||
examples/interactive
|
|
||||||
examples/editor
|
examples/editor
|
||||||
|
examples/interactive_basic
|
||||||
|
examples/interactive_history
|
||||||
getkey
|
getkey
|
||||||
|
|
19
editor.nim
19
editor.nim
|
@ -13,6 +13,9 @@ type
|
||||||
JaleEvent* = enum
|
JaleEvent* = enum
|
||||||
jeKeypress, jeQuit, jeFinish, jePreRead, jePostRead
|
jeKeypress, jeQuit, jeFinish, jePreRead, jePostRead
|
||||||
|
|
||||||
|
EditorState = enum
|
||||||
|
esOutside, esTyping, esFinishing, esQuitting
|
||||||
|
|
||||||
LineEditor* = ref object
|
LineEditor* = ref object
|
||||||
# permanents
|
# permanents
|
||||||
keystrokes*: Event[int]
|
keystrokes*: Event[int]
|
||||||
|
@ -25,22 +28,22 @@ type
|
||||||
content*: Multiline
|
content*: Multiline
|
||||||
lastKeystroke*: int
|
lastKeystroke*: int
|
||||||
# per-read internals
|
# per-read internals
|
||||||
finished: bool
|
state: EditorState
|
||||||
rendered: int # how many lines were printed last full refresh
|
rendered: int # how many lines were printed last full refresh
|
||||||
forceRedraw: bool
|
forceRedraw: bool
|
||||||
|
|
||||||
# getter/setter sorts
|
# getter/setter sorts
|
||||||
|
|
||||||
proc unfinish*(le: LineEditor) =
|
proc unfinish*(le: LineEditor) =
|
||||||
le.finished = false
|
le.state = esTyping
|
||||||
|
|
||||||
proc finish*(le: LineEditor) =
|
proc finish*(le: LineEditor) =
|
||||||
le.finished = true
|
le.state = esFinishing
|
||||||
# can be overwritten to false, inside the event
|
# can be overwritten to false, inside the event
|
||||||
le.events.call(jeFinish)
|
le.events.call(jeFinish)
|
||||||
|
|
||||||
proc quit*(le: LineEditor) =
|
proc quit*(le: LineEditor) =
|
||||||
le.finished = true
|
le.state = esQuitting
|
||||||
le.events.call(jeQuit)
|
le.events.call(jeQuit)
|
||||||
|
|
||||||
proc forceRedraw*(le: LineEditor) =
|
proc forceRedraw*(le: LineEditor) =
|
||||||
|
@ -57,11 +60,14 @@ proc newLineEditor*: LineEditor =
|
||||||
result.rendered = 0
|
result.rendered = 0
|
||||||
result.lastKeystroke = -1
|
result.lastKeystroke = -1
|
||||||
result.forceRedraw = false
|
result.forceRedraw = false
|
||||||
|
result.state = esOutside
|
||||||
|
|
||||||
# priv/pub methods
|
# priv/pub methods
|
||||||
|
|
||||||
proc reset(editor: LineEditor) =
|
proc reset(editor: LineEditor) =
|
||||||
editor.unfinish()
|
## Resets state to outside, resets internal rendering details
|
||||||
|
## resets last keystroke, creates new contents
|
||||||
|
editor.state = esOutside
|
||||||
editor.rendered = 0
|
editor.rendered = 0
|
||||||
editor.content = newMultiline()
|
editor.content = newMultiline()
|
||||||
editor.lastKeystroke = -1
|
editor.lastKeystroke = -1
|
||||||
|
@ -114,12 +120,13 @@ proc moveCursorToEnd(editor: LineEditor) =
|
||||||
|
|
||||||
proc read*(editor: LineEditor): string =
|
proc read*(editor: LineEditor): string =
|
||||||
|
|
||||||
|
editor.state = esTyping
|
||||||
editor.events.call(jePreRead)
|
editor.events.call(jePreRead)
|
||||||
|
|
||||||
# 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()
|
editor.fullRender()
|
||||||
|
|
||||||
while not editor.finished:
|
while editor.state == esTyping:
|
||||||
|
|
||||||
# refresh current line every time
|
# refresh current line every time
|
||||||
editor.render()
|
editor.render()
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import ../plugin/defaults
|
||||||
|
import ../plugin/history
|
||||||
|
import ../plugin/editor_history
|
||||||
|
import ../editor
|
||||||
|
import ../strutils
|
||||||
|
import ../templates
|
||||||
|
|
||||||
|
var keep = true
|
||||||
|
|
||||||
|
let e = newLineEditor()
|
||||||
|
|
||||||
|
e.bindEvent(jeQuit):
|
||||||
|
keep = false
|
||||||
|
|
||||||
|
e.prompt = "> "
|
||||||
|
e.populateDefaults()
|
||||||
|
let h = e.plugHistory()
|
||||||
|
e.bindHistory(h)
|
||||||
|
|
||||||
|
while keep:
|
||||||
|
let input = e.read()
|
||||||
|
echo "output:<" & input.replace("\n", "\\n") & ">"
|
||||||
|
|
|
@ -1,5 +1,55 @@
|
||||||
import history
|
import history
|
||||||
import ../editor
|
import ../editor
|
||||||
import ../multiline
|
import ../multiline
|
||||||
|
import ../templates
|
||||||
|
|
||||||
|
import options
|
||||||
|
|
||||||
|
proc plugHistory*(ed: LineEditor): History =
|
||||||
|
# adds hooks to events
|
||||||
|
# after reading finished, it adds to history
|
||||||
|
# before reading, it adds the temporary input to the history
|
||||||
|
let hist = newHistory()
|
||||||
|
ed.bindEvent(jeFinish):
|
||||||
|
hist.clean()
|
||||||
|
hist.newEntry(ed.content)
|
||||||
|
|
||||||
|
ed.bindEvent(jePreRead):
|
||||||
|
hist.newEntry(ed.content, temp = true)
|
||||||
|
discard hist.toEnd()
|
||||||
|
|
||||||
|
return hist
|
||||||
|
|
||||||
|
|
||||||
|
proc bindHistory*(ed: LineEditor, h: History, useShift: bool = false) =
|
||||||
|
## Adds history keybindings to editor (up, down, pg up/down)
|
||||||
|
## Works with the history provided
|
||||||
|
## if useShift is true, then the up/down keys and page up/down
|
||||||
|
## will remain free, and shift+up/down and ctrl+pg up/down
|
||||||
|
## will be used
|
||||||
|
|
||||||
|
let upkey = if useShift: "shiftup" else: "up"
|
||||||
|
let downkey = if useShift: "shiftdown" else: "down"
|
||||||
|
let homekey = if useShift: "ctrlpageup" else: "pageup"
|
||||||
|
let endkey = if useShift: "ctrlpagedown" else: "pagedown"
|
||||||
|
|
||||||
|
ed.bindKey(upkey):
|
||||||
|
let res = h.delta(-1)
|
||||||
|
if res.isSome():
|
||||||
|
ed.content = res.get()
|
||||||
|
|
||||||
|
ed.bindKey(downkey):
|
||||||
|
let res = h.delta(1)
|
||||||
|
if res.isSome():
|
||||||
|
ed.content = res.get()
|
||||||
|
|
||||||
|
ed.bindKey(homekey):
|
||||||
|
let res = h.toStart()
|
||||||
|
if res.isSome():
|
||||||
|
ed.content = res.get()
|
||||||
|
|
||||||
|
ed.bindKey(endKey):
|
||||||
|
let res = h.toStart()
|
||||||
|
if res.isSome():
|
||||||
|
ed.content = res.get()
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import ../multiline
|
import ../multiline
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import options
|
||||||
|
|
||||||
type HistoryElement* = ref object
|
type HistoryElement* = ref object
|
||||||
original*: Multiline
|
original*: Multiline
|
||||||
|
@ -20,20 +21,38 @@ proc newHistory*: History =
|
||||||
result.lowestTouchedIndex = 0
|
result.lowestTouchedIndex = 0
|
||||||
result.elements = @[]
|
result.elements = @[]
|
||||||
|
|
||||||
proc delta*(h: History, amt: int): Multiline =
|
template newIndex(h: History): Option[Multiline] =
|
||||||
|
if h.lowestTouchedIndex > h.index:
|
||||||
|
h.lowestTouchedIndex = h.index
|
||||||
|
|
||||||
|
some(h.elements[h.index].current)
|
||||||
|
|
||||||
|
proc delta*(h: History, amt: int): Option[Multiline] =
|
||||||
# move up/down in history and return reference to current
|
# move up/down in history and return reference to current
|
||||||
# also update lowest touched index
|
# also update lowest touched index
|
||||||
|
if h.elements.len() == 0:
|
||||||
|
return none[Multiline]()
|
||||||
|
|
||||||
if h.index + amt <= 0:
|
if h.index + amt <= 0:
|
||||||
h.index = 0
|
h.index = 0
|
||||||
elif h.index + amt >= h.elements.high():
|
elif h.index + amt >= h.elements.high():
|
||||||
h.index = h.elements.high()
|
h.index = h.elements.high()
|
||||||
else:
|
else:
|
||||||
h.index += amt
|
h.index += amt
|
||||||
|
h.newIndex()
|
||||||
|
|
||||||
if h.lowestTouchedIndex > h.index:
|
|
||||||
h.lowestTouchedIndex = h.index
|
|
||||||
|
|
||||||
h.elements[h.index]
|
proc toEnd*(h: History): Option[Multiline] =
|
||||||
|
if h.elements.len() == 0:
|
||||||
|
return none[Multiline]()
|
||||||
|
h.index = h.elements.high()
|
||||||
|
h.newIndex()
|
||||||
|
|
||||||
|
proc toStart*(h: History): Option[Multiline] =
|
||||||
|
if h.elements.len() == 0:
|
||||||
|
return none[Multiline]()
|
||||||
|
h.index = 0
|
||||||
|
h.newIndex()
|
||||||
|
|
||||||
proc clean*(h: History) =
|
proc clean*(h: History) =
|
||||||
# restore originals to current
|
# restore originals to current
|
||||||
|
@ -49,7 +68,7 @@ proc clean*(h: History) =
|
||||||
h.lowestTouchedIndex = h.elements.len()
|
h.lowestTouchedIndex = h.elements.len()
|
||||||
|
|
||||||
proc newEntry*(h: History, ml: Multiline, temp: bool = false) =
|
proc newEntry*(h: History, ml: Multiline, temp: bool = false) =
|
||||||
h.elements.add(History(original: ml, current: ml.copy(), temp: temp))
|
h.elements.add(HistoryElement(original: ml, current: ml.copy(), temp: temp))
|
||||||
|
|
||||||
proc save*(h: History, path: string) =
|
proc save*(h: History, path: string) =
|
||||||
# discards currents and temps, only saves originals
|
# discards currents and temps, only saves originals
|
||||||
|
|
Loading…
Reference in New Issue