#BUGFIX by exept
class: EditTextViewCompletionSupport
code completion view position fixes;
do not eat tab key
added: #adjustSizeOfCompletionView:
changed:
#closeCompletionView
#computeAndShowCompletions
#handleKeyPress:x:y:
#openCompletionView:
#postKeyPress:
#startCompletionProcess
--- a/EditTextViewCompletionSupport.st Sun Sep 15 15:09:07 2019 +0200
+++ b/EditTextViewCompletionSupport.st Sun Sep 15 18:29:12 2019 +0200
@@ -80,17 +80,19 @@
handleKeyPress:key x:x y:y
"return true, if I have eaten this keypress"
- |ch eatCursorLeftOrRight eatCursorUpDown|
+ |ch eatCursorLeftOrRight eatCursorUpDown sensor|
"/ completeImmediate := UserPreferences current immediateCodeCompletion.
+ sensor := editView sensor.
+
"/ open on CTRL- or TAB-key?
(completionView notNil and:[completionView realized]) ifFalse:[
editView hasSelection ifFalse:[
ch := editView characterBeforeCursor.
(ch notNil "/ i.e. not at begin of line
- and:[ ch isLetterOrDigitOrUnderline ]
+ and:[ ch isLetterOrDigitOrUnderline or:[ch == Character space]]
) ifTrue:[
(key == #Control_L or:[ key == #Ctrl or:[ key == #Control_R or:[ key == #Control]]]) ifTrue:[
UserPreferences current codeCompletionOnControlKey ifTrue:[
@@ -98,14 +100,14 @@
self updateCompletionList
]
].
- ((key == #Tab) and:[editView sensor shiftDown not]) ifTrue:[
+ ((key == #Tab) and:[sensor shiftDown not]) ifTrue:[
UserPreferences current codeCompletionOnTabKey ifTrue:[
"/ only if the character after the cursor is a separator!!
"/ otherwise, we cannot insert tabs
((ch := editView characterAfterCursor) isNil or:[ch isSeparator]) ifTrue:[
autoSelect := true.
self updateCompletionList.
- ^ true
+ "/ ^ true
].
].
]
@@ -114,6 +116,9 @@
^ false.
].
+ "/ the completion view is already open
+ "/ determine, if the key should be forwarded to it (cursor keys)
+
editView cursorCol <= 1 ifTrue:[^ false].
"/ key for completion view ? (careful: do not forward too many, it would disturb user's typing)
@@ -123,13 +128,13 @@
"/never
eatCursorLeftOrRight := false.
"/ completeImmediate not
-"/ or:[ editView sensor shiftDown
-"/ or:[ editView sensor ctrlDown ]].
+"/ or:[ sensor shiftDown
+"/ or:[ sensor ctrlDown ]].
"/ only with shift or ctrl
eatCursorUpDown :=
(UserPreferences current codeCompletionViewKeyboardNavigationNeedsModifier not)
- or:[ editView sensor shiftDown
- or:[ editView sensor ctrlDown]].
+ or:[ sensor shiftDown
+ or:[ sensor ctrlDown]].
((key == #CursorDown and:[eatCursorUpDown])
or:[ (key == #CursorUp and:[eatCursorUpDown])
@@ -138,7 +143,7 @@
or:[ ((key == #Return) and:[ completionView hasSelection ])
]]]]) ifTrue:[
"/ forward to completion view
- completionView sensor pushUserEvent:#value for:[ completionView keyPress:key x:0 y:0 ].
+ completionView sensor pushAction:[ completionView keyPress:key x:0 y:0 ].
^ true.
].
@@ -182,9 +187,12 @@
"/ (completionView notNil and:[completionView realized]) ifTrue:[^ self].
editView hasSelection ifTrue:[^ self].
+false ifTrue:[
ch := editView characterBeforeCursor.
- (ch notNil and:[ch isLetterOrDigitOrUnderline]) ifFalse:[^ self].
-
+ (ch notNil and:[ch isLetterOrDigitOrUnderline]) ifFalse:[
+ ^ self
+ ].
+].
(key == #BackSpace or:[key == #BasicBackspace]) ifTrue:[
autoSelect := false.
self updateCompletionList.
@@ -227,12 +235,21 @@
!EditTextViewCompletionSupport methodsFor:'private'!
computeAndShowCompletions
- "compute completions, then push an event to show them"
+ "compute completions, then push an event to show them.
+ Notice: this is interrupted and terminated if the user presses another key
+ within delayTime"
- |completions|
+ |delayTime completions startTime restTime|
+ delayTime := 0.4 seconds.
+
+ startTime := Timestamp now.
completions := self computeCompletions.
completions notEmptyOrNil ifTrue:[
+ restTime := (startTime + delayTime) - Timestamp now.
+ restTime positive ifTrue:[
+ Delay waitFor:restTime
+ ].
self assert:completions isArray.
self assert:completions size == 4.
editView sensor
@@ -283,14 +300,11 @@
^ self
].
- completionView isNil ifTrue:[
- initialList := #( 'Busy...' ).
- "/ 'op1' printCR.
- ] ifFalse:[
- initialList := completionView list.
- "/ 'op2' printCR.
+ initialList := #( 'Busy...' ).
+ completionView notNil ifTrue:[
+"/ initialList := completionView list.
].
- self openCompletionView:initialList.
+ "/ self openCompletionView:initialList.
completionProcess := p :=
[
@@ -302,13 +316,14 @@
].
] do:[
|startTime|
-
+
+false ifTrue:[
startTime := Timestamp now.
"/ Wait a while to give user chance finish typing.
"/ This also reduces CPU consumption by avoiding
"/ useless computation
Delay waitForMilliseconds: 200.
-
+].
(editView topView isDebugView) ifTrue:[
ControlInterrupt ignoreIn:[
self computeAndShowCompletions.
@@ -353,6 +368,62 @@
!EditTextViewCompletionSupport methodsFor:'private-API'!
+adjustSizeOfCompletionView:topView
+ |screenBounds screenBoundsCorner
+ helpViewsExtent helpViewsWidth helpViewsHeight
+ textCursorPosInTextView textCursorPosOnScreen
+ newX newY cursorX cursorY distanceFromCursorIfBelow distanceFromCursorIfAbove |
+
+ textCursorPosInTextView := editView xOfCursor @ editView yOfCursor.
+ textCursorPosOnScreen := editView device
+ translatePoint:textCursorPosInTextView
+ fromView:editView toView:nil.
+
+ cursorX := textCursorPosOnScreen x.
+ cursorY := textCursorPosOnScreen y.
+ distanceFromCursorIfAbove := editView font height.
+ distanceFromCursorIfBelow := distanceFromCursorIfAbove * 2.
+
+ topView resizeToFit.
+
+ "/ make sure, the window is visible
+ screenBounds := topView device monitorBoundsAt:topView origin.
+ screenBoundsCorner := screenBounds corner.
+
+ helpViewsExtent := topView extent.
+ helpViewsWidth := helpViewsExtent x.
+ helpViewsHeight := helpViewsExtent y.
+
+
+ newX := cursorX + 20.
+ newY := cursorY + distanceFromCursorIfBelow.
+
+ "/ if it does not lie completely inside the screen, move it
+ (newX + helpViewsWidth) > screenBoundsCorner x ifTrue:[
+ newX := screenBoundsCorner x - helpViewsWidth.
+ ].
+ (newY + helpViewsHeight) > screenBoundsCorner y ifTrue:[
+ newY := screenBoundsCorner y - helpViewsHeight.
+ ].
+ newX < 0 ifTrue:[
+ newX := 0
+ ].
+ newY < 0 ifTrue:[
+ newY := 0
+ ].
+
+ "/ topView origin:(newX @ newY).
+ (cursorY between:newY and:(newY + helpViewsHeight)) ifTrue:[
+ "/ lift it towards the top
+ newY := cursorY - distanceFromCursorIfAbove - helpViewsHeight.
+ ] ifFalse:[
+ "/ (cursorX between:newX and:(newX + helpViewsWidth)) ifTrue:[
+ "/ self halt.
+ "/ ].
+ ].
+ topView origin:(newX @ newY).
+!
+
closeCompletionView
|v|
@@ -360,9 +431,7 @@
completionView := nil.
"/ let it close itself - avoids synchronization problems
- v sensor
- pushUserEvent:#value
- for:[ v topView destroy ]
+ v sensor pushAction:[ v topView destroy ]
].
"Modified (format): / 14-09-2018 / 22:08:05 / Claus Gittinger"
@@ -380,9 +449,7 @@
openCompletionView: list
"Makes sure the completion view is opened and with given `list`."
- | textCursorPosInTextView textCursorPosOnScreen movePos topView
- screenBounds screenBoundsCorner
- helpViewsExtent helpViewsWidth helpViewsHeight|
+ | textCursorPosInTextView textCursorPosOnScreen movePos topView|
"/ move the window away from the text cursor (to not cover what user types in)
"/ get the screen-relative position of the text cursor
@@ -407,7 +474,8 @@
completionView enable:false.
completionView extent:completionView preferredExtentForContents.
"/ completionView font: editView font.
- topView := CodeCompletionHelpView with:completionView.
+ topView := CodeCompletionHelpView with:(HVScrollableView forView:completionView).
+ "/ topView := CodeCompletionHelpView with:completionView.
topView editView:editView.
] ifFalse:[
completionView list:list.
@@ -415,27 +483,7 @@
].
topView ~~ completionView ifTrue:[
- topView resizeToFit.
-
- "/ make sure, the window is visible
- screenBounds := topView device monitorBoundsAt:topView origin.
- screenBoundsCorner := screenBounds corner.
-
- helpViewsExtent := topView extent.
- helpViewsWidth := helpViewsExtent x.
- helpViewsHeight := helpViewsExtent y.
-
- "/ if it does not lie completely inside the screen, move it
- (movePos x + helpViewsWidth) > screenBoundsCorner x ifTrue:[
- movePos := (textCursorPosOnScreen x - 60 - helpViewsWidth) @ movePos y.
- ].
- (movePos y + helpViewsHeight) > screenBoundsCorner y ifTrue:[
- movePos := movePos x @ (textCursorPosOnScreen y - helpViewsHeight).
- ].
- movePos y < 0 ifTrue:[
- movePos := movePos x @ 0
- ].
- topView origin:movePos.
+ self adjustSizeOfCompletionView:topView.
].
"Created: / 26-09-2013 / 17:07:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"