9 "github.com/zyedidia/tcell"
12 var bindings map[Key][]func(*View) bool
13 var helpBinding string
15 var bindingActions = map[string]func(*View) bool{
16 "CursorUp": (*View).CursorUp,
17 "CursorDown": (*View).CursorDown,
18 "CursorPageUp": (*View).CursorPageUp,
19 "CursorPageDown": (*View).CursorPageDown,
20 "CursorLeft": (*View).CursorLeft,
21 "CursorRight": (*View).CursorRight,
22 "CursorStart": (*View).CursorStart,
23 "CursorEnd": (*View).CursorEnd,
24 "SelectToStart": (*View).SelectToStart,
25 "SelectToEnd": (*View).SelectToEnd,
26 "SelectUp": (*View).SelectUp,
27 "SelectDown": (*View).SelectDown,
28 "SelectLeft": (*View).SelectLeft,
29 "SelectRight": (*View).SelectRight,
30 "WordRight": (*View).WordRight,
31 "WordLeft": (*View).WordLeft,
32 "SelectWordRight": (*View).SelectWordRight,
33 "SelectWordLeft": (*View).SelectWordLeft,
34 "DeleteWordRight": (*View).DeleteWordRight,
35 "DeleteWordLeft": (*View).DeleteWordLeft,
36 "SelectToStartOfLine": (*View).SelectToStartOfLine,
37 "SelectToEndOfLine": (*View).SelectToEndOfLine,
38 "InsertEnter": (*View).InsertEnter,
39 "InsertSpace": (*View).InsertSpace,
40 "Backspace": (*View).Backspace,
41 "Delete": (*View).Delete,
42 "InsertTab": (*View).InsertTab,
45 "FindNext": (*View).FindNext,
46 "FindPrevious": (*View).FindPrevious,
51 "CutLine": (*View).CutLine,
52 "DuplicateLine": (*View).DuplicateLine,
53 "DeleteLine": (*View).DeleteLine,
54 "Paste": (*View).Paste,
55 "SelectAll": (*View).SelectAll,
56 "OpenFile": (*View).OpenFile,
57 "Start": (*View).Start,
59 "PageUp": (*View).PageUp,
60 "PageDown": (*View).PageDown,
61 "HalfPageUp": (*View).HalfPageUp,
62 "HalfPageDown": (*View).HalfPageDown,
63 "StartOfLine": (*View).StartOfLine,
64 "EndOfLine": (*View).EndOfLine,
65 "ToggleHelp": (*View).ToggleHelp,
66 "ToggleRuler": (*View).ToggleRuler,
67 "JumpLine": (*View).JumpLine,
68 "ClearStatus": (*View).ClearStatus,
69 "ShellMode": (*View).ShellMode,
70 "CommandMode": (*View).CommandMode,
72 "AddTab": (*View).AddTab,
73 "PreviousTab": (*View).PreviousTab,
74 "NextTab": (*View).NextTab,
75 "NextSplit": (*View).NextSplit,
76 "PreviousSplit": (*View).PreviousSplit,
79 var bindingKeys = map[string]tcell.Key{
81 "Down": tcell.KeyDown,
82 "Right": tcell.KeyRight,
83 "Left": tcell.KeyLeft,
84 "UpLeft": tcell.KeyUpLeft,
85 "UpRight": tcell.KeyUpRight,
86 "DownLeft": tcell.KeyDownLeft,
87 "DownRight": tcell.KeyDownRight,
88 "Center": tcell.KeyCenter,
89 "PageUp": tcell.KeyPgUp,
90 "PageDown": tcell.KeyPgDn,
91 "Home": tcell.KeyHome,
93 "Insert": tcell.KeyInsert,
94 "Delete": tcell.KeyDelete,
95 "Help": tcell.KeyHelp,
96 "Exit": tcell.KeyExit,
97 "Clear": tcell.KeyClear,
98 "Cancel": tcell.KeyCancel,
99 "Print": tcell.KeyPrint,
100 "Pause": tcell.KeyPause,
101 "Backtab": tcell.KeyBacktab,
166 "CtrlSpace": tcell.KeyCtrlSpace,
167 "CtrlA": tcell.KeyCtrlA,
168 "CtrlB": tcell.KeyCtrlB,
169 "CtrlC": tcell.KeyCtrlC,
170 "CtrlD": tcell.KeyCtrlD,
171 "CtrlE": tcell.KeyCtrlE,
172 "CtrlF": tcell.KeyCtrlF,
173 "CtrlG": tcell.KeyCtrlG,
174 "CtrlH": tcell.KeyCtrlH,
175 "CtrlI": tcell.KeyCtrlI,
176 "CtrlJ": tcell.KeyCtrlJ,
177 "CtrlK": tcell.KeyCtrlK,
178 "CtrlL": tcell.KeyCtrlL,
179 "CtrlM": tcell.KeyCtrlM,
180 "CtrlN": tcell.KeyCtrlN,
181 "CtrlO": tcell.KeyCtrlO,
182 "CtrlP": tcell.KeyCtrlP,
183 "CtrlQ": tcell.KeyCtrlQ,
184 "CtrlR": tcell.KeyCtrlR,
185 "CtrlS": tcell.KeyCtrlS,
186 "CtrlT": tcell.KeyCtrlT,
187 "CtrlU": tcell.KeyCtrlU,
188 "CtrlV": tcell.KeyCtrlV,
189 "CtrlW": tcell.KeyCtrlW,
190 "CtrlX": tcell.KeyCtrlX,
191 "CtrlY": tcell.KeyCtrlY,
192 "CtrlZ": tcell.KeyCtrlZ,
193 "CtrlLeftSq": tcell.KeyCtrlLeftSq,
194 "CtrlBackslash": tcell.KeyCtrlBackslash,
195 "CtrlRightSq": tcell.KeyCtrlRightSq,
196 "CtrlCarat": tcell.KeyCtrlCarat,
197 "CtrlUnderscore": tcell.KeyCtrlUnderscore,
198 "Backspace": tcell.KeyBackspace,
201 "Escape": tcell.KeyEscape,
202 "Enter": tcell.KeyEnter,
203 "Backspace2": tcell.KeyBackspace2,
205 // I renamed these keys to PageUp and PageDown but I don't want to break someone's keybindings
206 "PgUp": tcell.KeyPgUp,
207 "PgDown": tcell.KeyPgDn,
210 // The Key struct holds the data for a keypress (keycode + modifiers)
213 modifiers tcell.ModMask
217 // InitBindings initializes the keybindings for micro
218 func InitBindings() {
219 bindings = make(map[Key][]func(*View) bool)
221 var parsed map[string]string
222 defaults := DefaultBindings()
224 filename := configDir + "/bindings.json"
225 if _, e := os.Stat(filename); e == nil {
226 input, err := ioutil.ReadFile(filename)
228 TermMessage("Error reading bindings.json file: " + err.Error())
232 err = json.Unmarshal(input, &parsed)
234 TermMessage("Error reading bindings.json:", err.Error())
238 parseBindings(defaults)
239 parseBindings(parsed)
242 func parseBindings(userBindings map[string]string) {
243 for k, v := range userBindings {
248 // findKey will find binding Key 'b' using string 'k'
249 func findKey(k string) (b Key, ok bool) {
250 modifiers := tcell.ModNone
252 // First, we'll strip off all the modifiers in the name and add them to the
257 case strings.HasPrefix(k, "-"):
258 // We optionally support dashes between modifiers
260 case strings.HasPrefix(k, "Ctrl"):
262 modifiers |= tcell.ModCtrl
263 case strings.HasPrefix(k, "Alt"):
265 modifiers |= tcell.ModAlt
266 case strings.HasPrefix(k, "Shift"):
268 modifiers |= tcell.ModShift
274 // Control is handled specially, since some character codes in bindingKeys
275 // are different when Control is depressed. We should check for Control keys
277 if modifiers&tcell.ModCtrl != 0 {
278 // see if the key is in bindingKeys with the Ctrl prefix.
279 if code, ok := bindingKeys["Ctrl"+k]; ok {
280 // It is, we're done.
283 modifiers: modifiers,
289 // See if we can find the key in bindingKeys
290 if code, ok := bindingKeys[k]; ok {
293 modifiers: modifiers,
298 // If we were given one character, then we've got a rune.
301 keyCode: tcell.KeyRune,
302 modifiers: modifiers,
307 // We don't know what happened.
311 // findAction will find 'action' using string 'v'
312 func findAction(v string) (action func(*View) bool) {
313 action, ok := bindingActions[v]
315 // If the user seems to be binding a function that doesn't exist
316 // We hope that it's a lua function that exists and bind it to that
317 action = LuaFunctionBinding(v)
322 // BindKey takes a key and an action and binds the two together
323 func BindKey(k, v string) {
324 key, ok := findKey(k)
328 if v == "ToggleHelp" {
332 actionNames := strings.Split(v, ",")
333 actions := make([]func(*View) bool, 0, len(actionNames))
334 for _, actionName := range actionNames {
335 actions = append(actions, findAction(actionName))
338 bindings[key] = actions
341 // DefaultBindings returns a map containing micro's default keybindings
342 func DefaultBindings() map[string]string {
343 return map[string]string{
345 "Down": "CursorDown",
346 "Right": "CursorRight",
347 "Left": "CursorLeft",
348 "ShiftUp": "SelectUp",
349 "ShiftDown": "SelectDown",
350 "ShiftLeft": "SelectLeft",
351 "ShiftRight": "SelectRight",
352 "AltLeft": "WordLeft",
353 "AltRight": "WordRight",
354 "AltShiftRight": "SelectWordRight",
355 "AltShiftLeft": "SelectWordLeft",
356 "CtrlLeft": "StartOfLine",
357 "CtrlRight": "EndOfLine",
358 "CtrlShiftLeft": "SelectToStartOfLine",
359 "CtrlShiftRight": "SelectToEndOfLine",
360 "CtrlUp": "CursorStart",
361 "CtrlDown": "CursorEnd",
362 "CtrlShiftUp": "SelectToStart",
363 "CtrlShiftDown": "SelectToEnd",
364 "Enter": "InsertEnter",
365 "Space": "InsertSpace",
366 "Backspace": "Backspace",
367 "Backspace2": "Backspace",
368 "Alt-Backspace": "DeleteWordLeft",
369 "Alt-Backspace2": "DeleteWordLeft",
375 "CtrlP": "FindPrevious",
381 "CtrlD": "DuplicateLine",
383 "CtrlA": "SelectAll",
385 "CtrlRightSq": "PreviousTab",
386 "CtrlBackslash": "NextTab",
389 "PageUp": "CursorPageUp",
390 "PageDown": "CursorPageDown",
391 "CtrlG": "ToggleHelp",
392 "CtrlR": "ToggleRuler",
395 "Esc": "ClearStatus",
396 "CtrlB": "ShellMode",
398 "CtrlE": "CommandMode",
399 "CtrlW": "NextSplit",
401 // Emacs-style keybindings
402 "Alt-f": "WordRight",
404 "Alt-a": "StartOfLine",
405 "Alt-e": "EndOfLine",
407 "Alt-n": "CursorDown",