Compare commits

...
This repository has been archived on 2024-07-19. You can view files and clone it, but cannot push or open issues or pull requests.

23 commits

Author SHA1 Message Date
Marc Cataford
d12774d76a fix: look for yarn pnp when looking for eslint projdir 2021-03-13 20:40:22 -05:00
ourigen
80a48d01be
Fix texlab#GetProjectRoot (#3610)
* Fix texlab GetProjectRoot

* Fix indents in texlab#GetProjectRoot

* Prevent texlab from starting on every tex file

* Update texlab Vader tests

* Fix GetProjectRoot to return parent of .git

Previously, the function returned `../.git/`. We want the function to return the parent directory above that as the project root. This should help pass Vader tests.
2021-03-12 20:40:40 +09:00
Victor Fernandez
c21d6afd2f
Solve #3611 (#3612)
Fix dmd not using dub
2021-03-07 20:20:35 +09:00
Horacio Sanson
8c5081f631
Fix 3605 - set fallback for error detail (#3606)
* Fix 3605 - set fallback for error detail

* Add use case with no detail key

Co-authored-by: Horacio Sanson <horacio@allm.inc>
2021-03-04 20:45:33 +09:00
w0rp
826878c41e
Update documentation for floating window borders 2021-03-01 21:38:14 +00:00
Yen3
1d76fd55a1
Add borders for floating windows in Neovim (#3603)
* Add borders for floating windows in Neovim
* Add docs for floating window border setting

Co-authored-by: w0rp <w0rp@users.noreply.github.com>
2021-03-01 21:36:05 +00:00
w0rp
680ba68d81
#3599 - Use ale_root instead of ale_lsp_root
The `ale_lsp_root` setting is now deprecated, and `ale_root` should be
used instead. The setting will be used for both setting the root easily
for LSP linters, and for running other linters over whole projects.
2021-03-01 20:51:29 +00:00
w0rp
9fe7b1fe6a
Close #2281 - Separate cwd commands from commands
Working directories are now set seperately from the commands so they
can later be swapped out when running linters over projects is
supported, and also better support filename mapping for running linters
on other machines in future.
2021-03-01 20:11:10 +00:00
Antoine Gagné
48fab99a0a
Add support for erlfmt fixer (#3602)
* Add support for `erlfmt`

* Add missing entry to table of contents

* Fix warnings

* Add missing tools to supported tools
2021-02-28 22:31:44 +09:00
serapas
038e4a8c31
Fix ansible-lint linter definition. (#3601)
* Fix ansible-lint linter definition.

Use ansible-lint's feature auto-detection instead of temporary file.
For auto-detection to work, ansible project has to be also a git repository.

Don't use yaml rules. These are checked by yamllint.

Refactor pattern to work with ansible-lint >=5.0 version.

Clean-up obsolete test cases.

* Pull Request changes
2021-02-28 21:43:23 +09:00
Horacio Sanson
7696561555
Fix 3537 - remove -T argument from ruby linter (#3538)
Co-authored-by: Horacio Sanson <horacio@allm.inc>
2021-02-23 16:48:42 +09:00
Jon Parise
90b9597d50
Add a buildifier fixer for Bazel files (#3499)
This fixer enables buildifier's formatting and "lint fix" modes.
Additional options can be provided via `bazel_buildifier_options`.

It also implements some basic logic for guessing the file's type.
buildifier itself usually does this based on the filenames provided on
the command line, but because we're piping our buffer via stdin, we need
to do this manually.
2021-02-21 21:35:26 +09:00
Tomáš Janoušek
2550f5d952
Fixes to code actions (cursor moving, tests, EOL/EOF corner cases) (#3478)
* code_action: Don't move cursor when change covers entire file
* code_action: Refactor/simplify ApplyChanges
* code_action: Fix EOL at EOF corner cases while performing no changes
* code_action: Fix column around EOL corner cases
* code_action: Handle positions out of bounds
* code_action: Add instructions for verifying corner case tests against vscode
2021-02-20 16:16:47 +00:00
Alex LaFroscia
d340710fcf
Support going to type definition with tsserver (#3545) 2021-02-20 16:09:28 +00:00
Risto Stevcev
3ea887d2f4
Added ocamllsp (#3595)
* Added ocamllsp

* Update ordering in docs to be alphabetical

* Updated expected result in test
2021-02-18 23:51:11 +09:00
David Buchan-Swanson
1ee7f6c97b
add support for prettier-ruby to prettier fixer (#3593)
it _does_ need an additional plugin, but when it has the plugin, it
works as expected.
2021-02-18 16:33:02 +09:00
David Balatero
0b35c3a5b9
Make markdown vale linter command configurable with options (#3594)
* Make vale command user-configurable

* Add test for vale options

* Typo in test

Co-authored-by: David Balatero <dbalatero@stripe.com>
2021-02-18 10:10:49 +09:00
Jason Axelson
88d052b5a9
Update elixir-ls link in supported tools (#3588)
https://github.com/elixir-lsp/elixir-ls/ is now the canonical repo: 

> It's now being maintained by proactive volunteers from the Elixir community over at elixir-lsp/elixir-ls. Updates will continue to be published from that repo to the original VS Code extension, so no need to switch plugins if you're using VS Code.

from: https://github.com/JakeBecker/elixir-ls#this-project-has-moved
2021-02-14 23:04:12 +09:00
Mukund Mauji
b30c5c9b51
Allow clangformat to use a local style file (#3587)
* Allow clangformat to use a local style file.

* Add tests.

* Fix Vint issue.

* Improve explanation of feature in documentation.

* Fix failing test.

The test was checking the wrong directory.
2021-02-14 23:03:04 +09:00
Daniel Leong
8cb9f5ef51
mypy: Pass user options before any others (#3582)
This enables us to use a custom `python` exe as the "mypy" executable
and pass `-m mypy` in `mypy_options`
2021-02-11 20:29:23 +00:00
w0rp
3b184f88d3
Bump the ALE version to v3.1.0 2021-02-11 19:47:29 +00:00
Tarik Graba
ea72d66b6d
Verilator current file search path (#3500)
* Simplify verilator linter using ale command format strings
* Verilator Linter: Restructure linter command tests
* Verilator Linter: adds to the handler test the returned filename
* Verilator Linter: add the current file path to the search path
* Verilator Linter: Add the search path to the tests

Co-authored-by: TG <tarik.graba@telecom-paris.fr>
2021-02-11 19:35:25 +00:00
w0rp
1773a496ad
Clean up the hdl_checker test a bit better 2021-02-10 22:10:18 +00:00
168 changed files with 2309 additions and 1335 deletions

View file

@ -81,6 +81,7 @@ other content at [w0rp.com](https://w0rp.com).
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) 20. [How can I run linters or fixers via Docker or a VM?](#faq-vm)
21. [How can I change the borders for floating preview windows?](#faq-window-borders)
<a name="supported-languages"></a> <a name="supported-languages"></a>
@ -907,3 +908,23 @@ 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 correct commands and map filename paths between different file systems. See
`:help ale-lint-other-machines` for the full documentation on how to configure `:help ale-lint-other-machines` for the full documentation on how to configure
ALE to support this. ALE to support this.
<a name="faq-window-borders"></a>
### 5.xxi. How can I change the borders for floating preview windows?
Borders for floating preview windows are enabled by default. You can use the
`g:ale_floating_window_border` setting to configure them.
You could disable the border with an empty list.
```vim
let g:ale_floating_window_border = []
```
If the terminal supports Unicode, you might try setting the value like below, to
make it look nicer.
```vim
let g:ale_floating_window_border = ['│', '─', '╭', '╮', '╯', '╰']
```

View file

@ -1,4 +1,4 @@
" Author: Bjorn Neergaard <bjorn@neersighted.com> " Authors: Bjorn Neergaard <bjorn@neersighted.com>, Vytautas Macionis <vytautas.macionis@manomail.de>
" Description: ansible-lint for ansible-yaml files " Description: ansible-lint for ansible-yaml files
call ale#Set('ansible_ansible_lint_executable', 'ansible-lint') call ale#Set('ansible_ansible_lint_executable', 'ansible-lint')
@ -7,7 +7,7 @@ function! ale_linters#ansible#ansible_lint#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'ansible_ansible_lint_executable') return ale#Var(a:buffer, 'ansible_ansible_lint_executable')
endfunction endfunction
function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort function! ale_linters#ansible#ansible_lint#Handle(buffer, version, lines) abort
for l:line in a:lines[:10] for l:line in a:lines[:10]
if match(l:line, '^Traceback') >= 0 if match(l:line, '^Traceback') >= 0
return [{ return [{
@ -18,11 +18,34 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
endif endif
endfor endfor
let l:version_group = ale#semver#GTE(a:version, [5, 0, 0]) ? '>=5.0.0' : '<5.0.0'
let l:output = []
if '>=5.0.0' is# l:version_group
" Matches patterns line the following:
" test.yml:3:148: syntax-check 'var' is not a valid attribute for a Play
" roles/test/tasks/test.yml:8: [package-latest] [VERY_LOW] Package installs should not use latest
" D:\test\tasks\test.yml:8: [package-latest] [VERY_LOW] package installs should not use latest
let l:pattern = '\v^(%([a-zA-Z]:)?[^:]+):(\d+):%((\d+):)? %(\[([-[:alnum:]]+)\]) %(\[([_[:alnum:]]+)\]) (.*)$'
let l:error_codes = { 'VERY_HIGH': 'E', 'HIGH': 'E', 'MEDIUM': 'W', 'LOW': 'W', 'VERY_LOW': 'W', 'INFO': 'I' }
for l:match in ale#util#GetMatches(a:lines, l:pattern)
if ale#path#IsBufferPath(a:buffer, l:match[1])
call add(l:output, {
\ 'lnum': l:match[2] + 0,
\ 'col': l:match[3] + 0,
\ 'text': l:match[6],
\ 'code': l:match[4],
\ 'type': l:error_codes[l:match[5]],
\})
endif
endfor
endif
if '<5.0.0' is# l:version_group
" Matches patterns line the following: " Matches patterns line the following:
"
" test.yml:35: [EANSIBLE0002] Trailing whitespace " test.yml:35: [EANSIBLE0002] Trailing whitespace
let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$' let l:pattern = '\v^([a-zA-Z]?:?[^:]+):(\d+):?(\d+)?: \[?([[:alnum:]]+)\]? (.*)$'
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)
let l:code = l:match[4] let l:code = l:match[4]
@ -43,14 +66,38 @@ function! ale_linters#ansible#ansible_lint#Handle(buffer, lines) abort
\}) \})
endif endif
endfor endfor
endif
return l:output return l:output
endfunction endfunction
function! ale_linters#ansible#ansible_lint#GetCommand(buffer, version) abort
let l:commands = {
\ '>=5.0.0': '%e --parseable-severity -x yaml',
\ '<5.0.0': '%e -p %t'
\}
let l:command = ale#semver#GTE(a:version, [5, 0]) ? l:commands['>=5.0.0'] : l:commands['<5.0.0']
return l:command
endfunction
call ale#linter#Define('ansible', { call ale#linter#Define('ansible', {
\ 'name': 'ansible_lint', \ 'name': 'ansible_lint',
\ 'aliases': ['ansible', 'ansible-lint'], \ 'aliases': ['ansible', 'ansible-lint'],
\ 'executable': function('ale_linters#ansible#ansible_lint#GetExecutable'), \ 'executable': function('ale_linters#ansible#ansible_lint#GetExecutable'),
\ 'command': '%e -p %t', \ 'command': {buffer -> ale#semver#RunWithVersionCheck(
\ 'callback': 'ale_linters#ansible#ansible_lint#Handle', \ buffer,
\ ale_linters#ansible#ansible_lint#GetExecutable(buffer),
\ '%e --version',
\ function('ale_linters#ansible#ansible_lint#GetCommand'),
\ )},
\ 'callback': {buffer, lines -> ale#semver#RunWithVersionCheck(
\ buffer,
\ ale_linters#ansible#ansible_lint#GetExecutable(buffer),
\ '%e --version',
\ {buffer, version -> ale_linters#ansible#ansible_lint#Handle(
\ buffer,
\ l:version,
\ lines)},
\ )},
\}) \})

View file

@ -5,15 +5,13 @@ call ale#Set('c_cppcheck_executable', 'cppcheck')
call ale#Set('c_cppcheck_options', '--enable=style') call ale#Set('c_cppcheck_options', '--enable=style')
function! ale_linters#c#cppcheck#GetCommand(buffer) abort function! ale_linters#c#cppcheck#GetCommand(buffer) abort
let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer)
let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer) let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer)
let l:buffer_path_include = empty(l:compile_commands_option) let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
\ : '' \ : ''
let l:template = ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') let l:template = ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
return l:cd_command return '%e -q --language=c'
\ . '%e -q --language=c'
\ . l:template \ . l:template
\ . ale#Pad(l:compile_commands_option) \ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options')) \ . ale#Pad(ale#Var(a:buffer, 'c_cppcheck_options'))
@ -25,6 +23,7 @@ call ale#linter#Define('c', {
\ 'name': 'cppcheck', \ 'name': 'cppcheck',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'executable': {b -> ale#Var(b, 'c_cppcheck_executable')}, \ 'executable': {b -> ale#Var(b, 'c_cppcheck_executable')},
\ 'cwd': function('ale#handlers#cppcheck#GetCwd'),
\ 'command': function('ale_linters#c#cppcheck#GetCommand'), \ 'command': function('ale_linters#c#cppcheck#GetCommand'),
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat', \ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\}) \})

View file

@ -5,15 +5,13 @@ call ale#Set('cpp_cppcheck_executable', 'cppcheck')
call ale#Set('cpp_cppcheck_options', '--enable=style') call ale#Set('cpp_cppcheck_options', '--enable=style')
function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
let l:cd_command = ale#handlers#cppcheck#GetCdCommand(a:buffer)
let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer) let l:compile_commands_option = ale#handlers#cppcheck#GetCompileCommandsOptions(a:buffer)
let l:buffer_path_include = empty(l:compile_commands_option) let l:buffer_path_include = empty(l:compile_commands_option)
\ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer) \ ? ale#handlers#cppcheck#GetBufferPathIncludeOptions(a:buffer)
\ : '' \ : ''
let l:template = ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') let l:template = ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
return l:cd_command return '%e -q --language=c++'
\ . '%e -q --language=c++'
\ . l:template \ . l:template
\ . ale#Pad(l:compile_commands_option) \ . ale#Pad(l:compile_commands_option)
\ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options')) \ . ale#Pad(ale#Var(a:buffer, 'cpp_cppcheck_options'))
@ -25,6 +23,7 @@ call ale#linter#Define('cpp', {
\ 'name': 'cppcheck', \ 'name': 'cppcheck',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'executable': {b -> ale#Var(b, 'cpp_cppcheck_executable')}, \ 'executable': {b -> ale#Var(b, 'cpp_cppcheck_executable')},
\ 'cwd': function('ale#handlers#cppcheck#GetCwd'),
\ 'command': function('ale_linters#cpp#cppcheck#GetCommand'), \ 'command': function('ale_linters#cpp#cppcheck#GetCommand'),
\ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat', \ 'callback': 'ale#handlers#cppcheck#HandleCppCheckFormat',
\}) \})

View file

@ -3,14 +3,10 @@ call ale#Set('cs_csc_source', '')
call ale#Set('cs_csc_assembly_path', []) call ale#Set('cs_csc_assembly_path', [])
call ale#Set('cs_csc_assemblies', []) call ale#Set('cs_csc_assemblies', [])
function! s:GetWorkingDirectory(buffer) abort function! ale_linters#cs#csc#GetCwd(buffer) abort
let l:working_directory = ale#Var(a:buffer, 'cs_csc_source') let l:cwd = ale#Var(a:buffer, 'cs_csc_source')
if !empty(l:working_directory) return !empty(l:cwd) ? l:cwd : expand('#' . a:buffer . ':p:h')
return l:working_directory
endif
return expand('#' . a:buffer . ':p:h')
endfunction endfunction
function! ale_linters#cs#csc#GetCommand(buffer) abort function! ale_linters#cs#csc#GetCommand(buffer) abort
@ -34,8 +30,7 @@ function! ale_linters#cs#csc#GetCommand(buffer) abort
" The code is compiled as a module and the output is redirected to a " The code is compiled as a module and the output is redirected to a
" temporary file. " temporary file.
return ale#path#CdString(s:GetWorkingDirectory(a:buffer)) return 'csc /unsafe'
\ . 'csc /unsafe'
\ . ale#Pad(ale#Var(a:buffer, 'cs_csc_options')) \ . ale#Pad(ale#Var(a:buffer, 'cs_csc_options'))
\ . ale#Pad(l:lib_option) \ . ale#Pad(l:lib_option)
\ . ale#Pad(l:r_option) \ . ale#Pad(l:r_option)
@ -57,8 +52,7 @@ function! ale_linters#cs#csc#Handle(buffer, lines) abort
\ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$', \ '^\v([^ ]+)\s+([Cc][sS][^ ]+):\s+(.+)$',
\] \]
let l:output = [] let l:output = []
let l:dir = ale_linters#cs#csc#GetCwd(a:buffer)
let l:dir = s:GetWorkingDirectory(a:buffer)
for l:match in ale#util#GetMatches(a:lines, l:patterns) for l:match in ale#util#GetMatches(a:lines, l:patterns)
if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS' if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS'
@ -89,6 +83,7 @@ call ale#linter#Define('cs',{
\ 'name': 'csc', \ 'name': 'csc',
\ 'output_stream': 'stdout', \ 'output_stream': 'stdout',
\ 'executable': 'csc', \ 'executable': 'csc',
\ 'cwd': function('ale_linters#cs#csc#GetCwd'),
\ 'command': function('ale_linters#cs#csc#GetCommand'), \ 'command': function('ale_linters#cs#csc#GetCommand'),
\ 'callback': 'ale_linters#cs#csc#Handle', \ 'callback': 'ale_linters#cs#csc#Handle',
\ 'lint_file': 1 \ 'lint_file': 1

View file

@ -3,14 +3,10 @@ call ale#Set('cs_mcsc_source', '')
call ale#Set('cs_mcsc_assembly_path', []) call ale#Set('cs_mcsc_assembly_path', [])
call ale#Set('cs_mcsc_assemblies', []) call ale#Set('cs_mcsc_assemblies', [])
function! s:GetWorkingDirectory(buffer) abort function! ale_linters#cs#mcsc#GetCwd(buffer) abort
let l:working_directory = ale#Var(a:buffer, 'cs_mcsc_source') let l:cwd = ale#Var(a:buffer, 'cs_mcsc_source')
if !empty(l:working_directory) return !empty(l:cwd) ? l:cwd : expand('#' . a:buffer . ':p:h')
return l:working_directory
endif
return expand('#' . a:buffer . ':p:h')
endfunction endfunction
function! ale_linters#cs#mcsc#GetCommand(buffer) abort function! ale_linters#cs#mcsc#GetCommand(buffer) abort
@ -34,8 +30,7 @@ function! ale_linters#cs#mcsc#GetCommand(buffer) abort
" The code is compiled as a module and the output is redirected to a " The code is compiled as a module and the output is redirected to a
" temporary file. " temporary file.
return ale#path#CdString(s:GetWorkingDirectory(a:buffer)) return 'mcs -unsafe'
\ . 'mcs -unsafe'
\ . ale#Pad(ale#Var(a:buffer, 'cs_mcsc_options')) \ . ale#Pad(ale#Var(a:buffer, 'cs_mcsc_options'))
\ . ale#Pad(l:lib_option) \ . ale#Pad(l:lib_option)
\ . ale#Pad(l:r_option) \ . ale#Pad(l:r_option)
@ -58,7 +53,7 @@ function! ale_linters#cs#mcsc#Handle(buffer, lines) abort
\] \]
let l:output = [] let l:output = []
let l:dir = s:GetWorkingDirectory(a:buffer) let l:dir = ale_linters#cs#mcsc#GetCwd(a:buffer)
for l:match in ale#util#GetMatches(a:lines, l:patterns) for l:match in ale#util#GetMatches(a:lines, l:patterns)
if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS' if len(l:match) > 6 && strlen(l:match[5]) > 2 && l:match[5][:1] is? 'CS'
@ -89,6 +84,7 @@ call ale#linter#Define('cs',{
\ 'name': 'mcsc', \ 'name': 'mcsc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'mcs', \ 'executable': 'mcs',
\ 'cwd': function('ale_linters#cs#mcsc#GetCwd'),
\ 'command': function('ale_linters#cs#mcsc#GetCommand'), \ 'command': function('ale_linters#cs#mcsc#GetCommand'),
\ 'callback': 'ale_linters#cs#mcsc#Handle', \ 'callback': 'ale_linters#cs#mcsc#Handle',
\ 'lint_file': 1 \ 'lint_file': 1

View file

@ -1,35 +1,37 @@
" Author: w0rp <devw0rp@gmail.com> " Author: w0rp <devw0rp@gmail.com>
" Description: "dmd for D files" " Description: "dmd for D files"
function! ale_linters#d#dmd#GetDUBCommand(buffer) abort function! s:GetDUBCommand(buffer) abort
" If we can't run dub, then skip this command. " If we can't run dub, then skip this command.
if !executable('dub') if executable('dub')
" Returning an empty string skips to the DMD command. " Returning an empty string skips to the DMD command.
return '' let l:config = ale#d#FindDUBConfig(a:buffer)
endif
let l:dub_file = ale#d#FindDUBConfig(a:buffer) " To support older dub versions, we just change the directory to the
" directory where we found the dub config, and then run `dub describe`
if empty(l:dub_file)
return ''
endif
" To support older dub versions, we just change the directory to
" the directory where we found the dub config, and then run `dub describe`
" from that directory. " from that directory.
return 'cd ' . ale#Escape(fnamemodify(l:dub_file, ':h')) if !empty(l:config)
\ . ' && dub describe --import-paths' return [fnamemodify(l:config, ':h'), 'dub describe --import-paths']
endif
endif
return ['', '']
endfunction endfunction
function! ale_linters#d#dmd#RunDUBCommand(buffer) abort function! ale_linters#d#dmd#RunDUBCommand(buffer) abort
let l:command = ale_linters#d#dmd#GetDUBCommand(a:buffer) let [l:cwd, l:command] = s:GetDUBCommand(a:buffer)
if empty(l:command) if empty(l:command)
" If we can't run DUB, just run DMD. " If we can't run DUB, just run DMD.
return ale_linters#d#dmd#DMDCommand(a:buffer, [], {}) return ale_linters#d#dmd#DMDCommand(a:buffer, [], {})
endif endif
return ale#command#Run(a:buffer, l:command, function('ale_linters#d#dmd#DMDCommand')) return ale#command#Run(
\ a:buffer,
\ l:command,
\ function('ale_linters#d#dmd#DMDCommand'),
\ {'cwd': l:cwd},
\)
endfunction endfunction
function! ale_linters#d#dmd#DMDCommand(buffer, dub_output, meta) abort function! ale_linters#d#dmd#DMDCommand(buffer, dub_output, meta) abort

View file

@ -56,11 +56,7 @@ function! ale_linters#elixir#credo#GetConfigFile() 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#FindMixUmbrellaRoot(a:buffer) return 'mix help credo && '
let l:mode = ale_linters#elixir#credo#GetMode()
return ale#path#CdString(l:project_root)
\ . 'mix help credo && '
\ . 'mix credo ' . ale_linters#elixir#credo#GetMode() \ . 'mix credo ' . ale_linters#elixir#credo#GetMode()
\ . ale_linters#elixir#credo#GetConfigFile() \ . ale_linters#elixir#credo#GetConfigFile()
\ . ' --format=flycheck --read-from-stdin %s' \ . ' --format=flycheck --read-from-stdin %s'
@ -69,6 +65,7 @@ endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'credo', \ 'name': 'credo',
\ 'executable': 'mix', \ 'executable': 'mix',
\ 'cwd': function('ale#handlers#elixir#FindMixUmbrellaRoot'),
\ 'command': function('ale_linters#elixir#credo#GetCommand'), \ 'command': function('ale_linters#elixir#credo#GetCommand'),
\ 'callback': 'ale_linters#elixir#credo#Handle', \ 'callback': 'ale_linters#elixir#credo#Handle',
\}) \})

View file

@ -25,17 +25,10 @@ function! ale_linters#elixir#dialyxir#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale_linters#elixir#dialyxir#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
return ale#path#CdString(l:project_root)
\ . ' mix help dialyzer && mix dialyzer'
endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'dialyxir', \ 'name': 'dialyxir',
\ 'executable': 'mix', \ 'executable': 'mix',
\ 'command': function('ale_linters#elixir#dialyxir#GetCommand'), \ 'cwd': function('ale#handlers#elixir#FindMixProjectRoot'),
\ 'command': 'mix help dialyzer && mix dialyzer',
\ 'callback': 'ale_linters#elixir#dialyxir#Handle', \ 'callback': 'ale_linters#elixir#dialyxir#Handle',
\}) \})

View file

@ -29,17 +29,11 @@ function! ale_linters#elixir#dogma#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale_linters#elixir#dogma#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
return ale#path#CdString(l:project_root)
\ . ' mix help dogma && mix dogma %s --format=flycheck'
endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'dogma', \ 'name': 'dogma',
\ 'executable': 'mix', \ 'executable': 'mix',
\ 'command': function('ale_linters#elixir#dogma#GetCommand'), \ 'cwd': function('ale#handlers#elixir#FindMixProjectRoot'),
\ 'command': 'mix help dogma && mix dogma %s --format=flycheck',
\ 'lint_file': 1, \ 'lint_file': 1,
\ 'callback': 'ale_linters#elixir#dogma#Handle', \ 'callback': 'ale_linters#elixir#dogma#Handle',
\}) \})

View file

@ -30,22 +30,15 @@ function! ale_linters#elixir#mix#Handle(buffer, lines) abort
endfunction endfunction
function! ale_linters#elixir#mix#GetCommand(buffer) abort function! ale_linters#elixir#mix#GetCommand(buffer) abort
let l:project_root = ale#handlers#elixir#FindMixProjectRoot(a:buffer)
let l:temp_dir = ale#command#CreateDirectory(a:buffer) let l:temp_dir = ale#command#CreateDirectory(a:buffer)
let l:mix_build_path = has('win32') return ale#Env('MIX_BUILD_PATH', l:temp_dir) . 'mix compile %s'
\ ? 'set MIX_BUILD_PATH=' . ale#Escape(l:temp_dir) . ' &&'
\ : 'MIX_BUILD_PATH=' . ale#Escape(l:temp_dir)
return ale#path#CdString(l:project_root)
\ . l:mix_build_path
\ . ' mix compile %s'
endfunction endfunction
call ale#linter#Define('elixir', { call ale#linter#Define('elixir', {
\ 'name': 'mix', \ 'name': 'mix',
\ 'executable': 'mix', \ 'executable': 'mix',
\ 'cwd': function('ale#handlers#elixir#FindMixProjectRoot'),
\ 'command': function('ale_linters#elixir#mix#GetCommand'), \ 'command': function('ale_linters#elixir#mix#GetCommand'),
\ 'callback': 'ale_linters#elixir#mix#Handle', \ 'callback': 'ale_linters#elixir#mix#Handle',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -186,20 +186,19 @@ function! ale_linters#elm#make#IsTest(buffer) abort
endif endif
endfunction endfunction
function! ale_linters#elm#make#GetCwd(buffer) abort
let l:root_dir = ale_linters#elm#make#GetRootDir(a:buffer)
return !empty(l:root_dir) ? l:root_dir : ''
endfunction
" Return the command to execute the linter in the projects directory. " Return the command to execute the linter in the projects directory.
" If it doesn't, then this will fail when imports are needed. " If it doesn't, then this will fail when imports are needed.
function! ale_linters#elm#make#GetCommand(buffer) abort function! ale_linters#elm#make#GetCommand(buffer) abort
let l:executable = ale_linters#elm#make#GetExecutable(a:buffer) let l:executable = ale_linters#elm#make#GetExecutable(a:buffer)
let l:root_dir = ale_linters#elm#make#GetRootDir(a:buffer)
let l:is_v19 = ale_linters#elm#make#IsVersionGte19(a:buffer) let l:is_v19 = ale_linters#elm#make#IsVersionGte19(a:buffer)
let l:is_using_elm_test = l:executable =~# 'elm-test$' let l:is_using_elm_test = l:executable =~# 'elm-test$'
if empty(l:root_dir)
let l:dir_set_cmd = ''
else
let l:dir_set_cmd = 'cd ' . ale#Escape(l:root_dir) . ' && '
endif
" elm-test needs to know the path of elm-make if elm isn't installed globally. " elm-test needs to know the path of elm-make if elm isn't installed globally.
" https://github.com/rtfeldman/node-test-runner/blob/57728f10668f2d2ab3179e7e3208bcfa9a1f19aa/README.md#--compiler " https://github.com/rtfeldman/node-test-runner/blob/57728f10668f2d2ab3179e7e3208bcfa9a1f19aa/README.md#--compiler
if l:is_v19 && l:is_using_elm_test if l:is_v19 && l:is_using_elm_test
@ -213,7 +212,9 @@ function! ale_linters#elm#make#GetCommand(buffer) abort
" a sort of flag to tell the compiler not to generate an output file, " a sort of flag to tell the compiler not to generate an output file,
" which is why this is hard coded here. " which is why this is hard coded here.
" Source: https://github.com/elm-lang/elm-compiler/blob/19d5a769b30ec0b2fc4475985abb4cd94cd1d6c3/builder/src/Generate/Output.hs#L253 " Source: https://github.com/elm-lang/elm-compiler/blob/19d5a769b30ec0b2fc4475985abb4cd94cd1d6c3/builder/src/Generate/Output.hs#L253
return l:dir_set_cmd . '%e make --report=json --output=/dev/null' . l:elm_test_compiler_flag . '%t' return '%e make --report=json --output=/dev/null'
\ . l:elm_test_compiler_flag
\ . '%t'
endfunction endfunction
function! ale_linters#elm#make#GetExecutable(buffer) abort function! ale_linters#elm#make#GetExecutable(buffer) abort
@ -235,6 +236,7 @@ call ale#linter#Define('elm', {
\ 'name': 'make', \ 'name': 'make',
\ 'executable': function('ale_linters#elm#make#GetExecutable'), \ 'executable': function('ale_linters#elm#make#GetExecutable'),
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'cwd': function('ale_linters#elm#make#GetCwd'),
\ 'command': function('ale_linters#elm#make#GetCommand'), \ 'command': function('ale_linters#elm#make#GetCommand'),
\ 'callback': 'ale_linters#elm#make#Handle' \ 'callback': 'ale_linters#elm#make#Handle'
\}) \})

View file

@ -10,8 +10,7 @@ function! ale_linters#go#gobuild#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_gobuild_options') let l:options = ale#Var(a:buffer, 'go_gobuild_options')
" Run go test in local directory with relative path " Run go test in local directory with relative path
return ale#path#BufferCdString(a:buffer) return ale#go#EnvString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . ale#Var(a:buffer, 'go_go_executable') . ' test' \ . ale#Var(a:buffer, 'go_go_executable') . ' test'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -c -o /dev/null ./' \ . ' -c -o /dev/null ./'
@ -50,6 +49,7 @@ call ale#linter#Define('go', {
\ 'name': 'gobuild', \ 'name': 'gobuild',
\ 'aliases': ['go build'], \ 'aliases': ['go build'],
\ 'executable': {b -> ale#Var(b, 'go_go_executable')}, \ 'executable': {b -> ale#Var(b, 'go_go_executable')},
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#go#gobuild#GetCommand'), \ 'command': function('ale_linters#go#gobuild#GetCommand'),
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#go#gobuild#Handler', \ 'callback': 'ale_linters#go#gobuild#Handler',

View file

@ -12,14 +12,12 @@ function! ale_linters#go#golangci_lint#GetCommand(buffer) abort
if l:lint_package if l:lint_package
return ale#path#BufferCdString(a:buffer) return ale#go#EnvString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e run ' \ . '%e run '
\ . l:options \ . l:options
endif endif
return ale#path#BufferCdString(a:buffer) return ale#go#EnvString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e run ' \ . '%e run '
\ . ale#Escape(l:filename) \ . ale#Escape(l:filename)
\ . ' ' . l:options \ . ' ' . l:options
@ -53,6 +51,7 @@ endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'golangci-lint', \ 'name': 'golangci-lint',
\ 'executable': {b -> ale#Var(b, 'go_golangci_lint_executable')}, \ 'executable': {b -> ale#Var(b, 'go_golangci_lint_executable')},
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#go#golangci_lint#GetCommand'), \ 'command': function('ale_linters#go#golangci_lint#GetCommand'),
\ 'callback': 'ale_linters#go#golangci_lint#Handler', \ 'callback': 'ale_linters#go#golangci_lint#Handler',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -13,14 +13,12 @@ function! ale_linters#go#gometalinter#GetCommand(buffer) abort
" BufferCdString is used so that we can be sure the paths output from gometalinter can " BufferCdString is used so that we can be sure the paths output from gometalinter can
" be calculated to absolute paths in the Handler " be calculated to absolute paths in the Handler
if l:lint_package if l:lint_package
return ale#path#BufferCdString(a:buffer) return ale#go#EnvString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e' \ . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .' \ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif endif
return ale#path#BufferCdString(a:buffer) return ale#go#EnvString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . '%e' \ . '%e'
\ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename)) \ . ' --include=' . ale#Escape(ale#util#EscapePCRE(l:filename))
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .' \ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
@ -53,6 +51,7 @@ endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'gometalinter', \ 'name': 'gometalinter',
\ 'executable': {b -> ale#Var(b, 'go_gometalinter_executable')}, \ 'executable': {b -> ale#Var(b, 'go_gometalinter_executable')},
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#go#gometalinter#GetCommand'), \ 'command': function('ale_linters#go#gometalinter#GetCommand'),
\ 'callback': 'ale_linters#go#gometalinter#Handler', \ 'callback': 'ale_linters#go#gometalinter#Handler',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -1,15 +1,11 @@
" Author: Ben Reedy <https://github.com/breed808> " Author: Ben Reedy <https://github.com/breed808>
" Description: gosimple for Go files " Description: gosimple for Go files
function! ale_linters#go#gosimple#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer) . ' '
\ . ale#go#EnvString(a:buffer) . 'gosimple .'
endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'gosimple', \ 'name': 'gosimple',
\ 'executable': 'gosimple', \ 'executable': 'gosimple',
\ 'command': function('ale_linters#go#gosimple#GetCommand'), \ 'cwd': '%s:h',
\ 'command': {b -> ale#go#EnvString(b) . 'gosimple .'},
\ 'callback': 'ale#handlers#go#Handler', \ 'callback': 'ale#handlers#go#Handler',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -1,19 +1,23 @@
" Author: Jelte Fennema <github-public@jeltef.nl> " Author: Jelte Fennema <github-public@jeltef.nl>
" Description: gotype for Go files " Description: gotype for Go files
function! ale_linters#go#gotype#GetCommand(buffer) abort function! ale_linters#go#gotype#GetExecutable(buffer) abort
if expand('#' . a:buffer . ':p') =~# '_test\.go$' if expand('#' . a:buffer . ':p') =~# '_test\.go$'
return '' return ''
endif endif
return ale#path#BufferCdString(a:buffer) . ' ' return 'gotype'
\ . ale#go#EnvString(a:buffer) . 'gotype -e .' endfunction
function! ale_linters#go#gotype#GetCommand(buffer) abort
return ale#go#EnvString(a:buffer) . 'gotype -e .'
endfunction endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'gotype', \ 'name': 'gotype',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'gotype', \ 'executable': function('ale_linters#go#gotype#GetExecutable'),
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#go#gotype#GetCommand'), \ 'command': function('ale_linters#go#gotype#GetCommand'),
\ 'callback': 'ale#handlers#go#Handler', \ 'callback': 'ale#handlers#go#Handler',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -10,8 +10,7 @@ call ale#Set('go_govet_options', '')
function! ale_linters#go#govet#GetCommand(buffer) abort function! ale_linters#go#govet#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'go_govet_options') let l:options = ale#Var(a:buffer, 'go_govet_options')
return ale#path#BufferCdString(a:buffer) . ' ' return ale#go#EnvString(a:buffer)
\ . ale#go#EnvString(a:buffer)
\ . ale#Var(a:buffer, 'go_go_executable') . ' vet ' \ . ale#Var(a:buffer, 'go_go_executable') . ' vet '
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' .' \ . ' .'
@ -22,6 +21,7 @@ call ale#linter#Define('go', {
\ 'aliases': ['go vet'], \ 'aliases': ['go vet'],
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'go_go_executable')}, \ 'executable': {b -> ale#Var(b, 'go_go_executable')},
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#go#govet#GetCommand'), \ 'command': function('ale_linters#go#govet#GetCommand'),
\ 'callback': 'ale#handlers#go#Handler', \ 'callback': 'ale#handlers#go#Handler',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -5,28 +5,24 @@ call ale#Set('go_staticcheck_options', '')
call ale#Set('go_staticcheck_lint_package', 0) call ale#Set('go_staticcheck_lint_package', 0)
function! ale_linters#go#staticcheck#GetCommand(buffer) abort function! ale_linters#go#staticcheck#GetCommand(buffer) abort
let l:filename = expand('#' . a:buffer . ':t')
let l:options = ale#Var(a:buffer, 'go_staticcheck_options') let l:options = ale#Var(a:buffer, 'go_staticcheck_options')
let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package') let l:lint_package = ale#Var(a:buffer, 'go_staticcheck_lint_package')
let l:env = ale#go#EnvString(a:buffer) let l:env = ale#go#EnvString(a:buffer)
" BufferCdString is used so that we can be sure the paths output from
" staticcheck can be calculated to absolute paths in the Handler
if l:lint_package if l:lint_package
return ale#path#BufferCdString(a:buffer) return l:env . 'staticcheck'
\ . l:env . 'staticcheck'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .' \ . (!empty(l:options) ? ' ' . l:options : '') . ' .'
endif endif
return ale#path#BufferCdString(a:buffer) return l:env . 'staticcheck'
\ . l:env . 'staticcheck'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' ' . ale#Escape(l:filename) \ . ' %s:t'
endfunction endfunction
call ale#linter#Define('go', { call ale#linter#Define('go', {
\ 'name': 'staticcheck', \ 'name': 'staticcheck',
\ 'executable': 'staticcheck', \ 'executable': 'staticcheck',
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#go#staticcheck#GetCommand'), \ 'command': function('ale_linters#go#staticcheck#GetCommand'),
\ 'callback': 'ale#handlers#go#Handler', \ 'callback': 'ale#handlers#go#Handler',
\ 'output_stream': 'both', \ 'output_stream': 'both',

View file

@ -4,6 +4,7 @@
call ale#linter#Define('graphql', { call ale#linter#Define('graphql', {
\ 'name': 'eslint', \ 'name': 'eslint',
\ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'executable': function('ale#handlers#eslint#GetExecutable'),
\ 'cwd': function('ale#handlers#eslint#GetCwd'),
\ 'command': function('ale#handlers#eslint#GetCommand'), \ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#HandleJSON', \ 'callback': 'ale#handlers#eslint#HandleJSON',
\}) \})

View file

@ -1,15 +1,10 @@
" Author: Michiel Westerbeek <happylinks@gmail.com> " Author: Michiel Westerbeek <happylinks@gmail.com>
" Description: Linter for GraphQL Schemas " Description: Linter for GraphQL Schemas
function! ale_linters#graphql#gqlint#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer)
\ . 'gqlint'
\ . ' --reporter=simple %t'
endfunction
call ale#linter#Define('graphql', { call ale#linter#Define('graphql', {
\ 'name': 'gqlint', \ 'name': 'gqlint',
\ 'executable': 'gqlint', \ 'executable': 'gqlint',
\ 'command': function('ale_linters#graphql#gqlint#GetCommand'), \ 'cwd': '%s:h',
\ 'command': 'gqlint --reporter=simple %t',
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View file

@ -4,8 +4,7 @@
call ale#Set('haskell_cabal_ghc_options', '-fno-code -v0') call ale#Set('haskell_cabal_ghc_options', '-fno-code -v0')
function! ale_linters#haskell#cabal_ghc#GetCommand(buffer) abort function! ale_linters#haskell#cabal_ghc#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer) return 'cabal exec -- ghc '
\ . 'cabal exec -- ghc '
\ . ale#Var(a:buffer, 'haskell_cabal_ghc_options') \ . ale#Var(a:buffer, 'haskell_cabal_ghc_options')
\ . ' %t' \ . ' %t'
endfunction endfunction
@ -15,6 +14,7 @@ call ale#linter#Define('haskell', {
\ 'aliases': ['cabal-ghc'], \ 'aliases': ['cabal-ghc'],
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': 'cabal', \ 'executable': 'cabal',
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#haskell#cabal_ghc#GetCommand'), \ 'command': function('ale_linters#haskell#cabal_ghc#GetCommand'),
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\}) \})

View file

@ -4,8 +4,7 @@
call ale#Set('haskell_stack_ghc_options', '-fno-code -v0') call ale#Set('haskell_stack_ghc_options', '-fno-code -v0')
function! ale_linters#haskell#stack_ghc#GetCommand(buffer) abort function! ale_linters#haskell#stack_ghc#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer) return ale#handlers#haskell#GetStackExecutable(a:buffer)
\ . ale#handlers#haskell#GetStackExecutable(a:buffer)
\ . ' ghc -- ' \ . ' ghc -- '
\ . ale#Var(a:buffer, 'haskell_stack_ghc_options') \ . ale#Var(a:buffer, 'haskell_stack_ghc_options')
\ . ' %t' \ . ' %t'
@ -16,6 +15,7 @@ call ale#linter#Define('haskell', {
\ 'aliases': ['stack-ghc'], \ 'aliases': ['stack-ghc'],
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': function('ale#handlers#haskell#GetStackExecutable'), \ 'executable': function('ale#handlers#haskell#GetStackExecutable'),
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#haskell#stack_ghc#GetCommand'), \ 'command': function('ale_linters#haskell#stack_ghc#GetCommand'),
\ 'callback': 'ale#handlers#haskell#HandleGHCFormat', \ 'callback': 'ale#handlers#haskell#HandleGHCFormat',
\}) \})

View file

@ -9,16 +9,16 @@ call ale#Set('java_javac_classpath', '')
call ale#Set('java_javac_sourcepath', '') call ale#Set('java_javac_sourcepath', '')
function! ale_linters#java#javac#RunWithImportPaths(buffer) abort function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
let l:command = ale#maven#BuildClasspathCommand(a:buffer) let [l:cwd, l:command] = ale#maven#BuildClasspathCommand(a:buffer)
" Try to use Gradle if Maven isn't available. " Try to use Gradle if Maven isn't available.
if empty(l:command) if empty(l:command)
let l:command = ale#gradle#BuildClasspathCommand(a:buffer) let [l:cwd, l:command] = ale#gradle#BuildClasspathCommand(a:buffer)
endif endif
" Try to use Ant if Gradle and Maven aren't available " Try to use Ant if Gradle and Maven aren't available
if empty(l:command) if empty(l:command)
let l:command = ale#ant#BuildClasspathCommand(a:buffer) let [l:cwd, l:command] = ale#ant#BuildClasspathCommand(a:buffer)
endif endif
if empty(l:command) if empty(l:command)
@ -28,7 +28,8 @@ function! ale_linters#java#javac#RunWithImportPaths(buffer) abort
return ale#command#Run( return ale#command#Run(
\ a:buffer, \ a:buffer,
\ l:command, \ l:command,
\ function('ale_linters#java#javac#GetCommand') \ function('ale_linters#java#javac#GetCommand'),
\ {'cwd': l:cwd},
\) \)
endfunction endfunction
@ -110,8 +111,7 @@ function! ale_linters#java#javac#GetCommand(buffer, import_paths, meta) abort
" Always run javac from the directory the file is in, so we can resolve " Always run javac from the directory the file is in, so we can resolve
" relative paths correctly. " relative paths correctly.
return ale#path#BufferCdString(a:buffer) return '%e -Xlint'
\ . '%e -Xlint'
\ . ale#Pad(l:cp_option) \ . ale#Pad(l:cp_option)
\ . ale#Pad(l:sp_option) \ . ale#Pad(l:sp_option)
\ . ' -d ' . ale#Escape(l:class_file_directory) \ . ' -d ' . ale#Escape(l:class_file_directory)
@ -154,6 +154,7 @@ endfunction
call ale#linter#Define('java', { call ale#linter#Define('java', {
\ 'name': 'javac', \ 'name': 'javac',
\ 'executable': {b -> ale#Var(b, 'java_javac_executable')}, \ 'executable': {b -> ale#Var(b, 'java_javac_executable')},
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#java#javac#RunWithImportPaths'), \ 'command': function('ale_linters#java#javac#RunWithImportPaths'),
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'callback': 'ale_linters#java#javac#Handle', \ 'callback': 'ale_linters#java#javac#Handle',

View file

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

View file

@ -15,20 +15,15 @@ function! ale_linters#kotlin#kotlinc#RunWithImportPaths(buffer) abort
let l:command = '' let l:command = ''
" exec maven/gradle only if classpath is not set " exec maven/gradle only if classpath is not set
if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# '' if !empty(ale#Var(a:buffer, 'kotlin_kotlinc_classpath'))
return ale_linters#kotlin#kotlinc#GetCommand(a:buffer, [], {}) return ale_linters#kotlin#kotlinc#GetCommand(a:buffer, [], {})
endif endif
let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml') let [l:cwd, l:command] = ale#maven#BuildClasspathCommand(a:buffer)
if !empty(l:pom_path) && executable('mvn')
let l:command = ale#path#CdString(fnamemodify(l:pom_path, ':h'))
\ . 'mvn dependency:build-classpath'
endif
" Try to use Gradle if Maven isn't available. " Try to use Gradle if Maven isn't available.
if empty(l:command) if empty(l:command)
let l:command = ale#gradle#BuildClasspathCommand(a:buffer) let [l:cwd, l:command] = ale#gradle#BuildClasspathCommand(a:buffer)
endif endif
if empty(l:command) if empty(l:command)
@ -38,7 +33,8 @@ function! ale_linters#kotlin#kotlinc#RunWithImportPaths(buffer) abort
return ale#command#Run( return ale#command#Run(
\ a:buffer, \ a:buffer,
\ l:command, \ l:command,
\ function('ale_linters#kotlin#kotlinc#GetCommand') \ function('ale_linters#kotlin#kotlinc#GetCommand'),
\ {'cwd': l:cwd},
\) \)
endfunction endfunction

View file

@ -1,9 +1,24 @@
" Author: chew-z https://github.com/chew-z " Author: chew-z https://github.com/chew-z
" Description: vale for Markdown files " Description: vale for Markdown files
call ale#Set('markdown_vale_executable', 'vale')
call ale#Set('markdown_vale_input_file', '%t')
call ale#Set('markdown_vale_options', '')
function! ale_linters#markdown#vale#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'markdown_vale_executable')
let l:input_file = ale#Var(a:buffer, 'markdown_vale_input_file')
" Defaults to `vale --output=JSON %t`
return ale#Escape(l:executable)
\ . ' --output=JSON '
\ . ale#Var(a:buffer, 'markdown_vale_options')
\ . ' ' . l:input_file
endfunction
call ale#linter#Define('markdown', { call ale#linter#Define('markdown', {
\ 'name': 'vale', \ 'name': 'vale',
\ 'executable': 'vale', \ 'executable': {b -> ale#Var(b, 'markdown_vale_executable')},
\ 'command': 'vale --output=JSON %t', \ 'command': function('ale_linters#markdown#vale#GetCommand'),
\ 'callback': 'ale#handlers#vale#Handle', \ 'callback': 'ale#handlers#vale#Handle',
\}) \})

View file

@ -5,12 +5,9 @@ call ale#Set('mercury_mmc_executable', 'mmc')
call ale#Set('mercury_mmc_options', '--make --output-compile-error-lines 100') call ale#Set('mercury_mmc_options', '--make --output-compile-error-lines 100')
function! ale_linters#mercury#mmc#GetCommand(buffer) abort function! ale_linters#mercury#mmc#GetCommand(buffer) abort
let l:module_name = expand('#' . a:buffer . ':t:r') return '%e --errorcheck-only '
return ale#path#BufferCdString(a:buffer)
\ . '%e --errorcheck-only '
\ . ale#Var(a:buffer, 'mercury_mmc_options') \ . ale#Var(a:buffer, 'mercury_mmc_options')
\ . ' ' . l:module_name \ . ' %s:t:r'
endfunction endfunction
function! ale_linters#mercury#mmc#Handle(buffer, lines) abort function! ale_linters#mercury#mmc#Handle(buffer, lines) abort
@ -34,6 +31,7 @@ call ale#linter#Define('mercury', {
\ 'name': 'mmc', \ 'name': 'mmc',
\ 'output_stream': 'stderr', \ 'output_stream': 'stderr',
\ 'executable': {b -> ale#Var(b, 'mercury_mmc_executable')}, \ 'executable': {b -> ale#Var(b, 'mercury_mmc_executable')},
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#mercury#mmc#GetCommand'), \ 'command': function('ale_linters#mercury#mmc#GetCommand'),
\ 'callback': 'ale_linters#mercury#mmc#Handle', \ 'callback': 'ale_linters#mercury#mmc#Handle',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -0,0 +1,13 @@
" Author: Risto Stevcev <me@risto.codes>
" Description: The official language server for OCaml
call ale#Set('ocaml_ocamllsp_use_opam', 1)
call ale#linter#Define('ocaml', {
\ 'name': 'ocamllsp',
\ 'lsp': 'stdio',
\ 'executable': function('ale#handlers#ocamllsp#GetExecutable'),
\ 'command': function('ale#handlers#ocamllsp#GetCommand'),
\ 'language': function('ale#handlers#ocamllsp#GetLanguage'),
\ 'project_root': function('ale#handlers#ocamllsp#GetProjectRoot'),
\})

View file

@ -13,8 +13,7 @@ function! ale_linters#php#phpcs#GetCommand(buffer) abort
\ ? '--standard=' . ale#Escape(l:standard) \ ? '--standard=' . ale#Escape(l:standard)
\ : '' \ : ''
return ale#path#BufferCdString(a:buffer) return '%e -s --report=emacs --stdin-path=%s'
\ . '%e -s --report=emacs --stdin-path=%s'
\ . ale#Pad(l:standard_option) \ . ale#Pad(l:standard_option)
\ . ale#Pad(ale#Var(a:buffer, 'php_phpcs_options')) \ . ale#Pad(ale#Var(a:buffer, 'php_phpcs_options'))
endfunction endfunction
@ -49,6 +48,7 @@ call ale#linter#Define('php', {
\ 'vendor/bin/phpcs', \ 'vendor/bin/phpcs',
\ 'phpcs' \ 'phpcs'
\ ])}, \ ])},
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#php#phpcs#GetCommand'), \ 'command': function('ale_linters#php#phpcs#GetCommand'),
\ 'callback': 'ale_linters#php#phpcs#Handle', \ 'callback': 'ale_linters#php#phpcs#Handle',
\}) \})

View file

@ -38,30 +38,28 @@ function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort
\) \)
endfunction endfunction
function! ale_linters#python#flake8#GetCdString(buffer) abort function! ale_linters#python#flake8#GetCwd(buffer) abort
let l:change_directory = ale#Var(a:buffer, 'python_flake8_change_directory') let l:change_directory = ale#Var(a:buffer, 'python_flake8_change_directory')
let l:cd_string = '' let l:cwd = ''
if l:change_directory is# 'project' if l:change_directory is# 'project'
let l:project_root = ale#python#FindProjectRootIni(a:buffer) let l:project_root = ale#python#FindProjectRootIni(a:buffer)
if !empty(l:project_root) if !empty(l:project_root)
let l:cd_string = ale#path#CdString(l:project_root) let l:cwd = l:project_root
endif endif
endif endif
if (l:change_directory is# 'project' && empty(l:cd_string)) if (l:change_directory is# 'project' && empty(l:cwd))
\|| l:change_directory is# 1 \|| l:change_directory is# 1
\|| l:change_directory is# 'file' \|| l:change_directory is# 'file'
let l:cd_string = ale#path#BufferCdString(a:buffer) let l:cwd = '%s:h'
endif endif
return l:cd_string return l:cwd
endfunction endfunction
function! ale_linters#python#flake8#GetCommand(buffer, version) abort function! ale_linters#python#flake8#GetCommand(buffer, version) abort
let l:cd_string = ale_linters#python#flake8#GetCdString(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$'
@ -76,8 +74,7 @@ function! ale_linters#python#flake8#GetCommand(buffer, version) abort
let l:options = ale#Var(a:buffer, 'python_flake8_options') let l:options = ale#Var(a:buffer, 'python_flake8_options')
return l:cd_string return ale#Escape(l:executable) . l:exec_args
\ . ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --format=default' \ . ' --format=default'
\ . l:display_name_args . ' -' \ . l:display_name_args . ' -'
@ -161,6 +158,7 @@ endfunction
call ale#linter#Define('python', { call ale#linter#Define('python', {
\ 'name': 'flake8', \ 'name': 'flake8',
\ 'executable': function('ale_linters#python#flake8#GetExecutable'), \ 'executable': function('ale_linters#python#flake8#GetExecutable'),
\ 'cwd': function('ale_linters#python#flake8#GetCwd'),
\ 'command': function('ale_linters#python#flake8#RunWithVersionCheck'), \ 'command': function('ale_linters#python#flake8#RunWithVersionCheck'),
\ 'callback': 'ale_linters#python#flake8#Handle', \ 'callback': 'ale_linters#python#flake8#Handle',
\}) \})

View file

@ -18,7 +18,7 @@ function! ale_linters#python#mypy#GetExecutable(buffer) abort
endfunction endfunction
" The directory to change to before running mypy " The directory to change to before running mypy
function! s:GetDir(buffer) abort function! ale_linters#python#mypy#GetCwd(buffer) abort
" If we find a directory with "mypy.ini" in it use that, " If we find a directory with "mypy.ini" in it use that,
" else try and find the "python project" root, or failing " else try and find the "python project" root, or failing
" that, run from the same folder as the current file " that, run from the same folder as the current file
@ -36,24 +36,19 @@ function! s:GetDir(buffer) abort
endfunction endfunction
function! ale_linters#python#mypy#GetCommand(buffer) abort function! ale_linters#python#mypy#GetCommand(buffer) abort
let l:dir = s:GetDir(a:buffer)
let l:executable = ale_linters#python#mypy#GetExecutable(a:buffer) let l:executable = ale_linters#python#mypy#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run mypy' \ ? ' run mypy'
\ : '' \ : ''
" We have to always switch to an explicit directory for a command so return '%e' . l:exec_args
" we can know with certainty the base path for the 'filename' keys below. \ . ale#Pad(ale#Var(a:buffer, 'python_mypy_options'))
return ale#path#CdString(l:dir)
\ . ale#Escape(l:executable) . l:exec_args
\ . ' --show-column-numbers' \ . ' --show-column-numbers'
\ . ale#Var(a:buffer, 'python_mypy_options')
\ . ' --shadow-file %s %t %s' \ . ' --shadow-file %s %t %s'
endfunction endfunction
function! ale_linters#python#mypy#Handle(buffer, lines) abort function! ale_linters#python#mypy#Handle(buffer, lines) abort
let l:dir = s:GetDir(a:buffer) let l:dir = ale_linters#python#mypy#GetCwd(a:buffer)
" Look for lines like the following: " Look for lines like the following:
" "
" file.py:4: error: No library stub file for module 'django.db' " file.py:4: error: No library stub file for module 'django.db'
@ -95,6 +90,7 @@ endfunction
call ale#linter#Define('python', { call ale#linter#Define('python', {
\ 'name': 'mypy', \ 'name': 'mypy',
\ 'executable': function('ale_linters#python#mypy#GetExecutable'), \ 'executable': function('ale_linters#python#mypy#GetExecutable'),
\ 'cwd': function('ale_linters#python#mypy#GetCwd'),
\ 'command': function('ale_linters#python#mypy#GetCommand'), \ 'command': function('ale_linters#python#mypy#GetCommand'),
\ 'callback': 'ale_linters#python#mypy#Handle', \ 'callback': 'ale_linters#python#mypy#Handle',
\ 'output_stream': 'both' \ 'output_stream': 'both'

View file

@ -21,8 +21,7 @@ function! ale_linters#python#pydocstyle#GetCommand(buffer) abort
\ ? ' run pydocstyle' \ ? ' run pydocstyle'
\ : '' \ : ''
return ale#path#BufferCdString(a:buffer) return ale#Escape(l:executable) . l:exec_args
\ . ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_pydocstyle_options')) \ . ale#Pad(ale#Var(a:buffer, 'python_pydocstyle_options'))
\ . ' %s:t' \ . ' %s:t'
endfunction endfunction
@ -66,6 +65,7 @@ endfunction
call ale#linter#Define('python', { call ale#linter#Define('python', {
\ 'name': 'pydocstyle', \ 'name': 'pydocstyle',
\ 'executable': function('ale_linters#python#pydocstyle#GetExecutable'), \ 'executable': function('ale_linters#python#pydocstyle#GetExecutable'),
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#python#pydocstyle#GetCommand'), \ 'command': function('ale_linters#python#pydocstyle#GetCommand'),
\ 'callback': 'ale_linters#python#pydocstyle#Handle', \ 'callback': 'ale_linters#python#pydocstyle#Handle',
\}) \})

View file

@ -16,19 +16,20 @@ function! ale_linters#python#pylama#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_pylama', ['pylama']) return ale#python#FindExecutable(a:buffer, 'python_pylama', ['pylama'])
endfunction endfunction
function! ale_linters#python#pylama#GetCommand(buffer) abort function! ale_linters#python#pylama#GetCwd(buffer) abort
let l:cd_string = ''
if ale#Var(a:buffer, 'python_pylama_change_directory') if ale#Var(a:buffer, 'python_pylama_change_directory')
" Pylama loads its configuration from the current directory only, and " Pylama loads its configuration from the current directory only, and
" applies file masks using paths relative to the current directory. " applies file masks using paths relative to the current directory.
" Run from project root, if found, otherwise buffer dir. " Run from project root, if found, otherwise buffer dir.
let l:project_root = ale#python#FindProjectRoot(a:buffer) let l:project_root = ale#python#FindProjectRoot(a:buffer)
let l:cd_string = l:project_root isnot# ''
\ ? ale#path#CdString(l:project_root) return !empty(l:project_root) ? l:project_root : '%s:h'
\ : ale#path#BufferCdString(a:buffer)
endif endif
return ''
endfunction
function! ale_linters#python#pylama#GetCommand(buffer) abort
let l:executable = ale_linters#python#pylama#GetExecutable(a:buffer) let l:executable = ale_linters#python#pylama#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pylama' \ ? ' run pylama'
@ -37,8 +38,7 @@ function! ale_linters#python#pylama#GetCommand(buffer) abort
" Note: Using %t to lint changes would be preferable, but many pylama " Note: Using %t to lint changes would be preferable, but many pylama
" checks use surrounding paths (e.g. C0103 module name, E0402 relative " checks use surrounding paths (e.g. C0103 module name, E0402 relative
" import beyond top, etc.). Neither is ideal. " import beyond top, etc.). Neither is ideal.
return l:cd_string return ale#Escape(l:executable) . l:exec_args
\ . ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_pylama_options')) \ . ale#Pad(ale#Var(a:buffer, 'python_pylama_options'))
\ . ' %s' \ . ' %s'
endfunction endfunction
@ -86,6 +86,7 @@ endfunction
call ale#linter#Define('python', { call ale#linter#Define('python', {
\ 'name': 'pylama', \ 'name': 'pylama',
\ 'executable': function('ale_linters#python#pylama#GetExecutable'), \ 'executable': function('ale_linters#python#pylama#GetExecutable'),
\ 'cwd': function('ale_linters#python#pylama#GetCwd'),
\ 'command': function('ale_linters#python#pylama#GetCommand'), \ 'command': function('ale_linters#python#pylama#GetCommand'),
\ 'callback': 'ale_linters#python#pylama#Handle', \ 'callback': 'ale_linters#python#pylama#Handle',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -17,27 +17,26 @@ function! ale_linters#python#pylint#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint']) return ale#python#FindExecutable(a:buffer, 'python_pylint', ['pylint'])
endfunction endfunction
function! ale_linters#python#pylint#GetCommand(buffer, version) abort function! ale_linters#python#pylint#GetCwd(buffer) abort
let l:cd_string = ''
if ale#Var(a:buffer, 'python_pylint_change_directory') if ale#Var(a:buffer, 'python_pylint_change_directory')
" pylint only checks for pylintrc in the packages above its current " pylint only checks for pylintrc in the packages above its current
" directory before falling back to user and global pylintrc. " directory before falling back to user and global pylintrc.
" Run from project root, if found, otherwise buffer dir. " Run from project root, if found, otherwise buffer dir.
let l:project_root = ale#python#FindProjectRoot(a:buffer) let l:project_root = ale#python#FindProjectRoot(a:buffer)
let l:cd_string = l:project_root isnot# ''
\ ? ale#path#CdString(l:project_root) return !empty(l:project_root) ? l:project_root : '%s:h'
\ : ale#path#BufferCdString(a:buffer)
endif endif
let l:executable = ale_linters#python#pylint#GetExecutable(a:buffer) return ''
endfunction
function! ale_linters#python#pylint#GetCommand(buffer, version) abort
let l:executable = ale_linters#python#pylint#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run pylint' \ ? ' run pylint'
\ : '' \ : ''
return l:cd_string return ale#Escape(l:executable) . l:exec_args
\ . ale#Escape(l:executable) . l:exec_args
\ . ale#Pad(ale#Var(a:buffer, 'python_pylint_options')) \ . ale#Pad(ale#Var(a:buffer, 'python_pylint_options'))
\ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n' \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n'
\ . (ale#semver#GTE(a:version, [2, 4, 0]) ? ' --from-stdin' : '') \ . (ale#semver#GTE(a:version, [2, 4, 0]) ? ' --from-stdin' : '')
@ -104,6 +103,7 @@ call ale#linter#Define('python', {
\ '%e --version', \ '%e --version',
\ {buffer, version -> !ale#semver#GTE(version, [2, 4, 0])}, \ {buffer, version -> !ale#semver#GTE(version, [2, 4, 0])},
\ )}, \ )},
\ 'cwd': function('ale_linters#python#pylint#GetCwd'),
\ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ 'command': {buffer -> ale#semver#RunWithVersionCheck(
\ buffer, \ buffer,
\ ale#Var(buffer, 'python_pylint_executable'), \ ale#Var(buffer, 'python_pylint_executable'),

View file

@ -6,7 +6,6 @@ call ale#Set('python_vulture_options', '')
call ale#Set('python_vulture_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('python_vulture_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('python_vulture_change_directory', 1) call ale#Set('python_vulture_change_directory', 1)
" The directory to change to before running vulture " The directory to change to before running vulture
function! s:GetDir(buffer) abort function! s:GetDir(buffer) abort
let l:project_root = ale#python#FindProjectRoot(a:buffer) let l:project_root = ale#python#FindProjectRoot(a:buffer)
@ -16,29 +15,28 @@ function! s:GetDir(buffer) abort
\ : expand('#' . a:buffer . ':p:h') \ : expand('#' . a:buffer . ':p:h')
endfunction endfunction
function! ale_linters#python#vulture#GetExecutable(buffer) abort function! ale_linters#python#vulture#GetExecutable(buffer) abort
return ale#python#FindExecutable(a:buffer, 'python_vulture', ['vulture']) return ale#python#FindExecutable(a:buffer, 'python_vulture', ['vulture'])
endfunction endfunction
function! ale_linters#python#vulture#GetCwd(buffer) abort
if !ale#Var(a:buffer, 'python_vulture_change_directory')
return ''
endif
return s:GetDir(a:buffer)
endfunction
function! ale_linters#python#vulture#GetCommand(buffer) abort function! ale_linters#python#vulture#GetCommand(buffer) abort
let l:change_dir = ale#Var(a:buffer, 'python_vulture_change_directory')
\ ? ale#path#CdString(s:GetDir(a:buffer))
\ : ''
let l:executable = ale_linters#python#vulture#GetExecutable(a:buffer) let l:executable = ale_linters#python#vulture#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run vulture' \ ? ' run vulture'
\ : '' \ : ''
let l:lint_dest = ale#Var(a:buffer, 'python_vulture_change_directory') let l:lint_dest = ale#Var(a:buffer, 'python_vulture_change_directory')
\ ? ' .' \ ? ' .'
\ : ' %s' \ : ' %s'
return l:change_dir return ale#Escape(l:executable) . l:exec_args
\ . ale#Escape(l:executable) . l:exec_args
\ . ' ' \ . ' '
\ . ale#Var(a:buffer, 'python_vulture_options') \ . ale#Var(a:buffer, 'python_vulture_options')
\ . l:lint_dest \ . l:lint_dest
@ -74,6 +72,7 @@ endfunction
call ale#linter#Define('python', { call ale#linter#Define('python', {
\ 'name': 'vulture', \ 'name': 'vulture',
\ 'executable': function('ale_linters#python#vulture#GetExecutable'), \ 'executable': function('ale_linters#python#vulture#GetExecutable'),
\ 'cwd': function('ale_linters#python#vulture#GetCwd'),
\ 'command': function('ale_linters#python#vulture#GetCommand'), \ 'command': function('ale_linters#python#vulture#GetCommand'),
\ 'callback': 'ale_linters#python#vulture#Handle', \ 'callback': 'ale_linters#python#vulture#Handle',
\ 'lint_file': 1, \ 'lint_file': 1,

View file

@ -21,14 +21,13 @@ function! ale_linters#r#lintr#GetCommand(buffer) abort
let l:cmd_string = 'suppressPackageStartupMessages(library(lintr));' let l:cmd_string = 'suppressPackageStartupMessages(library(lintr));'
\ . l:lint_cmd \ . l:lint_cmd
return ale#path#BufferCdString(a:buffer) return 'Rscript --vanilla -e ' . ale#Escape(l:cmd_string) . ' %t'
\ . 'Rscript --vanilla -e '
\ . ale#Escape(l:cmd_string) . ' %t'
endfunction endfunction
call ale#linter#Define('r', { call ale#linter#Define('r', {
\ 'name': 'lintr', \ 'name': 'lintr',
\ 'executable': 'Rscript', \ 'executable': 'Rscript',
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#r#lintr#GetCommand'), \ 'command': function('ale_linters#r#lintr#GetCommand'),
\ 'callback': 'ale#handlers#gcc#HandleGCCFormat', \ 'callback': 'ale#handlers#gcc#HandleGCCFormat',
\ 'output_stream': 'both', \ 'output_stream': 'both',

View file

@ -1,6 +1,5 @@
" Author: John Nduli https://github.com/jnduli " Author: John Nduli https://github.com/jnduli
" Description: Rstcheck for reStructuredText files " Description: Rstcheck for reStructuredText files
"
function! ale_linters#rst#rstcheck#Handle(buffer, lines) abort function! ale_linters#rst#rstcheck#Handle(buffer, lines) abort
" matches: 'bad_rst.rst:1: (SEVERE/4) Title overline & underline " matches: 'bad_rst.rst:1: (SEVERE/4) Title overline & underline
@ -22,17 +21,11 @@ function! ale_linters#rst#rstcheck#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale_linters#rst#rstcheck#GetCommand(buffer) abort
return ale#path#BufferCdString(a:buffer)
\ . 'rstcheck'
\ . ' %t'
endfunction
call ale#linter#Define('rst', { call ale#linter#Define('rst', {
\ 'name': 'rstcheck', \ 'name': 'rstcheck',
\ 'executable': 'rstcheck', \ 'executable': 'rstcheck',
\ 'command': function('ale_linters#rst#rstcheck#GetCommand'), \ 'cwd': '%s:h',
\ 'command': 'rstcheck %t',
\ 'callback': 'ale_linters#rst#rstcheck#Handle', \ 'callback': 'ale_linters#rst#rstcheck#Handle',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\}) \})

View file

@ -23,6 +23,19 @@ function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort
endif endif
endfunction endfunction
function! ale_linters#rust#cargo#GetCwd(buffer) abort
if ale#Var(a:buffer, 'rust_cargo_avoid_whole_workspace')
let l:nearest_cargo = ale#path#FindNearestFile(a:buffer, 'Cargo.toml')
let l:nearest_cargo_dir = fnamemodify(l:nearest_cargo, ':h')
if l:nearest_cargo_dir isnot# '.'
return l:nearest_cargo_dir
endif
endif
return ''
endfunction
function! ale_linters#rust#cargo#GetCommand(buffer, version) abort function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check') let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check')
\ && ale#semver#GTE(a:version, [0, 17, 0]) \ && ale#semver#GTE(a:version, [0, 17, 0])
@ -42,18 +55,6 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
let l:include_features = ' --features ' . ale#Escape(l:include_features) let l:include_features = ' --features ' . ale#Escape(l:include_features)
endif endif
let l:avoid_whole_workspace = ale#Var(a:buffer, 'rust_cargo_avoid_whole_workspace')
let l:nearest_cargo_prefix = ''
if l:avoid_whole_workspace
let l:nearest_cargo = ale#path#FindNearestFile(a:buffer, 'Cargo.toml')
let l:nearest_cargo_dir = fnamemodify(l:nearest_cargo, ':h')
if l:nearest_cargo_dir isnot# '.'
let l:nearest_cargo_prefix = 'cd '. ale#Escape(l:nearest_cargo_dir) .' && '
endif
endif
let l:default_feature_behavior = ale#Var(a:buffer, 'rust_cargo_default_feature_behavior') let l:default_feature_behavior = ale#Var(a:buffer, 'rust_cargo_default_feature_behavior')
if l:default_feature_behavior is# 'all' if l:default_feature_behavior is# 'all'
@ -81,7 +82,7 @@ function! ale_linters#rust#cargo#GetCommand(buffer, version) abort
endif endif
endif endif
return l:nearest_cargo_prefix . 'cargo ' return 'cargo '
\ . l:subcommand \ . l:subcommand
\ . (l:use_all_targets ? ' --all-targets' : '') \ . (l:use_all_targets ? ' --all-targets' : '')
\ . (l:use_examples ? ' --examples' : '') \ . (l:use_examples ? ' --examples' : '')
@ -96,6 +97,7 @@ endfunction
call ale#linter#Define('rust', { call ale#linter#Define('rust', {
\ 'name': 'cargo', \ 'name': 'cargo',
\ 'executable': function('ale_linters#rust#cargo#GetCargoExecutable'), \ 'executable': function('ale_linters#rust#cargo#GetCargoExecutable'),
\ 'cwd': function('ale_linters#rust#cargo#GetCwd'),
\ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ 'command': {buffer -> ale#semver#RunWithVersionCheck(
\ buffer, \ buffer,
\ ale_linters#rust#cargo#GetCargoExecutable(buffer), \ ale_linters#rust#cargo#GetCargoExecutable(buffer),

View file

@ -20,6 +20,10 @@ function! ale_linters#terraform#terraform#GetType(severity) abort
return 'E' return 'E'
endfunction endfunction
function! ale_linters#terraform#terraform#GetDetail(error) abort
return get(a:error, 'detail', get(a:error, 'summary', ''))
endfunction
function! ale_linters#terraform#terraform#Handle(buffer, lines) abort function! ale_linters#terraform#terraform#Handle(buffer, lines) abort
let l:output = [] let l:output = []
@ -33,7 +37,7 @@ function! ale_linters#terraform#terraform#Handle(buffer, lines) abort
\ 'filename': ale#path#GetAbsPath(l:dir, l:error['range']['filename']), \ 'filename': ale#path#GetAbsPath(l:dir, l:error['range']['filename']),
\ 'lnum': l:error['range']['start']['line'], \ 'lnum': l:error['range']['start']['line'],
\ 'col': l:error['range']['start']['column'], \ 'col': l:error['range']['start']['column'],
\ 'text': l:error['detail'], \ 'text': ale_linters#terraform#terraform#GetDetail(l:error),
\ 'type': ale_linters#terraform#terraform#GetType(l:error['severity']), \ 'type': ale_linters#terraform#terraform#GetType(l:error['severity']),
\}) \})
else else
@ -41,7 +45,7 @@ function! ale_linters#terraform#terraform#Handle(buffer, lines) abort
\ 'filename': l:file, \ 'filename': l:file,
\ 'lnum': 0, \ 'lnum': 0,
\ 'col': 0, \ 'col': 0,
\ 'text': l:error['detail'], \ 'text': ale_linters#terraform#terraform#GetDetail(l:error),
\ 'type': ale_linters#terraform#terraform#GetType(l:error['severity']), \ 'type': ale_linters#terraform#terraform#GetType(l:error['severity']),
\}) \})
endif endif

View file

@ -1,11 +1,14 @@
" Author: Ricardo Liang <ricardoliang@gmail.com> " Author: Ricardo Liang <ricardoliang@gmail.com>
" Author: ourigen <ourigen [at] pm.me>
" Description: Texlab language server (Rust rewrite) " Description: Texlab language server (Rust rewrite)
call ale#Set('tex_texlab_executable', 'texlab') call ale#Set('tex_texlab_executable', 'texlab')
call ale#Set('tex_texlab_options', '') call ale#Set('tex_texlab_options', '')
function! ale_linters#tex#texlab#GetProjectRoot(buffer) abort function! ale_linters#tex#texlab#GetProjectRoot(buffer) abort
return '' let l:git_path = ale#path#FindNearestDirectory(a:buffer, '.git')
return !empty(l:git_path) ? fnamemodify(l:git_path, ':h:h') : ''
endfunction endfunction
function! ale_linters#tex#texlab#GetCommand(buffer) abort function! ale_linters#tex#texlab#GetCommand(buffer) abort

View file

@ -4,6 +4,7 @@
call ale#linter#Define('typescript', { call ale#linter#Define('typescript', {
\ 'name': 'eslint', \ 'name': 'eslint',
\ 'executable': function('ale#handlers#eslint#GetExecutable'), \ 'executable': function('ale#handlers#eslint#GetExecutable'),
\ 'cwd': function('ale#handlers#eslint#GetCwd'),
\ 'command': function('ale#handlers#eslint#GetCommand'), \ 'command': function('ale#handlers#eslint#GetCommand'),
\ 'callback': 'ale#handlers#eslint#HandleJSON', \ 'callback': 'ale#handlers#eslint#HandleJSON',
\}) \})

View file

@ -59,8 +59,7 @@ function! ale_linters#typescript#tslint#GetCommand(buffer) abort
\ ? ' -r ' . ale#Escape(l:tslint_rules_dir) \ ? ' -r ' . ale#Escape(l:tslint_rules_dir)
\ : '' \ : ''
return ale#path#BufferCdString(a:buffer) return ale#Escape(ale#handlers#tslint#GetExecutable(a:buffer))
\ . ale#Escape(ale#handlers#tslint#GetExecutable(a:buffer))
\ . ' --format json' \ . ' --format json'
\ . l:tslint_config_option \ . l:tslint_config_option
\ . l:tslint_rules_option \ . l:tslint_rules_option
@ -70,6 +69,7 @@ endfunction
call ale#linter#Define('typescript', { call ale#linter#Define('typescript', {
\ 'name': 'tslint', \ 'name': 'tslint',
\ 'executable': function('ale#handlers#tslint#GetExecutable'), \ 'executable': function('ale#handlers#tslint#GetExecutable'),
\ 'cwd': '%s:h',
\ 'command': function('ale_linters#typescript#tslint#GetCommand'), \ 'command': function('ale_linters#typescript#tslint#GetCommand'),
\ 'callback': 'ale_linters#typescript#tslint#Handle', \ 'callback': 'ale_linters#typescript#tslint#Handle',
\}) \})

View file

@ -7,16 +7,11 @@ if !exists('g:ale_verilog_verilator_options')
endif endif
function! ale_linters#verilog#verilator#GetCommand(buffer) abort function! ale_linters#verilog#verilator#GetCommand(buffer) abort
let l:filename = ale#util#Tempname() . '_verilator_linted.v' " the path to the current file is systematically added to the search path
" Create a special filename, so we can detect it in the handler.
call ale#command#ManageFile(a:buffer, l:filename)
let l:lines = getbufline(a:buffer, 1, '$')
call ale#util#Writefile(a:buffer, l:lines, l:filename)
return 'verilator --lint-only -Wall -Wno-DECLFILENAME ' return 'verilator --lint-only -Wall -Wno-DECLFILENAME '
\ . '-I%s:h '
\ . ale#Var(a:buffer, 'verilog_verilator_options') .' ' \ . ale#Var(a:buffer, 'verilog_verilator_options') .' '
\ . ale#Escape(l:filename) \ . '%t'
endfunction endfunction
function! ale_linters#verilog#verilator#Handle(buffer, lines) abort function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
@ -34,7 +29,7 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
" "
" to stay compatible with old versions of the tool, the column number is " to stay compatible with old versions of the tool, the column number is
" optional in the researched pattern " optional in the researched pattern
let l:pattern = '^%\(Warning\|Error\)[^:]*:\([^:]\+\):\(\d\+\):\(\d\+\)\?:\? \(.\+\)$' let l:pattern = '^%\(Warning\|Error\)[^:]*:\s*\([^:]\+\):\(\d\+\):\(\d\+\)\?:\? \(.\+\)$'
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)
@ -42,17 +37,14 @@ function! ale_linters#verilog#verilator#Handle(buffer, lines) abort
\ 'lnum': str2nr(l:match[3]), \ 'lnum': str2nr(l:match[3]),
\ 'text': l:match[5], \ 'text': l:match[5],
\ 'type': l:match[1] is# 'Error' ? 'E' : 'W', \ 'type': l:match[1] is# 'Error' ? 'E' : 'W',
\ 'filename': l:match[2],
\} \}
if !empty(l:match[4]) if !empty(l:match[4])
let l:item.col = str2nr(l:match[4]) let l:item.col = str2nr(l:match[4])
endif endif
let l:file = l:match[2]
if l:file =~# '_verilator_linted.v'
call add(l:output, l:item) call add(l:output, l:item)
endif
endfor endfor
return l:output return l:output

View file

@ -22,16 +22,20 @@ function! s:GetALEProjectDir(buffer) abort
return ale#path#Dirname(ale#path#Dirname(ale#path#Dirname(l:executable))) return ale#path#Dirname(ale#path#Dirname(ale#path#Dirname(l:executable)))
endfunction endfunction
function! ale_linters#vim#ale_custom_linting_rules#GetCommand(buffer) abort function! ale_linters#vim#ale_custom_linting_rules#GetCwd(buffer) abort
let l:dir = s:GetALEProjectDir(a:buffer) let l:executable = ale_linters#vim#ale_custom_linting_rules#GetExecutable(a:buffer)
return ale#path#Dirname(ale#path#Dirname(ale#path#Dirname(l:executable)))
endfunction
function! ale_linters#vim#ale_custom_linting_rules#GetCommand(buffer) abort
let l:temp_dir = ale#command#CreateDirectory(a:buffer) let l:temp_dir = ale#command#CreateDirectory(a:buffer)
let l:temp_file = l:temp_dir . '/example.vim' let l:temp_file = l:temp_dir . '/example.vim'
let l:lines = getbufline(a:buffer, 1, '$') let l:lines = getbufline(a:buffer, 1, '$')
call ale#util#Writefile(a:buffer, l:lines, l:temp_file) call ale#util#Writefile(a:buffer, l:lines, l:temp_file)
return ale#path#CdString(l:dir) . '%e ' . ale#Escape(l:temp_dir) return '%e ' . ale#Escape(l:temp_dir)
endfunction endfunction
function! ale_linters#vim#ale_custom_linting_rules#Handle(buffer, lines) abort function! ale_linters#vim#ale_custom_linting_rules#Handle(buffer, lines) abort
@ -59,6 +63,7 @@ endfunction
call ale#linter#Define('vim', { call ale#linter#Define('vim', {
\ 'name': 'ale_custom_linting_rules', \ 'name': 'ale_custom_linting_rules',
\ 'executable': function('ale_linters#vim#ale_custom_linting_rules#GetExecutable'), \ 'executable': function('ale_linters#vim#ale_custom_linting_rules#GetExecutable'),
\ 'cwd': function('ale_linters#vim#ale_custom_linting_rules#GetCwd'),
\ 'command': function('ale_linters#vim#ale_custom_linting_rules#GetCommand'), \ 'command': function('ale_linters#vim#ale_custom_linting_rules#GetCommand'),
\ 'callback': 'ale_linters#vim#ale_custom_linting_rules#Handle', \ 'callback': 'ale_linters#vim#ale_custom_linting_rules#Handle',
\ 'read_buffer': 0, \ 'read_buffer': 0,

View file

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

View file

@ -23,19 +23,23 @@ function! ale#ant#FindExecutable(buffer) abort
return '' return ''
endfunction endfunction
" Given a buffer number, build a command to print the classpath of the root " Given a buffer number, get a working directory and command to print the
" project. Returns an empty string if cannot build the command. " classpath of the root project.
"
" Returns an empty string for the command if Ant is not detected.
function! ale#ant#BuildClasspathCommand(buffer) abort function! ale#ant#BuildClasspathCommand(buffer) abort
let l:executable = ale#ant#FindExecutable(a:buffer) let l:executable = ale#ant#FindExecutable(a:buffer)
if !empty(l:executable)
let l:project_root = ale#ant#FindProjectRoot(a:buffer) let l:project_root = ale#ant#FindProjectRoot(a:buffer)
if !empty(l:executable) && !empty(l:project_root) if !empty(l:project_root)
return ale#path#CdString(l:project_root) return [
\ . ale#Escape(l:executable) \ l:project_root,
\ . ' classpath' \ ale#Escape(l:executable) .' classpath -S -q'
\ . ' -S' \]
\ . ' -q' endif
endif endif
return '' return ['', '']
endfunction endfunction

View file

@ -52,6 +52,36 @@ function! s:ProcessDeferredCommands(initial_result) abort
return l:command return l:command
endfunction endfunction
function! s:ProcessDeferredCwds(initial_command, initial_cwd) abort
let l:result = a:initial_command
let l:last_cwd = v:null
let l:command_index = 0
let l:cwd_list = []
while ale#command#IsDeferred(l:result)
call add(l:cwd_list, l:result.cwd)
if get(g:, 'ale_run_synchronously_emulate_commands')
" Don't run commands, but simulate the results.
let l:Callback = g:ale_run_synchronously_callbacks[0]
let l:output = get(s:command_output, l:command_index, [])
call l:Callback(0, l:output)
unlet g:ale_run_synchronously_callbacks
let l:command_index += 1
else
" Run the commands in the shell, synchronously.
call ale#test#FlushJobs()
endif
let l:result = l:result.value
endwhile
call add(l:cwd_list, a:initial_cwd is v:null ? l:last_cwd : a:initial_cwd)
return l:cwd_list
endfunction
" Load the currently loaded linter for a test case, and check that the command " Load the currently loaded linter for a test case, and check that the command
" matches the given string. " matches the given string.
function! ale#assert#Linter(expected_executable, expected_command) abort function! ale#assert#Linter(expected_executable, expected_command) abort
@ -85,6 +115,38 @@ function! ale#assert#Linter(expected_executable, expected_command) abort
\ [l:executable, l:command] \ [l:executable, l:command]
endfunction endfunction
function! ale#assert#LinterCwd(expected_cwd) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:initial_cwd = ale#linter#GetCwd(l:buffer, l:linter)
call ale#command#SetCwd(l:buffer, l:initial_cwd)
let l:cwd = s:ProcessDeferredCwds(
\ ale#linter#GetCommand(l:buffer, l:linter),
\ l:initial_cwd,
\)
call ale#command#ResetCwd(l:buffer)
if type(a:expected_cwd) isnot v:t_list
let l:cwd = l:cwd[-1]
endif
AssertEqual a:expected_cwd, l:cwd
endfunction
function! ale#assert#FixerCwd(expected_cwd) abort
let l:buffer = bufnr('')
let l:cwd = s:ProcessDeferredCwds(s:FixerFunction(l:buffer), v:null)
if type(a:expected_cwd) isnot v:t_list
let l:cwd = l:cwd[-1]
endif
AssertEqual a:expected_cwd, l:cwd
endfunction
function! ale#assert#Fixer(expected_result) abort function! ale#assert#Fixer(expected_result) abort
let l:buffer = bufnr('') let l:buffer = bufnr('')
let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer)) let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))
@ -153,6 +215,7 @@ endfunction
function! ale#assert#SetUpLinterTestCommands() abort function! ale#assert#SetUpLinterTestCommands() abort
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>) command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
command! -nargs=+ AssertLinterCwd :call ale#assert#LinterCwd(<args>)
command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>) command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>)
command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted() command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>) command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>)
@ -164,10 +227,35 @@ endfunction
function! ale#assert#SetUpFixerTestCommands() abort function! ale#assert#SetUpFixerTestCommands() abort
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>) command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
command! -nargs=+ AssertFixerCwd :call ale#assert#FixerCwd(<args>)
command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>) command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>)
command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted() command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted()
endfunction endfunction
function! ale#assert#ResetVariables(filetype, name, ...) abort
" If the suffix of the option names format is different, an additional
" argument can be used for that instead.
if a:0 > 1
throw 'Too many arguments'
endif
let l:option_suffix = get(a:000, 0, a:name)
let l:prefix = 'ale_' . a:filetype . '_'
\ . substitute(l:option_suffix, '-', '_', 'g')
let l:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
" Save and clear linter variables.
" We'll load the runtime file to reset them to defaults.
for l:key in filter(keys(g:), l:filter_expr)
execute 'Save g:' . l:key
unlet g:[l:key]
endfor
for l:key in filter(keys(b:), l:filter_expr)
unlet b:[l:key]
endfor
endfunction
" A dummy function for making sure this module is loaded. " A dummy function for making sure this module is loaded.
function! ale#assert#SetUpLinterTest(filetype, name) abort function! ale#assert#SetUpLinterTest(filetype, name) abort
" Set up a marker so ALE doesn't create real random temporary filenames. " Set up a marker so ALE doesn't create real random temporary filenames.
@ -177,31 +265,18 @@ function! ale#assert#SetUpLinterTest(filetype, name) abort
call ale#linter#Reset() call ale#linter#Reset()
call ale#linter#PreventLoading(a:filetype) call ale#linter#PreventLoading(a:filetype)
let l:prefix = 'ale_' . a:filetype . '_' . a:name Save g:ale_root
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix' let g:ale_root = {}
Save g:ale_lsp_root Save b:ale_root
let g:ale_lsp_root = {} unlet! b:ale_root
Save b:ale_lsp_root call ale#assert#ResetVariables(a:filetype, a:name)
unlet! b:ale_lsp_root
Save g:ale_c_build_dir Save g:ale_c_build_dir
unlet! g:ale_c_build_dir unlet! g:ale_c_build_dir
" Save and clear linter variables.
" We'll load the runtime file to reset them to defaults.
for l:key in filter(keys(g:), b:filter_expr)
execute 'Save g:' . l:key
unlet g:[l:key]
endfor
unlet! b:ale_c_build_dir unlet! b:ale_c_build_dir
for l:key in filter(keys(b:), b:filter_expr)
unlet b:[l:key]
endfor
execute 'runtime ale_linters/' . a:filetype . '/' . a:name . '.vim' execute 'runtime ale_linters/' . a:filetype . '/' . a:name . '.vim'
if !exists('g:dir') if !exists('g:dir')
@ -226,6 +301,10 @@ function! ale#assert#TearDownLinterTest() abort
delcommand GivenCommandOutput delcommand GivenCommandOutput
endif endif
if exists(':AssertLinterCwd')
delcommand AssertLinterCwd
endif
if exists(':AssertLinter') if exists(':AssertLinter')
delcommand AssertLinter delcommand AssertLinter
endif endif
@ -281,18 +360,7 @@ function! ale#assert#SetUpFixerTest(filetype, name, ...) abort
let s:FixerFunction = function(l:function_name) let s:FixerFunction = function(l:function_name)
let l:option_suffix = get(a:000, 0, a:name) let l:option_suffix = get(a:000, 0, a:name)
let l:prefix = 'ale_' . a:filetype . '_' call ale#assert#ResetVariables(a:filetype, a:name, l:option_suffix)
\ . substitute(l:option_suffix, '-', '_', 'g')
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
for l:key in filter(keys(g:), b:filter_expr)
execute 'Save g:' . l:key
unlet g:[l:key]
endfor
for l:key in filter(keys(b:), b:filter_expr)
unlet b:[l:key]
endfor
execute 'runtime autoload/ale/fixers/' . substitute(a:name, '-', '_', 'g') . '.vim' execute 'runtime autoload/ale/fixers/' . substitute(a:name, '-', '_', 'g') . '.vim'
@ -329,6 +397,10 @@ function! ale#assert#TearDownFixerTest() abort
delcommand GivenCommandOutput delcommand GivenCommandOutput
endif endif
if exists(':AssertFixerCwd')
delcommand AssertFixerCwd
endif
if exists(':AssertFixer') if exists(':AssertFixer')
delcommand AssertFixer delcommand AssertFixer
endif endif

View file

@ -513,16 +513,18 @@ function! ale#c#GetMakeCommand(buffer) abort
if !empty(l:path) if !empty(l:path)
let l:always_make = ale#Var(a:buffer, 'c_always_make') let l:always_make = ale#Var(a:buffer, 'c_always_make')
return ale#path#CdString(fnamemodify(l:path, ':h')) return [
\ . 'make -n' . (l:always_make ? ' --always-make' : '') \ fnamemodify(l:path, ':h'),
\ 'make -n' . (l:always_make ? ' --always-make' : ''),
\]
endif endif
endif endif
return '' return ['', '']
endfunction endfunction
function! ale#c#RunMakeCommand(buffer, Callback) abort function! ale#c#RunMakeCommand(buffer, Callback) abort
let l:command = ale#c#GetMakeCommand(a:buffer) let [l:cwd, l:command] = ale#c#GetMakeCommand(a:buffer)
if empty(l:command) if empty(l:command)
return a:Callback(a:buffer, []) return a:Callback(a:buffer, [])
@ -532,6 +534,7 @@ function! ale#c#RunMakeCommand(buffer, Callback) abort
\ a:buffer, \ a:buffer,
\ l:command, \ l:command,
\ {b, output -> a:Callback(a:buffer, output)}, \ {b, output -> a:Callback(a:buffer, output)},
\ {'cwd': l:cwd},
\) \)
endfunction endfunction

View file

@ -71,6 +71,11 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
if l:buffer > 0 if l:buffer > 0
let l:lines = getbufline(l:buffer, 1, '$') let l:lines = getbufline(l:buffer, 1, '$')
" Add empty line if there's trailing newline, like readfile() does.
if getbufvar(l:buffer, '&eol')
let l:lines += ['']
endif
else else
let l:lines = readfile(a:filename, 'b') let l:lines = readfile(a:filename, 'b')
endif endif
@ -89,62 +94,82 @@ function! ale#code_action#ApplyChanges(filename, changes, should_save) abort
let l:end_column = l:code_edit.end.offset let l:end_column = l:code_edit.end.offset
let l:text = l:code_edit.newText let l:text = l:code_edit.newText
" Adjust the ends according to previous edits.
if l:end_line > len(l:lines)
let l:end_line_len = 0
else
let l:end_line_len = len(l:lines[l:end_line - 1])
endif
let l:insertions = split(l:text, '\n', 1) let l:insertions = split(l:text, '\n', 1)
if l:line is 1 " Fix invalid columns
" Same logic as for column below. Vimscript's slice [:-1] will not let l:column = l:column > 0 ? l:column : 1
" be an empty list. let l:end_column = l:end_column > 0 ? l:end_column : 1
let l:start = []
else " Clamp start to BOF
let l:start = l:lines[: l:line - 2] if l:line < 1
let [l:line, l:column] = [1, 1]
endif endif
" Special case when text must be added after new line " Clamp start to EOF
if l:column > len(l:lines[l:line - 1]) if l:line > len(l:lines) || l:line == len(l:lines) && l:column > len(l:lines[-1]) + 1
call extend(l:start, [l:lines[l:line - 1]]) let [l:line, l:column] = [len(l:lines), len(l:lines[-1]) + 1]
let l:column = 1 " Special case when start is after EOL
elseif l:line < len(l:lines) && l:column > len(l:lines[l:line - 1]) + 1
let [l:line, l:column] = [l:line + 1, 1]
endif endif
if l:column is 1 " Adjust end: clamp if invalid and/or adjust if we moved start
" We need to handle column 1 specially, because we can't slice an if l:end_line < l:line || l:end_line == l:line && l:end_column < l:column
" empty string ending on index 0. let [l:end_line, l:end_column] = [l:line, l:column]
let l:middle = [l:insertions[0]]
else
let l:middle = [l:lines[l:line - 1][: l:column - 2] . l:insertions[0]]
endif endif
call extend(l:middle, l:insertions[1:]) " Clamp end to EOF
if l:end_line > len(l:lines) || l:end_line == len(l:lines) && l:end_column > len(l:lines[-1]) + 1
let [l:end_line, l:end_column] = [len(l:lines), len(l:lines[-1]) + 1]
" Special case when end is after EOL
elseif l:end_line < len(l:lines) && l:end_column > len(l:lines[l:end_line - 1]) + 1
let [l:end_line, l:end_column] = [l:end_line + 1, 1]
endif
if l:end_line <= len(l:lines) " Careful, [:-1] is not an empty list
" Only extend the last line if end_line is within the range of let l:start = l:line is 1 ? [] : l:lines[: l:line - 2]
" lines. let l:middle = l:column is 1 ? [''] : [l:lines[l:line - 1][: l:column - 2]]
let l:middle[-1] .= l:insertions[0]
let l:middle += l:insertions[1:]
let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :] let l:middle[-1] .= l:lines[l:end_line - 1][l:end_column - 1 :]
endif
let l:end_line_len = len(l:lines[l:end_line - 1])
let l:lines_before_change = len(l:lines) let l:lines_before_change = len(l:lines)
let l:lines = l:start + l:middle + l:lines[l:end_line :] let l:lines = l:start + l:middle + l:lines[l:end_line :]
let l:current_line_offset = len(l:lines) - l:lines_before_change let l:current_line_offset = len(l:lines) - l:lines_before_change
let l:column_offset = len(l:middle[-1]) - l:end_line_len let l:column_offset = len(l:middle[-1]) - l:end_line_len
" Keep cursor where it was (if outside of changes) or move it after
" the changed text (if inside), but don't touch it when the change
" spans the entire buffer, in which case we have no clue and it's
" better to not do anything.
if l:line isnot 1 || l:column isnot 1
\|| l:end_line < l:lines_before_change
\|| l:end_line == l:lines_before_change && l:end_column <= l:end_line_len
let l:pos = s:UpdateCursor(l:pos, let l:pos = s:UpdateCursor(l:pos,
\ [l:line, l:column], \ [l:line, l:column],
\ [l:end_line, l:end_column], \ [l:end_line, l:end_column],
\ [l:current_line_offset, l:column_offset]) \ [l:current_line_offset, l:column_offset])
endif
endfor endfor
if l:lines[-1] is# '' if l:buffer > 0
" Make sure ale#util#{Writefile,SetBufferContents} add trailing
" newline if and only if it should be added.
if l:lines[-1] is# '' && getbufvar(l:buffer, '&eol')
call remove(l:lines, -1)
else
call setbufvar(l:buffer, '&eol', 0)
endif
elseif exists('+fixeol') && &fixeol && l:lines[-1] is# ''
" Not in buffer, ale#util#Writefile can't check &eol and always adds
" newline if &fixeol: remove to prevent double trailing newline.
call remove(l:lines, -1) call remove(l:lines, -1)
endif endif
if a:should_save if a:should_save || l:buffer < 0
call ale#util#Writefile(l:buffer, l:lines, a:filename) call ale#util#Writefile(l:buffer, l:lines, a:filename)
else else
call ale#util#SetBufferContents(l:buffer, l:lines) call ale#util#SetBufferContents(l:buffer, l:lines)

View file

@ -7,6 +7,9 @@ if !exists('s:buffer_data')
let s:buffer_data = {} let s:buffer_data = {}
endif endif
" The regular expression used for formatting filenames with modifiers.
let s:path_format_regex = '\v\%s(%(:h|:t|:r|:e)*)'
" Used to get the data in tests. " Used to get the data in tests.
function! ale#command#GetData() abort function! ale#command#GetData() abort
return deepcopy(s:buffer_data) return deepcopy(s:buffer_data)
@ -26,6 +29,19 @@ function! ale#command#InitData(buffer) abort
endif endif
endfunction endfunction
" Set the cwd for commands that are about to run.
" Used internally.
function! ale#command#SetCwd(buffer, cwd) abort
call ale#command#InitData(a:buffer)
let s:buffer_data[a:buffer].cwd = a:cwd
endfunction
function! ale#command#ResetCwd(buffer) abort
if has_key(s:buffer_data, a:buffer)
let s:buffer_data[a:buffer].cwd = v:null
endif
endfunction
function! ale#command#ManageFile(buffer, file) abort function! ale#command#ManageFile(buffer, file) abort
call ale#command#InitData(a:buffer) call ale#command#InitData(a:buffer)
call add(s:buffer_data[a:buffer].file_list, a:file) call add(s:buffer_data[a:buffer].file_list, a:file)
@ -151,6 +167,24 @@ function! s:FormatFilename(filename, mappings, modifiers) abort
return ale#Escape(l:filename) return ale#Escape(l:filename)
endfunction endfunction
" Produce a command prefix to check to a particular directory for a command.
" %s format markers with filename-modifiers can be used as the directory, and
" will be returned verbatim for formatting in paths relative to files.
function! ale#command#CdString(directory) abort
let l:match = matchstrpos(a:directory, s:path_format_regex)
" Do not escape the directory here if it's a valid format string.
" This allows us to use sequences like %s:h, %s:h:h, etc.
let l:directory = l:match[1:] == [0, len(a:directory)]
\ ? a:directory
\ : ale#Escape(a:directory)
if has('win32')
return 'cd /d ' . l:directory . ' && '
endif
return 'cd ' . l:directory . ' && '
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
@ -161,11 +195,16 @@ function! ale#command#FormatCommand(
\ command, \ command,
\ pipe_file_if_needed, \ pipe_file_if_needed,
\ input, \ input,
\ cwd,
\ mappings, \ mappings,
\) abort \) abort
let l:temporary_file = '' let l:temporary_file = ''
let l:command = a:command let l:command = a:command
if !empty(a:cwd)
let l:command = ale#command#CdString(a:cwd) . l:command
endif
" First replace all uses of %%, used for literal percent characters, " First replace all uses of %%, used for literal percent characters,
" with an ugly string. " with an ugly string.
let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g') let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g')
@ -181,7 +220,7 @@ function! ale#command#FormatCommand(
let l:filename = fnamemodify(bufname(a:buffer), ':p') let l:filename = fnamemodify(bufname(a:buffer), ':p')
let l:command = substitute( let l:command = substitute(
\ l:command, \ l:command,
\ '\v\%s(%(:h|:t|:r|:e)*)', \ s:path_format_regex,
\ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))', \ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))',
\ 'g' \ 'g'
\) \)
@ -279,9 +318,16 @@ function! s:ExitCallback(buffer, line_list, Callback, data) abort
let l:result = a:data.result let l:result = a:data.result
let l:result.value = l:value let l:result.value = l:value
" Set the default cwd for this buffer in this call stack.
call ale#command#SetCwd(a:buffer, l:result.cwd)
try
if get(l:result, 'result_callback', v:null) isnot v:null if get(l:result, 'result_callback', v:null) isnot v:null
call call(l:result.result_callback, [l:value]) call call(l:result.result_callback, [l:value])
endif endif
finally
call ale#command#ResetCwd(a:buffer)
endtry
endfunction endfunction
function! ale#command#Run(buffer, command, Callback, ...) abort function! ale#command#Run(buffer, command, Callback, ...) abort
@ -293,6 +339,13 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
let l:output_stream = get(l:options, 'output_stream', 'stdout') let l:output_stream = get(l:options, 'output_stream', 'stdout')
let l:line_list = [] let l:line_list = []
let l:cwd = get(l:options, 'cwd', v:null)
if l:cwd is v:null
" Default the working directory to whatever it was for the last
" command run in the chain.
let l:cwd = get(get(s:buffer_data, a:buffer, {}), 'cwd', v:null)
endif
let [l:temporary_file, l:command, l:file_created] = ale#command#FormatCommand( let [l:temporary_file, l:command, l:file_created] = ale#command#FormatCommand(
\ a:buffer, \ a:buffer,
@ -300,6 +353,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),
\ l:cwd,
\ get(l:options, 'filename_mappings', []), \ 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)
@ -366,10 +420,14 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
" The `_deferred_job_id` is used for both checking the type of object, and " The `_deferred_job_id` is used for both checking the type of object, and
" for checking the job ID and status. " for checking the job ID and status.
" "
" The cwd is kept and used as the default value for the next command in
" the chain.
"
" The original command here is used in tests. " The original command here is used in tests.
let l:result = { let l:result = {
\ '_deferred_job_id': l:job_id, \ '_deferred_job_id': l:job_id,
\ 'executable': get(l:options, 'executable', ''), \ 'executable': get(l:options, 'executable', ''),
\ 'cwd': l:cwd,
\ 'command': a:command, \ 'command': a:command,
\} \}

View file

@ -33,13 +33,13 @@ let s:global_variable_list = [
\ 'ale_list_vertical', \ 'ale_list_vertical',
\ 'ale_list_window_size', \ 'ale_list_window_size',
\ 'ale_loclist_msg_format', \ 'ale_loclist_msg_format',
\ 'ale_lsp_root',
\ 'ale_max_buffer_history_size', \ 'ale_max_buffer_history_size',
\ 'ale_max_signs', \ 'ale_max_signs',
\ 'ale_maximum_file_size', \ 'ale_maximum_file_size',
\ 'ale_open_list', \ 'ale_open_list',
\ 'ale_pattern_options', \ 'ale_pattern_options',
\ 'ale_pattern_options_enabled', \ 'ale_pattern_options_enabled',
\ 'ale_root',
\ 'ale_set_balloons', \ 'ale_set_balloons',
\ 'ale_set_highlights', \ 'ale_set_highlights',
\ 'ale_set_loclist', \ 'ale_set_loclist',

View file

@ -36,7 +36,7 @@ function! ale#definition#UpdateTagStack() abort
endfunction endfunction
function! ale#definition#HandleTSServerResponse(conn_id, response) abort function! ale#definition#HandleTSServerResponse(conn_id, response) abort
if get(a:response, 'command', '') is# 'definition' if has_key(a:response, 'request_seq')
\&& has_key(s:go_to_definition_map, a:response.request_seq) \&& has_key(s:go_to_definition_map, a:response.request_seq)
let l:options = remove(s:go_to_definition_map, a:response.request_seq) let l:options = remove(s:go_to_definition_map, a:response.request_seq)
@ -92,11 +92,19 @@ function! s:OnReady(line, column, options, capability, linter, lsp_details) abor
call ale#lsp#RegisterCallback(l:id, l:Callback) call ale#lsp#RegisterCallback(l:id, l:Callback)
if a:linter.lsp is# 'tsserver' if a:linter.lsp is# 'tsserver'
if a:capability is# 'definition'
let l:message = ale#lsp#tsserver_message#Definition( let l:message = ale#lsp#tsserver_message#Definition(
\ l:buffer, \ l:buffer,
\ a:line, \ a:line,
\ a:column \ a:column
\) \)
elseif a:capability is# 'typeDefinition'
let l:message = ale#lsp#tsserver_message#TypeDefinition(
\ l:buffer,
\ a:line,
\ a:column
\)
endif
else else
" Send a message saying the buffer has changed first, or the " Send a message saying the buffer has changed first, or the
" definition position probably won't make sense. " definition position probably won't make sense.
@ -145,12 +153,6 @@ endfunction
function! ale#definition#GoToType(options) abort function! ale#definition#GoToType(options) abort
for l:linter in ale#linter#Get(&filetype) for l:linter in ale#linter#Get(&filetype)
if !empty(l:linter.lsp) if !empty(l:linter.lsp)
" TODO: handle typeDefinition for tsserver if supported by the
" protocol
if l:linter.lsp is# 'tsserver'
continue
endif
call s:GoToLSPDefinition(l:linter, a:options, 'typeDefinition') call s:GoToLSPDefinition(l:linter, a:options, 'typeDefinition')
endif endif
endfor endfor

View file

@ -413,6 +413,7 @@ function! s:RunJob(command, options) abort
return 0 return 0
endif endif
let l:cwd = a:options.cwd
let l:executable = a:options.executable let l:executable = a:options.executable
let l:buffer = a:options.buffer let l:buffer = a:options.buffer
let l:linter = a:options.linter let l:linter = a:options.linter
@ -425,6 +426,7 @@ function! s:RunJob(command, options) abort
\ 'executable': l:executable, \ 'executable': l:executable,
\}]) \}])
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, { let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
\ 'cwd': l:cwd,
\ '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,
@ -541,8 +543,22 @@ function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
let l:job_type = a: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)
" Get the cwd for the linter and set it before we call GetCommand.
" This will ensure that ale#command#Run uses it by default.
let l:cwd = ale#linter#GetCwd(a:buffer, a:linter)
if l:cwd isnot v:null
call ale#command#SetCwd(a:buffer, l:cwd)
endif
let l:command = ale#linter#GetCommand(a:buffer, a:linter) let l:command = ale#linter#GetCommand(a:buffer, a:linter)
if l:cwd isnot v:null
call ale#command#ResetCwd(a:buffer)
endif
let l:options = { let l:options = {
\ 'cwd': l:cwd,
\ 'executable': a:executable, \ 'executable': a:executable,
\ 'buffer': a:buffer, \ 'buffer': a:buffer,
\ 'linter': a:linter, \ 'linter': a:linter,

View file

@ -172,6 +172,7 @@ function! s:RunJob(result, options) abort
let l:read_temporary_file = get(a:result, 'read_temporary_file', 0) let l:read_temporary_file = get(a:result, 'read_temporary_file', 0)
let l:read_buffer = get(a:result, 'read_buffer', 1) let l:read_buffer = get(a:result, 'read_buffer', 1)
let l:output_stream = get(a:result, 'output_stream', 'stdout') let l:output_stream = get(a:result, 'output_stream', 'stdout')
let l:cwd = get(a:result, 'cwd', v:null)
if l:read_temporary_file if l:read_temporary_file
let l:output_stream = 'none' let l:output_stream = 'none'
@ -190,6 +191,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,
\ 'cwd': l:cwd,
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name), \ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name),
\}) \})

View file

@ -32,6 +32,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['python'], \ 'suggested_filetypes': ['python'],
\ 'description': 'Fix PEP8 issues with black.', \ 'description': 'Fix PEP8 issues with black.',
\ }, \ },
\ 'buildifier': {
\ 'function': 'ale#fixers#buildifier#Fix',
\ 'suggested_filetypes': ['bzl'],
\ 'description': 'Format BUILD and .bzl files with buildifier.',
\ },
\ 'deno': { \ 'deno': {
\ 'function': 'ale#fixers#deno#Fix', \ 'function': 'ale#fixers#deno#Fix',
\ 'suggested_filetypes': ['typescript'], \ 'suggested_filetypes': ['typescript'],
@ -107,7 +112,7 @@ let s:default_registry = {
\ }, \ },
\ 'prettier': { \ 'prettier': {
\ 'function': 'ale#fixers#prettier#Fix', \ 'function': 'ale#fixers#prettier#Fix',
\ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue', 'html', 'yaml', 'openapi'], \ 'suggested_filetypes': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'json5', 'graphql', 'markdown', 'vue', 'html', 'yaml', 'openapi', 'ruby'],
\ 'description': 'Apply prettier to a file.', \ 'description': 'Apply prettier to a file.',
\ }, \ },
\ 'prettier_eslint': { \ 'prettier_eslint': {

View file

@ -19,7 +19,9 @@ function! ale#fixers#autoimport#Fix(buffer) abort
endif endif
return { return {
\ 'command': ale#path#BufferCdString(a:buffer) \ 'cwd': '%s:h',
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -', \ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -',
\} \}
endfunction endfunction

View file

@ -17,25 +17,25 @@ function! ale#fixers#black#GetExecutable(buffer) abort
endfunction endfunction
function! ale#fixers#black#Fix(buffer) abort function! ale#fixers#black#Fix(buffer) abort
let l:cd_string = ale#Var(a:buffer, 'python_black_change_directory')
\ ? ale#path#BufferCdString(a:buffer)
\ : ''
let l:executable = ale#fixers#black#GetExecutable(a:buffer) let l:executable = ale#fixers#black#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run black' \ ? ' run black'
\ : '' \ : ''
let l:options = ale#Var(a:buffer, 'python_black_options') let l:options = ale#Var(a:buffer, 'python_black_options')
if expand('#' . a:buffer . ':e') is? 'pyi' if expand('#' . a:buffer . ':e') is? 'pyi'
let l:options .= '--pyi' let l:options .= '--pyi'
endif endif
return { let l:result = {
\ 'command': l:cd_string . ale#Escape(l:executable) . l:exec_args \ 'command': ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -', \ . ' -',
\} \}
if ale#Var(a:buffer, 'python_black_change_directory')
let l:result.cwd = '%s:h'
endif
return l:result
endfunction endfunction

View file

@ -0,0 +1,37 @@
" Author: Jon Parise <jon@indelible.org>
" Description: Format Bazel BUILD and .bzl files with buildifier.
"
call ale#Set('bazel_buildifier_executable', 'buildifier')
call ale#Set('bazel_buildifier_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('bazel_buildifier_options', '')
function! ale#fixers#buildifier#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'bazel_buildifier', [
\ 'buildifier',
\])
endfunction
function! ale#fixers#buildifier#Fix(buffer) abort
let l:executable = ale#Escape(ale#fixers#buildifier#GetExecutable(a:buffer))
let l:options = ale#Var(a:buffer, 'bazel_buildifier_options')
let l:filename = fnamemodify(bufname(a:buffer), ':t')
let l:command = l:executable . ' -mode fix -lint fix'
" Attempt to guess the file type based on the filename. buildifier itself
" usually does this based on the filenames provided on the command line,
" but because we're piping our buffer via stdin, we do this manually.
if l:filename =~? 'WORKSPACE'
let l:command .= ' -type workspace'
elseif l:filename =~? 'BUILD'
let l:command .= ' -type build'
elseif l:filename =~? '.bzl$'
let l:command .= ' -type bzl'
endif
if l:options isnot# ''
let l:command .= ' ' . l:options
endif
return {'command': l:command . ' -'}
endfunction

View file

@ -5,6 +5,8 @@ scriptencoding utf-8
call ale#Set('c_clangformat_executable', 'clang-format') call ale#Set('c_clangformat_executable', 'clang-format')
call ale#Set('c_clangformat_use_global', get(g:, 'ale_use_global_executables', 0)) call ale#Set('c_clangformat_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('c_clangformat_options', '') call ale#Set('c_clangformat_options', '')
call ale#Set('c_clangformat_style_option', '')
call ale#Set('c_clangformat_use_local_file', 0)
function! ale#fixers#clangformat#GetExecutable(buffer) abort function! ale#fixers#clangformat#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'c_clangformat', [ return ale#node#FindExecutable(a:buffer, 'c_clangformat', [
@ -16,6 +18,24 @@ function! ale#fixers#clangformat#Fix(buffer) abort
let l:executable = ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer)) let l:executable = ale#Escape(ale#fixers#clangformat#GetExecutable(a:buffer))
let l:filename = ale#Escape(bufname(a:buffer)) let l:filename = ale#Escape(bufname(a:buffer))
let l:options = ale#Var(a:buffer, 'c_clangformat_options') let l:options = ale#Var(a:buffer, 'c_clangformat_options')
let l:style_option = ale#Var(a:buffer, 'c_clangformat_style_option')
let l:use_local_file = ale#Var(a:buffer, 'c_clangformat_use_local_file')
if l:style_option isnot# ''
let l:style_option = '-style=' . "'" . l:style_option . "'"
endif
if l:use_local_file
let l:config = ale#path#FindNearestFile(a:buffer, '.clang-format')
if !empty(l:config)
let l:style_option = '-style=file'
endif
endif
if l:style_option isnot# ''
let l:options .= ' ' . l:style_option
endif
let l:command = l:executable . ' --assume-filename=' . l:filename let l:command = l:executable . ' --assume-filename=' . l:filename

View file

@ -0,0 +1,21 @@
" Author: AntoineGagne - https://github.com/AntoineGagne
" Description: Integration of erlfmt with ALE.
call ale#Set('erlang_erlfmt_executable', 'erlfmt')
call ale#Set('erlang_erlfmt_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('erlang_erlfmt_options', '')
function! ale#fixers#erlfmt#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'erlang_erlfmt', ['erlfmt'])
endfunction
function! ale#fixers#erlfmt#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'erlang_erlfmt_options')
let l:executable = ale#fixers#erlfmt#GetExecutable(a:buffer)
let l:command = ale#Escape(l:executable) . (empty(l:options) ? '' : ' ' . l:options) . ' %s'
return {
\ 'command': l:command
\}
endfunction

View file

@ -53,8 +53,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
" Use --fix-to-stdout with eslint_d " Use --fix-to-stdout with eslint_d
if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0]) if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0])
return { return {
\ 'command': ale#handlers#eslint#GetCdString(a:buffer) \ 'cwd': ale#handlers#eslint#GetCwd(a:buffer),
\ . ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ale#Pad(l:options) \ . ale#Pad(l:options)
\ . ' --stdin-filename %s --stdin --fix-to-stdout', \ . ' --stdin-filename %s --stdin --fix-to-stdout',
\ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput',
@ -64,8 +64,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
" 4.9.0 is the first version with --fix-dry-run " 4.9.0 is the first version with --fix-dry-run
if ale#semver#GTE(a:version, [4, 9, 0]) if ale#semver#GTE(a:version, [4, 9, 0])
return { return {
\ 'command': ale#handlers#eslint#GetCdString(a:buffer) \ 'cwd': ale#handlers#eslint#GetCwd(a:buffer),
\ . ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ale#Pad(l:options) \ . ale#Pad(l:options)
\ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json',
\ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput',
@ -73,8 +73,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
endif endif
return { return {
\ 'command': ale#handlers#eslint#GetCdString(a:buffer) \ 'cwd': ale#handlers#eslint#GetCwd(a:buffer),
\ . ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ale#Pad(l:options) \ . ale#Pad(l:options)
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '') \ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
\ . ' --fix %t', \ . ' --fix %t',

View file

@ -17,9 +17,7 @@ endfunction
function! ale#fixers#isort#Fix(buffer) abort function! ale#fixers#isort#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'python_isort_options') let l:options = ale#Var(a:buffer, 'python_isort_options')
let l:executable = ale#fixers#isort#GetExecutable(a:buffer) let l:executable = ale#fixers#isort#GetExecutable(a:buffer)
let l:exec_args = l:executable =~? 'pipenv$' let l:exec_args = l:executable =~? 'pipenv$'
\ ? ' run isort' \ ? ' run isort'
\ : '' \ : ''
@ -29,8 +27,8 @@ function! ale#fixers#isort#Fix(buffer) abort
endif endif
return { return {
\ 'command': ale#path#BufferCdString(a:buffer) \ 'cwd': '%s:h',
\ . ale#Escape(l:executable) . l:exec_args \ 'command': ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') . ' -', \ . (!empty(l:options) ? ' ' . l:options : '') . ' -',
\} \}
endfunction endfunction

View file

@ -34,19 +34,11 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
return a:output return a:output
endfunction endfunction
function! ale#fixers#prettier#GetProjectRoot(buffer) abort function! ale#fixers#prettier#GetCwd(buffer) abort
let l:config = ale#path#FindNearestFile(a:buffer, '.prettierignore') 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 " Fall back to the directory of the buffer
return fnamemodify(bufname(a:buffer), ':p:h') return !empty(l:config) ? fnamemodify(l:config, ':h') : '%s:h'
endfunction
function! ale#fixers#prettier#CdProjectRoot(buffer) abort
return ale#path#CdString(ale#fixers#prettier#GetProjectRoot(a:buffer))
endfunction endfunction
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
@ -85,6 +77,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
\ 'yaml': 'yaml', \ 'yaml': 'yaml',
\ 'openapi': 'yaml', \ 'openapi': 'yaml',
\ 'html': 'html', \ 'html': 'html',
\ 'ruby': 'ruby',
\} \}
for l:filetype in l:filetypes for l:filetype in l:filetypes
@ -102,8 +95,8 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
" Special error handling needed for prettier_d " Special error handling needed for prettier_d
if l:executable =~# 'prettier_d$' if l:executable =~# 'prettier_d$'
return { return {
\ 'command': ale#path#BufferCdString(a:buffer) \ 'cwd': '%s:h',
\ . ale#Escape(l:executable) \ 'command':ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
\ 'process_with': 'ale#fixers#prettier#ProcessPrettierDOutput', \ 'process_with': 'ale#fixers#prettier#ProcessPrettierDOutput',
@ -113,8 +106,8 @@ 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#fixers#prettier#CdProjectRoot(a:buffer) \ 'cwd': ale#fixers#prettier#GetCwd(a:buffer),
\ . ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
\} \}

View file

@ -37,8 +37,8 @@ function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version) abort
" 4.4.0 is the first version with --stdin-filepath " 4.4.0 is the first version with --stdin-filepath
if ale#semver#GTE(a:version, [4, 4, 0]) if ale#semver#GTE(a:version, [4, 4, 0])
return { return {
\ 'command': ale#path#BufferCdString(a:buffer) \ 'cwd': '%s:h',
\ . ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . l:eslint_config_option \ . l:eslint_config_option
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',

View file

@ -17,8 +17,8 @@ function! ale#fixers#stylelint#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'stylelint_options') let l:options = ale#Var(a:buffer, 'stylelint_options')
return { return {
\ 'command': ale#path#BufferCdString(a:buffer) \ 'cwd': '%s:h',
\ . ale#node#Executable(a:buffer, l:executable) \ 'command': ale#node#Executable(a:buffer, l:executable)
\ . ' %t' \ . ' %t'
\ . ale#Pad(l:options) \ . ale#Pad(l:options)
\ . ' --fix', \ . ' --fix',

View file

@ -7,7 +7,6 @@ call ale#Set('yaml_yamlfix_use_global', get(g:, 'ale_use_global_executables', 0)
function! ale#fixers#yamlfix#Fix(buffer) abort function! ale#fixers#yamlfix#Fix(buffer) abort
let l:options = ale#Var(a:buffer, 'yaml_yamlfix_options') let l:options = ale#Var(a:buffer, 'yaml_yamlfix_options')
let l:executable = ale#python#FindExecutable( let l:executable = ale#python#FindExecutable(
\ a:buffer, \ a:buffer,
\ 'yaml_yamlfix', \ 'yaml_yamlfix',
@ -19,7 +18,8 @@ function! ale#fixers#yamlfix#Fix(buffer) abort
endif endif
return { return {
\ 'command': ale#path#BufferCdString(a:buffer) \ 'cwd': '%s:h',
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -', \ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') . ' -',
\} \}
endfunction endfunction

View file

@ -47,16 +47,53 @@ function! ale#floating_preview#Show(lines, ...) abort
endif endif
augroup END augroup END
let l:width = max(map(copy(a:lines), 'strdisplaywidth(v:val)')) let [l:lines, l:width, l:height] = s:PrepareWindowContent(a:lines)
let l:height = min([len(a:lines), 10])
call nvim_win_set_width(w:preview['id'], l:width) call nvim_win_set_width(w:preview['id'], l:width)
call nvim_win_set_height(w:preview['id'], l:height) call nvim_win_set_height(w:preview['id'], l:height)
call nvim_buf_set_lines(w:preview['buffer'], 0, -1, v:false, l:lines)
call nvim_buf_set_lines(w:preview['buffer'], 0, -1, v:false, a:lines)
call nvim_buf_set_option(w:preview['buffer'], 'modified', v:false) call nvim_buf_set_option(w:preview['buffer'], 'modified', v:false)
call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:false) call nvim_buf_set_option(w:preview['buffer'], 'modifiable', v:false)
endfunction endfunction
function! s:PrepareWindowContent(lines) abort
let l:max_height = 10
let l:width = max(map(copy(a:lines), 'strdisplaywidth(v:val)'))
let l:height = min([len(a:lines), l:max_height])
if empty(g:ale_floating_window_border)
return [a:lines, l:width, l:height]
endif
" Add the size of borders
let l:width += 2
let l:height += 2
let l:hor = g:ale_floating_window_border[0]
let l:top = g:ale_floating_window_border[1]
let l:top_left = g:ale_floating_window_border[2]
let l:top_right = g:ale_floating_window_border[3]
let l:bottom_right = g:ale_floating_window_border[4]
let l:bottom_left = g:ale_floating_window_border[5]
let l:lines = [l:top_left . repeat(l:top, l:width - 2) . l:top_right]
for l:line in a:lines
let l:line_width = strchars(l:line)
let l:lines = add(l:lines, l:hor . l:line . repeat(' ', l:width - l:line_width - 2). l:hor)
endfor
" Truncate the lines
if len(l:lines) > l:max_height + 1
let l:lines = l:lines[0:l:max_height]
endif
let l:lines = add(l:lines, l:bottom_left . repeat(l:top, l:width - 2) . l:bottom_right)
return [l:lines, l:width, l:height]
endfunction
function! s:Create(options) abort function! s:Create(options) abort
let l:buffer = nvim_create_buf(v:false, v:false) let l:buffer = nvim_create_buf(v:false, v:false)
let l:winid = nvim_open_win(l:buffer, v:false, { let l:winid = nvim_open_win(l:buffer, v:false, {
@ -88,4 +125,3 @@ function! s:Close() abort
unlet w:preview unlet w:preview
endfunction endfunction

View file

@ -50,18 +50,25 @@ function! ale#gradle#FindExecutable(buffer) abort
return '' return ''
endfunction endfunction
" Given a buffer number, build a command to print the classpath of the root " Given a buffer number, get a working directory and command to print the
" project. Returns an empty string if cannot build the command. " classpath of the root project.
"
" Returns an empty string for the command if Gradle is not detected.
function! ale#gradle#BuildClasspathCommand(buffer) abort function! ale#gradle#BuildClasspathCommand(buffer) abort
let l:executable = ale#gradle#FindExecutable(a:buffer) let l:executable = ale#gradle#FindExecutable(a:buffer)
if !empty(l:executable)
let l:project_root = ale#gradle#FindProjectRoot(a:buffer) let l:project_root = ale#gradle#FindProjectRoot(a:buffer)
if !empty(l:executable) && !empty(l:project_root) if !empty(l:project_root)
return ale#path#CdString(l:project_root) return [
\ . ale#Escape(l:executable) \ l:project_root,
\ ale#Escape(l:executable)
\ . ' -I ' . ale#Escape(s:init_path) \ . ' -I ' . ale#Escape(s:init_path)
\ . ' -q printClasspath' \ . ' -q printClasspath'
\]
endif
endif endif
return '' return ['', '']
endfunction endfunction

View file

@ -1,10 +1,9 @@
" Description: Handle errors for cppcheck. " Description: Handle errors for cppcheck.
function! ale#handlers#cppcheck#GetCdCommand(buffer) abort function! ale#handlers#cppcheck#GetCwd(buffer) abort
let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer) let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer)
let l:cd_command = !empty(l:dir) ? ale#path#CdString(l:dir) : ''
return l:cd_command return !empty(l:dir) ? l:dir : ''
endfunction endfunction
function! ale#handlers#cppcheck#GetBufferPathIncludeOptions(buffer) abort function! ale#handlers#cppcheck#GetBufferPathIncludeOptions(buffer) abort

View file

@ -39,9 +39,8 @@ function! ale#handlers#eslint#GetExecutable(buffer) abort
return ale#node#FindExecutable(a:buffer, 'javascript_eslint', s:executables) return ale#node#FindExecutable(a:buffer, 'javascript_eslint', s:executables)
endfunction endfunction
" Given a buffer, return a command prefix string which changes directory " Given a buffer, return an appropriate working directory for ESLint.
" as necessary for running ESLint. function! ale#handlers#eslint#GetCwd(buffer) abort
function! ale#handlers#eslint#GetCdString(buffer) abort
" ESLint 6 loads plugins/configs/parsers from the project root " ESLint 6 loads plugins/configs/parsers from the project root
" By default, the project root is simply the CWD of the running process. " By default, the project root is simply the CWD of the running process.
" https://github.com/eslint/rfcs/blob/master/designs/2018-simplified-package-loading/README.md " https://github.com/eslint/rfcs/blob/master/designs/2018-simplified-package-loading/README.md
@ -56,11 +55,24 @@ function! ale#handlers#eslint#GetCdString(buffer) abort
let l:nmi = strridx(l:executable, 'node_modules') let l:nmi = strridx(l:executable, 'node_modules')
let l:project_dir = l:executable[0:l:nmi - 2] let l:project_dir = l:executable[0:l:nmi - 2]
else else
" Patched behaviour: looks up yarn pnp before node_modules to add
" support for Yarn Berry.
let l:modules_dir = ale#path#FindNearestDirectory(a:buffer, 'node_modules') let l:modules_dir = ale#path#FindNearestDirectory(a:buffer, 'node_modules')
let l:yarn_cpnp = ale#path#FindNearestFile(a:buffer, '.pnp.cjs')
let l:yarn_pnp = ale#path#FindNearestFile(a:buffer, '.pnp.js')
if !empty(l:yarn_pnp)
let l:project_dir = !empty(l:yarn_pnp) ? fnamemodify(l:yarn_pnp, ':h') : ''
elseif !empty(l:yarn_cpnp)
let l:project_dir = !empty(l:yarn_cpnp) ? fnamemodify(l:yarn_cpnp, ':h') : ''
elseif !empty(l:modules_dir)
let l:project_dir = !empty(l:modules_dir) ? fnamemodify(l:modules_dir, ':h:h') : '' let l:project_dir = !empty(l:modules_dir) ? fnamemodify(l:modules_dir, ':h:h') : ''
else
let l:project_dir = ''
endif
endif endif
return !empty(l:project_dir) ? ale#path#CdString(l:project_dir) : '' return !empty(l:project_dir) ? l:project_dir : ''
endfunction endfunction
function! ale#handlers#eslint#GetCommand(buffer) abort function! ale#handlers#eslint#GetCommand(buffer) abort
@ -68,8 +80,7 @@ function! ale#handlers#eslint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'javascript_eslint_options') let l:options = ale#Var(a:buffer, 'javascript_eslint_options')
return ale#handlers#eslint#GetCdString(a:buffer) return ale#node#Executable(a:buffer, l:executable)
\ . ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . ' -f json --stdin --stdin-filename %s' \ . ' -f json --stdin --stdin-filename %s'
endfunction endfunction

View file

@ -0,0 +1,23 @@
" Author: Risto Stevcev <me@risto.codes>
" Description: Handlers for the official OCaml language server
function! ale#handlers#ocamllsp#GetExecutable(buffer) abort
return 'ocamllsp'
endfunction
function! ale#handlers#ocamllsp#GetCommand(buffer) abort
let l:executable = ale#handlers#ocamllsp#GetExecutable(a:buffer)
let l:ocaml_ocamllsp_use_opam = ale#Var(a:buffer, 'ocaml_ocamllsp_use_opam')
return l:ocaml_ocamllsp_use_opam ? 'opam config exec -- ' . l:executable : l:executable
endfunction
function! ale#handlers#ocamllsp#GetLanguage(buffer) abort
return getbufvar(a:buffer, '&filetype')
endfunction
function! ale#handlers#ocamllsp#GetProjectRoot(buffer) abort
let l:dune_project_file = ale#path#FindNearestFile(a:buffer, 'dune-project')
return !empty(l:dune_project_file) ? fnamemodify(l:dune_project_file, ':h') : ''
endfunction

View file

@ -40,21 +40,21 @@ function! ale#handlers#shellcheck#GetDialectArgument(buffer) abort
return '' return ''
endfunction endfunction
function! ale#handlers#shellcheck#GetCwd(buffer) abort
return ale#Var(a:buffer, 'sh_shellcheck_change_directory') ? '%s:h' : ''
endfunction
function! ale#handlers#shellcheck#GetCommand(buffer, version) abort function! ale#handlers#shellcheck#GetCommand(buffer, version) abort
let l:options = ale#Var(a:buffer, 'sh_shellcheck_options') let l:options = ale#Var(a:buffer, 'sh_shellcheck_options')
let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions') let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions')
let l:dialect = ale#Var(a:buffer, 'sh_shellcheck_dialect') let l:dialect = ale#Var(a:buffer, 'sh_shellcheck_dialect')
let l:external_option = ale#semver#GTE(a:version, [0, 4, 0]) ? ' -x' : '' let l:external_option = ale#semver#GTE(a:version, [0, 4, 0]) ? ' -x' : ''
let l:cd_string = ale#Var(a:buffer, 'sh_shellcheck_change_directory')
\ ? ale#path#BufferCdString(a:buffer)
\ : ''
if l:dialect is# 'auto' if l:dialect is# 'auto'
let l:dialect = ale#handlers#shellcheck#GetDialectArgument(a:buffer) let l:dialect = ale#handlers#shellcheck#GetDialectArgument(a:buffer)
endif endif
return l:cd_string return '%e'
\ . '%e'
\ . (!empty(l:dialect) ? ' -s ' . l:dialect : '') \ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:options) ? ' ' . l:options : '')
\ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '') \ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '')
@ -111,6 +111,7 @@ function! ale#handlers#shellcheck#DefineLinter(filetype) abort
call ale#linter#Define(a:filetype, { call ale#linter#Define(a:filetype, {
\ 'name': 'shellcheck', \ 'name': 'shellcheck',
\ 'executable': {buffer -> ale#Var(buffer, 'sh_shellcheck_executable')}, \ 'executable': {buffer -> ale#Var(buffer, 'sh_shellcheck_executable')},
\ 'cwd': function('ale#handlers#shellcheck#GetCwd'),
\ 'command': {buffer -> ale#semver#RunWithVersionCheck( \ 'command': {buffer -> ale#semver#RunWithVersionCheck(
\ buffer, \ buffer,
\ ale#Var(buffer, 'sh_shellcheck_executable'), \ ale#Var(buffer, 'sh_shellcheck_executable'),

View file

@ -151,17 +151,30 @@ function! ale#linter#PreProcess(filetype, linter) abort
endif endif
let l:obj.address = a:linter.address let l:obj.address = a:linter.address
if has_key(a:linter, 'cwd')
throw '`cwd` makes no sense for socket LSP connections'
endif
else else
throw '`address` must be defined for getting the LSP address' throw '`address` must be defined for getting the LSP address'
endif endif
if has_key(a:linter, 'cwd')
let l:obj.cwd = a:linter.cwd
if type(l:obj.cwd) isnot v:t_string
\&& type(l:obj.cwd) isnot v:t_func
throw '`cwd` must be a String or Function if defined'
endif
endif
if l:needs_lsp_details if l:needs_lsp_details
" Default to using the filetype as the language. " Default to using the filetype as the language.
let l:obj.language = get(a:linter, 'language', a:filetype) let l:obj.language = get(a:linter, 'language', a:filetype)
if type(l:obj.language) isnot v:t_string if type(l:obj.language) isnot v:t_string
\&& type(l:obj.language) isnot v:t_func \&& type(l:obj.language) isnot v:t_func
throw '`language` must be a String or Funcref if defined' throw '`language` must be a String or Function if defined'
endif endif
if has_key(a:linter, 'project_root') if has_key(a:linter, 'project_root')
@ -415,6 +428,12 @@ function! ale#linter#GetExecutable(buffer, linter) abort
\ : l:Executable \ : l:Executable
endfunction endfunction
function! ale#linter#GetCwd(buffer, linter) abort
let l:Cwd = get(a:linter, 'cwd', v:null)
return type(l:Cwd) is v:t_func ? l:Cwd(a:buffer) : l:Cwd
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.
function! ale#linter#GetCommand(buffer, linter) abort function! ale#linter#GetCommand(buffer, linter) abort
let l:Command = a:linter.command let l:Command = a:linter.command

View file

@ -357,6 +357,7 @@ function! ale#lsp#MarkConnectionAsTsserver(conn_id) abort
let l:conn.capabilities.completion = 1 let l:conn.capabilities.completion = 1
let l:conn.capabilities.completion_trigger_characters = ['.'] let l:conn.capabilities.completion_trigger_characters = ['.']
let l:conn.capabilities.definition = 1 let l:conn.capabilities.definition = 1
let l:conn.capabilities.typeDefinition = 1
let l:conn.capabilities.symbol_search = 1 let l:conn.capabilities.symbol_search = 1
let l:conn.capabilities.rename = 1 let l:conn.capabilities.rename = 1
let l:conn.capabilities.code_actions = 1 let l:conn.capabilities.code_actions = 1

View file

@ -64,6 +64,14 @@ function! ale#lsp#tsserver_message#Definition(buffer, line, column) abort
\}] \}]
endfunction endfunction
function! ale#lsp#tsserver_message#TypeDefinition(buffer, line, column) abort
return [0, 'ts@typeDefinition', {
\ 'line': a:line,
\ 'offset': a:column,
\ 'file': expand('#' . a:buffer . ':p'),
\}]
endfunction
function! ale#lsp#tsserver_message#References(buffer, line, column) abort function! ale#lsp#tsserver_message#References(buffer, line, column) abort
return [0, 'ts@references', { return [0, 'ts@references', {
\ 'line': a:line, \ 'line': a:line,

View file

@ -201,7 +201,11 @@ function! ale#lsp_linter#GetConfig(buffer, linter) abort
endfunction endfunction
function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort
let l:buffer_ale_root = getbufvar(a:buffer, 'ale_lsp_root', {}) let l:buffer_ale_root = getbufvar(
\ a:buffer,
\ 'ale_root',
\ getbufvar(a:buffer, 'ale_lsp_root', {})
\)
if type(l:buffer_ale_root) is v:t_string if type(l:buffer_ale_root) is v:t_string
return l:buffer_ale_root return l:buffer_ale_root
@ -218,9 +222,15 @@ function! ale#lsp_linter#FindProjectRoot(buffer, linter) abort
endif endif
endif endif
let l:global_root = g:ale_root
if empty(g:ale_root) && exists('g:ale_lsp_root')
let l:global_root = g:ale_lsp_root
endif
" Try to get a global setting for the root " Try to get a global setting for the root
if has_key(g:ale_lsp_root, a:linter.name) if has_key(l:global_root, a:linter.name)
let l:Root = g:ale_lsp_root[a:linter.name] let l:Root = l:global_root[a:linter.name]
if type(l:Root) is v:t_func if type(l:Root) is v:t_func
return l:Root(a:buffer) return l:Root(a:buffer)
@ -290,6 +300,7 @@ function! s:StartLSP(options, address, executable, command) abort
\ a:command, \ a:command,
\ 0, \ 0,
\ v:false, \ v:false,
\ v:null,
\ [], \ [],
\)[1] \)[1]
let l:command = ale#job#PrepareCommand(l:buffer, l:command) let l:command = ale#job#PrepareCommand(l:buffer, l:command)

View file

@ -17,7 +17,6 @@ function! ale#maven#FindProjectRoot(buffer) abort
return '' return ''
endfunction endfunction
" Given a buffer number, find the path to the executable. " Given a buffer number, find the path to the executable.
" First search on the path for 'mvnw' (mvnw.cmd on Windows), if nothing is found, " First search on the path for 'mvnw' (mvnw.cmd on Windows), if nothing is found,
" try the global command. Returns an empty string if cannot find the executable. " try the global command. Returns an empty string if cannot find the executable.
@ -36,16 +35,23 @@ function! ale#maven#FindExecutable(buffer) abort
return '' return ''
endfunction endfunction
" Given a buffer number, build a command to print the classpath of the root " Given a buffer number, get a working directory and command to print the
" project. Returns an empty string if cannot build the command. " classpath of the root project.
"
" Returns an empty string for the command if Maven is not detected.
function! ale#maven#BuildClasspathCommand(buffer) abort function! ale#maven#BuildClasspathCommand(buffer) abort
let l:executable = ale#maven#FindExecutable(a:buffer) let l:executable = ale#maven#FindExecutable(a:buffer)
if !empty(l:executable)
let l:project_root = ale#maven#FindProjectRoot(a:buffer) let l:project_root = ale#maven#FindProjectRoot(a:buffer)
if !empty(l:executable) && !empty(l:project_root) if !empty(l:project_root)
return ale#path#CdString(l:project_root) return [
\ . l:executable . ' dependency:build-classpath' \ l:project_root,
\ ale#Escape(l:executable) . ' dependency:build-classpath'
\]
endif
endif endif
return '' return ['', '']
endfunction endfunction

View file

@ -77,26 +77,6 @@ function! ale#path#ResolveLocalPath(buffer, search_string, global_fallback) abor
return l:path return l:path
endfunction endfunction
" Output 'cd <directory> && '
" This function can be used changing the directory for a linter command.
function! ale#path#CdString(directory) abort
if has('win32')
return 'cd /d ' . ale#Escape(a:directory) . ' && '
endif
return 'cd ' . ale#Escape(a:directory) . ' && '
endfunction
" Output 'cd <buffer_filename_directory> && '
" This function can be used changing the directory for a linter command.
function! ale#path#BufferCdString(buffer) abort
if has('win32')
return 'cd /d %s:h && '
endif
return 'cd %s:h && '
endfunction
" Return 1 if a path is an absolute path. " Return 1 if a path is an absolute path.
function! ale#path#IsAbsolute(filename) abort function! ale#path#IsAbsolute(filename) abort
if has('win32') && a:filename[:0] is# '\' if has('win32') && a:filename[:0] is# '\'

28
doc/ale-bazel.txt Normal file
View file

@ -0,0 +1,28 @@
===============================================================================
ALE Bazel Integration *ale-bazel-options*
===============================================================================
buildifier *ale-bazel-buildifier*
g:ale_bazel_buildifier_executable *g:ale_bazel_buildifier_executable*
*b:ale_bazel_buildifier_executable*
Type: |String|
Default: `'buildifier'`
See |ale-integrations-local-executables|
g:ale_bazel_buildifier_options *g:ale_bazel_buildifier_options*
*b:ale_bazel_buildifier_options*
Type: |String|
Default: `''`
This variable can be set to pass extra options to buildifier.
g:ale_bazel_buildifier_use_global *g:ale_bazel_buildifier_use_global*
*b:ale_bazel_buildifier_use_global*
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', 0)`
See |ale-integrations-local-executables|

View file

@ -202,7 +202,45 @@ g:ale_c_clangformat_options *g:ale_c_clangformat_options*
Type: |String| Type: |String|
Default: `''` Default: `''`
This variable can be change to modify flags given to clang-format. This variable can be changed to modify flags given to clang-format.
g:ale_c_clangformat_style_option *g:ale_c_clangformat_style_option*
*b:ale_c_clangformat_style_option*
Type: |String|
Default: `''`
This variable can be changed to modify only the style flag given to
clang-format. The contents of the variable are passed directly to the -style
flag of clang-format.
Example: >
{
\ BasedOnStyle: Microsoft,
\ ColumnLimit: 80,
\ AllowShortBlocksOnASingleLine: Always,
\ AllowShortFunctionsOnASingleLine: Inline,
\ }
<
If you set this variable, ensure you don't modify -style in
|g:ale_c_clangformat_options|, as this will cause clang-format to error.
g:ale_c_clangformat_use_local_file *g:ale_c_clangformat_use_local_file*
*b:ale_c_clangformat_use_local_file*
Type: |Number|
Default: `0`
This variable can be changed to modify whether to use a local .clang-format
file. If the file is found, the flag '-style=file' is passed to clang-format
and any options configured via |g:ale_c_clangformat_style_option| are not
passed.
If this option is enabled but no .clang-format file is found, default back to
|g:ale_c_clangformat_style_option|, if it set.
If you set this variable, ensure you don't modify -style in
|g:ale_c_clangformat_options|, as this will cause clang-format to error.
=============================================================================== ===============================================================================

View file

@ -311,6 +311,7 @@ The full list of commands that will be temporarily defined for linter tests
given the above setup are as follows. given the above setup are as follows.
`GivenCommandOutput [...]` - Define output for ale#command#Run. `GivenCommandOutput [...]` - Define output for ale#command#Run.
`AssertLinterCwd cwd` - Check the `cwd` for the linter.
`AssertLinter executable, command` - Check the executable and command. `AssertLinter executable, command` - Check the executable and command.
`AssertLinterNotExecuted` - Check that linters will not be executed. `AssertLinterNotExecuted` - Check that linters will not be executed.
`AssertLSPLanguage language` - Check the language given to an LSP server. `AssertLSPLanguage language` - Check the language given to an LSP server.
@ -357,6 +358,7 @@ The full list of commands that will be temporarily defined for fixer tests
given the above setup are as follows. given the above setup are as follows.
`GivenCommandOutput [...]` - Define output for ale#command#Run. `GivenCommandOutput [...]` - Define output for ale#command#Run.
`AssertFixerCwd cwd` - Check the `cwd` for the fixer.
`AssertFixer results` - Check the fixer results `AssertFixer results` - Check the fixer results
`AssertFixerNotExecuted` - Check that fixers will not be executed. `AssertFixerNotExecuted` - Check that fixers will not be executed.

View file

@ -71,6 +71,26 @@ g:ale_erlang_erlc_options *g:ale_erlang_erlc_options*
or `-pa`. or `-pa`.
-------------------------------------------------------------------------------
erlfmt *ale-erlang-erlfmt*
g:ale_erlang_erlfmt_executable *g:ale_erlang_erlfmt_executable*
*b:ale_erlang_erlfmt_executable*
Type: |String|
Default: `'erlfmt'`
This variable can be changed to specify the erlfmt executable.
g:ale_erlang_erlfmt_options *g:ale_erlang_erlfmt_options*
*b:ale_erlang_erlfmt_options*
Type: |String|
Default: `''`
This variable controls additional parameters passed to `erlfmt`, such as
`--insert-pragma` or `--print-width`.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
syntaxerl *ale-erlang-syntaxerl* syntaxerl *ale-erlang-syntaxerl*

View file

@ -10,6 +10,21 @@ merlin *ale-ocaml-merlin*
detailed instructions detailed instructions
(https://github.com/the-lambda-church/merlin/wiki/vim-from-scratch). (https://github.com/the-lambda-church/merlin/wiki/vim-from-scratch).
===============================================================================
ocamllsp *ale-ocaml-ocamllsp*
The `ocaml-lsp-server` is the official OCaml implementation of the Language
Server Protocol. See the installation instructions:
https://github.com/ocaml/ocaml-lsp#installation
g:ale_ocaml_ocamllsp_use_opam *g:ale_ocaml_ocamllsp_use_opam*
*b:ale_ocaml_ocamllsp_use_opam*
Type: |Number|
Default: `get(g:, 'ale_ocaml_ocamllsp_use_opam', 1)`
This variable can be set to change whether or not opam is used to execute
the language server.
=============================================================================== ===============================================================================
ols *ale-ocaml-ols* ols *ale-ocaml-ols*

View file

@ -41,6 +41,11 @@ g:ale_ruby_debride_options *g:ale_ruby_debride_options*
This variable can be changed to modify flags given to debride. This variable can be changed to modify flags given to debride.
===============================================================================
prettier *ale-ruby-prettier*
See |ale-javascript-prettier| for information about the available options.
=============================================================================== ===============================================================================
rails_best_practices *ale-ruby-rails_best_practices* rails_best_practices *ale-ruby-rails_best_practices*

View file

@ -43,6 +43,8 @@ Notes:
* `shfmt` * `shfmt`
* Bats * Bats
* `shellcheck` * `shellcheck`
* Bazel
* `buildifier`
* BibTeX * BibTeX
* `bibclean` * `bibclean`
* Bourne Shell * Bourne Shell
@ -148,8 +150,10 @@ Notes:
* `ruumba` * `ruumba`
* Erlang * Erlang
* `SyntaxErl` * `SyntaxErl`
* `dialyzer`
* `elvis`!! * `elvis`!!
* `erlc` * `erlc`
* `erlfmt`
* Fish * Fish
* `fish` (-n flag) * `fish` (-n flag)
* `fish_indent` * `fish_indent`
@ -329,6 +333,7 @@ Notes:
* OCaml * OCaml
* `merlin` (see |ale-ocaml-merlin|) * `merlin` (see |ale-ocaml-merlin|)
* `ocamlformat` * `ocamlformat`
* `ocamllsp`
* `ocp-indent` * `ocp-indent`
* `ols` * `ols`
* OpenApi * OpenApi
@ -431,6 +436,7 @@ Notes:
* Ruby * Ruby
* `brakeman` * `brakeman`
* `debride` * `debride`
* `prettier`
* `rails_best_practices`!! * `rails_best_practices`!!
* `reek` * `reek`
* `rubocop` * `rubocop`

View file

@ -342,6 +342,12 @@ the buffers being checked.
When a |Dictionary| is returned for an |ALEFix| callback, the following keys When a |Dictionary| is returned for an |ALEFix| callback, the following keys
are supported for running the commands. are supported for running the commands.
`cwd` An optional |String| for setting the working directory
for the command.
If not set, or `v:null`, the `cwd` of the last command
that spawn this one will be used.
`command` A |String| for the command to run. This key is required. `command` A |String| for the command to run. This key is required.
When `%t` is included in a command string, a temporary When `%t` is included in a command string, a temporary
@ -647,7 +653,8 @@ Hover information can be displayed in the preview window instead by setting
|g:ale_hover_to_preview| to `1`. |g:ale_hover_to_preview| to `1`.
When using Neovim, if |g:ale_hover_to_floating_preview| or |g:ale_floating_preview| When using Neovim, if |g:ale_hover_to_floating_preview| or |g:ale_floating_preview|
is set to 1, the hover information will show in a floating window. is set to 1, the hover information will show in a floating window. And
|g:ale_floating_window_border| for the border setting.
For Vim 8.1+ terminals, mouse hovering is disabled by default. Enabling For Vim 8.1+ terminals, mouse hovering is disabled by default. Enabling
|balloonexpr| commands in terminals can cause scrolling issues in terminals, |balloonexpr| commands in terminals can cause scrolling issues in terminals,
@ -1199,6 +1206,19 @@ g:ale_floating_preview *g:ale_floating_pre
|g:ale_detail_to_floating_preview| to `1`. |g:ale_detail_to_floating_preview| to `1`.
g:ale_floating_window_border *g:ale_floating_window_border*
Type: |List|
Default: `['|', '-', '+', '+', '+', '+']`
When set to `[]`, window borders are disabled. The elements in the list set
the horizontal, top, top-left, top-right, bottom-right and bottom-left
border characters, respectively.
If the terminal supports Unicode, you might try setting the value to
` ['│', '─', '╭', '╮', '╯', '╰']`, to make it look nicer.
g:ale_history_enabled *g:ale_history_enabled* g:ale_history_enabled *g:ale_history_enabled*
Type: |Number| Type: |Number|
@ -1718,24 +1738,6 @@ g:ale_lsp_suggestions *g:ale_lsp_suggestions*
addition to warnings and errors. addition to warnings and errors.
g:ale_lsp_root *g:ale_lsp_root*
*b:ale_lsp_root*
Type: |Dictionary| or |String|
Default: {}
This option is used to determine the project root for the LSP linter. If the
value is a |Dictionary|, it maps a linter to either a string containing the
project root or a |Funcref| to call to look up the root. The funcref is
provided the buffer number as its argument.
The buffer-specific variable may additionally be a string containing the
project root itself.
If neither variable yields a result, a linter-specific function is invoked to
detect a project root. If this, too, yields no result, the linter is disabled.
g:ale_max_buffer_history_size *g:ale_max_buffer_history_size* g:ale_max_buffer_history_size *g:ale_max_buffer_history_size*
Type: |Number| Type: |Number|
@ -1880,6 +1882,25 @@ g:ale_rename_tsserver_find_in_strings *g:ale_rename_tsserver_find_in_strings*
`1`. `1`.
g:ale_root *g:ale_root*
*b:ale_root*
Type: |Dictionary| or |String|
Default: {}
This option is used to determine the project root for a linter. If the value
is a |Dictionary|, it maps a linter to either a |String| containing the
project root or a |Funcref| to call to look up the root. The |Funcref| is
provided the buffer number as its argument.
The buffer-specific variable may additionally be a string containing the
project root itself.
If neither variable yields a result, a linter-specific function is invoked to
detect a project root. If this, too, yields no result, and the linter is an
LSP linter, it will not run.
g:ale_set_balloons *g:ale_set_balloons* g:ale_set_balloons *g:ale_set_balloons*
*b:ale_set_balloons* *b:ale_set_balloons*
@ -2614,6 +2635,8 @@ documented in additional help files.
gawk..................................|ale-awk-gawk| gawk..................................|ale-awk-gawk|
bats....................................|ale-bats-options| bats....................................|ale-bats-options|
shellcheck............................|ale-bats-shellcheck| shellcheck............................|ale-bats-shellcheck|
bazel...................................|ale-bazel-options|
buildifier............................|ale-bazel-buildifier|
bib.....................................|ale-bib-options| bib.....................................|ale-bib-options|
bibclean..............................|ale-bib-bibclean| bibclean..............................|ale-bib-bibclean|
c.......................................|ale-c-options| c.......................................|ale-c-options|
@ -2695,6 +2718,7 @@ documented in additional help files.
dialyzer..............................|ale-erlang-dialyzer| dialyzer..............................|ale-erlang-dialyzer|
elvis.................................|ale-erlang-elvis| elvis.................................|ale-erlang-elvis|
erlc..................................|ale-erlang-erlc| erlc..................................|ale-erlang-erlc|
erlfmt................................|ale-erlang-erlfmt|
syntaxerl.............................|ale-erlang-syntaxerl| syntaxerl.............................|ale-erlang-syntaxerl|
eruby...................................|ale-eruby-options| eruby...................................|ale-eruby-options|
ruumba................................|ale-eruby-ruumba| ruumba................................|ale-eruby-ruumba|
@ -2843,6 +2867,7 @@ documented in additional help files.
uncrustify............................|ale-objcpp-uncrustify| uncrustify............................|ale-objcpp-uncrustify|
ocaml...................................|ale-ocaml-options| ocaml...................................|ale-ocaml-options|
merlin................................|ale-ocaml-merlin| merlin................................|ale-ocaml-merlin|
ocamllsp..............................|ale-ocaml-ocamllsp|
ols...................................|ale-ocaml-ols| ols...................................|ale-ocaml-ols|
ocamlformat...........................|ale-ocaml-ocamlformat| ocamlformat...........................|ale-ocaml-ocamlformat|
ocp-indent............................|ale-ocaml-ocp-indent| ocp-indent............................|ale-ocaml-ocp-indent|
@ -2931,6 +2956,7 @@ documented in additional help files.
ruby....................................|ale-ruby-options| ruby....................................|ale-ruby-options|
brakeman..............................|ale-ruby-brakeman| brakeman..............................|ale-ruby-brakeman|
debride...............................|ale-ruby-debride| debride...............................|ale-ruby-debride|
prettier..............................|ale-ruby-prettier|
rails_best_practices..................|ale-ruby-rails_best_practices| rails_best_practices..................|ale-ruby-rails_best_practices|
reek..................................|ale-ruby-reek| reek..................................|ale-ruby-reek|
rubocop...............................|ale-ruby-rubocop| rubocop...............................|ale-ruby-rubocop|
@ -3573,6 +3599,12 @@ ale#command#Run(buffer, command, callback, [options]) *ale#command#Run()*
< <
The following `options` can be provided. The following `options` can be provided.
`cwd` - An optional |String| for setting the working directory
for the command, just as per |ale#linter#Define|.
If not set, or `v:null`, the `cwd` of the last command
that spawned this one will be used.
`output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or `output_stream` - Either `'stdout'`, `'stderr'`, `'both'`, or
`'none`' for selecting which output streams to read `'none`' for selecting which output streams to read
lines from. lines from.
@ -3798,10 +3830,33 @@ ale#linter#Define(filetype, linter) *ale#linter#Define()*
The result can be computed with |ale#command#Run()|. The result can be computed with |ale#command#Run()|.
The command string can be formatted with format
markers. See |ale-command-format-strings|.
This command will be fed the lines from the buffer to This command will be fed the lines from the buffer to
check, and will produce the lines of output given to check, and will produce the lines of output given to
the `callback`. the `callback`.
`cwd` An optional |String| for setting the working
directory for the command, or a |Funcref| for a
function to call for computing the command, accepting
a buffer number. The working directory can be
specified as a format string for determining the path
dynamically. See |ale-command-format-strings|.
To set the working directory to the directory
containing the file you're checking, you should
probably use `'%s:h'` as the option value.
If this option is absent or the string is empty, the
`command` will be run with no determined working
directory in particular.
The directory specified with this option will be used
as the default working directory for all commands run
in a chain with |ale#command#Run()|, unless otherwise
specified.
`output_stream` A |String| for the output stream the lines of output `output_stream` A |String| for the output stream the lines of output
should be read from for the command which is run. The should be read from for the command which is run. The
accepted values are `'stdout'`, `'stderr'`, and accepted values are `'stdout'`, `'stderr'`, and

View file

@ -87,9 +87,6 @@ let g:ale_lint_on_save = get(g:, 'ale_lint_on_save', 1)
" This flag can be set to 1 to enable linting when the filetype is changed. " This flag can be set to 1 to enable linting when the filetype is changed.
let g:ale_lint_on_filetype_changed = get(g:, 'ale_lint_on_filetype_changed', 1) let g:ale_lint_on_filetype_changed = get(g:, 'ale_lint_on_filetype_changed', 1)
" This Dictionary configures the default LSP roots for various linters.
let g:ale_lsp_root = get(g:, 'ale_lsp_root', {})
" If set to 1, hints and suggestion from LSP servers and tsserver will be shown. " If set to 1, hints and suggestion from LSP servers and tsserver will be shown.
let g:ale_lsp_suggestions = get(g:, 'ale_lsp_suggestions', 0) let g:ale_lsp_suggestions = get(g:, 'ale_lsp_suggestions', 0)
@ -104,6 +101,9 @@ let g:ale_enabled = get(g:, 'ale_enabled', 1)
" mapping filename paths from one system to another. " mapping filename paths from one system to another.
let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {}) let g:ale_filename_mappings = get(g:, 'ale_filename_mappings', {})
" This Dictionary configures the default project roots for various linters.
let g:ale_root = get(g:, 'ale_root', {})
" 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)
@ -150,6 +150,11 @@ let g:ale_hover_to_floating_preview = get(g:, 'ale_hover_to_floating_preview', 0
" Detail uses floating windows in Neovim " Detail uses floating windows in Neovim
let g:ale_detail_to_floating_preview = get(g:, 'ale_detail_to_floating_preview', 0) let g:ale_detail_to_floating_preview = get(g:, 'ale_detail_to_floating_preview', 0)
" Border setting for floating preview windows in Neovim
" The element in the list presents - horizontal, top, top-left, top-right,
" bottom-right and bottom-left
let g:ale_floating_window_border = get(g:, 'ale_floating_window_border', ['|', '-', '+', '+', '+', '+'])
" This flag can be set to 0 to disable warnings for trailing whitespace " This flag can be set to 0 to disable warnings for trailing whitespace
let g:ale_warn_about_trailing_whitespace = get(g:, 'ale_warn_about_trailing_whitespace', 1) let g:ale_warn_about_trailing_whitespace = get(g:, 'ale_warn_about_trailing_whitespace', 1)
" This flag can be set to 0 to disable warnings for trailing blank lines " This flag can be set to 0 to disable warnings for trailing blank lines

View file

@ -52,6 +52,8 @@ formatting.
* [shfmt](https://github.com/mvdan/sh) * [shfmt](https://github.com/mvdan/sh)
* Bats * Bats
* [shellcheck](https://www.shellcheck.net/) * [shellcheck](https://www.shellcheck.net/)
* Bazel
* [buildifier](https://github.com/bazelbuild/buildtools)
* BibTeX * BibTeX
* [bibclean](http://ftp.math.utah.edu/pub/bibclean/) * [bibclean](http://ftp.math.utah.edu/pub/bibclean/)
* Bourne Shell * Bourne Shell
@ -144,7 +146,7 @@ formatting.
* [credo](https://github.com/rrrene/credo) * [credo](https://github.com/rrrene/credo)
* [dialyxir](https://github.com/jeremyjh/dialyxir) :floppy_disk: * [dialyxir](https://github.com/jeremyjh/dialyxir) :floppy_disk:
* [dogma](https://github.com/lpil/dogma) :floppy_disk: * [dogma](https://github.com/lpil/dogma) :floppy_disk:
* [elixir-ls](https://github.com/JakeBecker/elixir-ls) :warning: * [elixir-ls](https://github.com/elixir-lsp/elixir-ls) :warning:
* [mix](https://hexdocs.pm/mix/Mix.html) :warning: :floppy_disk: * [mix](https://hexdocs.pm/mix/Mix.html) :warning: :floppy_disk:
* Elm * Elm
* [elm-format](https://github.com/avh4/elm-format) * [elm-format](https://github.com/avh4/elm-format)
@ -157,8 +159,10 @@ formatting.
* [ruumba](https://github.com/ericqweinstein/ruumba) * [ruumba](https://github.com/ericqweinstein/ruumba)
* Erlang * Erlang
* [SyntaxErl](https://github.com/ten0s/syntaxerl) * [SyntaxErl](https://github.com/ten0s/syntaxerl)
* [dialyzer](http://erlang.org/doc/man/dialyzer.html)
* [elvis](https://github.com/inaka/elvis) :floppy_disk: * [elvis](https://github.com/inaka/elvis) :floppy_disk:
* [erlc](http://erlang.org/doc/man/erlc.html) * [erlc](http://erlang.org/doc/man/erlc.html)
* [erlfmt](https://github.com/WhatsApp/erlfmt)
* Fish * Fish
* fish [-n flag](https://linux.die.net/man/1/fish) * fish [-n flag](https://linux.die.net/man/1/fish)
* [fish_indent](https://fishshell.com/docs/current/cmds/fish_indent.html) * [fish_indent](https://fishshell.com/docs/current/cmds/fish_indent.html)
@ -338,6 +342,7 @@ formatting.
* OCaml * OCaml
* [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions * [merlin](https://github.com/the-lambda-church/merlin) see `:help ale-ocaml-merlin` for configuration instructions
* [ocamlformat](https://github.com/ocaml-ppx/ocamlformat) * [ocamlformat](https://github.com/ocaml-ppx/ocamlformat)
* [ocamllsp](https://github.com/ocaml/ocaml-lsp)
* [ocp-indent](https://github.com/OCamlPro/ocp-indent) * [ocp-indent](https://github.com/OCamlPro/ocp-indent)
* [ols](https://github.com/freebroccolo/ocaml-language-server) * [ols](https://github.com/freebroccolo/ocaml-language-server)
* OpenApi * OpenApi
@ -440,6 +445,7 @@ formatting.
* Ruby * Ruby
* [brakeman](http://brakemanscanner.org/) :floppy_disk: * [brakeman](http://brakemanscanner.org/) :floppy_disk:
* [debride](https://github.com/seattlerb/debride) :floppy_disk: * [debride](https://github.com/seattlerb/debride) :floppy_disk:
* [prettier](https://github.com/prettier/plugin-ruby)
* [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) :floppy_disk: * [rails_best_practices](https://github.com/flyerhzm/rails_best_practices) :floppy_disk:
* [reek](https://github.com/troessner/reek) * [reek](https://github.com/troessner/reek)
* [rubocop](https://github.com/bbatsov/rubocop) * [rubocop](https://github.com/bbatsov/rubocop)

View file

View file

@ -7,11 +7,16 @@ After:
unlet! b:executable unlet! b:executable
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()
Execute(The ansible_lint command callback should return default string): Execute(The ansible_lint version <5.0.0 command callback should return default string):
GivenCommandOutput ['v4.1.2']
AssertLinter 'ansible-lint', ale#Escape('ansible-lint') . ' -p %t' AssertLinter 'ansible-lint', ale#Escape('ansible-lint') . ' -p %t'
Execute(The ansible_lint version >=5.0.0 command callback should return default string):
GivenCommandOutput ['v5.1.2']
AssertLinter 'ansible-lint', ale#Escape('ansible-lint') . ' --parseable-severity -x yaml'
Execute(The ansible_lint executable should be configurable): Execute(The ansible_lint executable should be configurable):
let g:ale_ansible_ansible_lint_executable = '~/.local/bin/ansible-lint' let g:ale_ansible_ansible_lint_executable = '~/.local/bin/ansible-lint'
GivenCommandOutput ['v4.1.2']
AssertLinter '~/.local/bin/ansible-lint', AssertLinter '~/.local/bin/ansible-lint',
\ ale#Escape('~/.local/bin/ansible-lint') . ' -p %t' \ ale#Escape('~/.local/bin/ansible-lint') . ' -p %t'

View file

@ -17,14 +17,14 @@ Execute(The executable should be configurable):
let b:ale_c_cppcheck_executable = 'foobar' let b:ale_c_cppcheck_executable = 'foobar'
AssertLinterCwd ''
AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail
Execute(cppcheck for C should detect compile_commands.json files): Execute(cppcheck for C should detect compile_commands.json files):
call ale#test#SetFilename('cppcheck_paths/one/foo.c') call ale#test#SetFilename('cppcheck_paths/one/foo.c')
AssertLinter 'cppcheck', AssertLinterCwd ale#path#Simplify(g:dir . '/cppcheck_paths/one')
\ ale#path#CdString(ale#path#Simplify(g:dir . '/cppcheck_paths/one')) AssertLinter 'cppcheck', ale#Escape('cppcheck')
\ . ale#Escape('cppcheck')
\ . ' -q --language=c' \ . ' -q --language=c'
\ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
\ . ' --project=' . ale#Escape('compile_commands.json') \ . ' --project=' . ale#Escape('compile_commands.json')
@ -33,9 +33,8 @@ Execute(cppcheck for C should detect compile_commands.json files):
Execute(cppcheck for C should detect compile_commands.json files in build directories): Execute(cppcheck for C should detect compile_commands.json files in build directories):
call ale#test#SetFilename('cppcheck_paths/with_build_dir/foo.cpp') call ale#test#SetFilename('cppcheck_paths/with_build_dir/foo.cpp')
AssertLinter 'cppcheck', AssertLinterCwd ale#path#Simplify(g:dir . '/cppcheck_paths/with_build_dir')
\ ale#path#CdString(ale#path#Simplify(g:dir . '/cppcheck_paths/with_build_dir')) AssertLinter 'cppcheck', ale#Escape('cppcheck')
\ . ale#Escape('cppcheck')
\ . ' -q --language=c' \ . ' -q --language=c'
\ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
\ . ' --project=' . ale#Escape(ale#path#Simplify('build/compile_commands.json')) \ . ' --project=' . ale#Escape(ale#path#Simplify('build/compile_commands.json'))
@ -58,9 +57,8 @@ Execute(cppcheck for C should ignore compile_commands.json file if buffer is mod
set buftype= set buftype=
set modified set modified
AssertLinter 'cppcheck', AssertLinterCwd ale#path#Simplify(g:dir . '/cppcheck_paths/one')
\ ale#path#CdString(ale#path#Simplify(g:dir . '/cppcheck_paths/one')) AssertLinter 'cppcheck', ale#Escape('cppcheck')
\ . ale#Escape('cppcheck')
\ . ' -q --language=c' \ . ' -q --language=c'
\ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
\ . ' --enable=style' \ . ' --enable=style'

View file

@ -118,20 +118,23 @@ Execute(--all-features should be used when g:ale_rust_cargo_default_feature_beha
GivenCommandOutput ['cargo 0.22.0 (3423351a5 2017-10-06)'] GivenCommandOutput ['cargo 0.22.0 (3423351a5 2017-10-06)']
AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --all-features'] AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --all-features']
Execute(When a crate belongs to a workspace we should cd into the crate): Execute(Cargo should run from the crate directory when set to avoid the workspace):
let g:ale_rust_cargo_avoid_whole_workspace = 1 let g:ale_rust_cargo_avoid_whole_workspace = 1
call ale#test#SetFilename('cargo_workspace_paths/subpath/test.rs') call ale#test#SetFilename('cargo_workspace_paths/subpath/test.rs')
AssertLinterCwd ale#path#Simplify(g:dir . '/cargo_workspace_paths/subpath')
call ale#semver#ResetVersionCache()
AssertLinter 'cargo', [ AssertLinter 'cargo', [
\ ale#Escape('cargo') . ' --version', \ ale#Escape('cargo') . ' --version',
\ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/cargo_workspace_paths/subpath')) . ' && ' \ 'cargo check --frozen --message-format=json -q',
\ . 'cargo check --frozen --message-format=json -q',
\] \]
Execute(When a crate belongs to a workspace we chdir into the crate, unless we disabled it): Execute(Cargo should not run from the crate directory when not set to avoid the workspace):
let g:ale_rust_cargo_avoid_whole_workspace = 0 let g:ale_rust_cargo_avoid_whole_workspace = 0
call ale#test#SetFilename('cargo_workspace_paths/subpath/test.rs') call ale#test#SetFilename('cargo_workspace_paths/subpath/test.rs')
AssertLinterCwd ''
call ale#semver#ResetVersionCache()
AssertLinter 'cargo', [ AssertLinter 'cargo', [
\ ale#Escape('cargo') . ' --version', \ ale#Escape('cargo') . ' --version',
\ 'cargo check --frozen --message-format=json -q', \ 'cargo check --frozen --message-format=json -q',

View file

@ -17,14 +17,14 @@ Execute(The executable should be configurable):
let b:ale_cpp_cppcheck_executable = 'foobar' let b:ale_cpp_cppcheck_executable = 'foobar'
AssertLinterCwd ''
AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail AssertLinter 'foobar', ale#Escape('foobar') . b:command_tail
Execute(cppcheck for C++ should detect compile_commands.json files): Execute(cppcheck for C++ should detect compile_commands.json files):
call ale#test#SetFilename('cppcheck_paths/one/foo.cpp') call ale#test#SetFilename('cppcheck_paths/one/foo.cpp')
AssertLinter 'cppcheck', AssertLinterCwd ale#path#Simplify(g:dir . '/cppcheck_paths/one')
\ ale#path#CdString(ale#path#Simplify(g:dir . '/cppcheck_paths/one')) AssertLinter 'cppcheck', ale#Escape('cppcheck')
\ . ale#Escape('cppcheck')
\ . ' -q --language=c++' \ . ' -q --language=c++'
\ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
\ . ' --project=' . ale#Escape('compile_commands.json') \ . ' --project=' . ale#Escape('compile_commands.json')
@ -33,9 +33,8 @@ Execute(cppcheck for C++ should detect compile_commands.json files):
Execute(cppcheck for C++ should detect compile_commands.json files in build directories): Execute(cppcheck for C++ should detect compile_commands.json files in build directories):
call ale#test#SetFilename('cppcheck_paths/with_build_dir/foo.cpp') call ale#test#SetFilename('cppcheck_paths/with_build_dir/foo.cpp')
AssertLinter 'cppcheck', AssertLinterCwd ale#path#Simplify(g:dir . '/cppcheck_paths/with_build_dir')
\ ale#path#CdString(ale#path#Simplify(g:dir . '/cppcheck_paths/with_build_dir')) AssertLinter 'cppcheck', ale#Escape('cppcheck')
\ . ale#Escape('cppcheck')
\ . ' -q --language=c++' \ . ' -q --language=c++'
\ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
\ . ' --project=' . ale#Escape(ale#path#Simplify('build/compile_commands.json')) \ . ' --project=' . ale#Escape(ale#path#Simplify('build/compile_commands.json'))
@ -58,9 +57,8 @@ Execute(cppcheck for C++ should ignore compile_commands.json file if buffer is m
set buftype= set buftype=
set modified set modified
AssertLinter 'cppcheck', AssertLinterCwd ale#path#Simplify(g:dir . '/cppcheck_paths/one')
\ ale#path#CdString(ale#path#Simplify(g:dir . '/cppcheck_paths/one')) AssertLinter 'cppcheck', ale#Escape('cppcheck')
\ . ale#Escape('cppcheck')
\ . ' -q --language=c++' \ . ' -q --language=c++'
\ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}') \ . ' --template=' . ale#Escape('{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}')
\ . ' --enable=style' \ . ' --enable=style'

View file

@ -5,43 +5,38 @@ After:
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()
Execute(The csc linter should return the correct default command): Execute(The csc linter should return the correct default command):
AssertLinter 'csc', ale#path#CdString(g:dir) AssertLinterCwd expand('%:p:h')
\ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
Execute(The options should be be used in the command): Execute(The options should be be used in the command):
let g:ale_cs_csc_options = '' let g:ale_cs_csc_options = ''
AssertLinter 'csc', ale#path#CdString(g:dir) AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
\ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
Execute(The souce path should be be used in the command): Execute(The souce path should be be used in the command):
let g:ale_cs_csc_source = '../foo/bar' let g:ale_cs_csc_source = '../foo/bar'
AssertLinter 'csc', ale#path#CdString('../foo/bar') AssertLinterCwd '../foo/bar'
\ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
Execute(The list of search pathes for assemblies should be be used in the command if not empty): Execute(The list of search pathes for assemblies should be be used in the command if not empty):
let g:ale_cs_csc_assembly_path = ['/usr/lib/mono', '../foo/bar'] let g:ale_cs_csc_assembly_path = ['/usr/lib/mono', '../foo/bar']
AssertLinter 'csc', ale#path#CdString(g:dir) AssertLinter 'csc', 'csc /unsafe'
\ . 'csc /unsafe'
\ . ' /lib:' . ale#Escape('/usr/lib/mono') . ',' . ale#Escape('../foo/bar') \ . ' /lib:' . ale#Escape('/usr/lib/mono') . ',' . ale#Escape('../foo/bar')
\ . ' /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') \ . ' /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
let g:ale_cs_csc_assembly_path = [] let g:ale_cs_csc_assembly_path = []
AssertLinter 'csc', ale#path#CdString(g:dir) AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
\ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
Execute(The list of assemblies should be be used in the command if not empty): Execute(The list of assemblies should be be used in the command if not empty):
let g:ale_cs_csc_assemblies = ['foo.dll', 'bar.dll'] let g:ale_cs_csc_assemblies = ['foo.dll', 'bar.dll']
AssertLinter 'csc', ale#path#CdString(g:dir) AssertLinter 'csc', 'csc /unsafe'
\ . 'csc /unsafe'
\ . ' /r:' . ale#Escape('foo.dll') . ',' . ale#Escape('bar.dll') \ . ' /r:' . ale#Escape('foo.dll') . ',' . ale#Escape('bar.dll')
\ . ' /out:TEMP /t:module /recurse:' . ale#Escape('*.cs') \ . ' /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
let g:ale_cs_csc_assemblies = [] let g:ale_cs_csc_assemblies = []
AssertLinter 'csc', ale#path#CdString(g:dir) AssertLinter 'csc', 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')
\ . 'csc /unsafe /out:TEMP /t:module /recurse:' . ale#Escape('*.cs')

View file

@ -5,43 +5,38 @@ After:
call ale#assert#TearDownLinterTest() call ale#assert#TearDownLinterTest()
Execute(The mcsc linter should return the correct default command): Execute(The mcsc linter should return the correct default command):
AssertLinter 'mcs', ale#path#CdString(g:dir) AssertLinterCwd expand('%:p:h')
\ . 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs') AssertLinter 'mcs', 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
Execute(The options should be be used in the command): Execute(The options should be be used in the command):
let g:ale_cs_mcsc_options = '-pkg:dotnet' let g:ale_cs_mcsc_options = '-pkg:dotnet'
AssertLinter 'mcs', ale#path#CdString(g:dir) AssertLinter 'mcs', 'mcs -unsafe -pkg:dotnet -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
\ . 'mcs -unsafe -pkg:dotnet -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
Execute(The souce path should be be used in the command): Execute(The souce path should be be used in the command):
let g:ale_cs_mcsc_source = '../foo/bar' let g:ale_cs_mcsc_source = '../foo/bar'
AssertLinter 'mcs', ale#path#CdString('../foo/bar') AssertLinterCwd '../foo/bar'
\ . 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs') AssertLinter 'mcs', 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
Execute(The list of search pathes for assemblies should be be used in the command if not empty): Execute(The list of search pathes for assemblies should be be used in the command if not empty):
let g:ale_cs_mcsc_assembly_path = ['/usr/lib/mono', '../foo/bar'] let g:ale_cs_mcsc_assembly_path = ['/usr/lib/mono', '../foo/bar']
AssertLinter 'mcs', ale#path#CdString(g:dir) AssertLinter 'mcs', 'mcs -unsafe'
\ . 'mcs -unsafe'
\ . ' -lib:' . ale#Escape('/usr/lib/mono') . ',' . ale#Escape('../foo/bar') \ . ' -lib:' . ale#Escape('/usr/lib/mono') . ',' . ale#Escape('../foo/bar')
\ . ' -out:TEMP -t:module -recurse:' . ale#Escape('*.cs') \ . ' -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
let g:ale_cs_mcsc_assembly_path = [] let g:ale_cs_mcsc_assembly_path = []
AssertLinter 'mcs', ale#path#CdString(g:dir) AssertLinter 'mcs', 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
\ . 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
Execute(The list of assemblies should be be used in the command if not empty): Execute(The list of assemblies should be be used in the command if not empty):
let g:ale_cs_mcsc_assemblies = ['foo.dll', 'bar.dll'] let g:ale_cs_mcsc_assemblies = ['foo.dll', 'bar.dll']
AssertLinter 'mcs', ale#path#CdString(g:dir) AssertLinter 'mcs', 'mcs -unsafe'
\ . 'mcs -unsafe'
\ . ' -r:' . ale#Escape('foo.dll') . ',' . ale#Escape('bar.dll') \ . ' -r:' . ale#Escape('foo.dll') . ',' . ale#Escape('bar.dll')
\ . ' -out:TEMP -t:module -recurse:' . ale#Escape('*.cs') \ . ' -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
let g:ale_cs_mcsc_assemblies = [] let g:ale_cs_mcsc_assemblies = []
AssertLinter 'mcs', ale#path#CdString(g:dir) AssertLinter 'mcs', 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')
\ . 'mcs -unsafe -out:TEMP -t:module -recurse:' . ale#Escape('*.cs')

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