11 "github.com/zyedidia/json5"
12 "github.com/zyedidia/micro/internal/config"
13 "github.com/zyedidia/micro/internal/screen"
14 "github.com/zyedidia/tcell"
18 config.Bindings = DefaultBindings()
20 var parsed map[string]string
21 defaults := DefaultBindings()
23 filename := config.ConfigDir + "/bindings.json"
24 if _, e := os.Stat(filename); e == nil {
25 input, err := ioutil.ReadFile(filename)
27 screen.TermMessage("Error reading bindings.json file: " + err.Error())
31 err = json5.Unmarshal(input, &parsed)
33 screen.TermMessage("Error reading bindings.json:", err.Error())
37 for k, v := range defaults {
40 for k, v := range parsed {
45 func BindKey(k, v string) {
46 event, ok := findEvent(k)
48 screen.TermMessage(k, "is not a bindable event")
51 switch e := event.(type) {
60 config.Bindings[k] = v
63 // findEvent will find binding Key 'b' using string 'k'
64 func findEvent(k string) (b Event, ok bool) {
65 modifiers := tcell.ModNone
67 // First, we'll strip off all the modifiers in the name and add them to the
72 case strings.HasPrefix(k, "-"):
73 // We optionally support dashes between modifiers
75 case strings.HasPrefix(k, "Ctrl") && k != "CtrlH":
76 // CtrlH technically does not have a 'Ctrl' modifier because it is really backspace
78 modifiers |= tcell.ModCtrl
79 case strings.HasPrefix(k, "Alt"):
81 modifiers |= tcell.ModAlt
82 case strings.HasPrefix(k, "Shift"):
84 modifiers |= tcell.ModShift
85 case strings.HasPrefix(k, "\x1b"):
86 screen.Screen.RegisterRawSeq(k)
96 return KeyEvent{}, false
99 // Control is handled in a special way, since the terminal sends explicitly
100 // marked escape sequences for control keys
101 // We should check for Control keys first
102 if modifiers&tcell.ModCtrl != 0 {
103 // see if the key is in bindingKeys with the Ctrl prefix.
104 k = string(unicode.ToUpper(rune(k[0]))) + k[1:]
105 if code, ok := keyEvents["Ctrl"+k]; ok {
107 // Special case for escape, for some reason tcell doesn't send it with the esc character
108 if code < 256 && code != 27 {
111 // It is, we're done.
120 // See if we can find the key in bindingKeys
121 if code, ok := keyEvents[k]; ok {
123 // Special case for escape, for some reason tcell doesn't send it with the esc character
124 if code < 256 && code != 27 {
134 // See if we can find the key in bindingMouse
135 if code, ok := mouseEvents[k]; ok {
142 // If we were given one character, then we've got a rune.
151 // We don't know what happened.
152 return KeyEvent{}, false
155 // TryBindKey tries to bind a key by writing to config.ConfigDir/bindings.json
156 // Returns true if the keybinding already existed and a possible error
157 func TryBindKey(k, v string, overwrite bool) (bool, error) {
159 var parsed map[string]string
161 filename := config.ConfigDir + "/bindings.json"
162 if _, e = os.Stat(filename); e == nil {
163 input, err := ioutil.ReadFile(filename)
165 return false, errors.New("Error reading bindings.json file: " + err.Error())
168 err = json5.Unmarshal(input, &parsed)
170 return false, errors.New("Error reading bindings.json: " + err.Error())
173 key, ok := findEvent(k)
175 return false, errors.New("Invalid event " + k)
179 for ev := range parsed {
180 if e, ok := findEvent(ev); ok {
191 if found && !overwrite {
199 txt, _ := json.MarshalIndent(parsed, "", " ")
200 return true, ioutil.WriteFile(filename, append(txt, '\n'), 0644)
205 // UnbindKey removes the binding for a key from the bindings.json file
206 func UnbindKey(k string) error {
208 var parsed map[string]string
210 filename := config.ConfigDir + "/bindings.json"
211 if _, e = os.Stat(filename); e == nil {
212 input, err := ioutil.ReadFile(filename)
214 return errors.New("Error reading bindings.json file: " + err.Error())
217 err = json5.Unmarshal(input, &parsed)
219 return errors.New("Error reading bindings.json: " + err.Error())
222 key, ok := findEvent(k)
224 return errors.New("Invalid event " + k)
227 for ev := range parsed {
228 if e, ok := findEvent(ev); ok {
236 defaults := DefaultBindings()
237 if a, ok := defaults[k]; ok {
239 } else if _, ok := config.Bindings[k]; ok {
240 delete(config.Bindings, k)
243 txt, _ := json.MarshalIndent(parsed, "", " ")
244 return ioutil.WriteFile(filename, append(txt, '\n'), 0644)
249 var mouseEvents = map[string]tcell.ButtonMask{
250 "MouseLeft": tcell.Button1,
251 "MouseMiddle": tcell.Button2,
252 "MouseRight": tcell.Button3,
253 "MouseWheelUp": tcell.WheelUp,
254 "MouseWheelDown": tcell.WheelDown,
255 "MouseWheelLeft": tcell.WheelLeft,
256 "MouseWheelRight": tcell.WheelRight,
259 var keyEvents = map[string]tcell.Key{
261 "Down": tcell.KeyDown,
262 "Right": tcell.KeyRight,
263 "Left": tcell.KeyLeft,
264 "UpLeft": tcell.KeyUpLeft,
265 "UpRight": tcell.KeyUpRight,
266 "DownLeft": tcell.KeyDownLeft,
267 "DownRight": tcell.KeyDownRight,
268 "Center": tcell.KeyCenter,
269 "PageUp": tcell.KeyPgUp,
270 "PageDown": tcell.KeyPgDn,
271 "Home": tcell.KeyHome,
273 "Insert": tcell.KeyInsert,
274 "Delete": tcell.KeyDelete,
275 "Help": tcell.KeyHelp,
276 "Exit": tcell.KeyExit,
277 "Clear": tcell.KeyClear,
278 "Cancel": tcell.KeyCancel,
279 "Print": tcell.KeyPrint,
280 "Pause": tcell.KeyPause,
281 "Backtab": tcell.KeyBacktab,
346 "CtrlSpace": tcell.KeyCtrlSpace,
347 "CtrlA": tcell.KeyCtrlA,
348 "CtrlB": tcell.KeyCtrlB,
349 "CtrlC": tcell.KeyCtrlC,
350 "CtrlD": tcell.KeyCtrlD,
351 "CtrlE": tcell.KeyCtrlE,
352 "CtrlF": tcell.KeyCtrlF,
353 "CtrlG": tcell.KeyCtrlG,
354 "CtrlH": tcell.KeyCtrlH,
355 "CtrlI": tcell.KeyCtrlI,
356 "CtrlJ": tcell.KeyCtrlJ,
357 "CtrlK": tcell.KeyCtrlK,
358 "CtrlL": tcell.KeyCtrlL,
359 "CtrlM": tcell.KeyCtrlM,
360 "CtrlN": tcell.KeyCtrlN,
361 "CtrlO": tcell.KeyCtrlO,
362 "CtrlP": tcell.KeyCtrlP,
363 "CtrlQ": tcell.KeyCtrlQ,
364 "CtrlR": tcell.KeyCtrlR,
365 "CtrlS": tcell.KeyCtrlS,
366 "CtrlT": tcell.KeyCtrlT,
367 "CtrlU": tcell.KeyCtrlU,
368 "CtrlV": tcell.KeyCtrlV,
369 "CtrlW": tcell.KeyCtrlW,
370 "CtrlX": tcell.KeyCtrlX,
371 "CtrlY": tcell.KeyCtrlY,
372 "CtrlZ": tcell.KeyCtrlZ,
373 "CtrlLeftSq": tcell.KeyCtrlLeftSq,
374 "CtrlBackslash": tcell.KeyCtrlBackslash,
375 "CtrlRightSq": tcell.KeyCtrlRightSq,
376 "CtrlCarat": tcell.KeyCtrlCarat,
377 "CtrlUnderscore": tcell.KeyCtrlUnderscore,
380 "Escape": tcell.KeyEscape,
381 "Enter": tcell.KeyEnter,
382 "Backspace": tcell.KeyBackspace2,
383 "OldBackspace": tcell.KeyBackspace,
385 // I renamed these keys to PageUp and PageDown but I don't want to break someone's keybindings
386 "PgUp": tcell.KeyPgUp,
387 "PgDown": tcell.KeyPgDn,