Support completion of commands

This commit is contained in:
Cheer Xiao 2015-07-06 17:58:51 +02:00
parent f52e1760b0
commit 8794232b26
4 changed files with 47 additions and 22 deletions

View File

@ -6,6 +6,7 @@ import (
"path"
"strings"
"github.com/elves/elvish/eval"
"github.com/elves/elvish/parse"
)
@ -58,8 +59,8 @@ func (c *completion) next(cycle bool) {
}
}
func findCandidates(p string, all []string) (cands []*candidate) {
// Prefix match
// Find candidates by matching against a prefix.
func prefixMatchCandidates(p string, all []string) (cands []*candidate) {
for _, s := range all {
if len(s) >= len(p) && s[:len(p)] == p {
cand := newCandidate()
@ -117,6 +118,8 @@ func peekCurrentCompound(ctx *parse.Context, dot int) (string, int, error) {
}
switch ctx.Typ {
case parse.CommandContext:
return peekIncompleteCompound(ctx.Form.Command)
case parse.ArgContext:
compounds := ctx.Form.Args.Nodes
lastCompound := compounds[len(compounds)-1]
@ -134,6 +137,13 @@ func peekCurrentCompound(ctx *parse.Context, dot int) (string, int, error) {
}
}
var builtins []string
func init() {
builtins = append(builtins, eval.BuiltinFnNames...)
builtins = append(builtins, eval.BuiltinSpecialNames...)
}
func startCompletion(ed *Editor, k Key) *leReturn {
c := &completion{}
ctx, err := parse.Complete("<completion>", ed.line[:ed.dot])
@ -152,8 +162,13 @@ func startCompletion(ed *Editor, k Key) *leReturn {
switch ctx.Typ {
case parse.CommandContext:
// BUG(xiaq): When completing, CommandContext is not supported
ed.pushTip("command context not yet supported :(")
// BUG(xiaq): When completing commands, only builtins are searched
findAll = func() ([]string, error) {
return builtins, nil
}
makeCandidates = func(all []string) (cands []*candidate) {
return prefixMatchCandidates(compound, all)
}
case parse.NewArgContext, parse.ArgContext:
// BUG(xiaq): When completing, [New]ArgContext is treated like RedirFilenameContext
fallthrough

View File

@ -353,36 +353,38 @@ func (w *writer) refresh(bs *editorState) error {
}
comp := bs.completion
var suppress = false
hasComp := comp != nil && comp.current != -1
nowAt := func(i int) {
if hasComp && comp.start == i {
// Put the current completion candidate.
for _, part := range comp.candidates[comp.current].parts {
attr := attrForType[comp.typ]
if part.completed {
attr += attrForCompleted
}
b.writes(part.text, attr)
}
}
if bs.dot == i {
b.dot = b.cursor()
}
}
nowAt(0)
tokens:
for _, token := range bs.tokens {
for _, r := range token.Val {
if suppress && i < comp.end {
if hasComp && comp.start <= i && i < comp.end {
// Silence the part that is being completed
} else {
b.write(r, attrForType[token.Typ])
}
i += utf8.RuneLen(r)
if comp != nil && comp.current != -1 && i == comp.start {
// Put the current candidate and instruct text up to comp.end
// to be suppressed. The cursor should be placed correctly
// (i.e. right after the candidate)
for _, part := range comp.candidates[comp.current].parts {
attr := attrForType[comp.typ]
if part.completed {
attr += attrForCompleted
}
b.writes(part.text, attr)
}
suppress = true
}
nowAt(i)
if bs.mode == modeHistory && i == len(bs.history.prefix) {
break tokens
}
if bs.dot == i {
b.dot = b.cursor()
}
}
}

View File

@ -13,6 +13,7 @@ import (
)
var builtinFns []*builtinFn
var BuiltinFnNames []string
func init() {
// Needed to work around init loop.
@ -51,6 +52,9 @@ func init() {
&builtinFn{"=", eq},
}
for _, b := range builtinFns {
BuiltinFnNames = append(BuiltinFnNames, b.Name)
}
}
var (

View File

@ -19,6 +19,7 @@ type builtinSpecial struct {
}
var builtinSpecials map[string]builtinSpecial
var BuiltinSpecialNames []string
func init() {
// Needed to avoid initialization loop
@ -34,6 +35,9 @@ func init() {
"static-typeof": builtinSpecial{compileStaticTypeof},
}
for k, _ := range builtinSpecials {
BuiltinSpecialNames = append(BuiltinSpecialNames, k)
}
}
func mayAssign(tvar, tval Type) bool {