diff --git a/packages/Sandblocks-Babylonian/SBActiveVariantPermutation.class.st b/packages/Sandblocks-Babylonian/SBActiveVariantPermutation.class.st new file mode 100644 index 00000000..ddd9dd5d --- /dev/null +++ b/packages/Sandblocks-Babylonian/SBActiveVariantPermutation.class.st @@ -0,0 +1,5 @@ +Class { + #name : #SBActiveVariantPermutation, + #superclass : #ProcessLocalVariable, + #category : #'Sandblocks-Babylonian' +} diff --git a/packages/Sandblocks-Babylonian/SBExample.class.st b/packages/Sandblocks-Babylonian/SBExample.class.st index 3a301e2b..fa241a6e 100644 --- a/packages/Sandblocks-Babylonian/SBExample.class.st +++ b/packages/Sandblocks-Babylonian/SBExample.class.st @@ -17,12 +17,6 @@ Class { #category : #'Sandblocks-Babylonian' } -{ #category : #'as yet unclassified' } -SBExample class >> getAllInMethod: aBlock [ - - ^ aBlock body childSandblocks select: #isExample -] - { #category : #'as yet unclassified' } SBExample class >> instanceSuggestion [ @@ -46,6 +40,12 @@ SBExample class >> matches: aMessage [ and: [#('example:args:label:' 'example:args:label:assert:') includes: aMessage selector]] ] +{ #category : #constants } +SBExample class >> matchingSelectors [ + + ^ #(#self:args:label: #self:args:label:assert: #example:args:label: #example:args:label:assert:) +] + { #category : #'as yet unclassified' } SBExample class >> newFor: aMessage [ @@ -368,15 +368,8 @@ SBExample >> providesExecutionEnvironment [ { #category : #'as yet unclassified' } SBExample >> run [ - self containingArtefact valid ifFalse: [^ self]. - processRunning ifTrue: [^ self]. - currentProcess ifNotNil: #terminate. - - errorDecorator ifNotNil: #detach. - errorDecorator := nil. - returnValue clear. + self runSetup. self sendStartNotification. - "self collectTypeInfo." processRunning := true. currentProcess := [ @@ -394,7 +387,9 @@ SBExample >> run [ returnValue reportValue: returned. returnValue updateDisplay. self sendFinishNotification] - ] forkAt: Processor userBackgroundPriority + ] forkAt: Processor userBackgroundPriority. + + ^ currentProcess ] { #category : #'as yet unclassified' } @@ -405,6 +400,31 @@ SBExample >> runOnlyThis [ self startRunning ] +{ #category : #'as yet unclassified' } +SBExample >> runSetup [ + + self containingArtefact valid ifFalse: [^ self]. + processRunning ifTrue: [^ self]. + currentProcess ifNotNil: #terminate. + + errorDecorator ifNotNil: #detach. + errorDecorator := nil. + returnValue clear. +] + +{ #category : #'as yet unclassified' } +SBExample >> runSynchronouslyIgnoreReturn [ + + | returned | + self sendStartNotification. + + SBExecutionEnvironment value: self. + [returned := self evaluate] on: Error do: [:e | self scheduleLastError: e]. + self scheduleLastError: nil. + + self sendFinishNotification. +] + { #category : #'as yet unclassified' } SBExample >> scheduleLastError: anError [ diff --git a/packages/Sandblocks-Babylonian/SBExampleValueDisplay.class.st b/packages/Sandblocks-Babylonian/SBExampleValueDisplay.class.st index 142a3b61..416dabcd 100644 --- a/packages/Sandblocks-Babylonian/SBExampleValueDisplay.class.st +++ b/packages/Sandblocks-Babylonian/SBExampleValueDisplay.class.st @@ -13,6 +13,14 @@ Class { #category : #'Sandblocks-Babylonian' } +{ #category : #actions } +SBExampleValueDisplay >> clear [ + + display clear. + + hadValue := false +] + { #category : #accessing } SBExampleValueDisplay >> exampleFinished: anExample [ @@ -27,7 +35,6 @@ SBExampleValueDisplay >> exampleFinished: anExample [ SBExampleValueDisplay >> exampleStarting: anExample [ display exampleStarting: anExample. - display noValue. statusLabel contents: '...'. hadValue := false. @@ -73,7 +80,7 @@ SBExampleValueDisplay >> layoutCommands [ ] { #category : #naming } -SBExampleValueDisplay >> name: aString [ +SBExampleValueDisplay >> name: aString [ label contents: aString ] @@ -85,3 +92,21 @@ SBExampleValueDisplay >> reportValue: anObject name: aString [ label contents: aString. hadValue := true ] + +{ #category : #'event handling' } +SBExampleValueDisplay >> reportValues: aCollectionOfObjects name: aString [ + + display reportValues: aCollectionOfObjects. + label contents: aString. + hadValue := true +] + +{ #category : #actions } +SBExampleValueDisplay >> updateDisplay [ + + display updateDisplay. + + statusLabel contents: (hadValue + ifTrue: [''] + ifFalse: ['- Not reached -']) +] diff --git a/packages/Sandblocks-Babylonian/SBExampleWatch.class.st b/packages/Sandblocks-Babylonian/SBExampleWatch.class.st index f8ca0f21..c45b8b30 100644 --- a/packages/Sandblocks-Babylonian/SBExampleWatch.class.st +++ b/packages/Sandblocks-Babylonian/SBExampleWatch.class.st @@ -1,15 +1,16 @@ " -Observes (watches) an expression locally for added SBExamples. Whenever an example has finished running, it updates its belonging view. Further, with a given modifyExpression, it transforms the watched expression values. Also known as a Probe in the context of Babylonian Smalltalk. +Observes (watches) an expression locally for added SBExamples. Whenever an example has finished running, it updates its belonging view. Only active watches update their views. Further, with a given modifyExpression, it transforms the watched expression values. Also known as a Probe in the context of Babylonian Smalltalk. " Class { #name : #SBExampleWatch, #superclass : #SBStSubstitution, #instVars : [ 'identifier', - 'display', - 'exampleValues', 'watchedExpression', - 'modifyExpression' + 'modifyExpression', + 'isActive', + 'exampleToDisplay', + 'exampleToValues' ], #classVars : [ 'Registry' @@ -22,15 +23,35 @@ SBExampleWatch class >> matches: aBlock [ (super matches: aBlock) ifFalse: [^ false]. - ^ (aBlock receiver satisfies: #(notNil isBinding)) and: [aBlock receiver contents = self name] and: [aBlock selector = 'report:for:modifying:'] + ^ (aBlock receiver satisfies: #(notNil isBinding)) and: [aBlock receiver contents = self name] and: [aBlock selector = self matchingSelectors first] +] + +{ #category : #constants } +SBExampleWatch class >> matchingSelectors [ + + ^ #(#report:for:modifying:) ] { #category : #'instance creation' } -SBExampleWatch class >> newFor: aBlock [ +SBExampleWatch class >> newFor: aMessageSend [ + "Saving the temp is necessary here, as directly accessing will cause + the message send to lose an arguments with each assignment" + "Also done in SBMemoize" + | args | + args := aMessageSend arguments. ^ self new - identifier: aBlock arguments second contents asNumber; - expression: aBlock arguments first + identifier: args second contents asNumber; + modifyExpression: args third; + expression: args first +] + +{ #category : #shortcuts } +SBExampleWatch class >> registerShortcuts: aProvider [ + + aProvider registerShortcut: Character backspace do: #replaceWithWatchedExpression. + aProvider cmdShortcut: Character delete do: #replaceWithWatchedExpression. + ] { #category : #'event handling' } @@ -50,7 +71,7 @@ SBExampleWatch class >> registry [ SBExampleWatch class >> report: aValue for: aSymbol [ "Compatibility to SBWatch" - ^ self reportValue: aValue for: aSymbol modifying: (SBStBlockBody identityNamed: 'result'). + ^ self reportValue: aValue for: aSymbol modifying: (SBStBlockBody identityNamed: 'result'). ] { #category : #'event handling' } @@ -60,8 +81,10 @@ SBExampleWatch class >> report: aValue for: aSymbol modifying: aBlock [ example := SBExecutionEnvironment value ifNil: [^ aValue]. reg := self registry. - watchers := reg select: [:watcher | watcher notNil and: [watcher identifier = aSymbol]]. - watchers do: [:watcher | watcher reportValue: aValue for: example modifying: aBlock]. + watchers := reg select: [:watcher | watcher notNil + and: [watcher identifier = aSymbol] + and: [watcher isActive]]. + watchers do: [:watcher | watcher reportValue: aValue for: example]. ^ aValue ] @@ -78,18 +101,53 @@ SBExampleWatch class >> watchViewClass [ ^ SBExampleWatchView ] +{ #category : #callbacks } +SBExampleWatch >> applyModifyExpressionOnValues [ + + exampleToDisplay associationsDo: [:anExampleDisplayPair | + anExampleDisplayPair value clear. + anExampleDisplayPair value + reportValues: (self modifiedValuesFor: anExampleDisplayPair key) + name: (anExampleDisplayPair key ifNotNil: #label ifNil: ['']). + anExampleDisplayPair value updateDisplay] +] + +{ #category : #callbacks } +SBExampleWatch >> artefactSaved: aBlock [ + + "As we are inactive, we have to manually apply our modifyExpression if it changes. + Otherwise, we would reset by examples starting" + (self isActive not and: [aBlock = self containingArtefact]) ifTrue: [self applyModifyExpressionOnValues] +] + +{ #category : #copying } +SBExampleWatch >> asInactiveCopy [ + + ^ (self veryDeepCopy) beInactive. +] + +{ #category : #accessing } +SBExampleWatch >> beInactive [ + + isActive := false +] + { #category : #'colors and color policies' } SBExampleWatch >> color [ ^ self parentSandblock color ] +{ #category : #'insert/delete' } +SBExampleWatch >> deleteCommandFor: aBlock [ + + ^ nil +] + { #category : #'event handling' } SBExampleWatch >> doubleClick: anEvent [ - self sandblockEditor do: (SBReplaceCommand new - replacer: self expression; - target: self) + self replaceWithWatchedExpression ] { #category : #'colors and color policies' } @@ -101,15 +159,25 @@ SBExampleWatch >> drawnColor [ { #category : #'event handling' } SBExampleWatch >> exampleFinished: anExample [ - exampleValues at: anExample ifPresent: [:val | val exampleFinished: anExample] + exampleToDisplay + at: anExample + ifPresent: [:aDisplay | | modifiedValues | + modifiedValues := self modifiedValuesFor: anExample. + modifiedValues ifNotEmpty: [ + aDisplay + reportValues: modifiedValues + name: (anExample ifNotNil: #label ifNil: [''])]. + aDisplay exampleFinished: anExample] ] { #category : #'event handling' } SBExampleWatch >> exampleStarting: anExample [ - (exampleValues at: anExample ifAbsentPut: [ | display | + exampleToValues at: anExample put: OrderedCollection new. + + (exampleToDisplay at: anExample ifAbsentPut: [ | display | display := SBExampleValueDisplay new. - self addMorph: (exampleValues at: anExample put: display) atIndex: 2. + self addMorph: (exampleToDisplay at: anExample put: display) atIndex: 2. anExample when: #outOfWorld send: #exampleStopped: to: self with: anExample. display]) exampleStarting: anExample; @@ -119,9 +187,21 @@ SBExampleWatch >> exampleStarting: anExample [ { #category : #'event handling' } SBExampleWatch >> exampleStopped: anExample [ - exampleValues at: anExample ifPresent: [:val | - self removeMorph: val. - exampleValues removeKey: anExample] + exampleToDisplay at: anExample ifPresent: [:aDisplay | + self removeMorph: aDisplay. + exampleToDisplay removeKey: anExample] +] + +{ #category : #accessing } +SBExampleWatch >> exampleToDisplay: anExampleToDisplayDict [ + + exampleToDisplay := anExampleToDisplayDict +] + +{ #category : #accessing } +SBExampleWatch >> exampleToValues: anExampleToCollectionOfObjectsDict [ + + exampleToValues := anExampleToCollectionOfObjectsDict ] { #category : #accessing } @@ -162,9 +242,11 @@ SBExampleWatch >> initialize [ super initialize. - exampleValues := Dictionary new. + exampleToDisplay := Dictionary new. + exampleToValues := Dictionary new. watchedExpression := SBStMessageSend new. modifyExpression := SBStBlockBody identityNamed: 'result'. + isActive := true. self cellGap: 4; @@ -183,6 +265,12 @@ SBExampleWatch >> intoWorld: aWorld [ self class registerWatch: self ] +{ #category : #accessing } +SBExampleWatch >> isActive [ + + ^ isActive +] + { #category : #'*Sandblocks-Babylonian' } SBExampleWatch >> isExampleWatch [ @@ -201,6 +289,13 @@ SBExampleWatch >> isWatch [ ^ true ] +{ #category : #copying } +SBExampleWatch >> keepKeysDeepCopyValuesOf: aDictionary [ + + ^ Dictionary newFrom: ( + aDictionary associations collect: [:aKeyValuePair | aKeyValuePair key -> aKeyValuePair value sbSnapshot ]) +] + { #category : #layout } SBExampleWatch >> layoutCommands [ @@ -212,7 +307,16 @@ SBExampleWatch >> layoutCommands [ { #category : #'*Sandblocks-Babylonian' } SBExampleWatch >> listensToExamples [ - ^ true + ^ self isActive +] + +{ #category : #accessing } +SBExampleWatch >> modifiedValuesFor: anExample [ + + ^ exampleToValues at: anExample + ifPresent: [:aCollection | aCollection + collect: [:anObject | self modifyExpression evaluateWithArguments: {anObject}]] + ifAbsent: [{}] ] { #category : #accessing } @@ -252,40 +356,59 @@ SBExampleWatch >> printOn: aStream [ self modifyExpression printOn: aStream. ] +{ #category : #'event handling' } +SBExampleWatch >> replaceWithWatchedExpression [ + + + self sandblockEditor do: (SBReplaceCommand new + replacer: self expression; + target: self) +] + { #category : #actions } -SBExampleWatch >> reportValue: anObject for: anExample modifying: aBlock [ +SBExampleWatch >> reportValue: anObject for: anExample [ - exampleValues + exampleToValues at: anExample - ifPresent: [:display | display reportValue: (self modifyExpression evaluateWithArguments: {anObject}) name: (anExample ifNotNil: #label ifNil: [''])] + ifPresent: [:values | values add: anObject] ] { #category : #accessing } SBExampleWatch >> valuesForExample: anExample [ - ^ exampleValues at: anExample ifAbsent: [nil] + ^ exampleToValues at: anExample ifAbsent: [nil] ] { #category : #copying } SBExampleWatch >> veryDeepCopyWith: deepCopier [ " assure that copies of us have a unique id " - | new oldExamplesValues | - oldExamplesValues := exampleValues. - exampleValues := Dictionary new. + " disregarding deep copy of dictionaries to avoid duplicating examples" + | new oldExampleDisplays oldExampleValues | + oldExampleDisplays := exampleToDisplay. + oldExampleValues := exampleToValues. + exampleToDisplay := Dictionary new. + exampleToValues := Dictionary new. new := super veryDeepCopyWith: deepCopier. - exampleValues := oldExamplesValues. + exampleToDisplay := oldExampleDisplays. + exampleToValues := oldExampleValues. + new newIdentifier. + new exampleToDisplay: (Dictionary newFrom: + (exampleToDisplay keys withIndexCollect: [:anExample :i | anExample -> (new submorphs at: (i + 1))])). + new exampleToValues: (Dictionary newFrom: ( + oldExampleValues associations collect: [:aKeyValuePair | aKeyValuePair key -> aKeyValuePair value sbSnapshot ])). + ^ new ] { #category : #printing } SBExampleWatch >> writeSourceOn: aStream [ - aStream nextPutAll: '(SBExampleWatch report: '. + aStream nextPutAll: '(SBExampleWatch report: ('. self expression writeSourceOn: aStream. - aStream nextPutAll: ' for: '. + aStream nextPutAll: ') for: '. self identifier storeOn: aStream. aStream nextPutAll: ' modifying: '. self modifyExpression writeSourceOn: aStream. diff --git a/packages/Sandblocks-Babylonian/SBExampleWatch.extension.st b/packages/Sandblocks-Babylonian/SBExampleWatch.extension.st index 295787df..03cc8110 100644 --- a/packages/Sandblocks-Babylonian/SBExampleWatch.extension.st +++ b/packages/Sandblocks-Babylonian/SBExampleWatch.extension.st @@ -15,5 +15,5 @@ SBExampleWatch >> isGlobalWatch [ { #category : #'*Sandblocks-Babylonian' } SBExampleWatch >> listensToExamples [ - ^ true + ^ self isActive ] diff --git a/packages/Sandblocks-Babylonian/SBExploriants.class.st b/packages/Sandblocks-Babylonian/SBExploriants.class.st new file mode 100644 index 00000000..2a43ff42 --- /dev/null +++ b/packages/Sandblocks-Babylonian/SBExploriants.class.st @@ -0,0 +1,62 @@ +Class { + #name : #SBExploriants, + #superclass : #SBTabView, + #classInstVars : [ + 'uniqueInstance' + ], + #category : #'Sandblocks-Babylonian' +} + +{ #category : #accessing } +SBExploriants class >> deleteUniqueInstance [ + + uniqueInstance := nil +] + +{ #category : #'instance creation' } +SBExploriants class >> new [ + + ^ self error: 'Singleton. Use #uniqueInstance' +] + +{ #category : #accessing } +SBExploriants class >> uniqueInstance [ + + ^ uniqueInstance ifNil: [uniqueInstance := super new] +] + +{ #category : #comparing } +SBExploriants >> = other [ + + ^ self class = other class +] + +{ #category : #initialization } +SBExploriants >> initialize [ + + super initialize. + + self + attachDecorator: SBMoveDecorator new; + changeTableLayout; + hResizing: #shrinkWrap; + vResizing: #shrinkWrap +] + +{ #category : #testing } +SBExploriants >> isArtefact [ + + ^ true +] + +{ #category : #'artefact protocol' } +SBExploriants >> saveTryFixing: aFixBoolean quick: aQuickBoolean [ + + ^ true +] + +{ #category : #actions } +SBExploriants >> visualize [ + + self namedBlocks: SBExploriantsView getTabs activeIndex: 1 +] diff --git a/packages/Sandblocks-Babylonian/SBExploriantsView.class.st b/packages/Sandblocks-Babylonian/SBExploriantsView.class.st new file mode 100644 index 00000000..ccfa77f5 --- /dev/null +++ b/packages/Sandblocks-Babylonian/SBExploriantsView.class.st @@ -0,0 +1,97 @@ +Class { + #name : #SBExploriantsView, + #superclass : #SBNamedBlock, + #category : #'Sandblocks-Babylonian' +} + +{ #category : #'instance creation' } +SBExploriantsView class >> block: aSBBlock named: aString [ + + "only calling new allowed to guarantee intented purpose" + self shouldNotImplement +] + +{ #category : #'instance creation' } +SBExploriantsView class >> getTabs [ + + ^ self subclasses collect: #new +] + +{ #category : #accessing } +SBExploriantsView >> allCompiledMethodsContainingClass: aClass [ + + "aClass should have #matchingSelectors implemented" + ^ (((aClass matchingSelectors collect: [:aSelector | self systemNavigation allCallsOn: aSelector]) flatten) + reject: [:aMethodReference | aMethodReference actualClass = aClass class]) + collect: #compiledMethod +] + +{ #category : #accessing } +SBExploriantsView >> allCompiledMethodsContainingVariants [ + + ^ self allCompiledMethodsContainingClass: SBVariant +] + +{ #category : #accessing } +SBExploriantsView >> allMethodBlocksContainingVariants [ + + "We are looking for already opened methods so that we can assign the + variant there as the original in SBVariantProxy. That way, we immediately + have consistency between changes." + ^ self findExistingOrConvertToBlocks: self allCompiledMethodsContainingVariants + +] + +{ #category : #actions } +SBExploriantsView >> clean [ + + self block submorphs copy do: #delete +] + +{ #category : #building } +SBExploriantsView >> containerRow [ + + ^ SBRow new + color: Color transparent; + vResizing: #shrinkWrap; + hResizing: #shrinkWrap; + cellPositioning: #topLeft; + changeTableLayout; + listDirection: #leftToRight; + layoutInset: 8; + cellGap: 3; + cellInset: 3; + borderWidth: 0 +] + +{ #category : #accessing } +SBExploriantsView >> findExistingOrConvertToBlocks: aCollectionOfCompiledMethods [ + + ^ aCollectionOfCompiledMethods + collect: [:aCompiledMethod | + SBEditor current blockFor: aCompiledMethod withInterfaces: #(#isMethod) + ifOpen: [:existingMethodBlock | existingMethodBlock] + ifClosed: [aCompiledMethod asSandblock]] +] + +{ #category : #initialization } +SBExploriantsView >> initialize [ + + super initialize. + + self block: (SBBlock new + changeTableLayout; + color: Color white; + listDirection: #topToBottom; + layoutInset: 3; + cellGap: 4; + cellInset: 2; + hResizing: #shrinkWrap; + vResizing: #shrinkWrap) +] + +{ #category : #actions } +SBExploriantsView >> visualize [ + + self subclassResponsibility +] diff --git a/packages/Sandblocks-Babylonian/SBResultsView.class.st b/packages/Sandblocks-Babylonian/SBResultsView.class.st new file mode 100644 index 00000000..e3116543 --- /dev/null +++ b/packages/Sandblocks-Babylonian/SBResultsView.class.st @@ -0,0 +1,119 @@ +Class { + #name : #SBResultsView, + #superclass : #SBExploriantsView, + #category : #'Sandblocks-Babylonian' +} + +{ #category : #accessing } +SBResultsView >> allActiveExamples [ + + ^ (self allCompiledMethodsContainingExamples + collect: [:aCompiledMethod | + "Only examples which are open in the editor can actually be active." + SBEditor current blockFor: aCompiledMethod withInterfaces: #(#isMethod) + ifOpen: [:existingMethodBlock | existingMethodBlock containedExamples select: #active] + ifClosed: [#()]]) flatten +] + +{ #category : #accessing } +SBResultsView >> allCompiledMethodsContainingExampleWatches [ + + ^ self allCompiledMethodsContainingClass: SBExampleWatch +] + +{ #category : #accessing } +SBResultsView >> allCompiledMethodsContainingExamples [ + + ^ self allCompiledMethodsContainingClass: SBExample +] + +{ #category : #accessing } +SBResultsView >> allMethodBlocksContainingWatches [ + + "We need existing originals to be noticed of changes." + ^ self findExistingOrConvertToBlocks: self allCompiledMethodsContainingExampleWatches + +] + +{ #category : #accessing } +SBResultsView >> allWatchesIn: aCollectionOfMethodBlocks [ + + ^ (aCollectionOfMethodBlocks collect: [:aMethodBlock | + aMethodBlock containedExampleWatches collect: #asInactiveCopy]) flatten +] + +{ #category : #building } +SBResultsView >> applyButtonFor: aPermutation [ + + ^ SBButton new + icon: (SBIcon iconCheck + size: 6.0 sbScaled; + color: (Color r: 0.0 g: 1 b: 0.0)) + label: 'Apply Permutation' + do: [aPermutation apply]; + makeSmall; + cornerStyle: #squared +] + +{ #category : #building } +SBResultsView >> buildAllPossibleResults [ + + | permutations activeExamples watchMethodBlocks variants | + self flag: #todo. "don't calculate all variants a second time (first time being the variants view) -jb" + variants := (self allMethodBlocksContainingVariants collect: #containedVariants) flatten. + watchMethodBlocks := self allMethodBlocksContainingWatches. + activeExamples := self allActiveExamples. + permutations := SBPermutation allPermutationsOf: variants. + + [ permutations do: [:aPermutation | + SBActiveVariantPermutation value: aPermutation. + activeExamples do: #runSynchronouslyIgnoreReturn. + self buildPermutationFor: aPermutation collectingWatchesFrom: watchMethodBlocks]. + self resetWatchesToOriginalPermutationRunning: activeExamples] forkAt: Processor userSchedulingPriority +] + +{ #category : #building } +SBResultsView >> buildPermutationFor: aPermutation collectingWatchesFrom: aCollectionOfMethodBlocks [ + + self block addAllMorphsBack: { SBOwnTextMorph new contents: aPermutation asString. + self applyButtonFor: aPermutation. + (self containerRow listDirection: #leftToRight) + addAllMorphsBack: (self allWatchesIn: aCollectionOfMethodBlocks). + LineMorph from: 0@0 to: 50@0 color: Color black width: 2} +] + +{ #category : #initialization } +SBResultsView >> initialize [ + + super initialize. + + self name: 'Possible Results'. + + self visualize +] + +{ #category : #building } +SBResultsView >> resetWatchesToOriginalPermutationRunning: activeExamples [ + + SBActiveVariantPermutation value: nil. + activeExamples do: #runSynchronouslyIgnoreReturn +] + +{ #category : #building } +SBResultsView >> updateButton [ + + ^ SBButton new + icon: SBIcon iconRotateLeft + label: 'Re-Generate' + do: [self visualize]; + cornerStyle: #squared +] + +{ #category : #actions } +SBResultsView >> visualize [ + + self clean. + + self block addMorphBack: self updateButton. + self buildAllPossibleResults +] diff --git a/packages/Sandblocks-Babylonian/SBVariantsView.class.st b/packages/Sandblocks-Babylonian/SBVariantsView.class.st new file mode 100644 index 00000000..2ff68c30 --- /dev/null +++ b/packages/Sandblocks-Babylonian/SBVariantsView.class.st @@ -0,0 +1,32 @@ +Class { + #name : #SBVariantsView, + #superclass : #SBExploriantsView, + #category : #'Sandblocks-Babylonian' +} + +{ #category : #building } +SBVariantsView >> buildMethodSectionFor: aSBStMethod [ + + self block addAllMorphsBack: {aSBStMethod methodHeader copy. + self containerRow + addAllMorphsBack: (aSBStMethod containedVariants collect: #asProxy). + LineMorph from: 0@0 to: 50@0 color: Color black width: 2} +] + +{ #category : #initialization } +SBVariantsView >> initialize [ + + super initialize. + + self name: 'Variant Manager'. + + self visualize +] + +{ #category : #actions } +SBVariantsView >> visualize [ + + self clean. + + self allMethodBlocksContainingVariants do: [:aSBStMethod | self buildMethodSectionFor: aSBStMethod] +] diff --git a/packages/Sandblocks-Core/SBBlock.class.st b/packages/Sandblocks-Core/SBBlock.class.st index af75093d..538e1cda 100644 --- a/packages/Sandblocks-Core/SBBlock.class.st +++ b/packages/Sandblocks-Core/SBBlock.class.st @@ -1705,6 +1705,12 @@ SBBlock >> isValidAction: aPragmaOrMethod [ ^ validMode and: [validInvocation] ] +{ #category : #testing } +SBBlock >> isVariant [ + + ^ false +] + { #category : #testing } SBBlock >> isWatch [ diff --git a/packages/Sandblocks-Core/SBEditor.class.st b/packages/Sandblocks-Core/SBEditor.class.st index 3fba9db0..7b4859f8 100644 --- a/packages/Sandblocks-Core/SBEditor.class.st +++ b/packages/Sandblocks-Core/SBEditor.class.st @@ -1147,6 +1147,13 @@ SBEditor >> openAll: aCollection [ aCollection do: [:object | self open: object] ] +{ #category : #actions } +SBEditor >> openExploriants [ + + + self open: SBExploriants uniqueInstance visualize +] + { #category : #'actions creating' } SBEditor >> openFile [ diff --git a/packages/Sandblocks-Core/SBTabView.class.st b/packages/Sandblocks-Core/SBTabView.class.st index 21ba61ef..d94f08cd 100644 --- a/packages/Sandblocks-Core/SBTabView.class.st +++ b/packages/Sandblocks-Core/SBTabView.class.st @@ -160,6 +160,12 @@ SBTabView >> asTabButton: aNamedBlock [ ^ button ] +{ #category : #accessing } +SBTabView >> blockAt: anIndex [ + + ^ self namedBlocks at: anIndex +] + { #category : #ui } SBTabView >> buildTabs [ @@ -371,7 +377,7 @@ SBTabView >> removeCurrentTab [ { #category : #tabs } SBTabView >> setActive: aNamedBlock [ - self sandblockEditor do: + SBEditor current do: (self switchCommandFor: (self namedBlocks indexOf: aNamedBlock ifAbsent: 1)) ] @@ -396,6 +402,12 @@ SBTabView >> switchCommandFor: aNumber oldValue: oldNumber [ oldValue: oldNumber ] +{ #category : #accessing } +SBTabView >> tabCount [ + + ^ self namedBlocks size +] + { #category : #accessing } SBTabView >> tabs [ diff --git a/packages/Sandblocks-Smalltalk/SBStBasicMethod.class.st b/packages/Sandblocks-Smalltalk/SBStBasicMethod.class.st index 02257312..fbc65076 100644 --- a/packages/Sandblocks-Smalltalk/SBStBasicMethod.class.st +++ b/packages/Sandblocks-Smalltalk/SBStBasicMethod.class.st @@ -217,6 +217,24 @@ SBStBasicMethod >> compiledMethod [ ifAbsent: [self] ] +{ #category : #accessing } +SBStBasicMethod >> containedExampleWatches [ + + ^ self body containedExampleWatches +] + +{ #category : #accessing } +SBStBasicMethod >> containedExamples [ + + ^ self body containedExamples +] + +{ #category : #accessing } +SBStBasicMethod >> containedVariants [ + + ^ self body containedVariants +] + { #category : #actions } SBStBasicMethod >> createTestMethod [ @@ -291,6 +309,12 @@ SBStBasicMethod >> deleteMethod [ ^ self sandblockEditor do: (SBStDeleteMethodCommand new target: self) ] +{ #category : #accessing } +SBStBasicMethod >> detectVariant: aVariant [ + + ^ self body detectVariant: aVariant +] + { #category : #'artefact protocol' } SBStBasicMethod >> ensureExpanded [ diff --git a/packages/Sandblocks-Smalltalk/SBStBlockBody.class.st b/packages/Sandblocks-Smalltalk/SBStBlockBody.class.st index 13b24e61..a31b572d 100644 --- a/packages/Sandblocks-Smalltalk/SBStBlockBody.class.st +++ b/packages/Sandblocks-Smalltalk/SBStBlockBody.class.st @@ -113,18 +113,36 @@ SBStBlockBody >> blockBodyNestingDepth [ ^ d ] -{ #category : #'as yet unclassified' } +{ #category : #'insert/delete' } SBStBlockBody >> canDeleteChild: aBlock [ ^ true ] -{ #category : #'as yet unclassified' } +{ #category : #'layout properties - table' } SBStBlockBody >> cellGap [ ^ self colorPolicy lineGap ] +{ #category : #accessing } +SBStBlockBody >> containedExampleWatches [ + + ^ self allBlocksSelect: #isExampleWatch +] + +{ #category : #accessing } +SBStBlockBody >> containedExamples [ + + ^ self allBlocksSelect: #isExample +] + +{ #category : #accessing } +SBStBlockBody >> containedVariants [ + + ^ self allBlocksSelect: #isVariant +] + { #category : #'ast helpers' } SBStBlockBody >> declarationsDo: aBlock [ @@ -152,6 +170,12 @@ SBStBlockBody >> declareTemporaryVariableCommand: aString [ yourself] ] +{ #category : #accessing } +SBStBlockBody >> detectVariant: aVariant [ + + ^ (self containedVariants) detect: [:oneOfMyVariants | oneOfMyVariants = aVariant] ifNone: [nil] +] + { #category : #'as yet unclassified' } SBStBlockBody >> endPC [ @@ -176,13 +200,13 @@ SBStBlockBody >> fixedNumberOfChildren [ ^ false ] -{ #category : #'as yet unclassified' } +{ #category : #accessing } SBStBlockBody >> guessedClass [ ^ BlockClosure ] -{ #category : #'as yet unclassified' } +{ #category : #'initialize-release' } SBStBlockBody >> initialize [ super initialize. @@ -201,7 +225,7 @@ SBStBlockBody >> initialize [ addMorphBack: temporaries) ] -{ #category : #'as yet unclassified' } +{ #category : #'insert/delete' } SBStBlockBody >> insertCommandRequest: aMorph near: aBlock before: aBoolean [ (aBlock notNil and: [aBlock owner = bindings]) ifTrue: [ @@ -227,7 +251,7 @@ SBStBlockBody >> insertCommandRequest: aMorph near: aBlock before: aBoolean [ title: 'insert statement' ] -{ #category : #'as yet unclassified' } +{ #category : #testing } SBStBlockBody >> isBlockBody [ ^ true @@ -251,7 +275,7 @@ SBStBlockBody >> isScope [ ^ true ] -{ #category : #'as yet unclassified' } +{ #category : #layout } SBStBlockBody >> layoutCommands [ | preamble preambleHasContent multiLine | @@ -294,13 +318,13 @@ SBStBlockBody >> localNestingDepth [ ^ 1 ] -{ #category : #'as yet unclassified' } +{ #category : #layout } SBStBlockBody >> minHeight [ ^ self fontToUse height + self layoutInset asEdgeInsets y ] -{ #category : #'as yet unclassified' } +{ #category : #'geometry - layout' } SBStBlockBody >> minimumHeight [ ^ self fontToUse height + self layoutInset asEdgeInsets vertical @@ -320,7 +344,7 @@ SBStBlockBody >> newEmptyChildNear: aBlock before: aBoolean [ ^ super newEmptyChildNear: aBlock before: aBoolean ] -{ #category : #'as yet unclassified' } +{ #category : #'object interface' } SBStBlockBody >> objectInterfaceNear: aBlock at: aSymbol [ ({bindings. temporaries} includes: (aBlock ifNotNil: #owner)) ifTrue: [^ SBInterfaces stName]. @@ -395,7 +419,7 @@ SBStBlockBody >> statementsDo: aBlock [ ^ self submorphs allButFirstDo: aBlock ] -{ #category : #'as yet unclassified' } +{ #category : #'colors and color policies' } SBStBlockBody >> symbols [ ^ self isMethodBody ifTrue: [#(nil nil)] ifFalse: [self colorPolicy symbolsForBlock: self] @@ -413,7 +437,7 @@ SBStBlockBody >> temporaries: aCollection [ temporaries bindings: aCollection ] -{ #category : #'as yet unclassified' } +{ #category : #accessing } SBStBlockBody >> updatePCFrom: aBlock [ super updatePCFrom: aBlock. diff --git a/packages/Sandblocks-Smalltalk/SBStMethod.class.st b/packages/Sandblocks-Smalltalk/SBStMethod.class.st index f2dded4c..c2070443 100644 --- a/packages/Sandblocks-Smalltalk/SBStMethod.class.st +++ b/packages/Sandblocks-Smalltalk/SBStMethod.class.st @@ -144,6 +144,12 @@ SBStMethod >> methodClass [ ^ classPrefix selectedClass ifNil: [self outerArtefact ifNotNil: #relatedClass] ] +{ #category : #accessing } +SBStMethod >> methodHeader [ + + ^ self firstSubmorph +] + { #category : #'object interface' } SBStMethod >> objectInterfaceNear: aBlock at: aSymbol [ diff --git a/packages/Sandblocks-Smalltalk/SBVariant.class.st b/packages/Sandblocks-Smalltalk/SBVariant.class.st index d4f905f5..f4418aac 100644 --- a/packages/Sandblocks-Smalltalk/SBVariant.class.st +++ b/packages/Sandblocks-Smalltalk/SBVariant.class.st @@ -3,7 +3,8 @@ Class { #superclass : #SBStSubstitution, #instVars : [ 'name', - 'widget' + 'widget', + 'id' ], #category : #'Sandblocks-Smalltalk' } @@ -32,7 +33,13 @@ SBVariant class >> matches: aBlock [ ^ aBlock receiver isBinding and: [aBlock receiver contents = 'SBVariant'] - and: [aBlock selector = 'named:associations:activeIndex:'] + and: [aBlock selector = self matchingSelectors first] +] + +{ #category : #constants } +SBVariant class >> matchingSelectors [ + + ^ #(#named:associations:activeIndex:id:) ] { #category : #'instance creation' } @@ -46,9 +53,23 @@ SBVariant class >> named: aString alternatives: aCollectionOfNamedBlocks activeI ] { #category : #'instance creation' } -SBVariant class >> named: aString associations: aCollectionOfAssociations activeIndex: aNumber [ +SBVariant class >> named: aString alternatives: aCollectionOfNamedBlocks activeIndex: aNumber id: uuid [ - ^ aNumber > 0 ifTrue: [(aCollectionOfAssociations at: aNumber) value value] ifFalse: [nil] + ^ self new + named: aString + alternatives: aCollectionOfNamedBlocks + activeIndex: aNumber + id: uuid + +] + +{ #category : #'instance creation' } +SBVariant class >> named: aString associations: aCollectionOfAssociations activeIndex: aNumber id: uuid [ + + aNumber <= 0 ifTrue: [^ nil]. + ^ SBActiveVariantPermutation value + ifNil: [(aCollectionOfAssociations at: aNumber) value value] + ifNotNil: [(aCollectionOfAssociations at: (SBActiveVariantPermutation value at: uuid)) value value]. ] @@ -65,6 +86,7 @@ SBVariant class >> newFor: aBlock [ named: aBlock arguments first contents alternatives: (aBlock arguments second childSandblocks collect: [:anAssociation | SBNamedBlock block: (anAssociation arguments first) named: (anAssociation receiver contents)]) activeIndex: aBlock arguments third parsedContents + id: aBlock arguments fourth contents ] { #category : #shortcuts } @@ -74,6 +96,12 @@ SBVariant class >> registerShortcuts: aProvider [ ] +{ #category : #comparing } +SBVariant >> = otherVariant [ + + ^ otherVariant class = self class and: [otherVariant id = self id] +] + { #category : #accessing } SBVariant >> active [ @@ -98,6 +126,45 @@ SBVariant >> alternatives [ ^ self widget namedBlocks ] +{ #category : #accessing } +SBVariant >> alternativesCount [ + + ^ self widget tabCount +] + +{ #category : #comparing } +SBVariant >> alternativesEqual: otherAlternatives [ + + "Private" + "Does a cheap version of python's zip and then allSatisfy:" + | areSame | + areSame := true. + ^ self alternatives size = otherAlternatives size and: [ + (1 to: self alternatives size) do: [:index | + areSame := areSame and: [(self alternatives at: index) = (otherAlternatives at: index)]]. + areSame] +] + +{ #category : #converting } +SBVariant >> asProxy [ + + ^ SBVariantProxy for: self +] + +{ #category : #accessing } +SBVariant >> blockAt: anIndex [ + + ^ self widget blockAt: anIndex +] + +{ #category : #accessing } +SBVariant >> codeFor: aNamedBlock [ + + ^ (aNamedBlock block submorphs size > 1) + ifTrue: [aNamedBlock block lastSubmorph] + ifFalse: [nil] +] + { #category : #accessing } SBVariant >> color [ @@ -110,6 +177,16 @@ SBVariant >> drawnColor [ ^ Color white ] +{ #category : #accessing } +SBVariant >> id [ + ^ id +] + +{ #category : #accessing } +SBVariant >> id: anObject [ + id := anObject +] + { #category : #initialization } SBVariant >> initialize [ @@ -122,7 +199,7 @@ SBVariant >> initialize [ self widget: (SBTabView namedBlocks: {SBNamedBlock block: (SBStBlockBody emptyWithDeclarations: {'a'. 'c'}) named: 'Code'} activeIndex: 1). - + id := UUID new asString. self layoutInset: 0; @@ -134,6 +211,12 @@ SBVariant >> initialize [ hResizing: #shrinkWrap ] +{ #category : #testing } +SBVariant >> isVariant [ + + ^ true +] + { #category : #accessing } SBVariant >> name [ @@ -152,6 +235,13 @@ SBVariant >> named: aString alternatives: aCollectionOfNamedBlocks activeIndex: self widget namedBlocks: aCollectionOfNamedBlocks activeIndex: aNumber ] +{ #category : #initialization } +SBVariant >> named: aString alternatives: aCollectionOfNamedBlocks activeIndex: aNumber id: uuid [ + + self id: uuid. + self named: aString alternatives: aCollectionOfNamedBlocks activeIndex: aNumber +] + { #category : #accessing } SBVariant >> namedBlocks [ @@ -161,22 +251,44 @@ SBVariant >> namedBlocks [ { #category : #actions } SBVariant >> replaceSelfWithBlock: aNamedBlock [ + | command | "As deleting the last tab also deletes the tab view, we gotta recreate it" self widget: (SBTabView namedBlocks: {aNamedBlock} activeIndex: 1). self addMorphBack: widget. - self sandblockEditor do: (SBUnwrapConsecutiveCommand new + command := (self codeFor: widget active) + ifNil: [SBDeleteCommand new target: self] + ifNotNil: [SBUnwrapConsecutiveCommand new target: self; - unwrapped: {widget activeBlock lastSubmorph}) + unwrapped: {(self codeFor: widget active)}]. + + self sandblockEditor do: command ] { #category : #actions } SBVariant >> replaceSelfWithChosen [ - self sandblockEditor do: (SBUnwrapConsecutiveCommand new + | command | + command := (self codeFor: widget active) + ifNil: [SBDeleteCommand new target: self] + ifNotNil: [SBUnwrapConsecutiveCommand new target: self; - unwrapped: {self activeBlock lastSubmorph}) + unwrapped: {(self codeFor: widget active)}]. + + self sandblockEditor do: command +] + +{ #category : #initialization } +SBVariant >> replaceValuesFrom: anotherVariant [ + + self named: anotherVariant name alternatives: anotherVariant alternatives activeIndex: anotherVariant activeIndex +] + +{ #category : #actions } +SBVariant >> switchToAlternative: anIndex [ + + self widget jumpToTab: anIndex ] { #category : #ui } @@ -213,11 +325,15 @@ SBVariant >> writeSourceOn: aStream [ do: [:aNamedBlock | aNamedBlock name storeOn: aStream. aStream nextPutAll: ' -> ['. - aNamedBlock block lastSubmorph writeSourceOn: aStream. + (self codeFor: aNamedBlock) + ifNotNil: [(self codeFor: aNamedBlock) writeSourceOn: aStream] + ifNil: [aStream nextPutAll: ' ']. aStream nextPut: $]. ] separatedBy: [aStream nextPut: $.]. aStream nextPutAll: '} activeIndex: '. self activeIndex storeOn: aStream. + aStream nextPutAll: ' id: '. + self id storeOn: aStream. aStream nextPutAll: ')' ] diff --git a/packages/Sandblocks-Smalltalk/SBVariantProxy.class.st b/packages/Sandblocks-Smalltalk/SBVariantProxy.class.st new file mode 100644 index 00000000..d2a66d42 --- /dev/null +++ b/packages/Sandblocks-Smalltalk/SBVariantProxy.class.st @@ -0,0 +1,122 @@ +Class { + #name : #SBVariantProxy, + #superclass : #SBBlock, + #instVars : [ + 'original', + 'containedMethod' + ], + #category : #'Sandblocks-Smalltalk' +} + +{ #category : #'instance creation' } +SBVariantProxy class >> for: aVariant [ + + ^ self new for: aVariant +] + +{ #category : #callbacks } +SBVariantProxy >> artefactChanged: anArtefact [ + + anArtefact = self ifTrue: [ self updateOriginalWithOwnValues ]. + + (anArtefact = self containedMethod) + ifTrue: [ self updateSelfAfterMethodUpdate: anArtefact ] +] + +{ #category : #callbacks } +SBVariantProxy >> artefactSaved: anArtefact [ + + anArtefact = self containedMethod ifTrue: [self sandblockEditor markSaved: self] +] + +{ #category : #'ast helpers' } +SBVariantProxy >> binding: aString for: block class: aClass ifPresent: aBlock [ + + ^ original binding: aString for: block class: aClass ifPresent: aBlock +] + +{ #category : #accessing } +SBVariantProxy >> containedMethod [ + + ^ containedMethod +] + +{ #category : #initialization } +SBVariantProxy >> for: aVariant [ + + containedMethod := aVariant containingArtefact. + self assert: containedMethod notNil. + + original := aVariant. + self addMorphBack: original copyBlock. +] + +{ #category : #initialization } +SBVariantProxy >> initialize [ + + super initialize. + + self + hResizing: #shrinkWrap; + vResizing: #shrinkWrap; + changeTableLayout; + layoutInset: 4; + attachDecorator: SBForceMoveDecorator newConfigured +] + +{ #category : #testing } +SBVariantProxy >> isArtefact [ + + ^ true +] + +{ #category : #accessing } +SBVariantProxy >> original [ + + ^ original +] + +{ #category : #'artefact protocol' } +SBVariantProxy >> saveTryFixing: aFixBoolean quick: aQuickBoolean [ + + self sandblockEditor + save: self containedMethod + tryFixing: aFixBoolean + quick: aQuickBoolean. + ^ false +] + +{ #category : #'ast helpers' } +SBVariantProxy >> scopesDo: aBlock [ + + original scopesDo: aBlock +] + +{ #category : #callbacks } +SBVariantProxy >> updateOriginalWithOwnValues [ + + | variantThatNeedsChanging | + variantThatNeedsChanging := self containedMethod detectVariant: original. + + variantThatNeedsChanging ifNil: [self delete. ^ self]. + + original replaceBy: (original := self firstSubmorph copyBlock). + variantThatNeedsChanging replaceValuesFrom: original copyBlock. + self sandblockEditor markChanged: self containedMethod +] + +{ #category : #callbacks } +SBVariantProxy >> updateSelfAfterMethodUpdate: newMethod [ + + | variantThatMaybeChanged | + variantThatMaybeChanged := newMethod detectVariant: original. + + variantThatMaybeChanged ifNil: [self delete. ^ self]. + + (variantThatMaybeChanged sourceString ~= self firstSubmorph sourceString) + ifTrue: [ + original := variantThatMaybeChanged. + self firstSubmorph replaceBy: original copyBlock. + self sandblockEditor markChanged: self] + +] diff --git a/packages/Sandblocks-Utils/SBPermutation.class.st b/packages/Sandblocks-Utils/SBPermutation.class.st new file mode 100644 index 00000000..5b56c6c2 --- /dev/null +++ b/packages/Sandblocks-Utils/SBPermutation.class.st @@ -0,0 +1,63 @@ +" +A helper class with synctactic sugars for variant id -> alternative index dictionary +" +Class { + #name : #SBPermutation, + #superclass : #Dictionary, + #type : #variable, + #instVars : [ + 'referencedVariants' + ], + #category : #'Sandblocks-Utils' +} + +{ #category : #utils } +SBPermutation class >> allPermutationsOf: aCollectionOfVariants [ + + | permutations | + permutations := (1 to: aCollectionOfVariants first alternativesCount) collect: #asArray. + + (2 to: aCollectionOfVariants size) do: [:i | | alternatives | + alternatives := (aCollectionOfVariants at: i) alternativesCount. + permutations := permutations gather: [:aCollectionOfIndexes | + (1 to: alternatives) collect: [:aTabIndex | + {aCollectionOfIndexes. aTabIndex} flatten]]]. + + ^ permutations collect: [:aCollectionOfIndexes | + (self withAll: (aCollectionOfIndexes withIndexCollect: [:anAlternativeIndex :aVariantIndex | + (aCollectionOfVariants at: aVariantIndex) id -> anAlternativeIndex])) + referencedVariants: aCollectionOfVariants] + +] + +{ #category : #actions } +SBPermutation >> apply [ + + self referencedVariants do: [:aVariant | aVariant switchToAlternative: (self at: aVariant id)]. + (Set newFrom: (referencedVariants collect: #containingArtefact thenSelect: #isMethod)) + do: [:aMethodBlock | SBEditor current save: aMethodBlock tryFixing: true quick: true]. +] + +{ #category : #converting } +SBPermutation >> asString [ + + "collecting instead of calling (a active name), ', ', (b active name) in fold + as one variant only will not return a string but a variant" + ^ (self referencedVariants collect: [:aVariant | + aVariant name, ': ', (aVariant blockAt: (self at: aVariant id)) name]) + fold: [:a :b | a, ', ', b ] + + +] + +{ #category : #accessing } +SBPermutation >> referencedVariants [ + + ^ referencedVariants +] + +{ #category : #accessing } +SBPermutation >> referencedVariants: anObject [ + + referencedVariants := anObject +] diff --git a/packages/Sandblocks-Watch/SBExampleWatchView.class.st b/packages/Sandblocks-Watch/SBExampleWatchView.class.st index f09f1b75..8da392aa 100644 --- a/packages/Sandblocks-Watch/SBExampleWatchView.class.st +++ b/packages/Sandblocks-Watch/SBExampleWatchView.class.st @@ -36,10 +36,18 @@ SBExampleWatchView >> reportValue: anObject [ updateScheduled := true ] +{ #category : #accessing } +SBExampleWatchView >> reportValues: aCollectionOfObjects [ + + aCollectionOfObjects do: [:anObject | self addValue: anObject]. + + updateScheduled := true +] + { #category : #display } SBExampleWatchView >> updateDisplay [ super updateDisplay. - count contents: (watchValues size) asString + self count: (watchValues size) asString ] diff --git a/packages/Sandblocks-Watch/SBWatchView.class.st b/packages/Sandblocks-Watch/SBWatchView.class.st index e10bf7b0..506853c2 100644 --- a/packages/Sandblocks-Watch/SBWatchView.class.st +++ b/packages/Sandblocks-Watch/SBWatchView.class.st @@ -19,7 +19,6 @@ Class { { #category : #'as yet unclassified' } SBWatchView class >> saving: anInteger [ "Any value < 1 will result in saving all reported values" - ^ self new numSavedValues: anInteger ] @@ -31,6 +30,18 @@ SBWatchView >> addValue: anObject [ ^ watchValues addLast: (SBWatchValue value: anObject sbSnapshot identityHash: anObject identityHash) ] +{ #category : #'insert/delete' } +SBWatchView >> canDelete [ + + ^ false +] + +{ #category : #'insert/delete' } +SBWatchView >> canDeleteChild: aBlock [ + + ^ false +] + { #category : #display } SBWatchView >> changeDisplay [ @@ -62,6 +73,12 @@ SBWatchView >> count [ ^ count contents ] +{ #category : #accessing } +SBWatchView >> count: aNumber [ + + count contents: aNumber asString +] + { #category : #display } SBWatchView >> defaultDisplay [ @@ -80,6 +97,12 @@ SBWatchView >> defaultDisplay [ height: 20) ] +{ #category : #'insert/delete' } +SBWatchView >> deleteCommandFor: aBlock [ + + ^ nil +] + { #category : #accessing } SBWatchView >> display [ @@ -163,12 +186,6 @@ SBWatchView >> maxWidth [ ^ 450 ] -{ #category : #'event handling' } -SBWatchView >> noValue [ - - self scroller removeAllMorphs -] - { #category : #accessing } SBWatchView >> numSavedValues: anInteger [ "Private" @@ -206,6 +223,17 @@ SBWatchView >> reportValue: anObject [ Project current addDeferredUIMessage: [self updateDisplay]] ] +{ #category : #accessing } +SBWatchView >> reportValues: aCollectionOfObjects [ + + aCollectionOfObjects do: [:anObject | self addValue: anObject]. + self count: self count contents + aCollectionOfObjects size. + + updateScheduled ifFalse: [ + updateScheduled := true. + Project current addDeferredUIMessage: [self updateDisplay]] +] + { #category : #accessing } SBWatchView >> scrollBarHeight [