History plugin finished

not extensively tested yet
This commit is contained in:
Productive2 2021-02-18 23:58:47 +01:00
parent c913d4657d
commit ed00e87415
6 changed files with 112 additions and 12 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
examples/interactive
examples/editor
examples/interactive_basic
examples/interactive_history
getkey

View File

@ -13,6 +13,9 @@ type
JaleEvent* = enum
jeKeypress, jeQuit, jeFinish, jePreRead, jePostRead
EditorState = enum
esOutside, esTyping, esFinishing, esQuitting
LineEditor* = ref object
# permanents
keystrokes*: Event[int]
@ -25,22 +28,22 @@ type
content*: Multiline
lastKeystroke*: int
# per-read internals
finished: bool
state: EditorState
rendered: int # how many lines were printed last full refresh
forceRedraw: bool
# getter/setter sorts
proc unfinish*(le: LineEditor) =
le.finished = false
le.state = esTyping
proc finish*(le: LineEditor) =
le.finished = true
le.state = esFinishing
# can be overwritten to false, inside the event
le.events.call(jeFinish)
proc quit*(le: LineEditor) =
le.finished = true
le.state = esQuitting
le.events.call(jeQuit)
proc forceRedraw*(le: LineEditor) =
@ -57,11 +60,14 @@ proc newLineEditor*: LineEditor =
result.rendered = 0
result.lastKeystroke = -1
result.forceRedraw = false
result.state = esOutside
# priv/pub methods
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.content = newMultiline()
editor.lastKeystroke = -1
@ -114,12 +120,13 @@ proc moveCursorToEnd(editor: LineEditor) =
proc read*(editor: LineEditor): string =
editor.state = esTyping
editor.events.call(jePreRead)
# starts at the top, full render moves it into the right y
editor.fullRender()
while not editor.finished:
while editor.state == esTyping:
# refresh current line every time
editor.render()

View File

@ -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") & ">"

View File

@ -1,5 +1,55 @@
import history
import ../editor
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()

View File

@ -3,6 +3,7 @@
import ../multiline
import os
import options
type HistoryElement* = ref object
original*: Multiline
@ -20,20 +21,38 @@ proc newHistory*: History =
result.lowestTouchedIndex = 0
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
# also update lowest touched index
if h.elements.len() == 0:
return none[Multiline]()
if h.index + amt <= 0:
h.index = 0
elif h.index + amt >= h.elements.high():
h.index = h.elements.high()
else:
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) =
# restore originals to current
@ -49,7 +68,7 @@ proc clean*(h: History) =
h.lowestTouchedIndex = h.elements.len()
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) =
# discards currents and temps, only saves originals