Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bartek thindil Jasicki 2020-08-29 10:42:25 +02:00
commit 0de847a8e1
100 changed files with 1897 additions and 545 deletions

View file

@ -19,6 +19,9 @@ init:
# Stop git from changing newlines # Stop git from changing newlines
- git config --global core.autocrlf input - git config --global core.autocrlf input
# NOTE: If you change the Vim or Vader versions here, please also update the
# instructions for running tests on Windows in ale-development.txt
install: install:
# Download and unpack Vim # Download and unpack Vim
- ps: >- - ps: >-

5
.gitignore vendored
View file

@ -1,11 +1,12 @@
!.editorconfig !.editorconfig
*.obj *.obj
*.pyc
# Ignore all hidden files everywhere. # Ignore all hidden files everywhere.
# Use `git add -f` to add hidden files. # Use `git add -f` to add hidden files.
.* .*
__pycache__
*.pyc
/doc/tags /doc/tags
/init.vim /init.vim
/test/ale-info-test-file /test/ale-info-test-file
/vader_output
__pycache__
tags tags

View file

@ -79,6 +79,7 @@ other content at [w0rp.com](https://w0rp.com).
17. [How can I configure my C or C++ project?](#faq-c-configuration) 17. [How can I configure my C or C++ project?](#faq-c-configuration)
18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration) 18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
19. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height) 19. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
20. [How can I run linters or fixers via Docker or a VM?](#faq-vm)
<a name="supported-languages"></a> <a name="supported-languages"></a>
@ -877,3 +878,14 @@ To set a default height for the error list, use the `g:ale_list_window_size` var
" Show 5 lines of errors (default: 10) " Show 5 lines of errors (default: 10)
let g:ale_list_window_size = 5 let g:ale_list_window_size = 5
``` ```
<a name="faq-vm"></a>
### 5.xx. How can I run linters or fixers via Docker or a VM?
ALE supports running linters or fixers via Docker, virtual machines, or in
combination with any remote machine with a different file system, so long as the
tools are well-integrated with ALE, and ALE is properly configured to run the
correct commands and map filename paths between different file systems. See
`:help ale-lint-other-machines` for the full documentation on how to configure
ALE to support this.

View file

@ -18,7 +18,7 @@ function! ale_linters#ada#gcc#GetCommand(buffer) abort
" -gnatc: Check syntax and semantics only (no code generation attempted) " -gnatc: Check syntax and semantics only (no code generation attempted)
return '%e -x ada -c -gnatc' return '%e -x ada -c -gnatc'
\ . ' -o ' . ale#Escape(l:out_file) \ . ' -o ' . ale#Escape(l:out_file)
\ . ' -I ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' -I %s:h'
\ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options')) \ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options'))
\ . ' %t' \ . ' %t'
endfunction endfunction

View file

@ -9,7 +9,7 @@ function! ale_linters#asm#gcc#GetCommand(buffer) abort
" -fsyntax-only doesn't catch everything. " -fsyntax-only doesn't catch everything.
return '%e -x assembler' return '%e -x assembler'
\ . ' -o ' . g:ale#util#nul_file \ . ' -o ' . g:ale#util#nul_file
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . '-iquote %s:h'
\ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -' \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction endfunction

View file

@ -38,7 +38,7 @@ function! ale_linters#c#cc#GetCommand(buffer, output) abort
" -fsyntax-only doesn't catch everything. " -fsyntax-only doesn't catch everything.
return '%e -S -x c' return '%e -S -x c'
\ . ' -o ' . g:ale#util#nul_file \ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' -iquote %s:h'
\ . ale#Pad(l:cflags) \ . ale#Pad(l:cflags)
\ . ale#Pad(l:ale_flags) . ' -' \ . ale#Pad(l:ale_flags) . ' -'
endfunction endfunction

View file

@ -38,7 +38,7 @@ function! ale_linters#cpp#cc#GetCommand(buffer, output) abort
" -fsyntax-only doesn't catch everything. " -fsyntax-only doesn't catch everything.
return '%e -S -x c++' return '%e -S -x c++'
\ . ' -o ' . g:ale#util#nul_file \ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' -iquote %s:h'
\ . ale#Pad(l:cflags) \ . ale#Pad(l:cflags)
\ . ale#Pad(l:ale_flags) . ' -' \ . ale#Pad(l:ale_flags) . ' -'
endfunction endfunction

View file

@ -5,9 +5,6 @@ call ale#Set('cuda_nvcc_executable', 'nvcc')
call ale#Set('cuda_nvcc_options', '-std=c++11') call ale#Set('cuda_nvcc_options', '-std=c++11')
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
" Unused: use ale#util#nul_file
" let l:output_file = ale#util#Tempname() . '.ii'
" call ale#command#ManageFile(a:buffer, l:output_file)
return '%e -cuda' return '%e -cuda'
\ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))) \ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
\ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options')) \ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options'))

View file

@ -11,7 +11,7 @@ function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'ruumba') return ale#ruby#EscapeExecutable(l:executable, 'ruumba')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'eruby_ruumba_options') \ . ale#Var(a:buffer, 'eruby_ruumba_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p')) \ . ' --stdin %s'
endfunction endfunction
function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort

View file

@ -6,7 +6,6 @@ function! ale_linters#go#gofmt#GetCommand(buffer) abort
\ . '%e -e %t' \ . '%e -e %t'
endfunction endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'gofmt', \ 'name': 'gofmt',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',

View file

@ -7,10 +7,9 @@ call ale#Set('nasm_nasm_options', '')
function! ale_linters#nasm#nasm#GetCommand(buffer) abort function! ale_linters#nasm#nasm#GetCommand(buffer) abort
" Note that NASM requires a trailing slash for the -I option. " Note that NASM requires a trailing slash for the -I option.
let l:separator = has('win32') ? '\' : '/' let l:separator = has('win32') ? '\' : '/'
let l:path = fnamemodify(bufname(a:buffer), ':p:h') . l:separator
let l:output_null = has('win32') ? 'NUL' : '/dev/null' let l:output_null = has('win32') ? 'NUL' : '/dev/null'
return '%e -X gnu -I ' . ale#Escape(l:path) return '%e -X gnu -I %s:h' . l:separator
\ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options')) \ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options'))
\ . ' %s' \ . ' %s'
\ . ' -o ' . l:output_null \ . ' -o ' . l:output_null

View file

@ -10,7 +10,7 @@ function! ale_linters#objc#clang#GetCommand(buffer) 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 'clang -S -x objective-c -fsyntax-only ' return 'clang -S -x objective-c -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . '-iquote %s:h'
\ . ' ' . ale#Var(a:buffer, 'objc_clang_options') . ' -' \ . ' ' . ale#Var(a:buffer, 'objc_clang_options') . ' -'
endfunction endfunction

View file

@ -10,7 +10,7 @@ function! ale_linters#objcpp#clang#GetCommand(buffer) 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 'clang++ -S -x objective-c++ -fsyntax-only ' return 'clang++ -S -x objective-c++ -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . '-iquote %s:h'
\ . ' ' . ale#Var(a:buffer, 'objcpp_clang_options') . ' -' \ . ' ' . ale#Var(a:buffer, 'objcpp_clang_options') . ' -'
endfunction endfunction

View file

@ -6,9 +6,7 @@ call ale#Set('pyrex_cython_executable', 'cython')
call ale#Set('pyrex_cython_options', '--warning-extra') call ale#Set('pyrex_cython_options', '--warning-extra')
function! ale_linters#pyrex#cython#GetCommand(buffer) abort function! ale_linters#pyrex#cython#GetCommand(buffer) abort
let l:local_dir = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) return '%e --working %s:h --include-dir %s:h'
return '%e --working ' . l:local_dir . ' --include-dir ' . l:local_dir
\ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options')) \ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options'))
\ . ' --output-file ' . g:ale#util#nul_file . ' %t' \ . ' --output-file ' . g:ale#util#nul_file . ' %t'
endfunction endfunction

View file

@ -16,17 +16,15 @@ function! ale_linters#python#pydocstyle#GetExecutable(buffer) abort
endfunction endfunction
function! ale_linters#python#pydocstyle#GetCommand(buffer) abort function! ale_linters#python#pydocstyle#GetCommand(buffer) abort
let l:dir = fnamemodify(bufname(a:buffer), ':p:h')
let l:executable = ale_linters#python#pydocstyle#GetExecutable(a:buffer) let l:executable = ale_linters#python#pydocstyle#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pydocstyle' \ ? ' run pydocstyle'
\ : '' \ : ''
return ale#path#CdString(l:dir) return ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable) . l:exec_args \ . ale#Escape(l:executable) . l:exec_args
\ . ' ' . ale#Var(a:buffer, 'python_pydocstyle_options') \ . ale#Pad(ale#Var(a:buffer, 'python_pydocstyle_options'))
\ . ' ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:t')) \ . ' %s:t'
endfunction endfunction
function! ale_linters#python#pydocstyle#Handle(buffer, lines) abort function! ale_linters#python#pydocstyle#Handle(buffer, lines) abort

View file

@ -10,7 +10,7 @@ function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'rubocop') return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options') \ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p')) \ . ' --stdin %s'
endfunction endfunction
function! ale_linters#ruby#rubocop#GetType(severity) abort function! ale_linters#ruby#rubocop#GetType(severity) abort

View file

@ -11,7 +11,7 @@ function! ale_linters#ruby#standardrb#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'standardrb') return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_standardrb_options') \ . ale#Var(a:buffer, 'ruby_standardrb_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p')) \ . ' --stdin %s'
endfunction endfunction
" standardrb is based on RuboCop so the callback is the same " standardrb is based on RuboCop so the callback is the same

View file

@ -0,0 +1,33 @@
" ale_linters/sql/sqllint.vim
" Author: Joe Reynolds <joereynolds952@gmail.co>
" Description: sql-lint for SQL files.
" sql-lint can be found at
" https://www.npmjs.com/package/sql-lint
" https://github.com/joereynolds/sql-lint
function! ale_linters#sql#sqllint#Handle(buffer, lines) abort
" Matches patterns like the following:
"
" stdin:1 [ER_NO_DB_ERROR] No database selected
let l:pattern = '\v^[^:]+:(\d+) (.*)'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[1] + 0,
\ 'col': l:match[2] + 0,
\ 'type': l:match[3][0],
\ 'text': l:match[0],
\})
endfor
return l:output
endfunction
call ale#linter#Define('sql', {
\ 'name': 'sqllint',
\ 'aliases': ['sql-lint'],
\ 'executable': 'sql-lint',
\ 'command': 'sql-lint',
\ 'callback': 'ale_linters#sql#sqllint#Handle',
\})

View file

@ -266,3 +266,23 @@ function! ale#GetLocItemMessage(item, format_string) abort
return l:msg return l:msg
endfunction endfunction
" Given a buffer and a linter or fixer name, return an Array of two-item
" Arrays describing how to map filenames to and from the local to foreign file
" systems.
function! ale#GetFilenameMappings(buffer, name) abort
let l:linter_mappings = ale#Var(a:buffer, 'filename_mappings')
if type(l:linter_mappings) is v:t_list
return l:linter_mappings
endif
let l:name = a:name
if !has_key(l:linter_mappings, l:name)
" Use * as a default setting for all tools.
let l:name = '*'
endif
return get(l:linter_mappings, l:name, [])
endfunction

View file

@ -8,6 +8,11 @@ let s:sep = has('win32') ? '\' : '/'
" Set just so tests can override it. " Set just so tests can override it.
let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt'] let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt']
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])
function! s:CanParseMakefile(buffer) abort function! s:CanParseMakefile(buffer) abort
" Something somewhere seems to delete this setting in tests, so ensure we " Something somewhere seems to delete this setting in tests, so ensure we
" always have a default value. " always have a default value.
@ -84,10 +89,10 @@ function! ale#c#ExpandAtArgs(path_prefix, raw_split_lines) abort
let l:path = join(split(l:option, '\zs')[1:], '') let l:path = join(split(l:option, '\zs')[1:], '')
" Make path absolute " Make path absolute
if stridx(l:path, s:sep) != 0 && stridx(l:path, '/') != 0 if !ale#path#IsAbsolute(l:path)
let l:rel_path = substitute(l:path, '"', '', 'g') let l:rel_path = substitute(l:path, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g') let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:path = a:path_prefix . s:sep . l:rel_path let l:path = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
endif endif
" Read the file and add all the arguments " Read the file and add all the arguments
@ -115,16 +120,27 @@ function! ale#c#ExpandAtArgs(path_prefix, raw_split_lines) abort
return l:out_lines return l:out_lines
endfunction endfunction
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort " Quote C/C++ a compiler argument, if needed.
let l:cflags_list = [] "
" Quoting arguments might cause issues with some systems/compilers, so we only
" quote them if we need to.
function! ale#c#QuoteArg(arg) abort
if a:arg !~# '\v[#$&*()\\|[\]{};''"<>/?! ^%]'
return a:arg
endif
let l:raw_split_lines = ale#c#ShellSplit(a:cflag_line) return ale#Escape(a:arg)
endfunction
function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
" Expand @file arguments now before parsing " Expand @file arguments now before parsing
let l:split_lines = ale#c#ExpandAtArgs(a:path_prefix, l:raw_split_lines) let l:arguments = ale#c#ExpandAtArgs(a:path_prefix, a:raw_arguments)
" A list of [already_quoted, argument]
let l:items = []
let l:option_index = 0 let l:option_index = 0
while l:option_index < len(l:split_lines) while l:option_index < len(l:arguments)
let l:option = l:split_lines[l:option_index] let l:option = l:arguments[l:option_index]
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
" Include options, that may need relative path fix " Include options, that may need relative path fix
@ -133,36 +149,38 @@ function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
\ || stridx(l:option, '-isystem') == 0 \ || stridx(l:option, '-isystem') == 0
\ || stridx(l:option, '-idirafter') == 0 \ || stridx(l:option, '-idirafter') == 0
\ || stridx(l:option, '-iframework') == 0 \ || stridx(l:option, '-iframework') == 0
\ || stridx(l:option, '-include') == 0
if stridx(l:option, '-I') == 0 && l:option isnot# '-I' if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
let l:arg = join(split(l:option, '\zs')[2:], '') let l:arg = join(split(l:option, '\zs')[2:], '')
let l:option = '-I' let l:option = '-I'
else else
let l:arg = l:split_lines[l:option_index] let l:arg = l:arguments[l:option_index]
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
endif endif
" Fix relative paths if needed " Fix relative paths if needed
if stridx(l:arg, s:sep) != 0 && stridx(l:arg, '/') != 0 if !ale#path#IsAbsolute(l:arg)
let l:rel_path = substitute(l:arg, '"', '', 'g') let l:rel_path = substitute(l:arg, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g') let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:arg = ale#Escape(a:path_prefix . s:sep . l:rel_path) let l:arg = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
endif endif
call add(l:cflags_list, l:option) call add(l:items, [1, l:option])
call add(l:cflags_list, l:arg) call add(l:items, [1, ale#Escape(l:arg)])
" Options with arg that can be grouped with the option or separate " Options with arg that can be grouped with the option or separate
elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0 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' if l:option is# '-D' || l:option is# '-B'
call add(l:cflags_list, l:split_lines[l:option_index]) call add(l:items, [1, l:option])
call add(l:items, [0, l:arguments[l:option_index]])
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
else
call add(l:items, [0, l:option])
endif endif
" Options that have an argument (always separate) " Options that have an argument (always separate)
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0 elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
\ || l:option is# '-isysroot' || l:option is# '-imultilib' \ || l:option is# '-isysroot' || l:option is# '-imultilib'
call add(l:cflags_list, l:option) call add(l:items, [0, l:option])
call add(l:cflags_list, l:split_lines[l:option_index]) call add(l:items, [0, l:arguments[l:option_index]])
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
" Options without argument " Options without argument
elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0) elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0)
@ -174,11 +192,19 @@ function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
\ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0 \ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0
\ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix' \ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix'
\ || stridx(l:option, '-m') == 0 \ || stridx(l:option, '-m') == 0
call add(l:cflags_list, l:option) call add(l:items, [0, l:option])
endif endif
endwhile endwhile
return join(l:cflags_list, ' ') if a:should_quote
" Quote C arguments that haven't already been quoted above.
" If and only if we've been asked to quote them.
call map(l:items, 'v:val[0] ? v:val[1] : ale#c#QuoteArg(v:val[1])')
else
call map(l:items, 'v:val[1]')
endif
return join(l:items, ' ')
endfunction endfunction
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
@ -200,7 +226,7 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile') let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h') let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h')
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line) return ale#c#ParseCFlags(l:makefile_dir, 0, ale#c#ShellSplit(l:cflag_line))
endfunction endfunction
" Given a buffer number, find the project directory containing " Given a buffer number, find the project directory containing
@ -268,6 +294,10 @@ if !exists('s:compile_commands_cache')
let s:compile_commands_cache = {} let s:compile_commands_cache = {}
endif endif
function! ale#c#ResetCompileCommandsCache() abort
let s:compile_commands_cache = {}
endfunction
function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:empty = [{}, {}] let l:empty = [{}, {}]
@ -298,9 +328,20 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:dir_lookup = {} let l:dir_lookup = {}
for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : []) for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : [])
let l:filename = ale#path#GetAbsPath(l:entry.directory, l:entry.file)
" Store a key for lookups by the absolute path to the filename.
let l:file_lookup[l:filename] = get(l:file_lookup, l:filename, []) + [l:entry]
" Store a key for fuzzy lookups by the absolute path to the directory.
let l:dirname = fnamemodify(l:filename, ':h')
let l:dir_lookup[l:dirname] = get(l:dir_lookup, l:dirname, []) + [l:entry]
" Store a key for fuzzy lookups by just the basename of the file.
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]
" Store a key for fuzzy lookups by just the basename of the directory.
let l:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t')) let l:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t'))
let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry] let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry]
endfor endfor
@ -315,27 +356,79 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
return l:empty return l:empty
endfunction endfunction
function! ale#c#GetCompileCommand(json_item) abort " Get [should_quote, arguments] from either 'command' or 'arguments'
if has_key(a:json_item, 'command') " 'arguments' should be quoted later, the split 'command' strings should not.
return a:json_item.command function! s:GetArguments(json_item) abort
elseif has_key(a:json_item, 'arguments') if has_key(a:json_item, 'arguments')
return join(a:json_item.arguments, ' ') return [1, a:json_item.arguments]
elseif has_key(a:json_item, 'command')
return [0, ale#c#ShellSplit(a:json_item.command)]
endif endif
return '' return [0, []]
endfunction endfunction
function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
let l:buffer_filename = ale#path#Simplify(expand('#' . a:buffer . ':p'))
let l:basename = tolower(fnamemodify(l:buffer_filename, ':t'))
" Look for any file in the same directory if we can't find an exact match.
let l:dir = fnamemodify(l:buffer_filename, ':h')
" Search for an exact file match first. " Search for an exact file match first.
let l:basename = tolower(expand('#' . a:buffer . ':t')) let l:file_list = get(a:file_lookup, l:buffer_filename, [])
" We may have to look for /foo/bar instead of C:\foo\bar
if empty(l:file_list) && has('win32')
let l:file_list = get(
\ a:file_lookup,
\ ale#path#RemoveDriveLetter(l:buffer_filename),
\ []
\)
endif
" Try the absolute path to the directory second.
let l:dir_list = get(a:dir_lookup, l:dir, [])
if empty(l:dir_list) && has('win32')
let l:dir_list = get(
\ a:dir_lookup,
\ ale#path#RemoveDriveLetter(l:dir),
\ []
\)
endif
if empty(l:file_list) && empty(l:dir_list)
" If we can't find matches with the path to the file, try a
" case-insensitive match for any similarly-named file.
let l:file_list = get(a:file_lookup, l:basename, []) let l:file_list = get(a:file_lookup, l:basename, [])
" If we can't find matches with the path to the directory, try a
" case-insensitive match for anything in similarly-named directory.
let l:dir_list = get(a:dir_lookup, tolower(fnamemodify(l:dir, ':t')), [])
endif
" A source file matching the header filename. " A source file matching the header filename.
let l:source_file = '' let l:source_file = ''
if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$' if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$'
for l:suffix in ['.c', '.cpp'] for l:suffix in ['.c', '.cpp']
" Try to find a source file by an absolute path first.
let l:key = fnamemodify(l:buffer_filename, ':r') . l:suffix
let l:file_list = get(a:file_lookup, l:key, [])
if empty(l:file_list) && has('win32')
let l:file_list = get(
\ a:file_lookup,
\ ale#path#RemoveDriveLetter(l:key),
\ []
\)
endif
if empty(l:file_list)
" Look fuzzy matches on the basename second.
let l:key = fnamemodify(l:basename, ':r') . l:suffix let l:key = fnamemodify(l:basename, ':r') . l:suffix
let l:file_list = get(a:file_lookup, l:key, []) let l:file_list = get(a:file_lookup, l:key, [])
endif
if !empty(l:file_list) if !empty(l:file_list)
let l:source_file = l:key let l:source_file = l:key
@ -345,28 +438,31 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
endif endif
for l:item in l:file_list for l:item in l:file_list
let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
" Load the flags for this file, or for a source file matching the " Load the flags for this file, or for a source file matching the
" header file. " header file.
if ( if (
\ bufnr(l:item.file) is a:buffer \ bufnr(l:filename) is a:buffer
\ || ( \ || (
\ !empty(l:source_file) \ !empty(l:source_file)
\ && l:item.file[-len(l:source_file):] is? l:source_file \ && l:filename[-len(l:source_file):] is? l:source_file
\ ) \ )
\) \)
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item)) let [l:should_quote, l:args] = s:GetArguments(l:item)
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
endif endif
endfor endfor
" Look for any file in the same directory if we can't find an exact match.
let l:dir = ale#path#Simplify(expand('#' . a:buffer . ':p:h'))
let l:dirbasename = tolower(expand('#' . a:buffer . ':p:h:t'))
let l:dir_list = get(a:dir_lookup, l:dirbasename, [])
for l:item in l:dir_list for l:item in l:dir_list
if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
if ale#path#RemoveDriveLetter(fnamemodify(l:filename, ':h'))
\ is? ale#path#RemoveDriveLetter(l:dir)
let [l:should_quote, l:args] = s:GetArguments(l:item)
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
endif endif
endfor endfor
@ -405,10 +501,10 @@ endfunction
function! ale#c#GetMakeCommand(buffer) abort function! ale#c#GetMakeCommand(buffer) abort
if s:CanParseMakefile(a:buffer) if s:CanParseMakefile(a:buffer)
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile') let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile')
if !empty(l:makefile_path) if !empty(l:path)
return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n' return ale#path#CdString(fnamemodify(l:path, ':h')) . 'make -n'
endif endif
endif endif
@ -477,8 +573,3 @@ function! ale#c#IncludeOptions(include_paths) abort
return join(l:option_list) return join(l:option_list)
endfunction endfunction
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])

View file

@ -133,11 +133,36 @@ function! ale#command#EscapeCommandPart(command_part) abort
return substitute(a:command_part, '%', '%%', 'g') return substitute(a:command_part, '%', '%%', 'g')
endfunction endfunction
" Format a filename, converting it with filename mappings, if non-empty,
" and escaping it for putting into a command string.
"
" The filename can be modified.
function! s:FormatFilename(filename, mappings, modifiers) abort
let l:filename = a:filename
if !empty(a:mappings)
let l:filename = ale#filename_mapping#Map(l:filename, a:mappings)
endif
if !empty(a:modifiers)
let l:filename = fnamemodify(l:filename, a:modifiers)
endif
return ale#Escape(l:filename)
endfunction
" Given a command string, replace every... " Given a command string, replace every...
" %s -> with the current filename " %s -> with the current filename
" %t -> with the name of an unused file in a temporary directory " %t -> with the name of an unused file in a temporary directory
" %% -> with a literal % " %% -> with a literal %
function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_needed, input) abort function! ale#command#FormatCommand(
\ buffer,
\ executable,
\ command,
\ pipe_file_if_needed,
\ input,
\ mappings,
\) abort
let l:temporary_file = '' let l:temporary_file = ''
let l:command = a:command let l:command = a:command
@ -154,14 +179,24 @@ function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_ne
" file. " file.
if l:command =~# '%s' if l:command =~# '%s'
let l:filename = fnamemodify(bufname(a:buffer), ':p') let l:filename = fnamemodify(bufname(a:buffer), ':p')
let l:command = substitute(l:command, '%s', '\=ale#Escape(l:filename)', 'g') let l:command = substitute(
\ l:command,
\ '\v\%s(%(:h|:t|:r|:e)*)',
\ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))',
\ 'g'
\)
endif endif
if a:input isnot v:false && l:command =~# '%t' if a:input isnot v:false && l:command =~# '%t'
" Create a temporary filename, <temp_dir>/<original_basename> " Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function. " The file itself will not be created by this function.
let l:temporary_file = s:TemporaryFilename(a:buffer) let l:temporary_file = s:TemporaryFilename(a:buffer)
let l:command = substitute(l:command, '%t', '\=ale#Escape(l:temporary_file)', 'g') let l:command = substitute(
\ l:command,
\ '\v\%t(%(:h|:t|:r|:e)*)',
\ '\=s:FormatFilename(l:temporary_file, a:mappings, submatch(1))',
\ 'g'
\)
endif endif
" Finish formatting so %% becomes %. " Finish formatting so %% becomes %.
@ -265,6 +300,7 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
\ a:command, \ a:command,
\ get(l:options, 'read_buffer', 0), \ get(l:options, 'read_buffer', 0),
\ get(l:options, 'input', v:null), \ get(l:options, 'input', v:null),
\ get(l:options, 'filename_mappings', []),
\) \)
let l:command = ale#job#PrepareCommand(a:buffer, l:command) let l:command = ale#job#PrepareCommand(a:buffer, l:command)
let l:job_options = { let l:job_options = {

View file

@ -540,7 +540,8 @@ function! ale#completion#ParseLSPCompletions(response) abort
" Don't use LSP items with additional text edits when autoimport for " Don't use LSP items with additional text edits when autoimport for
" completions is turned off. " completions is turned off.
if has_key(l:item, 'additionalTextEdits') && !g:ale_completion_autoimport if !empty(get(l:item, 'additionalTextEdits'))
\&& !g:ale_completion_autoimport
continue continue
endif endif
@ -562,32 +563,33 @@ function! ale#completion#ParseLSPCompletions(response) abort
let l:text_changes = [] let l:text_changes = []
for l:edit in l:item.additionalTextEdits for l:edit in l:item.additionalTextEdits
let l:range = l:edit.range
call add(l:text_changes, { call add(l:text_changes, {
\ 'start': { \ 'start': {
\ 'line': l:range.start.line + 1, \ 'line': l:edit.range.start.line + 1,
\ 'offset': l:range.start.character + 1, \ 'offset': l:edit.range.start.character + 1,
\ }, \ },
\ 'end': { \ 'end': {
\ 'line': l:range.end.line + 1, \ 'line': l:edit.range.end.line + 1,
\ 'offset': l:range.end.character + 1, \ 'offset': l:edit.range.end.character + 1,
\ }, \ },
\ 'newText': l:edit.newText, \ 'newText': l:edit.newText,
\}) \})
endfor endfor
let l:changes = [{ if !empty(l:text_changes)
\ 'fileName': expand('#' . l:buffer . ':p'),
\ 'textChanges': l:text_changes,
\}]
\
let l:result.user_data = json_encode({ let l:result.user_data = json_encode({
\ 'codeActions': [{ \ 'codeActions': [{
\ 'description': 'completion', \ 'description': 'completion',
\ 'changes': l:changes, \ 'changes': [
\ {
\ 'fileName': expand('#' . l:buffer . ':p'),
\ 'textChanges': l:text_changes,
\ }
\ ],
\ }], \ }],
\}) \})
endif endif
endif
call add(l:results, l:result) call add(l:results, l:result)
endfor endfor
@ -900,6 +902,8 @@ function! ale#completion#Done() abort
endfunction endfunction
augroup ALECompletionActions augroup ALECompletionActions
autocmd!
autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item) autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item)
augroup END augroup END

View file

@ -39,6 +39,8 @@ function! ale#cursor#TruncatedEcho(original_message) abort
endif endif
exec 'echomsg l:message' exec 'echomsg l:message'
catch /E481/
" Do nothing if running from a visual selection.
endtry endtry
" Reset the cursor position if we moved off the end of the line. " Reset the cursor position if we moved off the end of the line.

View file

@ -4,6 +4,7 @@
" Remapping of linter problems. " Remapping of linter problems.
let g:ale_type_map = get(g:, 'ale_type_map', {}) let g:ale_type_map = get(g:, 'ale_type_map', {})
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
if !has_key(s:, 'executable_cache_map') if !has_key(s:, 'executable_cache_map')
let s:executable_cache_map = {} let s:executable_cache_map = {}
@ -256,6 +257,13 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfunction endfunction
function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort
let l:mappings = ale#GetFilenameMappings(a:buffer, a:linter_name)
if !empty(l:mappings)
" We need to apply reverse filename mapping here.
let l:mappings = ale#filename_mapping#Invert(l:mappings)
endif
let l:bufnr_map = {} let l:bufnr_map = {}
let l:new_loclist = [] let l:new_loclist = []
@ -296,13 +304,19 @@ function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist)
let l:item.code = l:old_item.code let l:item.code = l:old_item.code
endif endif
if has_key(l:old_item, 'filename') let l:old_name = get(l:old_item, 'filename', '')
\&& !ale#path#IsTempName(l:old_item.filename)
" Map parsed from output to local filesystem files.
if !empty(l:old_name) && !empty(l:mappings)
let l:old_name = ale#filename_mapping#Map(l:old_name, l:mappings)
endif
if !empty(l:old_name) && !ale#path#IsTempName(l:old_name)
" Use the filename given. " Use the filename given.
" Temporary files are assumed to be for this buffer, " Temporary files are assumed to be for this buffer,
" and the filename is not included then, because it looks bad " and the filename is not included then, because it looks bad
" in the loclist window. " in the loclist window.
let l:filename = l:old_item.filename let l:filename = l:old_name
let l:item.filename = l:filename let l:item.filename = l:filename
if has_key(l:old_item, 'bufnr') if has_key(l:old_item, 'bufnr')
@ -403,7 +417,7 @@ function! s:RunJob(command, options) abort
let l:buffer = a:options.buffer let l:buffer = a:options.buffer
let l:linter = a:options.linter let l:linter = a:options.linter
let l:output_stream = a:options.output_stream let l:output_stream = a:options.output_stream
let l:read_buffer = a:options.read_buffer let l:read_buffer = a:options.read_buffer && !a:options.lint_file
let l:info = g:ale_buffer_info[l:buffer] let l:info = g:ale_buffer_info[l:buffer]
let l:Callback = function('s:HandleExit', [{ let l:Callback = function('s:HandleExit', [{
@ -415,6 +429,7 @@ function! s:RunJob(command, options) abort
\ 'executable': l:executable, \ 'executable': l:executable,
\ 'read_buffer': l:read_buffer, \ 'read_buffer': l:read_buffer,
\ 'log_output': 1, \ 'log_output': 1,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:linter.name),
\}) \})
" Only proceed if the job is being run. " Only proceed if the job is being run.
@ -493,10 +508,15 @@ function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
endif endif
endfunction endfunction
function! s:RunIfExecutable(buffer, linter, executable) abort function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
if ale#command#IsDeferred(a:executable) if ale#command#IsDeferred(a:executable)
let a:executable.result_callback = { let a:executable.result_callback = {
\ executable -> s:RunIfExecutable(a:buffer, a:linter, executable) \ executable -> s:RunIfExecutable(
\ a:buffer,
\ a:linter,
\ a:lint_file,
\ executable
\ )
\} \}
return 1 return 1
@ -504,7 +524,7 @@ function! s:RunIfExecutable(buffer, linter, executable) abort
if ale#engine#IsExecutable(a:buffer, a:executable) if ale#engine#IsExecutable(a:buffer, a:executable)
" Use different job types for file or linter jobs. " Use different job types for file or linter jobs.
let l:job_type = a:linter.lint_file ? 'file_linter' : 'linter' let l:job_type = a:lint_file ? 'file_linter' : 'linter'
call setbufvar(a:buffer, 'ale_job_type', l:job_type) call setbufvar(a:buffer, 'ale_job_type', l:job_type)
let l:command = ale#linter#GetCommand(a:buffer, a:linter) let l:command = ale#linter#GetCommand(a:buffer, a:linter)
@ -514,6 +534,7 @@ function! s:RunIfExecutable(buffer, linter, executable) abort
\ 'linter': a:linter, \ 'linter': a:linter,
\ 'output_stream': get(a:linter, 'output_stream', 'stdout'), \ 'output_stream': get(a:linter, 'output_stream', 'stdout'),
\ 'read_buffer': a:linter.read_buffer, \ 'read_buffer': a:linter.read_buffer,
\ 'lint_file': a:lint_file,
\} \}
return s:RunJob(l:command, l:options) return s:RunJob(l:command, l:options)
@ -525,33 +546,62 @@ endfunction
" Run a linter for a buffer. " Run a linter for a buffer.
" "
" Returns 1 if the linter was successfully run. " Returns 1 if the linter was successfully run.
function! s:RunLinter(buffer, linter) abort function! s:RunLinter(buffer, linter, lint_file) abort
if !empty(a:linter.lsp) if !empty(a:linter.lsp)
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter) return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
else else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
return s:RunIfExecutable(a:buffer, a:linter, l:executable) return s:RunIfExecutable(a:buffer, a:linter, a:lint_file, l:executable)
endif endif
return 0 return 0
endfunction endfunction
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort function! s:GetLintFileValues(slots, Callback) abort
" Initialise the buffer information if needed. let l:deferred_list = []
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer) let l:new_slots = []
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer. for [l:lint_file, l:linter] in a:slots
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer) while ale#command#IsDeferred(l:lint_file) && has_key(l:lint_file, 'value')
" If we've already computed the return value, use it.
let l:lint_file = l:lint_file.value
endwhile
silent doautocmd <nomodeline> User ALELintPre if ale#command#IsDeferred(l:lint_file)
" If we are going to return the result later, wait for it.
call add(l:deferred_list, l:lint_file)
else
" If we have the value now, coerce it to 0 or 1.
let l:lint_file = l:lint_file is 1
endif
for l:linter in a:linters call add(l:new_slots, [l:lint_file, l:linter])
endfor
if !empty(l:deferred_list)
for l:deferred in l:deferred_list
let l:deferred.result_callback =
\ {-> s:GetLintFileValues(l:new_slots, a:Callback)}
endfor
else
call a:Callback(l:new_slots)
endif
endfunction
function! s:RunLinters(
\ buffer,
\ slots,
\ should_lint_file,
\ new_buffer,
\ can_clear_results
\) abort
let l:can_clear_results = a:can_clear_results
for [l:lint_file, l:linter] in a:slots
" Only run lint_file linters if we should. " Only run lint_file linters if we should.
if !l:linter.lint_file || a:should_lint_file if !l:lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter) if s:RunLinter(a:buffer, l:linter, l:lint_file)
" If a single linter ran, we shouldn't clear everything. " If a single linter ran, we shouldn't clear everything.
let l:can_clear_results = 0 let l:can_clear_results = 0
endif endif
@ -566,11 +616,49 @@ function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" disabled, or ALE itself is disabled. " disabled, or ALE itself is disabled.
if l:can_clear_results if l:can_clear_results
call ale#engine#SetResults(a:buffer, []) call ale#engine#SetResults(a:buffer, [])
elseif l:new_buffer elseif a:new_buffer
call s:AddProblemsFromOtherBuffers(a:buffer, a:linters) call s:AddProblemsFromOtherBuffers(
\ a:buffer,
\ map(copy(a:slots), 'v:val[1]')
\)
endif endif
endfunction endfunction
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" Initialise the buffer information if needed.
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer.
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)
silent doautocmd <nomodeline> User ALELintPre
" Handle `lint_file` callbacks first.
let l:linter_slots = []
for l:linter in a:linters
let l:LintFile = l:linter.lint_file
if type(l:LintFile) is v:t_func
let l:LintFile = l:LintFile(a:buffer)
endif
call add(l:linter_slots, [l:LintFile, l:linter])
endfor
call s:GetLintFileValues(l:linter_slots, {
\ new_slots -> s:RunLinters(
\ a:buffer,
\ new_slots,
\ a:should_lint_file,
\ l:new_buffer,
\ l:can_clear_results,
\ )
\})
endfunction
" Clean up a buffer. " Clean up a buffer.
" "
" This function will stop all current jobs for the buffer, " This function will stop all current jobs for the buffer,

View file

@ -105,11 +105,11 @@ function! ale#events#Init() abort
if g:ale_enabled if g:ale_enabled
if l:text_changed is? 'always' || l:text_changed is# '1' if l:text_changed is? 'always' || l:text_changed is# '1'
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay) autocmd TextChanged,TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
elseif l:text_changed is? 'normal' elseif l:text_changed is? 'normal'
autocmd TextChanged * call ale#Queue(g:ale_lint_delay) autocmd TextChanged * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
elseif l:text_changed is? 'insert' elseif l:text_changed is? 'insert'
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay) autocmd TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
endif endif
if g:ale_lint_on_enter if g:ale_lint_on_enter

View file

@ -0,0 +1,22 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Logic for handling mappings between files
" Invert filesystem mappings so they can be mapped in reverse.
function! ale#filename_mapping#Invert(filename_mappings) abort
return map(copy(a:filename_mappings), '[v:val[1], v:val[0]]')
endfunction
" Given a filename and some filename_mappings, map a filename.
function! ale#filename_mapping#Map(filename, filename_mappings) abort
let l:simplified_filename = ale#path#Simplify(a:filename)
for [l:mapping_from, l:mapping_to] in a:filename_mappings
let l:mapping_from = ale#path#Simplify(l:mapping_from)
if l:simplified_filename[:len(l:mapping_from) - 1] is# l:mapping_from
return l:mapping_to . l:simplified_filename[len(l:mapping_from):]
endif
endfor
return a:filename
endfunction

View file

@ -1,4 +1,8 @@
call ale#Set('fix_on_save_ignore', {}) " Author: w0rp <devw0rp@gmail.com>
" Description: Functions for fixing code with programs, or other means.
let g:ale_fix_on_save_ignore = get(g:, 'ale_fix_on_save_ignore', {})
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
" 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.
@ -110,7 +114,6 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
call s:RunFixer({ call s:RunFixer({
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'output': l:output,
\ 'callback_list': a:job_info.callback_list, \ 'callback_list': a:job_info.callback_list,
\ 'callback_index': a:job_info.callback_index + 1, \ 'callback_index': a:job_info.callback_index + 1,
\}) \})
@ -125,6 +128,7 @@ function! s:RunJob(result, options) abort
let l:buffer = a:options.buffer let l:buffer = a:options.buffer
let l:input = a:options.input let l:input = a:options.input
let l:fixer_name = a:options.fixer_name
if a:result is 0 || type(a:result) is v:t_list if a:result is 0 || type(a:result) is v:t_list
if type(a:result) is v:t_list if type(a:result) is v:t_list
@ -150,7 +154,6 @@ function! s:RunJob(result, options) abort
\ 'input': l:input, \ 'input': l:input,
\ 'callback_index': a:options.callback_index, \ 'callback_index': a:options.callback_index,
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'output': [],
\}) \})
return return
@ -177,6 +180,7 @@ function! s:RunJob(result, options) abort
\ 'read_buffer': l:read_buffer, \ 'read_buffer': l:read_buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'log_output': 0, \ 'log_output': 0,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name),
\}) \})
if empty(l:run_result) if empty(l:run_result)
@ -200,32 +204,22 @@ function! s:RunFixer(options) abort
return return
endif endif
let l:ChainCallback = get(a:options, 'chain_callback', v:null) let [l:fixer_name, l:Function] = a:options.callback_list[l:index]
let l:Function = l:ChainCallback isnot v:null
\ ? ale#util#GetFunction(l:ChainCallback)
\ : a:options.callback_list[l:index]
" Record new jobs started as fixer jobs. " Record new jobs started as fixer jobs.
call setbufvar(l:buffer, 'ale_job_type', 'fixer') call setbufvar(l:buffer, 'ale_job_type', 'fixer')
if l:ChainCallback isnot v:null
" Chained commands accept (buffer, output, [input])
let l:result = ale#util#FunctionArgCount(l:Function) == 2
\ ? call(l:Function, [l:buffer, a:options.output])
\ : call(l:Function, [l:buffer, a:options.output, copy(l:input)])
else
" Regular fixer commands accept (buffer, [input]) " Regular fixer commands accept (buffer, [input])
let l:result = ale#util#FunctionArgCount(l:Function) == 1 let l:result = ale#util#FunctionArgCount(l:Function) == 1
\ ? call(l:Function, [l:buffer]) \ ? call(l:Function, [l:buffer])
\ : call(l:Function, [l:buffer, copy(l:input)]) \ : call(l:Function, [l:buffer, copy(l:input)])
endif
call s:RunJob(l:result, { call s:RunJob(l:result, {
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'callback_index': l:index, \ 'callback_index': l:index,
\ 'fixer_name': l:fixer_name,
\}) \})
endfunction endfunction
@ -293,16 +287,24 @@ function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
" Variables with capital characters are needed, or Vim will complain about " Variables with capital characters are needed, or Vim will complain about
" funcref variables. " funcref variables.
for l:Item in l:callback_list for l:Item in l:callback_list
" Try to capture the names of registered fixer names, so we can use
" them for filename mapping or other purposes later.
let l:fixer_name = v:null
if type(l:Item) is v:t_string if type(l:Item) is v:t_string
let l:Func = ale#fix#registry#GetFunc(l:Item) let l:Func = ale#fix#registry#GetFunc(l:Item)
if !empty(l:Func) if !empty(l:Func)
let l:fixer_name = l:Item
let l:Item = l:Func let l:Item = l:Func
endif endif
endif endif
try try
call add(l:corrected_list, ale#util#GetFunction(l:Item)) call add(l:corrected_list, [
\ l:fixer_name,
\ ale#util#GetFunction(l:Item)
\])
catch /E475/ catch /E475/
" Rethrow exceptions for failing to get a function so we can print " Rethrow exceptions for failing to get a function so we can print
" a friendly message about it. " a friendly message about it.

View file

@ -375,6 +375,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['html', 'htmldjango'], \ 'suggested_filetypes': ['html', 'htmldjango'],
\ 'description': 'Fix HTML files with html-beautify.', \ 'description': 'Fix HTML files with html-beautify.',
\ }, \ },
\ 'dhall': {
\ 'function': 'ale#fixers#dhall#Fix',
\ 'suggested_filetypes': ['dhall'],
\ 'description': 'Fix Dhall files with dhall-format.',
\ },
\} \}
" Reset the function registry to the default entries. " Reset the function registry to the default entries.

View file

@ -0,0 +1,23 @@
" Author: Pat Brisbin <pbrisbin@gmail.com>
" Description: Integration of dhall-format with ALE.
call ale#Set('dhall_format_executable', 'dhall')
function! ale#fixers#dhall#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'dhall_format_executable')
" Dhall is written in Haskell and commonly installed with Stack
return ale#handlers#haskell_stack#EscapeExecutable(l:executable, 'dhall')
endfunction
function! ale#fixers#dhall#Fix(buffer) abort
let l:executable = ale#fixers#dhall#GetExecutable(a:buffer)
return {
\ 'command': l:executable
\ . ' format'
\ . ' --inplace'
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View file

@ -10,9 +10,7 @@ function! ale#fixers#latexindent#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . ' -l -w' \ . ' -l'
\ . (empty(l:options) ? '' : ' ' . l:options) \ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t',
\ 'read_temporary_file': 1,
\} \}
endfunction endfunction

View file

@ -5,14 +5,13 @@ call ale#Set('ocaml_ocamlformat_executable', 'ocamlformat')
call ale#Set('ocaml_ocamlformat_options', '') call ale#Set('ocaml_ocamlformat_options', '')
function! ale#fixers#ocamlformat#Fix(buffer) abort function! ale#fixers#ocamlformat#Fix(buffer) abort
let l:filename = expand('#' . a:buffer . ':p')
let l:executable = ale#Var(a:buffer, 'ocaml_ocamlformat_executable') let l:executable = ale#Var(a:buffer, 'ocaml_ocamlformat_executable')
let l:options = ale#Var(a:buffer, 'ocaml_ocamlformat_options') let l:options = ale#Var(a:buffer, 'ocaml_ocamlformat_options')
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options) \ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' --name=' . ale#Escape(l:filename) \ . ' --name=%s'
\ . ' -' \ . ' -'
\} \}
endfunction endfunction

View file

@ -34,6 +34,21 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
return a:output return a:output
endfunction endfunction
function! ale#fixers#prettier#GetProjectRoot(buffer) abort
let l:config = ale#path#FindNearestFile(a:buffer, '.prettierignore')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
" Fall back to the directory of the buffer
return fnamemodify(bufname(a:buffer), ':p:h')
endfunction
function! ale#fixers#prettier#CdProjectRoot(buffer) abort
return ale#path#CdString(ale#fixers#prettier#GetProjectRoot(a:buffer))
endfunction
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer) let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'javascript_prettier_options') let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
@ -97,7 +112,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
" 1.4.0 is the first version with --stdin-filepath " 1.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(a:version, [1, 4, 0]) if ale#semver#GTE(a:version, [1, 4, 0])
return { return {
\ 'command': ale#path#BufferCdString(a:buffer) \ 'command': ale#fixers#prettier#CdProjectRoot(a:buffer)
\ . ale#Escape(l:executable) \ . ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',

View file

@ -29,8 +29,7 @@ function! ale#fixers#rubocop#GetCommand(buffer) abort
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct') \ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct')
\ . ' --force-exclusion --stdin ' \ . ' --force-exclusion --stdin %s'
\ . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction endfunction
function! ale#fixers#rubocop#Fix(buffer) abort function! ale#fixers#rubocop#Fix(buffer) abort

View file

@ -32,7 +32,7 @@ let s:default_ale_linter_aliases = {
" "
" No linters are used for plaintext files by default. " No linters are used for plaintext files by default.
" "
" Only cargo is enabled for Rust by default. " Only cargo and rls are enabled for Rust by default.
" rpmlint is disabled by default because it can result in code execution. " rpmlint is disabled by default because it can result in code execution.
" hhast is disabled by default because it executes code in the project root. " hhast is disabled by default because it executes code in the project root.
" "
@ -46,7 +46,7 @@ let s:default_ale_linters = {
\ 'perl': ['perlcritic'], \ 'perl': ['perlcritic'],
\ 'perl6': [], \ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'], \ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'rust': ['cargo'], \ 'rust': ['cargo', 'rls'],
\ 'spec': [], \ 'spec': [],
\ 'text': [], \ 'text': [],
\ 'vue': ['eslint', 'vls'], \ 'vue': ['eslint', 'vls'],
@ -211,21 +211,17 @@ function! ale#linter#PreProcess(filetype, linter) abort
" file on disk. " file on disk.
let l:obj.lint_file = get(a:linter, 'lint_file', 0) let l:obj.lint_file = get(a:linter, 'lint_file', 0)
if !s:IsBoolean(l:obj.lint_file) if !s:IsBoolean(l:obj.lint_file) && type(l:obj.lint_file) isnot v:t_func
throw '`lint_file` must be `0` or `1`' throw '`lint_file` must be `0`, `1`, or a Function'
endif endif
" An option indicating that the buffer should be read. " An option indicating that the buffer should be read.
let l:obj.read_buffer = get(a:linter, 'read_buffer', !l:obj.lint_file) let l:obj.read_buffer = get(a:linter, 'read_buffer', 1)
if !s:IsBoolean(l:obj.read_buffer) if !s:IsBoolean(l:obj.read_buffer)
throw '`read_buffer` must be `0` or `1`' throw '`read_buffer` must be `0` or `1`'
endif endif
if l:obj.lint_file && l:obj.read_buffer
throw 'Only one of `lint_file` or `read_buffer` can be `1`'
endif
let l:obj.aliases = get(a:linter, 'aliases', []) let l:obj.aliases = get(a:linter, 'aliases', [])
if type(l:obj.aliases) isnot v:t_list if type(l:obj.aliases) isnot v:t_list

View file

@ -265,7 +265,14 @@ function! s:StartLSP(options, address, executable, command) abort
call ale#lsp#MarkConnectionAsTsserver(l:conn_id) call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif endif
let l:command = ale#command#FormatCommand(l:buffer, a:executable, a:command, 0, v:false)[1] let l:command = ale#command#FormatCommand(
\ l:buffer,
\ a:executable,
\ a:command,
\ 0,
\ v:false,
\ [],
\)[1]
let l:command = ale#job#PrepareCommand(l:buffer, l:command) let l:command = ale#job#PrepareCommand(l:buffer, l:command)
let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command) let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
endif endif

View file

@ -24,6 +24,14 @@ function! ale#path#Simplify(path) abort
return substitute(simplify(l:win_path), '^\\\+', '\', 'g') " no-custom-checks return substitute(simplify(l:win_path), '^\\\+', '\', 'g') " no-custom-checks
endfunction endfunction
" Simplify a path without a Windows drive letter.
" This function can be used for checking if paths are equal.
function! ale#path#RemoveDriveLetter(path) abort
return has('win32') && a:path[1:2] is# ':\'
\ ? ale#path#Simplify(a:path[2:])
\ : ale#path#Simplify(a:path)
endfunction
" Given a buffer and a filename, find the nearest file by searching upwards " Given a buffer and a filename, find the nearest file by searching upwards
" through the paths relative to the given buffer. " through the paths relative to the given buffer.
function! ale#path#FindNearestFile(buffer, filename) abort function! ale#path#FindNearestFile(buffer, filename) abort
@ -74,15 +82,19 @@ endfunction
function! ale#path#CdString(directory) abort function! ale#path#CdString(directory) abort
if has('win32') if has('win32')
return 'cd /d ' . ale#Escape(a:directory) . ' && ' return 'cd /d ' . ale#Escape(a:directory) . ' && '
else
return 'cd ' . ale#Escape(a:directory) . ' && '
endif endif
return 'cd ' . ale#Escape(a:directory) . ' && '
endfunction endfunction
" Output 'cd <buffer_filename_directory> && ' " Output 'cd <buffer_filename_directory> && '
" This function can be used changing the directory for a linter command. " This function can be used changing the directory for a linter command.
function! ale#path#BufferCdString(buffer) abort function! ale#path#BufferCdString(buffer) abort
return ale#path#CdString(fnamemodify(bufname(a:buffer), ':p:h')) if has('win32')
return 'cd /d %s:h && '
endif
return 'cd %s:h && '
endfunction endfunction
" Return 1 if a path is an absolute path. " Return 1 if a path is an absolute path.
@ -95,7 +107,7 @@ function! ale#path#IsAbsolute(filename) abort
return a:filename[:0] is# '/' || a:filename[1:2] is# ':\' return a:filename[:0] is# '/' || a:filename[1:2] is# ':\'
endfunction endfunction
let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h')) let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h:h'))
" Given a filename, return 1 if the file represents some temporary file " Given a filename, return 1 if the file represents some temporary file
" created by Vim. " created by Vim.

View file

@ -1,14 +1,22 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Preview windows for showing whatever information in. " Description: Preview windows for showing whatever information in.
if !has_key(s:, 'last_selection_list') if !has_key(s:, 'last__list')
let s:last_selection_list = [] let s:last_list = []
endif endif
if !has_key(s:, 'last_selection_open_in') if !has_key(s:, 'last_options')
let s:last_selection_open_in = 'current-buffer' let s:last_options = {}
endif endif
function! ale#preview#SetLastSelection(item_list, options) abort
let s:last_list = a:item_list
let s:last_options = {
\ 'open_in': get(a:options, 'open_in', 'current-buffer'),
\ 'use_relative_paths': get(a:options, 'use_relative_paths', 0),
\}
endfunction
" Open a preview window and show some lines in it. " Open a preview window and show some lines in it.
" A second argument can be passed as a Dictionary with options. They are... " A second argument can be passed as a Dictionary with options. They are...
" "
@ -81,19 +89,14 @@ function! ale#preview#ShowSelection(item_list, ...) abort
let b:ale_preview_item_list = a:item_list let b:ale_preview_item_list = a:item_list
let b:ale_preview_item_open_in = get(l:options, 'open_in', 'current-buffer') let b:ale_preview_item_open_in = get(l:options, 'open_in', 'current-buffer')
" Remove the last preview " Remember preview state, so we can repeat it later.
let s:last_selection_list = b:ale_preview_item_list call ale#preview#SetLastSelection(a:item_list, l:options)
let s:last_selection_open_in = b:ale_preview_item_open_in
endfunction endfunction
function! ale#preview#RepeatSelection() abort function! ale#preview#RepeatSelection() abort
if empty(s:last_selection_list) if !empty(s:last_list)
return call ale#preview#ShowSelection(s:last_list, s:last_options)
endif endif
call ale#preview#ShowSelection(s:last_selection_list, {
\ 'open_in': s:last_selection_open_in,
\})
endfunction endfunction
function! s:Open(open_in) abort function! s:Open(open_in) abort

View file

@ -505,6 +505,13 @@ function! ale#util#SetBufferContents(buffer, lines) abort
\ : a:lines \ : a:lines
let l:first_line_to_remove = len(l:new_lines) + 1 let l:first_line_to_remove = len(l:new_lines) + 1
" We'll temporarily make a buffer modifiable, to force edits.
let l:modifiable = getbufvar(a:buffer, '&modifiable')
if !l:modifiable
call setbufvar(a:buffer, '&modifiable', 1)
endif
" Use a Vim API for setting lines in other buffers, if available. " Use a Vim API for setting lines in other buffers, if available.
if l:has_bufline_api if l:has_bufline_api
call setbufline(a:buffer, 1, l:new_lines) call setbufline(a:buffer, 1, l:new_lines)
@ -523,5 +530,9 @@ function! ale#util#SetBufferContents(buffer, lines) abort
call setline(1, l:new_lines) call setline(1, l:new_lines)
endif endif
if !l:modifiable
call setbufvar(a:buffer, '&modifiable', 0)
endif
return l:new_lines return l:new_lines
endfunction endfunction

View file

@ -13,6 +13,7 @@ CONTENTS *ale-development-contents*
4. Testing ALE..........................|ale-development-tests| 4. Testing ALE..........................|ale-development-tests|
4.1. Writing Linter Tests.............|ale-development-linter-tests| 4.1. Writing Linter Tests.............|ale-development-linter-tests|
4.2. Writing Fixer Tests..............|ale-development-fixer-tests| 4.2. Writing Fixer Tests..............|ale-development-fixer-tests|
4.3. Running Tests in a Windows VM....|ale-development-windows-tests|
=============================================================================== ===============================================================================
1. Introduction *ale-development-introduction* 1. Introduction *ale-development-introduction*
@ -170,6 +171,11 @@ will run all of the tests in Vader, Vint checks, and several Bash scripts for
finding extra issues. Run `./run-tests --help` to see all of the options the finding extra issues. Run `./run-tests --help` to see all of the options the
script supports. Note that the script supports selecting particular test files. script supports. Note that the script supports selecting particular test files.
Once you get used to dealing with Vim and NeoVim compatibility issues, you
probably want to use `./run-tests --fast -q` for running tests with only the
fastest available Vim version, and with success messages from tests
suppressed.
Generally write tests for any changes you make. The following types of tests Generally write tests for any changes you make. The following types of tests
are recommended for the following types of code. are recommended for the following types of code.
@ -353,5 +359,81 @@ given the above setup are as follows.
`AssertFixerNotExecuted` - Check that fixers will not be executed. `AssertFixerNotExecuted` - Check that fixers will not be executed.
===============================================================================
4.3 Running Tests in a Windows VM *ale-development-windows-tests*
Tests are run for ALE in a build of Vim 8 for Windows via AppVeyor. These
tests can frequently break due to minor differences in paths and how escaping
is done for commands on Windows. If you are a Linux or Mac user, running these
tests locally can be difficult. Here is a process that will make that easier.
First, you want to install a Windows image with VirtualBox. Install VirtualBox
and grab a VirtualBox image for Windows such as from here:
https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/
NOTE: If you need to enter a password for the virtual machine at any point,
the password is "Passw0rd!" without the double quotes.
NOTE: If your trial period for Windows runs out, run the commands like the
wallpaper tells you to.
Your virtual machine will need to have PowerShell installed. Before you go any
further, confirm that PowerShell is installed in your Windows virtual machine.
Consult the VirtualBox documentation on how to install "Guest Additions."
You probably want to install "Guest Additions" for most things to work
properly.
After you've loaded your virtual machine image, go into "Settings" for your
virtual machine, and "Shared Folders." Add a shared folder with the name
"ale", and set the "Folder Path" to the path to your ALE repository, for
example: "/home/w0rp/ale"
Find out which drive letter "ale" has been mounted as in Windows. We'll use
"E:" as the drive letter, for example. Open the command prompt as an
administrator by typing in `cmd` in the start menu, right clicking on the
command prompt application, and clicking "Run as administrator." Click "Yes"
when prompted to ask if you're sure you want to run the command prompt. You
should type in the following command to mount the "ale" directory for testing,
where "E:" is replaced with your drive letter. >
mklink /D C:\testplugin E:
<
Close the administrator Command Prompt, and try running the command
`type C:\testplugin\LICENSE` in a new Command Prompt which you are NOT running
as administrator. You should see the license for ALE in your terminal. After
you have confirmed that you have mounted ALE on your machine, search in the
Start Menu for "power shell," run PowerShell as an administrator, and issue
the following commands to install the correct Vim and Vader versions for
running tests. >
Add-Type -A System.IO.Compression.FileSystem
Invoke-WebRequest ftp://ftp.vim.org/pub/vim/pc/vim80-586w32.zip -OutFile C:\vim.zip
[IO.Compression.ZipFile]::ExtractToDirectory('C:\vim.zip', 'C:\vim')
rm C:\vim.zip
Invoke-WebRequest ftp://ftp.vim.org/pub/vim/pc/vim80-586rt.zip -OutFile C:\rt.zip
[IO.Compression.ZipFile]::ExtractToDirectory('C:\rt.zip', 'C:\vim')
rm C:\rt.zip
Invoke-WebRequest https://github.com/junegunn/vader.vim/archive/c6243dd81c98350df4dec608fa972df98fa2a3af.zip -OutFile C:\vader.zip
[IO.Compression.ZipFile]::ExtractToDirectory('C:\vader.zip', 'C:\')
mv C:\vader.vim-c6243dd81c98350df4dec608fa972df98fa2a3af C:\vader
rm C:\vader.zip
<
After you have finished installing everything, you can run all of the tests
in Windows by opening a Command Prompt NOT as an administrator by navigating
to the directory where you've mounted the ALE code, which must be named
`C:\testplugin`, and by running the `run-tests.bat` batch file. >
cd C:\testplugin
run-tests
<
It will probably take several minutes for all of the tests to run. Be patient.
You can run a specific test by passing the filename as an argument to the
batch file, for example: `run-tests test/test_c_flag_parsing.vader` . This will
give you results much more quickly.
=============================================================================== ===============================================================================
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

@ -31,11 +31,11 @@ Integration Information
5. rustfmt -- If you have `rustfmt` installed, you can use it as a fixer to 5. rustfmt -- If you have `rustfmt` installed, you can use it as a fixer to
consistently reformat your Rust code. consistently reformat your Rust code.
Only cargo is enabled by default. To switch to using rustc instead of cargo, Only cargo and rls are enabled by default. To switch to using rustc instead
configure |g:ale_linters| appropriately: > of cargo, configure |g:ale_linters| appropriately: >
" See the help text for the option for more information. " See the help text for the option for more information.
let g:ale_linters = {'rust': ['rustc']} let g:ale_linters = {'rust': ['rustc', 'rls']}
< <
Also note that rustc 1.12. or later is needed. Also note that rustc 1.12. or later is needed.
@ -60,6 +60,7 @@ g:ale_rust_analyzer_config *g:ale_rust_analyzer_config*
Dictionary with configuration settings for rust-analyzer. Dictionary with configuration settings for rust-analyzer.
=============================================================================== ===============================================================================
cargo *ale-rust-cargo* cargo *ale-rust-cargo*
@ -252,14 +253,15 @@ g:ale_rust_ignore_error_codes *g:ale_rust_ignore_error_codes*
> >
let g:ale_rust_ignore_error_codes = ['E0432', 'E0433'] let g:ale_rust_ignore_error_codes = ['E0432', 'E0433']
g:ale_rust_ignore_secondary_spans *g:ale_rust_ignore_secondary_spans* g:ale_rust_ignore_secondary_spans *g:ale_rust_ignore_secondary_spans*
*b:ale_rust_ignore_secondary_spans* *b:ale_rust_ignore_secondary_spans*
Type: Number Type: Number
Default: 0 Default: 0
When set to 1, instructs the Rust error repporting to ignore secondary When set to 1, instructs the Rust error reporting to ignore secondary spans.
spans. The problem with secondary spans is that they sometimes appear in The problem with secondary spans is that they sometimes appear in error
error messages before the main cause of the error, for example: > messages before the main cause of the error, for example: >
1 src/main.rs|98 col 5 error| this function takes 4 parameters but 5 1 src/main.rs|98 col 5 error| this function takes 4 parameters but 5
parameters were supplied: defined here parameters were supplied: defined here
@ -269,6 +271,7 @@ g:ale_rust_ignore_secondary_spans *g:ale_rust_ignore_secondary_spans*
This is due to the sorting by line numbers. With this option set to 1, This is due to the sorting by line numbers. With this option set to 1,
the 'defined here' span will not be presented. the 'defined here' span will not be presented.
=============================================================================== ===============================================================================
rustfmt *ale-rust-rustfmt* rustfmt *ale-rust-rustfmt*

View file

@ -120,6 +120,8 @@ Notes:
* `dartanalyzer`!! * `dartanalyzer`!!
* `dartfmt`!! * `dartfmt`!!
* `language_server` * `language_server`
* Dhall
* `dhall-format`
* Dockerfile * Dockerfile
* `dockerfile_lint` * `dockerfile_lint`
* `hadolint` * `hadolint`
@ -448,6 +450,7 @@ Notes:
* `sqlfmt` * `sqlfmt`
* `sqlformat` * `sqlformat`
* `sqlint` * `sqlint`
* `sql-lint`
* Stylus * Stylus
* `stylelint` * `stylelint`
* SugarSS * SugarSS

View file

@ -9,8 +9,9 @@ CONTENTS *ale-contents*
1. Introduction.........................|ale-introduction| 1. Introduction.........................|ale-introduction|
2. Supported Languages & Tools..........|ale-support| 2. Supported Languages & Tools..........|ale-support|
3. Linting..............................|ale-lint| 3. Linting..............................|ale-lint|
3.1 Adding Language Servers...........|ale-lint-language-servers| 3.1 Linting On Other Machines.........|ale-lint-other-machines|
3.2 Other Sources.....................|ale-lint-other-sources| 3.2 Adding Language Servers...........|ale-lint-language-servers|
3.3 Other Sources.....................|ale-lint-other-sources|
4. Fixing Problems......................|ale-fix| 4. Fixing Problems......................|ale-fix|
5. Language Server Protocol Support.....|ale-lsp| 5. Language Server Protocol Support.....|ale-lsp|
5.1 Completion........................|ale-completion| 5.1 Completion........................|ale-completion|
@ -148,7 +149,61 @@ ALE offers several options for controlling which linters are run.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
3.1 Adding Language Servers *ale-lint-language-servers* 3.1 Linting On Other Machines *ale-lint-other-machines*
ALE offers support for running linters or fixers on files you are editing
locally on other machines, so long as the other machine has access the file
you are editing. This could be a linter or fixer run inside of a Docker image,
running in a virtual machine, running on a remote server, etc.
In order to run tools on other machines, you will need to configure your tools
to run via scripts that execute commands on those machines, such as by setting
the ALE `_executable` options for those tools to a path for a script to run,
or by using |g:ale_command_wrapper| to specify a script to wrap all commands
that are run by ALE, before they are executed. For tools that ALE runs where
ALE looks for locally installed executables first, you may need to set the
`_use_global` options for those tools to `1`, or you can set
|g:ale_use_global_executables| to `1` before ALE is loaded to only use global
executables for all tools.
In order for ALE to properly lint or fix files which are running on another
file system, you must provide ALE with |List|s of strings for mapping paths to
and from your local file system and the remote file system, such as the file
system of your Docker container. See |g:ale_filename_mappings| for all of the
different ways these filename mappings can be configured.
For example, you might configure `pylint` to run via Docker by creating a
script like so. >
#!/usr/bin/env bash
exec docker run --rm -v "$(pwd):/data" cytopia/pylint "$@"
<
With the above script in mind, you might configure ALE to lint your Python
project with `pylint` by providing the path to the script to execute, and
mappings which describe how to between the two file systems in your
`python.vim` |ftplugin| file, like so: >
if expand('%:p') =~# '^/home/w0rp/git/test-pylint/'
let b:ale_linters = ['pylint']
let b:ale_python_pylint_use_global = 1
" This is the path to the script above.
let b:ale_python_pylint_executable = '/home/w0rp/git/test-pylint/pylint.sh'
" /data matches the path in Docker.
let b:ale_filename_mappings = {
\ 'pylint': [
\ ['/home/w0rp/git/test-pylint', '/data'],
\ ],
\}
endif
<
You might consider using a Vim plugin for loading Vim configuration files
specific to each project, if you have a lot of projects to manage.
-------------------------------------------------------------------------------
3.2 Adding Language Servers *ale-lint-language-servers*
ALE comes with many default configurations for language servers, so they can ALE comes with many default configurations for language servers, so they can
be detected and run automatically. ALE can connect to other language servers be detected and run automatically. ALE can connect to other language servers
@ -189,7 +244,7 @@ address to connect to instead. >
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
3.2 Other Sources *ale-lint-other-sources* 3.3 Other Sources *ale-lint-other-sources*
Problems for a buffer can be taken from other sources and rendered by ALE. Problems for a buffer can be taken from other sources and rendered by ALE.
This allows ALE to be used in combination with other plugins which also want This allows ALE to be used in combination with other plugins which also want
@ -287,6 +342,8 @@ are supported for running the commands.
file will be created, containing the lines from the file file will be created, containing the lines from the file
after previous adjustment have been done. after previous adjustment have been done.
See |ale-command-format-strings| for formatting options.
`read_temporary_file` When set to `1`, ALE will read the contents of the `read_temporary_file` When set to `1`, ALE will read the contents of the
temporary file created for `%t`. This option can be used temporary file created for `%t`. This option can be used
for commands which need to modify some file on disk in for commands which need to modify some file on disk in
@ -356,6 +413,10 @@ by default.
Fixers can be disabled on save with |g:ale_fix_on_save_ignore|. They will Fixers can be disabled on save with |g:ale_fix_on_save_ignore|. They will
still be run when you manually run |ALEFix|. still be run when you manually run |ALEFix|.
Fixers can be run on another machines, just like linters, such as fixers run
from a Docker container, running in a virtual machine, running a remote
server, etc. See |ale-lint-other-machines|.
=============================================================================== ===============================================================================
5. Language Server Protocol Support *ale-lsp* 5. Language Server Protocol Support *ale-lsp*
@ -501,15 +562,9 @@ displayed.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
5.4 Find References *ale-find-references* 5.4 Find References *ale-find-references*
ALE supports finding references for symbols though any enabled LSP linters. ALE supports finding references for symbols though any enabled LSP linters
ALE will display a preview window showing the places where a symbol is with the |ALEFindReferences| command. See the documentation for the command
referenced in a codebase when a command is run. The following commands are for a full list of options.
supported:
|ALEFindReferences| - Find references for the word under the cursor.
Options:
`-relative` Show file paths in the results relative to the working dir
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
5.5 Hovering *ale-hover* 5.5 Hovering *ale-hover*
@ -552,13 +607,9 @@ Documentation for symbols at the cursor can be retrieved using the
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
5.6 Symbol Search *ale-symbol-search* 5.6 Symbol Search *ale-symbol-search*
ALE supports searching for workspace symbols via LSP linters. The following ALE supports searching for workspace symbols via LSP linters with the
commands are supported: |ALESymbolSearch| command. See the documentation for the command
for a full list of options.
|ALESymbolSearch| - Search for symbols in the workspace.
Options:
`-relative` Show file paths in the results relative to the working dir
=============================================================================== ===============================================================================
6. Global Options *ale-options* 6. Global Options *ale-options*
@ -810,7 +861,7 @@ g:ale_default_navigation *g:ale_default_navigation*
Default: `'buffer'` Default: `'buffer'`
The default method for navigating away from the current buffer to another The default method for navigating away from the current buffer to another
buffer, such as for |ALEFindReferences:|, or |ALEGoToDefinition|. buffer, such as for |ALEFindReferences|, or |ALEGoToDefinition|.
g:ale_disable_lsp *g:ale_disable_lsp* g:ale_disable_lsp *g:ale_disable_lsp*
@ -1121,7 +1172,7 @@ g:ale_list_window_size *g:ale_list_window_size*
g:ale_lint_delay *g:ale_lint_delay* g:ale_lint_delay *g:ale_lint_delay*
*b:ale_lint_delay*
Type: |Number| Type: |Number|
Default: `200` Default: `200`
@ -1129,6 +1180,9 @@ g:ale_lint_delay *g:ale_lint_delay*
be run after text is changed. This option is only meaningful with the be run after text is changed. This option is only meaningful with the
|g:ale_lint_on_text_changed| variable set to `always`, `insert`, or `normal`. |g:ale_lint_on_text_changed| variable set to `always`, `insert`, or `normal`.
A buffer-local option, `b:ale_lint_delay`, can be set to change the delay
for different buffers, such as in |ftplugin| files.
g:ale_lint_on_enter *g:ale_lint_on_enter* g:ale_lint_on_enter *g:ale_lint_on_enter*
@ -1286,6 +1340,90 @@ g:ale_linter_aliases *g:ale_linter_aliases*
< <
No linters will be loaded when the buffer's filetype is empty. No linters will be loaded when the buffer's filetype is empty.
g:ale_filename_mappings *g:ale_filename_mappings*
*b:ale_filename_mappings*
Type: |Dictionary| or |List|
Default: `{}`
Either a |Dictionary| mapping a linter or fixer name, as displayed in
|:ALEInfo|, to a |List| of two-item |List|s for filename mappings, or just a
|List| of two-item |List|s. When given some paths to files, the value of
this setting will be used to convert filenames on a local file system to
filenames on some remote file system, such as paths in a Docker image,
virtual machine, or network drive.
For example: >
let g:ale_filename_mappings = {
\ 'pylint': [
\ ['/home/john/proj', '/data'],
\ ],
\}
<
With the above configuration, a filename such as `/home/john/proj/foo.py`
will be provided to the linter/fixer as `/data/foo.py`, and paths parsed
from linter results such as `/data/foo.py` will be converted back to
`/home/john/proj/foo.py`.
You can use `*` as to apply a |List| of filename mappings to all other
linters or fixers not otherwise matched. >
" Use one List of paths for pylint.
" Use another List of paths for everything else.
let g:ale_filename_mappings = {
\ 'pylint': [
\ ['/home/john/proj', '/data'],
\ ],
\ '*': [
\ ['/home/john/proj', '/other-data'],
\ ],
\}
<
If you just want every single linter or fixer to use the same filename
mapping, you can just use a |List|. >
" Same as above, but for ALL linters and fixers.
let g:ale_filename_mappings = [
\ ['/home/john/proj', '/data'],
\]
<
You can provide many such filename paths for multiple projects. Paths are
matched by checking if the start of a file path matches the given strings,
in a case-sensitive manner. Earlier entries in the |List| will be tried
before later entries when mapping to a given file system.
Buffer-local options can be set to the same values to override the global
options, such as in |ftplugin| files.
NOTE: Only fixers registered with a short name can support filename mapping
by their fixer names. See |ale-fix|. Filename mappings set for all tools by
using only a |List| for the setting will also be applied to fixers not in
the registry.
NOTE: In order for this filename mapping to work correctly, linters and
fixers must exclusively determine paths to files to lint or fix via ALE
command formatting as per |ale-command-format-strings|, and paths parsed
from linter files must be provided in `filename` keys if a linter returns
results for more than one file at a time, as per |ale-loclist-format|. If
you discover a linter or fixer which does not behave properly, please report
it as an issue.
If you are running a linter or fixer through Docker or another remote file
system, you may have to mount your temporary directory, which you can
discover with the following command: >
:echo fnamemodify(tempname(), ':h:h')
<
You should provide a mapping from this temporary directory to whatever you
mount this directory to in Docker, or whatever remote file system you are
working with.
You can inspect the filename mappings ALE will use with the
|ale#GetFilenameMappings()| function.
g:ale_linters *g:ale_linters* g:ale_linters *g:ale_linters*
*b:ale_linters* *b:ale_linters*
Type: |Dictionary| Type: |Dictionary|
@ -1306,7 +1444,7 @@ g:ale_linters *g:ale_linters*
\ 'perl': ['perlcritic'], \ 'perl': ['perlcritic'],
\ 'perl6': [], \ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'], \ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'rust': ['cargo'], \ 'rust': ['cargo', 'rls'],
\ 'spec': [], \ 'spec': [],
\ 'text': [], \ 'text': [],
\ 'vue': ['eslint', 'vls'], \ 'vue': ['eslint', 'vls'],
@ -2767,13 +2905,20 @@ ALEFindReferences *ALEFindReferences*
The default method used for navigating to a new location can be changed The default method used for navigating to a new location can be changed
by modifying |g:ale_default_navigation|. by modifying |g:ale_default_navigation|.
You can add `-relative` to the command to view results with relatives paths,
instead of absolute paths.
The selection can be opened again with the |ALERepeatSelection| command. The selection can be opened again with the |ALERepeatSelection| command.
You can jump back to the position you were at before going to a reference of You can jump back to the position you were at before going to a reference of
something with jump motions like CTRL-O. See |jump-motions|. something with jump motions like CTRL-O. See |jump-motions|.
A plug mapping `<Plug>(ale_find_references)` is defined for this command. A plug mapping `<Plug>(ale_find_references)` is defined for this command.
You can define additional plug mapping with any additional options you want
like so: >
nnoremap <silent> <Plug>(my_mapping) :ALEFindReferences -relative<Return>
<
ALEFix *ALEFix* ALEFix *ALEFix*
@ -2885,14 +3030,17 @@ ALESymbolSearch `<query>` *ALESymbolSearch*
The arguments provided to this command will be used as a search query for The arguments provided to this command will be used as a search query for
finding symbols in the workspace, such as functions, types, etc. finding symbols in the workspace, such as functions, types, etc.
You can add `-relative` to the command to view results with relatives paths,
instead of absolute paths.
*:ALELint* *:ALELint*
ALELint *ALELint* ALELint *ALELint*
Run ALE once for the current buffer. This command can be used to run ALE Run ALE once for the current buffer. This command can be used to run ALE
manually, instead of automatically, if desired. manually, instead of automatically, if desired.
This command will also run linters where `lint_file` is set to `1`, or in This command will also run linters where `lint_file` is evaluates to `1`,
other words linters which check the file instead of the Vim buffer. meaning linters which check the file instead of the Vim buffer.
A plug mapping `<Plug>(ale_lint)` is defined for this command. A plug mapping `<Plug>(ale_lint)` is defined for this command.
@ -3074,6 +3222,15 @@ ale#Env(variable_name, value) *ale#Env()*
'set VAR="some value" && command' # On Windows 'set VAR="some value" && command' # On Windows
ale#GetFilenameMappings(buffer, name) *ale#GetFilenameMappings()*
Given a `buffer` and the `name` of either a linter for fixer, return a
|List| of two-item |List|s that describe mapping to and from the local and
foreign file systems for running a particular linter or fixer.
See |g:ale_filename_mappings| for details on filename mapping.
ale#Has(feature) *ale#Has()* ale#Has(feature) *ale#Has()*
Return `1` if ALE supports a given feature, like |has()| for Vim features. Return `1` if ALE supports a given feature, like |has()| for Vim features.
@ -3096,9 +3253,9 @@ ale#Queue(delay, [linting_flag, buffer_number]) *ale#Queue()*
The linters will always be run in the background. Calling this function The linters will always be run in the background. Calling this function
again from the same buffer again from the same buffer
An optional `linting_flag` argument can be given. If `linting_flag` An optional `linting_flag` argument can be given. If `linting_flag` is
is `'lint_file'`, then linters where the `lint_file` option is set to `1` will be `'lint_file'`, then linters where the `lint_file` option evaluates to `1`
run. Linters with `lint_file` set to `1` are not run by default. will be run. Otherwise, those linters will not be run.
An optional `buffer_number` argument can be given for specifying the buffer An optional `buffer_number` argument can be given for specifying the buffer
to check. The active buffer (`bufnr('')`) will be checked by default. to check. The active buffer (`bufnr('')`) will be checked by default.
@ -3188,23 +3345,36 @@ ale#command#Run(buffer, command, callback, [options]) *ale#command#Run()*
< <
The following `options` can be provided. The following `options` can be provided.
`output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or `'none`' for `output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or
selecting which output streams to read lines from. `'none`' for selecting which output streams to read
lines from.
The default is `'stdout'` The default is `'stdout'`
`executable` - An executable for formatting into `%e` in the command. `executable` - An executable for formatting into `%e` in the
If this option is not provided, formatting commands with command. If this option is not provided, formatting
`%e` will not work. commands with `%e` will not work.
`read_buffer` - If set to `1`, the buffer will be piped into the `read_buffer` - If set to `1`, the buffer will be piped into the
command. command.
The default is `0`. The default is `0`.
`input` - When creating temporary files with `%t` or piping text `input` - When creating temporary files with `%t` or piping
into a command `input` can be set to a |List| of text to text into a command `input` can be set to a |List| of
use instead of the buffer's text. text to use instead of the buffer's text.
`filename_mappings` - A |List| of two-item |List|s describing filename
mappings to apply for formatted filenames in the
command string, as per |g:ale_filename_mappings|.
If the call to this function is being used for a
linter or fixer, the mappings should be provided with
this option, and can be retrieved easily with
|ale#GetFilenameMappings()|.
The default is `[]`.
ale#command#EscapeCommandPart(command_part) *ale#command#EscapeCommandPart()* ale#command#EscapeCommandPart(command_part) *ale#command#EscapeCommandPart()*
@ -3419,24 +3589,30 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
if a command manually reads from a temporary file if a command manually reads from a temporary file
instead, etc. instead, etc.
This option behaves as if it was set to `0` when the
`lint_file` option evaluates to `1`.
*ale-lint-file* *ale-lint-file*
`lint_file` A |Number| (`0` or `1`) indicating whether a command `lint_file` A |Number| (`0` or `1`), or a |Funcref| for a function
should read the file instead of the Vim buffer. This accepting a buffer number for computing either `0` or
option can be used for linters which must check the `1`, indicating whether a command should read the file
file on disk, and which cannot check a Vim buffer instead of the Vim buffer. This option can be used
instead. for linters which must check the file on disk, and
which cannot check a Vim buffer instead.
Linters set with this option will not be run as a The result can be computed with |ale#command#Run()|.
user types, per |g:ale_lint_on_text_changed|. Linters
will instead be run only when events occur against
the file on disk, including |g:ale_lint_on_enter|
and |g:ale_lint_on_save|. Linters with this option
set to `1` will also be run when linters are run
manually, per |ALELintPost-autocmd|.
When this option is set to `1`, `read_buffer` will Linters where the eventual value of this option
be set automatically to `0`. The two options cannot evaluates to `1` will not be run as a user types, per
be used together. |g:ale_lint_on_text_changed|. Linters will instead be
run only when events occur against the file on disk,
including |g:ale_lint_on_enter| and
|g:ale_lint_on_save|. Linters where this option
evaluates to `1` will also be run when the |ALELint|
command is run.
When this option is evaluates to `1`, ALE will behave
as if `read_buffer` was set to `0`.
*ale-lsp-linters* *ale-lsp-linters*
`lsp` A |String| for defining LSP (Language Server Protocol) `lsp` A |String| for defining LSP (Language Server Protocol)
@ -3575,6 +3751,16 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
command, so literal character sequences `%s` and `%t` can be escaped by command, so literal character sequences `%s` and `%t` can be escaped by
using `%%s` and `%%t` instead, etc. using `%%s` and `%%t` instead, etc.
Some |filename-modifiers| can be applied to `%s` and `%t`. Only `:h`, `:t`,
`:r`, and `:e` may be applied, other modifiers will be ignored. Filename
modifiers can be applied to the format markers by placing them after them.
For example: >
'command': '%s:h %s:e %s:h:t',
<
Given a path `/foo/baz/bar.txt`, the above command string will generate
something akin to `'/foo/baz' 'txt' 'baz'`
If a callback for a command generates part of a command string which might If a callback for a command generates part of a command string which might
possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting
behavior is not desired, the |ale#command#EscapeCommandPart()| function can behavior is not desired, the |ale#command#EscapeCommandPart()| function can

View file

@ -97,6 +97,10 @@ let g:ale_fix_on_save = get(g:, 'ale_fix_on_save', 0)
" should be used instead. " should be used instead.
let g:ale_enabled = get(g:, 'ale_enabled', 1) let g:ale_enabled = get(g:, 'ale_enabled', 1)
" A Dictionary mapping linter or fixer names to Arrays of two-item Arrays
" mapping filename paths from one system to another.
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
" These flags dictates if ale uses the quickfix or the loclist (loclist is the " These flags dictates if ale uses the quickfix or the loclist (loclist is the
" default, quickfix overrides loclist). " default, quickfix overrides loclist).
let g:ale_set_loclist = get(g:, 'ale_set_loclist', 1) let g:ale_set_loclist = get(g:, 'ale_set_loclist', 1)

View file

@ -16,7 +16,7 @@ formatting.
| Key | Definition | | Key | Definition |
| ------------- | -------------------------------- | | ------------- | -------------------------------- |
| :floppy_disk: | Only checked when saved to disk | | :floppy_disk: | May only run on files on disk |
| :warning: | Disabled by default | | :warning: | Disabled by default |
--- ---
@ -129,6 +129,8 @@ formatting.
* [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) :floppy_disk: * [dartanalyzer](https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli) :floppy_disk:
* [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt) * [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt)
* [language_server](https://github.com/natebosch/dart_language_server) * [language_server](https://github.com/natebosch/dart_language_server)
* Dhall
* [dhall-format](https://github.com/dhall-lang/dhall-lang)
* Dockerfile * Dockerfile
* [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint) * [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint)
* [hadolint](https://github.com/hadolint/hadolint) * [hadolint](https://github.com/hadolint/hadolint)
@ -457,6 +459,7 @@ formatting.
* [sqlfmt](https://github.com/jackc/sqlfmt) * [sqlfmt](https://github.com/jackc/sqlfmt)
* [sqlformat](https://github.com/andialbrecht/sqlparse) * [sqlformat](https://github.com/andialbrecht/sqlparse)
* [sqlint](https://github.com/purcell/sqlint) * [sqlint](https://github.com/purcell/sqlint)
* [sql-lint](https://github.com/joereynolds/sql-lint)
* Stylus * Stylus
* [stylelint](https://github.com/stylelint/stylelint) * [stylelint](https://github.com/stylelint/stylelint)
* SugarSS * SugarSS

View file

@ -18,11 +18,10 @@ After:
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()
Execute(The executable should be configurable): Execute(The executable should be configurable):
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') . ' -x ada -c -gnatc' \ ale#Escape('gcc') . ' -x ada -c -gnatc'
\ . ' -o ' . b:out_file \ . ' -o ' . b:out_file
\ . ' -I ' . ale#Escape(getcwd()) \ . ' -I %s:h'
\ . ' -gnatwa -gnatq %t' \ . ' -gnatwa -gnatq %t'
let b:ale_ada_gcc_executable = 'foo' let b:ale_ada_gcc_executable = 'foo'
@ -30,15 +29,14 @@ Execute(The executable should be configurable):
AssertLinter 'foo', AssertLinter 'foo',
\ ale#Escape('foo') . ' -x ada -c -gnatc' \ ale#Escape('foo') . ' -x ada -c -gnatc'
\ . ' -o ' . b:out_file \ . ' -o ' . b:out_file
\ . ' -I ' . ale#Escape(getcwd()) \ . ' -I %s:h'
\ . ' -gnatwa -gnatq %t' \ . ' -gnatwa -gnatq %t'
Execute(The options should be configurable): Execute(The options should be configurable):
let g:ale_ada_gcc_options = '--foo --bar' let g:ale_ada_gcc_options = '--foo --bar'
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') . ' -x ada -c -gnatc' \ ale#Escape('gcc') . ' -x ada -c -gnatc'
\ . ' -o ' . b:out_file \ . ' -o ' . b:out_file
\ . ' -I ' . ale#Escape(getcwd()) \ . ' -I %s:h'
\ . ' --foo --bar %t' \ . ' --foo --bar %t'

View file

@ -3,7 +3,7 @@ Before:
call ale#test#SetFilename('test.cpp') call ale#test#SetFilename('test.cpp')
let b:command_tail = ' -x assembler' let b:command_tail = ' -x assembler'
\ . ' -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -o ' . (has('win32') ? 'nul': '/dev/null')
\ . '-iquote ' . ale#Escape(g:dir) \ . '-iquote %s:h'
\ . ' -Wall -' \ . ' -Wall -'
After: After:

View file

@ -23,7 +23,7 @@ Before:
let b:command_tail = ' -S -x c' let b:command_tail = ' -S -x c'
\ . ' -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(getcwd()) \ . ' -iquote %s:h'
\ . ' -std=c11 -Wall -' \ . ' -std=c11 -Wall -'
After: After:

View file

@ -43,7 +43,7 @@ Execute(The C cc linter should include 'include' directories for projects with a
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
\ . ' -' \ . ' -'
@ -55,7 +55,7 @@ Execute(The C cc linter should include 'include' directories for projects with a
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include'))
\ . ' -' \ . ' -'
@ -67,7 +67,7 @@ Execute(The C cc linter should include root directories for projects with .h fil
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
\ . ' -' \ . ' -'
@ -79,7 +79,7 @@ Execute(The C cc linter should include root directories for projects with .hpp f
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
\ . ' -' \ . ' -'
@ -101,7 +101,7 @@ Execute(The C++ cc linter should include 'include' directories for projects with
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
\ . ' -' \ . ' -'
@ -113,7 +113,7 @@ Execute(The C++ cc linter should include 'include' directories for projects with
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include'))
\ . ' -' \ . ' -'
@ -125,7 +125,7 @@ Execute(The C++ cc linter should include root directories for projects with .h f
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
\ . ' -' \ . ' -'
@ -137,7 +137,7 @@ Execute(The C++ cc linter should include root directories for projects with .hpp
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
\ . ' -' \ . ' -'

View file

@ -23,7 +23,7 @@ Before:
let b:command_tail = ' -S -x c++' let b:command_tail = ' -S -x c++'
\ . ' -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(getcwd()) \ . ' -iquote %s:h'
\ . ' -std=c++14 -Wall -' \ . ' -std=c++14 -Wall -'
After: After:

View file

@ -11,14 +11,14 @@ After:
Execute(The default commands should be correct): Execute(The default commands should be correct):
AssertLinter 'go', AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'go test -c -o /dev/null ./' \ . 'go test -c -o /dev/null ./'
Execute(Go environment variables should be supported): Execute(Go environment variables should be supported):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'go', AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on') \ . ale#Env('GO111MODULE', 'on')
\ . 'go test -c -o /dev/null ./' \ . 'go test -c -o /dev/null ./'
@ -28,7 +28,7 @@ Execute(Extra options should be supported):
let g:ale_go_gobuild_options = '--foo-bar' let g:ale_go_gobuild_options = '--foo-bar'
AssertLinter 'go', AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'go test --foo-bar -c -o /dev/null ./' \ . 'go test --foo-bar -c -o /dev/null ./'
let g:ale_go_gobuild_options = '' let g:ale_go_gobuild_options = ''
@ -37,5 +37,5 @@ Execute(The executable should be configurable):
let g:ale_go_go_executable = 'foobar' let g:ale_go_go_executable = 'foobar'
AssertLinter 'foobar', AssertLinter 'foobar',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'foobar test -c -o /dev/null ./' \ . 'foobar test -c -o /dev/null ./'

View file

@ -1,5 +1,8 @@
Before: Before:
Save g:ale_go_go111module Save g:ale_go_go111module
Save b:ale_go_go111module
let b:ale_go_go111module = ''
call ale#assert#SetUpLinterTest('go', 'gofmt') call ale#assert#SetUpLinterTest('go', 'gofmt')
call ale#test#SetFilename('../go_files/testfile2.go') call ale#test#SetFilename('../go_files/testfile2.go')

View file

@ -13,7 +13,7 @@ After:
Execute(The golangci-lint defaults should be correct): Execute(The golangci-lint defaults should be correct):
AssertLinter 'golangci-lint', AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint') \ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --enable-all' \ . ' --enable-all'
@ -22,7 +22,7 @@ Execute(The golangci-lint callback should use a configured executable):
let b:ale_go_golangci_lint_executable = 'something else' let b:ale_go_golangci_lint_executable = 'something else'
AssertLinter 'something else', AssertLinter 'something else',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('something else') \ . ale#Escape('something else')
\ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --enable-all' \ . ' --enable-all'
@ -31,7 +31,7 @@ Execute(The golangci-lint callback should use configured options):
let b:ale_go_golangci_lint_options = '--foobar' let b:ale_go_golangci_lint_options = '--foobar'
AssertLinter 'golangci-lint', AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint') \ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --foobar' \ . ' --foobar'
@ -40,7 +40,7 @@ Execute(The golangci-lint callback should support environment variables):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'golangci-lint', AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on') \ . ale#Env('GO111MODULE', 'on')
\ . ale#Escape('golangci-lint') \ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' run ' . ale#Escape(expand('%' . ':t'))
@ -50,5 +50,5 @@ Execute(The golangci-lint `lint_package` option should use the correct command):
let b:ale_go_golangci_lint_package = 1 let b:ale_go_golangci_lint_package = 1
AssertLinter 'golangci-lint', AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint') . ' run --enable-all' \ . ale#Escape('golangci-lint') . ' run --enable-all'

View file

@ -13,7 +13,7 @@ After:
Execute(The gometalinter defaults should be correct): Execute(The gometalinter defaults should be correct):
AssertLinter 'gometalinter', AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter') \ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t'))) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' .' \ . ' .'
@ -22,7 +22,7 @@ Execute(The gometalinter callback should use a configured executable):
let b:ale_go_gometalinter_executable = 'something else' let b:ale_go_gometalinter_executable = 'something else'
AssertLinter 'something else', AssertLinter 'something else',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('something else') \ . ale#Escape('something else')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t'))) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' .' \ . ' .'
@ -31,7 +31,7 @@ Execute(The gometalinter callback should use configured options):
let b:ale_go_gometalinter_options = '--foobar' let b:ale_go_gometalinter_options = '--foobar'
AssertLinter 'gometalinter', AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter') \ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t'))) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' --foobar' . ' .' \ . ' --foobar' . ' .'
@ -40,7 +40,7 @@ Execute(The gometalinter should use configured environment variables):
let b:ale_go_go111module = 'off' let b:ale_go_go111module = 'off'
AssertLinter 'gometalinter', AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'off') \ . ale#Env('GO111MODULE', 'off')
\ . ale#Escape('gometalinter') \ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t'))) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
@ -50,5 +50,5 @@ Execute(The gometalinter `lint_package` option should use the correct command):
let b:ale_go_gometalinter_lint_package = 1 let b:ale_go_gometalinter_lint_package = 1
AssertLinter 'gometalinter', AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter') . ' .' \ . ale#Escape('gometalinter') . ' .'

View file

@ -11,11 +11,12 @@ After:
Execute(The default gosimple command should be correct): Execute(The default gosimple command should be correct):
AssertLinter 'gosimple', AssertLinter 'gosimple',
\ ale#path#CdString(expand('%:p:h')) . ' gosimple .' \ ale#path#BufferCdString(bufnr(''))
\ . ' gosimple .'
Execute(The gosimple command should support Go environment variables): Execute(The gosimple command should support Go environment variables):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'gosimple', AssertLinter 'gosimple',
\ ale#path#CdString(expand('%:p:h')) . ' ' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on') . 'gosimple .' \ . ' ' . ale#Env('GO111MODULE', 'on') . 'gosimple .'

View file

@ -11,7 +11,8 @@ After:
Execute(The default gotype command should be correct): Execute(The default gotype command should be correct):
AssertLinter 'gotype', AssertLinter 'gotype',
\ ale#path#CdString(expand('%:p:h')) . ' gotype -e .' \ ale#path#BufferCdString(bufnr(''))
\ . ' gotype -e .'
Execute(The gotype callback should ignore test files): Execute(The gotype callback should ignore test files):
call ale#test#SetFilename('bla_test.go') call ale#test#SetFilename('bla_test.go')
@ -22,6 +23,6 @@ Execute(The gotype callback should support Go environment variables):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'gotype', AssertLinter 'gotype',
\ ale#path#CdString(expand('%:p:h')) . ' ' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on') \ . ' ' . ale#Env('GO111MODULE', 'on')
\ . 'gotype -e .' \ . 'gotype -e .'

View file

@ -13,22 +13,22 @@ After:
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()
Execute(The default command should be correct): Execute(The default command should be correct):
AssertLinter 'go', ale#path#CdString(expand('%:p:h')) . ' go vet .' AssertLinter 'go', ale#path#BufferCdString(bufnr('')) . ' go vet .'
Execute(Extra options should be supported): Execute(Extra options should be supported):
let g:ale_go_govet_options = '--foo-bar' let g:ale_go_govet_options = '--foo-bar'
AssertLinter 'go', ale#path#CdString(expand('%:p:h')) . ' go vet --foo-bar .' AssertLinter 'go', ale#path#BufferCdString(bufnr('')) . ' go vet --foo-bar .'
Execute(The executable should be configurable): Execute(The executable should be configurable):
let g:ale_go_go_executable = 'foobar' let g:ale_go_go_executable = 'foobar'
AssertLinter 'foobar', ale#path#CdString(expand('%:p:h')) . ' foobar vet .' AssertLinter 'foobar', ale#path#BufferCdString(bufnr('')) . ' foobar vet .'
Execute(Go environment variables should be supported): Execute(Go environment variables should be supported):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'go', AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) . ' ' \ ale#path#BufferCdString(bufnr('')) . ' '
\ . ale#Env('GO111MODULE', 'on') \ . ale#Env('GO111MODULE', 'on')
\ . 'go vet .' \ . 'go vet .'

View file

@ -6,6 +6,6 @@ After:
Execute(The linter should run from the directory of the file in the buffer): Execute(The linter should run from the directory of the file in the buffer):
AssertLinter 'gqlint', AssertLinter 'gqlint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'gqlint --reporter=simple' \ . 'gqlint --reporter=simple'
\ . ' %t' \ . ' %t'

View file

@ -3,7 +3,7 @@ Before:
call ale#test#SetFilename('dummy.java') call ale#test#SetFilename('dummy.java')
let g:cp_sep = has('unix') ? ':' : ';' let g:cp_sep = has('unix') ? ':' : ';'
let g:prefix = ale#path#CdString(expand('%:p:h')) let g:prefix = ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint' \ . ale#Escape('javac') . ' -Xlint'
function! GetCommand(previous_output) abort function! GetCommand(previous_output) abort
@ -51,7 +51,7 @@ Execute(The executable should be configurable):
let g:ale_java_javac_executable = 'foobar' let g:ale_java_javac_executable = 'foobar'
AssertLinter 'foobar', AssertLinter 'foobar',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('foobar') . ' -Xlint' \ . ale#Escape('foobar') . ' -Xlint'
\ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t'
@ -197,7 +197,8 @@ Execute(The javac callback should combine discovered sourcepath and manual ones)
let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {}) let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {})
AssertEqual AssertEqual
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([ \ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'), \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'),
\ ale#path#Simplify(g:dir . '/java_paths/build/gen/main/'), \ ale#path#Simplify(g:dir . '/java_paths/build/gen/main/'),
@ -210,7 +211,8 @@ Execute(The javac callback should combine discovered sourcepath and manual ones)
let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {}) let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {})
AssertEqual AssertEqual
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([ \ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'), \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'),
\ ale#path#Simplify(g:dir . '/java_paths/build/gen/main/'), \ ale#path#Simplify(g:dir . '/java_paths/build/gen/main/'),
@ -223,7 +225,8 @@ Execute(The javac callback should combine discovered sourcepath and manual ones)
let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {}) let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {})
AssertEqual AssertEqual
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([ \ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'), \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'),
\ ale#path#Simplify(g:dir . '/java_paths/build/gen/main/') \ ale#path#Simplify(g:dir . '/java_paths/build/gen/main/')
@ -238,7 +241,8 @@ Execute(The javac callback should combine discovered sourcepath and manual ones)
let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {}) let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [], {})
AssertEqual AssertEqual
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([ \ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'), \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'),
\ ale#path#Simplify(g:dir . '/java_paths/build/gen/main/'), \ ale#path#Simplify(g:dir . '/java_paths/build/gen/main/'),
@ -253,7 +257,8 @@ Execute(The javac callback should detect source directories):
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
AssertLinter 'javac', AssertLinter 'javac',
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape( \ . ' -sourcepath ' . ale#Escape(
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/') \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/')
\ ) \ )
@ -272,7 +277,8 @@ Execute(The javac callback should combine detected source directories and classp
\], {}) \], {})
AssertEqual AssertEqual
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -cp ' . ale#Escape(join(['/foo/bar.jar', '/xyz/abc.jar'], g:cp_sep)) \ . ' -cp ' . ale#Escape(join(['/foo/bar.jar', '/xyz/abc.jar'], g:cp_sep))
\ . ' -sourcepath ' . ale#Escape( \ . ' -sourcepath ' . ale#Escape(
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/') \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/')
@ -294,7 +300,8 @@ Execute(The javac callback should include src/test/java for test paths):
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
AssertLinter 'javac', AssertLinter 'javac',
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([ \ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'), \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'),
\ ale#path#Simplify(g:dir . '/java_paths/src/test/java/'), \ ale#path#Simplify(g:dir . '/java_paths/src/test/java/'),
@ -307,7 +314,8 @@ Execute(The javac callback should include src/main/jaxb when available):
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
AssertLinter 'javac', AssertLinter 'javac',
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([ \ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths_with_jaxb/src/main/java/'), \ ale#path#Simplify(g:dir . '/java_paths_with_jaxb/src/main/java/'),
\ ale#path#Simplify(g:dir . '/java_paths_with_jaxb/src/main/jaxb/'), \ ale#path#Simplify(g:dir . '/java_paths_with_jaxb/src/main/jaxb/'),
@ -320,7 +328,8 @@ Execute(The javac callback should add -sourcepath even if src/java/main doesn't
call ale#engine#InitBufferInfo(bufnr('')) call ale#engine#InitBufferInfo(bufnr(''))
AssertLinter 'javac', AssertLinter 'javac',
\ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('javac') . ' -Xlint'
\ . ' -sourcepath ' . ale#Escape(join([ \ . ' -sourcepath ' . ale#Escape(join([
\ ale#path#Simplify(g:dir . '/java_paths_no_main/src/test/java/'), \ ale#path#Simplify(g:dir . '/java_paths_no_main/src/test/java/'),
\ ], g:cp_sep)) \ ], g:cp_sep))

View file

@ -6,7 +6,7 @@ After:
Execute(The default lintr command should be correct): Execute(The default lintr command should be correct):
AssertLinter 'Rscript', AssertLinter 'Rscript',
\ ale#path#CdString(getcwd()) \ ale#path#BufferCdString(bufnr(''))
\ . 'Rscript --vanilla -e ' \ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint(cache = FALSE, commandArgs(TRUE), ' \ . 'lint(cache = FALSE, commandArgs(TRUE), '
@ -17,7 +17,7 @@ Execute(The lintr options should be configurable):
let b:ale_r_lintr_options = 'with_defaults(object_usage_linter = NULL)' let b:ale_r_lintr_options = 'with_defaults(object_usage_linter = NULL)'
AssertLinter 'Rscript', AssertLinter 'Rscript',
\ ale#path#CdString(getcwd()) \ ale#path#BufferCdString(bufnr(''))
\ . 'Rscript --vanilla -e ' \ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint(cache = FALSE, commandArgs(TRUE), ' \ . 'lint(cache = FALSE, commandArgs(TRUE), '
@ -28,7 +28,7 @@ Execute(If the lint_package flag is set, lintr::lint_package should be called):
let b:ale_r_lintr_lint_package = 1 let b:ale_r_lintr_lint_package = 1
AssertLinter 'Rscript', AssertLinter 'Rscript',
\ ale#path#CdString(getcwd()) \ ale#path#BufferCdString(bufnr(''))
\ . 'Rscript --vanilla -e ' \ . 'Rscript --vanilla -e '
\ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));'
\ . 'lint_package(cache = FALSE, ' \ . 'lint_package(cache = FALSE, '

View file

@ -75,14 +75,14 @@ Execute(Setting executable to 'pipenv' appends 'run mypy'):
let g:ale_python_mypy_executable = 'path/to/pipenv' let g:ale_python_mypy_executable = 'path/to/pipenv'
AssertLinter 'path/to/pipenv', AssertLinter 'path/to/pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('path/to/pipenv') . ' run mypy' \ . ale#Escape('path/to/pipenv') . ' run mypy'
\ . ' --show-column-numbers --shadow-file %s %t %s' \ . ' --show-column-numbers --shadow-file %s %t %s'
Execute(Pipenv is detected when python_mypy_auto_pipenv is set): Execute(Pipenv is detected when python_mypy_auto_pipenv is set):
let g:ale_python_mypy_auto_pipenv = 1 let g:ale_python_mypy_auto_pipenv = 1
call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py') call ale#test#SetFilename('../python_fixtures/pipenv/whatever.py')
AssertLinter 'pipenv', AssertLinter 'pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pipenv') . ' run mypy --show-column-numbers --shadow-file %s %t %s' \ . ale#Escape('pipenv') . ' run mypy --show-column-numbers --shadow-file %s %t %s'

View file

@ -2,9 +2,9 @@ Before:
call ale#assert#SetUpLinterTest('nasm', 'nasm') call ale#assert#SetUpLinterTest('nasm', 'nasm')
let b:command_tail = let b:command_tail =
\ ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' %s -o ' . (has('win32') ? 'NUL' : '/dev/null') \ ' -X gnu -I %s:h' . (has('win32') ? '\' : '/') . ' %s -o ' . (has('win32') ? 'NUL' : '/dev/null')
let b:command_tail_opt = let b:command_tail_opt =
\ ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' -w+orphan-labels %s -o ' . (has('win32') ? 'NUL' : '/dev/null') \ ' -X gnu -I %s:h' . (has('win32') ? '\' : '/') . ' -w+orphan-labels %s -o ' . (has('win32') ? 'NUL' : '/dev/null')
After: After:
unlet! b:command_tail unlet! b:command_tail
@ -23,7 +23,8 @@ Execute(The options should be configurable):
let b:ale_nasm_nasm_options = '-w-macro-params' let b:ale_nasm_nasm_options = '-w-macro-params'
AssertLinter 'nasm', ale#Escape('nasm') AssertLinter 'nasm', ale#Escape('nasm')
\ . ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' -w-macro-params %s -o ' . (has('win32') ? 'NUL' : '/dev/null') \ . ' -X gnu -I %s:h' . (has('win32') ? '\' : '/')
\ . ' -w-macro-params %s -o ' . (has('win32') ? 'NUL' : '/dev/null')
Execute(The options should be used in command): Execute(The options should be used in command):
let b:ale_nasm_nasm_options = '-w+orphan-labels' let b:ale_nasm_nasm_options = '-w+orphan-labels'

View file

@ -1,5 +1,6 @@
Before: Before:
call ale#assert#SetUpLinterTest('python', 'pydocstyle') call ale#assert#SetUpLinterTest('python', 'pydocstyle')
call ale#test#SetFilename('test.py')
After: After:
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()
@ -7,33 +8,33 @@ After:
Execute(The pydocstyle command callback should return default string): Execute(The pydocstyle command callback should return default string):
AssertLinter 'pydocstyle', AssertLinter 'pydocstyle',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('pydocstyle') . ' ' . ale#Escape('dummy.txt') \ . ale#Escape('pydocstyle') . ' %s:t'
Execute(The pydocstyle command callback should allow options): Execute(The pydocstyle command callback should allow options):
let g:ale_python_pydocstyle_options = '--verbose' let g:ale_python_pydocstyle_options = '--verbose'
AssertLinter 'pydocstyle', AssertLinter 'pydocstyle',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('pydocstyle') . ' --verbose ' . ale#Escape('dummy.txt') \ . ale#Escape('pydocstyle') . ' --verbose %s:t'
Execute(The pydocstyle executable should be configurable): Execute(The pydocstyle executable should be configurable):
let g:ale_python_pydocstyle_executable = '~/.local/bin/pydocstyle' let g:ale_python_pydocstyle_executable = '~/.local/bin/pydocstyle'
AssertLinter '~/.local/bin/pydocstyle', AssertLinter '~/.local/bin/pydocstyle',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('~/.local/bin/pydocstyle') . ' ' . ale#Escape('dummy.txt') \ . ale#Escape('~/.local/bin/pydocstyle') . ' %s:t'
Execute(Setting executable to 'pipenv' appends 'run pydocstyle'): Execute(Setting executable to 'pipenv' appends 'run pydocstyle'):
let g:ale_python_pydocstyle_executable = 'path/to/pipenv' let g:ale_python_pydocstyle_executable = 'path/to/pipenv'
AssertLinter 'path/to/pipenv', AssertLinter 'path/to/pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('path/to/pipenv') . ' run pydocstyle ' . ale#Escape('dummy.txt') \ . ale#Escape('path/to/pipenv') . ' run pydocstyle %s:t'
Execute(Pipenv is detected when python_pydocstyle_auto_pipenv is set): Execute(Pipenv is detected when python_pydocstyle_auto_pipenv is set):
let g:ale_python_pydocstyle_auto_pipenv = 1 let g:ale_python_pydocstyle_auto_pipenv = 1
call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py') call ale#test#SetFilename('../python_fixtures/pipenv/whatever.py')
AssertLinter 'pipenv', AssertLinter 'pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('pipenv') . ' run pydocstyle ' . ale#Escape('whatever.py') \ . ale#Escape('pipenv') . ' run pydocstyle %s:t'

View file

@ -14,7 +14,7 @@ After:
Execute(The pylama command callback should return a default): Execute(The pylama command callback should return a default):
AssertLinter 'pylama', AssertLinter 'pylama',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pylama') . b:command_tail \ . ale#Escape('pylama') . b:command_tail
Execute(The option for disabling changing directories should work): Execute(The option for disabling changing directories should work):
@ -26,14 +26,14 @@ Execute(The pylama executable should be configurable, and escaped properly):
let g:ale_python_pylama_executable = 'executable with spaces' let g:ale_python_pylama_executable = 'executable with spaces'
AssertLinter 'executable with spaces', AssertLinter 'executable with spaces',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('executable with spaces') . b:command_tail \ . ale#Escape('executable with spaces') . b:command_tail
Execute(The pylama command callback should let you set options): Execute(The pylama command callback should let you set options):
let g:ale_python_pylama_options = '--some-option' let g:ale_python_pylama_options = '--some-option'
AssertLinter 'pylama', AssertLinter 'pylama',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pylama') . ' --some-option' . b:command_tail \ . ale#Escape('pylama') . ' --some-option' . b:command_tail
Execute(The pylama command callback should switch directories to the detected project root): Execute(The pylama command callback should switch directories to the detected project root):
@ -73,13 +73,13 @@ Execute(Setting executable to 'pipenv' appends 'run pylama'):
let g:ale_python_pylama_executable = 'path/to/pipenv' let g:ale_python_pylama_executable = 'path/to/pipenv'
AssertLinter 'path/to/pipenv', AssertLinter 'path/to/pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('path/to/pipenv') . ' run pylama' . b:command_tail \ . ale#Escape('path/to/pipenv') . ' run pylama' . b:command_tail
Execute(Pipenv is detected when python_pylama_auto_pipenv is set): Execute(Pipenv is detected when python_pylama_auto_pipenv is set):
let g:ale_python_pylama_auto_pipenv = 1 let g:ale_python_pylama_auto_pipenv = 1
call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py') call ale#test#SetFilename('../python_fixtures/pipenv/whatever.py')
AssertLinter 'pipenv', AssertLinter 'pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pipenv') . ' run pylama' . b:command_tail \ . ale#Escape('pipenv') . ' run pylama' . b:command_tail

View file

@ -1,4 +1,8 @@
Before: Before:
Save g:ale_python_auto_pipenv
let g:ale_python_auto_pipenv = 0
call ale#assert#SetUpLinterTest('python', 'pylint') call ale#assert#SetUpLinterTest('python', 'pylint')
let b:bin_dir = has('win32') ? 'Scripts' : 'bin' let b:bin_dir = has('win32') ? 'Scripts' : 'bin'
@ -13,7 +17,7 @@ After:
Execute(The pylint callbacks should return the correct default values): Execute(The pylint callbacks should return the correct default values):
AssertLinter 'pylint', AssertLinter 'pylint',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pylint') . ' ' . b:command_tail \ . ale#Escape('pylint') . ' ' . b:command_tail
Execute(The option for disabling changing directories should work): Execute(The option for disabling changing directories should work):
@ -25,14 +29,14 @@ Execute(The pylint executable should be configurable, and escaped properly):
let g:ale_python_pylint_executable = 'executable with spaces' let g:ale_python_pylint_executable = 'executable with spaces'
AssertLinter 'executable with spaces', AssertLinter 'executable with spaces',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('executable with spaces') . ' ' . b:command_tail \ . ale#Escape('executable with spaces') . ' ' . b:command_tail
Execute(The pylint command callback should let you set options): Execute(The pylint command callback should let you set options):
let g:ale_python_pylint_options = '--some-option' let g:ale_python_pylint_options = '--some-option'
AssertLinter 'pylint', AssertLinter 'pylint',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pylint') . ' --some-option' . b:command_tail \ . ale#Escape('pylint') . ' --some-option' . b:command_tail
Execute(The pylint callbacks shouldn't detect virtualenv directories where they don't exist): Execute(The pylint callbacks shouldn't detect virtualenv directories where they don't exist):
@ -65,15 +69,15 @@ Execute(Setting executable to 'pipenv' appends 'run pylint'):
let g:ale_python_pylint_executable = 'path/to/pipenv' let g:ale_python_pylint_executable = 'path/to/pipenv'
AssertLinter 'path/to/pipenv', AssertLinter 'path/to/pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('path/to/pipenv') . ' run pylint' \ . ale#Escape('path/to/pipenv') . ' run pylint'
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s' \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'
Execute(Pipenv is detected when python_pylint_auto_pipenv is set): Execute(Pipenv is detected when python_pylint_auto_pipenv is set):
let g:ale_python_pylint_auto_pipenv = 1 let g:ale_python_pylint_auto_pipenv = 1
call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py') call ale#test#SetFilename('../python_fixtures/pipenv/whatever.py')
AssertLinter 'pipenv', AssertLinter 'pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('pipenv') . ' run pylint' \ . ale#Escape('pipenv') . ' run pylint'
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s' \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s'

View file

@ -6,8 +6,8 @@ After:
Execute(The default cython command should be correct): Execute(The default cython command should be correct):
AssertLinter 'cython', ale#Escape('cython') AssertLinter 'cython', ale#Escape('cython')
\ . ' --working ' . ale#Escape(g:dir) \ . ' --working %s:h'
\ . ' --include-dir ' . ale#Escape(g:dir) \ . ' --include-dir %s:h'
\ . ' --warning-extra' \ . ' --warning-extra'
\ . ' --output-file ' . g:ale#util#nul_file . ' %t' \ . ' --output-file ' . g:ale#util#nul_file . ' %t'
@ -15,8 +15,8 @@ Execute(The cython executable should be configurable):
let b:ale_pyrex_cython_executable = 'cython_foobar' let b:ale_pyrex_cython_executable = 'cython_foobar'
AssertLinter 'cython_foobar', ale#Escape('cython_foobar') AssertLinter 'cython_foobar', ale#Escape('cython_foobar')
\ . ' --working ' . ale#Escape(g:dir) \ . ' --working %s:h'
\ . ' --include-dir ' . ale#Escape(g:dir) \ . ' --include-dir %s:h'
\ . ' --warning-extra' \ . ' --warning-extra'
\ . ' --output-file ' . g:ale#util#nul_file . ' %t' \ . ' --output-file ' . g:ale#util#nul_file . ' %t'
@ -24,7 +24,7 @@ Execute(Additional cython options should be configurable):
let b:ale_pyrex_cython_options = '--foobar' let b:ale_pyrex_cython_options = '--foobar'
AssertLinter 'cython', ale#Escape('cython') AssertLinter 'cython', ale#Escape('cython')
\ . ' --working ' . ale#Escape(g:dir) \ . ' --working %s:h'
\ . ' --include-dir ' . ale#Escape(g:dir) \ . ' --include-dir %s:h'
\ . ' --foobar' \ . ' --foobar'
\ . ' --output-file ' . g:ale#util#nul_file . ' %t' \ . ' --output-file ' . g:ale#util#nul_file . ' %t'

View file

@ -10,20 +10,17 @@ After:
Execute(Executable should default to rubocop): Execute(Executable should default to rubocop):
AssertLinter 'rubocop', ale#Escape('rubocop') AssertLinter 'rubocop', ale#Escape('rubocop')
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.rb'))
Execute(Should be able to set a custom executable): Execute(Should be able to set a custom executable):
let g:ale_ruby_rubocop_executable = 'bin/rubocop' let g:ale_ruby_rubocop_executable = 'bin/rubocop'
AssertLinter 'bin/rubocop' , ale#Escape('bin/rubocop') AssertLinter 'bin/rubocop' , ale#Escape('bin/rubocop')
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.rb'))
Execute(Setting bundle appends 'exec rubocop'): Execute(Setting bundle appends 'exec rubocop'):
let g:ale_ruby_rubocop_executable = 'path to/bundle' let g:ale_ruby_rubocop_executable = 'path to/bundle'
AssertLinter 'path to/bundle', ale#Escape('path to/bundle') AssertLinter 'path to/bundle', ale#Escape('path to/bundle')
\ . ' exec rubocop' \ . ' exec rubocop'
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.rb'))

View file

@ -10,20 +10,17 @@ After:
Execute(Executable should default to ruumba): Execute(Executable should default to ruumba):
AssertLinter 'ruumba', ale#Escape('ruumba') AssertLinter 'ruumba', ale#Escape('ruumba')
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.html.erb'))
Execute(Should be able to set a custom executable): Execute(Should be able to set a custom executable):
let g:ale_eruby_ruumba_executable = 'bin/ruumba' let g:ale_eruby_ruumba_executable = 'bin/ruumba'
AssertLinter 'bin/ruumba' , ale#Escape('bin/ruumba') AssertLinter 'bin/ruumba' , ale#Escape('bin/ruumba')
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.html.erb'))
Execute(Setting bundle appends 'exec ruumba'): Execute(Setting bundle appends 'exec ruumba'):
let g:ale_eruby_ruumba_executable = 'path to/bundle' let g:ale_eruby_ruumba_executable = 'path to/bundle'
AssertLinter 'path to/bundle', ale#Escape('path to/bundle') AssertLinter 'path to/bundle', ale#Escape('path to/bundle')
\ . ' exec ruumba' \ . ' exec ruumba'
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.html.erb'))

View file

@ -2,7 +2,7 @@ Before:
call ale#assert#SetUpLinterTest('sh', 'shellcheck') call ale#assert#SetUpLinterTest('sh', 'shellcheck')
call ale#test#SetFilename('test.sh') call ale#test#SetFilename('test.sh')
let b:prefix = ale#path#CdString(ale#path#Simplify(g:dir)) let b:prefix = ale#path#BufferCdString(bufnr(''))
let b:suffix = ' -f gcc -' let b:suffix = ' -f gcc -'
After: After:

View file

@ -0,0 +1,12 @@
Before:
" Load the linter and set up a series of commands, reset linter variables,
" clear caches, etc.
"
" Vader's 'Save' command will be called here for linter variables.
call ale#assert#SetUpLinterTest('sql', 'sqllint')
After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
AssertLinter 'sql-lint', ['sql-lint']

View file

@ -10,20 +10,17 @@ After:
Execute(Executable should default to standardrb): Execute(Executable should default to standardrb):
AssertLinter 'standardrb', ale#Escape('standardrb') AssertLinter 'standardrb', ale#Escape('standardrb')
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.rb'))
Execute(Should be able to set a custom executable): Execute(Should be able to set a custom executable):
let g:ale_ruby_standardrb_executable = 'bin/standardrb' let g:ale_ruby_standardrb_executable = 'bin/standardrb'
AssertLinter 'bin/standardrb' , ale#Escape('bin/standardrb') AssertLinter 'bin/standardrb' , ale#Escape('bin/standardrb')
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.rb'))
Execute(Setting bundle appends 'exec standardrb'): Execute(Setting bundle appends 'exec standardrb'):
let g:ale_ruby_standardrb_executable = 'path to/bundle' let g:ale_ruby_standardrb_executable = 'path to/bundle'
AssertLinter 'path to/bundle', ale#Escape('path to/bundle') AssertLinter 'path to/bundle', ale#Escape('path to/bundle')
\ . ' exec standardrb' \ . ' exec standardrb'
\ . ' --format json --force-exclusion --stdin ' \ . ' --format json --force-exclusion --stdin %s'
\ . ale#Escape(ale#path#Simplify(g:dir . '/dummy.rb'))

View file

@ -11,7 +11,7 @@ After:
Execute(The staticcheck callback should return the right defaults): Execute(The staticcheck callback should return the right defaults):
AssertLinter 'staticcheck', AssertLinter 'staticcheck',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'staticcheck ' \ . 'staticcheck '
\ . ale#Escape(expand('%' . ':t')) \ . ale#Escape(expand('%' . ':t'))
@ -19,7 +19,7 @@ Execute(The staticcheck callback should use configured options):
let b:ale_go_staticcheck_options = '-test' let b:ale_go_staticcheck_options = '-test'
AssertLinter 'staticcheck', AssertLinter 'staticcheck',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'staticcheck ' \ . 'staticcheck '
\ . '-test ' . ale#Escape(expand('%' . ':t')) \ . '-test ' . ale#Escape(expand('%' . ':t'))
@ -27,13 +27,14 @@ Execute(The staticcheck `lint_package` option should use the correct command):
let b:ale_go_staticcheck_lint_package = 1 let b:ale_go_staticcheck_lint_package = 1
AssertLinter 'staticcheck', AssertLinter 'staticcheck',
\ ale#path#CdString(expand('%:p:h')) . 'staticcheck .', \ ale#path#BufferCdString(bufnr(''))
\ . 'staticcheck .',
Execute(The staticcheck callback should use the `GO111MODULE` option if set): Execute(The staticcheck callback should use the `GO111MODULE` option if set):
let b:ale_go_go111module = 'off' let b:ale_go_go111module = 'off'
AssertLinter 'staticcheck', AssertLinter 'staticcheck',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'off') \ . ale#Env('GO111MODULE', 'off')
\ . 'staticcheck ' \ . 'staticcheck '
\ . ale#Escape(expand('%' . ':t')) \ . ale#Escape(expand('%' . ':t'))
@ -42,6 +43,6 @@ Execute(The staticcheck callback should use the `GO111MODULE` option if set):
let b:ale_go_staticcheck_lint_package = 1 let b:ale_go_staticcheck_lint_package = 1
AssertLinter 'staticcheck', AssertLinter 'staticcheck',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'off') \ . ale#Env('GO111MODULE', 'off')
\ . 'staticcheck .' \ . 'staticcheck .'

View file

@ -7,14 +7,14 @@ After:
Execute(The default tslint command should be correct): Execute(The default tslint command should be correct):
AssertLinter 'tslint', AssertLinter 'tslint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('tslint') . ' --format json %t' \ . ale#Escape('tslint') . ' --format json %t'
Execute(The rules directory option should be included if set): Execute(The rules directory option should be included if set):
let b:ale_typescript_tslint_rules_dir = '/foo/bar' let b:ale_typescript_tslint_rules_dir = '/foo/bar'
AssertLinter 'tslint', AssertLinter 'tslint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('tslint') . ' --format json' \ . ale#Escape('tslint') . ' --format json'
\ . ' -r ' . ale#Escape('/foo/bar') \ . ' -r ' . ale#Escape('/foo/bar')
\ . ' %t' \ . ' %t'
@ -23,5 +23,5 @@ Execute(The executable should be configurable and escaped):
let b:ale_typescript_tslint_executable = 'foo bar' let b:ale_typescript_tslint_executable = 'foo bar'
AssertLinter 'foo bar', AssertLinter 'foo bar',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('foo bar') . ' --format json %t' \ . ale#Escape('foo bar') . ' --format json %t'

View file

@ -12,7 +12,7 @@ After:
Execute(The vulture command callback should lint file directory by default): Execute(The vulture command callback should lint file directory by default):
AssertLinter 'vulture', AssertLinter 'vulture',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('vulture') . ' .' \ . ale#Escape('vulture') . ' .'
Execute(The vulture command callback should lint project root, when present): Execute(The vulture command callback should lint project root, when present):
@ -31,14 +31,14 @@ Execute(The vulture executable should be configurable, and escaped properly):
let g:ale_python_vulture_executable = 'executable with spaces' let g:ale_python_vulture_executable = 'executable with spaces'
AssertLinter 'executable with spaces', AssertLinter 'executable with spaces',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('executable with spaces') . ' .' \ . ale#Escape('executable with spaces') . ' .'
Execute(The vulture command callback should let you set options): Execute(The vulture command callback should let you set options):
let g:ale_python_vulture_options = '--some-option' let g:ale_python_vulture_options = '--some-option'
AssertLinter 'vulture', AssertLinter 'vulture',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('vulture') . ' --some-option .' \ . ale#Escape('vulture') . ' --some-option .'
Execute(The vulture command callback should detect virtualenv directories and switch to the project root): Execute(The vulture command callback should detect virtualenv directories and switch to the project root):
@ -64,5 +64,5 @@ Execute(Setting executable to 'pipenv' appends 'run vulture'):
let g:ale_python_vulture_executable = 'path/to/pipenv' let g:ale_python_vulture_executable = 'path/to/pipenv'
AssertLinter 'path/to/pipenv', AssertLinter 'path/to/pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(expand('#' . bufnr('') . ':p:h'))
\ . ale#Escape('path/to/pipenv') . ' run vulture' . ' .' \ . ale#Escape('path/to/pipenv') . ' run vulture' . ' .'

View file

@ -609,6 +609,7 @@ Execute(Should handle completion messages with additionalTextEdits when ale_comp
Execute(Should not handle completion messages with additionalTextEdits when ale_completion_autoimport is turned off): Execute(Should not handle completion messages with additionalTextEdits when ale_completion_autoimport is turned off):
let g:ale_completion_autoimport = 0 let g:ale_completion_autoimport = 0
let b:ale_completion_info = {'line': 30}
AssertEqual AssertEqual
\ [], \ [],
@ -645,3 +646,36 @@ Execute(Should not handle completion messages with additionalTextEdits when ale_
\ ], \ ],
\ }, \ },
\ }) \ })
Execute(Should still handle completion messages with empty additionalTextEdits with ale_completion_autoimport turned off):
let g:ale_completion_autoimport = 0
AssertEqual
\ [
\ {
\ 'word': 'next_callback',
\ 'menu': 'PlayTimeCallback',
\ 'info': '',
\ 'kind': 'v',
\ 'icase': 1,
\ }
\ ],
\ ale#completion#ParseLSPCompletions({
\ 'id': 226,
\ 'jsonrpc': '2.0',
\ 'result': {
\ 'isIncomplete': v:false,
\ 'items': [
\ {
\ 'detail': 'PlayTimeCallback',
\ 'filterText': 'next_callback',
\ 'insertText': 'next_callback',
\ 'insertTextFormat': 1,
\ 'kind': 6,
\ 'label': ' next_callback',
\ 'sortText': '3ee19999next_callback',
\ 'additionalTextEdits': [],
\ },
\ ],
\ },
\ })

View file

@ -6,6 +6,7 @@ Before:
Save g:ale_lint_on_save Save g:ale_lint_on_save
Save g:ale_echo_cursor Save g:ale_echo_cursor
Save g:ale_command_wrapper Save g:ale_command_wrapper
Save g:ale_filename_mappings
silent! cd /testplugin/test/fix silent! cd /testplugin/test/fix
@ -19,6 +20,7 @@ Before:
let g:ale_fixers = { let g:ale_fixers = {
\ 'testft': [], \ 'testft': [],
\} \}
let g:ale_filename_mappings = {}
let g:pre_success = 0 let g:pre_success = 0
let g:post_success = 0 let g:post_success = 0
@ -72,6 +74,10 @@ Before:
return {'command': 'cat %t <(echo d)'} return {'command': 'cat %t <(echo d)'}
endfunction endfunction
function EchoFilename(buffer, lines) abort
return {'command': 'echo %s'}
endfunction
function RemoveLastLine(buffer, lines) abort function RemoveLastLine(buffer, lines) abort
return ['a', 'b'] return ['a', 'b']
endfunction endfunction
@ -155,6 +161,7 @@ After:
delfunction CatLineDeferred delfunction CatLineDeferred
delfunction ReplaceWithTempFile delfunction ReplaceWithTempFile
delfunction CatWithTempFile delfunction CatWithTempFile
delfunction EchoFilename
delfunction RemoveLastLine delfunction RemoveLastLine
delfunction RemoveLastLineOneArg delfunction RemoveLastLineOneArg
delfunction TestCallback delfunction TestCallback
@ -209,6 +216,25 @@ Expect(The first function should be used):
^b ^b
^c ^c
Execute(Should apply filename mpapings):
" The command echos %s, and we'll map the current path so we can check
" that ALEFix applies filename mappings, end-to-end.
let g:ale_filename_mappings = {
\ 'echo_filename': [
\ [expand('%:p:h') . '/', '/some/fake/path/'],
\ ],
\}
call ale#fix#registry#Add('echo_filename', 'EchoFilename', [], 'echo filename')
let g:ale_fixers.testft = ['echo_filename']
ALEFix
call ale#test#FlushJobs()
" Remote trailing whitespace from the line.
call setline(1, substitute(getline(1), '[ \r]\+$', '', ''))
Expect(The mapped filename should be printed):
/some/fake/path/test.txt
Execute(ALEFix should apply simple functions in a chain): Execute(ALEFix should apply simple functions in a chain):
let g:ale_fixers.testft = ['AddCarets', 'Capitalize'] let g:ale_fixers.testft = ['AddCarets', 'Capitalize']
ALEFix ALEFix

View file

@ -0,0 +1,11 @@
Before:
call ale#assert#SetUpFixerTest('dhall', 'dhall')
After:
call ale#assert#TearDownFixerTest()
Execute(The default command should be correct):
AssertFixer
\ { 'read_temporary_file': 1,
\ 'command': ale#Escape('dhall') . ' format --inplace %t'
\ }

View file

@ -4,6 +4,7 @@ Before:
" Use an invalid global executable, so we don't match it. " Use an invalid global executable, so we don't match it.
let g:ale_python_isort_executable = 'xxxinvalid' let g:ale_python_isort_executable = 'xxxinvalid'
let g:ale_python_isort_options = ''
call ale#test#SetDirectory('/testplugin/test/fixers') call ale#test#SetDirectory('/testplugin/test/fixers')
silent cd .. silent cd ..
@ -27,7 +28,7 @@ Execute(The isort callback should return the correct default values):
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
AssertEqual AssertEqual
\ { \ {
\ 'command': ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir/foo')) \ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/isort')) . ' -', \ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/isort')) . ' -',
\ }, \ },
\ ale#fixers#isort#Fix(bufnr('')) \ ale#fixers#isort#Fix(bufnr(''))
@ -42,7 +43,7 @@ Execute(The isort callback should respect custom options):
silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py')
AssertEqual AssertEqual
\ { \ {
\ 'command': ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir/foo')) \ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/isort')) \ . ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/isort'))
\ . ' --multi-line=3 --trailing-comma -', \ . ' --multi-line=3 --trailing-comma -',
\ }, \ },

View file

@ -18,10 +18,8 @@ Execute(The latexindent callback should return the correct default values):
AssertEqual AssertEqual
\ { \ {
\ 'read_temporary_file': 1,
\ 'command': ale#Escape('xxxinvalid') \ 'command': ale#Escape('xxxinvalid')
\ . ' -l -w' \ . ' -l'
\ . ' %t',
\ }, \ },
\ ale#fixers#latexindent#Fix(bufnr('')) \ ale#fixers#latexindent#Fix(bufnr(''))
@ -31,10 +29,8 @@ Execute(The latexindent callback should include custom gofmt options):
AssertEqual AssertEqual
\ { \ {
\ 'read_temporary_file': 1,
\ 'command': ale#Escape('xxxinvalid') \ 'command': ale#Escape('xxxinvalid')
\ . ' -l -w' \ . ' -l'
\ . ' ' . g:ale_tex_latexindent_options \ . ' ' . g:ale_tex_latexindent_options
\ . ' %t',
\ }, \ },
\ ale#fixers#latexindent#Fix(bufnr('')) \ ale#fixers#latexindent#Fix(bufnr(''))

View file

@ -19,8 +19,7 @@ Execute(The ocamlformat callback should return the correct default values):
AssertEqual AssertEqual
\ { \ {
\ 'command': ale#Escape('xxxinvalid') \ 'command': ale#Escape('xxxinvalid')
\ . ' --name=' . ale#Escape(bufname(bufnr(''))) \ . ' --name=%s -',
\ . ' -',
\ }, \ },
\ ale#fixers#ocamlformat#Fix(bufnr('')) \ ale#fixers#ocamlformat#Fix(bufnr(''))
@ -32,7 +31,6 @@ Execute(The ocamlformat callback should include custom ocamlformat options):
\ { \ {
\ 'command': ale#Escape('xxxinvalid') \ 'command': ale#Escape('xxxinvalid')
\ . ' ' . g:ale_ocaml_ocamlformat_options \ . ' ' . g:ale_ocaml_ocamlformat_options
\ . ' --name=' . ale#Escape(bufname(bufnr(''))) \ . ' --name=%s -',
\ . ' -',
\ }, \ },
\ ale#fixers#ocamlformat#Fix(bufnr('')) \ ale#fixers#ocamlformat#Fix(bufnr(''))

View file

@ -73,7 +73,7 @@ Execute(The new --stdin-filepath option should be used when the version is new e
GivenCommandOutput ['4.4.0'] GivenCommandOutput ['4.4.0']
AssertFixer AssertFixer
\ { \ {
\ 'command': ale#path#CdString(expand('%:p:h')) \ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('prettier-eslint') \ . ale#Escape('prettier-eslint')
\ . ' --eslint-config-path ' . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/.eslintrc.js')) \ . ' --eslint-config-path ' . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/.eslintrc.js'))
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
@ -83,7 +83,7 @@ Execute(The version number should be cached):
GivenCommandOutput ['4.4.0'] GivenCommandOutput ['4.4.0']
AssertFixer AssertFixer
\ { \ {
\ 'command': ale#path#CdString(expand('%:p:h')) \ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('prettier-eslint') \ . ale#Escape('prettier-eslint')
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
\ } \ }
@ -91,7 +91,7 @@ Execute(The version number should be cached):
GivenCommandOutput [] GivenCommandOutput []
AssertFixer AssertFixer
\ { \ {
\ 'command': ale#path#CdString(expand('%:p:h')) \ 'command': ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('prettier-eslint') \ . ale#Escape('prettier-eslint')
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
\ } \ }

View file

@ -297,6 +297,17 @@ Execute(Should set --parser for experimental language, Handlebars):
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
\ } \ }
Execute(Changes to directory where .prettierignore is found):
call ale#test#SetFilename('../prettier-test-files/with_prettierignore/src/testfile.js')
GivenCommandOutput ['1.6.0']
AssertFixer
\ {
\ 'command': ale#path#CdString(expand('%:p:h:h'))
\ . ale#Escape(g:ale_javascript_prettier_executable)
\ . ' --stdin-filepath %s --stdin',
\ }
Execute(The prettier_d post-processor should permit regular JavaScript content): Execute(The prettier_d post-processor should permit regular JavaScript content):
AssertEqual AssertEqual
\ [ \ [

View file

@ -23,8 +23,7 @@ Execute(The rubocop callback should return the correct default values):
\ { \ {
\ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --auto-correct --force-exclusion --stdin ' \ . ' --auto-correct --force-exclusion --stdin %s',
\ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ }, \ },
\ ale#fixers#rubocop#Fix(bufnr('')) \ ale#fixers#rubocop#Fix(bufnr(''))
@ -36,8 +35,7 @@ Execute(The rubocop callback should include configuration files):
\ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml')) \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml'))
\ . ' --auto-correct --force-exclusion --stdin ' \ . ' --auto-correct --force-exclusion --stdin %s',
\ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ }, \ },
\ ale#fixers#rubocop#Fix(bufnr('')) \ ale#fixers#rubocop#Fix(bufnr(''))
@ -51,8 +49,7 @@ Execute(The rubocop callback should include custom rubocop options):
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml')) \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml'))
\ . ' --except Lint/Debugger' \ . ' --except Lint/Debugger'
\ . ' --auto-correct --force-exclusion --stdin ' \ . ' --auto-correct --force-exclusion --stdin %s',
\ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ }, \ },
\ ale#fixers#rubocop#Fix(bufnr('')) \ ale#fixers#rubocop#Fix(bufnr(''))
@ -65,8 +62,7 @@ Execute(The rubocop callback should use auto-correct-all option when set):
\ 'process_with': 'ale#fixers#rubocop#PostProcess', \ 'process_with': 'ale#fixers#rubocop#PostProcess',
\ 'command': ale#Escape(g:ale_ruby_rubocop_executable) \ 'command': ale#Escape(g:ale_ruby_rubocop_executable)
\ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml')) \ . ' --config ' . ale#Escape(ale#path#Simplify(g:dir . '/ruby_paths/with_config/.rubocop.yml'))
\ . ' --auto-correct-all --force-exclusion --stdin ' \ . ' --auto-correct-all --force-exclusion --stdin %s'
\ . ale#Escape(expand('#' . bufnr('') . ':p')),
\ }, \ },
\ ale#fixers#rubocop#Fix(bufnr('')) \ ale#fixers#rubocop#Fix(bufnr(''))

View file

@ -1,4 +1,8 @@
Before: Before:
Save g:ale_stylelint_options
let g:ale_stylelint_options = ''
call ale#assert#SetUpFixerTest('css', 'stylelint') call ale#assert#SetUpFixerTest('css', 'stylelint')
After: After:
@ -10,7 +14,7 @@ Execute(The stylelint callback should return the correct default values):
AssertFixer AssertFixer
\ { \ {
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\ 'command': ale#path#CdString(expand('%:p:h')) \ 'command': ale#path#BufferCdString(bufnr(''))
\ . (has('win32') ? 'node.exe ' : '') \ . (has('win32') ? 'node.exe ' : '')
\ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/stylelint/bin/stylelint.js')) \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/stylelint/bin/stylelint.js'))
\ . ' %t' \ . ' %t'
@ -24,7 +28,7 @@ Execute(The stylelint callback should include custom stylelint options):
AssertFixer AssertFixer
\ { \ {
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\ 'command': ale#path#CdString(expand('%:p:h')) \ 'command': ale#path#BufferCdString(bufnr(''))
\ . (has('win32') ? 'node.exe ' : '') \ . (has('win32') ? 'node.exe ' : '')
\ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/stylelint/bin/stylelint.js')) \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/stylelint/bin/stylelint.js'))
\ . ' %t' \ . ' %t'

View file

@ -0,0 +1,23 @@
Before:
" Load the file which defines the linter.
runtime ale_linters/sql/sqllint.vim
After:
" Unload all linters again.
call ale#linter#Reset()
Execute (The output should be correct):
" Test that the right loclist items are parsed from the handler.
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'col': 0,
\ 'type': '',
\ 'text': 'stdin:1 [ER_NO_DB_ERROR] No database selected'
\ },
\ ],
\ ale_linters#sql#sqllint#Handle(bufnr(''), [
\ 'stdin:1 [ER_NO_DB_ERROR] No database selected'
\ ])

View file

@ -1,8 +1,10 @@
Before: Before:
Save g:ale_enabled
Save g:ale_set_lists_synchronously Save g:ale_set_lists_synchronously
Save g:ale_buffer_info Save g:ale_buffer_info
Save &shell Save &shell
let g:ale_enabled = 1
let g:ale_buffer_info = {} let g:ale_buffer_info = {}
let g:ale_set_lists_synchronously = 1 let g:ale_set_lists_synchronously = 1

View file

@ -92,8 +92,8 @@ Execute (All events should be set up when everything is on):
\ 'FileType * call ale#events#FileTypeEvent( str2nr(expand(''<abuf>'')), expand(''<amatch>''))', \ 'FileType * call ale#events#FileTypeEvent( str2nr(expand(''<abuf>'')), expand(''<amatch>''))',
\ 'InsertLeave * if ale#Var(str2nr(expand(''<abuf>'')), ''lint_on_insert_leave'') | call ale#Queue(0) | endif', \ 'InsertLeave * if ale#Var(str2nr(expand(''<abuf>'')), ''lint_on_insert_leave'') | call ale#Queue(0) | endif',
\ 'InsertLeave if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarning() | endif', \ 'InsertLeave if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarning() | endif',
\ 'TextChanged * call ale#Queue(g:ale_lint_delay)', \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ ], \ ],
\ CheckAutocmd('ALEEvents') \ CheckAutocmd('ALEEvents')
@ -145,8 +145,8 @@ Execute (g:ale_lint_on_text_changed = 1 bind both events):
AssertEqual AssertEqual
\ [ \ [
\ 'TextChanged * call ale#Queue(g:ale_lint_delay)', \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ ], \ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')
@ -155,8 +155,8 @@ Execute (g:ale_lint_on_text_changed = 'always' should bind both events):
AssertEqual AssertEqual
\ [ \ [
\ 'TextChanged * call ale#Queue(g:ale_lint_delay)', \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ ], \ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')
@ -165,7 +165,7 @@ Execute (g:ale_lint_on_text_changed = 'normal' should bind only TextChanged):
AssertEqual AssertEqual
\ [ \ [
\ 'TextChanged * call ale#Queue(g:ale_lint_delay)', \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ ], \ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')
@ -174,7 +174,7 @@ Execute (g:ale_lint_on_text_changed = 'insert' should bind only TextChangedI):
AssertEqual AssertEqual
\ [ \ [
\ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ ], \ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')

View file

@ -5,7 +5,15 @@ Before:
let g:ale_c_parse_makefile = 1 let g:ale_c_parse_makefile = 1
function SplitAndParse(path_prefix, command) abort
let l:args = ale#c#ShellSplit(a:command)
return ale#c#ParseCFlags(a:path_prefix, 0, l:args)
endfunction
After: After:
delfunction SplitAndParse
Restore Restore
call ale#test#RestoreDirectory() call ale#test#RestoreDirectory()
@ -18,7 +26,7 @@ Execute(The CFlags parser should be able to parse include directives):
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c']) \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c'])
AssertEqual AssertEqual
\ '-isystem ' . '/usr/include/dir', \ '-isystem ' . ale#Escape('/usr/include/dir'),
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -isystem /usr/include/dir -c file.c']) \ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -isystem /usr/include/dir -c file.c'])
Execute(ParseCFlags should ignore -c and -o): Execute(ParseCFlags should ignore -c and -o):
@ -57,48 +65,21 @@ Execute(ParseCFlags should be able to parse flags with relative paths):
\ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')) \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`', \ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags( \ SplitAndParse(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Isubdir ' \ 'gcc -Isubdir '
\ . '-I'. ale#path#Simplify('kernel/include') \ . '-I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c' \ . ' -DTEST=`date +%s` -c file.c'
\ ) \ )
Execute(ParseCFlags should be able to parse -Dgoal): Execute(We should handle paths with spaces in double quotes):
AssertEqual
\ '-Dgoal=9'
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Isubdir '
\ . '-I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should ignore -T and other arguments):
AssertEqual
\ '-Dgoal=9'
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . '--sysroot=subdir'
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir --sysroot=subdir '
\ . '-I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should handle paths with spaces in double quotes):
AssertEqual AssertEqual
\ '-Dgoal=9' \ '-Dgoal=9'
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`', \ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags( \ SplitAndParse(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-I"dir with spaces"' . ' -I'. ale#path#Simplify('kernel/include') \ . '-I"dir with spaces"' . ' -I'. ale#path#Simplify('kernel/include')
@ -112,7 +93,7 @@ Execute(ParseCFlags should handle paths with spaces in single quotes):
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`', \ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags( \ SplitAndParse(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-I''dir with spaces''' . ' -I'. ale#path#Simplify('kernel/include') \ . '-I''dir with spaces''' . ' -I'. ale#path#Simplify('kernel/include')
@ -127,7 +108,7 @@ Execute(ParseCFlags should handle paths with minuses):
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`', \ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags( \ SplitAndParse(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-I''dir with spaces''' . ' -Idir-with-dash' \ . '-I''dir with spaces''' . ' -Idir-with-dash'
@ -135,7 +116,7 @@ Execute(ParseCFlags should handle paths with minuses):
\ . ' -DTEST=`date +%s` -c file.c' \ . ' -DTEST=`date +%s` -c file.c'
\ ) \ )
Execute(ParseCFlags should handle -D with minuses): Execute(We should handle -D with minuses):
AssertEqual AssertEqual
\ '-Dgoal=9' \ '-Dgoal=9'
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
@ -144,7 +125,7 @@ Execute(ParseCFlags should handle -D with minuses):
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`', \ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags( \ SplitAndParse(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-Dmacro-with-dash ' \ . '-Dmacro-with-dash '
@ -153,7 +134,7 @@ Execute(ParseCFlags should handle -D with minuses):
\ . ' -DTEST=`date +%s` -c file.c' \ . ' -DTEST=`date +%s` -c file.c'
\ ) \ )
Execute(ParseCFlags should handle flags at the end of the line): Execute(We should handle flags at the end of the line):
AssertEqual AssertEqual
\ '-Dgoal=9' \ '-Dgoal=9'
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
@ -161,7 +142,7 @@ Execute(ParseCFlags should handle flags at the end of the line):
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')) \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ ale#c#ParseCFlags( \ SplitAndParse(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-Dmacro-with-dash ' \ . '-Dmacro-with-dash '
@ -178,9 +159,13 @@ Execute(ParseCompileCommandsFlags should tolerate empty values):
Execute(ParseCompileCommandsFlags should parse some basic flags): Execute(ParseCompileCommandsFlags should parse some basic flags):
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')) silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
" We should read the absolute path filename entry, not the other ones.
AssertEqual AssertEqual
\ '-I ' . ale#path#Simplify('/usr/include/xmms2'), \ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')),
\ ale#c#ParseCompileCommandsFlags(bufnr(''), { "xmms2-mpris.c": [ \ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
\ ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'): [
\ { \ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'), \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2') \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2')
@ -188,26 +173,122 @@ Execute(ParseCompileCommandsFlags should parse some basic flags):
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'), \ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'), \ 'file': ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ }, \ },
\ ] }, {}) \ ],
\ "xmms2-mpris.c": [
\ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ },
\ ],
\ },
\ {
\ ale#path#Simplify('/foo/bar/xmms2-mpris/src'): [
\ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris/src'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': 'other.c',
\ },
\ ],
\ "src": [
\ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': ale#path#Simplify((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'),
\ },
\ ],
\ },
\ )
Execute(ParseCompileCommandsFlags should tolerate items without commands): Execute(ParseCompileCommandsFlags should fall back to files with the same name):
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')) silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
" We should prefer the basename file flags, not the base dirname flags.
AssertEqual AssertEqual
\ '', \ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')),
\ ale#c#ParseCompileCommandsFlags(bufnr(''), { "xmms2-mpris.c": [ \ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ { \ {
\ 'directory': '/foo/bar/xmms2-mpris', \ "xmms2-mpris.c": [
\ 'file': '/foo/bar/xmms2-mpris/src/xmms2-mpris.c', \ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ }, \ },
\ ] }, {}) \ ],
\ },
\ {
\ "src": [
\ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': ale#path#Simplify((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'),
\ },
\ ],
\ },
\ )
Execute(ParseCompileCommandsFlags should parse flags for exact directory matches):
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
" We should ues the exact directory flags, not the file basename flags.
AssertEqual
\ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')),
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
\ "xmms2-mpris.c": [
\ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ },
\ ],
\ },
\ {
\ ale#path#Simplify('/foo/bar/xmms2-mpris/src'): [
\ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris/src'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': 'other.c',
\ },
\ ],
\ "src": [
\ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/ignoreme')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': ale#path#Simplify((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'),
\ },
\ ],
\ },
\ )
Execute(ParseCompileCommandsFlags should fall back to files in the same directory): Execute(ParseCompileCommandsFlags should fall back to files in the same directory):
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c')) silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
AssertEqual AssertEqual
\ '-I ' . ale#path#Simplify('/usr/include/xmms2'), \ '-I ' . ale#Escape(ale#path#Simplify('/usr/include/xmms2')),
\ ale#c#ParseCompileCommandsFlags(bufnr(''), {}, { "src": [ \ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {},
\ {
\ "src": [
\ { \ {
\ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'), \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
\ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2') \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2')
@ -215,13 +296,33 @@ Execute(ParseCompileCommandsFlags should fall back to files in the same director
\ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'), \ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ 'file': ale#path#Simplify((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'), \ 'file': ale#path#Simplify((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'),
\ }, \ },
\ ] }) \ ],
\ },
\ )
Execute(ParseCompileCommandsFlags should tolerate items without commands):
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
AssertEqual
\ '',
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
\ "xmms2-mpris.c": [
\ {
\ 'directory': '/foo/bar/xmms2-mpris',
\ 'file': '/foo/bar/xmms2-mpris/src/xmms2-mpris.c',
\ },
\ ],
\ },
\ {},
\ )
Execute(ParseCompileCommandsFlags should take commands from matching .c files for .h files): Execute(ParseCompileCommandsFlags should take commands from matching .c files for .h files):
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h')) silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h'))
AssertEqual AssertEqual
\ '-I /usr/include/xmms2', \ '-I ' . ale#Escape('/usr/include/xmms2'),
\ ale#c#ParseCompileCommandsFlags( \ ale#c#ParseCompileCommandsFlags(
\ bufnr(''), \ bufnr(''),
\ { \ {
@ -235,15 +336,14 @@ Execute(ParseCompileCommandsFlags should take commands from matching .c files fo
\ }, \ },
\ ], \ ],
\ }, \ },
\ { \ {},
\ },
\ ) \ )
Execute(ParseCompileCommandsFlags should take commands from matching .cpp files for .hpp files): Execute(ParseCompileCommandsFlags should take commands from matching .cpp files for .hpp files):
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.hpp')) silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.hpp'))
AssertEqual AssertEqual
\ '-I /usr/include/xmms2', \ '-I ' . ale#Escape('/usr/include/xmms2'),
\ ale#c#ParseCompileCommandsFlags( \ ale#c#ParseCompileCommandsFlags(
\ bufnr(''), \ bufnr(''),
\ { \ {
@ -265,7 +365,7 @@ Execute(ParseCompileCommandsFlags should take commands from matching .cpp files
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h')) silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h'))
AssertEqual AssertEqual
\ '-I /usr/include/xmms2', \ '-I ' . ale#Escape('/usr/include/xmms2'),
\ ale#c#ParseCompileCommandsFlags( \ ale#c#ParseCompileCommandsFlags(
\ bufnr(''), \ bufnr(''),
\ { \ {
@ -305,15 +405,25 @@ Execute(ParseCompileCommandsFlags should not take commands from .c files for .h
\ }, \ },
\ ) \ )
Execute(ParseCFlags should not merge flags): Execute(ShellSplit should not merge flags):
AssertEqual AssertEqual
\ '-Dgoal=9' \ [
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')) \ 'gcc',
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')) \ '-Dgoal=9',
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')) \ '-Tlinkerfile.ld',
\ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), \ 'blabla',
\ ale#c#ParseCFlags( \ '-Isubdir',
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ 'subdir/somedep1.o',
\ 'subdir/somedep2.o',
\ '-I''dir with spaces''',
\ '-Idir-with-dash',
\ 'subdir/somedep3.o',
\ 'subdir/somedep4.o',
\ '-I' . ale#path#Simplify('kernel/include'),
\ 'subdir/somedep5.o',
\ 'subdir/somedep6.o',
\ ],
\ ale#c#ShellSplit(
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . 'subdir/somedep1.o ' . 'subdir/somedep2.o ' \ . 'subdir/somedep1.o ' . 'subdir/somedep2.o '
\ . '-I''dir with spaces''' . ' -Idir-with-dash ' \ . '-I''dir with spaces''' . ' -Idir-with-dash '
@ -322,18 +432,28 @@ Execute(ParseCFlags should not merge flags):
\ . 'subdir/somedep5.o ' . 'subdir/somedep6.o' \ . 'subdir/somedep5.o ' . 'subdir/somedep6.o'
\ ) \ )
Execute(ParseCFlags should handle parenthesis and quotes): Execute(ShellSplit should handle parenthesis and quotes):
AssertEqual AssertEqual
\ '-Dgoal=9 -Dtest1="('' '')" -Dtest2=''(` `)'' -Dtest3=`(" ")`', \ [
\ ale#c#ParseCFlags( \ 'gcc',
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ '-Dgoal=9',
\ '-Tlinkerfile.ld',
\ 'blabla',
\ '-Dtest1="('' '')"',
\ 'file1.o',
\ '-Dtest2=''(` `)''',
\ 'file2.o',
\ '-Dtest3=`(" ")`',
\ 'file3.o',
\ ] ,
\ ale#c#ShellSplit(
\ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla ' \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla '
\ . '-Dtest1="('' '')" file1.o ' \ . '-Dtest1="('' '')" file1.o '
\ . '-Dtest2=''(` `)'' file2.o ' \ . '-Dtest2=''(` `)'' file2.o '
\ . '-Dtest3=`(" ")` file3.o' \ . '-Dtest3=`(" ")` file3.o'
\ ) \ )
Execute(CFlags we want to pass): Execute(We should include several important flags):
AssertEqual AssertEqual
\ '-I ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/inc')) \ '-I ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/inc'))
\ . ' -I ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) \ . ' -I ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include'))
@ -341,7 +461,13 @@ Execute(CFlags we want to pass):
\ . ' -isystem ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incsystem')) \ . ' -isystem ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incsystem'))
\ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incafter')) \ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incafter'))
\ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incframework')) \ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incframework'))
\ . ' -Dmacro=value -D macro2 -Bbdir -B bdir2' \ . ' -include ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/foo bar'))
\ . ' -Dmacro="value"'
\ . ' -DGoal=9'
\ . ' -D macro2'
\ . ' -D macro3="value"'
\ . ' -Bbdir'
\ . ' -B bdir2'
\ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3' \ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3'
\ . ' -isysroot sysroot --sysroot=test --no-sysroot-suffix -imultilib multidir' \ . ' -isysroot sysroot --sysroot=test --no-sysroot-suffix -imultilib multidir'
\ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi' \ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi'
@ -349,32 +475,175 @@ Execute(CFlags we want to pass):
\ . ' -iplugindir=dir -march=native -w', \ . ' -iplugindir=dir -march=native -w',
\ ale#c#ParseCFlags( \ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc' \ 0,
\ . ' -Iinc -I include -iquote incquote -isystem incsystem -idirafter incafter -iframework incframework' \ [
\ . ' -Dmacro=value -D macro2 -Bbdir -B bdir2' \ 'gcc',
\ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3' \ '-Iinc',
\ . ' -isysroot sysroot --sysroot=test --no-sysroot-suffix -imultilib multidir' \ '-I',
\ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi' \ 'include',
\ . ' -foption -O2 -C -CC -trigraphs -nostdinc -nostdinc++' \ '-iquote',
\ . ' -iplugindir=dir -march=native -w' \ 'incquote',
\ '-isystem',
\ 'incsystem',
\ '-idirafter',
\ 'incafter',
\ '-iframework',
\ 'incframework',
\ '-include',
\ '''foo bar''',
\ '-Dmacro="value"',
\ '-DGoal=9',
\ '-D',
\ 'macro2',
\ '-D',
\ 'macro3="value"',
\ '-Bbdir',
\ '-B',
\ 'bdir2',
\ '-iprefix',
\ 'prefix',
\ '-iwithprefix',
\ 'prefix2',
\ '-iwithprefixbefore',
\ 'prefix3',
\ '-isysroot',
\ 'sysroot',
\ '--sysroot=test',
\ '--no-sysroot-suffix',
\ '-imultilib',
\ 'multidir',
\ '-Wsome-warning',
\ '-std=c89',
\ '-pedantic',
\ '-pedantic-errors',
\ '-ansi',
\ '-foption',
\ '-O2',
\ '-C',
\ '-CC',
\ '-trigraphs',
\ '-nostdinc',
\ '-nostdinc++',
\ '-iplugindir=dir',
\ '-march=native',
\ '-w',
\ ],
\ ) \ )
Execute(CFlags we dont want to pass): Execute(We should quote the flags we need to quote):
AssertEqual
\ '-I ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/inc'))
\ . ' -I ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include'))
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incquote'))
\ . ' -isystem ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incsystem'))
\ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incafter'))
\ . ' -iframework ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/incframework'))
\ . ' -include ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/foo bar'))
\ . ' ' . ale#Escape('-Dmacro="value"')
\ . ' -DGoal=9'
\ . ' -D macro2'
\ . ' -D ' . ale#Escape('macro3="value"')
\ . ' -Bbdir'
\ . ' -B bdir2'
\ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3'
\ . ' -isysroot sysroot --sysroot=test'
\ . ' ' . ale#Escape('--sysroot="quoted"')
\ . ' ' . ale#Escape('--sysroot=foo bar')
\ . ' --no-sysroot-suffix -imultilib multidir'
\ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi'
\ . ' -foption -O2 -C -CC -trigraphs -nostdinc -nostdinc++'
\ . ' -iplugindir=dir -march=native -w',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 1,
\ [
\ 'gcc',
\ '-Iinc',
\ '-I',
\ 'include',
\ '-iquote',
\ 'incquote',
\ '-isystem',
\ 'incsystem',
\ '-idirafter',
\ 'incafter',
\ '-iframework',
\ 'incframework',
\ '-include',
\ '''foo bar''',
\ '-Dmacro="value"',
\ '-DGoal=9',
\ '-D',
\ 'macro2',
\ '-D',
\ 'macro3="value"',
\ '-Bbdir',
\ '-B',
\ 'bdir2',
\ '-iprefix',
\ 'prefix',
\ '-iwithprefix',
\ 'prefix2',
\ '-iwithprefixbefore',
\ 'prefix3',
\ '-isysroot',
\ 'sysroot',
\ '--sysroot=test',
\ '--sysroot="quoted"',
\ '--sysroot=foo bar',
\ '--no-sysroot-suffix',
\ '-imultilib',
\ 'multidir',
\ '-Wsome-warning',
\ '-std=c89',
\ '-pedantic',
\ '-pedantic-errors',
\ '-ansi',
\ '-foption',
\ '-O2',
\ '-C',
\ '-CC',
\ '-trigraphs',
\ '-nostdinc',
\ '-nostdinc++',
\ '-iplugindir=dir',
\ '-march=native',
\ '-w',
\ ],
\ )
Execute(We should exclude other flags that cause problems):
AssertEqual AssertEqual
\ '', \ '',
\ ale#c#ParseCFlags( \ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc -Wl,option -Wa,option -Wp,option filename.c somelib.a ' \ 0,
\ . '-fdump-file=name -fdiagnostics-arg -fno-show-column -fstack-usage' \ [
\ 'gcc',
\ '-Wl,option',
\ '-Wa,option',
\ '-Wp,option',
\ '-c',
\ 'filename.c',
\ 'somelib.a',
\ '-fdump-file=name',
\ '-fdiagnostics-arg',
\ '-fno-show-column',
\ '-fstack-usage',
\ '-Tlinkerfile.ld',
\ ],
\ ) \ )
Execute(Expanding @file in CFlags): Execute(We should expand @file in CFlags):
AssertEqual AssertEqual
\ '-DARGS1 -DARGS2 -O2', \ '-DARGS1 -DARGS2 -O2',
\ ale#c#ParseCFlags( \ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
\ 'gcc' \ 0,
\ . ' -g' \ [
\ . ' @./args' \ 'gcc',
\ . ' -O2', \ '-g',
\ '@./args',
\ '-O2',
\ ],
\ ) \ )

View file

@ -0,0 +1,134 @@
Before:
Save g:ale_enabled
Save g:ale_run_synchronously
Save g:ale_set_lists_synchronously
Save g:ale_buffer_info
let g:ale_enabled = 1
let g:ale_buffer_info = {}
let g:ale_run_synchronously = 1
let g:ale_set_lists_synchronously = 1
function! TestCallback(buffer, output)
" Windows adds extra spaces to the text from echo.
return [{
\ 'lnum': 2,
\ 'col': 3,
\ 'text': 'testlinter1',
\}]
endfunction
function! TestCallback2(buffer, output)
" Windows adds extra spaces to the text from echo.
return [{
\ 'lnum': 1,
\ 'col': 3,
\ 'text': 'testlinter2',
\}]
endfunction
function! TestCallback3(buffer, output)
" Windows adds extra spaces to the text from echo.
return [{
\ 'lnum': 3,
\ 'col': 3,
\ 'text': 'testlinter3',
\}]
endfunction
" These two linters computer their lint_file values after running commands.
call ale#linter#Define('foobar', {
\ 'name': 'testlinter1',
\ 'callback': 'TestCallback',
\ 'executable': has('win32') ? 'cmd' : 'echo',
\ 'command': has('win32') ? 'echo foo bar' : '/bin/sh -c ''echo foo bar''',
\ 'lint_file': {b -> ale#command#Run(b, 'echo', {-> 1})},
\})
call ale#linter#Define('foobar', {
\ 'name': 'testlinter2',
\ 'callback': 'TestCallback2',
\ 'executable': has('win32') ? 'cmd' : 'echo',
\ 'command': has('win32') ? 'echo foo bar' : '/bin/sh -c ''echo foo bar''',
\ 'lint_file': {b -> ale#command#Run(b, 'echo', {-> ale#command#Run(b, 'echo', {-> 1})})},
\})
" This one directly computes the result.
call ale#linter#Define('foobar', {
\ 'name': 'testlinter3',
\ 'callback': 'TestCallback3',
\ 'executable': has('win32') ? 'cmd' : 'echo',
\ 'command': has('win32') ? 'echo foo bar' : '/bin/sh -c ''echo foo bar''',
\ 'lint_file': {b -> 1},
\})
let g:filename = tempname()
call writefile([], g:filename)
call ale#test#SetFilename(g:filename)
After:
delfunction TestCallback
call ale#engine#Cleanup(bufnr(''))
Restore
call ale#linter#Reset()
" Items and markers, etc.
call setloclist(0, [])
call clearmatches()
call ale#sign#Clear()
if filereadable(g:filename)
call delete(g:filename)
endif
unlet g:filename
Given foobar(A file with some lines):
foo
bar
baz
Execute(lint_file results where the result is eventually computed should be run):
call ale#Queue(0, 'lint_file')
call ale#test#FlushJobs()
AssertEqual
\ [
\ {
\ 'bufnr': bufnr('%'),
\ 'lnum': 1,
\ 'vcol': 0,
\ 'col': 3,
\ 'text': 'testlinter2',
\ 'type': 'E',
\ 'nr': -1,
\ 'pattern': '',
\ 'valid': 1,
\ },
\ {
\ 'bufnr': bufnr('%'),
\ 'lnum': 2,
\ 'vcol': 0,
\ 'col': 3,
\ 'text': 'testlinter1',
\ 'type': 'E',
\ 'nr': -1,
\ 'pattern': '',
\ 'valid': 1,
\ },
\ {
\ 'bufnr': bufnr('%'),
\ 'lnum': 3,
\ 'vcol': 0,
\ 'col': 3,
\ 'text': 'testlinter3',
\ 'type': 'E',
\ 'nr': -1,
\ 'pattern': '',
\ 'valid': 1,
\ },
\ ],
\ ale#test#GetLoclistWithoutModule()
Execute(Linters where lint_file eventually evaluates to 1 shouldn't be run if we don't want to run them):
call ale#Queue(0, '')
call ale#test#FlushJobs()
AssertEqual [], ale#test#GetLoclistWithoutModule()

View file

@ -12,7 +12,7 @@ Before:
call ale#linter#Define('foobar', { call ale#linter#Define('foobar', {
\ 'name': 'lint_file_linter', \ 'name': 'lint_file_linter',
\ 'callback': 'LintFileCallback', \ 'callback': 'LintFileCallback',
\ 'executable': 'echo', \ 'executable': has('win32') ? 'cmd' : 'echo',
\ 'command': {b -> ale#command#Run(b, 'echo', {-> ale#command#Run(b, 'echo', {-> 'foo'})})}, \ 'command': {b -> ale#command#Run(b, 'echo', {-> ale#command#Run(b, 'echo', {-> 'foo'})})},
\ 'read_buffer': 0, \ 'read_buffer': 0,
\}) \})
@ -28,7 +28,7 @@ After:
Given foobar (Some imaginary filetype): Given foobar (Some imaginary filetype):
Execute(It should be possible to compute an executable to check based on the result of commands): Execute(It should be possible to compute an executable to check based on the result of commands):
AssertLinter 'echo', 'foo' AssertLinter has('win32') ? 'cmd' : 'echo', 'foo'
ALELint ALELint
call ale#test#FlushJobs() call ale#test#FlushJobs()
@ -40,7 +40,7 @@ Execute(It should be possible to compute an executable to check based on the res
Execute(It handle the deferred command failing): Execute(It handle the deferred command failing):
let g:ale_emulate_job_failure = 1 let g:ale_emulate_job_failure = 1
AssertLinter 'echo', 0 AssertLinter has('win32') ? 'cmd' : 'echo', 0
ALELint ALELint
call ale#test#FlushJobs() call ale#test#FlushJobs()

View file

@ -0,0 +1,62 @@
Before:
Save g:ale_filename_mappings
Save b:ale_filename_mappings
let g:ale_filename_mappings = {}
unlet! b:ale_filename_mappings
After:
Restore
Execute(ale#GetFilenameMappings should return the correct mappings for given linters/fixers):
let g:ale_filename_mappings = {'a': [['foo', 'bar']], 'b': [['baz', 'foo']]}
AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), 'a')
AssertEqual [['baz', 'foo']], ale#GetFilenameMappings(bufnr(''), 'b')
AssertEqual [], ale#GetFilenameMappings(bufnr(''), 'c')
let b:ale_filename_mappings = {'b': [['abc', 'xyz']]}
AssertEqual [], ale#GetFilenameMappings(bufnr(''), 'a')
AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), 'b')
AssertEqual [], ale#GetFilenameMappings(bufnr(''), 'c')
Execute(ale#GetFilenameMappings should return Lists set for use with all tools):
let g:ale_filename_mappings = [['foo', 'bar']]
AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), 'a')
AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), '')
AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), v:null)
let b:ale_filename_mappings = [['abc', 'xyz']]
AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), 'a')
AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), '')
AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), v:null)
Execute(ale#GetFilenameMappings should let you use * as a fallback):
let g:ale_filename_mappings = {'a': [['foo', 'bar']], '*': [['abc', 'xyz']]}
AssertEqual [['foo', 'bar']], ale#GetFilenameMappings(bufnr(''), 'a')
AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), 'b')
AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), '')
AssertEqual [['abc', 'xyz']], ale#GetFilenameMappings(bufnr(''), v:null)
Execute(ale#filename_mapping#Invert should invert filename mappings):
AssertEqual
\ [['b', 'a'], ['y', 'x']],
\ ale#filename_mapping#Invert([['a', 'b'], ['x', 'y']])
\
Execute(ale#filename_mapping#Map return the filename as-is if there are no mappings):
AssertEqual
\ '/foo//bar',
\ ale#filename_mapping#Map('/foo//bar', [['/bar', '/data/']])
Execute(ale#filename_mapping#Map should map filenames):
AssertEqual
\ '/data/bar',
\ ale#filename_mapping#Map('/foo//bar', [
\ ['/data/', '/baz/'],
\ ['/foo/', '/data/'],
\ ['/foo/', '/xyz/'],
\ ])

View file

@ -39,7 +39,7 @@ Execute(The defaults for the python filetype should be correct):
AssertEqual [], GetLinterNames('python') AssertEqual [], GetLinterNames('python')
Execute(The defaults for the rust filetype should be correct): Execute(The defaults for the rust filetype should be correct):
AssertEqual ['cargo'], GetLinterNames('rust') AssertEqual ['cargo', 'rls'], GetLinterNames('rust')
let g:ale_linters_explicit = 1 let g:ale_linters_explicit = 1

View file

@ -63,6 +63,8 @@ Before:
let g:preview_called = 1 let g:preview_called = 1
let g:item_list = a:item_list let g:item_list = a:item_list
let g:options = a:options let g:options = a:options
call ale#preview#SetLastSelection(a:item_list, a:options)
endfunction endfunction
After: After:
@ -110,7 +112,16 @@ Given typescript(Some typescript file):
bazxyzxyzxyz bazxyzxyzxyz
Execute(Results should be shown for tsserver responses): Execute(Results should be shown for tsserver responses):
call ale#references#SetMap({3: {}}) " We should remember these options when we repeat the selection.
call ale#references#SetMap(
\ {
\ 3: {
\ 'ignorethis': 'x',
\ 'open_in': 'tab',
\ 'use_relative_paths': 1,
\ }
\ }
\)
call ale#references#HandleTSServerResponse(1, { call ale#references#HandleTSServerResponse(1, {
\ 'command': 'references', \ 'command': 'references',
\ 'request_seq': 3, \ 'request_seq': 3,
@ -158,8 +169,7 @@ Execute(Results should be shown for tsserver responses):
AssertEqual {}, ale#references#GetMap() AssertEqual {}, ale#references#GetMap()
" We should be able to repeat selections with ALERepeatSelection " We should be able to repeat selections with ALERepeatSelection
let g:ale_item_list = [] let g:item_list = []
ALERepeatSelection ALERepeatSelection
AssertEqual AssertEqual
@ -170,6 +180,12 @@ Execute(Results should be shown for tsserver responses):
\ ], \ ],
\ g:item_list \ g:item_list
AssertEqual {}, ale#references#GetMap() AssertEqual {}, ale#references#GetMap()
AssertEqual
\ {
\ 'open_in': 'tab',
\ 'use_relative_paths': 1,
\ },
\ g:options
Execute(The preview window should not be opened for empty tsserver responses): Execute(The preview window should not be opened for empty tsserver responses):
call ale#references#SetMap({3: {}}) call ale#references#SetMap({3: {}})

View file

@ -25,12 +25,12 @@ After:
Execute(FormatCommand should do nothing to basic command strings): Execute(FormatCommand should do nothing to basic command strings):
AssertEqual AssertEqual
\ ['', 'awesome-linter do something', 0], \ ['', 'awesome-linter do something', 0],
\ ale#command#FormatCommand(bufnr('%'), '', 'awesome-linter do something', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), '', 'awesome-linter do something', 0, v:null, [])
Execute(FormatCommand should handle %%, and ignore other percents): Execute(FormatCommand should handle %%, and ignore other percents):
AssertEqual AssertEqual
\ ['', '% %%d %%f %x %', 0], \ ['', '% %%d %%f %x %', 0],
\ ale#command#FormatCommand(bufnr('%'), '', '%% %%%d %%%f %x %', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), '', '%% %%%d %%%f %x %', 0, v:null, [])
Execute(FormatCommand should convert %s to the current filename): Execute(FormatCommand should convert %s to the current filename):
AssertEqual AssertEqual
@ -39,10 +39,10 @@ Execute(FormatCommand should convert %s to the current filename):
\ 'foo ' . ale#Escape(expand('%:p')) . ' bar ' . ale#Escape(expand('%:p')), \ 'foo ' . ale#Escape(expand('%:p')) . ' bar ' . ale#Escape(expand('%:p')),
\ 0, \ 0,
\ ], \ ],
\ ale#command#FormatCommand(bufnr('%'), '', 'foo %s bar %s', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), '', 'foo %s bar %s', 0, v:null, [])
Execute(FormatCommand should convert %t to a new temporary filename): Execute(FormatCommand should convert %t to a new temporary filename):
let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %t', 0, v:null) let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %t', 0, v:null, [])
call CheckTempFile(g:result[0]) call CheckTempFile(g:result[0])
@ -56,21 +56,21 @@ Execute(FormatCommand should convert %t to a new temporary filename):
AssertEqual g:match[1], g:match[2] AssertEqual g:match[1], g:match[2]
Execute(FormatCommand should not convert %t to a new temporary filename when the input is given as v:false): Execute(FormatCommand should not convert %t to a new temporary filename when the input is given as v:false):
let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %t', 0, v:false) let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %t', 0, v:false, [])
AssertEqual ['', 'foo %t bar %t', 0], g:result AssertEqual ['', 'foo %t bar %t', 0], g:result
Execute(FormatCommand should signal that files are created when temporary files are needed): Execute(FormatCommand should signal that files are created when temporary files are needed):
AssertEqual AssertEqual
\ 1, \ 1,
\ ale#command#FormatCommand(bufnr('%'), '', 'foo %t', 0, v:null)[2] \ ale#command#FormatCommand(bufnr('%'), '', 'foo %t', 0, v:null, [])[2]
AssertEqual AssertEqual
\ 0, \ 0,
\ ale#command#FormatCommand(bufnr('%'), '', 'foo %s', 0, v:null)[2] \ ale#command#FormatCommand(bufnr('%'), '', 'foo %s', 0, v:null, [])[2]
Execute(FormatCommand should let you combine %s and %t): Execute(FormatCommand should let you combine %s and %t):
let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %s', 0, v:null) let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo %t bar %s', 0, v:null, [])
call CheckTempFile(g:result[0]) call CheckTempFile(g:result[0])
@ -87,30 +87,30 @@ Execute(FormatCommand should replace %e with the escaped executable):
if has('win32') if has('win32')
AssertEqual AssertEqual
\ ['', 'foo foo', 0], \ ['', 'foo foo', 0],
\ ale#command#FormatCommand(bufnr('%'), 'foo', '%e %e', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), 'foo', '%e %e', 0, v:null, [])
AssertEqual AssertEqual
\ ['', '"foo bar"', 0], \ ['', '"foo bar"', 0],
\ ale#command#FormatCommand(bufnr('%'), 'foo bar', '%e', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), 'foo bar', '%e', 0, v:null, [])
AssertEqual AssertEqual
\ ['', '%e %e', 0], \ ['', '%e %e', 0],
\ ale#command#FormatCommand(bufnr('%'), '', '%e %e', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), '', '%e %e', 0, v:null, [])
else else
AssertEqual AssertEqual
\ ['', '''foo'' ''foo''', 0], \ ['', '''foo'' ''foo''', 0],
\ ale#command#FormatCommand(bufnr('%'), 'foo', '%e %e', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), 'foo', '%e %e', 0, v:null, [])
AssertEqual AssertEqual
\ ['', '''foo bar''', 0], \ ['', '''foo bar''', 0],
\ ale#command#FormatCommand(bufnr('%'), 'foo bar', '%e', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), 'foo bar', '%e', 0, v:null, [])
AssertEqual AssertEqual
\ ['', '%e %e', 0], \ ['', '%e %e', 0],
\ ale#command#FormatCommand(bufnr('%'), '', '%e %e', 0, v:null) \ ale#command#FormatCommand(bufnr('%'), '', '%e %e', 0, v:null, [])
endif endif
Execute(EscapeCommandPart should escape all percent signs): Execute(EscapeCommandPart should escape all percent signs):
AssertEqual '%%s %%t %%%% %%s %%t %%%%', ale#engine#EscapeCommandPart('%s %t %% %s %t %%') AssertEqual '%%s %%t %%%% %%s %%t %%%%', ale#engine#EscapeCommandPart('%s %t %% %s %t %%')
Execute(EscapeCommandPart should pipe in temporary files appropriately): Execute(EscapeCommandPart should pipe in temporary files appropriately):
let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo bar', 1, v:null) let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo bar', 1, v:null, [])
call CheckTempFile(g:result[0]) call CheckTempFile(g:result[0])
@ -118,10 +118,57 @@ Execute(EscapeCommandPart should pipe in temporary files appropriately):
Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] Assert !empty(g:match), 'No match found! Result was: ' . g:result[1]
AssertEqual ale#Escape(g:result[0]), g:match[1] AssertEqual ale#Escape(g:result[0]), g:match[1]
let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo bar %t', 1, v:null) let g:result = ale#command#FormatCommand(bufnr('%'), '', 'foo bar %t', 1, v:null, [])
call CheckTempFile(g:result[0]) call CheckTempFile(g:result[0])
let g:match = matchlist(g:result[1], '\v^foo bar (.*)$') let g:match = matchlist(g:result[1], '\v^foo bar (.*)$')
Assert !empty(g:match), 'No match found! Result was: ' . g:result[1] Assert !empty(g:match), 'No match found! Result was: ' . g:result[1]
AssertEqual ale#Escape(g:result[0]), g:match[1] AssertEqual ale#Escape(g:result[0]), g:match[1]
Execute(FormatCommand should apply filename modifiers to the current file):
AssertEqual
\ ale#Escape(expand('%:p:h'))
\ . ' ' . ale#Escape('dummy.txt')
\ . ' ' . ale#Escape(expand('%:p:h:t'))
\ . ' ' . ale#Escape('txt')
\ . ' ' . ale#Escape(expand('%:p:r')),
\ ale#command#FormatCommand(bufnr(''), '', '%s:h %s:t %s:h:t %s:e %s:r', 0, v:null, [])[1]
Execute(FormatCommand should apply filename modifiers to the temporary file):
let g:result = ale#command#FormatCommand(bufnr(''), '', '%t:h %t:t %t:h:t %t:e %t:r', 0, v:null, [])
AssertEqual
\ ale#Escape(fnamemodify(g:result[0], ':h'))
\ . ' ' . ale#Escape('dummy.txt')
\ . ' ' . ale#Escape(fnamemodify(g:result[0], ':h:t'))
\ . ' ' . ale#Escape('txt')
\ . ' ' . ale#Escape(fnamemodify(g:result[0], ':r')),
\ g:result[1]
Execute(FormatCommand should apply filename mappings the current file):
let g:result = ale#command#FormatCommand(bufnr('%'), '', '%s', 0, v:null, [
\ [expand('%:p:h'), '/foo/bar'],
\])
Assert g:result[1] =~# '/foo/bar'
Execute(FormatCommand should apply filename mappings to temporary files):
let g:result = ale#command#FormatCommand(bufnr('%'), '', '%t', 0, v:null, [
\ [fnamemodify(tempname(), ':h:h'), '/foo/bar']
\])
Assert g:result[1] =~# '/foo/bar'
Execute(FormatCommand should apply filename modifiers to mapped filenames):
let g:result = ale#command#FormatCommand(bufnr('%'), '', '%s:h', 0, v:null, [
\ [expand('%:p:h'), '/foo/bar'],
\])
AssertEqual ale#Escape('/foo/bar'), g:result[1]
let g:result = ale#command#FormatCommand(bufnr('%'), '', '%t:h:h:h', 0, v:null, [
\ [fnamemodify(tempname(), ':h:h'), '/foo/bar']
\])
AssertEqual ale#Escape('/foo/bar'), g:result[1]

View file

@ -174,7 +174,7 @@ Execute(PreProcess should process the lint_file option correctly):
\} \}
AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertThrows call ale#linter#PreProcess('testft', g:linter)
AssertEqual '`lint_file` must be `0` or `1`', g:vader_exception AssertEqual '`lint_file` must be `0`, `1`, or a Function', g:vader_exception
let g:linter.lint_file = 0 let g:linter.lint_file = 0
@ -185,14 +185,17 @@ Execute(PreProcess should process the lint_file option correctly):
let g:linter.lint_file = 1 let g:linter.lint_file = 1
AssertEqual 1, ale#linter#PreProcess('testft', g:linter).lint_file AssertEqual 1, ale#linter#PreProcess('testft', g:linter).lint_file
" The default for read_buffer should change to 0 when lint_file is 1. " The default for read_buffer should still be 1
AssertEqual 0, ale#linter#PreProcess('testft', g:linter).read_buffer AssertEqual 1, ale#linter#PreProcess('testft', g:linter).read_buffer
let g:linter.read_buffer = 1 let g:linter.read_buffer = 1
" We shouldn't be able to set both options to 1 at the same time. " We should be able to set `read_buffer` and `lint_file` at the same time.
AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 1, ale#linter#PreProcess('testft', g:linter).read_buffer
AssertEqual 'Only one of `lint_file` or `read_buffer` can be `1`', g:vader_exception
let g:linter.lint_file = function('type')
Assert type(ale#linter#PreProcess('testft', g:linter).lint_file) is v:t_func
Execute(PreProcess should set a default value for lint_file): Execute(PreProcess should set a default value for lint_file):
let g:linter = { let g:linter = {

View file

@ -1,7 +1,50 @@
Before:
Save g:ale_filename_mappings
let g:ale_filename_mappings = {}
After: After:
unlet! b:temp_name unlet! b:temp_name
unlet! b:other_bufnr unlet! b:other_bufnr
Restore
Execute(FixLocList should map filenames):
" Paths converted back into temporary filenames shouldn't be included.
let g:ale_filename_mappings = {
\ 'linter2': [['/xxx/', '/data/']],
\ 'linter1': [
\ ['/bar/', '/data/special/'],
\ ['/foo/', '/data/'],
\ [
\ ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h:h')) . '/',
\ '/x-tmp/',
\ ],
\ ],
\}
AssertEqual
\ [
\ '/foo/file.txt',
\ v:null,
\ '/bar/file.txt',
\ ],
\ map(
\ ale#engine#FixLocList(
\ bufnr('%'),
\ 'linter1',
\ 0,
\ [
\ {'text': 'x', 'lnum': 1, 'filename': '/data/file.txt'},
\ {'text': 'x', 'lnum': 1, 'filename': '/x-tmp/file.txt'},
\ {'text': 'x', 'lnum': 1, 'filename': '/data/special/file.txt'},
\ ],
\ ),
\ 'get(v:val, ''filename'', v:null)',
\ )
Given foo (Some file with lines to count): Given foo (Some file with lines to count):
foo12345678 foo12345678
bar12345678 bar12345678

View file

@ -23,22 +23,22 @@ Execute(React Native apps using CocoaPods should take precedence over the defaul
call ale#test#SetFilename('swiftlint-test-files/react-native/testfile.swift') call ale#test#SetFilename('swiftlint-test-files/react-native/testfile.swift')
AssertEqual AssertEqual
\ ale#path#Simplify(g:dir . '/swiftlint-test-files/react-native/ios/Pods/SwiftLint/swiftlint'), \ tolower(ale#path#Simplify(g:dir . '/swiftlint-test-files/react-native/ios/Pods/SwiftLint/swiftlint')),
\ ale_linters#swift#swiftlint#GetExecutable(bufnr('')) \ tolower(ale_linters#swift#swiftlint#GetExecutable(bufnr('')))
Execute(CocoaPods installation should take precedence over the default executable): Execute(CocoaPods installation should take precedence over the default executable):
call ale#test#SetFilename('swiftlint-test-files/cocoapods/testfile.swift') call ale#test#SetFilename('swiftlint-test-files/cocoapods/testfile.swift')
AssertEqual AssertEqual
\ ale#path#Simplify(g:dir . '/swiftlint-test-files/cocoapods/Pods/SwiftLint/swiftlint'), \ tolower(ale#path#Simplify(g:dir . '/swiftlint-test-files/cocoapods/Pods/SwiftLint/swiftlint')),
\ ale_linters#swift#swiftlint#GetExecutable(bufnr('')) \ tolower(ale_linters#swift#swiftlint#GetExecutable(bufnr('')))
Execute(Top level CocoaPods installation should take precedence over React Native installation): Execute(Top level CocoaPods installation should take precedence over React Native installation):
call ale#test#SetFilename('swiftlint-test-files/cocoapods-and-react-native/testfile.swift') call ale#test#SetFilename('swiftlint-test-files/cocoapods-and-react-native/testfile.swift')
AssertEqual AssertEqual
\ ale#path#Simplify(g:dir . '/swiftlint-test-files/cocoapods-and-react-native/Pods/SwiftLint/swiftlint'), \ tolower(ale#path#Simplify(g:dir . '/swiftlint-test-files/cocoapods-and-react-native/Pods/SwiftLint/swiftlint')),
\ ale_linters#swift#swiftlint#GetExecutable(bufnr('')) \ tolower(ale_linters#swift#swiftlint#GetExecutable(bufnr('')))
Execute(use-global should override other versions): Execute(use-global should override other versions):
let g:ale_swift_swiftlint_use_global = 1 let g:ale_swift_swiftlint_use_global = 1

View file

@ -16,5 +16,5 @@ Execute(BufferCdString should output the correct command string):
call ale#test#SetFilename('foo.txt') call ale#test#SetFilename('foo.txt')
AssertEqual AssertEqual
\ has('unix') ? 'cd ' . ale#Escape(g:dir) . ' && ' : 'cd /d ' . ale#Escape(g:dir) . ' && ', \ has('unix') ? 'cd %s:h && ' : 'cd /d %s:h && ',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#BufferCdString(bufnr(''))