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

[Backport] Undo fixes p12 #17309

Merged
merged 3 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions src/NECompletion-Morphic/CompletionEngine.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ CompletionEngine >> replaceTokenInEditorWith: aString [

The completion context uses this API to insert text into the text editor"

| newString wordEnd old doubleSpace wordStart |
| newString wordEnd doubleSpace wordStart oldSelectionInterval |

newString := aString.
wordStart := self completionTokenStart.
Expand All @@ -355,12 +355,12 @@ CompletionEngine >> replaceTokenInEditorWith: aString [
"If the returned index is the size of the text that means that the caret is at the end of the text and there is no more word after, so add 1 to the index to be out of range to select the entierely word because of the selectInvisiblyFrom:to: remove 1 just after to be at the end of then final word"
wordEnd > self editor text size ifTrue:[ wordEnd := wordEnd + 1 ].

oldSelectionInterval := self editor selectionInterval.
self editor
selectInvisiblyFrom: wordStart
to: wordEnd - 1.
old := self editor selection.

self editor replaceSelectionWith: newString.
self editor replaceSelectionWith: newString fromSelection: oldSelectionInterval.

doubleSpace := newString indexOfSubCollection: ' ' startingAt: 1 ifAbsent: [ newString size ].
self editor selectAt: wordStart + doubleSpace.
Expand Down
50 changes: 50 additions & 0 deletions src/NECompletion-Tests/CompletionEngineTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ CompletionEngineTest >> editorTextWithCaret [
^ (source copyFrom: 1 to: editor caret-1), '|', (source copyFrom: editor caret to: source size)
]

{ #category : 'helpers' }
CompletionEngineTest >> expectText: aString [

self assert: editor text asString equals: aString
]

{ #category : 'accessing' }
CompletionEngineTest >> interactionModel [

Expand Down Expand Up @@ -995,3 +1001,47 @@ CompletionEngineTest >> testSmartQuoteSurroundsSelection [
controller smartCharacterWithEvent: (self keyboardPressFor: $').
self assert: editor text equals: ' ''text'' '
]

{ #category : 'tests - undo' }
CompletionEngineTest >> testUndoAutocompleteLeavesCursorInOriginalPosition [

"If the caret is at the end of a word, replace the entire word"
editor addString: 'self'.
editor closeTypeIn.
editor unselect.

"Put the cursor after the `sel` token, and then we will simulate code completion"
self selectAt: 'self' size - 1.

editor textArea openInWorld.
controller openMenu.

controller context replaceTokenInEditorWith: 'selection'.

editor undo.
self expectText: 'self'.
self assert: editor selectionInterval equals: (3 to: 2)
]

{ #category : 'tests - undo' }
CompletionEngineTest >> testUndoCompletionEntryKeepsFollowingLine [

"If the caret is at the end of a word, replace the entire word"

| text |
text := 'self mEthOdThatDoes
nextLine'.

self
setEditorText: text;
selectAt: text lines first size.

editor textArea openInWorld.
controller openMenu.

controller context replaceTokenInEditorWith: 'mEthOdThatDoesNotExist'.

editor undo.

self assert: editor text asString equals: text
]
20 changes: 20 additions & 0 deletions src/Rubric-Tests/RubAbstractTest.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Class {
#name : 'RubAbstractTest',
#superclass : 'TestCase',
#instVars : [
'string',
'editor'
],
#category : 'Rubric-Tests-Editing-Core',
#package : 'Rubric-Tests',
#tag : 'Editing-Core'
}

{ #category : 'running' }
RubAbstractTest >> setUp [

super setUp.
editor := RubTextEditor forTextArea: RubEditingArea new.
"Add text with a paragraph"
string := 'Lorem ipsum '
]
87 changes: 87 additions & 0 deletions src/Rubric-Tests/RubTextEditorLocalHistoryTest.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
Class {
#name : 'RubTextEditorLocalHistoryTest',
#superclass : 'RubAbstractTest',
#category : 'Rubric-Tests-Editing-Core',
#package : 'Rubric-Tests',
#tag : 'Editing-Core'
}

{ #category : 'tests - undo' }
RubTextEditorLocalHistoryTest >> expectText: aString [

self assert: editor text asString equals: aString
]

{ #category : 'tests - undo' }
RubTextEditorLocalHistoryTest >> selectAt: anIndex [
editor selectFrom: anIndex to: anIndex - 1
]

{ #category : 'tests - undo' }
RubTextEditorLocalHistoryTest >> testRedoCompletionEntryKeepsFollowingLine [

"If the caret is at the end of a word, replace the entire word"
editor addString: 'self'.
editor closeTypeIn.
editor unselect.
"Simulate an enter"
editor crWithIndent: KeyboardEvent new.
editor addString: ' b'.
editor closeTypeIn.
editor unselect.

"Put the cursor after the `self` token, and then we will simulate code completion"
self selectAt: 'self' size + 1.
editor addString: ' te'.
editor closeTypeIn.

self expectText: 'self te
b'.

editor undo.
self expectText: 'self
b'.

editor redo.
self expectText: 'self te
b'.
]

{ #category : 'tests - undo' }
RubTextEditorLocalHistoryTest >> testRedoLeavesCursorInOriginalPosition [

"If the caret is at the end of a word, replace the entire word"
editor addString: 'self'.
editor unselect.
editor undo.
editor redo.

self expectText: 'self'.
self assert: editor selectionInterval equals: (5 to: 4)
]

{ #category : 'tests - undo' }
RubTextEditorLocalHistoryTest >> testUndoAfterTypeThenTabUndoesOnlyTheTab [

editor addString: 'self'.
editor unselect.
editor tab: KeyboardEvent new.

editor undo.

self expectText: 'self'
]

{ #category : 'tests - undo' }
RubTextEditorLocalHistoryTest >> testUndoWordUndoesOneWordAtATime [

editor addString: 'self'.
editor unselect.
editor space: KeyboardEvent new.

editor addString: 'toto'.

editor undo.

self expectText: 'self'
]
6 changes: 1 addition & 5 deletions src/Rubric-Tests/RubTextEditorTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,7 @@ A RubTextEditorTest is a test class for testing the behavior of RubTextEditor
"
Class {
#name : 'RubTextEditorTest',
#superclass : 'TestCase',
#instVars : [
'editor',
'string'
],
#superclass : 'RubAbstractTest',
#category : 'Rubric-Tests-Editing-Core',
#package : 'Rubric-Tests',
#tag : 'Editing-Core'
Expand Down
16 changes: 14 additions & 2 deletions src/Rubric/RubAbstractTextArea.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -1744,7 +1744,13 @@ RubAbstractTextArea >> recomputeSelection [

{ #category : 'multi level undo' }
RubAbstractTextArea >> redoTypeIn: aText interval: anInterval [
self handleEdit: [self editor redoTypeIn: aText interval: anInterval]

^ self redoTypeIn: aText interval: anInterval selection: anInterval
]

{ #category : 'multi level undo' }
RubAbstractTextArea >> redoTypeIn: aText interval: anInterval selection: selection [
self handleEdit: [self editor redoTypeIn: aText interval: anInterval selection: selection]
]

{ #category : 'caching' }
Expand Down Expand Up @@ -2105,7 +2111,13 @@ RubAbstractTextArea >> undoRedoExchange: aninterval with: anotherInterval [

{ #category : 'multi level undo' }
RubAbstractTextArea >> undoTypeIn: aText interval: anInterval [
self handleEdit: [self editor undoTypeIn: aText interval: anInterval]

^ self undoTypeIn: aText interval: anInterval selection: anInterval
]

{ #category : 'multi level undo' }
RubAbstractTextArea >> undoTypeIn: aText interval: anInterval selection: aSelection [
self handleEdit: [self editor undoTypeIn: aText interval: anInterval selection: aSelection]
]

{ #category : 'private' }
Expand Down
Loading