From 63b9d9e9df9811eec3470e38b234cd2d959169eb Mon Sep 17 00:00:00 2001 From: w0rp Date: Thu, 27 Jul 2017 13:24:28 +0100 Subject: [PATCH] Fix #798 - Handle syntax errors for tsserver --- autoload/ale/engine.vim | 31 +++- test/test_engine_lsp_response_handling.vader | 155 +++++++++++++++++++ 2 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 test/test_engine_lsp_response_handling.vader diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index 8bef01d7..d66126ab 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -200,21 +200,42 @@ function! s:HandleLSPDiagnostics(response) abort call s:HandleLoclist('langserver', l:buffer, l:loclist) endfunction -function! s:HandleTSServerDiagnostics(response) abort +function! s:HandleTSServerDiagnostics(response, error_type) abort let l:buffer = bufnr(a:response.body.file) - let l:loclist = ale#lsp#response#ReadTSServerDiagnostics(a:response) + let l:info = get(g:ale_buffer_info, l:buffer, {}) + + if empty(l:info) + return + endif + + let l:thislist = ale#lsp#response#ReadTSServerDiagnostics(a:response) + + " tsserver sends syntax and semantic errors in separate messages, so we + " have to collect the messages separately for each buffer and join them + " back together again. + if a:error_type ==# 'syntax' + let l:info.syntax_loclist = l:thislist + else + let l:info.semantic_loclist = l:thislist + endif + + let l:loclist = get(l:info, 'semantic_loclist', []) + \ + get(l:info, 'syntax_loclist', []) call s:HandleLoclist('tsserver', l:buffer, l:loclist) endfunction -function! s:HandleLSPResponse(response) abort +function! ale#engine#HandleLSPResponse(response) abort let l:method = get(a:response, 'method', '') if l:method ==# 'textDocument/publishDiagnostics' call s:HandleLSPDiagnostics(a:response) elseif get(a:response, 'type', '') ==# 'event' \&& get(a:response, 'event', '') ==# 'semanticDiag' - call s:HandleTSServerDiagnostics(a:response) + call s:HandleTSServerDiagnostics(a:response, 'semantic') + elseif get(a:response, 'type', '') ==# 'event' + \&& get(a:response, 'event', '') ==# 'syntaxDiag' + call s:HandleTSServerDiagnostics(a:response, 'syntax') endif endfunction @@ -575,7 +596,7 @@ function! s:CheckWithLSP(buffer, linter) abort let l:lsp_details = ale#linter#StartLSP( \ a:buffer, \ a:linter, - \ function('s:HandleLSPResponse'), + \ function('ale#engine#HandleLSPResponse'), \) if empty(l:lsp_details) diff --git a/test/test_engine_lsp_response_handling.vader b/test/test_engine_lsp_response_handling.vader new file mode 100644 index 00000000..1f766baf --- /dev/null +++ b/test/test_engine_lsp_response_handling.vader @@ -0,0 +1,155 @@ +Before: + Save g:ale_buffer_info + call ale#test#SetDirectory('/testplugin/test') + +After: + Restore + + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(tsserver syntax error responses should be handled correctly): + runtime ale_linters/typescript/tsserver.vim + call ale#test#SetFilename('filename.ts') + call ale#engine#InitBufferInfo(bufnr('')) + + " When we get syntax errors and no semantic errors, we should keep the + " syntax errors. + call ale#engine#HandleLSPResponse({ + \ 'seq': 0, + \ 'type': 'event', + \ 'event': 'syntaxDiag', + \ 'body': { + \ 'file': g:dir . '/filename.ts', + \ 'diagnostics':[ + \ { + \ 'start': { + \ 'line':2, + \ 'offset':14, + \ }, + \ 'end': { + \ 'line':2, + \ 'offset':15, + \ }, + \ 'text': ''','' expected.', + \ "code":1005 + \ }, + \ ], + \ }, + \}) + call ale#engine#HandleLSPResponse({ + \ 'seq': 0, + \ 'type': 'event', + \ 'event': 'semanticDiag', + \ 'body': { + \ 'file': g:dir . '/filename.ts', + \ 'diagnostics':[ + \ ], + \ }, + \}) + + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'bufnr': bufnr(''), + \ 'col': 14, + \ 'vcol': 0, + \ 'nr': 1005, + \ 'type': 'E', + \ 'text': ''','' expected.', + \ 'valid': 1, + \ 'pattern': '', + \ }, + \ ], + \ getloclist(0) + + " After we get empty syntax errors, we should clear them. + call ale#engine#HandleLSPResponse({ + \ 'seq': 0, + \ 'type': 'event', + \ 'event': 'syntaxDiag', + \ 'body': { + \ 'file': g:dir . '/filename.ts', + \ 'diagnostics':[ + \ ], + \ }, + \}) + + AssertEqual + \ [ + \ ], + \ getloclist(0) + +Execute(tsserver semantic error responses should be handled correctly): + runtime ale_linters/typescript/tsserver.vim + call ale#test#SetFilename('filename.ts') + call ale#engine#InitBufferInfo(bufnr('')) + + " When we get syntax errors and no semantic errors, we should keep the + " syntax errors. + call ale#engine#HandleLSPResponse({ + \ 'seq': 0, + \ 'type': 'event', + \ 'event': 'syntaxDiag', + \ 'body': { + \ 'file': g:dir . '/filename.ts', + \ 'diagnostics':[ + \ ], + \ }, + \}) + call ale#engine#HandleLSPResponse({ + \ 'seq': 0, + \ 'type': 'event', + \ 'event': 'semanticDiag', + \ 'body': { + \ 'file': g:dir . '/filename.ts', + \ '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': 'Some semantic error', + \ 'valid': 1, + \ 'pattern': '', + \ }, + \ ], + \ getloclist(0) + + " After we get empty syntax errors, we should clear them. + call ale#engine#HandleLSPResponse({ + \ 'seq': 0, + \ 'type': 'event', + \ 'event': 'semanticDiag', + \ 'body': { + \ 'file': g:dir . '/filename.ts', + \ 'diagnostics':[ + \ ], + \ }, + \}) + + AssertEqual + \ [ + \ ], + \ getloclist(0)