<div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto">But since the names are all really short i think the way you did it is probably best</div></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><br></div><div dir="auto"><br></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 15, 2019 at 10:04 Kjell Godo <<a href="mailto:squeaklist@gmail.com">squeaklist@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span style="font-family:UICTFontTextStyleTallBody;font-size:17px">[_]— how about </span></div><div dir="auto"><span style="font-family:UICTFontTextStyleTallBody;font-size:17px"><br></span></div><div dir="auto"><span style="font-family:UICTFontTextStyleTallBody;font-size:17px">No that won’t work won’t fulfill the specification</span></div><div><span style="font-family:UICTFontTextStyleTallBody;font-size:17px">0 < ( ( eachName select:[ :c | c isUpperCase ] ) </span></div><div dir="auto"><span style="font-family:UICTFontTextStyleTallBody;font-size:17px">               indexOfSubCollection: pattern )</span><br></div><div dir="auto"><span style="font-family:UICTFontTextStyleTallBody;font-size:17px"><br></span></div><div dir="auto"><span style="font-family:UICTFontTextStyleTallBody;font-size:17px">almost</span></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 15, 2019 at 09:24 Marcel Taeumel <<a href="mailto:marcel.taeumel@hpi.de" target="_blank">marcel.taeumel@hpi.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div id="m_3688883981076232422m_-7869528651049377061__MailbirdStyleContent" style="font-size:10pt;font-family:Arial;color:#000000">
                                        
                                        
                                            
                                        
                                        
                                        Hi Kjell,<div><br></div><div>thanks for your suggestions. This algorithm is bound to what support is there in the Trunk image. So <span style="font-family:Arial,Helvetica,sans-serif;font-size:13px;line-height:19.5px">KEGGenerators is no option here.</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px;line-height:19.5px"><br></span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px;line-height:19.5px">Your alternative looks like this for Squeak:</span></div><div><span style="font-family:Arial,Helvetica,sans-serif;font-size:13px;line-height:19.5px"><br></span></div><div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b>potentialNames select: [:eachName | | first stillAMatch |</b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">       </span>first := true.</b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">     </span>stillAMatch := true.</b></span></span></div><div><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap;font-size:13px;line-height:19.5px"><span style="font-family:Arial,Helvetica,sans-serif"><b>     </b></span></span><b style="font-size:13px;line-height:19.5px;font-family:Arial,Helvetica,sans-serif">((pattern inject: 1 into: [:i :char | </b></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">           </span>stillAMatch</b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">                        </span>ifTrue: [</b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">                          </span>(eachName findString: char asString startingAt: i)</b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">                                 </span>in: [:i1 |</b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">                                         </span>stillAMatch := (first ifTrue: [i = i1] ifFalse: [i < i1]).</b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">                                              </span>first := false];</b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">                                   </span>yourself] </b></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><b><span class="m_3688883981076232422m_-7869528651049377061Apple-tab-span" style="white-space:pre-wrap">                        </span>ifFalse: [0]] ) > 0) & stillAMatch ] </b></span></span></div></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><br></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px">For 'WKD' as input, it takes 695 microseconds to find the results. The current version (after the re-used stream), takes 1670 microseconds to find the results.</span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><br></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px">Maybe we can also get rid of that "char asString" ? Or is that optimized?</span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px"><br></span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px">Best,</span></span></div><div><span style="font-family:Arial,Helvetica,sans-serif"><span style="font-size:13px;line-height:19.5px">Marcel</span></span></div></div><div id="m_3688883981076232422m_-7869528651049377061__MailbirdStyleContent" style="font-size:10pt;font-family:Arial;color:#000000"><div class="m_3688883981076232422m_-7869528651049377061mb_sig"></div>
                                        
                                        <blockquote class="m_3688883981076232422m_-7869528651049377061history_container" type="cite" style="border-left-style:solid;border-width:1px;margin-top:20px;margin-left:0px;padding-left:10px;min-width:500px">
                        <p style="color:#aaaaaa;margin-top:10px">Am 15.07.2019 17:08:54 schrieb Kjell Godo <<a href="mailto:squeaklist@gmail.com" target="_blank">squeaklist@gmail.com</a>>:</p><div style="font-family:Arial,Helvetica,sans-serif">
<div><div dir="auto"><div dir="auto">WHOOPS</div></div><div dir="auto"><div dir="auto"><div dir="auto">[_]— or how about </div></div><div dir="auto"><br></div><div dir="auto"> </div><div dir="auto">potentialNames select:[ :eachName | | first stillAMatch | first := stillAMatch := true  . [</div><div dir="auto">  ( ( pattern inject:( 1 )into:[ :i :p | </div><div dir="auto">     stillAMatch ifTrue:[</div><div dir="auto">       ( eachName indexOfSubCollection:( p asString )startingAt: i </div><div dir="auto">        )yourselfAfter:[ :i1 | stillAMatch := first ifTrue:[i = i1]ifFalse:[i<i1] . first := false ] </div><div dir="auto">       ifFalse:[ 0 ] ] </div><div dir="auto">    ) ~= 0 </div><div dir="auto">    ) && stillAMatch</div><div dir="auto">  ]on:Error do:[ :e | false ]</div><div dir="auto">  ]</div></div></div><div dir="auto"><br></div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 15, 2019 at 08:03 Kjell Godo <<a href="mailto:squeaklist@gmail.com" target="_blank">squeaklist@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;min-width:500px"><div><div dir="auto">WHOOPS</div></div><div><div dir="auto"><div dir="auto">[_]— or how about </div></div><div dir="auto"><br></div><div dir="auto"> </div><div dir="auto">potentialNames select:[ :eachName | | first stillAMatch | first := stillAMatch := true .</div><div dir="auto">  ( ( pattern inject:( 1 )into:[ :i :p | </div><div dir="auto">     stillAMatch ifTrue:[</div><div dir="auto">       ( eachName indexOfSubCollection:( p asString )startingAt: i </div><div dir="auto">        )yourselfAfter:[ :i1 | stillAMatch := first ifTrue:[i = i1]ifFalse:[i<i1] . first := false ] </div><div dir="auto">       ifFalse:[ 0 ] ] </div><div dir="auto">    ) ~= 0 </div><div dir="auto">    ) && stillAMatch</div><div dir="auto">   ]</div><div dir="auto"><br></div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 15, 2019 at 07:59 Kjell Godo <<a href="mailto:squeaklist@gmail.com" target="_blank">squeaklist@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;min-width:500px"><div><div dir="auto">[_]— or how about </div></div><div dir="auto"><br></div><div dir="auto"> </div><div dir="auto">potentialNames select:[ :eachName | | first stillAMatch | first := stillAMatch := true .</div><div dir="auto">  ( ( pattern inject:( 1 )into:[ :i :p | </div></blockquote></div></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;min-width:500px"><div dir="auto">     stillAMatch ifTrue:[</div><div dir="auto">       ( eachName indexOfSubCollection:( p asString )startingAt: i </div><div dir="auto">        )yourselfAfter:[ :i1 | stillAMatch := first ifTrue:[i = i1]ifFalse:[i<i1] . first := false ] </div><div dir="auto">       ifFalse:[ 0 ] ] </div><div dir="auto">    ) ~= 0 </div><div dir="auto">    ) && stillAMatch</div><div dir="auto">   ]</div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jul 15, 2019 at 06:55 Kjell Godo <<a href="mailto:squeaklist@gmail.com" target="_blank">squeaklist@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;min-width:500px"><div><br></div><div><br><div class="gmail_quote"></div></div><div><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" target="_blank">commits@source.squeak.org</a>> wrote:<br></div></div></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;min-width:500px"></blockquote></div></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;min-width:500px">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></blockquote></div></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;min-width:500px">
+                               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;min-width:500px"><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></div></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;min-width:500px"><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>
</blockquote></div></div>
</blockquote></div></div>
</blockquote></div></div>
</div></blockquote></div><br>
</blockquote></div></div>
</blockquote></div></div>