Christoph Thiede uploaded a new version of Morphic to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.2127.mcz
==================== Summary ====================
Name: Morphic-ct.2127 Author: ct Time: 1 September 2023, 1:29:26.309701 pm UUID: 7a729ae8-2ad8-0c45-b98d-aa25605321f8 Ancestors: Morphic-ct.2125
Revises #insertTextReplacement proposal for PluggableTextMorph by avoiding changes to #replaceSelectionWith: and #zapSelectionWith: in TextEditor. Fixes selection restoration for edge cases such as inverse selection. Indeed an ancestor of Morphic-ct.2125.
=============== Diff against Morphic-ct.2125 ===============
Item was changed: ----- Method: TextEditor>>insertText:from:to:invisibly: (in category 'accessing') ----- insertText: newText from: start to: stop invisibly: invisibly
+ | priorSelection replacement replacementStart replacementStop newSelection inverseSelection | + priorSelection := self markIndex to: self pointIndex - 1. - | priorSelection | - priorSelection := self selectionInterval. self selectInvisiblyFrom: start to: stop. + replacementStart := self startIndex. + replacementStop := self stopIndex. + self openTypeIn. + replacement := newText isText + ifTrue: [newText] + ifFalse: [Text string: newText attributes: + ((paragraph text attributesAt: (self pointIndex - 1 max: 1) forStyle: paragraph textStyle) + select: [:att | att mayBeExtended])]. + self text replaceFrom: replacementStart to: replacementStop - 1 with: replacement. + paragraph + recomposeFrom: replacementStart + to: replacementStart + replacement size - 1 + delta: replacement size - (replacementStop - replacementStart). + self markIndex: replacementStart pointIndex: replacementStart + replacement size. + otherInterval := self selectionInterval. + invisibly ifFalse: [ + self userHasEdited]. + self closeTypeIn. - self restoreEmphasisHereAfter: [ - self setEmphasisHere. - self replaceSelectionWith: newText invisibly: invisibly]. invisibly ifFalse: [^ self]. "Restore previous selection. Also update it if behind insertion." + inverseSelection := priorSelection start > (priorSelection stop + 1). + inverseSelection ifTrue: [priorSelection := priorSelection stop to: priorSelection start]. + newSelection := priorSelection. + priorSelection start >= replacementStop ifTrue: [ + newSelection := (newSelection start + replacement size - (stop - start) - 1) to: newSelection stop]. + ""(priorSelection start between: start and: stop) ifTrue: [ + newSelection := (newSelection start clampHigh: (replacementStart + replacement size - 1)) to: newSelection stop]."" + priorSelection stop >= replacementStop ifTrue: [ + newSelection := newSelection start to: newSelection stop + replacement size - (stop - start) - 1]. + (priorSelection stop between: start and: stop) ifTrue: [ + newSelection := newSelection start to: (newSelection stop clampLow: newSelection start - 1 high: replacementStart + replacement size)]. + inverseSelection ifTrue: [newSelection := newSelection stop to: newSelection start]. + self selectInvisiblyFrom: newSelection start to: newSelection stop.! - priorSelection start >= start ifTrue: [ - priorSelection := priorSelection start + newText size - (stop - start) - 1 to: priorSelection stop]. - priorSelection stop >= start ifTrue: [ - priorSelection := priorSelection start to: priorSelection stop + newText size - (stop - start) - 1]. - self selectInvisiblyFrom: priorSelection start to: priorSelection stop.!
Item was changed: ----- Method: TextEditor>>replaceSelectionWith: (in category 'undo') ----- replaceSelectionWith: aText + "Remember the selection text in UndoSelection. + Deselect, and replace the selection text by aText. + Remember the resulting selectionInterval in UndoInterval and PriorInterval. + Set up undo to use UndoReplace."
+ self openTypeIn. + self zapSelectionWith: aText. + self closeTypeIn.! - ^ self replaceSelectionWith: aText invisibly: false!
Item was removed: - ----- Method: TextEditor>>replaceSelectionWith:invisibly: (in category 'undo') ----- - replaceSelectionWith: aText invisibly: invisibly - "Remember the selection text in UndoSelection. - Deselect, and replace the selection text by aText. - Remember the resulting selectionInterval in UndoInterval and PriorInterval. - Set up undo to use UndoReplace. - Unless invisibly, notify the text morph about the change." - - self openTypeIn. - self zapSelectionWith: aText invisibly: invisibly. - self closeTypeIn.!
Item was removed: - ----- Method: TextEditor>>restoreEmphasisHereAfter: (in category 'accessing') ----- - restoreEmphasisHereAfter: aBlock - - | priorEmphasis | - priorEmphasis := emphasisHere. - ^ aBlock ensure: [ - emphasisHere := priorEmphasis]!
Item was changed: ----- Method: TextEditor>>zapSelectionWith: (in category 'mvc compatibility') ----- zapSelectionWith: replacement
+ | start stop rep | + morph readOnly ifTrue: [^ self]. + start := self startIndex. + stop := self stopIndex. + (replacement isEmpty and: [stop > start]) ifTrue: [ + "If deleting, then set emphasisHere from 1st character of the deletion" + emphasisHere := (self text attributesAt: start) select: [:att | att mayBeExtended]]. + (start = stop and: [ replacement isEmpty ]) ifFalse: [ + morph plainTextOnly + ifTrue: [ + "We support TextAlignment but nothing else. Rely on emphasisHere." + rep := Text string: replacement asString attributes: emphasisHere ] + ifFalse: [ replacement isText + ifTrue: [ rep := replacement] + ifFalse: [ rep := Text string: replacement attributes: emphasisHere ] ]. + + self text replaceFrom: start to: stop - 1 with: rep. + paragraph + recomposeFrom: start + to: start + rep size - 1 + delta: rep size - (stop-start). + self markIndex: start pointIndex: start + rep size. + otherInterval := self selectionInterval]. + + self userHasEdited " -- note text now dirty"! - ^ self zapSelectionWith: replacement invisibly: false!
Item was removed: - ----- Method: TextEditor>>zapSelectionWith:invisibly: (in category 'mvc compatibility') ----- - zapSelectionWith: replacement invisibly: invisibly - - | start stop rep | - morph readOnly ifTrue: [^ self]. - start := self startIndex. - stop := self stopIndex. - (replacement isEmpty and: [stop > start]) ifTrue: [ - "If deleting, then set emphasisHere from 1st character of the deletion" - emphasisHere := (self text attributesAt: start) select: [:att | att mayBeExtended]]. - (start = stop and: [ replacement isEmpty ]) ifFalse: [ - morph plainTextOnly - ifTrue: [ - "We support TextAlignment but nothing else. Rely on emphasisHere." - rep := Text string: replacement asString attributes: emphasisHere ] - ifFalse: [ replacement isText - ifTrue: [ rep := replacement] - ifFalse: [ rep := Text string: replacement attributes: emphasisHere ] ]. - - self text replaceFrom: start to: stop - 1 with: rep. - paragraph - recomposeFrom: start - to: start + rep size - 1 - delta: rep size - (stop-start). - self markIndex: start pointIndex: start + rep size. - otherInterval := self selectionInterval]. - - invisibly ifFalse: [ - self userHasEdited " -- note text now dirty"].!
squeak-dev@lists.squeakfoundation.org