mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-14 02:57:52 +08:00
cliedit: Support passing a query callback to edit:listing:start-custom.
This commit is contained in:
parent
db38b32717
commit
51323b609f
|
@ -32,8 +32,8 @@ func initListings(app cli.App, ev *eval.Evaler, ns eval.Ns, st storedefs.Store,
|
|||
"down-cycle": func() { listingDownCycle(app) },
|
||||
"page-up": func() { listingPageUp(app) },
|
||||
"page-down": func() { listingPageDown(app) },
|
||||
"start-custom": func(fm *eval.Frame, opts customListingOpts, items vals.List) {
|
||||
listingStartCustom(app, fm.Evaler, opts, items)
|
||||
"start-custom": func(fm *eval.Frame, opts customListingOpts, items interface{}) {
|
||||
listingStartCustom(app, fm, opts, items)
|
||||
},
|
||||
/*
|
||||
"toggle-filtering": cli.ListingToggleFiltering,
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package cliedit
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/elves/elvish/cli"
|
||||
"github.com/elves/elvish/cli/addons/listing"
|
||||
|
@ -26,41 +29,89 @@ func (*customListingOpts) SetDefaultOptions() {}
|
|||
//
|
||||
// Starts a custom listing addon.
|
||||
|
||||
func listingStartCustom(app cli.App, ev *eval.Evaler, opts customListingOpts, items vals.List) {
|
||||
func listingStartCustom(app cli.App, fm *eval.Frame, opts customListingOpts, items interface{}) {
|
||||
var binding el.Handler
|
||||
if opts.Binding.Map != nil {
|
||||
binding = newMapBinding(app, ev, vars.FromPtr(&opts.Binding))
|
||||
binding = newMapBinding(app, fm.Evaler, vars.FromPtr(&opts.Binding))
|
||||
}
|
||||
var getItems func(string) []listing.Item
|
||||
if fn, isFn := items.(eval.Callable); isFn {
|
||||
getItems = func(q string) []listing.Item {
|
||||
var items []listing.Item
|
||||
var itemsMutex sync.Mutex
|
||||
collect := func(item listing.Item) {
|
||||
itemsMutex.Lock()
|
||||
defer itemsMutex.Unlock()
|
||||
items = append(items, item)
|
||||
}
|
||||
valuesCb := func(ch <-chan interface{}) {
|
||||
for v := range ch {
|
||||
if item, itemOk := getListingItem(v); itemOk {
|
||||
collect(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
bytesCb := func(r *os.File) {
|
||||
buffered := bufio.NewReader(r)
|
||||
for {
|
||||
line, err := buffered.ReadString('\n')
|
||||
if line != "" {
|
||||
s := strings.TrimSuffix(line, "\n")
|
||||
collect(listing.Item{ToAccept: s, ToShow: ui.T(s)})
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
err := fm.CallWithOutputCallback(
|
||||
fn, []interface{}{q}, eval.NoOpts, valuesCb, bytesCb)
|
||||
// TODO(xiaq): Report the error.
|
||||
_ = err
|
||||
return items
|
||||
}
|
||||
} else {
|
||||
getItems = func(q string) []listing.Item {
|
||||
convertedItems := []listing.Item{}
|
||||
vals.Iterate(items, func(v interface{}) bool {
|
||||
toFilter, toFilterOk := getToFilter(v)
|
||||
item, itemOk := getListingItem(v)
|
||||
if toFilterOk && itemOk && strings.Contains(toFilter, q) {
|
||||
// TODO(xiaq): Report type error when ok is false.
|
||||
convertedItems = append(convertedItems, item)
|
||||
}
|
||||
return true
|
||||
})
|
||||
return convertedItems
|
||||
}
|
||||
}
|
||||
|
||||
listing.Start(app, listing.Config{
|
||||
Binding: binding,
|
||||
Caption: opts.Caption,
|
||||
GetItems: func(q string) ([]listing.Item, int) {
|
||||
parsedItems := []listing.Item{}
|
||||
vals.Iterate(items, func(v interface{}) bool {
|
||||
toFilter, item, ok := indexListingItem(v)
|
||||
if ok && strings.Contains(toFilter, q) {
|
||||
// TODO(xiaq): Report type error when ok is false.
|
||||
parsedItems = append(parsedItems, item)
|
||||
}
|
||||
return true
|
||||
})
|
||||
items := getItems(q)
|
||||
selected := 0
|
||||
if opts.KeepBottom {
|
||||
selected = len(parsedItems) - 1
|
||||
selected = len(items) - 1
|
||||
}
|
||||
return parsedItems, selected
|
||||
return items, selected
|
||||
},
|
||||
Accept: func(s string) bool {
|
||||
callWithNotifyPorts(app, ev, opts.Accept, s)
|
||||
callWithNotifyPorts(app, fm.Evaler, opts.Accept, s)
|
||||
return false
|
||||
},
|
||||
AutoAccept: opts.AutoAccept,
|
||||
})
|
||||
}
|
||||
|
||||
func indexListingItem(v interface{}) (toFilter string, item listing.Item, ok bool) {
|
||||
func getToFilter(v interface{}) (string, bool) {
|
||||
toFilterValue, _ := vals.Index(v, "to-filter")
|
||||
toFilter, toFilterOk := toFilterValue.(string)
|
||||
return toFilter, toFilterOk
|
||||
}
|
||||
|
||||
func getListingItem(v interface{}) (item listing.Item, ok bool) {
|
||||
toAcceptValue, _ := vals.Index(v, "to-accept")
|
||||
toAccept, toAcceptOk := toAcceptValue.(string)
|
||||
toShowValue, _ := vals.Index(v, "to-show")
|
||||
|
@ -69,7 +120,5 @@ func indexListingItem(v interface{}) (toFilter string, item listing.Item, ok boo
|
|||
toShow = ui.T(toShowString)
|
||||
toShowOk = true
|
||||
}
|
||||
return toFilter,
|
||||
listing.Item{ToAccept: toAccept, ToShow: toShow},
|
||||
toFilterOk && toAcceptOk && toShowOk
|
||||
return listing.Item{ToAccept: toAccept, ToShow: toShow}, toAcceptOk && toShowOk
|
||||
}
|
||||
|
|
|
@ -81,13 +81,13 @@ func TestLastCmdAddon(t *testing.T) {
|
|||
)
|
||||
}
|
||||
|
||||
func TestCustomListing(t *testing.T) {
|
||||
func TestCustomListing_PassingList(t *testing.T) {
|
||||
f := setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
evals(f.Evaler,
|
||||
`items = [[&to-filter=echo &to-accept=echo &to-show=echo]
|
||||
[&to-filter=put &to-accept=put &to-show=put]]`,
|
||||
`items = [[&to-filter=1 &to-accept=echo &to-show=echo]
|
||||
[&to-filter=2 &to-accept=put &to-show=(styled put green)]]`,
|
||||
`edit:listing:start-custom $items &accept=$edit:insert-at-dot~ &caption=A`)
|
||||
f.TestTTY(t,
|
||||
"~> \n",
|
||||
|
@ -95,11 +95,51 @@ func TestCustomListing(t *testing.T) {
|
|||
"* ", term.DotHere, "\n",
|
||||
"echo \n", Styles,
|
||||
"++++++++++++++++++++++++++++++++++++++++++++++++++",
|
||||
"put",
|
||||
"put ", Styles,
|
||||
"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv",
|
||||
)
|
||||
// Filter - "put" will be selected.
|
||||
f.TTYCtrl.Inject(term.K('2'))
|
||||
// Accept.
|
||||
f.TTYCtrl.Inject(term.K('\n'))
|
||||
f.TestTTY(t,
|
||||
"~> echo", Styles,
|
||||
" vvvv", term.DotHere,
|
||||
"~> put", Styles,
|
||||
" vvv", term.DotHere,
|
||||
)
|
||||
}
|
||||
|
||||
func TestCustomListing_PassingValueCallback(t *testing.T) {
|
||||
f := setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
evals(f.Evaler,
|
||||
`f = [q]{ put [&to-accept='q '$q &to-show=(styled 'q '$q blue)] }`,
|
||||
`edit:listing:start-custom $f &accept=$edit:insert-at-dot~ &caption=A`)
|
||||
// Query.
|
||||
f.TTYCtrl.Inject(term.K('x'))
|
||||
f.TestTTY(t,
|
||||
"~> \n",
|
||||
"A x", Styles,
|
||||
"* ", term.DotHere, "\n",
|
||||
"q x ", Styles,
|
||||
"##################################################",
|
||||
)
|
||||
}
|
||||
|
||||
func TestCustomListing_PassingBytesCallback(t *testing.T) {
|
||||
f := setup()
|
||||
defer f.Cleanup()
|
||||
|
||||
evals(f.Evaler,
|
||||
`f = [q]{ echo 'q '$q }`,
|
||||
`edit:listing:start-custom $f &accept=$edit:insert-at-dot~ &caption=A`)
|
||||
// Query.
|
||||
f.TTYCtrl.Inject(term.K('x'))
|
||||
f.TestTTY(t,
|
||||
"~> \n",
|
||||
"A x", Styles,
|
||||
"* ", term.DotHere, "\n",
|
||||
"q x ", Styles,
|
||||
"++++++++++++++++++++++++++++++++++++++++++++++++++",
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user