ChangeSorter: bug or feature?
frits.swinkels
frits.swinkels at shaw.ca
Tue Feb 3 04:06:44 UTC 2004
Attached is a change set which fixes the display of (old) code in the
ChangeSorter, the DualChangeSorter and -by inheritance- the
ChangeSetBrowser (called by CTL-B on the chandesorter menu). As well,
one can file out the actual contents of a Changeset. It does not fix the
message set browser called by CTL-b.
A note on implementation: the original implementation seemed to use
setContents to set contents;) and selectedMethod to respond to changed.
A override selectedMethod gets the real code. It is inserted into
setContents at the proper spot.
ChangeSorter was on the steppingList, courtesy of the codeHolder. It was
scanning for any possible change of the source of a method. That does
not make sense if we are trying to keep the old code: stepping code made
vacuous.
The way I tested this was as follows: before filing in the attached
change set, I created a change set called OldChangeset. I put the
ChangeSet class and ChangeSorter into this and filed it out. I then
looked at the ChangeSorterFixes with the File Contents Browser (lovely
tool that!) and filed it in. A dual change sorter then lets you look at
methods on both sides; I did not figure out how to diff them.
Finally, I considered making this effort a ChangeSorter subclass,
something like ImmutableChangeSorter. The problem is that I had to touch
other classes, i.e. ChangeSet, because ChangeSorter delegates some
copying and fileOut there.
Try it and tell me if an obvious angle was missed. Perhaps that is why
Roel Wuyts developed his SystemChangeNotification after what he called
"visiting the dark sides of Squeak";)
On Fri, 2004-01-23 at 05:43, C. David Shaffer wrote:
> Doug Way wrote:
>
> >
> > It would be interesting to "fix" the ChangeSorters so that they show
> > the original source from the changesets. It is true though that
> > everyone has gotten used to the ChangeSorters showing the current
> > code, so there would have to be some getting used to the new behavior.
> >
> > - Doug
>
>
> No, at least not everyone :-) I would love to see the suggested change
> to the ChangeSorters.
>
> --
> C. David Shaffer
> http://www.shaffer-consulting.com
>
>
>
-------------- next part --------------
'From Squeak3.6 of ''6 October 2003'' [latest update: #5429] on 31 January 2004 at 12:13:34 pm'!
!ChangeSet methodsFor: '*CSFixes' stamp: 'gms 1/26/2004 13:16'!
compiledMethodAtReference: methodReference
|classCgh methChg meth|
classCgh _ self changeRecords at: methodReference actualClass name ifAbsent:[^nil].
methChg _ classCgh methodChanges at: methodReference methodSymbol ifAbsent:[^nil].
methChg hasBeenRemoved ifTrue:[^nil].
meth _ methChg currentMethod.
meth ifNil:[^nil].
^meth
! !
!ChangeSet methodsFor: 'fileIn/Out' stamp: 'gms 1/23/2004 11:39'!
fileOutChangesFor: class on: stream
"Write out all the method changes for this class."
| changes |
changes _ Set new.
(self methodChangesAtClass: class name) associationsDo:
[:mAssoc | (mAssoc value = #remove or: [mAssoc value = #addedThenRemoved])
ifFalse: [changes add: mAssoc key]].
self fileOutChangedMessages: changes for: class on: stream .! !
!ChangeSet methodsFor: 'moving changes' stamp: 'gms 1/21/2004 11:13'!
absorbMethod: selector class: aClass from: aChangeSet
"Absorb a copy into the receiver all the changes for the method in the
class in the other change set."
(self changeRecorderFor: aClass) methodChanges
at: selector
put: ((aChangeSet changeRecords at: aClass name) methodChanges at: selector) copy! !
!ChangeSet methodsFor: '*CSFixes' stamp: 'gms 1/23/2004 09:02'!
sourceCodeAtReference: methodReference
|temp|
temp _ self compiledMethodAtReference: methodReference.
temp ifNil: [^nil].
^temp getSource! !
!ChangeSet methodsFor: 'fileIn/Out' stamp: 'gms 1/23/2004 12:40'!
fileOutChangedMessages: changes for: class on: outStream
"Write out all the method changes for this class."
"Derived from ClassDescription>>printMethodChunk:withPreamble:on:moveSource:toFile:"
"Files out the source code defined in the changeSet itself."
| methodPreamble method oldPos sourceFile |
changes do:[:selector|
methodPreamble _ class name , ' methodsFor: ' ,
(class organization categoryOfElement: selector) asString printString.
method _ self compiledMethodAtReference: (MethodReference new setStandardClass: class methodSymbol: selector).
((method fileIndex = 0
or: [(SourceFiles at: method fileIndex) == nil])
or: [(oldPos _ method filePosition) = 0])
ifTrue:
["The source code is not accessible. We must decompile..."
methodPreamble size > 0 ifTrue: [outStream cr; nextPut: $!!; nextChunkPut: methodPreamble; cr].
outStream nextChunkPut: (class decompilerClass new decompile: selector
in: class method: method) decompileString]
ifFalse:
[sourceFile _ SourceFiles at: method fileIndex.
sourceFile position: oldPos.
methodPreamble size > 0 ifTrue: "Copy the methodPreamble"
[outStream copyPreamble: methodPreamble from: sourceFile].
outStream copyMethodChunkFrom: sourceFile.
sourceFile skipSeparators. "The following chunk may have style"
sourceFile peek == $] ifTrue: [
outStream cr; copyMethodChunkFrom: sourceFile]].
methodPreamble size > 0 ifTrue: [outStream nextChunkPut: ' '].
outStream cr.].
outStream cr.
! !
!ChangeSet methodsFor: 'accessing' stamp: 'gms 1/20/2004 13:49'!
changeRecords
^changeRecords! !
!ChangeSet methodsFor: 'accessing' stamp: 'gms 1/20/2004 13:49'!
changeRecords: anObject
changeRecords := anObject! !
!ClassChangeRecord methodsFor: 'all changes' stamp: 'gms 1/27/2004 09:12'!
assimilateAllChangesIn: otherRecord
| selector changeRecord changeType |
otherRecord isClassRemoval ifTrue: [^ self noteChangeType: #remove].
otherRecord allChangeTypes do:
[:chg | self noteChangeType: chg fromClass: self realClass].
otherRecord methodChanges associationsDo:
[:assn | selector _ assn key. changeRecord _ assn value.
changeType _ changeRecord changeType.
(changeType == #remove or: [changeType == #addedThenRemoved])
ifTrue:
[changeType == #addedThenRemoved
ifTrue: [self methodChanges at: selector put: changeRecord copy.
self atSelector: selector put: #add].
self noteRemoveSelector: selector priorMethod: nil
lastMethodInfo: changeRecord methodInfoFromRemoval]
ifFalse:
[self methodChanges at: selector put: changeRecord copy]].
! !
!CodeHolder methodsFor: 'annotation' stamp: 'gms 1/20/2004 18:30'!
annotationForSelector: aSelector ofClass: aClass
"Provide a line of content for an annotation pane, representing
information about the given selector and class"
| stamp sendersCount implementorsCount aCategory separator aString aList aComment aStream requestList isLoaded |
aSelector == #Comment
ifTrue: [^ self annotationForClassCommentFor: aClass].
aSelector == #Definition
ifTrue: [^ self annotationForClassDefinitionFor: aClass].
aSelector == #Hierarchy
ifTrue: [^ self annotationForHierarchyFor: aClass].
aStream _ ReadWriteStream on: ''.
requestList _ self annotationRequests.
separator _ requestList size > 1
ifTrue: [self annotationSeparator]
ifFalse: [''].
requestList
do: [:aRequest |
aRequest == #firstComment
ifTrue: [aComment _ aClass firstCommentAt: aSelector.
aComment isEmptyOrNil
ifFalse: [aStream nextPutAll: aComment , separator]].
aRequest == #masterComment
ifTrue: [aComment _ aClass supermostPrecodeCommentFor: aSelector.
aComment isEmptyOrNil
ifFalse: [aStream nextPutAll: aComment , separator]].
aRequest == #documentation
ifTrue: [aComment _ aClass precodeCommentOrInheritedCommentFor: aSelector.
aComment isEmptyOrNil
ifFalse: [aStream nextPutAll: aComment , separator]].
aRequest == #timeStamp
ifTrue: [stamp _ self timeStamp.
isLoaded _ self isCurrentlyLoaded ifTrue:['*', separator] ifFalse:[''].
aStream
nextPutAll: (stamp size > 0
ifTrue: [isLoaded, stamp , separator]
ifFalse: [isLoaded, 'no timeStamp' , separator])].
aRequest == #messageCategory
ifTrue: [aCategory _ aClass organization categoryOfElement: aSelector.
aCategory
ifNotNil: ["woud be nil for a method no longer present,
e.g. in a recent-submissions browser"
aStream nextPutAll: aCategory , separator]].
aRequest == #sendersCount
ifTrue: [sendersCount _ (self systemNavigation allCallsOn: aSelector) size.
sendersCount _ sendersCount == 1
ifTrue: ['1 sender']
ifFalse: [sendersCount printString , ' senders'].
aStream nextPutAll: sendersCount , separator].
aRequest == #implementorsCount
ifTrue: [implementorsCount _ self systemNavigation numberOfImplementorsOf: aSelector.
implementorsCount _ implementorsCount == 1
ifTrue: ['1 implementor']
ifFalse: [implementorsCount printString , ' implementors'].
aStream nextPutAll: implementorsCount , separator].
aRequest == #priorVersionsCount
ifTrue: [self
addPriorVersionsCountForSelector: aSelector
ofClass: aClass
to: aStream].
aRequest == #priorTimeStamp
ifTrue: [stamp _ VersionsBrowser
timeStampFor: aSelector
class: aClass
reverseOrdinal: 2.
stamp
ifNotNil: [aStream nextPutAll: 'prior time stamp: ' , stamp , separator]].
aRequest == #recentChangeSet
ifTrue: [aString _ ChangeSorter mostRecentChangeSetWithChangeForClass: aClass selector: aSelector.
aString size > 0
ifTrue: [aStream nextPutAll: aString , separator]].
aRequest == #allChangeSets
ifTrue: [aList _ ChangeSorter allChangeSetsWithClass: aClass selector: aSelector.
aList size > 0
ifTrue: [aList size = 1
ifTrue: [aStream nextPutAll: 'only in change set ']
ifFalse: [aStream nextPutAll: 'in change sets: '].
aList
do: [:aChangeSet | aStream nextPutAll: aChangeSet name , ' ']]
ifFalse: [aStream nextPutAll: 'in no change set'].
aStream nextPutAll: separator]].
^ aStream contents! !
!CodeHolder methodsFor: '*CSFixes' stamp: 'gms 1/26/2004 15:19'!
isCurrentlyLoaded
"Is the method referred to by the selection currently loaded into the image?"
| class selector methodRef methodInImage|
class _ self selectedClassOrMetaClass.
(class isNil or: [(selector _ self selectedMessageName) isNil]) ifTrue: [^ false].
methodRef _ MethodReference new setStandardClass: class methodSymbol: selector.
methodInImage _ methodRef asCompiledMethod.
methodInImage ifNil:[^false].
currentCompiledMethod ifNil:[^false].
^currentCompiledMethod == methodInImage! !
!ChangeSorter methodsFor: 'changeSet menu' stamp: 'gms 1/27/2004 09:36'!
fileOutMessage
"Put a description of the selected message on a file"
| aClass selector nameBody fileStream |
self selectedMessageName ifNotNil:
[Cursor write showWhile:
[
aClass _ self selectedClassOrMetaClass.
selector _self selectedMessageName.
(selector == #Comment) ifTrue: [^ self inform: 'Sorry, cannot file out class comment in isolation.'].
(aClass includesSelector: selector) ifFalse: [^ self error: 'Selector ', selector asString, ' not found'].
nameBody _ aClass name , '-' , (selector copyReplaceAll: ':' with: '').
fileStream _ FileStream newFileNamed: nameBody , '.st'.
fileStream header; timeStamp.
myChangeSet fileOutChangedMessages: {selector} for: aClass on: fileStream.
fileStream close]]! !
!ChangeSorter methodsFor: 'as yet unclassified' stamp: 'gms 1/31/2004 07:25'!
wantsStepsIn: aWindow
^ false! !
!ChangeSorter methodsFor: 'code pane' stamp: 'gms 1/31/2004 08:43'!
setContents
"return the source code that shows in the bottom pane"
| sel class strm changeType |
self clearUserEditFlag.
currentClassName ifNil: [^ contents _ myChangeSet preambleString ifNil: ['']].
class _ self selectedClassOrMetaClass.
(sel _ currentSelector) == nil
ifFalse: [changeType _ (myChangeSet atSelector: (sel _ sel asSymbol) class: class).
changeType == #remove
ifTrue: [^ contents _ 'Method has been removed (see versions)'].
changeType == #addedThenRemoved
ifTrue: [^ contents _ 'Added then removed (see versions)'].
class ifNil: [^ contents _ 'Method was added, but cannot be found!!'].
(class includesSelector: sel)
ifFalse: [^ contents _ 'Method was added, but cannot be found!!'].
"contents _ class sourceCodeAt: sel. this is the source currently in the image"
contents _ self selectedMessage.
(#(prettyPrint colorPrint prettyDiffs altSyntax) includes: contentsSymbol) ifTrue:
[contents _ class compilerClass new
format: contents in: class notifying: nil contentsSymbol: contentsSymbol].
self showingAnyKindOfDiffs
ifTrue: [contents _ self diffFromPriorSourceFor: contents].
^ contents _ contents asText makeSelectorBoldIn: class]
ifTrue: [strm _ WriteStream on: (String new: 100).
(myChangeSet classChangeAt: currentClassName) do:
[:each |
each = #remove ifTrue: [strm nextPutAll: 'Entire class was removed.'; cr].
each = #addedThenRemoved ifTrue: [strm nextPutAll: 'Class was added then removed.'].
each = #rename ifTrue: [strm nextPutAll: 'Class name was changed.'; cr].
each = #add ifTrue: [strm nextPutAll: 'Class definition was added.'; cr].
each = #change ifTrue: [strm nextPutAll: 'Class definition was changed.'; cr].
each = #reorganize ifTrue: [strm nextPutAll: 'Class organization was changed.'; cr].
each = #comment ifTrue: [strm nextPutAll: 'New class comment.'; cr.
]].
^ contents _ strm contents].! !
!ChangeSorter methodsFor: 'annotation' stamp: 'gms 1/20/2004 17:38'!
timeStamp
currentCompiledMethod ifNil:[^''].
^currentCompiledMethod timeStamp asString! !
!ChangeSorter methodsFor: 'code pane' stamp: 'gms 1/31/2004 07:29'!
stepIn: aSystemWindow
! !
!ChangeSorter methodsFor: 'message list' stamp: 'gms 1/31/2004 08:41'!
selectedMessage
| class selector methodRef |
class _ self selectedClassOrMetaClass.
(class isNil or: [(selector _ self selectedMessageName) isNil]) ifTrue: [^ ''].
methodRef _ MethodReference new setStandardClass: class methodSymbol: selector.
currentCompiledMethod _ myChangeSet compiledMethodAtReference: methodRef.
currentCompiledMethod ifNil:[^''].
contents _ myChangeSet sourceCodeAtReference: methodRef.
contents ifNil:[^''].
^contents _ contents copy asText makeSelectorBoldIn: class.! !
!MethodChangeRecord methodsFor: 'as yet unclassified' stamp: 'gms 1/23/2004 09:09'!
hasBeenRemoved
^ (changeType == #remove or: [changeType == #addedThenRemoved])! !
!MethodReference methodsFor: '*CSFixes' stamp: 'gms 1/20/2004 18:16'!
asCompiledMethod
^self actualClass compiledMethodAt: self methodSymbol ifAbsent: [nil]! !
!MethodReference reorganize!
('queries' actualClass asStringOrText classIsMeta classSymbol isValid methodSymbol printOn:)
('setting' setClass:methodSymbol:stringVersion: setClassAndSelectorIn: setClassSymbol:classIsMeta:methodSymbol:stringVersion: setStandardClass:methodSymbol:)
('string version' stringVersion stringVersion:)
('comparisons' <= =)
('*packageinfo')
('*packageinfo-base' category sourceCode)
('*CSFixes' asCompiledMethod)
('*ma base additions' maActualMethod)
('*RA-modification' hash)
!
!CodeHolder reorganize!
('annotation' addOptionalAnnotationsTo:at:plus: addPriorVersionsCountForSelector:ofClass:to: annotation annotationForClassCommentFor: annotationForClassDefinitionFor: annotationForHierarchyFor: annotationForSelector:ofClass: annotationPaneMenu:shifted: annotationRequests annotationSeparator defaultAnnotationPaneHeight defaultButtonPaneHeight)
('categories' categoryOfCurrentMethod changeCategory methodCategoryChanged selectedMessageCategoryName)
('contents' commentContents contents contentsChanged contentsSymbol contentsSymbol:)
('commands' abbreviatedWordingFor: adoptMessageInCurrentChangeset browseImplementors browseSenders copyUpOrCopyDown makeSampleInstance offerMenu offerShiftedClassListMenu offerUnshiftedClassListMenu removeClass shiftedYellowButtonActivity showUnreferencedClassVars showUnreferencedInstVars spawnFullProtocol spawnProtocol spawnToCollidingClass: unshiftedYellowButtonActivity)
('construction' addLowerPanesTo:at:with: buildMorphicCodePaneWith:)
('controls' addOptionalButtonsTo:at:plus: buttonWithSelector: codePaneProvenanceButton codePaneProvenanceString contentsSymbolQuints decorateButtons decorateForInheritance inheritanceButton optionalButtonPairs optionalButtonRow sourceAndDiffsQuintsOnly)
('diffs' defaultDiffsSymbol diffButton diffFromPriorSourceFor: prettyDiffButton regularDiffButton restoreTextualCodingPane showDiffs showDiffs: showPrettyDiffs: showRegularDiffs: showingAnyKindOfDiffs showingDiffsString showingPrettyDiffs showingPrettyDiffsString showingRegularDiffs showingRegularDiffsString toggleColorPrint toggleDiff toggleDiffing togglePlainSource togglePrettyDiffing togglePrettyPrint toggleRegularDiffing wantsDiffFeedback)
('misc' getSelectorAndSendQuery:to: getSelectorAndSendQuery:to:with: isThereAnOverride isThisAnOverride menuButton modelWakeUpIn: okayToAccept priorSourceOrNil refreshAnnotation refusesToAcceptCode releaseCachedState sampleInstanceOfSelectedClass sendQuery:to: setClassAndSelectorIn: suggestCategoryToSpawnedBrowser: useSelector:orGetSelectorAndSendQuery:to:)
('self-updating' didCodeChangeElsewhere stepIn: updateCodePaneIfNeeded updateListsAndCodeIn: wantsStepsIn:)
('what to show' addContentsTogglesTo: colorPrintString offerWhatToShowMenu prettyPrintString setContentsToForceRefetch showAltSyntax: showByteCodes: showComment showDecompile: showDocumentation: showingAltSyntax showingAltSyntaxString showingByteCodes showingByteCodesString showingColorPrint showingDecompile showingDecompileString showingDocumentation showingDocumentationString showingPlainSource showingPlainSourceString showingPrettyPrint showingSource toggleAltSyntax toggleDecompile toggleShowDocumentation toggleShowingByteCodes)
('tiles' addModelItemsToWindowMenu: installTextualCodingPane installTilesForSelection showTiles: showingTiles showingTilesString toggleShowingTiles)
('categories & search pane' listPaneWithSelector: newSearchPane searchPane textPaneWithSelector:)
('message list' decompiledSourceIntoContents selectedBytecodes selectedMessage sourceStringPrettifiedAndDiffed validateMessageSource:forSelector:)
('message list menu' messageListKey:from:)
('message category functions' canShowMultipleMessageCategories)
('*Refactory-RBExternalBrowserReferences' buildClassBrowserEditString: spawn: spawnHierarchy spawnToClass:)
('*CSFixes' isCurrentlyLoaded)
!
More information about the Squeak-dev
mailing list
|