44function ! s: _SID () abort
55 return matchstr (expand (' <sfile>' ), ' <SNR>\zs\d\+\ze__SID$' )
66endfunction
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 " )
88delfunction s: _SID
99" ___vital___
1010"
@@ -23,144 +23,64 @@ function! s:_vital_depends() abort
2323 return [' VS.LSP.Text' , ' VS.LSP.Position' , ' VS.Vim.Option' ]
2424endfunction
2525
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-
8126"
8227" apply
8328"
8429function ! s: apply (path , text_edits) abort
8530 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 ()
8832
33+ let l: target_bufnr = s: _switch (a: path )
8934 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 )
9736 catch /.*/
98- call themis#log ( string ({ ' exception' : v: exception , ' throwpoint' : v: throwpoint }) )
37+ echomsg string ({ ' exception' : v: exception , ' throwpoint' : v: throwpoint })
9938 endtry
39+ let l: current_bufnr = s: _switch (l: current_bufname )
10040
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 ))
10343 endif
10444endfunction
10545
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-
13246"
133- " normal
47+ " _substitute
13448"
135- function ! s: _methods . normal (bufnr , text_edits, cursor_position ) abort
49+ function ! s: _substitute (bufnr , text_edits, current_position ) abort
13650 let l: fix_cursor = v: false
13751
13852 try
53+ " Save state.
13954 let l: Restore = s: Option .define ({
14055 \ ' foldenable' : ' 0' ,
141- \ ' virtualedit' : ' onemore' ,
142- \ ' whichwrap' : ' h' ,
143- \ ' selection' : ' exclusive' ,
14456 \ })
14557 let l: view = winsaveview ()
14658 let l: regx = getreg (' x' )
14759
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
14963 let l: start = s: Position .lsp_to_vim (a: bufnr , l: text_edit .range .start )
15064 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
15665 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
16074 endfor
75+
76+ " Remove last empty line if fixeol enabled.
77+ if l: fixeol && getline (' $' ) == ' '
78+ $delete _
79+ endif
16180 catch /.*/
16281 echomsg string ({ ' exception' : v: exception , ' throwpoint' : v: throwpoint })
16382 finally
83+ " Restore state.
16484 call l: Restore ()
16585 call winrestview (l: view )
16686 call setreg (' x' , l: regx )
@@ -169,50 +89,6 @@ function! s:_methods.normal(bufnr, text_edits, cursor_position) abort
16989 return l: fix_cursor
17090endfunction
17191
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-
21692"
21793" _fix_cursor
21894"
@@ -240,7 +116,7 @@ endfunction
240116function ! s: _normalize (bufnr , text_edits) abort
241117 let l: text_edits = type (a: text_edits ) == type ([]) ? a: text_edits : [a: text_edits ]
242118 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' ))
244120 let l: text_edits = s: _check (l: text_edits )
245121 let l: text_edits = reverse (l: text_edits )
246122 return s: _fix_text_edits (a: bufnr , l: text_edits )
@@ -250,15 +126,20 @@ endfunction
250126" _range
251127"
252128function ! s: _range (text_edits) abort
129+ let l: text_edits = []
253130 for l: text_edit in a: text_edits
131+ if type (l: text_edit ) != type ({})
132+ continue
133+ endif
254134 if l: text_edit .range .start .line > l: text_edit .range .end .line || (
255135 \ l: text_edit .range .start .line == l: text_edit .range .end .line &&
256136 \ l: text_edit .range .start .character > l: text_edit .range .end .character
257137 \ )
258138 let l: text_edit .range = { ' start' : l: text_edit .range .end , ' end' : l: text_edit .range .start }
259139 endif
140+ let l: text_edits += [l: text_edit ]
260141 endfor
261- return a : text_edits
142+ return l : text_edits
262143endfunction
263144
264145"
@@ -298,49 +179,35 @@ function! s:_fix_text_edits(bufnr, text_edits) abort
298179 let l: buf = getbufline (a: bufnr , ' ^' , ' $' )
299180 let l: max = len (l: buf )
300181
301- let l: has_overflowed = v: false
182+ let l: fixeol = v: false
302183 let l: text_edits = []
303184 for l: text_edit in a: text_edits
304185 if l: max <= l: text_edit .range .start .line
305186 let l: text_edit .range .start .line = l: max - 1
306187 let l: text_edit .range .start .character = strchars (get (l: buf , -1 , 0 ))
307188 let l: text_edit .newText = " \n " . l: text_edit .newText
308- let l: has_overflowed = v: true
189+ let l: fixeol = & fixendofline && ! & binary
309190 endif
310191 if l: max <= l: text_edit .range .end .line
311192 let l: text_edit .range .end .line = l: max - 1
312193 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
314195 endif
315196 call add (l: text_edits , l: text_edit )
316197 endfor
317198
318- return [l: has_overflowed , l: text_edits ]
199+ return [l: fixeol , l: text_edits ]
319200endfunction
320201
321202"
322203" _switch
323204"
324205function ! s: _switch (path ) abort
325206 if bufnr (a: path ) >= 0
326- execute printf (' keepalt keepjumps %sbuffer!' , bufnr (a: path ))
207+ execute printf (' noautocmd keepalt keepjumps %sbuffer!' , bufnr (a: path ))
327208 else
328- execute printf (' keepalt keepjumps edit! %s' , fnameescape (a: path ))
209+ execute printf (' noautocmd keepalt keepjumps edit! %s' , fnameescape (a: path ))
329210 endif
211+ return bufnr (' %' )
330212endfunction
331213
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