summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEyal Posener <[email protected]>2017-05-07 19:53:55 +0300
committerEyal Posener <[email protected]>2017-05-07 19:57:41 +0300
commit6fb4875efa1f536813da29972a0c3250bde8b5eb (patch)
treec7ee97d75ed8d1d6c734256e3ff789402571bcca
parente8f6dfad584cb1e3082bc7ea82f8c0551dd944b3 (diff)
Move match to a separate package
-rw-r--r--command.go14
-rw-r--r--gocomplete/complete.go4
-rw-r--r--gocomplete/tests.go7
-rw-r--r--match.go50
-rw-r--r--match/file.go30
-rw-r--r--match/match.go9
-rw-r--r--match/match_test.go (renamed from match_test.go)47
-rw-r--r--match/prefix.go15
-rw-r--r--predicate.go31
9 files changed, 113 insertions, 94 deletions
diff --git a/command.go b/command.go
index f2b8354..f64e225 100644
--- a/command.go
+++ b/command.go
@@ -1,5 +1,7 @@
package complete
+import "github.com/posener/complete/match"
+
// Command represents a command line
// It holds the data that enables auto completion of a given typed command line
// Command can also be a sub command.
@@ -27,7 +29,7 @@ type Flags map[string]Predicate
// options returns all available complete options for the given command
// args are all except the last command line arguments relevant to the command
-func (c *Command) options(args []string) (options []Matcher, only bool) {
+func (c *Command) options(args []string) (options []match.Matcher, only bool) {
// remove the first argument, which is the command name
args = args[1:]
@@ -51,7 +53,7 @@ func (c *Command) options(args []string) (options []Matcher, only bool) {
// add global available complete options
for flag := range c.Flags {
- options = append(options, MatchPrefix(flag))
+ options = append(options, match.Prefix(flag))
}
// add additional expected argument of the command
@@ -62,7 +64,7 @@ func (c *Command) options(args []string) (options []Matcher, only bool) {
// searchSub searches recursively within sub commands if the sub command appear
// in the on of the arguments.
-func (c *Command) searchSub(args []string) (sub string, all []Matcher, only bool) {
+func (c *Command) searchSub(args []string) (sub string, all []match.Matcher, only bool) {
for i, arg := range args {
if cmd, ok := c.Sub[arg]; ok {
sub = arg
@@ -74,10 +76,10 @@ func (c *Command) searchSub(args []string) (sub string, all []Matcher, only bool
}
// suvCommands returns a list of matchers according to the sub command names
-func (c *Command) subCommands() []Matcher {
- subs := make([]Matcher, 0, len(c.Sub))
+func (c *Command) subCommands() []match.Matcher {
+ subs := make([]match.Matcher, 0, len(c.Sub))
for sub := range c.Sub {
- subs = append(subs, MatchPrefix(sub))
+ subs = append(subs, match.Prefix(sub))
}
return subs
}
diff --git a/gocomplete/complete.go b/gocomplete/complete.go
index 4eab6a5..033a374 100644
--- a/gocomplete/complete.go
+++ b/gocomplete/complete.go
@@ -1,9 +1,7 @@
// Package main is complete tool for the go command line
package main
-import (
- "github.com/posener/complete"
-)
+import "github.com/posener/complete"
var (
predictEllipsis = complete.PredictSet("./...")
diff --git a/gocomplete/tests.go b/gocomplete/tests.go
index 3a6a185..905c5dc 100644
--- a/gocomplete/tests.go
+++ b/gocomplete/tests.go
@@ -9,14 +9,15 @@ import (
"strings"
"github.com/posener/complete"
+ "github.com/posener/complete/match"
)
func predictTest(testType string) complete.Predicate {
- return func(last string) []complete.Matcher {
+ return func(last string) []match.Matcher {
tests := testNames(testType)
- options := make([]complete.Matcher, len(tests))
+ options := make([]match.Matcher, len(tests))
for i := range tests {
- options[i] = complete.MatchPrefix(tests[i])
+ options[i] = match.Prefix(tests[i])
}
return options
}
diff --git a/match.go b/match.go
deleted file mode 100644
index 8da8f2c..0000000
--- a/match.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package complete
-
-import (
- "path/filepath"
- "strings"
-)
-
-// Matcher matches itself to a string
-// it is used for comparing a given argument to the last typed
-// word, and see if it is a possible auto complete option.
-type Matcher interface {
- String() string
- Match(prefix string) bool
-}
-
-// MatchPrefix is a simple Matcher, if the word is it's prefix, there is a match
-type MatchPrefix string
-
-func (a MatchPrefix) String() string {
- return string(a)
-}
-
-// Match returns true if a has the prefix as prefix
-func (a MatchPrefix) Match(prefix string) bool {
- return strings.HasPrefix(string(a), prefix)
-}
-
-// MatchFileName is a file name Matcher, if the last word can prefix the
-// MatchFileName path, there is a possible match
-type MatchFileName string
-
-func (a MatchFileName) String() string {
- return string(a)
-}
-
-// Match returns true if prefix's abs path prefixes a's abs path
-func (a MatchFileName) Match(prefix string) bool {
- full, err := filepath.Abs(string(a))
- if err != nil {
- Log("failed getting abs path of %s: %s", a, err)
- }
- prefixFull, err := filepath.Abs(prefix)
- if err != nil {
- Log("failed getting abs path of %s: %s", prefix, err)
- }
-
- // if the file has the prefix as prefix,
- // but we don't want to show too many files, so, if it is in a deeper directory - omit it.
- return strings.HasPrefix(full, prefixFull) && (full == prefixFull || !strings.Contains(full[len(prefixFull)+1:], "/"))
-}
diff --git a/match/file.go b/match/file.go
new file mode 100644
index 0000000..c972ce0
--- /dev/null
+++ b/match/file.go
@@ -0,0 +1,30 @@
+package match
+
+import (
+ "path/filepath"
+ "strings"
+)
+
+// File is a file name Matcher, if the last word can prefix the
+// File path, there is a possible match
+type File string
+
+func (a File) String() string {
+ return string(a)
+}
+
+// Match returns true if prefix's abs path prefixes a's abs path
+func (a File) Match(prefix string) bool {
+ full, err := filepath.Abs(string(a))
+ if err != nil {
+ return false
+ }
+ prefixFull, err := filepath.Abs(prefix)
+ if err != nil {
+ return false
+ }
+
+ // if the file has the prefix as prefix,
+ // but we don't want to show too many files, so, if it is in a deeper directory - omit it.
+ return strings.HasPrefix(full, prefixFull) && (full == prefixFull || !strings.Contains(full[len(prefixFull)+1:], "/"))
+}
diff --git a/match/match.go b/match/match.go
new file mode 100644
index 0000000..ffd7eb8
--- /dev/null
+++ b/match/match.go
@@ -0,0 +1,9 @@
+package match
+
+// Matcher matches itself to a string
+// it is used for comparing a given argument to the last typed
+// word, and see if it is a possible auto complete option.
+type Matcher interface {
+ String() string
+ Match(prefix string) bool
+}
diff --git a/match_test.go b/match/match_test.go
index 8605194..f9afd46 100644
--- a/match_test.go
+++ b/match/match_test.go
@@ -1,10 +1,19 @@
-package complete
+package match
-import "testing"
+import (
+ "os"
+ "testing"
+)
func TestMatch(t *testing.T) {
t.Parallel()
- initTests()
+
+ // Change to tests directory for testing completion of
+ // files and directories
+ err := os.Chdir("../tests")
+ if err != nil {
+ panic(err)
+ }
tests := []struct {
m Matcher
@@ -12,82 +21,82 @@ func TestMatch(t *testing.T) {
want bool
}{
{
- m: MatchPrefix("abcd"),
+ m: Prefix("abcd"),
prefix: "",
want: true,
},
{
- m: MatchPrefix("abcd"),
+ m: Prefix("abcd"),
prefix: "ab",
want: true,
},
{
- m: MatchPrefix("abcd"),
+ m: Prefix("abcd"),
prefix: "ac",
want: false,
},
{
- m: MatchPrefix(""),
+ m: Prefix(""),
prefix: "ac",
want: false,
},
{
- m: MatchPrefix(""),
+ m: Prefix(""),
prefix: "",
want: true,
},
{
- m: MatchFileName("file.txt"),
+ m: File("file.txt"),
prefix: "",
want: true,
},
{
- m: MatchFileName("./file.txt"),
+ m: File("./file.txt"),
prefix: "",
want: true,
},
{
- m: MatchFileName("./file.txt"),
+ m: File("./file.txt"),
prefix: "f",
want: true,
},
{
- m: MatchFileName("./file.txt"),
+ m: File("./file.txt"),
prefix: "file.",
want: true,
},
{
- m: MatchFileName("./file.txt"),
+ m: File("./file.txt"),
prefix: "./f",
want: true,
},
{
- m: MatchFileName("./file.txt"),
+ m: File("./file.txt"),
prefix: "other.txt",
want: false,
},
{
- m: MatchFileName("./file.txt"),
+ m: File("./file.txt"),
prefix: "/file.txt",
want: false,
},
{
- m: MatchFileName("/file.txt"),
+ m: File("/file.txt"),
prefix: "file.txt",
want: false,
},
{
- m: MatchFileName("/file.txt"),
+ m: File("/file.txt"),
prefix: "./file.txt",
want: false,
},
{
- m: MatchFileName("/file.txt"),
+ m: File("/file.txt"),
prefix: "/file.txt",
want: true,
},
{
- m: MatchFileName("/file.txt"),
+ m: File("/file.txt"),
prefix: "/fil",
want: true,
},
diff --git a/match/prefix.go b/match/prefix.go
new file mode 100644
index 0000000..d54902d
--- /dev/null
+++ b/match/prefix.go
@@ -0,0 +1,15 @@
+package match
+
+import "strings"
+
+// Prefix is a simple Matcher, if the word is it's prefix, there is a match
+type Prefix string
+
+func (a Prefix) String() string {
+ return string(a)
+}
+
+// Match returns true if a has the prefix as prefix
+func (a Prefix) Match(prefix string) bool {
+ return strings.HasPrefix(string(a), prefix)
+}
diff --git a/predicate.go b/predicate.go
index 5b0dcc0..163ccfd 100644
--- a/predicate.go
+++ b/predicate.go
@@ -3,12 +3,14 @@ package complete
import (
"os"
"path/filepath"
+
+ "github.com/posener/complete/match"
)
// Predicate determines what terms can follow a command or a flag
// It is used for auto completion, given last - the last word in the already
// in the command line, what words can complete it.
-type Predicate func(last string) []Matcher
+type Predicate func(last string) []match.Matcher
// Or unions two predicate functions, so that the result predicate
// returns the union of their predication
@@ -19,10 +21,10 @@ func (p Predicate) Or(other Predicate) Predicate {
if other == nil {
return p
}
- return func(last string) []Matcher { return append(p.predict(last), other.predict(last)...) }
+ return func(last string) []match.Matcher { return append(p.predict(last), other.predict(last)...) }
}
-func (p Predicate) predict(last string) []Matcher {
+func (p Predicate) predict(last string) []match.Matcher {
if p == nil {
return nil
}
@@ -34,14 +36,14 @@ var PredictNothing Predicate
// PredictAnything expects something, but nothing particular, such as a number
// or arbitrary name.
-func PredictAnything(last string) []Matcher { return nil }
+func PredictAnything(last string) []match.Matcher { return nil }
// PredictSet expects specific set of terms, given in the options argument.
func PredictSet(options ...string) Predicate {
- return func(last string) []Matcher {
- ret := make([]Matcher, len(options))
+ return func(last string) []match.Matcher {
+ ret := make([]match.Matcher, len(options))
for i := range options {
- ret[i] = MatchPrefix(options[i])
+ ret[i] = match.Prefix(options[i])
}
return ret
}
@@ -50,7 +52,7 @@ func PredictSet(options ...string) Predicate {
// PredictDirs will search for directories in the given started to be typed
// path, if no path was started to be typed, it will complete to directories
// in the current working directory.
-func PredictDirs(last string) (options []Matcher) {
+func PredictDirs(last string) (options []match.Matcher) {
dir := dirFromLast(last)
return dirsAt(dir)
}
@@ -60,7 +62,7 @@ func PredictDirs(last string) (options []Matcher) {
// match the pattern in the current working directory.
// To match any file, use "*" as pattern. To match go files use "*.go", and so on.
func PredictFiles(pattern string) Predicate {
- return func(last string) []Matcher {
+ return func(last string) []match.Matcher {
dir := dirFromLast(last)
files, err := filepath.Glob(filepath.Join(dir, pattern))
if err != nil {
@@ -73,9 +75,12 @@ func PredictFiles(pattern string) Predicate {
}
}
-func dirsAt(path string) []Matcher {
+func dirsAt(path string) []match.Matcher {
dirs := []string{}
filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return nil
+ }
if info.IsDir() {
dirs = append(dirs, path)
}
@@ -111,10 +116,10 @@ func filesToRel(files []string) {
return
}
-func filesToMatchers(files []string) []Matcher {
- options := make([]Matcher, len(files))
+func filesToMatchers(files []string) []match.Matcher {
+ options := make([]match.Matcher, len(files))
for i, f := range files {
- options[i] = MatchFileName(f)
+ options[i] = match.File(f)
}
return options
}