<div><br></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 15, 2019 at 00:18 <<a href="mailto:commits@source.squeak.org">commits@source.squeak.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Marcel Taeumel uploaded a new version of ToolBuilder-Kernel to project The Trunk:<br>
<a href="http://source.squeak.org/trunk/ToolBuilder-Kernel-mt.125.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/trunk/ToolBuilder-Kernel-mt.125.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: ToolBuilder-Kernel-mt.125<br>
Author: mt<br>
Time: 11 July 2019, 8:50:30.487838 am<br>
UUID: 3f3a21f8-a141-734f-8aed-f0c21aff22b9<br>
Ancestors: ToolBuilder-Kernel-mt.124<br>
<br>
Updates the search for class names using the new find-features feature on strings. Find WeakIdentityKeyDictionary (in a small list of results) with any of the following patterns:<br>
<br>
WKD<br>
Weak*Dict*<br>
WeakDict<br>
WeakIdentityKeyDictionary<br>
<br>
=============== Diff against ToolBuilder-Kernel-mt.124 ===============<br>
<br>
Item was changed:<br>
----- Method: UIManager>>classOrTraitFrom:pattern:label: (in category 'system introspecting') -----<br>
classOrTraitFrom: environment pattern: pattern label: label<br>
+ "Given a pattern and an environment, try to find a class or trait using several strategies:<br>
+ - EXACT: If there is a class or trait whose name exactly given by pattern, return it.<br>
+ - UPPER: If the pattern is upper-case only, find camel-case letters with that sequence.<br>
+ - WILD: Try the pattern as-is for regular wild-card search.<br>
+ - FEATURE: Split patterns at feature boundaries and insert wild cards between.<br>
+ - FUZZY: Split patterns at feature boundaries BUT treat each feature as a full class name.<br>
+ If there is only one class or trait in the given environment whose name matches pattern, return it. Otherwise, put up a menu offering the names of all classes that match pattern, and return the class chosen, else nil if nothing chosen.<br>
- "If there is a class or trait whose name exactly given by pattern, return it.<br>
- If there is only one class or trait in the given environment whose name matches pattern, return it.<br>
- Otherwise, put up a menu offering the names of all classes that match pattern, and return the class chosen, else nil if nothing chosen.<br>
- This method ignores separator characters in the pattern"<br>
<br>
+ !!!! In any case, separator characters in the pattern are ignored."<br>
+ <br>
+ | toMatch potentialNames names selectedIndex |<br>
+ <br>
+ "If there's a class or trait named as pattern, then return it."<br>
+ (environment classOrTraitNamed: pattern) ifNotNil: [:classOrTrait | ^ classOrTrait].<br>
+ <br>
+ "Validate pattern." <br>
- | toMatch potentialNames names exactMatch lines reducedIdentifiers selectedIndex |<br>
toMatch := pattern copyWithoutAll: Character separators.<br>
+ toMatch := toMatch asLowercase copyWithout: $..<br>
toMatch ifEmpty: [ ^nil ].<br>
+ <br>
+ "Fetch search space."<br>
+ names := OrderedCollection new.<br>
+ potentialNames := environment classAndTraitNames asOrderedCollection.<br>
+ <br>
+ "Try uppercase-only patterns for patterns such as 'WKD' to find 'WeakIdentityKeyDictionary' etc."<br>
+ names ifEmpty: [<br>
+ (pattern allSatisfy: [:char | char isUppercase]) ifTrue: [<br>
+ potentialNames do: [:each |<br>
+ | patternStream |<br>
+ patternStream := pattern readStream.<—-[ [_]— you don’t </blockquote><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">really need to recreate this same patternStream for each [ :each ... ] do you ? ]<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br></blockquote><div dir="auto"><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
+ each detect: [:char |<br>
+ (patternStream atEnd not and: [patternStream peek = char])<br>
+ ifTrue: [<br>
+ patternStream next.<br>
+ patternStream atEnd<br>
+ ifTrue: [names add: each. true "Match!!"]<br>
+ ifFalse: [false "Not yet..."]]<br>
+ ifFalse: [false "No match..."] ] ifNone: [] ] ]].</blockquote><div dir="auto"><br></div><div dir="auto"><——————-—-[ [_]— using KEGGenerators maybe it could be done like</div><div dir="auto"> [ | last eNGen | </div><div dir="auto"> ( pattern asCharacters lastDo:[ :p | last := true . p ] )ifNotNil:[ :patternGen |</div><div dir="auto"> potentialNames select:[ :eachName | last := false .</div><div dir="auto"> ( patternGen shuffle:[ :p :c | (p=c)yourselfDo:[ :b | b ifTrue:[ eNGen next ] . last := b&&last ] ]</div><div dir="auto"> with:( eNGen := eachName asGenerator )</div><div dir="auto"> ) iterate . last</div><div dir="auto"> ]</div><div dir="auto"> ]”<——-[ [x]— >>lastDo: evaluates its input on last element p of pattern </div><div dir="auto"> [x]— >>shuffle:with: does (p=c)<=>( patternGen next ) i think</div><div dir="auto"> [x]— >>yourselfDo: returns its receiver r after doing( aBlock value:r )</div><div dir="auto"> [_]— String>>asCharacters = String>>asCharacter<—-[ is part</div><div dir="auto"> of the singular is plural idea of you don’t have to separate </div><div dir="auto"> singular from plural with KEGGenerators just do( obj asGen ) ] ]”</div><div dir="auto">] value .”<—-[ [_]— move local vars last & eNGen up and delete this >>value ]”</div><div dir="auto"><br></div><div dir="auto">or </div><div dir="auto"><br></div><div dir="auto"><div dir="auto"> [ | last eNGen | </div><div dir="auto"> ( </div><div dir="auto"> ( pattern asCharacters lastDo:[ :p | last := true . p ] </div><div dir="auto"> ) shuffle:[ :p :c | (p=c)yourselfDo:[ :b | b ifTrue:[ eNGen next ]. last:=b&&last ] ] ]</div><div dir="auto"> with:( eNGen := KEGGenerator streamGenerator ) </div><div dir="auto"> )ifNotNil:[ :shuffleGen |</div><div dir="auto"> potentialNames select:[ :eachName | last := false . eNGen genOn:eacName . </div><div dir="auto"> shuffleGen iterate . last</div><div dir="auto"> ]</div><div dir="auto"> ]”<——-[ [_]— this actually does not reAllocate any ..Generator in the loop ]”</div><div dir="auto">] value .”<—-[ untested . not looked up . unpublished >>genOn: = >>on: i think ]”</div><div dir="auto"><br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
+ <br>
+ "Try wildcard search for patterns such as 'Weak*Dict*' to find 'WeakIdentityKeyDictionary' etc."<br>
+ names ifEmpty: [<br>
+ names := potentialNames select: [ :each | toMatch match: each ]].<br>
- "If there's a class or trait named as pattern, then return it."<br>
- Symbol hasInterned: pattern ifTrue: [ :symbol |<br>
- environment at: symbol ifPresent: [ :maybeClassOrTrait |<br>
- ((maybeClassOrTrait isKindOf: Class) or: [<br>
- maybeClassOrTrait isTrait ])<br>
- ifTrue: [ ^maybeClassOrTrait ] ] ].<br>
- "No exact match, look for potential matches."<br>
- toMatch := pattern asLowercase copyWithout: $..<br>
- potentialNames := (environment classAndTraitNames) asOrderedCollection.<br>
- names := pattern last = $. "This is some old hack, using String>>#match: may be better."<br>
- ifTrue: [ potentialNames select: [ :each | each asLowercase = toMatch ] ]<br>
- ifFalse: [<br>
- potentialNames select: [ :each |<br>
- each includesSubstring: toMatch caseSensitive: false ] ].<br>
- exactMatch := names detect: [ :each | each asLowercase = toMatch ] ifNone: [ nil ].<br>
- lines := OrderedCollection new.<br>
- exactMatch ifNotNil: [ lines add: 1 ].<br>
- "Also try some fuzzy matching."<br>
- reducedIdentifiers := pattern suggestedTypeNames select: [ :each |<br>
- potentialNames includes: each ].<br>
- reducedIdentifiers ifNotEmpty: [<br>
- names addAll: reducedIdentifiers.<br>
- lines add: 1 + names size + reducedIdentifiers size ].<br>
- "Let the user select if there's more than one possible match. This may give surprising results."<br>
- names size = 0 ifTrue: [^ nil "nothing matches"].<br>
<br>
+ "Try feature-based search for patterns such as 'WeakDict' to find 'WeakIdentityKeyDictionary' etc."<br>
+ names ifEmpty: [<br>
+ toMatch := pattern copyWithoutAll: '.*#'.<br>
+ toMatch findFeatures in: [:features |<br>
+ "1) Insert wildcards between features and at the end."<br>
+ toMatch := (features joinSeparatedBy: '*'), '*'.<br>
+ names := potentialNames select: [ :each | toMatch match: each ].<br>
+ names ifEmpty: [ <br>
+ "2) Insert wildcards before, between, and after features."<br>
+ toMatch := '*', (features joinSeparatedBy: '*'), '*'.<br>
+ names := potentialNames select: [ :each | toMatch match: each ] ]] ].<br>
+ <br>
+ "Try some fuzzy matching."<br>
+ names addAll: (pattern suggestedTypeNames select: [ :each | potentialNames includes: each ]).<br>
+ <br>
+ "Still no match?"<br>
+ names ifEmpty: [ ^ nil ].<br>
+ <br>
+ "Let the user select if there's more than one possible match. This may give surprising results." <br>
selectedIndex := names size = 1<br>
ifTrue: [ 1 ]<br>
+ ifFalse: [ self chooseFrom: names title: label ].<br>
- ifFalse: [<br>
- exactMatch ifNotNil: [ names addFirst: exactMatch ].<br>
- self chooseFrom: names lines: lines title: label ].<br>
selectedIndex = 0 ifTrue: [ ^nil ].<br>
^environment at: (names at: selectedIndex) asSymbol!<br>
<br>
<br>
</blockquote></div></div>