#UI_ENHANCEMENT
class: DoWhatIMeanSupport
comment/format in: #findNodeForInterval:in:allowErrors:mustBeMethod:mustBeExpression:
changed: #codeCompletionForMessage:into:
selectors already sent in the parsed method
are a very good heuristic hint.
Present them at top of the list.
--- a/DoWhatIMeanSupport.st Sun Jan 17 11:48:52 2016 +0100
+++ b/DoWhatIMeanSupport.st Sun Jan 17 22:26:26 2016 +0100
@@ -2290,14 +2290,20 @@
allBest := (bestSelectors3 ? #()) , allBest.
allBest isEmptyOrNil ifTrue:[ ^ self ].
+ "/ the one's which are a prefix are moved towards the top of the list
+ allBest := split value:allBest value:[:sel | sel notNil and:[sel startsWith:selector]].
+
+ rememberedNodes notNil ifTrue:[
+ selectorsSentInCode :=
+ (rememberedNodes
+ select:[:node | node isMessage]
+ thenCollect:[:node | node selector]) asSet.
+ selectorsSentInCode remove:selector ifAbsent:[].
+ ].
selectorsSentInCode notNil ifTrue:[
"/ the one's already sent in the code are moved to the top of the list.
allBest := split value:allBest value:[:sel | selectorsSentInCode includes:sel].
].
-
- "/ the one's which are a prefix are moved towards the top of the list
- allBest := split value:allBest value:[:sel | sel notNil and:[sel startsWith:selector]].
-
"/false ifTrue:[
"/ srchClass notNil ifTrue:[
"/ implClass := srchClass whichClassIncludesSelector:best.
@@ -3366,19 +3372,19 @@
interval isEmpty ifTrue: [^ nil].
languageOrNil notNil ifTrue:[
- parserClass := languageOrNil parserClass.
+ parserClass := languageOrNil parserClass.
] ifFalse:[
- classOrNil notNil ifTrue:[
- parserClass := classOrNil programmingLanguage parserClass.
- ]
+ classOrNil notNil ifTrue:[
+ parserClass := classOrNil programmingLanguage parserClass.
+ ]
].
parserClass notNil ifTrue:[
- "/ hack
- parserClass == Parser ifTrue: [
- parserClass := RBParser.
- ].
+ "/ hack
+ parserClass == Parser ifTrue: [
+ parserClass := RBParser.
+ ].
] ifFalse:[
- parserClass := RBParser.
+ parserClass := RBParser.
].
parserClass isNil ifTrue: [^ nil].
@@ -3387,136 +3393,136 @@
"/ LastSource := nil.
source = LastSource ifTrue:[
- tree := LastParseTree.
- tokens := LastScanTokens.
+ tree := LastParseTree.
+ tokens := LastScanTokens.
] ifFalse:[
- intersectingNodes := OrderedCollection new.
- currentScopeNodes := IdentitySet new.
-
- onErrorBlock :=
- [:str :err :nodesSoFar |
- |nodes|
-
- allowErrors ifTrue:[
- rememberedScopeNodes := currentScopeNodes.
- firstIntersectingNode notNil ifTrue:[
- ^ firstIntersectingNode
- ].
- nodesSoFar notNil ifTrue:[
- nodes := nodesSoFar asOrderedCollection
- collect:[:nd | nd whichNodeIntersects:interval]
- thenSelect:[:nd | nd notNil ].
- nodes size == 1 ifTrue:[
- ^ nodes first
- ].
- ]
- ].
- nil
- ].
-
- self debuggingCodeFor:#cg is:[
- Transcript show:'looking for: '; showCR:interval.
- ].
-
- nodeGenerationHook :=
- [:node |
- rememberedNodes add:node.
-
- "/ would like to return here as soon as the node has been created by the parser;
- "/ however, at that time, its parent(chain) is not yet created and so we might not know
- "/ what the semantic interpretation (especially: scope of variable) will be.
- "/ therefore, we parse all, and return the found node at the end.
- (node isMethod or:[node isBlock or:[node isSequence]]) ifTrue:[
- currentScopeNodes add:node.
- ] ifFalse:[
- self debuggingCodeFor:#cg is:[
- Transcript show:node; show:' '; show:node start; show:'->'; showCR:node stop.
- ].
-
- (node intersectsInterval:interval) ifTrue:[
- self debuggingCodeFor:#cg is:[
- Transcript showCR:'yes'.
- ].
- intersectingNodes add:node.
- firstIntersectingNode isNil ifTrue:[
- firstIntersectingNode := lastIntersectingNode := smallestIntersectingNode := node
- ] ifFalse:[
- |lenNode lenSmallest|
-
- lenNode := (node stop - node start).
- lenSmallest := (smallestIntersectingNode stop - smallestIntersectingNode start).
- lenNode < lenSmallest ifTrue:[
- smallestIntersectingNode := node.
- ].
- node start > lastIntersectingNode start ifTrue:[
- lastIntersectingNode := node.
- ].
- ].
- ].
- ].
- ].
-
- "/ one of the big problems when using the RBParser here is
- "/ that it behaves badly when a syntax error is encountered;
- "/ for example, a node's parent is usually set AFTER the children are
- "/ completely parsed (for example, a blockNode gets the parent-method only
- "/ after parsing). Thus, when an error is encountered, we cannot walk
- "/ the parent chain, and therefore will not see the outer locals/args of
- "/ an inner scope (allVariablesOnScope returns only a partial set).
- "/ A walkaround is to remember Method/Block nodes as created in the above node generation.
- "/ The disadvantage of it is that we do not have correct scope information, until the nodes
- "/ parent gets set eventually, this we might consider locals from sibling blocks.
- "/ See rememberedScopeNodes handling above.
- "/ Those other nodes are only remembered for failed parses;
- "/ if the parse is ok, rememberedScopeNodes will be nil.
-
- mustBeExpression ifFalse:[
- tree := parserClass
- parseMethod: source
- setup:[:p |
- parser := p.
- p rememberNodes:true.
- p rememberTokens:true.
- p nodeGenerationCallback:nodeGenerationHook
- ]
- onError: onErrorBlock.
- parser notNil ifTrue:[ tokens := parser rememberedTokens ].
- ].
-
- mustBeMethod ifTrue:[
- "/ only cache parsed methods
- tree notNil ifTrue:[
- LastSource := source.
- LastParseTree := tree.
- LastScanTokens := tokens.
- ].
- ] ifFalse:[
- (tree isNil or:[firstIntersectingNode isNil]) ifTrue:[
- "/ try as an expression
- tree := parserClass
- parseExpression: source
- setup:[:p |
- parser := p.
- p rememberNodes:true.
- p rememberTokens:true.
- p nodeGenerationCallback:nodeGenerationHook
- ]
- onError: onErrorBlock.
- parser notNil ifTrue:[ tokens := parser rememberedTokens ].
- ].
- ].
- lastIntersectingNode notNil ifTrue:[
- self debuggingCodeFor:#cg is:[
- Transcript show:'last: '; showCR:lastIntersectingNode.
- ].
- ^ lastIntersectingNode
- ].
- "/ firstIntersectingNode notNil ifTrue:[ ^ firstIntersectingNode ].
+ intersectingNodes := OrderedCollection new.
+ currentScopeNodes := IdentitySet new.
+
+ onErrorBlock :=
+ [:str :err :nodesSoFar |
+ |nodes|
+
+ allowErrors ifTrue:[
+ rememberedScopeNodes := currentScopeNodes.
+ firstIntersectingNode notNil ifTrue:[
+ ^ firstIntersectingNode
+ ].
+ nodesSoFar notNil ifTrue:[
+ nodes := nodesSoFar asOrderedCollection
+ collect:[:nd | nd whichNodeIntersects:interval]
+ thenSelect:[:nd | nd notNil ].
+ nodes size == 1 ifTrue:[
+ ^ nodes first
+ ].
+ ]
+ ].
+ nil
+ ].
+
+ self debuggingCodeFor:#cg is:[
+ Transcript show:'looking for: '; showCR:interval.
+ ].
+
+ nodeGenerationHook :=
+ [:node |
+ rememberedNodes add:node.
+
+ "/ would like to return here as soon as the node has been created by the parser;
+ "/ however, at that time, its parent(chain) is not yet created and so we might not know
+ "/ what the semantic interpretation (especially: scope of variable) will be.
+ "/ therefore, we parse all, and return the found node at the end.
+ (node isMethod or:[node isBlock or:[node isSequence]]) ifTrue:[
+ currentScopeNodes add:node.
+ ] ifFalse:[
+ self debuggingCodeFor:#cg is:[
+ Transcript show:node; show:' '; show:node start; show:'->'; showCR:node stop.
+ ].
+
+ (node intersectsInterval:interval) ifTrue:[
+ self debuggingCodeFor:#cg is:[
+ Transcript showCR:'yes'.
+ ].
+ intersectingNodes add:node.
+ firstIntersectingNode isNil ifTrue:[
+ firstIntersectingNode := lastIntersectingNode := smallestIntersectingNode := node
+ ] ifFalse:[
+ |lenNode lenSmallest|
+
+ lenNode := (node stop - node start).
+ lenSmallest := (smallestIntersectingNode stop - smallestIntersectingNode start).
+ lenNode < lenSmallest ifTrue:[
+ smallestIntersectingNode := node.
+ ].
+ node start > lastIntersectingNode start ifTrue:[
+ lastIntersectingNode := node.
+ ].
+ ].
+ ].
+ ].
+ ].
+
+ "/ one of the big problems when using the RBParser here is
+ "/ that it behaves badly when a syntax error is encountered;
+ "/ for example, a node's parent is usually set AFTER the children are
+ "/ completely parsed (for example, a blockNode gets the parent-method only
+ "/ after parsing). Thus, when an error is encountered, we cannot walk
+ "/ the parent chain, and therefore will not see the outer locals/args of
+ "/ an inner scope (allVariablesOnScope returns only a partial set).
+ "/ A walkaround is to remember Method/Block nodes as created in the above node generation.
+ "/ The disadvantage of it is that we do not have correct scope information, until the node's
+ "/ parent gets set eventually, thus we might consider locals from sibling blocks.
+ "/ See rememberedScopeNodes handling above.
+ "/ Those other nodes are only remembered for failed parses;
+ "/ if the parse is ok, rememberedScopeNodes will be nil.
+
+ mustBeExpression ifFalse:[
+ tree := parserClass
+ parseMethod: source
+ setup:[:p |
+ parser := p.
+ p rememberNodes:true.
+ p rememberTokens:true.
+ p nodeGenerationCallback:nodeGenerationHook
+ ]
+ onError: onErrorBlock.
+ parser notNil ifTrue:[ tokens := parser rememberedTokens ].
+ ].
+
+ mustBeMethod ifTrue:[
+ "/ only cache parsed methods
+ tree notNil ifTrue:[
+ LastSource := source.
+ LastParseTree := tree.
+ LastScanTokens := tokens.
+ ].
+ ] ifFalse:[
+ (tree isNil or:[firstIntersectingNode isNil]) ifTrue:[
+ "/ try as an expression
+ tree := parserClass
+ parseExpression: source
+ setup:[:p |
+ parser := p.
+ p rememberNodes:true.
+ p rememberTokens:true.
+ p nodeGenerationCallback:nodeGenerationHook
+ ]
+ onError: onErrorBlock.
+ parser notNil ifTrue:[ tokens := parser rememberedTokens ].
+ ].
+ ].
+ lastIntersectingNode notNil ifTrue:[
+ self debuggingCodeFor:#cg is:[
+ Transcript show:'last: '; showCR:lastIntersectingNode.
+ ].
+ ^ lastIntersectingNode
+ ].
+ "/ firstIntersectingNode notNil ifTrue:[ ^ firstIntersectingNode ].
].
bestNode := self findNodeForInterval:interval inParseTree:tree.
self debuggingCodeFor:#cg is:[
- Transcript show:'best: '; showCR:bestNode.
+ Transcript show:'best: '; showCR:bestNode.
].
^ bestNode