Skip to content

Commit

Permalink
Rewrite selection erase to not allocate internal string buffer twice
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacalz committed Feb 27, 2024
1 parent f1cfe93 commit 595c1fb
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 21 deletions.
61 changes: 41 additions & 20 deletions widget/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -901,16 +901,13 @@ func (e *Entry) TypedRune(r rune) {
// if we've typed a character and we're selecting then replace the selection with the character
cb := e.OnChanged
if e.selecting {
e.OnChanged = nil // don't propagate this change to binding etc
e.eraseSelection()
e.OnChanged = cb // the change later will then trigger callback
}

provider := e.textProvider()
e.selecting = false

runes := []rune{r}
pos := e.cursorTextPos()

provider := e.textProvider()
provider.insertAt(pos, string(runes))

content := provider.String()
Expand Down Expand Up @@ -985,7 +982,7 @@ func (e *Entry) cutToClipboard(clipboard fyne.Clipboard) {

e.copyToClipboard(clipboard)
e.propertyLock.Lock()
e.eraseSelection()
e.eraseSelectionAndUpdate()
content := e.Text
cb := e.OnChanged
e.propertyLock.Unlock()
Expand All @@ -997,17 +994,17 @@ func (e *Entry) cutToClipboard(clipboard fyne.Clipboard) {
e.Refresh()
}

// eraseSelection removes the current selected region and moves the cursor
func (e *Entry) eraseSelection() {
// eraseSelection deletes the selected text and moves the cursor but does not update the text field.
func (e *Entry) eraseSelection() bool {
if e.Disabled() {
return
return false
}

provider := e.textProvider()
posA, posB := e.selection()

if posA == posB {
return
return false
}

erasedText := e.Text[posA:posB]
Expand All @@ -1016,13 +1013,22 @@ func (e *Entry) eraseSelection() {
e.CursorRow, e.CursorColumn = e.rowColFromTextPos(posA)
e.selectRow, e.selectColumn = e.CursorRow, e.CursorColumn
e.selecting = false
e.updateText(provider.String(), false)

e.undoStack.MergeOrAdd(&entryModifyAction{
Delete: true,
Position: posA,
Text: erasedText,
})

return true
}

// eraseSelectionAndUpdate removes the current selected region and moves the cursor.
// It also updates the text if something has been erased.
func (e *Entry) eraseSelectionAndUpdate() {
if e.eraseSelection() {
e.updateText(e.textProvider().String(), false)
}
}

func (e *Entry) getRowCol(p fyne.Position) (int, int) {
Expand All @@ -1049,33 +1055,48 @@ func (e *Entry) getRowCol(p fyne.Position) (int, int) {
// pasteFromClipboard inserts text from the clipboard content,
// starting from the cursor position.
func (e *Entry) pasteFromClipboard(clipboard fyne.Clipboard) {
if e.selecting {
e.SetFieldsAndRefresh(e.eraseSelection)
}

text := clipboard.Content()
if text == "" {
e.propertyLock.Lock()
changed := e.selecting && e.eraseSelection()
e.propertyLock.Unlock()

if changed {
e.Refresh()
}

return // Nothing to paste into the text content.
}

if !e.MultiLine {
// format clipboard content to be compatible with single line entry
text = strings.Replace(text, "\n", " ", -1)
}
provider := e.textProvider()

e.propertyLock.Lock()
if e.selecting {
e.eraseSelection()
}

runes := []rune(text)
pos := e.cursorTextPos()
provider := e.textProvider()
provider.insertAt(pos, text)

e.propertyLock.Lock()
e.undoStack.Add(&entryModifyAction{
Position: pos,
Text: text,
})
e.updateText(provider.String(), false)
content := provider.String()
e.updateText(content, false)
e.CursorRow, e.CursorColumn = e.rowColFromTextPos(pos + len(runes))
cb := e.OnChanged
e.propertyLock.Unlock()

if cb != nil {
cb(content) // We know that the text has changed.
}

e.Refresh() // placing the cursor (and refreshing) happens last
}

Expand Down Expand Up @@ -1267,7 +1288,7 @@ func (e *Entry) selectingKeyHandler(key *fyne.KeyEvent) bool {
case fyne.KeyBackspace, fyne.KeyDelete:
// clears the selection -- return handled
e.propertyLock.Lock()
e.eraseSelection()
e.eraseSelectionAndUpdate()
content := e.Text
cb := e.OnChanged
e.propertyLock.Unlock()
Expand All @@ -1281,7 +1302,7 @@ func (e *Entry) selectingKeyHandler(key *fyne.KeyEvent) bool {
case fyne.KeyReturn, fyne.KeyEnter:
if e.MultiLine {
// clear the selection -- return unhandled to add the newline
e.SetFieldsAndRefresh(e.eraseSelection)
e.SetFieldsAndRefresh(e.eraseSelectionAndUpdate)
}
return false
}
Expand Down
2 changes: 1 addition & 1 deletion widget/entry_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ func TestEntry_EraseSelection(t *testing.T) {
keyPress(&fyne.KeyEvent{Name: fyne.KeyRight})

_ = e.Theme()
e.eraseSelection()
e.eraseSelectionAndUpdate()
e.updateText(e.textProvider().String(), false)
assert.Equal(t, "Testing\nTeng\nTesting", e.Text)
a, b := e.selection()
Expand Down

0 comments on commit 595c1fb

Please sign in to comment.