func LuaAction(fn string) func(*BufPane) bool {
luaFn := strings.Split(fn, ".")
+ if len(luaFn) <= 1 {
+ return nil
+ }
plName, plFn := luaFn[0], luaFn[1]
pl := config.FindPlugin(plName)
+ if pl == nil {
+ return nil
+ }
return func(h *BufPane) bool {
val, err := pl.Call(plFn, luar.New(ulua.L, h))
if err != nil {
// BufMapKey maps a key event to an action
func BufMapKey(k Event, action string) {
- if strings.HasPrefix(action, "command:") {
- action = strings.SplitN(action, ":", 2)[1]
- BufKeyStrings[k] = action
- BufKeyBindings[k] = CommandAction(action)
- } else if strings.HasPrefix(action, "command-edit:") {
- action = strings.SplitN(action, ":", 2)[1]
- BufKeyStrings[k] = action
- BufKeyBindings[k] = CommandEditAction(action)
- } else if strings.HasPrefix(action, "lua:") {
- action = strings.SplitN(action, ":", 2)[1]
- BufKeyStrings[k] = action
- BufKeyBindings[k] = LuaAction(action)
- } else if f, ok := BufKeyActions[action]; ok {
- BufKeyStrings[k] = action
- BufKeyBindings[k] = f
- } else {
- screen.TermMessage("Error:", action, "does not exist")
+ BufKeyStrings[k] = action
+ var actionfns []func(*BufPane) bool
+ var names []string
+ var types []byte
+ for i := 0; ; i++ {
+ if action == "" {
+ break
+ }
+
+ idx := strings.IndexAny(action, "&|,")
+ a := action
+ if idx >= 0 {
+ a = action[:idx]
+ types = append(types, action[idx])
+ action = action[idx+1:]
+ } else {
+ types = append(types, ' ')
+ action = ""
+ }
+
+ var afn func(*BufPane) bool
+ if strings.HasPrefix(action, "command:") {
+ a = strings.SplitN(a, ":", 2)[1]
+ afn = CommandAction(a)
+ names = append(names, "")
+ } else if strings.HasPrefix(a, "command-edit:") {
+ a = strings.SplitN(a, ":", 2)[1]
+ afn = CommandEditAction(a)
+ names = append(names, "")
+ } else if strings.HasPrefix(a, "lua:") {
+ a = strings.SplitN(a, ":", 2)[1]
+ afn = LuaAction(a)
+ if afn == nil {
+ screen.TermMessage("Lua Error:", action, "does not exist")
+ continue
+ }
+ names = append(names, "")
+ } else if f, ok := BufKeyActions[a]; ok {
+ afn = f
+ names = append(names, a)
+ } else {
+ screen.TermMessage("Error:", action, "does not exist")
+ continue
+ }
+ actionfns = append(actionfns, afn)
+ }
+ BufKeyBindings[k] = func(h *BufPane) bool {
+ cursors := h.Buf.GetCursors()
+ success := true
+ for i, a := range actionfns {
+ for j, c := range cursors {
+ h.Buf.SetCurCursor(c.Num)
+ h.Cursor = c
+ if i == 0 || (success && types[i-1] == '&') || (!success && types[i-1] == '|') || (types[i-1] == ',') {
+ success = h.execAction(a, names[i], j)
+ } else {
+ break
+ }
+ }
+ }
+ return true
}
}
}
// HandleEvent executes the tcell event properly
-// TODO: multiple actions bound to one key
func (h *BufPane) HandleEvent(event tcell.Event) {
+ if h.Buf.ExternallyModified() {
+ InfoBar.YNPrompt("The file on disk has changed. Reload file? (y,n)", func(yes, canceled bool) {
+ if !yes || canceled {
+ h.Buf.UpdateModTime()
+ } else {
+ h.Buf.ReOpen()
+ }
+ })
+
+ }
+
switch e := event.(type) {
case *tcell.EventRaw:
re := RawEvent{
// Mouse was just released
mx, my := e.Position()
- mouseLoc := h.GetMouseLoc(buffer.Loc{X: mx, Y: my})
+ mouseLoc := h.LocFromVisual(buffer.Loc{X: mx, Y: my})
// Relocating here isn't really necessary because the cursor will
// be in the right place from the last mouse event
// to and executing it (possibly multiple times for multiple cursors)
func (h *BufPane) DoKeyEvent(e Event) bool {
if action, ok := BufKeyBindings[e]; ok {
- estr := BufKeyStrings[e]
- if estr != "InsertTab" {
- h.Buf.HasSuggestions = false
- }
- for _, s := range MultiActions {
- if s == estr {
- cursors := h.Buf.GetCursors()
- for _, c := range cursors {
- h.Buf.SetCurCursor(c.Num)
- h.Cursor = c
- if !h.PluginCB("pre" + estr) {
- // canceled by plugin
- continue
- }
- rel := action(h)
- if h.PluginCB("on"+estr) && rel {
- h.Relocate()
+ return action(h)
+ }
+ return false
+}
+
+func (h *BufPane) execAction(action func(*BufPane) bool, name string, cursor int) bool {
+ if name != "Autocomplete" {
+ h.Buf.HasSuggestions = false
+ }
+
+ _, isMulti := MultiActions[name]
+ if (!isMulti && cursor == 0) || isMulti {
+ if h.PluginCB("pre" + name) {
+ asuccess := action(h)
+ psuccess := h.PluginCB("on" + name)
+
+ if isMulti {
+ if recording_macro {
+ if name != "ToggleMacro" && name != "PlayMacro" {
+ curmacro = append(curmacro, action)
}
}
- return true
}
+
+ return asuccess && psuccess
}
- if !h.PluginCB("pre" + estr) {
- return false
- }
- rel := action(h)
- if h.PluginCB("on"+estr) && rel {
- h.Relocate()
- }
- return true
}
+
return false
}
for _, c := range cursors {
// Insert a character
h.Buf.SetCurCursor(c.Num)
+ h.Cursor = c
if !h.PluginCBRune("preRune", r) {
continue
}
} else {
h.Buf.Insert(c.Loc, string(r))
}
+ if recording_macro {
+ curmacro = append(curmacro, r)
+ }
h.PluginCBRune("onRune", r)
}
}
-func (h *BufPane) VSplitBuf(buf *buffer.Buffer) {
+func (h *BufPane) VSplitBuf(buf *buffer.Buffer) *BufPane {
e := NewBufPaneFromBuf(buf)
e.splitID = MainTab().GetNode(h.splitID).VSplit(h.Buf.Settings["splitright"].(bool))
MainTab().Panes = append(MainTab().Panes, e)
MainTab().Resize()
MainTab().SetActive(len(MainTab().Panes) - 1)
+ return e
}
-func (h *BufPane) HSplitBuf(buf *buffer.Buffer) {
+func (h *BufPane) HSplitBuf(buf *buffer.Buffer) *BufPane {
e := NewBufPaneFromBuf(buf)
e.splitID = MainTab().GetNode(h.splitID).HSplit(h.Buf.Settings["splitbottom"].(bool))
MainTab().Panes = append(MainTab().Panes, e)
MainTab().Resize()
MainTab().SetActive(len(MainTab().Panes) - 1)
+ return e
}
func (h *BufPane) Close() {
h.Buf.Close()
"MoveLinesDown": (*BufPane).MoveLinesDown,
"IndentSelection": (*BufPane).IndentSelection,
"OutdentSelection": (*BufPane).OutdentSelection,
+ "Autocomplete": (*BufPane).Autocomplete,
"OutdentLine": (*BufPane).OutdentLine,
"Paste": (*BufPane).Paste,
"PastePrimary": (*BufPane).PastePrimary,
"RemoveAllMultiCursors": (*BufPane).RemoveAllMultiCursors,
"SkipMultiCursor": (*BufPane).SkipMultiCursor,
"JumpToMatchingBrace": (*BufPane).JumpToMatchingBrace,
+ "None": (*BufPane).None,
// This was changed to InsertNewline but I don't want to break backwards compatibility
"InsertEnter": (*BufPane).InsertNewline,
// times if there are multiple cursors (one per cursor)
// Generally actions that modify global editor state like quitting or
// saving should not be included in this list
-var MultiActions = []string{
- "CursorUp",
- "CursorDown",
- "CursorPageUp",
- "CursorPageDown",
- "CursorLeft",
- "CursorRight",
- "CursorStart",
- "CursorEnd",
- "SelectToStart",
- "SelectToEnd",
- "SelectUp",
- "SelectDown",
- "SelectLeft",
- "SelectRight",
- "WordRight",
- "WordLeft",
- "SelectWordRight",
- "SelectWordLeft",
- "DeleteWordRight",
- "DeleteWordLeft",
- "SelectLine",
- "SelectToStartOfLine",
- "SelectToEndOfLine",
- "ParagraphPrevious",
- "ParagraphNext",
- "InsertNewline",
- "Backspace",
- "Delete",
- "InsertTab",
- "FindNext",
- "FindPrevious",
- "Cut",
- "CutLine",
- "DuplicateLine",
- "DeleteLine",
- "MoveLinesUp",
- "MoveLinesDown",
- "IndentSelection",
- "OutdentSelection",
- "OutdentLine",
- "Paste",
- "PastePrimary",
- "SelectPageUp",
- "SelectPageDown",
- "StartOfLine",
- "EndOfLine",
- "JumpToMatchingBrace",
+var MultiActions = map[string]bool{
+ "CursorUp": true,
+ "CursorDown": true,
+ "CursorPageUp": true,
+ "CursorPageDown": true,
+ "CursorLeft": true,
+ "CursorRight": true,
+ "CursorStart": true,
+ "CursorEnd": true,
+ "SelectToStart": true,
+ "SelectToEnd": true,
+ "SelectUp": true,
+ "SelectDown": true,
+ "SelectLeft": true,
+ "SelectRight": true,
+ "WordRight": true,
+ "WordLeft": true,
+ "SelectWordRight": true,
+ "SelectWordLeft": true,
+ "DeleteWordRight": true,
+ "DeleteWordLeft": true,
+ "SelectLine": true,
+ "SelectToStartOfLine": true,
+ "SelectToEndOfLine": true,
+ "ParagraphPrevious": true,
+ "ParagraphNext": true,
+ "InsertNewline": true,
+ "Backspace": true,
+ "Delete": true,
+ "InsertTab": true,
+ "FindNext": true,
+ "FindPrevious": true,
+ "Cut": true,
+ "CutLine": true,
+ "DuplicateLine": true,
+ "DeleteLine": true,
+ "MoveLinesUp": true,
+ "MoveLinesDown": true,
+ "IndentSelection": true,
+ "OutdentSelection": true,
+ "OutdentLine": true,
+ "Paste": true,
+ "PastePrimary": true,
+ "SelectPageUp": true,
+ "SelectPageDown": true,
+ "StartOfLine": true,
+ "EndOfLine": true,
+ "JumpToMatchingBrace": true,
}