=============== Summary ===============
Change Set: browseMethodReference Date: 28 November 2022 Author: Christoph Thiede
Adds support for method references in editors's 'Browse it' and 'iMplmentors' shortcuts. Method references can have different formats such as String findMethodReference or String>>#findMethodReference. Includes tests and proper support for message traces.
Performance: <1.1 ms per run if you select an entire line, which should be fine. :-)
Also makes sure that no debuggers opens up when you browse the iMplementors of an incomplete literal such as a single quote.
=============== Diff ===============
MessageTrace>>browseMethod:requestor: {actions} · ct 11/28/2022 18:00 + browseMethod: aMethodReference requestor: requestor + "Overwritten to modify the trace if the request origins from a model-menu command such as the message-list menu (shortcut)." + + (Preferences traceMessages and: [ self hasUnacceptedEdits not ]) + ifTrue: [ self + addChildMessages: (OrderedCollection with: aMethodReference) + autoSelectString: '' ] + ifFalse: [ super browseAllImplementorsOf: aMethodReference requestor: requestor ].
Model>>browseMethod: {*Tools-MessageSets} · ct 11/28/2022 18:58 + browseMethod: aMethodReference + "A tool's widget/view (i.e., 'requestor') requested to browse aMethodReference. By default, dispatch back to the reference." + + ^ aMethodReference browse
Model>>browseMethod:requestor: {*Tools-MessageSets} · ct 11/28/2022 18:58 + browseMethod: aMethodReference requestor: requestor + "A tool's widget/view (i.e., 'requestor') requested to browse aMethodReference. By default, dispatch back to the reference." + + ^ self browseMethod: aMethodReference
ParagraphEditor>>selectedLiteral {menu messages} · ct 11/28/2022 18:18 (changed) selectedLiteral "Try to make a Smalltalk literal out of the current text selection."
- ^ self selection string findLiteral + ^ [self selection string findLiteral] ifError: ["e.g., incomplete string"]
String>>findMethodReference {converting} · ct 11/28/2022 19:03 + findMethodReference + "Find and parse a method reference within the receiver. Answer a MethodReference or nil if none is found. Heuristic." + + | str substrings | + str := self copyReplaceAll: '>>' with: ' >> '. + str := str copyWithRegex: '(?=(?<![^\p{L}:\s])[^\p{L}#:\s]|(?<=[^\p{L}#:\s])[\p{L}#:\s])' matchesReplacedWith: ' '. "beginning or end of token" + substrings := str substrings. + substrings size - 1 to: 1 by: -1 do: [:classIndex | | classStr | + classStr := substrings at: classIndex. + (self environment classNamed: classStr) ifNotNil: [:class | + (classIndex + 1 + ((substrings at: classIndex + 1) = '>>') asBit clampHigh: substrings size) to: classIndex + 1 by: -1 do: [:selIndex | + | ref selStr | + selStr := substrings at: selIndex. + (selStr size > 1 and: [selStr first = $#]) ifTrue: [selStr := selStr allButFirst]. + (Symbol lookup: selStr) ifNotNil: [:sel | + ref := MethodReference + class: class + selector: sel. + ref isValid ifTrue: [^ ref]]]]]. + ^ nil
StringTest>>testFindMethodReference {tests - finding} · ct 11/28/2022 18:11 + testFindMethodReference + + { + Number >> #negated. 'Number negated'. + Number >> #negated. 'Number>>negated'. + Number >> #negated. 'Number>>#negated'. + Number >> #negated. 'Number >> #negated'. + + Number >> #negated. 'Number >> #negated.'. + Number >> #negated. '"Number >> #negated"'. + Number >> #negated. 'For more information, see Number>>#negated or run the tests.'. + + nil. 'Number absentSelector'. + nil. ''. + + Morph >> #drawOn:. 'Morph drawOn:'. + nil. 'Morph drawOn'. "Do not add colons." + + Number >> #+. 'Number +'. + Number >> #+. 'Number>>+'. + Number >> #+. 'Number>>#+'. + Number >> #+. 'Number+'. + + Behavior >> #>>. 'Behavior >>'. + Behavior >> #>>. 'Behavior>>'. + Behavior >> #>>. 'Behavior>> >>'. + } pairsDo: [:method :string | + self + assert: (method ifNotNil: [method asCodeReference]) + equals: string findMethodReference].
TextEditor>>browseIt {menu messages} · ct 11/28/2022 17:53 (changed) browseIt "Launch a browser for the current selection, if appropriate."
+ self selectedMethodReference ifNotNil: + [:methodReference | ^self model browseMethod: methodReference requestor: morph]. Preferences alternativeBrowseIt ifTrue: [^ self browseClassFromIt].
self lineSelectAndEmptyCheck: [^ morph flash].
"First, try to show all accesses to instance or class variables." self selectedInstanceVariable ifNotNil: [:nameToClass | self systemNavigation browseAllAccessesTo: nameToClass key from: nameToClass value]. self selectedClassVariable ifNotNil: [:binding | self model browseAllCallsOn: binding].
"Then, either browse the class (from a binding) or all implementors of a selector." self selectedBinding ifNotNil: [:binding | ^ self systemNavigation browseClass: binding]. self selectedSelector ifNotNil: [:selector | ^ self model browseAllImplementorsOf: selector requestor: morph]. morph flash
TextEditor>>implementorsOfIt {menu messages} · ct 11/28/2022 17:05 (changed) implementorsOfIt "Open an implementors browser on the selected selector"
self lineSelectAndEmptyCheck: [^ self]. + self selectedMethodReference ifNotNil: + [:methodReference | ^self model browseMethod: methodReference requestor: morph]. self selectedSelector ifNotNil: [:aSelector| ^self model browseAllImplementorsOf: aSelector requestor: morph]. self selectedLiteral ifNotNil: [:aLiteral| ^self model browseAllImplementorsOf: aLiteral requestor: morph]. morph flash.
TextEditor>>selectedLiteral {menu messages} · ct 11/28/2022 18:18 (changed) selectedLiteral "Try to make a Smalltalk literal out of the current text selection."
- ^ self selection string findLiteral + ^ [self selection string findLiteral] ifError: ["e.g., incomplete string"]
TextEditor>>selectedMethodReference {menu messages} · ct 11/28/2022 17:06 + selectedMethodReference + "Try to make a method reference out of the current text selection." + + ^ self selection string findMethodReference
--- Sent from Squeak Inbox Talk ["browseMethodReference.1.cs"]
squeak-dev@lists.squeakfoundation.org