]> git.madduck.net Git - etc/vim.git/blob - .vim/bundle/vim-lsp/autoload/lsp/utils/diff.vim

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge commit 'a39f715c13be3352193ffd9c5b7536b8786eff64' as '.vim/bundle/vim-lsp'
[etc/vim.git] / .vim / bundle / vim-lsp / autoload / lsp / utils / diff.vim
1 " This is copied from https://github.com/natebosch/vim-lsc/blob/master/autoload/lsc/diff.vim
2 "
3 " Computes a simplistic diff between [old] and [new].
4 "
5 " Returns a dict with keys `range`, `rangeLength`, and `text` matching the LSP
6 " definition of `TextDocumentContentChangeEvent`.
7 "
8 " Finds a single change between the common prefix, and common postfix.
9 let s:has_lua = has('nvim-0.4.0') || (has('lua') && has('patch-8.2.0775'))
10 " lua array and neovim vim list index starts with 1 while vim lists starts with 0.
11 " starting patch-8.2.1066 vim lists array index was changed to start with 1.
12 let s:lua_array_start_index = has('nvim-0.4.0') || has('patch-8.2.1066')
13
14 function! s:init_lua() abort
15   lua <<EOF
16   -- Returns a zero-based index of the last line that is different between
17   -- old and new. If old and new are not zero indexed, pass offset to indicate
18   -- the index base.
19   function vimlsp_last_difference(old, new, offset, line_count)
20     for i = 0, line_count - 1 do
21       if old[#old - i + offset] ~= new[#new - i + offset] then
22         return -1 * i
23       end
24     end
25     return -1 * line_count
26   end
27   -- Returns a zero-based index of the first line that is different between
28   -- old and new. If old and new are not zero indexed, pass offset to indicate
29   -- the index base.
30   function vimlsp_first_difference(old, new, offset, line_count)
31     for i = 0, line_count - 1 do
32       if old[i + offset] ~= new[i + offset] then
33         return i
34       end
35     end
36     return line_count - 1
37   end
38 EOF
39         let s:lua = 1
40 endfunction
41
42 if s:has_lua && !exists('s:lua')
43   call s:init_lua()
44 endif
45
46 function! lsp#utils#diff#compute(old, new) abort
47   let [l:start_line, l:start_char] = s:FirstDifference(a:old, a:new)
48   let [l:end_line, l:end_char] =
49       \ s:LastDifference(a:old[l:start_line :], a:new[l:start_line :], l:start_char)
50
51   let l:text = s:ExtractText(a:new, l:start_line, l:start_char, l:end_line, l:end_char)
52   let l:length = s:Length(a:old, l:start_line, l:start_char, l:end_line, l:end_char)
53
54   let l:adj_end_line = len(a:old) + l:end_line
55   let l:adj_end_char = l:end_line == 0 ? 0 : strchars(a:old[l:end_line]) + l:end_char + 1
56
57   let l:result = { 'range': {'start': {'line': l:start_line, 'character': l:start_char},
58       \ 'end': {'line': l:adj_end_line, 'character': l:adj_end_char}},
59       \ 'text': l:text,
60       \ 'rangeLength': l:length,
61       \}
62
63   return l:result
64 endfunction
65
66 " Finds the line and character of the first different character between two
67 " list of Strings.
68 function! s:FirstDifference(old, new) abort
69   let l:line_count = min([len(a:old), len(a:new)])
70   if l:line_count == 0 | return [0, 0] | endif
71   if g:lsp_use_lua && s:has_lua
72     let l:eval = has('nvim') ? 'vim.api.nvim_eval' : 'vim.eval'
73     let l:i = luaeval('vimlsp_first_difference('
74         \.l:eval.'("a:old"),'.l:eval.'("a:new"),'.s:lua_array_start_index.','.l:line_count.')')
75   else
76         for l:i in range(l:line_count)
77           if a:old[l:i] !=# a:new[l:i] | break | endif
78         endfor
79   endif
80   if l:i >= l:line_count
81     return [l:line_count - 1, strchars(a:old[l:line_count - 1])]
82   endif
83   let l:old_line = a:old[l:i]
84   let l:new_line = a:new[l:i]
85   let l:length = min([strchars(l:old_line), strchars(l:new_line)])
86   let l:j = 0
87   while l:j < l:length
88     if strgetchar(l:old_line, l:j) != strgetchar(l:new_line, l:j) | break | endif
89     let l:j += 1
90   endwhile
91   return [l:i, l:j]
92 endfunction
93
94 function! s:LastDifference(old, new, start_char) abort
95   let l:line_count = min([len(a:old), len(a:new)])
96   if l:line_count == 0 | return [0, 0] | endif
97   if g:lsp_use_lua && s:has_lua
98     let l:eval = has('nvim') ? 'vim.api.nvim_eval' : 'vim.eval'
99     let l:i = luaeval('vimlsp_last_difference('
100         \.l:eval.'("a:old"),'.l:eval.'("a:new"),'.s:lua_array_start_index.','.l:line_count.')')
101   else
102         for l:i in range(-1, -1 * l:line_count, -1)
103           if a:old[l:i] !=# a:new[l:i] | break | endif
104         endfor
105   endif
106   if l:i <= -1 * l:line_count
107     let l:i = -1 * l:line_count
108     let l:old_line = strcharpart(a:old[l:i], a:start_char)
109     let l:new_line = strcharpart(a:new[l:i], a:start_char)
110   else
111     let l:old_line = a:old[l:i]
112     let l:new_line = a:new[l:i]
113   endif
114   let l:old_line_length = strchars(l:old_line)
115   let l:new_line_length = strchars(l:new_line)
116   let l:length = min([l:old_line_length, l:new_line_length])
117   let l:j = -1
118   while l:j >= -1 * l:length
119     if  strgetchar(l:old_line, l:old_line_length + l:j) !=
120         \ strgetchar(l:new_line, l:new_line_length + l:j)
121       break
122     endif
123     let l:j -= 1
124   endwhile
125   return [l:i, l:j]
126 endfunction
127
128 function! s:ExtractText(lines, start_line, start_char, end_line, end_char) abort
129   if a:start_line == len(a:lines) + a:end_line
130     if a:end_line == 0 | return '' | endif
131     let l:line = a:lines[a:start_line]
132     let l:length = strchars(l:line) + a:end_char - a:start_char + 1
133     return strcharpart(l:line, a:start_char, l:length)
134   endif
135   let l:result = strcharpart(a:lines[a:start_line], a:start_char) . "\n"
136   for l:line in a:lines[a:start_line + 1:a:end_line - 1]
137     let l:result .= l:line . "\n"
138   endfor
139   if a:end_line != 0
140     let l:line = a:lines[a:end_line]
141     let l:length = strchars(l:line) + a:end_char + 1
142     let l:result .= strcharpart(l:line, 0, l:length)
143   endif
144   return l:result
145 endfunction
146
147 function! s:Length(lines, start_line, start_char, end_line, end_char) abort
148   let l:adj_end_line = len(a:lines) + a:end_line
149   if l:adj_end_line >= len(a:lines)
150     let l:adj_end_char = a:end_char - 1
151   else
152     let l:adj_end_char = strchars(a:lines[l:adj_end_line]) + a:end_char
153   endif
154   if a:start_line == l:adj_end_line
155     return l:adj_end_char - a:start_char + 1
156   endif
157   let l:result = strchars(a:lines[a:start_line]) - a:start_char + 1
158   let l:line = a:start_line + 1
159   while l:line < l:adj_end_line
160     let l:result += strchars(a:lines[l:line]) + 1
161     let l:line += 1
162   endwhile
163   let l:result += l:adj_end_char + 1
164   return l:result
165 endfunction