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