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.
2 call ale#test#SetDirectory('/testplugin/test')
3 call ale#test#SetFilename('dummy.txt')
5 Save g:ale_default_navigation
7 let g:old_filename = expand('%:p')
9 let g:message_list = []
11 let g:capability_checked = ''
12 let g:conn_id = v:null
13 let g:InitCallback = v:null
14 let g:ale_default_navigation = 'buffer'
16 runtime autoload/ale/linter.vim
17 runtime autoload/ale/lsp_linter.vim
18 runtime autoload/ale/lsp.vim
19 runtime autoload/ale/util.vim
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)
25 if a:linter.lsp is# 'tsserver'
26 call ale#lsp#MarkConnectionAsTsserver(g:conn_id)
30 \ 'command': 'foobar',
32 \ 'connection_id': g:conn_id,
33 \ 'project_root': '/foo/bar',
36 let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)}
39 function! ale#lsp#HasCapability(conn_id, capability) abort
40 let g:capability_checked = a:capability
45 function! ale#lsp#RegisterCallback(conn_id, callback) abort
46 let g:Callback = a:callback
49 function! ale#lsp#Send(conn_id, message) abort
50 call add(g:message_list, a:message)
55 function! ale#util#Execute(expr) abort
56 call add(g:expr_list, a:expr)
62 if g:conn_id isnot v:null
63 call ale#lsp#RemoveConnectionWithID(g:conn_id)
66 call ale#definition#SetMap({})
67 call ale#test#RestoreDirectory()
68 call ale#linter#Reset()
70 unlet! g:capability_checked
79 runtime autoload/ale/lsp_linter.vim
80 runtime autoload/ale/lsp.vim
81 runtime autoload/ale/util.vim
83 Execute(Other messages for the tsserver handler should be ignored):
84 call ale#definition#HandleTSServerResponse(1, {'command': 'foo'})
86 Execute(Tagstack should be incremented if supported):
87 if exists('*gettagstack') && exists('*settagstack')
88 let original_stack_depth = gettagstack().length
90 call ale#definition#UpdateTagStack()
91 if exists('*gettagstack') && exists('*settagstack')
92 AssertEqual original_stack_depth + 1, gettagstack().length
95 Execute(Failed definition responses should be handled correctly):
96 call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
97 call ale#definition#HandleTSServerResponse(
99 \ {'command': 'definition', 'request_seq': 3}
101 AssertEqual {}, ale#definition#GetMap()
103 Execute(Failed definition responses with no files should be handled correctly):
104 call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
105 call ale#definition#HandleTSServerResponse(
108 \ 'command': 'definition',
114 AssertEqual {}, ale#definition#GetMap()
116 Given typescript(Some typescript file):
121 Execute(Other files should be jumped to for definition responses):
122 call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
123 call ale#definition#HandleTSServerResponse(
126 \ 'command': 'definition',
131 \ 'file': ale#path#Simplify(g:dir . '/completion_dummy_file'),
132 \ 'start': {'line': 3, 'offset': 7},
140 \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
143 AssertEqual [3, 7], getpos('.')[1:2]
144 AssertEqual {}, ale#definition#GetMap()
146 Execute(Other files should be jumped to for definition responses in tabs too):
147 call ale#definition#SetMap({3: {'open_in': 'tab'}})
148 call ale#definition#HandleTSServerResponse(
151 \ 'command': 'definition',
156 \ 'file': ale#path#Simplify(g:dir . '/completion_dummy_file'),
157 \ 'start': {'line': 3, 'offset': 7},
165 \ 'tabedit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
168 AssertEqual [3, 7], getpos('.')[1:2]
169 AssertEqual {}, ale#definition#GetMap()
171 Execute(Other files should be jumped to for definition responses in splits too):
172 call ale#definition#SetMap({3: {'open_in': 'split'}})
173 call ale#definition#HandleTSServerResponse(
176 \ 'command': 'definition',
181 \ 'file': ale#path#Simplify(g:dir . '/completion_dummy_file'),
182 \ 'start': {'line': 3, 'offset': 7},
190 \ 'split +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
193 AssertEqual [3, 7], getpos('.')[1:2]
194 AssertEqual {}, ale#definition#GetMap()
196 Execute(Other files should be jumped to for definition responses in vsplits too):
197 call ale#definition#SetMap({3: {'open_in': 'vsplit'}})
198 call ale#definition#HandleTSServerResponse(
201 \ 'command': 'definition',
206 \ 'file': ale#path#Simplify(g:dir . '/completion_dummy_file'),
207 \ 'start': {'line': 3, 'offset': 7},
215 \ 'vsplit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
218 AssertEqual [3, 7], getpos('.')[1:2]
219 AssertEqual {}, ale#definition#GetMap()
221 Execute(tsserver definition requests should be sent):
222 runtime ale_linters/typescript/tsserver.vim
223 call setpos('.', [bufnr(''), 2, 5, 0])
227 " We shouldn't register the callback yet.
228 AssertEqual '''''', string(g:Callback)
230 AssertEqual type(function('type')), type(g:InitCallback)
231 call g:InitCallback()
233 AssertEqual 'definition', g:capability_checked
235 \ 'function(''ale#definition#HandleTSServerResponse'')',
239 \ ale#lsp#tsserver_message#Change(bufnr('')),
240 \ [0, 'ts@definition', {'file': expand('%:p'), 'line': 2, 'offset': 5}]
243 AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap()
245 Execute(tsserver type definition requests should be sent):
246 runtime ale_linters/typescript/tsserver.vim
247 call setpos('.', [bufnr(''), 2, 5, 0])
249 ALEGoToTypeDefinition
251 " We shouldn't register the callback yet.
252 AssertEqual '''''', string(g:Callback)
254 AssertEqual type(function('type')), type(g:InitCallback)
255 call g:InitCallback()
257 AssertEqual 'typeDefinition', g:capability_checked
259 \ 'function(''ale#definition#HandleTSServerResponse'')',
263 \ ale#lsp#tsserver_message#Change(bufnr('')),
264 \ [0, 'ts@typeDefinition', {'file': expand('%:p'), 'line': 2, 'offset': 5}]
267 AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap()
269 Execute(tsserver implementation requests should be sent):
270 runtime ale_linters/typescript/tsserver.vim
271 call setpos('.', [bufnr(''), 2, 5, 0])
273 ALEGoToImplementation
275 " We shouldn't register the callback yet.
276 AssertEqual '''''', string(g:Callback)
278 AssertEqual type(function('type')), type(g:InitCallback)
279 call g:InitCallback()
281 AssertEqual 'implementation', g:capability_checked
283 \ 'function(''ale#definition#HandleTSServerResponse'')',
287 \ ale#lsp#tsserver_message#Change(bufnr('')),
288 \ [0, 'ts@implementation', {'file': expand('%:p'), 'line': 2, 'offset': 5}]
291 AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap()
293 Execute(tsserver tab definition requests should be sent):
294 runtime ale_linters/typescript/tsserver.vim
295 call setpos('.', [bufnr(''), 2, 5, 0])
297 ALEGoToDefinition -tab
299 " We shouldn't register the callback yet.
300 AssertEqual '''''', string(g:Callback)
302 AssertEqual type(function('type')), type(g:InitCallback)
303 call g:InitCallback()
305 AssertEqual 'definition', g:capability_checked
307 \ 'function(''ale#definition#HandleTSServerResponse'')',
311 \ ale#lsp#tsserver_message#Change(bufnr('')),
312 \ [0, 'ts@definition', {'file': expand('%:p'), 'line': 2, 'offset': 5}]
315 AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap()
317 Execute(The default navigation type should be used):
318 runtime ale_linters/typescript/tsserver.vim
319 call setpos('.', [bufnr(''), 2, 5, 0])
321 let g:ale_default_navigation = 'tab'
324 " We shouldn't register the callback yet.
325 AssertEqual '''''', string(g:Callback)
327 AssertEqual type(function('type')), type(g:InitCallback)
328 call g:InitCallback()
330 AssertEqual 'definition', g:capability_checked
332 \ 'function(''ale#definition#HandleTSServerResponse'')',
336 \ ale#lsp#tsserver_message#Change(bufnr('')),
337 \ [0, 'ts@definition', {'file': expand('%:p'), 'line': 2, 'offset': 5}]
340 AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap()
342 Given python(Some Python file):
347 Execute(Other files should be jumped to for LSP definition responses):
348 call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
349 call ale#definition#HandleLSPResponse(
354 \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')),
356 \ 'start': {'line': 2, 'character': 7},
364 \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
367 AssertEqual [3, 8], getpos('.')[1:2]
368 AssertEqual {}, ale#definition#GetMap()
370 Execute(Newer LocationLink items should be supported):
371 call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
372 call ale#definition#HandleLSPResponse(
377 \ 'targetUri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')),
379 \ 'start': {'line': 2, 'character': 7},
387 \ 'edit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
390 AssertEqual [3, 8], getpos('.')[1:2]
391 AssertEqual {}, ale#definition#GetMap()
393 Execute(Locations inside the same file should be jumped to without using :edit):
394 call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
395 call ale#definition#HandleLSPResponse(
400 \ 'uri': ale#path#ToFileURI(ale#path#Simplify(expand('%:p'))),
402 \ 'start': {'line': 2, 'character': 7},
412 AssertEqual [3, 8], getpos('.')[1:2]
413 AssertEqual {}, ale#definition#GetMap()
415 Execute(Other files should be jumped to in tabs for LSP definition responses):
416 call ale#definition#SetMap({3: {'open_in': 'tab'}})
417 call ale#definition#HandleLSPResponse(
422 \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')),
424 \ 'start': {'line': 2, 'character': 7},
432 \ 'tabedit +3 ' . fnameescape(ale#path#Simplify(g:dir . '/completion_dummy_file')),
435 AssertEqual [3, 8], getpos('.')[1:2]
436 AssertEqual {}, ale#definition#GetMap()
438 Execute(Definition responses with lists should be handled):
439 call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
440 call ale#definition#HandleLSPResponse(
446 \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/completion_dummy_file')),
448 \ 'start': {'line': 2, 'character': 7},
452 \ 'uri': ale#path#ToFileURI(ale#path#Simplify(g:dir . '/other_file')),
454 \ 'start': {'line': 20, 'character': 3},
461 " Multiple results should either open the ALEPreview or go to quickfix
462 AssertEqual [1, 1], getpos('.')[1:2]
463 AssertEqual {}, ale#definition#GetMap()
465 Execute(Definition responses with null response should be handled):
466 call ale#definition#SetMap({3: {'open_in': 'current-buffer'}})
467 call ale#definition#HandleLSPResponse(1, {'id': 3, 'result': v:null})
469 AssertEqual ['echom ''No definitions found'''], g:expr_list
471 Execute(LSP definition requests should be sent):
472 runtime ale_linters/python/pylsp.vim
473 let b:ale_linters = ['pylsp']
474 call setpos('.', [bufnr(''), 1, 5, 0])
478 " We shouldn't register the callback yet.
479 AssertEqual '''''', string(g:Callback)
481 AssertEqual type(function('type')), type(g:InitCallback)
482 call g:InitCallback()
484 AssertEqual 'definition', g:capability_checked
486 \ 'function(''ale#definition#HandleLSPResponse'')',
491 \ [1, 'textDocument/didChange', {
493 \ 'uri': ale#path#ToFileURI(expand('%:p')),
494 \ 'version': g:ale_lsp_next_version_id - 1,
496 \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
498 \ [0, 'textDocument/definition', {
499 \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
500 \ 'position': {'line': 0, 'character': 2},
505 AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap()
507 Execute(LSP type definition requests should be sent):
508 runtime ale_linters/python/pylsp.vim
509 let b:ale_linters = ['pylsp']
510 call setpos('.', [bufnr(''), 1, 5, 0])
512 ALEGoToTypeDefinition
514 " We shouldn't register the callback yet.
515 AssertEqual '''''', string(g:Callback)
517 AssertEqual type(function('type')), type(g:InitCallback)
518 call g:InitCallback()
520 AssertEqual 'typeDefinition', g:capability_checked
522 \ 'function(''ale#definition#HandleLSPResponse'')',
527 \ [1, 'textDocument/didChange', {
529 \ 'uri': ale#path#ToFileURI(expand('%:p')),
530 \ 'version': g:ale_lsp_next_version_id - 1,
532 \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
534 \ [0, 'textDocument/typeDefinition', {
535 \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
536 \ 'position': {'line': 0, 'character': 2},
541 AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap()
543 Execute(LSP implementation requests should be sent):
544 runtime ale_linters/python/pylsp.vim
545 let b:ale_linters = ['pylsp']
546 call setpos('.', [bufnr(''), 1, 5, 0])
548 ALEGoToImplementation
550 " We shouldn't register the callback yet.
551 AssertEqual '''''', string(g:Callback)
553 AssertEqual type(function('type')), type(g:InitCallback)
554 call g:InitCallback()
556 AssertEqual 'implementation', g:capability_checked
558 \ 'function(''ale#definition#HandleLSPResponse'')',
563 \ [1, 'textDocument/didChange', {
565 \ 'uri': ale#path#ToFileURI(expand('%:p')),
566 \ 'version': g:ale_lsp_next_version_id - 1,
568 \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
570 \ [0, 'textDocument/implementation', {
571 \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
572 \ 'position': {'line': 0, 'character': 2},
577 AssertEqual {'42': {'open_in': 'current-buffer'}}, ale#definition#GetMap()
579 Execute(LSP tab definition requests should be sent):
580 runtime ale_linters/python/pylsp.vim
581 let b:ale_linters = ['pylsp']
582 call setpos('.', [bufnr(''), 1, 5, 0])
584 ALEGoToDefinition -tab
586 " We shouldn't register the callback yet.
587 AssertEqual '''''', string(g:Callback)
589 AssertEqual type(function('type')), type(g:InitCallback)
590 call g:InitCallback()
592 AssertEqual 'definition', g:capability_checked
594 \ 'function(''ale#definition#HandleLSPResponse'')',
599 \ [1, 'textDocument/didChange', {
601 \ 'uri': ale#path#ToFileURI(expand('%:p')),
602 \ 'version': g:ale_lsp_next_version_id - 1,
604 \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
606 \ [0, 'textDocument/definition', {
607 \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
608 \ 'position': {'line': 0, 'character': 2},
613 AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap()
615 Execute(LSP tab type definition requests should be sent):
616 runtime ale_linters/python/pylsp.vim
617 let b:ale_linters = ['pylsp']
618 call setpos('.', [bufnr(''), 1, 5, 0])
620 ALEGoToTypeDefinition -tab
622 " We shouldn't register the callback yet.
623 AssertEqual '''''', string(g:Callback)
625 AssertEqual type(function('type')), type(g:InitCallback)
626 call g:InitCallback()
628 AssertEqual 'typeDefinition', g:capability_checked
630 \ 'function(''ale#definition#HandleLSPResponse'')',
635 \ [1, 'textDocument/didChange', {
637 \ 'uri': ale#path#ToFileURI(expand('%:p')),
638 \ 'version': g:ale_lsp_next_version_id - 1,
640 \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
642 \ [0, 'textDocument/typeDefinition', {
643 \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
644 \ 'position': {'line': 0, 'character': 2},
649 AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap()
651 Execute(LSP tab implementation requests should be sent):
652 runtime ale_linters/python/pylsp.vim
653 let b:ale_linters = ['pylsp']
654 call setpos('.', [bufnr(''), 1, 5, 0])
656 ALEGoToImplementation -tab
658 " We shouldn't register the callback yet.
659 AssertEqual '''''', string(g:Callback)
661 AssertEqual type(function('type')), type(g:InitCallback)
662 call g:InitCallback()
664 AssertEqual 'implementation', g:capability_checked
666 \ 'function(''ale#definition#HandleLSPResponse'')',
671 \ [1, 'textDocument/didChange', {
673 \ 'uri': ale#path#ToFileURI(expand('%:p')),
674 \ 'version': g:ale_lsp_next_version_id - 1,
676 \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
678 \ [0, 'textDocument/implementation', {
679 \ 'textDocument': {'uri': ale#path#ToFileURI(expand('%:p'))},
680 \ 'position': {'line': 0, 'character': 2},
685 AssertEqual {'42': {'open_in': 'tab'}}, ale#definition#GetMap()