ChangesBrowser.st
changeset 18059 819f12f70f46
parent 18054 3bb54349d57e
child 18061 f82108ac94a1
--- a/ChangesBrowser.st	Wed Apr 25 09:32:28 2018 +0200
+++ b/ChangesBrowser.st	Wed Apr 25 11:58:04 2018 +0200
@@ -49,7 +49,7 @@
 
 Object subclass:#ChangeInfo
 	instanceVariableNames:'position chunk className selector headerLine timestamp
-		isFollowupChange'
+		isFollowupChange categoryIfCategoryChange'
 	classVariableNames:''
 	poolDictionaries:''
 	privateIn:ChangesBrowser
@@ -81,7 +81,20 @@
 
     This is a very old leftover class (it was one of the very first apps in ST/X
     and the Merovingian has not yet detected this one ;-)
-    It will be completely replaced by the ChangeSetBrowser class in the near future.
+
+    At the time this was originally written, I had a 2Mb machine, and every memory byte was a very valuable.
+    Therefore, the original did not keep any infos in memory, but instead kept a list of change-chunk file offsets,
+    and parsed the chunks over and over (eg. when searching for classname/selector etc.)
+    Later, when bigger memories became available, more and more infos where cached in additional arrays (classname,
+    selector, etc.) and those where finally condensed into a single changeInfo object.
+    However, now that really enough memory is avail, this is really no longer useful, and we should keep
+    changeSet entries instead (which hold the same info plus more).
+    The ChangeSetBrowser does exactly this, but does not support all of the fancy compress/delete etc.
+    operations of the ChangesBrowser, to which we got used so much.
+    Thus, this one kept on living its zombie life and gets occasional features added (sigh)...
+    (Well, like many workhorses, they become ugly when aged, but still do their duty)
+
+    It MUST eventually be completely replaced by the ChangeSetBrowser class in the near future.
 
 
     [Class variables:]
@@ -503,6 +516,15 @@
             isVisible: notEditingClassSource
           )
          (MenuItem
+            label: 'Cleanup'
+            itemValue: doCleanup
+            isVisible: notEditingClassSource
+          )
+         (MenuItem
+            label: '-'
+            isVisible: notEditingClassSource
+          )
+         (MenuItem
             enabled: hasSingleSelection
             label: 'Fileout && Delete all Changes for Class'
             itemValue: doFileoutAndDeleteClassAll
@@ -1716,7 +1738,7 @@
 postRealize
     self setupTabSpec.
     self readChangesFileInBackground:true.
-    self setChangeList.
+    self updateChangeList.
     changeListView action:[:lineNrOrCollection | self changeSelection:lineNrOrCollection].
     Processor addTimedBlock:checkBlock afterSeconds:5.
 
@@ -1953,6 +1975,7 @@
 
         changeNr to:lastNr do:[:changeNr |
             | cls sel |
+
             changeListView setSelection:changeNr.
 
             ((cls := self classOfChange:changeNr ifAbsent:[:className| nil]) notNil
@@ -2076,7 +2099,7 @@
                         initialAnswer:nil.
         checkinInfo isNil ifTrue:[^ self ].
 
-        changeListView setSelection:nil.
+        self unselect.
         classes do:[:eachClass |
             (SourceCodeManagerUtilities default checkinClass:eachClass withInfo:checkinInfo)
                 ifTrue:[
@@ -2084,13 +2107,73 @@
                            from:1 to:(self numberOfChanges).
                 ]
         ].
-        self setChangeList.
+        self updateChangeList.
     ]
 
     "Modified: / 6.9.1995 / 17:11:16 / claus"
     "Modified: / 17.11.2001 / 14:21:13 / cg"
 !
 
+doCleanup
+    "cleanup the changefile/changeset.
+     actions done:
+     - from the end, find changes which are equal to the current version
+       and not in the current changeset (i.e. represent the current version as built).
+       Then delete it incl. previous versions of it."
+
+    |numChanges nextChangeNr changeNr changeSelector changeClass numDeleted|
+
+    numChanges := self numberOfChanges.
+    self unselect.
+
+    self withWaitCursorDo:[
+        "/ find the last method change which is equal
+        changeNr := numChanges.
+        [changeNr > 0] whileTrue:[
+            nextChangeNr := changeNr - 1.
+
+            (changeClass := self classOfChange:changeNr ifAbsent:nil) notNil ifTrue:[
+
+                (changeInfoList at:changeNr) isMethodCategoryChange ifTrue:[
+                    (self compareChange:changeNr showResult:false) == true ifTrue:[ 
+                        (changeSelector := self selectorOfMethodCategoryChange:changeNr) notNil ifTrue:[
+                            (ChangeSet current includesChangeForClass:changeClass selector:changeSelector) ifFalse:[
+                                infoHolder value:('Deleting category changes for %1 >> %2' bindWith:changeClass name with:changeSelector).
+                                self windowGroup repairDamage.
+                                numDeleted := self
+                                   silentDeleteMethodCategoryChangesFor:changeClass name selector:changeSelector
+                                   from:1 to:changeNr.
+                                "/ self selectChange:changeNr.
+                                "/ self doDeleteClassSelectorOlder.
+                                nextChangeNr := (changeNr - numDeleted + 1) min:self numberOfChanges.
+                            ].
+                        ].
+                    ].
+                ] ifFalse:[
+                    (changeSelector := self selectorOfMethodChange:changeNr) notNil ifTrue:[
+                        (self compareChange:changeNr showResult:false) == true ifTrue:[ 
+                            "/ found a method change, which is the same as the current version
+                            "/ if in the current changeSet, then do not delete (needs checkin first)
+                            (ChangeSet current includesChangeForClass:changeClass selector:changeSelector) ifFalse:[
+                                infoHolder value:('Deleting changes for %1 >> %2' bindWith:changeClass name with:changeSelector).
+                                self windowGroup repairDamage.
+                                numDeleted := self
+                                   silentDeleteChangesFor:changeClass name selector:changeSelector
+                                   from:1 to:changeNr.
+                                "/ self selectChange:changeNr.
+                                "/ self doDeleteClassSelectorOlder.
+                                nextChangeNr := (changeNr - numDeleted + 1) min:self numberOfChanges.
+                            ].
+                        ].
+                    ].
+                ].
+            ].
+            changeNr := nextChangeNr.
+        ].
+    ].
+    self updateChangeList.
+!
+
 doCompare
     "compare change with current system version"
 
@@ -2124,7 +2207,7 @@
     toDelete reverseDo:[:changeNr |
         self silentDeleteChange:changeNr.
     ].
-    self setChangeList.
+    self updateChangeList.
     "
      scroll back a bit, if we are left way behind the list
     "
@@ -2262,7 +2345,7 @@
     namespacesToDelete isEmpty ifTrue:[^ self].
 
     overAllNumDeletedBefore := 0.
-    changeListView setSelection:nil.
+    self unselect.
 
     self withExecuteCursorDo:[
         namespacesToDelete do:[:namespaceToDelete |
@@ -2281,7 +2364,7 @@
         ].
     ].
 
-    self setChangeList.
+    self updateChangeList.
     self autoSelectOrEnd:lastChangeNr.
 !
 
@@ -2317,7 +2400,7 @@
     ].
 
     overAllNumDeletedBefore := 0.
-    changeListView setSelection:nil.
+    self unselect.
 
     self withExecuteCursorDo:[
         classNamesToDelete do:[:classNameToDelete |
@@ -2335,7 +2418,7 @@
         ].
     ].
 
-    self setChangeList.
+    self updateChangeList.
     self autoSelectOrEnd:lastChangeNr.
 
     "Created: / 13.12.1995 / 16:07:14 / cg"
@@ -2361,7 +2444,7 @@
     ].
 
     overAllNumDeletedBefore := 0.
-    changeListView setSelection:nil.
+    self unselect.
 
     self withExecuteCursorDo:[
         classNamesToDelete do:[:classNameToDelete |
@@ -2381,7 +2464,7 @@
             ]
         ]
     ].
-    self setChangeList.
+    self updateChangeList.
     self autoSelectOrEnd:lastChangeNr.
 
     "Created: / 13.12.1995 / 16:07:14 / cg"
@@ -2394,19 +2477,19 @@
      Useful to get rid of obsolete changes before a fileout or checkin entry."
 
     self withSingleSelectedChangeDo:[:changeNr |
-	|classNameToDelete prevSelection numDeleted|
-
-	classNameToDelete := self classNameOfChange:changeNr.
-	classNameToDelete notNil ifTrue:[
-	    prevSelection := changeNr.
-	    changeListView setSelection:nil.
-	    numDeleted := self
-				silentDeleteChangesFor:classNameToDelete
-				from:1
-				to:changeNr.
-	    self setChangeList.
-	    self autoSelectOrEnd:(changeNr + 1 - numDeleted)
-	]
+        |classNameToDelete prevSelection numDeleted|
+
+        classNameToDelete := self classNameOfChange:changeNr.
+        classNameToDelete notNil ifTrue:[
+            prevSelection := changeNr.
+            self unselect.
+            numDeleted := self
+                                silentDeleteChangesFor:classNameToDelete
+                                from:1
+                                to:changeNr.
+            self updateChangeList.
+            self autoSelectOrEnd:(changeNr + 1 - numDeleted)
+        ]
     ].
 
     "Created: 13.12.1995 / 15:41:58 / cg"
@@ -2417,17 +2500,17 @@
     "delete rest of changes with same class as currently selected change"
 
     self withSingleSelectedChangeDo:[:changeNr |
-	| classNameToDelete |
-
-	classNameToDelete := self classNameOfChange:changeNr.
-	classNameToDelete notNil ifTrue:[
-	    changeListView setSelection:nil.
-	    self silentDeleteChangesFor:classNameToDelete
-				   from:changeNr
-				     to:(self numberOfChanges).
-	    self setChangeList.
-	    self autoSelectOrEnd:changeNr
-	]
+        | classNameToDelete |
+
+        classNameToDelete := self classNameOfChange:changeNr.
+        classNameToDelete notNil ifTrue:[
+            self unselect.
+            self silentDeleteChangesFor:classNameToDelete
+                                   from:changeNr
+                                     to:(self numberOfChanges).
+            self updateChangeList.
+            self autoSelectOrEnd:changeNr
+        ]
     ]
 
     "Modified: / 18.5.1998 / 14:25:07 / cg"
@@ -2454,7 +2537,7 @@
     ].
 
     overAllNumDeletedBefore := 0.
-    changeListView setSelection:nil.
+    self unselect.
 
     self withExecuteCursorDo:[
         classNameSelectorPairsToDelete do:[:pair |
@@ -2474,7 +2557,7 @@
         ].
     ].
 
-    self setChangeList.
+    self updateChangeList.
     self autoSelectOrEnd:lastChangeNr
 
     "Created: / 13.12.1995 / 16:07:14 / cg"
@@ -2482,7 +2565,7 @@
 !
 
 doDeleteClassSelectorOlder
-    "delete older changes with same class and selector as currently selected change(s)"
+    "delete this and older changes with same class and selector as currently selected change(s)"
 
     |classNameSelectorPairsToDelete upToPerClassAndSelector lastChangeNr overAllNumDeletedBefore|
 
@@ -2506,7 +2589,7 @@
     ].
         
     overAllNumDeletedBefore := 0.
-    changeListView setSelection:nil.
+    self unselect.
 
     self withExecuteCursorDo:[
         classNameSelectorPairsToDelete do:[:pair |
@@ -2525,7 +2608,7 @@
         ].
     ].
 
-    self setChangeList.
+    self updateChangeList.
     self autoSelectOrEnd:lastChangeNr
 
     "Modified: / 25-07-2017 / 10:57:31 / cg"
@@ -2712,7 +2795,7 @@
     self readChangesFileInBackground:true.
     self newLabel:''.
     realized ifTrue:[
-	self setChangeList.
+        self updateChangeList.
     ]
 !
 
@@ -2724,7 +2807,7 @@
             realized ifTrue:[
                 self readChangesFile.
                 realized ifTrue:[
-                    self setChangeList
+                    self updateChangeList
                 ]
             ]
         ]
@@ -2921,7 +3004,8 @@
 
     ^ self     
         findNextOrPrevious:#next 
-        forWhich:aBlock startingAt:changeNrToStartSearch
+        forWhich:aBlock 
+        startingAt:changeNrToStartSearch
 
     "Created: / 20-11-2006 / 16:34:06 / cg"
 !
@@ -2943,8 +3027,7 @@
               or:[ direction == #next and:[ nr <= lastNr]] 
             ] whileTrue:[
                 (aBlock value:nr) ifTrue:[
-                    changeListView setSelection:nr.
-                    self changeSelection:nr.
+                    self selectChange:nr.
                     ^ nr
                 ].
                 nr := nr + increment.
@@ -3120,7 +3203,8 @@
 
     ^ self     
         findNextOrPrevious:#previous 
-        forWhich:aBlock startingAt:changeNrToStartSearch
+        forWhich:aBlock 
+        startingAt:changeNrToStartSearch
 
     "Created: / 06-10-2006 / 11:01:09 / cg"
 !
@@ -3332,14 +3416,13 @@
     "select a change"
 
     self class autoSelectNext ifTrue:[
-	(changeNr <= self numberOfChanges) ifTrue:[
-	    changeListView setSelection:changeNr.
-	    self changeSelection:changeNr.
-	    ^ self
-	]
+        (changeNr <= self numberOfChanges) ifTrue:[
+            self selectChange:changeNr.
+            ^ self
+        ]
     ].
     self clearCodeView.
-    changeListView setSelection:nil.
+    self unselect.
 
     "Modified: / 18.5.1998 / 14:26:43 / cg"
 !
@@ -3357,13 +3440,12 @@
 
     last := self numberOfChanges.
     changeNr < last ifTrue:[
-	self autoSelect:changeNr
+        self autoSelect:changeNr
     ] ifFalse:[
-	last == 0 ifTrue:[
-	    last := nil
-	].
-	changeListView setSelection:last .
-	self changeSelection:last.
+        last == 0 ifTrue:[
+            last := nil
+        ].
+        self selectChange:last.
     ]
 
     "Modified: / 13.11.2001 / 13:00:45 / cg"
@@ -3652,11 +3734,15 @@
 !
 
 parseExpression:chunk
+    "parse an expression; return a parseTree"
+
     ^ self parseExpression:chunk inNameSpace:(self nameSpaceForApply).
 !
 
 parseExpression:text inNameSpace:nameSpace
-    |parser p|
+    "parse an expression; return a parseTree"
+
+    |parser parseTree|
 
     "/ old:
     "/ does not care for VW qualified names
@@ -3668,20 +3754,22 @@
 
     "/ new:
     parser := Parser for:(ReadStream on:text).
-    parser parserFlags allowQualifiedNames:true.
-    parser parserFlags allowDollarInIdentifier:true.
-    parser parserFlags allowParagraphInIdentifier:true.
+    parser parserFlags 
+        allowQualifiedNames:true;
+        allowDollarInIdentifier:true;
+        allowParagraphInIdentifier:true.
+
     Error handle:[:ex |
         ^ nil
     ] do:[
-        p := parser 
+        parseTree := parser 
             parseExpressionWithSelf:nil 
             notifying:nil 
             ignoreErrors:true 
             ignoreWarnings:true 
             inNameSpace:nameSpace.
     ].
-    ^ p
+    ^ parseTree
 
     "Modified: / 21-11-2016 / 23:25:48 / cg"
 !
@@ -3692,6 +3780,11 @@
     ^ 'Quit without updating changeFile ?'
 !
 
+selectChange:changeNr
+    changeListView setSelection:changeNr.
+    self changeSelection:changeNr.
+!
+
 selectedClassNames
     |classes|
 
@@ -3710,19 +3803,11 @@
 !
 
 setChangeList
+    <resource: #obsolete>
     "update the selection-list;
      called after the changeList has been modified"
 
-    |headerList|
-
-    headerList := changeInfoList collect:[:info | info headerLine].
-    changeListView setList:headerList expandTabs:false redraw:false.
-    changeListView invalidate.
-    self showNumberOfChanges.
-    
-    "/ changeListView deselect.
-
-    "Modified: / 01-05-2016 / 19:27:35 / cg"
+    self updateChangeList
 !
 
 setSingleSelection:changeNr
@@ -3771,6 +3856,22 @@
     "Modified: 25.5.1996 / 13:02:49 / cg"
 !
 
+updateChangeList
+    "update the selection-list;
+     called after the changeList has been modified"
+
+    |headerList|
+
+    headerList := changeInfoList collect:[:info | info headerLine].
+    changeListView setList:headerList expandTabs:false redraw:false.
+    changeListView invalidate.
+    self showNumberOfChanges.
+    
+    "/ changeListView deselect.
+
+    "Modified: / 01-05-2016 / 19:27:35 / cg"
+!
+
 withSelectedChangesDo:aBlock
     "just a helper, check for a selected change and evaluate aBlock
      with busy cursor"
@@ -4309,19 +4410,31 @@
     "Modified: / 01-05-2016 / 19:24:53 / cg"
 !
 
+selectorOfMethodCategoryChange:changeNr
+    "return a methodCategory-change's selector, 
+     or nil if it's not a methodCategoryChange"
+
+    (changeInfoList at:changeNr) isMethodCategoryChange ifFalse:[^ nil].
+    ^ (changeInfoList at:changeNr) selector.
+
+    "Modified: / 01-05-2016 / 19:26:21 / cg"
+!
+
 selectorOfMethodChange:changeNr
-    "return a method-changes selector, 
+    "return a method-change's selector, 
      or nil if it's not a methodChange"
 
     |sel |
 
     changeInfoList size >= changeNr ifTrue:[
+        (changeInfoList at:changeNr) isMethodCategoryChange ifTrue:[^ nil].
         sel := (changeInfoList at:changeNr) selector.
         sel notNil ifTrue:[ ^ sel ].
     ].
 
     sel := self extractSelectorOfMethodChange:changeNr.
     sel notNil ifTrue:[
+        self assert:(changeInfoList at:changeNr) isMethodCategoryChange not.
         (changeInfoList at:changeNr) selector:sel.
     ].
     ^ sel
@@ -4914,14 +5027,18 @@
 !
 
 compareChange:changeNr
-    "compare a change with the current (in-image) version; show the result of the compare (as dialog)"
+    "compare a change with the current (in-image) version; 
+     show the result of the compare (as dialog)"
 
     ^ self compareChange:changeNr showResult:true
 !
 
 compareChange:changeNr showResult:doShowResult
     "compare a change with current version.
-     Return the result of the compare (same -> true, different -> false, uncomparable -> nil).
+     Return the result of the compare 
+        same -> true, 
+        different -> false, 
+        uncomparable -> nil.
      If doShowResult is true, the outcome is shown in a dialog/diffViewer."
 
     |aStream chunk sawExcla parseTree thisClass cat oldSource newSource outcome showDiff d selector isLoaded beep superClass thisClassSym varsHere varsInChange addedVars removedVars
@@ -5550,13 +5667,13 @@
         "finally delete what has been found"
 
         (deleteSet size > 0) ifTrue:[
-            changeListView setSelection:nil.
+            self unselect.
             index := deleteSet size.
             [index > 0] whileTrue:[
                 self silentDeleteChange:(deleteSet at:index).
                 index := index - 1
             ].
-            self setChangeList.
+            self updateChangeList.
             "
              scroll back a bit, if we are left way behind the list
             "
@@ -5581,9 +5698,9 @@
 deleteChangesFrom:start to:stop
     "delete a range of changes"
 
-    changeListView setSelection:nil.
+    self unselect.
     stop to:start by:-1 do:[:changeNr |
-	self silentDeleteInternalChange:changeNr.
+        self silentDeleteInternalChange:changeNr.
     ].
     changeListView removeFromIndex:start toIndex:stop.
 
@@ -5720,6 +5837,48 @@
     "Modified: / 01-05-2016 / 19:20:59 / cg"
 !
 
+silentDeleteMethodCategoryChangesFor:aClassName selector:selector from:start to:stop
+    "delete method category changes for given class/selector in a range.
+     Return the number of deleted changes."
+
+    |thisClassName index numDeleted|
+
+    numDeleted := 0.
+    index := stop.
+    [index >= start] whileTrue:[
+        thisClassName := self realClassNameOfChange:index.
+        thisClassName = aClassName ifTrue:[
+            (self selectorOfMethodCategoryChange:index) == selector ifTrue:[
+                self silentDeleteChange:index.
+                numDeleted := numDeleted + 1.
+            ]
+        ].
+        index := index - 1
+    ].
+    ^ numDeleted
+!
+
+silentDeleteMethodChangesFor:aClassName selector:selector from:start to:stop
+    "delete method changes for given class/selector in a range.
+     Return the number of deleted changes."
+
+    |thisClassName index numDeleted|
+
+    numDeleted := 0.
+    index := stop.
+    [index >= start] whileTrue:[
+        thisClassName := self realClassNameOfChange:index.
+        thisClassName = aClassName ifTrue:[
+            (self selectorOfMethodChange:index) == selector ifTrue:[
+                self silentDeleteChange:index.
+                numDeleted := numDeleted + 1.
+            ]
+        ].
+        index := index - 1
+    ].
+    ^ numDeleted
+!
+
 updateDiffView
     self withSelectedChangesDo:[:changeNr |
 	self updateDiffViewFor:changeNr.
@@ -6154,14 +6313,14 @@
 !
 
 classOfChange:changeNr ifAbsent:exceptionBlock
-    "answer the class that is subject to the chamge at changeNr.
+    "answer the class that is subject to the change at changeNr.
      The classes owning class may be autoloaded, if autoloadAsRequired is true."
 
     |className cls isMeta nameSpaceForApply path ownerName owner|
 
     className := self realClassNameOfChange:changeNr.
     className isNil ifTrue:[
-        ^ exceptionBlock value:nil
+        ^ exceptionBlock valueWithOptionalArgument:nil
     ].
 
     isMeta := false.
@@ -6201,7 +6360,7 @@
     ].
 
     cls isNil ifTrue:[
-        ^ exceptionBlock value:className
+        ^ exceptionBlock valueWithOptionalArgument:className
     ].
     isMeta ifTrue:[
         cls := cls class
@@ -6614,6 +6773,18 @@
     "Modified: / 01-05-2016 / 19:07:49 / cg"
 !
 
+colorizeAsCommentChange:changeType
+    |c|
+
+    NoColoring ~~ true ifTrue:[
+        c := changeType allItalic.
+        "/ changeString := changeString allItalic.
+        c emphasisAllAdd:(#color -> UserPreferences current commentColor).
+        ^ c
+    ].
+    ^ changeType
+!
+
 headerLineForChangeType:changeType changeString:changeString changeDelta:changeDelta timeStampInfo:timeStampInfo
     |entry|
 
@@ -6645,11 +6816,6 @@
                         ChangesBrowser::ChangeInfo new 
                             position:chunkPosition chunk:chunkText className:nil selector:nil headerLine:nil
                             timestamp:timeStampInfo isFollowupChange:false).
-"/    changeChunks add:chunkText.
-"/    changeClassNames add:nil.
-"/    changePositions add:chunkPosition.
-"/    changeTimeStamps add:timeStampInfo.
-"/    changeIsFollowupMethodChange add:false.
 
     headerLine := nil.
     changeDelta := ' '.
@@ -6660,11 +6826,6 @@
         self processMethodChunkIfNone:
             [
                 changeInfo removeLast.
-"/                changeChunks removeLast.
-"/                changeClassNames removeLast.
-"/                changePositions removeLast.
-"/                changeTimeStamps removeLast.
-"/                changeIsFollowupMethodChange removeLast.
             ]
     ].
 
@@ -6721,12 +6882,12 @@
             sel == #categoriesForClass ifTrue:[
                 methodChunks := false.
                 classCategoryChunks := true.
-                changeType := '(class category change)'.
+                changeType := self colorizeAsCommentChange:'(class category change)'.
             ] ifFalse:[
                 sel == #categoriesFor: ifTrue:[
                     methodChunks := false.
                     methodCategoryChunks := true.
-                    changeType := '(category change)'.
+                    changeType := self colorizeAsCommentChange:'(category change)'.
                     methodSelector := (p args at:1) evaluate.
                 ] ifFalse:[
                     (sel numArgs == 0) ifTrue:[
@@ -6828,7 +6989,7 @@
                     headerLine := chunkText , ' (change)'.
                 ] ifFalse:[
                     changeString :=  self contractClass:clsName selector:methodSelector to:maxLen.
-                    changeType := '{ ' , category , ' }'.
+                    changeType := ('{ ' , category , ' }').
                     headerLine := clsName , ' ' , methodSelector , ' ' , '(change category: ''' , category , ''')'.
                 ].
 
@@ -6858,8 +7019,9 @@
 !
 
 processNonMethodChunk
-    |s changeClass sel  cls p rec clsName ownerTree ownerName
-     m nameAndClass args instVarsArg classVarsArg categoryArg|
+    |s changeClass sel cls parseTree rec clsName ownerTree ownerName
+     m nameAndClass args instVarsArg classVarsArg categoryArg
+     lastInfo newCategory|
 
     (chunkText startsWith:'''---- snap') ifTrue:[
         self processSnapshotChunk.
@@ -6880,39 +7042,29 @@
     ].
     changeString := (chunkText contractTo:maxLen) withoutSeparators.
 
-    p := browser parseExpression:fullChunkText inNameSpace:Smalltalk.
-    (p notNil and:[p ~~ #Error]) ifTrue:[
-        p isMessage ifTrue:[
-            sel := p selector.
-            rec := p receiver.
-            args := p args.        
+    parseTree := browser parseExpression:fullChunkText inNameSpace:Smalltalk.
+    (parseTree notNil and:[parseTree ~~ #Error]) ifTrue:[
+        parseTree isMessage ifTrue:[
+            sel := parseTree selector.
+            rec := parseTree receiver.
+            args := parseTree args.        
         ]
     ] ifFalse:[
         sel := nil.
         (Scanner new scanTokens:fullChunkText) size == 0 ifTrue:[
             "/ a comment only
-            changeType := '(comment)'.
-            NoColoring ~~ true ifTrue:[
-                changeType := changeType allItalic.
-                "/ changeString := changeString allItalic.
-                changeType emphasisAllAdd:(#color -> UserPreferences current commentColor).
-            ]
+            changeType := self colorizeAsCommentChange:'(comment)'.
         ] ifFalse:[
             changeType := '(???)'.
         ]
     ].
 
     (sel == #comment:) ifTrue:[
-        changeType := '(comment)'.
+        changeType := self colorizeAsCommentChange:'(comment)'.
         clsName := rec name.
         changeClass := (self nameSpaceForApply) classNamed:clsName.
         (changeInfo last) className:clsName.
-        "/ changeClassNames at:changeClassNames size put:clsName.
-        NoColoring ~~ true ifTrue:[
-            changeType := changeType allItalic.
-            changeType emphasisAllAdd:(#color -> UserPreferences current commentColor).
-            "/ changeString := clsName allItalic.
-        ].
+
         autoCompare value ifTrue:[
             (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
                 changeDelta := '?'
@@ -6928,11 +7080,11 @@
 
     (sel == #removeSelector:) ifTrue:[
         nameAndClass := self extractClassAndClassNameFromParseTree:rec.
-        clsName := nameAndClass key. changeClass := nameAndClass value.
+        clsName := nameAndClass key. 
+        changeClass := nameAndClass value.
 
         sel := (args at:1) evaluate.
         (changeInfo last) className:clsName.
-        "/ changeClassNames at:changeClassNames size put:clsName.
 
         autoCompare value ifTrue:[
             (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
@@ -6951,27 +7103,37 @@
         ^ self.
     ].
 
-    (p notNil
-    and:[p ~~ #Error
-    and:[p isMessage
+    (parseTree notNil
+    and:[parseTree ~~ #Error
+    and:[parseTree isMessage
     and:[rec isMessage
     and:[rec selector == #compiledMethodAt:]]]]) ifTrue:[
         nameAndClass := self extractClassAndClassNameFromParseTree:rec receiver.
-        clsName := nameAndClass key. changeClass := nameAndClass value.
+        clsName := nameAndClass key. 
+        changeClass := nameAndClass value.
 
         (sel == #category:) ifTrue:[
             sel := (rec args at:1) evaluate.
-            changeType := '(category change)'.
+            changeType := self colorizeAsCommentChange:'(category change)'.
             changeString := self contractClass:clsName selector:sel to:maxLen.
-            (changeInfo last) className:clsName.
-            "/ changeClassNames at:changeClassNames size put:clsName.
+            newCategory := (args at:1) evaluate.
+
+            "/ make it a category change
+            lastInfo := changeInfo last.
+            lastInfo className:clsName.
+            lastInfo selector:sel.
+            lastInfo categoryIfCategoryChange:newCategory.
+
             autoCompare value ifTrue:[
                 (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
                     changeDelta := '?'
                 ] ifFalse:[
                     m := changeClass compiledMethodAt:sel asSymbol.
-                    m notNil ifTrue:[
-                        m category = (p args at:1) evaluate ifTrue:[
+                    m isNil ifTrue:[
+                        "/ mhm - the method does not (no longer=) exist
+                        changeDelta := '?'
+                    ] ifFalse:[
+                        m category = newCategory ifTrue:[
                             changeDelta := '='.
                         ]
                     ]
@@ -6979,12 +7141,13 @@
             ].
             ^ self.
         ].
+
         (sel == #privacy:) ifTrue:[
             sel := (rec args at:1) evaluate.
             changeType := '(privacy change)'.
             changeString := self contractClass:clsName selector:sel to:maxLen.
             (changeInfo last) className:clsName.
-            "/ changeClassNames at:changeClassNames size put:clsName.
+
             autoCompare value ifTrue:[
                 (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
                     changeDelta := '?'
@@ -7001,7 +7164,6 @@
         changeType := '(class definition)'.
         clsName := (args at:1) evaluate.
         (changeInfo last) className:clsName.
-        "/ changeClassNames at:changeClassNames size put:clsName.
 
         "/ is it a private-class ?
         ('*privateIn:' match:sel) ifTrue:[
@@ -7028,12 +7190,12 @@
                 ])
                 ifTrue:[
                     ((cls superclass isNil
-                        and:[p receiver isLiteral
-                        and:[p receiver evaluate isNil]])
+                        and:[rec isLiteral
+                        and:[rec evaluate isNil]])
                     or:[
                         cls superclass notNil
-                        and:[p receiver isLiteral not
-                        and:[cls superclass name = p receiver name]]
+                        and:[rec isLiteral not
+                        and:[cls superclass name = rec name]]
                     ]) ifTrue:[
                         (sel == #'variableByteSubclass:classVariableNames:poolDictionaries:category:')
                         ifTrue:[
@@ -7056,7 +7218,7 @@
                                     cls category = categoryArg ifTrue:[
                                         changeDelta := '='.
                                     ] ifFalse:[
-                                        changeType := '(class category change)'.
+                                        changeType := self colorizeAsCommentChange:'(class category change)'.
                                     ]
                                 ]
                             ]
@@ -7086,13 +7248,12 @@
         changeClass := (self nameSpaceForApply) classNamed:clsName.
         changeType := '(class definition)'.
         (changeInfo last) className:clsName.
-        "/ changeClassNames at:changeClassNames size put:clsName.
 
         autoCompare value ifTrue:[
             changeClass isNil ifTrue:[
                 changeDelta := '?'.
             ] ifFalse:[
-                s := (p args at:1) evaluate.
+                s := (args at:1) evaluate.
                 s = changeClass class instanceVariableString ifTrue:[
                     changeDelta := '='.
                 ]
@@ -7164,8 +7325,34 @@
     "Modified: / 01-05-2016 / 18:33:36 / cg"
 ! !
 
+!ChangesBrowser::ChangeInfo class methodsFor:'documentation'!
+
+documentation
+"
+    documentation to be added.
+
+    [author:]
+        cg
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
 !ChangesBrowser::ChangeInfo methodsFor:'accessing'!
 
+categoryIfCategoryChange
+    ^ categoryIfCategoryChange
+!
+
+categoryIfCategoryChange:something
+    categoryIfCategoryChange := something.
+!
+
 chunk
     ^ chunk
 !
@@ -7190,6 +7377,10 @@
     ^ isFollowupChange
 !
 
+isMethodCategoryChange
+    ^ categoryIfCategoryChange notNil
+!
+
 position
     ^ position
 !