...
1 package completer
2
3 import (
4 "io/ioutil"
5 "os"
6 "os/user"
7 "path/filepath"
8 "runtime"
9
10 prompt "github.com/c-bata/go-prompt"
11 "github.com/c-bata/go-prompt/internal/debug"
12 )
13
14 var (
15
16 FilePathCompletionSeparator = string([]byte{' ', os.PathSeparator})
17 )
18
19
20
21
22 type FilePathCompleter struct {
23 Filter func(fi os.FileInfo) bool
24 IgnoreCase bool
25 fileListCache map[string][]prompt.Suggest
26 }
27
28 func cleanFilePath(path string) (dir, base string, err error) {
29 if path == "" {
30 return ".", "", nil
31 }
32
33 var endsWithSeparator bool
34 if len(path) >= 1 && path[len(path)-1] == os.PathSeparator {
35 endsWithSeparator = true
36 }
37
38 if runtime.GOOS != "windows" && len(path) >= 2 && path[0:2] == "~/" {
39 me, err := user.Current()
40 if err != nil {
41 return "", "", err
42 }
43 path = filepath.Join(me.HomeDir, path[1:])
44 }
45 path = filepath.Clean(os.ExpandEnv(path))
46 dir = filepath.Dir(path)
47 base = filepath.Base(path)
48
49 if endsWithSeparator {
50 dir = path + string(os.PathSeparator)
51 base = ""
52 }
53 return dir, base, nil
54 }
55
56
57 func (c *FilePathCompleter) Complete(d prompt.Document) []prompt.Suggest {
58 if c.fileListCache == nil {
59 c.fileListCache = make(map[string][]prompt.Suggest, 4)
60 }
61
62 path := d.GetWordBeforeCursor()
63 dir, base, err := cleanFilePath(path)
64 if err != nil {
65 debug.Log("completer: cannot get current user:" + err.Error())
66 return nil
67 }
68
69 if cached, ok := c.fileListCache[dir]; ok {
70 return prompt.FilterHasPrefix(cached, base, c.IgnoreCase)
71 }
72
73 files, err := ioutil.ReadDir(dir)
74 if err != nil && os.IsNotExist(err) {
75 return nil
76 } else if err != nil {
77 debug.Log("completer: cannot read directory items:" + err.Error())
78 return nil
79 }
80
81 suggests := make([]prompt.Suggest, 0, len(files))
82 for _, f := range files {
83 if c.Filter != nil && !c.Filter(f) {
84 continue
85 }
86 suggests = append(suggests, prompt.Suggest{Text: f.Name()})
87 }
88 c.fileListCache[dir] = suggests
89 return prompt.FilterHasPrefix(suggests, base, c.IgnoreCase)
90 }
91
View as plain text