@@ -34,6 +34,7 @@ let s:completion_status_pending = 'pending'
34
34
35
35
let s: is_user_data_support = has (' patch-8.0.1493' )
36
36
let s: user_data_key = ' vim-lsp/textEdit'
37
+ let s: user_data_additional_edits_key = ' vim-lsp/additionalTextEdits'
37
38
38
39
" }}}
39
40
@@ -207,17 +208,23 @@ function! lsp#omni#get_vim_completion_item(item, ...) abort
207
208
208
209
" add user_data in completion item, when
209
210
" 1. provided user_data
210
- " 2. provided textEdit
211
- " 3. textEdit value is Dictionary
212
- if g: lsp_text_edit_enabled && has_key (a: item , ' textEdit' )
213
- let l: text_edit = a: item [' textEdit' ]
211
+ " 2. provided textEdit or additionalTextEdits
212
+ " 3. textEdit value is Dictionary or additionalTextEdits is non-empty list
213
+ if g: lsp_text_edit_enabled
214
+ let l: text_edit = get (a: item , ' textEdit' , v: null )
215
+ let l: additional_text_edits = get (a: item , ' additionalTextEdits' , v: null )
216
+ let l: user_data = {}
214
217
215
218
" type check
216
219
if type (l: text_edit ) == type ({})
217
- let l: user_data = {
218
- \ s: user_data_key : l: text_edit
219
- \ }
220
+ let l: user_data [s: user_data_key ] = l: text_edit
221
+ endif
222
+
223
+ if type (l: additional_text_edits ) == type ([]) && ! empty (l: additional_text_edits )
224
+ let l: user_data [s: user_data_additional_edits_key ] = l: additional_text_edits
225
+ endif
220
226
227
+ if ! empty (l: user_data )
221
228
let l: completion [' user_data' ] = json_encode (l: user_data )
222
229
endif
223
230
endif
@@ -237,18 +244,25 @@ endfunction
237
244
238
245
augroup lsp_completion_item_text_edit
239
246
autocmd !
240
- autocmd CompleteDone * call <SID> apply_text_edit ()
247
+ autocmd CompleteDone * call <SID> apply_text_edits ()
241
248
augroup END
242
249
243
- function ! s: apply_text_edit () abort
250
+ function ! s: apply_text_edits () abort
244
251
" textEdit support function(callin from CompleteDone).
245
252
"
246
253
" expected user_data structure:
247
254
" v:completed_item['user_data']: {
248
255
" 'vim-lsp/textEdit': {
249
256
" 'range': { ...(snip) },
250
257
" 'newText': 'yyy'
251
- " },
258
+ " },
259
+ " 'vim-lsp/additionalTextEdits': [
260
+ " {
261
+ " 'range': { ...(snip) },
262
+ " 'newText': 'yyy'
263
+ " },
264
+ " ...
265
+ " ],
252
266
" }
253
267
if ! g: lsp_text_edit_enabled
254
268
return
@@ -272,30 +286,61 @@ function! s:apply_text_edit() abort
272
286
return
273
287
endtry
274
288
275
- if ! ( type (l: user_data ) == type ({}) && has_key ( l: user_data , s: user_data_key ) )
289
+ if type (l: user_data ) != type ({})
276
290
return
277
291
endif
278
292
293
+ let l: all_text_edits = []
294
+
279
295
" expand textEdit range, for omni complet inserted text.
280
- let l: text_edit = l: user_data [s: user_data_key ]
281
- let l: expanded_text_edit = s: expand_range (l: text_edit , len (v: completed_item [' word' ]))
282
-
283
- " apply textEdit
284
- call lsp#utils#text_edit#apply_text_edits (expand (' %:p' ), [l: expanded_text_edit ])
285
-
286
- " move to end of newText
287
- let l: start = l: text_edit [' range' ][' start' ]
288
- let l: line = l: start [' line' ] + 1
289
- let l: col = l: start [' character' ]
290
- let l: new_text_length = len (l: text_edit [' newText' ]) + 1
291
- call cursor (l: line , l: col + l: new_text_length )
296
+ let l: text_edit = get (l: user_data , s: user_data_key , {})
297
+ if ! empty (l: text_edit )
298
+ let l: expanded_text_edit = s: expand_range (l: text_edit , len (v: completed_item [' word' ]))
299
+ call add (l: all_text_edits , l: expanded_text_edit )
300
+ endif
301
+
302
+ if has_key (l: user_data , s: user_data_additional_edits_key )
303
+ let l: all_text_edits += l: user_data [s: user_data_additional_edits_key ]
304
+ endif
305
+
306
+ " save cursor position in a mark, vim will move it appropriately when
307
+ " applying edits
308
+ let l: saved_mark = getpos (" 'a" )
309
+ " move to end of newText but in two steps (as column may not exist yet)
310
+ let [l: pos , l: col_offset ] = s: get_cursor_pos_and_edit_length (l: text_edit )
311
+ call setpos (" 'a" , l: pos )
312
+
313
+ " apply textEdits
314
+ if ! empty (l: all_text_edits )
315
+ call lsp#utils#text_edit#apply_text_edits (lsp#utils#get_buffer_uri (), l: all_text_edits )
316
+ endif
317
+
318
+ let l: pos = getpos (" 'a" )
319
+ let l: pos [2 ] += l: col_offset
320
+ call setpos (" 'a" , l: saved_mark )
321
+ call setpos (' .' , l: pos )
292
322
endfunction
293
323
294
324
function ! s: expand_range (text_edit, expand_length) abort
295
- let expanded_text_edit = a: text_edit
325
+ let l: expanded_text_edit = a: text_edit
296
326
let l: expanded_text_edit [' range' ][' end' ][' character' ] += a: expand_length
297
327
298
328
return l: expanded_text_edit
299
329
endfunction
300
330
331
+ function ! s: get_cursor_pos_and_edit_length (text_edit) abort
332
+ if ! empty (a: text_edit )
333
+ let l: start = a: text_edit [' range' ][' start' ]
334
+ let l: line = l: start [' line' ] + 1
335
+ let l: col = l: start [' character' ] + 1
336
+ let l: length = len (a: text_edit [' newText' ])
337
+ let l: pos = [0 , l: line , l: col , 0 ]
338
+ else
339
+ let l: length = 0
340
+ let l: pos = getpos (' .' )
341
+ endif
342
+
343
+ return [l: pos , l: length ]
344
+ endfunction
345
+
301
346
" }}}
0 commit comments