changes to allow browsing Sqeak fileOut format.
authorClaus Gittinger <cg@exept.de>
Thu, 15 Jul 1999 16:45:31 +0200
changeset 2263 46fc2bb1b9c1
parent 2262 75d490e87d95
child 2264 036fa673217d
changes to allow browsing Sqeak fileOut format.
CBrowser.st
ChangesBrowser.st
--- a/CBrowser.st	Thu Jul 15 15:44:16 1999 +0200
+++ b/CBrowser.st	Thu Jul 15 16:45:31 1999 +0200
@@ -40,35 +40,39 @@
 
 documentation
 "
-    this implements a browser for the changes-file.
+    this implements a browser for the changes-file (actually, it can display
+    any sourceFiles contents).
     See the extra document 'doc/misc/cbrowser.doc' for how to use this browser.
 
     written jan 90 by claus
 
     [Class variables:]
-	CompressSnapshotInfo            if true (the default), snapshot entries
-					are also compressed in the compress function.
-					Some users prefer them to be not compressed.
-					Set it to false for this.
+        CompressSnapshotInfo            if true (the default), snapshot entries
+                                        are also compressed in the compress function.
+                                        Some users prefer them to be not compressed.
+                                        Set it to false for this.
 
     Notice:
-	this needs a total rewrite, to build up a changeSet from the file
-	(which did not exist when the ChangesBrowser was originally written) 
-	and manipulate that changeSet.
-
-	This way, we get a browser for any upcoming incore changeSets for
-	free. Also, this will put the chunk analyzation code into Change and
-	subclasses (where it belongs) and give a better encapsulation and
-	overall structure. Do not take this as an example for good style ;-)
+        this needs a total rewrite, to build up a changeSet from the file
+        (which did not exist when the ChangesBrowser was originally written) 
+        and manipulate that changeSet.
+
+        This way, we get a browser for any upcoming incore changeSets for
+        free. Also, this will put the chunk analyzation code into Change and
+        subclasses (where it belongs) and give a better encapsulation and
+        overall structure. Do not take this as an example for good style ;-)
+
+        The Change hierarchy is currently been completed, and the changes browser
+        will be adapted soon.
 
     [author:]
-	Claus Gittinger
+        Claus Gittinger
 
     [start with:]
-	ChangesBrowser open
+        ChangesBrowser open
 
     [see also:]
-	( Using the ChangesBrowser :html: tools/cbrowser/TOP.html )
+        ( Using the ChangesBrowser :html: tools/cbrowser/TOP.html )
         
 "
 ! !
@@ -142,12 +146,12 @@
 
 wantChangeLog
     "sent by the compiler to ask if a changeLog entry should
-     be written. Return false here."
+     be written when compiling. Return false here."
 
     ^ false
 ! !
 
-!ChangesBrowser methodsFor:'error handling'!
+!ChangesBrowser methodsFor:'compiler interface-error handling'!
 
 correctableError:aString position:relPos to:relEndPos from:aCompiler
     "compiler notifys us of an error - this should really not happen since
@@ -544,6 +548,1069 @@
 
 !ChangesBrowser methodsFor:'private'!
 
+autoSelect:changeNr
+    "select a change"
+
+    self class autoSelectNext ifTrue:[
+        (changeNr <= self numberOfChanges) ifTrue:[
+            changeListView setSelection:changeNr.
+            self changeSelection:changeNr.
+            ^ self
+        ]
+    ].
+    self clearCodeView.
+    changeListView setSelection:nil.
+
+    "Modified: / 18.5.1998 / 14:26:43 / cg"
+!
+
+autoSelectLast
+    "select the last change"
+
+    self autoSelect:(self numberOfChanges)
+!
+
+autoSelectOrEnd:changeNr
+    "select the next change or the last"
+
+    |last|
+
+    last := self numberOfChanges.
+    changeNr < last ifTrue:[
+	self autoSelect:changeNr
+    ] ifFalse:[
+	changeListView setSelection:last .
+	self changeSelection:last.
+    ]
+
+    "Modified: 25.5.1996 / 12:26:17 / cg"
+!
+
+checkClassIsLoaded:aClass
+    |cls|
+
+    aClass isMeta ifTrue:[
+	cls := aClass soleInstance
+    ] ifFalse:[
+	cls := aClass
+    ].
+    cls isLoaded ifFalse:[
+	(self confirm:(cls name , ' is an autoloaded class.\I can only compare the methods texts if its loaded first.\\Load the class first ?') withCRs)
+	ifTrue:[
+	    cls autoload
+	]
+    ].
+    ^ cls isLoaded
+
+    "Created: 12.12.1995 / 14:04:39 / cg"
+    "Modified: 12.12.1995 / 14:11:05 / cg"
+!
+
+clearCodeView
+    self unselect "changeListView deselect".
+    codeView contents:nil.
+    changeNrShown := nil
+!
+
+contractClass:className selector:selector to:maxLen
+    |s l|
+
+    s := className , ' ', selector.
+    s size > maxLen ifTrue:[
+	l := maxLen - 1 - selector size max:20.
+	s := (className contractTo:l) , ' ' , selector.
+
+	s size > maxLen ifTrue:[
+	    l := maxLen - 1 - className size max:20.
+	    s := className , ' ', (selector contractTo:l).
+
+	    s size > maxLen ifTrue:[
+		s := (className contractTo:(maxLen // 2 - 1)) , ' ' , (selector contractTo:maxLen // 2)
+	    ]
+	]
+    ].
+    ^ s
+!
+
+newLabel:how
+    |l|
+
+    (changeFileName ~= 'changes') ifTrue:[
+        l := self class defaultLabel , ': ', changeFileName
+    ] ifFalse:[
+        l := self class defaultLabel
+    ].
+    l := l , ' ' , how.
+    self label:l
+
+    "Created: / 8.9.1995 / 19:32:04 / claus"
+    "Modified: / 8.9.1995 / 19:39:29 / claus"
+    "Modified: / 6.2.1998 / 13:27:01 / cg"
+!
+
+queryCloseText
+    "made this a method for easy redefinition in subclasses"
+
+    ^ 'Quit without updating changeFile ?'
+!
+
+setChangeList
+    "extract type-information from changes and stuff into top selection
+     view"
+
+    changeListView setList:changeHeaderLines expandTabs:false redraw:false.
+    changeListView invalidate.
+
+    "/ changeListView deselect.
+
+    "Modified: / 18.5.1998 / 14:29:10 / cg"
+!
+
+showNotFound
+    |savedCursor|
+
+    savedCursor := cursor.
+    [
+        self cursor:(Cursor cross).
+        self beep.
+        Delay waitForMilliseconds:300.
+    ] valueNowOrOnUnwindDo:[
+        self cursor:savedCursor
+    ]
+
+    "Modified: / 29.4.1999 / 22:36:54 / cg"
+!
+
+unselect
+    "common unselect"
+
+    changeListView setSelection:nil.
+
+    "Modified: 25.5.1996 / 13:02:49 / cg"
+!
+
+withSelectedChangeDo:aBlock
+    "just a helper, check for a selected change and evaluate aBlock
+     with busy cursor"
+
+    |changeNr|
+
+    changeNr := changeListView selection.
+    changeNr notNil ifTrue:[
+	self withExecuteCursorDo:[
+	    aBlock value:changeNr
+	]
+    ]
+
+    "Modified: 14.12.1995 / 20:58:45 / cg"
+! !
+
+!ChangesBrowser methodsFor:'private-change access'!
+
+changeIsFollowupMethodChange:changeNr
+    ^ changeIsFollowupMethodChange at:changeNr
+
+    "Created: / 6.2.1998 / 13:03:39 / cg"
+!
+
+classNameOfChange:changeNr
+    "return the classname of a change 
+     (for classChanges (i.e. xxx class), the non-metaClassName (i.e. xxx) is returned)"
+
+    |name|
+
+    name := self fullClassNameOfChange:changeNr.
+    name isNil ifTrue:[^ nil].
+    (name endsWith:' class') ifTrue:[
+	^ name copyWithoutLast:6
+    ].
+    ^ name
+
+    "Modified: 6.12.1995 / 17:06:31 / cg"
+!
+
+fullClassNameOfChange:changeNr
+    "return the full classname of a change 
+     (for classChanges (i.e. xxx class), a string ending in ' class' is returned.
+     - since parsing ascii methods is slow, keep result cached in 
+       changeClassNames for the next query"
+
+    |chunk aParseTree recTree sel name arg1Tree isMeta prevMethodDefNr
+     words changeStream fullParseTree ownerTree ownerName oldDollarSetting|
+
+    changeNr isNil ifTrue:[^ nil].
+
+    "
+     first look, if not already known
+    "
+    name := changeClassNames at:changeNr.
+    name notNil ifTrue:[^ name].
+
+    prevMethodDefNr := changeNr.
+    [changeIsFollowupMethodChange at:prevMethodDefNr] whileTrue:[
+        prevMethodDefNr := prevMethodDefNr - 1.
+    ].
+
+    "
+     get the chunk
+    "
+    chunk := changeChunks at:prevMethodDefNr.
+    chunk isNil ifTrue:[^ nil].       "mhmh - empty"
+
+    (chunk startsWith:'''---') ifTrue:[
+        words := chunk asCollectionOfWords.
+        words size > 2 ifTrue:[
+            (words at:2) = 'checkin' ifTrue:[
+                name := words at:3.
+                changeClassNames at:changeNr put:name.
+                ^ name
+            ]
+        ].
+    ].
+
+    "/ fix it - otherwise, it cannot be parsed
+    (chunk endsWith:'primitiveDefinitions:') ifTrue:[
+        chunk := chunk , ''''''
+    ].
+    (chunk endsWith:'primitiveFunctions:') ifTrue:[
+        chunk := chunk , ''''''
+    ].
+    (chunk endsWith:'primitiveVariables:') ifTrue:[
+        chunk := chunk , ''''''
+    ].
+
+    "
+     use parser to construct a parseTree
+    "
+    oldDollarSetting := Parser allowDollarInIdentifier.
+    [
+        Parser allowDollarInIdentifier:true.
+        aParseTree := Parser parseExpression:chunk.
+
+        aParseTree == #Error ifTrue:[
+            (chunk includesString:'comment') ifTrue:[
+                "/ could be a comment ...
+                aParseTree := Parser parseExpression:chunk , ''''.
+            ]
+        ].
+    ] valueNowOrOnUnwindDo:[
+        Parser allowDollarInIdentifier:oldDollarSetting
+    ].
+
+    (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
+        ^ nil        "seems strange ... (could be a comment)"
+    ].
+    aParseTree isMessage ifFalse:[
+        ^ nil        "very strange ... (whats that ?)"
+    ].
+
+    "
+     ask parser for selector
+    "
+    sel := aParseTree selector.
+    recTree := aParseTree receiver.
+
+    "
+     is it a method-change, methodRemove or comment-change ?
+    "
+
+    (#(#'methodsFor:' 
+       #'privateMethodsFor:' 
+       #'protectedMethodsFor:' 
+       #'ignoredMethodsFor:' 
+       #'publicMethodsFor:' 
+       #'removeSelector:' 
+       #'comment:'
+       #'primitiveDefinitions:'
+       #'primitiveFunctions:'
+       #'primitiveVariables:'
+       #'renameCategory:to:'
+       #'instanceVariableNames:'
+
+       #'methodsFor:stamp:'          "/ Squeak support
+       #'commentStamp:prior:'        "/ Squeak support
+       #'addClassVarName:'           "/ Squeak support
+    ) includes:sel) ifTrue:[
+        "
+         yes, the className is the receiver
+        "
+        (recTree notNil and:[recTree ~~ #Error]) ifTrue:[
+            isMeta := false.
+            recTree isUnaryMessage ifTrue:[
+                (recTree selector ~~ #class) ifTrue:[^ nil].
+                "id class methodsFor:..."
+                recTree := recTree receiver.
+                isMeta := true.
+            ].
+            recTree isPrimary ifTrue:[
+                name := recTree name.
+                isMeta ifTrue:[
+                    name := name , ' class'.
+                ].
+                changeClassNames at:changeNr put:name.
+                ^ name
+            ]
+        ].
+        "more strange things"
+        ^ nil
+    ].
+
+    "
+     is it a change in a class-description ?
+    "
+    (('subclass:*' match:sel) 
+    or:[('variable*subclass:*' match:sel)]) ifTrue:[
+        "/ must parse the full changes text, to get
+        "/ privacy information.
+
+        changeStream := self streamForChange:changeNr.
+        changeStream notNil ifTrue:[
+            chunk := changeStream nextChunk.
+            changeStream close.
+            fullParseTree := Parser parseExpression:chunk.
+            (fullParseTree isNil or:[fullParseTree == #Error]) ifTrue:[
+                fullParseTree := nil
+            ].
+            fullParseTree isMessage ifFalse:[
+                fullParseTree := nil
+            ].
+            "/ actually, the nil case cannot happen
+            fullParseTree notNil ifTrue:[
+                aParseTree := fullParseTree.
+                sel := aParseTree selector.
+            ].
+        ].
+
+        arg1Tree := aParseTree arg1.
+        (arg1Tree notNil and:[arg1Tree isConstant]) ifTrue:[
+            name := arg1Tree value asString.
+
+            "/ is it a private-class ?
+            ('*privateIn:' match:sel) ifTrue:[
+                ownerTree := aParseTree args last.
+                ownerName := ownerTree name asString.
+                name := ownerName , '::' , name
+            ].
+            changeClassNames at:changeNr put:name.
+            ^ name
+        ].
+        "very strange"
+        ^ nil
+    ].
+
+    "
+     is it a class remove ?
+    "
+    (sel == #removeClass:) ifTrue:[
+        (recTree notNil 
+        and:[recTree ~~ #Error
+        and:[recTree isPrimary
+        and:[recTree name = 'Smalltalk']]]) ifTrue:[
+            arg1Tree := aParseTree arg1.
+            (arg1Tree notNil and:[arg1Tree isPrimary]) ifTrue:[
+                name := arg1Tree name.
+                changeClassNames at:changeNr put:name.
+                ^ name
+            ].
+        ]
+    ].
+
+    "
+     is it a method category change ?
+    "
+    ((sel == #category:)
+    or:[sel == #privacy:]) ifTrue:[
+        (recTree notNil 
+        and:[recTree ~~ #Error
+        and:[recTree isMessage
+        and:[recTree selector == #compiledMethodAt:]]]) ifTrue:[
+            isMeta := false.
+            recTree := recTree receiver.
+            recTree isUnaryMessage ifTrue:[
+                (recTree selector ~~ #class) ifTrue:[^ nil].
+                "id class "
+                recTree := recTree receiver
+            ].
+            recTree isPrimary ifTrue:[
+                isMeta ifTrue:[
+                    name := name , ' class'.
+                ].
+                name := recTree name.
+                changeClassNames at:changeNr put:name.
+                ^ name
+            ]
+        ]
+    ].
+    ^ nil
+
+    "Modified: / 3.8.1998 / 19:58:17 / cg"
+!
+
+numberOfChanges
+    ^ changePositions size
+
+    "Created: 3.12.1995 / 18:15:39 / cg"
+!
+
+selectorOfMethodChange:changeNr
+    "return a method-changes selector, or nil if its not a methodChange"
+
+    |source parser sel chunk aParseTree |
+
+    source := self sourceOfMethodChange:changeNr.
+    source isNil ifTrue:[
+        (self classNameOfChange:changeNr) notNil ifTrue:[
+            chunk := changeChunks at:changeNr.
+            chunk isNil ifTrue:[^ nil].       "mhmh - empty"
+            aParseTree := Parser parseExpression:chunk.
+            (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
+                ^ nil        "seems strange ... (could be a comment)"
+            ].
+            aParseTree isMessage ifFalse:[
+                ^ nil        "very strange ... (whats that ?)"
+            ].
+            sel := aParseTree selector.
+            (#(
+                #'removeSelector:' 
+            ) includes:sel) ifTrue:[
+                sel := aParseTree arguments at:1.
+                sel isConstant ifTrue:[
+                    sel := sel evaluate.
+                    sel isSymbol ifTrue:[
+                        ^ sel
+                    ]
+                ]
+            ]
+        ].
+        ^ nil
+    ].
+
+
+    parser := Parser 
+                parseMethodArgAndVarSpecification:source
+                in:nil 
+                ignoreErrors:true
+                ignoreWarnings:true
+                parseBody:false.
+
+"/    parser := Parser 
+"/                parseMethod:source 
+"/                in:nil 
+"/                ignoreErrors:true 
+"/                ignoreWarnings:true.
+
+    (parser notNil and:[parser ~~ #Error]) ifTrue:[
+        sel := parser selector.
+    ].
+    ^ sel
+
+    "Created: 24.11.1995 / 14:30:46 / cg"
+    "Modified: 5.9.1996 / 17:12:50 / cg"
+!
+
+sourceOfMethodChange:changeNr
+    "return a method-changes source code, or nil if its not a methodChange."
+
+    |aStream chunk sawExcla parseTree sourceChunk sel|
+
+    aStream := self streamForChange:changeNr.
+    aStream isNil ifTrue:[^ nil].
+
+    (self changeIsFollowupMethodChange:changeNr) ifFalse:[
+        sawExcla := aStream peekFor:(aStream class chunkSeparator).
+        chunk := aStream nextChunk.
+    ] ifTrue:[
+        chunk := (changeChunks at:changeNr).
+        sawExcla := true.
+    ].
+
+    sawExcla ifTrue:[
+        parseTree := Parser parseExpression:chunk.
+        (parseTree notNil and:[parseTree isMessage]) ifTrue:[
+            sel := parseTree selector.
+            (#(
+               #methodsFor: 
+               #privateMethodsFor:
+               #publicMethodsFor:
+               #ignoredMethodsFor:
+               #protectedMethodsFor:
+
+               #methodsFor:stamp:             "/ Squeak support
+               #commentStamp:prior:           "/ Squeak support
+              ) 
+            includes:sel) ifTrue:[
+                sourceChunk := aStream nextChunk.
+            ]
+        ].
+    ].
+    aStream close.
+    ^ sourceChunk
+
+    "Created: / 5.9.1996 / 17:11:32 / cg"
+    "Modified: / 3.8.1998 / 20:00:21 / cg"
+!
+
+streamForChange:changeNr
+    "answer a stream for change"
+ 
+    |aStream|
+
+    (changeNr between:1 and:changePositions size) ifFalse:[^ nil].
+    aStream := FileStream readonlyFileNamed:changeFileName.
+    aStream isNil ifTrue:[^ nil].
+    aStream position:(changePositions at:changeNr).
+    ^ aStream
+! !
+
+!ChangesBrowser methodsFor:'private-changeFile access'!
+
+changeFileName:aFileName
+    changeFileName := aFileName
+!
+
+checkIfFileHasChanged
+    |f info |
+
+    Processor removeTimedBlock:checkBlock.
+    f := changeFileName asFilename.
+    (info := f info) isNil ifTrue:[
+	self newLabel:'(unaccessable)'
+    ] ifFalse:[
+	(info modified) > changeFileTimestamp ifTrue:[
+	    self newLabel:'(outdated)'.
+	    autoUpdate ifTrue:[
+		self doUpdate
+	    ]
+	] ifFalse:[
+	    self newLabel:''
+	]
+    ].
+    Processor addTimedBlock:checkBlock afterSeconds:5.
+
+    "Created: 8.9.1995 / 19:30:19 / claus"
+    "Modified: 8.9.1995 / 19:38:18 / claus"
+    "Modified: 1.11.1996 / 20:22:56 / cg"
+!
+
+readChangesFile
+    "read the changes file, create a list of header-lines (changeChunks)
+     and a list of chunk-positions (changePositions)"
+
+    ^ self readChangesFileInBackground:false
+!
+
+readChangesFileInBackground:inBackground
+    "read the changes file, create a list of header-lines (changeChunks)
+     and a list of chunk-positions (changePositions).
+     Starting with 2.10.3, the entries are multi-col entries;
+     the cols are:
+        1   delta (only if comparing)
+                '+' -> new method (w.r.t. current state)
+                '-' -> removed method (w.r.t. current state)
+                '?' -> class does not exist currently
+                '=' -> change is same as current methods source
+        2   class/selector
+        3   type of change
+                doit
+                method
+                category change
+        4   timestamp
+
+     since comparing slows down startup time, it is now disabled by
+     default and can be enabled via a toggle."
+
+    |aStream maxLen i f chunkText fullChunkText|
+
+    editingClassSource := false.
+
+    maxLen := 60.
+
+    f := changeFileName asFilename.
+    aStream :=  f readStream.
+    aStream isNil ifTrue:[^ nil].
+
+    self newLabel:'updating ...'.
+
+    i := f info.
+    changeFileSize := i size.
+    changeFileTimestamp := i modified.
+
+    self withReadCursorDo:[
+        |myProcess myPriority|
+
+        "
+         this is a time consuming operation (especially, if reading an
+         NFS-mounted directory; therefore lower my priority ...
+        "
+        inBackground ifTrue:[
+            myProcess := Processor activeProcess.
+            myPriority := myProcess priority.
+            myProcess priority:(Processor userBackgroundPriority).
+        ].
+
+        [
+            |excla timeStampInfo|
+
+            changeChunks := OrderedCollection new.
+            changeHeaderLines := OrderedCollection new.
+            changePositions := OrderedCollection new.
+            changeTimeStamps := OrderedCollection new.
+            changeIsFollowupMethodChange := OrderedCollection new.
+
+            excla := aStream class chunkSeparator.
+
+            [aStream atEnd] whileFalse:[
+                |entry changeDelta changeString changeType 
+                 line s l changeClass sawExcla category 
+                  chunkPos sel|
+
+                "
+                 get a chunk (separated by excla)
+                "
+                aStream skipSeparators.
+                chunkPos := aStream position.
+
+
+                sawExcla := aStream peekFor:excla.
+                chunkText := fullChunkText := aStream nextChunk.
+                chunkText notNil ifTrue:[
+                    |index headerLine cls|
+
+                    (chunkText startsWith:'''---- timestamp ') ifTrue:[
+                        timeStampInfo := (chunkText copyFrom:16 to:(chunkText size - 6)) withoutSpaces.
+                    ] ifFalse:[
+
+                        "
+                         only first line is saved in changeChunks ...
+                        "
+                        index := chunkText indexOf:(Character cr).
+                        (index ~~ 0) ifTrue:[
+                            chunkText := chunkText copyTo:(index - 1).
+
+                            "take care for comment changes - must still be a
+                             valid expression for classNameOfChange: to work"
+
+                            (chunkText endsWith:'comment:''') ifTrue:[
+                                chunkText := chunkText , '...'''
+                            ].
+                            (chunkText endsWith:'primitiveDefinitions:''') ifTrue:[
+                                sel := 'primitiveDefinitions:'.
+                                chunkText := chunkText copyWithoutLast:1
+                            ].
+                            (chunkText endsWith:'primitiveVariables:''') ifTrue:[
+                                sel := 'primitiveVariables:'.
+                                chunkText := chunkText copyWithoutLast:1
+                            ].
+                            (chunkText endsWith:'primitiveFunctions:''') ifTrue:[
+                                sel := 'primitiveFunctions:'.
+                                chunkText := chunkText copyWithoutLast:1
+                            ].
+                        ].
+
+                        changeChunks add:chunkText.
+                        changePositions add:chunkPos.
+                        changeTimeStamps add:timeStampInfo.
+                        changeIsFollowupMethodChange add:false.
+
+                        headerLine := nil.
+                        changeDelta := ' '.
+
+                        sawExcla ifFalse:[
+                            (chunkText startsWith:'''---- snap') ifTrue:[
+                                changeType := ''.
+                                headerLine := chunkText.
+                                changeString := (chunkText contractTo:maxLen).
+                                timeStampInfo := nil.
+                            ] ifFalse:[
+
+                                |p cls clsName|
+
+                                headerLine := chunkText , ' (doIt)'.
+
+                                "
+                                 first, assume doIt - then lets have a more detailed look ...
+                                "
+                                ((chunkText startsWith:'''---- file')
+                                or:[(chunkText startsWith:'''---- check')]) ifTrue:[
+                                    changeType := ''.
+                                    timeStampInfo := nil.
+                                ] ifFalse:[
+                                    changeType := '(doIt)'.
+                                ].    
+                                changeString := (chunkText contractTo:maxLen).
+
+                                p := Parser parseExpression:fullChunkText inNameSpace:Smalltalk.
+                                (p notNil and:[p ~~ #Error]) ifTrue:[
+                                    p isMessage ifTrue:[
+                                        sel := p selector.
+                                    ]
+                                ] ifFalse:[
+                                    sel := nil.
+                                    (Scanner new scanTokens:fullChunkText) size == 0 ifTrue:[
+                                        "/ a comment only
+                                        changeType := '(comment)'.
+                                    ] ifFalse:[
+                                        changeType := '(???)'.
+                                    ]
+                                ].
+                                (sel == #removeSelector:) ifTrue:[
+                                    p receiver isUnaryMessage ifTrue:[
+                                        cls := p receiver receiver name.
+                                        changeClass := (Smalltalk classNamed:cls) class.
+                                        cls := cls , ' class'.
+                                    ] ifFalse:[
+                                        cls := p receiver name.
+                                        changeClass := (Smalltalk classNamed:cls)
+                                    ].
+                                    sel := (p args at:1) evaluate.
+
+                                    compareChanges ifTrue:[
+                                        (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
+                                            changeDelta := '?'
+                                        ] ifFalse:[
+                                            (changeClass implements:sel asSymbol) ifTrue:[
+                                                changeDelta := '-'.
+                                            ] ifFalse:[
+                                                changeDelta := '='.
+                                            ]
+                                        ]
+                                    ].
+                                    changeType := '(remove)'.
+                                    changeString := self contractClass:cls selector:sel to:maxLen.
+                                ].
+                                (p ~~ #Error
+                                and:[p isMessage 
+                                and:[p receiver isMessage
+                                and:[p receiver selector == #compiledMethodAt:]]]) ifTrue:[
+                                    p receiver receiver isUnaryMessage ifTrue:[
+                                        cls := p receiver receiver receiver name.
+                                        changeClass := (Smalltalk classNamed:cls) class.
+                                        cls := cls , ' class'.
+                                    ] ifFalse:[
+                                        cls := p receiver receiver name.
+                                        changeClass := (Smalltalk classNamed:cls)
+                                    ].
+                                    (sel == #category:) ifTrue:[
+                                        sel := (p receiver args at:1) evaluate.
+                                        changeType := '(category change)'.
+                                        changeString := self contractClass:cls selector:sel to:maxLen.
+                                    ].
+                                    (sel == #privacy:) ifTrue:[
+                                        sel := (p receiver args at:1) evaluate.
+                                        changeType := '(privacy change)'.
+                                        changeString := self contractClass:cls selector:sel to:maxLen.
+                                    ].
+                                ].
+                                (#(#'subclass:'
+                                  #'variableSubclass:'
+                                  #'variableByteSubclass:'
+                                  #'variableWordSubclass:'
+                                  #'variableLongSubclass:'
+                                  #'variableFloatSubclass:'
+                                  #'variableDoubleSubclass:'
+                                  #'primitiveDefinitions:'
+                                  #'primitiveFunctions:'
+                                  #'primitiveVariables:'
+                                 ) includes:sel) ifTrue:[
+                                    changeType := '(class definition)'.
+                                    clsName := (p args at:1) evaluate.
+                                    cls := Smalltalk at:clsName ifAbsent:nil.
+                                    cls isNil ifTrue:[
+                                        changeDelta := '+'.
+                                    ]
+                                ].
+                            ]
+                        ] ifTrue:[ "sawExcla"
+                            |done first p className cls text methodPos 
+                             singleJunkOnly methodChunks singleInfo|
+
+                            singleJunkOnly := false.
+                            methodChunks := false.
+                            singleInfo := false.
+
+                            "
+                             method definitions actually consist of
+                             two (or more) chunks; skip next chunk(s)
+                             up to an empty one.
+                             The system only writes one chunk,
+                             and we cannot handle more in this ChangesBrowser ....
+                            "
+                            className := nil.
+                            p := Parser parseExpression:chunkText inNameSpace:Smalltalk.
+
+                            (p notNil and:[p ~~ #Error]) ifTrue:[
+                                sel := p selector.
+                                (#(
+                                   #methodsFor: 
+                                   #privateMethodsFor:
+                                   #publicMethodsFor:
+                                   #ignoredMethodsFor:
+                                   #protectedMethodsFor:
+                                   #methodsFor:stamp:             "/ Squeak support
+                                   #'commentStamp:prior:'     
+                                  ) 
+                                includes:sel) ifTrue:[
+                                    methodChunks := true.
+                                    p receiver isUnaryMessage ifTrue:[
+                                        className := p receiver receiver name.
+                                        changeClass := (Smalltalk classNamed:className) class.
+                                        className := className , ' class'.
+                                    ] ifFalse:[
+                                        className := p receiver name.
+                                        changeClass := Smalltalk classNamed:className
+                                    ].
+                                    category := (p args at:1) evaluate.
+
+                                    sel == #'methodsFor:stamp:' ifTrue:[
+                                        "/ Squeak timeStamp
+                                        timeStampInfo := (p args at:2) evaluate.
+                                        singleInfo := true
+                                    ] ifFalse:[
+                                        sel == #'commentStamp:prior:' ifTrue:[
+                                            singleJunkOnly := true.
+                                            methodChunks := false.
+                                        ].
+                                    ]
+                                ].
+                            ].
+
+                            done := false.
+                            first := true.
+                            [done] whileFalse:[
+                                changeDelta := ' '.
+                                methodPos := aStream position.
+
+                                text := aStream nextChunk.
+                                text isNil ifTrue:[
+                                    done := true
+                                ] ifFalse:[
+                                    done := text isEmpty
+                                ].
+                                done ifFalse:[
+                                    first ifFalse:[
+                                        changeChunks add:chunkText.
+                                        changePositions add:methodPos.
+                                        changeTimeStamps add:timeStampInfo.
+                                        changeIsFollowupMethodChange add:true.
+                                        editingClassSource := true.
+                                    ].
+
+                                    first := false.
+                                    "
+                                     try to find the selector
+                                    "
+                                    sel := nil.
+                                    className notNil ifTrue:[
+                                        methodChunks ifTrue:[
+                                            p := Parser 
+                                                     parseMethodSpecification:text
+                                                     in:nil
+                                                     ignoreErrors:true
+                                                     ignoreWarnings:true.
+                                            (p notNil and:[p ~~ #Error]) ifTrue:[
+                                                sel := p selector.
+                                            ]
+                                        ]
+                                    ].
+
+                                    sel isNil ifTrue:[
+                                        changeString := (chunkText contractTo:maxLen).
+                                        changeType := '(change)'.
+                                        headerLine := chunkText , ' (change)'.
+                                    ] ifFalse:[
+                                        changeString :=  self contractClass:className selector:sel to:maxLen.
+                                        changeType := '(method in: ''' , category , ''')'.
+                                        headerLine := className , ' ' , sel , ' ' , '(change category: ''' , category , ''')'.
+                                    ].
+
+                                    compareChanges ifTrue:[ 
+                                        changeClass isNil ifFalse:[
+                                            changeClass isMeta ifTrue:[
+                                                cls := changeClass soleInstance
+                                            ] ifFalse:[
+                                                cls := changeClass
+                                            ].
+                                        ].
+
+                                        (changeClass isNil or:[cls isLoaded not]) ifTrue:[
+                                            changeDelta := '?'
+                                        ] ifFalse:[
+                                            (changeClass implements:sel asSymbol) ifFalse:[
+                                                changeDelta := '+'.
+                                            ] ifTrue:[
+                                                |m currentText t1 t2|
+
+                                                m := changeClass compiledMethodAt:sel asSymbol.
+                                                currentText := m source.
+                                                currentText notNil ifTrue:[
+                                                    text asString = currentText asString ifTrue:[
+                                                        changeDelta := '='
+                                                    ] ifFalse:[
+                                                        t1 := currentText asCollectionOfLines collect:[:s | s withTabsExpanded].
+                                                        t2 := text asCollectionOfLines collect:[:s | s withTabsExpanded].
+                                                        t1 = t2 ifTrue:[
+                                                            changeDelta := '='
+                                                        ]
+                                                    ]
+                                                ]
+                                            ]
+                                        ]
+                                    ].
+                                    entry := MultiColListEntry new.
+                                    entry tabulatorSpecification:tabSpec.
+                                    entry colAt:1 put:changeDelta.
+                                    entry colAt:2 put:changeString.
+                                    entry colAt:3 put:changeType.
+                                    timeStampInfo notNil ifTrue:[
+                                        entry colAt:4 put:timeStampInfo.
+                                    ].    
+                                    changeHeaderLines add:entry
+                                ].
+                                changeString := nil.
+                                headerLine := nil.
+                                singleJunkOnly ifTrue:[done := true]
+                            ].
+                            singleInfo ifTrue:[
+                                timeStampInfo := nil
+                            ].
+                        ].
+                        changeString notNil ifTrue:[
+                            entry := MultiColListEntry new.
+                            entry tabulatorSpecification:tabSpec.
+                            entry colAt:1 put:changeDelta.
+                            entry colAt:2 put:changeString.
+                            entry colAt:3 put:changeType.
+                            timeStampInfo notNil ifTrue:[
+                                entry colAt:4 put:timeStampInfo.
+                            ].    
+                            changeHeaderLines add:entry
+                        ] ifFalse:[
+                            headerLine notNil ifTrue:[
+                                changeHeaderLines add:headerLine
+                            ]
+                        ]
+                    ]
+                ]
+            ].
+            changeClassNames := OrderedCollection new grow:(changeChunks size).
+            anyChanges := false
+        ] valueNowOrOnUnwindDo:[
+            aStream close.
+            inBackground ifTrue:[myProcess priority:myPriority].
+        ].
+    ].
+
+    self checkIfFileHasChanged
+
+    "Modified: / 27.8.1995 / 23:06:55 / claus"
+    "Modified: / 17.7.1998 / 11:10:07 / cg"
+!
+
+writeBackChanges
+    "write back the changes file. To avoid problems when the disk is full
+     or a crash occurs while writing (well, or someone kills us), 
+     first write the stuff to a new temporary file. If this works ok,
+     rename the old change-file to a .bak file and finally rename the
+     tempfile back to the change-file. 
+     That way, if anything happens, either the original file is left unchanged,
+     or we have at least a backup of the previous change file."
+
+    |inStream outStream tempfile stamp f|
+
+    editingClassSource ifTrue:[
+        (self confirm:'You are editing a classes sourceFile (not a changeFile) !!\\Are you certain, you want to overwrite it ?' withCRs)
+        ifFalse:[
+            ^ false
+        ]
+    ].
+
+    tempfile := Filename newTemporaryIn:nil.
+    tempfile exists ifTrue:[tempfile remove].
+
+    outStream := tempfile writeStream.
+    outStream isNil ifTrue:[
+        self warn:'cannot create temporary file in current directory.'.
+        ^ false
+    ].
+
+    inStream := FileStream readonlyFileNamed:changeFileName.
+    inStream isNil ifTrue:[^ false].
+
+    self withCursor:(Cursor write) do:[
+        |excla sawExcla done first chunk
+         nChanges "{Class:SmallInteger}" |
+
+        Stream writeErrorSignal handle:[:ex |
+            self warn:('could not update the changes file.\\' , ex errorString) withCRs.
+            tempfile exists ifTrue:[tempfile remove].
+            ^ false
+        ] do:[
+
+            excla := inStream class chunkSeparator.
+            nChanges := self numberOfChanges.
+
+            1 to:nChanges do:[:index |
+                inStream position:(changePositions at:index).
+                sawExcla := inStream peekFor:excla.
+                chunk := inStream nextChunk.
+
+                (chunk notNil
+                and:[(chunk startsWith:'''---- snap') not]) ifTrue:[
+                    (stamp := changeTimeStamps at:index) notNil ifTrue:[
+                        outStream nextPutAll:'''---- timestamp ' , stamp , ' ----'''.
+                        outStream nextPut:excla; cr.
+                    ].
+                ].
+
+                sawExcla ifTrue:[
+                    outStream nextPut:excla.
+                    outStream nextChunkPut:chunk.
+                    outStream cr; cr.
+                    "
+                     a method-definition chunk - output followups
+                    "
+                    done := false.
+                    first := true.
+                    [done] whileFalse:[
+                        chunk := inStream nextChunk.
+                        chunk isNil ifTrue:[
+                            outStream cr; cr.
+                            done := true
+                        ] ifFalse:[
+                            chunk isEmpty ifTrue:[
+                                outStream space; nextChunkPut:chunk; cr; cr.
+                                done := true.
+                            ] ifFalse:[
+                                first ifFalse:[
+                                    outStream cr; cr.
+                                ].
+                                outStream nextChunkPut:chunk.
+                            ].
+                        ].
+                        first := false.
+                    ].
+                ] ifFalse:[
+                    outStream nextChunkPut:chunk.
+                    outStream cr
+                ]
+            ].
+            outStream close.
+            inStream close.
+        ].
+
+        f := changeFileName asFilename.
+        f renameTo:(f withSuffix:'bak').
+        tempfile renameTo:changeFileName.
+        anyChanges := false
+    ].
+    ^ true
+
+    "Modified: / 2.12.1996 / 22:29:15 / stefan"
+    "Modified: / 21.4.1998 / 17:50:11 / cg"
+! !
+
+!ChangesBrowser methodsFor:'private-user interaction ops'!
+
 appendChange:changeNr toFile:fileName
     "append change to a file. return true if ok."
 
@@ -661,120 +1728,6 @@
     "Modified: / 7.2.1998 / 19:56:34 / cg"
 !
 
-autoSelect:changeNr
-    "select a change"
-
-    self class autoSelectNext ifTrue:[
-        (changeNr <= self numberOfChanges) ifTrue:[
-            changeListView setSelection:changeNr.
-            self changeSelection:changeNr.
-            ^ self
-        ]
-    ].
-    self clearCodeView.
-    changeListView setSelection:nil.
-
-    "Modified: / 18.5.1998 / 14:26:43 / cg"
-!
-
-autoSelectLast
-    "select the last change"
-
-    self autoSelect:(self numberOfChanges)
-!
-
-autoSelectOrEnd:changeNr
-    "select the next change or the last"
-
-    |last|
-
-    last := self numberOfChanges.
-    changeNr < last ifTrue:[
-	self autoSelect:changeNr
-    ] ifFalse:[
-	changeListView setSelection:last .
-	self changeSelection:last.
-    ]
-
-    "Modified: 25.5.1996 / 12:26:17 / cg"
-!
-
-changeFileName:aFileName
-    changeFileName := aFileName
-!
-
-changeIsFollowupMethodChange:changeNr
-    ^ changeIsFollowupMethodChange at:changeNr
-
-    "Created: / 6.2.1998 / 13:03:39 / cg"
-!
-
-checkClassIsLoaded:aClass
-    |cls|
-
-    aClass isMeta ifTrue:[
-	cls := aClass soleInstance
-    ] ifFalse:[
-	cls := aClass
-    ].
-    cls isLoaded ifFalse:[
-	(self confirm:(cls name , ' is an autoloaded class.\I can only compare the methods texts if its loaded first.\\Load the class first ?') withCRs)
-	ifTrue:[
-	    cls autoload
-	]
-    ].
-    ^ cls isLoaded
-
-    "Created: 12.12.1995 / 14:04:39 / cg"
-    "Modified: 12.12.1995 / 14:11:05 / cg"
-!
-
-checkIfFileHasChanged
-    |f info |
-
-    Processor removeTimedBlock:checkBlock.
-    f := changeFileName asFilename.
-    (info := f info) isNil ifTrue:[
-	self newLabel:'(unaccessable)'
-    ] ifFalse:[
-	(info modified) > changeFileTimestamp ifTrue:[
-	    self newLabel:'(outdated)'.
-	    autoUpdate ifTrue:[
-		self doUpdate
-	    ]
-	] ifFalse:[
-	    self newLabel:''
-	]
-    ].
-    Processor addTimedBlock:checkBlock afterSeconds:5.
-
-    "Created: 8.9.1995 / 19:30:19 / claus"
-    "Modified: 8.9.1995 / 19:38:18 / claus"
-    "Modified: 1.11.1996 / 20:22:56 / cg"
-!
-
-classNameOfChange:changeNr
-    "return the classname of a change 
-     (for classChanges (i.e. xxx class), the non-metaClassName (i.e. xxx) is returned)"
-
-    |name|
-
-    name := self fullClassNameOfChange:changeNr.
-    name isNil ifTrue:[^ nil].
-    (name endsWith:' class') ifTrue:[
-	^ name copyWithoutLast:6
-    ].
-    ^ name
-
-    "Modified: 6.12.1995 / 17:06:31 / cg"
-!
-
-clearCodeView
-    self unselect "changeListView deselect".
-    codeView contents:nil.
-    changeNrShown := nil
-!
-
 compareChange:changeNr
     "compare a change with current version"
 
@@ -859,7 +1812,17 @@
         (parseTree notNil 
          and:[parseTree ~~ #Error
          and:[parseTree isMessage]]) ifTrue:[
-            (parseTree selector == #methodsFor:) ifTrue:[
+            "/ Squeak support (#methodsFor:***)
+            (#(
+               #methodsFor: 
+               #privateMethodsFor:
+               #publicMethodsFor:
+               #ignoredMethodsFor:
+               #protectedMethodsFor:
+
+               #methodsFor:stamp:             "/ Squeak support
+              ) 
+            includes:parseTree selector) ifTrue:[
                 thisClass := (parseTree receiver evaluate).
                 thisClass isBehavior ifTrue:[
                     (isLoaded := self checkClassIsLoaded:thisClass) ifFalse:[
@@ -969,160 +1932,168 @@
     aStream isNil ifTrue:[^ self].
 
     aClassNameOrNil isNil ifTrue:[
-	self newLabel:'compressing ...'.
+        self newLabel:'compressing ...'.
     ] ifFalse:[
-	self newLabel:'compressing for ' , aClassNameOrNil.
+        self newLabel:'compressing for ' , aClassNameOrNil.
     ].
 
     CompressSnapshotInfo == true ifTrue:[
-	"
-	 get a prototype snapshot record (to be independent of
-	 the actual format ..
-	"
-	str := WriteStream on:String new.
-	Class addChangeRecordForSnapshot:'foo' to:str.
-	snapshotProto := str contents.
-	snapshotPrefix := snapshotProto copyTo:10.
-	snapshotNameIndex := snapshotProto findString:'foo'.
+        "
+         get a prototype snapshot record (to be independent of
+         the actual format ..
+        "
+        str := WriteStream on:String new.
+        Class addChangeRecordForSnapshot:'foo' to:str.
+        snapshotProto := str contents.
+        snapshotPrefix := snapshotProto copyTo:10.
+        snapshotNameIndex := snapshotProto findString:'foo'.
     ].
 
     self withExecuteCursorDo:[
-	|numChanges classes selectors types excla sawExcla
-	 changeNr chunk aParseTree parseTreeChunk
-	 thisClass thisSelector codeChunk codeParser
-	 compressThis|
-
-	numChanges := self numberOfChanges.
-	classes := Array new:numChanges.
-	selectors := Array new:numChanges.
-	types := Array new:numChanges.
-
-	"starting at the end, get the change class and change selector;
-	 collect all in classes / selectors"
-
-	changeNr := numChanges.
-	excla := aStream class chunkSeparator.
-
-	[changeNr >= 1] whileTrue:[
-	    aStream position:(changePositions at:changeNr).
-	    sawExcla := aStream peekFor:excla.
-	    chunk := aStream nextChunk.
-	    sawExcla ifTrue:[
-		"optimize a bit if multiple methods for same category arrive"
-		(chunk = parseTreeChunk) ifFalse:[
-		    aParseTree := Parser parseExpression:chunk.
-		    parseTreeChunk := chunk
-		].
-		(aParseTree notNil 
-		and:[(aParseTree ~~ #Error) 
-		and:[aParseTree isMessage]]) ifTrue:[
-		    (aParseTree selector == #methodsFor:) ifTrue:[
-			thisClass := (aParseTree receiver evaluate).
-			codeChunk := aStream nextChunk.
-			codeParser := Parser 
-					  parseMethodSpecification:codeChunk
-					  in:thisClass
-					  ignoreErrors:true
-					  ignoreWarnings:true.
-			(codeParser notNil and:[codeParser ~~ #Error]) ifTrue:[
-			    selectors at:changeNr put:(codeParser selector).
-			    classes at:changeNr put:thisClass.
-			    types at:changeNr put:#methodsFor
-			]
-		    ]
-		]
-	    ] ifFalse:[
-		aParseTree := Parser parseExpression:chunk.
-		parseTreeChunk := chunk.
-		(aParseTree notNil 
-		and:[(aParseTree ~~ #Error) 
-		and:[aParseTree isMessage]]) ifTrue:[
-		    (aParseTree selector == #removeSelector:) ifTrue:[
-			selectors at:changeNr put:(aParseTree arg1 value ).
-			classes at:changeNr put:(aParseTree receiver evaluate).
-			types at:changeNr put:#removeSelector
-		    ]
-		] ifFalse:[
-		    CompressSnapshotInfo == true ifTrue:[
-			(chunk startsWith:snapshotPrefix) ifTrue:[
-			    str := chunk readStream position:snapshotNameIndex.
-			    fileName := str upTo:(Character space).
-			    "
-			     kludge to allow use of match-check below
-			    "
-			    selectors at:changeNr put:snapshotPrefix.
-			    classes at:changeNr put:fileName.
-			]
-		    ]
-		]
-	    ].
-	    changeNr := changeNr - 1
-	].
-	aStream close.
-
-	"for all changes, look for another class/selector occurence later
-	 in the list and, if there is one, add change number to the delete set"
-
-	deleteSet := OrderedCollection new.
-	changeNr := 1.
-	[changeNr < self numberOfChanges] whileTrue:[
-	    thisClass := classes at:changeNr.
-
-	    compressThis := false.
-	    aClassNameOrNil isNil ifTrue:[
-		compressThis := true
-	    ] ifFalse:[
-		"/ skipping unloaded/unknown classes
-		thisClass isBehavior ifTrue:[
-		    thisClass isMeta ifTrue:[
-			compressThis := aClassNameOrNil = thisClass soleInstance name. 
-		    ] ifFalse:[
-			compressThis := aClassNameOrNil = thisClass name
-		    ]
-		]
-	    ].
-
-	    compressThis ifTrue:[
-		thisSelector := selectors at:changeNr.
-		searchIndex := changeNr.
-		anyMore := true.
-		[anyMore] whileTrue:[
-		    searchIndex := classes indexOf:thisClass
-					startingAt:(searchIndex + 1).
-		    (searchIndex ~~ 0) ifTrue:[
-			((selectors at:searchIndex) == thisSelector) ifTrue:[
-			    thisClass notNil ifTrue:[
-				deleteSet add:changeNr.
-				anyMore := false
-			    ]
-			]
-		    ] ifFalse:[
-			anyMore := false      
-		    ]
-		].
-	    ].
-
-	    changeNr := changeNr + 1
-	].
-
-	"finally delete what has been found"
-
-	(deleteSet size > 0) ifTrue:[
-	    changeListView setSelection:nil.
-	    index := deleteSet size.
-	    [index > 0] whileTrue:[
-		self silentDeleteChange:(deleteSet at:index).
-		index := index - 1
-	    ].
-	    self setChangeList.
-	    "
-	     scroll back a bit, if we are left way behind the list
-	    "
-	    changeListView firstLineShown > self numberOfChanges ifTrue:[
-		changeListView makeLineVisible:self numberOfChanges
-	    ].
-	    self clearCodeView
-	]
+        |numChanges classes selectors types excla sawExcla
+         changeNr chunk aParseTree parseTreeChunk
+         thisClass thisSelector codeChunk codeParser
+         compressThis|
+
+        numChanges := self numberOfChanges.
+        classes := Array new:numChanges.
+        selectors := Array new:numChanges.
+        types := Array new:numChanges.
+
+        "starting at the end, get the change class and change selector;
+         collect all in classes / selectors"
+
+        changeNr := numChanges.
+        excla := aStream class chunkSeparator.
+
+        [changeNr >= 1] whileTrue:[
+            aStream position:(changePositions at:changeNr).
+            sawExcla := aStream peekFor:excla.
+            chunk := aStream nextChunk.
+            sawExcla ifTrue:[
+                "optimize a bit if multiple methods for same category arrive"
+                (chunk = parseTreeChunk) ifFalse:[
+                    aParseTree := Parser parseExpression:chunk.
+                    parseTreeChunk := chunk
+                ].
+                (aParseTree notNil 
+                and:[(aParseTree ~~ #Error) 
+                and:[aParseTree isMessage]]) ifTrue:[
+                    (#(
+                       #methodsFor: 
+                       #privateMethodsFor:
+                       #publicMethodsFor:
+                       #ignoredMethodsFor:
+                       #protectedMethodsFor:
+                       #methodsFor:stamp:             "/ Squeak support
+                      ) 
+                    includes:aParseTree selector) ifTrue:[
+                        thisClass := (aParseTree receiver evaluate).
+                        codeChunk := aStream nextChunk.
+                        codeParser := Parser 
+                                          parseMethodSpecification:codeChunk
+                                          in:thisClass
+                                          ignoreErrors:true
+                                          ignoreWarnings:true.
+                        (codeParser notNil and:[codeParser ~~ #Error]) ifTrue:[
+                            selectors at:changeNr put:(codeParser selector).
+                            classes at:changeNr put:thisClass.
+                            types at:changeNr put:#methodsFor
+                        ]
+                    ]
+                ]
+            ] ifFalse:[
+                aParseTree := Parser parseExpression:chunk.
+                parseTreeChunk := chunk.
+                (aParseTree notNil 
+                and:[(aParseTree ~~ #Error) 
+                and:[aParseTree isMessage]]) ifTrue:[
+                    (aParseTree selector == #removeSelector:) ifTrue:[
+                        selectors at:changeNr put:(aParseTree arg1 value ).
+                        classes at:changeNr put:(aParseTree receiver evaluate).
+                        types at:changeNr put:#removeSelector
+                    ]
+                ] ifFalse:[
+                    CompressSnapshotInfo == true ifTrue:[
+                        (chunk startsWith:snapshotPrefix) ifTrue:[
+                            str := chunk readStream position:snapshotNameIndex.
+                            fileName := str upTo:(Character space).
+                            "
+                             kludge to allow use of match-check below
+                            "
+                            selectors at:changeNr put:snapshotPrefix.
+                            classes at:changeNr put:fileName.
+                        ]
+                    ]
+                ]
+            ].
+            changeNr := changeNr - 1
+        ].
+        aStream close.
+
+        "for all changes, look for another class/selector occurence later
+         in the list and, if there is one, add change number to the delete set"
+
+        deleteSet := OrderedCollection new.
+        changeNr := 1.
+        [changeNr < self numberOfChanges] whileTrue:[
+            thisClass := classes at:changeNr.
+
+            compressThis := false.
+            aClassNameOrNil isNil ifTrue:[
+                compressThis := true
+            ] ifFalse:[
+                "/ skipping unloaded/unknown classes
+                thisClass isBehavior ifTrue:[
+                    thisClass isMeta ifTrue:[
+                        compressThis := aClassNameOrNil = thisClass soleInstance name. 
+                    ] ifFalse:[
+                        compressThis := aClassNameOrNil = thisClass name
+                    ]
+                ]
+            ].
+
+            compressThis ifTrue:[
+                thisSelector := selectors at:changeNr.
+                searchIndex := changeNr.
+                anyMore := true.
+                [anyMore] whileTrue:[
+                    searchIndex := classes indexOf:thisClass
+                                        startingAt:(searchIndex + 1).
+                    (searchIndex ~~ 0) ifTrue:[
+                        ((selectors at:searchIndex) == thisSelector) ifTrue:[
+                            thisClass notNil ifTrue:[
+                                deleteSet add:changeNr.
+                                anyMore := false
+                            ]
+                        ]
+                    ] ifFalse:[
+                        anyMore := false      
+                    ]
+                ].
+            ].
+
+            changeNr := changeNr + 1
+        ].
+
+        "finally delete what has been found"
+
+        (deleteSet size > 0) ifTrue:[
+            changeListView setSelection:nil.
+            index := deleteSet size.
+            [index > 0] whileTrue:[
+                self silentDeleteChange:(deleteSet at:index).
+                index := index - 1
+            ].
+            self setChangeList.
+            "
+             scroll back a bit, if we are left way behind the list
+            "
+            changeListView firstLineShown > self numberOfChanges ifTrue:[
+                changeListView makeLineVisible:self numberOfChanges
+            ].
+            self clearCodeView
+        ]
     ].
     self newLabel:''.
 
@@ -1130,26 +2101,6 @@
     "Modified: / 29.10.1997 / 01:26:59 / cg"
 !
 
-contractClass:className selector:selector to:maxLen
-    |s l|
-
-    s := className , ' ', selector.
-    s size > maxLen ifTrue:[
-	l := maxLen - 1 - selector size max:20.
-	s := (className contractTo:l) , ' ' , selector.
-
-	s size > maxLen ifTrue:[
-	    l := maxLen - 1 - className size max:20.
-	    s := className , ' ', (selector contractTo:l).
-
-	    s size > maxLen ifTrue:[
-		s := (className contractTo:(maxLen // 2 - 1)) , ' ' , (selector contractTo:maxLen // 2)
-	    ]
-	]
-    ].
-    ^ s
-!
-
 deleteChange:changeNr
     "delete a change"
 
@@ -1173,218 +2124,6 @@
     "Modified: / 18.5.1998 / 14:22:27 / cg"
 !
 
-fullClassNameOfChange:changeNr
-    "return the full classname of a change 
-     (for classChanges (i.e. xxx class), a string ending in ' class' is returned.
-     - since parsing ascii methods is slow, keep result cached in 
-       changeClassNames for the next query"
-
-    |chunk aParseTree recTree sel name arg1Tree isMeta prevMethodDefNr
-     words changeStream fullParseTree ownerTree ownerName oldDollarSetting|
-
-    changeNr isNil ifTrue:[^ nil].
-
-    "
-     first look, if not already known
-    "
-    name := changeClassNames at:changeNr.
-    name notNil ifTrue:[^ name].
-
-    prevMethodDefNr := changeNr.
-    [changeIsFollowupMethodChange at:prevMethodDefNr] whileTrue:[
-        prevMethodDefNr := prevMethodDefNr - 1.
-    ].
-
-    "
-     get the chunk
-    "
-    chunk := changeChunks at:prevMethodDefNr.
-    chunk isNil ifTrue:[^ nil].       "mhmh - empty"
-
-    (chunk startsWith:'''---') ifTrue:[
-        words := chunk asCollectionOfWords.
-        words size > 2 ifTrue:[
-            (words at:2) = 'checkin' ifTrue:[
-                name := words at:3.
-                changeClassNames at:changeNr put:name.
-                ^ name
-            ]
-        ].
-    ].
-
-    "/ fix it - otherwise, it cannot be parsed
-    (chunk endsWith:'primitiveDefinitions:') ifTrue:[
-        chunk := chunk , ''''''
-    ].
-    (chunk endsWith:'primitiveFunctions:') ifTrue:[
-        chunk := chunk , ''''''
-    ].
-    (chunk endsWith:'primitiveVariables:') ifTrue:[
-        chunk := chunk , ''''''
-    ].
-
-    "
-     use parser to construct a parseTree
-    "
-    oldDollarSetting := Parser allowDollarInIdentifier.
-    [
-        Parser allowDollarInIdentifier:true.
-        aParseTree := Parser parseExpression:chunk.
-
-        aParseTree == #Error ifTrue:[
-            (chunk includesString:'comment') ifTrue:[
-                "/ could be a comment ...
-                aParseTree := Parser parseExpression:chunk , ''''.
-            ]
-        ].
-    ] valueNowOrOnUnwindDo:[
-        Parser allowDollarInIdentifier:oldDollarSetting
-    ].
-
-    (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
-        ^ nil        "seems strange ... (could be a comment)"
-    ].
-    aParseTree isMessage ifFalse:[
-        ^ nil        "very strange ... (whats that ?)"
-    ].
-
-    "
-     ask parser for selector
-    "
-    sel := aParseTree selector.
-    recTree := aParseTree receiver.
-
-    "
-     is it a method-change, methodRemove or comment-change ?
-    "
-    (#(#'methodsFor:' 
-       #'privateMethodsFor:' 
-       #'protectedMethodsFor:' 
-       #'ignoredMethodsFor:' 
-       #'publicMethodsFor:' 
-       #'removeSelector:' 
-       #'comment:'
-       #'primitiveDefinitions:'
-       #'primitiveFunctions:'
-       #'primitiveVariables:'
-       #'renameCategory:to:'
-       #'instanceVariableNames:'
-    ) includes:sel) ifTrue:[
-        "
-         yes, the className is the receiver
-        "
-        (recTree notNil and:[recTree ~~ #Error]) ifTrue:[
-            isMeta := false.
-            recTree isUnaryMessage ifTrue:[
-                (recTree selector ~~ #class) ifTrue:[^ nil].
-                "id class methodsFor:..."
-                recTree := recTree receiver.
-                isMeta := true.
-            ].
-            recTree isPrimary ifTrue:[
-                name := recTree name.
-                isMeta ifTrue:[
-                    name := name , ' class'.
-                ].
-                changeClassNames at:changeNr put:name.
-                ^ name
-            ]
-        ].
-        "more strange things"
-        ^ nil
-    ].
-
-    "
-     is it a change in a class-description ?
-    "
-    (('subclass:*' match:sel) 
-    or:[('variable*subclass:*' match:sel)]) ifTrue:[
-        "/ must parse the full changes text, to get
-        "/ privacy information.
-
-        changeStream := self streamForChange:changeNr.
-        changeStream notNil ifTrue:[
-            chunk := changeStream nextChunk.
-            changeStream close.
-            fullParseTree := Parser parseExpression:chunk.
-            (fullParseTree isNil or:[fullParseTree == #Error]) ifTrue:[
-                fullParseTree := nil
-            ].
-            fullParseTree isMessage ifFalse:[
-                fullParseTree := nil
-            ].
-            "/ actually, the nil case cannot happen
-            fullParseTree notNil ifTrue:[
-                aParseTree := fullParseTree.
-                sel := aParseTree selector.
-            ].
-        ].
-
-        arg1Tree := aParseTree arg1.
-        (arg1Tree notNil and:[arg1Tree isConstant]) ifTrue:[
-            name := arg1Tree value asString.
-
-            "/ is it a private-class ?
-            ('*privateIn:' match:sel) ifTrue:[
-                ownerTree := aParseTree args last.
-                ownerName := ownerTree name asString.
-                name := ownerName , '::' , name
-            ].
-            changeClassNames at:changeNr put:name.
-            ^ name
-        ].
-        "very strange"
-        ^ nil
-    ].
-
-    "
-     is it a class remove ?
-    "
-    (sel == #removeClass:) ifTrue:[
-        (recTree notNil 
-        and:[recTree ~~ #Error
-        and:[recTree isPrimary
-        and:[recTree name = 'Smalltalk']]]) ifTrue:[
-            arg1Tree := aParseTree arg1.
-            (arg1Tree notNil and:[arg1Tree isPrimary]) ifTrue:[
-                name := arg1Tree name.
-                changeClassNames at:changeNr put:name.
-                ^ name
-            ].
-        ]
-    ].
-
-    "
-     is it a method category change ?
-    "
-    ((sel == #category:)
-    or:[sel == #privacy:]) ifTrue:[
-        (recTree notNil 
-        and:[recTree ~~ #Error
-        and:[recTree isMessage
-        and:[recTree selector == #compiledMethodAt:]]]) ifTrue:[
-            isMeta := false.
-            recTree := recTree receiver.
-            recTree isUnaryMessage ifTrue:[
-                (recTree selector ~~ #class) ifTrue:[^ nil].
-                "id class "
-                recTree := recTree receiver
-            ].
-            recTree isPrimary ifTrue:[
-                isMeta ifTrue:[
-                    name := name , ' class'.
-                ].
-                name := recTree name.
-                changeClassNames at:changeNr put:name.
-                ^ name
-            ]
-        ]
-    ].
-    ^ nil
-
-    "Modified: / 3.8.1998 / 19:58:17 / cg"
-!
-
 makeChangeAPatch:changeNr
     "append change to patchfile"
 
@@ -1397,494 +2136,6 @@
     self notify:'this is not yet implemented'
 !
 
-newLabel:how
-    |l|
-
-    (changeFileName ~= 'changes') ifTrue:[
-        l := self class defaultLabel , ': ', changeFileName
-    ] ifFalse:[
-        l := self class defaultLabel
-    ].
-    l := l , ' ' , how.
-    self label:l
-
-    "Created: / 8.9.1995 / 19:32:04 / claus"
-    "Modified: / 8.9.1995 / 19:39:29 / claus"
-    "Modified: / 6.2.1998 / 13:27:01 / cg"
-!
-
-numberOfChanges
-    ^ changePositions size
-
-    "Created: 3.12.1995 / 18:15:39 / cg"
-!
-
-queryCloseText
-    "made this a method for easy redefinition in subclasses"
-
-    ^ 'Quit without updating changeFile ?'
-!
-
-readChangesFile
-    "read the changes file, create a list of header-lines (changeChunks)
-     and a list of chunk-positions (changePositions)"
-
-    ^ self readChangesFileInBackground:false
-!
-
-readChangesFileInBackground:inBackground
-    "read the changes file, create a list of header-lines (changeChunks)
-     and a list of chunk-positions (changePositions).
-     Starting with 2.10.3, the entries are multi-col entries;
-     the cols are:
-        1   delta (only if comparing)
-                '+' -> new method (w.r.t. current state)
-                '-' -> removed method (w.r.t. current state)
-                '?' -> class does not exist currently
-                '=' -> change is same as current methods source
-        2   class/selector
-        3   type of change
-                doit
-                method
-                category change
-        4   timestamp
-
-     since comparing slows down startup time, it is now disabled by
-     default and can be enabled via a toggle."
-
-    |aStream maxLen i f|
-
-    editingClassSource := false.
-
-    maxLen := 60.
-
-    f := changeFileName asFilename.
-    aStream :=  f readStream.
-    aStream isNil ifTrue:[^ nil].
-
-    self newLabel:'updating ...'.
-
-    i := f info.
-    changeFileSize := i size.
-    changeFileTimestamp := i modified.
-
-    self withReadCursorDo:[
-        |myProcess myPriority|
-
-        "
-         this is a time consuming operation (especially, if reading an
-         NFS-mounted directory; therefore lower my priority ...
-        "
-        inBackground ifTrue:[
-            myProcess := Processor activeProcess.
-            myPriority := myProcess priority.
-            myProcess priority:(Processor userBackgroundPriority).
-        ].
-
-        [
-            |excla timeStampInfo|
-
-            changeChunks := OrderedCollection new.
-            changeHeaderLines := OrderedCollection new.
-            changePositions := OrderedCollection new.
-            changeTimeStamps := OrderedCollection new.
-            changeIsFollowupMethodChange := OrderedCollection new.
-
-            excla := aStream class chunkSeparator.
-
-            [aStream atEnd] whileFalse:[
-                |entry changeDelta changeString changeType 
-                 line s l changeClass sawExcla category 
-                 chunkText chunkPos sel|
-
-                "
-                 get a chunk (separated by excla)
-                "
-                aStream skipSeparators.
-                chunkPos := aStream position.
-
-
-                sawExcla := aStream peekFor:excla.
-                chunkText := aStream nextChunk.
-                chunkText notNil ifTrue:[
-                    |index headerLine cls|
-
-                    (chunkText startsWith:'''---- timestamp ') ifTrue:[
-                        timeStampInfo := (chunkText copyFrom:16 to:(chunkText size - 6)) withoutSpaces.
-                    ] ifFalse:[
-
-                        "
-                         only first line is saved in changeChunks ...
-                        "
-                        index := chunkText indexOf:(Character cr).
-                        (index ~~ 0) ifTrue:[
-                            chunkText := chunkText copyTo:(index - 1).
-
-                            "take care for comment changes - must still be a
-                             valid expression for classNameOfChange: to work"
-
-                            (chunkText endsWith:'comment:''') ifTrue:[
-                                chunkText := chunkText , '...'''
-                            ].
-                            (chunkText endsWith:'primitiveDefinitions:''') ifTrue:[
-                                sel := 'primitiveDefinitions:'.
-                                chunkText := chunkText copyWithoutLast:1
-                            ].
-                            (chunkText endsWith:'primitiveVariables:''') ifTrue:[
-                                sel := 'primitiveVariables:'.
-                                chunkText := chunkText copyWithoutLast:1
-                            ].
-                            (chunkText endsWith:'primitiveFunctions:''') ifTrue:[
-                                sel := 'primitiveFunctions:'.
-                                chunkText := chunkText copyWithoutLast:1
-                            ].
-                        ].
-
-                        changeChunks add:chunkText.
-                        changePositions add:chunkPos.
-                        changeTimeStamps add:timeStampInfo.
-                        changeIsFollowupMethodChange add:false.
-
-                        headerLine := nil.
-                        changeDelta := ' '.
-
-                        sawExcla ifFalse:[
-                            (chunkText startsWith:'''---- snap') ifTrue:[
-                                changeType := ''.
-                                headerLine := chunkText.
-                                changeString := (chunkText contractTo:maxLen).
-                                timeStampInfo := nil.
-                            ] ifFalse:[
-
-                                |p cls clsName|
-
-                                headerLine := chunkText , ' (doIt)'.
-
-                                "
-                                 first, assume doIt - then lets have a more detailed look ...
-                                "
-                                ((chunkText startsWith:'''---- file')
-                                or:[(chunkText startsWith:'''---- check')]) ifTrue:[
-                                    changeType := ''.
-                                    timeStampInfo := nil.
-                                ] ifFalse:[
-                                    changeType := '(doIt)'.
-                                ].    
-                                changeString := (chunkText contractTo:maxLen).
-
-                                p := Parser parseExpression:chunkText inNameSpace:Smalltalk.
-                                (p notNil 
-                                 and:[p ~~ #Error
-                                 and:[p isMessage]]) ifTrue:[
-                                    sel := p selector.
-                                ] ifFalse:[
-                                    sel := nil.    
-                                ].
-                                (sel == #removeSelector:) ifTrue:[
-                                    p receiver isUnaryMessage ifTrue:[
-                                        cls := p receiver receiver name.
-                                        changeClass := (Smalltalk classNamed:cls) class.
-                                        cls := cls , ' class'.
-                                    ] ifFalse:[
-                                        cls := p receiver name.
-                                        changeClass := (Smalltalk classNamed:cls)
-                                    ].
-                                    sel := (p args at:1) evaluate.
-
-                                    compareChanges ifTrue:[
-                                        (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
-                                            changeDelta := '?'
-                                        ] ifFalse:[
-                                            (changeClass implements:sel asSymbol) ifTrue:[
-                                                changeDelta := '-'.
-                                            ] ifFalse:[
-                                                changeDelta := '='.
-                                            ]
-                                        ]
-                                    ].
-                                    changeType := '(remove)'.
-                                    changeString := self contractClass:cls selector:sel to:maxLen.
-                                ].
-                                (p ~~ #Error
-                                and:[p isMessage 
-                                and:[p receiver isMessage
-                                and:[p receiver selector == #compiledMethodAt:]]]) ifTrue:[
-                                    p receiver receiver isUnaryMessage ifTrue:[
-                                        cls := p receiver receiver receiver name.
-                                        changeClass := (Smalltalk classNamed:cls) class.
-                                        cls := cls , ' class'.
-                                    ] ifFalse:[
-                                        cls := p receiver receiver name.
-                                        changeClass := (Smalltalk classNamed:cls)
-                                    ].
-                                    (sel == #category:) ifTrue:[
-                                        sel := (p receiver args at:1) evaluate.
-                                        changeType := '(category change)'.
-                                        changeString := self contractClass:cls selector:sel to:maxLen.
-                                    ].
-                                    (sel == #privacy:) ifTrue:[
-                                        sel := (p receiver args at:1) evaluate.
-                                        changeType := '(privacy change)'.
-                                        changeString := self contractClass:cls selector:sel to:maxLen.
-                                    ].
-                                ].
-                                (#(#'subclass:'
-                                  #'variableSubclass:'
-                                  #'variableByteSubclass:'
-                                  #'variableWordSubclass:'
-                                  #'variableLongSubclass:'
-                                  #'variableFloatSubclass:'
-                                  #'variableDoubleSubclass:'
-                                  #'primitiveDefinitions:'
-                                  #'primitiveFunctions:'
-                                  #'primitiveVariables:'
-                                 ) includes:sel) ifTrue:[
-                                    changeType := '(class definition)'.
-                                    clsName := (p args at:1) evaluate.
-                                    cls := Smalltalk at:clsName ifAbsent:nil.
-                                    cls isNil ifTrue:[
-                                        changeDelta := '+'.
-                                    ]
-                                ].
-                            ]
-                        ] ifTrue:[ "sawExcla"
-                            |done first p className cls text methodPos|
-
-                            "
-                             method definitions actually consist of
-                             two (or more) chunks; skip next chunk(s)
-                             up to an empty one.
-                             The system only writes one chunk,
-                             and we cannot handle more in this ChangesBrowser ....
-                            "
-                            className := nil.
-                            p := Parser parseExpression:chunkText inNameSpace:Smalltalk.
-
-                            (p notNil and:[p ~~ #Error]) ifTrue:[
-                                sel := p selector.
-                                (sel == #methodsFor:) ifTrue:[
-                                    p receiver isUnaryMessage ifTrue:[
-                                        className := p receiver receiver name.
-                                        changeClass := (Smalltalk classNamed:className) class.
-                                        className := className , ' class'.
-                                    ] ifFalse:[
-                                        className := p receiver name.
-                                        changeClass := Smalltalk classNamed:className
-                                    ].
-                                    category := (p args at:1) evaluate.
-                                ].
-                            ].
-
-                            done := false.
-                            first := true.
-                            [done] whileFalse:[
-                                changeDelta := ' '.
-                                methodPos := aStream position.
-
-                                text := aStream nextChunk.
-                                text isNil ifTrue:[
-                                    done := true
-                                ] ifFalse:[
-                                    done := text isEmpty
-                                ].
-                                done ifFalse:[
-                                    first ifFalse:[
-                                        changeChunks add:chunkText.
-                                        changePositions add:methodPos.
-                                        changeTimeStamps add:timeStampInfo.
-                                        changeIsFollowupMethodChange add:true.
-                                        editingClassSource := true.
-                                    ].
-
-                                    first := false.
-                                    "
-                                     try to find the selector
-                                    "
-                                    sel := nil.
-                                    className notNil ifTrue:[
-                                        p := Parser 
-                                                 parseMethodSpecification:text
-                                                 in:nil
-                                                 ignoreErrors:true
-                                                 ignoreWarnings:true.
-                                        (p notNil and:[p ~~ #Error]) ifTrue:[
-                                            sel := p selector.
-                                        ]
-                                    ].
-
-                                    sel isNil ifTrue:[
-                                        changeString := (chunkText contractTo:maxLen).
-                                        changeType := '(change)'.
-                                        headerLine := chunkText , ' (change)'.
-                                    ] ifFalse:[
-                                        changeString :=  self contractClass:className selector:sel to:maxLen.
-                                        changeType := '(method in: ''' , category , ''')'.
-                                        headerLine := className , ' ' , sel , ' ' , '(change category: ''' , category , ''')'.
-                                    ].
-
-                                    compareChanges ifTrue:[ 
-                                        changeClass isNil ifFalse:[
-                                            changeClass isMeta ifTrue:[
-                                                cls := changeClass soleInstance
-                                            ] ifFalse:[
-                                                cls := changeClass
-                                            ].
-                                        ].
-
-                                        (changeClass isNil or:[cls isLoaded not]) ifTrue:[
-                                            changeDelta := '?'
-                                        ] ifFalse:[
-                                            (changeClass implements:sel asSymbol) ifFalse:[
-                                                changeDelta := '+'.
-                                            ] ifTrue:[
-                                                |m currentText t1 t2|
-
-                                                m := changeClass compiledMethodAt:sel asSymbol.
-                                                currentText := m source.
-                                                currentText notNil ifTrue:[
-                                                    text asString = currentText asString ifTrue:[
-                                                        changeDelta := '='
-                                                    ] ifFalse:[
-                                                        t1 := currentText asCollectionOfLines collect:[:s | s withTabsExpanded].
-                                                        t2 := text asCollectionOfLines collect:[:s | s withTabsExpanded].
-                                                        t1 = t2 ifTrue:[
-                                                            changeDelta := '='
-                                                        ]
-                                                    ]
-                                                ]
-                                            ]
-                                        ]
-                                    ].
-                                    entry := MultiColListEntry new.
-                                    entry tabulatorSpecification:tabSpec.
-                                    entry colAt:1 put:changeDelta.
-                                    entry colAt:2 put:changeString.
-                                    entry colAt:3 put:changeType.
-                                    timeStampInfo notNil ifTrue:[
-                                        entry colAt:4 put:timeStampInfo.
-                                    ].    
-                                    changeHeaderLines add:entry
-                                ].
-                                changeString := nil.
-                                headerLine := nil.
-
-                            ]
-                        ].
-                        changeString notNil ifTrue:[
-                            entry := MultiColListEntry new.
-                            entry tabulatorSpecification:tabSpec.
-                            entry colAt:1 put:changeDelta.
-                            entry colAt:2 put:changeString.
-                            entry colAt:3 put:changeType.
-                            timeStampInfo notNil ifTrue:[
-                                entry colAt:4 put:timeStampInfo.
-                            ].    
-                            changeHeaderLines add:entry
-                        ] ifFalse:[
-                            headerLine notNil ifTrue:[
-                                changeHeaderLines add:headerLine
-                            ]
-                        ]
-                    ]
-                ]
-            ].
-            changeClassNames := OrderedCollection new grow:(changeChunks size).
-            anyChanges := false
-        ] valueNowOrOnUnwindDo:[
-            aStream close.
-            inBackground ifTrue:[myProcess priority:myPriority].
-        ].
-    ].
-
-    self checkIfFileHasChanged
-
-    "Modified: / 27.8.1995 / 23:06:55 / claus"
-    "Modified: / 17.7.1998 / 11:10:07 / cg"
-!
-
-selectorOfMethodChange:changeNr
-    "return a method-changes selector, or nil if its not a methodChange"
-
-    |source parser sel chunk aParseTree |
-
-    source := self sourceOfMethodChange:changeNr.
-    source isNil ifTrue:[
-        (self classNameOfChange:changeNr) notNil ifTrue:[
-            chunk := changeChunks at:changeNr.
-            chunk isNil ifTrue:[^ nil].       "mhmh - empty"
-            aParseTree := Parser parseExpression:chunk.
-            (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
-                ^ nil        "seems strange ... (could be a comment)"
-            ].
-            aParseTree isMessage ifFalse:[
-                ^ nil        "very strange ... (whats that ?)"
-            ].
-            sel := aParseTree selector.
-            (#(
-                #'removeSelector:' 
-            ) includes:sel) ifTrue:[
-                sel := aParseTree arguments at:1.
-                sel isConstant ifTrue:[
-                    sel := sel evaluate.
-                    sel isSymbol ifTrue:[
-                        ^ sel
-                    ]
-                ]
-            ]
-        ].
-        ^ nil
-    ].
-
-
-    parser := Parser 
-                parseMethodArgAndVarSpecification:source
-                in:nil 
-                ignoreErrors:true
-                ignoreWarnings:true
-                parseBody:false.
-
-"/    parser := Parser 
-"/                parseMethod:source 
-"/                in:nil 
-"/                ignoreErrors:true 
-"/                ignoreWarnings:true.
-
-    (parser notNil and:[parser ~~ #Error]) ifTrue:[
-        sel := parser selector.
-    ].
-    ^ sel
-
-    "Created: 24.11.1995 / 14:30:46 / cg"
-    "Modified: 5.9.1996 / 17:12:50 / cg"
-!
-
-setChangeList
-    "extract type-information from changes and stuff into top selection
-     view"
-
-    changeListView setList:changeHeaderLines expandTabs:false redraw:false.
-    changeListView invalidate.
-
-    "/ changeListView deselect.
-
-    "Modified: / 18.5.1998 / 14:29:10 / cg"
-!
-
-showNotFound
-    |savedCursor|
-
-    savedCursor := cursor.
-    [
-        self cursor:(Cursor cross).
-        self beep.
-        Delay waitForMilliseconds:300.
-    ] valueNowOrOnUnwindDo:[
-        self cursor:savedCursor
-    ]
-
-    "Modified: / 29.4.1999 / 22:36:54 / cg"
-!
-
 silentDeleteChange:changeNr
     "delete a change do not update changeListView"
 
@@ -1930,181 +2181,6 @@
     "Created: / 7.3.1997 / 16:28:32 / cg"
     "Modified: / 7.2.1998 / 19:59:11 / cg"
     "Modified: / 26.2.1998 / 18:20:48 / stefan"
-!
-
-sourceOfMethodChange:changeNr
-    "return a method-changes source code, or nil if its not a methodChange."
-
-    |aStream chunk sawExcla parseTree sourceChunk|
-
-    aStream := self streamForChange:changeNr.
-    aStream isNil ifTrue:[^ nil].
-
-    (self changeIsFollowupMethodChange:changeNr) ifFalse:[
-        sawExcla := aStream peekFor:(aStream class chunkSeparator).
-        chunk := aStream nextChunk.
-    ] ifTrue:[
-        chunk := (changeChunks at:changeNr).
-        sawExcla := true.
-    ].
-
-    sawExcla ifTrue:[
-        parseTree := Parser parseExpression:chunk.
-        (parseTree notNil and:[parseTree isMessage]) ifTrue:[
-            (#(#methodsFor: 
-               #privateMethodsFor:
-               #publicMethodsFor:
-               #ignoredMethodsFor:
-               #protectedMethodsFor:) 
-            includes:parseTree selector) ifTrue:[
-                sourceChunk := aStream nextChunk.
-            ]
-        ].
-    ].
-    aStream close.
-    ^ sourceChunk
-
-    "Created: / 5.9.1996 / 17:11:32 / cg"
-    "Modified: / 3.8.1998 / 20:00:21 / cg"
-!
-
-streamForChange:changeNr
-    "answer a stream for change"
- 
-    |aStream|
-
-    (changeNr between:1 and:changePositions size) ifFalse:[^ nil].
-    aStream := FileStream readonlyFileNamed:changeFileName.
-    aStream isNil ifTrue:[^ nil].
-    aStream position:(changePositions at:changeNr).
-    ^ aStream
-!
-
-unselect
-    "common unselect"
-
-    changeListView setSelection:nil.
-
-    "Modified: 25.5.1996 / 13:02:49 / cg"
-!
-
-withSelectedChangeDo:aBlock
-    "just a helper, check for a selected change and evaluate aBlock
-     with busy cursor"
-
-    |changeNr|
-
-    changeNr := changeListView selection.
-    changeNr notNil ifTrue:[
-	self withExecuteCursorDo:[
-	    aBlock value:changeNr
-	]
-    ]
-
-    "Modified: 14.12.1995 / 20:58:45 / cg"
-!
-
-writeBackChanges
-    "write back the changes file. To avoid problems when the disk is full
-     or a crash occurs while writing (well, or someone kills us), 
-     first write the stuff to a new temporary file. If this works ok,
-     rename the old change-file to a .bak file and finally rename the
-     tempfile back to the change-file. 
-     That way, if anything happens, either the original file is left unchanged,
-     or we have at least a backup of the previous change file."
-
-    |inStream outStream tempfile stamp f|
-
-    editingClassSource ifTrue:[
-        (self confirm:'You are editing a classes sourceFile (not a changeFile) !!\\Are you certain, you want to overwrite it ?' withCRs)
-        ifFalse:[
-            ^ false
-        ]
-    ].
-
-    tempfile := Filename newTemporaryIn:nil.
-    tempfile exists ifTrue:[tempfile remove].
-
-    outStream := tempfile writeStream.
-    outStream isNil ifTrue:[
-        self warn:'cannot create temporary file in current directory.'.
-        ^ false
-    ].
-
-    inStream := FileStream readonlyFileNamed:changeFileName.
-    inStream isNil ifTrue:[^ false].
-
-    self withCursor:(Cursor write) do:[
-        |excla sawExcla done first chunk
-         nChanges "{Class:SmallInteger}" |
-
-        Stream writeErrorSignal handle:[:ex |
-            self warn:('could not update the changes file.\\' , ex errorString) withCRs.
-            tempfile exists ifTrue:[tempfile remove].
-            ^ false
-        ] do:[
-
-            excla := inStream class chunkSeparator.
-            nChanges := self numberOfChanges.
-
-            1 to:nChanges do:[:index |
-                inStream position:(changePositions at:index).
-                sawExcla := inStream peekFor:excla.
-                chunk := inStream nextChunk.
-
-                (chunk notNil
-                and:[(chunk startsWith:'''---- snap') not]) ifTrue:[
-                    (stamp := changeTimeStamps at:index) notNil ifTrue:[
-                        outStream nextPutAll:'''---- timestamp ' , stamp , ' ----'''.
-                        outStream nextPut:excla; cr.
-                    ].
-                ].
-
-                sawExcla ifTrue:[
-                    outStream nextPut:excla.
-                    outStream nextChunkPut:chunk.
-                    outStream cr; cr.
-                    "
-                     a method-definition chunk - output followups
-                    "
-                    done := false.
-                    first := true.
-                    [done] whileFalse:[
-                        chunk := inStream nextChunk.
-                        chunk isNil ifTrue:[
-                            outStream cr; cr.
-                            done := true
-                        ] ifFalse:[
-                            chunk isEmpty ifTrue:[
-                                outStream space; nextChunkPut:chunk; cr; cr.
-                                done := true.
-                            ] ifFalse:[
-                                first ifFalse:[
-                                    outStream cr; cr.
-                                ].
-                                outStream nextChunkPut:chunk.
-                            ].
-                        ].
-                        first := false.
-                    ].
-                ] ifFalse:[
-                    outStream nextChunkPut:chunk.
-                    outStream cr
-                ]
-            ].
-            outStream close.
-            inStream close.
-        ].
-
-        f := changeFileName asFilename.
-        f renameTo:(f withSuffix:'bak').
-        tempfile renameTo:changeFileName.
-        anyChanges := false
-    ].
-    ^ true
-
-    "Modified: / 2.12.1996 / 22:29:15 / stefan"
-    "Modified: / 21.4.1998 / 17:50:11 / cg"
 ! !
 
 !ChangesBrowser methodsFor:'termination'!
@@ -2985,5 +3061,5 @@
 !ChangesBrowser class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libtool/Attic/CBrowser.st,v 1.155 1999-06-26 16:30:54 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libtool/Attic/CBrowser.st,v 1.156 1999-07-15 14:45:31 cg Exp $'
 ! !
--- a/ChangesBrowser.st	Thu Jul 15 15:44:16 1999 +0200
+++ b/ChangesBrowser.st	Thu Jul 15 16:45:31 1999 +0200
@@ -40,35 +40,39 @@
 
 documentation
 "
-    this implements a browser for the changes-file.
+    this implements a browser for the changes-file (actually, it can display
+    any sourceFiles contents).
     See the extra document 'doc/misc/cbrowser.doc' for how to use this browser.
 
     written jan 90 by claus
 
     [Class variables:]
-	CompressSnapshotInfo            if true (the default), snapshot entries
-					are also compressed in the compress function.
-					Some users prefer them to be not compressed.
-					Set it to false for this.
+        CompressSnapshotInfo            if true (the default), snapshot entries
+                                        are also compressed in the compress function.
+                                        Some users prefer them to be not compressed.
+                                        Set it to false for this.
 
     Notice:
-	this needs a total rewrite, to build up a changeSet from the file
-	(which did not exist when the ChangesBrowser was originally written) 
-	and manipulate that changeSet.
-
-	This way, we get a browser for any upcoming incore changeSets for
-	free. Also, this will put the chunk analyzation code into Change and
-	subclasses (where it belongs) and give a better encapsulation and
-	overall structure. Do not take this as an example for good style ;-)
+        this needs a total rewrite, to build up a changeSet from the file
+        (which did not exist when the ChangesBrowser was originally written) 
+        and manipulate that changeSet.
+
+        This way, we get a browser for any upcoming incore changeSets for
+        free. Also, this will put the chunk analyzation code into Change and
+        subclasses (where it belongs) and give a better encapsulation and
+        overall structure. Do not take this as an example for good style ;-)
+
+        The Change hierarchy is currently been completed, and the changes browser
+        will be adapted soon.
 
     [author:]
-	Claus Gittinger
+        Claus Gittinger
 
     [start with:]
-	ChangesBrowser open
+        ChangesBrowser open
 
     [see also:]
-	( Using the ChangesBrowser :html: tools/cbrowser/TOP.html )
+        ( Using the ChangesBrowser :html: tools/cbrowser/TOP.html )
         
 "
 ! !
@@ -142,12 +146,12 @@
 
 wantChangeLog
     "sent by the compiler to ask if a changeLog entry should
-     be written. Return false here."
+     be written when compiling. Return false here."
 
     ^ false
 ! !
 
-!ChangesBrowser methodsFor:'error handling'!
+!ChangesBrowser methodsFor:'compiler interface-error handling'!
 
 correctableError:aString position:relPos to:relEndPos from:aCompiler
     "compiler notifys us of an error - this should really not happen since
@@ -544,6 +548,1069 @@
 
 !ChangesBrowser methodsFor:'private'!
 
+autoSelect:changeNr
+    "select a change"
+
+    self class autoSelectNext ifTrue:[
+        (changeNr <= self numberOfChanges) ifTrue:[
+            changeListView setSelection:changeNr.
+            self changeSelection:changeNr.
+            ^ self
+        ]
+    ].
+    self clearCodeView.
+    changeListView setSelection:nil.
+
+    "Modified: / 18.5.1998 / 14:26:43 / cg"
+!
+
+autoSelectLast
+    "select the last change"
+
+    self autoSelect:(self numberOfChanges)
+!
+
+autoSelectOrEnd:changeNr
+    "select the next change or the last"
+
+    |last|
+
+    last := self numberOfChanges.
+    changeNr < last ifTrue:[
+	self autoSelect:changeNr
+    ] ifFalse:[
+	changeListView setSelection:last .
+	self changeSelection:last.
+    ]
+
+    "Modified: 25.5.1996 / 12:26:17 / cg"
+!
+
+checkClassIsLoaded:aClass
+    |cls|
+
+    aClass isMeta ifTrue:[
+	cls := aClass soleInstance
+    ] ifFalse:[
+	cls := aClass
+    ].
+    cls isLoaded ifFalse:[
+	(self confirm:(cls name , ' is an autoloaded class.\I can only compare the methods texts if its loaded first.\\Load the class first ?') withCRs)
+	ifTrue:[
+	    cls autoload
+	]
+    ].
+    ^ cls isLoaded
+
+    "Created: 12.12.1995 / 14:04:39 / cg"
+    "Modified: 12.12.1995 / 14:11:05 / cg"
+!
+
+clearCodeView
+    self unselect "changeListView deselect".
+    codeView contents:nil.
+    changeNrShown := nil
+!
+
+contractClass:className selector:selector to:maxLen
+    |s l|
+
+    s := className , ' ', selector.
+    s size > maxLen ifTrue:[
+	l := maxLen - 1 - selector size max:20.
+	s := (className contractTo:l) , ' ' , selector.
+
+	s size > maxLen ifTrue:[
+	    l := maxLen - 1 - className size max:20.
+	    s := className , ' ', (selector contractTo:l).
+
+	    s size > maxLen ifTrue:[
+		s := (className contractTo:(maxLen // 2 - 1)) , ' ' , (selector contractTo:maxLen // 2)
+	    ]
+	]
+    ].
+    ^ s
+!
+
+newLabel:how
+    |l|
+
+    (changeFileName ~= 'changes') ifTrue:[
+        l := self class defaultLabel , ': ', changeFileName
+    ] ifFalse:[
+        l := self class defaultLabel
+    ].
+    l := l , ' ' , how.
+    self label:l
+
+    "Created: / 8.9.1995 / 19:32:04 / claus"
+    "Modified: / 8.9.1995 / 19:39:29 / claus"
+    "Modified: / 6.2.1998 / 13:27:01 / cg"
+!
+
+queryCloseText
+    "made this a method for easy redefinition in subclasses"
+
+    ^ 'Quit without updating changeFile ?'
+!
+
+setChangeList
+    "extract type-information from changes and stuff into top selection
+     view"
+
+    changeListView setList:changeHeaderLines expandTabs:false redraw:false.
+    changeListView invalidate.
+
+    "/ changeListView deselect.
+
+    "Modified: / 18.5.1998 / 14:29:10 / cg"
+!
+
+showNotFound
+    |savedCursor|
+
+    savedCursor := cursor.
+    [
+        self cursor:(Cursor cross).
+        self beep.
+        Delay waitForMilliseconds:300.
+    ] valueNowOrOnUnwindDo:[
+        self cursor:savedCursor
+    ]
+
+    "Modified: / 29.4.1999 / 22:36:54 / cg"
+!
+
+unselect
+    "common unselect"
+
+    changeListView setSelection:nil.
+
+    "Modified: 25.5.1996 / 13:02:49 / cg"
+!
+
+withSelectedChangeDo:aBlock
+    "just a helper, check for a selected change and evaluate aBlock
+     with busy cursor"
+
+    |changeNr|
+
+    changeNr := changeListView selection.
+    changeNr notNil ifTrue:[
+	self withExecuteCursorDo:[
+	    aBlock value:changeNr
+	]
+    ]
+
+    "Modified: 14.12.1995 / 20:58:45 / cg"
+! !
+
+!ChangesBrowser methodsFor:'private-change access'!
+
+changeIsFollowupMethodChange:changeNr
+    ^ changeIsFollowupMethodChange at:changeNr
+
+    "Created: / 6.2.1998 / 13:03:39 / cg"
+!
+
+classNameOfChange:changeNr
+    "return the classname of a change 
+     (for classChanges (i.e. xxx class), the non-metaClassName (i.e. xxx) is returned)"
+
+    |name|
+
+    name := self fullClassNameOfChange:changeNr.
+    name isNil ifTrue:[^ nil].
+    (name endsWith:' class') ifTrue:[
+	^ name copyWithoutLast:6
+    ].
+    ^ name
+
+    "Modified: 6.12.1995 / 17:06:31 / cg"
+!
+
+fullClassNameOfChange:changeNr
+    "return the full classname of a change 
+     (for classChanges (i.e. xxx class), a string ending in ' class' is returned.
+     - since parsing ascii methods is slow, keep result cached in 
+       changeClassNames for the next query"
+
+    |chunk aParseTree recTree sel name arg1Tree isMeta prevMethodDefNr
+     words changeStream fullParseTree ownerTree ownerName oldDollarSetting|
+
+    changeNr isNil ifTrue:[^ nil].
+
+    "
+     first look, if not already known
+    "
+    name := changeClassNames at:changeNr.
+    name notNil ifTrue:[^ name].
+
+    prevMethodDefNr := changeNr.
+    [changeIsFollowupMethodChange at:prevMethodDefNr] whileTrue:[
+        prevMethodDefNr := prevMethodDefNr - 1.
+    ].
+
+    "
+     get the chunk
+    "
+    chunk := changeChunks at:prevMethodDefNr.
+    chunk isNil ifTrue:[^ nil].       "mhmh - empty"
+
+    (chunk startsWith:'''---') ifTrue:[
+        words := chunk asCollectionOfWords.
+        words size > 2 ifTrue:[
+            (words at:2) = 'checkin' ifTrue:[
+                name := words at:3.
+                changeClassNames at:changeNr put:name.
+                ^ name
+            ]
+        ].
+    ].
+
+    "/ fix it - otherwise, it cannot be parsed
+    (chunk endsWith:'primitiveDefinitions:') ifTrue:[
+        chunk := chunk , ''''''
+    ].
+    (chunk endsWith:'primitiveFunctions:') ifTrue:[
+        chunk := chunk , ''''''
+    ].
+    (chunk endsWith:'primitiveVariables:') ifTrue:[
+        chunk := chunk , ''''''
+    ].
+
+    "
+     use parser to construct a parseTree
+    "
+    oldDollarSetting := Parser allowDollarInIdentifier.
+    [
+        Parser allowDollarInIdentifier:true.
+        aParseTree := Parser parseExpression:chunk.
+
+        aParseTree == #Error ifTrue:[
+            (chunk includesString:'comment') ifTrue:[
+                "/ could be a comment ...
+                aParseTree := Parser parseExpression:chunk , ''''.
+            ]
+        ].
+    ] valueNowOrOnUnwindDo:[
+        Parser allowDollarInIdentifier:oldDollarSetting
+    ].
+
+    (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
+        ^ nil        "seems strange ... (could be a comment)"
+    ].
+    aParseTree isMessage ifFalse:[
+        ^ nil        "very strange ... (whats that ?)"
+    ].
+
+    "
+     ask parser for selector
+    "
+    sel := aParseTree selector.
+    recTree := aParseTree receiver.
+
+    "
+     is it a method-change, methodRemove or comment-change ?
+    "
+
+    (#(#'methodsFor:' 
+       #'privateMethodsFor:' 
+       #'protectedMethodsFor:' 
+       #'ignoredMethodsFor:' 
+       #'publicMethodsFor:' 
+       #'removeSelector:' 
+       #'comment:'
+       #'primitiveDefinitions:'
+       #'primitiveFunctions:'
+       #'primitiveVariables:'
+       #'renameCategory:to:'
+       #'instanceVariableNames:'
+
+       #'methodsFor:stamp:'          "/ Squeak support
+       #'commentStamp:prior:'        "/ Squeak support
+       #'addClassVarName:'           "/ Squeak support
+    ) includes:sel) ifTrue:[
+        "
+         yes, the className is the receiver
+        "
+        (recTree notNil and:[recTree ~~ #Error]) ifTrue:[
+            isMeta := false.
+            recTree isUnaryMessage ifTrue:[
+                (recTree selector ~~ #class) ifTrue:[^ nil].
+                "id class methodsFor:..."
+                recTree := recTree receiver.
+                isMeta := true.
+            ].
+            recTree isPrimary ifTrue:[
+                name := recTree name.
+                isMeta ifTrue:[
+                    name := name , ' class'.
+                ].
+                changeClassNames at:changeNr put:name.
+                ^ name
+            ]
+        ].
+        "more strange things"
+        ^ nil
+    ].
+
+    "
+     is it a change in a class-description ?
+    "
+    (('subclass:*' match:sel) 
+    or:[('variable*subclass:*' match:sel)]) ifTrue:[
+        "/ must parse the full changes text, to get
+        "/ privacy information.
+
+        changeStream := self streamForChange:changeNr.
+        changeStream notNil ifTrue:[
+            chunk := changeStream nextChunk.
+            changeStream close.
+            fullParseTree := Parser parseExpression:chunk.
+            (fullParseTree isNil or:[fullParseTree == #Error]) ifTrue:[
+                fullParseTree := nil
+            ].
+            fullParseTree isMessage ifFalse:[
+                fullParseTree := nil
+            ].
+            "/ actually, the nil case cannot happen
+            fullParseTree notNil ifTrue:[
+                aParseTree := fullParseTree.
+                sel := aParseTree selector.
+            ].
+        ].
+
+        arg1Tree := aParseTree arg1.
+        (arg1Tree notNil and:[arg1Tree isConstant]) ifTrue:[
+            name := arg1Tree value asString.
+
+            "/ is it a private-class ?
+            ('*privateIn:' match:sel) ifTrue:[
+                ownerTree := aParseTree args last.
+                ownerName := ownerTree name asString.
+                name := ownerName , '::' , name
+            ].
+            changeClassNames at:changeNr put:name.
+            ^ name
+        ].
+        "very strange"
+        ^ nil
+    ].
+
+    "
+     is it a class remove ?
+    "
+    (sel == #removeClass:) ifTrue:[
+        (recTree notNil 
+        and:[recTree ~~ #Error
+        and:[recTree isPrimary
+        and:[recTree name = 'Smalltalk']]]) ifTrue:[
+            arg1Tree := aParseTree arg1.
+            (arg1Tree notNil and:[arg1Tree isPrimary]) ifTrue:[
+                name := arg1Tree name.
+                changeClassNames at:changeNr put:name.
+                ^ name
+            ].
+        ]
+    ].
+
+    "
+     is it a method category change ?
+    "
+    ((sel == #category:)
+    or:[sel == #privacy:]) ifTrue:[
+        (recTree notNil 
+        and:[recTree ~~ #Error
+        and:[recTree isMessage
+        and:[recTree selector == #compiledMethodAt:]]]) ifTrue:[
+            isMeta := false.
+            recTree := recTree receiver.
+            recTree isUnaryMessage ifTrue:[
+                (recTree selector ~~ #class) ifTrue:[^ nil].
+                "id class "
+                recTree := recTree receiver
+            ].
+            recTree isPrimary ifTrue:[
+                isMeta ifTrue:[
+                    name := name , ' class'.
+                ].
+                name := recTree name.
+                changeClassNames at:changeNr put:name.
+                ^ name
+            ]
+        ]
+    ].
+    ^ nil
+
+    "Modified: / 3.8.1998 / 19:58:17 / cg"
+!
+
+numberOfChanges
+    ^ changePositions size
+
+    "Created: 3.12.1995 / 18:15:39 / cg"
+!
+
+selectorOfMethodChange:changeNr
+    "return a method-changes selector, or nil if its not a methodChange"
+
+    |source parser sel chunk aParseTree |
+
+    source := self sourceOfMethodChange:changeNr.
+    source isNil ifTrue:[
+        (self classNameOfChange:changeNr) notNil ifTrue:[
+            chunk := changeChunks at:changeNr.
+            chunk isNil ifTrue:[^ nil].       "mhmh - empty"
+            aParseTree := Parser parseExpression:chunk.
+            (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
+                ^ nil        "seems strange ... (could be a comment)"
+            ].
+            aParseTree isMessage ifFalse:[
+                ^ nil        "very strange ... (whats that ?)"
+            ].
+            sel := aParseTree selector.
+            (#(
+                #'removeSelector:' 
+            ) includes:sel) ifTrue:[
+                sel := aParseTree arguments at:1.
+                sel isConstant ifTrue:[
+                    sel := sel evaluate.
+                    sel isSymbol ifTrue:[
+                        ^ sel
+                    ]
+                ]
+            ]
+        ].
+        ^ nil
+    ].
+
+
+    parser := Parser 
+                parseMethodArgAndVarSpecification:source
+                in:nil 
+                ignoreErrors:true
+                ignoreWarnings:true
+                parseBody:false.
+
+"/    parser := Parser 
+"/                parseMethod:source 
+"/                in:nil 
+"/                ignoreErrors:true 
+"/                ignoreWarnings:true.
+
+    (parser notNil and:[parser ~~ #Error]) ifTrue:[
+        sel := parser selector.
+    ].
+    ^ sel
+
+    "Created: 24.11.1995 / 14:30:46 / cg"
+    "Modified: 5.9.1996 / 17:12:50 / cg"
+!
+
+sourceOfMethodChange:changeNr
+    "return a method-changes source code, or nil if its not a methodChange."
+
+    |aStream chunk sawExcla parseTree sourceChunk sel|
+
+    aStream := self streamForChange:changeNr.
+    aStream isNil ifTrue:[^ nil].
+
+    (self changeIsFollowupMethodChange:changeNr) ifFalse:[
+        sawExcla := aStream peekFor:(aStream class chunkSeparator).
+        chunk := aStream nextChunk.
+    ] ifTrue:[
+        chunk := (changeChunks at:changeNr).
+        sawExcla := true.
+    ].
+
+    sawExcla ifTrue:[
+        parseTree := Parser parseExpression:chunk.
+        (parseTree notNil and:[parseTree isMessage]) ifTrue:[
+            sel := parseTree selector.
+            (#(
+               #methodsFor: 
+               #privateMethodsFor:
+               #publicMethodsFor:
+               #ignoredMethodsFor:
+               #protectedMethodsFor:
+
+               #methodsFor:stamp:             "/ Squeak support
+               #commentStamp:prior:           "/ Squeak support
+              ) 
+            includes:sel) ifTrue:[
+                sourceChunk := aStream nextChunk.
+            ]
+        ].
+    ].
+    aStream close.
+    ^ sourceChunk
+
+    "Created: / 5.9.1996 / 17:11:32 / cg"
+    "Modified: / 3.8.1998 / 20:00:21 / cg"
+!
+
+streamForChange:changeNr
+    "answer a stream for change"
+ 
+    |aStream|
+
+    (changeNr between:1 and:changePositions size) ifFalse:[^ nil].
+    aStream := FileStream readonlyFileNamed:changeFileName.
+    aStream isNil ifTrue:[^ nil].
+    aStream position:(changePositions at:changeNr).
+    ^ aStream
+! !
+
+!ChangesBrowser methodsFor:'private-changeFile access'!
+
+changeFileName:aFileName
+    changeFileName := aFileName
+!
+
+checkIfFileHasChanged
+    |f info |
+
+    Processor removeTimedBlock:checkBlock.
+    f := changeFileName asFilename.
+    (info := f info) isNil ifTrue:[
+	self newLabel:'(unaccessable)'
+    ] ifFalse:[
+	(info modified) > changeFileTimestamp ifTrue:[
+	    self newLabel:'(outdated)'.
+	    autoUpdate ifTrue:[
+		self doUpdate
+	    ]
+	] ifFalse:[
+	    self newLabel:''
+	]
+    ].
+    Processor addTimedBlock:checkBlock afterSeconds:5.
+
+    "Created: 8.9.1995 / 19:30:19 / claus"
+    "Modified: 8.9.1995 / 19:38:18 / claus"
+    "Modified: 1.11.1996 / 20:22:56 / cg"
+!
+
+readChangesFile
+    "read the changes file, create a list of header-lines (changeChunks)
+     and a list of chunk-positions (changePositions)"
+
+    ^ self readChangesFileInBackground:false
+!
+
+readChangesFileInBackground:inBackground
+    "read the changes file, create a list of header-lines (changeChunks)
+     and a list of chunk-positions (changePositions).
+     Starting with 2.10.3, the entries are multi-col entries;
+     the cols are:
+        1   delta (only if comparing)
+                '+' -> new method (w.r.t. current state)
+                '-' -> removed method (w.r.t. current state)
+                '?' -> class does not exist currently
+                '=' -> change is same as current methods source
+        2   class/selector
+        3   type of change
+                doit
+                method
+                category change
+        4   timestamp
+
+     since comparing slows down startup time, it is now disabled by
+     default and can be enabled via a toggle."
+
+    |aStream maxLen i f chunkText fullChunkText|
+
+    editingClassSource := false.
+
+    maxLen := 60.
+
+    f := changeFileName asFilename.
+    aStream :=  f readStream.
+    aStream isNil ifTrue:[^ nil].
+
+    self newLabel:'updating ...'.
+
+    i := f info.
+    changeFileSize := i size.
+    changeFileTimestamp := i modified.
+
+    self withReadCursorDo:[
+        |myProcess myPriority|
+
+        "
+         this is a time consuming operation (especially, if reading an
+         NFS-mounted directory; therefore lower my priority ...
+        "
+        inBackground ifTrue:[
+            myProcess := Processor activeProcess.
+            myPriority := myProcess priority.
+            myProcess priority:(Processor userBackgroundPriority).
+        ].
+
+        [
+            |excla timeStampInfo|
+
+            changeChunks := OrderedCollection new.
+            changeHeaderLines := OrderedCollection new.
+            changePositions := OrderedCollection new.
+            changeTimeStamps := OrderedCollection new.
+            changeIsFollowupMethodChange := OrderedCollection new.
+
+            excla := aStream class chunkSeparator.
+
+            [aStream atEnd] whileFalse:[
+                |entry changeDelta changeString changeType 
+                 line s l changeClass sawExcla category 
+                  chunkPos sel|
+
+                "
+                 get a chunk (separated by excla)
+                "
+                aStream skipSeparators.
+                chunkPos := aStream position.
+
+
+                sawExcla := aStream peekFor:excla.
+                chunkText := fullChunkText := aStream nextChunk.
+                chunkText notNil ifTrue:[
+                    |index headerLine cls|
+
+                    (chunkText startsWith:'''---- timestamp ') ifTrue:[
+                        timeStampInfo := (chunkText copyFrom:16 to:(chunkText size - 6)) withoutSpaces.
+                    ] ifFalse:[
+
+                        "
+                         only first line is saved in changeChunks ...
+                        "
+                        index := chunkText indexOf:(Character cr).
+                        (index ~~ 0) ifTrue:[
+                            chunkText := chunkText copyTo:(index - 1).
+
+                            "take care for comment changes - must still be a
+                             valid expression for classNameOfChange: to work"
+
+                            (chunkText endsWith:'comment:''') ifTrue:[
+                                chunkText := chunkText , '...'''
+                            ].
+                            (chunkText endsWith:'primitiveDefinitions:''') ifTrue:[
+                                sel := 'primitiveDefinitions:'.
+                                chunkText := chunkText copyWithoutLast:1
+                            ].
+                            (chunkText endsWith:'primitiveVariables:''') ifTrue:[
+                                sel := 'primitiveVariables:'.
+                                chunkText := chunkText copyWithoutLast:1
+                            ].
+                            (chunkText endsWith:'primitiveFunctions:''') ifTrue:[
+                                sel := 'primitiveFunctions:'.
+                                chunkText := chunkText copyWithoutLast:1
+                            ].
+                        ].
+
+                        changeChunks add:chunkText.
+                        changePositions add:chunkPos.
+                        changeTimeStamps add:timeStampInfo.
+                        changeIsFollowupMethodChange add:false.
+
+                        headerLine := nil.
+                        changeDelta := ' '.
+
+                        sawExcla ifFalse:[
+                            (chunkText startsWith:'''---- snap') ifTrue:[
+                                changeType := ''.
+                                headerLine := chunkText.
+                                changeString := (chunkText contractTo:maxLen).
+                                timeStampInfo := nil.
+                            ] ifFalse:[
+
+                                |p cls clsName|
+
+                                headerLine := chunkText , ' (doIt)'.
+
+                                "
+                                 first, assume doIt - then lets have a more detailed look ...
+                                "
+                                ((chunkText startsWith:'''---- file')
+                                or:[(chunkText startsWith:'''---- check')]) ifTrue:[
+                                    changeType := ''.
+                                    timeStampInfo := nil.
+                                ] ifFalse:[
+                                    changeType := '(doIt)'.
+                                ].    
+                                changeString := (chunkText contractTo:maxLen).
+
+                                p := Parser parseExpression:fullChunkText inNameSpace:Smalltalk.
+                                (p notNil and:[p ~~ #Error]) ifTrue:[
+                                    p isMessage ifTrue:[
+                                        sel := p selector.
+                                    ]
+                                ] ifFalse:[
+                                    sel := nil.
+                                    (Scanner new scanTokens:fullChunkText) size == 0 ifTrue:[
+                                        "/ a comment only
+                                        changeType := '(comment)'.
+                                    ] ifFalse:[
+                                        changeType := '(???)'.
+                                    ]
+                                ].
+                                (sel == #removeSelector:) ifTrue:[
+                                    p receiver isUnaryMessage ifTrue:[
+                                        cls := p receiver receiver name.
+                                        changeClass := (Smalltalk classNamed:cls) class.
+                                        cls := cls , ' class'.
+                                    ] ifFalse:[
+                                        cls := p receiver name.
+                                        changeClass := (Smalltalk classNamed:cls)
+                                    ].
+                                    sel := (p args at:1) evaluate.
+
+                                    compareChanges ifTrue:[
+                                        (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
+                                            changeDelta := '?'
+                                        ] ifFalse:[
+                                            (changeClass implements:sel asSymbol) ifTrue:[
+                                                changeDelta := '-'.
+                                            ] ifFalse:[
+                                                changeDelta := '='.
+                                            ]
+                                        ]
+                                    ].
+                                    changeType := '(remove)'.
+                                    changeString := self contractClass:cls selector:sel to:maxLen.
+                                ].
+                                (p ~~ #Error
+                                and:[p isMessage 
+                                and:[p receiver isMessage
+                                and:[p receiver selector == #compiledMethodAt:]]]) ifTrue:[
+                                    p receiver receiver isUnaryMessage ifTrue:[
+                                        cls := p receiver receiver receiver name.
+                                        changeClass := (Smalltalk classNamed:cls) class.
+                                        cls := cls , ' class'.
+                                    ] ifFalse:[
+                                        cls := p receiver receiver name.
+                                        changeClass := (Smalltalk classNamed:cls)
+                                    ].
+                                    (sel == #category:) ifTrue:[
+                                        sel := (p receiver args at:1) evaluate.
+                                        changeType := '(category change)'.
+                                        changeString := self contractClass:cls selector:sel to:maxLen.
+                                    ].
+                                    (sel == #privacy:) ifTrue:[
+                                        sel := (p receiver args at:1) evaluate.
+                                        changeType := '(privacy change)'.
+                                        changeString := self contractClass:cls selector:sel to:maxLen.
+                                    ].
+                                ].
+                                (#(#'subclass:'
+                                  #'variableSubclass:'
+                                  #'variableByteSubclass:'
+                                  #'variableWordSubclass:'
+                                  #'variableLongSubclass:'
+                                  #'variableFloatSubclass:'
+                                  #'variableDoubleSubclass:'
+                                  #'primitiveDefinitions:'
+                                  #'primitiveFunctions:'
+                                  #'primitiveVariables:'
+                                 ) includes:sel) ifTrue:[
+                                    changeType := '(class definition)'.
+                                    clsName := (p args at:1) evaluate.
+                                    cls := Smalltalk at:clsName ifAbsent:nil.
+                                    cls isNil ifTrue:[
+                                        changeDelta := '+'.
+                                    ]
+                                ].
+                            ]
+                        ] ifTrue:[ "sawExcla"
+                            |done first p className cls text methodPos 
+                             singleJunkOnly methodChunks singleInfo|
+
+                            singleJunkOnly := false.
+                            methodChunks := false.
+                            singleInfo := false.
+
+                            "
+                             method definitions actually consist of
+                             two (or more) chunks; skip next chunk(s)
+                             up to an empty one.
+                             The system only writes one chunk,
+                             and we cannot handle more in this ChangesBrowser ....
+                            "
+                            className := nil.
+                            p := Parser parseExpression:chunkText inNameSpace:Smalltalk.
+
+                            (p notNil and:[p ~~ #Error]) ifTrue:[
+                                sel := p selector.
+                                (#(
+                                   #methodsFor: 
+                                   #privateMethodsFor:
+                                   #publicMethodsFor:
+                                   #ignoredMethodsFor:
+                                   #protectedMethodsFor:
+                                   #methodsFor:stamp:             "/ Squeak support
+                                   #'commentStamp:prior:'     
+                                  ) 
+                                includes:sel) ifTrue:[
+                                    methodChunks := true.
+                                    p receiver isUnaryMessage ifTrue:[
+                                        className := p receiver receiver name.
+                                        changeClass := (Smalltalk classNamed:className) class.
+                                        className := className , ' class'.
+                                    ] ifFalse:[
+                                        className := p receiver name.
+                                        changeClass := Smalltalk classNamed:className
+                                    ].
+                                    category := (p args at:1) evaluate.
+
+                                    sel == #'methodsFor:stamp:' ifTrue:[
+                                        "/ Squeak timeStamp
+                                        timeStampInfo := (p args at:2) evaluate.
+                                        singleInfo := true
+                                    ] ifFalse:[
+                                        sel == #'commentStamp:prior:' ifTrue:[
+                                            singleJunkOnly := true.
+                                            methodChunks := false.
+                                        ].
+                                    ]
+                                ].
+                            ].
+
+                            done := false.
+                            first := true.
+                            [done] whileFalse:[
+                                changeDelta := ' '.
+                                methodPos := aStream position.
+
+                                text := aStream nextChunk.
+                                text isNil ifTrue:[
+                                    done := true
+                                ] ifFalse:[
+                                    done := text isEmpty
+                                ].
+                                done ifFalse:[
+                                    first ifFalse:[
+                                        changeChunks add:chunkText.
+                                        changePositions add:methodPos.
+                                        changeTimeStamps add:timeStampInfo.
+                                        changeIsFollowupMethodChange add:true.
+                                        editingClassSource := true.
+                                    ].
+
+                                    first := false.
+                                    "
+                                     try to find the selector
+                                    "
+                                    sel := nil.
+                                    className notNil ifTrue:[
+                                        methodChunks ifTrue:[
+                                            p := Parser 
+                                                     parseMethodSpecification:text
+                                                     in:nil
+                                                     ignoreErrors:true
+                                                     ignoreWarnings:true.
+                                            (p notNil and:[p ~~ #Error]) ifTrue:[
+                                                sel := p selector.
+                                            ]
+                                        ]
+                                    ].
+
+                                    sel isNil ifTrue:[
+                                        changeString := (chunkText contractTo:maxLen).
+                                        changeType := '(change)'.
+                                        headerLine := chunkText , ' (change)'.
+                                    ] ifFalse:[
+                                        changeString :=  self contractClass:className selector:sel to:maxLen.
+                                        changeType := '(method in: ''' , category , ''')'.
+                                        headerLine := className , ' ' , sel , ' ' , '(change category: ''' , category , ''')'.
+                                    ].
+
+                                    compareChanges ifTrue:[ 
+                                        changeClass isNil ifFalse:[
+                                            changeClass isMeta ifTrue:[
+                                                cls := changeClass soleInstance
+                                            ] ifFalse:[
+                                                cls := changeClass
+                                            ].
+                                        ].
+
+                                        (changeClass isNil or:[cls isLoaded not]) ifTrue:[
+                                            changeDelta := '?'
+                                        ] ifFalse:[
+                                            (changeClass implements:sel asSymbol) ifFalse:[
+                                                changeDelta := '+'.
+                                            ] ifTrue:[
+                                                |m currentText t1 t2|
+
+                                                m := changeClass compiledMethodAt:sel asSymbol.
+                                                currentText := m source.
+                                                currentText notNil ifTrue:[
+                                                    text asString = currentText asString ifTrue:[
+                                                        changeDelta := '='
+                                                    ] ifFalse:[
+                                                        t1 := currentText asCollectionOfLines collect:[:s | s withTabsExpanded].
+                                                        t2 := text asCollectionOfLines collect:[:s | s withTabsExpanded].
+                                                        t1 = t2 ifTrue:[
+                                                            changeDelta := '='
+                                                        ]
+                                                    ]
+                                                ]
+                                            ]
+                                        ]
+                                    ].
+                                    entry := MultiColListEntry new.
+                                    entry tabulatorSpecification:tabSpec.
+                                    entry colAt:1 put:changeDelta.
+                                    entry colAt:2 put:changeString.
+                                    entry colAt:3 put:changeType.
+                                    timeStampInfo notNil ifTrue:[
+                                        entry colAt:4 put:timeStampInfo.
+                                    ].    
+                                    changeHeaderLines add:entry
+                                ].
+                                changeString := nil.
+                                headerLine := nil.
+                                singleJunkOnly ifTrue:[done := true]
+                            ].
+                            singleInfo ifTrue:[
+                                timeStampInfo := nil
+                            ].
+                        ].
+                        changeString notNil ifTrue:[
+                            entry := MultiColListEntry new.
+                            entry tabulatorSpecification:tabSpec.
+                            entry colAt:1 put:changeDelta.
+                            entry colAt:2 put:changeString.
+                            entry colAt:3 put:changeType.
+                            timeStampInfo notNil ifTrue:[
+                                entry colAt:4 put:timeStampInfo.
+                            ].    
+                            changeHeaderLines add:entry
+                        ] ifFalse:[
+                            headerLine notNil ifTrue:[
+                                changeHeaderLines add:headerLine
+                            ]
+                        ]
+                    ]
+                ]
+            ].
+            changeClassNames := OrderedCollection new grow:(changeChunks size).
+            anyChanges := false
+        ] valueNowOrOnUnwindDo:[
+            aStream close.
+            inBackground ifTrue:[myProcess priority:myPriority].
+        ].
+    ].
+
+    self checkIfFileHasChanged
+
+    "Modified: / 27.8.1995 / 23:06:55 / claus"
+    "Modified: / 17.7.1998 / 11:10:07 / cg"
+!
+
+writeBackChanges
+    "write back the changes file. To avoid problems when the disk is full
+     or a crash occurs while writing (well, or someone kills us), 
+     first write the stuff to a new temporary file. If this works ok,
+     rename the old change-file to a .bak file and finally rename the
+     tempfile back to the change-file. 
+     That way, if anything happens, either the original file is left unchanged,
+     or we have at least a backup of the previous change file."
+
+    |inStream outStream tempfile stamp f|
+
+    editingClassSource ifTrue:[
+        (self confirm:'You are editing a classes sourceFile (not a changeFile) !!\\Are you certain, you want to overwrite it ?' withCRs)
+        ifFalse:[
+            ^ false
+        ]
+    ].
+
+    tempfile := Filename newTemporaryIn:nil.
+    tempfile exists ifTrue:[tempfile remove].
+
+    outStream := tempfile writeStream.
+    outStream isNil ifTrue:[
+        self warn:'cannot create temporary file in current directory.'.
+        ^ false
+    ].
+
+    inStream := FileStream readonlyFileNamed:changeFileName.
+    inStream isNil ifTrue:[^ false].
+
+    self withCursor:(Cursor write) do:[
+        |excla sawExcla done first chunk
+         nChanges "{Class:SmallInteger}" |
+
+        Stream writeErrorSignal handle:[:ex |
+            self warn:('could not update the changes file.\\' , ex errorString) withCRs.
+            tempfile exists ifTrue:[tempfile remove].
+            ^ false
+        ] do:[
+
+            excla := inStream class chunkSeparator.
+            nChanges := self numberOfChanges.
+
+            1 to:nChanges do:[:index |
+                inStream position:(changePositions at:index).
+                sawExcla := inStream peekFor:excla.
+                chunk := inStream nextChunk.
+
+                (chunk notNil
+                and:[(chunk startsWith:'''---- snap') not]) ifTrue:[
+                    (stamp := changeTimeStamps at:index) notNil ifTrue:[
+                        outStream nextPutAll:'''---- timestamp ' , stamp , ' ----'''.
+                        outStream nextPut:excla; cr.
+                    ].
+                ].
+
+                sawExcla ifTrue:[
+                    outStream nextPut:excla.
+                    outStream nextChunkPut:chunk.
+                    outStream cr; cr.
+                    "
+                     a method-definition chunk - output followups
+                    "
+                    done := false.
+                    first := true.
+                    [done] whileFalse:[
+                        chunk := inStream nextChunk.
+                        chunk isNil ifTrue:[
+                            outStream cr; cr.
+                            done := true
+                        ] ifFalse:[
+                            chunk isEmpty ifTrue:[
+                                outStream space; nextChunkPut:chunk; cr; cr.
+                                done := true.
+                            ] ifFalse:[
+                                first ifFalse:[
+                                    outStream cr; cr.
+                                ].
+                                outStream nextChunkPut:chunk.
+                            ].
+                        ].
+                        first := false.
+                    ].
+                ] ifFalse:[
+                    outStream nextChunkPut:chunk.
+                    outStream cr
+                ]
+            ].
+            outStream close.
+            inStream close.
+        ].
+
+        f := changeFileName asFilename.
+        f renameTo:(f withSuffix:'bak').
+        tempfile renameTo:changeFileName.
+        anyChanges := false
+    ].
+    ^ true
+
+    "Modified: / 2.12.1996 / 22:29:15 / stefan"
+    "Modified: / 21.4.1998 / 17:50:11 / cg"
+! !
+
+!ChangesBrowser methodsFor:'private-user interaction ops'!
+
 appendChange:changeNr toFile:fileName
     "append change to a file. return true if ok."
 
@@ -661,120 +1728,6 @@
     "Modified: / 7.2.1998 / 19:56:34 / cg"
 !
 
-autoSelect:changeNr
-    "select a change"
-
-    self class autoSelectNext ifTrue:[
-        (changeNr <= self numberOfChanges) ifTrue:[
-            changeListView setSelection:changeNr.
-            self changeSelection:changeNr.
-            ^ self
-        ]
-    ].
-    self clearCodeView.
-    changeListView setSelection:nil.
-
-    "Modified: / 18.5.1998 / 14:26:43 / cg"
-!
-
-autoSelectLast
-    "select the last change"
-
-    self autoSelect:(self numberOfChanges)
-!
-
-autoSelectOrEnd:changeNr
-    "select the next change or the last"
-
-    |last|
-
-    last := self numberOfChanges.
-    changeNr < last ifTrue:[
-	self autoSelect:changeNr
-    ] ifFalse:[
-	changeListView setSelection:last .
-	self changeSelection:last.
-    ]
-
-    "Modified: 25.5.1996 / 12:26:17 / cg"
-!
-
-changeFileName:aFileName
-    changeFileName := aFileName
-!
-
-changeIsFollowupMethodChange:changeNr
-    ^ changeIsFollowupMethodChange at:changeNr
-
-    "Created: / 6.2.1998 / 13:03:39 / cg"
-!
-
-checkClassIsLoaded:aClass
-    |cls|
-
-    aClass isMeta ifTrue:[
-	cls := aClass soleInstance
-    ] ifFalse:[
-	cls := aClass
-    ].
-    cls isLoaded ifFalse:[
-	(self confirm:(cls name , ' is an autoloaded class.\I can only compare the methods texts if its loaded first.\\Load the class first ?') withCRs)
-	ifTrue:[
-	    cls autoload
-	]
-    ].
-    ^ cls isLoaded
-
-    "Created: 12.12.1995 / 14:04:39 / cg"
-    "Modified: 12.12.1995 / 14:11:05 / cg"
-!
-
-checkIfFileHasChanged
-    |f info |
-
-    Processor removeTimedBlock:checkBlock.
-    f := changeFileName asFilename.
-    (info := f info) isNil ifTrue:[
-	self newLabel:'(unaccessable)'
-    ] ifFalse:[
-	(info modified) > changeFileTimestamp ifTrue:[
-	    self newLabel:'(outdated)'.
-	    autoUpdate ifTrue:[
-		self doUpdate
-	    ]
-	] ifFalse:[
-	    self newLabel:''
-	]
-    ].
-    Processor addTimedBlock:checkBlock afterSeconds:5.
-
-    "Created: 8.9.1995 / 19:30:19 / claus"
-    "Modified: 8.9.1995 / 19:38:18 / claus"
-    "Modified: 1.11.1996 / 20:22:56 / cg"
-!
-
-classNameOfChange:changeNr
-    "return the classname of a change 
-     (for classChanges (i.e. xxx class), the non-metaClassName (i.e. xxx) is returned)"
-
-    |name|
-
-    name := self fullClassNameOfChange:changeNr.
-    name isNil ifTrue:[^ nil].
-    (name endsWith:' class') ifTrue:[
-	^ name copyWithoutLast:6
-    ].
-    ^ name
-
-    "Modified: 6.12.1995 / 17:06:31 / cg"
-!
-
-clearCodeView
-    self unselect "changeListView deselect".
-    codeView contents:nil.
-    changeNrShown := nil
-!
-
 compareChange:changeNr
     "compare a change with current version"
 
@@ -859,7 +1812,17 @@
         (parseTree notNil 
          and:[parseTree ~~ #Error
          and:[parseTree isMessage]]) ifTrue:[
-            (parseTree selector == #methodsFor:) ifTrue:[
+            "/ Squeak support (#methodsFor:***)
+            (#(
+               #methodsFor: 
+               #privateMethodsFor:
+               #publicMethodsFor:
+               #ignoredMethodsFor:
+               #protectedMethodsFor:
+
+               #methodsFor:stamp:             "/ Squeak support
+              ) 
+            includes:parseTree selector) ifTrue:[
                 thisClass := (parseTree receiver evaluate).
                 thisClass isBehavior ifTrue:[
                     (isLoaded := self checkClassIsLoaded:thisClass) ifFalse:[
@@ -969,160 +1932,168 @@
     aStream isNil ifTrue:[^ self].
 
     aClassNameOrNil isNil ifTrue:[
-	self newLabel:'compressing ...'.
+        self newLabel:'compressing ...'.
     ] ifFalse:[
-	self newLabel:'compressing for ' , aClassNameOrNil.
+        self newLabel:'compressing for ' , aClassNameOrNil.
     ].
 
     CompressSnapshotInfo == true ifTrue:[
-	"
-	 get a prototype snapshot record (to be independent of
-	 the actual format ..
-	"
-	str := WriteStream on:String new.
-	Class addChangeRecordForSnapshot:'foo' to:str.
-	snapshotProto := str contents.
-	snapshotPrefix := snapshotProto copyTo:10.
-	snapshotNameIndex := snapshotProto findString:'foo'.
+        "
+         get a prototype snapshot record (to be independent of
+         the actual format ..
+        "
+        str := WriteStream on:String new.
+        Class addChangeRecordForSnapshot:'foo' to:str.
+        snapshotProto := str contents.
+        snapshotPrefix := snapshotProto copyTo:10.
+        snapshotNameIndex := snapshotProto findString:'foo'.
     ].
 
     self withExecuteCursorDo:[
-	|numChanges classes selectors types excla sawExcla
-	 changeNr chunk aParseTree parseTreeChunk
-	 thisClass thisSelector codeChunk codeParser
-	 compressThis|
-
-	numChanges := self numberOfChanges.
-	classes := Array new:numChanges.
-	selectors := Array new:numChanges.
-	types := Array new:numChanges.
-
-	"starting at the end, get the change class and change selector;
-	 collect all in classes / selectors"
-
-	changeNr := numChanges.
-	excla := aStream class chunkSeparator.
-
-	[changeNr >= 1] whileTrue:[
-	    aStream position:(changePositions at:changeNr).
-	    sawExcla := aStream peekFor:excla.
-	    chunk := aStream nextChunk.
-	    sawExcla ifTrue:[
-		"optimize a bit if multiple methods for same category arrive"
-		(chunk = parseTreeChunk) ifFalse:[
-		    aParseTree := Parser parseExpression:chunk.
-		    parseTreeChunk := chunk
-		].
-		(aParseTree notNil 
-		and:[(aParseTree ~~ #Error) 
-		and:[aParseTree isMessage]]) ifTrue:[
-		    (aParseTree selector == #methodsFor:) ifTrue:[
-			thisClass := (aParseTree receiver evaluate).
-			codeChunk := aStream nextChunk.
-			codeParser := Parser 
-					  parseMethodSpecification:codeChunk
-					  in:thisClass
-					  ignoreErrors:true
-					  ignoreWarnings:true.
-			(codeParser notNil and:[codeParser ~~ #Error]) ifTrue:[
-			    selectors at:changeNr put:(codeParser selector).
-			    classes at:changeNr put:thisClass.
-			    types at:changeNr put:#methodsFor
-			]
-		    ]
-		]
-	    ] ifFalse:[
-		aParseTree := Parser parseExpression:chunk.
-		parseTreeChunk := chunk.
-		(aParseTree notNil 
-		and:[(aParseTree ~~ #Error) 
-		and:[aParseTree isMessage]]) ifTrue:[
-		    (aParseTree selector == #removeSelector:) ifTrue:[
-			selectors at:changeNr put:(aParseTree arg1 value ).
-			classes at:changeNr put:(aParseTree receiver evaluate).
-			types at:changeNr put:#removeSelector
-		    ]
-		] ifFalse:[
-		    CompressSnapshotInfo == true ifTrue:[
-			(chunk startsWith:snapshotPrefix) ifTrue:[
-			    str := chunk readStream position:snapshotNameIndex.
-			    fileName := str upTo:(Character space).
-			    "
-			     kludge to allow use of match-check below
-			    "
-			    selectors at:changeNr put:snapshotPrefix.
-			    classes at:changeNr put:fileName.
-			]
-		    ]
-		]
-	    ].
-	    changeNr := changeNr - 1
-	].
-	aStream close.
-
-	"for all changes, look for another class/selector occurence later
-	 in the list and, if there is one, add change number to the delete set"
-
-	deleteSet := OrderedCollection new.
-	changeNr := 1.
-	[changeNr < self numberOfChanges] whileTrue:[
-	    thisClass := classes at:changeNr.
-
-	    compressThis := false.
-	    aClassNameOrNil isNil ifTrue:[
-		compressThis := true
-	    ] ifFalse:[
-		"/ skipping unloaded/unknown classes
-		thisClass isBehavior ifTrue:[
-		    thisClass isMeta ifTrue:[
-			compressThis := aClassNameOrNil = thisClass soleInstance name. 
-		    ] ifFalse:[
-			compressThis := aClassNameOrNil = thisClass name
-		    ]
-		]
-	    ].
-
-	    compressThis ifTrue:[
-		thisSelector := selectors at:changeNr.
-		searchIndex := changeNr.
-		anyMore := true.
-		[anyMore] whileTrue:[
-		    searchIndex := classes indexOf:thisClass
-					startingAt:(searchIndex + 1).
-		    (searchIndex ~~ 0) ifTrue:[
-			((selectors at:searchIndex) == thisSelector) ifTrue:[
-			    thisClass notNil ifTrue:[
-				deleteSet add:changeNr.
-				anyMore := false
-			    ]
-			]
-		    ] ifFalse:[
-			anyMore := false      
-		    ]
-		].
-	    ].
-
-	    changeNr := changeNr + 1
-	].
-
-	"finally delete what has been found"
-
-	(deleteSet size > 0) ifTrue:[
-	    changeListView setSelection:nil.
-	    index := deleteSet size.
-	    [index > 0] whileTrue:[
-		self silentDeleteChange:(deleteSet at:index).
-		index := index - 1
-	    ].
-	    self setChangeList.
-	    "
-	     scroll back a bit, if we are left way behind the list
-	    "
-	    changeListView firstLineShown > self numberOfChanges ifTrue:[
-		changeListView makeLineVisible:self numberOfChanges
-	    ].
-	    self clearCodeView
-	]
+        |numChanges classes selectors types excla sawExcla
+         changeNr chunk aParseTree parseTreeChunk
+         thisClass thisSelector codeChunk codeParser
+         compressThis|
+
+        numChanges := self numberOfChanges.
+        classes := Array new:numChanges.
+        selectors := Array new:numChanges.
+        types := Array new:numChanges.
+
+        "starting at the end, get the change class and change selector;
+         collect all in classes / selectors"
+
+        changeNr := numChanges.
+        excla := aStream class chunkSeparator.
+
+        [changeNr >= 1] whileTrue:[
+            aStream position:(changePositions at:changeNr).
+            sawExcla := aStream peekFor:excla.
+            chunk := aStream nextChunk.
+            sawExcla ifTrue:[
+                "optimize a bit if multiple methods for same category arrive"
+                (chunk = parseTreeChunk) ifFalse:[
+                    aParseTree := Parser parseExpression:chunk.
+                    parseTreeChunk := chunk
+                ].
+                (aParseTree notNil 
+                and:[(aParseTree ~~ #Error) 
+                and:[aParseTree isMessage]]) ifTrue:[
+                    (#(
+                       #methodsFor: 
+                       #privateMethodsFor:
+                       #publicMethodsFor:
+                       #ignoredMethodsFor:
+                       #protectedMethodsFor:
+                       #methodsFor:stamp:             "/ Squeak support
+                      ) 
+                    includes:aParseTree selector) ifTrue:[
+                        thisClass := (aParseTree receiver evaluate).
+                        codeChunk := aStream nextChunk.
+                        codeParser := Parser 
+                                          parseMethodSpecification:codeChunk
+                                          in:thisClass
+                                          ignoreErrors:true
+                                          ignoreWarnings:true.
+                        (codeParser notNil and:[codeParser ~~ #Error]) ifTrue:[
+                            selectors at:changeNr put:(codeParser selector).
+                            classes at:changeNr put:thisClass.
+                            types at:changeNr put:#methodsFor
+                        ]
+                    ]
+                ]
+            ] ifFalse:[
+                aParseTree := Parser parseExpression:chunk.
+                parseTreeChunk := chunk.
+                (aParseTree notNil 
+                and:[(aParseTree ~~ #Error) 
+                and:[aParseTree isMessage]]) ifTrue:[
+                    (aParseTree selector == #removeSelector:) ifTrue:[
+                        selectors at:changeNr put:(aParseTree arg1 value ).
+                        classes at:changeNr put:(aParseTree receiver evaluate).
+                        types at:changeNr put:#removeSelector
+                    ]
+                ] ifFalse:[
+                    CompressSnapshotInfo == true ifTrue:[
+                        (chunk startsWith:snapshotPrefix) ifTrue:[
+                            str := chunk readStream position:snapshotNameIndex.
+                            fileName := str upTo:(Character space).
+                            "
+                             kludge to allow use of match-check below
+                            "
+                            selectors at:changeNr put:snapshotPrefix.
+                            classes at:changeNr put:fileName.
+                        ]
+                    ]
+                ]
+            ].
+            changeNr := changeNr - 1
+        ].
+        aStream close.
+
+        "for all changes, look for another class/selector occurence later
+         in the list and, if there is one, add change number to the delete set"
+
+        deleteSet := OrderedCollection new.
+        changeNr := 1.
+        [changeNr < self numberOfChanges] whileTrue:[
+            thisClass := classes at:changeNr.
+
+            compressThis := false.
+            aClassNameOrNil isNil ifTrue:[
+                compressThis := true
+            ] ifFalse:[
+                "/ skipping unloaded/unknown classes
+                thisClass isBehavior ifTrue:[
+                    thisClass isMeta ifTrue:[
+                        compressThis := aClassNameOrNil = thisClass soleInstance name. 
+                    ] ifFalse:[
+                        compressThis := aClassNameOrNil = thisClass name
+                    ]
+                ]
+            ].
+
+            compressThis ifTrue:[
+                thisSelector := selectors at:changeNr.
+                searchIndex := changeNr.
+                anyMore := true.
+                [anyMore] whileTrue:[
+                    searchIndex := classes indexOf:thisClass
+                                        startingAt:(searchIndex + 1).
+                    (searchIndex ~~ 0) ifTrue:[
+                        ((selectors at:searchIndex) == thisSelector) ifTrue:[
+                            thisClass notNil ifTrue:[
+                                deleteSet add:changeNr.
+                                anyMore := false
+                            ]
+                        ]
+                    ] ifFalse:[
+                        anyMore := false      
+                    ]
+                ].
+            ].
+
+            changeNr := changeNr + 1
+        ].
+
+        "finally delete what has been found"
+
+        (deleteSet size > 0) ifTrue:[
+            changeListView setSelection:nil.
+            index := deleteSet size.
+            [index > 0] whileTrue:[
+                self silentDeleteChange:(deleteSet at:index).
+                index := index - 1
+            ].
+            self setChangeList.
+            "
+             scroll back a bit, if we are left way behind the list
+            "
+            changeListView firstLineShown > self numberOfChanges ifTrue:[
+                changeListView makeLineVisible:self numberOfChanges
+            ].
+            self clearCodeView
+        ]
     ].
     self newLabel:''.
 
@@ -1130,26 +2101,6 @@
     "Modified: / 29.10.1997 / 01:26:59 / cg"
 !
 
-contractClass:className selector:selector to:maxLen
-    |s l|
-
-    s := className , ' ', selector.
-    s size > maxLen ifTrue:[
-	l := maxLen - 1 - selector size max:20.
-	s := (className contractTo:l) , ' ' , selector.
-
-	s size > maxLen ifTrue:[
-	    l := maxLen - 1 - className size max:20.
-	    s := className , ' ', (selector contractTo:l).
-
-	    s size > maxLen ifTrue:[
-		s := (className contractTo:(maxLen // 2 - 1)) , ' ' , (selector contractTo:maxLen // 2)
-	    ]
-	]
-    ].
-    ^ s
-!
-
 deleteChange:changeNr
     "delete a change"
 
@@ -1173,218 +2124,6 @@
     "Modified: / 18.5.1998 / 14:22:27 / cg"
 !
 
-fullClassNameOfChange:changeNr
-    "return the full classname of a change 
-     (for classChanges (i.e. xxx class), a string ending in ' class' is returned.
-     - since parsing ascii methods is slow, keep result cached in 
-       changeClassNames for the next query"
-
-    |chunk aParseTree recTree sel name arg1Tree isMeta prevMethodDefNr
-     words changeStream fullParseTree ownerTree ownerName oldDollarSetting|
-
-    changeNr isNil ifTrue:[^ nil].
-
-    "
-     first look, if not already known
-    "
-    name := changeClassNames at:changeNr.
-    name notNil ifTrue:[^ name].
-
-    prevMethodDefNr := changeNr.
-    [changeIsFollowupMethodChange at:prevMethodDefNr] whileTrue:[
-        prevMethodDefNr := prevMethodDefNr - 1.
-    ].
-
-    "
-     get the chunk
-    "
-    chunk := changeChunks at:prevMethodDefNr.
-    chunk isNil ifTrue:[^ nil].       "mhmh - empty"
-
-    (chunk startsWith:'''---') ifTrue:[
-        words := chunk asCollectionOfWords.
-        words size > 2 ifTrue:[
-            (words at:2) = 'checkin' ifTrue:[
-                name := words at:3.
-                changeClassNames at:changeNr put:name.
-                ^ name
-            ]
-        ].
-    ].
-
-    "/ fix it - otherwise, it cannot be parsed
-    (chunk endsWith:'primitiveDefinitions:') ifTrue:[
-        chunk := chunk , ''''''
-    ].
-    (chunk endsWith:'primitiveFunctions:') ifTrue:[
-        chunk := chunk , ''''''
-    ].
-    (chunk endsWith:'primitiveVariables:') ifTrue:[
-        chunk := chunk , ''''''
-    ].
-
-    "
-     use parser to construct a parseTree
-    "
-    oldDollarSetting := Parser allowDollarInIdentifier.
-    [
-        Parser allowDollarInIdentifier:true.
-        aParseTree := Parser parseExpression:chunk.
-
-        aParseTree == #Error ifTrue:[
-            (chunk includesString:'comment') ifTrue:[
-                "/ could be a comment ...
-                aParseTree := Parser parseExpression:chunk , ''''.
-            ]
-        ].
-    ] valueNowOrOnUnwindDo:[
-        Parser allowDollarInIdentifier:oldDollarSetting
-    ].
-
-    (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
-        ^ nil        "seems strange ... (could be a comment)"
-    ].
-    aParseTree isMessage ifFalse:[
-        ^ nil        "very strange ... (whats that ?)"
-    ].
-
-    "
-     ask parser for selector
-    "
-    sel := aParseTree selector.
-    recTree := aParseTree receiver.
-
-    "
-     is it a method-change, methodRemove or comment-change ?
-    "
-    (#(#'methodsFor:' 
-       #'privateMethodsFor:' 
-       #'protectedMethodsFor:' 
-       #'ignoredMethodsFor:' 
-       #'publicMethodsFor:' 
-       #'removeSelector:' 
-       #'comment:'
-       #'primitiveDefinitions:'
-       #'primitiveFunctions:'
-       #'primitiveVariables:'
-       #'renameCategory:to:'
-       #'instanceVariableNames:'
-    ) includes:sel) ifTrue:[
-        "
-         yes, the className is the receiver
-        "
-        (recTree notNil and:[recTree ~~ #Error]) ifTrue:[
-            isMeta := false.
-            recTree isUnaryMessage ifTrue:[
-                (recTree selector ~~ #class) ifTrue:[^ nil].
-                "id class methodsFor:..."
-                recTree := recTree receiver.
-                isMeta := true.
-            ].
-            recTree isPrimary ifTrue:[
-                name := recTree name.
-                isMeta ifTrue:[
-                    name := name , ' class'.
-                ].
-                changeClassNames at:changeNr put:name.
-                ^ name
-            ]
-        ].
-        "more strange things"
-        ^ nil
-    ].
-
-    "
-     is it a change in a class-description ?
-    "
-    (('subclass:*' match:sel) 
-    or:[('variable*subclass:*' match:sel)]) ifTrue:[
-        "/ must parse the full changes text, to get
-        "/ privacy information.
-
-        changeStream := self streamForChange:changeNr.
-        changeStream notNil ifTrue:[
-            chunk := changeStream nextChunk.
-            changeStream close.
-            fullParseTree := Parser parseExpression:chunk.
-            (fullParseTree isNil or:[fullParseTree == #Error]) ifTrue:[
-                fullParseTree := nil
-            ].
-            fullParseTree isMessage ifFalse:[
-                fullParseTree := nil
-            ].
-            "/ actually, the nil case cannot happen
-            fullParseTree notNil ifTrue:[
-                aParseTree := fullParseTree.
-                sel := aParseTree selector.
-            ].
-        ].
-
-        arg1Tree := aParseTree arg1.
-        (arg1Tree notNil and:[arg1Tree isConstant]) ifTrue:[
-            name := arg1Tree value asString.
-
-            "/ is it a private-class ?
-            ('*privateIn:' match:sel) ifTrue:[
-                ownerTree := aParseTree args last.
-                ownerName := ownerTree name asString.
-                name := ownerName , '::' , name
-            ].
-            changeClassNames at:changeNr put:name.
-            ^ name
-        ].
-        "very strange"
-        ^ nil
-    ].
-
-    "
-     is it a class remove ?
-    "
-    (sel == #removeClass:) ifTrue:[
-        (recTree notNil 
-        and:[recTree ~~ #Error
-        and:[recTree isPrimary
-        and:[recTree name = 'Smalltalk']]]) ifTrue:[
-            arg1Tree := aParseTree arg1.
-            (arg1Tree notNil and:[arg1Tree isPrimary]) ifTrue:[
-                name := arg1Tree name.
-                changeClassNames at:changeNr put:name.
-                ^ name
-            ].
-        ]
-    ].
-
-    "
-     is it a method category change ?
-    "
-    ((sel == #category:)
-    or:[sel == #privacy:]) ifTrue:[
-        (recTree notNil 
-        and:[recTree ~~ #Error
-        and:[recTree isMessage
-        and:[recTree selector == #compiledMethodAt:]]]) ifTrue:[
-            isMeta := false.
-            recTree := recTree receiver.
-            recTree isUnaryMessage ifTrue:[
-                (recTree selector ~~ #class) ifTrue:[^ nil].
-                "id class "
-                recTree := recTree receiver
-            ].
-            recTree isPrimary ifTrue:[
-                isMeta ifTrue:[
-                    name := name , ' class'.
-                ].
-                name := recTree name.
-                changeClassNames at:changeNr put:name.
-                ^ name
-            ]
-        ]
-    ].
-    ^ nil
-
-    "Modified: / 3.8.1998 / 19:58:17 / cg"
-!
-
 makeChangeAPatch:changeNr
     "append change to patchfile"
 
@@ -1397,494 +2136,6 @@
     self notify:'this is not yet implemented'
 !
 
-newLabel:how
-    |l|
-
-    (changeFileName ~= 'changes') ifTrue:[
-        l := self class defaultLabel , ': ', changeFileName
-    ] ifFalse:[
-        l := self class defaultLabel
-    ].
-    l := l , ' ' , how.
-    self label:l
-
-    "Created: / 8.9.1995 / 19:32:04 / claus"
-    "Modified: / 8.9.1995 / 19:39:29 / claus"
-    "Modified: / 6.2.1998 / 13:27:01 / cg"
-!
-
-numberOfChanges
-    ^ changePositions size
-
-    "Created: 3.12.1995 / 18:15:39 / cg"
-!
-
-queryCloseText
-    "made this a method for easy redefinition in subclasses"
-
-    ^ 'Quit without updating changeFile ?'
-!
-
-readChangesFile
-    "read the changes file, create a list of header-lines (changeChunks)
-     and a list of chunk-positions (changePositions)"
-
-    ^ self readChangesFileInBackground:false
-!
-
-readChangesFileInBackground:inBackground
-    "read the changes file, create a list of header-lines (changeChunks)
-     and a list of chunk-positions (changePositions).
-     Starting with 2.10.3, the entries are multi-col entries;
-     the cols are:
-        1   delta (only if comparing)
-                '+' -> new method (w.r.t. current state)
-                '-' -> removed method (w.r.t. current state)
-                '?' -> class does not exist currently
-                '=' -> change is same as current methods source
-        2   class/selector
-        3   type of change
-                doit
-                method
-                category change
-        4   timestamp
-
-     since comparing slows down startup time, it is now disabled by
-     default and can be enabled via a toggle."
-
-    |aStream maxLen i f|
-
-    editingClassSource := false.
-
-    maxLen := 60.
-
-    f := changeFileName asFilename.
-    aStream :=  f readStream.
-    aStream isNil ifTrue:[^ nil].
-
-    self newLabel:'updating ...'.
-
-    i := f info.
-    changeFileSize := i size.
-    changeFileTimestamp := i modified.
-
-    self withReadCursorDo:[
-        |myProcess myPriority|
-
-        "
-         this is a time consuming operation (especially, if reading an
-         NFS-mounted directory; therefore lower my priority ...
-        "
-        inBackground ifTrue:[
-            myProcess := Processor activeProcess.
-            myPriority := myProcess priority.
-            myProcess priority:(Processor userBackgroundPriority).
-        ].
-
-        [
-            |excla timeStampInfo|
-
-            changeChunks := OrderedCollection new.
-            changeHeaderLines := OrderedCollection new.
-            changePositions := OrderedCollection new.
-            changeTimeStamps := OrderedCollection new.
-            changeIsFollowupMethodChange := OrderedCollection new.
-
-            excla := aStream class chunkSeparator.
-
-            [aStream atEnd] whileFalse:[
-                |entry changeDelta changeString changeType 
-                 line s l changeClass sawExcla category 
-                 chunkText chunkPos sel|
-
-                "
-                 get a chunk (separated by excla)
-                "
-                aStream skipSeparators.
-                chunkPos := aStream position.
-
-
-                sawExcla := aStream peekFor:excla.
-                chunkText := aStream nextChunk.
-                chunkText notNil ifTrue:[
-                    |index headerLine cls|
-
-                    (chunkText startsWith:'''---- timestamp ') ifTrue:[
-                        timeStampInfo := (chunkText copyFrom:16 to:(chunkText size - 6)) withoutSpaces.
-                    ] ifFalse:[
-
-                        "
-                         only first line is saved in changeChunks ...
-                        "
-                        index := chunkText indexOf:(Character cr).
-                        (index ~~ 0) ifTrue:[
-                            chunkText := chunkText copyTo:(index - 1).
-
-                            "take care for comment changes - must still be a
-                             valid expression for classNameOfChange: to work"
-
-                            (chunkText endsWith:'comment:''') ifTrue:[
-                                chunkText := chunkText , '...'''
-                            ].
-                            (chunkText endsWith:'primitiveDefinitions:''') ifTrue:[
-                                sel := 'primitiveDefinitions:'.
-                                chunkText := chunkText copyWithoutLast:1
-                            ].
-                            (chunkText endsWith:'primitiveVariables:''') ifTrue:[
-                                sel := 'primitiveVariables:'.
-                                chunkText := chunkText copyWithoutLast:1
-                            ].
-                            (chunkText endsWith:'primitiveFunctions:''') ifTrue:[
-                                sel := 'primitiveFunctions:'.
-                                chunkText := chunkText copyWithoutLast:1
-                            ].
-                        ].
-
-                        changeChunks add:chunkText.
-                        changePositions add:chunkPos.
-                        changeTimeStamps add:timeStampInfo.
-                        changeIsFollowupMethodChange add:false.
-
-                        headerLine := nil.
-                        changeDelta := ' '.
-
-                        sawExcla ifFalse:[
-                            (chunkText startsWith:'''---- snap') ifTrue:[
-                                changeType := ''.
-                                headerLine := chunkText.
-                                changeString := (chunkText contractTo:maxLen).
-                                timeStampInfo := nil.
-                            ] ifFalse:[
-
-                                |p cls clsName|
-
-                                headerLine := chunkText , ' (doIt)'.
-
-                                "
-                                 first, assume doIt - then lets have a more detailed look ...
-                                "
-                                ((chunkText startsWith:'''---- file')
-                                or:[(chunkText startsWith:'''---- check')]) ifTrue:[
-                                    changeType := ''.
-                                    timeStampInfo := nil.
-                                ] ifFalse:[
-                                    changeType := '(doIt)'.
-                                ].    
-                                changeString := (chunkText contractTo:maxLen).
-
-                                p := Parser parseExpression:chunkText inNameSpace:Smalltalk.
-                                (p notNil 
-                                 and:[p ~~ #Error
-                                 and:[p isMessage]]) ifTrue:[
-                                    sel := p selector.
-                                ] ifFalse:[
-                                    sel := nil.    
-                                ].
-                                (sel == #removeSelector:) ifTrue:[
-                                    p receiver isUnaryMessage ifTrue:[
-                                        cls := p receiver receiver name.
-                                        changeClass := (Smalltalk classNamed:cls) class.
-                                        cls := cls , ' class'.
-                                    ] ifFalse:[
-                                        cls := p receiver name.
-                                        changeClass := (Smalltalk classNamed:cls)
-                                    ].
-                                    sel := (p args at:1) evaluate.
-
-                                    compareChanges ifTrue:[
-                                        (changeClass isNil or:[changeClass isLoaded not]) ifTrue:[
-                                            changeDelta := '?'
-                                        ] ifFalse:[
-                                            (changeClass implements:sel asSymbol) ifTrue:[
-                                                changeDelta := '-'.
-                                            ] ifFalse:[
-                                                changeDelta := '='.
-                                            ]
-                                        ]
-                                    ].
-                                    changeType := '(remove)'.
-                                    changeString := self contractClass:cls selector:sel to:maxLen.
-                                ].
-                                (p ~~ #Error
-                                and:[p isMessage 
-                                and:[p receiver isMessage
-                                and:[p receiver selector == #compiledMethodAt:]]]) ifTrue:[
-                                    p receiver receiver isUnaryMessage ifTrue:[
-                                        cls := p receiver receiver receiver name.
-                                        changeClass := (Smalltalk classNamed:cls) class.
-                                        cls := cls , ' class'.
-                                    ] ifFalse:[
-                                        cls := p receiver receiver name.
-                                        changeClass := (Smalltalk classNamed:cls)
-                                    ].
-                                    (sel == #category:) ifTrue:[
-                                        sel := (p receiver args at:1) evaluate.
-                                        changeType := '(category change)'.
-                                        changeString := self contractClass:cls selector:sel to:maxLen.
-                                    ].
-                                    (sel == #privacy:) ifTrue:[
-                                        sel := (p receiver args at:1) evaluate.
-                                        changeType := '(privacy change)'.
-                                        changeString := self contractClass:cls selector:sel to:maxLen.
-                                    ].
-                                ].
-                                (#(#'subclass:'
-                                  #'variableSubclass:'
-                                  #'variableByteSubclass:'
-                                  #'variableWordSubclass:'
-                                  #'variableLongSubclass:'
-                                  #'variableFloatSubclass:'
-                                  #'variableDoubleSubclass:'
-                                  #'primitiveDefinitions:'
-                                  #'primitiveFunctions:'
-                                  #'primitiveVariables:'
-                                 ) includes:sel) ifTrue:[
-                                    changeType := '(class definition)'.
-                                    clsName := (p args at:1) evaluate.
-                                    cls := Smalltalk at:clsName ifAbsent:nil.
-                                    cls isNil ifTrue:[
-                                        changeDelta := '+'.
-                                    ]
-                                ].
-                            ]
-                        ] ifTrue:[ "sawExcla"
-                            |done first p className cls text methodPos|
-
-                            "
-                             method definitions actually consist of
-                             two (or more) chunks; skip next chunk(s)
-                             up to an empty one.
-                             The system only writes one chunk,
-                             and we cannot handle more in this ChangesBrowser ....
-                            "
-                            className := nil.
-                            p := Parser parseExpression:chunkText inNameSpace:Smalltalk.
-
-                            (p notNil and:[p ~~ #Error]) ifTrue:[
-                                sel := p selector.
-                                (sel == #methodsFor:) ifTrue:[
-                                    p receiver isUnaryMessage ifTrue:[
-                                        className := p receiver receiver name.
-                                        changeClass := (Smalltalk classNamed:className) class.
-                                        className := className , ' class'.
-                                    ] ifFalse:[
-                                        className := p receiver name.
-                                        changeClass := Smalltalk classNamed:className
-                                    ].
-                                    category := (p args at:1) evaluate.
-                                ].
-                            ].
-
-                            done := false.
-                            first := true.
-                            [done] whileFalse:[
-                                changeDelta := ' '.
-                                methodPos := aStream position.
-
-                                text := aStream nextChunk.
-                                text isNil ifTrue:[
-                                    done := true
-                                ] ifFalse:[
-                                    done := text isEmpty
-                                ].
-                                done ifFalse:[
-                                    first ifFalse:[
-                                        changeChunks add:chunkText.
-                                        changePositions add:methodPos.
-                                        changeTimeStamps add:timeStampInfo.
-                                        changeIsFollowupMethodChange add:true.
-                                        editingClassSource := true.
-                                    ].
-
-                                    first := false.
-                                    "
-                                     try to find the selector
-                                    "
-                                    sel := nil.
-                                    className notNil ifTrue:[
-                                        p := Parser 
-                                                 parseMethodSpecification:text
-                                                 in:nil
-                                                 ignoreErrors:true
-                                                 ignoreWarnings:true.
-                                        (p notNil and:[p ~~ #Error]) ifTrue:[
-                                            sel := p selector.
-                                        ]
-                                    ].
-
-                                    sel isNil ifTrue:[
-                                        changeString := (chunkText contractTo:maxLen).
-                                        changeType := '(change)'.
-                                        headerLine := chunkText , ' (change)'.
-                                    ] ifFalse:[
-                                        changeString :=  self contractClass:className selector:sel to:maxLen.
-                                        changeType := '(method in: ''' , category , ''')'.
-                                        headerLine := className , ' ' , sel , ' ' , '(change category: ''' , category , ''')'.
-                                    ].
-
-                                    compareChanges ifTrue:[ 
-                                        changeClass isNil ifFalse:[
-                                            changeClass isMeta ifTrue:[
-                                                cls := changeClass soleInstance
-                                            ] ifFalse:[
-                                                cls := changeClass
-                                            ].
-                                        ].
-
-                                        (changeClass isNil or:[cls isLoaded not]) ifTrue:[
-                                            changeDelta := '?'
-                                        ] ifFalse:[
-                                            (changeClass implements:sel asSymbol) ifFalse:[
-                                                changeDelta := '+'.
-                                            ] ifTrue:[
-                                                |m currentText t1 t2|
-
-                                                m := changeClass compiledMethodAt:sel asSymbol.
-                                                currentText := m source.
-                                                currentText notNil ifTrue:[
-                                                    text asString = currentText asString ifTrue:[
-                                                        changeDelta := '='
-                                                    ] ifFalse:[
-                                                        t1 := currentText asCollectionOfLines collect:[:s | s withTabsExpanded].
-                                                        t2 := text asCollectionOfLines collect:[:s | s withTabsExpanded].
-                                                        t1 = t2 ifTrue:[
-                                                            changeDelta := '='
-                                                        ]
-                                                    ]
-                                                ]
-                                            ]
-                                        ]
-                                    ].
-                                    entry := MultiColListEntry new.
-                                    entry tabulatorSpecification:tabSpec.
-                                    entry colAt:1 put:changeDelta.
-                                    entry colAt:2 put:changeString.
-                                    entry colAt:3 put:changeType.
-                                    timeStampInfo notNil ifTrue:[
-                                        entry colAt:4 put:timeStampInfo.
-                                    ].    
-                                    changeHeaderLines add:entry
-                                ].
-                                changeString := nil.
-                                headerLine := nil.
-
-                            ]
-                        ].
-                        changeString notNil ifTrue:[
-                            entry := MultiColListEntry new.
-                            entry tabulatorSpecification:tabSpec.
-                            entry colAt:1 put:changeDelta.
-                            entry colAt:2 put:changeString.
-                            entry colAt:3 put:changeType.
-                            timeStampInfo notNil ifTrue:[
-                                entry colAt:4 put:timeStampInfo.
-                            ].    
-                            changeHeaderLines add:entry
-                        ] ifFalse:[
-                            headerLine notNil ifTrue:[
-                                changeHeaderLines add:headerLine
-                            ]
-                        ]
-                    ]
-                ]
-            ].
-            changeClassNames := OrderedCollection new grow:(changeChunks size).
-            anyChanges := false
-        ] valueNowOrOnUnwindDo:[
-            aStream close.
-            inBackground ifTrue:[myProcess priority:myPriority].
-        ].
-    ].
-
-    self checkIfFileHasChanged
-
-    "Modified: / 27.8.1995 / 23:06:55 / claus"
-    "Modified: / 17.7.1998 / 11:10:07 / cg"
-!
-
-selectorOfMethodChange:changeNr
-    "return a method-changes selector, or nil if its not a methodChange"
-
-    |source parser sel chunk aParseTree |
-
-    source := self sourceOfMethodChange:changeNr.
-    source isNil ifTrue:[
-        (self classNameOfChange:changeNr) notNil ifTrue:[
-            chunk := changeChunks at:changeNr.
-            chunk isNil ifTrue:[^ nil].       "mhmh - empty"
-            aParseTree := Parser parseExpression:chunk.
-            (aParseTree isNil or:[aParseTree == #Error]) ifTrue:[
-                ^ nil        "seems strange ... (could be a comment)"
-            ].
-            aParseTree isMessage ifFalse:[
-                ^ nil        "very strange ... (whats that ?)"
-            ].
-            sel := aParseTree selector.
-            (#(
-                #'removeSelector:' 
-            ) includes:sel) ifTrue:[
-                sel := aParseTree arguments at:1.
-                sel isConstant ifTrue:[
-                    sel := sel evaluate.
-                    sel isSymbol ifTrue:[
-                        ^ sel
-                    ]
-                ]
-            ]
-        ].
-        ^ nil
-    ].
-
-
-    parser := Parser 
-                parseMethodArgAndVarSpecification:source
-                in:nil 
-                ignoreErrors:true
-                ignoreWarnings:true
-                parseBody:false.
-
-"/    parser := Parser 
-"/                parseMethod:source 
-"/                in:nil 
-"/                ignoreErrors:true 
-"/                ignoreWarnings:true.
-
-    (parser notNil and:[parser ~~ #Error]) ifTrue:[
-        sel := parser selector.
-    ].
-    ^ sel
-
-    "Created: 24.11.1995 / 14:30:46 / cg"
-    "Modified: 5.9.1996 / 17:12:50 / cg"
-!
-
-setChangeList
-    "extract type-information from changes and stuff into top selection
-     view"
-
-    changeListView setList:changeHeaderLines expandTabs:false redraw:false.
-    changeListView invalidate.
-
-    "/ changeListView deselect.
-
-    "Modified: / 18.5.1998 / 14:29:10 / cg"
-!
-
-showNotFound
-    |savedCursor|
-
-    savedCursor := cursor.
-    [
-        self cursor:(Cursor cross).
-        self beep.
-        Delay waitForMilliseconds:300.
-    ] valueNowOrOnUnwindDo:[
-        self cursor:savedCursor
-    ]
-
-    "Modified: / 29.4.1999 / 22:36:54 / cg"
-!
-
 silentDeleteChange:changeNr
     "delete a change do not update changeListView"
 
@@ -1930,181 +2181,6 @@
     "Created: / 7.3.1997 / 16:28:32 / cg"
     "Modified: / 7.2.1998 / 19:59:11 / cg"
     "Modified: / 26.2.1998 / 18:20:48 / stefan"
-!
-
-sourceOfMethodChange:changeNr
-    "return a method-changes source code, or nil if its not a methodChange."
-
-    |aStream chunk sawExcla parseTree sourceChunk|
-
-    aStream := self streamForChange:changeNr.
-    aStream isNil ifTrue:[^ nil].
-
-    (self changeIsFollowupMethodChange:changeNr) ifFalse:[
-        sawExcla := aStream peekFor:(aStream class chunkSeparator).
-        chunk := aStream nextChunk.
-    ] ifTrue:[
-        chunk := (changeChunks at:changeNr).
-        sawExcla := true.
-    ].
-
-    sawExcla ifTrue:[
-        parseTree := Parser parseExpression:chunk.
-        (parseTree notNil and:[parseTree isMessage]) ifTrue:[
-            (#(#methodsFor: 
-               #privateMethodsFor:
-               #publicMethodsFor:
-               #ignoredMethodsFor:
-               #protectedMethodsFor:) 
-            includes:parseTree selector) ifTrue:[
-                sourceChunk := aStream nextChunk.
-            ]
-        ].
-    ].
-    aStream close.
-    ^ sourceChunk
-
-    "Created: / 5.9.1996 / 17:11:32 / cg"
-    "Modified: / 3.8.1998 / 20:00:21 / cg"
-!
-
-streamForChange:changeNr
-    "answer a stream for change"
- 
-    |aStream|
-
-    (changeNr between:1 and:changePositions size) ifFalse:[^ nil].
-    aStream := FileStream readonlyFileNamed:changeFileName.
-    aStream isNil ifTrue:[^ nil].
-    aStream position:(changePositions at:changeNr).
-    ^ aStream
-!
-
-unselect
-    "common unselect"
-
-    changeListView setSelection:nil.
-
-    "Modified: 25.5.1996 / 13:02:49 / cg"
-!
-
-withSelectedChangeDo:aBlock
-    "just a helper, check for a selected change and evaluate aBlock
-     with busy cursor"
-
-    |changeNr|
-
-    changeNr := changeListView selection.
-    changeNr notNil ifTrue:[
-	self withExecuteCursorDo:[
-	    aBlock value:changeNr
-	]
-    ]
-
-    "Modified: 14.12.1995 / 20:58:45 / cg"
-!
-
-writeBackChanges
-    "write back the changes file. To avoid problems when the disk is full
-     or a crash occurs while writing (well, or someone kills us), 
-     first write the stuff to a new temporary file. If this works ok,
-     rename the old change-file to a .bak file and finally rename the
-     tempfile back to the change-file. 
-     That way, if anything happens, either the original file is left unchanged,
-     or we have at least a backup of the previous change file."
-
-    |inStream outStream tempfile stamp f|
-
-    editingClassSource ifTrue:[
-        (self confirm:'You are editing a classes sourceFile (not a changeFile) !!\\Are you certain, you want to overwrite it ?' withCRs)
-        ifFalse:[
-            ^ false
-        ]
-    ].
-
-    tempfile := Filename newTemporaryIn:nil.
-    tempfile exists ifTrue:[tempfile remove].
-
-    outStream := tempfile writeStream.
-    outStream isNil ifTrue:[
-        self warn:'cannot create temporary file in current directory.'.
-        ^ false
-    ].
-
-    inStream := FileStream readonlyFileNamed:changeFileName.
-    inStream isNil ifTrue:[^ false].
-
-    self withCursor:(Cursor write) do:[
-        |excla sawExcla done first chunk
-         nChanges "{Class:SmallInteger}" |
-
-        Stream writeErrorSignal handle:[:ex |
-            self warn:('could not update the changes file.\\' , ex errorString) withCRs.
-            tempfile exists ifTrue:[tempfile remove].
-            ^ false
-        ] do:[
-
-            excla := inStream class chunkSeparator.
-            nChanges := self numberOfChanges.
-
-            1 to:nChanges do:[:index |
-                inStream position:(changePositions at:index).
-                sawExcla := inStream peekFor:excla.
-                chunk := inStream nextChunk.
-
-                (chunk notNil
-                and:[(chunk startsWith:'''---- snap') not]) ifTrue:[
-                    (stamp := changeTimeStamps at:index) notNil ifTrue:[
-                        outStream nextPutAll:'''---- timestamp ' , stamp , ' ----'''.
-                        outStream nextPut:excla; cr.
-                    ].
-                ].
-
-                sawExcla ifTrue:[
-                    outStream nextPut:excla.
-                    outStream nextChunkPut:chunk.
-                    outStream cr; cr.
-                    "
-                     a method-definition chunk - output followups
-                    "
-                    done := false.
-                    first := true.
-                    [done] whileFalse:[
-                        chunk := inStream nextChunk.
-                        chunk isNil ifTrue:[
-                            outStream cr; cr.
-                            done := true
-                        ] ifFalse:[
-                            chunk isEmpty ifTrue:[
-                                outStream space; nextChunkPut:chunk; cr; cr.
-                                done := true.
-                            ] ifFalse:[
-                                first ifFalse:[
-                                    outStream cr; cr.
-                                ].
-                                outStream nextChunkPut:chunk.
-                            ].
-                        ].
-                        first := false.
-                    ].
-                ] ifFalse:[
-                    outStream nextChunkPut:chunk.
-                    outStream cr
-                ]
-            ].
-            outStream close.
-            inStream close.
-        ].
-
-        f := changeFileName asFilename.
-        f renameTo:(f withSuffix:'bak').
-        tempfile renameTo:changeFileName.
-        anyChanges := false
-    ].
-    ^ true
-
-    "Modified: / 2.12.1996 / 22:29:15 / stefan"
-    "Modified: / 21.4.1998 / 17:50:11 / cg"
 ! !
 
 !ChangesBrowser methodsFor:'termination'!
@@ -2985,5 +3061,5 @@
 !ChangesBrowser class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libtool/ChangesBrowser.st,v 1.155 1999-06-26 16:30:54 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libtool/ChangesBrowser.st,v 1.156 1999-07-15 14:45:31 cg Exp $'
 ! !