Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaq committed Oct 7, 2024
1 parent 4e88016 commit 7aa9e2d
Show file tree
Hide file tree
Showing 23 changed files with 191 additions and 170 deletions.
34 changes: 0 additions & 34 deletions pkg/etk/combobox.go

This file was deleted.

35 changes: 35 additions & 0 deletions pkg/etk/comps/combobox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package comps

import (
"src.elv.sh/pkg/cli/term"
"src.elv.sh/pkg/etk"
)

func ComboBox(c etk.Context) (etk.View, etk.React) {
filterView, filterReact := c.Subcomp("filter", TextArea)
filterBufferVar := etk.BindState(c, "filter/buffer", TextBuffer{})
listView, listReact := c.Subcomp("list", ListBox)
listItemsVar := etk.BindState(c, "list/items", ListItems(nil))
listSelectedVar := etk.BindState(c, "list/selected", 0)

genListVar := etk.State(c, "gen-list", func(string) (ListItems, int) {
return nil, -1
})
lastFilterContentVar := etk.State(c, "-last-filter-content", "")

return etk.VBoxView(0, filterView, listView),
c.WithBinding(func(ev term.Event) etk.Reaction {
if reaction := filterReact(ev); reaction != etk.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)
}
})
}
25 changes: 13 additions & 12 deletions pkg/etk/listbox.go → pkg/etk/comps/listbox.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package etk
package comps

import (
"src.elv.sh/pkg/cli/term"
"src.elv.sh/pkg/etk"
"src.elv.sh/pkg/ui"
)

Expand All @@ -20,10 +21,10 @@ func StringItems(items ...string) ListItems { return stringItems(items) }
func (si stringItems) Show(i int) ui.Text { return ui.T(si[i]) }
func (si stringItems) Len() int { return len(si) }

func ListBox(c Context) (View, React) {
itemsVar := State(c, "items", ListItems(nil))
selectedVar := State(c, "selected", 0)
horizontalVar := State(c, "horizontal", false)
func ListBox(c etk.Context) (etk.View, etk.React) {
itemsVar := etk.State(c, "items", ListItems(nil))
selectedVar := etk.State(c, "selected", 0)
horizontalVar := etk.State(c, "horizontal", false)

selected := selectedVar.Get()
focus := 0
Expand All @@ -46,37 +47,37 @@ func ListBox(c Context) (View, React) {
}
}

return TextView(focus, spans...),
c.WithBinding(func(e term.Event) Reaction {
return etk.TextView(focus, spans...),
c.WithBinding(func(e term.Event) etk.Reaction {
selected := selectedVar.Get()
items := itemsVar.Get()
if horizontalVar.Get() {
switch e {
case term.K(ui.Left):
if selected > 0 {
selectedVar.Set(selected - 1)
return Consumed
return etk.Consumed
}
case term.K(ui.Right):
if selected < items.Len()-1 {
selectedVar.Set(selected + 1)
return Consumed
return etk.Consumed
}
}
} else {
switch e {
case term.K(ui.Up):
if selected > 0 {
selectedVar.Set(selected - 1)
return Consumed
return etk.Consumed
}
case term.K(ui.Down):
if selected < items.Len()-1 {
selectedVar.Set(selected + 1)
return Consumed
return etk.Consumed
}
}
}
return Unused
return etk.Unused
})
}
65 changes: 33 additions & 32 deletions pkg/etk/textarea.go → pkg/etk/comps/textarea.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
package etk
package comps

import (
"strings"
"unicode"
"unicode/utf8"

"src.elv.sh/pkg/cli/term"
"src.elv.sh/pkg/etk"
"src.elv.sh/pkg/parse"
"src.elv.sh/pkg/ui"
)

func TextArea(c Context) (View, React) {
quotePasteVar := State(c, "quote-paste", false)
func TextArea(c etk.Context) (etk.View, etk.React) {
quotePasteVar := etk.State(c, "quote-paste", false)

pastingVar := State(c, "pasting", false)
pasteBufferVar := State(c, "paste-buffer", &strings.Builder{})
pastingVar := etk.State(c, "pasting", false)
pasteBufferVar := etk.State(c, "paste-buffer", &strings.Builder{})
innerView, innerReact := textAreaWithAbbr(c)
bufferVar := BindState(c, "buffer", TextBuffer{})
bufferVar := etk.BindState(c, "buffer", TextBuffer{})

return innerView, c.WithBinding(func(event term.Event) Reaction {
return innerView, c.WithBinding(func(event term.Event) etk.Reaction {
switch event := event.(type) {
case term.PasteSetting:
startPaste := bool(event)
Expand All @@ -36,7 +37,7 @@ func TextArea(c Context) (View, React) {
}
bufferVar.Swap(insertAtDot(text))
}
return Consumed
return etk.Consumed
case term.KeyEvent:
key := ui.Key(event)
if pastingVar.Get() {
Expand All @@ -46,26 +47,26 @@ func TextArea(c Context) (View, React) {
} else {
pasteBufferVar.Get().WriteRune(key.Rune)
}
return Consumed
return etk.Consumed
}
}
return innerReact(event)
})
}

func textAreaWithAbbr(c Context) (View, React) {
abbrVar := State(c, "abbr", func(func(a, f string)) {})
cmdAbbrVar := State(c, "command-abbr", func(func(a, f string)) {})
smallWordAbbr := State(c, "small-word-abbr", func(func(a, f string)) {})
func textAreaWithAbbr(c etk.Context) (etk.View, etk.React) {
abbrVar := etk.State(c, "abbr", func(func(a, f string)) {})
cmdAbbrVar := etk.State(c, "command-abbr", func(func(a, f string)) {})
smallWordAbbr := etk.State(c, "small-word-abbr", func(func(a, f string)) {})

streakVar := State(c, "streak", "")
streakVar := etk.State(c, "streak", "")
innerView, innerReact := textAreaCore(c)
bufferVar := BindState(c, "buffer", TextBuffer{})
return innerView, func(event term.Event) Reaction {
bufferVar := etk.BindState(c, "buffer", TextBuffer{})
return innerView, func(event term.Event) etk.Reaction {
if keyEvent, ok := event.(term.KeyEvent); ok {
bufferBefore := bufferVar.Get()
reaction := innerReact(event)
if reaction != Consumed {
if reaction != etk.Consumed {
return reaction
}
buffer := bufferVar.Get()
Expand All @@ -74,23 +75,23 @@ func textAreaWithAbbr(c Context) (View, React) {
if newBuffer, ok := expandSimpleAbbr(abbrVar.Get(), buffer, streak); ok {
bufferVar.Set(newBuffer)
streakVar.Set("")
return Consumed
return etk.Consumed
}
if newBuffer, ok := expandCmdAbbr(cmdAbbrVar.Get(), buffer, streak); ok {
bufferVar.Set(newBuffer)
streakVar.Set("")
return Consumed
return etk.Consumed
}
if newBuffer, ok := expandSmallWordAbbr(smallWordAbbr.Get(), buffer, streak, keyEvent.Rune, categorizeSmallWord); ok {
bufferVar.Set(newBuffer)
streakVar.Set("")
return Consumed
return etk.Consumed
}
streakVar.Set(streak)
} else {
streakVar.Set("")
}
return Consumed
return etk.Consumed
} else {
return innerReact(event)
}
Expand All @@ -111,12 +112,12 @@ func isLiteralInsert(event term.KeyEvent, before, after TextBuffer) (string, boo
}
}

func textAreaCore(c Context) (View, React) {
promptVar := State(c, "prompt", ui.T(""))
rpromptVar := State(c, "rprompt", ui.T(""))
bufferVar := State(c, "buffer", TextBuffer{})
pendingVar := State(c, "pending", PendingText{})
highlighterVar := State(c, "highlighter",
func textAreaCore(c etk.Context) (etk.View, etk.React) {
promptVar := etk.State(c, "prompt", ui.T(""))
rpromptVar := etk.State(c, "rprompt", ui.T(""))
bufferVar := etk.State(c, "buffer", TextBuffer{})
pendingVar := etk.State(c, "pending", PendingText{})
highlighterVar := etk.State(c, "highlighter",
func(code string) (ui.Text, []ui.Text) { return ui.T(code), nil })

buffer := bufferVar.Get()
Expand All @@ -133,25 +134,25 @@ func textAreaCore(c Context) (View, React) {
promptVar.Get(), rpromptVar.Get(),
styledCode, bufferVar.Get().Dot, tips,
}
return view, func(event term.Event) Reaction {
return view, func(event term.Event) etk.Reaction {
if event, ok := event.(term.KeyEvent); ok {
key := ui.Key(event)
// Implement the absolute essential functionalities here. Others
// can be added via keybindings.
switch key {
case ui.K(ui.Backspace), ui.K('H', ui.Ctrl):
bufferVar.Swap(backspace)
return Consumed
return etk.Consumed
case ui.K(ui.Enter):
return Finish
return etk.Finish
default:
if key == ui.K(ui.Enter, ui.Alt) || (!isFuncKey(key) && unicode.IsGraphic(key.Rune)) {
bufferVar.Swap(insertAtDot(string(key.Rune)))
return Consumed
return etk.Consumed
}
}
}
return Unused
return etk.Unused
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package etk
package comps

import (
"regexp"
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package etk
package comps

import (
"src.elv.sh/pkg/cli/term"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package etk_test
package comps_test

import (
"embed"
Expand All @@ -8,6 +8,7 @@ import (
"src.elv.sh/pkg/cli/term"
"src.elv.sh/pkg/edit/highlight"
"src.elv.sh/pkg/etk"
"src.elv.sh/pkg/etk/comps"
"src.elv.sh/pkg/etk/etktest"
"src.elv.sh/pkg/eval/evaltest"
"src.elv.sh/pkg/eval/vals"
Expand All @@ -24,15 +25,15 @@ func TestTranscripts(t *testing.T) {
})

evaltest.TestTranscriptsInFS(t, transcripts,
"text-area-fixture", etktest.MakeFixture(etk.TextArea),
"text-area-fixture", etktest.MakeFixture(comps.TextArea),
"text-area-demo-fixture", etktest.MakeFixture(
etk.WithInit(etk.TextArea,
etk.WithInit(comps.TextArea,
"binding", func(ev term.Event, c etk.Context, r etk.React) etk.Reaction {
reaction := r(ev)
if reaction != etk.Unused {
return reaction
}
bufferVar := etk.BindState(c, "buffer", etk.TextBuffer{})
bufferVar := etk.BindState(c, "buffer", comps.TextBuffer{})
switch ev {
case term.K(ui.Left):
bufferVar.Swap(makeMove(moveDotLeft))
Expand Down Expand Up @@ -63,8 +64,8 @@ func TestTranscripts(t *testing.T) {

// For demo

func makeMove(m func(string, int) int) func(etk.TextBuffer) etk.TextBuffer {
return func(buf etk.TextBuffer) etk.TextBuffer {
func makeMove(m func(string, int) int) func(comps.TextBuffer) comps.TextBuffer {
return func(buf comps.TextBuffer) comps.TextBuffer {
buf.Dot = m(buf.Content, buf.Dot)
return buf
}
Expand Down
22 changes: 20 additions & 2 deletions pkg/etk/etk.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
package etk

import (
"fmt"
"reflect"
"slices"
"strings"
Expand Down Expand Up @@ -335,7 +336,24 @@ func (sv StateVar[T]) setAny(v any) {
func (sv StateVar[T]) get() any { return getPath(*sv.state, sv.path) }
func (sv StateVar[T]) set(v any) { *sv.state = assocPath(*sv.state, sv.path, v) }

func getPath(m vals.Map, path []string) any {
type StateSubTreeVar Context

func (v StateSubTreeVar) Get() any {
return getPath(v.g.state, v.path)
}

func (v StateSubTreeVar) Set(val any) error {
valMap, ok := val.(vals.Map)
if !ok {
return fmt.Errorf("must be map")
}
v.g.state = assocPath(v.g.state, v.path, valMap)
return nil
}

// TODO: Move the following to vals?

func getPath[T any](m vals.Map, path []T) any {
if len(path) == 0 {
return m
}
Expand All @@ -351,7 +369,7 @@ func getPath(m vals.Map, path []string) any {
return v
}

func assocPath(m vals.Map, path []string, newVal any) vals.Map {
func assocPath[T any](m vals.Map, path []T, newVal any) vals.Map {
if len(path) == 0 {
return newVal.(vals.Map)
}
Expand Down
Loading

0 comments on commit 7aa9e2d

Please sign in to comment.