edit: Factor out filtering stage of completion.

This commit is contained in:
Qi Xiao 2017-12-18 13:31:15 +00:00
parent 2abf1cf358
commit b64227e498
6 changed files with 51 additions and 124 deletions

View File

@ -67,29 +67,8 @@ func evalFormPure(form *parse.Form, seed string, seedBegin int, ev pureEvaler) [
// To complete an argument, delegate the actual completion work to a suitable
// complContext.
func (ctx *argComplContext) complete(ev *eval.Evaler, matcher eval.CallableValue) (*complSpec, error) {
rawCands := make(chan rawCandidate)
collectErr := make(chan error)
go func() {
var err error
defer func() {
close(rawCands)
collectErr <- err
}()
err = completeArg(ctx.words, ev, rawCands)
}()
cands, err := ev.Editor.(*Editor).filterAndCookCandidates(
ev, matcher, ctx.seed, rawCands, ctx.quoting)
if ce := <-collectErr; ce != nil {
return nil, ce
}
if err != nil {
return nil, err
}
return &complSpec{ctx.begin, ctx.end, cands}, nil
func (ctx *argComplContext) generate(ev *eval.Evaler, ch chan<- rawCandidate) error {
return completeArg(ctx.words, ev, ch)
}
// TODO: getStyle does redundant stats.

View File

@ -55,28 +55,8 @@ func findCommandComplContext(n parse.Node, ev pureEvaler) complContext {
func (*commandComplContext) name() string { return "command" }
func (ctx *commandComplContext) complete(ev *eval.Evaler, matcher eval.CallableValue) (*complSpec, error) {
rawCands := make(chan rawCandidate)
collectErr := make(chan error)
go func() {
var err error
defer func() {
close(rawCands)
collectErr <- err
}()
err = complFormHeadInner(ctx.seed, ev, rawCands)
}()
cands, err := ev.Editor.(*Editor).filterAndCookCandidates(
ev, matcher, ctx.seed, rawCands, ctx.quoting)
if ce := <-collectErr; ce != nil {
return nil, ce
}
if err != nil {
return nil, err
}
return &complSpec{ctx.begin, ctx.end, cands}, nil
func (ctx *commandComplContext) generate(ev *eval.Evaler, ch chan<- rawCandidate) error {
return complFormHeadInner(ctx.seed, ev, ch)
}
func complFormHeadInner(head string, ev *eval.Evaler, rawCands chan<- rawCandidate) error {

View File

@ -79,31 +79,19 @@ func findIndexComplContext(n parse.Node, ev pureEvaler) complContext {
return nil
}
func (ctx *indexComplContext) complete(ev *eval.Evaler, matcher eval.CallableValue) (*complSpec, error) {
func (ctx *indexComplContext) generate(ev *eval.Evaler, ch chan<- rawCandidate) error {
m, ok := ctx.indexee.(eval.IterateKeyer)
if !ok {
return nil, errCannotIterateKey
return errCannotIterateKey
}
rawCands := make(chan rawCandidate)
go func() {
defer close(rawCands)
complIndexInner(m, rawCands)
}()
cands, err := ev.Editor.(*Editor).filterAndCookCandidates(
ev, matcher, ctx.seed, rawCands, ctx.quoting)
if err != nil {
return nil, err
}
return &complSpec{ctx.begin, ctx.end, cands}, nil
complIndexInner(m, ch)
return nil
}
func complIndexInner(m eval.IterateKeyer, rawCands chan rawCandidate) {
func complIndexInner(m eval.IterateKeyer, ch chan<- rawCandidate) {
m.IterateKey(func(v eval.Value) bool {
if keyv, ok := v.(eval.String); ok {
rawCands <- plainCandidate(keyv)
ch <- plainCandidate(keyv)
}
return true
})

View File

@ -29,28 +29,6 @@ func findRedirComplContext(n parse.Node, ev pureEvaler) complContext {
return nil
}
func (ctx *redirComplContext) complete(ev *eval.Evaler, matcher eval.CallableValue) (*complSpec, error) {
rawCands := make(chan rawCandidate)
collectErr := make(chan error)
go func() {
var err error
defer func() {
close(rawCands)
collectErr <- err
}()
err = complFilenameInner(ctx.seed, false, rawCands)
}()
cands, err := ev.Editor.(*Editor).filterAndCookCandidates(
ev, matcher, ctx.seed, rawCands, ctx.quoting)
if ce := <-collectErr; ce != nil {
return nil, ce
}
if err != nil {
return nil, err
}
return &complSpec{ctx.begin, ctx.end, cands}, nil
func (ctx *redirComplContext) generate(ev *eval.Evaler, ch chan<- rawCandidate) error {
return complFilenameInner(ctx.seed, false, ch)
}

View File

@ -34,42 +34,31 @@ func findVariableComplContext(n parse.Node, _ pureEvaler) complContext {
return nil
}
func (ctx *variableComplContext) complete(ev *eval.Evaler, matcher eval.CallableValue) (*complSpec, error) {
rawCands := make(chan rawCandidate)
go func() {
defer close(rawCands)
func (ctx *variableComplContext) generate(ev *eval.Evaler, ch chan<- rawCandidate) error {
// Collect matching variables.
iterateVariables(ev, ctx.ns, func(varname string) {
rawCands <- noQuoteCandidate(varname)
})
// Collect matching variables.
iterateVariables(ev, ctx.ns, func(varname string) {
ch <- noQuoteCandidate(varname)
})
seenMod := func(mod string) {
modNsPart := mod + ":"
// This is to match namespaces that are "nested" under the current
// namespace.
if hasProperPrefix(modNsPart, ctx.nsPart) {
rawCands <- noQuoteCandidate(modNsPart[len(ctx.nsPart):])
}
seenMod := func(mod string) {
modNsPart := mod + ":"
// This is to match namespaces that are "nested" under the current
// namespace.
if hasProperPrefix(modNsPart, ctx.nsPart) {
ch <- noQuoteCandidate(modNsPart[len(ctx.nsPart):])
}
// Collect namespace prefixes.
// TODO Support non-module namespaces.
for mod := range ev.Global.Uses {
seenMod(mod)
}
for mod := range ev.Builtin.Uses {
seenMod(mod)
}
}()
cands, err := ev.Editor.(*Editor).filterAndCookCandidates(ev, matcher, ctx.seed,
rawCands, parse.Bareword)
if err != nil {
return nil, err
}
return &complSpec{ctx.begin, ctx.end, cands}, nil
// Collect namespace prefixes.
// TODO Support non-module namespaces.
for mod := range ev.Global.Uses {
seenMod(mod)
}
for mod := range ev.Builtin.Uses {
seenMod(mod)
}
return nil
}
func hasProperPrefix(s, p string) bool {

View File

@ -34,12 +34,13 @@ package edit
import (
"github.com/elves/elvish/eval"
"github.com/elves/elvish/parse"
"github.com/elves/elvish/util"
)
type complContext interface {
name() string
common() *complContextCommon
complete(ev *eval.Evaler, matcher eval.CallableValue) (*complSpec, error)
generate(*eval.Evaler, chan<- rawCandidate) error
}
type complContextCommon struct {
@ -83,19 +84,31 @@ var complContextFinders = []complContextFinder{
func complete(n parse.Node, ev *eval.Evaler) (string, *complSpec, error) {
ed := ev.Editor.(*Editor)
for _, finder := range complContextFinders {
complContext := finder(n, ev)
if complContext == nil {
ctx := finder(n, ev)
if ctx == nil {
continue
}
name := complContext.name()
name := ctx.name()
ctxCommon := ctx.common()
matcher, ok := ed.lookupMatcher(name)
if !ok {
return name, nil, errMatcherMustBeFn
}
ctx, err := complContext.complete(ev, matcher)
return name, ctx, err
chanRawCandidate := make(chan rawCandidate)
chanErrGenerate := make(chan error)
go func() {
err := ctx.generate(ev, chanRawCandidate)
close(chanRawCandidate)
chanErrGenerate <- err
}()
candidates, errFilter := ev.Editor.(*Editor).filterAndCookCandidates(
ev, matcher, ctxCommon.seed, chanRawCandidate, ctxCommon.quoting)
spec := &complSpec{ctxCommon.begin, ctxCommon.end, candidates}
return name, spec, util.Errors(<-chanErrGenerate, errFilter)
}
return "", nil, nil
}