mirror of
https://github.com/daylinmorgan/hwylterm.git
synced 2024-12-21 02:30:44 -06:00
implement an interactive "chooser"
This commit is contained in:
parent
398b77cc2b
commit
38b1854c12
5 changed files with 153 additions and 5 deletions
|
@ -12,7 +12,8 @@ task docs, "Deploy doc html + search index to public/ directory":
|
|||
deployDir = getCurrentDir() / "public"
|
||||
pkgName = "hwylterm"
|
||||
gitUrl = fmt"https://github.com/daylinmorgan/{pkgName}"
|
||||
selfExec fmt"doc --docRoot:{getCurrentDir()}/src/ --index:on --outdir:{deployDir} src/hwylterm/cli"
|
||||
for module in ["cli", "chooser"]:
|
||||
selfExec fmt"doc --docRoot:{getCurrentDir()}/src/ --index:on --outdir:{deployDir} src/hwylterm/{module}"
|
||||
selfExec fmt"doc --project --index:on --git.url:{gitUrl} --git.commit:main --outdir:{deployDir} --project src/{pkgName}.nim"
|
||||
withDir deployDir:
|
||||
mvFile(pkgName & ".html", "index.html")
|
||||
|
@ -24,3 +25,4 @@ task docs, "Deploy doc html + search index to public/ directory":
|
|||
|
||||
when withDir(thisDir(), system.dirExists("nimbledeps")):
|
||||
--path:"./nimbledeps/pkgs2/cligen-1.7.5-f3ffe7329c8db755677d3ca377d02ff176cec8b1"
|
||||
--path:"./nimbledeps/pkgs2/illwill-0.4.1-9c58351502f89a16caf031cbd1992ad3fdfd3c67"
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
##[
|
||||
# Hwylterm
|
||||
|
||||
[see bbansi](./hwylterm/bbansi.html)
|
||||
[see cli](./hwylterm/cli.html)
|
||||
see also these utility modules:
|
||||
|
||||
- [cli](./hwylterm/cli.html), requires [cligen](https://github.com/c-blake/cligen)
|
||||
- [chooser](./hwylterm/chooser.html), requires [illwill](https://github.com/johnnovak/illwill)
|
||||
]##
|
||||
|
||||
import hwylterm/[spin, bbansi]
|
||||
|
|
139
src/hwylterm/chooser.nim
Normal file
139
src/hwylterm/chooser.nim
Normal file
|
@ -0,0 +1,139 @@
|
|||
##[
|
||||
# Hwylterm Chooser
|
||||
|
||||
```nim
|
||||
import hwylterm/chooser
|
||||
|
||||
let items = ["a","b","c"]
|
||||
let item = choose(items)
|
||||
```
|
||||
]##
|
||||
|
||||
|
||||
import std/[enumerate, os, strutils, sequtils, sets, terminal]
|
||||
|
||||
template canImport(x): bool = compiles: import x
|
||||
when not canImport(illwill): {.fatal: "hwylterm/choose requires illwill >= 0.4.1".}
|
||||
import illwill
|
||||
|
||||
|
||||
proc exitProc() {.noconv.} =
|
||||
illwillDeInit()
|
||||
showCursor()
|
||||
|
||||
proc quitProc() {.noconv.} =
|
||||
exitProc()
|
||||
quit(0)
|
||||
|
||||
type
|
||||
State = object
|
||||
lastKey: Key
|
||||
buffer: string
|
||||
selections: HashSet[Natural]
|
||||
height, max, pos, low, high: Natural
|
||||
|
||||
func newState[T](things: openArray[T], height: Natural): State =
|
||||
result.max = len(things) - 1
|
||||
result.height = height
|
||||
result.high = height
|
||||
|
||||
func up(s: var State) =
|
||||
if s.pos > 0: dec s.pos
|
||||
if (s.pos < s.low):
|
||||
dec s.low
|
||||
dec s.high
|
||||
|
||||
func down(s: var State) =
|
||||
if s.pos < s.max:
|
||||
inc s.pos
|
||||
if ((s.pos - s.low) > s.height) and
|
||||
(s.pos > s.high) and
|
||||
(s.high < s.max):
|
||||
inc s.low
|
||||
inc s.high
|
||||
|
||||
func pressed(s: var State, k: Key) = s.lastKey = k
|
||||
|
||||
func select(s: var State ) =
|
||||
s.selections =
|
||||
symmetricDifference(s.selections, toHashSet([s.pos]))
|
||||
|
||||
proc clip(s: string, length: int): string =
|
||||
if s.len > length: s[0..length]
|
||||
else: s
|
||||
|
||||
# proc addHelp(s: var screen) =
|
||||
|
||||
func addThingsWindow[T](state: var State, things: openArray[T]) =
|
||||
var window: string
|
||||
for i, t in enumerate(things[state.low..state.high]):
|
||||
window.add (
|
||||
if (i + state.low) == state.pos: ">"
|
||||
else: " "
|
||||
)
|
||||
window.add (
|
||||
if (i + state.low) in state.selections: ">"
|
||||
else: " "
|
||||
)
|
||||
window.add $t
|
||||
window.add "\n"
|
||||
state.buffer.add window
|
||||
|
||||
|
||||
proc draw(s: var State) =
|
||||
let maxWidth = terminalWidth()
|
||||
var lines= (
|
||||
s.buffer.splitLines().mapIt((" " & it).clip(maxWidth).alignLeft(maxWidth))
|
||||
)
|
||||
when defined(debugChoose):
|
||||
lines = @[$s] & lines
|
||||
|
||||
for l in lines:
|
||||
stdout.writeLine l
|
||||
|
||||
cursorUp lines.len
|
||||
flushFile stdout
|
||||
s.buffer = ""
|
||||
|
||||
proc getSelections[T](state: State, things: openArray[T]): seq[T] =
|
||||
if state.selections.len == 0:
|
||||
result.add things[state.pos]
|
||||
for i in state.selections:
|
||||
result.add things[i]
|
||||
|
||||
|
||||
proc choose*[T](things: openArray[T], height: Natural = 6): seq[T] =
|
||||
illwillInit(fullscreen = false)
|
||||
setControlCHook(quitProc)
|
||||
hideCursor()
|
||||
|
||||
var state = newState(things, height)
|
||||
|
||||
while true:
|
||||
var key = getKey()
|
||||
pressed(state, key)
|
||||
case key:
|
||||
of Key.None: discard
|
||||
of Key.Down, Key.J:
|
||||
down state
|
||||
of Key.Up, Key.K:
|
||||
up state
|
||||
of Key.Tab:
|
||||
select state
|
||||
of Key.Enter:
|
||||
exitProc()
|
||||
return getSelections(state, things)
|
||||
else: discard
|
||||
|
||||
addThingsWindow(state, things)
|
||||
draw state
|
||||
sleep 20
|
||||
|
||||
|
||||
when isMainModule:
|
||||
let items = LowercaseLetters.toSeq()
|
||||
let item = choose(items)
|
||||
echo "selected: ", item
|
||||
|
||||
|
||||
|
|
@ -4,8 +4,10 @@
|
|||
Adapter to add hwylterm colors to cligen output.
|
||||
]##
|
||||
import std/[tables]
|
||||
import cligen
|
||||
import ./bbansi
|
||||
template canImport(x): bool = compiles: import x
|
||||
when not canImport(cligen): {.fatal: "hwylterm/cli requires cligen>= 1.7.5".}
|
||||
import cligen
|
||||
|
||||
|
||||
type
|
||||
|
|
|
@ -5,7 +5,10 @@ author = "Daylin Morgan"
|
|||
description = "bringing some fun (hwyl) to the terminal"
|
||||
license = "MIT"
|
||||
srcDir = "../src"
|
||||
namedBin = {"hwylterm/bbansi":"bbansi"}.toTable
|
||||
namedBin = {
|
||||
"hwylterm/bbansi" :"bbansi",
|
||||
"hwylterm/chooser":"hwylchoose"
|
||||
}.toTable
|
||||
|
||||
|
||||
requires "nim >= 2.0.8"
|
||||
|
|
Loading…
Reference in a new issue