merge master -- apparently someone else added dhall?

This commit is contained in:
toastal 2020-09-08 10:08:00 +07:00
commit f07ecbc579
No known key found for this signature in database
GPG key ID: A1CAFFE4DB109A47
182 changed files with 4228 additions and 2146 deletions

View file

@ -19,6 +19,9 @@ init:
# Stop git from changing newlines
- 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:
# Download and unpack Vim
- ps: >-

5
.github/stale.yml vendored
View file

@ -1,9 +1,10 @@
---
# This configuration closes stale PRs after 30 days.
# This configuration closes stale PRs after 28 + 7 days.
# That's 4 weeks until stale bot complains, and a week until it closes a PR.
# Issues in ALE are never, ever stale. They are either resolved or not.
only: pulls
daysUntilStale: 28
daysUntilClose: 2
daysUntilClose: 7
exemptLabels: []
staleLabel: stale
markComment: >

5
.gitignore vendored
View file

@ -1,11 +1,12 @@
!.editorconfig
*.obj
*.pyc
# Ignore all hidden files everywhere.
# Use `git add -f` to add hidden files.
.*
__pycache__
*.pyc
/doc/tags
/init.vim
/test/ale-info-test-file
/vader_output
__pycache__
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)
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)
20. [How can I run linters or fixers via Docker or a VM?](#faq-vm)
<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)
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)
return '%e -x ada -c -gnatc'
\ . ' -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'))
\ . ' %t'
endfunction

View file

@ -0,0 +1,5 @@
" Author: Horacio Sanson (hsanson [ät] gmail.com)
" Description: languagetool for asciidoc files, copied from markdown.
call ale#handlers#languagetool#DefineLinter('asciidoc')

View file

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

53
ale_linters/c/cc.vim Normal file
View file

@ -0,0 +1,53 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: A C compiler linter for C files with gcc/clang, etc.
call ale#Set('c_cc_executable', '<auto>')
call ale#Set('c_cc_options', '-std=c11 -Wall')
function! ale_linters#c#cc#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'c_cc_executable')
" Default to either clang or gcc.
if l:executable is# '<auto>'
if ale#engine#IsExecutable(a:buffer, 'clang')
let l:executable = 'clang'
else
let l:executable = 'gcc'
endif
endif
return l:executable
endfunction
function! ale_linters#c#cc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
let l:ale_flags = ale#Var(a:buffer, 'c_cc_options')
if l:cflags =~# '-std='
let l:ale_flags = substitute(
\ l:ale_flags,
\ '-std=\(c\|gnu\)[0-9]\{2\}',
\ '',
\ 'g')
endif
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote %s:h'
\ . ale#Pad(l:cflags)
\ . ale#Pad(l:ale_flags) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'cc',
\ 'aliases': ['gcc', 'clang'],
\ 'output_stream': 'stderr',
\ 'executable': function('ale_linters#c#cc#GetExecutable'),
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#cc#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View file

@ -1,24 +0,0 @@
" Author: Masahiro H https://github.com/mshr-h
" Description: clang linter for c files
call ale#Set('c_clang_executable', 'clang')
call ale#Set('c_clang_options', '-std=c11 -Wall')
function! ale_linters#c#clang#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return '%e -S -x c -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_clang_options')) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'c_clang_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clang#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View file

@ -1,28 +0,0 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: gcc linter for c files
call ale#Set('c_gcc_executable', 'gcc')
call ale#Set('c_gcc_options', '-std=c11 -Wall')
function! ale_linters#c#gcc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'c_gcc_options')) . ' -'
endfunction
call ale#linter#Define('c', {
\ 'name': 'gcc',
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'c_gcc_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#gcc#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

53
ale_linters/cpp/cc.vim Normal file
View file

@ -0,0 +1,53 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: A C++ compiler linter for C++ files with gcc/clang, etc.
call ale#Set('cpp_cc_executable', '<auto>')
call ale#Set('cpp_cc_options', '-std=c++14 -Wall')
function! ale_linters#cpp#cc#GetExecutable(buffer) abort
let l:executable = ale#Var(a:buffer, 'cpp_cc_executable')
" Default to either clang++ or gcc.
if l:executable is# '<auto>'
if ale#engine#IsExecutable(a:buffer, 'clang++')
let l:executable = 'clang++'
else
let l:executable = 'gcc'
endif
endif
return l:executable
endfunction
function! ale_linters#cpp#cc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
let l:ale_flags = ale#Var(a:buffer, 'cpp_cc_options')
if l:cflags =~# '-std='
let l:ale_flags = substitute(
\ l:ale_flags,
\ '-std=\(c\|gnu\)++[0-9]\{2\}',
\ '',
\ 'g')
endif
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c++'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote %s:h'
\ . ale#Pad(l:cflags)
\ . ale#Pad(l:ale_flags) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'cc',
\ 'aliases': ['gcc', 'clang', 'g++', 'clang++'],
\ 'output_stream': 'stderr',
\ 'executable': function('ale_linters#cpp#cc#GetExecutable'),
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#cc#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View file

@ -1,24 +0,0 @@
" Author: Tomota Nakamura <https://github.com/tomotanakamura>
" Description: clang linter for cpp files
call ale#Set('cpp_clang_executable', 'clang++')
call ale#Set('cpp_clang_options', '-std=c++14 -Wall')
function! ale_linters#cpp#clang#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
return '%e -S -x c++ -fsyntax-only'
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_clang_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'clang',
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'cpp_clang_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clang#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View file

@ -1,29 +0,0 @@
" Author: geam <mdelage@student.42.fr>
" Description: gcc linter for cpp files
"
call ale#Set('cpp_gcc_executable', 'gcc')
call ale#Set('cpp_gcc_options', '-std=c++14 -Wall')
function! ale_linters#cpp#gcc#GetCommand(buffer, output) abort
let l:cflags = ale#c#GetCFlags(a:buffer, a:output)
" -iquote with the directory the file is in makes #include work for
" headers in the same directory.
"
" `-o /dev/null` or `-o null` is needed to catch all errors,
" -fsyntax-only doesn't catch everything.
return '%e -S -x c++'
\ . ' -o ' . g:ale#util#nul_file
\ . ' -iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h'))
\ . ale#Pad(l:cflags)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_gcc_options')) . ' -'
endfunction
call ale#linter#Define('cpp', {
\ 'name': 'gcc',
\ 'aliases': ['g++'],
\ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'cpp_gcc_executable')},
\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#gcc#GetCommand'))},
\ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes',
\})

View file

@ -5,9 +5,6 @@ call ale#Set('cuda_nvcc_executable', 'nvcc')
call ale#Set('cuda_nvcc_options', '-std=c++11')
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'
\ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
\ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options'))

View file

@ -46,7 +46,7 @@ function! ale_linters#elixir#credo#GetMode() abort
endfunction
function! ale_linters#elixir#credo#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
let l:project_root = ale#handlers#elixir#FindMixUmbrellaRoot(a:buffer)
let l:mode = ale_linters#elixir#credo#GetMode()
return ale#path#CdString(l:project_root)

View file

@ -11,7 +11,7 @@ function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'ruumba')
\ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'eruby_ruumba_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
\ . ' --stdin %s'
endfunction
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'
endfunction
call ale#linter#Define('go', {
\ 'name': 'gofmt',
\ 'output_stream': 'stderr',

View file

@ -4,6 +4,28 @@
call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint')
call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#handlebars#embertemplatelint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'handlebars_embertemplatelint', [
\ 'node_modules/.bin/ember-template-lint',
\])
endfunction
function! ale_linters#handlebars#embertemplatelint#GetCommand(buffer, version) abort
" Reading from stdin was introduced in ember-template-lint@1.6.0
return ale#semver#GTE(a:version, [1, 6, 0])
\ ? '%e --json --filename %s'
\ : '%e --json %t'
endfunction
function! ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck(buffer) abort
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ ale_linters#handlebars#embertemplatelint#GetExecutable(a:buffer),
\ '%e --version',
\ function('ale_linters#handlebars#embertemplatelint#GetCommand'),
\)
endfunction
function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
let l:output = []
let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
@ -30,10 +52,9 @@ function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
endfunction
call ale#linter#Define('handlebars', {
\ 'name': 'ember-template-lint',
\ 'executable': {b -> ale#node#FindExecutable(b, 'handlebars_embertemplatelint', [
\ 'node_modules/.bin/ember-template-lint',
\ ])},
\ 'command': '%e --json %t',
\ 'name': 'embertemplatelint',
\ 'aliases': ['ember-template-lint'],
\ 'executable': function('ale_linters#handlebars#embertemplatelint#GetExecutable'),
\ 'command': function('ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck'),
\ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle',
\})

View file

@ -31,21 +31,28 @@ function! ale_linters#java#eclipselsp#JarPath(buffer) abort
" Search jar file within repository path when manually built using mvn
let l:files = globpath(l:path, '**/'.l:platform.'/**/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) > 1
if len(l:files) >= 1
return l:files[0]
endif
" Search jar file within VSCode extensions folder.
let l:files = globpath(l:path, '**/'.l:platform.'/plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) > 1
if len(l:files) >= 1
return l:files[0]
endif
" Search jar file within unzipped tar.gz file
let l:files = globpath(l:path, 'plugins/org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) >= 1
return l:files[0]
endif
" Search jar file within system package path
let l:files = globpath('/usr/share/java/jdtls/plugins', 'org.eclipse.equinox.launcher_\d\.\d\.\d\d\d\.*\.jar', 1, 1)
if len(l:files) > 1
if len(l:files) >= 1
return l:files[0]
endif

View file

@ -1,11 +1,22 @@
" Author: Ty-Lucas Kelley <tylucaskelley@gmail.com>
" Description: Adds support for markdownlint
call ale#Set('markdown_markdownlint_options', '')
function! ale_linters#markdown#markdownlint#GetCommand(buffer) abort
let l:executable = 'markdownlint'
let l:options = ale#Var(a:buffer, 'markdown_markdownlint_options')
return ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') . ' %s'
endfunction
call ale#linter#Define('markdown', {
\ 'name': 'markdownlint',
\ 'executable': 'markdownlint',
\ 'lint_file': 1,
\ 'output_stream': 'both',
\ 'command': 'markdownlint %s',
\ 'command': function('ale_linters#markdown#markdownlint#GetCommand'),
\ 'callback': 'ale#handlers#markdownlint#Handle'
\})

View file

@ -7,10 +7,9 @@ call ale#Set('nasm_nasm_options', '')
function! ale_linters#nasm#nasm#GetCommand(buffer) abort
" Note that NASM requires a trailing slash for the -I option.
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'
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'))
\ . ' %s'
\ . ' -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
" headers in the same directory.
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') . ' -'
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
" headers in the same directory.
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') . ' -'
endfunction

View file

@ -9,6 +9,6 @@ call ale#linter#Define('ocaml', {
\ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'),
\ 'language_callback': 'ale#handlers#ols#GetLanguage',
\ 'language': function('ale#handlers#ols#GetLanguage'),
\ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\})

View file

@ -1,9 +1,9 @@
" Author: Matt Brown <https://github.com/muglug>
" Description: plugin for Psalm, static analyzer for PHP
call ale#Set('psalm_langserver_executable', 'psalm')
call ale#Set('psalm_langserver_options', '')
call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('php_psalm_executable', 'psalm')
call ale#Set('php_psalm_options', '')
call ale#Set('php_psalm_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
@ -12,13 +12,13 @@ function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
endfunction
function! ale_linters#php#psalm#GetCommand(buffer) abort
return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'psalm_langserver_options'))
return '%e --language-server' . ale#Pad(ale#Var(a:buffer, 'php_psalm_options'))
endfunction
call ale#linter#Define('php', {
\ 'name': 'psalm',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [
\ 'executable': {b -> ale#node#FindExecutable(b, 'php_psalm', [
\ 'vendor/bin/psalm',
\ ])},
\ 'command': function('ale_linters#php#psalm#GetCommand'),

View file

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

View file

@ -4,7 +4,7 @@
call ale#Set('python_flake8_executable', 'flake8')
call ale#Set('python_flake8_options', '')
call ale#Set('python_flake8_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_flake8_change_directory', 1)
call ale#Set('python_flake8_change_directory', 'project')
call ale#Set('python_flake8_auto_pipenv', 0)
function! s:UsingModule(buffer) abort
@ -38,10 +38,30 @@ function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort
\)
endfunction
function! ale_linters#python#flake8#GetCdString(buffer) abort
let l:change_directory = ale#Var(a:buffer, 'python_flake8_change_directory')
let l:cd_string = ''
if l:change_directory is# 'project'
let l:project_root = ale#python#FindProjectRootIni(a:buffer)
if !empty(l:project_root)
let l:cd_string = ale#path#CdString(l:project_root)
endif
endif
if (l:change_directory is# 'project' && empty(l:cd_string))
\|| l:change_directory is# 1
\|| l:change_directory is# 'file'
let l:cd_string = ale#path#BufferCdString(a:buffer)
endif
return l:cd_string
endfunction
function! ale_linters#python#flake8#GetCommand(buffer, version) abort
let l:cd_string = ale#Var(a:buffer, 'python_flake8_change_directory')
\ ? ale#path#BufferCdString(a:buffer)
\ : ''
let l:cd_string = ale_linters#python#flake8#GetCdString(a:buffer)
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$'

View file

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

View file

@ -9,6 +9,6 @@ call ale#linter#Define('reason', {
\ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'),
\ 'language_callback': 'ale#handlers#ols#GetLanguage',
\ 'language': function('ale#handlers#ols#GetLanguage'),
\ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\})

View file

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

View file

@ -1,5 +1,5 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Lints sh files using bash -n
" Description: Lints shell files by invoking the shell with -n
" Backwards compatibility
if exists('g:ale_linters_sh_shell_default_shell')

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

@ -0,0 +1,62 @@
" Author: Klaas Pieter Annema <https://github.com/klaaspieter>
" Description: Support for swift-format https://github.com/apple/swift-format
let s:default_executable = 'swift-format'
call ale#Set('swift_swiftformat_executable', s:default_executable)
function! ale_linters#swift#swiftformat#UseSwift(buffer) abort
let l:swift_config = ale#path#FindNearestFile(a:buffer, 'Package.swift')
let l:executable = ale#Var(a:buffer, 'swift_swiftformat_executable')
return !empty(l:swift_config) && l:executable is# s:default_executable
endfunction
function! ale_linters#swift#swiftformat#GetExecutable(buffer) abort
if ale_linters#swift#swiftformat#UseSwift(a:buffer)
return 'swift'
endif
return ale#Var(a:buffer, 'swift_swiftformat_executable')
endfunction
function! ale_linters#swift#swiftformat#GetCommand(buffer) abort
let l:executable = ale_linters#swift#swiftformat#GetExecutable(a:buffer)
let l:args = '--mode lint %t'
if ale_linters#swift#swiftformat#UseSwift(a:buffer)
let l:args = 'run swift-format' . ' ' . l:args
endif
return ale#Escape(l:executable) . ' ' . l:args
endfunction
function! ale_linters#swift#swiftformat#Handle(buffer, lines) abort
" Matches lines of the following pattern:
"
" Sources/main.swift:4:21: warning: [DoNotUseSemicolons]: remove ';' and move the next statement to the new line
" Sources/main.swift:3:12: warning: [Spacing]: remove 1 space
let l:pattern = '\v^.*:(\d+):(\d+): (\S+) \[(\S+)\]: (.*)$'
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] is# 'error' ? 'E' : 'W',
\ 'code': l:match[4],
\ 'text': l:match[5],
\})
endfor
return l:output
endfunction
call ale#linter#Define('swift', {
\ 'name': 'swift-format',
\ 'executable': function('ale_linters#swift#swiftformat#GetExecutable'),
\ 'command': function('ale_linters#swift#swiftformat#GetCommand'),
\ 'output_stream': 'stderr',
\ 'language': 'swift',
\ 'callback': 'ale_linters#swift#swiftformat#Handle'
\})

View file

@ -13,14 +13,15 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
"Matches patterns like the following:
"** Warning: add.v(7): (vlog-2623) Undefined variable: C.
"** Error: file.v(1): (vlog-13294) Identifier must be declared with a port mode: C.
let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
let l:pattern = '^**\s\(\w*\): \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)'
let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[2] + 0,
\ 'lnum': l:match[3] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
\ 'text': l:match[3],
\ 'text': l:match[4],
\ 'filename': l:match[2],
\})
endfor
@ -28,13 +29,14 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
"** Warning: (vlog-2623) add.v(7): Undefined variable: C.
"** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: C.
" let l:pattern = '^**\s\(\w*\):[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
let l:pattern = '^**\s\(\w*\):\s\([^)]*)\)[a-zA-Z0-9\-\.\_\/ ]\+(\(\d\+\)):\s\+\(.*\)'
let l:pattern = '^**\s\(\w*\):\s\([^)]*)\) \([a-zA-Z0-9\-\.\_\/ ]\+\)(\(\d\+\)):\s\+\(.*\)'
for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, {
\ 'lnum': l:match[3] + 0,
\ 'lnum': l:match[4] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
\ 'text': l:match[2] . ' ' . l:match[4],
\ 'text': l:match[2] . ' ' . l:match[5],
\ 'filename': l:match[3],
\})
endfor

View file

@ -5,7 +5,7 @@
call ale#Set('vim_vint_show_style_issues', 1)
call ale#Set('vim_vint_executable', 'vint')
let s:enable_neovim = has('nvim') ? ' --enable-neovim' : ''
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"'
let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {policy_name} - {description} (see {reference})"'
function! ale_linters#vim#vint#GetCommand(buffer, version) abort
let l:can_use_no_color_flag = empty(a:version)

View file

@ -263,6 +263,28 @@ function! ale#GetLocItemMessage(item, format_string) abort
let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g')
" Replace %s with the text.
let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g')
" Windows may insert carriage return line endings (^M), strip these characters.
let l:msg = substitute(l:msg, '\r', '', 'g')
return l:msg
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

@ -130,7 +130,7 @@ endfunction
function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:language = ale#util#GetFunction(l:linter.language_callback)(l:buffer)
let l:language = ale#linter#GetLanguage(l:buffer, l:linter)
AssertEqual a:expected_language, l:language
endfunction

View file

@ -2,12 +2,27 @@
" Description: Functions for integrating with C-family linters.
call ale#Set('c_parse_makefile', 0)
call ale#Set('c_always_make', has('unix') && !has('macunix'))
call ale#Set('c_parse_compile_commands', 1)
let s:sep = has('win32') ? '\' : '/'
" Set just so tests can override it.
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
" Something somewhere seems to delete this setting in tests, so ensure we
" always have a default value.
call ale#Set('c_parse_makefile', 0)
return ale#Var(a:buffer, 'c_parse_makefile')
endfunction
function! ale#c#GetBuildDirectory(buffer) abort
let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
@ -61,14 +76,73 @@ function! ale#c#ShellSplit(line) abort
return l:args
endfunction
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
let l:cflags_list = []
" Takes the path prefix and a list of cflags and expands @file arguments to
" the contents of the file.
"
" @file arguments are command line arguments recognised by gcc and clang. For
" instance, if @./path/to/file was given to gcc, it would load .path/to/file
" and use the contents of that file as arguments.
function! ale#c#ExpandAtArgs(path_prefix, raw_split_lines) abort
let l:out_lines = []
let l:split_lines = ale#c#ShellSplit(a:cflag_line)
for l:option in a:raw_split_lines
if stridx(l:option, '@') == 0
" This is an argument specifying a location of a file containing other arguments
let l:path = join(split(l:option, '\zs')[1:], '')
" Make path absolute
if !ale#path#IsAbsolute(l:path)
let l:rel_path = substitute(l:path, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:path = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
endif
" Read the file and add all the arguments
try
let l:additional_args = readfile(l:path)
catch
continue " All we can really do is skip this argument
endtry
let l:file_lines = []
for l:line in l:additional_args
let l:file_lines += ale#c#ShellSplit(l:line)
endfor
" @file arguments can include other @file arguments, so we must
" recurse.
let l:out_lines += ale#c#ExpandAtArgs(a:path_prefix, l:file_lines)
else
" This is not an @file argument, so don't touch it.
let l:out_lines += [l:option]
endif
endfor
return l:out_lines
endfunction
" Quote C/C++ a compiler argument, if needed.
"
" 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
return ale#Escape(a:arg)
endfunction
function! ale#c#ParseCFlags(path_prefix, should_quote, raw_arguments) abort
" Expand @file arguments now before parsing
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
while l:option_index < len(l:split_lines)
let l:option = l:split_lines[l:option_index]
while l:option_index < len(l:arguments)
let l:option = l:arguments[l:option_index]
let l:option_index = l:option_index + 1
" Include options, that may need relative path fix
@ -76,56 +150,67 @@ function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
\ || stridx(l:option, '-iquote') == 0
\ || stridx(l:option, '-isystem') == 0
\ || stridx(l:option, '-idirafter') == 0
\ || stridx(l:option, '-iframework') == 0
\ || stridx(l:option, '-include') == 0
if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
let l:arg = join(split(l:option, '\zs')[2:], '')
let l:option = '-I'
else
let l:arg = l:split_lines[l:option_index]
let l:arg = l:arguments[l:option_index]
let l:option_index = l:option_index + 1
endif
" Fix relative paths if needed
if stridx(l:arg, s:sep) != 0 && stridx(l:arg, '/') != 0
if !ale#path#IsAbsolute(l:arg)
let l:rel_path = substitute(l:arg, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:arg = ale#Escape(a:path_prefix . s:sep . l:rel_path)
let l:arg = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
endif
call add(l:cflags_list, l:option)
call add(l:cflags_list, l:arg)
call add(l:items, [1, l:option])
call add(l:items, [1, ale#Escape(l:arg)])
" Options with arg that can be grouped with the option or separate
elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0
call add(l:cflags_list, l:option)
if l:option is# '-D' || l:option is# '-B'
call add(l:cflags_list, l:split_lines[l:option_index])
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
else
call add(l:items, [0, l:option])
endif
" Options that have an argument (always separate)
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
\ || l:option is# '-isysroot' || l:option is# '-imultilib'
call add(l:cflags_list, l:option)
call add(l:cflags_list, l:split_lines[l:option_index])
call add(l:items, [0, l:option])
call add(l:items, [0, l:arguments[l:option_index]])
let l:option_index = l:option_index + 1
" Options without argument
elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0)
\ || l:option is# '-w' || stridx(l:option, '-pedantic') == 0
\ || l:option is# '-ansi' || stridx(l:option, '-std=') == 0
\ || (stridx(l:option, '-f') == 0 && stridx(l:option, '-fdump') != 0 && stridx(l:option, '-fdiagnostics') != 0 && stridx(l:option, '-fno-show-column') != 0)
\ || stridx(l:option, '-f') == 0 && l:option !~# '\v^-f(dump|diagnostics|no-show-column|stack-usage)'
\ || stridx(l:option, '-O') == 0
\ || l:option is# '-C' || l:option is# '-CC' || l:option is# '-trigraphs'
\ || stridx(l:option, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0
\ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix'
\ || stridx(l:option, '-m') == 0
call add(l:cflags_list, l:option)
call add(l:items, [0, l:option])
endif
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
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !g:ale_c_parse_makefile
if !s:CanParseMakefile(a:buffer)
return v:null
endif
@ -143,7 +228,7 @@ function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
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
" Given a buffer number, find the project directory containing
@ -211,6 +296,10 @@ if !exists('s:compile_commands_cache')
let s:compile_commands_cache = {}
endif
function! ale#c#ResetCompileCommandsCache() abort
let s:compile_commands_cache = {}
endfunction
function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:empty = [{}, {}]
@ -241,9 +330,20 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:dir_lookup = {}
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: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:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry]
endfor
@ -258,27 +358,79 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
return l:empty
endfunction
function! ale#c#GetCompileCommand(json_item) abort
if has_key(a:json_item, 'command')
return a:json_item.command
elseif has_key(a:json_item, 'arguments')
return join(a:json_item.arguments, ' ')
" Get [should_quote, arguments] from either 'command' or 'arguments'
" 'arguments' should be quoted later, the split 'command' strings should not.
function! s:GetArguments(json_item) abort
if has_key(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
return ''
return [0, []]
endfunction
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.
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, [])
" 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.
let l:source_file = ''
if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$'
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:file_list = get(a:file_lookup, l:key, [])
endif
if !empty(l:file_list)
let l:source_file = l:key
@ -288,28 +440,31 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
endif
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
" header file.
if (
\ bufnr(l:item.file) is a:buffer
\ bufnr(l:filename) is a:buffer
\ || (
\ !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
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
if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
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
endfor
@ -335,9 +490,7 @@ function! ale#c#GetCFlags(buffer, output) abort
endif
endif
if ale#Var(a:buffer, 'c_parse_makefile')
\&& !empty(a:output)
\&& !empty(l:cflags)
if s:CanParseMakefile(a:buffer) && !empty(a:output) && !empty(l:cflags)
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
endif
@ -349,11 +502,14 @@ function! ale#c#GetCFlags(buffer, output) abort
endfunction
function! ale#c#GetMakeCommand(buffer) abort
if ale#Var(a:buffer, 'c_parse_makefile')
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
if s:CanParseMakefile(a:buffer)
let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile')
if !empty(l:makefile_path)
return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n'
if !empty(l:path)
let l:always_make = ale#Var(a:buffer, 'c_always_make')
return ale#path#CdString(fnamemodify(l:path, ':h'))
\ . 'make -n' . (l:always_make ? ' --always-make' : '')
endif
endif
@ -422,8 +578,3 @@ function! ale#c#IncludeOptions(include_paths) abort
return join(l:option_list)
endfunction
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])

View file

@ -24,6 +24,42 @@ function! ale#code_action#HandleCodeAction(code_action, should_save) abort
endfor
endfunction
function! s:ChangeCmp(left, right) abort
if a:left.start.line < a:right.start.line
return -1
endif
if a:left.start.line > a:right.start.line
return 1
endif
if a:left.start.offset < a:right.start.offset
return -1
endif
if a:left.start.offset > a:right.start.offset
return 1
endif
if a:left.end.line < a:right.end.line
return -1
endif
if a:left.end.line > a:right.end.line
return 1
endif
if a:left.end.offset < a:right.end.offset
return -1
endif
if a:left.end.offset > a:right.end.offset
return 1
endif
return 0
endfunction
function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
let l:current_buffer = bufnr('')
" The buffer is used to determine the fileformat, if available.
@ -48,7 +84,8 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
let l:column_offset = 0
let l:last_end_line = 0
for l:code_edit in a:changes
" Changes have to be sorted so we apply them from top-to-bottom.
for l:code_edit in sort(copy(a:changes), function('s:ChangeCmp'))
if l:code_edit.start.line isnot l:last_end_line
let l:column_offset = 0
endif

View file

@ -133,11 +133,36 @@ function! ale#command#EscapeCommandPart(command_part) abort
return substitute(a:command_part, '%', '%%', 'g')
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...
" %s -> with the current filename
" %t -> with the name of an unused file in a temporary directory
" %% -> 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:command = a:command
@ -154,14 +179,24 @@ function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_ne
" file.
if l:command =~# '%s'
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
if a:input isnot v:false && l:command =~# '%t'
" Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function.
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
" Finish formatting so %% becomes %.
@ -265,6 +300,7 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
\ a:command,
\ get(l:options, 'read_buffer', 0),
\ get(l:options, 'input', v:null),
\ get(l:options, 'filename_mappings', []),
\)
let l:command = ale#job#PrepareCommand(a:buffer, l:command)
let l:job_options = {

View file

@ -5,7 +5,7 @@ scriptencoding utf-8
" The omnicompletion menu is shown through a special Plug mapping which is
" only valid in Insert mode. This way, feedkeys() won't send these keys if you
" quit Insert mode quickly enough.
inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o>
inoremap <silent> <Plug>(ale_show_completion_menu) <C-x><C-o><C-p>
" If we hit the key sequence in normal mode, then we won't show the menu, so
" we should restore the old settings right away.
nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR>
@ -188,7 +188,13 @@ function! ale#completion#GetTriggerCharacter(filetype, prefix) abort
return ''
endfunction
function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
function! ale#completion#Filter(
\ buffer,
\ filetype,
\ suggestions,
\ prefix,
\ exact_prefix_match,
\) abort
let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words')
if empty(a:prefix)
@ -215,11 +221,18 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
" Dictionaries is accepted here.
let l:word = type(l:item) is v:t_string ? l:item : l:item.word
if a:exact_prefix_match
" Add suggestions if the word is an exact match.
if l:word is# a:prefix
call add(l:filtered_suggestions, l:item)
endif
else
" Add suggestions if the suggestion starts with a
" case-insensitive match for the prefix.
if l:word[: len(a:prefix) - 1] is? a:prefix
call add(l:filtered_suggestions, l:item)
endif
endif
endfor
endif
endif
@ -241,10 +254,7 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
return l:filtered_suggestions
endfunction
function! s:ReplaceCompletionOptions() abort
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
function! s:ReplaceCompletionOptions(source) abort
" Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
" This will stop some random exceptions from appearing.
@ -253,9 +263,8 @@ function! s:ReplaceCompletionOptions() abort
endif
let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
endif
if l:source is# 'ale-automatic'
if a:source is# 'ale-automatic'
if !exists('b:ale_old_completeopt')
let b:ale_old_completeopt = &l:completeopt
endif
@ -318,41 +327,70 @@ function! ale#completion#AutomaticOmniFunc(findstart, base) abort
else
let l:result = ale#completion#GetCompletionResult()
call s:ReplaceCompletionOptions()
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
call s:ReplaceCompletionOptions(l:source)
endif
return l:result isnot v:null ? l:result : []
endif
endfunction
function! s:OpenCompletionMenu(...) abort
if !&l:paste
call ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")
endif
endfunction
function! ale#completion#Show(result) abort
if ale#util#Mode() isnot# 'i'
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if ale#util#Mode() isnot# 'i' && l:source isnot# 'ale-import'
return
endif
" Set the list in the buffer, temporarily replace omnifunc with our
" function, and then start omni-completion.
" Set the list in the buffer.
let b:ale_completion_result = a:result
" Don't try to open the completion menu if there's nothing to show.
if empty(b:ale_completion_result)
if l:source is# 'ale-import'
" If we ran completion from :ALEImport,
" tell the user that nothing is going to happen.
call s:message('No possible imports found.')
endif
return
endif
" Replace completion options shortly before opening the menu.
call s:ReplaceCompletionOptions()
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '')
if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
call timer_start(
\ 0,
\ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")}
\)
call s:ReplaceCompletionOptions(l:source)
call timer_start(0, function('s:OpenCompletionMenu'))
endif
if l:source is# 'ale-callback'
call b:CompleteCallback(b:ale_completion_result)
endif
if l:source is# 'ale-import'
call ale#completion#HandleUserData(b:ale_completion_result[0])
let l:text_changed = '' . g:ale_lint_on_text_changed
" Check the buffer again right away, if linting is enabled.
if g:ale_enabled
\&& (
\ l:text_changed is# '1'
\ || l:text_changed is# 'always'
\ || l:text_changed is# 'normal'
\ || l:text_changed is# 'insert'
\)
call ale#Queue(0, '')
endif
endif
endfunction
function! ale#completion#GetAllTriggers() abort
@ -383,14 +421,18 @@ endfunction
function! s:CompletionStillValid(request_id) abort
let [l:line, l:column] = getpos('.')[1:2]
return ale#util#Mode() is# 'i'
\&& has_key(b:, 'ale_completion_info')
return has_key(b:, 'ale_completion_info')
\&& (
\ ale#util#Mode() is# 'i'
\ || b:ale_completion_info.source is# 'ale-import'
\)
\&& b:ale_completion_info.request_id == a:request_id
\&& b:ale_completion_info.line == l:line
\&& (
\ b:ale_completion_info.column == l:column
\ || b:ale_completion_info.source is# 'ale-omnifunc'
\ || b:ale_completion_info.source is# 'ale-callback'
\ || b:ale_completion_info.source is# 'ale-import'
\)
endfunction
@ -415,15 +457,26 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
let l:buffer = bufnr('')
let l:results = []
let l:names_with_details = []
let l:info = get(b:, 'ale_completion_info', {})
for l:suggestion in a:response.body
let l:displayParts = []
let l:local_name = v:null
for l:action in get(l:suggestion, 'codeActions', [])
call add(l:displayParts, l:action.description . ' ')
endfor
for l:part in l:suggestion.displayParts
" Stop on stop on line breaks for the menu.
if get(l:part, 'kind') is# 'lineBreak'
break
endif
if get(l:part, 'kind') is# 'localName'
let l:local_name = l:part.text
endif
call add(l:displayParts, l:part.text)
endfor
@ -436,11 +489,18 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
" See :help complete-items
let l:result = {
\ 'word': l:suggestion.name,
\ 'word': (
\ l:suggestion.name is# 'default'
\ && l:suggestion.kind is# 'alias'
\ && !empty(l:local_name)
\ ? l:local_name
\ : l:suggestion.name
\ ),
\ 'kind': ale#completion#GetCompletionSymbols(l:suggestion.kind),
\ 'icase': 1,
\ 'menu': join(l:displayParts, ''),
\ 'dup': g:ale_completion_autoimport,
\ 'dup': get(l:info, 'additional_edits_only', 0)
\ || g:ale_completion_autoimport,
\ 'info': join(l:documentationParts, ''),
\}
@ -450,7 +510,12 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
\ })
endif
" Include this item if we'll accept any items,
" or if we only want items with additional edits, and this has them.
if !get(l:info, 'additional_edits_only', 0)
\|| has_key(l:result, 'user_data')
call add(l:results, l:result)
endif
endfor
let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', [])
@ -524,7 +589,11 @@ function! ale#completion#ParseLSPCompletions(response) abort
" Don't use LSP items with additional text edits when autoimport for
" completions is turned off.
if has_key(l:item, 'additionalTextEdits') && !g:ale_completion_autoimport
if !empty(get(l:item, 'additionalTextEdits'))
\&& !(
\ get(l:info, 'additional_edits_only', 0)
\ || g:ale_completion_autoimport
\)
continue
endif
@ -546,38 +615,50 @@ function! ale#completion#ParseLSPCompletions(response) abort
let l:text_changes = []
for l:edit in l:item.additionalTextEdits
let l:range = l:edit.range
call add(l:text_changes, {
\ 'start': {
\ 'line': l:range.start.line + 1,
\ 'offset': l:range.start.character + 1,
\ 'line': l:edit.range.start.line + 1,
\ 'offset': l:edit.range.start.character + 1,
\ },
\ 'end': {
\ 'line': l:range.end.line + 1,
\ 'offset': l:range.end.character + 1,
\ 'line': l:edit.range.end.line + 1,
\ 'offset': l:edit.range.end.character + 1,
\ },
\ 'newText': l:edit.newText,
\})
endfor
let l:changes = [{
\ 'fileName': expand('#' . l:buffer . ':p'),
\ 'textChanges': l:text_changes,
\}]
\
if !empty(l:text_changes)
let l:result.user_data = json_encode({
\ 'codeActions': [{
\ 'description': 'completion',
\ 'changes': l:changes,
\ 'changes': [
\ {
\ 'fileName': expand('#' . l:buffer . ':p'),
\ 'textChanges': l:text_changes,
\ }
\ ],
\ }],
\ })
\})
endif
endif
" Include this item if we'll accept any items,
" or if we only want items with additional edits, and this has them.
if !get(l:info, 'additional_edits_only', 0)
\|| has_key(l:result, 'user_data')
call add(l:results, l:result)
endif
endfor
if has_key(l:info, 'prefix')
let l:results = ale#completion#Filter(l:buffer, &filetype, l:results, l:info.prefix)
let l:results = ale#completion#Filter(
\ l:buffer,
\ &filetype,
\ l:results,
\ l:info.prefix,
\ get(l:info, 'additional_edits_only', 0),
\)
endif
return l:results[: g:ale_completion_max_suggestions - 1]
@ -601,13 +682,18 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
\ &filetype,
\ ale#completion#ParseTSServerCompletions(a:response),
\ b:ale_completion_info.prefix,
\ get(b:ale_completion_info, 'additional_edits_only', 0),
\)[: g:ale_completion_max_suggestions - 1]
" We need to remember some names for tsserver, as it doesn't send
" details back for everything we send.
call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names)
if !empty(l:names)
if empty(l:names)
" Response with no results now and skip making a redundant request
" for nothing.
call ale#completion#Show([])
else
let l:identifiers = []
for l:name in l:names
@ -681,7 +767,8 @@ function! s:OnReady(linter, lsp_details) abort
\ b:ale_completion_info.line,
\ b:ale_completion_info.column,
\ b:ale_completion_info.prefix,
\ g:ale_completion_autoimport,
\ get(b:ale_completion_info, 'additional_edits_only', 0)
\ || g:ale_completion_autoimport,
\)
else
" Send a message saying the buffer has changed first, otherwise
@ -740,9 +827,19 @@ function! ale#completion#GetCompletions(...) abort
let b:CompleteCallback = l:CompleteCallback
endif
if has_key(l:options, 'line') && has_key(l:options, 'column')
" Use a provided line and column, if given.
let l:line = l:options.line
let l:column = l:options.column
else
let [l:line, l:column] = getpos('.')[1:2]
endif
if has_key(l:options, 'prefix')
let l:prefix = l:options.prefix
else
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column)
endif
if l:source is# 'ale-automatic' && empty(l:prefix)
return 0
@ -761,6 +858,11 @@ function! ale#completion#GetCompletions(...) abort
\}
unlet! b:ale_completion_result
if has_key(l:options, 'additional_edits_only')
let b:ale_completion_info.additional_edits_only =
\ l:options.additional_edits_only
endif
let l:buffer = bufnr('')
let l:Callback = function('s:OnReady')
@ -777,6 +879,37 @@ function! ale#completion#GetCompletions(...) abort
return l:started
endfunction
function! s:message(message) abort
call ale#util#Execute('echom ' . string(a:message))
endfunction
" This function implements the :ALEImport command.
function! ale#completion#Import() abort
let l:word = expand('<cword>')
if empty(l:word)
call s:message('Nothing to complete at cursor!')
return
endif
let [l:line, l:column] = getpos('.')[1:2]
let l:column = searchpos('\V' . escape(l:word, '/\'), 'bn', l:line)[1]
if l:column isnot 0
let l:started = ale#completion#GetCompletions('ale-import', {
\ 'line': l:line,
\ 'column': l:column,
\ 'prefix': l:word,
\ 'additional_edits_only': 1,
\})
if !l:started
call s:message('No completion providers are available.')
endif
endif
endfunction
function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart
let l:started = ale#completion#GetCompletions('ale-omnifunc')
@ -855,6 +988,7 @@ function! ale#completion#HandleUserData(completed_item) abort
if l:source isnot# 'ale-automatic'
\&& l:source isnot# 'ale-manual'
\&& l:source isnot# 'ale-callback'
\&& l:source isnot# 'ale-import'
return
endif
@ -884,6 +1018,8 @@ function! ale#completion#Done() abort
endfunction
augroup ALECompletionActions
autocmd!
autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item)
augroup END

View file

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

View file

@ -135,10 +135,6 @@ function! s:GoToLSPDefinition(linter, options, capability) abort
endfunction
function! ale#definition#GoTo(options) abort
if !get(g:, 'ale_ignore_2_7_warnings') && has_key(a:options, 'deprecated_command')
execute 'echom '':' . a:options.deprecated_command . ' is deprecated. Use `let g:ale_ignore_2_7_warnings = 1` to disable this message.'''
endif
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
call s:GoToLSPDefinition(l:linter, a:options, 'definition')
@ -147,10 +143,6 @@ function! ale#definition#GoTo(options) abort
endfunction
function! ale#definition#GoToType(options) abort
if !get(g:, 'ale_ignore_2_7_warnings') && has_key(a:options, 'deprecated_command')
execute 'echom '':' . a:options.deprecated_command . ' is deprecated. Use `let g:ale_ignore_2_7_warnings = 1` to disable this message.'''
endif
for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp)
" TODO: handle typeDefinition for tsserver if supported by the

View file

@ -4,6 +4,7 @@
" Remapping of linter problems.
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')
let s:executable_cache_map = {}
@ -104,42 +105,6 @@ function! ale#engine#IsCheckingBuffer(buffer) abort
\ || !empty(get(l:info, 'active_other_sources_list', []))
endfunction
" Register a temporary file to be managed with the ALE engine for
" a current job run.
function! ale#engine#ManageFile(buffer, filename) abort
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#ManageFile is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
call ale#command#ManageFile(a:buffer, a:filename)
endfunction
" Same as the above, but manage an entire directory.
function! ale#engine#ManageDirectory(buffer, directory) abort
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#ManageDirectory is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
call ale#command#ManageDirectory(a:buffer, a:directory)
endfunction
function! ale#engine#CreateFile(buffer) abort
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#CreateFile is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
return ale#command#CreateFile(a:buffer)
endfunction
" Create a new temporary directory and manage it in one go.
function! ale#engine#CreateDirectory(buffer) abort
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''ale#engine#CreateDirectory is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
return ale#command#CreateDirectory(a:buffer)
endfunction
function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
@ -192,7 +157,6 @@ function! s:HandleExit(job_info, buffer, output, data) abort
let l:linter = a:job_info.linter
let l:executable = a:job_info.executable
let l:next_chain_index = a:job_info.next_chain_index
" Remove this job from the list.
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name)
@ -207,20 +171,6 @@ function! s:HandleExit(job_info, buffer, output, data) abort
call remove(a:output, -1)
endif
if l:next_chain_index < len(get(l:linter, 'command_chain', []))
let [l:command, l:options] = ale#engine#ProcessChain(
\ a:buffer,
\ l:executable,
\ l:linter,
\ l:next_chain_index,
\ a:output,
\)
call s:RunJob(l:command, l:options)
return
endif
try
let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output)
" Handle the function being unknown, or being deleted.
@ -307,6 +257,13 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfunction
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:new_loclist = []
@ -347,13 +304,19 @@ function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist)
let l:item.code = l:old_item.code
endif
if has_key(l:old_item, 'filename')
\&& !ale#path#IsTempName(l:old_item.filename)
let l:old_name = get(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.
" Temporary files are assumed to be for this buffer,
" and the filename is not included then, because it looks bad
" in the loclist window.
let l:filename = l:old_item.filename
let l:filename = l:old_name
let l:item.filename = l:filename
if has_key(l:old_item, 'bufnr')
@ -454,20 +417,19 @@ function! s:RunJob(command, options) abort
let l:buffer = a:options.buffer
let l:linter = a:options.linter
let l:output_stream = a:options.output_stream
let l:next_chain_index = a:options.next_chain_index
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:Callback = function('s:HandleExit', [{
\ 'linter': l:linter,
\ 'executable': l:executable,
\ 'next_chain_index': l:next_chain_index,
\}])
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
\ 'output_stream': l:output_stream,
\ 'executable': l:executable,
\ 'read_buffer': l:read_buffer,
\ 'log_output': l:next_chain_index >= len(get(l:linter, 'command_chain', [])),
\ 'log_output': 1,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:linter.name),
\})
" Only proceed if the job is being run.
@ -482,68 +444,6 @@ function! s:RunJob(command, options) abort
return 1
endfunction
" Determine which commands to run for a link in a command chain, or
" just a regular command.
function! ale#engine#ProcessChain(buffer, executable, linter, chain_index, input) abort
let l:output_stream = get(a:linter, 'output_stream', 'stdout')
let l:read_buffer = a:linter.read_buffer
let l:chain_index = a:chain_index
let l:input = a:input
while l:chain_index < len(a:linter.command_chain)
" Run a chain of commands, one asynchronous command after the other,
" so that many programs can be run in a sequence.
let l:chain_item = a:linter.command_chain[l:chain_index]
if l:chain_index == 0
" The first callback in the chain takes only a buffer number.
let l:command = ale#util#GetFunction(l:chain_item.callback)(
\ a:buffer
\)
else
" The second callback in the chain takes some input too.
let l:command = ale#util#GetFunction(l:chain_item.callback)(
\ a:buffer,
\ l:input
\)
endif
" If we have a command to run, execute that.
if !empty(l:command)
" The chain item can override the output_stream option.
if has_key(l:chain_item, 'output_stream')
let l:output_stream = l:chain_item.output_stream
endif
" The chain item can override the read_buffer option.
if has_key(l:chain_item, 'read_buffer')
let l:read_buffer = l:chain_item.read_buffer
elseif l:chain_index != len(a:linter.command_chain) - 1
" Don't read the buffer for commands besides the last one
" in the chain by default.
let l:read_buffer = 0
endif
break
endif
" Command chain items can return an empty string to indicate that
" a command should be skipped, so we should try the next item
" with no input.
let l:input = []
let l:chain_index += 1
endwhile
return [l:command, {
\ 'executable': a:executable,
\ 'buffer': a:buffer,
\ 'linter': a:linter,
\ 'output_stream': l:output_stream,
\ 'next_chain_index': l:chain_index + 1,
\ 'read_buffer': l:read_buffer,
\}]
endfunction
function! s:StopCurrentJobs(buffer, clear_lint_file_jobs) abort
let l:info = get(g:ale_buffer_info, a:buffer, {})
call ale#command#StopJobs(a:buffer, 'linter')
@ -608,10 +508,15 @@ function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
endif
endfunction
function! s:RunIfExecutable(buffer, linter, executable) abort
function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
if ale#command#IsDeferred(a:executable)
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
@ -619,29 +524,17 @@ function! s:RunIfExecutable(buffer, linter, executable) abort
if ale#engine#IsExecutable(a:buffer, a:executable)
" 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)
if has_key(a:linter, 'command_chain')
let [l:command, l:options] = ale#engine#ProcessChain(
\ a:buffer,
\ a:executable,
\ a:linter,
\ 0,
\ []
\)
return s:RunJob(l:command, l:options)
endif
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
let l:options = {
\ 'executable': a:executable,
\ 'buffer': a:buffer,
\ 'linter': a:linter,
\ 'output_stream': get(a:linter, 'output_stream', 'stdout'),
\ 'next_chain_index': 1,
\ 'read_buffer': a:linter.read_buffer,
\ 'lint_file': a:lint_file,
\}
return s:RunJob(l:command, l:options)
@ -653,33 +546,62 @@ endfunction
" Run a linter for a buffer.
"
" 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)
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
else
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
return 0
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)
function! s:GetLintFileValues(slots, Callback) abort
let l:deferred_list = []
let l:new_slots = []
" We can only clear the results if we aren't checking the buffer.
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)
for [l:lint_file, l:linter] in a:slots
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.
if !l:linter.lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter)
if !l:lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter, l:lint_file)
" If a single linter ran, we shouldn't clear everything.
let l:can_clear_results = 0
endif
@ -694,11 +616,49 @@ function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" disabled, or ALE itself is disabled.
if l:can_clear_results
call ale#engine#SetResults(a:buffer, [])
elseif l:new_buffer
call s:AddProblemsFromOtherBuffers(a:buffer, a:linters)
elseif a:new_buffer
call s:AddProblemsFromOtherBuffers(
\ a:buffer,
\ map(copy(a:slots), 'v:val[1]')
\)
endif
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.
"
" 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 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'
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'
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay)
autocmd TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
endif
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.
" Vim doesn't let you modify hidden buffers.
@ -11,6 +15,7 @@ function! ale#fix#ApplyQueuedFixes(buffer) abort
call remove(g:ale_fix_buffer_data, a:buffer)
try
if l:data.changes_made
let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output)
@ -27,6 +32,12 @@ function! ale#fix#ApplyQueuedFixes(buffer) abort
endif
endif
endif
catch /E21/
" If we cannot modify the buffer now, try again later.
let g:ale_fix_buffer_data[a:buffer] = l:data
return
endtry
if l:data.should_save
let l:should_lint = ale#Var(a:buffer, 'fix_on_save')
@ -90,7 +101,6 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
let l:output = a:job_output
endif
let l:ChainCallback = get(a:job_info, 'chain_with', v:null)
let l:ProcessWith = get(a:job_info, 'process_with', v:null)
" Post-process the output with a function if we have one.
@ -102,27 +112,17 @@ function! s:HandleExit(job_info, buffer, job_output, data) abort
" otherwise skip this job and use the input from before.
"
" We'll use the input from before for chained commands.
if l:ChainCallback is v:null && !empty(split(join(l:output)))
if !empty(split(join(l:output)))
let l:input = l:output
else
let l:input = a:job_info.input
endif
if l:ChainCallback isnot v:null && !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom ''chain_with is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
let l:next_index = l:ChainCallback is v:null
\ ? a:job_info.callback_index + 1
\ : a:job_info.callback_index
call s:RunFixer({
\ 'buffer': a:buffer,
\ 'input': l:input,
\ 'output': l:output,
\ 'callback_list': a:job_info.callback_list,
\ 'callback_index': l:next_index,
\ 'chain_callback': l:ChainCallback,
\ 'callback_index': a:job_info.callback_index + 1,
\})
endfunction
@ -135,6 +135,7 @@ function! s:RunJob(result, options) abort
let l:buffer = a:options.buffer
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 type(a:result) is v:t_list
@ -152,26 +153,21 @@ function! s:RunJob(result, options) abort
endif
let l:command = get(a:result, 'command', '')
let l:ChainWith = get(a:result, 'chain_with', v:null)
if empty(l:command)
" If the command is empty, skip to the next item, or call the
" chain_with function.
" If the command is empty, skip to the next item.
call s:RunFixer({
\ 'buffer': l:buffer,
\ 'input': l:input,
\ 'callback_index': a:options.callback_index + (l:ChainWith is v:null),
\ 'callback_index': a:options.callback_index,
\ 'callback_list': a:options.callback_list,
\ 'chain_callback': l:ChainWith,
\ 'output': [],
\})
return
endif
let l:read_temporary_file = get(a:result, 'read_temporary_file', 0)
" Default to piping the buffer for the last fixer in the chain.
let l:read_buffer = get(a:result, 'read_buffer', l:ChainWith is v:null)
let l:read_buffer = get(a:result, 'read_buffer', 1)
let l:output_stream = get(a:result, 'output_stream', 'stdout')
if l:read_temporary_file
@ -180,7 +176,6 @@ function! s:RunJob(result, options) abort
let l:Callback = function('s:HandleExit', [{
\ 'input': l:input,
\ 'chain_with': l:ChainWith,
\ 'callback_index': a:options.callback_index,
\ 'callback_list': a:options.callback_list,
\ 'process_with': get(a:result, 'process_with', v:null),
@ -192,6 +187,7 @@ function! s:RunJob(result, options) abort
\ 'read_buffer': l:read_buffer,
\ 'input': l:input,
\ 'log_output': 0,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name),
\})
if empty(l:run_result)
@ -215,32 +211,22 @@ function! s:RunFixer(options) abort
return
endif
let l:ChainCallback = get(a:options, 'chain_callback', v:null)
let l:Function = l:ChainCallback isnot v:null
\ ? ale#util#GetFunction(l:ChainCallback)
\ : a:options.callback_list[l:index]
let [l:fixer_name, l:Function] = a:options.callback_list[l:index]
" Record new jobs started as fixer jobs.
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])
let l:result = ale#util#FunctionArgCount(l:Function) == 1
\ ? call(l:Function, [l:buffer])
\ : call(l:Function, [l:buffer, copy(l:input)])
endif
call s:RunJob(l:result, {
\ 'buffer': l:buffer,
\ 'input': l:input,
\ 'callback_list': a:options.callback_list,
\ 'callback_index': l:index,
\ 'fixer_name': l:fixer_name,
\})
endfunction
@ -308,16 +294,24 @@ function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
" Variables with capital characters are needed, or Vim will complain about
" funcref variables.
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
let l:Func = ale#fix#registry#GetFunc(l:Item)
if !empty(l:Func)
let l:fixer_name = l:Item
let l:Item = l:Func
endif
endif
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/
" Rethrow exceptions for failing to get a function so we can print
" a friendly message about it.
@ -389,3 +383,4 @@ endfunction
augroup ALEBufferFixGroup
autocmd!
autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
augroup END

View file

@ -380,11 +380,21 @@ let s:default_registry = {
\ 'suggested_filetypes': ['nix'],
\ 'description': 'A formatter for Nix code',
\ },
\ 'remark-lint': {
\ 'function': 'ale#fixers#remark_lint#Fix',
\ 'suggested_filetypes': ['markdown'],
\ 'description': 'Fix markdown files with remark-lint',
\ },
\ 'html-beautify': {
\ 'function': 'ale#fixers#html_beautify#Fix',
\ 'suggested_filetypes': ['html', 'htmldjango'],
\ '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.

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 {
\ 'command': ale#Escape(l:executable)
\ . ' -l -w'
\ . ' -l'
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View file

@ -5,14 +5,13 @@ call ale#Set('ocaml_ocamlformat_executable', 'ocamlformat')
call ale#Set('ocaml_ocamlformat_options', '')
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:options = ale#Var(a:buffer, 'ocaml_ocamlformat_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' --name=' . ale#Escape(l:filename)
\ . ' --name=%s'
\ . ' -'
\}
endfunction

View file

@ -34,6 +34,21 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
return a:output
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
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
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
if ale#semver#GTE(a:version, [1, 4, 0])
return {
\ 'command': ale#path#BufferCdString(a:buffer)
\ 'command': ale#fixers#prettier#CdProjectRoot(a:buffer)
\ . ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin-filepath %s --stdin',

View file

@ -17,8 +17,8 @@ function! ale#fixers#prettier_standard#Fix(buffer) abort
return {
\ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer))
\ . ' %t'
\ . ' --stdin'
\ . ' --stdin-filepath=%s'
\ . ' ' . l:options,
\ 'read_temporary_file': 1,
\}
endfunction

View file

@ -0,0 +1,24 @@
" Author: blyoa <blyoa110@gmail.com>
" Description: Fixing files with remark-lint.
call ale#Set('markdown_remark_lint_executable', 'remark')
call ale#Set('markdown_remark_lint_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('markdown_remark_lint_options', '')
function! ale#fixers#remark_lint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'markdown_remark_lint', [
\ 'node_modules/remark-cli/cli.js',
\ 'node_modules/.bin/remark',
\])
endfunction
function! ale#fixers#remark_lint#Fix(buffer) abort
let l:executable = ale#fixers#remark_lint#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'markdown_remark_lint_options')
return {
\ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : ''),
\}
endfunction

View file

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

View file

@ -27,7 +27,7 @@ function! ale#fixers#standard#Fix(buffer) abort
return {
\ 'command': ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --fix %t',
\ . ' --fix --stdin < %s > %t',
\ 'read_temporary_file': 1,
\}
endfunction

View file

@ -10,7 +10,7 @@ let s:pragma_error = '#pragma once in main file'
" <stdin>:8:5: warning: conversion lacks type at end of format [-Wformat=]
" <stdin>:10:27: error: invalid operands to binary - (have int and char *)
" -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004]
let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$'
let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+)?:?(\d+)?:? ([^:]+): (.+)$'
let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$'
function! s:IsHeaderFile(filename) abort
@ -117,6 +117,23 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort
if !empty(l:output)
if !has_key(l:output[-1], 'detail')
let l:output[-1].detail = l:output[-1].text
" handle macro expansion errors/notes
if l:match[5] =~? '^in expansion of macro \w*\w$'
" if the macro expansion is in the file we're in, add
" the lnum and col keys to the previous error
if l:match[1] is# '<stdin>'
\ && !has_key(l:output[-1], 'col')
let l:output[-1].lnum = str2nr(l:match[2])
let l:output[-1].col = str2nr(l:match[3])
else
" the error is not in the current file, and since
" macro expansion errors don't show the full path to
" the error from the current file, we have to just
" give out a generic error message
let l:output[-1].text = 'Error found in macro expansion. See :ALEDetail'
endif
endif
endif
let l:output[-1].detail = l:output[-1].detail . "\n"

View file

@ -4,17 +4,24 @@
function! ale#handlers#sh#GetShellType(buffer) abort
let l:bang_line = get(getbufline(a:buffer, 1), 0, '')
let l:command = ''
" Take the shell executable from the hashbang, if we can.
if l:bang_line[:1] is# '#!'
" Remove options like -e, etc.
let l:command = substitute(l:bang_line, ' --\?[a-zA-Z0-9]\+', '', 'g')
endif
" If we couldn't find a hashbang, try the filetype
if l:command is# ''
let l:command = &filetype
endif
for l:possible_shell in ['bash', 'dash', 'ash', 'tcsh', 'csh', 'zsh', 'ksh', 'sh']
if l:command =~# l:possible_shell . '\s*$'
return l:possible_shell
endif
endfor
endif
return ''
endfunction

View file

@ -264,7 +264,10 @@ function! s:OnReady(line, column, opt, linter, lsp_details) abort
" hover position probably won't make sense.
call ale#lsp#NotifyForChanges(l:id, l:buffer)
let l:column = min([a:column, len(getbufline(l:buffer, a:line)[0])])
let l:column = max([
\ min([a:column, len(getbufline(l:buffer, a:line)[0])]),
\ 1,
\])
let l:message = ale#lsp#message#Hover(l:buffer, a:line, l:column)
endif

View file

@ -32,7 +32,7 @@ let s:default_ale_linter_aliases = {
"
" 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.
" hhast is disabled by default because it executes code in the project root.
"
@ -46,7 +46,7 @@ let s:default_ale_linters = {
\ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'rust': ['cargo'],
\ 'rust': ['cargo', 'rls'],
\ 'spec': [],
\ 'text': [],
\ 'vue': ['eslint', 'vls'],
@ -77,10 +77,6 @@ function! s:IsBoolean(value) abort
return type(a:value) is v:t_number && (a:value == 0 || a:value == 1)
endfunction
function! s:LanguageGetter(buffer) dict abort
return l:self.language
endfunction
function! ale#linter#PreProcess(filetype, linter) abort
if type(a:linter) isnot v:t_dict
throw 'The linter object must be a Dictionary'
@ -114,14 +110,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
if !l:needs_executable
if has_key(a:linter, 'executable')
\|| has_key(a:linter, 'executable_callback')
throw '`executable` and `executable_callback` cannot be used when lsp == ''socket'''
endif
elseif has_key(a:linter, 'executable_callback')
let l:obj.executable_callback = a:linter.executable_callback
if !s:IsCallback(l:obj.executable_callback)
throw '`executable_callback` must be a callback if defined'
throw '`executable` cannot be used when lsp == ''socket'''
endif
elseif has_key(a:linter, 'executable')
let l:obj.executable = a:linter.executable
@ -131,54 +120,12 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`executable` must be a String or Function if defined'
endif
else
throw 'Either `executable` or `executable_callback` must be defined'
throw '`executable` must be defined'
endif
if !l:needs_command
if has_key(a:linter, 'command')
\|| has_key(a:linter, 'command_callback')
\|| has_key(a:linter, 'command_chain')
throw '`command` and `command_callback` and `command_chain` cannot be used when lsp == ''socket'''
endif
elseif has_key(a:linter, 'command_chain')
let l:obj.command_chain = a:linter.command_chain
if type(l:obj.command_chain) isnot v:t_list
throw '`command_chain` must be a List'
endif
if empty(l:obj.command_chain)
throw '`command_chain` must contain at least one item'
endif
let l:link_index = 0
for l:link in l:obj.command_chain
let l:err_prefix = 'The `command_chain` item ' . l:link_index . ' '
if !s:IsCallback(get(l:link, 'callback'))
throw l:err_prefix . 'must define a `callback` function'
endif
if has_key(l:link, 'output_stream')
if type(l:link.output_stream) isnot v:t_string
\|| index(['stdout', 'stderr', 'both'], l:link.output_stream) < 0
throw l:err_prefix . '`output_stream` flag must be '
\ . "'stdout', 'stderr', or 'both'"
endif
endif
if has_key(l:link, 'read_buffer') && !s:IsBoolean(l:link.read_buffer)
throw l:err_prefix . 'value for `read_buffer` must be `0` or `1`'
endif
let l:link_index += 1
endfor
elseif has_key(a:linter, 'command_callback')
let l:obj.command_callback = a:linter.command_callback
if !s:IsCallback(l:obj.command_callback)
throw '`command_callback` must be a callback if defined'
throw '`command` cannot be used when lsp == ''socket'''
endif
elseif has_key(a:linter, 'command')
let l:obj.command = a:linter.command
@ -188,22 +135,12 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`command` must be a String or Function if defined'
endif
else
throw 'Either `command`, `executable_callback`, `command_chain` '
\ . 'must be defined'
endif
if (
\ has_key(a:linter, 'command')
\ + has_key(a:linter, 'command_chain')
\ + has_key(a:linter, 'command_callback')
\) > 1
throw 'Only one of `command`, `command_callback`, or `command_chain` '
\ . 'should be set'
throw '`command` must be defined'
endif
if !l:needs_address
if has_key(a:linter, 'address') || has_key(a:linter, 'address_callback')
throw '`address` or `address_callback` cannot be used when lsp != ''socket'''
if has_key(a:linter, 'address')
throw '`address` cannot be used when lsp != ''socket'''
endif
elseif has_key(a:linter, 'address')
if type(a:linter.address) isnot v:t_string
@ -212,41 +149,17 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
let l:obj.address = a:linter.address
elseif has_key(a:linter, 'address_callback')
let l:obj.address_callback = a:linter.address_callback
if !s:IsCallback(l:obj.address_callback)
throw '`address_callback` must be a callback if defined'
endif
else
throw '`address` or `address_callback` must be defined for getting the LSP address'
throw '`address` must be defined for getting the LSP address'
endif
if l:needs_lsp_details
if has_key(a:linter, 'language_callback')
if has_key(a:linter, 'language')
throw 'Only one of `language` or `language_callback` '
\ . 'should be set'
endif
let l:obj.language_callback = get(a:linter, 'language_callback')
if !s:IsCallback(l:obj.language_callback)
throw '`language_callback` must be a callback for LSP linters'
endif
else
" Default to using the filetype as the language.
let l:Language = get(a:linter, 'language', a:filetype)
let l:obj.language = get(a:linter, 'language', a:filetype)
if type(l:Language) is v:t_string
" Make 'language_callback' return the 'language' value.
let l:obj.language = l:Language
let l:obj.language_callback = function('s:LanguageGetter')
elseif type(l:Language) is v:t_func
let l:obj.language_callback = l:Language
else
throw '`language` must be a String or Funcref'
endif
if type(l:obj.language) isnot v:t_string
\&& type(l:obj.language) isnot v:t_func
throw '`language` must be a String or Funcref if defined'
endif
if has_key(a:linter, 'project_root')
@ -254,16 +167,10 @@ function! ale#linter#PreProcess(filetype, linter) abort
if type(l:obj.project_root) isnot v:t_string
\&& type(l:obj.project_root) isnot v:t_func
throw '`project_root` must be a String or Function if defined'
endif
elseif has_key(a:linter, 'project_root_callback')
let l:obj.project_root_callback = a:linter.project_root_callback
if !s:IsCallback(l:obj.project_root_callback)
throw '`project_root_callback` must be a callback if defined'
throw '`project_root` must be a String or Function'
endif
else
throw '`project_root` or `project_root_callback` must be defined for LSP linters'
throw '`project_root` must be defined for LSP linters'
endif
if has_key(a:linter, 'completion_filter')
@ -274,37 +181,16 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif
endif
if has_key(a:linter, 'initialization_options_callback')
if has_key(a:linter, 'initialization_options')
throw 'Only one of `initialization_options` or '
\ . '`initialization_options_callback` should be set'
endif
let l:obj.initialization_options_callback = a:linter.initialization_options_callback
if !s:IsCallback(l:obj.initialization_options_callback)
throw '`initialization_options_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'initialization_options')
let l:obj.initialization_options = a:linter.initialization_options
if type(l:obj.initialization_options) isnot v:t_dict
\&& type(l:obj.initialization_options) isnot v:t_func
throw '`initialization_options` must be a String or Function if defined'
throw '`initialization_options` must be a Dictionary or Function if defined'
endif
endif
if has_key(a:linter, 'lsp_config_callback')
if has_key(a:linter, 'lsp_config')
throw 'Only one of `lsp_config` or `lsp_config_callback` should be set'
endif
let l:obj.lsp_config_callback = a:linter.lsp_config_callback
if !s:IsCallback(l:obj.lsp_config_callback)
throw '`lsp_config_callback` must be a callback if defined'
endif
elseif has_key(a:linter, 'lsp_config')
if type(a:linter.lsp_config) isnot v:t_dict
\&& type(a:linter.lsp_config) isnot v:t_func
throw '`lsp_config` must be a Dictionary or Function if defined'
@ -325,21 +211,17 @@ function! ale#linter#PreProcess(filetype, linter) abort
" file on disk.
let l:obj.lint_file = get(a:linter, 'lint_file', 0)
if !s:IsBoolean(l:obj.lint_file)
throw '`lint_file` must be `0` or `1`'
if !s:IsBoolean(l:obj.lint_file) && type(l:obj.lint_file) isnot v:t_func
throw '`lint_file` must be `0`, `1`, or a Function'
endif
" 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)
throw '`read_buffer` must be `0` or `1`'
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', [])
if type(l:obj.aliases) isnot v:t_list
@ -347,14 +229,6 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`aliases` must be a List of String values'
endif
for l:key in filter(keys(a:linter), 'v:val[-9:] is# ''_callback'' || v:val is# ''command_chain''')
if !get(g:, 'ale_ignore_2_4_warnings')
execute 'echom l:key . '' is deprecated. Use `let g:ale_ignore_2_4_warnings = 1` to disable this message.'''
endif
break
endfor
return l:obj
endfunction
@ -522,9 +396,7 @@ endfunction
" Given a buffer and linter, get the executable String for the linter.
function! ale#linter#GetExecutable(buffer, linter) abort
let l:Executable = has_key(a:linter, 'executable_callback')
\ ? function(a:linter.executable_callback)
\ : a:linter.executable
let l:Executable = a:linter.executable
return type(l:Executable) is v:t_func
\ ? l:Executable(a:buffer)
@ -532,24 +404,21 @@ function! ale#linter#GetExecutable(buffer, linter) abort
endfunction
" Given a buffer and linter, get the command String for the linter.
" The command_chain key is not supported.
function! ale#linter#GetCommand(buffer, linter) abort
let l:Command = has_key(a:linter, 'command_callback')
\ ? function(a:linter.command_callback)
\ : a:linter.command
let l:Command = a:linter.command
return type(l:Command) is v:t_func
\ ? l:Command(a:buffer)
\ : l:Command
return type(l:Command) is v:t_func ? l:Command(a:buffer) : l:Command
endfunction
" Given a buffer and linter, get the address for connecting to the server.
function! ale#linter#GetAddress(buffer, linter) abort
let l:Address = has_key(a:linter, 'address_callback')
\ ? function(a:linter.address_callback)
\ : a:linter.address
let l:Address = a:linter.address
return type(l:Address) is v:t_func
\ ? l:Address(a:buffer)
\ : l:Address
return type(l:Address) is v:t_func ? l:Address(a:buffer) : l:Address
endfunction
function! ale#linter#GetLanguage(buffer, linter) abort
let l:Language = a:linter.language
return type(l:Language) is v:t_func ? l:Language(a:buffer) : l:Language
endfunction

View file

@ -64,6 +64,9 @@ endfunction
" Used only in tests.
function! ale#lsp#GetConnections() abort
" This command will throw from the sandbox.
let &l:equalprg=&l:equalprg
return s:connections
endfunction
@ -449,6 +452,7 @@ function! ale#lsp#StartProgram(conn_id, executable, command) abort
endif
if l:started && !l:conn.is_tsserver
let l:conn.initialized = 0
call s:SendInitMessage(l:conn)
endif

View file

@ -34,7 +34,11 @@ endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri)
let l:buffer = bufnr('^' . l:filename . '$')
let l:escaped_name = escape(
\ fnameescape(l:filename),
\ has('win32') ? '^' : '^,}]'
\)
let l:buffer = bufnr('^' . l:escaped_name . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info)
@ -52,7 +56,11 @@ endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:linter_name = 'tsserver'
let l:buffer = bufnr('^' . a:response.body.file . '$')
let l:escaped_name = escape(
\ fnameescape(a:response.body.file),
\ has('win32') ? '^' : '^,}]'
\)
let l:buffer = bufnr('^' . l:escaped_name . '$')
let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info)
@ -227,7 +235,7 @@ function! ale#lsp_linter#OnInit(linter, details, Callback) abort
let l:command = a:details.command
let l:config = ale#lsp_linter#GetConfig(l:buffer, a:linter)
let l:language_id = ale#util#GetFunction(a:linter.language_callback)(l:buffer)
let l:language_id = ale#linter#GetLanguage(l:buffer, a:linter)
call ale#lsp#UpdateConfig(l:conn_id, l:buffer, l:config)
@ -265,7 +273,14 @@ function! s:StartLSP(options, address, executable, command) abort
call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
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:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
endif

View file

@ -24,6 +24,14 @@ function! ale#path#Simplify(path) abort
return substitute(simplify(l:win_path), '^\\\+', '\', 'g') " no-custom-checks
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
" through the paths relative to the given buffer.
function! ale#path#FindNearestFile(buffer, filename) abort
@ -74,15 +82,19 @@ endfunction
function! ale#path#CdString(directory) abort
if has('win32')
return 'cd /d ' . ale#Escape(a:directory) . ' && '
else
return 'cd ' . ale#Escape(a:directory) . ' && '
endif
return 'cd ' . ale#Escape(a:directory) . ' && '
endfunction
" Output 'cd <buffer_filename_directory> && '
" This function can be used changing the directory for a linter command.
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
" 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# ':\'
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
" created by Vim.

View file

@ -1,14 +1,22 @@
" Author: w0rp <devw0rp@gmail.com>
" Description: Preview windows for showing whatever information in.
if !has_key(s:, 'last_selection_list')
let s:last_selection_list = []
if !has_key(s:, 'last__list')
let s:last_list = []
endif
if !has_key(s:, 'last_selection_open_in')
let s:last_selection_open_in = 'current-buffer'
if !has_key(s:, 'last_options')
let s:last_options = {}
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.
" 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_open_in = get(l:options, 'open_in', 'current-buffer')
" Remove the last preview
let s:last_selection_list = b:ale_preview_item_list
let s:last_selection_open_in = b:ale_preview_item_open_in
" Remember preview state, so we can repeat it later.
call ale#preview#SetLastSelection(a:item_list, l:options)
endfunction
function! ale#preview#RepeatSelection() abort
if empty(s:last_selection_list)
return
if !empty(s:last_list)
call ale#preview#ShowSelection(s:last_list, s:last_options)
endif
call ale#preview#ShowSelection(s:last_selection_list, {
\ 'open_in': s:last_selection_open_in,
\})
endfunction
function! s:Open(open_in) abort

View file

@ -145,8 +145,8 @@ function! ale#test#WaitForJobs(deadline) abort
" end, but before handlers are run.
sleep 10ms
" We must check the buffer data again to see if new jobs started
" for command_chain linters.
" We must check the buffer data again to see if new jobs started for
" linters with chained commands.
let l:has_new_jobs = 0
" Check again to see if any jobs are running.

View file

@ -423,7 +423,10 @@ function! ale#util#Writefile(buffer, lines, filename) abort
\ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')')
\ : a:lines
call writefile(l:corrected_lines, a:filename, 'S') " no-custom-checks
" Set binary flag if buffer doesn't have eol and nofixeol to avoid appending newline
let l:flags = !getbufvar(a:buffer, '&eol') && exists('+fixeol') && !&fixeol ? 'bS' : 'S'
call writefile(l:corrected_lines, a:filename, l:flags) " no-custom-checks
endfunction
if !exists('s:patial_timers')

View file

@ -1,22 +1,36 @@
===============================================================================
ALE C Integration *ale-c-options*
For basic checking of problems with C files, ALE offers the `cc` linter, which
runs either `clang`, or `gcc`. See |ale-c-cc|.
===============================================================================
Global Options
g:ale_c_always_make *g:ale_c_always_make*
*b:ale_c_always_make*
Type: |Number|
Default: `has('unix') && !has('macunix')`
If set to `1`, use `--always-make` for `make`, which means that output will
always be parsed from `make` dry runs with GNU make. BSD `make` does not
support this option, so you probably want to turn this option off when using
a BSD variant.
g:ale_c_build_dir_names *g:ale_c_build_dir_names*
*b:ale_c_build_dir_names*
Type: |List|
Default: `['build', 'bin']`
A list of directory names to be used when searching upwards from cpp
files to discover compilation databases with. For directory named `'foo'`,
ALE will search for `'foo/compile_commands.json'` in all directories on and above
the directory containing the cpp file to find path to compilation database.
This feature is useful for the clang tools wrapped around LibTooling (namely
here, clang-tidy)
A list of directory names to be used when searching upwards from cpp files
to discover compilation databases with. For directory named `'foo'`, ALE
will search for `'foo/compile_commands.json'` in all directories on and
above the directory containing the cpp file to find path to compilation
database. This feature is useful for the clang tools wrapped around
LibTooling (namely here, clang-tidy)
g:ale_c_build_dir *g:ale_c_build_dir*
@ -55,6 +69,11 @@ g:ale_c_parse_makefile *g:ale_c_parse_makefile*
set for C or C++ compilers. This can make it easier to determine the correct
build flags to use for different files.
NOTE: When using this option on BSD, you may need to set
|g:ale_c_always_make| to `0`, and `make -n` will not provide consistent
results if binaries have already been built, so use `make clean` when
editing your files.
WARNING: Running `make -n` automatically can execute arbitrary code, even
though it's supposed to be a dry run, so enable this option with care. You
might prefer to use the buffer-local version of the option instead with
@ -94,22 +113,58 @@ g:ale_c_astyle_project_options *g:ale_c_astyle_project_options*
===============================================================================
clang *ale-c-clang*
cc *ale-c-cc*
*ale-c-gcc*
*ale-c-clang*
g:ale_c_clang_executable *g:ale_c_clang_executable*
*b:ale_c_clang_executable*
g:ale_c_cc_executable *g:ale_c_cc_executable*
*b:ale_c_cc_executable*
Type: |String|
Default: `'clang'`
Default: `'<auto>'`
This variable can be changed to use a different executable for clang.
This variable can be changed to use a different executable for a C compiler.
ALE will try to use `clang` if Clang is available, otherwise ALE will
default to checking C code with `gcc`.
g:ale_c_clang_options *g:ale_c_clang_options*
*b:ale_c_clang_options*
g:ale_c_cc_options *g:ale_c_cc_options*
*b:ale_c_cc_options*
Type: |String|
Default: `'-std=c11 -Wall'`
This variable can be changed to modify flags given to clang.
This variable can be change to modify flags given to the C compiler.
===============================================================================
ccls *ale-c-ccls*
g:ale_c_ccls_executable *g:ale_c_ccls_executable*
*b:ale_c_ccls_executable*
Type: |String|
Default: `'ccls'`
This variable can be changed to use a different executable for ccls.
g:ale_c_ccls_init_options *g:ale_c_ccls_init_options*
*b:ale_c_ccls_init_options*
Type: |Dictionary|
Default: `{}`
This variable can be changed to customize ccls initialization options.
Example: >
{
\ 'cacheDirectory': '/tmp/ccls',
\ 'cacheFormat': 'binary',
\ 'diagnostics': {
\ 'onOpen': 0,
\ 'opChange': 1000,
\ },
\ }
<
Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
available options and explanations.
===============================================================================
@ -294,25 +349,6 @@ g:ale_c_flawfinder_error_severity *g:ale_c_flawfinder_error_severity*
error. This setting also applies to flawfinder for c++.
===============================================================================
gcc *ale-c-gcc*
g:ale_c_gcc_executable *g:ale_c_gcc_executable*
*b:ale_c_gcc_executable*
Type: |String|
Default: `'gcc'`
This variable can be changed to use a different executable for gcc.
g:ale_c_gcc_options *g:ale_c_gcc_options*
*b:ale_c_gcc_options*
Type: |String|
Default: `'-std=c11 -Wall'`
This variable can be change to modify flags given to gcc.
===============================================================================
uncrustify *ale-c-uncrustify*
@ -332,36 +368,5 @@ g:ale_c_uncrustify_options *g:ale_c_uncrustify_options*
This variable can be change to modify flags given to uncrustify.
===============================================================================
ccls *ale-c-ccls*
g:ale_c_ccls_executable *g:ale_c_ccls_executable*
*b:ale_c_ccls_executable*
Type: |String|
Default: `'ccls'`
This variable can be changed to use a different executable for ccls.
g:ale_c_ccls_init_options *g:ale_c_ccls_init_options*
*b:ale_c_ccls_init_options*
Type: |Dictionary|
Default: `{}`
This variable can be changed to customize ccls initialization options.
Example: >
{
\ 'cacheDirectory': '/tmp/ccls',
\ 'cacheFormat': 'binary',
\ 'diagnostics': {
\ 'onOpen': 0,
\ 'opChange': 1000,
\ },
\ }
<
Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
available options and explanations.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -1,12 +1,16 @@
===============================================================================
ALE C++ Integration *ale-cpp-options*
For basic checking of problems with C++ files, ALE offers the `cc` linter,
which runs either `clang++`, or `gcc`. See |ale-cpp-cc|.
===============================================================================
Global Options
The following C options also apply to some C++ linters too.
* |g:ale_c_always_make|
* |g:ale_c_build_dir_names|
* |g:ale_c_build_dir|
* |g:ale_c_parse_makefile|
@ -38,41 +42,58 @@ g:ale_cpp_astyle_project_options *g:ale_cpp_astyle_project_options*
===============================================================================
clang *ale-cpp-clang*
cc *ale-cpp-cc*
*ale-cpp-gcc*
*ale-cpp-clang*
g:ale_cpp_clang_executable *g:ale_cpp_clang_executable*
*b:ale_cpp_clang_executable*
g:ale_cpp_cc_executable *g:ale_cpp_cc_executable*
*b:ale_cpp_cc_executable*
Type: |String|
Default: `'clang++'`
Default: `'<auto>'`
This variable can be changed to use a different executable for clang.
This variable can be changed to use a different executable for a C++ compiler.
ALE will try to use `clang++` if Clang is available, otherwise ALE will
default to checking C++ code with `gcc`.
g:ale_cpp_clang_options *g:ale_cpp_clang_options*
*b:ale_cpp_clang_options*
g:ale_cpp_cc_options *g:ale_cpp_cc_options*
*b:ale_cpp_cc_options*
Type: |String|
Default: `'-std=c++14 -Wall'`
This variable can be changed to modify flags given to clang.
This variable can be change to modify flags given to the C++ compiler.
===============================================================================
clangd *ale-cpp-clangd*
ccls *ale-cpp-ccls*
g:ale_cpp_clangd_executable *g:ale_cpp_clangd_executable*
*b:ale_cpp_clangd_executable*
g:ale_cpp_ccls_executable *g:ale_cpp_ccls_executable*
*b:ale_cpp_ccls_executable*
Type: |String|
Default: `'clangd'`
Default: `'ccls'`
This variable can be changed to use a different executable for clangd.
This variable can be changed to use a different executable for ccls.
g:ale_cpp_clangd_options *g:ale_cpp_clangd_options*
*b:ale_cpp_clangd_options*
Type: |String|
Default: `''`
g:ale_cpp_ccls_init_options *g:ale_cpp_ccls_init_options*
*b:ale_cpp_ccls_init_options*
Type: |Dictionary|
Default: `{}`
This variable can be changed to modify flags given to clangd.
This variable can be changed to customize ccls initialization options.
Example: >
{
\ 'cacheDirectory': '/tmp/ccls',
\ 'cacheFormat': 'binary',
\ 'diagnostics': {
\ 'onOpen': 0,
\ 'opChange': 1000,
\ },
\ }
<
Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
available options and explanations.
===============================================================================
@ -106,6 +127,25 @@ g:ale_cpp_clangcheck_options *g:ale_cpp_clangcheck_options*
option.
===============================================================================
clangd *ale-cpp-clangd*
g:ale_cpp_clangd_executable *g:ale_cpp_clangd_executable*
*b:ale_cpp_clangd_executable*
Type: |String|
Default: `'clangd'`
This variable can be changed to use a different executable for clangd.
g:ale_cpp_clangd_options *g:ale_cpp_clangd_options*
*b:ale_cpp_clangd_options*
Type: |String|
Default: `''`
This variable can be changed to modify flags given to clangd.
===============================================================================
clang-format *ale-cpp-clangformat*
@ -295,61 +335,11 @@ g:ale_cpp_flawfinder_options *g:ale-cpp-flawfinder*
This variable can be used to pass extra options into the flawfinder command.
===============================================================================
gcc *ale-cpp-gcc*
g:ale_cpp_gcc_executable *g:ale_cpp_gcc_executable*
*b:ale_cpp_gcc_executable*
Type: |String|
Default: `'gcc'`
This variable can be changed to use a different executable for gcc.
g:ale_cpp_gcc_options *g:ale_cpp_gcc_options*
*b:ale_cpp_gcc_options*
Type: |String|
Default: `'-std=c++14 -Wall'`
This variable can be changed to modify flags given to gcc.
===============================================================================
uncrustify *ale-cpp-uncrustify*
See |ale-c-uncrustify| for information about the available options.
===============================================================================
ccls *ale-cpp-ccls*
g:ale_cpp_ccls_executable *g:ale_cpp_ccls_executable*
*b:ale_cpp_ccls_executable*
Type: |String|
Default: `'ccls'`
This variable can be changed to use a different executable for ccls.
g:ale_cpp_ccls_init_options *g:ale_cpp_ccls_init_options*
*b:ale_cpp_ccls_init_options*
Type: |Dictionary|
Default: `{}`
This variable can be changed to customize ccls initialization options.
Example: >
{
\ 'cacheDirectory': '/tmp/ccls',
\ 'cacheFormat': 'binary',
\ 'diagnostics': {
\ 'onOpen': 0,
\ 'opChange': 1000,
\ },
\ }
<
Visit https://github.com/MaskRay/ccls/wiki/Initialization-options for all
available options and explanations.
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View file

@ -13,6 +13,7 @@ CONTENTS *ale-development-contents*
4. Testing ALE..........................|ale-development-tests|
4.1. Writing Linter Tests.............|ale-development-linter-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*
@ -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
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
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.
===============================================================================
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:

View file

@ -6,7 +6,7 @@ ALE Elixir Integration *ale-elixir-options*
mix *ale-elixir-mix*
The `mix` linter is disabled by default, as it can bee too expensive to run.
The `mix` linter is disabled by default, as it can be too expensive to run.
See `:help g:ale_linters`

View file

@ -14,7 +14,8 @@ ember-template-lint *ale-handlebars-embertemplatelint*
g:ale_handlebars_embertemplatelint_executable
*g:ale_handlebars_embertemplatelint_executable*
Type: |String| *b:ale_handlebars_embertemplatelint_executable*
*b:ale_handlebars_embertemplatelint_executable*
Type: |String|
Default: `'ember-template-lint'`
See |ale-integrations-local-executables|
@ -22,7 +23,8 @@ g:ale_handlebars_embertemplatelint_executable
g:ale_handlebars_embertemplatelint_use_global
*g:ale_handlebars_embertemplatelint_use_global*
Type: |Number| *b:ale_handlebars_embertemplatelint_use_global*
*b:ale_handlebars_embertemplatelint_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|

View file

@ -2,6 +2,17 @@
ALE Markdown Integration *ale-markdown-options*
===============================================================================
markdownlint *ale-markdown-markdownlint*
g:ale_markdown_markdownlint_options *g:ale_markdown_markdownlint_options*
*b:ale_markdown_markdownlint_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to markdownlint.
===============================================================================
mdl *ale-markdown-mdl*

View file

@ -189,13 +189,23 @@ g:ale_php_psalm_executable *g:ale_php_psalm_executable*
This variable sets the executable used for psalm.
g:ale_psalm_langserver_options *g:ale_psalm_langserver_options*
*b:ale_psalm_langserver_options*
g:ale_php_psalm_options *g:ale_php_psalm_options*
*b:ale_php_psalm_options*
Type: |String|
Default: `''`
This variable can be set to pass additional options to psalm.
g:ale_php_psalm_use_global *g:ale_php_psalm_use_global*
*b:ale_php_psalm_use_global*
Type: |Boolean|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
php-cs-fixer *ale-php-php-cs-fixer*
@ -206,12 +216,6 @@ g:ale_php_cs_fixer_executable *g:ale_php_cs_fixer_executable*
This variable sets executable used for php-cs-fixer.
g:ale_php_cs_fixer_use_global *g:ale_php_cs_fixer_use_global*
*b:ale_php_cs_fixer_use_global*
Type: |Boolean|
Default: `get(g:, 'ale_use_global_executables', 0)`
This variable force globally installed fixer.
g:ale_php_cs_fixer_options *g:ale_php_cs_fixer_options*
*b:ale_php_cs_fixer_options*
@ -220,6 +224,15 @@ g:ale_php_cs_fixer_options *g:ale_php_cs_fixer_options*
This variable can be set to pass additional options to php-cs-fixer.
g:ale_php_cs_fixer_use_global *g:ale_php_cs_fixer_use_global*
*b:ale_php_cs_fixer_use_global*
Type: |Boolean|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|
===============================================================================
php *ale-php-php*

View file

@ -169,13 +169,14 @@ flake8 *ale-python-flake8*
g:ale_python_flake8_change_directory *g:ale_python_flake8_change_directory*
*b:ale_python_flake8_change_directory*
Type: |Number|
Default: `1`
Type: |String|
Default: `project`
If set to `1`, ALE will switch to the directory the Python file being
checked with `flake8` is in before checking it. This helps `flake8` find
configuration files more easily. This option can be turned off if you want
to control the directory Python is executed from yourself.
If set to `project`, ALE will switch to the project root before checking file.
If set to `file`, ALE will switch to directory the Python file being
checked with `flake8` is in before checking it.
You can turn it off with `off` option if you want to control the directory
Python is executed from yourself.
g:ale_python_flake8_executable *g:ale_python_flake8_executable*

View file

@ -31,11 +31,11 @@ Integration Information
5. rustfmt -- If you have `rustfmt` installed, you can use it as a fixer to
consistently reformat your Rust code.
Only cargo is enabled by default. To switch to using rustc instead of cargo,
configure |g:ale_linters| appropriately: >
Only cargo and rls are enabled by default. To switch to using rustc instead
of cargo, configure |g:ale_linters| appropriately: >
" 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.
@ -60,6 +60,7 @@ g:ale_rust_analyzer_config *g:ale_rust_analyzer_config*
Dictionary with configuration settings for rust-analyzer.
===============================================================================
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']
g:ale_rust_ignore_secondary_spans *g:ale_rust_ignore_secondary_spans*
*b:ale_rust_ignore_secondary_spans*
Type: Number
Default: 0
When set to 1, instructs the Rust error repporting to ignore secondary
spans. The problem with secondary spans is that they sometimes appear in
error messages before the main cause of the error, for example: >
When set to 1, instructs the Rust error reporting to ignore secondary spans.
The problem with secondary spans is that they sometimes appear in error
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
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,
the 'defined here' span will not be presented.
===============================================================================
rustfmt *ale-rust-rustfmt*

View file

@ -21,6 +21,7 @@ Notes:
* `drafter`
* AsciiDoc
* `alex`!!
* `languagetool`!!
* `proselint`
* `redpen`
* `textlint`
@ -47,7 +48,7 @@ Notes:
* C
* `astyle`
* `ccls`
* `clang`
* `clang` (`cc`)
* `clangd`
* `clang-format`
* `clangtidy`!!
@ -55,7 +56,7 @@ Notes:
* `cpplint`!!
* `cquery`
* `flawfinder`
* `gcc`
* `gcc` (`cc`)
* `uncrustify`
* C#
* `csc`!!
@ -65,7 +66,7 @@ Notes:
* C++ (filetype cpp)
* `astyle`
* `ccls`
* `clang`
* `clang` (`cc`)
* `clangcheck`!!
* `clangd`
* `clang-format`
@ -75,7 +76,7 @@ Notes:
* `cpplint`!!
* `cquery`
* `flawfinder`
* `gcc`
* `gcc` (`cc`)
* `uncrustify`
* Chef
* `cookstyle`
@ -118,6 +119,8 @@ Notes:
* `dartanalyzer`!!
* `dartfmt`!!
* `language_server`
* Dhall
* `dhall-format`
* Dockerfile
* `dockerfile_lint`
* `hadolint`
@ -446,6 +449,7 @@ Notes:
* `sqlfmt`
* `sqlformat`
* `sqlint`
* `sql-lint`
* Stylus
* `stylelint`
* SugarSS
@ -453,6 +457,7 @@ Notes:
* Swift
* `sourcekit-lsp`
* `swiftformat`
* `swift-format`
* `swiftlint`
* Tcl
* `nagelfar`!!

View file

@ -9,8 +9,9 @@ CONTENTS *ale-contents*
1. Introduction.........................|ale-introduction|
2. Supported Languages & Tools..........|ale-support|
3. Linting..............................|ale-lint|
3.1 Adding Language Servers...........|ale-lint-language-servers|
3.2 Other Sources.....................|ale-lint-other-sources|
3.1 Linting On Other Machines.........|ale-lint-other-machines|
3.2 Adding Language Servers...........|ale-lint-language-servers|
3.3 Other Sources.....................|ale-lint-other-sources|
4. Fixing Problems......................|ale-fix|
5. Language Server Protocol Support.....|ale-lsp|
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
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.
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
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
temporary file created for `%t`. This option can be used
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
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*
@ -402,12 +463,56 @@ is loaded. The delay for completion can be configured with
|g:ale_completion_delay|. This setting should not be enabled if you wish to
use ALE as a completion source for other plugins.
ALE automatic completion will not work when 'paste' is active. Only set
'paste' when you are copy and pasting text into your buffers.
ALE automatic completion will interfere with default insert completion with
`CTRL-N` and so on (|compl-vim|). You can write your own keybinds and a
function in your |vimrc| file to force insert completion instead, like so: >
function! SmartInsertCompletion() abort
" Use the default CTRL-N in completion menus
if pumvisible()
return "\<C-n>"
endif
" Exit and re-enter insert mode, and use insert completion
return "\<C-c>a\<C-n>"
endfunction
inoremap <silent> <C-n> <C-R>=SmartInsertCompletion()<CR>
<
ALE provides an 'omnifunc' function |ale#completion#OmniFunc| for triggering
completion manually with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O| >
" Use ALE's function for omnicompletion.
set omnifunc=ale#completion#OmniFunc
<
*ale-completion-fallback*
You can write your own completion function and fallback on other methods of
completion by checking if there are no results that ALE can determine. For
example, for Python code, you could fall back on the `python3complete`
function. >
function! TestCompletionFunc(findstart, base) abort
let l:result = ale#completion#OmniFunc(a:findstart, a:base)
" Check if ALE couldn't find anything.
if (a:findstart && l:result is -3)
\|| (!a:findstart && empty(l:result))
" Defer to another omnifunc if ALE couldn't find anything.
return python3complete#Complete(a:findstart, a:base)
endif
return l:result
endfunction
set omnifunc=TestCompletionFunc
<
See |complete-functions| for documentation on how to write completion
functions.
ALE will only suggest so many possible matches for completion. The maximum
number of items can be controlled with |g:ale_completion_max_suggestions|.
@ -421,6 +526,12 @@ completion information with Deoplete, consult Deoplete's documentation.
ALE by can support automatic imports from external modules. This behavior can
be enabled by setting the |g:ale_completion_autoimport| variable to `1`.
You can manually request imports for symbols at the cursor with the
|ALEImport| command. The word at the cursor must be an exact match for some
potential completion result which includes additional text to insert into the
current buffer, which ALE will assume is code for an import line. This command
can be useful when your code already contains something you need to import.
When working with TypeScript files, ALE can remove warnings from your
completions by setting the |g:ale_completion_tsserver_remove_warnings|
variable to 1.
@ -501,15 +612,9 @@ displayed.
-------------------------------------------------------------------------------
5.4 Find References *ale-find-references*
ALE supports finding references for symbols though any enabled LSP linters.
ALE will display a preview window showing the places where a symbol is
referenced in a codebase when a command is run. The following commands are
supported:
|ALEFindReferences| - Find references for the word under the cursor.
Options:
`-relative` Show file paths in the results relative to the working dir
ALE supports finding references for symbols though any enabled LSP linters
with the |ALEFindReferences| command. See the documentation for the command
for a full list of options.
-------------------------------------------------------------------------------
5.5 Hovering *ale-hover*
@ -552,13 +657,9 @@ Documentation for symbols at the cursor can be retrieved using the
-------------------------------------------------------------------------------
5.6 Symbol Search *ale-symbol-search*
ALE supports searching for workspace symbols via LSP linters. The following
commands are supported:
|ALESymbolSearch| - Search for symbols in the workspace.
Options:
`-relative` Show file paths in the results relative to the working dir
ALE supports searching for workspace symbols via LSP linters with the
|ALESymbolSearch| command. See the documentation for the command
for a full list of options.
===============================================================================
6. Global Options *ale-options*
@ -678,13 +779,18 @@ g:ale_completion_enabled *g:ale_completion_enabled*
This setting should not be enabled if you wish to use ALE as a completion
source for other completion plugins.
ALE automatic completion will not work when 'paste' is active. Only set
'paste' when you are copy and pasting text into your buffers.
A buffer-local version of this setting `b:ale_completion_enabled` can be set
to `0` to disable ALE's automatic completion support for a single buffer.
ALE's completion support must be enabled globally to be enabled locally.
See |ale-completion|
g:ale_completion_tsserver_remove_warnings *g:ale_completion_tsserver_remove_warnings*
*g:ale_completion_tsserver_remove_warnings*
g:ale_completion_tsserver_remove_warnings
Type: Number
Default: `0`
@ -693,6 +799,7 @@ g:ale_completion_tsserver_remove_warnings *g:ale_completion_tsserver_remove_warn
including those that are a warning. Warnings can be excluded from completed
items by setting it to `1`.
g:ale_completion_autoimport *g:ale_completion_autoimport*
Type: Number
@ -807,7 +914,7 @@ g:ale_default_navigation *g:ale_default_navigation*
Default: `'buffer'`
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*
@ -1118,7 +1225,7 @@ g:ale_list_window_size *g:ale_list_window_size*
g:ale_lint_delay *g:ale_lint_delay*
*b:ale_lint_delay*
Type: |Number|
Default: `200`
@ -1126,6 +1233,9 @@ g:ale_lint_delay *g:ale_lint_delay*
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`.
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*
@ -1283,6 +1393,90 @@ g:ale_linter_aliases *g:ale_linter_aliases*
<
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*
*b:ale_linters*
Type: |Dictionary|
@ -1303,7 +1497,7 @@ g:ale_linters *g:ale_linters*
\ 'perl': ['perlcritic'],
\ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'rust': ['cargo'],
\ 'rust': ['cargo', 'rls'],
\ 'spec': [],
\ 'text': [],
\ 'vue': ['eslint', 'vls'],
@ -2319,16 +2513,15 @@ documented in additional help files.
bibclean..............................|ale-bib-bibclean|
c.......................................|ale-c-options|
astyle................................|ale-c-astyle|
clang.................................|ale-c-clang|
cc....................................|ale-c-cc|
ccls..................................|ale-c-ccls|
clangd................................|ale-c-clangd|
clang-format..........................|ale-c-clangformat|
clangtidy.............................|ale-c-clangtidy|
cppcheck..............................|ale-c-cppcheck|
cquery................................|ale-c-cquery|
flawfinder............................|ale-c-flawfinder|
gcc...................................|ale-c-gcc|
uncrustify............................|ale-c-uncrustify|
ccls..................................|ale-c-ccls|
chef....................................|ale-chef-options|
cookstyle.............................|ale-chef-cookstyle|
foodcritic............................|ale-chef-foodcritic|
@ -2342,9 +2535,10 @@ documented in additional help files.
cmake-format..........................|ale-cmake-cmakeformat|
cpp.....................................|ale-cpp-options|
astyle................................|ale-cpp-astyle|
clang.................................|ale-cpp-clang|
clangd................................|ale-cpp-clangd|
cc....................................|ale-cpp-cc|
ccls..................................|ale-cpp-ccls|
clangcheck............................|ale-cpp-clangcheck|
clangd................................|ale-cpp-clangd|
clang-format..........................|ale-cpp-clangformat|
clangtidy.............................|ale-cpp-clangtidy|
clazy.................................|ale-cpp-clazy|
@ -2352,9 +2546,7 @@ documented in additional help files.
cpplint...............................|ale-cpp-cpplint|
cquery................................|ale-cpp-cquery|
flawfinder............................|ale-cpp-flawfinder|
gcc...................................|ale-cpp-gcc|
uncrustify............................|ale-cpp-uncrustify|
ccls..................................|ale-cpp-ccls|
c#......................................|ale-cs-options|
csc...................................|ale-cs-csc|
mcs...................................|ale-cs-mcs|
@ -2506,6 +2698,7 @@ documented in additional help files.
luac..................................|ale-lua-luac|
luacheck..............................|ale-lua-luacheck|
markdown................................|ale-markdown-options|
markdownlint..........................|ale-markdown-markdownlint|
mdl...................................|ale-markdown-mdl|
prettier..............................|ale-markdown-prettier|
remark-lint...........................|ale-markdown-remark-lint|
@ -2768,13 +2961,20 @@ ALEFindReferences *ALEFindReferences*
The default method used for navigating to a new location can be changed
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.
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|.
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*
@ -2812,7 +3012,13 @@ ALEGoToDefinition `<options>` *ALEGoToDefinition*
command. Otherwise, Vim will refuse to leave the buffer you're jumping from
unless you have saved your edits.
A plug mapping `<Plug>(ale_go_to_definition)` is defined for this command.
The following Plug mappings are defined for this command, which correspond
to the following commands.
`<Plug>(ale_go_to_definition)` - `:ALEGoToDefinition`
`<Plug>(ale_go_to_definition_in_tab)` - `:ALEGoToDefinition -tab`
`<Plug>(ale_go_to_definition_in_split)` - `:ALEGoToDefinition -split`
`<Plug>(ale_go_to_definition_in_vsplit)` - `:ALEGoToDefinition -vsplit`
ALEGoToTypeDefinition *ALEGoToTypeDefinition*
@ -2834,8 +3040,13 @@ ALEGoToTypeDefinition *ALEGoToTypeDefinition*
You can jump back to the position you were at before going to the definition
of something with jump motions like CTRL-O. See |jump-motions|.
A plug mapping `<Plug>(ale_go_to_type_definition)` is defined for this
command.
The following Plug mappings are defined for this command, which correspond
to the following commands.
`<Plug>(ale_go_to_type_definition)` - `:ALEGoToTypeDefinition`
`<Plug>(ale_go_to_type_definition_in_tab)` - `:ALEGoToTypeDefinition -tab`
`<Plug>(ale_go_to_type_definition_in_split)` - `:ALEGoToTypeDefinition -split`
`<Plug>(ale_go_to_type_definition_in_vsplit)` - `:ALEGoToTypeDefinition -vsplit`
ALEHover *ALEHover*
@ -2851,6 +3062,23 @@ ALEHover *ALEHover*
A plug mapping `<Plug>(ale_hover)` is defined for this command.
ALEImport *ALEImport*
Try to import a symbol using `tsserver` or a Language Server.
ALE will look for completions for the word at the cursor which contain
additional text edits that possible insert lines to import the symbol. The
first match with additional text edits will be used, and may add other code
to the current buffer other than import lines.
If linting is enabled, and |g:ale_lint_on_text_changed| is set to ever check
buffers when text is changed, the buffer will be checked again after changes
are made.
A Plug mapping `<Plug>(ale_import)` is defined for this command. This
mapping should only be bound for normal mode.
ALEOrganizeImports *ALEOrganizeImports*
Organize imports using tsserver. Currently not implemented for LSPs.
@ -2858,9 +3086,10 @@ ALEOrganizeImports *ALEOrganizeImports*
ALERename *ALERename*
Rename a symbol using TypeScript server or Language Server.
Rename a symbol using `tsserver` or a Language Server.
The user will be prompted for a new name.
The symbol where the cursor is resting will be the symbol renamed, and a
prompt will open to request a new name.
ALERepeatSelection *ALERepeatSelection*
@ -2875,14 +3104,17 @@ ALESymbolSearch `<query>` *ALESymbolSearch*
The arguments provided to this command will be used as a search query for
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*
Run ALE once for the current buffer. This command can be used to run ALE
manually, instead of automatically, if desired.
This command will also run linters where `lint_file` is set to `1`, or in
other words linters which check the file instead of the Vim buffer.
This command will also run linters where `lint_file` is evaluates to `1`,
meaning linters which check the file instead of the Vim buffer.
A plug mapping `<Plug>(ale_lint)` is defined for this command.
@ -3064,6 +3296,15 @@ ale#Env(variable_name, value) *ale#Env()*
'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()*
Return `1` if ALE supports a given feature, like |has()| for Vim features.
@ -3086,9 +3327,9 @@ ale#Queue(delay, [linting_flag, buffer_number]) *ale#Queue()*
The linters will always be run in the background. Calling this function
again from the same buffer
An optional `linting_flag` argument can be given. If `linting_flag`
is `'lint_file'`, then linters where the `lint_file` option is set to `1` will be
run. Linters with `lint_file` set to `1` are not run by default.
An optional `linting_flag` argument can be given. If `linting_flag` is
`'lint_file'`, then linters where the `lint_file` option evaluates to `1`
will be run. Otherwise, those linters will not be run.
An optional `buffer_number` argument can be given for specifying the buffer
to check. The active buffer (`bufnr('')`) will be checked by default.
@ -3178,23 +3419,36 @@ ale#command#Run(buffer, command, callback, [options]) *ale#command#Run()*
<
The following `options` can be provided.
`output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or `'none`' for
selecting which output streams to read lines from.
`output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or
`'none`' for selecting which output streams to read
lines from.
The default is `'stdout'`
`executable` - An executable for formatting into `%e` in the command.
If this option is not provided, formatting commands with
`%e` will not work.
`executable` - An executable for formatting into `%e` in the
command. If this option is not provided, formatting
commands with `%e` will not work.
`read_buffer` - If set to `1`, the buffer will be piped into the
command.
The default is `0`.
`input` - When creating temporary files with `%t` or piping text
into a command `input` can be set to a |List| of text to
use instead of the buffer's text.
`input` - When creating temporary files with `%t` or piping
text into a command `input` can be set to a |List| of
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()*
@ -3409,24 +3663,30 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
if a command manually reads from a temporary file
instead, etc.
This option behaves as if it was set to `0` when the
`lint_file` option evaluates to `1`.
*ale-lint-file*
`lint_file` A |Number| (`0` or `1`) indicating whether a command
should read the file instead of the Vim buffer. This
option can be used for linters which must check the
file on disk, and which cannot check a Vim buffer
instead.
`lint_file` A |Number| (`0` or `1`), or a |Funcref| for a function
accepting a buffer number for computing either `0` or
`1`, indicating whether a command should read the file
instead of the Vim buffer. This option can be used
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
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|.
The result can be computed with |ale#command#Run()|.
When this option is set to `1`, `read_buffer` will
be set automatically to `0`. The two options cannot
be used together.
Linters where the eventual value of this option
evaluates to `1` will not be run as a 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 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*
`lsp` A |String| for defining LSP (Language Server Protocol)
@ -3565,6 +3825,16 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
command, so literal character sequences `%s` and `%t` can be escaped by
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
possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting
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.
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
" default, quickfix overrides loclist).
let g:ale_set_loclist = get(g:, 'ale_set_loclist', 1)
@ -207,19 +211,9 @@ command! -bar ALEFixSuggest :call ale#fix#registry#Suggest(&filetype)
" Go to definition for tsserver and LSP
command! -bar -nargs=* ALEGoToDefinition :call ale#definition#GoToCommandHandler('', <f-args>)
" Deprecated commands we have to keep for now.
command! -bar ALEGoToDefinitionInTab :call ale#definition#GoTo({'open_in': 'tab', 'deprecated_command': 'ALEGoToDefinitionInTab'})
command! -bar ALEGoToDefinitionInSplit :call ale#definition#GoTo({'open_in': 'split', 'deprecated_command': 'ALEGoToDefinitionInSplit'})
command! -bar ALEGoToDefinitionInVSplit :call ale#definition#GoTo({'open_in': 'vsplit', 'deprecated_command': 'ALEGoToDefinitionInVSplit'})
" Go to type definition for tsserver and LSP
command! -bar -nargs=* ALEGoToTypeDefinition :call ale#definition#GoToCommandHandler('type', <f-args>)
" Deprecated commands we have to keep for now.
command! -bar ALEGoToTypeDefinitionInTab :call ale#definition#GoToType({'open_in': 'tab', 'deprecated_command': 'ALEGoToTypeDefinitionInTab'})
command! -bar ALEGoToTypeDefinitionInSplit :call ale#definition#GoToType({'open_in': 'split', 'deprecated_command': 'ALEGoToTypeDefinitionInSplit'})
command! -bar ALEGoToTypeDefinitionInVSplit :call ale#definition#GoToType({'open_in': 'vsplit', 'deprecated_command': 'ALEGoToTypeDefinitionInVSplit'})
" Repeat a previous selection in the preview window
command! -bar ALERepeatSelection :call ale#preview#RepeatSelection()
@ -235,8 +229,12 @@ command! -bar ALEDocumentation :call ale#hover#ShowDocumentationAtCursor()
" Search for appearances of a symbol, such as a type name or function name.
command! -nargs=1 ALESymbolSearch :call ale#symbol#Search(<q-args>)
" Complete text with tsserver and LSP
command! -bar ALEComplete :call ale#completion#GetCompletions('ale-manual')
" Try to find completions for the current symbol that add additional text.
command! -bar ALEImport :call ale#completion#Import()
" Rename symbols using tsserver and LSP
command! -bar ALERename :call ale#rename#Execute()
@ -270,22 +268,21 @@ nnoremap <silent> <Plug>(ale_lint) :ALELint<Return>
nnoremap <silent> <Plug>(ale_detail) :ALEDetail<Return>
nnoremap <silent> <Plug>(ale_fix) :ALEFix<Return>
nnoremap <silent> <Plug>(ale_go_to_definition) :ALEGoToDefinition<Return>
nnoremap <silent> <Plug>(ale_go_to_definition_in_tab) :ALEGoToDefinition -tab<Return>
nnoremap <silent> <Plug>(ale_go_to_definition_in_split) :ALEGoToDefinition -split<Return>
nnoremap <silent> <Plug>(ale_go_to_definition_in_vsplit) :ALEGoToDefinition -vsplit<Return>
nnoremap <silent> <Plug>(ale_go_to_type_definition) :ALEGoToTypeDefinition<Return>
nnoremap <silent> <Plug>(ale_go_to_type_definition_in_tab) :ALEGoToTypeDefinition -tab<Return>
nnoremap <silent> <Plug>(ale_go_to_type_definition_in_split) :ALEGoToTypeDefinition -split<Return>
nnoremap <silent> <Plug>(ale_go_to_type_definition_in_vsplit) :ALEGoToTypeDefinitionIn -vsplit<Return>
nnoremap <silent> <Plug>(ale_find_references) :ALEFindReferences<Return>
nnoremap <silent> <Plug>(ale_hover) :ALEHover<Return>
nnoremap <silent> <Plug>(ale_documentation) :ALEDocumentation<Return>
inoremap <silent> <Plug>(ale_complete) <C-\><C-O>:ALEComplete<Return>
nnoremap <silent> <Plug>(ale_import) :ALEImport<Return>
nnoremap <silent> <Plug>(ale_rename) :ALERename<Return>
nnoremap <silent> <Plug>(ale_repeat_selection) :ALERepeatSelection<Return>
" Deprecated <Plug> mappings
nnoremap <silent> <Plug>(ale_go_to_definition_in_tab) :ALEGoToDefinitionInTab<Return>
nnoremap <silent> <Plug>(ale_go_to_definition_in_split) :ALEGoToDefinitionInSplit<Return>
nnoremap <silent> <Plug>(ale_go_to_definition_in_vsplit) :ALEGoToDefinitionInVSplit<Return>
nnoremap <silent> <Plug>(ale_go_to_type_definition_in_tab) :ALEGoToTypeDefinitionInTab<Return>
nnoremap <silent> <Plug>(ale_go_to_type_definition_in_split) :ALEGoToTypeDefinitionInSplit<Return>
nnoremap <silent> <Plug>(ale_go_to_type_definition_in_vsplit) :ALEGoToTypeDefinitionInVSplit<Return>
" Set up autocmd groups now.
call ale#events#Init()

View file

@ -83,6 +83,13 @@ while [ $# -ne 0 ]; do
run_neovim_03_tests=0
shift
;;
--fast)
run_vim_80_tests=0
run_vim_81_tests=0
run_neovim_02_tests=0
run_neovim_03_tests=1
shift
;;
--help)
echo 'Usage: ./run-tests [OPTION]... [FILE]...'
echo
@ -99,6 +106,7 @@ while [ $# -ne 0 ]; do
echo ' --vim-80-only Run tests only for Vim 8.0'
echo ' --vim-81-only Run tests only for Vim 8.1'
echo ' --linters-only Run only Vint and custom checks'
echo ' --fast Run only the fastest Vim and custom checks'
echo ' --help Show this help text'
echo ' -- Stop parsing options after this'
exit 0

View file

@ -16,7 +16,7 @@ formatting.
| Key | Definition |
| ------------- | -------------------------------- |
| :floppy_disk: | Only checked when saved to disk |
| :floppy_disk: | May only run on files on disk |
| :warning: | Disabled by default |
---
@ -30,6 +30,7 @@ formatting.
* [drafter](https://github.com/apiaryio/drafter)
* AsciiDoc
* [alex](https://github.com/wooorm/alex) :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk:
* [proselint](http://proselint.com/)
* [redpen](http://redpen.cc/)
* [textlint](https://textlint.github.io/)
@ -128,9 +129,9 @@ formatting.
* [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt)
* [language_server](https://github.com/natebosch/dart_language_server)
* Dhall
* [dhall-format](https://github.com/dhall-lang)
* [dhall-freeze](https://github.com/dhall-lang)
* [dhall-lint](https://github.com/dhall-lang)
* [dhall-format](https://github.com/dhall-lang/dhall-lang)
* [dhall-freeze](https://github.com/dhall-lang/dhall-lang)
* [dhall-lint](https://github.com/dhall-lang/dhall-lang)
* Dockerfile
* [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint)
* [hadolint](https://github.com/hadolint/hadolint)
@ -459,6 +460,7 @@ formatting.
* [sqlfmt](https://github.com/jackc/sqlfmt)
* [sqlformat](https://github.com/andialbrecht/sqlparse)
* [sqlint](https://github.com/purcell/sqlint)
* [sql-lint](https://github.com/joereynolds/sql-lint)
* Stylus
* [stylelint](https://github.com/stylelint/stylelint)
* SugarSS
@ -466,6 +468,7 @@ formatting.
* Swift
* [sourcekit-lsp](https://github.com/apple/sourcekit-lsp)
* [swiftformat](https://github.com/nicklockwood/SwiftFormat)
* [swift-format](https://github.com/apple/swift-format)
* [swiftlint](https://github.com/realm/SwiftLint)
* Tcl
* [nagelfar](http://nagelfar.sourceforge.net) :floppy_disk:

View file

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

View file

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

View file

@ -0,0 +1,55 @@
Before:
Save g:ale_c_parse_makefile
Save g:ale_history_enabled
let g:ale_c_parse_makefile = 0
let g:ale_history_enabled = 0
let g:get_cflags_return_value = ''
let g:executable_map = {}
runtime autoload/ale/c.vim
runtime autoload/ale/engine.vim
function! ale#engine#IsExecutable(buffer, executable) abort
return has_key(g:executable_map, a:executable)
endfunction
function! ale#c#GetCFlags(buffer, output) abort
return g:get_cflags_return_value
endfunction
call ale#assert#SetUpLinterTest('c', 'cc')
let b:command_tail = ' -S -x c'
\ . ' -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote %s:h'
\ . ' -std=c11 -Wall -'
After:
unlet! g:get_cflags_return_value
unlet! g:executable_map
unlet! b:command_tail
runtime autoload/ale/c.vim
runtime autoload/ale/engine.vim
call ale#assert#TearDownLinterTest()
Execute(clang should be used instead of gcc, if available):
let g:executable_map = {'clang': 1}
AssertLinter 'clang', [ale#Escape('clang') . b:command_tail]
Execute(The executable should be configurable):
AssertLinter 'gcc', [ale#Escape('gcc') . b:command_tail]
let b:ale_c_cc_executable = 'foobar'
AssertLinter 'foobar', [ale#Escape('foobar') . b:command_tail]
Execute(The -std flag should be replaced by parsed C flags):
let b:command_tail = substitute(b:command_tail, 'c11', 'c99 ', '')
let g:get_cflags_return_value = '-std=c99'
AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail

View file

@ -1,20 +0,0 @@
Before:
Save g:ale_c_parse_makefile
let g:ale_c_parse_makefile = 0
call ale#assert#SetUpLinterTest('c', 'clang')
let b:command_tail = ' -S -x c -fsyntax-only -iquote'
\ . ' ' . ale#Escape(getcwd())
\ . ' -std=c11 -Wall -'
After:
unlet! b:command_tail
call ale#assert#TearDownLinterTest()
Execute(The executable should be configurable):
AssertLinter 'clang', [ale#Escape('clang') . b:command_tail]
let b:ale_c_clang_executable = 'foobar'
AssertLinter 'foobar', [ale#Escape('foobar') . b:command_tail]

View file

@ -1,22 +0,0 @@
Before:
Save g:ale_c_parse_makefile
let g:ale_c_parse_makefile = 0
call ale#assert#SetUpLinterTest('c', 'gcc')
let b:command_tail = ' -S -x c'
\ . ' -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(getcwd())
\ . ' -std=c11 -Wall -'
After:
call ale#assert#TearDownLinterTest()
unlet! b:command_tail
Execute(The executable should be configurable):
AssertLinter 'gcc', [ale#Escape('gcc') . b:command_tail]
let b:ale_c_gcc_executable = 'foobar'
AssertLinter 'foobar', [ale#Escape('foobar') . b:command_tail]

View file

@ -7,6 +7,7 @@ Before:
Save g:__ale_c_project_filenames
let g:original_project_filenames = g:__ale_c_project_filenames
let g:executable_map = {}
" Remove the .git/HEAD dir for C import paths for these tests.
" The tests run inside of a git repo.
@ -18,106 +19,67 @@ Before:
let g:ale_c_parse_compile_commands = 0
let g:ale_c_parse_makefile = 0
runtime autoload/ale/engine.vim
function! ale#engine#IsExecutable(buffer, executable) abort
return has_key(g:executable_map, a:executable)
endfunction
After:
Restore
unlet! g:original_project_filenames
unlet! g:executable_map
runtime autoload/ale/engine.vim
call ale#assert#TearDownLinterTest()
Execute(The C GCC handler should include 'include' directories for projects with a Makefile):
call ale#assert#SetUpLinterTest('c', 'gcc')
Execute(The C cc linter should include 'include' directories for projects with a Makefile):
call ale#assert#SetUpLinterTest('c', 'cc')
call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.c')
let g:ale_c_gcc_options = ''
let g:ale_c_cc_options = ''
AssertLinter 'gcc',
\ ale#Escape('gcc')
\ . ' -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'))
\ . ' -'
Execute(The C GCC handler should include 'include' directories for projects with a configure file):
call ale#assert#SetUpLinterTest('c', 'gcc')
Execute(The C cc linter should include 'include' directories for projects with a configure file):
call ale#assert#SetUpLinterTest('c', 'cc')
call ale#test#SetFilename('../test_c_projects/configure_project/subdir/file.c')
let g:ale_c_gcc_options = ''
let g:ale_c_cc_options = ''
AssertLinter 'gcc',
\ ale#Escape('gcc')
\ . ' -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'))
\ . ' -'
Execute(The C GCC handler should include root directories for projects with .h files in them):
call ale#assert#SetUpLinterTest('c', 'gcc')
Execute(The C cc linter should include root directories for projects with .h files in them):
call ale#assert#SetUpLinterTest('c', 'cc')
call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.c')
let g:ale_c_gcc_options = ''
let g:ale_c_cc_options = ''
AssertLinter 'gcc',
\ ale#Escape('gcc')
\ . ' -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'))
\ . ' -'
Execute(The C GCC handler should include root directories for projects with .hpp files in them):
call ale#assert#SetUpLinterTest('c', 'gcc')
Execute(The C cc linter should include root directories for projects with .hpp files in them):
call ale#assert#SetUpLinterTest('c', 'cc')
call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.c')
let g:ale_c_gcc_options = ''
let g:ale_c_cc_options = ''
AssertLinter 'gcc',
\ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir'))
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
\ . ' -'
Execute(The C Clang handler should include 'include' directories for projects with a Makefile):
call ale#assert#SetUpLinterTest('c', 'clang')
call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.c')
let g:ale_c_clang_options = ''
AssertLinter 'clang',
\ ale#Escape('clang')
\ . ' -S -x c -fsyntax-only'
\ . ' -iquote ' . 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/include'))
\ . ' -'
Execute(The C Clang handler should include 'include' directories for projects with a configure file):
call ale#assert#SetUpLinterTest('c', 'clang')
call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.c')
let g:ale_c_clang_options = ''
AssertLinter 'clang',
\ ale#Escape('clang')
\ . ' -S -x c -fsyntax-only'
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir'))
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
\ . ' -'
Execute(The C Clang handler should include root directories for projects with .h files in them):
call ale#assert#SetUpLinterTest('c', 'clang')
call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.c')
let g:ale_c_clang_options = ''
AssertLinter 'clang',
\ ale#Escape('clang')
\ . ' -S -x c -fsyntax-only'
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir'))
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
\ . ' -'
Execute(The C Clang handler should include root directories for projects with .hpp files in them):
call ale#assert#SetUpLinterTest('c', 'clang')
call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.c')
let g:ale_c_clang_options = ''
AssertLinter 'clang',
\ ale#Escape('clang')
\ . ' -S -x c -fsyntax-only'
\ . ' -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'))
\ . ' -'
@ -131,99 +93,51 @@ Execute(The C ClangTidy handler should include 'include' directories for project
\ . ' %s '
\ . '-- -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
Execute(The C++ GCC handler should include 'include' directories for projects with a Makefile):
call ale#assert#SetUpLinterTest('cpp', 'gcc')
Execute(The C++ cc linter should include 'include' directories for projects with a Makefile):
call ale#assert#SetUpLinterTest('cpp', 'cc')
call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.cpp')
let g:ale_cpp_gcc_options = ''
let g:ale_cpp_cc_options = ''
AssertLinter 'gcc',
\ ale#Escape('gcc')
\ . ' -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'))
\ . ' -'
Execute(The C++ GCC handler should include 'include' directories for projects with a configure file):
call ale#assert#SetUpLinterTest('cpp', 'gcc')
Execute(The C++ cc linter should include 'include' directories for projects with a configure file):
call ale#assert#SetUpLinterTest('cpp', 'cc')
call ale#test#SetFilename('../test_c_projects/configure_project/subdir/file.cpp')
let g:ale_cpp_gcc_options = ''
let g:ale_cpp_cc_options = ''
AssertLinter 'gcc',
\ ale#Escape('gcc')
\ . ' -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'))
\ . ' -'
Execute(The C++ GCC handler should include root directories for projects with .h files in them):
call ale#assert#SetUpLinterTest('cpp', 'gcc')
Execute(The C++ cc linter should include root directories for projects with .h files in them):
call ale#assert#SetUpLinterTest('cpp', 'cc')
call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.cpp')
let g:ale_cpp_gcc_options = ''
let g:ale_cpp_cc_options = ''
AssertLinter 'gcc',
\ ale#Escape('gcc')
\ . ' -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'))
\ . ' -'
Execute(The C++ GCC handler should include root directories for projects with .hpp files in them):
call ale#assert#SetUpLinterTest('cpp', 'gcc')
Execute(The C++ cc linter should include root directories for projects with .hpp files in them):
call ale#assert#SetUpLinterTest('cpp', 'cc')
call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.cpp')
let g:ale_cpp_gcc_options = ''
let g:ale_cpp_cc_options = ''
AssertLinter 'gcc',
\ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir'))
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
\ . ' -'
Execute(The C++ Clang handler should include 'include' directories for projects with a Makefile):
call ale#assert#SetUpLinterTest('cpp', 'clang')
call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.cpp')
let g:ale_cpp_clang_options = ''
AssertLinter 'clang++',
\ ale#Escape('clang++')
\ . ' -S -x c++ -fsyntax-only'
\ . ' -iquote ' . 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/include'))
\ . ' -'
Execute(The C++ Clang handler should include 'include' directories for projects with a configure file):
call ale#assert#SetUpLinterTest('cpp', 'clang')
call ale#test#SetFilename('../test_c_projects/configure_project/subdir/file.cpp')
let g:ale_cpp_clang_options = ''
AssertLinter 'clang++',
\ ale#Escape('clang++')
\ . ' -S -x c++ -fsyntax-only'
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/subdir'))
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include'))
\ . ' -'
Execute(The C++ Clang handler should include root directories for projects with .h files in them):
call ale#assert#SetUpLinterTest('cpp', 'clang')
call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.cpp')
let g:ale_cpp_clang_options = ''
AssertLinter 'clang++',
\ ale#Escape('clang++')
\ . ' -S -x c++ -fsyntax-only'
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir'))
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
\ . ' -'
Execute(The C++ Clang handler should include root directories for projects with .hpp files in them):
call ale#assert#SetUpLinterTest('cpp', 'clang')
call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.cpp')
let g:ale_cpp_clang_options = ''
AssertLinter 'clang++',
\ ale#Escape('clang++')
\ . ' -S -x c++ -fsyntax-only'
\ . ' -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'))
\ . ' -'

View file

@ -0,0 +1,55 @@
Before:
Save g:ale_c_parse_makefile
Save g:ale_history_enabled
let g:ale_c_parse_makefile = 0
let g:ale_history_enabled = 0
let g:get_cflags_return_value = ''
let g:executable_map = {}
runtime autoload/ale/c.vim
runtime autoload/ale/engine.vim
function! ale#engine#IsExecutable(buffer, executable) abort
return has_key(g:executable_map, a:executable)
endfunction
function! ale#c#GetCFlags(buffer, output) abort
return g:get_cflags_return_value
endfunction
call ale#assert#SetUpLinterTest('cpp', 'cc')
let b:command_tail = ' -S -x c++'
\ . ' -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote %s:h'
\ . ' -std=c++14 -Wall -'
After:
unlet! g:get_cflags_return_value
unlet! g:executable_map
unlet! b:command_tail
runtime autoload/ale/c.vim
runtime autoload/ale/engine.vim
call ale#assert#TearDownLinterTest()
Execute(clang++ should be used instead of gcc, if available):
let g:executable_map = {'clang++': 1}
AssertLinter 'clang++', [ale#Escape('clang++') . b:command_tail]
Execute(The executable should be configurable):
AssertLinter 'gcc', [ale#Escape('gcc') . b:command_tail]
let b:ale_cpp_cc_executable = 'foobar'
AssertLinter 'foobar', [ale#Escape('foobar') . b:command_tail]
Execute(The -std flag should be replaced by parsed C flags):
let b:command_tail = substitute(b:command_tail, 'c++14', 'c++11 ', '')
let g:get_cflags_return_value = '-std=c++11'
AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail

View file

@ -1,19 +0,0 @@
Before:
Save g:ale_c_parse_makefile
let g:ale_c_parse_makefile = 0
call ale#assert#SetUpLinterTest('cpp', 'clang')
let b:command_tail = ' -S -x c++ -fsyntax-only -iquote'
\ . ' ' . ale#Escape(getcwd())
\ . ' -std=c++14 -Wall -'
After:
unlet! b:command_tail
call ale#assert#TearDownLinterTest()
Execute(The executable should be configurable):
AssertLinter 'clang++', ale#Escape('clang++') . b:command_tail
let b:ale_cpp_clang_executable = 'foobar'
AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail

View file

@ -1,20 +0,0 @@
Before:
Save g:ale_c_parse_makefile
let g:ale_c_parse_makefile = 0
call ale#assert#SetUpLinterTest('cpp', 'gcc')
let b:command_tail = ' -S -x c++'
\ . ' -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(getcwd())
\ . ' -std=c++14 -Wall -'
After:
unlet! b:command_tail
call ale#assert#TearDownLinterTest()
Execute(The executable should be configurable):
AssertLinter 'gcc', ale#Escape('gcc') . b:command_tail
let b:ale_cpp_gcc_executable = 'foobar'
AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail

View file

@ -8,6 +8,18 @@ After:
call ale#assert#TearDownLinterTest()
Execute(Builds credo command with normal project):
AssertLinter 'mix',
\ ale#path#CdString(ale#path#Simplify(g:dir . '/elixir_paths/mix_project'))
\ . 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s'
Execute(Builds credo command with umbrella project):
call ale#test#SetFilename('elixir_paths/umbrella_project/apps/mix_project/lib/app.ex')
AssertLinter 'mix',
\ ale#path#CdString(ale#path#Simplify(g:dir . '/elixir_paths/umbrella_project'))
\ . 'mix help credo && mix credo suggest --format=flycheck --read-from-stdin %s'
Execute(Builds credo command with --strict mode when set to 1):
let g:ale_elixir_credo_strict = 1

View file

@ -0,0 +1,17 @@
Before:
call ale#assert#SetUpLinterTest('handlebars', 'embertemplatelint')
GivenCommandOutput ['1.6.0']
After:
call ale#assert#TearDownLinterTest()
Execute(ember-template-lint executables runs the right command):
AssertLinter 'ember-template-lint',
\ ale#Escape('ember-template-lint') . ' --json --filename %s'
Execute(old ember-template-lint executables runs the right command):
GivenCommandOutput []
AssertLinter 'ember-template-lint',
\ ale#Escape('ember-template-lint') . ' --json %t'

View file

@ -34,13 +34,52 @@ Execute(The flake8 callbacks should return the correct default values):
\]
Execute(The option for disabling changing directories should work):
let g:ale_python_flake8_change_directory = 0
let g:ale_python_flake8_change_directory = 'off'
AssertLinter 'flake8', [
\ ale#Escape('flake8') . ' --version',
\ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -',
\]
let g:ale_python_flake8_change_directory = 0
AssertLinter 'flake8', [
\ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -',
\]
" Invalid options should be considered the same as turning the setting off.
let g:ale_python_flake8_change_directory = 'xxx'
AssertLinter 'flake8', [
\ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -',
\]
Execute(The option for changing directory to project root should work):
silent execute 'file ' . fnameescape(g:dir . '/python_paths/namespace_package_tox/namespace/foo/bar.py')
AssertLinter 'flake8', [
\ ale#Escape('flake8') . ' --version',
\ ale#path#CdString(ale#python#FindProjectRootIni(bufnr('')))
\ . ale#Escape('flake8') . ' --format=default --stdin-display-name %s -',
\]
Execute(The option for changing directory to file dir should work):
let g:ale_python_flake8_change_directory = 'file'
silent execute 'file ' . fnameescape(g:dir . '/python_paths/namespace_package_tox/namespace/foo/bar.py')
AssertLinter 'flake8', [
\ ale#Escape('flake8') . ' --version',
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('flake8') . ' --format=default --stdin-display-name %s -',
\]
let g:ale_python_flake8_change_directory = 1
AssertLinter 'flake8', [
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('flake8') . ' --format=default --stdin-display-name %s -',
\]
Execute(The flake8 command callback should let you set options):
let g:ale_python_flake8_options = '--some-option'
@ -163,5 +202,5 @@ Execute(Pipenv is detected when python_flake8_auto_pipenv is set):
call ale#test#SetFilename('../python_fixtures/pipenv/whatever.py')
AssertLinter 'pipenv',
\ ale#path#BufferCdString(bufnr(''))
\ ale#path#CdString(ale#python#FindProjectRootIni(bufnr('')))
\ . ale#Escape('pipenv') . ' run flake8 --format=default --stdin-display-name %s -'

View file

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

View file

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

View file

@ -13,7 +13,7 @@ After:
Execute(The golangci-lint defaults should be correct):
AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --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'
AssertLinter 'something else',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('something else')
\ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --enable-all'
@ -31,7 +31,7 @@ Execute(The golangci-lint callback should use configured options):
let b:ale_go_golangci_lint_options = '--foobar'
AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --foobar'
@ -40,7 +40,7 @@ Execute(The golangci-lint callback should support environment variables):
let b:ale_go_go111module = 'on'
AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on')
\ . ale#Escape('golangci-lint')
\ . ' 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
AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint') . ' run --enable-all'

View file

@ -13,7 +13,7 @@ After:
Execute(The gometalinter defaults should be correct):
AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter')
\ . ' --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'
AssertLinter 'something else',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('something else')
\ . ' --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'
AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' --foobar' . ' .'
@ -40,7 +40,7 @@ Execute(The gometalinter should use configured environment variables):
let b:ale_go_go111module = 'off'
AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'off')
\ . ale#Escape('gometalinter')
\ . ' --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
AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h'))
\ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter') . ' .'

View file

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

View file

@ -11,7 +11,8 @@ After:
Execute(The default gotype command should be correct):
AssertLinter 'gotype',
\ ale#path#CdString(expand('%:p:h')) . ' gotype -e .'
\ ale#path#BufferCdString(bufnr(''))
\ . ' gotype -e .'
Execute(The gotype callback should ignore test files):
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'
AssertLinter 'gotype',
\ ale#path#CdString(expand('%:p:h')) . ' '
\ . ale#Env('GO111MODULE', 'on')
\ ale#path#BufferCdString(bufnr(''))
\ . ' ' . ale#Env('GO111MODULE', 'on')
\ . 'gotype -e .'

View file

@ -13,22 +13,22 @@ After:
call ale#assert#TearDownLinterTest()
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):
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):
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):
let b:ale_go_go111module = 'on'
AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) . ' '
\ ale#path#BufferCdString(bufnr('')) . ' '
\ . ale#Env('GO111MODULE', 'on')
\ . 'go vet .'

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