#4607 No conflicts with nvim-lspconfig by default

Default `g:ale_disable_lsp` to a new mode `'auto'` by default. With this
setting applied, ALE will now check for the presence of nvim-lspconfig
and automatically turn off particular LSP linters if already configured
via nvim-lspconfig.

For users that do not use `nvim-lspconfig`, everything should work as
before.
This commit is contained in:
w0rp
2023-09-14 00:38:12 +01:00
parent 9092af9ad6
commit be69af2705
54 changed files with 578 additions and 225 deletions

View File

@@ -603,9 +603,19 @@ including the option `g:ale_lint_on_enter`, and you can run ALE manually with
ALE offers an API for letting any other plugin integrate with ALE. If you are ALE offers an API for letting any other plugin integrate with ALE. If you are
interested in writing an integration, see `:help ale-lint-other-sources`. interested in writing an integration, see `:help ale-lint-other-sources`.
If you are running ALE in combination with another LSP client, you may wish If you're running ALE in Neovim with
to disable ALE's LSP functionality entirely. You can add a setting to your [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) for configuring
vimrc/init.vim to do so. particular language servers. ALE will automatically disable its LSP
functionality for any language servers configured with nvim-lspconfig by
default. The following setting is applied by default:
```vim
let g:ale_disable_lsp = 'auto'
```
If you are running ALE in combination with another LSP client, you may wish to
disable ALE's LSP functionality entirely. You can change the setting to `1` to
always disable all LSP functionality.
```vim ```vim
let g:ale_disable_lsp = 1 let g:ale_disable_lsp = 1

View File

@@ -4,17 +4,17 @@
call ale#Set('ansible_language_server_executable', 'ansible-language-server') call ale#Set('ansible_language_server_executable', 'ansible-language-server')
call ale#Set('ansible_language_server_config', {}) call ale#Set('ansible_language_server_config', {})
function! ale_linters#ansible#ansible_language_server#Executable(buffer) abort function! ale_linters#ansible#language_server#Executable(buffer) abort
return ale#Var(a:buffer, 'ansible_language_server_executable') return ale#Var(a:buffer, 'ansible_language_server_executable')
endfunction endfunction
function! ale_linters#ansible#ansible_language_server#GetCommand(buffer) abort function! ale_linters#ansible#language_server#GetCommand(buffer) abort
let l:executable = ale_linters#ansible#ansible_language_server#Executable(a:buffer) let l:executable = ale_linters#ansible#language_server#Executable(a:buffer)
return ale#Escape(l:executable) . ' --stdio' return ale#Escape(l:executable) . ' --stdio'
endfunction endfunction
function! ale_linters#ansible#ansible_language_server#FindProjectRoot(buffer) abort function! ale_linters#ansible#language_server#FindProjectRoot(buffer) abort
let l:dir = fnamemodify( let l:dir = fnamemodify(
\ ale#path#FindNearestFile(a:buffer, 'ansible.cfg'), \ ale#path#FindNearestFile(a:buffer, 'ansible.cfg'),
\ ':h' \ ':h'
@@ -37,10 +37,11 @@ function! ale_linters#ansible#ansible_language_server#FindProjectRoot(buffer) ab
endfunction endfunction
call ale#linter#Define('ansible', { call ale#linter#Define('ansible', {
\ 'name': 'ansible-language-server', \ 'name': 'language_server',
\ 'aliases': ['ansible_language_server', 'ansible-language-server'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale_linters#ansible#ansible_language_server#Executable'), \ 'executable': function('ale_linters#ansible#language_server#Executable'),
\ 'command': function('ale_linters#ansible#ansible_language_server#GetCommand'), \ 'command': function('ale_linters#ansible#language_server#GetCommand'),
\ 'project_root': function('ale_linters#ansible#ansible_language_server#FindProjectRoot'), \ 'project_root': function('ale_linters#ansible#language_server#FindProjectRoot'),
\ 'lsp_config': {b -> ale#Var(b, 'ansible_language_server_config')} \ 'lsp_config': {b -> ale#Var(b, 'ansible_language_server_config')}
\}) \})

View File

@@ -1,4 +1,5 @@
" Author: Taylor Blau <me@ttaylorr.com> " Author: Taylor Blau <me@ttaylorr.com>
call ale#Set('dafny_dafny_timelimit', 10)
function! ale_linters#dafny#dafny#Handle(buffer, lines) abort function! ale_linters#dafny#dafny#Handle(buffer, lines) abort
let l:pattern = '\v(.*)\((\d+),(\d+)\): (.*): (.*)' let l:pattern = '\v(.*)\((\d+),(\d+)\): (.*): (.*)'
@@ -31,7 +32,6 @@ function! ale_linters#dafny#dafny#GetCommand(buffer) abort
return printf('dafny %%s /compile:0 /timeLimit:%d', ale#Var(a:buffer, 'dafny_dafny_timelimit')) return printf('dafny %%s /compile:0 /timeLimit:%d', ale#Var(a:buffer, 'dafny_dafny_timelimit'))
endfunction endfunction
call ale#Set('dafny_dafny_timelimit', 10)
call ale#linter#Define('dafny', { call ale#linter#Define('dafny', {
\ 'name': 'dafny', \ 'name': 'dafny',
\ 'executable': 'dafny', \ 'executable': 'dafny',

View File

@@ -12,7 +12,8 @@ function! ale_linters#elixir#elixir_ls#GetExecutable(buffer) abort
endfunction endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'elixir-ls', \ 'name': 'elixir_ls',
\ 'aliases': ['elixir-ls', 'elixirls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale_linters#elixir#elixir_ls#GetExecutable'), \ 'executable': function('ale_linters#elixir#elixir_ls#GetExecutable'),
\ 'command': function('ale_linters#elixir#elixir_ls#GetExecutable'), \ 'command': function('ale_linters#elixir#elixir_ls#GetExecutable'),

View File

@@ -10,13 +10,13 @@ call ale#Set('elm_ls_elm_format_path', '')
call ale#Set('elm_ls_elm_test_path', '') call ale#Set('elm_ls_elm_test_path', '')
call ale#Set('elm_ls_elm_analyse_trigger', 'change') call ale#Set('elm_ls_elm_analyse_trigger', 'change')
function! elm_ls#GetRootDir(buffer) abort function! ale_linters#elm#ls#GetProjectRoot(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json') let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : '' return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : ''
endfunction endfunction
function! elm_ls#GetOptions(buffer) abort function! ale_linters#elm#ls#GetOptions(buffer) abort
return { return {
\ 'elmPath': ale#Var(a:buffer, 'elm_ls_elm_path'), \ 'elmPath': ale#Var(a:buffer, 'elm_ls_elm_path'),
\ 'elmFormatPath': ale#Var(a:buffer, 'elm_ls_elm_format_path'), \ 'elmFormatPath': ale#Var(a:buffer, 'elm_ls_elm_format_path'),
@@ -26,7 +26,8 @@ function! elm_ls#GetOptions(buffer) abort
endfunction endfunction
call ale#linter#Define('elm', { call ale#linter#Define('elm', {
\ 'name': 'elm_ls', \ 'name': 'ls',
\ 'aliases': ['elm_ls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#path#FindExecutable(b, 'elm_ls', [ \ 'executable': {b -> ale#path#FindExecutable(b, 'elm_ls', [
\ 'node_modules/.bin/elm-language-server', \ 'node_modules/.bin/elm-language-server',
@@ -34,7 +35,7 @@ call ale#linter#Define('elm', {
\ 'elm-lsp' \ 'elm-lsp'
\ ])}, \ ])},
\ 'command': '%e --stdio', \ 'command': '%e --stdio',
\ 'project_root': function('elm_ls#GetRootDir'), \ 'project_root': function('ale_linters#elm#ls#GetProjectRoot'),
\ 'language': 'elm', \ 'language': 'elm',
\ 'initialization_options': function('elm_ls#GetOptions') \ 'initialization_options': function('elm_ls#GetOptions')
\}) \})

View File

@@ -12,6 +12,7 @@ endfunction
call ale#linter#Define('fortran', { call ale#linter#Define('fortran', {
\ 'name': 'language_server', \ 'name': 'language_server',
\ 'aliases': ['fortls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'fortran_language_server_executable')}, \ 'executable': {b -> ale#Var(b, 'fortran_language_server_executable')},
\ 'command': '%e', \ 'command': '%e',

View File

@@ -48,7 +48,7 @@ endfunction
call ale#linter#Define('html', { call ale#linter#Define('html', {
\ 'name': 'angular', \ 'name': 'angular',
\ 'aliases': ['angular-language-server'], \ 'aliases': ['angular-language-server', 'angularls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale_linters#html#angular#GetExecutable'), \ 'executable': function('ale_linters#html#angular#GetExecutable'),
\ 'command': function('ale_linters#html#angular#GetCommand'), \ 'command': function('ale_linters#html#angular#GetCommand'),

View File

@@ -46,6 +46,7 @@ endfunction
call ale#linter#Define('java', { call ale#linter#Define('java', {
\ 'name': 'javalsp', \ 'name': 'javalsp',
\ 'aliases': ['java_language_server'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale_linters#java#javalsp#Executable'), \ 'executable': function('ale_linters#java#javalsp#Executable'),
\ 'command': function('ale_linters#java#javalsp#Command'), \ 'command': function('ale_linters#java#javalsp#Command'),

View File

@@ -17,7 +17,8 @@ function! ale_linters#javascript#flow_ls#FindProjectRoot(buffer) abort
endfunction endfunction
call ale#linter#Define('javascript', { call ale#linter#Define('javascript', {
\ 'name': 'flow-language-server', \ 'name': 'flow_ls',
\ 'aliaes': ['flow-language-server'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#path#FindExecutable(b, 'javascript_flow_ls', [ \ 'executable': {b -> ale#path#FindExecutable(b, 'javascript_flow_ls', [
\ 'node_modules/.bin/flow', \ 'node_modules/.bin/flow',

View File

@@ -13,6 +13,7 @@ endfunction
call ale#linter#Define('julia', { call ale#linter#Define('julia', {
\ 'name': 'languageserver', \ 'name': 'languageserver',
\ 'aliases': ['julials'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'julia_executable')}, \ 'executable': {b -> ale#Var(b, 'julia_executable')},
\ 'command': function('ale_linters#julia#languageserver#GetCommand'), \ 'command': function('ale_linters#julia#languageserver#GetCommand'),

View File

@@ -21,6 +21,7 @@ endfunction
call ale#linter#Define('kotlin', { call ale#linter#Define('kotlin', {
\ 'name': 'languageserver', \ 'name': 'languageserver',
\ 'aliaes': ['kotlin_language_server'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'kotlin_languageserver_executable')}, \ 'executable': {b -> ale#Var(b, 'kotlin_languageserver_executable')},
\ 'command': '%e', \ 'command': '%e',

View File

@@ -6,7 +6,7 @@ call ale#Set('lua_language_server_config', {})
call ale#linter#Define('lua', { call ale#linter#Define('lua', {
\ 'name': 'lua_language_server', \ 'name': 'lua_language_server',
\ 'aliases': ['lua-language-server'], \ 'aliases': ['lua-language-server', 'lua_ls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'lua_language_server_executable')}, \ 'executable': {b -> ale#Var(b, 'lua_language_server_executable')},
\ 'command': '%e', \ 'command': '%e',

View File

@@ -9,6 +9,7 @@ endfunction
call ale#linter#Define('nix', { call ale#linter#Define('nix', {
\ 'name': 'rnix_lsp', \ 'name': 'rnix_lsp',
\ 'aliases': ['rnix'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': 'rnix-lsp', \ 'executable': 'rnix-lsp',
\ 'command': '%e', \ 'command': '%e',

View File

@@ -6,6 +6,7 @@ call ale#Set('ocaml_ols_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#linter#Define('ocaml', { call ale#linter#Define('ocaml', {
\ 'name': 'ols', \ 'name': 'ols',
\ 'aliases': ['ocaml-language-server'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'), \ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'), \ 'command': function('ale#handlers#ols#GetCommand'),

View File

@@ -29,6 +29,7 @@ endfunction
call ale#linter#Define('puppet', { call ale#linter#Define('puppet', {
\ 'name': 'languageserver', \ 'name': 'languageserver',
\ 'aliases': ['puppet_languageserver'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'puppet_languageserver_executable')}, \ 'executable': {b -> ale#Var(b, 'puppet_languageserver_executable')},
\ 'command': '%e --stdio', \ 'command': '%e --stdio',

View File

@@ -41,6 +41,7 @@ endfunction
call ale#linter#Define('purescript', { call ale#linter#Define('purescript', {
\ 'name': 'purescript-language-server', \ 'name': 'purescript-language-server',
\ 'aliases': ['purescriptls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale_linters#purescript#ls#GetExecutable'), \ 'executable': function('ale_linters#purescript#ls#GetExecutable'),
\ 'command': function('ale_linters#purescript#ls#GetCommand'), \ 'command': function('ale_linters#purescript#ls#GetCommand'),

View File

@@ -30,6 +30,7 @@ endfunction
call ale#linter#Define('python', { call ale#linter#Define('python', {
\ 'name': 'jedils', \ 'name': 'jedils',
\ 'aliases': ['jedi_language_server'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale_linters#python#jedils#GetExecutable'), \ 'executable': function('ale_linters#python#jedils#GetExecutable'),
\ 'command': function('ale_linters#python#jedils#GetCommand'), \ 'command': function('ale_linters#python#jedils#GetCommand'),

View File

@@ -19,6 +19,7 @@ endfunction
call ale#linter#Define('r', { call ale#linter#Define('r', {
\ 'name': 'languageserver', \ 'name': 'languageserver',
\ 'aliases': ['r_language_server'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'lsp_config': {b -> ale#Var(b, 'r_languageserver_config')}, \ 'lsp_config': {b -> ale#Var(b, 'r_languageserver_config')},
\ 'executable': 'Rscript', \ 'executable': 'Rscript',

View File

@@ -15,6 +15,7 @@ endfunction
call ale#linter#Define('reason', { call ale#linter#Define('reason', {
\ 'name': 'reason-language-server', \ 'name': 'reason-language-server',
\ 'aliases': ['reason_ls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {buffer -> ale#Var(buffer, 'reason_ls_executable')}, \ 'executable': {buffer -> ale#Var(buffer, 'reason_ls_executable')},
\ 'command': '%e', \ 'command': '%e',

View File

@@ -6,6 +6,7 @@ call ale#Set('reason_ols_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#linter#Define('reason', { call ale#linter#Define('reason', {
\ 'name': 'ols', \ 'name': 'ols',
\ 'aliases': ['ocaml-language-server'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'), \ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'), \ 'command': function('ale#handlers#ols#GetCommand'),

View File

@@ -28,6 +28,7 @@ endfunction
call ale#linter#Define('rust', { call ale#linter#Define('rust', {
\ 'name': 'analyzer', \ 'name': 'analyzer',
\ 'aliases': ['rust_analyzer'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'initialization_options': {b -> ale#Var(b, 'rust_analyzer_config')}, \ 'initialization_options': {b -> ale#Var(b, 'rust_analyzer_config')},
\ 'executable': {b -> ale#Var(b, 'rust_analyzer_executable')}, \ 'executable': {b -> ale#Var(b, 'rust_analyzer_executable')},

View File

@@ -5,6 +5,7 @@ call ale#Set('sourcekit_lsp_executable', 'sourcekit-lsp')
call ale#linter#Define('swift', { call ale#linter#Define('swift', {
\ 'name': 'sourcekitlsp', \ 'name': 'sourcekitlsp',
\ 'aliases': ['sourcekit'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'sourcekit_lsp_executable')}, \ 'executable': {b -> ale#Var(b, 'sourcekit_lsp_executable')},
\ 'command': '%e', \ 'command': '%e',

View File

@@ -30,6 +30,7 @@ endfunction
call ale#linter#Define('terraform', { call ale#linter#Define('terraform', {
\ 'name': 'terraform_ls', \ 'name': 'terraform_ls',
\ 'aliases': ['terraformls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'terraform_ls_executable')}, \ 'executable': {b -> ale#Var(b, 'terraform_ls_executable')},
\ 'command': function('ale_linters#terraform#terraform_ls#GetCommand'), \ 'command': function('ale_linters#terraform#terraform_ls#GetCommand'),

View File

@@ -12,6 +12,7 @@ endfunction
call ale#linter#Define('vue', { call ale#linter#Define('vue', {
\ 'name': 'vls', \ 'name': 'vls',
\ 'aliases': ['vuels'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#path#FindExecutable(b, 'vue_vls', [ \ 'executable': {b -> ale#path#FindExecutable(b, 'vue_vls', [
\ 'node_modules/.bin/vls', \ 'node_modules/.bin/vls',

View File

@@ -26,6 +26,7 @@ endfunction
call ale#linter#Define('yaml', { call ale#linter#Define('yaml', {
\ 'name': 'yaml-language-server', \ 'name': 'yaml-language-server',
\ 'aliases': ['yamlls'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale_linters#yaml#ls#GetExecutable'), \ 'executable': function('ale_linters#yaml#ls#GetExecutable'),
\ 'command': function('ale_linters#yaml#ls#GetCommand'), \ 'command': function('ale_linters#yaml#ls#GetCommand'),

View File

@@ -7,9 +7,6 @@ let g:ale_echo_msg_error_str = get(g:, 'ale_echo_msg_error_str', 'Error')
let g:ale_echo_msg_info_str = get(g:, 'ale_echo_msg_info_str', 'Info') let g:ale_echo_msg_info_str = get(g:, 'ale_echo_msg_info_str', 'Info')
let g:ale_echo_msg_log_str = get(g:, 'ale_echo_msg_log_str', 'Log') let g:ale_echo_msg_log_str = get(g:, 'ale_echo_msg_log_str', 'Log')
let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning') let g:ale_echo_msg_warning_str = get(g:, 'ale_echo_msg_warning_str', 'Warning')
" Ignoring linters, for disabling some, or ignoring LSP diagnostics.
let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {})
let g:ale_disable_lsp = get(g:, 'ale_disable_lsp', 0)
" LSP window/showMessage format " LSP window/showMessage format
let g:ale_lsp_show_message_format = get(g:, 'ale_lsp_show_message_format', '%severity%:%linter%: %s') let g:ale_lsp_show_message_format = get(g:, 'ale_lsp_show_message_format', '%severity%:%linter%: %s')
@@ -100,7 +97,24 @@ function! s:Lint(buffer, should_lint_file, timer_id) abort
" Use the filetype from the buffer " Use the filetype from the buffer
let l:filetype = getbufvar(a:buffer, '&filetype') let l:filetype = getbufvar(a:buffer, '&filetype')
let l:linters = ale#linter#Get(l:filetype) let l:linters = ale#linter#Get(l:filetype)
let l:linters = ale#linter#RemoveIgnored(a:buffer, l:filetype, l:linters)
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
" Load code to ignore linters only if we need to.
if (
\ !empty(l:ignore_config)
\ || l:disable_lsp is 1
\ || l:disable_lsp is v:true
\ || (l:disable_lsp is# 'auto' && get(g:, 'lspconfig', 0))
\)
let l:linters = ale#engine#ignore#Exclude(
\ l:filetype,
\ l:linters,
\ l:ignore_config,
\ l:disable_lsp,
\)
endif
" Tell other sources that they can start checking the buffer now. " Tell other sources that they can start checking the buffer now.
let g:ale_want_results_buffer = a:buffer let g:ale_want_results_buffer = a:buffer

View File

@@ -339,17 +339,7 @@ function! ale#code_action#GetCodeActions(options) abort
silent! aunmenu PopUp.Refactor\.\.\. silent! aunmenu PopUp.Refactor\.\.\.
" Only display the menu items if there's an LSP server. " Only display the menu items if there's an LSP server.
let l:has_lsp = 0 if len(ale#lsp_linter#GetEnabled(bufnr(''))) > 0
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
let l:has_lsp = 1
break
endif
endfor
if l:has_lsp
if !empty(expand('<cword>')) if !empty(expand('<cword>'))
silent! anoremenu <silent> PopUp.Rename :ALERename<CR> silent! anoremenu <silent> PopUp.Rename :ALERename<CR>
endif endif

View File

@@ -473,15 +473,9 @@ function! ale#codefix#Execute(range, ...) abort
endif endif
let l:MenuCallback = get(a:000, 0, v:null) let l:MenuCallback = get(a:000, 0, v:null)
let l:lsp_linters = [] let l:linters = ale#lsp_linter#GetEnabled(bufnr(''))
for l:linter in ale#linter#Get(&filetype) if empty(l:linters)
if !empty(l:linter.lsp)
call add(l:lsp_linters, l:linter)
endif
endfor
if empty(l:lsp_linters)
if l:MenuCallback is v:null if l:MenuCallback is v:null
call s:message('No active LSPs') call s:message('No active LSPs')
else else
@@ -491,7 +485,7 @@ function! ale#codefix#Execute(range, ...) abort
return return
endif endif
for l:lsp_linter in l:lsp_linters for l:linter in l:linters
call s:ExecuteGetCodeFix(l:lsp_linter, a:range, l:MenuCallback) call s:ExecuteGetCodeFix(l:linter, a:range, l:MenuCallback)
endfor endfor
endfunction endfunction

View File

@@ -824,6 +824,8 @@ endfunction
" the current buffer. 1 will be returned if there's a potential source of " the current buffer. 1 will be returned if there's a potential source of
" completion data ALE can use, and 0 will be returned otherwise. " completion data ALE can use, and 0 will be returned otherwise.
function! ale#completion#CanProvideCompletions() abort function! ale#completion#CanProvideCompletions() abort
" NOTE: We can report that ALE can provide completions to Deoplete from
" here, and we might ignore linters still below.
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
return 1 return 1
@@ -890,11 +892,9 @@ function! ale#completion#GetCompletions(...) abort
let l:started = 0 let l:started = 0
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#lsp_linter#GetEnabled(l:buffer)
if !empty(l:linter.lsp) if ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
if ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback) let l:started = 1
let l:started = 1
endif
endif endif
endfor endfor

View File

@@ -201,6 +201,35 @@ function! s:EchoLSPErrorMessages(all_linter_names) abort
endfor endfor
endfunction endfunction
function! s:GetIgnoredLinters(buffer, enabled_linters) abort
let l:filetype = &filetype
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
if (
\ !empty(l:ignore_config)
\ || l:disable_lsp is 1
\ || l:disable_lsp is v:true
\ || (l:disable_lsp is# 'auto' && get(g:, 'lspconfig', 0))
\)
let l:non_ignored = ale#engine#ignore#Exclude(
\ l:filetype,
\ a:enabled_linters,
\ l:ignore_config,
\ l:disable_lsp,
\)
else
let l:non_ignored = copy(a:enabled_linters)
endif
call map(l:non_ignored, 'v:val.name')
return filter(
\ copy(a:enabled_linters),
\ 'index(l:non_ignored, v:val.name) < 0'
\)
endfunction
function! ale#debugging#Info(...) abort function! ale#debugging#Info(...) abort
let l:options = (a:0 > 0) ? a:1 : {} let l:options = (a:0 > 0) ? a:1 : {}
let l:show_preview_info = get(l:options, 'preview') let l:show_preview_info = get(l:options, 'preview')
@@ -208,7 +237,6 @@ function! ale#debugging#Info(...) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:filetype = &filetype let l:filetype = &filetype
" We get the list of enabled linters for free by the above function.
let l:enabled_linters = deepcopy(ale#linter#Get(l:filetype)) let l:enabled_linters = deepcopy(ale#linter#Get(l:filetype))
" But have to build the list of available linters ourselves. " But have to build the list of available linters ourselves.
@@ -232,13 +260,10 @@ function! ale#debugging#Info(...) abort
let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1])) let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1]))
let l:fixers_string = join(map(copy(l:fixers), '"\n " . v:val'), '') let l:fixers_string = join(map(copy(l:fixers), '"\n " . v:val'), '')
let l:non_ignored_names = map( " Get the names of ignored linters.
\ copy(ale#linter#RemoveIgnored(l:buffer, l:filetype, l:enabled_linters)), let l:ignored_names = map(
\ 'v:val[''name'']', \ s:GetIgnoredLinters(l:buffer, l:enabled_linters),
\) \ 'v:val.name'
let l:ignored_names = filter(
\ copy(l:enabled_names),
\ 'index(l:non_ignored_names, v:val) < 0'
\) \)
call s:Echo(' Current Filetype: ' . l:filetype) call s:Echo(' Current Filetype: ' . l:filetype)

View File

@@ -168,26 +168,20 @@ function! s:GoToLSPDefinition(linter, options, capability) abort
endfunction endfunction
function! ale#definition#GoTo(options) abort function! ale#definition#GoTo(options) abort
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#lsp_linter#GetEnabled(bufnr(''))
if !empty(l:linter.lsp) call s:GoToLSPDefinition(l:linter, a:options, 'definition')
call s:GoToLSPDefinition(l:linter, a:options, 'definition')
endif
endfor endfor
endfunction endfunction
function! ale#definition#GoToType(options) abort function! ale#definition#GoToType(options) abort
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#lsp_linter#GetEnabled(bufnr(''))
if !empty(l:linter.lsp) call s:GoToLSPDefinition(l:linter, a:options, 'typeDefinition')
call s:GoToLSPDefinition(l:linter, a:options, 'typeDefinition')
endif
endfor endfor
endfunction endfunction
function! ale#definition#GoToImpl(options) abort function! ale#definition#GoToImpl(options) abort
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#lsp_linter#GetEnabled(bufnr(''))
if !empty(l:linter.lsp) call s:GoToLSPDefinition(l:linter, a:options, 'implementation')
call s:GoToLSPDefinition(l:linter, a:options, 'implementation')
endif
endfor endfor
endfunction endfunction

View File

@@ -253,7 +253,7 @@ function! ale#engine#SendResultsToNeovimDiagnostics(buffer, loclist) abort
" Keep the Lua surface area really small in the VimL part of ALE, " Keep the Lua surface area really small in the VimL part of ALE,
" and just require the diagnostics.lua module on demand. " and just require the diagnostics.lua module on demand.
let l:SendDiagnostics = luaeval('require("diagnostics").sendAleResultsToDiagnostics') let l:SendDiagnostics = luaeval('require("ale.diagnostics").sendAleResultsToDiagnostics')
call l:SendDiagnostics(a:buffer, a:loclist) call l:SendDiagnostics(a:buffer, a:loclist)
endfunction endfunction

View File

@@ -1,6 +1,26 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Code for ignoring linters. Only loaded and if configured. " Description: Code for ignoring linters. Only loaded and if configured.
" A map for remapping lspconfig server names to linter names or aliases in
" ALE. We should change the names where they will conflict with names in ALE.
"
" Notes on names from nvim-lspconfig not included here.
"
" * 'rubocop' is run in a language server mode
" * 'eslint' is run via 'vscode-eslint-language-server'
let s:lspconfig_map = {
\ 'als': 'adals',
\ 'ansiblels': 'ansible-language-server',
\ 'bicep': 'bicep_language_server',
\ 'cmake': 'cmake_language_server',
\ 'denols': 'deno',
\ 'erlangls': 'erlang_ls',
\ 'html': 'vscodehtml',
\ 'ocamlls': 'ocaml-language-server',
\ 'ols': 'odin-lsp',
\ 'puppet': 'puppet_languageserver',
\}
" Given a filetype and a configuration for ignoring linters, return a List of " Given a filetype and a configuration for ignoring linters, return a List of
" Strings for linter names to ignore. " Strings for linter names to ignore.
function! ale#engine#ignore#GetList(filetype, config) abort function! ale#engine#ignore#GetList(filetype, config) abort
@@ -21,24 +41,51 @@ function! ale#engine#ignore#GetList(filetype, config) abort
return [] return []
endfunction endfunction
" This function can be mocked in tests.
function! ale#engine#ignore#GetLSPConfigNames() abort
return luaeval('require ''ale.util''.configured_lspconfig_servers()')
endfunction
function! s:GetMappedLSPConfigNames() abort
" Check the lspconfig flag before calling luaeval.
if !get(g:, 'lspconfig', 0)
return []
endif
let l:lspconfig_servers = ale#engine#ignore#GetLSPConfigNames()
return map(
\ !empty(l:lspconfig_servers) ? l:lspconfig_servers : [],
\ {_, val -> get(s:lspconfig_map, val, val) }
\)
endfunction
" Given a List of linter descriptions, exclude the linters to be ignored. " Given a List of linter descriptions, exclude the linters to be ignored.
function! ale#engine#ignore#Exclude(filetype, all_linters, config, disable_lsp) abort function! ale#engine#ignore#Exclude(filetype, all_linters, config, disable_lsp) abort
let l:names_to_remove = ale#engine#ignore#GetList(a:filetype, a:config) let l:names_to_remove = ale#engine#ignore#GetList(a:filetype, a:config)
" If configured to automatically ignore otherwise configured LSP linter
" names, add them to the names to remove. This could ignore linters
" with matching names that are not marked as LSP linters.
if a:disable_lsp is# 'auto'
call extend(l:names_to_remove, s:GetMappedLSPConfigNames())
endif
let l:ignore_all_lsps = a:disable_lsp is 1 || a:disable_lsp is v:true
let l:filtered_linters = [] let l:filtered_linters = []
for l:linter in a:all_linters for l:linter in a:all_linters
let l:name_list = [l:linter.name] + l:linter.aliases let l:should_include = index(l:names_to_remove, l:linter.name) == -1
let l:should_include = 1 let l:i = 0
for l:name in l:name_list while l:should_include && l:i < len(l:linter.aliases)
if index(l:names_to_remove, l:name) >= 0 let l:name = l:linter.aliases[l:i]
let l:should_include = 0 let l:should_include = index(l:names_to_remove, l:name) == -1
break let l:i += 1
endif endwhile
endfor
if a:disable_lsp && has_key(l:linter, 'lsp') && l:linter.lsp isnot# '' if l:should_include && l:ignore_all_lsps
let l:should_include = 0 let l:should_include = empty(get(l:linter, 'lsp'))
endif endif
if l:should_include if l:should_include

View File

@@ -94,9 +94,10 @@ function! s:ExecuteFileRename(linter, options) abort
endfunction endfunction
function! ale#filerename#Execute() abort function! ale#filerename#Execute() abort
let l:buffer = bufnr('')
let l:lsp_linters = [] let l:lsp_linters = []
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#lsp_linter#GetEnabled(l:buffer)
if l:linter.lsp is# 'tsserver' if l:linter.lsp is# 'tsserver'
call add(l:lsp_linters, l:linter) call add(l:lsp_linters, l:linter)
endif endif
@@ -108,7 +109,6 @@ function! ale#filerename#Execute() abort
return return
endif endif
let l:buffer = bufnr('')
let l:old_name = expand('#' . l:buffer . ':p') let l:old_name = expand('#' . l:buffer . ':p')
let l:new_name = ale#util#Input('New file name: ', l:old_name, 'file') let l:new_name = ale#util#Input('New file name: ', l:old_name, 'file')

View File

@@ -61,7 +61,8 @@ endfunction
" Define the hdl_checker linter for a given filetype. " Define the hdl_checker linter for a given filetype.
function! ale#handlers#hdl_checker#DefineLinter(filetype) abort function! ale#handlers#hdl_checker#DefineLinter(filetype) abort
call ale#linter#Define(a:filetype, { call ale#linter#Define(a:filetype, {
\ 'name': 'hdl-checker', \ 'name': 'hdl_checker',
\ 'aliases': ['hdl-checker'],
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'language': a:filetype, \ 'language': a:filetype,
\ 'executable': function('ale#handlers#hdl_checker#GetExecutable'), \ 'executable': function('ale#handlers#hdl_checker#GetExecutable'),
@@ -70,4 +71,3 @@ function! ale#handlers#hdl_checker#DefineLinter(filetype) abort
\ 'initialization_options': function('ale#handlers#hdl_checker#GetInitOptions'), \ 'initialization_options': function('ale#handlers#hdl_checker#GetInitOptions'),
\ }) \ })
endfunction endfunction

View File

@@ -329,10 +329,9 @@ function! ale#hover#Show(buffer, line, col, opt) abort
let l:show_documentation = get(a:opt, 'show_documentation', 0) let l:show_documentation = get(a:opt, 'show_documentation', 0)
let l:Callback = function('s:OnReady', [a:line, a:col, a:opt]) let l:Callback = function('s:OnReady', [a:line, a:col, a:opt])
for l:linter in ale#linter#Get(getbufvar(a:buffer, '&filetype')) for l:linter in ale#lsp_linter#GetEnabled(a:buffer)
" Only tsserver supports documentation requests at the moment. " Only tsserver supports documentation requests at the moment.
if !empty(l:linter.lsp) if !l:show_documentation || l:linter.lsp is# 'tsserver'
\&& (!l:show_documentation || l:linter.lsp is# 'tsserver')
call ale#lsp_linter#StartLSP(a:buffer, l:linter, l:Callback) call ale#lsp_linter#StartLSP(a:buffer, l:linter, l:Callback)
endif endif
endfor endfor

View File

@@ -417,16 +417,6 @@ function! ale#linter#Get(original_filetypes) abort
return reverse(l:combined_linters) return reverse(l:combined_linters)
endfunction endfunction
function! ale#linter#RemoveIgnored(buffer, filetype, linters) abort
" Apply ignore lists for linters only if needed.
let l:ignore_config = ale#Var(a:buffer, 'linters_ignore')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
return !empty(l:ignore_config) || l:disable_lsp
\ ? ale#engine#ignore#Exclude(a:filetype, a:linters, l:ignore_config, l:disable_lsp)
\ : a:linters
endfunction
" Given a buffer and linter, get the executable String for the linter. " Given a buffer and linter, get the executable String for the linter.
function! ale#linter#GetExecutable(buffer, linter) abort function! ale#linter#GetExecutable(buffer, linter) abort
let l:Executable = a:linter.executable let l:Executable = a:linter.executable

View File

@@ -15,6 +15,8 @@ function! ale#lsp#reset#StopAllLSPs() abort
for l:buffer_string in keys(g:ale_buffer_info) for l:buffer_string in keys(g:ale_buffer_info)
let l:buffer = str2nr(l:buffer_string) let l:buffer = str2nr(l:buffer_string)
" Non-ignored and disabled linters are included here so we can
" clear results for them after we ignore or disable them.
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype')) for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype'))
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
call ale#engine#HandleLoclist(l:linter.name, l:buffer, [], 0) call ale#engine#HandleLoclist(l:linter.name, l:buffer, [], 0)

View File

@@ -27,28 +27,62 @@ function! ale#lsp_linter#SetLSPLinterMap(replacement_map) abort
let s:lsp_linter_map = a:replacement_map let s:lsp_linter_map = a:replacement_map
endfunction endfunction
" Check if diagnostics for a particular linter should be ignored. " Get all enabled LSP linters.
function! s:ShouldIgnore(buffer, linter_name) abort " This list still includes linters ignored with `ale_linters_ignore`.
" Ignore all diagnostics if LSP integration is disabled. "
if ale#Var(a:buffer, 'disable_lsp') " `ale_linters_ignore` is designed to allow language servers to be used for
return 1 " their functionality while ignoring the diagnostics they return.
endif function! ale#lsp_linter#GetEnabled(buffer) abort
let l:config = ale#Var(a:buffer, 'linters_ignore')
" Don't load code for ignoring diagnostics if there's nothing to ignore.
if empty(l:config)
return 0
endif
let l:filetype = getbufvar(a:buffer, '&filetype') let l:filetype = getbufvar(a:buffer, '&filetype')
let l:ignore_list = ale#engine#ignore#GetList(l:filetype, l:config) " Only LSP linters are included here.
let l:linters = filter(ale#linter#Get(l:filetype), '!empty(v:val.lsp)')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
return index(l:ignore_list, a:linter_name) >= 0 " Only load code for ignoring linters if we need it.
if (
\ l:disable_lsp is 1
\ || l:disable_lsp is v:true
\ || (l:disable_lsp is# 'auto' && get(g:, 'lspconfig', 0))
\)
let l:linters = ale#engine#ignore#Exclude(
\ l:filetype,
\ l:linters,
\ [],
\ l:disable_lsp,
\)
endif
return l:linters
endfunction
" Check if diagnostics for a particular linter should be ignored.
function! s:ShouldIgnoreDiagnostics(buffer, linter) abort
let l:config = ale#Var(a:buffer, 'linters_ignore')
let l:disable_lsp = ale#Var(a:buffer, 'disable_lsp')
" Only load code for ignoring linters if we need it.
if (
\ !empty(l:config)
\ || l:disable_lsp is 1
\ || l:disable_lsp is v:true
\ || (l:disable_lsp is# 'auto' && get(g:, 'lspconfig', 0))
\)
" Re-use the ignore implementation just for this linter.
return empty(
\ ale#engine#ignore#Exclude(
\ getbufvar(a:buffer, '&filetype'),
\ [a:linter],
\ l:config,
\ l:disable_lsp,
\ )
\)
endif
return 0
endfunction endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id] let l:linter = s:lsp_linter_map[a:conn_id]
let l:filename = ale#util#ToResource(a:response.params.uri) let l:filename = ale#util#ToResource(a:response.params.uri)
let l:escaped_name = escape( let l:escaped_name = escape(
\ fnameescape(l:filename), \ fnameescape(l:filename),
@@ -61,17 +95,22 @@ function! s:HandleLSPDiagnostics(conn_id, response) abort
return return
endif endif
if s:ShouldIgnore(l:buffer, l:linter_name) if s:ShouldIgnoreDiagnostics(l:buffer, l:linter)
return return
endif endif
let l:loclist = ale#lsp#response#ReadDiagnostics(a:response) let l:loclist = ale#lsp#response#ReadDiagnostics(a:response)
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0) call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist, 0)
endfunction endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:linter_name = 'tsserver' " Re-create a fake linter object for tsserver.
let l:linter = {
\ 'name': 'tsserver',
\ 'aliases': [],
\ 'lsp': 'tsserver',
\}
let l:escaped_name = escape( let l:escaped_name = escape(
\ fnameescape(a:response.body.file), \ fnameescape(a:response.body.file),
\ has('win32') ? '^' : '^,}]' \ has('win32') ? '^' : '^,}]'
@@ -83,9 +122,9 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
return return
endif endif
call ale#engine#MarkLinterInactive(l:info, l:linter_name) call ale#engine#MarkLinterInactive(l:info, l:linter.name)
if s:ShouldIgnore(l:buffer, l:linter_name) if s:ShouldIgnoreDiagnostics(l:buffer, l:linter)
return return
endif endif
@@ -123,15 +162,15 @@ function! s:HandleTSServerDiagnostics(response, error_type) abort
\ + get(l:info, 'suggestion_loclist', []) \ + get(l:info, 'suggestion_loclist', [])
\ + get(l:info, 'syntax_loclist', []) \ + get(l:info, 'syntax_loclist', [])
call ale#engine#HandleLoclist(l:linter_name, l:buffer, l:loclist, 0) call ale#engine#HandleLoclist(l:linter.name, l:buffer, l:loclist, 0)
endfunction endfunction
function! s:HandleLSPErrorMessage(linter_name, response) abort function! s:HandleLSPErrorMessage(linter, response) abort
if !g:ale_history_enabled || !g:ale_history_log_output if !g:ale_history_enabled || !g:ale_history_log_output
return return
endif endif
if empty(a:linter_name) if empty(a:linter)
return return
endif endif
@@ -141,7 +180,7 @@ function! s:HandleLSPErrorMessage(linter_name, response) abort
return return
endif endif
call ale#lsp_linter#AddErrorMessage(a:linter_name, l:message) call ale#lsp_linter#AddErrorMessage(a:linter.name, l:message)
endfunction endfunction
function! ale#lsp_linter#AddErrorMessage(linter_name, message) abort function! ale#lsp_linter#AddErrorMessage(linter_name, message) abort
@@ -160,14 +199,14 @@ function! ale#lsp_linter#HandleLSPResponse(conn_id, response) abort
let l:method = get(a:response, 'method', '') let l:method = get(a:response, 'method', '')
if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error') if get(a:response, 'jsonrpc', '') is# '2.0' && has_key(a:response, 'error')
let l:linter_name = get(s:lsp_linter_map, a:conn_id, '') let l:linter = get(s:lsp_linter_map, a:conn_id, {})
call s:HandleLSPErrorMessage(l:linter_name, a:response) call s:HandleLSPErrorMessage(l:linter, a:response)
elseif l:method is# 'textDocument/publishDiagnostics' elseif l:method is# 'textDocument/publishDiagnostics'
call s:HandleLSPDiagnostics(a:conn_id, a:response) call s:HandleLSPDiagnostics(a:conn_id, a:response)
elseif l:method is# 'window/showMessage' elseif l:method is# 'window/showMessage'
call ale#lsp_window#HandleShowMessage( call ale#lsp_window#HandleShowMessage(
\ s:lsp_linter_map[a:conn_id], \ s:lsp_linter_map[a:conn_id].name,
\ g:ale_lsp_show_message_format, \ g:ale_lsp_show_message_format,
\ a:response.params \ a:response.params
\) \)
@@ -472,7 +511,7 @@ function! s:CheckWithLSP(linter, details) abort
call ale#lsp#RegisterCallback(l:id, l:Callback) call ale#lsp#RegisterCallback(l:id, l:Callback)
" Remember the linter this connection is for. " Remember the linter this connection is for.
let s:lsp_linter_map[l:id] = a:linter.name let s:lsp_linter_map[l:id] = a:linter
if a:linter.lsp is# 'tsserver' if a:linter.lsp is# 'tsserver'
let l:message = ale#lsp#tsserver_message#Geterr(l:buffer) let l:message = ale#lsp#tsserver_message#Geterr(l:buffer)

View File

@@ -57,9 +57,7 @@ function! s:OrganizeImports(linter) abort
endfunction endfunction
function! ale#organize_imports#Execute() abort function! ale#organize_imports#Execute() abort
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#lsp_linter#GetEnabled(bufnr(''))
if !empty(l:linter.lsp) call s:OrganizeImports(l:linter)
call s:OrganizeImports(l:linter)
endif
endfor endfor
endfunction endfunction

View File

@@ -179,9 +179,7 @@ function! ale#references#Find(...) abort
let l:column = min([l:column, len(getline(l:line))]) let l:column = min([l:column, len(getline(l:line))])
let l:Callback = function('s:OnReady', [l:line, l:column, l:options]) let l:Callback = function('s:OnReady', [l:line, l:column, l:options])
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#lsp_linter#GetEnabled(l:buffer)
if !empty(l:linter.lsp) call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
endif
endfor endfor
endfunction endfunction

View File

@@ -178,15 +178,9 @@ function! s:ExecuteRename(linter, options) abort
endfunction endfunction
function! ale#rename#Execute() abort function! ale#rename#Execute() abort
let l:lsp_linters = [] let l:linters = ale#lsp_linter#GetEnabled(bufnr(''))
for l:linter in ale#linter#Get(&filetype) if empty(l:linters)
if !empty(l:linter.lsp)
call add(l:lsp_linters, l:linter)
endif
endfor
if empty(l:lsp_linters)
call s:message('No active LSPs') call s:message('No active LSPs')
return return
@@ -201,8 +195,8 @@ function! ale#rename#Execute() abort
return return
endif endif
for l:lsp_linter in l:lsp_linters for l:linter in l:linters
call s:ExecuteRename(l:lsp_linter, { call s:ExecuteRename(l:linter, {
\ 'old_name': l:old_name, \ 'old_name': l:old_name,
\ 'new_name': l:new_name, \ 'new_name': l:new_name,
\}) \})

View File

@@ -102,8 +102,8 @@ function! ale#symbol#Search(args) abort
call setbufvar(l:buffer, 'ale_symbol_request_made', 0) call setbufvar(l:buffer, 'ale_symbol_request_made', 0)
let l:Callback = function('s:OnReady', [l:query, l:options]) let l:Callback = function('s:OnReady', [l:query, l:options])
for l:linter in ale#linter#Get(getbufvar(l:buffer, '&filetype')) for l:linter in ale#lsp_linter#GetEnabled(l:buffer)
if !empty(l:linter.lsp) && l:linter.lsp isnot# 'tsserver' if l:linter.lsp isnot# 'tsserver'
call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback) call ale#lsp_linter#StartLSP(l:buffer, l:linter, l:Callback)
endif endif
endfor endfor

View File

@@ -39,6 +39,8 @@ endfunction
function! ale#uri#jdt#OpenJDTLink(encoded_uri, line, column, options, conn_id) abort function! ale#uri#jdt#OpenJDTLink(encoded_uri, line, column, options, conn_id) abort
let l:found_eclipselsp = v:false let l:found_eclipselsp = v:false
" We should only arrive here from a 'go to definition' request, so we'll
" assume the eclipselsp linter is enabled.
for l:linter in ale#linter#Get('java') for l:linter in ale#linter#Get('java')
if l:linter.name is# 'eclipselsp' if l:linter.name is# 'eclipselsp'
let l:found_eclipselsp = v:true let l:found_eclipselsp = v:true
@@ -87,8 +89,8 @@ function! ale#uri#jdt#ReadJDTLink(encoded_uri) abort
let l:linter_map = ale#lsp_linter#GetLSPLinterMap() let l:linter_map = ale#lsp_linter#GetLSPLinterMap()
for l:conn_id in keys(l:linter_map) for [l:conn_id, l:linter] in items(l:linter_map)
if l:linter_map[l:conn_id] is# 'eclipselsp' if l:linter.name is# 'eclipselsp'
let l:root = l:conn_id[stridx(l:conn_id, ':')+1:] let l:root = l:conn_id[stridx(l:conn_id, ':')+1:]
endif endif
endfor endfor

View File

@@ -1002,11 +1002,16 @@ g:ale_detail_to_floating_preview *g:ale_detail_to_floating_preview*
g:ale_disable_lsp *g:ale_disable_lsp* g:ale_disable_lsp *g:ale_disable_lsp*
*b:ale_disable_lsp* *b:ale_disable_lsp*
Type: |Number| Type: |Number| OR |String|
Default: `0` Default: `'auto'`
When this option is set to `1`, ALE ignores all linters powered by LSP, When this option is set to `'auto'`, ALE will automatically disable linters
and also `tsserver`. that it detects as having already been configured with the nvim-lspconfig
plugin. When this option is set to `1`, ALE ignores all linters powered by
LSP, and also `tsserver`.
Any linters that are disabled will also not be usable for LSP functionality
other than just linting.
Please see also |ale-lsp|. Please see also |ale-lsp|.

3
lspconfig.vim Normal file
View File

@@ -0,0 +1,3 @@
if get(g:, 'lspconfig', 0)
" lspconfig is installed.
endif

14
lua/ale/util.lua Normal file
View File

@@ -0,0 +1,14 @@
local M = {}
function M.configured_lspconfig_servers()
local configs = require 'lspconfig.configs'
local keys = {}
for key, _ in pairs(configs) do
table.insert(keys, key)
end
return keys
end
return M

View File

@@ -60,6 +60,10 @@ let g:ale_filetype_blacklist = [
let g:ale_linters = get(g:, 'ale_linters', {}) let g:ale_linters = get(g:, 'ale_linters', {})
" This option can be changed to only enable explicitly selected linters. " This option can be changed to only enable explicitly selected linters.
let g:ale_linters_explicit = get(g:, 'ale_linters_explicit', 0) let g:ale_linters_explicit = get(g:, 'ale_linters_explicit', 0)
" Ignoring linters, for disabling some, or ignoring LSP diagnostics.
let g:ale_linters_ignore = get(g:, 'ale_linters_ignore', {})
" Disabling all language server functionality.
let g:ale_disable_lsp = get(g:, 'ale_disable_lsp', 'auto')
" This Dictionary configures which functions will be used for fixing problems. " This Dictionary configures which functions will be used for fixing problems.
let g:ale_fixers = get(g:, 'ale_fixers', {}) let g:ale_fixers = get(g:, 'ale_fixers', {})

View File

@@ -1,5 +1,5 @@
Before: Before:
call ale#assert#SetUpLinterTest('ansible', 'ansible_language_server') call ale#assert#SetUpLinterTest('ansible', 'language_server')
After: After:
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()

View File

@@ -1,5 +1,5 @@
Before: Before:
call ale#assert#SetUpLinterTest('elm', 'elm_ls') call ale#assert#SetUpLinterTest('elm', 'ls')
After: After:
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()

View File

@@ -302,7 +302,7 @@ Execute(LSP diagnostics responses should be handled correctly):
endif endif
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'1': 'eclipselsp'}) call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
if has('win32') if has('win32')
AssertEqual 'filename,[]^$.ts', expand('%:p:t') AssertEqual 'filename,[]^$.ts', expand('%:p:t')
@@ -357,7 +357,7 @@ Execute(LSP diagnostics responses on project root should not populate loclist):
runtime ale_linters/java/eclipselsp.vim runtime ale_linters/java/eclipselsp.vim
call ale#test#SetFilename('filename.java') call ale#test#SetFilename('filename.java')
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'1': 'eclipselsp'}) call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
call ale#lsp_linter#HandleLSPResponse(1, { call ale#lsp_linter#HandleLSPResponse(1, {
\ 'jsonrpc':'2.0', \ 'jsonrpc':'2.0',
@@ -395,7 +395,7 @@ Execute(LSP errors should mark linters no longer active):
runtime ale_linters/python/pylsp.vim runtime ale_linters/python/pylsp.vim
call ale#test#SetFilename('filename.py') call ale#test#SetFilename('filename.py')
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({1: 'pylsp'}) call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'pylsp', 'aliases': [], 'lsp': 'stdio'}})
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('python') let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('python')
Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list) Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list)
@@ -411,7 +411,7 @@ Execute(LSP errors should mark linters no longer active):
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
Execute(LSP errors should be logged in the history): Execute(LSP errors should be logged in the history):
call ale#lsp_linter#SetLSPLinterMap({'347': 'foobar'}) call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'foobar', 'aliases': [], 'lsp': 'stdio'}})
call ale#lsp_linter#HandleLSPResponse(347, { call ale#lsp_linter#HandleLSPResponse(347, {
\ 'jsonrpc': '2.0', \ 'jsonrpc': '2.0',
\ 'error': { \ 'error': {

View File

@@ -119,7 +119,7 @@ Execute(The defaults for the zsh filetype should be correct):
Execute(The defaults for the verilog filetype should be correct): Execute(The defaults for the verilog filetype should be correct):
" This filetype isn't configured with default, so we can test loading all " This filetype isn't configured with default, so we can test loading all
" available linters with this. " available linters with this.
AssertEqual ['hdl-checker', 'iverilog', 'verilator', 'vlog', 'xvlog', 'yosys'], GetLinterNames('verilog') AssertEqual ['hdl_checker', 'iverilog', 'verilator', 'vlog', 'xvlog', 'yosys'], GetLinterNames('verilog')
let g:ale_linters_explicit = 1 let g:ale_linters_explicit = 1

View File

@@ -1,10 +1,60 @@
Before: Before:
Save g:lspconfig
Save g:ale_linters_ignore
Save g:ale_buffer_info
Save g:ale_disable_lsp Save g:ale_disable_lsp
let g:lspconfig = 0
let g:lspconfig_names = {}
let g:ale_disable_lsp = 0
let g:linters = []
let g:loclist = []
let g:run_linters_called = 0
runtime autoload/ale/engine.vim
runtime autoload/ale/engine/ignore.vim
" Mock the engine function so we can set it up.
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
let g:linters = a:linters
let g:run_linters_called = 1
endfunction
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let g:loclist = a:loclist
endfunction
function! ale#engine#ignore#GetLSPConfigNames() abort
return g:lspconfig_names
endfunction
call ale#linter#Define('foobar', {
\ 'name': 'testlinter',
\ 'callback': 'TestCallback',
\ 'executable': has('win32') ? 'cmd' : 'true',
\ 'command': has('win32') ? 'echo' : 'true',
\})
call ale#test#SetDirectory('/testplugin/test')
After: After:
unlet! b:ale_linted
unlet! b:ale_linters_ignore
unlet! b:ale_quitting
unlet! b:ale_save_event_fired
unlet! b:ale_disable_lsp
unlet! g:linters
unlet! g:loclist
unlet! g:lsp_message
unlet! g:lspconfig_names
Restore Restore
unlet! b:ale_disable_lsp call ale#test#RestoreDirectory()
call ale#linter#Reset()
call ale#lsp_linter#ClearLSPData()
runtime autoload/ale/engine.vim
runtime autoload/ale/engine/ignore.vim
Execute(GetList should ignore some invalid values): Execute(GetList should ignore some invalid values):
AssertEqual [], ale#engine#ignore#GetList('', 'foo') AssertEqual [], ale#engine#ignore#GetList('', 'foo')
@@ -105,7 +155,7 @@ Execute(Exclude should handle Dictionaries):
\ 0, \ 0,
\ ) \ )
Execute(Exclude should filter LSP linters when g:ale_disable_lsp is set to 1): Execute(Exclude should filter LSP linters when ale_disable_lsp is set to 1):
AssertEqual AssertEqual
\ [ \ [
\ {'name': 'linter1', 'aliases': [], 'lsp': ''}, \ {'name': 'linter1', 'aliases': [], 'lsp': ''},
@@ -122,70 +172,81 @@ Execute(Exclude should filter LSP linters when g:ale_disable_lsp is set to 1):
\ 1, \ 1,
\ ) \ )
Execute(Exclude should filter LSP linters when b:ale_disable_lsp is set to 1): Execute(Exclude should remove lspconfig linters with ale_disable_lsp = 'auto'):
AssertEqual let g:lspconfig = 1
\ [ " A map is used here so you can easily see what the ignore mapping should be
\ {'name': 'linter1', 'aliases': [], 'lsp': ''}, " remapping the nvim-lspconfig names to.
\ {'name': 'linter2', 'aliases': []}, let g:lspconfig_names = keys({
\ ], \ 'als': 'adals',
\ ale#engine#ignore#Exclude( \ 'ansiblels': 'ansible-language-server',
\ 'foo', \ 'bicep': 'bicep_language_server',
\ [ \ 'cmake': 'cmake_language_server',
\ {'name': 'linter1', 'aliases': [], 'lsp': ''}, \ 'denols': 'deno',
\ {'name': 'linter2', 'aliases': []}, \ 'erlangls': 'erlang_ls',
\ {'name': 'linter3', 'aliases': [], 'lsp': 'stdio'}, \ 'html': 'vscodehtml',
\ ], \ 'ocamlls': 'ocaml-language-server',
\ [], \ 'puppet': 'puppet_languageserver',
\ 1, \ 'pyright': 'pyright',
\ )
Before:
Save g:ale_linters_ignore
Save g:ale_buffer_info
Save g:ale_disable_lsp
let g:ale_disable_lsp = 0
let g:linters = []
let g:loclist = []
let g:run_linters_called = 0
runtime autoload/ale/engine.vim
" Mock the engine function so we can set it up.
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
let g:linters = a:linters
let g:run_linters_called = 1
endfunction
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let g:loclist = a:loclist
endfunction
call ale#linter#Define('foobar', {
\ 'name': 'testlinter',
\ 'callback': 'TestCallback',
\ 'executable': has('win32') ? 'cmd' : 'true',
\ 'command': has('win32') ? 'echo' : 'true',
\}) \})
call ale#test#SetDirectory('/testplugin/test')
After: " We should keep bicep, as it's different tool.
Restore AssertEqual
\ [
\ {'name': 'bicep', 'aliases': []},
\ ],
\ ale#engine#ignore#Exclude(
\ 'foo',
\ [
\ {'name': 'adals', 'aliases': []},
\ {'name': 'language_server', 'aliases': ['ansible-language-server']},
\ {'name': 'cmake_language_server', 'aliases': []},
\ {'name': 'deno', 'aliases': []},
\ {'name': 'erlang_ls', 'aliases': []},
\ {'name': 'vscodehtml', 'aliases': []},
\ {'name': 'bicep', 'aliases': []},
\ {'name': 'ols', 'aliases': ['ocaml-language-server']},
\ {'name': 'languageserver', 'aliases': ['puppet_languageserver']},
\ {'name': 'pyright', 'aliases': []},
\ ],
\ [],
\ 'auto',
\ )
unlet! b:ale_linted Execute(Exclude should check that the nvim-lspconfig plugin is installed with ale_disable_lsp = 'auto'):
unlet! b:ale_linters_ignore let g:lspconfig = 0
unlet! b:ale_quitting let g:lspconfig_names = ['pyright']
unlet! b:ale_save_event_fired
unlet! b:ale_disable_lsp
unlet! g:linters
unlet! g:loclist
unlet! g:lsp_message
call ale#test#RestoreDirectory() " We should keep pyright here, because g:lspconfig is 0.
call ale#linter#Reset() AssertEqual
call ale#lsp_linter#ClearLSPData() \ [
runtime autoload/ale/engine.vim \ {'name': 'pyright', 'aliases': []},
\ ],
\ ale#engine#ignore#Exclude(
\ 'foo',
\ [
\ {'name': 'pyright', 'aliases': []},
\ ],
\ [],
\ 'auto',
\ )
Execute(Exclude should handle the lspconfig result being a Dictionary):
let g:lspconfig = 1
let g:lspconfig_names = {}
" We should keep pyright here, because the configuration is empty.
AssertEqual
\ [
\ {'name': 'pyright', 'aliases': []},
\ ],
\ ale#engine#ignore#Exclude(
\ 'foo',
\ [
\ {'name': 'pyright', 'aliases': []},
\ ],
\ [],
\ 'auto',
\ )
Given foobar(An empty file): Given foobar(An empty file):
Execute(Global ignore lists should be applied for linters): Execute(Global ignore lists should be applied for linters):
@@ -265,7 +326,7 @@ Execute(Buffer ignore lists should be applied for tsserver):
Execute(Buffer ignore lists should be applied for LSP linters): Execute(Buffer ignore lists should be applied for LSP linters):
call ale#test#SetFilename('filename.py') call ale#test#SetFilename('filename.py')
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'347': 'lsplinter'}) call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}})
let g:lsp_message = { let g:lsp_message = {
\ 'jsonrpc': '2.0', \ 'jsonrpc': '2.0',
@@ -357,10 +418,63 @@ Execute(ale_disable_lsp should be applied for tsserver):
AssertEqual [], g:loclist AssertEqual [], g:loclist
Execute(ale_disable_lsp = 'auto' should be applied for tsserver):
let g:lspconfig = 1
let g:lspconfig_names = ['tsserver']
call ale#test#SetFilename('filename.ts')
call ale#engine#InitBufferInfo(bufnr(''))
let g:lsp_message = {
\ '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#lsp_linter#HandleLSPResponse(347, g:lsp_message)
AssertEqual
\ [
\ {
\ 'lnum': 2,
\ 'col': 14,
\ 'nr': 1005,
\ 'code': '1005',
\ 'type': 'E',
\ 'end_col': 14,
\ 'end_lnum': 2,
\ 'text': ''','' expected.',
\ },
\ ],
\ g:loclist
let g:loclist = []
let g:ale_disable_lsp = 'auto'
call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)
AssertEqual [], g:loclist
Execute(ale_disable_lsp should be applied for LSP linters): Execute(ale_disable_lsp should be applied for LSP linters):
call ale#test#SetFilename('filename.py') call ale#test#SetFilename('filename.py')
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'347': 'lsplinter'}) call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}})
let g:lsp_message = { let g:lsp_message = {
\ 'jsonrpc': '2.0', \ 'jsonrpc': '2.0',
@@ -401,3 +515,99 @@ Execute(ale_disable_lsp should be applied for LSP linters):
call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)
AssertEqual [], g:loclist AssertEqual [], g:loclist
Execute(ale_disable_lsp = 'auto' should be applied for LSP linters):
let g:lspconfig = 1
let g:lspconfig_names = ['lsplinter']
call ale#test#SetFilename('filename.py')
call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'lsplinter', 'aliases': [], 'lsp': 'stdio'}})
let g:lsp_message = {
\ 'jsonrpc': '2.0',
\ 'method': 'textDocument/publishDiagnostics',
\ 'params': {
\ 'uri': ale#path#ToFileURI(expand('%:p')),
\ 'diagnostics': [
\ {
\ 'severity': 1,
\ 'message': 'x',
\ 'range': {
\ 'start': {'line': 0, 'character': 9},
\ 'end': {'line': 0, 'character': 9},
\ },
\ }
\ ],
\ },
\}
call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'col': 10,
\ 'type': 'E',
\ 'end_col': 9,
\ 'end_lnum': 1,
\ 'text': 'x',
\ }
\ ],
\ g:loclist
let g:ale_disable_lsp = 'auto'
let g:loclist = []
call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)
AssertEqual [], g:loclist
Execute(ale_disable_lsp = 'auto' should ignore LSP linters by alias too):
let g:lspconfig = 1
let g:lspconfig_names = ['lsplinter']
call ale#test#SetFilename('filename.py')
call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'notthis', 'aliases': ['lsplinter'], 'lsp': 'stdio'}})
let g:lsp_message = {
\ 'jsonrpc': '2.0',
\ 'method': 'textDocument/publishDiagnostics',
\ 'params': {
\ 'uri': ale#path#ToFileURI(expand('%:p')),
\ 'diagnostics': [
\ {
\ 'severity': 1,
\ 'message': 'x',
\ 'range': {
\ 'start': {'line': 0, 'character': 9},
\ 'end': {'line': 0, 'character': 9},
\ },
\ }
\ ],
\ },
\}
call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'col': 10,
\ 'type': 'E',
\ 'end_col': 9,
\ 'end_lnum': 1,
\ 'text': 'x',
\ }
\ ],
\ g:loclist
let g:ale_disable_lsp = 'auto'
let g:loclist = []
call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message)
AssertEqual [], g:loclist