Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 116 additions & 12 deletions src/HeuristicCompletion-Model/CoCompletionContext.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ Class {
'completionBuilder',
'completionClass',
'completion',
'completionToken'
'completionToken',
'groupStack',
'groupedEntries',
'rawEntries'
],
#category : 'HeuristicCompletion-Model-SystemIntegration',
#package : 'HeuristicCompletion-Model',
Expand All @@ -32,12 +35,45 @@ CoCompletionContext class >> engine: aCompletionEngine class: aClass source: aSt
yourself
]

{ #category : 'activation' }
{ #category : 'accessing' }
CoCompletionContext >> activateEntryAt: anIndex [

(self entries at: anIndex) activateOn: self
]

{ #category : 'private-grouping' }
CoCompletionContext >> buildGroupedEntriesFrom: aCollection [


| grouped order buckets |
NECPreferences groupEntries ifFalse: [ ^ aCollection asOrderedCollection ].
grouped := OrderedCollection new.
order := OrderedCollection new.
buckets := Dictionary new.

aCollection do: [ :entry |
| prefix bucket |
prefix := self groupingPrefixFor: entry.
prefix
ifNil: [ grouped add: entry ]
ifNotNil: [
bucket := buckets
at: prefix
ifAbsentPut: [
order add: prefix.
OrderedCollection new ].
bucket add: entry ] ].

order do: [ :prefix |
| bucket |
bucket := buckets at: prefix.
bucket size = 1
ifTrue: [ grouped add: bucket first ]
ifFalse: [ grouped add: (NECPrefixGroupEntry prefix: prefix children: bucket) ] ].

^ grouped
]

{ #category : 'testing' }
CoCompletionContext >> completion [

Expand Down Expand Up @@ -125,11 +161,21 @@ CoCompletionContext >> engine: anObject [
{ #category : 'accessing' }
CoCompletionContext >> entries [

^ self completion first: 20
| currentEntries limit |
currentEntries := (groupStack notNil and: [ groupStack notEmpty ])
ifTrue: [ groupStack last ]
ifFalse: [
groupedEntries ifNil: [
groupedEntries := self buildGroupedEntriesFrom: self rawEntries ].
groupedEntries ].

limit := currentEntries size min: 20.
^ currentEntries first: limit
]

{ #category : 'accessing' }
CoCompletionContext >> entryCount [

^ self entries size
]

Expand All @@ -139,23 +185,41 @@ CoCompletionContext >> environmentAt: aString ifPresent: aBlockClosure [
^ self systemNavigation environmentAt: aString ifPresent: aBlockClosure
]

{ #category : 'testing' }
{ #category : 'accessing' }
CoCompletionContext >> groupingPrefixFor: anEntry [

| text prefixSize |
text := anEntry contents.
prefixSize := self groupingPrefixSize max: self completionToken size.

text size <= prefixSize ifTrue: [ ^ nil ].
^ text copyFrom: 1 to: prefixSize
]

{ #category : 'private-grouping' }
CoCompletionContext >> groupingPrefixSize [

^ NECPreferences groupingPrefixSize
]

{ #category : 'accessing' }
CoCompletionContext >> hasEntries [

^ self completion notEmpty
^ self entries notEmpty
]

{ #category : 'menu' }
{ #category : 'accessing' }
CoCompletionContext >> hasMessage [

^ false
^ (groupStack notNil and: [ groupStack notEmpty ])
]

{ #category : 'initialization' }
{ #category : 'accessing' }
CoCompletionContext >> initialize [

super initialize.
completionBuilder := CoASTHeuristicsResultSetBuilder initializeOnContext: self
completionBuilder := CoASTHeuristicsResultSetBuilder initializeOnContext: self.
groupStack := OrderedCollection new.
]

{ #category : 'testing' }
Expand All @@ -164,11 +228,40 @@ CoCompletionContext >> isScripting [
^ engine isNotNil and: [ engine isScripting ]
]

{ #category : 'narrowing' }
{ #category : 'accessing' }
CoCompletionContext >> leaveGroup [

groupStack isEmpty ifTrue: [ ^ false ].
groupStack removeLast.
^ true
]

{ #category : 'accessing' }
CoCompletionContext >> message [
groupStack isEmpty ifTrue: [ ^ '' ].
^ ' back • '
, (groupStack last size asString)
, ' matches for '
, groupStack last first contents
]

{ #category : 'accessing' }
CoCompletionContext >> narrowWith: aString [

completionToken := aString.
self completion replaceFilterWith: (CoBeginsWithFilter caseSensitive: NECPreferences caseSensitive filterString: aString)
groupStack removeAll.
groupedEntries := nil.
rawEntries := nil.
self completion replaceFilterWith:
(CoBeginsWithFilter
caseSensitive: NECPreferences caseSensitive
filterString: aString)
]

{ #category : 'accessing' }
CoCompletionContext >> openGroup: aGroupEntry [

groupStack add: aGroupEntry children
]

{ #category : 'accessing' }
Expand All @@ -181,6 +274,15 @@ CoCompletionContext >> position: anObject [
position := anObject
]

{ #category : 'accessing' }
CoCompletionContext >> rawEntries [

rawEntries ifNil: [
self completion fetchAll.
rawEntries := self completion results asOrderedCollection ].
^ rawEntries
]

{ #category : 'replacing' }
CoCompletionContext >> replaceTokenInEditorWith: aString [

Expand All @@ -206,7 +308,9 @@ CoCompletionContext >> systemNavigation [
{ #category : 'accessing' }
CoCompletionContext >> title [

^ ''
^ groupStack isEmpty
ifTrue: [ '' ]
ifFalse: [ 'Completions · ' , groupStack last first contents ]
]

{ #category : 'accessing' }
Expand Down
53 changes: 31 additions & 22 deletions src/NECompletion-Morphic/CompletionEngine.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -144,52 +144,61 @@ CompletionEngine >> handleKeyDownBefore: aKeyboardEvent editor: anEditor [
key := aKeyboardEvent key.

(self isMenuOpen not and: [
self editor atCompletionPosition and: [
NECPreferences popupShowWithShortcut matches: { aKeyboardEvent } ] ])
ifTrue: [
self editor atCompletionPosition and: [ NECPreferences popupShowWithShortcut matches: { aKeyboardEvent } ] ]) ifTrue: [
aKeyboardEvent supressNextKeyPress: true.
self openMenu.
^ true ].

key = KeyboardKey backspace ifTrue: [
self smartBackspace ifTrue: [ ^ true ] ].
key = KeyboardKey backspace ifTrue: [ self smartBackspace ifTrue: [ ^ true ] ].

self isMenuOpen ifFalse: [ ^ false ].

({
KeyboardKey left.
KeyboardKey keypadLeft } includes: key) ifTrue: [
menuMorph leaveGroup ifTrue: [ ^ true ].
^ false ].

({
KeyboardKey right.
KeyboardKey keypadLeft.
KeyboardKey keypadRight } includes: key) ifTrue: [ "just move the caret"
^ false ].
KeyboardKey keypadRight } includes: key) ifTrue: [
menuMorph insertSelected ifTrue: [ ^ true ].
^ false ].

({
KeyboardKey up.
KeyboardKey keypadUp } includes: key) ifTrue: [
menuMorph moveUp.
^ true ].
menuMorph moveUp.
^ true ].

({
KeyboardKey down.
KeyboardKey keypadDown } includes: key) ifTrue: [
menuMorph moveDown.
^ true ].
menuMorph moveDown.
^ true ].

key = KeyboardKey pageUp ifTrue: [
menuMorph pageUp.
^ true ].
menuMorph pageUp.
^ true ].

key = KeyboardKey pageDown ifTrue: [
menuMorph pageDown.
^ true ].
((key = KeyboardKey enter or: [ key = KeyboardKey keypadEnter ])
and: [ NECPreferences useEnterToAccept ]) ifTrue: [
menuMorph pageDown.
^ true ].

((key = KeyboardKey enter or: [ key = KeyboardKey keypadEnter ]) and: [ NECPreferences useEnterToAccept ]) ifTrue: [
menuMorph insertSelected ifTrue: [ ^ true ] ].

key = KeyboardKey tab ifTrue: [
menuMorph insertSelected ifTrue: [ ^ true ] ].

key = KeyboardKey backspace ifTrue: [
editor isCaretBehindChar ifFalse: [ self closeMenu ].
^ false ].
editor isCaretBehindChar ifFalse: [ self closeMenu ].
^ false ].

key = KeyboardKey escape ifTrue: [
self closeMenu.
^ true ].
self closeMenu.
^ true ].

^ false
]

Expand Down
41 changes: 30 additions & 11 deletions src/NECompletion-Morphic/NECMenuMorph.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -487,21 +487,31 @@ NECMenuMorph >> initialize [
isDetailMorphVisible := false
]

{ #category : 'actions' }
{ #category : 'drawing' }
NECMenuMorph >> insertSelected [

| selectionIndex |
self delete.
| selectionIndex selectedEntry |
context hasEntries ifFalse: [ ^ false ].
context activateEntryAt: self selectedIndex.

"Now we can handle the announcement"

selectionIndex := self selectedIndex.
self class environment codeChangeAnnouncer announce: (CompletionItemSelected new
selectedItem: (context entries at: selectionIndex);
token: context completionToken;
entries: context entries;
index: selectionIndex).
selectedEntry := context entries at: selectionIndex.

selectedEntry isGroupEntry ifTrue: [
selectedEntry activateOn: context.
self hideDetail.
self refreshSelection.
^ true ].

self delete.
context activateEntryAt: selectionIndex.

self class environment codeChangeAnnouncer announce:
(CompletionItemSelected new
selectedItem: selectedEntry;
token: context completionToken;
entries: context entries;
index: selectionIndex).

^ true
]

Expand All @@ -521,6 +531,15 @@ NECMenuMorph >> lastVisible [
^ (self firstVisible + self height-1) min: (self itemsCount)
]

{ #category : 'drawing' }
NECMenuMorph >> leaveGroup [

(context leaveGroup) ifFalse: [ ^ false ].
self hideDetail.
self refreshSelection.
^ true
]

{ #category : 'event handling' }
NECMenuMorph >> mouseDown: evt [
(self bounds containsPoint: evt cursorPoint)
Expand Down
Loading