]> git.lizzy.rs Git - micro.git/blob - cmd/micro/autocomplete.go
Add sucmd to customize "sudo" command
[micro.git] / cmd / micro / autocomplete.go
1 package main
2
3 import (
4         "io/ioutil"
5         "os"
6         "strings"
7 )
8
9 var pluginCompletions []func(string) []string
10
11 // This file is meant (for now) for autocompletion in command mode, not
12 // while coding. This helps micro autocomplete commands and then filenames
13 // for example with `vsplit filename`.
14
15 // FileComplete autocompletes filenames
16 func FileComplete(input string) (string, []string) {
17         var sep string = string(os.PathSeparator)
18         dirs := strings.Split(input, sep)
19
20         var files []os.FileInfo
21         var err error
22         if len(dirs) > 1 {
23                 directories := strings.Join(dirs[:len(dirs)-1], sep) + sep
24
25                 directories = ReplaceHome(directories)
26                 files, err = ioutil.ReadDir(directories)
27         } else {
28                 files, err = ioutil.ReadDir(".")
29         }
30
31         var suggestions []string
32         if err != nil {
33                 return "", suggestions
34         }
35         for _, f := range files {
36                 name := f.Name()
37                 if f.IsDir() {
38                         name += sep
39                 }
40                 if strings.HasPrefix(name, dirs[len(dirs)-1]) {
41                         suggestions = append(suggestions, name)
42                 }
43         }
44
45         var chosen string
46         if len(suggestions) == 1 {
47                 if len(dirs) > 1 {
48                         chosen = strings.Join(dirs[:len(dirs)-1], sep) + sep + suggestions[0]
49                 } else {
50                         chosen = suggestions[0]
51                 }
52         } else {
53                 if len(dirs) > 1 {
54                         chosen = strings.Join(dirs[:len(dirs)-1], sep) + sep
55                 }
56         }
57
58         return chosen, suggestions
59 }
60
61 // CommandComplete autocompletes commands
62 func CommandComplete(input string) (string, []string) {
63         var suggestions []string
64         for cmd := range commands {
65                 if strings.HasPrefix(cmd, input) {
66                         suggestions = append(suggestions, cmd)
67                 }
68         }
69
70         var chosen string
71         if len(suggestions) == 1 {
72                 chosen = suggestions[0]
73         }
74         return chosen, suggestions
75 }
76
77 // HelpComplete autocompletes help topics
78 func HelpComplete(input string) (string, []string) {
79         var suggestions []string
80
81         for _, file := range ListRuntimeFiles(RTHelp) {
82                 topic := file.Name()
83                 if strings.HasPrefix(topic, input) {
84                         suggestions = append(suggestions, topic)
85                 }
86         }
87
88         var chosen string
89         if len(suggestions) == 1 {
90                 chosen = suggestions[0]
91         }
92         return chosen, suggestions
93 }
94
95 // ColorschemeComplete tab-completes names of colorschemes.
96 func ColorschemeComplete(input string) (string, []string) {
97         var suggestions []string
98         files := ListRuntimeFiles(RTColorscheme)
99
100         for _, f := range files {
101                 if strings.HasPrefix(f.Name(), input) {
102                         suggestions = append(suggestions, f.Name())
103                 }
104         }
105
106         var chosen string
107         if len(suggestions) == 1 {
108                 chosen = suggestions[0]
109         }
110
111         return chosen, suggestions
112 }
113
114 func contains(s []string, e string) bool {
115         for _, a := range s {
116                 if a == e {
117                         return true
118                 }
119         }
120         return false
121 }
122
123 // OptionComplete autocompletes options
124 func OptionComplete(input string) (string, []string) {
125         var suggestions []string
126         localSettings := DefaultLocalSettings()
127         for option := range globalSettings {
128                 if strings.HasPrefix(option, input) {
129                         suggestions = append(suggestions, option)
130                 }
131         }
132         for option := range localSettings {
133                 if strings.HasPrefix(option, input) && !contains(suggestions, option) {
134                         suggestions = append(suggestions, option)
135                 }
136         }
137
138         var chosen string
139         if len(suggestions) == 1 {
140                 chosen = suggestions[0]
141         }
142         return chosen, suggestions
143 }
144
145 func OptionValueComplete(inputOpt, input string) (string, []string) {
146         inputOpt = strings.TrimSpace(inputOpt)
147         var suggestions []string
148         localSettings := DefaultLocalSettings()
149         var optionVal interface{}
150         for k, option := range globalSettings {
151                 if k == inputOpt {
152                         optionVal = option
153                 }
154         }
155         for k, option := range localSettings {
156                 if k == inputOpt {
157                         optionVal = option
158                 }
159         }
160
161         switch optionVal.(type) {
162         case bool:
163                 if strings.HasPrefix("on", input) {
164                         suggestions = append(suggestions, "on")
165                 } else if strings.HasPrefix("true", input) {
166                         suggestions = append(suggestions, "true")
167                 }
168                 if strings.HasPrefix("off", input) {
169                         suggestions = append(suggestions, "off")
170                 } else if strings.HasPrefix("false", input) {
171                         suggestions = append(suggestions, "false")
172                 }
173         case string:
174                 switch inputOpt {
175                 case "colorscheme":
176                         _, suggestions = ColorschemeComplete(input)
177                 case "fileformat":
178                         if strings.HasPrefix("unix", input) {
179                                 suggestions = append(suggestions, "unix")
180                         }
181                         if strings.HasPrefix("dos", input) {
182                                 suggestions = append(suggestions, "dos")
183                         }
184                 case "sucmd":
185                         if strings.HasPrefix("sudo", input) {
186                                 suggestions = append(suggestions, "sudo")
187                         }
188                         if strings.HasPrefix("doas", input) {
189                                 suggestions = append(suggestions, "doas")
190                         }
191                 }
192         }
193
194         var chosen string
195         if len(suggestions) == 1 {
196                 chosen = suggestions[0]
197         }
198         return chosen, suggestions
199 }
200
201 // MakeCompletion registers a function from a plugin for autocomplete commands
202 func MakeCompletion(function string) Completion {
203         pluginCompletions = append(pluginCompletions, LuaFunctionComplete(function))
204         return Completion(-len(pluginCompletions))
205 }
206
207 // PluginComplete autocompletes from plugin function
208 func PluginComplete(complete Completion, input string) (chosen string, suggestions []string) {
209         idx := int(-complete) - 1
210
211         if len(pluginCompletions) <= idx {
212                 return "", nil
213         }
214         suggestions = pluginCompletions[idx](input)
215
216         if len(suggestions) == 1 {
217                 chosen = suggestions[0]
218         }
219         return
220 }
221
222 func PluginCmdComplete(input string) (chosen string, suggestions []string) {
223         for _, cmd := range []string{"install", "remove", "search", "update", "list"} {
224                 if strings.HasPrefix(cmd, input) {
225                         suggestions = append(suggestions, cmd)
226                 }
227         }
228
229         if len(suggestions) == 1 {
230                 chosen = suggestions[0]
231         }
232         return chosen, suggestions
233 }
234
235 func PluginNameComplete(input string) (chosen string, suggestions []string) {
236         for _, pp := range GetAllPluginPackages() {
237                 if strings.HasPrefix(pp.Name, input) {
238                         suggestions = append(suggestions, pp.Name)
239                 }
240         }
241
242         if len(suggestions) == 1 {
243                 chosen = suggestions[0]
244         }
245         return chosen, suggestions
246 }