@@ -37,6 +37,8 @@ let s:completion_status_pending = 'pending'
37
37
let s: is_user_data_support = has (' patch-8.0.1493' )
38
38
let s: user_data_key = ' vim-lsp/textEdit'
39
39
let s: user_data_additional_edits_key = ' vim-lsp/additionalTextEdits'
40
+ let s: user_data_insert_start_key = ' vim-lsp/insertStart'
41
+ let s: user_data_filtertext_key = ' vim-lsp/filterText'
40
42
41
43
" }}}
42
44
@@ -65,26 +67,79 @@ function! lsp#omni#complete(findstart, base) abort
65
67
while s: completion [' status' ] is # s: completion_status_pending && ! complete_check ()
66
68
sleep 10 m
67
69
endwhile
68
- let Is_prefix_match = s: create_prefix_matcher (a: base )
69
- let s: completion [' matches' ] = filter (s: completion [' matches' ], {_, match - > Is_prefix_match (match [' word' ])})
70
+
71
+ " TODO: Allow multiple servers
72
+ let l: server_name = l: info [' server_names' ][0 ]
73
+ let l: server_info = lsp#get_server_info (l: server_name )
74
+
75
+ let l: typed_pattern = has_key (l: server_info , ' config' ) && has_key (l: server_info [' config' ], ' typed_pattern' ) ? l: server_info [' config' ][' typed_pattern' ] : ' \k*$'
76
+ let l: current_line = strpart (getline (' .' ), 0 , col (' .' ) - 1 )
77
+
78
+ let s: start_pos = min (map (copy (s: completion [' matches' ]), {_, item - > s: get_insertion_point (item, l: current_line , l: typed_pattern ) }))
79
+
80
+ let l: filter = has_key (l: server_info , ' config' ) && has_key (l: server_info [' config' ], ' filter' ) ? l: server_info [' config' ][' filter' ] : { ' name' : ' none' }
81
+ let l: last_typed_word = strpart (l: current_line , s: start_pos )
82
+
83
+ if l: filter [' name' ] == ? ' prefix'
84
+ let s: completion [' matches' ] = filter (s: completion [' matches' ], {_, item - > s: prefix_filter (item, l: last_typed_word )})
85
+ elseif l: filter [' name' ] == ? ' contains'
86
+ let s: completion [' matches' ] = filter (s: completion [' matches' ], {_, item - > s: contains_filter (item, l: last_typed_word )})
87
+ endif
88
+
70
89
let s: completion [' status' ] = ' '
71
- return s: completion [' matches' ]
90
+
91
+ call timer_start (0 , function (' s:display_completions' ))
92
+
93
+ return exists (' v:none' ) ? v: none : []
72
94
endif
73
95
endif
74
96
endfunction
75
97
76
- function ! s: normalize_word (word) abort
77
- if &g: ignorecase
78
- return tolower (a: word )
98
+ function ! s: get_insertion_point (item, current_line, typed_pattern) abort
99
+ if ! has_key (a: item , ' user_data' )
100
+ let l: insert_start = -1
101
+ else
102
+ let l: insert_start = get (json_decode (a: item [' user_data' ]), s: user_data_insert_start_key , -1 )
103
+ endif
104
+
105
+ if l: insert_start >= 0
106
+ return l: insert_start
79
107
else
80
- return a: word
108
+ return match ( a: current_line , a: typed_pattern )
81
109
endif
82
110
endfunction
83
111
84
- function ! s: create_prefix_matcher (prefix) abort
85
- let l: prefix = s: normalize_word (a: prefix )
112
+ function ! s: get_filter_label (item) abort
113
+ if ! has_key (a: item , ' user_data' )
114
+ return trim (a: item [' word' ])
115
+ endif
86
116
87
- return { word - > stridx (s: normalize_word (word), l: prefix ) == 0 }
117
+ let l: user_data = json_decode (a: item [' user_data' ])
118
+ return trim (get (l: user_data , s: user_data_filtertext_key , a: item [' word' ]))
119
+ endfunction
120
+
121
+ function ! s: prefix_filter (item, last_typed_word) abort
122
+ let l: label = s: get_filter_label (a: item )
123
+
124
+ if g: lsp_ignorecase
125
+ return stridx (tolower (l: label ), tolower (a: last_typed_word )) == 0
126
+ else
127
+ return stridx (l: label , a: last_typed_word ) == 0
128
+ endif
129
+ endfunction
130
+
131
+ function ! s: contains_filter (item, last_typed_word) abort
132
+ let l: label = s: get_filter_label (a: item )
133
+
134
+ if g: lsp_ignorecase
135
+ return stridx (tolower (l: label ), tolower (a: last_typed_word )) >= 0
136
+ else
137
+ return stridx (l: label , a: last_typed_word ) >= 0
138
+ endif
139
+ endfunction
140
+
141
+ function ! s: display_completions (timer) abort
142
+ call complete (s: start_pos + 1 , s: completion [' matches' ])
88
143
endfunction
89
144
90
145
function ! s: handle_omnicompletion (server_name, complete_counter, data) abort
@@ -111,7 +166,7 @@ endfunction
111
166
112
167
function ! lsp#omni#get_kind_text (completion_item, ... ) abort
113
168
let l: server = get (a: , 1 , ' ' )
114
- if empty (l: server ) " server name
169
+ if empty (l: server ) " server name
115
170
let l: completion_item_kinds = s: default_completion_item_kinds
116
171
else
117
172
if ! has_key (s: completion_item_kinds , l: server )
@@ -125,7 +180,7 @@ function! lsp#omni#get_kind_text(completion_item, ...) abort
125
180
let l: completion_item_kinds = s: completion_item_kinds [l: server ]
126
181
endif
127
182
128
- return has_key (a: completion_item , ' kind' ) && has_key (l: completion_item_kinds , a: completion_item [' kind' ])
183
+ return has_key (a: completion_item , ' kind' ) && has_key (l: completion_item_kinds , a: completion_item [' kind' ])
129
184
\ ? l: completion_item_kinds [a: completion_item [' kind' ]] : ' '
130
185
endfunction
131
186
@@ -172,36 +227,13 @@ function! s:get_completion_result(server_name, data) abort
172
227
let l: incomplete = 0
173
228
endif
174
229
175
- let l: matches = type (l: items ) == type ([]) ? map (l: items , {_, item - > lsp#omni#get_vim_completion_item (item, a: server_name, 1 ) }) : []
230
+ let l: matches = type (l: items ) == type ([]) ? map (l: items , {_, item - > lsp#omni#get_vim_completion_item (item, a: server_name ) }) : []
176
231
177
232
return {' matches' : l: matches , ' incomplete' : l: incomplete }
178
233
endfunction
179
234
180
-
181
- function ! s: remove_typed_part (word) abort
182
- let l: current_line = strpart (getline (' .' ), 0 , col (' .' ) - 1 )
183
-
184
- let l: overlap_length = 0
185
- let l: i = 1
186
- let l: max_possible_overlap = min ([len (a: word ), len (l: current_line )])
187
-
188
- while l: i <= l: max_possible_overlap
189
- let l: current_line_suffix = strpart (l: current_line , len (l: current_line ) - l: i , l: i )
190
- let l: word_prefix = strpart (a: word , 0 , l: i )
191
-
192
- if l: current_line_suffix == l: word_prefix
193
- let l: overlap_length = l: i
194
- endif
195
-
196
- let l: i += 1
197
- endwhile
198
-
199
- return strpart (a: word , l: overlap_length )
200
- endfunction
201
-
202
235
function ! lsp#omni#default_get_vim_completion_item (item, ... ) abort
203
236
let l: server_name = get (a: , 1 , ' ' )
204
- let l: do_remove_typed_part = get (a: , 2 , 0 )
205
237
206
238
if g: lsp_insert_text_enabled && has_key (a: item , ' insertText' ) && ! empty (a: item [' insertText' ])
207
239
if has_key (a: item , ' insertTextFormat' ) && a: item [' insertTextFormat' ] != 1
@@ -215,10 +247,6 @@ function! lsp#omni#default_get_vim_completion_item(item, ...) abort
215
247
let l: abbr = a: item [' label' ]
216
248
endif
217
249
218
- if l: do_remove_typed_part
219
- let l: word = s: remove_typed_part (l: word )
220
- endif
221
-
222
250
let l: kind = lsp#omni#get_kind_text (a: item , l: server_name )
223
251
224
252
let l: completion = {
@@ -240,27 +268,37 @@ function! lsp#omni#default_get_vim_completion_item(item, ...) abort
240
268
call lsp#log (l: no_support_error_message )
241
269
endif
242
270
271
+ let l: user_data = {}
272
+
273
+ " Use '-1' to signal "no specific insertion point" set.
274
+ let l: user_data [s: user_data_insert_start_key ] = -1
275
+
243
276
" add user_data in completion item, when
244
277
" 1. provided user_data
245
278
" 2. provided textEdit or additionalTextEdits
246
279
" 3. textEdit value is Dictionary or additionalTextEdits is non-empty list
247
280
if g: lsp_text_edit_enabled
248
281
let l: text_edit = get (a: item , ' textEdit' , v: null )
249
282
let l: additional_text_edits = get (a: item , ' additionalTextEdits' , v: null )
250
- let l: user_data = {}
251
283
252
284
" type check
253
285
if type (l: text_edit ) == type ({})
254
286
let l: user_data [s: user_data_key ] = l: text_edit
287
+ let l: user_data [s: user_data_insert_start_key ] = l: text_edit [' range' ][' start' ][' character' ]
255
288
endif
256
289
257
290
if type (l: additional_text_edits ) == type ([]) && ! empty (l: additional_text_edits )
258
291
let l: user_data [s: user_data_additional_edits_key ] = l: additional_text_edits
259
292
endif
293
+ endif
260
294
261
- if ! empty (l: user_data )
262
- let l: completion [' user_data' ] = json_encode (l: user_data )
263
- endif
295
+ " Store filterText in user_data
296
+ if s: is_user_data_support && has_key (a: item , ' filterText' )
297
+ let l: user_data [s: user_data_filtertext_key ] = a: item [' filterText' ]
298
+ endif
299
+
300
+ if ! empty (l: user_data )
301
+ let l: completion [' user_data' ] = json_encode (l: user_data )
264
302
endif
265
303
266
304
if has_key (a: item , ' detail' ) && ! empty (a: item [' detail' ])
@@ -270,7 +308,7 @@ function! lsp#omni#default_get_vim_completion_item(item, ...) abort
270
308
if has_key (a: item , ' documentation' )
271
309
if type (a: item [' documentation' ]) == type (' ' ) " field is string
272
310
let l: completion [' info' ] .= a: item [' documentation' ]
273
- elseif type (a: item [' documentation' ]) == type ({}) &&
311
+ elseif type (a: item [' documentation' ]) == type ({}) &&
274
312
\ has_key (a: item [' documentation' ], ' value' )
275
313
" field is MarkupContent (hopefully 'plaintext')
276
314
let l: completion [' info' ] .= a: item [' documentation' ][' value' ]
0 commit comments