]>
Commit | Line | Data |
---|---|---|
1 | package complete | |
2 | ||
3 | import ( | |
4 | "os" | |
5 | "path/filepath" | |
6 | "strings" | |
7 | "unicode" | |
8 | ) | |
9 | ||
10 | // Args describes command line arguments | |
11 | type Args struct { | |
12 | // All lists of all arguments in command line (not including the command itself) | |
13 | All []string | |
14 | // Completed lists of all completed arguments in command line, | |
15 | // If the last one is still being typed - no space after it, | |
16 | // it won't appear in this list of arguments. | |
17 | Completed []string | |
18 | // Last argument in command line, the one being typed, if the last | |
19 | // character in the command line is a space, this argument will be empty, | |
20 | // otherwise this would be the last word. | |
21 | Last string | |
22 | // LastCompleted is the last argument that was fully typed. | |
23 | // If the last character in the command line is space, this would be the | |
24 | // last word, otherwise, it would be the word before that. | |
25 | LastCompleted string | |
26 | } | |
27 | ||
28 | // Directory gives the directory of the current written | |
29 | // last argument if it represents a file name being written. | |
30 | // in case that it is not, we fall back to the current directory. | |
31 | func (a Args) Directory() string { | |
32 | if info, err := os.Stat(a.Last); err == nil && info.IsDir() { | |
33 | return fixPathForm(a.Last, a.Last) | |
34 | } | |
35 | dir := filepath.Dir(a.Last) | |
36 | if info, err := os.Stat(dir); err != nil || !info.IsDir() { | |
37 | return "./" | |
38 | } | |
39 | return fixPathForm(a.Last, dir) | |
40 | } | |
41 | ||
42 | func newArgs(line string) Args { | |
43 | var ( | |
44 | all []string | |
45 | completed []string | |
46 | ) | |
47 | parts := splitFields(line) | |
48 | if len(parts) > 0 { | |
49 | all = parts[1:] | |
50 | completed = removeLast(parts[1:]) | |
51 | } | |
52 | return Args{ | |
53 | All: all, | |
54 | Completed: completed, | |
55 | Last: last(parts), | |
56 | LastCompleted: last(completed), | |
57 | } | |
58 | } | |
59 | ||
60 | // splitFields returns a list of fields from the given command line. | |
61 | // If the last character is space, it appends an empty field in the end | |
62 | // indicating that the field before it was completed. | |
63 | // If the last field is of the form "a=b", it splits it to two fields: "a", "b", | |
64 | // So it can be completed. | |
65 | func splitFields(line string) []string { | |
66 | parts := strings.Fields(line) | |
67 | ||
68 | // Add empty field if the last field was completed. | |
69 | if len(line) > 0 && unicode.IsSpace(rune(line[len(line)-1])) { | |
70 | parts = append(parts, "") | |
71 | } | |
72 | ||
73 | // Treat the last field if it is of the form "a=b" | |
74 | parts = splitLastEqual(parts) | |
75 | return parts | |
76 | } | |
77 | ||
78 | func splitLastEqual(line []string) []string { | |
79 | if len(line) == 0 { | |
80 | return line | |
81 | } | |
82 | parts := strings.Split(line[len(line)-1], "=") | |
83 | return append(line[:len(line)-1], parts...) | |
84 | } | |
85 | ||
86 | func (a Args) from(i int) Args { | |
87 | if i > len(a.All) { | |
88 | i = len(a.All) | |
89 | } | |
90 | a.All = a.All[i:] | |
91 | ||
92 | if i > len(a.Completed) { | |
93 | i = len(a.Completed) | |
94 | } | |
95 | a.Completed = a.Completed[i:] | |
96 | return a | |
97 | } | |
98 | ||
99 | func removeLast(a []string) []string { | |
100 | if len(a) > 0 { | |
101 | return a[:len(a)-1] | |
102 | } | |
103 | return a | |
104 | } | |
105 | ||
106 | func last(args []string) string { | |
107 | if len(args) == 0 { | |
108 | return "" | |
109 | } | |
110 | return args[len(args)-1] | |
111 | } |