mirror of
1
0
Fork 0

Updated plugins

This commit is contained in:
Amir Salihefendic 2019-08-22 17:36:17 +02:00
parent 6711ae6453
commit 3aefdbd21a
244 changed files with 9486 additions and 3395 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2016-2018, w0rp <devw0rp@gmail.com> Copyright (c) 2016-2019, w0rp <devw0rp@gmail.com>
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -5,7 +5,10 @@ call ale#Set('asm_gcc_executable', 'gcc')
call ale#Set('asm_gcc_options', '-Wall') call ale#Set('asm_gcc_options', '-Wall')
function! ale_linters#asm#gcc#GetCommand(buffer) abort function! ale_linters#asm#gcc#GetCommand(buffer) abort
return '%e -x assembler -fsyntax-only ' " `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -x assembler'
\ . ' -o ' . g:ale#util#nul_file
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -' \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction endfunction

View File

@ -4,12 +4,6 @@
call ale#Set('c_clangd_executable', 'clangd') call ale#Set('c_clangd_executable', 'clangd')
call ale#Set('c_clangd_options', '') call ale#Set('c_clangd_options', '')
function! ale_linters#c#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#c#clangd#GetCommand(buffer) abort function! ale_linters#c#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options')) return '%e' . ale#Pad(ale#Var(a:buffer, 'c_clangd_options'))
endfunction endfunction
@ -19,5 +13,5 @@ call ale#linter#Define('c', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'c_clangd_executable')}, \ 'executable': {b -> ale#Var(b, 'c_clangd_executable')},
\ 'command': function('ale_linters#c#clangd#GetCommand'), \ 'command': function('ale_linters#c#clangd#GetCommand'),
\ 'project_root': function('ale_linters#c#clangd#GetProjectRoot'), \ 'project_root': function('ale#c#FindProjectRoot'),
\}) \})

View File

@ -11,9 +11,12 @@ call ale#Set('c_clangtidy_executable', 'clang-tidy')
" http://clang.llvm.org/extra/clang-tidy/checks/list.html " http://clang.llvm.org/extra/clang-tidy/checks/list.html
call ale#Set('c_clangtidy_checks', []) call ale#Set('c_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy. " Set this option to manually set some options for clang-tidy to use as compile
" flags.
" This will disable compile_commands.json detection. " This will disable compile_commands.json detection.
call ale#Set('c_clangtidy_options', '') call ale#Set('c_clangtidy_options', '')
" Set this option to manually set options for clang-tidy directly.
call ale#Set('c_clangtidy_extra_options', '')
call ale#Set('c_build_dir', '') call ale#Set('c_build_dir', '')
function! ale_linters#c#clangtidy#GetCommand(buffer) abort function! ale_linters#c#clangtidy#GetCommand(buffer) abort
@ -25,8 +28,12 @@ function! ale_linters#c#clangtidy#GetCommand(buffer) abort
\ ? ale#Var(a:buffer, 'c_clangtidy_options') \ ? ale#Var(a:buffer, 'c_clangtidy_options')
\ : '' \ : ''
" Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'c_clangtidy_extra_options')
return '%e' return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '') \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '')
\ . ' %s' \ . ' %s'
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
\ . (!empty(l:options) ? ' -- ' . l:options : '') \ . (!empty(l:options) ? ' -- ' . l:options : '')

View File

@ -5,23 +5,17 @@ call ale#Set('c_cppcheck_executable', 'cppcheck')
call ale#Set('c_cppcheck_options', '--enable=style') call ale#Set('c_cppcheck_options', '--enable=style')
function! ale_linters#c#cppcheck#GetCommand(buffer) abort function! ale_linters#c#cppcheck#GetCommand(buffer) abort
" Search upwards from the file for compile_commands.json. let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer)
" let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer)
" If we find it, we'll `cd` to where the compile_commands.json file is, let l:buffer_path_include = empty(l:compile_commands_option)
" then use the file to set up import paths, etc. \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
let l:cd_command = !empty(l:compile_commmands_path)
\ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h'))
\ : ''
let l:compile_commands_option = !empty(l:compile_commmands_path)
\ ? '--project=compile_commands.json '
\ : '' \ : ''
return l:cd_command return l:cd_command
\ . '%e -q --language=c ' \ . '%e -q --language=c'
\ . l:compile_commands_option \ . ale#Pad(l:compile_commands_option)
\ . ale#Var(a:buffer, 'c_cppcheck_options') \ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
\ . l:buffer_path_include
\ . ' %t' \ . ' %t'
endfunction endfunction

View File

@ -5,13 +5,15 @@ call ale#Set('c_cquery_executable', 'cquery')
call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery')) call ale#Set('c_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#c#cquery#GetProjectRoot(buffer) abort function! ale_linters#c#cquery#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') " Try to find cquery configuration files first.
let l:config = ale#path#FindNearestFile(a:buffer, '.cquery')
if empty(l:project_root) if !empty(l:config)
let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery') return fnamemodify(l:config, ':h')
endif endif
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' " Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
endfunction endfunction
function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort function! ale_linters#c#cquery#GetInitializationOptions(buffer) abort

View File

@ -9,7 +9,11 @@ function! ale_linters#c#gcc#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return '%e -S -x c -fsyntax-only' "
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags) \ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -' \ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'

View File

@ -12,7 +12,8 @@ function! ale_linters#cpp#clangcheck#GetCommand(buffer) abort
let l:build_dir = ale#Var(a:buffer, 'c_build_dir') let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
if empty(l:build_dir) if empty(l:build_dir)
let l:build_dir = ale#path#Dirname(ale#c#FindCompileCommands(a:buffer)) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
let l:build_dir = ale#path#Dirname(l:json_file)
endif endif
" The extra arguments in the command are used to prevent .plist files from " The extra arguments in the command are used to prevent .plist files from

View File

@ -4,12 +4,6 @@
call ale#Set('cpp_clangd_executable', 'clangd') call ale#Set('cpp_clangd_executable', 'clangd')
call ale#Set('cpp_clangd_options', '') call ale#Set('cpp_clangd_options', '')
function! ale_linters#cpp#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#cpp#clangd#GetCommand(buffer) abort function! ale_linters#cpp#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options')) return '%e' . ale#Pad(ale#Var(a:buffer, 'cpp_clangd_options'))
endfunction endfunction
@ -19,5 +13,5 @@ call ale#linter#Define('cpp', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')}, \ 'executable': {b -> ale#Var(b, 'cpp_clangd_executable')},
\ 'command': function('ale_linters#cpp#clangd#GetCommand'), \ 'command': function('ale_linters#cpp#clangd#GetCommand'),
\ 'project_root': function('ale_linters#cpp#clangd#GetProjectRoot'), \ 'project_root': function('ale#c#FindProjectRoot'),
\}) \})

View File

@ -5,9 +5,12 @@
call ale#Set('cpp_clangtidy_executable', 'clang-tidy') call ale#Set('cpp_clangtidy_executable', 'clang-tidy')
" Set this option to check the checks clang-tidy will apply. " Set this option to check the checks clang-tidy will apply.
call ale#Set('cpp_clangtidy_checks', []) call ale#Set('cpp_clangtidy_checks', [])
" Set this option to manually set some options for clang-tidy. " Set this option to manually set some options for clang-tidy to use as compile
" flags.
" This will disable compile_commands.json detection. " This will disable compile_commands.json detection.
call ale#Set('cpp_clangtidy_options', '') call ale#Set('cpp_clangtidy_options', '')
" Set this option to manually set options for clang-tidy directly.
call ale#Set('cpp_clangtidy_extra_options', '')
call ale#Set('c_build_dir', '') call ale#Set('c_build_dir', '')
function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
@ -19,8 +22,12 @@ function! ale_linters#cpp#clangtidy#GetCommand(buffer) abort
\ ? ale#Var(a:buffer, 'cpp_clangtidy_options') \ ? ale#Var(a:buffer, 'cpp_clangtidy_options')
\ : '' \ : ''
" Get the options to pass directly to clang-tidy
let l:extra_options = ale#Var(a:buffer, 'cpp_clangtidy_extra_options')
return '%e' return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '') \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . (!empty(l:extra_options) ? ' ' . ale#Escape(l:extra_options) : '')
\ . ' %s' \ . ' %s'
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
\ . (!empty(l:options) ? ' -- ' . l:options : '') \ . (!empty(l:options) ? ' -- ' . l:options : '')

View File

@ -5,23 +5,17 @@ call ale#Set('cpp_cppcheck_executable', 'cppcheck')
call ale#Set('cpp_cppcheck_options', '--enable=style') call ale#Set('cpp_cppcheck_options', '--enable=style')
function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
" Search upwards from the file for compile_commands.json. let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer)
" let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer)
" If we find it, we'll `cd` to where the compile_commands.json file is, let l:buffer_path_include = empty(l:compile_commands_option)
" then use the file to set up import paths, etc. \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
let l:compile_commmands_path = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
let l:cd_command = !empty(l:compile_commmands_path)
\ ? ale#path#CdString(fnamemodify(l:compile_commmands_path, ':h'))
\ : ''
let l:compile_commands_option = !empty(l:compile_commmands_path)
\ ? '--project=compile_commands.json '
\ : '' \ : ''
return l:cd_command return l:cd_command
\ . '%e -q --language=c++ ' \ . '%e -q --language=c++'
\ . l:compile_commands_option \ . ale#Pad(l:compile_commands_option)
\ . ale#Var(a:buffer, 'cpp_cppcheck_options') \ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
\ . l:buffer_path_include
\ . ' %t' \ . ' %t'
endfunction endfunction

View File

@ -5,13 +5,15 @@ call ale#Set('cpp_cquery_executable', 'cquery')
call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery')) call ale#Set('cpp_cquery_cache_directory', expand('~/.cache/cquery'))
function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort function! ale_linters#cpp#cquery#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') " Try to find cquery configuration files first.
let l:config = ale#path#FindNearestFile(a:buffer, '.cquery')
if empty(l:project_root) if !empty(l:config)
let l:project_root = ale#path#FindNearestFile(a:buffer, '.cquery') return fnamemodify(l:config, ':h')
endif endif
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' " Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
endfunction endfunction
function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort function! ale_linters#cpp#cquery#GetInitializationOptions(buffer) abort

View File

@ -9,7 +9,11 @@ function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return '%e -S -x c++ -fsyntax-only' "
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c++'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags) \ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -' \ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'

View File

@ -0,0 +1,95 @@
call ale#Set('cs_csc_options', '')
call ale#Set('cs_csc_source', '')
call ale#Set('cs_csc_assembly_path', [])
call ale#Set('cs_csc_assemblies', [])
function! s:GetWorkingDirectory(buffer) abort
let l:working_directory = ale#Var(a:buffer, 'cs_csc_source')
if !empty(l:working_directory)
return l:working_directory
endif
return expand('#' . a:buffer . ':p:h')
endfunction
function! ale_linters#cs#csc#GetCommand(buffer) abort
" Pass assembly paths via the -lib: parameter.
let l:path_list = ale#Var(a:buffer, 'cs_csc_assembly_path')
let l:lib_option = !empty(l:path_list)
\ ? '/lib:' . join(map(copy(l:path_list), 'ale#Escape(v:val)'), ',')
\ : ''
" Pass paths to DLL files via the -r: parameter.
let l:assembly_list = ale#Var(a:buffer, 'cs_csc_assemblies')
let l:r_option = !empty(l:assembly_list)
\ ? '/r:' . join(map(copy(l:assembly_list), 'ale#Escape(v:val)'), ',')
\ : ''
" register temporary module target file with ale
" register temporary module target file with ALE.
let l:out = ale#command#CreateFile(a:buffer)
" The code is compiled as a module and the output is redirected to a
" temporary file.
return ale#path#CdString(s:GetWorkingDirectory(a:buffer))
\ . 'csc /unsafe'
\ . ale#Pad(ale#Var(a:buffer, 'cs_csc_options'))
\ . ale#Pad(l:lib_option)
\ . ale#Pad(l:r_option)
\ . ' /out:' . l:out
\ . ' /t:module'
\ . ' /recurse:' . ale#Escape('*.cs')
endfunction
function! ale_linters#cs#csc#Handle(buffer, lines) abort
" Look for lines like the following.
"
" Tests.cs(12,29): error CSXXXX: ; expected
"
" NOTE: pattern also captures file name as linter compiles all
" files within the source tree rooted at the specified source
" path and not just the file loaded in the buffer
let l:patterns = [
\ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$',
\ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$',
\]
let l:output = []
let l:dir = s:GetWorkingDirectory(a:buffer)
for l:match in ale#util#GetMatches(a:lines, l:patterns)
if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS'
call add(l:output, {
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'type': l:match[4] is# 'error' ? 'E' : 'W',
\ 'code': l:match[5],
\ 'text': l:match[6] ,
\})
elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS'
call add(l:output, {
\ 'filename':'<csc>',
\ 'lnum': -1,
\ 'col': -1,
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
\ 'code': l:match[2],
\ 'text': l:match[3],
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('cs',{
\ 'name': 'csc',
\ 'output_stream': 'stdout',
\ 'executable': 'csc',
\ 'command': function('ale_linters#cs#csc#GetCommand'),
\ 'callback': 'ale_linters#cs#csc#Handle',
\ 'lint_file': 1
\})

View File

@ -52,20 +52,34 @@ function! ale_linters#cs#mcsc#Handle(buffer, lines) abort
" NOTE: pattern also captures file name as linter compiles all " NOTE: pattern also captures file name as linter compiles all
" files within the source tree rooted at the specified source " files within the source tree rooted at the specified source
" path and not just the file loaded in the buffer " path and not just the file loaded in the buffer
let l:pattern = '^\v(.+\.cs)\((\d+),(\d+)\)\: ([^ ]+) ([^ ]+): (.+)$' let l:patterns = [
\ '^\v(.+\.cs)\((\d+),(\d+)\)\:\s+([^ ]+)\s+([cC][sS][^ ]+):\s(.+)$',
\ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$',
\]
let l:output = [] let l:output = []
let l:dir = s:GetWorkingDirectory(a:buffer) let l:dir = s:GetWorkingDirectory(a:buffer)
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:patterns)
call add(l:output, { if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS'
\ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]), call add(l:output, {
\ 'lnum': l:match[2] + 0, \ 'filename': ale#path#GetAbsPath(l:dir, l:match[1]),
\ 'col': l:match[3] + 0, \ 'lnum': l:match[2] + 0,
\ 'type': l:match[4] is# 'error' ? 'E' : 'W', \ 'col': l:match[3] + 0,
\ 'code': l:match[5], \ 'type': l:match[4] is# 'error' ? 'E' : 'W',
\ 'text': l:match[6], \ 'code': l:match[5],
\}) \ 'text': l:match[6] ,
\})
elseif strlen(l:match[2]) > 2 && l:match[2][:1] is? 'CS'
call add(l:output, {
\ 'filename':'<mcs>',
\ 'lnum': -1,
\ 'col': -1,
\ 'type': l:match[1] is# 'error' ? 'E' : 'W',
\ 'code': l:match[2],
\ 'text': l:match[3],
\})
endif
endfor endfor
return l:output return l:output

View File

@ -0,0 +1,37 @@
" Author: antew - https://github.com/antew
" Description: elm-language-server integration for elm (diagnostics, formatting, and more)
call ale#Set('elm_ls_executable', 'elm-language-server')
call ale#Set('elm_ls_use_global', get(g:, 'ale_use_global_executables', 1))
call ale#Set('elm_ls_elm_path', 'elm')
call ale#Set('elm_ls_elm_format_path', 'elm-format')
call ale#Set('elm_ls_elm_test_path', 'elm-test')
function! elm_ls#GetRootDir(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : ''
endfunction
function! elm_ls#GetOptions(buffer) abort
return {
\ 'runtime': 'node',
\ 'elmPath': ale#Var(a:buffer, 'elm_ls_elm_path'),
\ 'elmFormatPath': ale#Var(a:buffer, 'elm_ls_elm_format_path'),
\ 'elmTestPath': ale#Var(a:buffer, 'elm_ls_elm_test_path'),
\}
endfunction
call ale#linter#Define('elm', {
\ 'name': 'elm_ls',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'elm_ls', [
\ 'node_modules/.bin/elm-language-server',
\ 'node_modules/.bin/elm-lsp',
\ 'elm-lsp'
\ ])},
\ 'command': '%e --stdio',
\ 'project_root': function('elm_ls#GetRootDir'),
\ 'language': 'elm',
\ 'initialization_options': function('elm_ls#GetOptions')
\})

View File

@ -1,22 +0,0 @@
" Author: antew - https://github.com/antew
" Description: LSP integration for elm, currently supports diagnostics (linting)
call ale#Set('elm_lsp_executable', 'elm-lsp')
call ale#Set('elm_lsp_use_global', get(g:, 'ale_use_global_executables', 0))
function! elm_lsp#GetRootDir(buffer) abort
let l:elm_json = ale#path#FindNearestFile(a:buffer, 'elm.json')
return !empty(l:elm_json) ? fnamemodify(l:elm_json, ':p:h') : ''
endfunction
call ale#linter#Define('elm', {
\ 'name': 'elm_lsp',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'elm_lsp', [
\ 'node_modules/.bin/elm-lsp',
\ ])},
\ 'command': '%e --stdio',
\ 'project_root': function('elm_lsp#GetRootDir'),
\ 'language': 'elm'
\})

View File

@ -0,0 +1,93 @@
" Author: Autoine Gagne - https://github.com/AntoineGagne
" Description: Define a checker that runs dialyzer on Erlang files.
let g:ale_erlang_dialyzer_executable =
\ get(g:, 'ale_erlang_dialyzer_executable', 'dialyzer')
let g:ale_erlang_dialyzer_plt_file =
\ get(g:, 'ale_erlang_dialyzer_plt_file', '')
let g:ale_erlang_dialyzer_rebar3_profile =
\ get(g:, 'ale_erlang_dialyzer_rebar3_profile', 'default')
function! ale_linters#erlang#dialyzer#GetRebar3Profile(buffer) abort
return ale#Var(a:buffer, 'erlang_dialyzer_rebar3_profile')
endfunction
function! ale_linters#erlang#dialyzer#FindPlt(buffer) abort
let l:plt_file = ''
let l:rebar3_profile = ale_linters#erlang#dialyzer#GetRebar3Profile(a:buffer)
let l:plt_file_directory = ale#path#FindNearestDirectory(a:buffer, '_build' . l:rebar3_profile)
if !empty(l:plt_file_directory)
let l:plt_file = split(globpath(l:plt_file_directory, '/*_plt'), '\n')
endif
if !empty(l:plt_file)
return l:plt_file[0]
endif
if !empty($REBAR_PLT_DIR)
return expand('$REBAR_PLT_DIR/dialyzer/plt')
endif
return expand('$HOME/.dialyzer_plt')
endfunction
function! ale_linters#erlang#dialyzer#GetPlt(buffer) abort
let l:plt_file = ale#Var(a:buffer, 'erlang_dialyzer_plt_file')
if !empty(l:plt_file)
return l:plt_file
endif
return ale_linters#erlang#dialyzer#FindPlt(a:buffer)
endfunction
function! ale_linters#erlang#dialyzer#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'erlang_dialyzer_executable')
endfunction
function! ale_linters#erlang#dialyzer#GetCommand(buffer) abort
let l:command = ale#Escape(ale_linters#erlang#dialyzer#GetExecutable(a:buffer))
\ . ' -n'
\ . ' --plt ' . ale#Escape(ale_linters#erlang#dialyzer#GetPlt(a:buffer))
\ . ' -Wunmatched_returns'
\ . ' -Werror_handling'
\ . ' -Wrace_conditions'
\ . ' -Wunderspecs'
\ . ' %s'
return l:command
endfunction
function! ale_linters#erlang#dialyzer#Handle(buffer, lines) abort
" Match patterns like the following:
"
" erl_tidy_prv_fmt.erl:3: Callback info about the provider behaviour is not available
let l:pattern = '^\S\+:\(\d\+\): \(.\+\)$'
let l:output = []
for l:line in a:lines
let l:match = matchlist(l:line, l:pattern)
if len(l:match) != 0
let l:code = l:match[2]
call add(l:output, {
\ 'lnum': str2nr(l:match[1]),
\ 'lcol': 0,
\ 'text': l:code,
\ 'type': 'W'
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('erlang', {
\ 'name': 'dialyzer',
\ 'executable': function('ale_linters#erlang#dialyzer#GetExecutable'),
\ 'command': function('ale_linters#erlang#dialyzer#GetCommand'),
\ 'callback': function('ale_linters#erlang#dialyzer#Handle'),
\ 'lint_file': 1
\})

View File

@ -5,11 +5,13 @@ call ale#Set('go_bingo_executable', 'bingo')
call ale#Set('go_bingo_options', '--mode stdio') call ale#Set('go_bingo_options', '--mode stdio')
function! ale_linters#go#bingo#GetCommand(buffer) abort function! ale_linters#go#bingo#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options')) return ale#go#EnvString(a:buffer) . '%e' . ale#Pad(ale#Var(a:buffer, 'go_bingo_options'))
endfunction endfunction
function! ale_linters#go#bingo#FindProjectRoot(buffer) abort function! ale_linters#go#bingo#FindProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'go.mod') let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off'
let l:project_root = l:go_modules_off ?
\ '' : ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:mods = ':h' let l:mods = ':h'
if empty(l:project_root) if empty(l:project_root)

View File

@ -11,6 +11,7 @@ function! ale_linters#go#gobuild#GetCommand(buffer) abort
" Run go test in local directory with relative path " Run go test in local directory with relative path
return ale#path#BufferCdString(a:buffer) return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . ale#Var(a:buffer, 'go_go_executable') . ' test' \ . ale#Var(a:buffer, 'go_go_executable') . ' test'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -c -o /dev/null ./' \ . ' -c -o /dev/null ./'

View File

@ -1,10 +1,16 @@
" Author: neersighted <bjorn@neersighted.com> " Author: neersighted <bjorn@neersighted.com>
" Description: gofmt for Go files " Description: gofmt for Go files
function! ale_linters#go#gofmt#GetCommand(buffer) abort
return ale#go#EnvString(a:buffer)
\ . '%e -e %t'
endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'gofmt', \ 'name': 'gofmt',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'gofmt', \ 'executable': 'gofmt',
\ 'command': 'gofmt -e %t', \ 'command': function('ale_linters#go#gofmt#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsError', \ 'callback': 'ale#handlers#unix#HandleAsError',
\}) \})

View File

@ -10,13 +10,16 @@ function! ale_linters#go#golangci_lint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_golangci_lint_options') let l:options = ale#Var(a:buffer, 'go_golangci_lint_options')
let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package') let l:lint_package = ale#Var(a:buffer, 'go_golangci_lint_package')
if l:lint_package if l:lint_package
return ale#path#BufferCdString(a:buffer) return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e run ' \ . '%e run '
\ . l:options \ . l:options
endif endif
return ale#path#BufferCdString(a:buffer) return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e run ' \ . '%e run '
\ . ale#Escape(l:filename) \ . ale#Escape(l:filename)
\ . ' ' . l:options \ . ' ' . l:options

View File

@ -7,7 +7,7 @@ call ale#Set('go_golint_options', '')
function! ale_linters#go#golint#GetCommand(buffer) abort function! ale_linters#go#golint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_golint_options') let l:options = ale#Var(a:buffer, 'go_golint_options')
return '%e' return ale#go#EnvString(a:buffer) . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' %t' \ . ' %t'
endfunction endfunction

View File

@ -14,11 +14,13 @@ function! ale_linters#go#gometalinter#GetCommand(buffer) abort
" be calculated to absolute paths in the Handler " be calculated to absolute paths in the Handler
if l:lint_package if l:lint_package
return ale#path#BufferCdString(a:buffer) return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e' \ . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .' \ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif endif
return ale#path#BufferCdString(a:buffer) return ale#path#BufferCdString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e' \ . '%e'
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename)) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename))
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .' \ . (!empty(l:options) ? ' ' . l:options : '') . ' .'

View File

@ -6,11 +6,15 @@ call ale#Set('go_gopls_executable', 'gopls')
call ale#Set('go_gopls_options', '--mode stdio') call ale#Set('go_gopls_options', '--mode stdio')
function! ale_linters#go#gopls#GetCommand(buffer) abort function! ale_linters#go#gopls#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'go_gopls_options')) return ale#go#EnvString(a:buffer)
\ . '%e'
\ . ale#Pad(ale#Var(a:buffer, 'go_gopls_options'))
endfunction endfunction
function! ale_linters#go#gopls#FindProjectRoot(buffer) abort function! ale_linters#go#gopls#FindProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'go.mod') let l:go_modules_off = ale#Var(a:buffer, 'go_go111module') is# 'off'
let l:project_root = l:go_modules_off ?
\ '' : ale#path#FindNearestFile(a:buffer, 'go.mod')
let l:mods = ':h' let l:mods = ':h'
if empty(l:project_root) if empty(l:project_root)

View File

@ -2,7 +2,8 @@
" Description: gosimple for Go files " Description: gosimple for Go files
function! ale_linters#go#gosimple#GetCommand(buffer) abort function! ale_linters#go#gosimple#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer) . ' gosimple .' return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer) . 'gosimple .'
endfunction endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {

View File

@ -6,7 +6,8 @@ function! ale_linters#go#gotype#GetCommand(buffer) abort
return '' return ''
endif endif
return ale#path#BufferCdString(a:buffer) . ' gotype -e .' return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer) . 'gotype -e .'
endfunction endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {

View File

@ -11,6 +11,7 @@ function! ale_linters#go#govet#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_govet_options') let l:options = ale#Var(a:buffer, 'go_govet_options')
return ale#path#BufferCdString(a:buffer) . ' ' return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer)
\ . ale#Var(a:buffer, 'go_go_executable') . ' vet ' \ . ale#Var(a:buffer, 'go_go_executable') . ' vet '
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' .' \ . ' .'

View File

@ -15,8 +15,9 @@ function! ale_linters#go#langserver#GetCommand(buffer) abort
endif endif
let l:options = uniq(sort(l:options)) let l:options = uniq(sort(l:options))
let l:env = ale#go#EnvString(a:buffer)
return join(extend(l:executable, l:options), ' ') return l:env . join(extend(l:executable, l:options), ' ')
endfunction endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {

View File

@ -8,17 +8,18 @@ function! ale_linters#go#staticcheck#GetCommand(buffer) abort
let l:filename = expand('#' . a:buffer . ':t') let l:filename = expand('#' . a:buffer . ':t')
let l:options = ale#Var(a:buffer, 'go_staticcheck_options') let l:options = ale#Var(a:buffer, 'go_staticcheck_options')
let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package') let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package')
let l:env = ale#go#EnvString(a:buffer)
" BufferCdString is used so that we can be sure the paths output from " BufferCdString is used so that we can be sure the paths output from
" staticcheck can be calculated to absolute paths in the Handler " staticcheck can be calculated to absolute paths in the Handler
if l:lint_package if l:lint_package
return ale#path#BufferCdString(a:buffer) return ale#path#BufferCdString(a:buffer)
\ . 'staticcheck' \ . l:env . 'staticcheck'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .' \ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif endif
return ale#path#BufferCdString(a:buffer) return ale#path#BufferCdString(a:buffer)
\ . 'staticcheck' \ . l:env . 'staticcheck'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' ' . ale#Escape(l:filename) \ . ' ' . ale#Escape(l:filename)
endfunction endfunction

View File

@ -1,6 +1,10 @@
" Author: Devon Meunier <devon.meunier@gmail.com> " Author: Devon Meunier <devon.meunier@gmail.com>
" Description: checkstyle for Java files " Description: checkstyle for Java files
call ale#Set('java_checkstyle_executable', 'checkstyle')
call ale#Set('java_checkstyle_config', '/google_checks.xml')
call ale#Set('java_checkstyle_options', '')
function! ale_linters#java#checkstyle#Handle(buffer, lines) abort function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
let l:output = [] let l:output = []
@ -17,6 +21,10 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
\}) \})
endfor endfor
if !empty(l:output)
return l:output
endif
" old checkstyle versions " old checkstyle versions
let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$' let l:pattern = '\v(.+):(\d+): ([^:]+): (.+)$'
@ -31,19 +39,32 @@ function! ale_linters#java#checkstyle#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! s:GetConfig(buffer, config) abort
if ale#path#IsAbsolute(a:config)
return a:config
endif
let s:file = ale#path#FindNearestFile(a:buffer, a:config)
return !empty(s:file) ? s:file : a:config
endfunction
function! ale_linters#java#checkstyle#GetCommand(buffer) abort function! ale_linters#java#checkstyle#GetCommand(buffer) abort
return 'checkstyle ' let l:options = ale#Var(a:buffer, 'java_checkstyle_options')
\ . ale#Var(a:buffer, 'java_checkstyle_options') let l:config_option = ale#Var(a:buffer, 'java_checkstyle_config')
let l:config = l:options !~# '\v(^| )-c' && !empty(l:config_option)
\ ? s:GetConfig(a:buffer, l:config_option)
\ : ''
return '%e'
\ . ale#Pad(l:options)
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
\ . ' %s' \ . ' %s'
endfunction endfunction
if !exists('g:ale_java_checkstyle_options')
let g:ale_java_checkstyle_options = '-c /google_checks.xml'
endif
call ale#linter#Define('java', { call ale#linter#Define('java', {
\ 'name': 'checkstyle', \ 'name': 'checkstyle',
\ 'executable': 'checkstyle', \ 'executable': {b -> ale#Var(b, 'java_checkstyle_executable')},
\ 'command': function('ale_linters#java#checkstyle#GetCommand'), \ 'command': function('ale_linters#java#checkstyle#GetCommand'),
\ 'callback': 'ale_linters#java#checkstyle#Handle', \ 'callback': 'ale_linters#java#checkstyle#Handle',
\ 'lint_file': 1, \ 'lint_file': 1,

View File

@ -4,6 +4,8 @@
let s:version_cache = {} let s:version_cache = {}
call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls')) call ale#Set('java_eclipselsp_path', ale#path#Simplify($HOME . '/eclipse.jdt.ls'))
call ale#Set('java_eclipselsp_config_path', '')
call ale#Set('java_eclipselsp_workspace_path', '')
call ale#Set('java_eclipselsp_executable', 'java') call ale#Set('java_eclipselsp_executable', 'java')
function! ale_linters#java#eclipselsp#Executable(buffer) abort function! ale_linters#java#eclipselsp#Executable(buffer) abort
@ -32,11 +34,23 @@ function! ale_linters#java#eclipselsp#JarPath(buffer) abort
return l:files[0] return l:files[0]
endif endif
" Search jar file within system package path
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) == 1
return l:files[0]
endif
return '' return ''
endfunction endfunction
function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort function! ale_linters#java#eclipselsp#ConfigurationPath(buffer) abort
let l:path = fnamemodify(ale_linters#java#eclipselsp#JarPath(a:buffer), ':p:h:h') let l:path = fnamemodify(ale_linters#java#eclipselsp#JarPath(a:buffer), ':p:h:h')
let l:config_path = ale#Var(a:buffer, 'java_eclipselsp_config_path')
if !empty(l:config_path)
return ale#path#Simplify(l:config_path)
endif
if has('win32') if has('win32')
let l:path = l:path . '/config_win' let l:path = l:path . '/config_win'
@ -76,6 +90,16 @@ function! ale_linters#java#eclipselsp#CommandWithVersion(buffer, version_lines,
return ale_linters#java#eclipselsp#Command(a:buffer, l:version) return ale_linters#java#eclipselsp#Command(a:buffer, l:version)
endfunction endfunction
function! ale_linters#java#eclipselsp#WorkspacePath(buffer) abort
let l:wspath = ale#Var(a:buffer, 'java_eclipselsp_workspace_path')
if !empty(l:wspath)
return l:wspath
endif
return ale#path#Dirname(ale#java#FindProjectRoot(a:buffer))
endfunction
function! ale_linters#java#eclipselsp#Command(buffer, version) abort function! ale_linters#java#eclipselsp#Command(buffer, version) abort
let l:path = ale#Var(a:buffer, 'java_eclipselsp_path') let l:path = ale#Var(a:buffer, 'java_eclipselsp_path')
@ -89,11 +113,11 @@ function! ale_linters#java#eclipselsp#Command(buffer, version) abort
\ '-noverify', \ '-noverify',
\ '-Xmx1G', \ '-Xmx1G',
\ '-jar', \ '-jar',
\ ale_linters#java#eclipselsp#JarPath(a:buffer), \ ale#Escape(ale_linters#java#eclipselsp#JarPath(a:buffer)),
\ '-configuration', \ '-configuration',
\ ale_linters#java#eclipselsp#ConfigurationPath(a:buffer), \ ale#Escape(ale_linters#java#eclipselsp#ConfigurationPath(a:buffer)),
\ '-data', \ '-data',
\ ale#java#FindProjectRoot(a:buffer) \ ale#Escape(ale_linters#java#eclipselsp#WorkspacePath(a:buffer))
\ ] \ ]
if ale#semver#GTE(a:version, [1, 9]) if ale#semver#GTE(a:version, [1, 9])

View File

@ -21,6 +21,11 @@ function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
let l:command = ale#gradle#BuildClasspathCommand(a:buffer) let l:command = ale#gradle#BuildClasspathCommand(a:buffer)
endif endif
" Try to use Ant if Gradle and Maven aren't available
if empty(l:command)
let l:command = ale#ant#BuildClasspathCommand(a:buffer)
endif
if empty(l:command) if empty(l:command)
return ale_linters#java#javac#GetCommand(a:buffer, [], {}) return ale_linters#java#javac#GetCommand(a:buffer, [], {})
endif endif

View File

@ -1,16 +1,47 @@
" Author: Horacio Sanson <https://github.com/hsanson> " Author: Horacio Sanson <https://github.com/hsanson>
" Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac " Description: Support for the Java language server https://github.com/georgewfraser/vscode-javac
call ale#Set('java_javalsp_executable', 'java') call ale#Set('java_javalsp_executable', '')
call ale#Set('java_javalsp_config', {})
function! ale_linters#java#javalsp#Executable(buffer) abort function! ale_linters#java#javalsp#Executable(buffer) abort
return ale#Var(a:buffer, 'java_javalsp_executable') return ale#Var(a:buffer, 'java_javalsp_executable')
endfunction endfunction
function! ale_linters#java#javalsp#Config(buffer) abort
let l:defaults = { 'java': { 'classPath': [], 'externalDependencies': [] } }
let l:config = ale#Var(a:buffer, 'java_javalsp_config')
" Ensure the config dictionary contains both classPath and
" externalDependencies keys to avoid a NPE crash on Java Language Server.
call extend(l:config, l:defaults, 'keep')
call extend(l:config['java'], l:defaults['java'], 'keep')
return l:config
endfunction
function! ale_linters#java#javalsp#Command(buffer) abort function! ale_linters#java#javalsp#Command(buffer) abort
let l:executable = ale_linters#java#javalsp#Executable(a:buffer) let l:executable = ale_linters#java#javalsp#Executable(a:buffer)
return ale#Escape(l:executable) . ' -Xverify:none -m javacs/org.javacs.Main' if fnamemodify(l:executable, ':t') is# 'java'
" For backward compatibility.
let l:cmd = [
\ ale#Escape(l:executable),
\ '--add-exports jdk.compiler/com.sun.tools.javac.api=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.code=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.comp=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.main=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.tree=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.model=javacs',
\ '--add-exports jdk.compiler/com.sun.tools.javac.util=javacs',
\ '--add-opens jdk.compiler/com.sun.tools.javac.api=javacs',
\ '-m javacs/org.javacs.Main',
\]
return join(l:cmd, ' ')
else
return ale#Escape(l:executable)
endif
endfunction endfunction
call ale#linter#Define('java', { call ale#linter#Define('java', {
@ -20,4 +51,5 @@ call ale#linter#Define('java', {
\ 'command': function('ale_linters#java#javalsp#Command'), \ 'command': function('ale_linters#java#javalsp#Command'),
\ 'language': 'java', \ 'language': 'java',
\ 'project_root': function('ale#java#FindProjectRoot'), \ 'project_root': function('ale#java#FindProjectRoot'),
\ 'lsp_config': function('ale_linters#java#javalsp#Config')
\}) \})

View File

@ -6,5 +6,5 @@ call ale#linter#Define('javascript', {
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'executable': function('ale#handlers#eslint#GetExecutable'),
\ 'command': function('ale#handlers#eslint#GetCommand'), \ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle', \ 'callback': 'ale#handlers#eslint#HandleJSON',
\}) \})

View File

@ -14,7 +14,7 @@ endfunction
function! ale_linters#javascript#xo#GetCommand(buffer) abort function! ale_linters#javascript#xo#GetCommand(buffer) abort
return ale#Escape(ale_linters#javascript#xo#GetExecutable(a:buffer)) return ale#Escape(ale_linters#javascript#xo#GetExecutable(a:buffer))
\ . ' ' . ale#Var(a:buffer, 'javascript_xo_options') \ . ' ' . ale#Var(a:buffer, 'javascript_xo_options')
\ . ' --reporter unix --stdin --stdin-filename %s' \ . ' --reporter json --stdin --stdin-filename %s'
endfunction endfunction
" xo uses eslint and the output format is the same " xo uses eslint and the output format is the same
@ -22,5 +22,5 @@ call ale#linter#Define('javascript', {
\ 'name': 'xo', \ 'name': 'xo',
\ 'executable': function('ale_linters#javascript#xo#GetExecutable'), \ 'executable': function('ale_linters#javascript#xo#GetExecutable'),
\ 'command': function('ale_linters#javascript#xo#GetCommand'), \ 'command': function('ale_linters#javascript#xo#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle', \ 'callback': 'ale#handlers#eslint#HandleJSON',
\}) \})

View File

@ -4,12 +4,6 @@
call ale#Set('objc_clangd_executable', 'clangd') call ale#Set('objc_clangd_executable', 'clangd')
call ale#Set('objc_clangd_options', '') call ale#Set('objc_clangd_options', '')
function! ale_linters#objc#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#objc#clangd#GetCommand(buffer) abort function! ale_linters#objc#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options')) return '%e' . ale#Pad(ale#Var(a:buffer, 'objc_clangd_options'))
endfunction endfunction
@ -19,5 +13,5 @@ call ale#linter#Define('objc', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'objc_clangd_executable')}, \ 'executable': {b -> ale#Var(b, 'objc_clangd_executable')},
\ 'command': function('ale_linters#objc#clangd#GetCommand'), \ 'command': function('ale_linters#objc#clangd#GetCommand'),
\ 'project_root': function('ale_linters#objc#clangd#GetProjectRoot'), \ 'project_root': function('ale#c#FindProjectRoot'),
\}) \})

View File

@ -4,12 +4,6 @@
call ale#Set('objcpp_clangd_executable', 'clangd') call ale#Set('objcpp_clangd_executable', 'clangd')
call ale#Set('objcpp_clangd_options', '') call ale#Set('objcpp_clangd_options', '')
function! ale_linters#objcpp#clangd#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : ''
endfunction
function! ale_linters#objcpp#clangd#GetCommand(buffer) abort function! ale_linters#objcpp#clangd#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options')) return '%e' . ale#Pad(ale#Var(a:buffer, 'objcpp_clangd_options'))
endfunction endfunction
@ -19,5 +13,5 @@ call ale#linter#Define('objcpp', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'objcpp_clangd_executable')}, \ 'executable': {b -> ale#Var(b, 'objcpp_clangd_executable')},
\ 'command': function('ale_linters#objcpp#clangd#GetCommand'), \ 'command': function('ale_linters#objcpp#clangd#GetCommand'),
\ 'project_root': function('ale_linters#objcpp#clangd#GetProjectRoot'), \ 'project_root': function('ale#c#FindProjectRoot'),
\}) \})

View File

@ -10,13 +10,13 @@ call ale#Set('php_phpcs_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#phpcs#GetCommand(buffer) abort function! ale_linters#php#phpcs#GetCommand(buffer) abort
let l:standard = ale#Var(a:buffer, 'php_phpcs_standard') let l:standard = ale#Var(a:buffer, 'php_phpcs_standard')
let l:standard_option = !empty(l:standard) let l:standard_option = !empty(l:standard)
\ ? '--standard=' . l:standard \ ? '--standard=' . ale#Escape(l:standard)
\ : '' \ : ''
let l:options = ale#Var(a:buffer, 'php_phpcs_options')
return '%e -s --report=emacs --stdin-path=%s' return ale#path#BufferCdString(a:buffer)
\ . ale#Pad(l:standard_option) \ . '%e -s --report=emacs --stdin-path=%s'
\ . ale#Pad(l:options) \ . ale#Pad(l:standard_option)
\ . ale#Pad(ale#Var(a:buffer, 'php_phpcs_options'))
endfunction endfunction
function! ale_linters#php#phpcs#Handle(buffer, lines) abort function! ale_linters#php#phpcs#Handle(buffer, lines) abort
@ -36,6 +36,7 @@ function! ale_linters#php#phpcs#Handle(buffer, lines) abort
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
\ 'text': l:text, \ 'text': l:text,
\ 'type': l:type is# 'error' ? 'E' : 'W', \ 'type': l:type is# 'error' ? 'E' : 'W',
\ 'sub_type': 'style',
\}) \})
endfor endfor

View File

@ -49,11 +49,19 @@ function! ale_linters#powershell#powershell#Handle(buffer, lines) abort
let l:matchcount = 1 let l:matchcount = 1
endif endif
let l:item = { " If the match is 0, it was a failed match
\ 'lnum': str2nr(l:match[1]), " probably due to an unexpected token which
\ 'col': str2nr(l:match[2]), " contained a newline. Reset matchcount. to
\ 'type': 'E', " continue to the next match
\} if !empty(l:match[1])
let l:item = {
\ 'lnum': str2nr(l:match[1]),
\ 'col': str2nr(l:match[2]),
\ 'type': 'E',
\}
else
let l:matchcount = 0
endif
elseif l:matchcount == 2 elseif l:matchcount == 2
" Second match[0] grabs the full line in order " Second match[0] grabs the full line in order
" to handles the text " to handles the text
@ -84,8 +92,8 @@ endfunction
call ale#linter#Define('powershell', { call ale#linter#Define('powershell', {
\ 'name': 'powershell', \ 'name': 'powershell',
\ 'executable_callback': 'ale_linters#powershell#powershell#GetExecutable', \ 'executable': function('ale_linters#powershell#powershell#GetExecutable'),
\ 'command_callback': 'ale_linters#powershell#powershell#GetCommand', \ 'command': function('ale_linters#powershell#powershell#GetCommand'),
\ 'output_stream': 'stdout', \ 'output_stream': 'stdout',
\ 'callback': 'ale_linters#powershell#powershell#Handle', \ 'callback': 'ale_linters#powershell#powershell#Handle',
\}) \})

View File

@ -31,6 +31,20 @@ function! ale_linters#pug#puglint#GetCommand(buffer) abort
\ . ' -r inline %t' \ . ' -r inline %t'
endfunction endfunction
function! ale_linters#pug#puglint#Handle(buffer, lines) abort
for l:line in a:lines[:10]
if l:line =~# '^SyntaxError: '
return [{
\ 'lnum': 1,
\ 'text': 'puglint configuration error (type :ALEDetail for more information)',
\ 'detail': join(a:lines, "\n"),
\}]
endif
endfor
return ale#handlers#unix#HandleAsError(a:buffer, a:lines)
endfunction
call ale#linter#Define('pug', { call ale#linter#Define('pug', {
\ 'name': 'puglint', \ 'name': 'puglint',
\ 'executable': {b -> ale#node#FindExecutable(b, 'pug_puglint', [ \ 'executable': {b -> ale#node#FindExecutable(b, 'pug_puglint', [
@ -38,5 +52,5 @@ call ale#linter#Define('pug', {
\ ])}, \ ])},
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'command': function('ale_linters#pug#puglint#GetCommand'), \ 'command': function('ale_linters#pug#puglint#GetCommand'),
\ 'callback': 'ale#handlers#unix#HandleAsError', \ 'callback': 'ale_linters#pug#puglint#Handle',
\}) \})

View File

@ -0,0 +1,49 @@
" Author: Drew Olson <drew@drewolson.org>
" Description: Integrate ALE with purescript-language-server.
call ale#Set('purescript_ls_executable', 'purescript-language-server')
call ale#Set('purescript_ls_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('purescript_ls_config', {})
function! ale_linters#purescript#ls#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'purescript_ls', [
\ 'node_modules/.bin/purescript-language-server',
\])
endfunction
function! ale_linters#purescript#ls#GetCommand(buffer) abort
let l:executable = ale_linters#purescript#ls#GetExecutable(a:buffer)
return ale#Escape(l:executable) . ' --stdio'
endfunction
function! ale_linters#purescript#ls#FindProjectRoot(buffer) abort
let l:config = ale#path#FindNearestFile(a:buffer, 'bower.json')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
let l:config = ale#path#FindNearestFile(a:buffer, 'psc-package.json')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
let l:config = ale#path#FindNearestFile(a:buffer, 'spago.dhall')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
return ''
endfunction
call ale#linter#Define('purescript', {
\ 'name': 'purescript-language-server',
\ 'lsp': 'stdio',
\ 'executable': function('ale_linters#purescript#ls#GetExecutable'),
\ 'command': function('ale_linters#purescript#ls#GetCommand'),
\ 'project_root': function('ale_linters#purescript#ls#FindProjectRoot'),
\ 'lsp_config': {b -> ale#Var(b, 'purescript_ls_config')},
\})

View File

@ -78,4 +78,5 @@ call ale#linter#Define('python', {
\ 'executable': function('ale_linters#python#mypy#GetExecutable'), \ 'executable': function('ale_linters#python#mypy#GetExecutable'),
\ 'command': function('ale_linters#python#mypy#GetCommand'), \ 'command': function('ale_linters#python#mypy#GetCommand'),
\ 'callback': 'ale_linters#python#mypy#Handle', \ 'callback': 'ale_linters#python#mypy#Handle',
\ 'output_stream': 'both'
\}) \})

View File

@ -0,0 +1,23 @@
" Author: David Buchan-Swanson <github@deecewan.com>
" Description: Integrate ALE with reason-language-server.
call ale#Set('reason_ls_executable', '')
function! ale_linters#reason#ls#FindProjectRoot(buffer) abort
let l:reason_config = ale#path#FindNearestFile(a:buffer, 'bsconfig.json')
if !empty(l:reason_config)
return fnamemodify(l:reason_config, ':h')
endif
return ''
endfunction
call ale#linter#Define('reason', {
\ 'name': 'reason-language-server',
\ 'lsp': 'stdio',
\ 'executable': {buffer -> ale#Var(buffer, 'reason_ls_executable')},
\ 'command': '%e',
\ 'project_root': function('ale_linters#reason#ls#FindProjectRoot'),
\ 'language': 'reason',
\})

View File

@ -0,0 +1,23 @@
call ale#Set('ruby_sorbet_executable', 'srb')
call ale#Set('ruby_sorbet_options', '')
function! ale_linters#ruby#sorbet#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable')
let l:options = ale#Var(a:buffer, 'ruby_sorbet_options')
return ale#handlers#ruby#EscapeExecutable(l:executable, 'srb')
\ . ' tc'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --lsp --disable-watchman'
endfunction
call ale#linter#Define('ruby', {
\ 'name': 'sorbet',
\ 'aliases': ['srb'],
\ 'lsp': 'stdio',
\ 'language': 'ruby',
\ 'executable': {b -> ale#Var(b, 'ruby_sorbet_executable')},
\ 'command': function('ale_linters#ruby#sorbet#GetCommand'),
\ 'project_root': function('ale#ruby#FindProjectRoot')
\})

View File

@ -25,14 +25,11 @@ endfunction
function! ale_linters#rust#cargo#GetCommand(buffer, version) abort function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check') let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check')
\ && ale#semver#GTE(a:version, [0, 17, 0]) \ && ale#semver#GTE(a:version, [0, 17, 0])
let l:use_all_targets = l:use_check let l:use_all_targets = ale#Var(a:buffer, 'rust_cargo_check_all_targets')
\ && ale#Var(a:buffer, 'rust_cargo_check_all_targets')
\ && ale#semver#GTE(a:version, [0, 22, 0]) \ && ale#semver#GTE(a:version, [0, 22, 0])
let l:use_examples = l:use_check let l:use_examples = ale#Var(a:buffer, 'rust_cargo_check_examples')
\ && ale#Var(a:buffer, 'rust_cargo_check_examples')
\ && ale#semver#GTE(a:version, [0, 22, 0]) \ && ale#semver#GTE(a:version, [0, 22, 0])
let l:use_tests = l:use_check let l:use_tests = ale#Var(a:buffer, 'rust_cargo_check_tests')
\ && ale#Var(a:buffer, 'rust_cargo_check_tests')
\ && ale#semver#GTE(a:version, [0, 22, 0]) \ && ale#semver#GTE(a:version, [0, 22, 0])
let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features') let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features')
@ -69,7 +66,15 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
if ale#Var(a:buffer, 'rust_cargo_use_clippy') if ale#Var(a:buffer, 'rust_cargo_use_clippy')
let l:subcommand = 'clippy' let l:subcommand = 'clippy'
let l:clippy_options = ' ' . ale#Var(a:buffer, 'rust_cargo_clippy_options') let l:clippy_options = ale#Var(a:buffer, 'rust_cargo_clippy_options')
if l:clippy_options =~# '^-- '
let l:clippy_options = join(split(l:clippy_options, '-- '))
endif
if l:clippy_options isnot# ''
let l:clippy_options = ' -- ' . l:clippy_options
endif
endif endif
return l:nearest_cargo_prefix . 'cargo ' return l:nearest_cargo_prefix . 'cargo '

View File

@ -0,0 +1,49 @@
" Author: Keith Maxwell <keith.maxwell@gmail.com>
" Description: terraform fmt to check for errors
call ale#Set('terraform_terraform_executable', 'terraform')
function! ale_linters#terraform#terraform#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'terraform_terraform_executable')
endfunction
function! ale_linters#terraform#terraform#GetCommand(buffer) abort
return ale#Escape(ale_linters#terraform#terraform#GetExecutable(a:buffer))
\ . ' fmt -no-color --check=true -'
endfunction
function! ale_linters#terraform#terraform#Handle(buffer, lines) abort
let l:head = '^Error running fmt: In <standard input>: '
let l:output = []
let l:patterns = [
\ l:head.'At \(\d\+\):\(\d\+\): \(.*\)$',
\ l:head.'\(.*\)$'
\]
for l:match in ale#util#GetMatches(a:lines, l:patterns)
if len(l:match[2]) > 0
call add(l:output, {
\ 'lnum': str2nr(l:match[1]),
\ 'col': str2nr(l:match[2]),
\ 'text': l:match[3],
\ 'type': 'E',
\})
else
call add(l:output, {
\ 'lnum': line('$'),
\ 'text': l:match[1],
\ 'type': 'E',
\})
endif
endfor
return l:output
endfunction
call ale#linter#Define('terraform', {
\ 'name': 'terraform',
\ 'output_stream': 'stderr',
\ 'executable': function('ale_linters#terraform#terraform#GetExecutable'),
\ 'command': function('ale_linters#terraform#terraform#GetCommand'),
\ 'callback': 'ale_linters#terraform#terraform#Handle',
\})

View File

@ -0,0 +1,21 @@
" Author: Ricardo Liang <ricardoliang@gmail.com>
" Description: Texlab language server (Rust rewrite)
call ale#Set('tex_texlab_executable', 'texlab')
call ale#Set('tex_texlab_options', '')
function! ale_linters#tex#texlab#GetProjectRoot(buffer) abort
return ''
endfunction
function! ale_linters#tex#texlab#GetCommand(buffer) abort
return '%e' . ale#Pad(ale#Var(a:buffer, 'tex_texlab_options'))
endfunction
call ale#linter#Define('tex', {
\ 'name': 'texlab',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#Var(b, 'tex_texlab_executable')},
\ 'command': function('ale_linters#tex#texlab#GetCommand'),
\ 'project_root': function('ale_linters#tex#texlab#GetProjectRoot'),
\})

View File

@ -5,5 +5,5 @@ call ale#linter#Define('typescript', {
\ 'name': 'eslint', \ 'name': 'eslint',
\ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'executable': function('ale#handlers#eslint#GetExecutable'),
\ 'command': function('ale#handlers#eslint#GetCommand'), \ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle', \ 'callback': 'ale#handlers#eslint#HandleJSON',
\}) \})

View File

@ -11,7 +11,7 @@ endfunction
function! ale_linters#typescript#xo#GetCommand(buffer) abort function! ale_linters#typescript#xo#GetCommand(buffer) abort
return ale#Escape(ale_linters#typescript#xo#GetExecutable(a:buffer)) return ale#Escape(ale_linters#typescript#xo#GetExecutable(a:buffer))
\ . ale#Pad(ale#Var(a:buffer, 'typescript_xo_options')) \ . ale#Pad(ale#Var(a:buffer, 'typescript_xo_options'))
\ . ' --reporter unix --stdin --stdin-filename %s' \ . ' --reporter json --stdin --stdin-filename %s'
endfunction endfunction
" xo uses eslint and the output format is the same " xo uses eslint and the output format is the same
@ -19,5 +19,5 @@ call ale#linter#Define('typescript', {
\ 'name': 'xo', \ 'name': 'xo',
\ 'executable': function('ale_linters#typescript#xo#GetExecutable'), \ 'executable': function('ale_linters#typescript#xo#GetExecutable'),
\ 'command': function('ale_linters#typescript#xo#GetCommand'), \ 'command': function('ale_linters#typescript#xo#GetCommand'),
\ 'callback': 'ale#handlers#eslint#Handle', \ 'callback': 'ale#handlers#eslint#HandleJSON',
\}) \})

View File

@ -156,7 +156,7 @@ function! ale#Queue(delay, ...) abort
endif endif
endfunction endfunction
let s:current_ale_version = [2, 4, 0] let s:current_ale_version = [2, 5, 0]
" A function used to check for ALE features in files outside of the project. " A function used to check for ALE features in files outside of the project.
function! ale#Has(feature) abort function! ale#Has(feature) abort

View File

@ -0,0 +1,41 @@
" Author: Andrew Lee <andrewl@mbda.fun>.
" Inspired by ale/gradle.vim by Michael Pardo <michael@michaelpardo.com>
" Description: Functions for working with Ant projects.
" Given a buffer number, find an Ant project root
function! ale#ant#FindProjectRoot(buffer) abort
let l:build_xml_path = ale#path#FindNearestFile(a:buffer, 'build.xml')
if !empty(l:build_xml_path)
return fnamemodify(l:build_xml_path, ':h')
endif
return ''
endfunction
" Given a buffer number, find the path to the `ant` executable. Returns an empty
" string if cannot find the executable.
function! ale#ant#FindExecutable(buffer) abort
if executable('ant')
return 'ant'
endif
return ''
endfunction
" Given a buffer number, build a command to print the classpath of the root
" project. Returns an empty string if cannot build the command.
function! ale#ant#BuildClasspathCommand(buffer) abort
let l:executable = ale#ant#FindExecutable(a:buffer)
let l:project_root = ale#ant#FindProjectRoot(a:buffer)
if !empty(l:executable) && !empty(l:project_root)
return ale#path#CdString(l:project_root)
\ . ale#Escape(l:executable)
\ . ' classpath'
\ . ' -S'
\ . ' -q'
endif
return ''
endfunction

View File

@ -96,6 +96,13 @@ function! ale#assert#Fixer(expected_result) abort
AssertEqual a:expected_result, l:result AssertEqual a:expected_result, l:result
endfunction endfunction
function! ale#assert#FixerNotExecuted() abort
let l:buffer = bufnr('')
let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))[-1]
Assert empty(l:result), "The fixer will be executed when it shouldn't be"
endfunction
function! ale#assert#LinterNotExecuted() abort function! ale#assert#LinterNotExecuted() abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:linter = s:GetLinter() let l:linter = s:GetLinter()
@ -158,6 +165,7 @@ endfunction
function! ale#assert#SetUpFixerTestCommands() abort function! ale#assert#SetUpFixerTestCommands() abort
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>) command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>) command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>)
command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted()
endfunction endfunction
" A dummy function for making sure this module is loaded. " A dummy function for making sure this module is loaded.
@ -316,4 +324,8 @@ function! ale#assert#TearDownFixerTest() abort
if exists(':AssertFixer') if exists(':AssertFixer')
delcommand AssertFixer delcommand AssertFixer
endif endif
if exists(':AssertFixerNotExecuted')
delcommand AssertFixerNotExecuted
endif
endfunction endfunction

View File

@ -23,104 +23,117 @@ function! ale#c#GetBuildDirectory(buffer) abort
return l:build_dir return l:build_dir
endif endif
return ale#path#Dirname(ale#c#FindCompileCommands(a:buffer)) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
return ale#path#Dirname(l:json_file)
endfunction endfunction
function! ale#c#ShellSplit(line) abort
function! ale#c#FindProjectRoot(buffer) abort
for l:project_filename in g:__ale_c_project_filenames
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
if !empty(l:full_path)
let l:path = fnamemodify(l:full_path, ':h')
" Correct .git path detection.
if fnamemodify(l:path, ':t') is# '.git'
let l:path = fnamemodify(l:path, ':h')
endif
return l:path
endif
endfor
return ''
endfunction
function! ale#c#AreSpecialCharsBalanced(option) abort
" Escape \"
let l:option_escaped = substitute(a:option, '\\"', '', 'g')
" Retain special chars only
let l:special_chars = substitute(l:option_escaped, '[^"''()`]', '', 'g')
let l:special_chars = split(l:special_chars, '\zs')
" Check if they are balanced
let l:stack = [] let l:stack = []
let l:args = ['']
let l:prev = ''
for l:char in l:special_chars for l:char in split(a:line, '\zs')
if l:char is# ')' if l:char is# ''''
if len(l:stack) == 0 || get(l:stack, -1) isnot# '(' if len(l:stack) > 0 && get(l:stack, -1) is# ''''
return 0
endif
call remove(l:stack, -1)
elseif l:char is# '('
call add(l:stack, l:char)
else
if len(l:stack) > 0 && get(l:stack, -1) is# l:char
call remove(l:stack, -1) call remove(l:stack, -1)
else elseif (len(l:stack) == 0 || get(l:stack, -1) isnot# '"') && l:prev isnot# '\'
call add(l:stack, l:char) call add(l:stack, l:char)
endif endif
elseif (l:char is# '"' || l:char is# '`') && l:prev isnot# '\'
if len(l:stack) > 0 && get(l:stack, -1) is# l:char
call remove(l:stack, -1)
elseif len(l:stack) == 0 || get(l:stack, -1) isnot# ''''
call add(l:stack, l:char)
endif
elseif (l:char is# '(' || l:char is# '[' || l:char is# '{') && l:prev isnot# '\'
if len(l:stack) == 0 || get(l:stack, -1) isnot# ''''
call add(l:stack, l:char)
endif
elseif (l:char is# ')' || l:char is# ']' || l:char is# '}') && l:prev isnot# '\'
if len(l:stack) > 0 && get(l:stack, -1) is# {')': '(', ']': '[', '}': '{'}[l:char]
call remove(l:stack, -1)
endif
elseif l:char is# ' ' && len(l:stack) == 0
if len(get(l:args, -1)) > 0
call add(l:args, '')
endif
continue
endif endif
let l:args[-1] = get(l:args, -1) . l:char
endfor endfor
return len(l:stack) == 0 return l:args
endfunction endfunction
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
let l:split_lines = split(a:cflag_line) let l:cflags_list = []
let l:split_lines = ale#c#ShellSplit(a:cflag_line)
let l:option_index = 0 let l:option_index = 0
while l:option_index < len(l:split_lines) while l:option_index < len(l:split_lines)
let l:next_option_index = l:option_index + 1 let l:option = l:split_lines[l:option_index]
" Join space-separated option
while l:next_option_index < len(l:split_lines)
\&& stridx(l:split_lines[l:next_option_index], '-') != 0
let l:next_option_index += 1
endwhile
let l:option = join(l:split_lines[l:option_index : l:next_option_index-1], ' ')
call remove(l:split_lines, l:option_index, l:next_option_index-1)
call insert(l:split_lines, l:option, l:option_index)
" Ignore invalid or conflicting options
if stridx(l:option, '-') != 0
\|| stridx(l:option, '-o') == 0
\|| stridx(l:option, '-c') == 0
call remove(l:split_lines, l:option_index)
let l:option_index = l:option_index - 1
" Fix relative path
elseif stridx(l:option, '-I') == 0
if !(stridx(l:option, ':') == 2+1 || stridx(l:option, '/') == 2+0)
let l:option = '-I' . a:path_prefix . s:sep . l:option[2:]
call remove(l:split_lines, l:option_index)
call insert(l:split_lines, l:option, l:option_index)
endif
endif
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
" Include options, that may need relative path fix
if stridx(l:option, '-I') == 0
\ || stridx(l:option, '-iquote') == 0
\ || stridx(l:option, '-isystem') == 0
\ || stridx(l:option, '-idirafter') == 0
if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
let l:arg = join(split(l:option, '\zs')[2:], '')
let l:option = '-I'
else
let l:arg = l:split_lines[l:option_index]
let l:option_index = l:option_index + 1
endif
" Fix relative paths if needed
if stridx(l:arg, s:sep) != 0 && stridx(l:arg, '/') != 0
let l:rel_path = substitute(l:arg, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:arg = ale#Escape(a:path_prefix . s:sep . l:rel_path)
endif
call add(l:cflags_list, l:option)
call add(l:cflags_list, l:arg)
" Options with arg that can be grouped with the option or separate
elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0
call add(l:cflags_list, l:option)
if l:option is# '-D' || l:option is# '-B'
call add(l:cflags_list, l:split_lines[l:option_index])
let l:option_index = l:option_index + 1
endif
" Options that have an argument (always separate)
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
\ || l:option is# '-isysroot' || l:option is# '-imultilib'
call add(l:cflags_list, l:option)
call add(l:cflags_list, l:split_lines[l:option_index])
let l:option_index = l:option_index + 1
" Options without argument
elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0)
\ || l:option is# '-w' || stridx(l:option, '-pedantic') == 0
\ || l:option is# '-ansi' || stridx(l:option, '-std=') == 0
\ || (stridx(l:option, '-f') == 0 && stridx(l:option, '-fdump') != 0 && stridx(l:option, '-fdiagnostics') != 0 && stridx(l:option, '-fno-show-column') != 0)
\ || stridx(l:option, '-O') == 0
\ || l:option is# '-C' || l:option is# '-CC' || l:option is# '-trigraphs'
\ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0
\ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix'
\ || stridx(l:option, '-m') == 0
call add(l:cflags_list, l:option)
endif
endwhile endwhile
call uniq(l:split_lines) return join(l:cflags_list, ' ')
return join(l:split_lines, ' ')
endfunction endfunction
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !g:ale_c_parse_makefile if !g:ale_c_parse_makefile
return '' return v:null
endif endif
let l:buffer_filename = expand('#' . a:buffer . ':t') let l:buffer_filename = expand('#' . a:buffer . ':t')
@ -140,14 +153,17 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line) return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line)
endfunction endfunction
" Given a buffer number, find the build subdirectory with compile commands " Given a buffer number, find the project directory containing
" The subdirectory is returned without the trailing / " compile_commands.json, and the path to the compile_commands.json file.
"
" If compile_commands.json cannot be found, two empty strings will be
" returned.
function! ale#c#FindCompileCommands(buffer) abort function! ale#c#FindCompileCommands(buffer) abort
" Look above the current source file to find compile_commands.json " Look above the current source file to find compile_commands.json
let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') let l:json_file = ale#path#FindNearestFile(a:buffer, 'compile_commands.json')
if !empty(l:json_file) if !empty(l:json_file)
return l:json_file return [fnamemodify(l:json_file, ':h'), l:json_file]
endif endif
" Search in build directories if we can't find it in the project. " Search in build directories if we can't find it in the project.
@ -157,12 +173,42 @@ function! ale#c#FindCompileCommands(buffer) abort
let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json' let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json'
if filereadable(l:json_file) if filereadable(l:json_file)
return l:json_file return [l:path, l:json_file]
endif endif
endfor endfor
endfor endfor
return '' return ['', '']
endfunction
" Find the project root for C/C++ projects.
"
" The location of compile_commands.json will be used to find project roots.
"
" If compile_commands.json cannot be found, other common configuration files
" will be used to detect the project root.
function! ale#c#FindProjectRoot(buffer) abort
let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
" Fall back on detecting the project root based on other filenames.
if empty(l:root)
for l:project_filename in g:__ale_c_project_filenames
let l:full_path = ale#path#FindNearestFile(a:buffer, l:project_filename)
if !empty(l:full_path)
let l:path = fnamemodify(l:full_path, ':h')
" Correct .git path detection.
if fnamemodify(l:path, ':t') is# '.git'
let l:path = fnamemodify(l:path, ':h')
endif
return l:path
endif
endfor
endif
return l:root
endfunction endfunction
" Cache compile_commands.json data in a Dictionary, so we don't need to read " Cache compile_commands.json data in a Dictionary, so we don't need to read
@ -194,10 +240,14 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:raw_data = [] let l:raw_data = []
silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), '')) silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), ''))
if type(l:raw_data) isnot v:t_list
let l:raw_data = []
endif
let l:file_lookup = {} let l:file_lookup = {}
let l:dir_lookup = {} let l:dir_lookup = {}
for l:entry in l:raw_data for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : [])
let l:basename = tolower(fnamemodify(l:entry.file, ':t')) let l:basename = tolower(fnamemodify(l:entry.file, ':t'))
let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry] let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry]
@ -274,25 +324,25 @@ function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort
endfunction endfunction
function! ale#c#GetCFlags(buffer, output) abort function! ale#c#GetCFlags(buffer, output) abort
let l:cflags = ' ' let l:cflags = v:null
if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output) if ale#Var(a:buffer, 'c_parse_makefile') && !empty(a:output)
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output) let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
endif endif
if ale#Var(a:buffer, 'c_parse_compile_commands') if ale#Var(a:buffer, 'c_parse_compile_commands')
let l:json_file = ale#c#FindCompileCommands(a:buffer) let [l:root, l:json_file] = ale#c#FindCompileCommands(a:buffer)
if !empty(l:json_file) if !empty(l:json_file)
let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file) let l:cflags = ale#c#FlagsFromCompileCommands(a:buffer, l:json_file)
endif endif
endif endif
if l:cflags is# ' ' if l:cflags is v:null
let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)) let l:cflags = ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))
endif endif
return l:cflags return l:cflags isnot v:null ? l:cflags : ''
endfunction endfunction
function! ale#c#GetMakeCommand(buffer) abort function! ale#c#GetMakeCommand(buffer) abort

View File

@ -52,6 +52,7 @@ let s:should_complete_map = {
\ 'lisp': s:lisp_regex, \ 'lisp': s:lisp_regex,
\ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|''$|"$', \ 'typescript': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|''$|"$',
\ 'rust': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$', \ 'rust': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$',
\ 'cpp': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$|\.$|::$|-\>$',
\} \}
" Regular expressions for finding the start column to replace with completion. " Regular expressions for finding the start column to replace with completion.
@ -59,11 +60,13 @@ let s:omni_start_map = {
\ '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$', \ '<default>': '\v[a-zA-Z$_][a-zA-Z$_0-9]*$',
\} \}
" A map of exact characters for triggering LSP completions. " A map of exact characters for triggering LSP completions. Do not forget to
" update self.input_patterns in ale.py in updating entries in this map.
let s:trigger_character_map = { let s:trigger_character_map = {
\ '<default>': ['.'], \ '<default>': ['.'],
\ 'typescript': ['.', '''', '"'], \ 'typescript': ['.', '''', '"'],
\ 'rust': ['.', '::'], \ 'rust': ['.', '::'],
\ 'cpp': ['.', '::', '->'],
\} \}
function! s:GetFiletypeValue(map, filetype) abort function! s:GetFiletypeValue(map, filetype) abort
@ -169,7 +172,7 @@ function! s:ReplaceCompletionOptions() abort
let b:ale_old_omnifunc = &l:omnifunc let b:ale_old_omnifunc = &l:omnifunc
endif endif
let &l:omnifunc = 'ale#completion#OmniFunc' let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
endif endif
if l:source is# 'ale-automatic' if l:source is# 'ale-automatic'
@ -215,19 +218,11 @@ function! ale#completion#GetCompletionPosition() abort
return l:column - len(l:match) - 1 return l:column - len(l:match) - 1
endfunction endfunction
function! ale#completion#GetCompletionPositionForDeoplete(input) abort
return match(a:input, '\k*$')
endfunction
function! ale#completion#GetCompletionResult() abort function! ale#completion#GetCompletionResult() abort
" Parse a new response if there is one.
if exists('b:ale_completion_response')
\&& exists('b:ale_completion_parser')
let l:response = b:ale_completion_response
let l:parser = b:ale_completion_parser
unlet b:ale_completion_response
unlet b:ale_completion_parser
let b:ale_completion_result = function(l:parser)(l:response)
endif
if exists('b:ale_completion_result') if exists('b:ale_completion_result')
return b:ale_completion_result return b:ale_completion_result
endif endif
@ -235,7 +230,7 @@ function! ale#completion#GetCompletionResult() abort
return v:null return v:null
endfunction endfunction
function! ale#completion#OmniFunc(findstart, base) abort function! ale#completion#AutomaticOmniFunc(findstart, base) abort
if a:findstart if a:findstart
return ale#completion#GetCompletionPosition() return ale#completion#GetCompletionPosition()
else else
@ -247,15 +242,20 @@ function! ale#completion#OmniFunc(findstart, base) abort
endif endif
endfunction endfunction
function! ale#completion#Show(response, completion_parser) abort function! ale#completion#Show(result) abort
if ale#util#Mode() isnot# 'i' if ale#util#Mode() isnot# 'i'
return return
endif endif
" Set the list in the buffer, temporarily replace omnifunc with our " Set the list in the buffer, temporarily replace omnifunc with our
" function, and then start omni-completion. " function, and then start omni-completion.
let b:ale_completion_response = a:response let b:ale_completion_result = a:result
let b:ale_completion_parser = a:completion_parser
" Don't try to open the completion menu if there's nothing to show.
if empty(b:ale_completion_result)
return
endif
" Replace completion options shortly before opening the menu. " Replace completion options shortly before opening the menu.
call s:ReplaceCompletionOptions() call s:ReplaceCompletionOptions()
@ -267,6 +267,14 @@ function! ale#completion#Show(response, completion_parser) abort
\ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")} \ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")}
\) \)
endif endif
if l:source is# 'ale-callback'
call b:CompleteCallback(b:ale_completion_result)
endif
endfunction
function! ale#completion#GetAllTriggers() abort
return deepcopy(s:trigger_character_map)
endfunction endfunction
function! s:CompletionStillValid(request_id) abort function! s:CompletionStillValid(request_id) abort
@ -279,6 +287,8 @@ function! s:CompletionStillValid(request_id) abort
\&& ( \&& (
\ b:ale_completion_info.column == l:column \ b:ale_completion_info.column == l:column
\ || b:ale_completion_info.source is# 'deoplete' \ || b:ale_completion_info.source is# 'deoplete'
\ || b:ale_completion_info.source is# 'ale-omnifunc'
\ || b:ale_completion_info.source is# 'ale-callback'
\) \)
endfunction endfunction
@ -474,8 +484,7 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
endif endif
elseif l:command is# 'completionEntryDetails' elseif l:command is# 'completionEntryDetails'
call ale#completion#Show( call ale#completion#Show(
\ a:response, \ ale#completion#ParseTSServerCompletionEntryDetails(a:response),
\ 'ale#completion#ParseTSServerCompletionEntryDetails',
\) \)
endif endif
endfunction endfunction
@ -487,8 +496,7 @@ function! ale#completion#HandleLSPResponse(conn_id, response) abort
endif endif
call ale#completion#Show( call ale#completion#Show(
\ a:response, \ ale#completion#ParseLSPCompletions(a:response),
\ 'ale#completion#ParseLSPCompletions',
\) \)
endfunction endfunction
@ -529,10 +537,7 @@ function! s:OnReady(linter, lsp_details) abort
let l:message = ale#lsp#message#Completion( let l:message = ale#lsp#message#Completion(
\ l:buffer, \ l:buffer,
\ b:ale_completion_info.line, \ b:ale_completion_info.line,
\ min([ \ b:ale_completion_info.column,
\ b:ale_completion_info.line_length,
\ b:ale_completion_info.column,
\ ]) + 1,
\ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix), \ ale#completion#GetTriggerCharacter(&filetype, b:ale_completion_info.prefix),
\) \)
endif endif
@ -564,13 +569,26 @@ endfunction
" This function can be used to manually trigger autocomplete, even when " This function can be used to manually trigger autocomplete, even when
" g:ale_completion_enabled is set to false " g:ale_completion_enabled is set to false
function! ale#completion#GetCompletions(source) abort function! ale#completion#GetCompletions(...) abort
let l:source = get(a:000, 0, '')
let l:options = get(a:000, 1, {})
if len(a:000) > 2
throw 'Too many arguments!'
endif
let l:CompleteCallback = get(l:options, 'callback', v:null)
if l:CompleteCallback isnot v:null
let b:CompleteCallback = l:CompleteCallback
endif
let [l:line, l:column] = getpos('.')[1:2] let [l:line, l:column] = getpos('.')[1:2]
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column) let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
if a:source is# 'ale-automatic' && empty(l:prefix) if l:source is# 'ale-automatic' && empty(l:prefix)
return return 0
endif endif
let l:line_length = len(getline('.')) let l:line_length = len(getline('.'))
@ -582,18 +600,47 @@ function! ale#completion#GetCompletions(source) abort
\ 'prefix': l:prefix, \ 'prefix': l:prefix,
\ 'conn_id': 0, \ 'conn_id': 0,
\ 'request_id': 0, \ 'request_id': 0,
\ 'source': a:source, \ 'source': l:source,
\} \}
unlet! b:ale_completion_result unlet! b:ale_completion_result
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:Callback = function('s:OnReady') let l:Callback = function('s:OnReady')
let l:started = 0
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)
call 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
endif
endif endif
endfor endfor
return l:started
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:started = ale#completion#GetCompletions('ale-omnifunc')
if !l:started
" This is the special value for cancelling completions silently.
" See :help complete-functions
return -3
endif
return ale#completion#GetCompletionPosition()
else
let l:result = ale#completion#GetCompletionResult()
while l:result is v:null && !complete_check()
sleep 2ms
let l:result = ale#completion#GetCompletionResult()
endwhile
return l:result isnot v:null ? l:result : []
endif
endfunction endfunction
function! s:TimerHandler(...) abort function! s:TimerHandler(...) abort

View File

@ -62,7 +62,7 @@ function! s:Echo(message) abort
execute 'echo a:message' execute 'echo a:message'
endfunction endfunction
function! s:GetLinterVariables(filetype, linter_names) abort function! s:GetLinterVariables(filetype, exclude_linter_names) abort
let l:variable_list = [] let l:variable_list = []
let l:filetype_parts = split(a:filetype, '\.') let l:filetype_parts = split(a:filetype, '\.')
@ -73,7 +73,7 @@ function! s:GetLinterVariables(filetype, linter_names) abort
" Include matching variables. " Include matching variables.
if !empty(l:match) if !empty(l:match)
\&& index(l:filetype_parts, l:match[1]) >= 0 \&& index(l:filetype_parts, l:match[1]) >= 0
\&& index(a:linter_names, l:match[2]) >= 0 \&& index(a:exclude_linter_names, l:match[2]) == -1
call add(l:variable_list, l:key) call add(l:variable_list, l:key)
endif endif
endfor endfor
@ -211,10 +211,11 @@ function! ale#debugging#Info() abort
let l:all_names = map(copy(l:all_linters), 'v:val[''name'']') let l:all_names = map(copy(l:all_linters), 'v:val[''name'']')
let l:enabled_names = map(copy(l:enabled_linters), 'v:val[''name'']') let l:enabled_names = map(copy(l:enabled_linters), 'v:val[''name'']')
let l:exclude_names = filter(copy(l:all_names), 'index(l:enabled_names, v:val) == -1')
" Load linter variables to display " Load linter variables to display
" This must be done after linters are loaded. " This must be done after linters are loaded.
let l:variable_list = s:GetLinterVariables(l:filetype, l:enabled_names) let l:variable_list = s:GetLinterVariables(l:filetype, l:exclude_names)
let l:fixers = ale#fix#registry#SuggestedFixers(l:filetype) let l:fixers = ale#fix#registry#SuggestedFixers(l:filetype)
let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1])) let l:fixers = uniq(sort(l:fixers[0] + l:fixers[1]))
@ -238,6 +239,12 @@ function! ale#debugging#Info() abort
endfunction endfunction
function! ale#debugging#InfoToClipboard() abort function! ale#debugging#InfoToClipboard() abort
if !has('clipboard')
call s:Echo('clipboard not available. Try :ALEInfoToFile instead.')
return
endif
redir => l:output redir => l:output
silent call ale#debugging#Info() silent call ale#debugging#Info()
redir END redir END

View File

@ -710,6 +710,10 @@ function! ale#engine#Cleanup(buffer) abort
return return
endif endif
if exists('*ale#lsp#CloseDocument')
call ale#lsp#CloseDocument(a:buffer)
endif
if !has_key(g:ale_buffer_info, a:buffer) if !has_key(g:ale_buffer_info, a:buffer)
return return
endif endif

View File

@ -128,7 +128,7 @@ function! ale#events#Init() abort
endif endif
if g:ale_lint_on_insert_leave if g:ale_lint_on_insert_leave
autocmd InsertLeave * call ale#Queue(0) autocmd InsertLeave * if ale#Var(str2nr(expand('<abuf>')), 'lint_on_insert_leave') | call ale#Queue(0) | endif
endif endif
if g:ale_echo_cursor || g:ale_cursor_detail if g:ale_echo_cursor || g:ale_cursor_detail

View File

@ -2,46 +2,60 @@ call ale#Set('fix_on_save_ignore', {})
" Apply fixes queued up for buffers which may be hidden. " Apply fixes queued up for buffers which may be hidden.
" Vim doesn't let you modify hidden buffers. " Vim doesn't let you modify hidden buffers.
function! ale#fix#ApplyQueuedFixes() abort function! ale#fix#ApplyQueuedFixes(buffer) abort
let l:buffer = bufnr('') let l:data = get(g:ale_fix_buffer_data, a:buffer, {'done': 0})
let l:data = get(g:ale_fix_buffer_data, l:buffer, {'done': 0}) let l:has_bufline_api = exists('*deletebufline') && exists('*setbufline')
if !l:data.done if !l:data.done || (!l:has_bufline_api && a:buffer isnot bufnr(''))
return return
endif endif
call remove(g:ale_fix_buffer_data, l:buffer) call remove(g:ale_fix_buffer_data, a:buffer)
if l:data.changes_made if l:data.changes_made
let l:start_line = len(l:data.output) + 1
let l:end_line = len(l:data.lines_before)
if l:end_line >= l:start_line
let l:save = winsaveview()
silent execute l:start_line . ',' . l:end_line . 'd_'
call winrestview(l:save)
endif
" If the file is in DOS mode, we have to remove carriage returns from " If the file is in DOS mode, we have to remove carriage returns from
" the ends of lines before calling setline(), or we will see them " the ends of lines before calling setline(), or we will see them
" twice. " twice.
let l:lines_to_set = getbufvar(l:buffer, '&fileformat') is# 'dos' let l:new_lines = getbufvar(a:buffer, '&fileformat') is# 'dos'
\ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')') \ ? map(copy(l:data.output), 'substitute(v:val, ''\r\+$'', '''', '''')')
\ : l:data.output \ : l:data.output
let l:first_line_to_remove = len(l:new_lines) + 1
call setline(1, l:lines_to_set) " Use a Vim API for setting lines in other buffers, if available.
if l:has_bufline_api
call setbufline(a:buffer, 1, l:new_lines)
call deletebufline(a:buffer, l:first_line_to_remove, '$')
" Fall back on setting lines the old way, for the current buffer.
else
let l:old_line_length = len(l:data.lines_before)
if l:old_line_length >= l:first_line_to_remove
let l:save = winsaveview()
silent execute
\ l:first_line_to_remove . ',' . l:old_line_length . 'd_'
call winrestview(l:save)
endif
call setline(1, l:new_lines)
endif
if l:data.should_save if l:data.should_save
if empty(&buftype) if a:buffer is bufnr('')
noautocmd :w! if empty(&buftype)
noautocmd :w!
else
set nomodified
endif
else else
set nomodified call writefile(l:new_lines, expand(a:buffer . ':p')) " no-custom-checks
call setbufvar(a:buffer, '&modified', 0)
endif endif
endif endif
endif endif
if l:data.should_save if l:data.should_save
let l:should_lint = g:ale_fix_on_save let l:should_lint = ale#Var(a:buffer, 'fix_on_save')
\ && ale#Var(a:buffer, 'lint_on_save')
else else
let l:should_lint = l:data.changes_made let l:should_lint = l:data.changes_made
endif endif
@ -52,7 +66,7 @@ function! ale#fix#ApplyQueuedFixes() abort
" fixing problems. " fixing problems.
if g:ale_enabled if g:ale_enabled
\&& l:should_lint \&& l:should_lint
\&& !ale#events#QuitRecently(l:buffer) \&& !ale#events#QuitRecently(a:buffer)
call ale#Queue(0, l:data.should_save ? 'lint_file' : '') call ale#Queue(0, l:data.should_save ? 'lint_file' : '')
endif endif
endfunction endfunction
@ -83,7 +97,7 @@ function! ale#fix#ApplyFixes(buffer, output) abort
" We can only change the lines of a buffer which is currently open, " We can only change the lines of a buffer which is currently open,
" so try and apply the fixes to the current buffer. " so try and apply the fixes to the current buffer.
call ale#fix#ApplyQueuedFixes() call ale#fix#ApplyQueuedFixes(a:buffer)
endfunction endfunction
function! s:HandleExit(job_info, buffer, job_output, data) abort function! s:HandleExit(job_info, buffer, job_output, data) abort
@ -399,5 +413,4 @@ endfunction
" Set up an autocmd command to try and apply buffer fixes when available. " Set up an autocmd command to try and apply buffer fixes when available.
augroup ALEBufferFixGroup augroup ALEBufferFixGroup
autocmd! autocmd!
autocmd BufEnter * call ale#fix#ApplyQueuedFixes() autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
augroup END

View File

@ -115,6 +115,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['scala'], \ 'suggested_filetypes': ['scala'],
\ 'description': 'Fix Scala files using scalafmt', \ 'description': 'Fix Scala files using scalafmt',
\ }, \ },
\ 'sorbet': {
\ 'function': 'ale#fixers#sorbet#Fix',
\ 'suggested_filetypes': ['ruby'],
\ 'description': 'Fix ruby files with srb tc --autocorrect.',
\ },
\ 'standard': { \ 'standard': {
\ 'function': 'ale#fixers#standard#Fix', \ 'function': 'ale#fixers#standard#Fix',
\ 'suggested_filetypes': ['javascript'], \ 'suggested_filetypes': ['javascript'],
@ -145,6 +150,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['php'], \ 'suggested_filetypes': ['php'],
\ 'description': 'Fix PHP files with php-cs-fixer.', \ 'description': 'Fix PHP files with php-cs-fixer.',
\ }, \ },
\ 'clangtidy': {
\ 'function': 'ale#fixers#clangtidy#Fix',
\ 'suggested_filetypes': ['c', 'cpp', 'objc'],
\ 'description': 'Fix C/C++ and ObjectiveC files with clang-tidy.',
\ },
\ 'clang-format': { \ 'clang-format': {
\ 'function': 'ale#fixers#clangformat#Fix', \ 'function': 'ale#fixers#clangformat#Fix',
\ 'suggested_filetypes': ['c', 'cpp', 'cuda'], \ 'suggested_filetypes': ['c', 'cpp', 'cuda'],
@ -205,6 +215,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['haskell'], \ 'suggested_filetypes': ['haskell'],
\ 'description': 'Fix Haskell files with brittany.', \ 'description': 'Fix Haskell files with brittany.',
\ }, \ },
\ 'hindent': {
\ 'function': 'ale#fixers#hindent#Fix',
\ 'suggested_filetypes': ['haskell'],
\ 'description': 'Fix Haskell files with hindent.',
\ },
\ 'hlint': { \ 'hlint': {
\ 'function': 'ale#fixers#hlint#Fix', \ 'function': 'ale#fixers#hlint#Fix',
\ 'suggested_filetypes': ['haskell'], \ 'suggested_filetypes': ['haskell'],
@ -297,7 +312,7 @@ let s:default_registry = {
\ }, \ },
\ 'styler': { \ 'styler': {
\ 'function': 'ale#fixers#styler#Fix', \ 'function': 'ale#fixers#styler#Fix',
\ 'suggested_filetypes': ['r'], \ 'suggested_filetypes': ['r', 'rmarkdown'],
\ 'description': 'Fix R files with styler.', \ 'description': 'Fix R files with styler.',
\ }, \ },
\ 'latexindent': { \ 'latexindent': {
@ -305,6 +320,21 @@ let s:default_registry = {
\ 'suggested_filetypes': ['tex'], \ 'suggested_filetypes': ['tex'],
\ 'description' : 'Indent code within environments, commands, after headings and within special code blocks.', \ 'description' : 'Indent code within environments, commands, after headings and within special code blocks.',
\ }, \ },
\ 'pgformatter': {
\ 'function': 'ale#fixers#pgformatter#Fix',
\ 'suggested_filetypes': ['sql'],
\ 'description': 'A PostgreSQL SQL syntax beautifier',
\ },
\ 'reorder-python-imports': {
\ 'function': 'ale#fixers#reorder_python_imports#Fix',
\ 'suggested_filetypes': ['python'],
\ 'description': 'Sort Python imports with reorder-python-imports.',
\ },
\ 'gnatpp': {
\ 'function': 'ale#fixers#gnatpp#Fix',
\ 'suggested_filetypes': ['ada'],
\ 'description': 'Format Ada files with gnatpp.',
\ },
\} \}
" Reset the function registry to the default entries. " Reset the function registry to the default entries.

View File

@ -29,6 +29,10 @@ function! ale#fixers#black#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'python_black_options') let l:options = ale#Var(a:buffer, 'python_black_options')
if expand('#' . a:buffer . ':e') is? 'pyi'
let l:options .= '--pyi'
endif
return { return {
\ 'command': l:cd_string . ale#Escape(l:executable) . l:exec_args \ 'command': l:cd_string . ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')

View File

@ -13,10 +13,15 @@ function! ale#fixers#clangformat#GetExecutable(buffer) abort
endfunction endfunction
function! ale#fixers#clangformat#Fix(buffer) abort function! ale#fixers#clangformat#Fix(buffer) abort
let l:executable = ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer))
let l:filename = ale#Escape(bufname(a:buffer))
let l:options = ale#Var(a:buffer, 'c_clangformat_options') let l:options = ale#Var(a:buffer, 'c_clangformat_options')
return { let l:command = l:executable . ' --assume-filename=' . l:filename
\ 'command': ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer))
\ . ' ' . l:options, if l:options isnot# ''
\} let l:command .= ' ' . l:options
endif
return {'command': l:command}
endfunction endfunction

View File

@ -0,0 +1,52 @@
scriptencoding utf-8
" Author: ObserverOfTime <chronobserver@disroot.org>
" Description: Fixing C/C++ files with clang-tidy.
function! s:set_variables() abort
let l:use_global = get(g:, 'ale_use_global_executables', 0)
for l:ft in ['c', 'cpp']
call ale#Set(l:ft . '_clangtidy_executable', 'clang-tidy')
call ale#Set(l:ft . '_clangtidy_use_global', l:use_global)
call ale#Set(l:ft . '_clangtidy_checks', [])
call ale#Set(l:ft . '_clangtidy_options', '')
call ale#Set(l:ft . '_clangtidy_extra_options', '')
call ale#Set(l:ft . '_clangtidy_fix_errors', 1)
endfor
call ale#Set('c_build_dir', '')
endfunction
call s:set_variables()
function! ale#fixers#clangtidy#Var(buffer, name) abort
let l:ft = getbufvar(str2nr(a:buffer), '&filetype')
let l:ft = l:ft =~# 'cpp' ? 'cpp' : 'c'
return ale#Var(a:buffer, l:ft . '_clangtidy_' . a:name)
endfunction
function! ale#fixers#clangtidy#GetCommand(buffer) abort
let l:checks = join(ale#fixers#clangtidy#Var(a:buffer, 'checks'), ',')
let l:extra_options = ale#fixers#clangtidy#Var(a:buffer, 'extra_options')
let l:build_dir = ale#c#GetBuildDirectory(a:buffer)
let l:options = empty(l:build_dir)
\ ? ale#fixers#clangtidy#Var(a:buffer, 'options') : ''
let l:fix_errors = ale#fixers#clangtidy#Var(a:buffer, 'fix_errors')
return ' -fix' . (l:fix_errors ? ' -fix-errors' : '')
\ . (empty(l:checks) ? '' : ' -checks=' . ale#Escape(l:checks))
\ . (empty(l:extra_options) ? '' : ' ' . l:extra_options)
\ . (empty(l:build_dir) ? '' : ' -p ' . ale#Escape(l:build_dir))
\ . ' %t' . (empty(l:options) ? '' : ' -- ' . l:options)
endfunction
function! ale#fixers#clangtidy#Fix(buffer) abort
let l:executable = ale#fixers#clangtidy#Var(a:buffer, 'executable')
let l:command = ale#fixers#clangtidy#GetCommand(a:buffer)
return {
\ 'command': ale#Escape(l:executable) . l:command,
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -35,9 +35,18 @@ endfunction
function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) let l:executable = ale#handlers#eslint#GetExecutable(a:buffer)
let l:config = ale#handlers#eslint#FindConfig(a:buffer) let l:options = ale#Var(a:buffer, 'javascript_eslint_options')
if empty(l:config) " Use the configuration file from the options, if configured.
if l:options =~# '\v(^| )-c|(^| )--config'
let l:config = ''
let l:has_config = 1
else
let l:config = ale#handlers#eslint#FindConfig(a:buffer)
let l:has_config = !empty(l:config)
endif
if !l:has_config
return 0 return 0
endif endif
@ -45,6 +54,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0]) if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0])
return { return {
\ 'command': ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ale#Pad(l:options)
\ . ' --stdin-filename %s --stdin --fix-to-stdout', \ . ' --stdin-filename %s --stdin --fix-to-stdout',
\ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput',
\} \}
@ -54,6 +64,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
if ale#semver#GTE(a:version, [4, 9, 0]) if ale#semver#GTE(a:version, [4, 9, 0])
return { return {
\ 'command': ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ale#Pad(l:options)
\ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json',
\ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput',
\} \}
@ -61,7 +72,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
return { return {
\ 'command': ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ' -c ' . ale#Escape(l:config) \ . ale#Pad(l:options)
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
\ . ' --fix %t', \ . ' --fix %t',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\} \}

View File

@ -0,0 +1,17 @@
" Author: tim <tim@inept.tech>
" Description: Fix files with gnatpp.
call ale#Set('ada_gnatpp_executable', 'gnatpp')
call ale#Set('ada_gnatpp_options', '')
function! ale#fixers#gnatpp#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'ada_gnatpp_executable')
let l:options = ale#Var(a:buffer, 'ada_gnatpp_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -7,9 +7,10 @@ call ale#Set('go_gofmt_options', '')
function! ale#fixers#gofmt#Fix(buffer) abort function! ale#fixers#gofmt#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'go_gofmt_executable') let l:executable = ale#Var(a:buffer, 'go_gofmt_executable')
let l:options = ale#Var(a:buffer, 'go_gofmt_options') let l:options = ale#Var(a:buffer, 'go_gofmt_options')
let l:env = ale#go#EnvString(a:buffer)
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': l:env . ale#Escape(l:executable)
\ . ' -l -w' \ . ' -l -w'
\ . (empty(l:options) ? '' : ' ' . l:options) \ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t', \ . ' %t',

View File

@ -7,13 +7,14 @@ call ale#Set('go_goimports_options', '')
function! ale#fixers#goimports#Fix(buffer) abort function! ale#fixers#goimports#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'go_goimports_executable') let l:executable = ale#Var(a:buffer, 'go_goimports_executable')
let l:options = ale#Var(a:buffer, 'go_goimports_options') let l:options = ale#Var(a:buffer, 'go_goimports_options')
let l:env = ale#go#EnvString(a:buffer)
if !executable(l:executable) if !executable(l:executable)
return 0 return 0
endif endif
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': l:env . ale#Escape(l:executable)
\ . ' -l -w -srcdir %s' \ . ' -l -w -srcdir %s'
\ . (empty(l:options) ? '' : ' ' . l:options) \ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t', \ . ' %t',

View File

@ -2,9 +2,10 @@ call ale#Set('go_go_executable', 'go')
function! ale#fixers#gomod#Fix(buffer) abort function! ale#fixers#gomod#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'go_go_executable') let l:executable = ale#Var(a:buffer, 'go_go_executable')
let l:env = ale#go#EnvString(a:buffer)
return { return {
\ 'command': ale#Escape(l:executable) . ' mod edit -fmt %t', \ 'command': l:env . ale#Escape(l:executable) . ' mod edit -fmt %t',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\} \}
endfunction endfunction

View File

@ -0,0 +1,20 @@
" Author: AlexeiDrake <drake.alexei@gmail.com>
" Description: Integration of hindent formatting with ALE.
"
call ale#Set('haskell_hindent_executable', 'hindent')
function! ale#fixers#hindent#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'haskell_hindent_executable')
return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'hindent')
endfunction
function! ale#fixers#hindent#Fix(buffer) abort
let l:executable = ale#fixers#hindent#GetExecutable(a:buffer)
return {
\ 'command': l:executable
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -0,0 +1,12 @@
call ale#Set('sql_pgformatter_executable', 'pg_format')
call ale#Set('sql_pgformatter_options', '')
function! ale#fixers#pgformatter#Fix(buffer) abort
let l:executable = ale#Var(a:buffer, 'sql_pgformatter_executable')
let l:options = ale#Var(a:buffer, 'sql_pgformatter_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options),
\}
endfunction

View File

@ -39,9 +39,15 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
let l:options = ale#Var(a:buffer, 'javascript_prettier_options') let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
let l:parser = '' let l:parser = ''
let l:filetypes = split(getbufvar(a:buffer, '&filetype'), '\.')
if index(l:filetypes, 'handlebars') > -1
let l:parser = 'glimmer'
endif
" Append the --parser flag depending on the current filetype (unless it's " Append the --parser flag depending on the current filetype (unless it's
" already set in g:javascript_prettier_options). " already set in g:javascript_prettier_options).
if empty(expand('#' . a:buffer . ':e')) && match(l:options, '--parser') == -1 if empty(expand('#' . a:buffer . ':e')) && l:parser is# '' && match(l:options, '--parser') == -1
" Mimic Prettier's defaults. In cases without a file extension or " Mimic Prettier's defaults. In cases without a file extension or
" filetype (scratch buffer), Prettier needs `parser` set to know how " filetype (scratch buffer), Prettier needs `parser` set to know how
" to process the buffer. " to process the buffer.
@ -65,7 +71,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
\ 'html': 'html', \ 'html': 'html',
\} \}
for l:filetype in split(getbufvar(a:buffer, '&filetype'), '\.') for l:filetype in l:filetypes
if has_key(l:prettier_parsers, l:filetype) if has_key(l:prettier_parsers, l:filetype)
let l:parser = l:prettier_parsers[l:filetype] let l:parser = l:prettier_parsers[l:filetype]
break break

View File

@ -0,0 +1,25 @@
" Author: jake <me@jake.computer>
" Description: Fixing Python imports with reorder-python-imports.
call ale#Set('python_reorder_python_imports_executable', 'reorder-python-imports')
call ale#Set('python_reorder_python_imports_options', '')
call ale#Set('python_reorder_python_imports_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale#fixers#reorder_python_imports#Fix(buffer) abort
let l:executable = ale#python#FindExecutable(
\ a:buffer,
\ 'python_reorder_python_imports',
\ ['reorder-python-imports'],
\)
if !executable(l:executable)
return 0
endif
let l:options = ale#Var(a:buffer, 'python_reorder_python_imports_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') . ' -',
\}
endfunction

View File

@ -0,0 +1,19 @@
call ale#Set('ruby_sorbet_executable', 'srb')
call ale#Set('ruby_sorbet_options', '')
function! ale#fixers#sorbet#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'ruby_sorbet_executable')
let l:options = ale#Var(a:buffer, 'ruby_sorbet_options')
return ale#handlers#ruby#EscapeExecutable(l:executable, 'srb')
\ . ' tc'
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --autocorrect --file %t'
endfunction
function! ale#fixers#sorbet#Fix(buffer) abort
return {
\ 'command': ale#fixers#sorbet#GetCommand(a:buffer),
\ 'read_temporary_file': 1,
\}
endfunction

View File

@ -25,3 +25,20 @@ function! ale#go#FindProjectRoot(buffer) abort
return '' return ''
endfunction endfunction
call ale#Set('go_go111module', '')
" Return a string setting Go-specific environment variables
function! ale#go#EnvString(buffer) abort
let l:env = ''
" GO111MODULE - turn go modules behavior on/off
let l:go111module = ale#Var(a:buffer, 'go_go111module')
if !empty(l:go111module)
let l:env = ale#Env('GO111MODULE', l:go111module) . l:env
endif
return l:env
endfunction

View File

@ -3,15 +3,17 @@ scriptencoding utf-8
" Description: Utilities for ccls " Description: Utilities for ccls
function! ale#handlers#ccls#GetProjectRoot(buffer) abort function! ale#handlers#ccls#GetProjectRoot(buffer) abort
let l:project_root = ale#path#FindNearestFile(a:buffer, '.ccls-root') " Try to find ccls configuration files first.
let l:config = ale#path#FindNearestFile(a:buffer, '.ccls-root')
if empty(l:project_root) if empty(l:config)
let l:project_root = ale#path#FindNearestFile(a:buffer, 'compile_commands.json') let l:config = ale#path#FindNearestFile(a:buffer, '.ccls')
endif endif
if empty(l:project_root) if !empty(l:config)
let l:project_root = ale#path#FindNearestFile(a:buffer, '.ccls') return fnamemodify(l:config, ':h')
endif endif
return !empty(l:project_root) ? fnamemodify(l:project_root, ':h') : '' " Fall back on default project root detection.
return ale#c#FindProjectRoot(a:buffer)
endfunction endfunction

View File

@ -1,5 +1,46 @@
" Description: Handle errors for cppcheck. " Description: Handle errors for cppcheck.
function! ale#handlers#cppcheck#GetCdCommand(buffer) abort
let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer)
let l:cd_command = !empty(l:dir) ? ale#path#CdString(l:dir) : ''
return l:cd_command
endfunction
function! ale#handlers#cppcheck#GetBufferPathIncludeOptions(buffer) abort
let l:buffer_path_include = ''
" Get path to this buffer so we can include it into cppcheck with -I
" This could be expanded to get more -I directives from the compile
" command in compile_commands.json, if it's found.
let l:buffer_path = fnamemodify(bufname(a:buffer), ':p:h')
let l:buffer_path_include = ' -I' . ale#Escape(l:buffer_path)
return l:buffer_path_include
endfunction
function! ale#handlers#cppcheck#GetCompileCommandsOptions(buffer) abort
" If the current buffer is modified, using compile_commands.json does no
" good, so include the file's directory instead. It's not quite as good as
" using --project, but is at least equivalent to running cppcheck on this
" file manually from the file's directory.
let l:modified = getbufvar(a:buffer, '&modified')
if l:modified
return ''
endif
" Search upwards from the file for compile_commands.json.
"
" If we find it, we'll `cd` to where the compile_commands.json file is,
" then use the file to set up import paths, etc.
let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer)
return !empty(l:json_path)
\ ? '--project=' . ale#Escape(l:json_path[len(l:dir) + 1: ])
\ : ''
endfunction
function! ale#handlers#cppcheck#HandleCppCheckFormat(buffer, lines) abort function! ale#handlers#cppcheck#HandleCppCheckFormat(buffer, lines) abort
" Look for lines like the following. " Look for lines like the following.
" "

View File

@ -44,16 +44,9 @@ function! ale#handlers#eslint#GetCommand(buffer) abort
return ale#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -f unix --stdin --stdin-filename %s' \ . ' -f json --stdin --stdin-filename %s'
endfunction endfunction
let s:col_end_patterns = [
\ '\vParsing error: Unexpected token (.+) ?',
\ '\v''(.+)'' is not defined.',
\ '\v%(Unexpected|Redundant use of) [''`](.+)[''`]',
\ '\vUnexpected (console) statement',
\]
function! s:AddHintsForTypeScriptParsingErrors(output) abort function! s:AddHintsForTypeScriptParsingErrors(output) abort
for l:item in a:output for l:item in a:output
let l:item.text = substitute( let l:item.text = substitute(
@ -90,22 +83,71 @@ function! s:CheckForBadConfig(buffer, lines) abort
return 0 return 0
endfunction endfunction
function! ale#handlers#eslint#Handle(buffer, lines) abort function! s:parseJSON(buffer, lines) abort
if s:CheckForBadConfig(a:buffer, a:lines) try
return [{ let l:parsed = json_decode(a:lines[-1])
\ 'lnum': 1, catch
\ 'text': 'eslint configuration error (type :ALEDetail for more information)', return []
\ 'detail': join(a:lines, "\n"), endtry
\}]
if type(l:parsed) != v:t_list || empty(l:parsed)
return []
endif endif
if a:lines == ['Could not connect'] let l:errors = l:parsed[0]['messages']
return [{
\ 'lnum': 1, if empty(l:errors)
\ 'text': 'Could not connect to eslint_d. Try updating eslint_d or killing it.', return []
\}]
endif endif
let l:output = []
for l:error in l:errors
let l:obj = ({
\ 'lnum': get(l:error, 'line', 0),
\ 'text': get(l:error, 'message', ''),
\ 'type': 'E',
\})
if get(l:error, 'severity', 0) is# 1
let l:obj.type = 'W'
endif
if has_key(l:error, 'ruleId')
let l:code = l:error['ruleId']
" Sometimes ESLint returns null here
if !empty(l:code)
let l:obj.code = l:code
endif
endif
if has_key(l:error, 'column')
let l:obj.col = l:error['column']
endif
if has_key(l:error, 'endColumn')
let l:obj.end_col = l:error['endColumn'] - 1
endif
if has_key(l:error, 'endLine')
let l:obj.end_lnum = l:error['endLine']
endif
call add(l:output, l:obj)
endfor
return l:output
endfunction
let s:col_end_patterns = [
\ '\vParsing error: Unexpected token (.+) ?',
\ '\v''(.+)'' is not defined.',
\ '\v%(Unexpected|Redundant use of) [''`](.+)[''`]',
\ '\vUnexpected (console) statement',
\]
function! s:parseLines(buffer, lines) abort
" Matches patterns line the following: " Matches patterns line the following:
" "
" /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle] " /path/to/some-filename.js:47:14: Missing trailing comma. [Warning/comma-dangle]
@ -120,12 +162,6 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort
for l:match in ale#util#GetMatches(a:lines, [l:pattern, l:parsing_pattern]) for l:match in ale#util#GetMatches(a:lines, [l:pattern, l:parsing_pattern])
let l:text = l:match[3] let l:text = l:match[3]
if ale#Var(a:buffer, 'javascript_eslint_suppress_eslintignore')
if l:text =~# '^File ignored'
continue
endif
endif
let l:obj = { let l:obj = {
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0, \ 'col': l:match[2] + 0,
@ -143,11 +179,6 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort
" The code can be something like 'Error/foo/bar', or just 'Error' " The code can be something like 'Error/foo/bar', or just 'Error'
if !empty(get(l:split_code, 1)) if !empty(get(l:split_code, 1))
let l:obj.code = join(l:split_code[1:], '/') let l:obj.code = join(l:split_code[1:], '/')
if l:obj.code is# 'no-trailing-spaces'
\&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
continue
endif
endif endif
for l:col_match in ale#util#GetMatches(l:text, s:col_end_patterns) for l:col_match in ale#util#GetMatches(l:text, s:col_end_patterns)
@ -157,9 +188,59 @@ function! ale#handlers#eslint#Handle(buffer, lines) abort
call add(l:output, l:obj) call add(l:output, l:obj)
endfor endfor
return l:output
endfunction
function! s:FilterResult(buffer, obj) abort
if ale#Var(a:buffer, 'javascript_eslint_suppress_eslintignore')
if a:obj.text =~# '^File ignored'
return 0
endif
endif
if has_key(a:obj, 'code') && a:obj.code is# 'no-trailing-spaces'
\&& !ale#Var(a:buffer, 'warn_about_trailing_whitespace')
return 0
endif
return 1
endfunction
function! s:HandleESLintOutput(buffer, lines, type) abort
if s:CheckForBadConfig(a:buffer, a:lines)
return [{
\ 'lnum': 1,
\ 'text': 'eslint configuration error (type :ALEDetail for more information)',
\ 'detail': join(a:lines, "\n"),
\}]
endif
if a:lines == ['Could not connect']
return [{
\ 'lnum': 1,
\ 'text': 'Could not connect to eslint_d. Try updating eslint_d or killing it.',
\}]
endif
if a:type is# 'json'
let l:output = s:parseJSON(a:buffer, a:lines)
else
let l:output = s:parseLines(a:buffer, a:lines)
endif
call filter(l:output, {idx, obj -> s:FilterResult(a:buffer, obj)})
if expand('#' . a:buffer . ':t') =~? '\.tsx\?$' if expand('#' . a:buffer . ':t') =~? '\.tsx\?$'
call s:AddHintsForTypeScriptParsingErrors(l:output) call s:AddHintsForTypeScriptParsingErrors(l:output)
endif endif
return l:output return l:output
endfunction endfunction
function! ale#handlers#eslint#HandleJSON(buffer, lines) abort
return s:HandleESLintOutput(a:buffer, a:lines, 'json')
endfunction
function! ale#handlers#eslint#Handle(buffer, lines) abort
return s:HandleESLintOutput(a:buffer, a:lines, 'lines')
endfunction

View File

@ -11,6 +11,7 @@ let s:pragma_error = '#pragma once in main file'
" <stdin>:10:27: error: invalid operands to binary - (have int and char *) " <stdin>:10:27: error: invalid operands to binary - (have int and char *)
" -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004] " -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004]
let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$' let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$'
let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$'
function! s:IsHeaderFile(filename) abort function! s:IsHeaderFile(filename) abort
return a:filename =~? '\v\.(h|hpp)$' return a:filename =~? '\v\.(h|hpp)$'
@ -25,6 +26,28 @@ function! s:RemoveUnicodeQuotes(text) abort
return l:text return l:text
endfunction endfunction
function! s:ParseInlinedFunctionProblems(buffer, lines) abort
let l:output = []
let l:pos_match = []
for l:line in a:lines
let l:match = matchlist(l:line, s:pattern)
if !empty(l:match) && !empty(l:pos_match)
call add(l:output, {
\ 'lnum': str2nr(l:pos_match[1]),
\ 'col': str2nr(l:pos_match[2]),
\ 'type': (l:match[4] is# 'error' || l:match[4] is# 'fatal error') ? 'E' : 'W',
\ 'text': s:RemoveUnicodeQuotes(l:match[5]),
\})
endif
let l:pos_match = matchlist(l:line, s:inline_pattern)
endfor
return l:output
endfunction
" Report problems inside of header files just for gcc and clang " Report problems inside of header files just for gcc and clang
function! s:ParseProblemsInHeaders(buffer, lines) abort function! s:ParseProblemsInHeaders(buffer, lines) abort
let l:output = [] let l:output = []
@ -129,6 +152,7 @@ endfunction
function! ale#handlers#gcc#HandleGCCFormatWithIncludes(buffer, lines) abort function! ale#handlers#gcc#HandleGCCFormatWithIncludes(buffer, lines) abort
let l:output = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines) let l:output = ale#handlers#gcc#HandleGCCFormat(a:buffer, a:lines)
call extend(l:output, s:ParseInlinedFunctionProblems(a:buffer, a:lines))
call extend(l:output, s:ParseProblemsInHeaders(a:buffer, a:lines)) call extend(l:output, s:ParseProblemsInHeaders(a:buffer, a:lines))
return l:output return l:output

View File

@ -56,14 +56,20 @@ function! ale#handlers#rust#HandleRustErrors(buffer, lines) abort
endif endif
if !empty(l:span) if !empty(l:span)
call add(l:output, { let l:output_line = {
\ 'lnum': l:span.line_start, \ 'lnum': l:span.line_start,
\ 'end_lnum': l:span.line_end, \ 'end_lnum': l:span.line_end,
\ 'col': l:span.column_start, \ 'col': l:span.column_start,
\ 'end_col': l:span.column_end-1, \ 'end_col': l:span.column_end-1,
\ 'text': empty(l:span.label) ? l:error.message : printf('%s: %s', l:error.message, l:span.label), \ 'text': empty(l:span.label) ? l:error.message : printf('%s: %s', l:error.message, l:span.label),
\ 'type': toupper(l:error.level[0]), \ 'type': toupper(l:error.level[0]),
\}) \}
if has_key(l:error, 'rendered') && !empty(l:error.rendered)
let l:output_line.detail = l:error.rendered
endif
call add(l:output, l:output_line)
endif endif
endfor endfor
endfor endfor

View File

@ -26,41 +26,6 @@ endif
let s:MAX_POS_VALUES = 8 let s:MAX_POS_VALUES = 8
let s:MAX_COL_SIZE = 1073741824 " pow(2, 30) let s:MAX_COL_SIZE = 1073741824 " pow(2, 30)
" Check if we have neovim's buffer highlight API
"
" Below we define some functions' implementation conditionally if this API
" exists or not.
"
" The API itself is more ergonomic and neovim performs highlights positions
" rebases during edits so we see less stalled highlights.
let s:nvim_api = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace')
function! ale#highlight#HasNeovimApi() abort
return s:nvim_api
endfunction
function! ale#highlight#nvim_buf_clear_namespace(...) abort
return call('nvim_buf_clear_namespace', a:000)
endfunction
function! ale#highlight#nvim_buf_add_highlight(...) abort
return call('nvim_buf_add_highlight', a:000)
endfunction
function! s:ale_nvim_highlight_id(bufnr) abort
let l:id = getbufvar(a:bufnr, 'ale_nvim_highlight_id', -1)
if l:id is -1
" NOTE: This will highlight nothing but will allocate new id
let l:id = ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, 0, '', 0, 0, -1
\)
call setbufvar(a:bufnr, 'ale_nvim_highlight_id', l:id)
endif
return l:id
endfunction
function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort function! ale#highlight#CreatePositions(line, col, end_line, end_col) abort
if a:line >= a:end_line if a:line >= a:end_line
" For single lines, just return the one position. " For single lines, just return the one position.
@ -86,88 +51,29 @@ endfunction
" except these which have matching loclist item entries. " except these which have matching loclist item entries.
function! ale#highlight#RemoveHighlights() abort function! ale#highlight#RemoveHighlights() abort
if ale#highlight#HasNeovimApi() for l:match in getmatches()
if get(b:, 'ale_nvim_highlight_id', 0) if l:match.group =~? '\v^ALE(Style)?(Error|Warning|Info)(Line)?$'
let l:bufnr = bufnr('%') call matchdelete(l:match.id)
" NOTE: 0, -1 means from 0 line till the end of buffer
call ale#highlight#nvim_buf_clear_namespace(
\ l:bufnr,
\ b:ale_nvim_highlight_id,
\ 0, -1
\)
endif endif
else endfor
for l:match in getmatches()
if l:match.group =~# '^ALE'
call matchdelete(l:match.id)
endif
endfor
endif
endfunction endfunction
function! s:highlight_line(bufnr, lnum, group) abort function! s:highlight_line(bufnr, lnum, group) abort
if ale#highlight#HasNeovimApi() call matchaddpos(a:group, [a:lnum])
let l:highlight_id = s:ale_nvim_highlight_id(a:bufnr)
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ a:lnum - 1, 0, -1
\)
else
call matchaddpos(a:group, [a:lnum])
endif
endfunction endfunction
function! s:highlight_range(bufnr, range, group) abort function! s:highlight_range(bufnr, range, group) abort
if ale#highlight#HasNeovimApi() " Set all of the positions, which are chunked into Lists which
let l:highlight_id = s:ale_nvim_highlight_id(a:bufnr) " are as large as will be accepted by matchaddpos.
" NOTE: lines and columns indicies are 0-based in nvim_buf_* API. call map(
let l:lnum = a:range.lnum - 1 \ ale#highlight#CreatePositions(
let l:end_lnum = a:range.end_lnum - 1 \ a:range.lnum,
let l:col = a:range.col - 1 \ a:range.col,
let l:end_col = a:range.end_col \ a:range.end_lnum,
\ a:range.end_col
if l:lnum >= l:end_lnum \ ),
" For single lines, just return the one position. \ 'matchaddpos(a:group, v:val)'
call ale#highlight#nvim_buf_add_highlight( \)
\ a:bufnr, l:highlight_id, a:group,
\ l:lnum, l:col, l:end_col
\)
else
" highlight first line from start till the line end
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ l:lnum, l:col, -1
\)
" highlight all lines between the first and last entirely
let l:cur = l:lnum + 1
while l:cur < l:end_lnum
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ l:cur, 0, -1
\ )
let l:cur += 1
endwhile
call ale#highlight#nvim_buf_add_highlight(
\ a:bufnr, l:highlight_id, a:group,
\ l:end_lnum, 0, l:end_col
\)
endif
else
" Set all of the positions, which are chunked into Lists which
" are as large as will be accepted by matchaddpos.
call map(
\ ale#highlight#CreatePositions(
\ a:range.lnum,
\ a:range.col,
\ a:range.end_lnum,
\ a:range.end_col
\ ),
\ 'matchaddpos(a:group, v:val)'
\)
endif
endfunction endfunction
function! ale#highlight#UpdateHighlights() abort function! ale#highlight#UpdateHighlights() abort

View File

@ -16,5 +16,11 @@ function! ale#java#FindProjectRoot(buffer) abort
return fnamemodify(l:maven_pom_file, ':h') return fnamemodify(l:maven_pom_file, ':h')
endif endif
let l:ant_root = ale#ant#FindProjectRoot(a:buffer)
if !empty(l:ant_root)
return l:ant_root
endif
return '' return ''
endfunction endfunction

View File

@ -13,10 +13,13 @@ let s:default_ale_linter_aliases = {
\ 'Dockerfile': 'dockerfile', \ 'Dockerfile': 'dockerfile',
\ 'csh': 'sh', \ 'csh': 'sh',
\ 'plaintex': 'tex', \ 'plaintex': 'tex',
\ 'rmarkdown': 'r',
\ 'systemverilog': 'verilog', \ 'systemverilog': 'verilog',
\ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'], \ 'verilog_systemverilog': ['verilog_systemverilog', 'verilog'],
\ 'vimwiki': 'markdown', \ 'vimwiki': 'markdown',
\ 'vue': ['vue', 'javascript'], \ 'vue': ['vue', 'javascript'],
\ 'xsd': ['xsd', 'xml'],
\ 'xslt': ['xslt', 'xml'],
\ 'zsh': 'sh', \ 'zsh': 'sh',
\} \}
@ -355,12 +358,14 @@ function! ale#linter#Define(filetype, linter) abort
" This command will throw from the sandbox. " This command will throw from the sandbox.
let &l:equalprg=&l:equalprg let &l:equalprg=&l:equalprg
let l:new_linter = ale#linter#PreProcess(a:filetype, a:linter)
if !has_key(s:linters, a:filetype) if !has_key(s:linters, a:filetype)
let s:linters[a:filetype] = [] let s:linters[a:filetype] = []
endif endif
let l:new_linter = ale#linter#PreProcess(a:filetype, a:linter) " Remove previously defined linters with the same name.
call filter(s:linters[a:filetype], 'v:val.name isnot# a:linter.name')
call add(s:linters[a:filetype], l:new_linter) call add(s:linters[a:filetype], l:new_linter)
endfunction endfunction

View File

@ -71,8 +71,8 @@ function! s:FixList(buffer, list) abort
return l:new_list return l:new_list
endfunction endfunction
function! s:BufWinId(buffer) abort function! s:WinFindBuf(buffer) abort
return exists('*bufwinid') ? bufwinid(str2nr(a:buffer)) : 0 return exists('*win_findbuf') ? win_findbuf(str2nr(a:buffer)) : [0]
endfunction endfunction
function! s:SetListsImpl(timer_id, buffer, loclist) abort function! s:SetListsImpl(timer_id, buffer, loclist) abort
@ -88,19 +88,24 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort
call setqflist([], 'r', {'title': l:title}) call setqflist([], 'r', {'title': l:title})
endif endif
elseif g:ale_set_loclist elseif g:ale_set_loclist
" If windows support is off, bufwinid() may not exist. " If windows support is off, win_findbuf() may not exist.
" We'll set result in the current window, which might not be correct, " We'll set result in the current window, which might not be correct,
" but it's better than nothing. " but it's better than nothing.
let l:id = s:BufWinId(a:buffer) let l:ids = s:WinFindBuf(a:buffer)
if has('nvim') for l:id in l:ids
call setloclist(l:id, s:FixList(a:buffer, a:loclist), ' ', l:title) if has('nvim')
else call setloclist(l:id, s:FixList(a:buffer, a:loclist), ' ', l:title)
call setloclist(l:id, s:FixList(a:buffer, a:loclist)) else
call setloclist(l:id, [], 'r', {'title': l:title}) call setloclist(l:id, s:FixList(a:buffer, a:loclist))
endif call setloclist(l:id, [], 'r', {'title': l:title})
endif
endfor
endif endif
" Save the current view before opening/closing any window
call setbufvar(a:buffer, 'ale_winview', winsaveview())
" Open a window to show the problems if we need to. " Open a window to show the problems if we need to.
" "
" We'll check if the current buffer's List is not empty here, so the " We'll check if the current buffer's List is not empty here, so the
@ -108,8 +113,6 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort
if s:ShouldOpen(a:buffer) && !empty(a:loclist) if s:ShouldOpen(a:buffer) && !empty(a:loclist)
let l:winnr = winnr() let l:winnr = winnr()
let l:mode = mode() let l:mode = mode()
let l:reset_visual_selection = l:mode is? 'v' || l:mode is# "\<c-v>"
let l:reset_character_selection = l:mode is? 's' || l:mode is# "\<c-s>"
" open windows vertically instead of default horizontally " open windows vertically instead of default horizontally
let l:open_type = '' let l:open_type = ''
@ -131,15 +134,18 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort
wincmd p wincmd p
endif endif
if l:reset_visual_selection || l:reset_character_selection " Return to original mode when applicable
" If we were in a selection mode before, select the last selection. if mode() != l:mode
normal! gv if l:mode is? 'v' || l:mode is# "\<c-v>"
" Reset our last visual selection
if l:reset_character_selection normal! gv
" Switch back to Select mode, if we were in that. elseif l:mode is? 's' || l:mode is# "\<c-s>"
" Reset our last character selection
normal! "\<c-g>" normal! "\<c-g>"
endif endif
endif endif
call s:RestoreViewIfNeeded(a:buffer)
endif endif
" If ALE isn't currently checking for more problems, close the window if " If ALE isn't currently checking for more problems, close the window if
@ -150,6 +156,30 @@ function! s:SetListsImpl(timer_id, buffer, loclist) abort
endif endif
endfunction endfunction
" Try to restore the window view after closing any of the lists to avoid making
" the it moving around, especially useful when on insert mode
function! s:RestoreViewIfNeeded(buffer) abort
let l:saved_view = getbufvar(a:buffer, 'ale_winview', {})
" Saved view is empty, can't do anything
if empty(l:saved_view)
return
endif
" Check wether the cursor has moved since linting was actually requested. If
" the user has indeed moved lines, do nothing
let l:current_view = winsaveview()
if l:current_view['lnum'] != l:saved_view['lnum']
return
endif
" Anchor view by topline if the list is set to open horizontally
if ale#Var(a:buffer, 'list_vertical') == 0
call winrestview({'topline': l:saved_view['topline']})
endif
endfunction
function! ale#list#SetLists(buffer, loclist) abort function! ale#list#SetLists(buffer, loclist) abort
if get(g:, 'ale_set_lists_synchronously') == 1 if get(g:, 'ale_set_lists_synchronously') == 1
\|| getbufvar(a:buffer, 'ale_save_event_fired', 0) \|| getbufvar(a:buffer, 'ale_save_event_fired', 0)
@ -173,21 +203,31 @@ function! s:CloseWindowIfNeeded(buffer) abort
return return
endif endif
let l:did_close_any_list = 0
try try
" Only close windows if the quickfix list or loclist is completely empty, " Only close windows if the quickfix list or loclist is completely empty,
" including errors set through other means. " including errors set through other means.
if g:ale_set_quickfix if g:ale_set_quickfix
if empty(getqflist()) if empty(getqflist())
cclose cclose
let l:did_close_any_list = 1
endif endif
else else
let l:win_id = s:BufWinId(a:buffer) let l:win_ids = s:WinFindBuf(a:buffer)
if g:ale_set_loclist && empty(getloclist(l:win_id)) for l:win_id in l:win_ids
lclose if g:ale_set_loclist && empty(getloclist(l:win_id))
endif lclose
let l:did_close_any_list = 1
endif
endfor
endif endif
" Ignore 'Cannot close last window' errors. " Ignore 'Cannot close last window' errors.
catch /E444/ catch /E444/
endtry endtry
if l:did_close_any_list
call s:RestoreViewIfNeeded(a:buffer)
endif
endfunction endfunction

View File

@ -111,7 +111,7 @@ function! ale#loclist_jumping#Jump(direction, ...) abort
if !empty(l:nearest) if !empty(l:nearest)
normal! m` normal! m`
call cursor(l:nearest) call cursor([l:nearest[0], max([l:nearest[1], 1])])
endif endif
endfunction endfunction

View File

@ -321,7 +321,69 @@ endfunction
function! s:SendInitMessage(conn) abort function! s:SendInitMessage(conn) abort
let [l:init_id, l:init_data] = ale#lsp#CreateMessageData( let [l:init_id, l:init_data] = ale#lsp#CreateMessageData(
\ ale#lsp#message#Initialize(a:conn.root, a:conn.init_options), \ ale#lsp#message#Initialize(
\ a:conn.root,
\ a:conn.init_options,
\ {
\ 'workspace': {
\ 'applyEdit': v:false,
\ 'didChangeConfiguration': {
\ 'dynamicRegistration': v:false,
\ },
\ 'symbol': {
\ 'dynamicRegistration': v:false,
\ },
\ 'workspaceFolders': v:false,
\ 'configuration': v:false,
\ },
\ 'textDocument': {
\ 'synchronization': {
\ 'dynamicRegistration': v:false,
\ 'willSave': v:false,
\ 'willSaveWaitUntil': v:false,
\ 'didSave': v:true,
\ },
\ 'completion': {
\ 'dynamicRegistration': v:false,
\ 'completionItem': {
\ 'snippetSupport': v:false,
\ 'commitCharactersSupport': v:false,
\ 'documentationFormat': ['plaintext'],
\ 'deprecatedSupport': v:false,
\ 'preselectSupport': v:false,
\ },
\ 'contextSupport': v:false,
\ },
\ 'hover': {
\ 'dynamicRegistration': v:false,
\ 'contentFormat': ['plaintext'],
\ },
\ 'references': {
\ 'dynamicRegistration': v:false,
\ },
\ 'documentSymbol': {
\ 'dynamicRegistration': v:false,
\ 'hierarchicalDocumentSymbolSupport': v:false,
\ },
\ 'definition': {
\ 'dynamicRegistration': v:false,
\ 'linkSupport': v:false,
\ },
\ 'typeDefinition': {
\ 'dynamicRegistration': v:false,
\ },
\ 'publishDiagnostics': {
\ 'relatedInformation': v:true,
\ },
\ 'codeAction': {
\ 'dynamicRegistration': v:false,
\ },
\ 'rename': {
\ 'dynamicRegistration': v:false,
\ },
\ },
\ },
\ ),
\) \)
let a:conn.init_request_id = l:init_id let a:conn.init_request_id = l:init_id
call s:SendMessageData(a:conn, l:init_data) call s:SendMessageData(a:conn, l:init_data)
@ -484,6 +546,35 @@ function! ale#lsp#OpenDocument(conn_id, buffer, language_id) abort
return l:opened return l:opened
endfunction endfunction
" Notify LSP servers or tsserver that a document is closed, if opened before.
" If a document is closed, 1 will be returned, otherwise 0 will be returned.
"
" Only the buffer number is required here. A message will be sent to every
" language server that was notified previously of the document being opened.
function! ale#lsp#CloseDocument(buffer) abort
let l:closed = 0
" The connection keys are sorted so the messages are easier to test, and
" so messages are sent in a consistent order.
for l:conn_id in sort(keys(s:connections))
let l:conn = s:connections[l:conn_id]
if l:conn.initialized && has_key(l:conn.open_documents, a:buffer)
if l:conn.is_tsserver
let l:message = ale#lsp#tsserver_message#Close(a:buffer)
else
let l:message = ale#lsp#message#DidClose(a:buffer)
endif
call ale#lsp#Send(l:conn_id, l:message)
call remove(l:conn.open_documents, a:buffer)
let l:closed = 1
endif
endfor
return l:closed
endfunction
" Notify LSP servers or tsserver that a document has changed, if needed. " Notify LSP servers or tsserver that a document has changed, if needed.
" If a notification is sent, 1 will be returned, otherwise 0 will be returned. " If a notification is sent, 1 will be returned, otherwise 0 will be returned.
function! ale#lsp#NotifyForChanges(conn_id, buffer) abort function! ale#lsp#NotifyForChanges(conn_id, buffer) abort

View File

@ -28,14 +28,13 @@ function! ale#lsp#message#GetNextVersionID() abort
return l:id return l:id
endfunction endfunction
function! ale#lsp#message#Initialize(root_path, initialization_options) abort function! ale#lsp#message#Initialize(root_path, options, capabilities) abort
" TODO: Define needed capabilities.
" NOTE: rootPath is deprecated in favour of rootUri " NOTE: rootPath is deprecated in favour of rootUri
return [0, 'initialize', { return [0, 'initialize', {
\ 'processId': getpid(), \ 'processId': getpid(),
\ 'rootPath': a:root_path, \ 'rootPath': a:root_path,
\ 'capabilities': {}, \ 'capabilities': a:capabilities,
\ 'initializationOptions': a:initialization_options, \ 'initializationOptions': a:options,
\ 'rootUri': ale#path#ToURI(a:root_path), \ 'rootUri': ale#path#ToURI(a:root_path),
\}] \}]
endfunction endfunction

View File

@ -90,7 +90,7 @@ function! ale#lsp#response#ReadTSServerDiagnostics(response) abort
\ 'lnum': l:diagnostic.start.line, \ 'lnum': l:diagnostic.start.line,
\ 'col': l:diagnostic.start.offset, \ 'col': l:diagnostic.start.offset,
\ 'end_lnum': l:diagnostic.end.line, \ 'end_lnum': l:diagnostic.end.line,
\ 'end_col': l:diagnostic.end.offset, \ 'end_col': l:diagnostic.end.offset - 1,
\} \}
if has_key(l:diagnostic, 'code') if has_key(l:diagnostic, 'code')

View File

@ -8,6 +8,9 @@ if !has_key(s:, 'lsp_linter_map')
let s:lsp_linter_map = {} let s:lsp_linter_map = {}
endif endif
" A Dictionary to track one-shot handlers for custom LSP requests
let s:custom_handlers_map = get(s:, 'custom_handlers_map', {})
" Check if diagnostics for a particular linter should be ignored. " Check if diagnostics for a particular linter should be ignored.
function! s:ShouldIgnore(buffer, linter_name) abort function! s:ShouldIgnore(buffer, linter_name) abort
" Ignore all diagnostics if LSP integration is disabled. " Ignore all diagnostics if LSP integration is disabled.
@ -31,7 +34,7 @@ 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_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri) let l:filename = ale#path#FromURI(a:response.params.uri)
let l:buffer = bufnr(l:filename) let l:buffer = bufnr('^' . l:filename . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) if empty(l:info)
@ -49,7 +52,7 @@ endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:linter_name = 'tsserver' let l:linter_name = 'tsserver'
let l:buffer = bufnr(a:response.body.file) let l:buffer = bufnr('^' . a:response.body.file . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) if empty(l:info)
@ -407,9 +410,57 @@ endfunction
" Clear LSP linter data for the linting engine. " Clear LSP linter data for the linting engine.
function! ale#lsp_linter#ClearLSPData() abort function! ale#lsp_linter#ClearLSPData() abort
let s:lsp_linter_map = {} let s:lsp_linter_map = {}
let s:custom_handlers_map = {}
endfunction endfunction
" Just for tests. " Just for tests.
function! ale#lsp_linter#SetLSPLinterMap(replacement_map) abort 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
function! s:HandleLSPResponseToCustomRequests(conn_id, response) abort
if has_key(a:response, 'id')
\&& has_key(s:custom_handlers_map, a:response.id)
let l:Handler = remove(s:custom_handlers_map, a:response.id)
call l:Handler(a:response)
endif
endfunction
function! s:OnReadyForCustomRequests(args, linter, lsp_details) abort
let l:id = a:lsp_details.connection_id
let l:request_id = ale#lsp#Send(l:id, a:args.message)
if l:request_id > 0 && has_key(a:args, 'handler')
let l:Callback = function('s:HandleLSPResponseToCustomRequests')
call ale#lsp#RegisterCallback(l:id, l:Callback)
let s:custom_handlers_map[l:request_id] = a:args.handler
endif
endfunction
" Send a custom request to an LSP linter.
function! ale#lsp_linter#SendRequest(buffer, linter_name, message, ...) abort
let l:filetype = ale#linter#ResolveFiletype(getbufvar(a:buffer, '&filetype'))
let l:linter_list = ale#linter#GetAll(l:filetype)
let l:linter_list = filter(l:linter_list, {_, v -> v.name is# a:linter_name})
if len(l:linter_list) < 1
throw 'Linter "' . a:linter_name . '" not found!'
endif
let l:linter = l:linter_list[0]
if empty(l:linter.lsp)
throw 'Linter "' . a:linter_name . '" does not support LSP!'
endif
let l:is_notification = a:message[0]
let l:callback_args = {'message': a:message}
if !l:is_notification && a:0
let l:callback_args.handler = a:1
endif
let l:Callback = function('s:OnReadyForCustomRequests', [l:callback_args])
return ale#lsp_linter#StartLSP(a:buffer, l:linter, l:Callback)
endfunction

View File

@ -3,13 +3,20 @@
" simplify a path, and fix annoying issues with paths on Windows. " simplify a path, and fix annoying issues with paths on Windows.
" "
" Forward slashes are changed to back slashes so path equality works better. " Forward slashes are changed to back slashes so path equality works better
" on Windows. Back slashes are changed to forward slashes on Unix.
"
" Unix paths can technically contain back slashes, but in practice no path
" should, and replacing back slashes with forward slashes makes linters work
" in environments like MSYS.
" "
" Paths starting with more than one forward slash are changed to only one " Paths starting with more than one forward slash are changed to only one
" forward slash, to prevent the paths being treated as special MSYS paths. " forward slash, to prevent the paths being treated as special MSYS paths.
function! ale#path#Simplify(path) abort function! ale#path#Simplify(path) abort
if has('unix') if has('unix')
return substitute(simplify(a:path), '^//\+', '/', 'g') " no-custom-checks let l:unix_path = substitute(a:path, '\\', '/', 'g')
return substitute(simplify(l:unix_path), '^//\+', '/', 'g') " no-custom-checks
endif endif
let l:win_path = substitute(a:path, '/', '\\', 'g') let l:win_path = substitute(a:path, '/', '\\', 'g')

View File

@ -25,7 +25,7 @@ function! ale#python#FindProjectRootIni(buffer) abort
\|| filereadable(l:path . '/tox.ini') \|| filereadable(l:path . '/tox.ini')
\|| filereadable(l:path . '/mypy.ini') \|| filereadable(l:path . '/mypy.ini')
\|| filereadable(l:path . '/pycodestyle.cfg') \|| filereadable(l:path . '/pycodestyle.cfg')
\|| filereadable(l:path . '/flake8.cfg') \|| filereadable(l:path . '/.flake8')
\|| filereadable(l:path . '/.flake8rc') \|| filereadable(l:path . '/.flake8rc')
\|| filereadable(l:path . '/pylama.ini') \|| filereadable(l:path . '/pylama.ini')
\|| filereadable(l:path . '/pylintrc') \|| filereadable(l:path . '/pylintrc')

View File

@ -82,6 +82,34 @@ execute 'sign define ALEInfoSign text=' . s:EscapeSignText(g:ale_sign_info)
\ . ' texthl=ALEInfoSign linehl=ALEInfoLine' \ . ' texthl=ALEInfoSign linehl=ALEInfoLine'
sign define ALEDummySign sign define ALEDummySign
if has('nvim-0.3.2')
if !hlexists('ALEErrorSignLineNr')
highlight link ALEErrorSignLineNr CursorLineNr
endif
if !hlexists('ALEStyleErrorSignLineNr')
highlight link ALEStyleErrorSignLineNr CursorLineNr
endif
if !hlexists('ALEWarningSignLineNr')
highlight link ALEWarningSignLineNr CursorLineNr
endif
if !hlexists('ALEStyleWarningSignLineNr')
highlight link ALEStyleWarningSignLineNr CursorLineNr
endif
if !hlexists('ALEInfoSignLineNr')
highlight link ALEInfoSignLineNr CursorLineNr
endif
sign define ALEErrorSign numhl=ALEErrorSignLineNr
sign define ALEStyleErrorSign numhl=ALEStyleErrorSignLineNr
sign define ALEWarningSign numhl=ALEWarningSignLineNr
sign define ALEStyleWarningSign numhl=ALEStyleWarningSignLineNr
sign define ALEInfoSign numhl=ALEInfoSignLineNr
endif
function! ale#sign#GetSignName(sublist) abort function! ale#sign#GetSignName(sublist) abort
let l:priority = g:ale#util#style_warning_priority let l:priority = g:ale#util#style_warning_priority

View File

@ -0,0 +1,26 @@
function! asyncomplete#sources#ale#get_source_options(...) abort
let l:default = extend({
\ 'name': 'ale',
\ 'completor': function('asyncomplete#sources#ale#completor'),
\ 'whitelist': ['*'],
\ 'triggers': asyncomplete#sources#ale#get_triggers(),
\ }, a:0 >= 1 ? a:1 : {})
return extend(l:default, {'refresh_pattern': '\k\+$'})
endfunction
function! asyncomplete#sources#ale#get_triggers() abort
let l:triggers = ale#completion#GetAllTriggers()
let l:triggers['*'] = l:triggers['<default>']
return l:triggers
endfunction
function! asyncomplete#sources#ale#completor(options, context) abort
let l:keyword = matchstr(a:context.typed, '\w\+$')
let l:startcol = a:context.col - len(l:keyword)
call ale#completion#GetCompletions('ale-callback', { 'callback': {completions ->
\ asyncomplete#complete(a:options.name, a:context, l:startcol, completions)
\ }})
endfunction

View File

@ -21,5 +21,16 @@ g:ale_ada_gcc_options *g:ale_ada_gcc_options*
This variable can be set to pass additional options to gcc. This variable can be set to pass additional options to gcc.
===============================================================================
gnatpp *ale-ada-gnatpp*
g:ale_ada_gnatpp_options *g:ale_ada_gnatpp_options*
*b:ale_ada_gnatpp_options*
Type: |String|
Default: `''`
This variable can be set to pass extra options to the gnatpp fixer.
=============================================================================== ===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@ -156,7 +156,7 @@ g:ale_c_clangtidy_options *g:ale_c_clangtidy_options*
Type: |String| Type: |String|
Default: `''` Default: `''`
This variable can be changed to modify flags given to clang-tidy. This variable can be changed to modify compiler flags given to clang-tidy.
- Setting this variable to a non-empty string, - Setting this variable to a non-empty string,
- and working in a buffer where no compilation database is found using - and working in a buffer where no compilation database is found using
@ -169,6 +169,23 @@ g:ale_c_clangtidy_options *g:ale_c_clangtidy_options*
of the |g:ale_c_build_dir_names| directories of the project tree. of the |g:ale_c_build_dir_names| directories of the project tree.
g:ale_c_clangtidy_extra_options *g:ale_c_clangtidy_extra_options*
*b:ale_c_clangtidy_extra_options*
Type: |String|
Default: `''`
This variable can be changed to modify flags given to clang-tidy.
g:ale_c_clangtidy_fix_errors *g:ale_c_clangtidy_fix_errors*
*b:ale_c_clangtidy_fix_errors*
Type: |Number|
Default: `1`
This variable can be changed to disable the `-fix-errors` option for the
|clangtidy| fixer.
=============================================================================== ===============================================================================
cppcheck *ale-c-cppcheck* cppcheck *ale-c-cppcheck*

View File

@ -125,7 +125,7 @@ g:ale_cpp_clangtidy_options *g:ale_cpp_clangtidy_options*
Type: |String| Type: |String|
Default: `''` Default: `''`
This variable can be changed to modify flags given to clang-tidy. This variable can be changed to modify compiler flags given to clang-tidy.
- Setting this variable to a non-empty string, - Setting this variable to a non-empty string,
- and working in a buffer where no compilation database is found using - and working in a buffer where no compilation database is found using
@ -138,6 +138,23 @@ g:ale_cpp_clangtidy_options *g:ale_cpp_clangtidy_options*
of the |g:ale_c_build_dir_names| directories of the project tree. of the |g:ale_c_build_dir_names| directories of the project tree.
g:ale_cpp_clangtidy_extra_options *g:ale_cpp_clangtidy_extra_options*
*b:ale_cpp_clangtidy_extra_options*
Type: |String|
Default: `''`
This variable can be changed to modify flags given to clang-tidy.
g:ale_cpp_clangtidy_fix_errors *g:ale_cpp_clangtidy_fix_errors*
*b:ale_cpp_clangtidy_fix_errors*
Type: |Number|
Default: `1`
This variable can be changed to disable the `-fix-errors` option for the
|clangtidy| fixer.
=============================================================================== ===============================================================================
clazy *ale-cpp-clazy* clazy *ale-cpp-clazy*

View File

@ -6,11 +6,97 @@ In addition to the linters that are provided with ALE, C# code can be checked
with the OmniSharp plugin. See here: https://github.com/OmniSharp/omnisharp-vim with the OmniSharp plugin. See here: https://github.com/OmniSharp/omnisharp-vim
===============================================================================
csc *ale-cs-csc*
The |ale-cs-csc| linter checks for semantic errors when files are opened or
saved.
See |ale-lint-file-linters| for more information on linters which do not
check for problems while you type.
The csc linter uses the mono csc compiler providing full c# 7 and newer
support to generate a temporary module target file (/t:module). The module
includes including all '*.cs' files contained in the directory tree rooted
at the path defined by the |g:ale_cs_csc_source| or |b:ale_cs_csc_source|
variabl and all sub directories.
It will in future replace the |ale-cs-mcs| and |ale-cs-mcsc| linters as both
utilizer the mcsc compiler which according to mono porject ist further
developed and as of writint these lines only receives maintenance updates.
The down is that the csc compiler does not support the -sytax option any more
and therefore |ale-cs-csc| linter doese not offer any as you type syntax
checking like the |ale-cs-mcsc| linter doesn't.
The paths to search for additional assembly files can be specified using the
|g:ale_cs_csc_assembly_path| or |b:ale_cs_csc_assembly_path| variables.
NOTE: ALE will not find any errors in files apart from syntax errors if any
one of the source files contains a syntax error. Syntax errors must be fixed
first before other errors will be shown.
g:ale_cs_csc_options *g:ale_cs_csc_options*
*b:ale_cs_csc_options*
Type: |String|
Default: `''`
This option can be set to pass additional arguments to the `csc` compiler.
For example, to add the dotnet package which is not added per default: >
let g:ale_cs_mcs_options = ' /warn:4 /langversion:7.2'
<
NOTE: the `/unsafe` option is always passed to `csc`.
g:ale_cs_csc_source *g:ale_cs_csc_source*
*b:ale_cs_csc_source*
Type: |String|
Default: `''`
This variable defines the root path of the directory tree searched for the
'*.cs' files to be linted. If this option is empty, the source file's
directory will be used.
NOTE: Currently it is not possible to specify sub directories and
directory sub trees which shall not be searched for *.cs files.
g:ale_cs_csc_assembly_path *g:ale_cs_csc_assembly_path*
*b:ale_cs_csc_assembly_path*
Type: |List|
Default: `[]`
This variable defines a list of path strings to be searched for external
assembly files. The list is passed to the csc compiler using the `/lib:`
flag.
g:ale_cs_csc_assemblies *g:ale_cs_csc_assemblies*
*b:ale_cs_csc_assemblies*
Type: |List|
Default: `[]`
This variable defines a list of external assembly (*.dll) files required
by the mono mcs compiler to generate a valid module target. The list is
passed the csc compiler using the `/r:` flag.
For example: >
" Compile C# programs with the Unity engine DLL file on Mac.
let g:ale_cs_mcsc_assemblies = [
\ '/Applications/Unity/Unity.app/Contents/Frameworks/Managed/UnityEngine.dll',
\ 'path-to-unityproject/obj/Debug',
\]
<
=============================================================================== ===============================================================================
mcs *ale-cs-mcs* mcs *ale-cs-mcs*
The `mcs` linter looks only for syntax errors while you type. See |ale-cs-mcsc| The `mcs` linter looks only for syntax errors while you type. See
for the separately configured linter for checking for semantic errors. |ale-cs-mcsc| for the separately configured linter for checking for semantic
errors.
g:ale_cs_mcs_options *g:ale_cs_mcs_options* g:ale_cs_mcs_options *g:ale_cs_mcs_options*

View File

@ -151,9 +151,9 @@ ALE is tested with a suite of tests executed in Travis CI and AppVeyor. ALE
runs tests with the following versions of Vim in the following environments. runs tests with the following versions of Vim in the following environments.
1. Vim 8.0.0027 on Linux via Travis CI. 1. Vim 8.0.0027 on Linux via Travis CI.
2. Vim 8.1.0204 on Linux via Travis CI. 2. Vim 8.1.0519 on Linux via Travis CI.
3. NeoVim 0.2.0 on Linux via Travis CI. 3. NeoVim 0.2.0 on Linux via Travis CI.
4. NeoVim 0.3.0 on Linux via Travis CI. 4. NeoVim 0.3.5 on Linux via Travis CI.
5. Vim 8 (stable builds) on Windows via AppVeyor. 5. Vim 8 (stable builds) on Windows via AppVeyor.
If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs If you are developing ALE code on Linux, Mac OSX, or BSD, you can run ALEs
@ -351,6 +351,7 @@ given the above setup are as follows.
`GivenCommandOutput [...]` - Define output for ale#command#Run. `GivenCommandOutput [...]` - Define output for ale#command#Run.
`AssertFixer results` - Check the fixer results `AssertFixer results` - Check the fixer results
`AssertFixerNotExecuted` - Check that fixers will not be executed.
=============================================================================== ===============================================================================

View File

@ -29,20 +29,44 @@ g:ale_elm_format_options *g:ale_elm_format_options*
This variable can be set to pass additional options to elm-format. This variable can be set to pass additional options to elm-format.
=============================================================================== ===============================================================================
elm-lsp *ale-elm-elm-lsp* elm-ls *ale-elm-elm-ls*
g:ale_elm_lsp_executable *g:ale_elm_lsp_executable* g:ale_elm_ls_executable *g:ale_elm_ls_executable*
*b:ale_elm_lsp_executable* *b:ale_elm_ls_executable*
Type: |String| Type: |String|
Default: `'elm-lsp'` Default: `'elm-language-server'`
See |ale-integrations-local-executables| See |ale-integrations-local-executables|
g:ale_elm_lsp_use_global *g:ale_elm_lsp_use_global* g:ale_elm_ls_use_global *g:ale_elm_ls_use_global*
*b:ale_elm_lsp_use_global* *b:ale_elm_ls_use_global*
Type: |Number| Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)` Default: `get(g:, 'ale_use_global_executables', 1)`
See |ale-integrations-local-executables|
g:ale_elm_ls_elm_path *g:ale_elm_ls_elm_path*
*b:ale_elm_ls_elm_path*
Type: |String|
Default: `'elm'`
See |ale-integrations-local-executables|
g:ale_elm_ls_elm_format_path *g:ale_elm_ls_elm_format_path*
*b:ale_elm_ls_elm_format_path*
Type: |String|
Default: `'elm-format'`
See |ale-integrations-local-executables|
g:ale_elm_ls_elm_test_path *g:ale_elm_ls_elm_test_path*
*b:ale_elm_ls_elm_test_path*
Type: |String|
Default: `'elm-test'`
See |ale-integrations-local-executables| See |ale-integrations-local-executables|

View File

@ -3,6 +3,35 @@ ALE Erlang Integration *ale-erlang-options*
=============================================================================== ===============================================================================
dialyzer *ale-erlang-dialyzer*
g:ale_erlang_dialyzer_executable *g:ale_erlang_dialyzer_executable*
*b:ale_erlang_dialyzer_executable*
Type: |String|
Default: `'dialyzer'`
This variable can be changed to specify the dialyzer executable.
g:ale_erlang_dialyzer_plt_file *g:ale_erlang_dialyzer_plt_file*
*b:ale_erlang_dialyzer_plt_file*
Type: |String|
This variable can be changed to specify the path to the PLT file. By
default, it will search for the PLT file inside the `_build` directory. If
there isn't one, it will fallback to the path `$REBAR_PLT_DIR/dialyzer/plt`.
Otherwise, it will default to `$HOME/.dialyzer_plt`.
g:ale_erlang_dialyzer_rebar3_profile *g:ale_erlang_dialyzer_rebar3_profile*
*b:ale_erlang_dialyzer_rebar3_profile*
Type: |String|
Default: `'default'`
This variable can be changed to specify the profile that is used to
run dialyzer with rebar3.
-------------------------------------------------------------------------------
erlc *ale-erlang-erlc* erlc *ale-erlang-erlc*
g:ale_erlang_erlc_options *g:ale_erlang_erlc_options* g:ale_erlang_erlc_options *g:ale_erlang_erlc_options*

View File

@ -30,6 +30,16 @@ g:ale_go_go_executable *g:ale_go_go_options*
the `gomod` fixer. the `gomod` fixer.
g:ale_go_go111module *g:ale_go_go111module*
*b:ale_go_go111module*
Type: |String|
Default: `''`
Override the value of the `$GO111MODULE` environment variable for
golang tools.
=============================================================================== ===============================================================================
bingo *ale-go-bingo* bingo *ale-go-bingo*

Some files were not shown because too many files have changed in this diff Show More