4
4
function ! s: _SID () abort
5
5
return matchstr (expand (' <sfile>' ), ' <SNR>\zs\d\+\ze__SID$' )
6
6
endfunction
7
- execute join ([' function! vital#_lsp#VS#LSP#TextEdit#import() abort' , printf (" return map({'set_method': '', ' _vital_depends': '', 'get_method': '', 'is_text_mark_preserved': '', ' apply': '', 'get_methods': '', 'delete ': '', '_vital_loaded': ''}, \" vital#_lsp#function('<SNR>%s_' . v:key)\" )" , s: _SID ()), ' endfunction' ], " \n " )
7
+ execute join ([' function! vital#_lsp#VS#LSP#TextEdit#import() abort' , printf (" return map({'_vital_depends': '', 'apply': '', '_vital_loaded': ''}, \" vital#_lsp#function('<SNR>%s_' . v:key)\" )" , s: _SID ()), ' endfunction' ], " \n " )
8
8
delfunction s: _SID
9
9
" ___vital___
10
10
"
@@ -23,144 +23,64 @@ function! s:_vital_depends() abort
23
23
return [' VS.LSP.Text' , ' VS.LSP.Position' , ' VS.Vim.Option' ]
24
24
endfunction
25
25
26
- "
27
- " Current selected method.
28
- "
29
- let s: _method = ' auto'
30
-
31
- "
32
- " This dict contains some logics for patching text.
33
- "
34
- let s: _methods = {}
35
-
36
- "
37
- " set_method
38
- "
39
- function ! s: set_method (method) abort
40
- if ! has_key (s: _methods , a: method )
41
- let s: _method = ' auto'
42
- elseif a: method == # ' nvim_buf_set_text' && ! exists (' *nvim_buf_set_text' )
43
- let s: _method = ' auto'
44
- elseif a: method == # ' normal' && has (' nvim' )
45
- let s: _method = ' auto'
46
- else
47
- let s: _method = a: method
48
- endif
49
- endfunction
50
-
51
- "
52
- " get_method
53
- "
54
- function ! s: get_method () abort
55
- if s: _method == # ' auto'
56
- if exists (' *nvim_buf_set_text' )
57
- return ' nvim_buf_set_text'
58
- elseif ! has (' nvim' )
59
- return ' normal'
60
- else
61
- return ' function'
62
- endif
63
- endif
64
- return s: _method
65
- endfunction
66
-
67
- "
68
- " get_methods
69
- "
70
- function ! s: get_methods () abort
71
- return [' nvim_buf_set_text' , ' normal' , ' function' ]
72
- endfunction
73
-
74
- "
75
- " is_text_mark_preserved
76
- "
77
- function ! s: is_text_mark_preserved () abort
78
- return index ([' nvim_buf_set_text' ], s: get_method ()) >= 0
79
- endfunction
80
-
81
26
"
82
27
" apply
83
28
"
84
29
function ! s: apply (path , text_edits) abort
85
30
let l: current_bufname = bufname (' %' )
86
- let l: target_bufname = a: path
87
- let l: cursor_position = s: Position .cursor ()
31
+ let l: current_position = s: Position .cursor ()
88
32
33
+ let l: target_bufnr = s: _switch (a: path )
89
34
try
90
- call s: _switch (a: path )
91
- let [l: has_overflowed , l: text_edits ] = s: _normalize (bufnr (l: target_bufname ), a: text_edits )
92
- let l: fix_cursor = s: _methods [s: get_method ()](bufnr (l: target_bufname ), l: text_edits , l: cursor_position )
93
- if l: has_overflowed && getline (' $' ) == # ' '
94
- call s: delete (bufnr (l: target_bufname ), ' $' , ' $' )
95
- endif
96
- call s: _switch (l: current_bufname )
35
+ let l: fix_cursor = s: _substitute (l: target_bufnr , a: text_edits , l: current_position )
97
36
catch /.*/
98
- call themis#log ( string ({ ' exception' : v: exception , ' throwpoint' : v: throwpoint }) )
37
+ echomsg string ({ ' exception' : v: exception , ' throwpoint' : v: throwpoint })
99
38
endtry
39
+ let l: current_bufnr = s: _switch (l: current_bufname )
100
40
101
- if get (l: , ' fix_cursor' , v: false ) && bufnr ( l: current_bufname ) == bufnr ( l: target_bufname )
102
- call cursor (s: Position .lsp_to_vim (' %' , l: cursor_position ))
41
+ if get (l: , ' fix_cursor' , v: false ) && l: current_bufnr == l: target_bufnr
42
+ call cursor (s: Position .lsp_to_vim (' %' , l: current_position ))
103
43
endif
104
44
endfunction
105
45
106
- let s: _methods = {}
107
-
108
- "
109
- " nvim_buf_set_text
110
- "
111
- function ! s: _methods .nvim_buf_set_text (bufnr , text_edits, cursor_position) abort
112
- let l: fix_cursor = v: false
113
-
114
- for l: text_edit in a: text_edits
115
- let l: start = s: Position .lsp_to_vim (a: bufnr , l: text_edit .range .start )
116
- let l: end = s: Position .lsp_to_vim (a: bufnr , l: text_edit .range .end )
117
- let l: lines = s: Text .split_by_eol (l: text_edit .newText)
118
- call nvim_buf_set_text (
119
- \ a: bufnr ,
120
- \ l: start [0 ] - 1 ,
121
- \ l: start [1 ] - 1 ,
122
- \ l: end [0 ] - 1 ,
123
- \ l: end [1 ] - 1 ,
124
- \ l: lines
125
- \ )
126
- let l: fix_cursor = s: _fix_cursor (a: cursor_position , l: text_edit , l: lines ) || l: fix_cursor
127
- endfor
128
-
129
- return l: fix_cursor
130
- endfunction
131
-
132
46
"
133
- " normal
47
+ " _substitute
134
48
"
135
- function ! s: _methods . normal (bufnr , text_edits, cursor_position ) abort
49
+ function ! s: _substitute (bufnr , text_edits, current_position ) abort
136
50
let l: fix_cursor = v: false
137
51
138
52
try
53
+ " Save state.
139
54
let l: Restore = s: Option .define ({
140
55
\ ' foldenable' : ' 0' ,
141
- \ ' virtualedit' : ' onemore' ,
142
- \ ' whichwrap' : ' h' ,
143
- \ ' selection' : ' exclusive' ,
144
56
\ })
145
57
let l: view = winsaveview ()
146
58
let l: regx = getreg (' x' )
147
59
148
- for l: text_edit in a: text_edits
60
+ " Apply substitute.
61
+ let [l: fixeol , l: text_edits ] = s: _normalize (a: bufnr , a: text_edits )
62
+ for l: text_edit in l: text_edits
149
63
let l: start = s: Position .lsp_to_vim (a: bufnr , l: text_edit .range .start )
150
64
let l: end = s: Position .lsp_to_vim (a: bufnr , l: text_edit .range .end )
151
- if l: start [0 ] != l: end [0 ] || l: start [1 ] != l: end [1 ]
152
- let l: command = printf (' %sG%s|v%sG%s|"_d' , l: start [0 ], l: start [1 ], l: end [0 ], l: end [1 ])
153
- else
154
- let l: command = printf (' %sG%s|' , l: start [0 ], l: start [1 ])
155
- endif
156
65
call setreg (' x' , s: Text .normalize_eol (l: text_edit .newText), ' c' )
157
- execute printf (' noautocmd keepjumps normal! %s"xP' , l: command )
158
-
159
- let l: fix_cursor = s: _fix_cursor (a: cursor_position , l: text_edit , s: Text .split_by_eol (l: text_edit .newText)) || l: fix_cursor
66
+ execute printf (' noautocmd keepjumps %ssubstitute/\%%%sl\%%%sc\zs\_.\{-}\ze\%%%sl\%%%sc/\=getreg("x")/' ,
67
+ \ l: start [0 ],
68
+ \ l: start [0 ],
69
+ \ l: start [1 ],
70
+ \ l: end [0 ],
71
+ \ l: end [1 ]
72
+ \ )
73
+ let l: fix_cursor = s: _fix_cursor (a: current_position , l: text_edit , getreg (' x' , 1 , v: true )) || l: fix_cursor
160
74
endfor
75
+
76
+ " Remove last empty line if fixeol enabled.
77
+ if l: fixeol && getline (' $' ) == ' '
78
+ $delete _
79
+ endif
161
80
catch /.*/
162
81
echomsg string ({ ' exception' : v: exception , ' throwpoint' : v: throwpoint })
163
82
finally
83
+ " Restore state.
164
84
call l: Restore ()
165
85
call winrestview (l: view )
166
86
call setreg (' x' , l: regx )
@@ -169,50 +89,6 @@ function! s:_methods.normal(bufnr, text_edits, cursor_position) abort
169
89
return l: fix_cursor
170
90
endfunction
171
91
172
- "
173
- " function
174
- "
175
- function ! s: _methods .function (bufnr , text_edits, cursor_position) abort
176
- let l: fix_cursor = v: false
177
-
178
- for l: text_edit in a: text_edits
179
- let l: start_line = getline (l: text_edit .range .start .line + 1 )
180
- let l: end_line = getline (l: text_edit .range .end .line + 1 )
181
- let l: before_line = strcharpart (l: start_line , 0 , l: text_edit .range .start .character )
182
- let l: after_line = strcharpart (l: end_line , l: text_edit .range .end .character , strchars (l: end_line ) - l: text_edit .range .end .character )
183
-
184
- " create lines.
185
- let l: lines = s: Text .split_by_eol (l: text_edit .newText)
186
- let l: lines [0 ] = l: before_line . l: lines [0 ]
187
- let l: lines [-1 ] = l: lines [-1 ] . l: after_line
188
-
189
- " save length.
190
- let l: lines_len = len (l: lines )
191
- let l: range_len = (l: text_edit .range .end .line - l: text_edit .range .start .line ) + 1
192
-
193
- " append or delete lines.
194
- if l: lines_len > l: range_len
195
- call append (l: text_edit .range .end .line , repeat ([' ' ], l: lines_len - l: range_len ))
196
- elseif l: lines_len < l: range_len
197
- call s: delete (a: bufnr , l: text_edit .range .start .line + l: lines_len , l: text_edit .range .end .line )
198
- endif
199
-
200
- " set lines.
201
- let l: i = 0
202
- while l: i < len (l: lines )
203
- let l: lnum = l: text_edit .range .start .line + l: i + 1
204
- if get (getbufline (a: bufnr , l: lnum ), 0 , v: null ) !=# l: lines [l: i ]
205
- call setline (l: lnum , l: lines [l: i ])
206
- endif
207
- let l: i += 1
208
- endwhile
209
-
210
- let l: fix_cursor = s: _fix_cursor (a: cursor_position , l: text_edit , s: Text .split_by_eol (l: text_edit .newText))
211
- endfor
212
-
213
- return l: fix_cursor
214
- endfunction
215
-
216
92
"
217
93
" _fix_cursor
218
94
"
@@ -240,7 +116,7 @@ endfunction
240
116
function ! s: _normalize (bufnr , text_edits) abort
241
117
let l: text_edits = type (a: text_edits ) == type ([]) ? a: text_edits : [a: text_edits ]
242
118
let l: text_edits = s: _range (l: text_edits )
243
- let l: text_edits = sort (copy ( l: text_edits) , function (' s:_compare' , [], {} ))
119
+ let l: text_edits = sort (l: text_edits , function (' s:_compare' ))
244
120
let l: text_edits = s: _check (l: text_edits )
245
121
let l: text_edits = reverse (l: text_edits )
246
122
return s: _fix_text_edits (a: bufnr , l: text_edits )
@@ -250,15 +126,20 @@ endfunction
250
126
" _range
251
127
"
252
128
function ! s: _range (text_edits) abort
129
+ let l: text_edits = []
253
130
for l: text_edit in a: text_edits
131
+ if type (l: text_edit ) != type ({})
132
+ continue
133
+ endif
254
134
if l: text_edit .range .start .line > l: text_edit .range .end .line || (
255
135
\ l: text_edit .range .start .line == l: text_edit .range .end .line &&
256
136
\ l: text_edit .range .start .character > l: text_edit .range .end .character
257
137
\ )
258
138
let l: text_edit .range = { ' start' : l: text_edit .range .end , ' end' : l: text_edit .range .start }
259
139
endif
140
+ let l: text_edits += [l: text_edit ]
260
141
endfor
261
- return a : text_edits
142
+ return l : text_edits
262
143
endfunction
263
144
264
145
"
@@ -298,49 +179,35 @@ function! s:_fix_text_edits(bufnr, text_edits) abort
298
179
let l: buf = getbufline (a: bufnr , ' ^' , ' $' )
299
180
let l: max = len (l: buf )
300
181
301
- let l: has_overflowed = v: false
182
+ let l: fixeol = v: false
302
183
let l: text_edits = []
303
184
for l: text_edit in a: text_edits
304
185
if l: max <= l: text_edit .range .start .line
305
186
let l: text_edit .range .start .line = l: max - 1
306
187
let l: text_edit .range .start .character = strchars (get (l: buf , -1 , 0 ))
307
188
let l: text_edit .newText = " \n " . l: text_edit .newText
308
- let l: has_overflowed = v: true
189
+ let l: fixeol = & fixendofline && ! & binary
309
190
endif
310
191
if l: max <= l: text_edit .range .end .line
311
192
let l: text_edit .range .end .line = l: max - 1
312
193
let l: text_edit .range .end .character = strchars (get (l: buf , -1 , 0 ))
313
- let l: has_overflowed = v: true
194
+ let l: fixeol = & fixendofline && ! & binary
314
195
endif
315
196
call add (l: text_edits , l: text_edit )
316
197
endfor
317
198
318
- return [l: has_overflowed , l: text_edits ]
199
+ return [l: fixeol , l: text_edits ]
319
200
endfunction
320
201
321
202
"
322
203
" _switch
323
204
"
324
205
function ! s: _switch (path ) abort
325
206
if bufnr (a: path ) >= 0
326
- execute printf (' keepalt keepjumps %sbuffer!' , bufnr (a: path ))
207
+ execute printf (' noautocmd keepalt keepjumps %sbuffer!' , bufnr (a: path ))
327
208
else
328
- execute printf (' keepalt keepjumps edit! %s' , fnameescape (a: path ))
209
+ execute printf (' noautocmd keepalt keepjumps edit! %s' , fnameescape (a: path ))
329
210
endif
211
+ return bufnr (' %' )
330
212
endfunction
331
213
332
- "
333
- " delete
334
- "
335
- function ! s: delete (bufnr , start , end ) abort
336
- if exists (' *deletebufline' )
337
- call deletebufline (a: bufnr , a: start , a: end )
338
- else
339
- try
340
- let l: Restore = s: Option .define ({ ' foldenable' : ' 0' })
341
- execute printf (' %s,%sdelete _' , a: start , a: end )
342
- finally
343
- call l: Restore ()
344
- endtry
345
- endif
346
- endfunction
0 commit comments