David T. Lewis uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-jr.745.mcz
==================== Summary ====================
Name: Tools-jr.745
Author: jr
Time: 28 February 2017, 2:20:44.822081 am
UUID: c3e3bfae-ac2c-0d4e-a606-c41b7d388d67
Ancestors: Tools-cmm.744
improve Tools support for environments
allows...
- navigating senders/implementors
- using the hierarchy browser
- defining new classes and traits
- enjoying a Workspace
...in other environments
Also ensure all objects understand #environment, so tools can send it without fear.
Depends on ToolBuilder-Kernel-jr.109 for choosing something in 'find class'.
=============== Diff against Tools-cmm.744 ===============
Item was changed:
----- Method: Browser>>copyClass (in category 'class functions') -----
copyClass
| originalClass originalName copysName |
self hasClassSelected ifFalse: [^ self].
self okToChange ifFalse: [^ self].
originalClass := self selectedClass.
originalName := originalClass name.
copysName := self request: 'Please type new class name' initialAnswer: originalName.
copysName = '' ifTrue: [^ self]. " Cancel returns '' "
copysName := copysName asSymbol.
copysName = originalName ifTrue: [^ self].
+ (self environment hasClassNamed: copysName)
- (Smalltalk hasClassNamed: copysName)
ifTrue: [^ self error: copysName , ' already exists'].
Cursor wait showWhile: [
| newDefinition newMetaDefinition newClass |
newDefinition := originalClass definition
copyReplaceAll: originalName printString
with: copysName printString.
+ newClass := Compiler evaluate: newDefinition environment: self environment
+ logged: true.
- newClass := Compiler evaluate: newDefinition logged: true.
newMetaDefinition := originalClass class definition
copyReplaceAll: originalClass class name
with: newClass class name.
+ Compiler evaluate: newMetaDefinition environment: self environment
+ logged: true.
- Compiler evaluate: newMetaDefinition logged: true.
newClass copyAllCategoriesFrom: originalClass.
newClass class copyAllCategoriesFrom: originalClass class.
originalClass hasComment ifTrue: [
newClass comment: originalClass comment ] ].
self classListIndex: 0.
self changed: #classList!
Item was changed:
----- Method: Browser>>defineClass:notifying: (in category 'class functions') -----
defineClass: defString notifying: aController
"The receiver's textual content is a request to define a new class. The
source code is defString. If any errors occur in compilation, notify
aController."
| oldClass class newClassName defTokens keywdIx envt |
oldClass := self selectedClassOrMetaClass.
defTokens := defString findTokens: Character separators.
((defTokens first = 'Trait' and: [defTokens second = 'named:'])
or: [defTokens second = 'classTrait'])
ifTrue: [^self defineTrait: defString notifying: aController].
keywdIx := defTokens findFirst: [:x | x beginsWith: 'category'].
+ envt := self selectedEnvironment.
- envt := Smalltalk.
keywdIx := defTokens findFirst: [:x | '*subclass*' match: x].
newClassName := (defTokens at: keywdIx+1) copyWithoutAll: '#()'.
((oldClass isNil or: [oldClass theNonMetaClass name asString ~= newClassName])
and: [envt includesKey: newClassName asSymbol]) ifTrue:
["Attempting to define new class over existing one when
not looking at the original one in this browser..."
(self confirm: ((newClassName , ' is an existing class in this system.
Redefining it might cause serious problems.
Is this really what you want to do?') asText makeBoldFrom: 1 to: newClassName size))
ifFalse: [^ false]].
"ar 8/29/1999: Use oldClass superclass for defining oldClass
since oldClass superclass knows the definerClass of oldClass."
oldClass ifNotNil:[oldClass := oldClass superclass].
+ class := envt beCurrentDuring:
+ [oldClass subclassDefinerClass
- class := oldClass subclassDefinerClass
evaluate: defString
+ in: envt
notifying: aController
+ logged: false].
- logged: false.
(class isKindOf: Behavior)
ifTrue: [self changed: #systemCategoryList.
self changed: #classList.
self clearUserEditFlag.
self setClass: class selector: nil.
"self clearUserEditFlag; editClass."
^ true]
ifFalse: [^ false]!
Item was changed:
----- Method: Browser>>defineTrait:notifying: (in category 'traits') -----
defineTrait: defString notifying: aController
| defTokens keywdIx envt oldTrait newTraitName trait |
oldTrait := self selectedClassOrMetaClass.
defTokens := defString findTokens: Character separators.
keywdIx := defTokens findFirst: [:x | x = 'category'].
envt := self selectedEnvironment.
keywdIx := defTokens findFirst: [:x | x = 'named:'].
newTraitName := (defTokens at: keywdIx+1) copyWithoutAll: '#()'.
((oldTrait isNil or: [oldTrait baseTrait name asString ~= newTraitName])
and: [envt includesKey: newTraitName asSymbol]) ifTrue:
["Attempting to define new class/trait over existing one when
not looking at the original one in this browser..."
(self confirm: ((newTraitName , ' is an existing class/trait in this system.
Redefining it might cause serious problems.
Is this really what you want to do?') asText makeBoldFrom: 1 to: newTraitName size))
ifFalse: [^ false]].
+ trait := envt beCurrentDuring:
+ [Compiler evaluate: defString in: envt notifying: aController logged: true].
- trait := Compiler evaluate: defString notifying: aController logged: true.
^(trait isTrait)
ifTrue: [
self changed: #classList.
self classListIndex: (self classListIndexOf: trait baseTrait name).
self clearUserEditFlag; editClass.
true]
ifFalse: [ false ]
!
Item was added:
+ ----- Method: Browser>>environment (in category 'accessing') -----
+ environment
+ ^ environment ifNil: [super environment]!
Item was changed:
----- Method: Browser>>findClass (in category 'system category functions') -----
findClass
"Search for a class by name."
| foundClass |
(self multiWindowState notNil
or: [self okToChange]) ifFalse:
[^self classNotFound].
+ foundClass := UIManager default chooseClassOrTraitFrom: self environment.
- foundClass := UIManager default chooseClassOrTrait.
foundClass ifNil: [^self classNotFound].
(self selectedClass notNil
and: [self multiWindowState notNil
"Can only support multi-window if original window has all the right panes."
and: [self multiWindowState prototype isHierarchy not]]) ifTrue:
[(self classList includes: foundClass name)
ifTrue: [self multiWindowState copyWindow]
ifFalse: [self multiWindowState addNewWindow]].
self selectCategoryForClass: foundClass.
self selectClass: foundClass!
Item was changed:
----- Method: Browser>>hierarchicalClassList (in category 'class list') -----
hierarchicalClassList
"classNames are an arbitrary collection of classNames of the system.
Reorder those class names so that they are sorted and indended by inheritance"
| classes |
"Creating the hierarchy is *really slow* for the full class list. Skip it for now."
self selectedSystemCategory = SystemOrganizer allCategory
ifTrue: [^ self defaultClassList].
+ classes := self defaultClassList collect: [:sym | self environment classNamed: sym].
- classes := self defaultClassList collect: [:sym | Smalltalk classNamed: sym].
^ self
flattenHierarchyTree: (self createHierarchyTreeOf: classes)
on: OrderedCollection new
indent: ''.!
Item was changed:
----- Method: Browser>>selectedClass (in category 'class list') -----
selectedClass
"Answer the class that is currently selected. Answer nil if no selection
exists."
| name envt |
(name := self selectedClassName) ifNil: [^ nil].
(envt := self selectedEnvironment) ifNil: [^ nil].
+ ^ envt at: name ifAbsent: [envt valueOf: name ifAbsent: [nil]]!
- ^ envt at: name ifAbsent: [nil]!
Item was changed:
----- Method: Browser>>selectedEnvironment (in category 'system category list') -----
selectedEnvironment
+ "Answer the browsed environment. If this returned a system category dependent
+ value and possibly nil (as it did in previous versions), selectedClass would not work in
+ a hierarchy browser that has to display classes from different environments
+ (because the correct categories might be missing in the browser)"
- "Answer the name of the selected system category or nil."
+ ^ environment ifNil: [Smalltalk globals]!
- self hasSystemCategorySelected ifFalse: [^nil].
- ^ environment ifNil: [Smalltalk]!
Item was changed:
----- Method: ChangeList>>diffedVersionContents (in category 'viewing access') -----
diffedVersionContents
"Answer diffed version contents, maybe pretty maybe not"
| change class earlier later |
(listIndex = 0
or: [changeList size < listIndex])
ifTrue: [^ ''].
change := changeList at: listIndex.
later := change text.
+ class := change methodClass: self environment.
- class := change methodClass.
(listIndex == changeList size or: [class == nil])
ifTrue: [^ (self showingPrettyDiffs and: [class notNil])
ifTrue: [class prettyPrinterClass format: later in: class notifying: nil]
ifFalse: [later]].
earlier := (changeList at: listIndex + 1) text.
^ TextDiffBuilder buildDisplayPatchFrom: earlier to: later inClass: class prettyDiffs: self showingPrettyDiffs!
Item was changed:
----- Method: ChangeList>>fileInSelections (in category 'menu actions') -----
fileInSelections
| any |
any := false.
+ self selectedClass environment beCurrentDuring: [
+ listSelections with: changeList do:
+ [:selected :item | selected ifTrue: [any := true. item fileIn]]].
- listSelections with: changeList do:
- [:selected :item | selected ifTrue: [any := true. item fileIn]].
any ifFalse:
[self inform: 'nothing selected, so nothing done']!
Item was changed:
----- Method: DependencyBrowser>>selectedEnvironment (in category 'accessing') -----
selectedEnvironment
"Answer the name of the selected package or nil."
self hasPackageSelected ifFalse: [^nil].
+ ^ Smalltalk globals!
- ^ Smalltalk!
Item was changed:
----- Method: HierarchyBrowser>>classList (in category 'class list') -----
classList
+ classDisplayList := classDisplayList select: [:each | (self environment valueOf: each withBlanksTrimmed asSymbol) notNil].
- classDisplayList := classDisplayList select: [:each | Smalltalk includesKey: each withBlanksTrimmed asSymbol].
^ classDisplayList!
Item was changed:
----- Method: HierarchyBrowser>>classListIndex: (in category 'initialization') -----
classListIndex: newIndex
"Cause system organization to reflect appropriate category"
| newClassName ind |
newIndex ~= 0 ifTrue:
[newClassName := (classDisplayList at: newIndex) copyWithout: $ .
selectedSystemCategory := (systemOrganizer categories at:
+ (systemOrganizer numberOfCategoryOfElement: newClassName)
+ ifAbsent: [nil])].
- (systemOrganizer numberOfCategoryOfElement: newClassName))].
ind := super classListIndex: newIndex.
"What I'd like to write:"
"self selectedClassName ifNotNil:
[ selectedSystemCategory := self selectedClass category ]."
self changed: #systemCategorySingleton.
^ ind!
Item was changed:
----- Method: HierarchyBrowser>>initHierarchyForClass: (in category 'initialization') -----
initHierarchyForClass: aClassOrMetaClass
| nonMetaClass superclasses |
centralClass := aClassOrMetaClass.
nonMetaClass := aClassOrMetaClass theNonMetaClass.
+ self selectEnvironment: aClassOrMetaClass environment.
- self systemOrganizer: SystemOrganization.
metaClassIndicated := aClassOrMetaClass isMeta.
classDisplayList := OrderedCollection new.
(superclasses := nonMetaClass allSuperclasses reversed) withIndexDo:
[ : each : indent | classDisplayList add:
(String streamContents:
[ : stream | indent - 1 timesRepeat: [ stream nextPutAll: ' ' ].
stream nextPutAll: each name ]) ].
nonMetaClass
allSubclassesWithLevelDo:
[ : eachClass : lvl | classDisplayList add:
(String streamContents:
[ : stream | lvl timesRepeat: [ stream nextPutAll: ' ' ].
stream nextPutAll: eachClass name ]) ]
startingLevel: superclasses size.
self changed: #classList.
self selectClass: nonMetaClass!
Item was changed:
----- Method: MessageSet class>>parse:toClassAndSelector: (in category 'utilities') -----
parse: methodRef toClassAndSelector: csBlock
"Decode strings of the form <className> [class] <selectorName>."
| tuple cl |
self flag: #mref. "compatibility with pre-MethodReference lists"
methodRef ifNil: [^ csBlock value: nil value: nil].
methodRef isString ifFalse:
[^methodRef setClassAndSelectorIn: csBlock].
methodRef isEmpty ifTrue:
[^csBlock value: nil value: nil].
tuple := (methodRef asString includesSubstring: '>>')
ifTrue: [(methodRef findTokens: '>>') fold: [:a :b| (a findTokens: ' '), {b first = $# ifTrue: [b allButFirst] ifFalse: [b]}]]
ifFalse: [methodRef asString findTokens: ' .'].
+ self flag: #environments. "missing information about the class environment"
cl := Smalltalk at: tuple first asSymbol ifAbsent: [^ csBlock value: nil value: nil].
^(tuple size = 2 or: [tuple size > 2 and: [(tuple at: 2) ~= 'class']])
ifTrue: [csBlock value: cl value: (tuple at: 2) asSymbol]
ifFalse: [csBlock value: cl class value: (tuple at: 3) asSymbol]!
Item was changed:
----- Method: MessageTrace>>filteredSelectorsNamed: (in category 'filtering') -----
filteredSelectorsNamed: selectorSymbol
+ ^(SystemNavigation for: self environment) allImplementorsOf: selectorSymbol
- ^SystemNavigation new allImplementorsOf: selectorSymbol
!
Item was added:
+ ----- Method: Model>>environment (in category '*Tools') -----
+ environment
+ ^ (self selectedClass ifNil: [self class]) environment!
Item was added:
+ ----- Method: Object>>environment (in category '*Tools') -----
+ environment
+ "This is a fallback for models that do not inherit from Model or something else that provides
+ a useful Environment answer. You should consider copying this method to (base) classes of
+ objects from which you expect exactly the behavior below.
+ Absolutely feel free to override this method for objects that have or operate on a dedicated
+ environment, such as references to classes, code loaders, or tools."
+ ^ self class environment!
Item was changed:
StringHolder subclass: #Workspace
+ instanceVariableNames: 'bindings acceptDroppedMorphs acceptAction mustDeclareVariables shouldStyle environment'
- instanceVariableNames: 'bindings acceptDroppedMorphs acceptAction mustDeclareVariables shouldStyle'
classVariableNames: 'LookupPools ShouldStyle'
poolDictionaries: ''
category: 'Tools-Base'!
!Workspace commentStamp: 'fbs 6/2/2012 20:46' prior: 0!
A Workspace is a text area plus a lot of support for executable code. It is a great place to execute top-level commands to compute something useful, and it is a great place to develop bits of a program before those bits get put into class methods.
To open a new workspace, execute:
Workspace open
A workspace can have its own variables, called "workspace variables", to hold intermediate results. For example, if you type into a workspace "x := 5" and do-it, then later you could type in "y := x * 2" and y would become 10.
Additionally, in Morphic, a workspace can gain access to morphs that are on the screen. If acceptDroppedMorphs is turned on, then whenever a morph is dropped on the workspace, a variable will be created which references that morph. This functionality is toggled with the window-wide menu of a workspace.
The instance variables of this class are:
bindings - holds the workspace variables for this workspace
acceptDroppedMorphs - whether dropped morphs should create new variables!
Item was added:
+ ----- Method: Workspace>>environment (in category 'accessing') -----
+ environment
+ ^ environment ifNil: [Smalltalk globals]!
Item was added:
+ ----- Method: Workspace>>environment: (in category 'accessing') -----
+ environment: anEnvironment
+
+ environment := anEnvironment.!
Item was changed:
----- Method: Workspace>>initialize (in category 'initialize-release') -----
initialize
super initialize.
self initializeBindings.
acceptDroppedMorphs := false.
+ mustDeclareVariables := false.
+ environment := Environment current.!
- mustDeclareVariables := false!
David T. Lewis uploaded a new version of ToolBuilder-Kernel to project The Trunk:
http://source.squeak.org/trunk/ToolBuilder-Kernel-jr.109.mcz
==================== Summary ====================
Name: ToolBuilder-Kernel-jr.109
Author: jr
Time: 28 February 2017, 1:37:47.610081 am
UUID: edda3c34-f8df-fc4f-b6a5-6404053750f1
Ancestors: ToolBuilder-Kernel-tfel.108
offer a class selection from another environment
=============== Diff against ToolBuilder-Kernel-tfel.108 ===============
Item was changed:
----- Method: UIManager>>chooseClassOrTrait (in category 'ui requests') -----
chooseClassOrTrait
"Let the user choose a Class or Trait"
+ ^self chooseClassOrTraitFrom: Smalltalk globals!
- ^self chooseClassOrTrait: 'Class name or fragment?'!
Item was added:
+ ----- Method: UIManager>>chooseClassOrTraitFrom: (in category 'ui requests') -----
+ chooseClassOrTraitFrom: anEnvironment
+ "Let the user choose a Class or Trait from the given environment"
+
+ ^self chooseClassOrTrait: 'Class name or fragment?' from: anEnvironment!
Item was changed:
----- Method: UIManager>>classFromPattern:withCaption: (in category 'system introspecting') -----
classFromPattern: pattern withCaption: aCaption
+ ^self classFromPattern: pattern withCaption: aCaption in: Smalltalk environment
- "If there is a class or trait whose name exactly given by pattern, return it.
- If there is only one class or trait in the system whose name matches pattern, return it.
- Otherwise, put up a menu offering the names of all classes that match pattern, and return the class chosen, else nil if nothing chosen.
- This method ignores separator characters in the pattern"
-
- ^self classOrTraitFrom: Smalltalk environment pattern: pattern label: aCaption
"
self classFromPattern: 'CharRecog' withCaption: ''
self classFromPattern: 'rRecog' withCaption: ''
self classFromPattern: 'znak' withCaption: ''
self classFromPattern: 'orph' withCaption: ''
self classFromPattern: 'TCompil' withCaption: ''
"
!
Item was added:
+ ----- Method: UIManager>>classFromPattern:withCaption:in: (in category 'system introspecting') -----
+ classFromPattern: pattern withCaption: aCaption in: anEnvironment
+ "If there is a class or trait whose name exactly given by pattern, return it.
+ If there is only one class or trait in the system whose name matches pattern, return it.
+ Otherwise, put up a menu offering the names of all classes that match pattern, and return the class chosen, else nil if nothing chosen.
+ This method ignores separator characters in the pattern"
+
+ ^self classOrTraitFrom: anEnvironment pattern: pattern label: aCaption
+ "
+ for examples, see #classFromPattern:withCaption:
+ "
+ !
David T. Lewis uploaded a new version of Compiler to project The Trunk:
http://source.squeak.org/trunk/Compiler-jr.329.mcz
==================== Summary ====================
Name: Compiler-jr.329
Author: jr
Time: 28 February 2017, 12:19:04.434081 am
UUID: 6053da84-5a5b-b043-8dcc-019bc75762df
Ancestors: Compiler-nice.328
add method variants with environment parameters
=============== Diff against Compiler-nice.328 ===============
Item was added:
+ ----- Method: CompilationCue class>>source:context:class:environment:requestor: (in category 'instance creation') -----
+ source: aTextOrStream context: aContext class: aClass environment: anEnvironment requestor: reqObject
+ ^ self basicNew
+ initializeWithSource: aTextOrStream
+ context: aContext
+ receiver: (aContext ifNotNil: [aContext receiver])
+ class: aClass
+ environment: anEnvironment
+ requestor: reqObject!
Item was added:
+ ----- Method: CompilationCue class>>source:environment:requestor: (in category 'instance creation') -----
+ source: aString environment: anEnvironment requestor: aRequestor
+ ^ self
+ source: aString
+ context: nil
+ receiver: nil
+ class: UndefinedObject
+ environment: anEnvironment
+ requestor: aRequestor!
Item was added:
+ ----- Method: Compiler class>>evaluate:in:notifying:logged: (in category 'evaluating logged') -----
+ evaluate: textOrString in: anEnvironment notifying: aController logged: logFlag
+ "Compile and execute the argument, textOrString in anEnvironment.
+ If a compilation error occurs, notify aController. If both
+ compilation and execution are successful then, if logFlag is true, log
+ (write) the text onto a system changes file so that it can be replayed if
+ necessary."
+
+ ^ self new
+ evaluate: textOrString
+ in: anEnvironment
+ notifying: aController
+ logged: logFlag.!
Item was added:
+ ----- Method: Compiler>>compile:in:environment:notifying:ifFail: (in category 'public access') -----
+ compile: textOrStream in: aClass environment: anEnvironment notifying: aRequestor ifFail: failBlock
+ "Answer a MethodNode for the argument, textOrStream. If the
+ MethodNode can not be created, notify the argument, aRequestor; if
+ aRequestor is nil, evaluate failBlock instead. The MethodNode is the root
+ of a parse tree. It can be told to generate a CompiledMethod to be
+ installed in the method dictionary of the argument, aClass."
+
+ ^self
+ compileCue: (CompilationCue
+ source: textOrStream
+ class: aClass
+ environment: anEnvironment
+ requestor: aRequestor)
+ noPattern: false
+ ifFail: failBlock
+ !
Item was added:
+ ----- Method: Compiler>>compileNoPattern:in:context:environment:notifying:ifFail: (in category 'public access') -----
+ compileNoPattern: textOrStream in: aClass context: aContext environment: anEnvironment notifying: aRequestor ifFail: failBlock
+ "Similar to #compile:in:notifying:ifFail:, but the compiled code is
+ expected to be a do-it expression, with no message pattern,
+ and it will be in an explicit environment."
+
+ ^self
+ compileCue: (CompilationCue
+ source: textOrStream
+ context: aContext
+ class: aClass
+ environment: anEnvironment
+ requestor: aRequestor)
+ noPattern: true
+ ifFail: failBlock
+ !
Item was added:
+ ----- Method: Compiler>>evaluate:in:environment:notifying:ifFail:logged: (in category 'public access logging') -----
+ evaluate: textOrStream in: aContext environment: anEnvironment notifying: aRequestor ifFail: failBlock logged: logFlag
+ "Compiles the sourceStream into a parse tree, then generates code into
+ a method. If aContext is not nil, the text can refer to temporaries in that
+ context (the Debugger uses this). If aRequestor is not nil, then it will receive
+ a notify:at: message before the attempt to evaluate is aborted. Finally, the
+ compiled method is invoked from here via withArgs:executeMethod:, hence
+ the system no longer creates Doit method litter on errors."
+ ^self
+ evaluateCue: (CompilationCue
+ source: textOrStream
+ context: aContext
+ receiver: nil
+ class: UndefinedObject
+ environment: anEnvironment
+ requestor: aRequestor)
+ ifFail: failBlock
+ logged: logFlag!
Item was added:
+ ----- Method: Compiler>>evaluate:in:notifying:logged: (in category 'public access logging') -----
+ evaluate: textOrString in: anEnvironment notifying: aController logged: logFlag
+ "Compile and execute the argument, textOrString in anEnvironment.
+ If a compilation error occurs, notify aController. If both
+ compilation and execution are successful then, if logFlag is true, log
+ (write) the text onto a system changes file so that it can be replayed if
+ necessary."
+
+ ^self
+ evaluate: textOrString
+ in: nil
+ environment: anEnvironment
+ notifying: aController
+ ifFail: [^nil]
+ logged: logFlag!
Item was added:
+ ----- Method: Compiler>>evaluate:in:to:environment:notifying:ifFail:logged: (in category 'public access logging') -----
+ evaluate: textOrStream in: aContext to: receiver environment: anEnvironment notifying: aRequestor ifFail: failBlock logged: logFlag
+ "Same as #evaluate:in:to:notifying:ifFail:logged: but with an explicit environment"
+ | theClass |
+ theClass := (aContext == nil ifTrue: [receiver class] ifFalse: [aContext methodClass]).
+ ^self
+ evaluateCue: (CompilationCue
+ source: textOrStream
+ context: aContext
+ receiver: receiver
+ class: theClass
+ environment: anEnvironment
+ requestor: aRequestor)
+ ifFail: failBlock
+ logged: logFlag!