commit
2f2ff270a9
16
.travis.yml
16
.travis.yml
|
@ -1,16 +1,16 @@
|
||||||
language: go
|
language: go
|
||||||
sudo: false
|
|
||||||
go:
|
go:
|
||||||
- 1.11
|
- tip
|
||||||
|
- 1.12.x
|
||||||
|
- 1.11.x
|
||||||
- 1.10.x
|
- 1.10.x
|
||||||
- 1.9
|
|
||||||
- 1.8
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- go get -u -t ./...
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- GO111MODULE=on ./test.sh
|
- go test -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- bash <(curl -s https://codecov.io/bash)
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
2
args.go
2
args.go
|
@ -28,6 +28,8 @@ type Args struct {
|
||||||
// Directory gives the directory of the current written
|
// Directory gives the directory of the current written
|
||||||
// last argument if it represents a file name being written.
|
// last argument if it represents a file name being written.
|
||||||
// in case that it is not, we fall back to the current directory.
|
// in case that it is not, we fall back to the current directory.
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
func (a Args) Directory() string {
|
func (a Args) Directory() string {
|
||||||
if info, err := os.Stat(a.Last); err == nil && info.IsDir() {
|
if info, err := os.Stat(a.Last); err == nil && info.IsDir() {
|
||||||
return fixPathForm(a.Last, a.Last)
|
return fixPathForm(a.Last, a.Last)
|
||||||
|
|
|
@ -6,9 +6,9 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/posener/complete/cmd"
|
"github.com/posener/complete/cmd"
|
||||||
"github.com/posener/complete/match"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -72,7 +72,7 @@ func (c *Complete) Complete() bool {
|
||||||
// filter only options that match the last argument
|
// filter only options that match the last argument
|
||||||
matches := []string{}
|
matches := []string{}
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
if match.Prefix(option, a.Last) {
|
if strings.HasPrefix(option, a.Last) {
|
||||||
matches = append(matches, option)
|
matches = append(matches, option)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,7 +449,7 @@ func main() {
|
||||||
"-unusedfuncs": complete.PredictAnything,
|
"-unusedfuncs": complete.PredictAnything,
|
||||||
"-unusedresult": complete.PredictNothing,
|
"-unusedresult": complete.PredictNothing,
|
||||||
"-unusedstringmethods": complete.PredictAnything,
|
"-unusedstringmethods": complete.PredictAnything,
|
||||||
"-v": complete.PredictNothing,
|
"-v": complete.PredictNothing,
|
||||||
},
|
},
|
||||||
Args: anyGo,
|
Args: anyGo,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
package match
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// File returns true if prefix can match the file
|
|
||||||
func File(file, prefix string) bool {
|
|
||||||
// special case for current directory completion
|
|
||||||
if file == "./" && (prefix == "." || prefix == "") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if prefix == "." && strings.HasPrefix(file, ".") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
file = strings.TrimPrefix(file, "./")
|
|
||||||
prefix = strings.TrimPrefix(prefix, "./")
|
|
||||||
|
|
||||||
return strings.HasPrefix(file, prefix)
|
|
||||||
}
|
|
|
@ -1,7 +1,39 @@
|
||||||
// Package match contains matchers that decide if to apply completion.
|
// Package match contains matchers that decide if to apply completion.
|
||||||
|
//
|
||||||
|
// This package is deprecated.
|
||||||
package match
|
package match
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
// Match matches two strings
|
// Match matches two strings
|
||||||
// it is used for comparing a term to the last typed
|
// it is used for comparing a term to the last typed
|
||||||
// word, the prefix, and see if it is a possible auto complete option.
|
// word, the prefix, and see if it is a possible auto complete option.
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
type Match func(term, prefix string) bool
|
type Match func(term, prefix string) bool
|
||||||
|
|
||||||
|
// Prefix is a simple Matcher, if the word is it's prefix, there is a match
|
||||||
|
// Match returns true if a has the prefix as prefix
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
|
func Prefix(long, prefix string) bool {
|
||||||
|
return strings.HasPrefix(long, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// File returns true if prefix can match the file
|
||||||
|
//
|
||||||
|
// Deprecated.
|
||||||
|
func File(file, prefix string) bool {
|
||||||
|
// special case for current directory completion
|
||||||
|
if file == "./" && (prefix == "." || prefix == "") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if prefix == "." && strings.HasPrefix(file, ".") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
file = strings.TrimPrefix(file, "./")
|
||||||
|
prefix = strings.TrimPrefix(prefix, "./")
|
||||||
|
|
||||||
|
return strings.HasPrefix(file, prefix)
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
package match
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// Prefix is a simple Matcher, if the word is it's prefix, there is a match
|
|
||||||
// Match returns true if a has the prefix as prefix
|
|
||||||
func Prefix(long, prefix string) bool {
|
|
||||||
return strings.HasPrefix(long, prefix)
|
|
||||||
}
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/posener/complete/match"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// PredictDirs will search for directories in the given started to be typed
|
// PredictDirs will search for directories in the given started to be typed
|
||||||
|
@ -53,7 +51,7 @@ func predictFiles(a Args, pattern string, allowFiles bool) []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dir := a.Directory()
|
dir := directory(a.Last)
|
||||||
files := listFiles(dir, pattern, allowFiles)
|
files := listFiles(dir, pattern, allowFiles)
|
||||||
|
|
||||||
// add dir if match
|
// add dir if match
|
||||||
|
@ -62,6 +60,19 @@ func predictFiles(a Args, pattern string, allowFiles bool) []string {
|
||||||
return PredictFilesSet(files).Predict(a)
|
return PredictFilesSet(files).Predict(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// directory gives the directory of the given partial path
|
||||||
|
// in case that it is not, we fall back to the current directory.
|
||||||
|
func directory(path string) string {
|
||||||
|
if info, err := os.Stat(path); err == nil && info.IsDir() {
|
||||||
|
return fixPathForm(path, path)
|
||||||
|
}
|
||||||
|
dir := filepath.Dir(path)
|
||||||
|
if info, err := os.Stat(dir); err == nil && info.IsDir() {
|
||||||
|
return fixPathForm(path, dir)
|
||||||
|
}
|
||||||
|
return "./"
|
||||||
|
}
|
||||||
|
|
||||||
// PredictFilesSet predict according to file rules to a given set of file names
|
// PredictFilesSet predict according to file rules to a given set of file names
|
||||||
func PredictFilesSet(files []string) PredictFunc {
|
func PredictFilesSet(files []string) PredictFunc {
|
||||||
return func(a Args) (prediction []string) {
|
return func(a Args) (prediction []string) {
|
||||||
|
@ -70,7 +81,7 @@ func PredictFilesSet(files []string) PredictFunc {
|
||||||
f = fixPathForm(a.Last, f)
|
f = fixPathForm(a.Last, f)
|
||||||
|
|
||||||
// test matching of file to the argument
|
// test matching of file to the argument
|
||||||
if match.File(f, a.Last) {
|
if matchFile(f, a.Last) {
|
||||||
prediction = append(prediction, f)
|
prediction = append(prediction, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,3 +117,58 @@ func listFiles(dir, pattern string, allowFiles bool) []string {
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MatchFile returns true if prefix can match the file
|
||||||
|
func matchFile(file, prefix string) bool {
|
||||||
|
// special case for current directory completion
|
||||||
|
if file == "./" && (prefix == "." || prefix == "") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if prefix == "." && strings.HasPrefix(file, ".") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
file = strings.TrimPrefix(file, "./")
|
||||||
|
prefix = strings.TrimPrefix(prefix, "./")
|
||||||
|
|
||||||
|
return strings.HasPrefix(file, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixPathForm changes a file name to a relative name
|
||||||
|
func fixPathForm(last string, file string) string {
|
||||||
|
// get wording directory for relative name
|
||||||
|
workDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
abs, err := filepath.Abs(file)
|
||||||
|
if err != nil {
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
// if last is absolute, return path as absolute
|
||||||
|
if filepath.IsAbs(last) {
|
||||||
|
return fixDirPath(abs)
|
||||||
|
}
|
||||||
|
|
||||||
|
rel, err := filepath.Rel(workDir, abs)
|
||||||
|
if err != nil {
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix ./ prefix of path
|
||||||
|
if rel != "." && strings.HasPrefix(last, ".") {
|
||||||
|
rel = "./" + rel
|
||||||
|
}
|
||||||
|
|
||||||
|
return fixDirPath(rel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixDirPath(path string) string {
|
||||||
|
info, err := os.Stat(path)
|
||||||
|
if err == nil && info.IsDir() && !strings.HasSuffix(path, "/") {
|
||||||
|
path += "/"
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
102
predict_test.go
102
predict_test.go
|
@ -1,6 +1,8 @@
|
||||||
package complete
|
package complete
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -167,3 +169,103 @@ func TestPredicate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMatchFile(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Change to tests directory for testing completion of
|
||||||
|
// files and directories
|
||||||
|
err := os.Chdir("../tests")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type matcherTest struct {
|
||||||
|
prefix string
|
||||||
|
want bool
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
long string
|
||||||
|
tests []matcherTest
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
long: "file.txt",
|
||||||
|
tests: []matcherTest{
|
||||||
|
{prefix: "", want: true},
|
||||||
|
{prefix: "f", want: true},
|
||||||
|
{prefix: "./f", want: true},
|
||||||
|
{prefix: "./.", want: false},
|
||||||
|
{prefix: "file.", want: true},
|
||||||
|
{prefix: "./file.", want: true},
|
||||||
|
{prefix: "file.txt", want: true},
|
||||||
|
{prefix: "./file.txt", want: true},
|
||||||
|
{prefix: "other.txt", want: false},
|
||||||
|
{prefix: "/other.txt", want: false},
|
||||||
|
{prefix: "/file.txt", want: false},
|
||||||
|
{prefix: "/fil", want: false},
|
||||||
|
{prefix: "/file.txt2", want: false},
|
||||||
|
{prefix: "/.", want: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
long: "./file.txt",
|
||||||
|
tests: []matcherTest{
|
||||||
|
{prefix: "", want: true},
|
||||||
|
{prefix: "f", want: true},
|
||||||
|
{prefix: "./f", want: true},
|
||||||
|
{prefix: "./.", want: false},
|
||||||
|
{prefix: "file.", want: true},
|
||||||
|
{prefix: "./file.", want: true},
|
||||||
|
{prefix: "file.txt", want: true},
|
||||||
|
{prefix: "./file.txt", want: true},
|
||||||
|
{prefix: "other.txt", want: false},
|
||||||
|
{prefix: "/other.txt", want: false},
|
||||||
|
{prefix: "/file.txt", want: false},
|
||||||
|
{prefix: "/fil", want: false},
|
||||||
|
{prefix: "/file.txt2", want: false},
|
||||||
|
{prefix: "/.", want: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
long: "/file.txt",
|
||||||
|
tests: []matcherTest{
|
||||||
|
{prefix: "", want: true},
|
||||||
|
{prefix: "f", want: false},
|
||||||
|
{prefix: "./f", want: false},
|
||||||
|
{prefix: "./.", want: false},
|
||||||
|
{prefix: "file.", want: false},
|
||||||
|
{prefix: "./file.", want: false},
|
||||||
|
{prefix: "file.txt", want: false},
|
||||||
|
{prefix: "./file.txt", want: false},
|
||||||
|
{prefix: "other.txt", want: false},
|
||||||
|
{prefix: "/other.txt", want: false},
|
||||||
|
{prefix: "/file.txt", want: true},
|
||||||
|
{prefix: "/fil", want: true},
|
||||||
|
{prefix: "/file.txt2", want: false},
|
||||||
|
{prefix: "/.", want: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
long: "./",
|
||||||
|
tests: []matcherTest{
|
||||||
|
{prefix: "", want: true},
|
||||||
|
{prefix: ".", want: true},
|
||||||
|
{prefix: "./", want: true},
|
||||||
|
{prefix: "./.", want: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
for _, ttt := range tt.tests {
|
||||||
|
name := fmt.Sprintf("long=%q&prefix=%q", tt.long, ttt.prefix)
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
got := matchFile(tt.long, ttt.prefix)
|
||||||
|
if got != ttt.want {
|
||||||
|
t.Errorf("Failed %s: got = %t, want: %t", name, got, ttt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
12
test.sh
12
test.sh
|
@ -1,12 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
echo "" > coverage.txt
|
|
||||||
|
|
||||||
for d in $(go list ./... | grep -v vendor); do
|
|
||||||
go test -v -race -coverprofile=profile.out -covermode=atomic $d
|
|
||||||
if [ -f profile.out ]; then
|
|
||||||
cat profile.out >> coverage.txt
|
|
||||||
rm profile.out
|
|
||||||
fi
|
|
||||||
done
|
|
46
utils.go
46
utils.go
|
@ -1,46 +0,0 @@
|
||||||
package complete
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// fixPathForm changes a file name to a relative name
|
|
||||||
func fixPathForm(last string, file string) string {
|
|
||||||
// get wording directory for relative name
|
|
||||||
workDir, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
||||||
abs, err := filepath.Abs(file)
|
|
||||||
if err != nil {
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
||||||
// if last is absolute, return path as absolute
|
|
||||||
if filepath.IsAbs(last) {
|
|
||||||
return fixDirPath(abs)
|
|
||||||
}
|
|
||||||
|
|
||||||
rel, err := filepath.Rel(workDir, abs)
|
|
||||||
if err != nil {
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix ./ prefix of path
|
|
||||||
if rel != "." && strings.HasPrefix(last, ".") {
|
|
||||||
rel = "./" + rel
|
|
||||||
}
|
|
||||||
|
|
||||||
return fixDirPath(rel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fixDirPath(path string) string {
|
|
||||||
info, err := os.Stat(path)
|
|
||||||
if err == nil && info.IsDir() && !strings.HasSuffix(path, "/") {
|
|
||||||
path += "/"
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
|
Loading…
Reference in New Issue