summaryrefslogtreecommitdiff
path: root/predict_files.go
diff options
context:
space:
mode:
Diffstat (limited to 'predict_files.go')
-rw-r--r--predict_files.go116
1 files changed, 68 insertions, 48 deletions
diff --git a/predict_files.go b/predict_files.go
index 8ad5368..5f83e77 100644
--- a/predict_files.go
+++ b/predict_files.go
@@ -25,64 +25,93 @@ func PredictFiles(pattern string) Predictor {
}
func files(pattern string, allowFiles bool) PredictFunc {
+
+ // search for files according to arguments,
+ // if only one directory has matched the result, search recursively into
+ // this directory to give more results.
return func(a Args) (prediction []string) {
- prediction = predictFiles(a.Last, pattern, allowFiles)
- return
+ for {
+
+ prediction = predictFiles(a, pattern, allowFiles)
+
+ // if the number of prediction is not 1, we either have many results or
+ // have no results, so we return it.
+ if len(prediction) != 1 {
+ return
+ }
+
+ // if the result is only one item, we might want to recursively check
+ // for more accurate results.
+ if prediction[0] == a.Last { // avoid loop forever
+ return
+ }
+
+ // only try deeper, if the one item is a directory
+ if stat, err := os.Stat(prediction[0]); err != nil || !stat.IsDir() {
+ return
+ }
+
+ a.Last = prediction[0]
+ }
}
}
-func predictFiles(last string, pattern string, allowFiles bool) (prediction []string) {
- if strings.HasSuffix(last, "/..") {
- return
+func predictFiles(a Args, pattern string, allowFiles bool) []string {
+ if strings.HasSuffix(a.Last, "/..") {
+ return nil
}
- dir := dirFromLast(last)
- rel := !filepath.IsAbs(pattern)
- files := listFiles(dir, pattern)
-
- // get wording directory for relative name
- workDir, err := os.Getwd()
- if err != nil {
- workDir = ""
- }
+ dir := a.Directory()
+ files := listFiles(dir, pattern, allowFiles)
// add dir if match
files = append(files, dir)
- // add all matching files to prediction
- for _, f := range files {
- if stat, err := os.Stat(f); err != nil || (!stat.IsDir() && !allowFiles) {
- continue
- }
+ return PredictFilesSet(files).Predict(a)
+}
- // change file name to relative if necessary
- if rel && workDir != "" {
- f = toRel(workDir, f)
- }
+// PredictFilesSet predict according to file rules to a given set of file names
+func PredictFilesSet(files []string) PredictFunc {
+ return func(a Args) (prediction []string) {
+ rel := !filepath.IsAbs(a.Directory())
+ // add all matching files to prediction
+ for _, f := range files {
+ // change file name to relative if necessary
+ if rel {
+ f = toRel(f)
+ }
- // test matching of file to the argument
- if match.File(f, last) {
- prediction = append(prediction, f)
+ // test matching of file to the argument
+ if match.File(f, a.Last) {
+ prediction = append(prediction, f)
+ }
}
+ return
}
- return
-
}
-func listFiles(dir, pattern string) []string {
+func listFiles(dir, pattern string, allowFiles bool) []string {
+ // set of all file names
m := map[string]bool{}
+
+ // list files
if files, err := filepath.Glob(filepath.Join(dir, pattern)); err == nil {
for _, f := range files {
- m[f] = true
+ if stat, err := os.Stat(f); err != nil || stat.IsDir() || allowFiles {
+ m[f] = true
+ }
}
}
+
+ // list directories
if dirs, err := ioutil.ReadDir(dir); err == nil {
for _, d := range dirs {
if d.IsDir() {
- m[d.Name()] = true
+ m[filepath.Join(dir, d.Name())] = true
}
}
}
+
list := make([]string, 0, len(m))
for k := range m {
list = append(list, k)
@@ -91,12 +120,18 @@ func listFiles(dir, pattern string) []string {
}
// toRel changes a file name to a relative name
-func toRel(wd, file string) string {
+func toRel(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
}
- rel, err := filepath.Rel(wd, abs)
+ rel, err := filepath.Rel(workDir, abs)
if err != nil {
return file
}
@@ -108,18 +143,3 @@ func toRel(wd, file string) string {
}
return rel
}
-
-// dirFromLast gives the directory of the current written
-// last argument if it represents a file name being written.
-// in case that it is not, we fall back to the current directory.
-func dirFromLast(last string) string {
- if info, err := os.Stat(last); err == nil && info.IsDir() {
- return last
- }
- dir := filepath.Dir(last)
- _, err := os.Stat(dir)
- if err != nil {
- return "./"
- }
- return dir
-}