-
-
Notifications
You must be signed in to change notification settings - Fork 300
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce pkg/etk, a new TUI framework.
The framework has the following interesting features: - It has a first-class Elvish binding with the same expressive power as the Go version of the framework. - It has an immediate-mode API, meaning that a component is represented by a function that gets invoked every time the state changes. For more on the motivation and tradeoffs of the design, see the slidedeck in website/slides/draft-etk.md. This package will eventually replace pkg/cli/tk as Elvish's internal TUI framework, and Elvish's TUI will be rewritten to use it.
- Loading branch information
Showing
68 changed files
with
5,088 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use etk | ||
|
||
# mkdir prompt - what can be done today: | ||
var w | ||
set w = (edit:new-codearea [&prompt=(styled 'mkdir:' inverse)' ' &on-submit={ mkdir (edit:get-state $w)[buffer][content] }]) | ||
edit:push-addon $w | ||
|
||
# mkdir prompt - slightly cleaned up version | ||
edit:push-addon (etk:new-codearea [&prompt='mkdir: ' &on-submit={|s| mkdir $s[buffer][content] }]) | ||
|
||
# mkdir prompt - state management version | ||
var dirname | ||
edit:push-addon { | ||
etk:textbox [&prompt='mkdir: ' &on-submit={ mkdir $dirname }] ^ | ||
[&buffer=[&content=(bind dirname)]] | ||
} | ||
|
||
# Temperature conversion | ||
var c = '' | ||
etk:run-app { | ||
var f = (/ (- $c 32) 1.8) | ||
etk:vbox [&children=[ | ||
(etk:textbox [&prompt='input: '] [&buffer=[&content=(bind c)]]) | ||
(etk:label $c' ℉ = '$f' ℃') | ||
]] | ||
} | ||
|
||
# Elvish configuration helper | ||
var tasks = [ | ||
[&name='Use readline binding' | ||
&detail='Readline binding enables keys like Ctrl-N, Ctrl-F' | ||
&eval-code='' | ||
&rc-code='use readline-binding'] | ||
|
||
[&name='Install Carapace' | ||
&detail='Carapace provides completions.' | ||
&eval-code='brew install carapace' | ||
&rc-code='eval (carapace init elvish)'] | ||
] | ||
|
||
fn execute-task {|task| | ||
eval $task[eval-code] | ||
eval $task[rc-code] | ||
echo $task[rc-code] >> $runtime:rc-file | ||
} | ||
|
||
var i = (num 0) | ||
etk:run-app { | ||
etk:hbox [&children=[ | ||
(etk:list [&items=$tasks &display={|t| put $t[name]} &on-submit=$execute-task~] ^ | ||
[&selected=(bind i)]) | ||
(etk:label $tasks[i][detail]) | ||
]] | ||
} | ||
|
||
# Markdown-driven presentation | ||
var filename = 'a.md' | ||
var @slides = (slurp < $filename | | ||
re:split '\n {0,3}((?:-[ \t]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})\n' (one)) | ||
|
||
var i = (num 0) | ||
etk:run-app { | ||
etk:vbox [ | ||
&binding=[&Left={|_| set i = (- $i 1) } &Right={|_| set i = (+ $i 1) }] | ||
&children=[ | ||
(etk:label $slides[i]) | ||
(etk:label (+ 1 $i)/(count $slides)) | ||
] | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package edit | ||
|
||
import ( | ||
"src.elv.sh/pkg/cli" | ||
"src.elv.sh/pkg/eval" | ||
) | ||
|
||
func initCustomWidgetAPI(app cli.App, nb eval.NsBuilder) { | ||
nb.AddGoFns(map[string]any{ | ||
"push-addon": app.PushAddon, | ||
"pop-addon": app.PopAddon, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package etk | ||
|
||
import ( | ||
"src.elv.sh/pkg/cli/term" | ||
) | ||
|
||
func ComboBox(c Context) (View, React) { | ||
filterView, filterReact := c.Subcomp("filter", TextArea) | ||
filterBufferVar := BindState(c, "filter/buffer", TextBuffer{}) | ||
listView, listReact := c.Subcomp("list", ListBox) | ||
listItemsVar := BindState(c, "list/items", ListItems(nil)) | ||
listSelectedVar := BindState(c, "list/selected", 0) | ||
|
||
genListVar := State(c, "gen-list", func(string) (ListItems, int) { | ||
return nil, -1 | ||
}) | ||
lastFilterContentVar := State(c, "-last-filter-content", "") | ||
|
||
return VBoxView(0, filterView, listView), | ||
c.WithBinding(func(ev term.Event) Reaction { | ||
if reaction := filterReact(ev); reaction != Unused { | ||
filterContent := filterBufferVar.Get().Content | ||
if filterContent != lastFilterContentVar.Get() { | ||
lastFilterContentVar.Set(filterContent) | ||
items, selected := genListVar.Get()(filterContent) | ||
listItemsVar.Set(items) | ||
listSelectedVar.Set(selected) | ||
} | ||
return reaction | ||
} else { | ||
return listReact(ev) | ||
} | ||
}) | ||
} |
Oops, something went wrong.