mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-06 20:54:26 +08:00
Implement pull diagnostics in the VimL implementation so ALE is able to track when servers are busy checking files. Only servers that support this feature will return diagnostics these ways.
553 lines
13 KiB
Plaintext
553 lines
13 KiB
Plaintext
Before:
|
|
Save g:ale_set_lists_synchronously
|
|
Save g:ale_buffer_info
|
|
Save g:ale_lsp_error_messages
|
|
Save g:ale_set_loclist
|
|
Save g:ale_set_signs
|
|
Save g:ale_set_quickfix
|
|
Save g:ale_set_highlights
|
|
Save g:ale_echo_cursor
|
|
Save g:ale_disable_lsp
|
|
Save g:ale_history_enabled
|
|
Save g:ale_history_log_output
|
|
|
|
let g:ale_disable_lsp = 0
|
|
let g:ale_set_lists_synchronously = 1
|
|
let g:ale_buffer_info = {}
|
|
let g:ale_set_loclist = 1
|
|
" Disable features we don't need for these tests.
|
|
let g:ale_set_signs = 0
|
|
let g:ale_set_quickfix = 0
|
|
let g:ale_set_highlights = 0
|
|
let g:ale_echo_cursor = 0
|
|
let g:ale_history_enabled = 1
|
|
let g:ale_history_log_output = 1
|
|
|
|
unlet! g:ale_lsp_error_messages
|
|
unlet! b:ale_linters
|
|
unlet! b:ale_disable_lsp
|
|
|
|
call ale#linter#Reset()
|
|
call ale#test#SetDirectory('/testplugin/test')
|
|
call setloclist(0, [])
|
|
|
|
After:
|
|
Restore
|
|
|
|
unlet! b:ale_linters
|
|
|
|
call setloclist(0, [])
|
|
call ale#test#RestoreDirectory()
|
|
call ale#linter#Reset()
|
|
call ale#lsp_linter#ClearLSPData()
|
|
|
|
Given foobar(An empty file):
|
|
Execute(tsserver syntax error responses should be handled correctly):
|
|
runtime ale_linters/typescript/tsserver.vim
|
|
|
|
if has('win32')
|
|
call ale#test#SetFilename('filename,[]^$.ts')
|
|
else
|
|
call ale#test#SetFilename('filename*?,{}[]^$.ts')
|
|
endif
|
|
|
|
call ale#engine#InitBufferInfo(bufnr(''))
|
|
|
|
if has('win32')
|
|
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
|
|
else
|
|
AssertEqual 'filename*?,{}[]^$.ts', expand('%:p:t')
|
|
endif
|
|
|
|
" When we get syntax errors and no semantic errors, we should keep the
|
|
" syntax errors.
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'syntaxDiag',
|
|
\ 'body': {
|
|
\ 'file': expand('%:p'),
|
|
\ 'diagnostics':[
|
|
\ {
|
|
\ 'start': {
|
|
\ 'line':2,
|
|
\ 'offset':14,
|
|
\ },
|
|
\ 'end': {
|
|
\ 'line':2,
|
|
\ 'offset':15,
|
|
\ },
|
|
\ 'text': ''','' expected.',
|
|
\ "code":1005
|
|
\ },
|
|
\ ],
|
|
\ },
|
|
\})
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'semanticDiag',
|
|
\ 'body': {
|
|
\ 'file': expand('%:p'),
|
|
\ 'diagnostics':[
|
|
\ ],
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ {
|
|
\ 'lnum': 1,
|
|
\ 'bufnr': bufnr(''),
|
|
\ 'col': 14,
|
|
\ 'vcol': 0,
|
|
\ 'nr': 1005,
|
|
\ 'type': 'E',
|
|
\ 'text': '1005: '','' expected.',
|
|
\ 'valid': 1,
|
|
\ 'pattern': '',
|
|
\ },
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
|
|
" After we get empty syntax errors, we should clear them.
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'syntaxDiag',
|
|
\ 'body': {
|
|
\ 'file': expand('%:p'),
|
|
\ 'diagnostics':[
|
|
\ ],
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
|
|
" Syntax errors on the project root should not populate the LocList.
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'syntaxDiag',
|
|
\ 'body': {
|
|
\ 'file': g:dir,
|
|
\ 'diagnostics':[
|
|
\ {
|
|
\ 'start': {
|
|
\ 'line':2,
|
|
\ 'offset':14,
|
|
\ },
|
|
\ 'end': {
|
|
\ 'line':2,
|
|
\ 'offset':15,
|
|
\ },
|
|
\ 'text': ''','' expected.',
|
|
\ "code":1005
|
|
\ },
|
|
\ ],
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
|
|
Execute(tsserver semantic error responses should be handled correctly):
|
|
runtime ale_linters/typescript/tsserver.vim
|
|
|
|
if has('win32')
|
|
call ale#test#SetFilename('filename,[]^$.ts')
|
|
else
|
|
call ale#test#SetFilename('filename*?,{}[]^$.ts')
|
|
endif
|
|
|
|
call ale#engine#InitBufferInfo(bufnr(''))
|
|
|
|
if has('win32')
|
|
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
|
|
else
|
|
AssertEqual 'filename*?,{}[]^$.ts', expand('%:p:t')
|
|
endif
|
|
|
|
" When we get syntax errors and no semantic errors, we should keep the
|
|
" syntax errors.
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'syntaxDiag',
|
|
\ 'body': {
|
|
\ 'file': expand('%:p'),
|
|
\ 'diagnostics':[
|
|
\ ],
|
|
\ },
|
|
\})
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'semanticDiag',
|
|
\ 'body': {
|
|
\ 'file': expand('%:p'),
|
|
\ 'diagnostics':[
|
|
\ {
|
|
\ 'start': {
|
|
\ 'line':2,
|
|
\ 'offset':14,
|
|
\ },
|
|
\ 'end': {
|
|
\ 'line':2,
|
|
\ 'offset':15,
|
|
\ },
|
|
\ 'text': 'Some semantic error',
|
|
\ "code":1005
|
|
\ },
|
|
\ ],
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ {
|
|
\ 'lnum': 1,
|
|
\ 'bufnr': bufnr(''),
|
|
\ 'col': 14,
|
|
\ 'vcol': 0,
|
|
\ 'nr': 1005,
|
|
\ 'type': 'E',
|
|
\ 'text': '1005: Some semantic error',
|
|
\ 'valid': 1,
|
|
\ 'pattern': '',
|
|
\ },
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
|
|
" After we get empty syntax errors, we should clear them.
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'semanticDiag',
|
|
\ 'body': {
|
|
\ 'file': expand('%:p'),
|
|
\ 'diagnostics':[
|
|
\ ],
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
|
|
" Semantic errors on the project root should not populate the LocList.
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'semanticDiag',
|
|
\ 'body': {
|
|
\ 'file': g:dir,
|
|
\ 'diagnostics':[
|
|
\ {
|
|
\ 'start': {
|
|
\ 'line':2,
|
|
\ 'offset':14,
|
|
\ },
|
|
\ 'end': {
|
|
\ 'line':2,
|
|
\ 'offset':15,
|
|
\ },
|
|
\ 'text': 'Some semantic error',
|
|
\ "code":1005
|
|
\ },
|
|
\ ],
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
|
|
Execute(tsserver errors should mark tsserver no longer active):
|
|
let b:ale_linters = ['tsserver']
|
|
runtime ale_linters/typescript/tsserver.vim
|
|
call ale#test#SetFilename('filename.ts')
|
|
call ale#engine#InitBufferInfo(bufnr(''))
|
|
|
|
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('typescript')
|
|
Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list)
|
|
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'seq': 0,
|
|
\ 'type': 'event',
|
|
\ 'event': 'semanticDiag',
|
|
\ 'body': {
|
|
\ 'file': g:dir . '/filename.ts',
|
|
\ 'diagnostics':[],
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
|
|
|
|
Execute(LSP diagnostics responses should be handled correctly):
|
|
let b:ale_linters = ['eclipselsp']
|
|
runtime ale_linters/java/eclipselsp.vim
|
|
|
|
if has('win32')
|
|
call ale#test#SetFilename('filename,[]^$.ts')
|
|
else
|
|
call ale#test#SetFilename('filename*?,{}[]^$.java')
|
|
endif
|
|
|
|
call ale#engine#InitBufferInfo(bufnr(''))
|
|
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
|
|
|
|
if has('win32')
|
|
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
|
|
else
|
|
AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t')
|
|
endif
|
|
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'jsonrpc':'2.0',
|
|
\ 'method':'textDocument/publishDiagnostics',
|
|
\ 'params': {
|
|
\ 'uri': ale#path#ToFileURI(expand('%:p')),
|
|
\ 'diagnostics': [
|
|
\ {
|
|
\ 'range': {
|
|
\ 'start': {
|
|
\ 'line': 0,
|
|
\ 'character':0
|
|
\ },
|
|
\ 'end': {
|
|
\ 'line': 0,
|
|
\ 'character':0
|
|
\ }
|
|
\ },
|
|
\ 'severity': 2,
|
|
\ 'code': "",
|
|
\ 'source': 'Java',
|
|
\ 'message': 'Missing JRE 1-8'
|
|
\ }
|
|
\ ]
|
|
\ }
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ {
|
|
\ 'lnum': 1,
|
|
\ 'bufnr': bufnr(''),
|
|
\ 'col': 1,
|
|
\ 'pattern': '',
|
|
\ 'valid': 1,
|
|
\ 'vcol': 0,
|
|
\ 'nr': -1,
|
|
\ 'type': 'W',
|
|
\ 'text': 'Missing JRE 1-8'
|
|
\ }
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
|
|
Execute(LSP diagnostics responses on project root should not populate loclist):
|
|
let b:ale_linters = ['eclipselsp']
|
|
runtime ale_linters/java/eclipselsp.vim
|
|
call ale#test#SetFilename('filename.java')
|
|
call ale#engine#InitBufferInfo(bufnr(''))
|
|
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
|
|
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'jsonrpc':'2.0',
|
|
\ 'method':'textDocument/publishDiagnostics',
|
|
\ 'params': {
|
|
\ 'uri':'file://' . g:dir,
|
|
\ 'diagnostics': [
|
|
\ {
|
|
\ 'range': {
|
|
\ 'start': {
|
|
\ 'line': 0,
|
|
\ 'character':0
|
|
\ },
|
|
\ 'end': {
|
|
\ 'line': 0,
|
|
\ 'character':0
|
|
\ }
|
|
\ },
|
|
\ 'severity': 2,
|
|
\ 'code': "",
|
|
\ 'source': 'Java',
|
|
\ 'message': 'Missing JRE 1-8'
|
|
\ }
|
|
\ ]
|
|
\ }
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
|
|
Execute(LSP errors should mark linters no longer active):
|
|
let b:ale_linters = ['pylsp']
|
|
runtime ale_linters/python/pylsp.vim
|
|
call ale#test#SetFilename('filename.py')
|
|
call ale#engine#InitBufferInfo(bufnr(''))
|
|
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'pylsp', 'aliases': [], 'lsp': 'stdio'}})
|
|
|
|
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('python')
|
|
Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list)
|
|
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'method': 'textDocument/publishDiagnostics',
|
|
\ 'params': {
|
|
\ 'uri': ale#path#ToFileURI(g:dir . '/filename.py'),
|
|
\ 'diagnostics': [],
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
|
|
|
|
Execute(LSP pull model diagnostic responses should be handled):
|
|
let b:ale_linters = ['eclipselsp']
|
|
runtime ale_linters/java/eclipselsp.vim
|
|
|
|
if has('win32')
|
|
call ale#test#SetFilename('filename,[]^$.ts')
|
|
else
|
|
call ale#test#SetFilename('filename*?,{}[]^$.java')
|
|
endif
|
|
|
|
call ale#engine#InitBufferInfo(bufnr(''))
|
|
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('eclipselsp')
|
|
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
|
|
call ale#lsp_linter#SetDiagnosticURIMap({'347': ale#util#ToURI(expand('%:p'))})
|
|
|
|
if has('win32')
|
|
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
|
|
else
|
|
AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t')
|
|
endif
|
|
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'jsonrpc':'2.0',
|
|
\ 'id': 347,
|
|
\ 'result': {
|
|
\ 'kind': 'full',
|
|
\ 'items': [
|
|
\ {
|
|
\ 'range': {
|
|
\ 'start': {
|
|
\ 'line': 0,
|
|
\ 'character':0
|
|
\ },
|
|
\ 'end': {
|
|
\ 'line': 0,
|
|
\ 'character':0
|
|
\ }
|
|
\ },
|
|
\ 'severity': 2,
|
|
\ 'code': "",
|
|
\ 'source': 'Java',
|
|
\ 'message': 'Missing JRE 1-8'
|
|
\ }
|
|
\ ]
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ {
|
|
\ 'lnum': 1,
|
|
\ 'bufnr': bufnr(''),
|
|
\ 'col': 1,
|
|
\ 'pattern': '',
|
|
\ 'valid': 1,
|
|
\ 'vcol': 0,
|
|
\ 'nr': -1,
|
|
\ 'type': 'W',
|
|
\ 'text': 'Missing JRE 1-8'
|
|
\ }
|
|
\ ],
|
|
\ ale#test#GetLoclistWithoutNewerKeys()
|
|
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
|
|
|
|
Execute(LSP pull model diagnostic responses that are 'unchanged' should be handled):
|
|
let b:ale_linters = ['eclipselsp']
|
|
runtime ale_linters/java/eclipselsp.vim
|
|
|
|
if has('win32')
|
|
call ale#test#SetFilename('filename,[]^$.ts')
|
|
else
|
|
call ale#test#SetFilename('filename*?,{}[]^$.java')
|
|
endif
|
|
|
|
call ale#engine#InitBufferInfo(bufnr(''))
|
|
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('eclipselsp')
|
|
let g:ale_buffer_info[bufnr('')].loclist = [
|
|
\ {
|
|
\ 'lnum': 1,
|
|
\ 'bufnr': bufnr(''),
|
|
\ 'col': 1,
|
|
\ 'pattern': '',
|
|
\ 'valid': 1,
|
|
\ 'vcol': 0,
|
|
\ 'nr': -1,
|
|
\ 'type': 'W',
|
|
\ 'text': 'Missing JRE 1-8'
|
|
\ },
|
|
\]
|
|
|
|
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
|
|
call ale#lsp_linter#SetDiagnosticURIMap({'347': ale#util#ToURI(expand('%:p'))})
|
|
|
|
if has('win32')
|
|
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
|
|
else
|
|
AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t')
|
|
endif
|
|
|
|
call ale#lsp_linter#HandleLSPResponse(1, {
|
|
\ 'jsonrpc':'2.0',
|
|
\ 'id': 347,
|
|
\ 'result': {
|
|
\ 'kind': 'unchanged',
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ [
|
|
\ {
|
|
\ 'lnum': 1,
|
|
\ 'bufnr': bufnr(''),
|
|
\ 'col': 1,
|
|
\ 'pattern': '',
|
|
\ 'valid': 1,
|
|
\ 'vcol': 0,
|
|
\ 'nr': -1,
|
|
\ 'type': 'W',
|
|
\ 'text': 'Missing JRE 1-8'
|
|
\ }
|
|
\ ],
|
|
\ g:ale_buffer_info[bufnr('')].loclist
|
|
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
|
|
|
|
Execute(LSP errors should be logged in the history):
|
|
call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'foobar', 'aliases': [], 'lsp': 'stdio'}})
|
|
call ale#lsp_linter#HandleLSPResponse(347, {
|
|
\ 'jsonrpc': '2.0',
|
|
\ 'error': {
|
|
\ 'code': -32602,
|
|
\ 'message': 'xyz',
|
|
\ 'data': {
|
|
\ 'traceback': ['123', '456'],
|
|
\ },
|
|
\ },
|
|
\})
|
|
|
|
AssertEqual
|
|
\ {'foobar': ["xyz\n123\n456"]},
|
|
\ get(g:, 'ale_lsp_error_messages', {})
|