Platform-specific edit bindings for move-by-word and backspace-word (#5564)

Make the edit keybindings for "move-by-word" and "backspace-word"
platform-dependent so that they are with ctrl on Windows and Linux, but
alt on Mac. These are the common conventions on these platforms. Also,
make them configurable so that user who can't get used to the change can
map it back to what they were.

Add a "forward-delete-word" keybinding, bound to alt-delete on Mac, and
ctrl-delete on Windows and Linux.
This commit is contained in:
Stefan Haller 2026-04-30 22:38:35 +02:00 committed by GitHub
commit ccae993b40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 89 additions and 8 deletions

View file

@ -630,6 +630,18 @@ keybinding:
nextMatch: "n"
prevMatch: "N"
startSearch: /
# <a-left> on Mac
moveWordLeft: <c-left>
# <a-right> on Mac
moveWordRight: <c-right>
# <a-backspace> on Mac
backspaceWord: <c-backspace>
# <a-delete> on Mac
forwardDeleteWord: <c-delete>
optionMenu: <disabled>
optionMenu-alt1: '?'
select: <space>

View file

@ -454,6 +454,10 @@ type KeybindingUniversalConfig struct {
NextMatch string `yaml:"nextMatch"`
PrevMatch string `yaml:"prevMatch"`
StartSearch string `yaml:"startSearch"`
MoveWordLeft string `yaml:"moveWordLeft"` // <a-left> on Mac
MoveWordRight string `yaml:"moveWordRight"` // <a-right> on Mac
BackspaceWord string `yaml:"backspaceWord"` // <a-backspace> on Mac
ForwardDeleteWord string `yaml:"forwardDeleteWord"` // <a-delete> on Mac
OptionMenu string `yaml:"optionMenu"`
OptionMenuAlt1 string `yaml:"optionMenu-alt1"`
Select string `yaml:"select"`
@ -933,6 +937,10 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig {
NextMatch: "n",
PrevMatch: "N",
StartSearch: "/",
MoveWordLeft: platformKeyBinding(platform, map[string]string{"darwin": "<a-left>"}, "<c-left>"),
MoveWordRight: platformKeyBinding(platform, map[string]string{"darwin": "<a-right>"}, "<c-right>"),
BackspaceWord: platformKeyBinding(platform, map[string]string{"darwin": "<a-backspace>"}, "<c-backspace>"),
ForwardDeleteWord: platformKeyBinding(platform, map[string]string{"darwin": "<a-delete>"}, "<c-delete>"),
OptionMenu: "<disabled>",
OptionMenuAlt1: "?",
Select: "<space>",

View file

@ -22,12 +22,22 @@ func (f EditorFunc) Edit(v *View, key Key) bool {
// DefaultEditor is the default editor.
var DefaultEditor Editor = EditorFunc(SimpleEditor)
var (
moveWordLeftKeybinding = NewKey(KeyArrowLeft, "", ModCtrl)
moveWordRightKeybinding = NewKey(KeyArrowRight, "", ModCtrl)
backspaceWordKeybinding = NewKey(KeyBackspace, "", ModCtrl)
forwardDeleteWordKeybinding = NewKey(KeyDelete, "", ModCtrl)
)
// SimpleEditor is used as the default gocui editor.
func SimpleEditor(v *View, key Key) bool {
switch {
case key.Equals(NewKey(KeyBackspace, "", ModAlt)),
case key.Equals(backspaceWordKeybinding),
key.Equals(NewKeyStrMod("w", ModCtrl)):
v.TextArea.BackSpaceWord()
case key.Equals(forwardDeleteWordKeybinding),
key.Equals(NewKeyStrMod("d", ModAlt)):
v.TextArea.ForwardDeleteWord()
case key.Equals(NewKeyName(KeyBackspace)):
v.TextArea.BackSpaceChar()
case key.Equals(NewKeyStrMod("d", ModCtrl)),
@ -38,13 +48,13 @@ func SimpleEditor(v *View, key Key) bool {
case key.Equals(NewKeyName(KeyArrowUp)):
v.TextArea.MoveCursorUp()
case key.Equals(NewKeyStrMod("b", ModAlt)),
key.Equals(NewKey(KeyArrowLeft, "", ModAlt)):
key.Equals(moveWordLeftKeybinding):
v.TextArea.MoveLeftWord()
case key.Equals(NewKeyName(KeyArrowLeft)),
key.Equals(NewKeyStrMod("b", ModCtrl)):
v.TextArea.MoveCursorLeft()
case key.Equals(NewKeyStrMod("f", ModAlt)),
key.Equals(NewKey(KeyArrowRight, "", ModAlt)):
key.Equals(moveWordRightKeybinding):
v.TextArea.MoveRightWord()
case key.Equals(NewKeyName(KeyArrowRight)),
key.Equals(NewKeyStrMod("b", ModCtrl)):

View file

@ -1629,3 +1629,10 @@ func (g *Gui) Snapshot() string {
return builder.String()
}
func (g *Gui) SetEditKeybindings(moveWordLeft, moveWordRight, backspaceWord, forwardDeleteWord Key) {
moveWordLeftKeybinding = moveWordLeft
moveWordRightKeybinding = moveWordRight
backspaceWordKeybinding = backspaceWord
forwardDeleteWordKeybinding = forwardDeleteWord
}

View file

@ -340,13 +340,12 @@ func (self *TextArea) MoveLeftWord() {
self.cursor = self.newCursorForMoveLeftWord()
}
func (self *TextArea) MoveRightWord() {
func (self *TextArea) newCursorForMoveRightWord() int {
if self.atEnd() {
return
return self.cursor
}
if self.atLineEnd() {
self.cursor++
return
return self.cursor + 1
}
cellCursor := self.contentCursorToCellCursor(self.cursor)
@ -364,7 +363,11 @@ func (self *TextArea) MoveRightWord() {
}
}
self.cursor = self.cellCursorToContentCursor(cellCursor)
return self.cellCursorToContentCursor(cellCursor)
}
func (self *TextArea) MoveRightWord() {
self.cursor = self.newCursorForMoveRightWord()
}
func (self *TextArea) MoveCursorUp() {
@ -559,6 +562,20 @@ func (self *TextArea) BackSpaceWord() {
self.updateCells()
}
func (self *TextArea) ForwardDeleteWord() {
newCursor := self.newCursorForMoveRightWord()
if newCursor == self.cursor {
return
}
clipboard := self.content[self.cursor:newCursor]
if clipboard != "\n" {
self.clipboard = clipboard
}
self.content = self.content[:self.cursor] + self.content[newCursor:]
self.updateCells()
}
func (self *TextArea) Yank() {
self.TypeString(self.clipboard)
}

View file

@ -474,6 +474,13 @@ func (gui *Gui) onUserConfigLoaded() error {
gui.g.NextSearchMatchKey = config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.NextMatch)
gui.g.PrevSearchMatchKey = config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.PrevMatch)
gui.g.SetEditKeybindings(
config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.MoveWordLeft),
config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.MoveWordRight),
config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.BackspaceWord),
config.GetValidatedKeyBindingKey(userConfig.Keybinding.Universal.ForwardDeleteWord),
)
gui.g.ShowListFooter = userConfig.Gui.ShowListFooter
gui.g.Mouse = userConfig.Gui.MouseEvents

View file

@ -1410,6 +1410,26 @@
"type": "string",
"default": "/"
},
"moveWordLeft": {
"type": "string",
"description": "\u003ca-left\u003e on Mac",
"default": "\u003cc-left\u003e"
},
"moveWordRight": {
"type": "string",
"description": "\u003ca-right\u003e on Mac",
"default": "\u003cc-right\u003e"
},
"backspaceWord": {
"type": "string",
"description": "\u003ca-backspace\u003e on Mac",
"default": "\u003cc-backspace\u003e"
},
"forwardDeleteWord": {
"type": "string",
"description": "\u003ca-delete\u003e on Mac",
"default": "\u003cc-delete\u003e"
},
"optionMenu": {
"type": "string",
"default": "\u003cdisabled\u003e"