diff options
| author | Eyal Posener <[email protected]> | 2017-05-13 00:45:08 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2017-05-13 00:45:08 +0300 |
| commit | 9123548bc5f7725948b6096be4ef490af71194b3 (patch) | |
| tree | 33e21d60ec1412ff7aaf1c73363208e79d96d8b3 /predict_files.go | |
| parent | 136e52e074be4a85fb9e9bccf93d060c46e67561 (diff) | |
| parent | bc5d682221f38e82bbd977d5567da8b884a30cbc (diff) | |
Merge pull request #16 from posener/recursive-dirs
Recursive directories and complete by go packages
Diffstat (limited to 'predict_files.go')
| -rw-r--r-- | predict_files.go | 116 |
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 -} |
