test_lsp_completion_messages.vader
1 Before: 2 Save g:ale_completion_delay 3 Save g:ale_completion_max_suggestions 4 Save g:ale_completion_info 5 Save &l:omnifunc 6 Save &l:completeopt 7 8 let g:ale_completion_enabled = 1 9 10 call ale#test#SetDirectory('/testplugin/test/completion') 11 call ale#test#SetFilename('dummy.txt') 12 13 runtime autoload/ale/lsp.vim 14 15 let g:message_list = [] 16 let g:capability_checked = '' 17 let g:conn_id = v:null 18 let g:Callback = '' 19 let g:init_callback_list = [] 20 21 function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort 22 let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {}) 23 call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer) 24 25 let l:details = { 26 \ 'command': 'foobar', 27 \ 'buffer': a:buffer, 28 \ 'connection_id': g:conn_id, 29 \ 'project_root': '/foo/bar', 30 \} 31 32 call add(g:init_callback_list, {-> a:Callback(a:linter, l:details)}) 33 endfunction 34 35 " Pretend we're in insert mode for most tests. 36 function! ale#util#Mode(...) abort 37 return 'i' 38 endfunction 39 40 function! ale#lsp#HasCapability(conn_id, capability) abort 41 let g:capability_checked = a:capability 42 43 return 1 44 endfunction 45 46 function! ale#lsp#RegisterCallback(conn_id, callback) abort 47 let g:Callback = a:callback 48 endfunction 49 50 " Replace the Send function for LSP, so we can monitor calls to it. 51 function! ale#lsp#Send(conn_id, message) abort 52 call add(g:message_list, a:message) 53 54 return 1 55 endfunction 56 57 After: 58 Restore 59 60 if g:conn_id isnot v:null 61 call ale#lsp#RemoveConnectionWithID(g:conn_id) 62 endif 63 64 unlet! g:message_list 65 unlet! g:capability_checked 66 unlet! g:init_callback_list 67 unlet! g:conn_id 68 unlet! g:Callback 69 unlet! b:ale_old_omnifunc 70 unlet! b:ale_old_completeopt 71 unlet! b:ale_completion_info 72 unlet! b:ale_complete_done_time 73 unlet! b:ale_linters 74 unlet! b:ale_tsserver_completion_names 75 76 " Reset the function. 77 function! ale#util#Mode(...) abort 78 return call('mode', a:000) 79 endfunction 80 81 call ale#test#RestoreDirectory() 82 call ale#linter#Reset() 83 84 " Stop any timers we left behind. 85 " This stops the tests from failing randomly. 86 call ale#completion#StopTimer() 87 88 runtime autoload/ale/completion.vim 89 runtime autoload/ale/lsp.vim 90 runtime autoload/ale/lsp_linter.vim 91 92 Given typescript(Some typescript file): 93 foo 94 somelongerline 95 bazxyzxyzxyz 96 97 Execute(The right message should be sent for the initial tsserver request): 98 runtime ale_linters/typescript/tsserver.vim 99 let b:ale_linters = ['tsserver'] 100 " The cursor position needs to match what was saved before. 101 call setpos('.', [bufnr(''), 1, 3, 0]) 102 103 call ale#completion#GetCompletions('ale-automatic') 104 105 " We shouldn't register the callback yet. 106 AssertEqual '''''', string(g:Callback) 107 108 AssertEqual 1, len(g:init_callback_list) 109 call map(g:init_callback_list, 'v:val()') 110 111 AssertEqual 'completion', g:capability_checked 112 113 " We should send the right callback. 114 AssertEqual 115 \ 'function(''ale#completion#HandleTSServerResponse'')', 116 \ string(g:Callback) 117 " We should send the right message. 118 AssertEqual 119 \ [[0, 'ts@completions', { 120 \ 'file': expand('%:p'), 121 \ 'line': 1, 122 \ 'offset': 3, 123 \ 'prefix': 'fo', 124 \ 'includeExternalModuleExports': g:ale_completion_autoimport, 125 \ }]], 126 \ g:message_list 127 " We should set up the completion info correctly. 128 AssertEqual 129 \ { 130 \ 'line_length': 3, 131 \ 'conn_id': g:conn_id, 132 \ 'column': 3, 133 \ 'request_id': 1, 134 \ 'line': 1, 135 \ 'prefix': 'fo', 136 \ 'source': 'ale-automatic', 137 \ }, 138 \ get(b:, 'ale_completion_info', {}) 139 140 Execute(The right message sent to the tsserver LSP when the first completion message is received): 141 " The cursor position needs to match what was saved before. 142 call setpos('.', [bufnr(''), 1, 1, 0]) 143 let b:ale_completion_info = { 144 \ 'conn_id': 123, 145 \ 'prefix': 'f', 146 \ 'request_id': 4, 147 \ 'line': 1, 148 \ 'column': 1, 149 \} 150 " We should only show up to this many suggestions. 151 let g:ale_completion_max_suggestions = 3 152 153 " Handle the response for completions. 154 call ale#completion#HandleTSServerResponse(123, { 155 \ 'request_seq': 4, 156 \ 'command': 'completions', 157 \ 'body': [ 158 \ {'name': 'Baz'}, 159 \ {'name': 'dingDong'}, 160 \ {'name': 'Foo', 'source': '/path/to/foo.ts'}, 161 \ {'name': 'FooBar'}, 162 \ {'name': 'frazzle'}, 163 \ {'name': 'FFS'}, 164 \ ], 165 \}) 166 167 " We should save the names we got in the buffer, as TSServer doesn't return 168 " details for every name. 169 AssertEqual [{ 170 \ 'word': 'Foo', 171 \ 'source': '/path/to/foo.ts', 172 \ }, { 173 \ 'word': 'FooBar', 174 \ 'source': '', 175 \ }, { 176 \ 'word': 'frazzle', 177 \ 'source': '', 178 \}], 179 \ get(b:, 'ale_tsserver_completion_names', []) 180 181 " The entry details messages should have been sent. 182 AssertEqual 183 \ [[ 184 \ 0, 185 \ 'ts@completionEntryDetails', 186 \ { 187 \ 'file': expand('%:p'), 188 \ 'entryNames': [{ 189 \ 'name': 'Foo', 190 \ 'source': '/path/to/foo.ts', 191 \ }, { 192 \ 'name': 'FooBar', 193 \ }, { 194 \ 'name': 'frazzle', 195 \ }], 196 \ 'offset': 1, 197 \ 'line': 1, 198 \ }, 199 \ ]], 200 \ g:message_list 201 202 Given python(Some Python file): 203 foo 204 somelongerline 205 bazxyzxyzxyz 206 207 Execute(The right message should be sent for the initial LSP request): 208 runtime ale_linters/python/pylsp.vim 209 let b:ale_linters = ['pylsp'] 210 " The cursor position needs to match what was saved before. 211 call setpos('.', [bufnr(''), 1, 5, 0]) 212 213 call ale#completion#GetCompletions('ale-automatic') 214 215 " We shouldn't register the callback yet. 216 AssertEqual '''''', string(g:Callback) 217 218 AssertEqual 1, len(g:init_callback_list) 219 call map(g:init_callback_list, 'v:val()') 220 221 AssertEqual 'completion', g:capability_checked 222 223 " We should send the right callback. 224 AssertEqual 225 \ 'function(''ale#completion#HandleLSPResponse'')', 226 \ string(g:Callback) 227 " We should send the right message. 228 " The character index needs to be at most the index of the last character on 229 " the line, or integration with pylsp will be broken. 230 " 231 " We need to send the message for changing the document first. 232 AssertEqual 233 \ [ 234 \ [1, 'textDocument/didChange', { 235 \ 'textDocument': { 236 \ 'uri': ale#path#ToFileURI(expand('%:p')), 237 \ 'version': g:ale_lsp_next_version_id - 1, 238 \ }, 239 \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] 240 \ }], 241 \ [0, 'textDocument/completion', { 242 \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, 243 \ 'position': {'line': 0, 'character': 2}, 244 \ }], 245 \ ], 246 \ g:message_list 247 " We should set up the completion info correctly. 248 AssertEqual 249 \ { 250 \ 'line_length': 3, 251 \ 'conn_id': g:conn_id, 252 \ 'column': 3, 253 \ 'request_id': 1, 254 \ 'line': 1, 255 \ 'prefix': 'fo', 256 \ 'source': 'ale-automatic', 257 \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', 258 \ }, 259 \ get(b:, 'ale_completion_info', {}) 260 261 Execute(Two completion requests shouldn't be sent in a row): 262 call ale#linter#PreventLoading('python') 263 call ale#linter#Define('python', { 264 \ 'name': 'foo', 265 \ 'lsp': 'stdio', 266 \ 'executable': 'foo', 267 \ 'command': 'foo', 268 \ 'project_root': {-> '/foo/bar'}, 269 \}) 270 call ale#linter#Define('python', { 271 \ 'name': 'bar', 272 \ 'lsp': 'stdio', 273 \ 'executable': 'foo', 274 \ 'command': 'foo', 275 \ 'project_root': {-> '/foo/bar'}, 276 \}) 277 let b:ale_linters = ['foo', 'bar'] 278 279 " The cursor position needs to match what was saved before. 280 call setpos('.', [bufnr(''), 1, 5, 0]) 281 282 call ale#completion#GetCompletions('ale-automatic') 283 284 " We shouldn't register the callback yet. 285 AssertEqual '''''', string(g:Callback) 286 287 AssertEqual 2, len(g:init_callback_list) 288 call map(g:init_callback_list, 'v:val()') 289 290 AssertEqual 'completion', g:capability_checked 291 292 " We should only send one completion message for two LSP servers. 293 AssertEqual 294 \ [ 295 \ [1, 'textDocument/didChange', { 296 \ 'textDocument': { 297 \ 'uri': ale#path#ToFileURI(expand('%:p')), 298 \ 'version': g:ale_lsp_next_version_id - 1, 299 \ }, 300 \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] 301 \ }], 302 \ [0, 'textDocument/completion', { 303 \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))}, 304 \ 'position': {'line': 0, 'character': 2}, 305 \ }], 306 \ ], 307 \ g:message_list