From e5e851fadc41c55727f801ce8feacd2bd53e2aac Mon Sep 17 00:00:00 2001 From: yen3 Date: Mon, 30 Nov 2020 09:05:33 +0100 Subject: Add linter for haskell-language-server The patch adds a new linter for haskell-language-server (hls). hls is the integration point of haskell-ide-engine (hie) and ghcide. --- ale_linters/haskell/hls.vim | 63 ++++++++++++++++++++++ doc/ale-haskell.txt | 12 +++++ doc/ale-supported-languages-and-tools.txt | 1 + doc/ale.txt | 1 + supported-tools.md | 1 + .../test_haskell_hls_callbacks.vader | 27 ++++++++++ 6 files changed, 105 insertions(+) create mode 100644 ale_linters/haskell/hls.vim create mode 100644 test/command_callback/test_haskell_hls_callbacks.vader diff --git a/ale_linters/haskell/hls.vim b/ale_linters/haskell/hls.vim new file mode 100644 index 00000000..ae0556a4 --- /dev/null +++ b/ale_linters/haskell/hls.vim @@ -0,0 +1,63 @@ +" Author: Yen3 +" Description: A language server for haskell +" The file is based on hie.vim (author: Luxed +" ). It search more project root files. +" +call ale#Set('haskell_hls_executable', 'haskell-language-server-wrapper') + +function! ale_linters#haskell#hls#FindRootFile(buffer) abort + let l:serach_root_files = [ + \ 'stack.yaml', + \ 'cabal.project', + \ 'package.yaml', + \ 'hie.yaml' + \ ] + + for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) + for l:root_file in l:serach_root_files + if filereadable(l:path . l:root_file) + return l:path + endif + endfor + endfor + + return '' +endfunction + +function! ale_linters#haskell#hls#GetProjectRoot(buffer) abort + " Search for the project file first + let l:project_file = ale_linters#haskell#hls#FindRootFile(a:buffer) + + " If it's empty, search for the cabal file + if empty(l:project_file) + " Search all of the paths except for the root filesystem path. + let l:paths = join( + \ ale#path#Upwards(expand('#' . a:buffer . ':p:h'))[:-2], + \ ',' + \) + let l:project_file = globpath(l:paths, '*.cabal') + endif + + " If we still can't find one, use the current file. + if empty(l:project_file) + let l:project_file = expand('#' . a:buffer . ':p') + endif + + return fnamemodify(l:project_file, ':h') +endfunction + +function! ale_linters#haskell#hls#GetCommand(buffer) abort + let l:executable = ale#Var(a:buffer, 'haskell_hls_executable') + + return ale#handlers#haskell_stack#EscapeExecutable(l:executable, + \ 'haskell-language-server-wrapper') + \ . ' --lsp' +endfunction + +call ale#linter#Define('haskell', { +\ 'name': 'hls', +\ 'lsp': 'stdio', +\ 'command': function('ale_linters#haskell#hls#GetCommand'), +\ 'executable': {b -> ale#Var(b, 'haskell_hls_executable')}, +\ 'project_root': function('ale_linters#haskell#hls#GetProjectRoot'), +\}) diff --git a/doc/ale-haskell.txt b/doc/ale-haskell.txt index fde439fe..09894340 100644 --- a/doc/ale-haskell.txt +++ b/doc/ale-haskell.txt @@ -124,6 +124,18 @@ g:ale_haskell_hlint_options g:ale_haskell_hlint_options executable. +=============================================================================== +hls *ale-haskell-hls* + +g:ale_haskell_hls_executable *g:ale_haskell_hls_executable* + *b:ale_haskell_his_executable* + Type: |String| + Default: `'haskell-language-server-wrapper'` + + This variable can be changed to use a different executable for the haskell + language server. + + =============================================================================== stack-build *ale-haskell-stack-build* diff --git a/doc/ale-supported-languages-and-tools.txt b/doc/ale-supported-languages-and-tools.txt index d9b5f68f..72c685c5 100644 --- a/doc/ale-supported-languages-and-tools.txt +++ b/doc/ale-supported-languages-and-tools.txt @@ -203,6 +203,7 @@ Notes: * `hie` * `hindent` * `hlint` + * `hls` * `ormolu` * `stack-build`!! * `stack-ghc` diff --git a/doc/ale.txt b/doc/ale.txt index 84f20686..8a6417ee 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -2741,6 +2741,7 @@ documented in additional help files. hfmt..................................|ale-haskell-hfmt| hindent...............................|ale-haskell-hindent| hlint.................................|ale-haskell-hlint| + hls...................................|ale-haskell-hls| stack-build...........................|ale-haskell-stack-build| stack-ghc.............................|ale-haskell-stack-ghc| stylish-haskell.......................|ale-haskell-stylish-haskell| diff --git a/supported-tools.md b/supported-tools.md index 069432ca..e449ff39 100644 --- a/supported-tools.md +++ b/supported-tools.md @@ -212,6 +212,7 @@ formatting. * [hie](https://github.com/haskell/haskell-ide-engine) * [hindent](https://hackage.haskell.org/package/hindent) * [hlint](https://hackage.haskell.org/package/hlint) + * [hls](https://github.com/haskell/haskell-language-server) * [ormolu](https://github.com/tweag/ormolu) * [stack-build](https://haskellstack.org/) :floppy_disk: * [stack-ghc](https://haskellstack.org/) diff --git a/test/command_callback/test_haskell_hls_callbacks.vader b/test/command_callback/test_haskell_hls_callbacks.vader new file mode 100644 index 00000000..e64aab6f --- /dev/null +++ b/test/command_callback/test_haskell_hls_callbacks.vader @@ -0,0 +1,27 @@ +Before: + call ale#assert#SetUpLinterTest('haskell', 'hls') + + Save &filetype + let &filetype = 'haskell' + +After: + call ale#assert#TearDownLinterTest() + +Execute(The language string should be correct): + AssertLSPLanguage 'haskell' + +Execute(The default executable should be correct): + AssertLinter 'haskell-language-server-wrapper', + \ ale#Escape('haskell-language-server-wrapper') . ' --lsp' + +Execute(The project root should be detected correctly): + AssertLSPProject g:dir + + call ale#test#SetFilename('hls_paths/file.hs') + + AssertLSPProject ale#path#Simplify(g:dir . '/hls_paths') + +Execute(The executable should be configurable): + let g:ale_haskell_hls_executable = 'foobar' + + AssertLinter 'foobar', ale#Escape('foobar') . ' --lsp' -- cgit v1.2.3