Add hdevtools linter for haskell

This adds support for the hdevtools haskell linter
https://github.com/hdevtools/hdevtools

The output for hdevtools is near identical to the ghc output so this
also extracts the ghc handler into the handle file and adds tests
This commit is contained in:
Rob Berry 2017-02-14 22:47:53 +00:00
parent c460602cbb
commit c4afd72792
4 changed files with 87 additions and 53 deletions

View File

@ -5,63 +5,12 @@ if exists('g:loaded_ale_linters_haskell_ghc')
finish finish
endif endif
let g:loaded_ale_linters_haskell_ghc = 1
function! ale_linters#haskell#ghc#Handle(buffer, lines) abort
" Look for lines like the following.
"
" /dev/stdin:28:26: Not in scope: `>>>>>'
let l:pattern = '^[^:]\+:\(\d\+\):\(\d\+\): \(.\+\)$'
let l:output = []
" For some reason the output coming out of the GHC through the wrapper
" script breaks the lines up in strange ways. So we have to join some
" lines back together again.
let l:corrected_lines = []
for l:line in a:lines
if len(matchlist(l:line, l:pattern)) > 0
call add(l:corrected_lines, l:line)
if l:line !~# ': error:$'
call add(l:corrected_lines, '')
endif
elseif l:line ==# ''
call add(l:corrected_lines, l:line)
else
if len(l:corrected_lines) > 0
let l:line = substitute(l:line, '\v\s+', ' ', '')
let l:corrected_lines[-1] .= l:line
endif
endif
endfor
for l:line in l:corrected_lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[3],
\ 'type': 'E',
\ 'nr': -1,
\})
endfor
return l:output
endfunction
call ale#linter#Define('haskell', { call ale#linter#Define('haskell', {
\ 'name': 'ghc', \ 'name': 'ghc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'ghc', \ 'executable': 'ghc',
\ 'command': 'ghc -fno-code -v0 %t', \ 'command': 'ghc -fno-code -v0 %t',
\ 'callback': 'ale_linters#haskell#ghc#Handle', \ 'callback': 'ale#handlers#HandleGhcFormat',
\}) \})
call ale#linter#Define('haskell', { call ale#linter#Define('haskell', {
@ -69,5 +18,5 @@ call ale#linter#Define('haskell', {
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'stack', \ 'executable': 'stack',
\ 'command': 'stack ghc -- -fno-code -v0 %t', \ 'command': 'stack ghc -- -fno-code -v0 %t',
\ 'callback': 'ale_linters#haskell#ghc#Handle', \ 'callback': 'ale#handlers#HandleGhcFormat',
\}) \})

View File

@ -0,0 +1,9 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: hdevtools for Haskell files
call ale#linter#Define('haskell', {
\ 'name': 'hdevtools',
\ 'executable': 'hdevtools',
\ 'command': 'hdevtools check -g -Wall -p %s %t',
\ 'callback': 'ale#handlers#HandleGhcFormat',
\})

View File

@ -220,3 +220,49 @@ function! ale#handlers#HandleStyleLintFormat(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale#handlers#HandleGhcFormat(buffer, lines) abort
" Look for lines like the following.
"
" /dev/stdin:28:26: Not in scope: `>>>>>'
"Appoint/Lib.hs:8:1: warning:
let l:pattern = '^[^:]\+:\(\d\+\):\(\d\+\):\s\{-}\(warning\|error\)\(.\+\)$'
let l:output = []
let l:corrected_lines = []
for l:line in a:lines
if len(matchlist(l:line, l:pattern)) > 0
call add(l:corrected_lines, l:line)
if l:line !~# '\(: error\|warning\):$'
call add(l:corrected_lines, '')
endif
elseif l:line ==# ''
call add(l:corrected_lines, l:line)
else
if len(l:corrected_lines) > 0
let l:line = substitute(l:line, '\v^\s+', ' ', '')
let l:corrected_lines[-1] .= l:line
endif
endif
endfor
for l:line in l:corrected_lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) == 0
continue
endif
call add(l:output, {
\ 'bufnr': a:buffer,
\ 'lnum': l:match[1] + 0,
\ 'vcol': 0,
\ 'col': l:match[2] + 0,
\ 'text': l:match[4],
\ 'type': toupper(l:match[3][0]),
\ 'nr': -1,
\})
endfor
return l:output
endfunction

View File

@ -0,0 +1,30 @@
Execute(The ghc handler should handle hdevtools output):
AssertEqual
\ [
\ {'lnum': 147, 'bufnr': 12, 'vcol': 0, 'nr': -1, 'type': 'W', 'col': 62, 'text': ':• Couldnt match type a -> T.Text with T.Text Expected type: [T.Text]'},
\ ],
\ ale#handlers#HandleGhcFormat(12, [
\ '/path/to/foo.hs:147:62: warning:',
\ '• Couldnt match type a -> T.Text with T.Text',
\ ' Expected type: [T.Text]',
\ ])
Execute(The ghc handler should handle ghc output):
AssertEqual
\ [
\ {'lnum': 6, 'bufnr': 47, 'vcol': 0, 'nr': -1, 'type': 'E', 'col': 1, 'text': ': Failed to load interface for GitHub.Data Use -v to see a list of the files searched for.'},
\ {'lnum': 7, 'bufnr': 47, 'vcol': 0, 'nr': -1, 'type': 'E', 'col': 1, 'text': ': Failed to load interface for GitHub.Endpoints.PullRequests Use -v to see a list of the files searched for.'},
\ ],
\ ale#handlers#HandleGhcFormat(47, [
\ '',
\ 'src/Appoint/Lib.hs:6:1: error:',
\ ' Failed to load interface for GitHub.Data',
\ ' Use -v to see a list of the files searched for.',
\ '',
\ 'src/Appoint/Lib.hs:7:1: error:',
\ ' Failed to load interface for GitHub.Endpoints.PullRequests',
\ ' Use -v to see a list of the files searched for.',
\ ])