@@ -59,50 +59,6 @@ export class GenericCompleterModel<
5959 return item as T ;
6060 }
6161
62- setCompletionItems ( newValue : T [ ] ) {
63- super . setCompletionItems ( newValue ) ;
64-
65- if ( this . current && this . cursor ) {
66- // set initial query to pre-filter items; in future we should use:
67- // https://github.com/jupyterlab/jupyterlab/issues/9763#issuecomment-1001603348
68-
69- // note: start/end from cursor are not ideal because these get populated from fetch
70- // reply which will vary depending on what providers decide to return; we want the
71- // actual position in token, the same as passed in request to fetch. We can get it
72- // by searching for longest common prefix as seen below (or by counting characters).
73- // Maybe upstream should expose it directly?
74- const { start, end } = this . cursor ;
75- const { text, line, column } = this . original ! ;
76-
77- const queryRange = text . substring ( start , end ) . trim ( ) ;
78- const linePrefix = text . split ( '\n' ) [ line ] . substring ( 0 , column ) . trim ( ) ;
79- let query = '' ;
80- for ( let i = queryRange . length ; i > 0 ; i -- ) {
81- if ( queryRange . slice ( 0 , i ) == linePrefix . slice ( - i ) ) {
82- query = linePrefix . slice ( - i ) ;
83- break ;
84- }
85- }
86- if ( ! query ) {
87- return ;
88- }
89-
90- let trimmedQuotes = false ;
91- // special case for "Completes Paths In Strings" test case
92- if ( query . startsWith ( '"' ) || query . startsWith ( "'" ) ) {
93- query = query . substring ( 1 ) ;
94- trimmedQuotes = true ;
95- }
96- if ( query . endsWith ( '"' ) || query . endsWith ( "'" ) ) {
97- query = query . substring ( 0 , - 1 ) ;
98- trimmedQuotes = true ;
99- }
100- if ( this . settings . preFilterMatches || trimmedQuotes ) {
101- this . query = query ;
102- }
103- }
104- }
105-
10662 private _markFragment ( value : string ) : string {
10763 return `<mark>${ value } </mark>` ;
10864 }
@@ -138,7 +94,11 @@ export class GenericCompleterModel<
13894 return super . createPatch ( patch ) ;
13995 }
14096
141- private _sortAndFilter ( query : string , items : T [ ] ) : T [ ] {
97+ protected resolveQuery ( userQuery : string , _item : T ) {
98+ return userQuery ;
99+ }
100+
101+ private _sortAndFilter ( userQuery : string , items : T [ ] ) : T [ ] {
142102 let results : ICompletionMatch < T > [ ] = [ ] ;
143103
144104 for ( let item of items ) {
@@ -149,6 +109,8 @@ export class GenericCompleterModel<
149109 let filterText : string | null = null ;
150110 let filterMatch : StringExt . IMatchResult | null = null ;
151111
112+ const query = this . resolveQuery ( userQuery , item ) ;
113+
152114 let lowerCaseQuery = query . toLowerCase ( ) ;
153115
154116 if ( query ) {
@@ -246,10 +208,6 @@ export namespace GenericCompleterModel {
246208 * Whether perfect matches should be included (default = true)
247209 */
248210 includePerfectMatches ?: boolean ;
249- /**
250- * Whether matches should be pre-filtered (default = true)
251- */
252- preFilterMatches ?: boolean ;
253211 /**
254212 * Whether kernel completions should be shown first.
255213 */
@@ -258,7 +216,6 @@ export namespace GenericCompleterModel {
258216 export const defaultOptions : IOptions = {
259217 caseSensitive : true ,
260218 includePerfectMatches : true ,
261- preFilterMatches : true ,
262219 kernelCompletionsFirst : false
263220 } ;
264221}
@@ -267,13 +224,73 @@ type MaybeCompletionItem = Partial<CompletionItem> &
267224 CompletionHandler . ICompletionItem ;
268225
269226export class LSPCompleterModel extends GenericCompleterModel < MaybeCompletionItem > {
227+ public settings : LSPCompleterModel . IOptions ;
228+
229+ constructor ( settings : LSPCompleterModel . IOptions = { } ) {
230+ super ( ) ;
231+ this . settings = { ...LSPCompleterModel . defaultOptions , ...settings } ;
232+ }
233+
270234 protected getFilterText ( item : MaybeCompletionItem ) : string {
271235 if ( item . filterText ) {
272236 return item . filterText ;
273237 }
274238 return super . getFilterText ( item ) ;
275239 }
276240
241+ setCompletionItems ( newValue : MaybeCompletionItem [ ] ) {
242+ super . setCompletionItems ( newValue ) ;
243+ this . _preFilterQuery = '' ;
244+
245+ if ( this . current && this . cursor ) {
246+ // set initial query to pre-filter items; in future we should use:
247+ // https://github.com/jupyterlab/jupyterlab/issues/9763#issuecomment-1001603348
248+
249+ // note: start/end from cursor are not ideal because these get populated from fetch
250+ // reply which will vary depending on what providers decide to return; we want the
251+ // actual position in token, the same as passed in request to fetch. We can get it
252+ // by searching for longest common prefix as seen below (or by counting characters).
253+ // Maybe upstream should expose it directly?
254+ const { start, end } = this . cursor ;
255+ const { text, line, column } = this . original ! ;
256+
257+ const queryRange = text . substring ( start , end ) . trim ( ) ;
258+ const linePrefix = text . split ( '\n' ) [ line ] . substring ( 0 , column ) . trim ( ) ;
259+ let query = '' ;
260+ for ( let i = queryRange . length ; i > 0 ; i -- ) {
261+ if ( queryRange . slice ( 0 , i ) == linePrefix . slice ( - i ) ) {
262+ query = linePrefix . slice ( - i ) ;
263+ break ;
264+ }
265+ }
266+ if ( ! query ) {
267+ return ;
268+ }
269+
270+ let trimmedQuotes = false ;
271+ // special case for "Completes Paths In Strings" test case
272+ if ( query . startsWith ( '"' ) || query . startsWith ( "'" ) ) {
273+ query = query . substring ( 1 ) ;
274+ trimmedQuotes = true ;
275+ }
276+ if ( query . endsWith ( '"' ) || query . endsWith ( "'" ) ) {
277+ query = query . substring ( 0 , - 1 ) ;
278+ trimmedQuotes = true ;
279+ }
280+ if ( this . settings . preFilterMatches || trimmedQuotes ) {
281+ this . _preFilterQuery = query ;
282+ }
283+ }
284+ }
285+
286+ protected resolveQuery ( userQuery : string , item : MaybeCompletionItem ) {
287+ return userQuery
288+ ? userQuery
289+ : item . source === 'LSP'
290+ ? this . _preFilterQuery
291+ : '' ;
292+ }
293+
277294 protected harmoniseItem ( item : CompletionHandler . ICompletionItem ) {
278295 if ( ( item as any ) . self ) {
279296 const self = ( item as any ) . self ;
@@ -306,4 +323,19 @@ export class LSPCompleterModel extends GenericCompleterModel<MaybeCompletionItem
306323 a . score - b . score
307324 ) ;
308325 }
326+
327+ private _preFilterQuery : string = '' ;
328+ }
329+
330+ export namespace LSPCompleterModel {
331+ export interface IOptions extends GenericCompleterModel . IOptions {
332+ /**
333+ * Whether matches should be pre-filtered (default = true)
334+ */
335+ preFilterMatches ?: boolean ;
336+ }
337+ export const defaultOptions : IOptions = {
338+ ...GenericCompleterModel . defaultOptions ,
339+ preFilterMatches : true
340+ } ;
309341}
0 commit comments