Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Ctrl+[backspace/delete] to delete the word to the left or right of the cursor #4662

Merged
merged 5 commits into from
May 18, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions widget/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,37 @@ func (e *Entry) typedKeyEnd(provider *RichText) {
e.propertyLock.Unlock()
}

// handler for Ctrl+[backspace/delete] - delete the word
// to the left or right of the cursor
func (e *Entry) deleteWord(right bool) {
provider := e.textProvider()
cursorRow, cursorCol := e.CursorRow, e.CursorColumn

// start, end relative to text row
start, end := getTextWhitespaceRegion(provider.row(cursorRow), cursorCol, true)
if right {
start = cursorCol
} else {
end = cursorCol
}
if start == -1 || end == -1 {
return
}

// convert start, end to absolute text position
b := provider.rowBoundary(cursorRow)
if b != nil {
start += b.begin
end += b.begin
}

provider.deleteFromTo(start, end)
if !right {
e.CursorColumn = cursorCol - (end - start)
}
e.updateTextAndRefresh(provider.String(), false)
}

// TypedRune receives text input events when the Entry widget is focused.
//
// Implements: fyne.Focusable
Expand Down Expand Up @@ -1176,6 +1207,11 @@ func (e *Entry) registerShortcut() {
e.shortcut.AddShortcut(&desktop.CustomShortcut{KeyName: fyne.KeyLeft, Modifier: moveWordModifier | fyne.KeyModifierShift}, selectMoveWord)
e.shortcut.AddShortcut(&desktop.CustomShortcut{KeyName: fyne.KeyRight, Modifier: moveWordModifier}, unselectMoveWord)
e.shortcut.AddShortcut(&desktop.CustomShortcut{KeyName: fyne.KeyRight, Modifier: moveWordModifier | fyne.KeyModifierShift}, selectMoveWord)

e.shortcut.AddShortcut(&desktop.CustomShortcut{KeyName: fyne.KeyBackspace, Modifier: moveWordModifier},
func(fyne.Shortcut) { e.deleteWord(false) })
e.shortcut.AddShortcut(&desktop.CustomShortcut{KeyName: fyne.KeyDelete, Modifier: moveWordModifier},
func(fyne.Shortcut) { e.deleteWord(true) })
}

func (e *Entry) requestFocus() {
Expand Down
26 changes: 26 additions & 0 deletions widget/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,32 @@ func TestEntry_Control_Word(t *testing.T) {
assert.Equal(t, "", entry.SelectedText())
}

func TestEntry_Control_DeleteWord(t *testing.T) {
entry := widget.NewMultiLineEntry()
entry.SetText("Hello world\nhere is a second line")
entry.CursorRow = 1
entry.CursorColumn = 10 // right before "second"
modifier := fyne.KeyModifierControl
if runtime.GOOS == "darwin" {
modifier = fyne.KeyModifierAlt
}
// Ctrl+delete - delete word to right ("second")
entry.TypedShortcut(&desktop.CustomShortcut{Modifier: modifier, KeyName: fyne.KeyDelete})
assert.Equal(t, "Hello world\nhere is a line", entry.Text)
assert.Equal(t, 10, entry.CursorColumn)

entry.CursorColumn = 8 // right before "a"
// Ctrl+backspace - delete word to left ("is")
entry.TypedShortcut(&desktop.CustomShortcut{Modifier: modifier, KeyName: fyne.KeyBackspace})
assert.Equal(t, "Hello world\nhere a line", entry.Text)
assert.Equal(t, 5, entry.CursorColumn)

// does nothing when nothing left to delete
entry.SetText("")
entry.TypedShortcut(&desktop.CustomShortcut{Modifier: modifier, KeyName: fyne.KeyBackspace})
assert.Equal(t, "", entry.Text)
}

func TestEntry_CursorColumn_Wrap(t *testing.T) {
entry := widget.NewMultiLineEntry()
entry.SetText("a\nb")
Expand Down
Loading