SmallSense__CompletionController.st
changeset 117 441529422c2f
child 118 88e6fd734a11
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SmallSense__CompletionController.st	Wed Oct 02 13:37:01 2013 +0100
@@ -0,0 +1,204 @@
+"{ Package: 'jv:smallsense' }"
+
+"{ NameSpace: SmallSense }"
+
+EditTextViewCompletionSupport subclass:#CompletionController
+	instanceVariableNames:'support'
+	classVariableNames:''
+	poolDictionaries:''
+	category:'SmallSense-Core'
+!
+
+!CompletionController methodsFor:'accessing'!
+
+support
+    ^ support
+!
+
+support:anEditSupport
+    support := anEditSupport.
+! !
+
+!CompletionController methodsFor:'events'!
+
+handleKeyPress:key x:x y:y
+
+    key == #Control_L ifTrue:[
+        completionView notNil ifTrue:[
+            ^ false.
+        ].
+    ].
+
+    key == #CodeCompletion  ifTrue: [
+        autoSelect := true.    
+        self startCompletionProcess.
+        ^ true
+    ].
+
+    (key == #BackSpace or:[key == #BasicBackspace]) ifTrue:[
+        | c |
+
+        c := editView characterBeforeCursor.
+        (c notNil and:[c isAlphaNumeric]) ifTrue:[
+             ^ false
+        ].
+    ].     
+
+
+    completionView notNil ifTrue:[
+        (key == #Return and:[completionView hasSelection]) ifTrue:[
+            self complete.
+            ^ true.
+        ].
+        key isCharacter ifTrue:[
+            self updateSelection.
+        ].
+    ].
+    ^ super handleKeyPress:key x:x y:y
+
+    "Created: / 27-09-2013 / 15:38:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 30-09-2013 / 15:00:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+postKeyPress:key
+    UserPreferences current immediateCodeCompletion ifFalse:[
+        "/ only update, if already open
+        completionView isNil ifTrue:[^ self].
+    ].
+
+    (key == #BackSpace or:[key == #BasicBackspace]) ifTrue:[
+        | c |
+
+        c := editView characterBeforeCursor.
+        (c notNil and:[c isLetterOrDigit]) ifTrue:[
+            autoSelect := false.
+            self updateCompletionList.
+        ] ifFalse:[
+             self closeCompletionView.
+        ].
+        ^ self
+    ].
+
+    key isCharacter ifTrue:[
+        key isLetterOrDigit not ifTrue:[
+            self closeCompletionView
+        ] ifFalse:[
+            autoSelect := false.
+            self updateCompletionList.
+        ].
+        ^ self
+    ].
+
+    "Created: / 28-09-2013 / 00:21:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 30-09-2013 / 14:55:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!CompletionController methodsFor:'private'!
+
+complete
+    support insertCompletion: completionView selection.
+    self closeCompletionView.
+
+    "Created: / 27-09-2013 / 15:38:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+updateCompletionList
+    "called for keypress events"
+
+    completionView isNil ifTrue:[
+        super updateCompletionList
+    ] ifFalse:[
+         self updateSelection.
+    ].
+
+    "Created: / 27-09-2013 / 15:58:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 28-09-2013 / 00:15:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+updateSelection
+
+    | matches word |
+
+    word := support wordBeforeCursor.
+    matches := completionView list select:[:po | po stringToComplete startsWith: word ].
+    matches notEmptyOrNil ifTrue:[
+        completionView selection: (matches inject: matches anElement into:[:shortest :each |
+            each stringToComplete size < shortest stringToComplete size 
+                ifTrue:[each]
+                ifFalse:[shortest]
+        ]).
+    ] ifFalse:[
+        completionView selection: nil.
+    ]
+
+    "Created: / 27-09-2013 / 16:16:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+
+!CompletionController methodsFor:'private-API'!
+
+computeCompletions
+    "Actually compute the completions and update the completion view."  
+
+    | completions |
+
+    "/ Wait a while to give user chance finish typing.
+    "/ This also reduces CPU consumption by avoiding
+    "/ useless computation
+    Delay waitForMilliseconds: 200. 
+    completions := support computeCompletion.
+    completions notEmptyOrNil ifTrue:[
+        editView sensor pushUserEvent: #updateCompletions: for: self withArgument: completions.
+    ].
+
+    "Created: / 27-09-2013 / 13:12:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 30-09-2013 / 11:53:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+openCompletionView
+    self openCompletionView: #()
+
+    "Created: / 27-09-2013 / 16:17:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+openCompletionView: list
+    "Makes sure the completion view is opened and with given `list`."
+    
+    | movePos topView x y|
+    "/ move the window
+
+    list isEmpty ifTrue:[ ^ self ].
+
+    x := (editView xOfCol:editView cursorCol  inVisibleLine:editView cursorLine)
+            - 16"icon" - (editView widthOfString:  support wordBeforeCursor) - 5"magic constant".
+    y := editView yOfCursor + editView font maxHeight + 3.
+    movePos := (editView originRelativeTo: nil) + (x @ y).           
+
+    completionView isNil ifTrue:[
+        completionView := CompletionView new.
+        completionView list:list.
+        completionView font: editView font.
+        topView := completionView.
+        topView origin:movePos.
+"/        topView resizeToFit.
+        self updateSelection.
+        topView open.
+    ] ifFalse:[
+        completionView list:list.
+        self updateSelection.
+"/        topView := completionView topView.
+"/        topView ~~ completionView ifTrue:[
+"/            topView origin:movePos.
+"/            topView resizeToFit.
+"/        ]
+    ].
+
+    "Created: / 27-09-2013 / 14:01:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+    "Modified: / 27-09-2013 / 23:54:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+!
+
+updateCompletions: completionResult
+    self openCompletionView: completionResult
+
+    "Created: / 27-09-2013 / 13:52:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
+! !
+