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.
This commit is contained in:
Zachary Yedidia
2020-06-30 22:51:13 -04:00
parent d33c28eeb8
commit 2363a4019b
5 changed files with 256 additions and 120 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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",
}
}

View File

@@ -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",
}
}

View File

@@ -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
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:?
}
}
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 {
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() {
// AbortCommand cancels the prompt
func (h *InfoPane) AbortCommand() {
h.DonePrompt(true)
}
// QuitAll cancels the prompt
func (h *InfoPane) QuitAll() {
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,
}