From 5fc8f847a679f5f5d3bf4d708748daedee415a71 Mon Sep 17 00:00:00 2001 From: Zachary Yedidia Date: Fri, 24 Nov 2017 14:43:26 -0500 Subject: [PATCH] Improve command bar keybindings The command bar now supports better keybindings: CtrlA, CtrlLeft: start of line CtrlE, CtrlRight: end of line CtrlF, AltRight: next word CtrlB, AltLeft: previous word CtrlW, AltBackspace: delete previous word CtrlV: Paste Arrow keys as usual These keybindings are not rebindable (maybe support will be added in the future). --- cmd/micro/messenger.go | 179 +++++++++++++++++++++++++++++------------ 1 file changed, 128 insertions(+), 51 deletions(-) diff --git a/cmd/micro/messenger.go b/cmd/micro/messenger.go index 05c0bef3b..808152a86 100644 --- a/cmd/micro/messenger.go +++ b/cmd/micro/messenger.go @@ -348,62 +348,139 @@ func (m *Messenger) Prompt(prompt, placeholder, historyType string, completionTy return response, canceled } +func (m *Messenger) UpHistory(history []string) { + if m.historyNum > 0 { + m.historyNum-- + m.response = history[m.historyNum] + m.cursorx = Count(m.response) + } +} +func (m *Messenger) DownHistory(history []string) { + if m.historyNum < len(history)-1 { + m.historyNum++ + m.response = history[m.historyNum] + m.cursorx = Count(m.response) + } +} +func (m *Messenger) CursorLeft() { + if m.cursorx > 0 { + m.cursorx-- + } +} +func (m *Messenger) CursorRight() { + if m.cursorx < Count(m.response) { + m.cursorx++ + } +} +func (m *Messenger) Start() { + m.cursorx = 0 +} +func (m *Messenger) End() { + m.cursorx = Count(m.response) +} +func (m *Messenger) Backspace() { + if m.cursorx > 0 { + m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:]) + m.cursorx-- + } +} +func (m *Messenger) Paste() { + clip, _ := clipboard.ReadAll("clipboard") + m.response = Insert(m.response, m.cursorx, clip) + m.cursorx += Count(clip) +} +func (m *Messenger) WordLeft() { + response := []rune(m.response) + m.CursorLeft() + if m.cursorx <= 0 { + return + } + for IsWhitespace(response[m.cursorx]) { + if m.cursorx <= 0 { + return + } + m.CursorLeft() + } + m.CursorLeft() + for IsWordChar(string(response[m.cursorx])) { + if m.cursorx <= 0 { + return + } + m.CursorLeft() + } + m.CursorRight() +} +func (m *Messenger) WordRight() { + response := []rune(m.response) + if m.cursorx >= len(response) { + return + } + for IsWhitespace(response[m.cursorx]) { + m.CursorRight() + if m.cursorx >= len(response) { + m.CursorRight() + return + } + } + m.CursorRight() + if m.cursorx >= len(response) { + return + } + for IsWordChar(string(response[m.cursorx])) { + m.CursorRight() + if m.cursorx >= len(response) { + return + } + } +} +func (m *Messenger) DeleteWordLeft() { + m.WordLeft() + m.response = string([]rune(m.response)[:m.cursorx]) +} + // HandleEvent handles an event for the prompter func (m *Messenger) HandleEvent(event tcell.Event, history []string) { switch e := event.(type) { case *tcell.EventKey: - if e.Key() != tcell.KeyRune || e.Modifiers() != 0 { - for key, actions := range bindings { - if e.Key() == key.keyCode { - if e.Key() == tcell.KeyRune { - if e.Rune() != key.r { - continue - } - } - if e.Modifiers() == key.modifiers { - for _, action := range actions { - funcName := FuncName(action) - switch funcName { - case "main.(*View).CursorUp": - if m.historyNum > 0 { - m.historyNum-- - m.response = history[m.historyNum] - m.cursorx = Count(m.response) - } - case "main.(*View).CursorDown": - if m.historyNum < len(history)-1 { - m.historyNum++ - m.response = history[m.historyNum] - m.cursorx = Count(m.response) - } - case "main.(*View).CursorLeft": - if m.cursorx > 0 { - m.cursorx-- - } - case "main.(*View).CursorRight": - if m.cursorx < Count(m.response) { - m.cursorx++ - } - case "main.(*View).CursorStart", "main.(*View).StartOfLine": - m.cursorx = 0 - case "main.(*View).CursorEnd", "main.(*View).EndOfLine": - m.cursorx = Count(m.response) - case "main.(*View).Backspace": - if m.cursorx > 0 { - m.response = string([]rune(m.response)[:m.cursorx-1]) + string([]rune(m.response)[m.cursorx:]) - m.cursorx-- - } - case "main.(*View).Paste": - clip, _ := clipboard.ReadAll("clipboard") - m.response = Insert(m.response, m.cursorx, clip) - m.cursorx += Count(clip) - } - } - } - } - } - } switch e.Key() { + case tcell.KeyCtrlA: + m.Start() + case tcell.KeyCtrlE: + m.End() + case tcell.KeyUp: + m.UpHistory(history) + case tcell.KeyDown: + m.DownHistory(history) + case tcell.KeyLeft: + if e.Modifiers() == tcell.ModCtrl { + m.Start() + } else if e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta { + m.WordLeft() + } else { + m.CursorLeft() + } + case tcell.KeyRight: + if e.Modifiers() == tcell.ModCtrl { + m.End() + } else if e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta { + m.WordRight() + } else { + m.CursorRight() + } + case tcell.KeyBackspace2, tcell.KeyBackspace: + if e.Modifiers() == tcell.ModCtrl || e.Modifiers() == tcell.ModAlt || e.Modifiers() == tcell.ModMeta { + m.DeleteWordLeft() + } else { + m.Backspace() + } + case tcell.KeyCtrlW: + m.DeleteWordLeft() + case tcell.KeyCtrlV: + m.Paste() + case tcell.KeyCtrlF: + m.WordRight() + case tcell.KeyCtrlB: + m.WordLeft() case tcell.KeyRune: m.response = Insert(m.response, m.cursorx, string(e.Rune())) m.cursorx++