--- a/DoWhatIMeanSupport.st Sun May 01 22:09:43 2016 +0200
+++ b/DoWhatIMeanSupport.st Mon May 02 14:10:20 2016 +0200
@@ -1,5 +1,3 @@
-"{ Encoding: utf8 }"
-
"
COPYRIGHT (c) 2002 by eXept Software AG
All Rights Reserved
@@ -1214,7 +1212,7 @@
!
codeCompletionForLanguage: languageOrNil class: classOrNilArg context:contextOrNilArg codeView:codeViewArg
- "OBSOLETE; migrating to use the the new 'xxx: into:' protocol.
+ "going to become OBSOLETE; migrating to use the the new 'xxx: into:' protocol.
contextOrNil is the current context, if this is called from the debugger;
nil, if called from the browser.
If nonNil, we can make better guesses,
@@ -1621,6 +1619,46 @@
!DoWhatIMeanSupport methodsFor:'code completion-helpers'!
+addClassesOfExpression:expr inClass:aClass to:setOfTypes
+ |cls exprSelector val|
+
+ expr isConstant ifTrue:[
+ val := expr evaluate.
+ cls := val class.
+ (val isArray or:[ val isByteArray or:[ val isString ]]) ifTrue:[
+ val isImmutable ifTrue:[
+ setOfTypes add:cls mutableClass.
+ ^ self.
+ ]
+ ].
+ setOfTypes add:cls.
+ ^ self.
+ ].
+
+ expr isMessage ifTrue:[
+ exprSelector := expr selector.
+ ( #(+ - * /) includes:exprSelector ) ifTrue:[
+ setOfTypes add:Number.
+ ^ self.
+ ].
+ ( #(// size) includes:exprSelector ) ifTrue:[
+ setOfTypes add:Integer.
+ ^ self.
+ ].
+ ( #(copy shallowCopy) includes:exprSelector ) ifTrue:[
+ "/ self addClassesOfExpression:expression receiver inClass:aClass to:setOfTypes
+ ^ self.
+ ].
+ ( #(new new: basicNew basicNew:) includes:exprSelector ) ifTrue:[
+ expr receiver isGlobal ifTrue:[
+ setOfTypes add:expr receiver evaluate.
+ ^ self.
+ ].
+ ].
+self breakPoint:#cg.
+ ].
+!
+
askUserForCompletion:what for:codeView at:position from:allTheBest
|list choice lastChoice|
@@ -1724,6 +1762,25 @@
^ nil
!
+classesFromAssignmentTo:varName in:aTree
+ |classesFromAssignments|
+
+ classesFromAssignments := Set new.
+ "/ assignments...
+ aTree allAssignmentNodesDo:[:eachAssignmentNode |
+ |exprCls leftSide|
+
+ leftSide := eachAssignmentNode variable.
+ leftSide name = varName ifTrue:[
+ exprCls := self classOfNode:eachAssignmentNode value.
+ exprCls notNil ifTrue:[
+ classesFromAssignments add:exprCls
+ ]
+ ]
+ ].
+ ^ classesFromAssignments.
+!
+
classesOfInstVarNamed:varName inClass:aClass
|setOfTypes instIndex|
@@ -1751,30 +1808,32 @@
visitor
actionForNodeClass:AssignmentNode
put:[:node |
- |val|
+ |val expr exprSelector|
node variable name = varName ifTrue:[
+ expr := node expression.
"/ only look for wellknown types on the right side.
- node expression isConstant ifTrue:[
- val := node expression evaluate.
+ expr isConstant ifTrue:[
+ val := expr evaluate.
val isArray ifTrue:[
setOfTypes add:Array
] ifFalse:[
setOfTypes add:val class
].
] ifFalse:[
- node expression isMessage ifTrue:[
- ( #(+ - * /) includes:node expression selector ) ifTrue:[
+ expr isMessage ifTrue:[
+ exprSelector := expr selector.
+ ( #(+ - * /) includes:exprSelector ) ifTrue:[
setOfTypes add:Number
] ifFalse:[
- ( #(// size) includes:node expression selector ) ifTrue:[
+ ( #(// size) includes:exprSelector ) ifTrue:[
setOfTypes add:Integer
] ifFalse:[
- ( #(copy shallowCopy) includes:node expression selector ) ifTrue:[
+ ( #(copy shallowCopy) includes:exprSelector ) ifTrue:[
] ifFalse:[
- ( #(new new: basicNew basicNew:) includes:node expression selector ) ifTrue:[
- node expression receiver isGlobal ifTrue:[
- setOfTypes add:node expression receiver evaluate
+ ( #(new new: basicNew basicNew:) includes:exprSelector ) ifTrue:[
+ expr receiver isGlobal ifTrue:[
+ setOfTypes add:expr receiver evaluate
].
] ifFalse:[
self breakPoint:#cg.
@@ -2063,7 +2122,8 @@
receiverNodeClassIfKnown
offerParenthisationAroundNode parenthesisAroundIndex
parentNodeToParenthesize
- classesFromAssignmentsToReceiver otherMessagesToReceiver|
+ classesFromAssignmentsToReceiver otherMessagesToReceiver
+ canParenthesize|
"/ Transcript show:'node '; show:node; show:' ; '.
"/ Transcript show:'msg in '; show:methodOrNil; show:' / '; showCR:classOrNil.
@@ -2131,7 +2191,7 @@
lcSelector := selector asLowercase.
parentNode := node parent.
nodeReceiver := node receiver.
-
+
"/ if there is already space before the cursor, and the parent node is not a message,
"/ do not attempt to complete the current message.
"/ If it is a message, we will look for parent-message completion also below (best2 stuff)
@@ -2161,43 +2221,12 @@
receiverName := nodeReceiver name.
- classesFromAssignmentsToReceiver := Set new.
- "/ assignments...
- tree allAssignmentNodesDo:[:eachAssignmentNode |
- |exprCls leftSide|
-
- leftSide := eachAssignmentNode variable.
- leftSide name = receiverName ifTrue:[
- exprCls := self classOfNode:eachAssignmentNode value.
- exprCls notNil ifTrue:[
- classesFromAssignmentsToReceiver add:exprCls
- ]
- ]
- ].
+ classesFromAssignmentsToReceiver := self classesFromAssignmentTo:receiverName in:tree.
+
possibleClasses := classesFromAssignmentsToReceiver.
-
possibleClasses isEmpty ifTrue:[
"/ messages sent
- otherMessagesToReceiver := Set new.
- rememberedNodes notNil ifTrue:[
- rememberedNodes do:[:node |
- (node isMessage
- and:[node receiver isVariable
- and:[node receiver name = nodeReceiver name]]) ifTrue:[
- selector ~= node selector ifTrue:[
- otherMessagesToReceiver add:(node selector)
- ].
- ].
- ].
- ] ifFalse:[
- tree allMessageNodesDo:[:eachMessageNode |
- (nodeReceiver = eachMessageNode receiver
- and:[ selector ~= eachMessageNode selector]
- ) ifTrue:[
- otherMessagesToReceiver add:eachMessageNode selector
- ]
- ].
- ].
+ otherMessagesToReceiver := self messagesSentTo:receiverName in:tree.
otherMessagesToReceiver remove:selector ifAbsent:[].
otherMessagesToReceiver notEmpty ifTrue:[
@@ -2287,7 +2316,7 @@
] ifFalse:[
"/ when completing a non-keyword AND the parent is a keyword message,
"/ only consider longer keyword messages or unary messages
- (parentNode notNil and:[ parentNode isMessage and:[parentNode selector isKeywordSelector ]]) ifTrue:[
+ (parentNode notNil and:[ parentNode isKeywordMessage ]) ifTrue:[
bestSelectors := bestSelectors select:[:sel | sel isUnarySelector ]
]
].
@@ -2296,12 +2325,12 @@
"/ bestSelectors sort:[:a :b | a size < b size].
(selector isUnarySelector and:[ parentNode notNil and:[ parentNode isMessage ]]) ifTrue:[
- (selector2 := parentNode selector) isKeywordSelector ifTrue:[
+ (selector2 := parentNode selector) isKeyword ifTrue:[
"/ if its a unary message AND the parent is a keyword node, look for parent completion too.
"/ i.e. look if there is a longer keyword possible
selector2 := selector2,selector.
bestSelectors2 := findBest value:(parentNode receiver) value:selector2.
- bestSelectors2 := bestSelectors2 select:[:sel | sel isKeywordSelector and:[ sel startsWith:selector2]].
+ bestSelectors2 := bestSelectors2 select:[:sel | sel isKeyword and:[ sel startsWith:selector2]].
bestSelectors2 := bestSelectors2 asOrderedCollection sort:[:a :b | a size < b size].
bestSelectors := bestSelectors reject:[:sel | bestSelectors2 includes:sel].
@@ -2338,7 +2367,7 @@
"/ arg
kwSels := findBest value:parentNode value:selector.
- kwSels := kwSels select:[:sel | sel isKeywordSelector].
+ kwSels := kwSels select:[:sel | sel isKeyword].
kwSels := kwSels asOrderedCollection sort:[:a :b | a size < b size].
@@ -2380,11 +2409,27 @@
forPartial:selector.
].
].
- (parentNode notNil
- and:[ parentNode isMessage
- and:[ ((parentNode selector isUnarySelector not) and:[selector isUnarySelector])
- or:[ ((parentNode selector isKeywordSelector) and:[selector isBinarySelector]) ]]]
- ) ifTrue:[
+
+ Transcript show:'parentNode: '; showCR:parentNode.
+ Transcript show:'parentNode: '; showCR:parentNode class.
+ Transcript show:'sel: '; showCR:selector.
+
+ canParenthesize := false.
+ parentNode notNil ifTrue:[
+ parentNode isMessage ifTrue:[
+ (((parentNode selector isUnarySelector not) and:[selector isUnarySelector])
+ or:[ ((parentNode selector isKeyword) and:[selector isBinarySelector]) ]) ifTrue:[
+ canParenthesize := true.
+ ]
+ ] ifFalse:[
+ offerParenthisationAroundNode isNil ifTrue:[
+ selector isKeyword ifTrue:[
+ offerParenthisationAroundNode := node.
+ ].
+ ].
+ ].
+ ].
+ canParenthesize ifTrue:[
"/ completing an already existing keyword or binary message with something starting with
"/ if, and, or or while.
"/ Here, offer a special completion which inserts parenthesis / brackets around the already
@@ -2436,33 +2481,7 @@
].
allBest := (bestSelectors ? #()) , (bestSelectors2 ? #()).
- allBest sort:
- [:a :b |
- |aBeforeB|
-
- (a startsWith:selector) ifTrue:[
- (b startsWith:selector) ifFalse:[
- aBeforeB := true
- ]
- ] ifFalse:[
- (b startsWith:selector) ifTrue:[
- aBeforeB := false
- ]
- ].
- aBeforeB isNil ifTrue:[
- aBeforeB := a asLowercase < b asLowercase.
- (a asLowercase startsWith:lcSelector) ifTrue:[
- (b asLowercase startsWith:lcSelector) ifFalse:[
- aBeforeB := true
- ]
- ] ifFalse:[
- (b asLowercase startsWith:lcSelector) ifTrue:[
- aBeforeB := false
- ]
- ].
- ].
- aBeforeB
- ].
+ self sortSelectors:allBest forSelector:selector lcSelector:lcSelector.
split :=
[:list :splitHow |
@@ -2847,6 +2866,7 @@
suggestions := selectorsImplementedInClass asNewOrderedCollection sort.
].
+ suggestions := suggestions reject:[:sel | sel first == $_].
self sortUsefulSelectorsIn:suggestions. "/cosmetics
pos := codeView characterPositionOfCursor.
@@ -3164,7 +3184,6 @@
selectors0 notEmptyOrNil ifTrue:[
selectors := selectors0,selectors.
].
-
editAction :=
[:selectedCompletionIndex |
@@ -3409,7 +3428,11 @@
ifTrue:[ otherArgNames addAll:(parseTree arguments collect:[:each | each name])] ].
addWithFactorBlock value:otherArgNames value:(1.5 * localFactor).
].
- addWithFactorBlock value:(codeView previousReplacements collect:[:p | p value asString]) value:(1.3 * localFactor).
+ addWithFactorBlock
+ value:(codeView previousReplacements
+ collect:[:p | p value asString]
+ thenSelect:[:s | s isValidSmalltalkIdentifier])
+ value:(1.3 * localFactor).
] ifFalse:[
"/ locals in the block/method
|names nameSpace|
@@ -4125,6 +4148,32 @@
].
!
+messagesSentTo:varName in:aTree
+ |messagesToReceiver|
+
+ "/ collect messages sent
+ messagesToReceiver := Set new.
+ "/ remembered nodes is nonNil if parser aborte with error
+ rememberedNodes notNil ifTrue:[
+ rememberedNodes do:[:node |
+ (node isMessage
+ and:[node receiver isVariable
+ and:[node receiver name = varName]]) ifTrue:[
+ messagesToReceiver add:(node selector)
+ ].
+ ].
+ ] ifFalse:[
+ tree allMessageNodesDo:[:node |
+ (node isMessage
+ and:[node receiver isVariable
+ and:[node receiver name = varName]]) ifTrue:[
+ messagesToReceiver add:node selector
+ ]
+ ].
+ ].
+ ^ messagesToReceiver
+!
+
old_askUserForCompletion:what for:codeView from:allTheBest
|list resources choice lastChoice|
@@ -4188,6 +4237,35 @@
"Modified: / 28-08-2013 / 15:28:01 / cg"
!
+sortSelectors:list forSelector:selector lcSelector:lcSelector
+ list sort: [:a :b |
+ |aBeforeB|
+
+ (a startsWith:selector) ifTrue:[
+ (b startsWith:selector) ifFalse:[
+ aBeforeB := true
+ ]
+ ] ifFalse:[
+ (b startsWith:selector) ifTrue:[
+ aBeforeB := false
+ ]
+ ].
+ aBeforeB isNil ifTrue:[
+ aBeforeB := a asLowercase < b asLowercase.
+ (a asLowercase startsWith:lcSelector) ifTrue:[
+ (b asLowercase startsWith:lcSelector) ifFalse:[
+ aBeforeB := true
+ ]
+ ] ifFalse:[
+ (b asLowercase startsWith:lcSelector) ifTrue:[
+ aBeforeB := false
+ ]
+ ].
+ ].
+ aBeforeB
+ ].
+!
+
sortUsefulSelectorsIn:selectorList
"/ cosmetics:
"/ ifTrue / whileTrue should come before ifFalse/whileFalse
@@ -4323,7 +4401,8 @@
self codeCompletionForVariable:node into:actionBlock.
^ self.
].
- ].
+ ].
+ "/ nodeParent isNil or:[nodeParent isMessage not]
].
false ifTrue:[
@@ -4407,32 +4486,29 @@
].
- "/ Transcript show:'node is ';showCR:node.
+ Transcript show:'node is '.
+ Error ignoreIn:[ Transcript show:node ].
+ Transcript cr.
+
+ (node isVariable or:[node isBlock and:[node stop notNil]]) ifTrue:[
+ (characterPositionOfCursor == (node stop + 1)
+ "/ hack (spaces at end of line)
+ or:[characterPositionOfCursor == (node stop)]) ifTrue:[
+ codeView characterBeforeCursor == Character space ifTrue:[
+ self codeCompletionForMessageTo:node into:actionBlock.
+ ^ self
+ ].
+ ].
+ ].
"/ move outward, until we find a message-send node,
"/ or the method's selector pattern node.
checkedNode := node.
[checkedNode notNil] whileTrue:[
- (characterPositionOfCursor < (checkedNode stop ? source size)) ifTrue:[
+ (characterPositionOfCursor <= (checkedNode stop ? source size)) ifTrue:[
"/ Transcript show:'T: '; showCR:node.
- "/ Transcript showCR:('Inside a ',(checkedNode className)).
- self information:('Inside a ',(checkedNode className)).
- (node isVariable or:[node isBlock and:[node stop notNil]]) ifTrue:[
- characterPositionOfCursor == (node stop + 1) ifTrue:[
- codeView characterBeforeCursor == Character space ifTrue:[
- self codeCompletionForMessageTo:node into:actionBlock.
- ^ self
- ].
- ].
- characterPositionOfCursor == (node stop) ifTrue:[
- "/ hack (spaces at end of line)
- codeView characterBeforeCursor == Character space ifTrue:[
- self codeCompletionForMessageTo:node into:actionBlock.
- ^ self
- ]
- ].
- ].
-
+ Transcript showCR:('Inside a ',(checkedNode className)).
+ "/ self information:('Inside a ',(checkedNode className)).
(checkedNode isMessage
and:[characterPositionOfCursor < (checkedNode selectorParts first start)]) ifTrue:[
self codeCompletionForMessageTo:checkedNode receiver into:actionBlock.