<div dir="ltr">Very nice.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jun 12, 2020 at 5:55 AM Marcel Taeumel <<a href="mailto:marcel.taeumel@hpi.de">marcel.taeumel@hpi.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div id="gmail-m_-1220167939263343435__MailbirdStyleContent" style="font-size:10pt;font-family:Arial;color:rgb(0,0,0)">
                                        <img id="gmail-m_-1220167939263343435c1c8dbf5-5e72-43f5-a463-0ee0c975fa7a" src="cid:172ab31cc31cb971f161" width="auto"><br><div></div><blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-top:20px;margin-left:0px;padding-left:10px">
                        <p style="color:rgb(170,170,170);margin-top:10px">Am 12.06.2020 12:53:10 schrieb <a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a> <<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>>:</p><div style="font-family:Arial,Helvetica,sans-serif">Marcel Taeumel uploaded a new version of Tools to project The Trunk:<br><a href="http://source.squeak.org/trunk/Tools-mt.975.mcz" target="_blank">http://source.squeak.org/trunk/Tools-mt.975.mcz</a><br><br>==================== Summary ====================<br><br>Name: Tools-mt.975<br>Author: mt<br>Time: 12 June 2020, 12:52:57.245703 pm<br>UUID: c79c0e69-43cf-1d48-9f95-7fd4f4435bb7<br>Ancestors: Tools-mt.974<br><br>- adds support for extension methods to dep browser<br>- adds support for shared pools to dep browser<br>- reveal nature of deps in labels early on<br>- pre-select the first item in lists to speed up dependency browsing<br><br>=============== Diff against Tools-mt.974 ===============<br><br>Item was changed:<br>  CodeHolder subclass: #DependencyBrowser<br>+       instanceVariableNames: 'packageList packageDeps packageDepsList classDeps classDepsList classList messageList packageListIndex packageDepsIndex classDepsIndex classListIndex messageListIndex'<br>-      instanceVariableNames: 'packageList packageDeps classDeps classList messageList packageListIndex packageDepsIndex classDepsIndex classListIndex messageListIndex'<br>     classVariableNames: ''<br>        poolDictionaries: ''<br>          category: 'Tools-Browser'!<br>  <br>  !DependencyBrowser commentStamp: 'fbs 5/6/2011 11:29' prior: 0!<br>  A simple dependency browser showing five panes:<br>  [1]: Packages: The list of available packages in the system.<br>  [2]: Package Dependencies: The dependent packages of the currently selected package.<br>  [3]: Class Dependencies: The classes causing the dependencies.<br>  [4]: Class List: The classes introducing the dependencies.<br>  [5]: Messages: The messages introducing the dependencies.!<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>buildClassDepsWith: (in category 'toolbuilder') -----<br>  buildClassDepsWith: builder<br>        | listSpec |<br>          listSpec := builder pluggableListSpec new.<br>    listSpec <br>             model: self;<br>                  name: 'Required Classes' ;<br>+           list: #classDepsList; <br>-               list: #classDeps; <br>            getIndex: #classDepsIndex; <br>           setIndex: #classDepsIndex:; <br>                  menu: #classDepsMenu:; <br>               keyPress: #classDepsKey:from:.<br>        ^listSpec<br>  !<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>buildPackageDepsWith: (in category 'toolbuilder') -----<br>  buildPackageDepsWith: builder<br>        | listSpec |<br>          listSpec := builder pluggableListSpec new.<br>    listSpec <br>             model: self;<br>                  name: 'Required Packages' ;<br>+          list: #packageDepsList; <br>-             list: #packageDeps; <br>                  getIndex: #packageDepsIndex; <br>                 setIndex: #packageDepsIndex:; <br>                menu: #packageDepsMenu:; <br>             keyPress: #packageDepsKey:from:.<br>      ^listSpec<br>  !<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>classDepsIndex: (in category 'class deps') -----<br>  classDepsIndex: idx<br>         "Class dependency selection"<br>        classDepsIndex := idx.<br>-       self classListIndex: 0.<br>       self changed: #classDepsIndex.<br>+       classList := nil.<br>     self changed: #classList.<br>+    self classListIndex: (idx = 0 ifTrue: [0] ifFalse: [1]).!<br>- !<br><br>Item was added:<br>+ ----- Method: DependencyBrowser>>classDepsList (in category 'class deps') -----<br>+ classDepsList<br>+  "Class dependencies for the currently selected package"<br>+ <br>+        ^ classDepsList ifNil: [        <br>+             classDepsList := self classDeps.<br>+             classDepsList := classDepsList collect: [:className |<br>+                        (self<br>+                                depsForClassNamed: className<br>+                                 allSatisfy: [:mref | mref selector = #Definition])<br>+                                   ifTrue: [className, ' (defs only)']<br>+                                  ifFalse: [(self<br>+                                              depsForClassNamed: className<br>+                                                 allSatisfy: [:mref | mref category notNil and: [mref category first = $*]])<br>+                                                  ifTrue: [className, ' *ext only*']<br>+                                                   ifFalse: [className]]].<br>+              classDepsList]!<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>classList (in category 'class list') -----<br>  classList<br>        "List of classes that refer to dependencies"<br>+       |  selectedPackage |<br>          classDeps ifNil: [^ #()].<br>+    self classDepsSelection ifNil: [^ #()].<br>       <br>+     selectedPackage := PackageOrganizer default<br>+          packageNamed: self packageListSelection ifAbsent: [nil]. <br>-    "classList stores the actual classes displayed in my class list, corresponding to the collection of Strings returned by self classList. This allows us to unambiguously determine the class or metaclass currently being browsed simply by knowing the index of the selected class."<br>-       classList := ((classDeps at: self classDepsSelection ifAbsent:[#()]) <br>-                collect:[:mref| mref actualClass] as: Set) asArray sort: [:a :b | a name < b=""><br>              <br>+     classList := (classDeps at: self classDepsSelection ifAbsent: [#()]) <br>+                collect: [:mref |<br>+                    mref selector = #Definition<br>+                          ifTrue: [mref actualClass name, ' (class definition)']<br>+                               ifFalse: [mref category first = $*<br>+                                   ifTrue: ['*extensions']<br>+                                      ifFalse: [mref actualClass name]]]<br>+           as: Set.<br>+     <br>+     ^ classList := classList asArray sort!<br>-       ^ classList collect: #name.!<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>classListIndex: (in category 'class list') -----<br>  classListIndex: idx<br>   "Class list selection"<br>      classListIndex := idx.<br>-       self messageListIndex: 0.<br>     self changed: #classListIndex.<br>        self changed: #messageList.<br>+  self messageListIndex: (idx = 0 ifTrue: [0] ifFalse: [1]).<br>  !<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>classListSelection (in category 'class list') -----<br>  classListSelection<br>      "Class list selection"<br>+     ^ self selectedClassOrMetaClass name!<br>-        ^(self classListIndex between: 1 and: self classList size)<br>-           ifTrue:[self classList at: self classListIndex]!<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>computePackageDependencies: (in category 'package deps') -----<br>  computePackageDependencies: pkgName<br>         "Compute the dependencies for the given package"<br>    | pi |<br>        classDeps := Dictionary new.<br>          packageDeps := Dictionary new.<br>        pkgName ifNil:[^self].<br>        pi := PackageOrganizer default packageNamed: pkgName ifAbsent:[^self]. "unloaded"<br>+  pi classes do:[:pkgClass |<br>-   pi classes do:[:pkgClass| <br>            (classDeps at: (pkgClass superclass ifNil:[ProtoObject]) name<br>                         ifAbsentPut:[OrderedCollection new]) add: <br>+                           (MethodReference class: pkgClass selector: #Definition).<br>+             pkgClass sharedPools do: [:sharedPool |<br>+                      sharedPool isBehavior ifTrue: [<br>+                              (classDeps at: sharedPool name<br>+                                       ifAbsentPut:[OrderedCollection new]) add: <br>+                                           (MethodReference class: pkgClass selector: #Definition)]]].<br>-                          (MethodReference class: pkgClass selector: #Definition)].<br>  <br>+        pi coreMethods do:[:mref| <br>-   pi methods do:[:mref| <br>                mref compiledMethod allLiteralsDo:[:lit |<br>                     (lit isVariableBinding and: [lit value isBehavior]) ifTrue:[<br>                                  (classDeps at: lit value name ifAbsentPut:[OrderedCollection new])<br>                                    add: mref]]].<br>  <br>+    pi extensionMethods do:[:mref|<br>+               (classDeps at: mref actualClass name ifAbsentPut: [OrderedCollection new])<br>+                   add: mref].<br>+ <br>       classDeps keys do:[:className| | aClass pkg |<br>                 aClass := Smalltalk classNamed: className.<br>            pkg := aClass ifNil: [nil] ifNotNil: [PackageOrganizer default packageOfClass: aClass ifNone:[nil]].<br>                  pkg ifNil:[<br>                   Transcript cr; show: 'WARNING: No package for ', className.<br>                   (classDeps removeKey: className) do:[:each| Transcript crtab; show: each].<br>            ] ifNotNil:[<br>                          (packageDeps at: pkg name ifAbsentPut:[OrderedCollection new]) add: className.<br>                ].<br>    ].<br>  <br>        (packageDeps removeKey: pkgName ifAbsent:[#()]) do:[:each|<br>            classDeps removeKey: each ifAbsent:[].<br>        ].!<br><br>Item was added:<br>+ ----- Method: DependencyBrowser>>depsForClassNamed:allSatisfy: (in category 'enumerating') -----<br>+ depsForClassNamed: className allSatisfy: workBlock<br>+ <br>+   self<br>+                 depsForClassNamed: className<br>+                 do: [:mref | (workBlock value: mref) ifFalse: [^ false]].<br>+    ^ true!<br><br>Item was added:<br>+ ----- Method: DependencyBrowser>>depsForClassNamed:do: (in category 'enumerating') -----<br>+ depsForClassNamed: className do: workBlock<br>+ <br>+       classDeps ifNil: [^ self].<br>+   (classDeps at: className ifAbsent: [^ self]) do: workBlock.!<br><br>Item was added:<br>+ ----- Method: DependencyBrowser>>depsForPackageNamed:allSatisfy: (in category 'enumerating') -----<br>+ depsForPackageNamed: packageName allSatisfy: workBlock<br>+ <br>+    self<br>+                 depsForPackageNamed: packageName<br>+             do: [:mref | (workBlock value: mref) ifFalse: [^ false]].<br>+    ^ true!<br><br>Item was added:<br>+ ----- Method: DependencyBrowser>>depsForPackageNamed:do: (in category 'enumerating') -----<br>+ depsForPackageNamed: packageName do: workBlock<br>+ <br>+         classDeps ifNil: [^ self].<br>+   classDeps keysAndValuesDo: [:className :dependencies |<br>+               (self selectedEnvironment classNamed: className) ifNotNil: [:class |<br>+                         class packageInfo name = packageName ifTrue: [<br>+                               dependencies do: workBlock]]].!<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>messageList (in category 'message list') -----<br>  messageList<br>          "List of messages creating dependencies"<br>+   | selectedClass label filter |<br>-       | selectedClass |<br>     classDeps ifNil: [^ #()].<br>+    classList ifNil: [^ #()].<br>     <br>      selectedClass := self classListSelection.<br>+    label := classList at: classListIndex ifAbsent: [''].<br>+        <br>+     filter := label ifEmpty: [ [:mref | false] ] ifNotEmpty: [<br>+           (label first = $* or: [(label endsWith: '(class definition)') not])<br>+                  ifTrue: [ [:mref | mref selector ~= #Definition and: [mref actualClass name = selectedClass]] ]<br>+                      ifFalse: [ [:mref | mref selector = #Definition and: [mref actualClass name = selectedClass]] ]].<br>+    <br>      ^((classDeps at: self classDepsSelection ifAbsent:[#()]) <br>+            select: filter<br>+               thenCollect:[:mref| mref methodSymbol]) asSet asArray sort!<br>-          select:[:each| each actualClass name = selectedClass]<br>-                thenCollect:[:mref| mref methodSymbol]) asArray sort!<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>packageDepsIndex: (in category 'package deps') -----<br>  packageDepsIndex: aNumber<br>        "Current package dependencies selection"<br>    packageDepsIndex := aNumber.<br>-         self classDepsIndex: 0.<br>       self changed: #packageDepsIndex.<br>+     <br>+     classDepsList := nil.<br>+        self changed: #classDepsList.<br>+        self classDepsIndex: (aNumber = 0 ifTrue: [0] ifFalse: [1]).<br>-         self changed: #classDeps.<br>  !<br><br>Item was added:<br>+ ----- Method: DependencyBrowser>>packageDepsList (in category 'package deps') -----<br>+ packageDepsList<br>+    "Package dependencies for the currently selected package"<br>+  <br>+     ^ packageDepsList ifNil: [<br>+           packageDepsList := self packageDeps.<br>+                 packageDepsList := packageDepsList collect: [:packageName |<br>+                  (self<br>+                                depsForPackageNamed: packageName<br>+                             allSatisfy: [:mref | mref selector = #Definition])<br>+                                   ifTrue: [packageName, ' (defs only)']<br>+                                        ifFalse: [(self<br>+                                              depsForPackageNamed: packageName<br>+                                             allSatisfy: [:mref | mref category notNil and: [mref category first = $*]])<br>+                                                  ifTrue: [packageName, ' *ext only*']<br>+                                                         ifFalse: [packageName]]].<br>+            packageDepsList]!<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>packageListIndex: (in category 'package list') -----<br>  packageListIndex: aNumber<br>    "Current package list selection"<br>    packageListIndex := aNumber.<br>          self changed: #packageListIndex.<br>-     self packageDepsIndex: 0.<br>     packageDeps := nil.<br>+  packageDepsList := nil.<br>+      self changed: #packageDepsList.<br>+      self packageDepsIndex: (aNumber = 0 ifTrue: [0] ifFalse: [1]).<br>-       self changed: #packageDeps.<br>  !<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>selectedClass (in category 'class list') -----<br>  selectedClass<br>+      "Answer the class that is currently selected. Answer nil if no selection exists."<br>-  "Answer the class that is currently selected. Answer nil if no selection <br>-       exists."<br>         <br>+     ^ self selectedClassOrMetaClass<br>-      | name envt nonMetaClass nonMetaName |<br>-       (name := self selectedClassName) ifNil: [^ nil].<br>-     (envt := self selectedEnvironment) ifNil: [^ nil].<br>-   nonMetaName := (name endsWith: ' class') ifTrue: [name allButLast: 6] ifFalse: [name].<br>-       nonMetaClass := envt at: nonMetaName asSymbol ifAbsent: [^ nil].<br>-     ^ nonMetaName = name ifTrue: [nonMetaClass] ifFalse: [nonMetaClass class].<br>  !<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>selectedClassName (in category 'class list') -----<br>  selectedClassName<br>        | idx |<br>       idx := classListIndex ifNil: [0].<br>+    ^ (classList ifNotNil: [ :l | l at: idx ifAbsent: [nil]])<br>+            ifNotNil: [:label |<br>+                  label first = $*<br>+                             ifTrue: [nil "extension methods"]<br>+                          ifFalse: [(label endsWith: '(class definition)')<br>+                                     ifTrue: [label findTokens first]<br>+                                     ifFalse: [label "e.g., 'String' or 'String class'"]]]!<br>-     ^ self classList ifNotNil: [ :l | l at: idx ifAbsent: [nil]]!<br><br>Item was changed:<br>  ----- Method: DependencyBrowser>>selectedClassOrMetaClass (in category 'class list') -----<br>  selectedClassOrMetaClass<br>    "Answer the class or metaclass that is currently selected. Answer nil if no selection <br>   exists."<br>         classList ifNil: [^nil].<br>+     ^ (self selectedEnvironment classNamed: (self selectedClassName ifNil: ['']))<br>+                ifNil: [classListIndex > 0 ifFalse: [nil] ifTrue: [<br>+                       "Use the class the current selection is depending on such as for method extensions or (base) class definitions."<br>+                   self selectedEnvironment classNamed: (self classDepsSelection ifNil: [''])]]!<br>-        ^ classList at: classListIndex ifAbsent: [nil].!<br><br><br></div></blockquote>
                                        </div></div><br>
</blockquote></div>