--- a/Workspace.st Thu Sep 26 19:34:39 2013 +0200
+++ b/Workspace.st Thu Sep 26 19:34:48 2013 +0200
@@ -25,13 +25,6 @@
category:'Interface-Smalltalk'
!
-Object subclass:#CodeCompletionService
- instanceVariableNames:'completionView completionProcess editView autoSelect'
- classVariableNames:'LastCompletions'
- poolDictionaries:''
- privateIn:Workspace
-!
-
Workspace comment:''
!
@@ -125,8 +118,10 @@
!Workspace class methodsFor:'defaults'!
-codeCompletionServiceClass
- ^ CodeCompletionService
+defaultCompletionSupportClass
+ ^ WorkspaceCompletionSupport
+
+ "Created: / 26-09-2013 / 17:59:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
defaultLabel
@@ -2191,419 +2186,13 @@
"Modified (comment): / 07-03-2012 / 17:52:59 / cg"
! !
-!Workspace::CodeCompletionService class methodsFor:'instance creation'!
-
-for:anEditView
- ^ self new editView:anEditView
-! !
-
-!Workspace::CodeCompletionService methodsFor:'accessing'!
-
-editView:something
- editView := something.
-! !
-
-!Workspace::CodeCompletionService methodsFor:'events'!
-
-buttonPress:button x:x y:y
- self closeCompletionView.
-!
-
-editViewLostFocus
- completionView notNil ifTrue:[
- self closeCompletionView
- ]
-!
-
-handleKeyPress:key x:x y:y
- "return true, if I have eaten this keypress"
-
- |ch completeImmediate eatCursorLeftOrRight|
-
- completeImmediate := UserPreferences current immediateCodeCompletion.
-
- "/ open on CTRL- or TAB-key?
- (completionView isNil or:[completionView realized not]) ifTrue:[
- editView hasSelection ifFalse:[
- ((ch := editView characterBeforeCursor) notNil "/ i.e. not at begin of line
- and:[ ch isSeparator not ]) ifTrue:[
- (key == #Control_L or:[ key == #Ctrl or:[ key == #Control_R or:[ key == #Control]]]) ifTrue:[
- UserPreferences current codeCompletionOnControlKey ifTrue:[
- autoSelect := true.
- self updateCompletionList
- ]
- ].
- (key == #Tab) ifTrue:[
- UserPreferences current codeCompletionOnTabKey ifTrue:[
- autoSelect := true.
- self updateCompletionList.
- ^ true
- ].
- ]
- ].
- ].
- ^ false.
- ].
-
- "/ key for completion view ? (careful: do not forward too many, it would disturb user's typing)
- key isCharacter ifFalse:[
- "/ forward to menu
- (completionView notNil) ifTrue:[
- eatCursorLeftOrRight := false.
-"/ completeImmediate not
-"/ or:[ editView sensor shiftDown
-"/ or:[ editView sensor ctrlDown ]].
- (key == #CursorDown
- or:[ (key == #CursorUp)
- or:[ ((key == #CursorLeft) and:[eatCursorLeftOrRight])
- or:[ ((key == #CursorRight) and:[eatCursorLeftOrRight])
- or:[ ((key == #Return) and:[ completionView hasSelection ])
- ]]]]) ifTrue:[
- "/ only with shift - normal user typing should not interfere with completion
- true "editView sensor shiftDown" ifTrue:[
- "/ forward to completion view
- completionView sensor pushUserEvent:#value for:[ completionView keyPress:key x:0 y:0 ].
- ^ true.
- ].
- ].
-
- (key == #Control_L or:[ key == #Control_R or:[ key == #Control or:[ key == #Ctrl ]]]) ifTrue:[
- "/ CTRL is a toggle
- self closeCompletionView.
- ^ true.
- "/ ^ false
- ].
- (key == #Escape) ifTrue:[
- self closeCompletionView.
- ^ true "/ EAT
- ].
- "/ shift does not close
- (key == #Shift_L or:[ key == #Shift_R or:[ key == #Shift]]) ifTrue:[
- ^ false "/ don' eat
- ].
-
- self closeCompletionView.
- ^ false "/ don' eat
- ].
- ].
- ^ false.
-!
-
-postKeyPress:key
- UserPreferences current immediateCodeCompletion ifFalse:[
- "/ only update, if already open
- completionView isNil ifTrue:[^ self].
- ].
-
- (key == #BackSpace or:[key == #BasicBackspace]) ifTrue:[
- autoSelect := false.
- self updateCompletionList.
- ^ self
- ].
-
- key isCharacter ifTrue:[
- key isSeparator ifTrue:[
- self closeCompletionView
- ] ifFalse:[
- autoSelect := false.
- self updateCompletionList.
- ].
- ^ self
- ].
-! !
-
-!Workspace::CodeCompletionService methodsFor:'private'!
-
-closeCompletionView
- |v|
-
- (v := completionView) notNil ifTrue:[
- completionView := nil.
- "/ let it close itself - avoids synchronization problems
- v sensor
- pushUserEvent:#value
- for:[ v topView destroy ]
- ].
-!
-
-release
- self stopCompletionProcess.
- self closeCompletionView.
- super release
-!
-
-startCompletionProcess
- "start the code completion process in the background"
-
- |movePos topView initialList cursorX cursorY|
-
- "/ terminate any previous process
- self stopCompletionProcess.
-
- (editView sensor hasKeyPressEventFor:nil) ifTrue:[
- self closeCompletionView.
- ^ self
- ].
- ((cursorX := editView xOfCursor) isNil
- or:[ (cursorY := editView yOfCursor) isNil ]) ifTrue:[
- "/ no cursor - user is selecting, or cursor has been scrolled out of sight.
- self closeCompletionView.
- ^ self
- ].
-
- initialList := #( 'busy...' ).
-
- "/ move the window
- movePos := editView device translatePoint:(cursorX @ cursorY) fromView:editView toView:nil.
- movePos := movePos - (editView viewOrigin x @ 0).
- "/ currently, we have to stay away a bit, to avoid getting the focus
- movePos := movePos + (60 @ (editView font height)).
-
- completionView isNil ifTrue:[
- completionView := CodeCompletionHelpMenuView new.
- completionView name:'completion'.
- completionView level:0.
- completionView list:initialList.
- completionView enable:false.
- completionView extent:completionView preferredExtentForContents.
- topView := CodeCompletionHelpView with:completionView.
- topView origin:movePos.
- topView resizeToFit.
- "/ topView open.
- ] ifFalse:[
- completionView list:initialList.
- topView := completionView topView.
- topView ~~ completionView ifTrue:[
- topView origin:movePos.
- topView resizeToFit.
- ]
- ].
-
- completionProcess :=
- [
- |suggestions implementations actions anyFound contextOrNil|
-
- "/ a hack
- (editView topView isKindOf: DebugView) ifTrue:[
- contextOrNil := editView topView selectedContext
- ].
-
- UserInformation ignoreIn:[
- anyFound := false.
- DoWhatIMeanSupport
- codeCompletionForLanguage: editView editedLanguage
- method:editView editedMethod
- orClass:editView editedClass
- context:contextOrNil
- codeView:editView
- into:[:listOfSuggestions :listOfActions :titleWhenAsking |
-"/ (listOfSuggestions contains:[:l | l isEmptyOrNil]) ifTrue:[self halt].
- suggestions := listOfSuggestions collect:[:entry | entry isArray ifTrue:[entry first] ifFalse:[entry]].
- implementations := listOfSuggestions collect:[:entry | entry isArray ifTrue:[entry second] ifFalse:[nil]].
- actions := listOfActions.
- anyFound := true.
- nil "/ must return nil to avoid DWIM to do it itself (for now)
- ]
- ].
- "/ anyFound ifFalse:[self halt].
- "/ Transcript show:'suggestions: '; showCR:suggestions.
- "/ Transcript show:'actions: '; showCR:actions.
- editView sensor
- pushUserEvent:#'suggestionsArrived:implementations:actions:autoSelect:'
- for:self
- withArguments:{suggestions . implementations . actions . autoSelect }
- ] forkAt:(Processor activePriority - 1).
-
- "Modified: / 18-09-2013 / 14:17:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
-!
-
-stopCompletionProcess
- "kill any background completion process"
-
- |p|
-
- (p := completionProcess) notNil ifTrue:[
- completionProcess := nil.
- p terminate.
- ].
-!
-
-suggestionsArrived:suggestionsArg implementations:implementationsArg actions:actionsArg autoSelect:autoSelectArg
- "the background process has generated some suggestions"
-
- |v suggestions implementations actions suggestionOffset keyAndSnippet indexOfSnippet|
-
- (editView sensor hasKeyPressEventFor:nil) ifTrue:[
- self closeCompletionView.
- ^ self
- ].
-
- implementations := implementationsArg.
- actions := actionsArg.
-
- suggestions := suggestionsArg ? #().
- suggestions size > 20 ifTrue:[
- suggestions := suggestions copyTo:20.
- implementations := implementations copyTo:20.
- actions isArray ifTrue:[ actions := actions copyTo:20 ].
- ].
-
- "/ append snipplet, if any (can be easily reached via CRSR-up)
- suggestionOffset := 0.
- indexOfSnippet := nil.
- (keyAndSnippet := editView findAbbreviationKeyBeforeCursor) notNil ifTrue:[
- |abbrev sniplet i line|
-
- abbrev := keyAndSnippet first.
- sniplet := keyAndSnippet second.
-
- "/ if the abbreviation is simply at the end of a longer word, ignore the abbrev.
- line := editView lineStringBeforeCursor.
- i := line findLast:[:ch | ch isLetterOrDigit not].
- (i < (line size - abbrev size - 1)) ifFalse:[
- sniplet := sniplet copyWithout:$!!.
-
- "/ true, false and self are often found in both lists
- (suggestions includes:sniplet) ifFalse:[
- suggestions isEmpty ifFalse:[ suggestions := suggestions copyWith: '-' ].
- suggestions := suggestions copyWith: ( '%1 %2'
- bindWith:(sniplet asStringCollection first "contractTo:25")
- with: ( ('("',abbrev,'" snippet)') colorizeAllWith:Color grey)).
- indexOfSnippet := suggestions size.
-
- "/ change below, when reversing the order in above code
- "/ suggestionOffset := 2.
- ]
- ]
- ].
- suggestions isEmptyOrNil ifTrue:[
- self closeCompletionView.
- ^ self
- ].
- (v := completionView) isNil ifTrue: [
- ^ self
- ].
-
- v sensor
- pushUserEvent:#value
- for:[
- |top idx preselectIdx performCompletion|
-
- (v == completionView) ifTrue: [
- top := v topView.
-
- LastCompletions notNil ifTrue:[
- "/ one of the last completions in list?
- idx := LastCompletions findFirst:[:compl | suggestions includes:compl].
- idx ~~ 0 ifTrue:[
- preselectIdx := suggestions indexOf:(LastCompletions at:idx).
- ].
- ].
- autoSelectArg ifTrue:[
- (preselectIdx isNil and:[suggestions size == 1]) ifTrue:[
- preselectIdx := 1.
- ].
- ].
- preselectIdx notNil ifTrue:[
- |pref|
-
- pref := suggestions at:preselectIdx.
- "/ for now, do not move to front (action needs the index)
- suggestions at:preselectIdx put:(pref allBold).
-"/ suggestions removeAtIndex:preselectIdx.
-"/ suggestions addFirst:(pref allBold).
-"/ implementations notNil ifTrue:[
-"/ implementations removeAtIndex:preselectIdx.
-"/ implementations addFirst:implementations.
-"/ ]
- ].
-
- performCompletion :=
- [:selectedListIndex |
- |indexInSuggestions|
-
- self closeCompletionView.
- indexInSuggestions := selectedListIndex - suggestionOffset.
- (selectedListIndex == indexOfSnippet) ifTrue:[
- "/ replace the sniplet
- editView sensor pushUserEvent:#expandAbbreviation for:editView
- ] ifFalse:[
- LastCompletions isNil ifTrue:[
- LastCompletions := OrderedCollection new.
- ].
- LastCompletions add:(suggestions at:indexInSuggestions).
- LastCompletions size > 200 ifTrue:[
- LastCompletions removeLast
- ].
-
- actions notNil ifTrue:[
- actions isBlock ifTrue:[
- actions value:indexInSuggestions
- ] ifFalse:[
- (actions at:indexInSuggestions) value
- ].
- ].
- ].
- "/ disabled - user has made his choice; so don't show more suggestions
- "/ editView sensor pushUserEvent:#updateCompletionList for:self
- ].
-
- ((suggestions size == 1) and:[preselectIdx == 1]) ifTrue:[
- "/ do it, right here and now
- performCompletion value:preselectIdx.
- ] ifFalse:[
- top open.
- v list:suggestions
- expandTabs:false scanForNonStrings:false
- includesNonStrings:false redraw:true.
-
- implementations notNil ifTrue:[
- implementations keysAndValuesDo:[:idx :impls |
- |implsMenu|
-
- impls notEmptyOrNil ifTrue:[
- implsMenu := Menu new.
- impls do:[:each |
- implsMenu addItem:(MenuItem new label:each name).
- ].
- v subMenuAt:idx put:implsMenu
- ].
- ].
- ].
-
- v enable:true.
- preselectIdx notNil ifTrue:[
- "/ very disturbing!!
- v selection:preselectIdx.
- ].
- v extent:completionView preferredExtentForContents.
- v action:performCompletion.
-
- (top ~~ v) ifTrue:[
- top resizeToFit.
- top bottom > v device usableHeight ifTrue:[
- top origin:((top origin x) @ (v device usableHeight - v height)).
- ].
- top raise.
- ]
- ]
- ]
- ]
-!
-
-updateCompletionList
- "called for keypress events"
-
- self startCompletionProcess.
-! !
-
!Workspace class methodsFor:'documentation'!
version
- ^ '$Header: /cvs/stx/stx/libwidg/Workspace.st,v 1.308 2013-09-24 15:21:54 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libwidg/Workspace.st,v 1.309 2013-09-26 17:34:48 vrany Exp $'
!
version_CVS
- ^ '$Header: /cvs/stx/stx/libwidg/Workspace.st,v 1.308 2013-09-24 15:21:54 cg Exp $'
+ ^ '$Header: /cvs/stx/stx/libwidg/Workspace.st,v 1.309 2013-09-26 17:34:48 vrany Exp $'
! !