Add logic to complete when last flag uses the equal sign
If the last flag is of the form -flag=value, complete the value according to -flag.
This commit is contained in:
parent
88e59760ad
commit
aae7e1e39f
43
args.go
43
args.go
|
@ -3,6 +3,8 @@ package complete
|
|||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Args describes command line arguments
|
||||
|
@ -37,16 +39,41 @@ func (a Args) Directory() string {
|
|||
return fixPathForm(a.Last, dir)
|
||||
}
|
||||
|
||||
func newArgs(line []string) Args {
|
||||
completed := removeLast(line[1:])
|
||||
func newArgs(line string) Args {
|
||||
var (
|
||||
all []string
|
||||
completed []string
|
||||
)
|
||||
parts := splitFields(line)
|
||||
if len(parts) > 0 {
|
||||
all = parts[1:]
|
||||
completed = removeLast(parts[1:])
|
||||
}
|
||||
return Args{
|
||||
All: line[1:],
|
||||
All: all,
|
||||
Completed: completed,
|
||||
Last: last(line),
|
||||
Last: last(parts),
|
||||
LastCompleted: last(completed),
|
||||
}
|
||||
}
|
||||
|
||||
func splitFields(line string) []string {
|
||||
parts := strings.Fields(line)
|
||||
if len(line) > 0 && unicode.IsSpace(rune(line[len(line)-1])) {
|
||||
parts = append(parts, "")
|
||||
}
|
||||
parts = splitLastEqual(parts)
|
||||
return parts
|
||||
}
|
||||
|
||||
func splitLastEqual(line []string) []string {
|
||||
if len(line) == 0 {
|
||||
return line
|
||||
}
|
||||
parts := strings.Split(line[len(line)-1], "=")
|
||||
return append(line[:len(line)-1], parts...)
|
||||
}
|
||||
|
||||
func (a Args) from(i int) Args {
|
||||
if i > len(a.All) {
|
||||
i = len(a.All)
|
||||
|
@ -67,9 +94,9 @@ func removeLast(a []string) []string {
|
|||
return a
|
||||
}
|
||||
|
||||
func last(args []string) (last string) {
|
||||
if len(args) > 0 {
|
||||
last = args[len(args)-1]
|
||||
func last(args []string) string {
|
||||
if len(args) == 0 {
|
||||
return ""
|
||||
}
|
||||
return
|
||||
return args[len(args)-1]
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ func TestArgs(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.line, func(t *testing.T) {
|
||||
|
||||
a := newArgs(strings.Split(tt.line, " "))
|
||||
a := newArgs(tt.line)
|
||||
|
||||
if got, want := strings.Join(a.Completed, " "), tt.completed; got != want {
|
||||
t.Errorf("%s failed: Completed = %q, want %q", t.Name(), got, want)
|
||||
|
@ -131,7 +131,7 @@ func TestArgs_From(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%s/%d", tt.line, tt.from), func(t *testing.T) {
|
||||
|
||||
a := newArgs(strings.Split(tt.line, " "))
|
||||
a := newArgs(tt.line)
|
||||
n := a.from(tt.from)
|
||||
|
||||
if got, want := strings.Join(n.All, " "), tt.newLine; got != want {
|
||||
|
@ -205,7 +205,7 @@ func TestArgs_Directory(t *testing.T) {
|
|||
for _, tt := range tests {
|
||||
t.Run(tt.line, func(t *testing.T) {
|
||||
|
||||
a := newArgs(strings.Split(tt.line, " "))
|
||||
a := newArgs(tt.line)
|
||||
|
||||
if got, want := a.Directory(), tt.directory; got != want {
|
||||
t.Errorf("%s failed: directory = %q, want %q", t.Name(), got, want)
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/posener/complete/cmd"
|
||||
)
|
||||
|
@ -61,7 +60,7 @@ func (c *Complete) Complete() bool {
|
|||
Log("Completing line: %s", line)
|
||||
|
||||
a := newArgs(line)
|
||||
|
||||
Log("Completing last field: %s", a.Last)
|
||||
options := c.Command.Predict(a)
|
||||
|
||||
Log("Completion: %s", options)
|
||||
|
@ -69,12 +68,12 @@ func (c *Complete) Complete() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func getLine() ([]string, bool) {
|
||||
func getLine() (string, bool) {
|
||||
line := os.Getenv(envComplete)
|
||||
if line == "" {
|
||||
return nil, false
|
||||
return "", false
|
||||
}
|
||||
return strings.Split(line, " "), true
|
||||
return line, true
|
||||
}
|
||||
|
||||
func output(options []string) {
|
||||
|
|
|
@ -143,14 +143,30 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
args: "-o ./",
|
||||
want: []string{"./a.txt", "./b.txt", "./c.txt", "./.dot.txt", "./", "./dir/", "./outer/"},
|
||||
},
|
||||
{
|
||||
args: "-o=./",
|
||||
want: []string{"./a.txt", "./b.txt", "./c.txt", "./.dot.txt", "./", "./dir/", "./outer/"},
|
||||
},
|
||||
{
|
||||
args: "-o .",
|
||||
want: []string{"./a.txt", "./b.txt", "./c.txt", "./.dot.txt", "./", "./dir/", "./outer/"},
|
||||
},
|
||||
{
|
||||
args: "-o ./b",
|
||||
want: []string{"./b.txt"},
|
||||
},
|
||||
{
|
||||
args: "-o=./b",
|
||||
want: []string{"./b.txt"},
|
||||
},
|
||||
{
|
||||
args: "-o ./read",
|
||||
want: []string{},
|
||||
},
|
||||
{
|
||||
args: "-o=./read",
|
||||
want: []string{},
|
||||
},
|
||||
{
|
||||
args: "-o ./readme.md",
|
||||
want: []string{},
|
||||
|
@ -159,6 +175,10 @@ func TestCompleter_Complete(t *testing.T) {
|
|||
args: "-o ./readme.md ",
|
||||
want: []string{"sub1", "sub2"},
|
||||
},
|
||||
{
|
||||
args: "-o=./readme.md ",
|
||||
want: []string{"sub1", "sub2"},
|
||||
},
|
||||
{
|
||||
args: "-o sub2 -flag3 ",
|
||||
want: []string{"opt1", "opt2", "opt12"},
|
||||
|
|
|
@ -28,7 +28,7 @@ func main() {
|
|||
"-asmflags": complete.PredictAnything,
|
||||
"-buildmode": complete.PredictAnything,
|
||||
"-compiler": complete.PredictAnything,
|
||||
"-gccgoflags": complete.PredictAnything,
|
||||
"-gccgoflags": complete.PredictSet("gccgo", "gc"),
|
||||
"-gcflags": complete.PredictAnything,
|
||||
"-installsuffix": complete.PredictAnything,
|
||||
"-ldflags": complete.PredictAnything,
|
||||
|
|
|
@ -158,7 +158,7 @@ func TestPredicate(t *testing.T) {
|
|||
for _, arg := range tt.argList {
|
||||
t.Run(tt.name+"/arg="+arg, func(t *testing.T) {
|
||||
|
||||
matches := tt.p.Predict(newArgs(strings.Split(arg, " ")))
|
||||
matches := tt.p.Predict(newArgs(arg))
|
||||
|
||||
sort.Strings(matches)
|
||||
sort.Strings(tt.want)
|
||||
|
|
Loading…
Reference in New Issue