Add erlang_ls linter for Erlang files (#4346)

This commit is contained in:
Dmitri Vereshchagin 2022-10-29 14:58:30 +03:00 committed by GitHub
parent d02e58b404
commit 06efbdd25a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 125 additions and 0 deletions

View File

@ -0,0 +1,49 @@
" Author: Dmitri Vereshchagin <dmitri.vereshchagin@gmail.com>
" Description: LSP linter for Erlang files
call ale#Set('erlang_erlang_ls_executable', 'erlang_ls')
call ale#Set('erlang_erlang_ls_log_dir', '')
call ale#Set('erlang_erlang_ls_log_level', 'info')
function! s:GetCommand(buffer) abort
let l:log_dir = ale#Var(a:buffer, 'erlang_erlang_ls_log_dir')
let l:log_level = ale#Var(a:buffer, 'erlang_erlang_ls_log_level')
let l:command = '%e'
if !empty(l:log_dir)
let l:command .= ' --log-dir=' . ale#Escape(l:log_dir)
endif
let l:command .= ' --log-level=' . ale#Escape(l:log_level)
return l:command
endfunction
function! s:FindProjectRoot(buffer) abort
let l:markers = ['_build/', 'erlang_ls.config', 'rebar.lock']
" This is a way to find Erlang/OTP root (the one that is managed
" by kerl or asdf). Useful if :ALEGoToDefinition takes us there.
let l:markers += ['.kerl_config']
for l:marker in l:markers
let l:path = l:marker[-1:] is# '/'
\ ? ale#path#FindNearestDirectory(a:buffer, l:marker)
\ : ale#path#FindNearestFile(a:buffer, l:marker)
if !empty(l:path)
return ale#path#Dirname(l:path)
endif
endfor
return ''
endfunction
call ale#linter#Define('erlang', {
\ 'name': 'erlang_ls',
\ 'executable': {b -> ale#Var(b, 'erlang_erlang_ls_executable')},
\ 'command': function('s:GetCommand'),
\ 'lsp': 'stdio',
\ 'project_root': function('s:FindProjectRoot'),
\})

View File

@ -51,6 +51,31 @@ g:ale_erlang_elvis_executable *g:ale_erlang_elvis_executable*
This variable can be changed to specify the elvis executable.
-------------------------------------------------------------------------------
erlang_ls *ale-erlang-erlang_ls*
g:ale_erlang_erlang_ls_executable *g:ale_erlang_erlang_ls_executable*
*b:ale_erlang_erlang_ls_executable*
Type: |String|
Default: `'erlang_ls'`
This variable can be changed to specify the erlang_ls executable.
g:ale_erlang_erlang_ls_log_dir *g:ale_erlang_erlang_ls_log_dir*
*b:ale_erlang_erlang_ls_log_dir*
Type: |String|
Default: `''`
If set this variable overrides default directory where logs will be written.
g:ale_erlang_erlang_ls_log_level *g:ale_erlang_erlang_ls_log_level*
*b:ale_erlang_erlang_ls_log_level*
Type: |String|
Default: `'info'`
This variable can be changed to specify log level.
-------------------------------------------------------------------------------
erlc *ale-erlang-erlc*

View File

@ -178,6 +178,7 @@ Notes:
* `SyntaxErl`
* `dialyzer`!!
* `elvis`!!
* `erlang_ls`
* `erlc`
* `erlfmt`
* Fish

View File

@ -2885,6 +2885,7 @@ documented in additional help files.
erlang..................................|ale-erlang-options|
dialyzer..............................|ale-erlang-dialyzer|
elvis.................................|ale-erlang-elvis|
erlang_ls.............................|ale-erlang-erlang_ls|
erlc..................................|ale-erlang-erlc|
erlfmt................................|ale-erlang-erlfmt|
syntaxerl.............................|ale-erlang-syntaxerl|

View File

@ -187,6 +187,7 @@ formatting.
* [SyntaxErl](https://github.com/ten0s/syntaxerl)
* [dialyzer](http://erlang.org/doc/man/dialyzer.html) :floppy_disk:
* [elvis](https://github.com/inaka/elvis) :floppy_disk:
* [erlang_ls](https://github.com/erlang-ls/erlang_ls)
* [erlc](http://erlang.org/doc/man/erlc.html)
* [erlfmt](https://github.com/WhatsApp/erlfmt)
* Fish

View File

@ -0,0 +1,48 @@
Before:
let b:files = '../test-files/erlang'
call ale#assert#SetUpLinterTest('erlang', 'erlang_ls')
After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
AssertLinter 'erlang_ls',
\ ale#Escape('erlang_ls') . ' --log-level=' . ale#Escape('info')
Execute(Executable should be configurable):
let b:ale_erlang_erlang_ls_executable = '/path/to/erlang_ls'
AssertLinter '/path/to/erlang_ls',
\ ale#Escape('/path/to/erlang_ls') . ' --log-level=' . ale#Escape('info')
Execute(Log level should be configurable):
let b:ale_erlang_erlang_ls_log_level = 'debug'
AssertLinter 'erlang_ls',
\ ale#Escape('erlang_ls') . ' --log-level=' . ale#Escape('debug')
Execute(Log directory should be configurable):
let b:ale_erlang_erlang_ls_log_dir = '/path/to/logs'
AssertLinter 'erlang_ls',
\ ale#Escape('erlang_ls')
\ . ' --log-dir=' . ale#Escape('/path/to/logs')
\ . ' --log-level=' . ale#Escape('info')
Execute(Project root should be detected using erlang_ls.config):
call ale#test#SetFilename(b:files . '/app_with_erlang_ls_config/src/app.erl')
AssertLSPProject ale#test#GetFilename(b:files . '/app_with_erlang_ls_config')
call ale#test#SetFilename(b:files . '/app_with_erlang_ls_config/_build/default/lib/dep/src/dep.erl')
AssertLSPProject ale#test#GetFilename(b:files . '/app_with_erlang_ls_config')
Execute(Root of Rebar3 project should be detected):
call ale#test#SetFilename(b:files . '/app/src/app.erl')
AssertLSPProject ale#test#GetFilename(b:files . '/app')
call ale#test#SetFilename(b:files . '/app/_build/default/lib/dep/src/dep.erl')
AssertLSPProject ale#test#GetFilename(b:files . '/app')
Execute(Root of kerl managed Erlang/OTP installation should be detected):
call ale#test#SetFilename(b:files . '/kerl_otp_root/lib/stdlib-4.1.1/array.erl')
AssertLSPProject ale#test#GetFilename(b:files . '/kerl_otp_root')

View File

View File