argument-name completion in a methods selector pattern
authorClaus Gittinger <cg@exept.de>
Thu, 10 Jan 2008 13:02:28 +0100
changeset 3306 40e860fd2f02
parent 3305 4fa0a476b474
child 3307 15f429081b7c
argument-name completion in a methods selector pattern
DoWhatIMeanSupport.st
--- a/DoWhatIMeanSupport.st	Wed Jan 09 21:41:17 2008 +0100
+++ b/DoWhatIMeanSupport.st	Thu Jan 10 13:02:28 2008 +0100
@@ -62,8 +62,9 @@
 
     interval := codeView selectedInterval.
     interval isEmpty ifTrue:[
-        crsrPos := codeView characterPositionOfCursor - 1.
-        char := codeView characterUnderCursor.
+        crsrPos := codeView characterPositionOfCursor-1.
+        char := codeView characterAtCharacterPosition:crsrPos.
+
         [crsrPos > 1 and:[char isSeparator or:['.' includes:char]]] whileTrue:[
             crsrPos := crsrPos - 1.
             char := codeView characterAtCharacterPosition:crsrPos.
@@ -77,6 +78,8 @@
     [node isNil] whileTrue:[
         "/ expand to the left ...
         interval start > 1 ifFalse:[
+            crsrPos := codeView characterPositionOfCursor.
+self halt.
             self information:'No parseNode found'.
             ^ self.
         ].
@@ -92,10 +95,12 @@
     checkedNode := node.
     [checkedNode notNil] whileTrue:[
         checkedNode isMessage ifTrue:[
+            "/ completion in a message-send
             self codeCompletionForMessage:checkedNode inClass:cls codeView:codeView.
             ^ self
         ].
         checkedNode isMethod ifTrue:[
+            "/ completion in a methods selector pattern
             self codeCompletionForMethod:checkedNode inClass:cls codeView:codeView.
             ^ self.
         ].
@@ -320,14 +325,18 @@
 !
 
 codeCompletionForMethod:node inClass:cls codeView:codeView
+    "completion in a methods selector pattern"
+
     |crsrPos
      selectorSoFar matchingSelectors
-     selectors distances best rest|
+     selectors distances best rest 
+     allExistingMethods namesOfArguments 
+     nameBag namesByCount|  
 
     crsrPos := codeView characterPositionOfCursor - 1.
 
     selectorSoFar := ''.
-    node selectorParts do:[:partToken |
+    node selectorParts doWithIndex:[:partToken :argNr|
         |part|
 
         part := partToken value.
@@ -349,23 +358,48 @@
                                         theSet.
                                     ].
             selectors := matchingSelectors asOrderedCollection.
-            distances := selectors collect:[:each | each spellAgainst:selectorSoFar].
-            distances sortWith:selectors.
-            selectors reverse.
-            best := self askUserForCompletion:'selector' for:codeView from:selectors.
-            best isNil ifTrue:[^ self].
+            "/ if there is only one, and user has already entered it, he might want to complete the argument-name    
+            (selectors size == 1 
+            and:[selectors first = selectorSoFar]) ifTrue:[
+                allExistingMethods := (Smalltalk allImplementorsOf:selectorSoFar asSymbol)
+                                            collect:[:cls | cls compiledMethodAt:selectorSoFar asSymbol].
+                namesOfArguments := allExistingMethods collect:[:eachMethod | eachMethod methodArgNames].
+                nameBag := Bag new.
+                namesOfArguments do:[:eachNameVector | nameBag add:(eachNameVector at:argNr)].
+                namesByCount := nameBag valuesAndCounts sort:[:a :b | a value < b value].   
+                "/ take the one which occurs most often     
+                best := self askUserForCompletion:'argument' for:codeView from:(namesByCount collect:[:a | a key]).
 
-            rest := best copyFrom:selectorSoFar size.
-            codeView
-                undoableDo:[ 
-                    codeView 
-                        replaceFromCharacterPosition:crsrPos 
-                        to:crsrPos 
-                        with:rest 
-                ]
-                info:'completion'.
-            codeView cursorToCharacterPosition:(crsrPos + rest size - 1).    
-            codeView cursorRight.    
+                codeView
+                    undoableDo:[
+                        (crsrPos+1) >= codeView contents size ifTrue:[
+                            codeView paste:best.
+                        ] ifFalse:[
+                            codeView insertString:best atCharacterPosition:crsrPos+1.
+                        ]
+                    ]
+                    info:'completion'.
+                codeView cursorToCharacterPosition:(crsrPos + best size - 1).    
+            ] ifFalse:[
+                distances := selectors collect:[:each | each spellAgainst:selectorSoFar].
+                distances sortWith:selectors.
+                selectors reverse.
+                best := self askUserForCompletion:'selector' for:codeView from:selectors.
+                best isNil ifTrue:[^ self].
+
+                rest := best copyFrom:selectorSoFar size.
+
+                codeView
+                    undoableDo:[ 
+                        codeView 
+                            replaceFromCharacterPosition:crsrPos 
+                            to:crsrPos 
+                            with:rest 
+                    ]
+                    info:'completion'.
+                codeView cursorToCharacterPosition:(crsrPos + rest size - 1).    
+            ].
+            codeView cursorRight. "/ kludge to make it visible   
         ].
     ].
 
@@ -615,7 +649,7 @@
 !
 
 findNodeForInterval:interval in:source allowErrors:allowErrors
-    |tree node "errCount"|
+    |tree "errCount"|
 
     interval isEmpty ifTrue: [^ nil].
     RBParser isNil ifTrue: [^ nil].
@@ -626,8 +660,9 @@
                                 |nodes|
 
                                 allowErrors ifTrue:[
-                                    nodes := nodesSoFar collect:[:nd | nd whichNodeIntersects:interval].
-                                    nodes := nodes select:[:nd | nd notNil ].
+                                    nodes := nodesSoFar 
+                                                collect:[:nd | nd whichNodeIntersects:interval]
+                                                thenSelect:[:nd | nd notNil ].
                                     nodes size == 1 ifTrue:[
                                         ^ nodes first
                                     ].
@@ -637,11 +672,18 @@
 "/                onError: [:str :err | errCount := (errCount?0) + 1. self halt.]
 "/                proceedAfterError:true.
 
-    tree isNil ifTrue:[^ nil].
+    ^ self findNodeForInterval:interval inParseTree:tree.
+!
+
+findNodeForInterval:interval inParseTree:parseTree
+    |node|
 
-    node := tree whichNodeIsContainedBy:interval.
+    interval isEmpty ifTrue: [^ nil].
+    parseTree isNil ifTrue:[^ nil].
+
+    node := parseTree whichNodeIsContainedBy:interval.
     node isNil ifTrue: [
-        node := self findNodeIn:tree forInterval:interval
+        node := self findNodeIn:parseTree forInterval:interval
     ].
     ^ node
 
@@ -1482,5 +1524,5 @@
 !DoWhatIMeanSupport class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libwidg2/DoWhatIMeanSupport.st,v 1.25 2008-01-07 13:49:18 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libwidg2/DoWhatIMeanSupport.st,v 1.26 2008-01-10 12:02:28 cg Exp $'
 ! !