From f0da73bae211cbd9a35c3e8412fe1e6c220166f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Jan=C4=8D=C3=A1r?= Date: Fri, 10 Apr 2020 23:21:02 +0200 Subject: [PATCH] Add StartOfTextToggle and SelectToStartOfTextToggle actions. (#1612) These actions reintroduce the behavior of micro where the Home key toggles between the start of text (first) and the start of the line. The same applies for the variant with selection. This commit also sets these bindings as the defaults. --- internal/action/actions.go | 30 +++ internal/action/bufpane.go | 308 +++++++++++++++-------------- internal/action/defaults_darwin.go | 8 +- internal/action/defaults_other.go | 8 +- internal/buffer/cursor.go | 13 ++ runtime/help/keybindings.md | 19 +- 6 files changed, 220 insertions(+), 166 deletions(-) diff --git a/internal/action/actions.go b/internal/action/actions.go index 97074653..ed4151f8 100644 --- a/internal/action/actions.go +++ b/internal/action/actions.go @@ -291,6 +291,19 @@ func (h *BufPane) StartOfText() bool { return true } +// StartOfTextToggle toggles the cursor between the start of the text of the line +// and the start of the line +func (h *BufPane) StartOfTextToggle() bool { + h.Cursor.Deselect(true) + if h.Cursor.IsStartOfText() { + h.Cursor.Start() + } else { + h.Cursor.StartOfText() + } + h.Relocate() + return true +} + // StartOfLine moves the cursor to the start of the line func (h *BufPane) StartOfLine() bool { h.Cursor.Deselect(true) @@ -325,6 +338,23 @@ func (h *BufPane) SelectToStartOfText() bool { return true } +// SelectToStartOfTextToggle toggles the selection between the start of the text +// on the current line and the start of the line +func (h *BufPane) SelectToStartOfTextToggle() bool { + if !h.Cursor.HasSelection() { + h.Cursor.OrigSelection[0] = h.Cursor.Loc + } + if h.Cursor.IsStartOfText() { + h.Cursor.Start() + } else { + h.Cursor.StartOfText() + } + h.Cursor.SelectTo(h.Cursor.Loc) + h.Relocate() + return true +} + + // SelectToStartOfLine selects to the start of the current line func (h *BufPane) SelectToStartOfLine() bool { if !h.Cursor.HasSelection() { diff --git a/internal/action/bufpane.go b/internal/action/bufpane.go index 91e2040e..07ba5d68 100644 --- a/internal/action/bufpane.go +++ b/internal/action/bufpane.go @@ -517,110 +517,112 @@ func (h *BufPane) SetActive(b bool) { // BufKeyActions contains the list of all possible key actions the bufhandler could execute var BufKeyActions = map[string]BufKeyAction{ - "CursorUp": (*BufPane).CursorUp, - "CursorDown": (*BufPane).CursorDown, - "CursorPageUp": (*BufPane).CursorPageUp, - "CursorPageDown": (*BufPane).CursorPageDown, - "CursorLeft": (*BufPane).CursorLeft, - "CursorRight": (*BufPane).CursorRight, - "CursorStart": (*BufPane).CursorStart, - "CursorEnd": (*BufPane).CursorEnd, - "SelectToStart": (*BufPane).SelectToStart, - "SelectToEnd": (*BufPane).SelectToEnd, - "SelectUp": (*BufPane).SelectUp, - "SelectDown": (*BufPane).SelectDown, - "SelectLeft": (*BufPane).SelectLeft, - "SelectRight": (*BufPane).SelectRight, - "WordRight": (*BufPane).WordRight, - "WordLeft": (*BufPane).WordLeft, - "SelectWordRight": (*BufPane).SelectWordRight, - "SelectWordLeft": (*BufPane).SelectWordLeft, - "DeleteWordRight": (*BufPane).DeleteWordRight, - "DeleteWordLeft": (*BufPane).DeleteWordLeft, - "SelectLine": (*BufPane).SelectLine, - "SelectToStartOfLine": (*BufPane).SelectToStartOfLine, - "SelectToStartOfText": (*BufPane).SelectToStartOfText, - "SelectToEndOfLine": (*BufPane).SelectToEndOfLine, - "ParagraphPrevious": (*BufPane).ParagraphPrevious, - "ParagraphNext": (*BufPane).ParagraphNext, - "InsertNewline": (*BufPane).InsertNewline, - "Backspace": (*BufPane).Backspace, - "Delete": (*BufPane).Delete, - "InsertTab": (*BufPane).InsertTab, - "Save": (*BufPane).Save, - "SaveAll": (*BufPane).SaveAll, - "SaveAs": (*BufPane).SaveAs, - "Find": (*BufPane).Find, - "FindNext": (*BufPane).FindNext, - "FindPrevious": (*BufPane).FindPrevious, - "Center": (*BufPane).Center, - "Undo": (*BufPane).Undo, - "Redo": (*BufPane).Redo, - "Copy": (*BufPane).Copy, - "Cut": (*BufPane).Cut, - "CutLine": (*BufPane).CutLine, - "DuplicateLine": (*BufPane).DuplicateLine, - "DeleteLine": (*BufPane).DeleteLine, - "MoveLinesUp": (*BufPane).MoveLinesUp, - "MoveLinesDown": (*BufPane).MoveLinesDown, - "IndentSelection": (*BufPane).IndentSelection, - "OutdentSelection": (*BufPane).OutdentSelection, - "Autocomplete": (*BufPane).Autocomplete, - "CycleAutocompleteBack": (*BufPane).CycleAutocompleteBack, - "OutdentLine": (*BufPane).OutdentLine, - "IndentLine": (*BufPane).IndentLine, - "Paste": (*BufPane).Paste, - "PastePrimary": (*BufPane).PastePrimary, - "SelectAll": (*BufPane).SelectAll, - "OpenFile": (*BufPane).OpenFile, - "Start": (*BufPane).Start, - "End": (*BufPane).End, - "PageUp": (*BufPane).PageUp, - "PageDown": (*BufPane).PageDown, - "SelectPageUp": (*BufPane).SelectPageUp, - "SelectPageDown": (*BufPane).SelectPageDown, - "HalfPageUp": (*BufPane).HalfPageUp, - "HalfPageDown": (*BufPane).HalfPageDown, - "StartOfText": (*BufPane).StartOfText, - "StartOfLine": (*BufPane).StartOfLine, - "EndOfLine": (*BufPane).EndOfLine, - "ToggleHelp": (*BufPane).ToggleHelp, - "ToggleKeyMenu": (*BufPane).ToggleKeyMenu, - "ToggleDiffGutter": (*BufPane).ToggleDiffGutter, - "ToggleRuler": (*BufPane).ToggleRuler, - "ClearStatus": (*BufPane).ClearStatus, - "ShellMode": (*BufPane).ShellMode, - "CommandMode": (*BufPane).CommandMode, - "ToggleOverwriteMode": (*BufPane).ToggleOverwriteMode, - "Escape": (*BufPane).Escape, - "Quit": (*BufPane).Quit, - "QuitAll": (*BufPane).QuitAll, - "AddTab": (*BufPane).AddTab, - "PreviousTab": (*BufPane).PreviousTab, - "NextTab": (*BufPane).NextTab, - "NextSplit": (*BufPane).NextSplit, - "PreviousSplit": (*BufPane).PreviousSplit, - "Unsplit": (*BufPane).Unsplit, - "VSplit": (*BufPane).VSplitAction, - "HSplit": (*BufPane).HSplitAction, - "ToggleMacro": (*BufPane).ToggleMacro, - "PlayMacro": (*BufPane).PlayMacro, - "Suspend": (*BufPane).Suspend, - "ScrollUp": (*BufPane).ScrollUpAction, - "ScrollDown": (*BufPane).ScrollDownAction, - "SpawnMultiCursor": (*BufPane).SpawnMultiCursor, - "SpawnMultiCursorUp": (*BufPane).SpawnMultiCursorUp, - "SpawnMultiCursorDown": (*BufPane).SpawnMultiCursorDown, - "SpawnMultiCursorSelect": (*BufPane).SpawnMultiCursorSelect, - "RemoveMultiCursor": (*BufPane).RemoveMultiCursor, - "RemoveAllMultiCursors": (*BufPane).RemoveAllMultiCursors, - "SkipMultiCursor": (*BufPane).SkipMultiCursor, - "JumpToMatchingBrace": (*BufPane).JumpToMatchingBrace, - "JumpLine": (*BufPane).JumpLine, - "None": (*BufPane).None, + "CursorUp": (*BufPane).CursorUp, + "CursorDown": (*BufPane).CursorDown, + "CursorPageUp": (*BufPane).CursorPageUp, + "CursorPageDown": (*BufPane).CursorPageDown, + "CursorLeft": (*BufPane).CursorLeft, + "CursorRight": (*BufPane).CursorRight, + "CursorStart": (*BufPane).CursorStart, + "CursorEnd": (*BufPane).CursorEnd, + "SelectToStart": (*BufPane).SelectToStart, + "SelectToEnd": (*BufPane).SelectToEnd, + "SelectUp": (*BufPane).SelectUp, + "SelectDown": (*BufPane).SelectDown, + "SelectLeft": (*BufPane).SelectLeft, + "SelectRight": (*BufPane).SelectRight, + "WordRight": (*BufPane).WordRight, + "WordLeft": (*BufPane).WordLeft, + "SelectWordRight": (*BufPane).SelectWordRight, + "SelectWordLeft": (*BufPane).SelectWordLeft, + "DeleteWordRight": (*BufPane).DeleteWordRight, + "DeleteWordLeft": (*BufPane).DeleteWordLeft, + "SelectLine": (*BufPane).SelectLine, + "SelectToStartOfLine": (*BufPane).SelectToStartOfLine, + "SelectToStartOfText": (*BufPane).SelectToStartOfText, + "SelectToStartOfTextToggle":(*BufPane).SelectToStartOfTextToggle, + "SelectToEndOfLine": (*BufPane).SelectToEndOfLine, + "ParagraphPrevious": (*BufPane).ParagraphPrevious, + "ParagraphNext": (*BufPane).ParagraphNext, + "InsertNewline": (*BufPane).InsertNewline, + "Backspace": (*BufPane).Backspace, + "Delete": (*BufPane).Delete, + "InsertTab": (*BufPane).InsertTab, + "Save": (*BufPane).Save, + "SaveAll": (*BufPane).SaveAll, + "SaveAs": (*BufPane).SaveAs, + "Find": (*BufPane).Find, + "FindNext": (*BufPane).FindNext, + "FindPrevious": (*BufPane).FindPrevious, + "Center": (*BufPane).Center, + "Undo": (*BufPane).Undo, + "Redo": (*BufPane).Redo, + "Copy": (*BufPane).Copy, + "Cut": (*BufPane).Cut, + "CutLine": (*BufPane).CutLine, + "DuplicateLine": (*BufPane).DuplicateLine, + "DeleteLine": (*BufPane).DeleteLine, + "MoveLinesUp": (*BufPane).MoveLinesUp, + "MoveLinesDown": (*BufPane).MoveLinesDown, + "IndentSelection": (*BufPane).IndentSelection, + "OutdentSelection": (*BufPane).OutdentSelection, + "Autocomplete": (*BufPane).Autocomplete, + "CycleAutocompleteBack": (*BufPane).CycleAutocompleteBack, + "OutdentLine": (*BufPane).OutdentLine, + "IndentLine": (*BufPane).IndentLine, + "Paste": (*BufPane).Paste, + "PastePrimary": (*BufPane).PastePrimary, + "SelectAll": (*BufPane).SelectAll, + "OpenFile": (*BufPane).OpenFile, + "Start": (*BufPane).Start, + "End": (*BufPane).End, + "PageUp": (*BufPane).PageUp, + "PageDown": (*BufPane).PageDown, + "SelectPageUp": (*BufPane).SelectPageUp, + "SelectPageDown": (*BufPane).SelectPageDown, + "HalfPageUp": (*BufPane).HalfPageUp, + "HalfPageDown": (*BufPane).HalfPageDown, + "StartOfText": (*BufPane).StartOfText, + "StartOfTextToggle": (*BufPane).StartOfTextToggle, + "StartOfLine": (*BufPane).StartOfLine, + "EndOfLine": (*BufPane).EndOfLine, + "ToggleHelp": (*BufPane).ToggleHelp, + "ToggleKeyMenu": (*BufPane).ToggleKeyMenu, + "ToggleDiffGutter": (*BufPane).ToggleDiffGutter, + "ToggleRuler": (*BufPane).ToggleRuler, + "ClearStatus": (*BufPane).ClearStatus, + "ShellMode": (*BufPane).ShellMode, + "CommandMode": (*BufPane).CommandMode, + "ToggleOverwriteMode": (*BufPane).ToggleOverwriteMode, + "Escape": (*BufPane).Escape, + "Quit": (*BufPane).Quit, + "QuitAll": (*BufPane).QuitAll, + "AddTab": (*BufPane).AddTab, + "PreviousTab": (*BufPane).PreviousTab, + "NextTab": (*BufPane).NextTab, + "NextSplit": (*BufPane).NextSplit, + "PreviousSplit": (*BufPane).PreviousSplit, + "Unsplit": (*BufPane).Unsplit, + "VSplit": (*BufPane).VSplitAction, + "HSplit": (*BufPane).HSplitAction, + "ToggleMacro": (*BufPane).ToggleMacro, + "PlayMacro": (*BufPane).PlayMacro, + "Suspend": (*BufPane).Suspend, + "ScrollUp": (*BufPane).ScrollUpAction, + "ScrollDown": (*BufPane).ScrollDownAction, + "SpawnMultiCursor": (*BufPane).SpawnMultiCursor, + "SpawnMultiCursorUp": (*BufPane).SpawnMultiCursorUp, + "SpawnMultiCursorDown": (*BufPane).SpawnMultiCursorDown, + "SpawnMultiCursorSelect": (*BufPane).SpawnMultiCursorSelect, + "RemoveMultiCursor": (*BufPane).RemoveMultiCursor, + "RemoveAllMultiCursors": (*BufPane).RemoveAllMultiCursors, + "SkipMultiCursor": (*BufPane).SkipMultiCursor, + "JumpToMatchingBrace": (*BufPane).JumpToMatchingBrace, + "JumpLine": (*BufPane).JumpLine, + "None": (*BufPane).None, // This was changed to InsertNewline but I don't want to break backwards compatibility - "InsertEnter": (*BufPane).InsertNewline, + "InsertEnter": (*BufPane).InsertNewline, } // BufMouseActions contains the list of all possible mouse actions the bufhandler could execute @@ -634,54 +636,56 @@ var BufMouseActions = map[string]BufMouseAction{ // Generally actions that modify global editor state like quitting or // saving should not be included in this list 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, - "SelectToStartOfText": 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, - "IndentLine": true, - "Paste": true, - "PastePrimary": true, - "SelectPageUp": true, - "SelectPageDown": true, - "StartOfLine": true, - "StartOfText": true, - "EndOfLine": true, - "JumpToMatchingBrace": true, + "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, + "SelectToStartOfText": true, + "SelectToStartOfTextToggle": 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, + "IndentLine": true, + "Paste": true, + "PastePrimary": true, + "SelectPageUp": true, + "SelectPageDown": true, + "StartOfLine": true, + "StartOfText": true, + "StartOfTextToggle": true, + "EndOfLine": true, + "JumpToMatchingBrace": true, } diff --git a/internal/action/defaults_darwin.go b/internal/action/defaults_darwin.go index 45b6359a..89f03290 100644 --- a/internal/action/defaults_darwin.go +++ b/internal/action/defaults_darwin.go @@ -17,10 +17,10 @@ func DefaultBindings() map[string]string { "AltDown": "MoveLinesDown", "AltShiftRight": "SelectWordRight", "AltShiftLeft": "SelectWordLeft", - "CtrlLeft": "StartOfText", + "CtrlLeft": "StartOfTextToggle", "CtrlRight": "EndOfLine", - "CtrlShiftLeft": "SelectToStartOfText", - "ShiftHome": "SelectToStartOfText", + "CtrlShiftLeft": "SelectToStartOfTextToggle", + "ShiftHome": "SelectToStartOfTextToggle", "CtrlShiftRight": "SelectToEndOfLine", "ShiftEnd": "SelectToEndOfLine", "CtrlUp": "CursorStart", @@ -52,7 +52,7 @@ func DefaultBindings() map[string]string { "CtrlT": "AddTab", "Alt,": "PreviousTab", "Alt.": "NextTab", - "Home": "StartOfText", + "Home": "StartOfTextToggle", "End": "EndOfLine", "CtrlHome": "CursorStart", "CtrlEnd": "CursorEnd", diff --git a/internal/action/defaults_other.go b/internal/action/defaults_other.go index 1ee40648..e63c1ee1 100644 --- a/internal/action/defaults_other.go +++ b/internal/action/defaults_other.go @@ -19,10 +19,10 @@ func DefaultBindings() map[string]string { "AltDown": "MoveLinesDown", "CtrlShiftRight": "SelectWordRight", "CtrlShiftLeft": "SelectWordLeft", - "AltLeft": "StartOfText", + "AltLeft": "StartOfTextToggle", "AltRight": "EndOfLine", - "AltShiftLeft": "SelectToStartOfText", - "ShiftHome": "SelectToStartOfText", + "AltShiftLeft": "SelectToStartOfTextToggle", + "ShiftHome": "SelectToStartOfTextToggle", "AltShiftRight": "SelectToEndOfLine", "ShiftEnd": "SelectToEndOfLine", "CtrlUp": "CursorStart", @@ -54,7 +54,7 @@ func DefaultBindings() map[string]string { "CtrlT": "AddTab", "Alt,": "PreviousTab", "Alt.": "NextTab", - "Home": "StartOfText", + "Home": "StartOfTextToggle", "End": "EndOfLine", "CtrlHome": "CursorStart", "CtrlEnd": "CursorEnd", diff --git a/internal/buffer/cursor.go b/internal/buffer/cursor.go index f3d6d059..6ea9a3d1 100644 --- a/internal/buffer/cursor.go +++ b/internal/buffer/cursor.go @@ -109,6 +109,19 @@ func (c *Cursor) StartOfText() { } } +// IsStartOfText returns whether the cursor is at the first +// non-whitespace rune of the line it is on +func (c *Cursor) IsStartOfText() bool { + x := 0 + for util.IsWhitespace(c.RuneUnder(x)) { + if x == utf8.RuneCount(c.buf.LineBytes(c.Y)) { + break + } + x++ + } + return c.X == x +} + // End moves the cursor to the end of the line it is on func (c *Cursor) End() { c.X = utf8.RuneCount(c.buf.LineBytes(c.Y)) diff --git a/runtime/help/keybindings.md b/runtime/help/keybindings.md index 12105306..f303e8a2 100644 --- a/runtime/help/keybindings.md +++ b/runtime/help/keybindings.md @@ -162,6 +162,8 @@ SelectUp SelectDown SelectLeft SelectRight +SelectToStartOfText +SelectToStartOfTextToggle WordRight WordLeft SelectWordRight @@ -209,6 +211,8 @@ HalfPageUp HalfPageDown StartOfLine EndOfLine +StartOfText +StartOfTextToggle ParagraphPrevious ParagraphNext ToggleHelp @@ -245,6 +249,9 @@ JumpToMatchingBrace Autocomplete ``` +The `StartOfTextToggle` and `SelectToStartOfTextToggle` actions toggle between +jumping to the start of the text (first) and start of the line. + You can also bind some mouse actions (these must be bound to mouse buttons) ``` @@ -410,21 +417,21 @@ conventions for text editing defaults. "ShiftDown": "SelectDown", "ShiftLeft": "SelectLeft", "ShiftRight": "SelectRight", - "AltLeft": "WordLeft", - "AltRight": "WordRight", + "AltLeft": "WordLeft", (Mac) + "AltRight": "WordRight", (Mac) "AltUp": "MoveLinesUp", "AltDown": "MoveLinesDown", "CtrlShiftRight": "SelectWordRight", "CtrlShiftLeft": "SelectWordLeft", - "AltLeft": "StartOfLine", + "AltLeft": "StartOfTextToggle", "AltRight": "EndOfLine", "AltShiftRight": "SelectWordRight", (Mac) "AltShiftLeft": "SelectWordLeft", (Mac) "CtrlLeft": "StartOfText", (Mac) "CtrlRight": "EndOfLine", (Mac) - "AltShiftLeft": "SelectToStartOfLine", - "CtrlShiftLeft": "SelectToStartOfText", (Mac) - "ShiftHome": "SelectToStartOfLine", + "AltShiftLeft": "SelectToStartOfTextToggle", + "CtrlShiftLeft": "SelectToStartOfTextToggle", (Mac) + "ShiftHome": "SelectToStartOfTextToggle", "AltShiftRight": "SelectToEndOfLine", "CtrlShiftRight": "SelectToEndOfLine", (Mac) "ShiftEnd": "SelectToEndOfLine",