Add argon linter for haskell

Argon is a monitor for cyclomatic complexity
in Haskell.

https://github.com/rubik/argon
This commit is contained in:
Julian Ospald 2018-06-17 02:16:06 +02:00
parent f1b72218c3
commit 024369c72d
No known key found for this signature in database
GPG Key ID: 511B62C09D50CD28
5 changed files with 193 additions and 1 deletions

View File

@ -122,7 +122,7 @@ formatting.
| GraphQL | [eslint](http://eslint.org/), [gqlint](https://github.com/happylinks/gqlint), [prettier](https://github.com/prettier/prettier) |
| Haml | [haml-lint](https://github.com/brigade/haml-lint) |
| Handlebars | [ember-template-lint](https://github.com/rwjblue/ember-template-lint) |
| Haskell | [brittany](https://github.com/lspitzner/brittany), [ghc](https://www.haskell.org/ghc/), [stack-ghc](https://haskellstack.org/), [stack-build](https://haskellstack.org/) !!, [ghc-mod](https://github.com/DanielG/ghc-mod), [stack-ghc-mod](https://github.com/DanielG/ghc-mod), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools), [hfmt](https://github.com/danstiner/hfmt) |
| Haskell | [argon](https://github.com/rubik/argon), [brittany](https://github.com/lspitzner/brittany), [ghc](https://www.haskell.org/ghc/), [stack-ghc](https://haskellstack.org/), [stack-build](https://haskellstack.org/) !!, [ghc-mod](https://github.com/DanielG/ghc-mod), [stack-ghc-mod](https://github.com/DanielG/ghc-mod), [hlint](https://hackage.haskell.org/package/hlint), [hdevtools](https://hackage.haskell.org/package/hdevtools), [hfmt](https://github.com/danstiner/hfmt) |
| HTML | [alex](https://github.com/wooorm/alex) !!, [HTMLHint](http://htmlhint.com/), [proselint](http://proselint.com/), [tidy](http://www.html-tidy.org/), [write-good](https://github.com/btford/write-good) |
| Idris | [idris](http://www.idris-lang.org/) |
| Java | [checkstyle](http://checkstyle.sourceforge.net), [javac](http://www.oracle.com/technetwork/java/javase/downloads/index.html), [google-java-format](https://github.com/google/google-java-format), [PMD](https://pmd.github.io/) |

View File

@ -0,0 +1,69 @@
" Author: Julian Ospald <hasufell@hasufell.de>
" Description: argon for Haskell files
call ale#Set('haskell_argon_executable', 'argon')
call ale#Set('haskell_argon_options', '')
call ale#Set('haskell_argon_error_level', 12)
call ale#Set('haskell_argon_warn_level', 8)
call ale#Set('haskell_argon_info_level', 4)
function! ale_linters#haskell#argon#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'haskell_argon_executable')
endfunction
function! ale_linters#haskell#argon#GetCommand(buffer) abort
return ale#Escape(ale_linters#haskell#argon#GetExecutable(a:buffer))
\ . ' '
\ . ale#Var(a:buffer, 'haskell_argon_options')
\ . ' -m ' . ale#Var(a:buffer, 'haskell_argon_info_level')
\ . ' -j'
\ . ' %t'
endfunction
function! ale_linters#haskell#argon#Handle(buffer, lines) abort
let l:output = []
for l:error in ale#util#FuzzyJSONDecode(a:lines, [])
if !has_key(l:error, 'blocks')
" this cannot be formatted properly into an ALE error
execute 'echom ''[argon] '' l:error.message'
return l:output
endif
for l:block in l:error.blocks
let l:complexity = l:block.complexity
if l:complexity >= ale#Var(a:buffer, 'haskell_argon_error_level')
let l:type = 'E'
let l:max_c = ale#Var(a:buffer, 'haskell_argon_error_level')
elseif l:complexity >= ale#Var(a:buffer, 'haskell_argon_warn_level')
let l:type = 'W'
let l:max_c = ale#Var(a:buffer, 'haskell_argon_warn_level')
else
let l:type = 'I'
let l:max_c = ale#Var(a:buffer, 'haskell_argon_info_level')
endif
call add(l:output, {
\ 'filename': l:error.path,
\ 'lnum': l:block.lineno,
\ 'col': l:block.col,
\ 'text': l:block.name . ': cyclomatic complexity of ' . l:complexity,
\ 'type': l:type,
\})
endfor
endfor
return l:output
endfunction
call ale#linter#Define('haskell', {
\ 'name': 'argon',
\ 'executable_callback': 'ale_linters#haskell#argon#GetExecutable',
\ 'command_callback': 'ale_linters#haskell#argon#GetCommand',
\ 'callback': 'ale_linters#haskell#argon#Handle',
\})

View File

@ -2,6 +2,54 @@
ALE Haskell Integration *ale-haskell-options*
===============================================================================
argon *ale-haskell-argon*
g:ale_haskell_argon_executable *g:ale_haskell_argon_executable*
*b:ale_haskell_argon_executable*
Type: |String|
Default: `'argon'`
This variable can be changed to use a different executable for argon.
g:ale_haskell_argon_options *g:ale_haskell_argon_options*
*b:ale_haskell_argon_options*
Type: |String|
Default: `''`
This variable can be changed to modify flags given to argon. This
should usually not bet set, unless you know what you are doing.
For setting the minimum cyclomatic complexity set
`g:ale_haskell_argon_info_level` instead.
g:ale_haskell_argon_info_level *g:ale_haskell_argon_info_level*
*b:ale_haskell_argon_info_level*
Type: |Number|
Default: `4`
What minimum cyclomatic complexity to consider "info level". This also
sets the minimum. Everything below this will not be shown.
Maximum is determined by `g:ale_haskell_argon_warn_level`.
g:ale_haskell_argon_warn_level *g:ale_haskell_argon_warn_level*
*b:ale_haskell_argon_warn_level*
Type: |Number|
Default: `8`
What minimum cyclomatic complexity to consider a warning.
Maximum is determined by `g:ale_haskell_argon_error_level`.
g:ale_haskell_argon_error_level *g:ale_haskell_argon_error_level*
*b:ale_haskell_argon_error_level*
Type: |Number|
Default: `12`
What minimum cyclomatic complexity to consider an error.
===============================================================================
brittany *ale-haskell-brittany*

View File

@ -93,6 +93,7 @@ CONTENTS *ale-contents*
handlebars............................|ale-handlebars-options|
ember-template-lint.................|ale-handlebars-embertemplatelint|
haskell...............................|ale-haskell-options|
argon...............................|ale-haskell-argon|
brittany............................|ale-haskell-brittany|
ghc.................................|ale-haskell-ghc|
hdevtools...........................|ale-haskell-hdevtools|

View File

@ -0,0 +1,74 @@
Before:
runtime ale_linters/haskell/argon.vim
After:
call ale#linter#Reset()
Execute(The argon handler should parse items correctly):
AssertEqual
\ [
\ {
\ 'filename': 'src/Main.hs',
\ 'lnum': 69,
\ 'col': 1,
\ 'text': 'toMicrosec: cyclomatic complexity of 13',
\ 'type': 'E',
\ },
\ {
\ 'filename': 'src/Main.hs',
\ 'lnum': 202,
\ 'col': 1,
\ 'text': 'same: cyclomatic complexity of 8',
\ 'type': 'W',
\ },
\ {
\ 'filename': 'src/Main.hs',
\ 'lnum': 503,
\ 'col': 1,
\ 'text': 'go: cyclomatic complexity of 7',
\ 'type': 'I',
\ },
\ ],
\ ale_linters#haskell#argon#Handle(bufnr(''), [json_encode([
\ {
\ "blocks": [
\ {
\ "complexity":13,
\ "name":"toMicrosec",
\ "lineno":69,
\ "col":1,
\ },
\ {
\ "complexity":8,
\ "name":"same",
\ "lineno":202,
\ "col":1,
\ },
\ {
\ "complexity":7,
\ "name":"go",
\ "lineno":503,
\ "col":1,
\ }
\ ],
\ "path":"src/Main.hs",
\ "type":"result"
\ },
\ ])])
Execute(The argon handler should handle empty output):
AssertEqual
\ [],
\ ale_linters#haskell#argon#Handle(bufnr(''), [])
Execute(The argon handler should handle errors):
AssertEqual
\ [],
\ ale_linters#haskell#argon#Handle(bufnr(''), [json_encode([
\ {
\ "path":"src/Main.hs",
\ "type":"error",
\ "message":"3:6 Illegal datatype context (use DatatypeContexts): Show a =>",
\ },
\ ])])