From 2363a4019b78adcac27e8b9d6650d9194691839f Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Tue, 30 Jun 2020 22:51:13 -0400 Subject: [PATCH] Separate bindings for buffers and command bar This commit separates actions in the command bar from actions in a normal buffer, and implements what is needed to allow rebinding, although an interface for command bar keybindings is not yet exposed to the user. --- internal/action/bindings.go | 23 ++++ internal/action/bufpane.go | 36 +++---- internal/action/defaults_darwin.go | 76 +++++++++++++ internal/action/defaults_other.go | 76 +++++++++++++ internal/action/infopane.go | 165 ++++++++++++----------------- 5 files changed, 256 insertions(+), 120 deletions(-) diff --git a/internal/action/bindings.go b/internal/action/bindings.go index 92715f8b..17eceb37 100644 --- a/internal/action/bindings.go +++ b/internal/action/bindings.go @@ -51,6 +51,29 @@ func InitBindings() { for k, v := range parsed { BindKey(k, v) } + + defaultInfos := DefaultInfoBindings() + for k, v := range defaultInfos { + BindInfoKey(k, v) + } +} + +func BindInfoKey(k, v string) { + event, err := findEvent(k) + if err != nil { + screen.TermMessage(err) + } + + switch e := event.(type) { + case KeyEvent: + InfoMapKey(e, v) + case KeySequenceEvent: + InfoMapKey(e, v) + case MouseEvent: + InfoMapMouse(e, v) + case RawEvent: + InfoMapKey(e, v) + } } func BindKey(k, v string) { diff --git a/internal/action/bufpane.go b/internal/action/bufpane.go index 1e18da0f..3b4ba699 100644 --- a/internal/action/bufpane.go +++ b/internal/action/bufpane.go @@ -21,9 +21,6 @@ type BufKeyAction func(*BufPane) bool type BufMouseAction func(*BufPane, *tcell.EventMouse) bool var BufBindings *KeyTree -var BufKeyBindings map[Event]BufKeyAction -var BufKeyStrings map[Event]string -var BufMouseBindings map[MouseEvent]BufMouseAction func BufKeyActionGeneral(a BufKeyAction) PaneKeyAction { return func(p Pane) bool { @@ -38,10 +35,6 @@ func BufMouseActionGeneral(a BufMouseAction) PaneMouseAction { } func init() { - BufKeyBindings = make(map[Event]BufKeyAction) - BufKeyStrings = make(map[Event]string) - BufMouseBindings = make(map[MouseEvent]BufMouseAction) - BufBindings = NewKeyTree() } @@ -70,7 +63,6 @@ func LuaAction(fn string) func(*BufPane) bool { // BufMapKey maps a key event to an action func BufMapKey(k Event, action string) { - // BufKeyStrings[k] = action var actionfns []func(*BufPane) bool var names []string var types []byte @@ -156,11 +148,9 @@ func BufMapKey(k Event, action string) { func BufMapMouse(k MouseEvent, action string) { if f, ok := BufMouseActions[action]; ok { BufBindings.RegisterMouseBinding(k, BufMouseActionGeneral(f)) - // BufMouseBindings[k] = f } else { // TODO // delete(BufMouseBindings, k) - // BufMapKey(k, action) BufMapKey(k, action) } } @@ -169,7 +159,6 @@ func BufMapMouse(k MouseEvent, action string) { func BufUnmap(k Event) { // TODO // delete(BufKeyBindings, k) - // delete(BufKeyStrings, k) // // switch e := k.(type) { // case MouseEvent: @@ -188,7 +177,7 @@ type BufPane struct { // Buf is the buffer this BufPane views Buf *buffer.Buffer // Bindings stores the association of key events and actions - Bindings *KeyTree + bindings *KeyTree // Cursor is the currently active buffer cursor Cursor *buffer.Cursor @@ -422,20 +411,25 @@ func (h *BufPane) HandleEvent(event tcell.Event) { } } +func (h *BufPane) Bindings() *KeyTree { + if h.bindings != nil { + return h.bindings + } + return BufBindings +} + // DoKeyEvent executes a key event by finding the action it is bound // to and executing it (possibly multiple times for multiple cursors) func (h *BufPane) DoKeyEvent(e Event) bool { - action, more := BufBindings.NextEvent(e, nil) + binds := h.Bindings() + action, more := binds.NextEvent(e, nil) log.Println("Next event", e, more) if action != nil && !more { action(h) - BufBindings.ResetEvents() + binds.ResetEvents() } else if action == nil && !more { - BufBindings.ResetEvents() + binds.ResetEvents() } - // if action, ok := BufKeyBindings[e]; ok { - // return action(h) - // } return false } @@ -479,13 +473,13 @@ func (h *BufPane) HasKeyEvent(e Event) bool { // DoMouseEvent executes a mouse event by finding the action it is bound // to and executing it func (h *BufPane) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool { - log.Println("DOMOUSEEVENT") - action, _ := BufBindings.NextEvent(e, te) + binds := h.Bindings() + action, _ := binds.NextEvent(e, te) if action != nil { if action(h) { h.Relocate() } - BufBindings.ResetEvents() + binds.ResetEvents() return true } // TODO diff --git a/internal/action/defaults_darwin.go b/internal/action/defaults_darwin.go index aac1ebec..6df65d31 100644 --- a/internal/action/defaults_darwin.go +++ b/internal/action/defaults_darwin.go @@ -106,3 +106,79 @@ func DefaultBindings() map[string]string { "Alt-x": "SkipMultiCursor", } } + +func DefaultInfoBindings() map[string]string { + return map[string]string{ + "Up": "HistoryUp", + "Down": "HistoryDown", + "Right": "CursorRight", + "Left": "CursorLeft", + "ShiftUp": "SelectUp", + "ShiftDown": "SelectDown", + "ShiftLeft": "SelectLeft", + "ShiftRight": "SelectRight", + "AltLeft": "WordLeft", + "AltRight": "WordRight", + "AltUp": "CursorStart", + "AltDown": "CursorEnd", + "AltShiftRight": "SelectWordRight", + "AltShiftLeft": "SelectWordLeft", + "CtrlLeft": "StartOfTextToggle", + "CtrlRight": "EndOfLine", + "CtrlShiftLeft": "SelectToStartOfTextToggle", + "ShiftHome": "SelectToStartOfTextToggle", + "CtrlShiftRight": "SelectToEndOfLine", + "ShiftEnd": "SelectToEndOfLine", + "CtrlUp": "CursorStart", + "CtrlDown": "CursorEnd", + "CtrlShiftUp": "SelectToStart", + "CtrlShiftDown": "SelectToEnd", + "Enter": "ExecuteCommand", + "CtrlH": "Backspace", + "Backspace": "Backspace", + "OldBackspace": "Backspace", + "Alt-CtrlH": "DeleteWordLeft", + "Alt-Backspace": "DeleteWordLeft", + "Tab": "CommandComplete", + "Backtab": "CycleAutocompleteBack", + "Ctrl-z": "Undo", + "Ctrl-y": "Redo", + "Ctrl-c": "CopyLine|Copy", + "Ctrl-x": "Cut", + "Ctrl-k": "CutLine", + "Ctrl-v": "Paste", + "Home": "StartOfTextToggle", + "End": "EndOfLine", + "CtrlHome": "CursorStart", + "CtrlEnd": "CursorEnd", + "Delete": "Delete", + "Ctrl-q": "AbortCommand", + "Ctrl-e": "EndOfLine", + "Ctrl-a": "StartOfLine", + "Ctrl-w": "DeleteWordLeft", + "Insert": "ToggleOverwriteMode", + "Ctrl-b": "WordLeft", + "Ctrl-f": "WordRight", + "Ctrl-d": "DeleteWordLeft", + "Ctrl-m": "ExecuteCommand", + "Ctrl-n": "HistoryDown", + "Ctrl-p": "HistoryUp", + "Ctrl-u": "SelectToStart", + + // Emacs-style keybindings + "Alt-f": "WordRight", + "Alt-b": "WordLeft", + "Alt-a": "StartOfText", + "Alt-e": "EndOfLine", + + // Integration with file managers + "F10": "AbortCommand", + "Esc": "AbortCommand", + + // Mouse bindings + "MouseWheelUp": "HistoryUp", + "MouseWheelDown": "HistoryDown", + "MouseLeft": "MousePress", + "MouseMiddle": "PastePrimary", + } +} diff --git a/internal/action/defaults_other.go b/internal/action/defaults_other.go index e518e781..ee4e311d 100644 --- a/internal/action/defaults_other.go +++ b/internal/action/defaults_other.go @@ -108,3 +108,79 @@ func DefaultBindings() map[string]string { "Alt-x": "SkipMultiCursor", } } + +func DefaultInfoBindings() map[string]string { + return map[string]string{ + "Up": "HistoryUp", + "Down": "HistoryDown", + "Right": "CursorRight", + "Left": "CursorLeft", + "ShiftUp": "SelectUp", + "ShiftDown": "SelectDown", + "ShiftLeft": "SelectLeft", + "ShiftRight": "SelectRight", + "AltLeft": "StartOfTextToggle", + "AltRight": "EndOfLine", + "AltUp": "CursorStart", + "AltDown": "CursorEnd", + "AltShiftRight": "SelectWordRight", + "AltShiftLeft": "SelectWordLeft", + "CtrlLeft": "WordLeft", + "CtrlRight": "WordRight", + "CtrlShiftLeft": "SelectToStartOfTextToggle", + "ShiftHome": "SelectToStartOfTextToggle", + "CtrlShiftRight": "SelectToEndOfLine", + "ShiftEnd": "SelectToEndOfLine", + "CtrlUp": "CursorStart", + "CtrlDown": "CursorEnd", + "CtrlShiftUp": "SelectToStart", + "CtrlShiftDown": "SelectToEnd", + "Enter": "ExecuteCommand", + "CtrlH": "Backspace", + "Backspace": "Backspace", + "OldBackspace": "Backspace", + "Alt-CtrlH": "DeleteWordLeft", + "Alt-Backspace": "DeleteWordLeft", + "Tab": "CommandComplete", + "Backtab": "CycleAutocompleteBack", + "Ctrl-z": "Undo", + "Ctrl-y": "Redo", + "Ctrl-c": "CopyLine|Copy", + "Ctrl-x": "Cut", + "Ctrl-k": "CutLine", + "Ctrl-v": "Paste", + "Home": "StartOfTextToggle", + "End": "EndOfLine", + "CtrlHome": "CursorStart", + "CtrlEnd": "CursorEnd", + "Delete": "Delete", + "Ctrl-q": "AbortCommand", + "Ctrl-e": "EndOfLine", + "Ctrl-a": "StartOfLine", + "Ctrl-w": "DeleteWordLeft", + "Insert": "ToggleOverwriteMode", + "Ctrl-b": "WordLeft", + "Ctrl-f": "WordRight", + "Ctrl-d": "DeleteWordLeft", + "Ctrl-m": "ExecuteCommand", + "Ctrl-n": "HistoryDown", + "Ctrl-p": "HistoryUp", + "Ctrl-u": "SelectToStart", + + // Emacs-style keybindings + "Alt-f": "WordRight", + "Alt-b": "WordLeft", + "Alt-a": "StartOfText", + "Alt-e": "EndOfLine", + + // Integration with file managers + "F10": "AbortCommand", + "Esc": "AbortCommand", + + // Mouse bindings + "MouseWheelUp": "HistoryUp", + "MouseWheelDown": "HistoryDown", + "MouseLeft": "MousePress", + "MouseMiddle": "PastePrimary", + } +} diff --git a/internal/action/infopane.go b/internal/action/infopane.go index c72c9ebd..8c2c6690 100644 --- a/internal/action/infopane.go +++ b/internal/action/infopane.go @@ -2,7 +2,6 @@ package action import ( "bytes" - "strings" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/display" @@ -13,6 +12,37 @@ import ( type InfoKeyAction func(*InfoPane) +var InfoBindings *KeyTree +var InfoBufBindings *KeyTree + +func init() { + InfoBindings = NewKeyTree() + InfoBufBindings = NewKeyTree() +} + +func InfoMapKey(k Event, action string) { + if f, ok := InfoKeyActions[action]; ok { + InfoBindings.RegisterKeyBinding(k, InfoKeyActionGeneral(f)) + } else if f, ok := BufKeyActions[action]; ok { + InfoBufBindings.RegisterKeyBinding(k, BufKeyActionGeneral(f)) + } +} + +func InfoMapMouse(k MouseEvent, action string) { + if f, ok := BufMouseActions[action]; ok { + InfoBufBindings.RegisterMouseBinding(k, BufMouseActionGeneral(f)) + } else { + InfoMapKey(k, action) + } +} + +func InfoKeyActionGeneral(a InfoKeyAction) PaneKeyAction { + return func(p Pane) bool { + a(p.(*InfoPane)) + return false + } +} + type InfoPane struct { *BufPane *info.InfoBuf @@ -22,6 +52,7 @@ func NewInfoPane(ib *info.InfoBuf, w display.BWindow, tab *Tab) *InfoPane { ip := new(InfoPane) ip.InfoBuf = ib ip.BufPane = NewBufPane(ib.Buffer, w, tab) + ip.BufPane.bindings = InfoBufBindings return ip } @@ -77,103 +108,40 @@ func (h *InfoPane) HandleEvent(event tcell.Event) { // DoKeyEvent executes a key event for the command bar, doing any overridden actions func (h *InfoPane) DoKeyEvent(e KeyEvent) bool { done := false - if action, ok := BufKeyBindings[e]; ok { - estr := BufKeyStrings[e] - for _, s := range InfoNones { - if s == estr { - return false - } - } - for s, a := range InfoOverrides { - // TODO this is a hack and really we should have support - // for having binding overrides for different buffers - if strings.HasPrefix(estr, s) { - done = true - a(h) - break - } - } - if !done { - done = action(h.BufPane) - } + action, more := InfoBindings.NextEvent(e, nil) + if action != nil && !more { + action(h) + InfoBindings.ResetEvents() + + return true + } else if action == nil && !more { + InfoBindings.ResetEvents() + // return false //TODO:? + } + + action, more = InfoBufBindings.NextEvent(e, nil) + if action != nil && !more { + done = action(h.BufPane) + InfoBufBindings.ResetEvents() + } else if action == nil && !more { + InfoBufBindings.ResetEvents() } + return done } -// InfoNones is a list of actions that should have no effect when executed -// by an infohandler -var InfoNones = []string{ - "Save", - "SaveAll", - "SaveAs", - "Find", - "FindNext", - "FindPrevious", - "Center", - "DuplicateLine", - "MoveLinesUp", - "MoveLinesDown", - "OpenFile", - "Start", - "End", - "PageUp", - "PageDown", - "SelectPageUp", - "SelectPageDown", - "HalfPageUp", - "HalfPageDown", - "ToggleHelp", - "ToggleKeyMenu", - "ToggleDiffGutter", - "ToggleRuler", - "JumpLine", - "ClearStatus", - "ShellMode", - "CommandMode", - "AddTab", - "PreviousTab", - "NextTab", - "NextSplit", - "PreviousSplit", - "Unsplit", - "VSplit", - "HSplit", - "ToggleMacro", - "PlayMacro", - "Suspend", - "ScrollUp", - "ScrollDown", - "SpawnMultiCursor", - "SpawnMultiCursorSelect", - "RemoveMultiCursor", - "RemoveAllMultiCursors", - "SkipMultiCursor", -} - -// InfoOverrides is the list of actions which have been overridden -// by the infohandler -var InfoOverrides = map[string]InfoKeyAction{ - "CursorUp": (*InfoPane).CursorUp, - "CursorDown": (*InfoPane).CursorDown, - "InsertNewline": (*InfoPane).InsertNewline, - "Autocomplete": (*InfoPane).Autocomplete, - "Escape": (*InfoPane).Escape, - "Quit": (*InfoPane).Quit, - "QuitAll": (*InfoPane).QuitAll, -} - -// CursorUp cycles history up -func (h *InfoPane) CursorUp() { +// HistoryUp cycles history up +func (h *InfoPane) HistoryUp() { h.UpHistory(h.History[h.PromptType]) } -// CursorDown cycles history down -func (h *InfoPane) CursorDown() { +// HistoryDown cycles history down +func (h *InfoPane) HistoryDown() { h.DownHistory(h.History[h.PromptType]) } // Autocomplete begins autocompletion -func (h *InfoPane) Autocomplete() { +func (h *InfoPane) CommandComplete() { b := h.Buf if b.HasSuggestions { b.CycleAutocomplete(true) @@ -201,24 +169,23 @@ func (h *InfoPane) Autocomplete() { } } -// InsertNewline completes the prompt -func (h *InfoPane) InsertNewline() { +// ExecuteCommand completes the prompt +func (h *InfoPane) ExecuteCommand() { if !h.HasYN { h.DonePrompt(false) } } -// Quit cancels the prompt -func (h *InfoPane) Quit() { - h.DonePrompt(true) -} - -// QuitAll cancels the prompt -func (h *InfoPane) QuitAll() { +// AbortCommand cancels the prompt +func (h *InfoPane) AbortCommand() { h.DonePrompt(true) } -// Escape cancels the prompt -func (h *InfoPane) Escape() { - h.DonePrompt(true) +// BufKeyActions contains the list of all possible key actions the bufhandler could execute +var InfoKeyActions = map[string]InfoKeyAction{ + "HistoryUp": (*InfoPane).HistoryUp, + "HistoryDown": (*InfoPane).HistoryDown, + "CommandComplete": (*InfoPane).CommandComplete, + "ExecuteCommand": (*InfoPane).ExecuteCommand, + "AbortCommand": (*InfoPane).AbortCommand, } -- 2.44.0