merge master -- apparently someone else added dhall?

This commit is contained in:
toastal
2020-09-08 10:08:00 +07:00
182 changed files with 4228 additions and 2146 deletions
+3
View File
@@ -19,6 +19,9 @@ init:
# Stop git from changing newlines # Stop git from changing newlines
- git config --global core.autocrlf input - git config --global core.autocrlf input
# NOTE: If you change the Vim or Vader versions here, please also update the
# instructions for running tests on Windows in ale-development.txt
install: install:
# Download and unpack Vim # Download and unpack Vim
- ps: >- - ps: >-
+3 -2
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. # Issues in ALE are never, ever stale. They are either resolved or not.
only: pulls only: pulls
daysUntilStale: 28 daysUntilStale: 28
daysUntilClose: 2 daysUntilClose: 7
exemptLabels: [] exemptLabels: []
staleLabel: stale staleLabel: stale
markComment: > markComment: >
+3 -2
View File
@@ -1,11 +1,12 @@
!.editorconfig !.editorconfig
*.obj *.obj
*.pyc
# Ignore all hidden files everywhere. # Ignore all hidden files everywhere.
# Use `git add -f` to add hidden files. # Use `git add -f` to add hidden files.
.* .*
__pycache__
*.pyc
/doc/tags /doc/tags
/init.vim /init.vim
/test/ale-info-test-file /test/ale-info-test-file
/vader_output
__pycache__
tags tags
+12
View File
@@ -79,6 +79,7 @@ other content at [w0rp.com](https://w0rp.com).
17. [How can I configure my C or C++ project?](#faq-c-configuration) 17. [How can I configure my C or C++ project?](#faq-c-configuration)
18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration) 18. [How can I configure ALE differently for different buffers?](#faq-buffer-configuration)
19. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height) 19. [How can I configure the height of the list in which ALE displays errors?](#faq-list-window-height)
20. [How can I run linters or fixers via Docker or a VM?](#faq-vm)
<a name="supported-languages"></a> <a name="supported-languages"></a>
@@ -877,3 +878,14 @@ To set a default height for the error list, use the `g:ale_list_window_size` var
" Show 5 lines of errors (default: 10) " Show 5 lines of errors (default: 10)
let g:ale_list_window_size = 5 let g:ale_list_window_size = 5
``` ```
<a name="faq-vm"></a>
### 5.xx. How can I run linters or fixers via Docker or a VM?
ALE supports running linters or fixers via Docker, virtual machines, or in
combination with any remote machine with a different file system, so long as the
tools are well-integrated with ALE, and ALE is properly configured to run the
correct commands and map filename paths between different file systems. See
`:help ale-lint-other-machines` for the full documentation on how to configure
ALE to support this.
+1 -1
View File
@@ -18,7 +18,7 @@ function! ale_linters#ada#gcc#GetCommand(buffer) abort
" -gnatc: Check syntax and semantics only (no code generation attempted) " -gnatc: Check syntax and semantics only (no code generation attempted)
return '%e -x ada -c -gnatc' return '%e -x ada -c -gnatc'
\ . ' -o ' . ale#Escape(l:out_file) \ . ' -o ' . ale#Escape(l:out_file)
\ . ' -I ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . ' -I %s:h'
\ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options')) \ . ale#Pad(ale#Var(a:buffer, 'ada_gcc_options'))
\ . ' %t' \ . ' %t'
endfunction endfunction
+5
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')
+1 -1
View File
@@ -9,7 +9,7 @@ function! ale_linters#asm#gcc#GetCommand(buffer) abort
" -fsyntax-only doesn't catch everything. " -fsyntax-only doesn't catch everything.
return '%e -x assembler' return '%e -x assembler'
\ . ' -o ' . g:ale#util#nul_file \ . ' -o ' . g:ale#util#nul_file
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . '-iquote %s:h'
\ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -' \ . ' ' . ale#Var(a:buffer, 'asm_gcc_options') . ' -'
endfunction endfunction
+53
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',
\})
-24
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',
\})
-28
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
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',
\})
-24
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',
\})
-29
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',
\})
-3
View File
@@ -5,9 +5,6 @@ call ale#Set('cuda_nvcc_executable', 'nvcc')
call ale#Set('cuda_nvcc_options', '-std=c++11') call ale#Set('cuda_nvcc_options', '-std=c++11')
function! ale_linters#cuda#nvcc#GetCommand(buffer) abort function! ale_linters#cuda#nvcc#GetCommand(buffer) abort
" Unused: use ale#util#nul_file
" let l:output_file = ale#util#Tempname() . '.ii'
" call ale#command#ManageFile(a:buffer, l:output_file)
return '%e -cuda' return '%e -cuda'
\ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer))) \ . ale#Pad(ale#c#IncludeOptions(ale#c#FindLocalHeaderPaths(a:buffer)))
\ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options')) \ . ale#Pad(ale#Var(a:buffer, 'cuda_nvcc_options'))
+1 -1
View File
@@ -46,7 +46,7 @@ function! ale_linters#elixir#credo#GetMode() abort
endfunction endfunction
function! ale_linters#elixir#credo#GetCommand(buffer) abort 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() let l:mode = ale_linters#elixir#credo#GetMode()
return ale#path#CdString(l:project_root) return ale#path#CdString(l:project_root)
+1 -1
View File
@@ -11,7 +11,7 @@ function! ale_linters#eruby#ruumba#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'ruumba') return ale#ruby#EscapeExecutable(l:executable, 'ruumba')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'eruby_ruumba_options') \ . ale#Var(a:buffer, 'eruby_ruumba_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p')) \ . ' --stdin %s'
endfunction endfunction
function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort function! ale_linters#eruby#ruumba#Handle(buffer, lines) abort
-1
View File
@@ -6,7 +6,6 @@ function! ale_linters#go#gofmt#GetCommand(buffer) abort
\ . '%e -e %t' \ . '%e -e %t'
endfunction endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'gofmt', \ 'name': 'gofmt',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
+26 -5
View File
@@ -4,6 +4,28 @@
call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint') call ale#Set('handlebars_embertemplatelint_executable', 'ember-template-lint')
call ale#Set('handlebars_embertemplatelint_use_global', get(g:, 'ale_use_global_executables', 0)) 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 function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
let l:output = [] let l:output = []
let l:json = ale#util#FuzzyJSONDecode(a:lines, {}) let l:json = ale#util#FuzzyJSONDecode(a:lines, {})
@@ -30,10 +52,9 @@ function! ale_linters#handlebars#embertemplatelint#Handle(buffer, lines) abort
endfunction endfunction
call ale#linter#Define('handlebars', { call ale#linter#Define('handlebars', {
\ 'name': 'ember-template-lint', \ 'name': 'embertemplatelint',
\ 'executable': {b -> ale#node#FindExecutable(b, 'handlebars_embertemplatelint', [ \ 'aliases': ['ember-template-lint'],
\ 'node_modules/.bin/ember-template-lint', \ 'executable': function('ale_linters#handlebars#embertemplatelint#GetExecutable'),
\ ])}, \ 'command': function('ale_linters#handlebars#embertemplatelint#GetCommandWithVersionCheck'),
\ 'command': '%e --json %t',
\ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle', \ 'callback': 'ale_linters#handlebars#embertemplatelint#Handle',
\}) \})
+10 -3
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 " 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) 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] return l:files[0]
endif endif
" Search jar file within VSCode extensions folder. " 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) 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] return l:files[0]
endif endif
" Search jar file within system package path " 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) 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] return l:files[0]
endif endif
+12 -1
View File
@@ -1,11 +1,22 @@
" Author: Ty-Lucas Kelley <tylucaskelley@gmail.com> " Author: Ty-Lucas Kelley <tylucaskelley@gmail.com>
" Description: Adds support for markdownlint " 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', { call ale#linter#Define('markdown', {
\ 'name': 'markdownlint', \ 'name': 'markdownlint',
\ 'executable': 'markdownlint', \ 'executable': 'markdownlint',
\ 'lint_file': 1, \ 'lint_file': 1,
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'command': 'markdownlint %s', \ 'command': function('ale_linters#markdown#markdownlint#GetCommand'),
\ 'callback': 'ale#handlers#markdownlint#Handle' \ 'callback': 'ale#handlers#markdownlint#Handle'
\}) \})
+1 -2
View File
@@ -7,10 +7,9 @@ call ale#Set('nasm_nasm_options', '')
function! ale_linters#nasm#nasm#GetCommand(buffer) abort function! ale_linters#nasm#nasm#GetCommand(buffer) abort
" Note that NASM requires a trailing slash for the -I option. " Note that NASM requires a trailing slash for the -I option.
let l:separator = has('win32') ? '\' : '/' let l:separator = has('win32') ? '\' : '/'
let l:path = fnamemodify(bufname(a:buffer), ':p:h') . l:separator
let l:output_null = has('win32') ? 'NUL' : '/dev/null' let l:output_null = has('win32') ? 'NUL' : '/dev/null'
return '%e -X gnu -I ' . ale#Escape(l:path) return '%e -X gnu -I %s:h' . l:separator
\ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options')) \ . ale#Pad(ale#Var(a:buffer, 'nasm_nasm_options'))
\ . ' %s' \ . ' %s'
\ . ' -o ' . l:output_null \ . ' -o ' . l:output_null
+1 -1
View File
@@ -10,7 +10,7 @@ function! ale_linters#objc#clang#GetCommand(buffer) abort
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return 'clang -S -x objective-c -fsyntax-only ' return 'clang -S -x objective-c -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . '-iquote %s:h'
\ . ' ' . ale#Var(a:buffer, 'objc_clang_options') . ' -' \ . ' ' . ale#Var(a:buffer, 'objc_clang_options') . ' -'
endfunction endfunction
+1 -1
View File
@@ -10,7 +10,7 @@ function! ale_linters#objcpp#clang#GetCommand(buffer) abort
" -iquote with the directory the file is in makes #include work for " -iquote with the directory the file is in makes #include work for
" headers in the same directory. " headers in the same directory.
return 'clang++ -S -x objective-c++ -fsyntax-only ' return 'clang++ -S -x objective-c++ -fsyntax-only '
\ . '-iquote ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) \ . '-iquote %s:h'
\ . ' ' . ale#Var(a:buffer, 'objcpp_clang_options') . ' -' \ . ' ' . ale#Var(a:buffer, 'objcpp_clang_options') . ' -'
endfunction endfunction
+1 -1
View File
@@ -9,6 +9,6 @@ call ale#linter#Define('ocaml', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'), \ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'), \ 'command': function('ale#handlers#ols#GetCommand'),
\ 'language_callback': 'ale#handlers#ols#GetLanguage', \ 'language': function('ale#handlers#ols#GetLanguage'),
\ 'project_root': function('ale#handlers#ols#GetProjectRoot'), \ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\}) \})
+5 -5
View File
@@ -1,9 +1,9 @@
" Author: Matt Brown <https://github.com/muglug> " Author: Matt Brown <https://github.com/muglug>
" Description: plugin for Psalm, static analyzer for PHP " Description: plugin for Psalm, static analyzer for PHP
call ale#Set('psalm_langserver_executable', 'psalm') call ale#Set('php_psalm_executable', 'psalm')
call ale#Set('psalm_langserver_options', '') call ale#Set('php_psalm_options', '')
call ale#Set('psalm_langserver_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('php_psalm_use_global', get(g:, 'ale_use_global_executables', 0))
function! ale_linters#php#psalm#GetProjectRoot(buffer) abort function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git') let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
@@ -12,13 +12,13 @@ function! ale_linters#php#psalm#GetProjectRoot(buffer) abort
endfunction endfunction
function! ale_linters#php#psalm#GetCommand(buffer) abort 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 endfunction
call ale#linter#Define('php', { call ale#linter#Define('php', {
\ 'name': 'psalm', \ 'name': 'psalm',
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': {b -> ale#node#FindExecutable(b, 'psalm_langserver', [ \ 'executable': {b -> ale#node#FindExecutable(b, 'php_psalm', [
\ 'vendor/bin/psalm', \ 'vendor/bin/psalm',
\ ])}, \ ])},
\ 'command': function('ale_linters#php#psalm#GetCommand'), \ 'command': function('ale_linters#php#psalm#GetCommand'),
+1 -3
View File
@@ -6,9 +6,7 @@ call ale#Set('pyrex_cython_executable', 'cython')
call ale#Set('pyrex_cython_options', '--warning-extra') call ale#Set('pyrex_cython_options', '--warning-extra')
function! ale_linters#pyrex#cython#GetCommand(buffer) abort function! ale_linters#pyrex#cython#GetCommand(buffer) abort
let l:local_dir = ale#Escape(fnamemodify(bufname(a:buffer), ':p:h')) return '%e --working %s:h --include-dir %s:h'
return '%e --working ' . l:local_dir . ' --include-dir ' . l:local_dir
\ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options')) \ . ale#Pad(ale#Var(a:buffer, 'pyrex_cython_options'))
\ . ' --output-file ' . g:ale#util#nul_file . ' %t' \ . ' --output-file ' . g:ale#util#nul_file . ' %t'
endfunction endfunction
+24 -4
View File
@@ -4,7 +4,7 @@
call ale#Set('python_flake8_executable', 'flake8') call ale#Set('python_flake8_executable', 'flake8')
call ale#Set('python_flake8_options', '') 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_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) call ale#Set('python_flake8_auto_pipenv', 0)
function! s:UsingModule(buffer) abort function! s:UsingModule(buffer) abort
@@ -38,10 +38,30 @@ function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort
\) \)
endfunction 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 function! ale_linters#python#flake8#GetCommand(buffer, version) abort
let l:cd_string = ale#Var(a:buffer, 'python_flake8_change_directory') let l:cd_string = ale_linters#python#flake8#GetCdString(a:buffer)
\ ? ale#path#BufferCdString(a:buffer)
\ : ''
let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer) let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
+3 -5
View File
@@ -16,17 +16,15 @@ function! ale_linters#python#pydocstyle#GetExecutable(buffer) abort
endfunction endfunction
function! ale_linters#python#pydocstyle#GetCommand(buffer) abort function! ale_linters#python#pydocstyle#GetCommand(buffer) abort
let l:dir = fnamemodify(bufname(a:buffer), ':p:h')
let l:executable = ale_linters#python#pydocstyle#GetExecutable(a:buffer) let l:executable = ale_linters#python#pydocstyle#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pydocstyle' \ ? ' run pydocstyle'
\ : '' \ : ''
return ale#path#CdString(l:dir) return ale#path#BufferCdString(a:buffer)
\ . ale#Escape(l:executable) . l:exec_args \ . ale#Escape(l:executable) . l:exec_args
\ . ' ' . ale#Var(a:buffer, 'python_pydocstyle_options') \ . ale#Pad(ale#Var(a:buffer, 'python_pydocstyle_options'))
\ . ' ' . ale#Escape(fnamemodify(bufname(a:buffer), ':p:t')) \ . ' %s:t'
endfunction endfunction
function! ale_linters#python#pydocstyle#Handle(buffer, lines) abort function! ale_linters#python#pydocstyle#Handle(buffer, lines) abort
+1 -1
View File
@@ -9,6 +9,6 @@ call ale#linter#Define('reason', {
\ 'lsp': 'stdio', \ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ols#GetExecutable'), \ 'executable': function('ale#handlers#ols#GetExecutable'),
\ 'command': function('ale#handlers#ols#GetCommand'), \ 'command': function('ale#handlers#ols#GetCommand'),
\ 'language_callback': 'ale#handlers#ols#GetLanguage', \ 'language': function('ale#handlers#ols#GetLanguage'),
\ 'project_root': function('ale#handlers#ols#GetProjectRoot'), \ 'project_root': function('ale#handlers#ols#GetProjectRoot'),
\}) \})
+1 -1
View File
@@ -10,7 +10,7 @@ function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'rubocop') return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_rubocop_options') \ . ale#Var(a:buffer, 'ruby_rubocop_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p')) \ . ' --stdin %s'
endfunction endfunction
function! ale_linters#ruby#rubocop#GetType(severity) abort function! ale_linters#ruby#rubocop#GetType(severity) abort
+1 -1
View File
@@ -11,7 +11,7 @@ function! ale_linters#ruby#standardrb#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'standardrb') return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
\ . ' --format json --force-exclusion ' \ . ' --format json --force-exclusion '
\ . ale#Var(a:buffer, 'ruby_standardrb_options') \ . ale#Var(a:buffer, 'ruby_standardrb_options')
\ . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p')) \ . ' --stdin %s'
endfunction endfunction
" standardrb is based on RuboCop so the callback is the same " standardrb is based on RuboCop so the callback is the same
+1 -1
View File
@@ -1,5 +1,5 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Lints sh files using bash -n " Description: Lints shell files by invoking the shell with -n
" Backwards compatibility " Backwards compatibility
if exists('g:ale_linters_sh_shell_default_shell') if exists('g:ale_linters_sh_shell_default_shell')
+33
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',
\})
+62
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'
\})
+8 -6
View File
@@ -13,14 +13,15 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
"Matches patterns like the following: "Matches patterns like the following:
"** Warning: add.v(7): (vlog-2623) Undefined variable: C. "** Warning: add.v(7): (vlog-2623) Undefined variable: C.
"** Error: file.v(1): (vlog-13294) Identifier must be declared with a port mode: 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 = [] let l:output = []
for l:match in ale#util#GetMatches(a:lines, l:pattern) for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[2] + 0, \ 'lnum': l:match[3] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W', \ 'type': l:match[1] is? 'Error' ? 'E' : 'W',
\ 'text': l:match[3], \ 'text': l:match[4],
\ 'filename': l:match[2],
\}) \})
endfor endfor
@@ -28,13 +29,14 @@ function! ale_linters#verilog#vlog#Handle(buffer, lines) abort
"** Warning: (vlog-2623) add.v(7): Undefined variable: C. "** Warning: (vlog-2623) add.v(7): Undefined variable: C.
"** Error: (vlog-13294) file.v(1): Identifier must be declared with a port mode: 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*\):[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) for l:match in ale#util#GetMatches(a:lines, l:pattern)
call add(l:output, { call add(l:output, {
\ 'lnum': l:match[3] + 0, \ 'lnum': l:match[4] + 0,
\ 'type': l:match[1] is? 'Error' ? 'E' : 'W', \ '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 endfor
+1 -1
View File
@@ -5,7 +5,7 @@
call ale#Set('vim_vint_show_style_issues', 1) call ale#Set('vim_vint_show_style_issues', 1)
call ale#Set('vim_vint_executable', 'vint') call ale#Set('vim_vint_executable', 'vint')
let s:enable_neovim = has('nvim') ? ' --enable-neovim' : '' 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 function! ale_linters#vim#vint#GetCommand(buffer, version) abort
let l:can_use_no_color_flag = empty(a:version) let l:can_use_no_color_flag = empty(a:version)
+22
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') let l:msg = substitute(l:msg, '\V%linter%', '\=l:linter_name', 'g')
" Replace %s with the text. " Replace %s with the text.
let l:msg = substitute(l:msg, '\V%s', '\=a:item.text', 'g') 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 return l:msg
endfunction endfunction
" Given a buffer and a linter or fixer name, return an Array of two-item
" Arrays describing how to map filenames to and from the local to foreign file
" systems.
function! ale#GetFilenameMappings(buffer, name) abort
let l:linter_mappings = ale#Var(a:buffer, 'filename_mappings')
if type(l:linter_mappings) is v:t_list
return l:linter_mappings
endif
let l:name = a:name
if !has_key(l:linter_mappings, l:name)
" Use * as a default setting for all tools.
let l:name = '*'
endif
return get(l:linter_mappings, l:name, [])
endfunction
+1 -1
View File
@@ -130,7 +130,7 @@ endfunction
function! ale#assert#LSPLanguage(expected_language) abort function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:linter = s:GetLinter() 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 AssertEqual a:expected_language, l:language
endfunction endfunction
+203 -52
View File
@@ -2,12 +2,27 @@
" Description: Functions for integrating with C-family linters. " Description: Functions for integrating with C-family linters.
call ale#Set('c_parse_makefile', 0) 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) call ale#Set('c_parse_compile_commands', 1)
let s:sep = has('win32') ? '\' : '/' let s:sep = has('win32') ? '\' : '/'
" Set just so tests can override it. " Set just so tests can override it.
let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt'] let g:__ale_c_project_filenames = ['.git/HEAD', 'configure', 'Makefile', 'CMakeLists.txt']
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])
function! s:CanParseMakefile(buffer) abort
" 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 function! ale#c#GetBuildDirectory(buffer) abort
let l:build_dir = ale#Var(a:buffer, 'c_build_dir') let l:build_dir = ale#Var(a:buffer, 'c_build_dir')
@@ -61,14 +76,73 @@ function! ale#c#ShellSplit(line) abort
return l:args return l:args
endfunction endfunction
function! ale#c#ParseCFlags(path_prefix, cflag_line) abort " Takes the path prefix and a list of cflags and expands @file arguments to
let l:cflags_list = [] " 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 let l:option_index = 0
while l:option_index < len(l:split_lines) while l:option_index < len(l:arguments)
let l:option = l:split_lines[l:option_index] let l:option = l:arguments[l:option_index]
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
" Include options, that may need relative path fix " Include options, that may need relative path fix
@@ -76,56 +150,67 @@ function! ale#c#ParseCFlags(path_prefix, cflag_line) abort
\ || stridx(l:option, '-iquote') == 0 \ || stridx(l:option, '-iquote') == 0
\ || stridx(l:option, '-isystem') == 0 \ || stridx(l:option, '-isystem') == 0
\ || stridx(l:option, '-idirafter') == 0 \ || stridx(l:option, '-idirafter') == 0
\ || stridx(l:option, '-iframework') == 0
\ || stridx(l:option, '-include') == 0
if stridx(l:option, '-I') == 0 && l:option isnot# '-I' if stridx(l:option, '-I') == 0 && l:option isnot# '-I'
let l:arg = join(split(l:option, '\zs')[2:], '') let l:arg = join(split(l:option, '\zs')[2:], '')
let l:option = '-I' let l:option = '-I'
else else
let l:arg = l:split_lines[l:option_index] let l:arg = l:arguments[l:option_index]
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
endif endif
" Fix relative paths if needed " Fix relative paths if needed
if stridx(l:arg, s:sep) != 0 && stridx(l:arg, '/') != 0 if !ale#path#IsAbsolute(l:arg)
let l:rel_path = substitute(l:arg, '"', '', 'g') let l:rel_path = substitute(l:arg, '"', '', 'g')
let l:rel_path = substitute(l:rel_path, '''', '', 'g') let l:rel_path = substitute(l:rel_path, '''', '', 'g')
let l:arg = ale#Escape(a:path_prefix . s:sep . l:rel_path) let l:arg = ale#path#GetAbsPath(a:path_prefix, l:rel_path)
endif endif
call add(l:cflags_list, l:option) call add(l:items, [1, l:option])
call add(l:cflags_list, l:arg) call add(l:items, [1, ale#Escape(l:arg)])
" Options with arg that can be grouped with the option or separate " Options with arg that can be grouped with the option or separate
elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0 elseif stridx(l:option, '-D') == 0 || stridx(l:option, '-B') == 0
call add(l:cflags_list, l:option)
if l:option is# '-D' || l:option is# '-B' if l:option is# '-D' || l:option is# '-B'
call add(l:cflags_list, l:split_lines[l:option_index]) call add(l:items, [1, l:option])
call add(l:items, [0, l:arguments[l:option_index]])
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
else
call add(l:items, [0, l:option])
endif endif
" Options that have an argument (always separate) " Options that have an argument (always separate)
elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0 elseif l:option is# '-iprefix' || stridx(l:option, '-iwithprefix') == 0
\ || l:option is# '-isysroot' || l:option is# '-imultilib' \ || l:option is# '-isysroot' || l:option is# '-imultilib'
call add(l:cflags_list, l:option) call add(l:items, [0, l:option])
call add(l:cflags_list, l:split_lines[l:option_index]) call add(l:items, [0, l:arguments[l:option_index]])
let l:option_index = l:option_index + 1 let l:option_index = l:option_index + 1
" Options without argument " Options without argument
elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0) elseif (stridx(l:option, '-W') == 0 && stridx(l:option, '-Wa,') != 0 && stridx(l:option, '-Wl,') != 0 && stridx(l:option, '-Wp,') != 0)
\ || l:option is# '-w' || stridx(l:option, '-pedantic') == 0 \ || l:option is# '-w' || stridx(l:option, '-pedantic') == 0
\ || l:option is# '-ansi' || stridx(l:option, '-std=') == 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 \ || stridx(l:option, '-O') == 0
\ || l:option is# '-C' || l:option is# '-CC' || l:option is# '-trigraphs' \ || 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, '-nostdinc') == 0 || stridx(l:option, '-iplugindir=') == 0
\ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix' \ || stridx(l:option, '--sysroot=') == 0 || l:option is# '--no-sysroot-suffix'
\ || stridx(l:option, '-m') == 0 \ || stridx(l:option, '-m') == 0
call add(l:cflags_list, l:option) call add(l:items, [0, l:option])
endif endif
endwhile endwhile
return join(l:cflags_list, ' ') if a:should_quote
" Quote C arguments that haven't already been quoted above.
" If and only if we've been asked to quote them.
call map(l:items, 'v:val[0] ? v:val[1] : ale#c#QuoteArg(v:val[1])')
else
call map(l:items, 'v:val[1]')
endif
return join(l:items, ' ')
endfunction endfunction
function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort function! ale#c#ParseCFlagsFromMakeOutput(buffer, make_output) abort
if !g:ale_c_parse_makefile if !s:CanParseMakefile(a:buffer)
return v:null return v:null
endif 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_path = ale#path#FindNearestFile(a:buffer, 'Makefile')
let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h') let l:makefile_dir = fnamemodify(l:makefile_path, ':p:h')
return ale#c#ParseCFlags(l:makefile_dir, l:cflag_line) return ale#c#ParseCFlags(l:makefile_dir, 0, ale#c#ShellSplit(l:cflag_line))
endfunction endfunction
" Given a buffer number, find the project directory containing " Given a buffer number, find the project directory containing
@@ -211,6 +296,10 @@ if !exists('s:compile_commands_cache')
let s:compile_commands_cache = {} let s:compile_commands_cache = {}
endif endif
function! ale#c#ResetCompileCommandsCache() abort
let s:compile_commands_cache = {}
endfunction
function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:empty = [{}, {}] let l:empty = [{}, {}]
@@ -241,9 +330,20 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
let l:dir_lookup = {} let l:dir_lookup = {}
for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : []) for l:entry in (type(l:raw_data) is v:t_list ? l:raw_data : [])
let l:filename = ale#path#GetAbsPath(l:entry.directory, l:entry.file)
" Store a key for lookups by the absolute path to the filename.
let l:file_lookup[l:filename] = get(l:file_lookup, l:filename, []) + [l:entry]
" Store a key for fuzzy lookups by the absolute path to the directory.
let l:dirname = fnamemodify(l:filename, ':h')
let l:dir_lookup[l:dirname] = get(l:dir_lookup, l:dirname, []) + [l:entry]
" Store a key for fuzzy lookups by just the basename of the file.
let l:basename = tolower(fnamemodify(l:entry.file, ':t')) let l:basename = tolower(fnamemodify(l:entry.file, ':t'))
let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry] let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry]
" Store a key for fuzzy lookups by just the basename of the directory.
let l:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t')) let l:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t'))
let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry] let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:dirbasename, []) + [l:entry]
endfor endfor
@@ -258,28 +358,80 @@ function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort
return l:empty return l:empty
endfunction endfunction
function! ale#c#GetCompileCommand(json_item) abort " Get [should_quote, arguments] from either 'command' or 'arguments'
if has_key(a:json_item, 'command') " 'arguments' should be quoted later, the split 'command' strings should not.
return a:json_item.command function! s:GetArguments(json_item) abort
elseif has_key(a:json_item, 'arguments') if has_key(a:json_item, 'arguments')
return join(a:json_item.arguments, ' ') return [1, a:json_item.arguments]
elseif has_key(a:json_item, 'command')
return [0, ale#c#ShellSplit(a:json_item.command)]
endif endif
return '' return [0, []]
endfunction endfunction
function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
let l:buffer_filename = ale#path#Simplify(expand('#' . a:buffer . ':p'))
let l:basename = tolower(fnamemodify(l:buffer_filename, ':t'))
" Look for any file in the same directory if we can't find an exact match.
let l:dir = fnamemodify(l:buffer_filename, ':h')
" Search for an exact file match first. " Search for an exact file match first.
let l:basename = tolower(expand('#' . a:buffer . ':t')) let l:file_list = get(a:file_lookup, l:buffer_filename, [])
let l:file_list = get(a:file_lookup, l:basename, [])
" 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. " A source file matching the header filename.
let l:source_file = '' let l:source_file = ''
if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$' if empty(l:file_list) && l:basename =~? '\.h$\|\.hpp$'
for l:suffix in ['.c', '.cpp'] for l:suffix in ['.c', '.cpp']
let l:key = fnamemodify(l:basename, ':r') . l:suffix " 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, []) 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) if !empty(l:file_list)
let l:source_file = l:key let l:source_file = l:key
break break
@@ -288,28 +440,31 @@ function! ale#c#ParseCompileCommandsFlags(buffer, file_lookup, dir_lookup) abort
endif endif
for l:item in l:file_list for l:item in l:file_list
let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
" Load the flags for this file, or for a source file matching the " Load the flags for this file, or for a source file matching the
" header file. " header file.
if ( if (
\ bufnr(l:item.file) is a:buffer \ bufnr(l:filename) is a:buffer
\ || ( \ || (
\ !empty(l:source_file) \ !empty(l:source_file)
\ && l:item.file[-len(l:source_file):] is? l:source_file \ && l:filename[-len(l:source_file):] is? l:source_file
\ ) \ )
\) \)
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item)) let [l:should_quote, l:args] = s:GetArguments(l:item)
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
endif endif
endfor endfor
" Look for any file in the same directory if we can't find an exact match.
let l:dir = ale#path#Simplify(expand('#' . a:buffer . ':p:h'))
let l:dirbasename = tolower(expand('#' . a:buffer . ':p:h:t'))
let l:dir_list = get(a:dir_lookup, l:dirbasename, [])
for l:item in l:dir_list for l:item in l:dir_list
if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir let l:filename = ale#path#GetAbsPath(l:item.directory, l:item.file)
return ale#c#ParseCFlags(l:item.directory, ale#c#GetCompileCommand(l:item))
if ale#path#RemoveDriveLetter(fnamemodify(l:filename, ':h'))
\ is? ale#path#RemoveDriveLetter(l:dir)
let [l:should_quote, l:args] = s:GetArguments(l:item)
return ale#c#ParseCFlags(l:item.directory, l:should_quote, l:args)
endif endif
endfor endfor
@@ -335,9 +490,7 @@ function! ale#c#GetCFlags(buffer, output) abort
endif endif
endif endif
if ale#Var(a:buffer, 'c_parse_makefile') if s:CanParseMakefile(a:buffer) && !empty(a:output) && !empty(l:cflags)
\&& !empty(a:output)
\&& !empty(l:cflags)
let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output) let l:cflags = ale#c#ParseCFlagsFromMakeOutput(a:buffer, a:output)
endif endif
@@ -349,11 +502,14 @@ function! ale#c#GetCFlags(buffer, output) abort
endfunction endfunction
function! ale#c#GetMakeCommand(buffer) abort function! ale#c#GetMakeCommand(buffer) abort
if ale#Var(a:buffer, 'c_parse_makefile') if s:CanParseMakefile(a:buffer)
let l:makefile_path = ale#path#FindNearestFile(a:buffer, 'Makefile') let l:path = ale#path#FindNearestFile(a:buffer, 'Makefile')
if !empty(l:makefile_path) if !empty(l:path)
return 'cd '. fnamemodify(l:makefile_path, ':p:h') . ' && make -n' 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
endif endif
@@ -422,8 +578,3 @@ function! ale#c#IncludeOptions(include_paths) abort
return join(l:option_list) return join(l:option_list)
endfunction endfunction
let g:ale_c_build_dir_names = get(g:, 'ale_c_build_dir_names', [
\ 'build',
\ 'bin',
\])
+38 -1
View File
@@ -24,6 +24,42 @@ function! ale#code_action#HandleCodeAction(code_action, should_save) abort
endfor endfor
endfunction 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 function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
let l:current_buffer = bufnr('') let l:current_buffer = bufnr('')
" The buffer is used to determine the fileformat, if available. " 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:column_offset = 0
let l:last_end_line = 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 if l:code_edit.start.line isnot l:last_end_line
let l:column_offset = 0 let l:column_offset = 0
endif endif
+39 -3
View File
@@ -133,11 +133,36 @@ function! ale#command#EscapeCommandPart(command_part) abort
return substitute(a:command_part, '%', '%%', 'g') return substitute(a:command_part, '%', '%%', 'g')
endfunction endfunction
" Format a filename, converting it with filename mappings, if non-empty,
" and escaping it for putting into a command string.
"
" The filename can be modified.
function! s:FormatFilename(filename, mappings, modifiers) abort
let l:filename = a:filename
if !empty(a:mappings)
let l:filename = ale#filename_mapping#Map(l:filename, a:mappings)
endif
if !empty(a:modifiers)
let l:filename = fnamemodify(l:filename, a:modifiers)
endif
return ale#Escape(l:filename)
endfunction
" Given a command string, replace every... " Given a command string, replace every...
" %s -> with the current filename " %s -> with the current filename
" %t -> with the name of an unused file in a temporary directory " %t -> with the name of an unused file in a temporary directory
" %% -> with a literal % " %% -> with a literal %
function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_needed, input) abort function! ale#command#FormatCommand(
\ buffer,
\ executable,
\ command,
\ pipe_file_if_needed,
\ input,
\ mappings,
\) abort
let l:temporary_file = '' let l:temporary_file = ''
let l:command = a:command let l:command = a:command
@@ -154,14 +179,24 @@ function! ale#command#FormatCommand(buffer, executable, command, pipe_file_if_ne
" file. " file.
if l:command =~# '%s' if l:command =~# '%s'
let l:filename = fnamemodify(bufname(a:buffer), ':p') let l:filename = fnamemodify(bufname(a:buffer), ':p')
let l:command = substitute(l:command, '%s', '\=ale#Escape(l:filename)', 'g') let l:command = substitute(
\ l:command,
\ '\v\%s(%(:h|:t|:r|:e)*)',
\ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))',
\ 'g'
\)
endif endif
if a:input isnot v:false && l:command =~# '%t' if a:input isnot v:false && l:command =~# '%t'
" Create a temporary filename, <temp_dir>/<original_basename> " Create a temporary filename, <temp_dir>/<original_basename>
" The file itself will not be created by this function. " The file itself will not be created by this function.
let l:temporary_file = s:TemporaryFilename(a:buffer) let l:temporary_file = s:TemporaryFilename(a:buffer)
let l:command = substitute(l:command, '%t', '\=ale#Escape(l:temporary_file)', 'g') let l:command = substitute(
\ l:command,
\ '\v\%t(%(:h|:t|:r|:e)*)',
\ '\=s:FormatFilename(l:temporary_file, a:mappings, submatch(1))',
\ 'g'
\)
endif endif
" Finish formatting so %% becomes %. " Finish formatting so %% becomes %.
@@ -265,6 +300,7 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
\ a:command, \ a:command,
\ get(l:options, 'read_buffer', 0), \ get(l:options, 'read_buffer', 0),
\ get(l:options, 'input', v:null), \ get(l:options, 'input', v:null),
\ get(l:options, 'filename_mappings', []),
\) \)
let l:command = ale#job#PrepareCommand(a:buffer, l:command) let l:command = ale#job#PrepareCommand(a:buffer, l:command)
let l:job_options = { let l:job_options = {
+195 -59
View File
@@ -5,7 +5,7 @@ scriptencoding utf-8
" The omnicompletion menu is shown through a special Plug mapping which is " 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 " only valid in Insert mode. This way, feedkeys() won't send these keys if you
" quit Insert mode quickly enough. " 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 " 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. " we should restore the old settings right away.
nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR> nnoremap <silent> <Plug>(ale_show_completion_menu) :call ale#completion#RestoreCompletionOptions()<CR>
@@ -188,7 +188,13 @@ function! ale#completion#GetTriggerCharacter(filetype, prefix) abort
return '' return ''
endfunction 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') let l:excluded_words = ale#Var(a:buffer, 'completion_excluded_words')
if empty(a:prefix) if empty(a:prefix)
@@ -215,10 +221,17 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
" Dictionaries is accepted here. " Dictionaries is accepted here.
let l:word = type(l:item) is v:t_string ? l:item : l:item.word let l:word = type(l:item) is v:t_string ? l:item : l:item.word
" Add suggestions if the suggestion starts with a if a:exact_prefix_match
" case-insensitive match for the prefix. " Add suggestions if the word is an exact match.
if l:word[: len(a:prefix) - 1] is? a:prefix if l:word is# a:prefix
call add(l:filtered_suggestions, l:item) 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 endif
endfor endfor
endif endif
@@ -241,21 +254,17 @@ function! ale#completion#Filter(buffer, filetype, suggestions, prefix) abort
return l:filtered_suggestions return l:filtered_suggestions
endfunction endfunction
function! s:ReplaceCompletionOptions() abort function! s:ReplaceCompletionOptions(source) abort
let l:source = get(get(b:, 'ale_completion_info', {}), 'source', '') " Remember the old omnifunc value, if there is one.
" If we don't store an old one, we'll just never reset the option.
if l:source is# 'ale-automatic' || l:source is# 'ale-manual' " This will stop some random exceptions from appearing.
" Remember the old omnifunc value, if there is one. if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
" If we don't store an old one, we'll just never reset the option. let b:ale_old_omnifunc = &l:omnifunc
" This will stop some random exceptions from appearing.
if !exists('b:ale_old_omnifunc') && !empty(&l:omnifunc)
let b:ale_old_omnifunc = &l:omnifunc
endif
let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
endif endif
if l:source is# 'ale-automatic' let &l:omnifunc = 'ale#completion#AutomaticOmniFunc'
if a:source is# 'ale-automatic'
if !exists('b:ale_old_completeopt') if !exists('b:ale_old_completeopt')
let b:ale_old_completeopt = &l:completeopt let b:ale_old_completeopt = &l:completeopt
endif endif
@@ -318,41 +327,70 @@ function! ale#completion#AutomaticOmniFunc(findstart, base) abort
else else
let l:result = ale#completion#GetCompletionResult() 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 : [] return l:result isnot v:null ? l:result : []
endif endif
endfunction 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 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 return
endif endif
" Set the list in the buffer, temporarily replace omnifunc with our " Set the list in the buffer.
" function, and then start omni-completion.
let b:ale_completion_result = a:result let b:ale_completion_result = a:result
" Don't try to open the completion menu if there's nothing to show. " Don't try to open the completion menu if there's nothing to show.
if empty(b:ale_completion_result) 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 return
endif endif
" Replace completion options shortly before opening the menu. " 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' if l:source is# 'ale-automatic' || l:source is# 'ale-manual'
call timer_start( call s:ReplaceCompletionOptions(l:source)
\ 0,
\ {-> ale#util#FeedKeys("\<Plug>(ale_show_completion_menu)")} call timer_start(0, function('s:OpenCompletionMenu'))
\)
endif endif
if l:source is# 'ale-callback' if l:source is# 'ale-callback'
call b:CompleteCallback(b:ale_completion_result) call b:CompleteCallback(b:ale_completion_result)
endif 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 endfunction
function! ale#completion#GetAllTriggers() abort function! ale#completion#GetAllTriggers() abort
@@ -383,14 +421,18 @@ endfunction
function! s:CompletionStillValid(request_id) abort function! s:CompletionStillValid(request_id) abort
let [l:line, l:column] = getpos('.')[1:2] let [l:line, l:column] = getpos('.')[1:2]
return ale#util#Mode() is# 'i' return has_key(b:, 'ale_completion_info')
\&& 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.request_id == a:request_id
\&& b:ale_completion_info.line == l:line \&& b:ale_completion_info.line == l:line
\&& ( \&& (
\ b:ale_completion_info.column == l:column \ b:ale_completion_info.column == l:column
\ || b:ale_completion_info.source is# 'ale-omnifunc' \ || b:ale_completion_info.source is# 'ale-omnifunc'
\ || b:ale_completion_info.source is# 'ale-callback' \ || b:ale_completion_info.source is# 'ale-callback'
\ || b:ale_completion_info.source is# 'ale-import'
\) \)
endfunction endfunction
@@ -415,15 +457,26 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:results = [] let l:results = []
let l:names_with_details = [] let l:names_with_details = []
let l:info = get(b:, 'ale_completion_info', {})
for l:suggestion in a:response.body for l:suggestion in a:response.body
let l:displayParts = [] let l:displayParts = []
let l:local_name = v:null
for l:action in get(l:suggestion, 'codeActions', []) for l:action in get(l:suggestion, 'codeActions', [])
call add(l:displayParts, l:action.description . ' ') call add(l:displayParts, l:action.description . ' ')
endfor endfor
for l:part in l:suggestion.displayParts 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) call add(l:displayParts, l:part.text)
endfor endfor
@@ -436,11 +489,18 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
" See :help complete-items " See :help complete-items
let l:result = { 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), \ 'kind': ale#completion#GetCompletionSymbols(l:suggestion.kind),
\ 'icase': 1, \ 'icase': 1,
\ 'menu': join(l:displayParts, ''), \ '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, ''), \ 'info': join(l:documentationParts, ''),
\} \}
@@ -450,7 +510,12 @@ function! ale#completion#ParseTSServerCompletionEntryDetails(response) abort
\ }) \ })
endif endif
call add(l:results, l:result) " 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 endfor
let l:names = getbufvar(l:buffer, 'ale_tsserver_completion_names', []) 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 " Don't use LSP items with additional text edits when autoimport for
" completions is turned off. " completions is turned off.
if has_key(l:item, 'additionalTextEdits') && !g:ale_completion_autoimport if !empty(get(l:item, 'additionalTextEdits'))
\&& !(
\ get(l:info, 'additional_edits_only', 0)
\ || g:ale_completion_autoimport
\)
continue continue
endif endif
@@ -546,38 +615,50 @@ function! ale#completion#ParseLSPCompletions(response) abort
let l:text_changes = [] let l:text_changes = []
for l:edit in l:item.additionalTextEdits for l:edit in l:item.additionalTextEdits
let l:range = l:edit.range
call add(l:text_changes, { call add(l:text_changes, {
\ 'start': { \ 'start': {
\ 'line': l:range.start.line + 1, \ 'line': l:edit.range.start.line + 1,
\ 'offset': l:range.start.character + 1, \ 'offset': l:edit.range.start.character + 1,
\ }, \ },
\ 'end': { \ 'end': {
\ 'line': l:range.end.line + 1, \ 'line': l:edit.range.end.line + 1,
\ 'offset': l:range.end.character + 1, \ 'offset': l:edit.range.end.character + 1,
\ }, \ },
\ 'newText': l:edit.newText, \ 'newText': l:edit.newText,
\}) \})
endfor endfor
let l:changes = [{ if !empty(l:text_changes)
\ 'fileName': expand('#' . l:buffer . ':p'), let l:result.user_data = json_encode({
\ 'textChanges': l:text_changes, \ 'codeActions': [{
\}] \ 'description': 'completion',
\ \ 'changes': [
let l:result.user_data = json_encode({ \ {
\ 'codeActions': [{ \ 'fileName': expand('#' . l:buffer . ':p'),
\ 'description': 'completion', \ 'textChanges': l:text_changes,
\ 'changes': l:changes, \ }
\ }], \ ],
\ }) \ }],
\})
endif
endif endif
call add(l:results, l:result) " 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 endfor
if has_key(l:info, 'prefix') 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 endif
return l:results[: g:ale_completion_max_suggestions - 1] return l:results[: g:ale_completion_max_suggestions - 1]
@@ -601,13 +682,18 @@ function! ale#completion#HandleTSServerResponse(conn_id, response) abort
\ &filetype, \ &filetype,
\ ale#completion#ParseTSServerCompletions(a:response), \ ale#completion#ParseTSServerCompletions(a:response),
\ b:ale_completion_info.prefix, \ b:ale_completion_info.prefix,
\ get(b:ale_completion_info, 'additional_edits_only', 0),
\)[: g:ale_completion_max_suggestions - 1] \)[: g:ale_completion_max_suggestions - 1]
" We need to remember some names for tsserver, as it doesn't send " We need to remember some names for tsserver, as it doesn't send
" details back for everything we send. " details back for everything we send.
call setbufvar(l:buffer, 'ale_tsserver_completion_names', l:names) 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 = [] let l:identifiers = []
for l:name in l:names 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.line,
\ b:ale_completion_info.column, \ b:ale_completion_info.column,
\ b:ale_completion_info.prefix, \ b:ale_completion_info.prefix,
\ g:ale_completion_autoimport, \ get(b:ale_completion_info, 'additional_edits_only', 0)
\ || g:ale_completion_autoimport,
\) \)
else else
" Send a message saying the buffer has changed first, otherwise " Send a message saying the buffer has changed first, otherwise
@@ -740,9 +827,19 @@ function! ale#completion#GetCompletions(...) abort
let b:CompleteCallback = l:CompleteCallback let b:CompleteCallback = l:CompleteCallback
endif endif
let [l:line, l:column] = getpos('.')[1:2] 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
let l:prefix = ale#completion#GetPrefix(&filetype, l:line, l:column) 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) if l:source is# 'ale-automatic' && empty(l:prefix)
return 0 return 0
@@ -761,6 +858,11 @@ function! ale#completion#GetCompletions(...) abort
\} \}
unlet! b:ale_completion_result 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:buffer = bufnr('')
let l:Callback = function('s:OnReady') let l:Callback = function('s:OnReady')
@@ -777,6 +879,37 @@ function! ale#completion#GetCompletions(...) abort
return l:started return l:started
endfunction 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 function! ale#completion#OmniFunc(findstart, base) abort
if a:findstart if a:findstart
let l:started = ale#completion#GetCompletions('ale-omnifunc') 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' if l:source isnot# 'ale-automatic'
\&& l:source isnot# 'ale-manual' \&& l:source isnot# 'ale-manual'
\&& l:source isnot# 'ale-callback' \&& l:source isnot# 'ale-callback'
\&& l:source isnot# 'ale-import'
return return
endif endif
@@ -884,6 +1018,8 @@ function! ale#completion#Done() abort
endfunction endfunction
augroup ALECompletionActions augroup ALECompletionActions
autocmd!
autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item) autocmd CompleteDone * call ale#completion#HandleUserData(v:completed_item)
augroup END augroup END
+2
View File
@@ -39,6 +39,8 @@ function! ale#cursor#TruncatedEcho(original_message) abort
endif endif
exec 'echomsg l:message' exec 'echomsg l:message'
catch /E481/
" Do nothing if running from a visual selection.
endtry endtry
" Reset the cursor position if we moved off the end of the line. " Reset the cursor position if we moved off the end of the line.
-8
View File
@@ -135,10 +135,6 @@ function! s:GoToLSPDefinition(linter, options, capability) abort
endfunction endfunction
function! ale#definition#GoTo(options) abort 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) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
call s:GoToLSPDefinition(l:linter, a:options, 'definition') call s:GoToLSPDefinition(l:linter, a:options, 'definition')
@@ -147,10 +143,6 @@ function! ale#definition#GoTo(options) abort
endfunction endfunction
function! ale#definition#GoToType(options) abort 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) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
" TODO: handle typeDefinition for tsserver if supported by the " TODO: handle typeDefinition for tsserver if supported by the
+111 -151
View File
@@ -4,6 +4,7 @@
" Remapping of linter problems. " Remapping of linter problems.
let g:ale_type_map = get(g:, 'ale_type_map', {}) let g:ale_type_map = get(g:, 'ale_type_map', {})
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
if !has_key(s:, 'executable_cache_map') if !has_key(s:, 'executable_cache_map')
let s:executable_cache_map = {} let s:executable_cache_map = {}
@@ -104,42 +105,6 @@ function! ale#engine#IsCheckingBuffer(buffer) abort
\ || !empty(get(l:info, 'active_other_sources_list', [])) \ || !empty(get(l:info, 'active_other_sources_list', []))
endfunction 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 function! ale#engine#HandleLoclist(linter_name, buffer, loclist, from_other_source) abort
let l:info = get(g:ale_buffer_info, a:buffer, {}) 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:linter = a:job_info.linter
let l:executable = a:job_info.executable let l:executable = a:job_info.executable
let l:next_chain_index = a:job_info.next_chain_index
" Remove this job from the list. " Remove this job from the list.
call ale#engine#MarkLinterInactive(l:buffer_info, l:linter.name) 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) call remove(a:output, -1)
endif 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 try
let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output) let l:loclist = ale#util#GetFunction(l:linter.callback)(a:buffer, a:output)
" Handle the function being unknown, or being deleted. " Handle the function being unknown, or being deleted.
@@ -307,6 +257,13 @@ function! s:RemapItemTypes(type_map, loclist) abort
endfunction endfunction
function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist) abort
let l:mappings = ale#GetFilenameMappings(a:buffer, a:linter_name)
if !empty(l:mappings)
" We need to apply reverse filename mapping here.
let l:mappings = ale#filename_mapping#Invert(l:mappings)
endif
let l:bufnr_map = {} let l:bufnr_map = {}
let l:new_loclist = [] let l:new_loclist = []
@@ -347,13 +304,19 @@ function! ale#engine#FixLocList(buffer, linter_name, from_other_source, loclist)
let l:item.code = l:old_item.code let l:item.code = l:old_item.code
endif endif
if has_key(l:old_item, 'filename') let l:old_name = get(l:old_item, 'filename', '')
\&& !ale#path#IsTempName(l:old_item.filename)
" Map parsed from output to local filesystem files.
if !empty(l:old_name) && !empty(l:mappings)
let l:old_name = ale#filename_mapping#Map(l:old_name, l:mappings)
endif
if !empty(l:old_name) && !ale#path#IsTempName(l:old_name)
" Use the filename given. " Use the filename given.
" Temporary files are assumed to be for this buffer, " Temporary files are assumed to be for this buffer,
" and the filename is not included then, because it looks bad " and the filename is not included then, because it looks bad
" in the loclist window. " in the loclist window.
let l:filename = l:old_item.filename let l:filename = l:old_name
let l:item.filename = l:filename let l:item.filename = l:filename
if has_key(l:old_item, 'bufnr') if has_key(l:old_item, 'bufnr')
@@ -454,20 +417,19 @@ function! s:RunJob(command, options) abort
let l:buffer = a:options.buffer let l:buffer = a:options.buffer
let l:linter = a:options.linter let l:linter = a:options.linter
let l:output_stream = a:options.output_stream let l:output_stream = a:options.output_stream
let l:next_chain_index = a:options.next_chain_index let l:read_buffer = a:options.read_buffer && !a:options.lint_file
let l:read_buffer = a:options.read_buffer
let l:info = g:ale_buffer_info[l:buffer] let l:info = g:ale_buffer_info[l:buffer]
let l:Callback = function('s:HandleExit', [{ let l:Callback = function('s:HandleExit', [{
\ 'linter': l:linter, \ 'linter': l:linter,
\ 'executable': l:executable, \ 'executable': l:executable,
\ 'next_chain_index': l:next_chain_index,
\}]) \}])
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, { let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
\ 'output_stream': l:output_stream, \ 'output_stream': l:output_stream,
\ 'executable': l:executable, \ 'executable': l:executable,
\ 'read_buffer': l:read_buffer, \ '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. " Only proceed if the job is being run.
@@ -482,68 +444,6 @@ function! s:RunJob(command, options) abort
return 1 return 1
endfunction 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 function! s:StopCurrentJobs(buffer, clear_lint_file_jobs) abort
let l:info = get(g:ale_buffer_info, a:buffer, {}) let l:info = get(g:ale_buffer_info, a:buffer, {})
call ale#command#StopJobs(a:buffer, 'linter') call ale#command#StopJobs(a:buffer, 'linter')
@@ -608,10 +508,15 @@ function! s:AddProblemsFromOtherBuffers(buffer, linters) abort
endif endif
endfunction endfunction
function! s:RunIfExecutable(buffer, linter, executable) abort function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
if ale#command#IsDeferred(a:executable) if ale#command#IsDeferred(a:executable)
let a:executable.result_callback = { let a:executable.result_callback = {
\ executable -> s:RunIfExecutable(a:buffer, a:linter, executable) \ executable -> s:RunIfExecutable(
\ a:buffer,
\ a:linter,
\ a:lint_file,
\ executable
\ )
\} \}
return 1 return 1
@@ -619,29 +524,17 @@ function! s:RunIfExecutable(buffer, linter, executable) abort
if ale#engine#IsExecutable(a:buffer, a:executable) if ale#engine#IsExecutable(a:buffer, a:executable)
" Use different job types for file or linter jobs. " Use different job types for file or linter jobs.
let l:job_type = a:linter.lint_file ? 'file_linter' : 'linter' let l:job_type = a:lint_file ? 'file_linter' : 'linter'
call setbufvar(a:buffer, 'ale_job_type', l:job_type) call setbufvar(a:buffer, 'ale_job_type', l:job_type)
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:command = ale#linter#GetCommand(a:buffer, a:linter)
let l:options = { let l:options = {
\ 'executable': a:executable, \ 'executable': a:executable,
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'linter': a:linter, \ 'linter': a:linter,
\ 'output_stream': get(a:linter, 'output_stream', 'stdout'), \ 'output_stream': get(a:linter, 'output_stream', 'stdout'),
\ 'next_chain_index': 1,
\ 'read_buffer': a:linter.read_buffer, \ 'read_buffer': a:linter.read_buffer,
\ 'lint_file': a:lint_file,
\} \}
return s:RunJob(l:command, l:options) return s:RunJob(l:command, l:options)
@@ -653,33 +546,62 @@ endfunction
" Run a linter for a buffer. " Run a linter for a buffer.
" "
" Returns 1 if the linter was successfully run. " Returns 1 if the linter was successfully run.
function! s:RunLinter(buffer, linter) abort function! s:RunLinter(buffer, linter, lint_file) abort
if !empty(a:linter.lsp) if !empty(a:linter.lsp)
return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter) return ale#lsp_linter#CheckWithLSP(a:buffer, a:linter)
else else
let l:executable = ale#linter#GetExecutable(a:buffer, a:linter) let l:executable = ale#linter#GetExecutable(a:buffer, a:linter)
return s:RunIfExecutable(a:buffer, a:linter, l:executable) return s:RunIfExecutable(a:buffer, a:linter, a:lint_file, l:executable)
endif endif
return 0 return 0
endfunction endfunction
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort function! s:GetLintFileValues(slots, Callback) abort
" Initialise the buffer information if needed. let l:deferred_list = []
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer) let l:new_slots = []
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer. for [l:lint_file, l:linter] in a:slots
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer) while ale#command#IsDeferred(l:lint_file) && has_key(l:lint_file, 'value')
" If we've already computed the return value, use it.
let l:lint_file = l:lint_file.value
endwhile
silent doautocmd <nomodeline> User ALELintPre if ale#command#IsDeferred(l:lint_file)
" If we are going to return the result later, wait for it.
call add(l:deferred_list, l:lint_file)
else
" If we have the value now, coerce it to 0 or 1.
let l:lint_file = l:lint_file is 1
endif
for l:linter in a:linters call add(l:new_slots, [l:lint_file, l:linter])
endfor
if !empty(l:deferred_list)
for l:deferred in l:deferred_list
let l:deferred.result_callback =
\ {-> s:GetLintFileValues(l:new_slots, a:Callback)}
endfor
else
call a:Callback(l:new_slots)
endif
endfunction
function! s:RunLinters(
\ buffer,
\ slots,
\ should_lint_file,
\ new_buffer,
\ can_clear_results
\) abort
let l:can_clear_results = a:can_clear_results
for [l:lint_file, l:linter] in a:slots
" Only run lint_file linters if we should. " Only run lint_file linters if we should.
if !l:linter.lint_file || a:should_lint_file if !l:lint_file || a:should_lint_file
if s:RunLinter(a:buffer, l:linter) if s:RunLinter(a:buffer, l:linter, l:lint_file)
" If a single linter ran, we shouldn't clear everything. " If a single linter ran, we shouldn't clear everything.
let l:can_clear_results = 0 let l:can_clear_results = 0
endif endif
@@ -694,11 +616,49 @@ function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" disabled, or ALE itself is disabled. " disabled, or ALE itself is disabled.
if l:can_clear_results if l:can_clear_results
call ale#engine#SetResults(a:buffer, []) call ale#engine#SetResults(a:buffer, [])
elseif l:new_buffer elseif a:new_buffer
call s:AddProblemsFromOtherBuffers(a:buffer, a:linters) call s:AddProblemsFromOtherBuffers(
\ a:buffer,
\ map(copy(a:slots), 'v:val[1]')
\)
endif endif
endfunction endfunction
function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort
" Initialise the buffer information if needed.
let l:new_buffer = ale#engine#InitBufferInfo(a:buffer)
call s:StopCurrentJobs(a:buffer, a:should_lint_file)
call s:RemoveProblemsForDisabledLinters(a:buffer, a:linters)
" We can only clear the results if we aren't checking the buffer.
let l:can_clear_results = !ale#engine#IsCheckingBuffer(a:buffer)
silent doautocmd <nomodeline> User ALELintPre
" Handle `lint_file` callbacks first.
let l:linter_slots = []
for l:linter in a:linters
let l:LintFile = l:linter.lint_file
if type(l:LintFile) is v:t_func
let l:LintFile = l:LintFile(a:buffer)
endif
call add(l:linter_slots, [l:LintFile, l:linter])
endfor
call s:GetLintFileValues(l:linter_slots, {
\ new_slots -> s:RunLinters(
\ a:buffer,
\ new_slots,
\ a:should_lint_file,
\ l:new_buffer,
\ l:can_clear_results,
\ )
\})
endfunction
" Clean up a buffer. " Clean up a buffer.
" "
" This function will stop all current jobs for the buffer, " This function will stop all current jobs for the buffer,
+3 -3
View File
@@ -105,11 +105,11 @@ function! ale#events#Init() abort
if g:ale_enabled if g:ale_enabled
if l:text_changed is? 'always' || l:text_changed is# '1' if l:text_changed is? 'always' || l:text_changed is# '1'
autocmd TextChanged,TextChangedI * call ale#Queue(g:ale_lint_delay) autocmd TextChanged,TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
elseif l:text_changed is? 'normal' elseif l:text_changed is? 'normal'
autocmd TextChanged * call ale#Queue(g:ale_lint_delay) autocmd TextChanged * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
elseif l:text_changed is? 'insert' elseif l:text_changed is? 'insert'
autocmd TextChangedI * call ale#Queue(g:ale_lint_delay) autocmd TextChangedI * call ale#Queue(ale#Var(str2nr(expand('<abuf>')), 'lint_delay'))
endif endif
if g:ale_lint_on_enter if g:ale_lint_on_enter
+22
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
+46 -51
View File
@@ -1,4 +1,8 @@
call ale#Set('fix_on_save_ignore', {}) " Author: w0rp <devw0rp@gmail.com>
" Description: Functions for fixing code with programs, or other means.
let g:ale_fix_on_save_ignore = get(g:, 'ale_fix_on_save_ignore', {})
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
" Apply fixes queued up for buffers which may be hidden. " Apply fixes queued up for buffers which may be hidden.
" Vim doesn't let you modify hidden buffers. " Vim doesn't let you modify hidden buffers.
@@ -11,22 +15,29 @@ function! ale#fix#ApplyQueuedFixes(buffer) abort
call remove(g:ale_fix_buffer_data, a:buffer) call remove(g:ale_fix_buffer_data, a:buffer)
if l:data.changes_made try
let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output) if l:data.changes_made
let l:new_lines = ale#util#SetBufferContents(a:buffer, l:data.output)
if l:data.should_save if l:data.should_save
if a:buffer is bufnr('') if a:buffer is bufnr('')
if empty(&buftype) if empty(&buftype)
noautocmd :w! noautocmd :w!
else
set nomodified
endif
else else
set nomodified call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks
call setbufvar(a:buffer, '&modified', 0)
endif endif
else
call writefile(l:new_lines, expand('#' . a:buffer . ':p')) " no-custom-checks
call setbufvar(a:buffer, '&modified', 0)
endif endif
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 if l:data.should_save
let l:should_lint = ale#Var(a:buffer, 'fix_on_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 let l:output = a:job_output
endif endif
let l:ChainCallback = get(a:job_info, 'chain_with', v:null)
let l:ProcessWith = get(a:job_info, 'process_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. " 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. " otherwise skip this job and use the input from before.
" "
" We'll use the input from before for chained commands. " 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 let l:input = l:output
else else
let l:input = a:job_info.input let l:input = a:job_info.input
endif 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({ call s:RunFixer({
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'output': l:output,
\ 'callback_list': a:job_info.callback_list, \ 'callback_list': a:job_info.callback_list,
\ 'callback_index': l:next_index, \ 'callback_index': a:job_info.callback_index + 1,
\ 'chain_callback': l:ChainCallback,
\}) \})
endfunction endfunction
@@ -135,6 +135,7 @@ function! s:RunJob(result, options) abort
let l:buffer = a:options.buffer let l:buffer = a:options.buffer
let l:input = a:options.input let l:input = a:options.input
let l:fixer_name = a:options.fixer_name
if a:result is 0 || type(a:result) is v:t_list if a:result is 0 || type(a:result) is v:t_list
if type(a:result) is v:t_list if type(a:result) is v:t_list
@@ -152,26 +153,21 @@ function! s:RunJob(result, options) abort
endif endif
let l:command = get(a:result, 'command', '') let l:command = get(a:result, 'command', '')
let l:ChainWith = get(a:result, 'chain_with', v:null)
if empty(l:command) if empty(l:command)
" If the command is empty, skip to the next item, or call the " If the command is empty, skip to the next item.
" chain_with function.
call s:RunFixer({ call s:RunFixer({
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'input': l:input, \ '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, \ 'callback_list': a:options.callback_list,
\ 'chain_callback': l:ChainWith,
\ 'output': [],
\}) \})
return return
endif endif
let l:read_temporary_file = get(a:result, 'read_temporary_file', 0) 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', 1)
let l:read_buffer = get(a:result, 'read_buffer', l:ChainWith is v:null)
let l:output_stream = get(a:result, 'output_stream', 'stdout') let l:output_stream = get(a:result, 'output_stream', 'stdout')
if l:read_temporary_file if l:read_temporary_file
@@ -180,7 +176,6 @@ function! s:RunJob(result, options) abort
let l:Callback = function('s:HandleExit', [{ let l:Callback = function('s:HandleExit', [{
\ 'input': l:input, \ 'input': l:input,
\ 'chain_with': l:ChainWith,
\ 'callback_index': a:options.callback_index, \ 'callback_index': a:options.callback_index,
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'process_with': get(a:result, 'process_with', v:null), \ 'process_with': get(a:result, 'process_with', v:null),
@@ -192,6 +187,7 @@ function! s:RunJob(result, options) abort
\ 'read_buffer': l:read_buffer, \ 'read_buffer': l:read_buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'log_output': 0, \ 'log_output': 0,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name),
\}) \})
if empty(l:run_result) if empty(l:run_result)
@@ -215,32 +211,22 @@ function! s:RunFixer(options) abort
return return
endif endif
let l:ChainCallback = get(a:options, 'chain_callback', v:null) let [l:fixer_name, l:Function] = a:options.callback_list[l:index]
let l:Function = l:ChainCallback isnot v:null
\ ? ale#util#GetFunction(l:ChainCallback)
\ : a:options.callback_list[l:index]
" Record new jobs started as fixer jobs. " Record new jobs started as fixer jobs.
call setbufvar(l:buffer, 'ale_job_type', 'fixer') call setbufvar(l:buffer, 'ale_job_type', 'fixer')
if l:ChainCallback isnot v:null " Regular fixer commands accept (buffer, [input])
" Chained commands accept (buffer, output, [input]) let l:result = ale#util#FunctionArgCount(l:Function) == 1
let l:result = ale#util#FunctionArgCount(l:Function) == 2 \ ? call(l:Function, [l:buffer])
\ ? call(l:Function, [l:buffer, a:options.output]) \ : call(l:Function, [l:buffer, copy(l:input)])
\ : 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, { call s:RunJob(l:result, {
\ 'buffer': l:buffer, \ 'buffer': l:buffer,
\ 'input': l:input, \ 'input': l:input,
\ 'callback_list': a:options.callback_list, \ 'callback_list': a:options.callback_list,
\ 'callback_index': l:index, \ 'callback_index': l:index,
\ 'fixer_name': l:fixer_name,
\}) \})
endfunction endfunction
@@ -308,16 +294,24 @@ function! s:GetCallbacks(buffer, fixing_flag, fixers) abort
" Variables with capital characters are needed, or Vim will complain about " Variables with capital characters are needed, or Vim will complain about
" funcref variables. " funcref variables.
for l:Item in l:callback_list for l:Item in l:callback_list
" Try to capture the names of registered fixer names, so we can use
" them for filename mapping or other purposes later.
let l:fixer_name = v:null
if type(l:Item) is v:t_string if type(l:Item) is v:t_string
let l:Func = ale#fix#registry#GetFunc(l:Item) let l:Func = ale#fix#registry#GetFunc(l:Item)
if !empty(l:Func) if !empty(l:Func)
let l:fixer_name = l:Item
let l:Item = l:Func let l:Item = l:Func
endif endif
endif endif
try try
call add(l:corrected_list, ale#util#GetFunction(l:Item)) call add(l:corrected_list, [
\ l:fixer_name,
\ ale#util#GetFunction(l:Item)
\])
catch /E475/ catch /E475/
" Rethrow exceptions for failing to get a function so we can print " Rethrow exceptions for failing to get a function so we can print
" a friendly message about it. " a friendly message about it.
@@ -389,3 +383,4 @@ endfunction
augroup ALEBufferFixGroup augroup ALEBufferFixGroup
autocmd! autocmd!
autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>'))) autocmd BufEnter * call ale#fix#ApplyQueuedFixes(str2nr(expand('<abuf>')))
augroup END
+12 -2
View File
@@ -175,11 +175,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['php'], \ 'suggested_filetypes': ['php'],
\ 'description': 'Fix PHP files with php-cs-fixer.', \ 'description': 'Fix PHP files with php-cs-fixer.',
\ }, \ },
\ 'astyle': { \ 'astyle': {
\ 'function': 'ale#fixers#astyle#Fix', \ 'function': 'ale#fixers#astyle#Fix',
\ 'suggested_filetypes': ['c', 'cpp'], \ 'suggested_filetypes': ['c', 'cpp'],
\ 'description': 'Fix C/C++ with astyle.', \ 'description': 'Fix C/C++ with astyle.',
\ }, \ },
\ 'clangtidy': { \ 'clangtidy': {
\ 'function': 'ale#fixers#clangtidy#Fix', \ 'function': 'ale#fixers#clangtidy#Fix',
\ 'suggested_filetypes': ['c', 'cpp', 'objc'], \ 'suggested_filetypes': ['c', 'cpp', 'objc'],
@@ -380,11 +380,21 @@ let s:default_registry = {
\ 'suggested_filetypes': ['nix'], \ 'suggested_filetypes': ['nix'],
\ 'description': 'A formatter for Nix code', \ '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': { \ 'html-beautify': {
\ 'function': 'ale#fixers#html_beautify#Fix', \ 'function': 'ale#fixers#html_beautify#Fix',
\ 'suggested_filetypes': ['html', 'htmldjango'], \ 'suggested_filetypes': ['html', 'htmldjango'],
\ 'description': 'Fix HTML files with html-beautify.', \ 'description': 'Fix HTML files with html-beautify.',
\ }, \ },
\ 'dhall': {
\ 'function': 'ale#fixers#dhall#Fix',
\ 'suggested_filetypes': ['dhall'],
\ 'description': 'Fix Dhall files with dhall-format.',
\ },
\} \}
" Reset the function registry to the default entries. " Reset the function registry to the default entries.
+23
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
+1 -3
View File
@@ -10,9 +10,7 @@ function! ale#fixers#latexindent#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . ' -l -w' \ . ' -l'
\ . (empty(l:options) ? '' : ' ' . l:options) \ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' %t',
\ 'read_temporary_file': 1,
\} \}
endfunction endfunction
+1 -2
View File
@@ -5,14 +5,13 @@ call ale#Set('ocaml_ocamlformat_executable', 'ocamlformat')
call ale#Set('ocaml_ocamlformat_options', '') call ale#Set('ocaml_ocamlformat_options', '')
function! ale#fixers#ocamlformat#Fix(buffer) abort function! ale#fixers#ocamlformat#Fix(buffer) abort
let l:filename = expand('#' . a:buffer . ':p')
let l:executable = ale#Var(a:buffer, 'ocaml_ocamlformat_executable') let l:executable = ale#Var(a:buffer, 'ocaml_ocamlformat_executable')
let l:options = ale#Var(a:buffer, 'ocaml_ocamlformat_options') let l:options = ale#Var(a:buffer, 'ocaml_ocamlformat_options')
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . (empty(l:options) ? '' : ' ' . l:options) \ . (empty(l:options) ? '' : ' ' . l:options)
\ . ' --name=' . ale#Escape(l:filename) \ . ' --name=%s'
\ . ' -' \ . ' -'
\} \}
endfunction endfunction
+16 -1
View File
@@ -34,6 +34,21 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
return a:output return a:output
endfunction endfunction
function! ale#fixers#prettier#GetProjectRoot(buffer) abort
let l:config = ale#path#FindNearestFile(a:buffer, '.prettierignore')
if !empty(l:config)
return fnamemodify(l:config, ':h')
endif
" Fall back to the directory of the buffer
return fnamemodify(bufname(a:buffer), ':p:h')
endfunction
function! ale#fixers#prettier#CdProjectRoot(buffer) abort
return ale#path#CdString(ale#fixers#prettier#GetProjectRoot(a:buffer))
endfunction
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
let l:executable = ale#fixers#prettier#GetExecutable(a:buffer) let l:executable = ale#fixers#prettier#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'javascript_prettier_options') let l:options = ale#Var(a:buffer, 'javascript_prettier_options')
@@ -97,7 +112,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
" 1.4.0 is the first version with --stdin-filepath " 1.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(a:version, [1, 4, 0]) if ale#semver#GTE(a:version, [1, 4, 0])
return { return {
\ 'command': ale#path#BufferCdString(a:buffer) \ 'command': ale#fixers#prettier#CdProjectRoot(a:buffer)
\ . ale#Escape(l:executable) \ . ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
+2 -2
View File
@@ -17,8 +17,8 @@ function! ale#fixers#prettier_standard#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer)) \ 'command': ale#Escape(ale#fixers#prettier_standard#GetExecutable(a:buffer))
\ . ' %t' \ . ' --stdin'
\ . ' --stdin-filepath=%s'
\ . ' ' . l:options, \ . ' ' . l:options,
\ 'read_temporary_file': 1,
\} \}
endfunction endfunction
+24
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
+1 -2
View File
@@ -29,8 +29,7 @@ function! ale#fixers#rubocop#GetCommand(buffer) abort
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct') \ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct')
\ . ' --force-exclusion --stdin ' \ . ' --force-exclusion --stdin %s'
\ . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction endfunction
function! ale#fixers#rubocop#Fix(buffer) abort function! ale#fixers#rubocop#Fix(buffer) abort
+1 -1
View File
@@ -27,7 +27,7 @@ function! ale#fixers#standard#Fix(buffer) abort
return { return {
\ 'command': ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --fix %t', \ . ' --fix --stdin < %s > %t',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\} \}
endfunction endfunction
+18 -1
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>:8:5: warning: conversion lacks type at end of format [-Wformat=]
" <stdin>:10:27: error: invalid operands to binary - (have int and char *) " <stdin>:10:27: error: invalid operands to binary - (have int and char *)
" -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004] " -:189:7: note: $/${} is unnecessary on arithmetic variables. [SC2004]
let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):(\d+)?:? ([^:]+): (.+)$' let s:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+)?:?(\d+)?:? ([^:]+): (.+)$'
let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$' let s:inline_pattern = '\v inlined from .* at \<stdin\>:(\d+):(\d+):$'
function! s:IsHeaderFile(filename) abort function! s:IsHeaderFile(filename) abort
@@ -117,6 +117,23 @@ function! ale#handlers#gcc#HandleGCCFormat(buffer, lines) abort
if !empty(l:output) if !empty(l:output)
if !has_key(l:output[-1], 'detail') if !has_key(l:output[-1], 'detail')
let l:output[-1].detail = l:output[-1].text 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 endif
let l:output[-1].detail = l:output[-1].detail . "\n" let l:output[-1].detail = l:output[-1].detail . "\n"
+13 -6
View File
@@ -4,17 +4,24 @@
function! ale#handlers#sh#GetShellType(buffer) abort function! ale#handlers#sh#GetShellType(buffer) abort
let l:bang_line = get(getbufline(a:buffer, 1), 0, '') let l:bang_line = get(getbufline(a:buffer, 1), 0, '')
let l:command = ''
" Take the shell executable from the hashbang, if we can. " Take the shell executable from the hashbang, if we can.
if l:bang_line[:1] is# '#!' if l:bang_line[:1] is# '#!'
" Remove options like -e, etc. " Remove options like -e, etc.
let l:command = substitute(l:bang_line, ' --\?[a-zA-Z0-9]\+', '', 'g') let l:command = substitute(l:bang_line, ' --\?[a-zA-Z0-9]\+', '', 'g')
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 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
return '' return ''
endfunction endfunction
+4 -1
View File
@@ -264,7 +264,10 @@ function! s:OnReady(line, column, opt, linter, lsp_details) abort
" hover position probably won't make sense. " hover position probably won't make sense.
call ale#lsp#NotifyForChanges(l:id, l:buffer) 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) let l:message = ale#lsp#message#Hover(l:buffer, a:line, l:column)
endif endif
+33 -164
View File
@@ -32,7 +32,7 @@ let s:default_ale_linter_aliases = {
" "
" No linters are used for plaintext files by default. " No linters are used for plaintext files by default.
" "
" Only cargo is enabled for Rust by default. " Only cargo and rls are enabled for Rust by default.
" rpmlint is disabled by default because it can result in code execution. " rpmlint is disabled by default because it can result in code execution.
" hhast is disabled by default because it executes code in the project root. " hhast is disabled by default because it executes code in the project root.
" "
@@ -46,7 +46,7 @@ let s:default_ale_linters = {
\ 'perl': ['perlcritic'], \ 'perl': ['perlcritic'],
\ 'perl6': [], \ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'], \ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'rust': ['cargo'], \ 'rust': ['cargo', 'rls'],
\ 'spec': [], \ 'spec': [],
\ 'text': [], \ 'text': [],
\ 'vue': ['eslint', 'vls'], \ 'vue': ['eslint', 'vls'],
@@ -77,10 +77,6 @@ function! s:IsBoolean(value) abort
return type(a:value) is v:t_number && (a:value == 0 || a:value == 1) return type(a:value) is v:t_number && (a:value == 0 || a:value == 1)
endfunction endfunction
function! s:LanguageGetter(buffer) dict abort
return l:self.language
endfunction
function! ale#linter#PreProcess(filetype, linter) abort function! ale#linter#PreProcess(filetype, linter) abort
if type(a:linter) isnot v:t_dict if type(a:linter) isnot v:t_dict
throw 'The linter object must be a Dictionary' throw 'The linter object must be a Dictionary'
@@ -114,14 +110,7 @@ function! ale#linter#PreProcess(filetype, linter) abort
if !l:needs_executable if !l:needs_executable
if has_key(a:linter, 'executable') if has_key(a:linter, 'executable')
\|| has_key(a:linter, 'executable_callback') throw '`executable` cannot be used when lsp == ''socket'''
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'
endif endif
elseif has_key(a:linter, 'executable') elseif has_key(a:linter, 'executable')
let l:obj.executable = 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' throw '`executable` must be a String or Function if defined'
endif endif
else else
throw 'Either `executable` or `executable_callback` must be defined' throw '`executable` must be defined'
endif endif
if !l:needs_command if !l:needs_command
if has_key(a:linter, 'command') if has_key(a:linter, 'command')
\|| has_key(a:linter, 'command_callback') throw '`command` cannot be used when lsp == ''socket'''
\|| 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'
endif endif
elseif has_key(a:linter, 'command') elseif has_key(a:linter, 'command')
let l:obj.command = 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' throw '`command` must be a String or Function if defined'
endif endif
else else
throw 'Either `command`, `executable_callback`, `command_chain` ' throw '`command` must be defined'
\ . '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'
endif endif
if !l:needs_address if !l:needs_address
if has_key(a:linter, 'address') || has_key(a:linter, 'address_callback') if has_key(a:linter, 'address')
throw '`address` or `address_callback` cannot be used when lsp != ''socket''' throw '`address` cannot be used when lsp != ''socket'''
endif endif
elseif has_key(a:linter, 'address') elseif has_key(a:linter, 'address')
if type(a:linter.address) isnot v:t_string if type(a:linter.address) isnot v:t_string
@@ -212,41 +149,17 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif endif
let l:obj.address = a:linter.address 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 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 endif
if l:needs_lsp_details if l:needs_lsp_details
if has_key(a:linter, 'language_callback') " Default to using the filetype as the language.
if has_key(a:linter, 'language') let l:obj.language = get(a:linter, 'language', a:filetype)
throw 'Only one of `language` or `language_callback` '
\ . 'should be set'
endif
let l:obj.language_callback = get(a:linter, 'language_callback') if type(l:obj.language) isnot v:t_string
\&& type(l:obj.language) isnot v:t_func
if !s:IsCallback(l:obj.language_callback) throw '`language` must be a String or Funcref if defined'
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)
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
endif endif
if has_key(a:linter, 'project_root') 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 if type(l:obj.project_root) isnot v:t_string
\&& type(l:obj.project_root) isnot v:t_func \&& type(l:obj.project_root) isnot v:t_func
throw '`project_root` must be a String or Function if defined' throw '`project_root` must be a String or Function'
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'
endif endif
else else
throw '`project_root` or `project_root_callback` must be defined for LSP linters' throw '`project_root` must be defined for LSP linters'
endif endif
if has_key(a:linter, 'completion_filter') if has_key(a:linter, 'completion_filter')
@@ -274,37 +181,16 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif endif
endif endif
if has_key(a:linter, 'initialization_options_callback') if has_key(a:linter, 'initialization_options')
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 let l:obj.initialization_options = a:linter.initialization_options
if type(l:obj.initialization_options) isnot v:t_dict if type(l:obj.initialization_options) isnot v:t_dict
\&& type(l:obj.initialization_options) isnot v:t_func \&& 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
endif endif
if has_key(a:linter, 'lsp_config_callback') if has_key(a:linter, 'lsp_config')
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 if type(a:linter.lsp_config) isnot v:t_dict
\&& type(a:linter.lsp_config) isnot v:t_func \&& type(a:linter.lsp_config) isnot v:t_func
throw '`lsp_config` must be a Dictionary or Function if defined' 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. " file on disk.
let l:obj.lint_file = get(a:linter, 'lint_file', 0) let l:obj.lint_file = get(a:linter, 'lint_file', 0)
if !s:IsBoolean(l:obj.lint_file) if !s:IsBoolean(l:obj.lint_file) && type(l:obj.lint_file) isnot v:t_func
throw '`lint_file` must be `0` or `1`' throw '`lint_file` must be `0`, `1`, or a Function'
endif endif
" An option indicating that the buffer should be read. " An option indicating that the buffer should be read.
let l:obj.read_buffer = get(a:linter, 'read_buffer', !l:obj.lint_file) let l:obj.read_buffer = get(a:linter, 'read_buffer', 1)
if !s:IsBoolean(l:obj.read_buffer) if !s:IsBoolean(l:obj.read_buffer)
throw '`read_buffer` must be `0` or `1`' throw '`read_buffer` must be `0` or `1`'
endif endif
if l:obj.lint_file && l:obj.read_buffer
throw 'Only one of `lint_file` or `read_buffer` can be `1`'
endif
let l:obj.aliases = get(a:linter, 'aliases', []) let l:obj.aliases = get(a:linter, 'aliases', [])
if type(l:obj.aliases) isnot v:t_list if type(l:obj.aliases) isnot v:t_list
@@ -347,14 +229,6 @@ function! ale#linter#PreProcess(filetype, linter) abort
throw '`aliases` must be a List of String values' throw '`aliases` must be a List of String values'
endif 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 return l:obj
endfunction endfunction
@@ -522,9 +396,7 @@ endfunction
" Given a buffer and linter, get the executable String for the linter. " Given a buffer and linter, get the executable String for the linter.
function! ale#linter#GetExecutable(buffer, linter) abort function! ale#linter#GetExecutable(buffer, linter) abort
let l:Executable = has_key(a:linter, 'executable_callback') let l:Executable = a:linter.executable
\ ? function(a:linter.executable_callback)
\ : a:linter.executable
return type(l:Executable) is v:t_func return type(l:Executable) is v:t_func
\ ? l:Executable(a:buffer) \ ? l:Executable(a:buffer)
@@ -532,24 +404,21 @@ function! ale#linter#GetExecutable(buffer, linter) abort
endfunction endfunction
" Given a buffer and linter, get the command String for the linter. " 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 function! ale#linter#GetCommand(buffer, linter) abort
let l:Command = has_key(a:linter, 'command_callback') let l:Command = a:linter.command
\ ? function(a:linter.command_callback)
\ : a:linter.command
return type(l:Command) is v:t_func return type(l:Command) is v:t_func ? l:Command(a:buffer) : l:Command
\ ? l:Command(a:buffer)
\ : l:Command
endfunction endfunction
" Given a buffer and linter, get the address for connecting to the server. " Given a buffer and linter, get the address for connecting to the server.
function! ale#linter#GetAddress(buffer, linter) abort function! ale#linter#GetAddress(buffer, linter) abort
let l:Address = has_key(a:linter, 'address_callback') let l:Address = a:linter.address
\ ? function(a:linter.address_callback)
\ : a:linter.address
return type(l:Address) is v:t_func return type(l:Address) is v:t_func ? l:Address(a:buffer) : l:Address
\ ? l:Address(a:buffer) endfunction
\ : l:Address
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 endfunction
+4
View File
@@ -64,6 +64,9 @@ endfunction
" Used only in tests. " Used only in tests.
function! ale#lsp#GetConnections() abort function! ale#lsp#GetConnections() abort
" This command will throw from the sandbox.
let &l:equalprg=&l:equalprg
return s:connections return s:connections
endfunction endfunction
@@ -449,6 +452,7 @@ function! ale#lsp#StartProgram(conn_id, executable, command) abort
endif endif
if l:started && !l:conn.is_tsserver if l:started && !l:conn.is_tsserver
let l:conn.initialized = 0
call s:SendInitMessage(l:conn) call s:SendInitMessage(l:conn)
endif endif
+19 -4
View File
@@ -34,7 +34,11 @@ endfunction
function! s:HandleLSPDiagnostics(conn_id, response) abort function! s:HandleLSPDiagnostics(conn_id, response) abort
let l:linter_name = s:lsp_linter_map[a:conn_id] let l:linter_name = s:lsp_linter_map[a:conn_id]
let l:filename = ale#path#FromURI(a:response.params.uri) let l:filename = ale#path#FromURI(a:response.params.uri)
let l:buffer = bufnr('^' . l:filename . '$') let l: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, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) if empty(l:info)
@@ -52,7 +56,11 @@ endfunction
function! s:HandleTSServerDiagnostics(response, error_type) abort function! s:HandleTSServerDiagnostics(response, error_type) abort
let l:linter_name = 'tsserver' let l:linter_name = 'tsserver'
let l:buffer = bufnr('^' . a:response.body.file . '$') let l: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, {}) let l:info = get(g:ale_buffer_info, l:buffer, {})
if empty(l:info) 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:command = a:details.command
let l:config = ale#lsp_linter#GetConfig(l:buffer, a:linter) 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) 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) call ale#lsp#MarkConnectionAsTsserver(l:conn_id)
endif endif
let l:command = ale#command#FormatCommand(l:buffer, a:executable, a:command, 0, v:false)[1] let l:command = ale#command#FormatCommand(
\ l:buffer,
\ a:executable,
\ a:command,
\ 0,
\ v:false,
\ [],
\)[1]
let l:command = ale#job#PrepareCommand(l:buffer, l:command) let l:command = ale#job#PrepareCommand(l:buffer, l:command)
let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command) let l:ready = ale#lsp#StartProgram(l:conn_id, a:executable, l:command)
endif endif
+16 -4
View File
@@ -24,6 +24,14 @@ function! ale#path#Simplify(path) abort
return substitute(simplify(l:win_path), '^\\\+', '\', 'g') " no-custom-checks return substitute(simplify(l:win_path), '^\\\+', '\', 'g') " no-custom-checks
endfunction endfunction
" Simplify a path without a Windows drive letter.
" This function can be used for checking if paths are equal.
function! ale#path#RemoveDriveLetter(path) abort
return has('win32') && a:path[1:2] is# ':\'
\ ? ale#path#Simplify(a:path[2:])
\ : ale#path#Simplify(a:path)
endfunction
" Given a buffer and a filename, find the nearest file by searching upwards " Given a buffer and a filename, find the nearest file by searching upwards
" through the paths relative to the given buffer. " through the paths relative to the given buffer.
function! ale#path#FindNearestFile(buffer, filename) abort function! ale#path#FindNearestFile(buffer, filename) abort
@@ -74,15 +82,19 @@ endfunction
function! ale#path#CdString(directory) abort function! ale#path#CdString(directory) abort
if has('win32') if has('win32')
return 'cd /d ' . ale#Escape(a:directory) . ' && ' return 'cd /d ' . ale#Escape(a:directory) . ' && '
else
return 'cd ' . ale#Escape(a:directory) . ' && '
endif endif
return 'cd ' . ale#Escape(a:directory) . ' && '
endfunction endfunction
" Output 'cd <buffer_filename_directory> && ' " Output 'cd <buffer_filename_directory> && '
" This function can be used changing the directory for a linter command. " This function can be used changing the directory for a linter command.
function! ale#path#BufferCdString(buffer) abort function! ale#path#BufferCdString(buffer) abort
return ale#path#CdString(fnamemodify(bufname(a:buffer), ':p:h')) if has('win32')
return 'cd /d %s:h && '
endif
return 'cd %s:h && '
endfunction endfunction
" Return 1 if a path is an absolute path. " Return 1 if a path is an absolute path.
@@ -95,7 +107,7 @@ function! ale#path#IsAbsolute(filename) abort
return a:filename[:0] is# '/' || a:filename[1:2] is# ':\' return a:filename[:0] is# '/' || a:filename[1:2] is# ':\'
endfunction endfunction
let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h')) let s:temp_dir = ale#path#Simplify(fnamemodify(ale#util#Tempname(), ':h:h'))
" Given a filename, return 1 if the file represents some temporary file " Given a filename, return 1 if the file represents some temporary file
" created by Vim. " created by Vim.
+16 -13
View File
@@ -1,14 +1,22 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: Preview windows for showing whatever information in. " Description: Preview windows for showing whatever information in.
if !has_key(s:, 'last_selection_list') if !has_key(s:, 'last__list')
let s:last_selection_list = [] let s:last_list = []
endif endif
if !has_key(s:, 'last_selection_open_in') if !has_key(s:, 'last_options')
let s:last_selection_open_in = 'current-buffer' let s:last_options = {}
endif endif
function! ale#preview#SetLastSelection(item_list, options) abort
let s:last_list = a:item_list
let s:last_options = {
\ 'open_in': get(a:options, 'open_in', 'current-buffer'),
\ 'use_relative_paths': get(a:options, 'use_relative_paths', 0),
\}
endfunction
" Open a preview window and show some lines in it. " Open a preview window and show some lines in it.
" A second argument can be passed as a Dictionary with options. They are... " A second argument can be passed as a Dictionary with options. They are...
" "
@@ -81,19 +89,14 @@ function! ale#preview#ShowSelection(item_list, ...) abort
let b:ale_preview_item_list = a:item_list let b:ale_preview_item_list = a:item_list
let b:ale_preview_item_open_in = get(l:options, 'open_in', 'current-buffer') let b:ale_preview_item_open_in = get(l:options, 'open_in', 'current-buffer')
" Remove the last preview " Remember preview state, so we can repeat it later.
let s:last_selection_list = b:ale_preview_item_list call ale#preview#SetLastSelection(a:item_list, l:options)
let s:last_selection_open_in = b:ale_preview_item_open_in
endfunction endfunction
function! ale#preview#RepeatSelection() abort function! ale#preview#RepeatSelection() abort
if empty(s:last_selection_list) if !empty(s:last_list)
return call ale#preview#ShowSelection(s:last_list, s:last_options)
endif endif
call ale#preview#ShowSelection(s:last_selection_list, {
\ 'open_in': s:last_selection_open_in,
\})
endfunction endfunction
function! s:Open(open_in) abort function! s:Open(open_in) abort
+2 -2
View File
@@ -145,8 +145,8 @@ function! ale#test#WaitForJobs(deadline) abort
" end, but before handlers are run. " end, but before handlers are run.
sleep 10ms sleep 10ms
" We must check the buffer data again to see if new jobs started " We must check the buffer data again to see if new jobs started for
" for command_chain linters. " linters with chained commands.
let l:has_new_jobs = 0 let l:has_new_jobs = 0
" Check again to see if any jobs are running. " Check again to see if any jobs are running.
+4 -1
View File
@@ -423,7 +423,10 @@ function! ale#util#Writefile(buffer, lines, filename) abort
\ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')') \ ? map(copy(a:lines), 'substitute(v:val, ''\r*$'', ''\r'', '''')')
\ : a:lines \ : 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 endfunction
if !exists('s:patial_timers') if !exists('s:patial_timers')
+69 -64
View File
@@ -1,22 +1,36 @@
=============================================================================== ===============================================================================
ALE C Integration *ale-c-options* 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 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* g:ale_c_build_dir_names *g:ale_c_build_dir_names*
*b:ale_c_build_dir_names* *b:ale_c_build_dir_names*
Type: |List| Type: |List|
Default: `['build', 'bin']` Default: `['build', 'bin']`
A list of directory names to be used when searching upwards from cpp A list of directory names to be used when searching upwards from cpp files
files to discover compilation databases with. For directory named `'foo'`, to discover compilation databases with. For directory named `'foo'`, ALE
ALE will search for `'foo/compile_commands.json'` in all directories on and above will search for `'foo/compile_commands.json'` in all directories on and
the directory containing the cpp file to find path to compilation database. above the directory containing the cpp file to find path to compilation
This feature is useful for the clang tools wrapped around LibTooling (namely database. This feature is useful for the clang tools wrapped around
here, clang-tidy) LibTooling (namely here, clang-tidy)
g:ale_c_build_dir *g:ale_c_build_dir* 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 set for C or C++ compilers. This can make it easier to determine the correct
build flags to use for different files. 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 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 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 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* g:ale_c_cc_executable *g:ale_c_cc_executable*
*b:ale_c_clang_executable* *b:ale_c_cc_executable*
Type: |String| 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* g:ale_c_cc_options *g:ale_c_cc_options*
*b:ale_c_clang_options* *b:ale_c_cc_options*
Type: |String| Type: |String|
Default: `'-std=c11 -Wall'` 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++. 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* 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. 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: vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
+58 -68
View File
@@ -1,12 +1,16 @@
=============================================================================== ===============================================================================
ALE C++ Integration *ale-cpp-options* 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 Global Options
The following C options also apply to some C++ linters too. 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_names|
* |g:ale_c_build_dir| * |g:ale_c_build_dir|
* |g:ale_c_parse_makefile| * |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* g:ale_cpp_cc_executable *g:ale_cpp_cc_executable*
*b:ale_cpp_clang_executable* *b:ale_cpp_cc_executable*
Type: |String| 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* g:ale_cpp_cc_options *g:ale_cpp_cc_options*
*b:ale_cpp_clang_options* *b:ale_cpp_cc_options*
Type: |String| Type: |String|
Default: `'-std=c++14 -Wall'` 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* g:ale_cpp_ccls_executable *g:ale_cpp_ccls_executable*
*b:ale_cpp_clangd_executable* *b:ale_cpp_ccls_executable*
Type: |String| 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* g:ale_cpp_ccls_init_options *g:ale_cpp_ccls_init_options*
*b:ale_cpp_clangd_options* *b:ale_cpp_ccls_init_options*
Type: |String| Type: |Dictionary|
Default: `''` 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. 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* 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. 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* uncrustify *ale-cpp-uncrustify*
See |ale-c-uncrustify| for information about the available options. 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: vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
+82
View File
@@ -13,6 +13,7 @@ CONTENTS *ale-development-contents*
4. Testing ALE..........................|ale-development-tests| 4. Testing ALE..........................|ale-development-tests|
4.1. Writing Linter Tests.............|ale-development-linter-tests| 4.1. Writing Linter Tests.............|ale-development-linter-tests|
4.2. Writing Fixer Tests..............|ale-development-fixer-tests| 4.2. Writing Fixer Tests..............|ale-development-fixer-tests|
4.3. Running Tests in a Windows VM....|ale-development-windows-tests|
=============================================================================== ===============================================================================
1. Introduction *ale-development-introduction* 1. Introduction *ale-development-introduction*
@@ -170,6 +171,11 @@ will run all of the tests in Vader, Vint checks, and several Bash scripts for
finding extra issues. Run `./run-tests --help` to see all of the options the finding extra issues. Run `./run-tests --help` to see all of the options the
script supports. Note that the script supports selecting particular test files. script supports. Note that the script supports selecting particular test files.
Once you get used to dealing with Vim and NeoVim compatibility issues, you
probably want to use `./run-tests --fast -q` for running tests with only the
fastest available Vim version, and with success messages from tests
suppressed.
Generally write tests for any changes you make. The following types of tests Generally write tests for any changes you make. The following types of tests
are recommended for the following types of code. are recommended for the following types of code.
@@ -353,5 +359,81 @@ given the above setup are as follows.
`AssertFixerNotExecuted` - Check that fixers will not be executed. `AssertFixerNotExecuted` - Check that fixers will not be executed.
===============================================================================
4.3 Running Tests in a Windows VM *ale-development-windows-tests*
Tests are run for ALE in a build of Vim 8 for Windows via AppVeyor. These
tests can frequently break due to minor differences in paths and how escaping
is done for commands on Windows. If you are a Linux or Mac user, running these
tests locally can be difficult. Here is a process that will make that easier.
First, you want to install a Windows image with VirtualBox. Install VirtualBox
and grab a VirtualBox image for Windows such as from here:
https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/
NOTE: If you need to enter a password for the virtual machine at any point,
the password is "Passw0rd!" without the double quotes.
NOTE: If your trial period for Windows runs out, run the commands like the
wallpaper tells you to.
Your virtual machine will need to have PowerShell installed. Before you go any
further, confirm that PowerShell is installed in your Windows virtual machine.
Consult the VirtualBox documentation on how to install "Guest Additions."
You probably want to install "Guest Additions" for most things to work
properly.
After you've loaded your virtual machine image, go into "Settings" for your
virtual machine, and "Shared Folders." Add a shared folder with the name
"ale", and set the "Folder Path" to the path to your ALE repository, for
example: "/home/w0rp/ale"
Find out which drive letter "ale" has been mounted as in Windows. We'll use
"E:" as the drive letter, for example. Open the command prompt as an
administrator by typing in `cmd` in the start menu, right clicking on the
command prompt application, and clicking "Run as administrator." Click "Yes"
when prompted to ask if you're sure you want to run the command prompt. You
should type in the following command to mount the "ale" directory for testing,
where "E:" is replaced with your drive letter. >
mklink /D C:\testplugin E:
<
Close the administrator Command Prompt, and try running the command
`type C:\testplugin\LICENSE` in a new Command Prompt which you are NOT running
as administrator. You should see the license for ALE in your terminal. After
you have confirmed that you have mounted ALE on your machine, search in the
Start Menu for "power shell," run PowerShell as an administrator, and issue
the following commands to install the correct Vim and Vader versions for
running tests. >
Add-Type -A System.IO.Compression.FileSystem
Invoke-WebRequest ftp://ftp.vim.org/pub/vim/pc/vim80-586w32.zip -OutFile C:\vim.zip
[IO.Compression.ZipFile]::ExtractToDirectory('C:\vim.zip', 'C:\vim')
rm C:\vim.zip
Invoke-WebRequest ftp://ftp.vim.org/pub/vim/pc/vim80-586rt.zip -OutFile C:\rt.zip
[IO.Compression.ZipFile]::ExtractToDirectory('C:\rt.zip', 'C:\vim')
rm C:\rt.zip
Invoke-WebRequest https://github.com/junegunn/vader.vim/archive/c6243dd81c98350df4dec608fa972df98fa2a3af.zip -OutFile C:\vader.zip
[IO.Compression.ZipFile]::ExtractToDirectory('C:\vader.zip', 'C:\')
mv C:\vader.vim-c6243dd81c98350df4dec608fa972df98fa2a3af C:\vader
rm C:\vader.zip
<
After you have finished installing everything, you can run all of the tests
in Windows by opening a Command Prompt NOT as an administrator by navigating
to the directory where you've mounted the ALE code, which must be named
`C:\testplugin`, and by running the `run-tests.bat` batch file. >
cd C:\testplugin
run-tests
<
It will probably take several minutes for all of the tests to run. Be patient.
You can run a specific test by passing the filename as an argument to the
batch file, for example: `run-tests test/test_c_flag_parsing.vader` . This will
give you results much more quickly.
=============================================================================== ===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
+1 -1
View File
@@ -6,7 +6,7 @@ ALE Elixir Integration *ale-elixir-options*
mix *ale-elixir-mix* 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` See `:help g:ale_linters`
+4 -2
View File
@@ -14,7 +14,8 @@ ember-template-lint *ale-handlebars-embertemplatelint*
g:ale_handlebars_embertemplatelint_executable g:ale_handlebars_embertemplatelint_executable
*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'` Default: `'ember-template-lint'`
See |ale-integrations-local-executables| 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
*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)` Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables| See |ale-integrations-local-executables|
+11
View File
@@ -2,6 +2,17 @@
ALE Markdown Integration *ale-markdown-options* 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* mdl *ale-markdown-mdl*
+31 -18
View File
@@ -189,42 +189,55 @@ g:ale_php_psalm_executable *g:ale_php_psalm_executable*
This variable sets the executable used for psalm. 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| Type: |String|
Default: `''` Default: `''`
This variable can be set to pass additional options to psalm. This variable can be set to pass additional options to psalm.
===============================================================================
php-cs-fixer *ale-php-php-cs-fixer*
g:ale_php_cs_fixer_executable *g:ale_php_cs_fixer_executable* g:ale_php_psalm_use_global *g:ale_php_psalm_use_global*
*b:ale_php_cs_fixer_executable* *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*
g:ale_php_cs_fixer_executable *g:ale_php_cs_fixer_executable*
*b:ale_php_cs_fixer_executable*
Type: |String| Type: |String|
Default: `'php-cs-fixer'` Default: `'php-cs-fixer'`
This variable sets executable used for php-cs-fixer. 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*
g:ale_php_cs_fixer_options *g:ale_php_cs_fixer_options*
*b:ale_php_cs_fixer_options*
Type: |String| Type: |String|
Default: `''` Default: `''`
This variable can be set to pass additional options to php-cs-fixer. This variable can be set to pass additional options to php-cs-fixer.
===============================================================================
php *ale-php-php*
g:ale_php_php_executable *g:ale_php_php_executable* g:ale_php_cs_fixer_use_global *g:ale_php_cs_fixer_use_global*
*b:ale_php_php_executable* *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*
g:ale_php_php_executable *g:ale_php_php_executable*
*b:ale_php_php_executable*
Type: |String| Type: |String|
Default: `'php'` Default: `'php'`
+7 -6
View File
@@ -169,13 +169,14 @@ flake8 *ale-python-flake8*
g:ale_python_flake8_change_directory *g:ale_python_flake8_change_directory* g:ale_python_flake8_change_directory *g:ale_python_flake8_change_directory*
*b:ale_python_flake8_change_directory* *b:ale_python_flake8_change_directory*
Type: |Number| Type: |String|
Default: `1` Default: `project`
If set to `1`, ALE will switch to the directory the Python file being If set to `project`, ALE will switch to the project root before checking file.
checked with `flake8` is in before checking it. This helps `flake8` find If set to `file`, ALE will switch to directory the Python file being
configuration files more easily. This option can be turned off if you want checked with `flake8` is in before checking it.
to control the directory Python is executed from yourself. 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* g:ale_python_flake8_executable *g:ale_python_flake8_executable*
+11 -8
View File
@@ -31,11 +31,11 @@ Integration Information
5. rustfmt -- If you have `rustfmt` installed, you can use it as a fixer to 5. rustfmt -- If you have `rustfmt` installed, you can use it as a fixer to
consistently reformat your Rust code. consistently reformat your Rust code.
Only cargo is enabled by default. To switch to using rustc instead of cargo, Only cargo and rls are enabled by default. To switch to using rustc instead
configure |g:ale_linters| appropriately: > of cargo, configure |g:ale_linters| appropriately: >
" See the help text for the option for more information. " See the help text for the option for more information.
let g:ale_linters = {'rust': ['rustc']} let g:ale_linters = {'rust': ['rustc', 'rls']}
< <
Also note that rustc 1.12. or later is needed. Also note that rustc 1.12. or later is needed.
@@ -60,6 +60,7 @@ g:ale_rust_analyzer_config *g:ale_rust_analyzer_config*
Dictionary with configuration settings for rust-analyzer. Dictionary with configuration settings for rust-analyzer.
=============================================================================== ===============================================================================
cargo *ale-rust-cargo* cargo *ale-rust-cargo*
@@ -252,23 +253,25 @@ g:ale_rust_ignore_error_codes *g:ale_rust_ignore_error_codes*
> >
let g:ale_rust_ignore_error_codes = ['E0432', 'E0433'] let g:ale_rust_ignore_error_codes = ['E0432', 'E0433']
g:ale_rust_ignore_secondary_spans *g:ale_rust_ignore_secondary_spans* g:ale_rust_ignore_secondary_spans *g:ale_rust_ignore_secondary_spans*
*b:ale_rust_ignore_secondary_spans* *b:ale_rust_ignore_secondary_spans*
Type: Number Type: Number
Default: 0 Default: 0
When set to 1, instructs the Rust error repporting to ignore secondary When set to 1, instructs the Rust error reporting to ignore secondary spans.
spans. The problem with secondary spans is that they sometimes appear in The problem with secondary spans is that they sometimes appear in error
error messages before the main cause of the error, for example: > messages before the main cause of the error, for example: >
1 src/main.rs|98 col 5 error| this function takes 4 parameters but 5 1 src/main.rs|98 col 5 error| this function takes 4 parameters but 5
parameters were supplied: defined here parameters were supplied: defined here
2 src/main.rs|430 col 32 error| this function takes 4 parameters but 5 2 src/main.rs|430 col 32 error| this function takes 4 parameters but 5
parameters were supplied: expected 4 parameters parameters were supplied: expected 4 parameters
< <
This is due to the sorting by line numbers. With this option set to 1, This is due to the sorting by line numbers. With this option set to 1,
the 'defined here' span will not be presented. the 'defined here' span will not be presented.
=============================================================================== ===============================================================================
rustfmt *ale-rust-rustfmt* rustfmt *ale-rust-rustfmt*
+1 -1
View File
@@ -3,7 +3,7 @@ ALE SQL Integration *ale-sql-options*
=============================================================================== ===============================================================================
pgformatter *ale-sql-pgformatter* pgformatter *ale-sql-pgformatter*
g:ale_sql_pgformatter_executable *g:ale_sql_pgformatter_executable* g:ale_sql_pgformatter_executable *g:ale_sql_pgformatter_executable*
*b:ale_sql_pgformatter_executable* *b:ale_sql_pgformatter_executable*
+9 -4
View File
@@ -21,6 +21,7 @@ Notes:
* `drafter` * `drafter`
* AsciiDoc * AsciiDoc
* `alex`!! * `alex`!!
* `languagetool`!!
* `proselint` * `proselint`
* `redpen` * `redpen`
* `textlint` * `textlint`
@@ -47,7 +48,7 @@ Notes:
* C * C
* `astyle` * `astyle`
* `ccls` * `ccls`
* `clang` * `clang` (`cc`)
* `clangd` * `clangd`
* `clang-format` * `clang-format`
* `clangtidy`!! * `clangtidy`!!
@@ -55,7 +56,7 @@ Notes:
* `cpplint`!! * `cpplint`!!
* `cquery` * `cquery`
* `flawfinder` * `flawfinder`
* `gcc` * `gcc` (`cc`)
* `uncrustify` * `uncrustify`
* C# * C#
* `csc`!! * `csc`!!
@@ -65,7 +66,7 @@ Notes:
* C++ (filetype cpp) * C++ (filetype cpp)
* `astyle` * `astyle`
* `ccls` * `ccls`
* `clang` * `clang` (`cc`)
* `clangcheck`!! * `clangcheck`!!
* `clangd` * `clangd`
* `clang-format` * `clang-format`
@@ -75,7 +76,7 @@ Notes:
* `cpplint`!! * `cpplint`!!
* `cquery` * `cquery`
* `flawfinder` * `flawfinder`
* `gcc` * `gcc` (`cc`)
* `uncrustify` * `uncrustify`
* Chef * Chef
* `cookstyle` * `cookstyle`
@@ -118,6 +119,8 @@ Notes:
* `dartanalyzer`!! * `dartanalyzer`!!
* `dartfmt`!! * `dartfmt`!!
* `language_server` * `language_server`
* Dhall
* `dhall-format`
* Dockerfile * Dockerfile
* `dockerfile_lint` * `dockerfile_lint`
* `hadolint` * `hadolint`
@@ -446,6 +449,7 @@ Notes:
* `sqlfmt` * `sqlfmt`
* `sqlformat` * `sqlformat`
* `sqlint` * `sqlint`
* `sql-lint`
* Stylus * Stylus
* `stylelint` * `stylelint`
* SugarSS * SugarSS
@@ -453,6 +457,7 @@ Notes:
* Swift * Swift
* `sourcekit-lsp` * `sourcekit-lsp`
* `swiftformat` * `swiftformat`
* `swift-format`
* `swiftlint` * `swiftlint`
* Tcl * Tcl
* `nagelfar`!! * `nagelfar`!!
+338 -68
View File
@@ -9,8 +9,9 @@ CONTENTS *ale-contents*
1. Introduction.........................|ale-introduction| 1. Introduction.........................|ale-introduction|
2. Supported Languages & Tools..........|ale-support| 2. Supported Languages & Tools..........|ale-support|
3. Linting..............................|ale-lint| 3. Linting..............................|ale-lint|
3.1 Adding Language Servers...........|ale-lint-language-servers| 3.1 Linting On Other Machines.........|ale-lint-other-machines|
3.2 Other Sources.....................|ale-lint-other-sources| 3.2 Adding Language Servers...........|ale-lint-language-servers|
3.3 Other Sources.....................|ale-lint-other-sources|
4. Fixing Problems......................|ale-fix| 4. Fixing Problems......................|ale-fix|
5. Language Server Protocol Support.....|ale-lsp| 5. Language Server Protocol Support.....|ale-lsp|
5.1 Completion........................|ale-completion| 5.1 Completion........................|ale-completion|
@@ -148,7 +149,61 @@ ALE offers several options for controlling which linters are run.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
3.1 Adding Language Servers *ale-lint-language-servers* 3.1 Linting On Other Machines *ale-lint-other-machines*
ALE offers support for running linters or fixers on files you are editing
locally on other machines, so long as the other machine has access the file
you are editing. This could be a linter or fixer run inside of a Docker image,
running in a virtual machine, running on a remote server, etc.
In order to run tools on other machines, you will need to configure your tools
to run via scripts that execute commands on those machines, such as by setting
the ALE `_executable` options for those tools to a path for a script to run,
or by using |g:ale_command_wrapper| to specify a script to wrap all commands
that are run by ALE, before they are executed. For tools that ALE runs where
ALE looks for locally installed executables first, you may need to set the
`_use_global` options for those tools to `1`, or you can set
|g:ale_use_global_executables| to `1` before ALE is loaded to only use global
executables for all tools.
In order for ALE to properly lint or fix files which are running on another
file system, you must provide ALE with |List|s of strings for mapping paths to
and from your local file system and the remote file system, such as the file
system of your Docker container. See |g:ale_filename_mappings| for all of the
different ways these filename mappings can be configured.
For example, you might configure `pylint` to run via Docker by creating a
script like so. >
#!/usr/bin/env bash
exec docker run --rm -v "$(pwd):/data" cytopia/pylint "$@"
<
With the above script in mind, you might configure ALE to lint your Python
project with `pylint` by providing the path to the script to execute, and
mappings which describe how to between the two file systems in your
`python.vim` |ftplugin| file, like so: >
if expand('%:p') =~# '^/home/w0rp/git/test-pylint/'
let b:ale_linters = ['pylint']
let b:ale_python_pylint_use_global = 1
" This is the path to the script above.
let b:ale_python_pylint_executable = '/home/w0rp/git/test-pylint/pylint.sh'
" /data matches the path in Docker.
let b:ale_filename_mappings = {
\ 'pylint': [
\ ['/home/w0rp/git/test-pylint', '/data'],
\ ],
\}
endif
<
You might consider using a Vim plugin for loading Vim configuration files
specific to each project, if you have a lot of projects to manage.
-------------------------------------------------------------------------------
3.2 Adding Language Servers *ale-lint-language-servers*
ALE comes with many default configurations for language servers, so they can ALE comes with many default configurations for language servers, so they can
be detected and run automatically. ALE can connect to other language servers be detected and run automatically. ALE can connect to other language servers
@@ -189,7 +244,7 @@ address to connect to instead. >
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
3.2 Other Sources *ale-lint-other-sources* 3.3 Other Sources *ale-lint-other-sources*
Problems for a buffer can be taken from other sources and rendered by ALE. Problems for a buffer can be taken from other sources and rendered by ALE.
This allows ALE to be used in combination with other plugins which also want This allows ALE to be used in combination with other plugins which also want
@@ -287,6 +342,8 @@ are supported for running the commands.
file will be created, containing the lines from the file file will be created, containing the lines from the file
after previous adjustment have been done. after previous adjustment have been done.
See |ale-command-format-strings| for formatting options.
`read_temporary_file` When set to `1`, ALE will read the contents of the `read_temporary_file` When set to `1`, ALE will read the contents of the
temporary file created for `%t`. This option can be used temporary file created for `%t`. This option can be used
for commands which need to modify some file on disk in for commands which need to modify some file on disk in
@@ -356,6 +413,10 @@ by default.
Fixers can be disabled on save with |g:ale_fix_on_save_ignore|. They will Fixers can be disabled on save with |g:ale_fix_on_save_ignore|. They will
still be run when you manually run |ALEFix|. still be run when you manually run |ALEFix|.
Fixers can be run on another machines, just like linters, such as fixers run
from a Docker container, running in a virtual machine, running a remote
server, etc. See |ale-lint-other-machines|.
=============================================================================== ===============================================================================
5. Language Server Protocol Support *ale-lsp* 5. Language Server Protocol Support *ale-lsp*
@@ -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 |g:ale_completion_delay|. This setting should not be enabled if you wish to
use ALE as a completion source for other plugins. 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 ALE provides an 'omnifunc' function |ale#completion#OmniFunc| for triggering
completion manually with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O| > completion manually with CTRL-X CTRL-O. |i_CTRL-X_CTRL-O| >
" Use ALE's function for omnicompletion. " Use ALE's function for omnicompletion.
set omnifunc=ale#completion#OmniFunc 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 ALE will only suggest so many possible matches for completion. The maximum
number of items can be controlled with |g:ale_completion_max_suggestions|. 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 ALE by can support automatic imports from external modules. This behavior can
be enabled by setting the |g:ale_completion_autoimport| variable to `1`. 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 When working with TypeScript files, ALE can remove warnings from your
completions by setting the |g:ale_completion_tsserver_remove_warnings| completions by setting the |g:ale_completion_tsserver_remove_warnings|
variable to 1. variable to 1.
@@ -501,15 +612,9 @@ displayed.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
5.4 Find References *ale-find-references* 5.4 Find References *ale-find-references*
ALE supports finding references for symbols though any enabled LSP linters. ALE supports finding references for symbols though any enabled LSP linters
ALE will display a preview window showing the places where a symbol is with the |ALEFindReferences| command. See the documentation for the command
referenced in a codebase when a command is run. The following commands are for a full list of options.
supported:
|ALEFindReferences| - Find references for the word under the cursor.
Options:
`-relative` Show file paths in the results relative to the working dir
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
5.5 Hovering *ale-hover* 5.5 Hovering *ale-hover*
@@ -552,13 +657,9 @@ Documentation for symbols at the cursor can be retrieved using the
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
5.6 Symbol Search *ale-symbol-search* 5.6 Symbol Search *ale-symbol-search*
ALE supports searching for workspace symbols via LSP linters. The following ALE supports searching for workspace symbols via LSP linters with the
commands are supported: |ALESymbolSearch| command. See the documentation for the command
for a full list of options.
|ALESymbolSearch| - Search for symbols in the workspace.
Options:
`-relative` Show file paths in the results relative to the working dir
=============================================================================== ===============================================================================
6. Global Options *ale-options* 6. Global Options *ale-options*
@@ -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 This setting should not be enabled if you wish to use ALE as a completion
source for other completion plugins. 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 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. 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. ALE's completion support must be enabled globally to be enabled locally.
See |ale-completion| 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 Type: Number
Default: `0` 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 including those that are a warning. Warnings can be excluded from completed
items by setting it to `1`. items by setting it to `1`.
g:ale_completion_autoimport *g:ale_completion_autoimport* g:ale_completion_autoimport *g:ale_completion_autoimport*
Type: Number Type: Number
@@ -807,7 +914,7 @@ g:ale_default_navigation *g:ale_default_navigation*
Default: `'buffer'` Default: `'buffer'`
The default method for navigating away from the current buffer to another The default method for navigating away from the current buffer to another
buffer, such as for |ALEFindReferences:|, or |ALEGoToDefinition|. buffer, such as for |ALEFindReferences|, or |ALEGoToDefinition|.
g:ale_disable_lsp *g:ale_disable_lsp* g:ale_disable_lsp *g:ale_disable_lsp*
@@ -1118,7 +1225,7 @@ g:ale_list_window_size *g:ale_list_window_size*
g:ale_lint_delay *g:ale_lint_delay* g:ale_lint_delay *g:ale_lint_delay*
*b:ale_lint_delay*
Type: |Number| Type: |Number|
Default: `200` Default: `200`
@@ -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 be run after text is changed. This option is only meaningful with the
|g:ale_lint_on_text_changed| variable set to `always`, `insert`, or `normal`. |g:ale_lint_on_text_changed| variable set to `always`, `insert`, or `normal`.
A buffer-local option, `b:ale_lint_delay`, can be set to change the delay
for different buffers, such as in |ftplugin| files.
g:ale_lint_on_enter *g:ale_lint_on_enter* g:ale_lint_on_enter *g:ale_lint_on_enter*
@@ -1283,6 +1393,90 @@ g:ale_linter_aliases *g:ale_linter_aliases*
< <
No linters will be loaded when the buffer's filetype is empty. No linters will be loaded when the buffer's filetype is empty.
g:ale_filename_mappings *g:ale_filename_mappings*
*b:ale_filename_mappings*
Type: |Dictionary| or |List|
Default: `{}`
Either a |Dictionary| mapping a linter or fixer name, as displayed in
|:ALEInfo|, to a |List| of two-item |List|s for filename mappings, or just a
|List| of two-item |List|s. When given some paths to files, the value of
this setting will be used to convert filenames on a local file system to
filenames on some remote file system, such as paths in a Docker image,
virtual machine, or network drive.
For example: >
let g:ale_filename_mappings = {
\ 'pylint': [
\ ['/home/john/proj', '/data'],
\ ],
\}
<
With the above configuration, a filename such as `/home/john/proj/foo.py`
will be provided to the linter/fixer as `/data/foo.py`, and paths parsed
from linter results such as `/data/foo.py` will be converted back to
`/home/john/proj/foo.py`.
You can use `*` as to apply a |List| of filename mappings to all other
linters or fixers not otherwise matched. >
" Use one List of paths for pylint.
" Use another List of paths for everything else.
let g:ale_filename_mappings = {
\ 'pylint': [
\ ['/home/john/proj', '/data'],
\ ],
\ '*': [
\ ['/home/john/proj', '/other-data'],
\ ],
\}
<
If you just want every single linter or fixer to use the same filename
mapping, you can just use a |List|. >
" Same as above, but for ALL linters and fixers.
let g:ale_filename_mappings = [
\ ['/home/john/proj', '/data'],
\]
<
You can provide many such filename paths for multiple projects. Paths are
matched by checking if the start of a file path matches the given strings,
in a case-sensitive manner. Earlier entries in the |List| will be tried
before later entries when mapping to a given file system.
Buffer-local options can be set to the same values to override the global
options, such as in |ftplugin| files.
NOTE: Only fixers registered with a short name can support filename mapping
by their fixer names. See |ale-fix|. Filename mappings set for all tools by
using only a |List| for the setting will also be applied to fixers not in
the registry.
NOTE: In order for this filename mapping to work correctly, linters and
fixers must exclusively determine paths to files to lint or fix via ALE
command formatting as per |ale-command-format-strings|, and paths parsed
from linter files must be provided in `filename` keys if a linter returns
results for more than one file at a time, as per |ale-loclist-format|. If
you discover a linter or fixer which does not behave properly, please report
it as an issue.
If you are running a linter or fixer through Docker or another remote file
system, you may have to mount your temporary directory, which you can
discover with the following command: >
:echo fnamemodify(tempname(), ':h:h')
<
You should provide a mapping from this temporary directory to whatever you
mount this directory to in Docker, or whatever remote file system you are
working with.
You can inspect the filename mappings ALE will use with the
|ale#GetFilenameMappings()| function.
g:ale_linters *g:ale_linters* g:ale_linters *g:ale_linters*
*b:ale_linters* *b:ale_linters*
Type: |Dictionary| Type: |Dictionary|
@@ -1303,7 +1497,7 @@ g:ale_linters *g:ale_linters*
\ 'perl': ['perlcritic'], \ 'perl': ['perlcritic'],
\ 'perl6': [], \ 'perl6': [],
\ 'python': ['flake8', 'mypy', 'pylint', 'pyright'], \ 'python': ['flake8', 'mypy', 'pylint', 'pyright'],
\ 'rust': ['cargo'], \ 'rust': ['cargo', 'rls'],
\ 'spec': [], \ 'spec': [],
\ 'text': [], \ 'text': [],
\ 'vue': ['eslint', 'vls'], \ 'vue': ['eslint', 'vls'],
@@ -2319,16 +2513,15 @@ documented in additional help files.
bibclean..............................|ale-bib-bibclean| bibclean..............................|ale-bib-bibclean|
c.......................................|ale-c-options| c.......................................|ale-c-options|
astyle................................|ale-c-astyle| astyle................................|ale-c-astyle|
clang.................................|ale-c-clang| cc....................................|ale-c-cc|
ccls..................................|ale-c-ccls|
clangd................................|ale-c-clangd| clangd................................|ale-c-clangd|
clang-format..........................|ale-c-clangformat| clang-format..........................|ale-c-clangformat|
clangtidy.............................|ale-c-clangtidy| clangtidy.............................|ale-c-clangtidy|
cppcheck..............................|ale-c-cppcheck| cppcheck..............................|ale-c-cppcheck|
cquery................................|ale-c-cquery| cquery................................|ale-c-cquery|
flawfinder............................|ale-c-flawfinder| flawfinder............................|ale-c-flawfinder|
gcc...................................|ale-c-gcc|
uncrustify............................|ale-c-uncrustify| uncrustify............................|ale-c-uncrustify|
ccls..................................|ale-c-ccls|
chef....................................|ale-chef-options| chef....................................|ale-chef-options|
cookstyle.............................|ale-chef-cookstyle| cookstyle.............................|ale-chef-cookstyle|
foodcritic............................|ale-chef-foodcritic| foodcritic............................|ale-chef-foodcritic|
@@ -2342,9 +2535,10 @@ documented in additional help files.
cmake-format..........................|ale-cmake-cmakeformat| cmake-format..........................|ale-cmake-cmakeformat|
cpp.....................................|ale-cpp-options| cpp.....................................|ale-cpp-options|
astyle................................|ale-cpp-astyle| astyle................................|ale-cpp-astyle|
clang.................................|ale-cpp-clang| cc....................................|ale-cpp-cc|
clangd................................|ale-cpp-clangd| ccls..................................|ale-cpp-ccls|
clangcheck............................|ale-cpp-clangcheck| clangcheck............................|ale-cpp-clangcheck|
clangd................................|ale-cpp-clangd|
clang-format..........................|ale-cpp-clangformat| clang-format..........................|ale-cpp-clangformat|
clangtidy.............................|ale-cpp-clangtidy| clangtidy.............................|ale-cpp-clangtidy|
clazy.................................|ale-cpp-clazy| clazy.................................|ale-cpp-clazy|
@@ -2352,9 +2546,7 @@ documented in additional help files.
cpplint...............................|ale-cpp-cpplint| cpplint...............................|ale-cpp-cpplint|
cquery................................|ale-cpp-cquery| cquery................................|ale-cpp-cquery|
flawfinder............................|ale-cpp-flawfinder| flawfinder............................|ale-cpp-flawfinder|
gcc...................................|ale-cpp-gcc|
uncrustify............................|ale-cpp-uncrustify| uncrustify............................|ale-cpp-uncrustify|
ccls..................................|ale-cpp-ccls|
c#......................................|ale-cs-options| c#......................................|ale-cs-options|
csc...................................|ale-cs-csc| csc...................................|ale-cs-csc|
mcs...................................|ale-cs-mcs| mcs...................................|ale-cs-mcs|
@@ -2506,6 +2698,7 @@ documented in additional help files.
luac..................................|ale-lua-luac| luac..................................|ale-lua-luac|
luacheck..............................|ale-lua-luacheck| luacheck..............................|ale-lua-luacheck|
markdown................................|ale-markdown-options| markdown................................|ale-markdown-options|
markdownlint..........................|ale-markdown-markdownlint|
mdl...................................|ale-markdown-mdl| mdl...................................|ale-markdown-mdl|
prettier..............................|ale-markdown-prettier| prettier..............................|ale-markdown-prettier|
remark-lint...........................|ale-markdown-remark-lint| 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 The default method used for navigating to a new location can be changed
by modifying |g:ale_default_navigation|. by modifying |g:ale_default_navigation|.
You can add `-relative` to the command to view results with relatives paths,
instead of absolute paths.
The selection can be opened again with the |ALERepeatSelection| command. The selection can be opened again with the |ALERepeatSelection| command.
You can jump back to the position you were at before going to a reference of You can jump back to the position you were at before going to a reference of
something with jump motions like CTRL-O. See |jump-motions|. something with jump motions like CTRL-O. See |jump-motions|.
A plug mapping `<Plug>(ale_find_references)` is defined for this command. A plug mapping `<Plug>(ale_find_references)` is defined for this command.
You can define additional plug mapping with any additional options you want
like so: >
nnoremap <silent> <Plug>(my_mapping) :ALEFindReferences -relative<Return>
<
ALEFix *ALEFix* ALEFix *ALEFix*
@@ -2812,7 +3012,13 @@ ALEGoToDefinition `<options>` *ALEGoToDefinition*
command. Otherwise, Vim will refuse to leave the buffer you're jumping from command. Otherwise, Vim will refuse to leave the buffer you're jumping from
unless you have saved your edits. 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* ALEGoToTypeDefinition *ALEGoToTypeDefinition*
@@ -2834,8 +3040,13 @@ ALEGoToTypeDefinition *ALEGoToTypeDefinition*
You can jump back to the position you were at before going to the definition 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|. of something with jump motions like CTRL-O. See |jump-motions|.
A plug mapping `<Plug>(ale_go_to_type_definition)` is defined for this The following Plug mappings are defined for this command, which correspond
command. 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* ALEHover *ALEHover*
@@ -2851,6 +3062,23 @@ ALEHover *ALEHover*
A plug mapping `<Plug>(ale_hover)` is defined for this command. 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* ALEOrganizeImports *ALEOrganizeImports*
Organize imports using tsserver. Currently not implemented for LSPs. Organize imports using tsserver. Currently not implemented for LSPs.
@@ -2858,9 +3086,10 @@ ALEOrganizeImports *ALEOrganizeImports*
ALERename *ALERename* 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* ALERepeatSelection *ALERepeatSelection*
@@ -2875,14 +3104,17 @@ ALESymbolSearch `<query>` *ALESymbolSearch*
The arguments provided to this command will be used as a search query for The arguments provided to this command will be used as a search query for
finding symbols in the workspace, such as functions, types, etc. finding symbols in the workspace, such as functions, types, etc.
You can add `-relative` to the command to view results with relatives paths,
instead of absolute paths.
*:ALELint* *:ALELint*
ALELint *ALELint* ALELint *ALELint*
Run ALE once for the current buffer. This command can be used to run ALE Run ALE once for the current buffer. This command can be used to run ALE
manually, instead of automatically, if desired. manually, instead of automatically, if desired.
This command will also run linters where `lint_file` is set to `1`, or in This command will also run linters where `lint_file` is evaluates to `1`,
other words linters which check the file instead of the Vim buffer. meaning linters which check the file instead of the Vim buffer.
A plug mapping `<Plug>(ale_lint)` is defined for this command. A plug mapping `<Plug>(ale_lint)` is defined for this command.
@@ -3064,6 +3296,15 @@ ale#Env(variable_name, value) *ale#Env()*
'set VAR="some value" && command' # On Windows 'set VAR="some value" && command' # On Windows
ale#GetFilenameMappings(buffer, name) *ale#GetFilenameMappings()*
Given a `buffer` and the `name` of either a linter for fixer, return a
|List| of two-item |List|s that describe mapping to and from the local and
foreign file systems for running a particular linter or fixer.
See |g:ale_filename_mappings| for details on filename mapping.
ale#Has(feature) *ale#Has()* ale#Has(feature) *ale#Has()*
Return `1` if ALE supports a given feature, like |has()| for Vim features. Return `1` if ALE supports a given feature, like |has()| for Vim features.
@@ -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 The linters will always be run in the background. Calling this function
again from the same buffer again from the same buffer
An optional `linting_flag` argument can be given. If `linting_flag` An optional `linting_flag` argument can be given. If `linting_flag` is
is `'lint_file'`, then linters where the `lint_file` option is set to `1` will be `'lint_file'`, then linters where the `lint_file` option evaluates to `1`
run. Linters with `lint_file` set to `1` are not run by default. will be run. Otherwise, those linters will not be run.
An optional `buffer_number` argument can be given for specifying the buffer An optional `buffer_number` argument can be given for specifying the buffer
to check. The active buffer (`bufnr('')`) will be checked by default. to check. The active buffer (`bufnr('')`) will be checked by default.
@@ -3178,23 +3419,36 @@ ale#command#Run(buffer, command, callback, [options]) *ale#command#Run()*
< <
The following `options` can be provided. The following `options` can be provided.
`output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or `'none`' for `output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or
selecting which output streams to read lines from. `'none`' for selecting which output streams to read
lines from.
The default is `'stdout'` The default is `'stdout'`
`executable` - An executable for formatting into `%e` in the command. `executable` - An executable for formatting into `%e` in the
If this option is not provided, formatting commands with command. If this option is not provided, formatting
`%e` will not work. commands with `%e` will not work.
`read_buffer` - If set to `1`, the buffer will be piped into the `read_buffer` - If set to `1`, the buffer will be piped into the
command. command.
The default is `0`. The default is `0`.
`input` - When creating temporary files with `%t` or piping
text 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 `[]`.
`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.
ale#command#EscapeCommandPart(command_part) *ale#command#EscapeCommandPart()* 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 if a command manually reads from a temporary file
instead, etc. instead, etc.
This option behaves as if it was set to `0` when the
`lint_file` option evaluates to `1`.
*ale-lint-file* *ale-lint-file*
`lint_file` A |Number| (`0` or `1`) indicating whether a command `lint_file` A |Number| (`0` or `1`), or a |Funcref| for a function
should read the file instead of the Vim buffer. This accepting a buffer number for computing either `0` or
option can be used for linters which must check the `1`, indicating whether a command should read the file
file on disk, and which cannot check a Vim buffer instead of the Vim buffer. This option can be used
instead. for linters which must check the file on disk, and
which cannot check a Vim buffer instead.
Linters set with this option will not be run as a The result can be computed with |ale#command#Run()|.
user types, per |g:ale_lint_on_text_changed|. Linters
will instead be run only when events occur against
the file on disk, including |g:ale_lint_on_enter|
and |g:ale_lint_on_save|. Linters with this option
set to `1` will also be run when linters are run
manually, per |ALELintPost-autocmd|.
When this option is set to `1`, `read_buffer` will Linters where the eventual value of this option
be set automatically to `0`. The two options cannot evaluates to `1` will not be run as a user types, per
be used together. |g:ale_lint_on_text_changed|. Linters will instead be
run only when events occur against the file on disk,
including |g:ale_lint_on_enter| and
|g:ale_lint_on_save|. Linters where this option
evaluates to `1` will also be run when the |ALELint|
command is run.
When this option is evaluates to `1`, ALE will behave
as if `read_buffer` was set to `0`.
*ale-lsp-linters* *ale-lsp-linters*
`lsp` A |String| for defining LSP (Language Server Protocol) `lsp` A |String| for defining LSP (Language Server Protocol)
@@ -3565,6 +3825,16 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
command, so literal character sequences `%s` and `%t` can be escaped by command, so literal character sequences `%s` and `%t` can be escaped by
using `%%s` and `%%t` instead, etc. using `%%s` and `%%t` instead, etc.
Some |filename-modifiers| can be applied to `%s` and `%t`. Only `:h`, `:t`,
`:r`, and `:e` may be applied, other modifiers will be ignored. Filename
modifiers can be applied to the format markers by placing them after them.
For example: >
'command': '%s:h %s:e %s:h:t',
<
Given a path `/foo/baz/bar.txt`, the above command string will generate
something akin to `'/foo/baz' 'txt' 'baz'`
If a callback for a command generates part of a command string which might If a callback for a command generates part of a command string which might
possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting possibly contain `%%`, `%s`, `%t`, or `%e`, where the special formatting
behavior is not desired, the |ale#command#EscapeCommandPart()| function can behavior is not desired, the |ale#command#EscapeCommandPart()| function can
+15 -18
View File
@@ -97,6 +97,10 @@ let g:ale_fix_on_save = get(g:, 'ale_fix_on_save', 0)
" should be used instead. " should be used instead.
let g:ale_enabled = get(g:, 'ale_enabled', 1) let g:ale_enabled = get(g:, 'ale_enabled', 1)
" A Dictionary mapping linter or fixer names to Arrays of two-item Arrays
" mapping filename paths from one system to another.
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
" These flags dictates if ale uses the quickfix or the loclist (loclist is the " These flags dictates if ale uses the quickfix or the loclist (loclist is the
" default, quickfix overrides loclist). " default, quickfix overrides loclist).
let g:ale_set_loclist = get(g:, 'ale_set_loclist', 1) let g:ale_set_loclist = get(g:, 'ale_set_loclist', 1)
@@ -207,19 +211,9 @@ command! -bar ALEFixSuggest :call ale#fix#registry#Suggest(&filetype)
" Go to definition for tsserver and LSP " Go to definition for tsserver and LSP
command! -bar -nargs=* ALEGoToDefinition :call ale#definition#GoToCommandHandler('', <f-args>) 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 " Go to type definition for tsserver and LSP
command! -bar -nargs=* ALEGoToTypeDefinition :call ale#definition#GoToCommandHandler('type', <f-args>) 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 " Repeat a previous selection in the preview window
command! -bar ALERepeatSelection :call ale#preview#RepeatSelection() 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. " Search for appearances of a symbol, such as a type name or function name.
command! -nargs=1 ALESymbolSearch :call ale#symbol#Search(<q-args>) 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') 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 " Rename symbols using tsserver and LSP
command! -bar ALERename :call ale#rename#Execute() 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_detail) :ALEDetail<Return>
nnoremap <silent> <Plug>(ale_fix) :ALEFix<Return> nnoremap <silent> <Plug>(ale_fix) :ALEFix<Return>
nnoremap <silent> <Plug>(ale_go_to_definition) :ALEGoToDefinition<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) :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_find_references) :ALEFindReferences<Return>
nnoremap <silent> <Plug>(ale_hover) :ALEHover<Return> nnoremap <silent> <Plug>(ale_hover) :ALEHover<Return>
nnoremap <silent> <Plug>(ale_documentation) :ALEDocumentation<Return> nnoremap <silent> <Plug>(ale_documentation) :ALEDocumentation<Return>
inoremap <silent> <Plug>(ale_complete) <C-\><C-O>:ALEComplete<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_rename) :ALERename<Return>
nnoremap <silent> <Plug>(ale_repeat_selection) :ALERepeatSelection<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. " Set up autocmd groups now.
call ale#events#Init() call ale#events#Init()
+8
View File
@@ -83,6 +83,13 @@ while [ $# -ne 0 ]; do
run_neovim_03_tests=0 run_neovim_03_tests=0
shift shift
;; ;;
--fast)
run_vim_80_tests=0
run_vim_81_tests=0
run_neovim_02_tests=0
run_neovim_03_tests=1
shift
;;
--help) --help)
echo 'Usage: ./run-tests [OPTION]... [FILE]...' echo 'Usage: ./run-tests [OPTION]... [FILE]...'
echo echo
@@ -99,6 +106,7 @@ while [ $# -ne 0 ]; do
echo ' --vim-80-only Run tests only for Vim 8.0' echo ' --vim-80-only Run tests only for Vim 8.0'
echo ' --vim-81-only Run tests only for Vim 8.1' echo ' --vim-81-only Run tests only for Vim 8.1'
echo ' --linters-only Run only Vint and custom checks' 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 ' --help Show this help text'
echo ' -- Stop parsing options after this' echo ' -- Stop parsing options after this'
exit 0 exit 0
+7 -4
View File
@@ -16,7 +16,7 @@ formatting.
| Key | Definition | | Key | Definition |
| ------------- | -------------------------------- | | ------------- | -------------------------------- |
| :floppy_disk: | Only checked when saved to disk | | :floppy_disk: | May only run on files on disk |
| :warning: | Disabled by default | | :warning: | Disabled by default |
--- ---
@@ -30,6 +30,7 @@ formatting.
* [drafter](https://github.com/apiaryio/drafter) * [drafter](https://github.com/apiaryio/drafter)
* AsciiDoc * AsciiDoc
* [alex](https://github.com/wooorm/alex) :floppy_disk: * [alex](https://github.com/wooorm/alex) :floppy_disk:
* [languagetool](https://languagetool.org/) :floppy_disk:
* [proselint](http://proselint.com/) * [proselint](http://proselint.com/)
* [redpen](http://redpen.cc/) * [redpen](http://redpen.cc/)
* [textlint](https://textlint.github.io/) * [textlint](https://textlint.github.io/)
@@ -128,9 +129,9 @@ formatting.
* [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt) * [dartfmt](https://github.com/dart-lang/sdk/tree/master/utils/dartfmt)
* [language_server](https://github.com/natebosch/dart_language_server) * [language_server](https://github.com/natebosch/dart_language_server)
* Dhall * Dhall
* [dhall-format](https://github.com/dhall-lang) * [dhall-format](https://github.com/dhall-lang/dhall-lang)
* [dhall-freeze](https://github.com/dhall-lang) * [dhall-freeze](https://github.com/dhall-lang/dhall-lang)
* [dhall-lint](https://github.com/dhall-lang) * [dhall-lint](https://github.com/dhall-lang/dhall-lang)
* Dockerfile * Dockerfile
* [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint) * [dockerfile_lint](https://github.com/projectatomic/dockerfile_lint)
* [hadolint](https://github.com/hadolint/hadolint) * [hadolint](https://github.com/hadolint/hadolint)
@@ -459,6 +460,7 @@ formatting.
* [sqlfmt](https://github.com/jackc/sqlfmt) * [sqlfmt](https://github.com/jackc/sqlfmt)
* [sqlformat](https://github.com/andialbrecht/sqlparse) * [sqlformat](https://github.com/andialbrecht/sqlparse)
* [sqlint](https://github.com/purcell/sqlint) * [sqlint](https://github.com/purcell/sqlint)
* [sql-lint](https://github.com/joereynolds/sql-lint)
* Stylus * Stylus
* [stylelint](https://github.com/stylelint/stylelint) * [stylelint](https://github.com/stylelint/stylelint)
* SugarSS * SugarSS
@@ -466,6 +468,7 @@ formatting.
* Swift * Swift
* [sourcekit-lsp](https://github.com/apple/sourcekit-lsp) * [sourcekit-lsp](https://github.com/apple/sourcekit-lsp)
* [swiftformat](https://github.com/nicklockwood/SwiftFormat) * [swiftformat](https://github.com/nicklockwood/SwiftFormat)
* [swift-format](https://github.com/apple/swift-format)
* [swiftlint](https://github.com/realm/SwiftLint) * [swiftlint](https://github.com/realm/SwiftLint)
* Tcl * Tcl
* [nagelfar](http://nagelfar.sourceforge.net) :floppy_disk: * [nagelfar](http://nagelfar.sourceforge.net) :floppy_disk:
@@ -18,11 +18,10 @@ After:
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()
Execute(The executable should be configurable): Execute(The executable should be configurable):
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') . ' -x ada -c -gnatc' \ ale#Escape('gcc') . ' -x ada -c -gnatc'
\ . ' -o ' . b:out_file \ . ' -o ' . b:out_file
\ . ' -I ' . ale#Escape(getcwd()) \ . ' -I %s:h'
\ . ' -gnatwa -gnatq %t' \ . ' -gnatwa -gnatq %t'
let b:ale_ada_gcc_executable = 'foo' let b:ale_ada_gcc_executable = 'foo'
@@ -30,15 +29,14 @@ Execute(The executable should be configurable):
AssertLinter 'foo', AssertLinter 'foo',
\ ale#Escape('foo') . ' -x ada -c -gnatc' \ ale#Escape('foo') . ' -x ada -c -gnatc'
\ . ' -o ' . b:out_file \ . ' -o ' . b:out_file
\ . ' -I ' . ale#Escape(getcwd()) \ . ' -I %s:h'
\ . ' -gnatwa -gnatq %t' \ . ' -gnatwa -gnatq %t'
Execute(The options should be configurable): Execute(The options should be configurable):
let g:ale_ada_gcc_options = '--foo --bar' let g:ale_ada_gcc_options = '--foo --bar'
AssertLinter 'gcc', AssertLinter 'gcc',
\ ale#Escape('gcc') . ' -x ada -c -gnatc' \ ale#Escape('gcc') . ' -x ada -c -gnatc'
\ . ' -o ' . b:out_file \ . ' -o ' . b:out_file
\ . ' -I ' . ale#Escape(getcwd()) \ . ' -I %s:h'
\ . ' --foo --bar %t' \ . ' --foo --bar %t'
@@ -3,7 +3,7 @@ Before:
call ale#test#SetFilename('test.cpp') call ale#test#SetFilename('test.cpp')
let b:command_tail = ' -x assembler' let b:command_tail = ' -x assembler'
\ . ' -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -o ' . (has('win32') ? 'nul': '/dev/null')
\ . '-iquote ' . ale#Escape(g:dir) \ . '-iquote %s:h'
\ . ' -Wall -' \ . ' -Wall -'
After: After:
@@ -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
@@ -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]
@@ -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]
+42 -128
View File
@@ -7,6 +7,7 @@ Before:
Save g:__ale_c_project_filenames Save g:__ale_c_project_filenames
let g:original_project_filenames = 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. " Remove the .git/HEAD dir for C import paths for these tests.
" The tests run inside of a git repo. " 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_compile_commands = 0
let g:ale_c_parse_makefile = 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: After:
Restore Restore
unlet! g:original_project_filenames unlet! g:original_project_filenames
unlet! g:executable_map
runtime autoload/ale/engine.vim
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()
Execute(The C GCC handler should include 'include' directories for projects with a Makefile): Execute(The C cc linter should include 'include' directories for projects with a Makefile):
call ale#assert#SetUpLinterTest('c', 'gcc') call ale#assert#SetUpLinterTest('c', 'cc')
call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.c') 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', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
\ . ' -' \ . ' -'
Execute(The C GCC handler should include 'include' directories for projects with a configure file): Execute(The C cc linter should include 'include' directories for projects with a configure file):
call ale#assert#SetUpLinterTest('c', 'gcc') call ale#assert#SetUpLinterTest('c', 'cc')
call ale#test#SetFilename('../test_c_projects/configure_project/subdir/file.c') 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', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include'))
\ . ' -' \ . ' -'
Execute(The C GCC handler should include root directories for projects with .h files in them): Execute(The C cc linter should include root directories for projects with .h files in them):
call ale#assert#SetUpLinterTest('c', 'gcc') call ale#assert#SetUpLinterTest('c', 'cc')
call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.c') 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', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
\ . ' -' \ . ' -'
Execute(The C GCC handler should include root directories for projects with .hpp files in them): Execute(The C cc linter should include root directories for projects with .hpp files in them):
call ale#assert#SetUpLinterTest('c', 'gcc') call ale#assert#SetUpLinterTest('c', 'cc')
call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.c') 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', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
\ . ' -'
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'))
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
\ . ' -' \ . ' -'
@@ -131,99 +93,51 @@ Execute(The C ClangTidy handler should include 'include' directories for project
\ . ' %s ' \ . ' %s '
\ . '-- -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include')) \ . '-- -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
Execute(The C++ GCC handler should include 'include' directories for projects with a Makefile): Execute(The C++ cc linter should include 'include' directories for projects with a Makefile):
call ale#assert#SetUpLinterTest('cpp', 'gcc') call ale#assert#SetUpLinterTest('cpp', 'cc')
call ale#test#SetFilename('../test_c_projects/makefile_project/subdir/file.cpp') 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', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/makefile_project/include'))
\ . ' -' \ . ' -'
Execute(The C++ GCC handler should include 'include' directories for projects with a configure file): Execute(The C++ cc linter should include 'include' directories for projects with a configure file):
call ale#assert#SetUpLinterTest('cpp', 'gcc') call ale#assert#SetUpLinterTest('cpp', 'cc')
call ale#test#SetFilename('../test_c_projects/configure_project/subdir/file.cpp') 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', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/configure_project/include'))
\ . ' -' \ . ' -'
Execute(The C++ GCC handler should include root directories for projects with .h files in them): Execute(The C++ cc linter should include root directories for projects with .h files in them):
call ale#assert#SetUpLinterTest('cpp', 'gcc') call ale#assert#SetUpLinterTest('cpp', 'cc')
call ale#test#SetFilename('../test_c_projects/h_file_project/subdir/file.cpp') 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', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/h_file_project'))
\ . ' -' \ . ' -'
Execute(The C++ GCC handler should include root directories for projects with .hpp files in them): Execute(The C++ cc linter should include root directories for projects with .hpp files in them):
call ale#assert#SetUpLinterTest('cpp', 'gcc') call ale#assert#SetUpLinterTest('cpp', 'cc')
call ale#test#SetFilename('../test_c_projects/hpp_file_project/subdir/file.cpp') 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', AssertLinter 'gcc',
\ ale#Escape('gcc') \ ale#Escape('gcc')
\ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null') \ . ' -S -x c++ -o ' . (has('win32') ? 'nul': '/dev/null')
\ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project/subdir')) \ . ' -iquote %s:h'
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
\ . ' -'
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'))
\ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project')) \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/../test_c_projects/hpp_file_project'))
\ . ' -' \ . ' -'
@@ -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
@@ -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
@@ -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
@@ -8,6 +8,18 @@ After:
call ale#assert#TearDownLinterTest() 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): Execute(Builds credo command with --strict mode when set to 1):
let g:ale_elixir_credo_strict = 1 let g:ale_elixir_credo_strict = 1
@@ -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'
@@ -34,13 +34,52 @@ Execute(The flake8 callbacks should return the correct default values):
\] \]
Execute(The option for disabling changing directories should work): 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', [ AssertLinter 'flake8', [
\ ale#Escape('flake8') . ' --version', \ ale#Escape('flake8') . ' --version',
\ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \ 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): Execute(The flake8 command callback should let you set options):
let g:ale_python_flake8_options = '--some-option' 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') call ale#test#SetFilename('../python_fixtures/pipenv/whatever.py')
AssertLinter 'pipenv', AssertLinter 'pipenv',
\ ale#path#BufferCdString(bufnr('')) \ ale#path#CdString(ale#python#FindProjectRootIni(bufnr('')))
\ . ale#Escape('pipenv') . ' run flake8 --format=default --stdin-display-name %s -' \ . ale#Escape('pipenv') . ' run flake8 --format=default --stdin-display-name %s -'
@@ -11,14 +11,14 @@ After:
Execute(The default commands should be correct): Execute(The default commands should be correct):
AssertLinter 'go', AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'go test -c -o /dev/null ./' \ . 'go test -c -o /dev/null ./'
Execute(Go environment variables should be supported): Execute(Go environment variables should be supported):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'go', AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on') \ . ale#Env('GO111MODULE', 'on')
\ . 'go test -c -o /dev/null ./' \ . 'go test -c -o /dev/null ./'
@@ -28,7 +28,7 @@ Execute(Extra options should be supported):
let g:ale_go_gobuild_options = '--foo-bar' let g:ale_go_gobuild_options = '--foo-bar'
AssertLinter 'go', AssertLinter 'go',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'go test --foo-bar -c -o /dev/null ./' \ . 'go test --foo-bar -c -o /dev/null ./'
let g:ale_go_gobuild_options = '' let g:ale_go_gobuild_options = ''
@@ -37,5 +37,5 @@ Execute(The executable should be configurable):
let g:ale_go_go_executable = 'foobar' let g:ale_go_go_executable = 'foobar'
AssertLinter 'foobar', AssertLinter 'foobar',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . 'foobar test -c -o /dev/null ./' \ . 'foobar test -c -o /dev/null ./'
@@ -1,5 +1,8 @@
Before: Before:
Save g:ale_go_go111module Save g:ale_go_go111module
Save b:ale_go_go111module
let b:ale_go_go111module = ''
call ale#assert#SetUpLinterTest('go', 'gofmt') call ale#assert#SetUpLinterTest('go', 'gofmt')
call ale#test#SetFilename('../go_files/testfile2.go') call ale#test#SetFilename('../go_files/testfile2.go')
@@ -13,7 +13,7 @@ After:
Execute(The golangci-lint defaults should be correct): Execute(The golangci-lint defaults should be correct):
AssertLinter 'golangci-lint', AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint') \ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --enable-all' \ . ' --enable-all'
@@ -22,7 +22,7 @@ Execute(The golangci-lint callback should use a configured executable):
let b:ale_go_golangci_lint_executable = 'something else' let b:ale_go_golangci_lint_executable = 'something else'
AssertLinter 'something else', AssertLinter 'something else',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('something else') \ . ale#Escape('something else')
\ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --enable-all' \ . ' --enable-all'
@@ -31,7 +31,7 @@ Execute(The golangci-lint callback should use configured options):
let b:ale_go_golangci_lint_options = '--foobar' let b:ale_go_golangci_lint_options = '--foobar'
AssertLinter 'golangci-lint', AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint') \ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' run ' . ale#Escape(expand('%' . ':t'))
\ . ' --foobar' \ . ' --foobar'
@@ -40,7 +40,7 @@ Execute(The golangci-lint callback should support environment variables):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'golangci-lint', AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on') \ . ale#Env('GO111MODULE', 'on')
\ . ale#Escape('golangci-lint') \ . ale#Escape('golangci-lint')
\ . ' run ' . ale#Escape(expand('%' . ':t')) \ . ' run ' . ale#Escape(expand('%' . ':t'))
@@ -50,5 +50,5 @@ Execute(The golangci-lint `lint_package` option should use the correct command):
let b:ale_go_golangci_lint_package = 1 let b:ale_go_golangci_lint_package = 1
AssertLinter 'golangci-lint', AssertLinter 'golangci-lint',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('golangci-lint') . ' run --enable-all' \ . ale#Escape('golangci-lint') . ' run --enable-all'
@@ -13,7 +13,7 @@ After:
Execute(The gometalinter defaults should be correct): Execute(The gometalinter defaults should be correct):
AssertLinter 'gometalinter', AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter') \ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t'))) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' .' \ . ' .'
@@ -22,7 +22,7 @@ Execute(The gometalinter callback should use a configured executable):
let b:ale_go_gometalinter_executable = 'something else' let b:ale_go_gometalinter_executable = 'something else'
AssertLinter 'something else', AssertLinter 'something else',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('something else') \ . ale#Escape('something else')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t'))) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' .' \ . ' .'
@@ -31,7 +31,7 @@ Execute(The gometalinter callback should use configured options):
let b:ale_go_gometalinter_options = '--foobar' let b:ale_go_gometalinter_options = '--foobar'
AssertLinter 'gometalinter', AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter') \ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t'))) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
\ . ' --foobar' . ' .' \ . ' --foobar' . ' .'
@@ -40,7 +40,7 @@ Execute(The gometalinter should use configured environment variables):
let b:ale_go_go111module = 'off' let b:ale_go_go111module = 'off'
AssertLinter 'gometalinter', AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'off') \ . ale#Env('GO111MODULE', 'off')
\ . ale#Escape('gometalinter') \ . ale#Escape('gometalinter')
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t'))) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(expand('%' . ':t')))
@@ -50,5 +50,5 @@ Execute(The gometalinter `lint_package` option should use the correct command):
let b:ale_go_gometalinter_lint_package = 1 let b:ale_go_gometalinter_lint_package = 1
AssertLinter 'gometalinter', AssertLinter 'gometalinter',
\ ale#path#CdString(expand('%:p:h')) \ ale#path#BufferCdString(bufnr(''))
\ . ale#Escape('gometalinter') . ' .' \ . ale#Escape('gometalinter') . ' .'
@@ -11,11 +11,12 @@ After:
Execute(The default gosimple command should be correct): Execute(The default gosimple command should be correct):
AssertLinter 'gosimple', AssertLinter 'gosimple',
\ ale#path#CdString(expand('%:p:h')) . ' gosimple .' \ ale#path#BufferCdString(bufnr(''))
\ . ' gosimple .'
Execute(The gosimple command should support Go environment variables): Execute(The gosimple command should support Go environment variables):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'gosimple', AssertLinter 'gosimple',
\ ale#path#CdString(expand('%:p:h')) . ' ' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on') . 'gosimple .' \ . ' ' . ale#Env('GO111MODULE', 'on') . 'gosimple .'
@@ -11,7 +11,8 @@ After:
Execute(The default gotype command should be correct): Execute(The default gotype command should be correct):
AssertLinter 'gotype', AssertLinter 'gotype',
\ ale#path#CdString(expand('%:p:h')) . ' gotype -e .' \ ale#path#BufferCdString(bufnr(''))
\ . ' gotype -e .'
Execute(The gotype callback should ignore test files): Execute(The gotype callback should ignore test files):
call ale#test#SetFilename('bla_test.go') call ale#test#SetFilename('bla_test.go')
@@ -22,6 +23,6 @@ Execute(The gotype callback should support Go environment variables):
let b:ale_go_go111module = 'on' let b:ale_go_go111module = 'on'
AssertLinter 'gotype', AssertLinter 'gotype',
\ ale#path#CdString(expand('%:p:h')) . ' ' \ ale#path#BufferCdString(bufnr(''))
\ . ale#Env('GO111MODULE', 'on') \ . ' ' . ale#Env('GO111MODULE', 'on')
\ . 'gotype -e .' \ . 'gotype -e .'

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