]> git.lizzy.rs Git - micro.git/blobdiff - cmd/micro/bindings.go
Add JumpToMatchingBrace action
[micro.git] / cmd / micro / bindings.go
index 7f5dccdcc56cae0f28386a577d595e6a192f0ea5..c14ce7240961550f3b3d53fe7a10fb06309bb820 100644 (file)
@@ -1,14 +1,17 @@
 package main
 
 import (
+       "fmt"
        "io/ioutil"
        "os"
        "strings"
+       "unicode"
 
        "github.com/flynn/json5"
        "github.com/zyedidia/tcell"
 )
 
+var bindingsStr map[string]string
 var bindings map[Key][]func(*View, bool) bool
 var mouseBindings map[Key][]func(*View, bool, *tcell.EventMouse) bool
 var helpBinding string
@@ -42,6 +45,8 @@ var bindingActions = map[string]func(*View, bool) bool{
        "DeleteWordLeft":        (*View).DeleteWordLeft,
        "SelectToStartOfLine":   (*View).SelectToStartOfLine,
        "SelectToEndOfLine":     (*View).SelectToEndOfLine,
+       "ParagraphPrevious":     (*View).ParagraphPrevious,
+       "ParagraphNext":         (*View).ParagraphNext,
        "InsertNewline":         (*View).InsertNewline,
        "InsertSpace":           (*View).InsertSpace,
        "Backspace":             (*View).Backspace,
@@ -85,6 +90,7 @@ var bindingActions = map[string]func(*View, bool) bool{
        "ClearStatus":           (*View).ClearStatus,
        "ShellMode":             (*View).ShellMode,
        "CommandMode":           (*View).CommandMode,
+       "ToggleOverwriteMode":   (*View).ToggleOverwriteMode,
        "Escape":                (*View).Escape,
        "Quit":                  (*View).Quit,
        "QuitAll":               (*View).QuitAll,
@@ -105,6 +111,7 @@ var bindingActions = map[string]func(*View, bool) bool{
        "RemoveMultiCursor":     (*View).RemoveMultiCursor,
        "RemoveAllMultiCursors": (*View).RemoveAllMultiCursors,
        "SkipMultiCursor":       (*View).SkipMultiCursor,
+       "JumpToMatchingBrace":   (*View).JumpToMatchingBrace,
 
        // This was changed to InsertNewline but I don't want to break backwards compatibility
        "InsertEnter": (*View).InsertNewline,
@@ -258,11 +265,13 @@ type Key struct {
        modifiers tcell.ModMask
        buttons   tcell.ButtonMask
        r         rune
+       escape    string
 }
 
 // InitBindings initializes the keybindings for micro
 func InitBindings() {
        bindings = make(map[Key][]func(*View, bool) bool)
+       bindingsStr = make(map[string]string)
        mouseBindings = make(map[Key][]func(*View, bool, *tcell.EventMouse) bool)
 
        var parsed map[string]string
@@ -314,6 +323,14 @@ modSearch:
                case strings.HasPrefix(k, "Shift"):
                        k = k[5:]
                        modifiers |= tcell.ModShift
+               case strings.HasPrefix(k, "\x1b"):
+                       return Key{
+                               keyCode:   -1,
+                               modifiers: modifiers,
+                               buttons:   -1,
+                               r:         0,
+                               escape:    k,
+                       }, true
                default:
                        break modSearch
                }
@@ -324,6 +341,7 @@ modSearch:
        // first.
        if modifiers&tcell.ModCtrl != 0 {
                // see if the key is in bindingKeys with the Ctrl prefix.
+               k = string(unicode.ToUpper(rune(k[0]))) + k[1:]
                if code, ok := bindingKeys["Ctrl"+k]; ok {
                        // It is, we're done.
                        return Key{
@@ -389,6 +407,43 @@ func findMouseAction(v string) func(*View, bool, *tcell.EventMouse) bool {
        return action
 }
 
+// TryBindKey tries to bind a key by writing to configDir/bindings.json
+// This function is unused for now
+func TryBindKey(k, v string) {
+       filename := configDir + "/bindings.json"
+       if _, e := os.Stat(filename); e == nil {
+               input, err := ioutil.ReadFile(filename)
+               if err != nil {
+                       TermMessage("Error reading bindings.json file: " + err.Error())
+                       return
+               }
+
+               conflict := -1
+               lines := strings.Split(string(input), "\n")
+               for i, l := range lines {
+                       parts := strings.Split(l, ":")
+                       if len(parts) >= 2 {
+                               if strings.Contains(parts[0], k) {
+                                       conflict = i
+                                       TermMessage("Warning: Keybinding conflict:", k, " has been overwritten")
+                               }
+                       }
+               }
+
+               binding := fmt.Sprintf("    \"%s\": \"%s\",", k, v)
+               if conflict == -1 {
+                       lines = append([]string{lines[0], binding}, lines[conflict:]...)
+               } else {
+                       lines = append(append(lines[:conflict], binding), lines[conflict+1:]...)
+               }
+               txt := strings.Join(lines, "\n")
+               err = ioutil.WriteFile(filename, []byte(txt), 0644)
+               if err != nil {
+                       TermMessage("Error")
+               }
+       }
+}
+
 // BindKey takes a key and an action and binds the two together
 func BindKey(k, v string) {
        key, ok := findKey(k)
@@ -413,6 +468,7 @@ func BindKey(k, v string) {
        if actionNames[0] == "UnbindKey" {
                delete(bindings, key)
                delete(mouseBindings, key)
+               delete(bindingsStr, k)
                if len(actionNames) == 1 {
                        return
                }
@@ -423,6 +479,12 @@ func BindKey(k, v string) {
        for _, actionName := range actionNames {
                if strings.HasPrefix(actionName, "Mouse") {
                        mouseActions = append(mouseActions, findMouseAction(actionName))
+               } else if strings.HasPrefix(actionName, "command:") {
+                       cmd := strings.SplitN(actionName, ":", 2)[1]
+                       actions = append(actions, CommandAction(cmd))
+               } else if strings.HasPrefix(actionName, "command-edit:") {
+                       cmd := strings.SplitN(actionName, ":", 2)[1]
+                       actions = append(actions, CommandEditAction(cmd))
                } else {
                        actions = append(actions, findAction(actionName))
                }
@@ -432,6 +494,7 @@ func BindKey(k, v string) {
                // Can't have a binding be both mouse and normal
                delete(mouseBindings, key)
                bindings[key] = actions
+               bindingsStr[k] = v
        } else if len(mouseActions) > 0 {
                // Can't have a binding be both mouse and normal
                delete(bindings, key)
@@ -466,6 +529,8 @@ func DefaultBindings() map[string]string {
                "CtrlDown":       "CursorEnd",
                "CtrlShiftUp":    "SelectToStart",
                "CtrlShiftDown":  "SelectToEnd",
+               "Alt-{":          "ParagraphPrevious",
+               "Alt-}":          "ParagraphNext",
                "Enter":          "InsertNewline",
                "CtrlH":          "Backspace",
                "Backspace":      "Backspace",
@@ -508,6 +573,7 @@ func DefaultBindings() map[string]string {
                "CtrlW":          "NextSplit",
                "CtrlU":          "ToggleMacro",
                "CtrlJ":          "PlayMacro",
+               "Insert":         "ToggleOverwriteMode",
 
                // Emacs-style keybindings
                "Alt-f": "WordRight",