]> git.lizzy.rs Git - micro.git/blobdiff - cmd/micro/bindings.go
Log erroneous keybindings
[micro.git] / cmd / micro / bindings.go
index f94309ec9f8e411c71c807dd84c7285999529881..b537a9e12e9241082c1005e2baf533b0c7e63d2e 100644 (file)
@@ -1,22 +1,18 @@
 package main
 
 import (
-       "encoding/json"
        "io/ioutil"
        "os"
-       "strconv"
        "strings"
-       "time"
 
-       "github.com/mitchellh/go-homedir"
-       "github.com/zyedidia/clipboard"
+       "github.com/zyedidia/json5/encoding/json5"
        "github.com/zyedidia/tcell"
 )
 
-var bindings map[Key][]func(*View) bool
+var bindings map[Key][]func(*View, bool) bool
 var helpBinding string
 
-var bindingActions = map[string]func(*View) bool{
+var bindingActions = map[string]func(*View, bool) bool{
        "CursorUp":            (*View).CursorUp,
        "CursorDown":          (*View).CursorDown,
        "CursorPageUp":        (*View).CursorPageUp,
@@ -39,7 +35,7 @@ var bindingActions = map[string]func(*View) bool{
        "DeleteWordLeft":      (*View).DeleteWordLeft,
        "SelectToStartOfLine": (*View).SelectToStartOfLine,
        "SelectToEndOfLine":   (*View).SelectToEndOfLine,
-       "InsertEnter":         (*View).InsertEnter,
+       "InsertNewline":       (*View).InsertNewline,
        "InsertSpace":         (*View).InsertSpace,
        "Backspace":           (*View).Backspace,
        "Delete":              (*View).Delete,
@@ -48,13 +44,21 @@ var bindingActions = map[string]func(*View) bool{
        "Find":                (*View).Find,
        "FindNext":            (*View).FindNext,
        "FindPrevious":        (*View).FindPrevious,
+       "Center":              (*View).Center,
        "Undo":                (*View).Undo,
        "Redo":                (*View).Redo,
        "Copy":                (*View).Copy,
        "Cut":                 (*View).Cut,
        "CutLine":             (*View).CutLine,
        "DuplicateLine":       (*View).DuplicateLine,
+       "DeleteLine":          (*View).DeleteLine,
+       "MoveLinesUp":         (*View).MoveLinesUp,
+       "MoveLinesDown":       (*View).MoveLinesDown,
+       "IndentSelection":     (*View).IndentSelection,
+       "OutdentSelection":    (*View).OutdentSelection,
+       "OutdentLine":         (*View).OutdentLine,
        "Paste":               (*View).Paste,
+       "PastePrimary":        (*View).PastePrimary,
        "SelectAll":           (*View).SelectAll,
        "OpenFile":            (*View).OpenFile,
        "Start":               (*View).Start,
@@ -71,7 +75,22 @@ var bindingActions = map[string]func(*View) bool{
        "ClearStatus":         (*View).ClearStatus,
        "ShellMode":           (*View).ShellMode,
        "CommandMode":         (*View).CommandMode,
+       "Escape":              (*View).Escape,
        "Quit":                (*View).Quit,
+       "QuitAll":             (*View).QuitAll,
+       "AddTab":              (*View).AddTab,
+       "PreviousTab":         (*View).PreviousTab,
+       "NextTab":             (*View).NextTab,
+       "NextSplit":           (*View).NextSplit,
+       "PreviousSplit":       (*View).PreviousSplit,
+       "Unsplit":             (*View).Unsplit,
+       "VSplit":              (*View).VSplitBinding,
+       "HSplit":              (*View).HSplitBinding,
+       "ToggleMacro":         (*View).ToggleMacro,
+       "PlayMacro":           (*View).PlayMacro,
+
+       // This was changed to InsertNewline but I don't want to break backwards compatibility
+       "InsertEnter": (*View).InsertNewline,
 }
 
 var bindingKeys = map[string]tcell.Key{
@@ -193,12 +212,11 @@ var bindingKeys = map[string]tcell.Key{
        "CtrlRightSq":    tcell.KeyCtrlRightSq,
        "CtrlCarat":      tcell.KeyCtrlCarat,
        "CtrlUnderscore": tcell.KeyCtrlUnderscore,
-       "Backspace":      tcell.KeyBackspace,
        "Tab":            tcell.KeyTab,
        "Esc":            tcell.KeyEsc,
        "Escape":         tcell.KeyEscape,
        "Enter":          tcell.KeyEnter,
-       "Backspace2":     tcell.KeyBackspace2,
+       "Backspace":      tcell.KeyBackspace2,
 
        // I renamed these keys to PageUp and PageDown but I don't want to break someone's keybindings
        "PgUp":   tcell.KeyPgUp,
@@ -214,7 +232,7 @@ type Key struct {
 
 // InitBindings initializes the keybindings for micro
 func InitBindings() {
-       bindings = make(map[Key][]func(*View) bool)
+       bindings = make(map[Key][]func(*View, bool) bool)
 
        var parsed map[string]string
        defaults := DefaultBindings()
@@ -227,7 +245,7 @@ func InitBindings() {
                        return
                }
 
-               err = json.Unmarshal(input, &parsed)
+               err = json5.Unmarshal(input, &parsed)
                if err != nil {
                        TermMessage("Error reading bindings.json:", err.Error())
                }
@@ -255,7 +273,8 @@ modSearch:
                case strings.HasPrefix(k, "-"):
                        // We optionally support dashes between modifiers
                        k = k[1:]
-               case strings.HasPrefix(k, "Ctrl"):
+               case strings.HasPrefix(k, "Ctrl") && k != "CtrlH":
+                       // CtrlH technically does not have a 'Ctrl' modifier because it is really backspace
                        k = k[4:]
                        modifiers |= tcell.ModCtrl
                case strings.HasPrefix(k, "Alt"):
@@ -307,7 +326,7 @@ modSearch:
 }
 
 // findAction will find 'action' using string 'v'
-func findAction(v string) (action func(*View) bool) {
+func findAction(v string) (action func(*View, bool) bool) {
        action, ok := bindingActions[v]
        if !ok {
                // If the user seems to be binding a function that doesn't exist
@@ -321,6 +340,7 @@ func findAction(v string) (action func(*View) bool) {
 func BindKey(k, v string) {
        key, ok := findKey(k)
        if !ok {
+               TermMessage("Unknown keybinding: " + k)
                return
        }
        if v == "ToggleHelp" {
@@ -328,7 +348,7 @@ func BindKey(k, v string) {
        }
 
        actionNames := strings.Split(v, ",")
-       actions := make([]func(*View) bool, 0, len(actionNames))
+       actions := make([]func(*View, bool) bool, 0, len(actionNames))
        for _, actionName := range actionNames {
                actions = append(actions, findAction(actionName))
        }
@@ -349,6 +369,8 @@ func DefaultBindings() map[string]string {
                "ShiftRight":     "SelectRight",
                "AltLeft":        "WordLeft",
                "AltRight":       "WordRight",
+               "AltUp":          "MoveLinesUp",
+               "AltDown":        "MoveLinesDown",
                "AltShiftRight":  "SelectWordRight",
                "AltShiftLeft":   "SelectWordLeft",
                "CtrlLeft":       "StartOfLine",
@@ -359,13 +381,13 @@ func DefaultBindings() map[string]string {
                "CtrlDown":       "CursorEnd",
                "CtrlShiftUp":    "SelectToStart",
                "CtrlShiftDown":  "SelectToEnd",
-               "Enter":          "InsertEnter",
-               "Space":          "InsertSpace",
+               "Enter":          "InsertNewline",
+               "CtrlH":          "Backspace",
                "Backspace":      "Backspace",
-               "Backspace2":     "Backspace",
+               "Alt-CtrlH":      "DeleteWordLeft",
                "Alt-Backspace":  "DeleteWordLeft",
-               "Alt-Backspace2": "DeleteWordLeft",
-               "Tab":            "InsertTab",
+               "Tab":            "IndentSelection,InsertTab",
+               "Backtab":        "OutdentSelection,OutdentLine",
                "CtrlO":          "OpenFile",
                "CtrlS":          "Save",
                "CtrlF":          "Find",
@@ -379,18 +401,25 @@ func DefaultBindings() map[string]string {
                "CtrlD":          "DuplicateLine",
                "CtrlV":          "Paste",
                "CtrlA":          "SelectAll",
-               "Home":           "Start",
-               "End":            "End",
+               "CtrlT":          "AddTab",
+               "CtrlRightSq":    "PreviousTab",
+               "CtrlBackslash":  "NextTab",
+               "Home":           "StartOfLine",
+               "End":            "EndOfLine",
+               "CtrlHome":       "CursorStart",
+               "CtrlEnd":        "CursorEnd",
                "PageUp":         "CursorPageUp",
                "PageDown":       "CursorPageDown",
                "CtrlG":          "ToggleHelp",
                "CtrlR":          "ToggleRuler",
                "CtrlL":          "JumpLine",
                "Delete":         "Delete",
-               "Esc":            "ClearStatus",
                "CtrlB":          "ShellMode",
                "CtrlQ":          "Quit",
                "CtrlE":          "CommandMode",
+               "CtrlW":          "NextSplit",
+               "CtrlU":          "ToggleMacro",
+               "CtrlJ":          "PlayMacro",
 
                // Emacs-style keybindings
                "Alt-f": "WordRight",
@@ -399,678 +428,13 @@ func DefaultBindings() map[string]string {
                "Alt-e": "EndOfLine",
                "Alt-p": "CursorUp",
                "Alt-n": "CursorDown",
-       }
-}
-
-// CursorUp moves the cursor up
-func (v *View) CursorUp() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.SetLoc(v.Cursor.CurSelection[0])
-               v.Cursor.ResetSelection()
-       }
-       v.Cursor.Up()
-       return true
-}
-
-// CursorDown moves the cursor down
-func (v *View) CursorDown() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.SetLoc(v.Cursor.CurSelection[1])
-               v.Cursor.ResetSelection()
-       }
-       v.Cursor.Down()
-       return true
-}
-
-// CursorLeft moves the cursor left
-func (v *View) CursorLeft() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.SetLoc(v.Cursor.CurSelection[0])
-               v.Cursor.ResetSelection()
-       } else {
-               v.Cursor.Left()
-       }
-       return true
-}
-
-// CursorRight moves the cursor right
-func (v *View) CursorRight() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.SetLoc(v.Cursor.CurSelection[1] - 1)
-               v.Cursor.ResetSelection()
-       } else {
-               v.Cursor.Right()
-       }
-       return true
-}
-
-// WordRight moves the cursor one word to the right
-func (v *View) WordRight() bool {
-       v.Cursor.WordRight()
-       return true
-}
-
-// WordLeft moves the cursor one word to the left
-func (v *View) WordLeft() bool {
-       v.Cursor.WordLeft()
-       return true
-}
-
-// SelectUp selects up one line
-func (v *View) SelectUp() bool {
-       loc := v.Cursor.Loc()
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.Cursor.Up()
-       v.Cursor.SelectTo(v.Cursor.Loc())
-       return true
-}
-
-// SelectDown selects down one line
-func (v *View) SelectDown() bool {
-       loc := v.Cursor.Loc()
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.Cursor.Down()
-       v.Cursor.SelectTo(v.Cursor.Loc())
-       return true
-}
-
-// SelectLeft selects the character to the left of the cursor
-func (v *View) SelectLeft() bool {
-       loc := v.Cursor.Loc()
-       count := v.Buf.Len() - 1
-       if loc > count {
-               loc = count
-       }
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.Cursor.Left()
-       v.Cursor.SelectTo(v.Cursor.Loc())
-       return true
-}
-
-// SelectRight selects the character to the right of the cursor
-func (v *View) SelectRight() bool {
-       loc := v.Cursor.Loc()
-       count := v.Buf.Len() - 1
-       if loc > count {
-               loc = count
-       }
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.Cursor.Right()
-       v.Cursor.SelectTo(v.Cursor.Loc())
-       return true
-}
-
-// SelectWordRight selects the word to the right of the cursor
-func (v *View) SelectWordRight() bool {
-       loc := v.Cursor.Loc()
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.Cursor.WordRight()
-       v.Cursor.SelectTo(v.Cursor.Loc())
-       return true
-}
-
-// SelectWordLeft selects the word to the left of the cursor
-func (v *View) SelectWordLeft() bool {
-       loc := v.Cursor.Loc()
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.Cursor.WordLeft()
-       v.Cursor.SelectTo(v.Cursor.Loc())
-       return true
-}
-
-// StartOfLine moves the cursor to the start of the line
-func (v *View) StartOfLine() bool {
-       v.Cursor.Start()
-       return true
-}
-
-// EndOfLine moves the cursor to the end of the line
-func (v *View) EndOfLine() bool {
-       v.Cursor.End()
-       return true
-}
-
-// SelectToStartOfLine selects to the start of the current line
-func (v *View) SelectToStartOfLine() bool {
-       loc := v.Cursor.Loc()
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.Cursor.Start()
-       v.Cursor.SelectTo(v.Cursor.Loc())
-       return true
-}
-
-// SelectToEndOfLine selects to the end of the current line
-func (v *View) SelectToEndOfLine() bool {
-       loc := v.Cursor.Loc()
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.Cursor.End()
-       v.Cursor.SelectTo(v.Cursor.Loc())
-       return true
-}
-
-// CursorStart moves the cursor to the start of the buffer
-func (v *View) CursorStart() bool {
-       v.Cursor.X = 0
-       v.Cursor.Y = 0
-       return true
-}
-
-// CursorEnd moves the cursor to the end of the buffer
-func (v *View) CursorEnd() bool {
-       v.Cursor.SetLoc(v.Buf.Len())
-       return true
-}
-
-// SelectToStart selects the text from the cursor to the start of the buffer
-func (v *View) SelectToStart() bool {
-       loc := v.Cursor.Loc()
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.CursorStart()
-       v.Cursor.SelectTo(0)
-       return true
-}
-
-// SelectToEnd selects the text from the cursor to the end of the buffer
-func (v *View) SelectToEnd() bool {
-       loc := v.Cursor.Loc()
-       if !v.Cursor.HasSelection() {
-               v.Cursor.OrigSelection[0] = loc
-       }
-       v.CursorEnd()
-       v.Cursor.SelectTo(v.Buf.Len())
-       return true
-}
-
-// InsertSpace inserts a space
-func (v *View) InsertSpace() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-       }
-       v.Buf.Insert(v.Cursor.Loc(), " ")
-       v.Cursor.Right()
-       return true
-}
-
-// InsertEnter inserts a newline plus possible some whitespace if autoindent is on
-func (v *View) InsertEnter() bool {
-       // Insert a newline
-       if v.Cursor.HasSelection() {
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-       }
-
-       v.Buf.Insert(v.Cursor.Loc(), "\n")
-       ws := GetLeadingWhitespace(v.Buf.Lines[v.Cursor.Y])
-       v.Cursor.Right()
-
-       if settings["autoindent"].(bool) {
-               v.Buf.Insert(v.Cursor.Loc(), ws)
-               for i := 0; i < len(ws); i++ {
-                       v.Cursor.Right()
-               }
-       }
-       v.Cursor.LastVisualX = v.Cursor.GetVisualX()
-       return true
-}
-
-// Backspace deletes the previous character
-func (v *View) Backspace() bool {
-       // Delete a character
-       if v.Cursor.HasSelection() {
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-       } else if v.Cursor.Loc() > 0 {
-               // We have to do something a bit hacky here because we want to
-               // delete the line by first moving left and then deleting backwards
-               // but the undo redo would place the cursor in the wrong place
-               // So instead we move left, save the position, move back, delete
-               // and restore the position
-
-               // If the user is using spaces instead of tabs and they are deleting
-               // whitespace at the start of the line, we should delete as if its a
-               // tab (tabSize number of spaces)
-               lineStart := v.Buf.Lines[v.Cursor.Y][:v.Cursor.X]
-               tabSize := int(settings["tabsize"].(float64))
-               if settings["tabstospaces"].(bool) && IsSpaces(lineStart) && len(lineStart) != 0 && len(lineStart)%tabSize == 0 {
-                       loc := v.Cursor.Loc()
-                       v.Cursor.SetLoc(loc - tabSize)
-                       cx, cy := v.Cursor.X, v.Cursor.Y
-                       v.Cursor.SetLoc(loc)
-                       v.Buf.Remove(loc-tabSize, loc)
-                       v.Cursor.X, v.Cursor.Y = cx, cy
-               } else {
-                       v.Cursor.Left()
-                       cx, cy := v.Cursor.X, v.Cursor.Y
-                       v.Cursor.Right()
-                       loc := v.Cursor.Loc()
-                       v.Buf.Remove(loc-1, loc)
-                       v.Cursor.X, v.Cursor.Y = cx, cy
-               }
-       }
-       v.Cursor.LastVisualX = v.Cursor.GetVisualX()
-       return true
-}
-
-// DeleteWordRight deletes the word to the right of the cursor
-func (v *View) DeleteWordRight() bool {
-       v.SelectWordRight()
-       if v.Cursor.HasSelection() {
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-       }
-       return true
-}
-
-// DeleteWordLeft deletes the word to the left of the cursor
-func (v *View) DeleteWordLeft() bool {
-       v.SelectWordLeft()
-       if v.Cursor.HasSelection() {
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-       }
-       return true
-}
-
-// Delete deletes the next character
-func (v *View) Delete() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-       } else {
-               loc := v.Cursor.Loc()
-               if loc < v.Buf.Len() {
-                       v.Buf.Remove(loc, loc+1)
-               }
-       }
-       return true
-}
-
-// InsertTab inserts a tab or spaces
-func (v *View) InsertTab() bool {
-       // Insert a tab
-       if v.Cursor.HasSelection() {
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-       }
-       if settings["tabstospaces"].(bool) {
-               tabSize := int(settings["tabsize"].(float64))
-               v.Buf.Insert(v.Cursor.Loc(), Spaces(tabSize))
-               for i := 0; i < tabSize; i++ {
-                       v.Cursor.Right()
-               }
-       } else {
-               v.Buf.Insert(v.Cursor.Loc(), "\t")
-               v.Cursor.Right()
-       }
-       return true
-}
-
-// Save the buffer to disk
-func (v *View) Save() bool {
-       if v.helpOpen {
-               // We can't save the help text
-               return false
-       }
-       // If this is an empty buffer, ask for a filename
-       if v.Buf.Path == "" {
-               filename, canceled := messenger.Prompt("Filename: ", "Save")
-               if !canceled {
-                       v.Buf.Path = filename
-                       v.Buf.Name = filename
-               } else {
-                       return true
-               }
-       }
-       err := v.Buf.Save()
-       if err != nil {
-               messenger.Error(err.Error())
-       } else {
-               messenger.Message("Saved " + v.Buf.Path)
-       }
-       return true
-}
-
-// Find opens a prompt and searches forward for the input
-func (v *View) Find() bool {
-       if v.Cursor.HasSelection() {
-               searchStart = v.Cursor.CurSelection[1]
-       } else {
-               searchStart = ToCharPos(v.Cursor.X, v.Cursor.Y, v.Buf)
-       }
-       BeginSearch()
-       return true
-}
-
-// FindNext searches forwards for the last used search term
-func (v *View) FindNext() bool {
-       if v.Cursor.HasSelection() {
-               searchStart = v.Cursor.CurSelection[1]
-       } else {
-               searchStart = ToCharPos(v.Cursor.X, v.Cursor.Y, v.Buf)
-       }
-       messenger.Message("Finding: " + lastSearch)
-       Search(lastSearch, v, true)
-       return true
-}
-
-// FindPrevious searches backwards for the last used search term
-func (v *View) FindPrevious() bool {
-       if v.Cursor.HasSelection() {
-               searchStart = v.Cursor.CurSelection[0]
-       } else {
-               searchStart = ToCharPos(v.Cursor.X, v.Cursor.Y, v.Buf)
-       }
-       messenger.Message("Finding: " + lastSearch)
-       Search(lastSearch, v, false)
-       return true
-}
-
-// Undo undoes the last action
-func (v *View) Undo() bool {
-       v.Buf.Undo()
-       messenger.Message("Undid action")
-       return true
-}
-
-// Redo redoes the last action
-func (v *View) Redo() bool {
-       v.Buf.Redo()
-       messenger.Message("Redid action")
-       return true
-}
-
-// Copy the selection to the system clipboard
-func (v *View) Copy() bool {
-       if v.Cursor.HasSelection() {
-               clipboard.WriteAll(v.Cursor.GetSelection())
-               v.freshClip = true
-               messenger.Message("Copied selection")
-       }
-       return true
-}
-
-// CutLine cuts the current line to the clipboard
-func (v *View) CutLine() bool {
-       v.Cursor.SelectLine()
-       if !v.Cursor.HasSelection() {
-               return false
-       }
-       if v.freshClip == true {
-               if v.Cursor.HasSelection() {
-                       if clip, err := clipboard.ReadAll(); err != nil {
-                               messenger.Error(err)
-                       } else {
-                               clipboard.WriteAll(clip + v.Cursor.GetSelection())
-                       }
-               }
-       } else if time.Since(v.lastCutTime)/time.Second > 10*time.Second || v.freshClip == false {
-               v.Copy()
-       }
-       v.freshClip = true
-       v.lastCutTime = time.Now()
-       v.Cursor.DeleteSelection()
-       v.Cursor.ResetSelection()
-       messenger.Message("Cut line")
-       return true
-}
-
-// Cut the selection to the system clipboard
-func (v *View) Cut() bool {
-       if v.Cursor.HasSelection() {
-               clipboard.WriteAll(v.Cursor.GetSelection())
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-               v.freshClip = true
-               messenger.Message("Cut selection")
-       }
-       return true
-}
-
-// DuplicateLine duplicates the current line
-func (v *View) DuplicateLine() bool {
-       v.Cursor.End()
-       v.Buf.Insert(v.Cursor.Loc(), "\n"+v.Buf.Lines[v.Cursor.Y])
-       v.Cursor.Right()
-       messenger.Message("Duplicated line")
-       return true
-}
-
-// Paste whatever is in the system clipboard into the buffer
-// Delete and paste if the user has a selection
-func (v *View) Paste() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.DeleteSelection()
-               v.Cursor.ResetSelection()
-       }
-       clip, _ := clipboard.ReadAll()
-       v.Buf.Insert(v.Cursor.Loc(), clip)
-       v.Cursor.SetLoc(v.Cursor.Loc() + Count(clip))
-       v.freshClip = false
-       messenger.Message("Pasted clipboard")
-       return true
-}
-
-// SelectAll selects the entire buffer
-func (v *View) SelectAll() bool {
-       v.Cursor.CurSelection[0] = 0
-       v.Cursor.CurSelection[1] = v.Buf.Len()
-       // Put the cursor at the beginning
-       v.Cursor.X = 0
-       v.Cursor.Y = 0
-       return true
-}
-
-// OpenFile opens a new file in the buffer
-func (v *View) OpenFile() bool {
-       if v.CanClose("Continue? (yes, no, save) ") {
-               filename, canceled := messenger.Prompt("File to open: ", "Open")
-               if canceled {
-                       return true
-               }
-               home, _ := homedir.Dir()
-               filename = strings.Replace(filename, "~", home, 1)
-               file, err := ioutil.ReadFile(filename)
-
-               if err != nil {
-                       messenger.Error(err.Error())
-                       return true
-               }
-               buf := NewBuffer(string(file), filename)
-               v.OpenBuffer(buf)
-       }
-       return true
-}
-
-// Start moves the viewport to the start of the buffer
-func (v *View) Start() bool {
-       v.Topline = 0
-       return false
-}
 
-// End moves the viewport to the end of the buffer
-func (v *View) End() bool {
-       if v.height > v.Buf.NumLines {
-               v.Topline = 0
-       } else {
-               v.Topline = v.Buf.NumLines - v.height
+               // Integration with file managers
+               "F1":  "ToggleHelp",
+               "F2":  "Save",
+               "F4":  "Quit",
+               "F7":  "Find",
+               "F10": "Quit",
+               "Esc": "Escape",
        }
-       return false
-}
-
-// PageUp scrolls the view up a page
-func (v *View) PageUp() bool {
-       if v.Topline > v.height {
-               v.ScrollUp(v.height)
-       } else {
-               v.Topline = 0
-       }
-       return false
-}
-
-// PageDown scrolls the view down a page
-func (v *View) PageDown() bool {
-       if v.Buf.NumLines-(v.Topline+v.height) > v.height {
-               v.ScrollDown(v.height)
-       } else if v.Buf.NumLines >= v.height {
-               v.Topline = v.Buf.NumLines - v.height
-       }
-       return false
-}
-
-// CursorPageUp places the cursor a page up
-func (v *View) CursorPageUp() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.SetLoc(v.Cursor.CurSelection[0])
-               v.Cursor.ResetSelection()
-       }
-       v.Cursor.UpN(v.height)
-       return true
-}
-
-// CursorPageDown places the cursor a page up
-func (v *View) CursorPageDown() bool {
-       if v.Cursor.HasSelection() {
-               v.Cursor.SetLoc(v.Cursor.CurSelection[1])
-               v.Cursor.ResetSelection()
-       }
-       v.Cursor.DownN(v.height)
-       return true
-}
-
-// HalfPageUp scrolls the view up half a page
-func (v *View) HalfPageUp() bool {
-       if v.Topline > v.height/2 {
-               v.ScrollUp(v.height / 2)
-       } else {
-               v.Topline = 0
-       }
-       return false
-}
-
-// HalfPageDown scrolls the view down half a page
-func (v *View) HalfPageDown() bool {
-       if v.Buf.NumLines-(v.Topline+v.height) > v.height/2 {
-               v.ScrollDown(v.height / 2)
-       } else {
-               if v.Buf.NumLines >= v.height {
-                       v.Topline = v.Buf.NumLines - v.height
-               }
-       }
-       return false
-}
-
-// ToggleRuler turns line numbers off and on
-func (v *View) ToggleRuler() bool {
-       if settings["ruler"] == false {
-               settings["ruler"] = true
-               messenger.Message("Enabled ruler")
-       } else {
-               settings["ruler"] = false
-               messenger.Message("Disabled ruler")
-       }
-       return false
-}
-
-// JumpLine jumps to a line and moves the view accordingly.
-func (v *View) JumpLine() bool {
-       // Prompt for line number
-       linestring, canceled := messenger.Prompt("Jump to line # ", "LineNumber")
-       if canceled {
-               return false
-       }
-       lineint, err := strconv.Atoi(linestring)
-       lineint = lineint - 1 // fix offset
-       if err != nil {
-               messenger.Error(err) // return errors
-               return false
-       }
-       // Move cursor and view if possible.
-       if lineint < v.Buf.NumLines {
-               v.Cursor.X = 0
-               v.Cursor.Y = lineint
-               return true
-       }
-       messenger.Error("Only ", v.Buf.NumLines, " lines to jump")
-       return false
-}
-
-// ClearStatus clears the messenger bar
-func (v *View) ClearStatus() bool {
-       messenger.Message("")
-       return false
-}
-
-// ToggleHelp toggles the help screen
-func (v *View) ToggleHelp() bool {
-       if !v.helpOpen {
-               v.lastBuffer = v.Buf
-               helpBuffer := NewBuffer(helpTxt, "help.md")
-               helpBuffer.Name = "Help"
-               v.helpOpen = true
-               v.OpenBuffer(helpBuffer)
-       } else {
-               v.OpenBuffer(v.lastBuffer)
-               v.helpOpen = false
-       }
-       return true
-}
-
-// ShellMode opens a terminal to run a shell command
-func (v *View) ShellMode() bool {
-       input, canceled := messenger.Prompt("$ ", "Shell")
-       if !canceled {
-               // The true here is for openTerm to make the command interactive
-               HandleShellCommand(input, true)
-       }
-       return false
-}
-
-// CommandMode lets the user enter a command
-func (v *View) CommandMode() bool {
-       input, canceled := messenger.Prompt("> ", "Command")
-       if !canceled {
-               HandleCommand(input)
-       }
-       return false
-}
-
-// Quit quits the editor
-// This behavior needs to be changed and should really only quit the editor if this
-// is the last view
-// However, since micro only supports one view for now, it doesn't really matter
-func (v *View) Quit() bool {
-       if v.helpOpen {
-               return v.ToggleHelp()
-       }
-       // Make sure not to quit if there are unsaved changes
-       if views[mainView].CanClose("Quit anyway? (yes, no, save) ") {
-               views[mainView].CloseBuffer()
-               screen.Fini()
-               os.Exit(0)
-       }
-       return false
-}
-
-// None is no action
-func None() bool {
-       return false
 }