Compare commits

...

25 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
c849345a8d Add defensive ale#Set for c_build_dir_names in FindCompileCommands
Mirror the existing s:CanParseMakefile pattern to ensure the
g:ale_c_build_dir_names variable always exists when ale#Var is
called, even if test Save/Restore cycles delete it.

Co-authored-by: w0rp <3518142+w0rp@users.noreply.github.com>
2026-02-17 20:28:19 +00:00
copilot-swe-agent[bot]
014c959fee Improve comment clarity in FindCompileCommands
Co-authored-by: w0rp <3518142+w0rp@users.noreply.github.com>
2026-02-12 00:25:08 +00:00
copilot-swe-agent[bot]
520c775c6a Fix FindCompileCommands to handle absolute paths in c_build_dir_names
Use ale#path#GetAbsPath to resolve build directory paths, which correctly
handles both absolute and relative paths. When the dirname is absolute,
derive the project root from the parent of the build directory.

Co-authored-by: w0rp <3518142+w0rp@users.noreply.github.com>
2026-02-12 00:24:39 +00:00
copilot-swe-agent[bot]
7f79d30fb9 Initial plan 2026-02-12 00:20:49 +00:00
w0rp
cb8c4662aa Fix #5062 - Keep ALE LSP compatible with Neovim 0.10 and 0.11+
Some checks failed
CI / build_image (push) Has been cancelled
CI / test_ale (--linters-only) (push) Has been cancelled
CI / test_ale (--lua-only) (push) Has been cancelled
CI / test_ale (--neovim-07-only) (push) Has been cancelled
CI / test_ale (--neovim-08-only) (push) Has been cancelled
CI / test_ale (--vim-80-only) (push) Has been cancelled
CI / test_ale (--vim-90-only) (push) Has been cancelled
2026-02-12 00:12:54 +00:00
w0rp
d87b4956ad Tell OpenCode how to write ALE code 2026-02-11 21:14:09 +00:00
PsickOSSH
3c837714cd feat(rstcheck): Add automatic --config support with version check (#5095)
* Add automatic --config support for rstcheck >= 3.4.0
* Add tests for rstcheck

Co-authored-by: PsickOSSH <PsickOSSH@protonmail.com>
Co-authored-by: w0rp <devw0rp@gmail.com>
2026-02-11 21:12:30 +00:00
w0rp
bee0b49067 Truncate astro test files to quiet dependabot
Some checks failed
CI / build_image (push) Has been cancelled
CI / test_ale (--linters-only) (push) Has been cancelled
CI / test_ale (--lua-only) (push) Has been cancelled
CI / test_ale (--neovim-07-only) (push) Has been cancelled
CI / test_ale (--neovim-08-only) (push) Has been cancelled
CI / test_ale (--vim-80-only) (push) Has been cancelled
CI / test_ale (--vim-90-only) (push) Has been cancelled
2026-02-11 20:21:57 +00:00
w0rp
be0dfdb671 Skip ALE docker download attempts
Turns out the "image" variable never finds a local image any more
because the "docker.io/" part isn't part of the image name locally,
so we must alter the string slightly to find a local copy.
2026-02-11 20:16:15 +00:00
yoan667
b5f8cb296a doc goimport (#5093)
Some checks failed
CI / build_image (push) Has been cancelled
CI / test_ale (--linters-only) (push) Has been cancelled
CI / test_ale (--lua-only) (push) Has been cancelled
CI / test_ale (--neovim-07-only) (push) Has been cancelled
CI / test_ale (--neovim-08-only) (push) Has been cancelled
CI / test_ale (--vim-80-only) (push) Has been cancelled
CI / test_ale (--vim-90-only) (push) Has been cancelled
2026-02-07 17:24:34 +09:00
PsickOSSH
af5a38c697 refactor: use ale#Pad for option padding across the codebase (#5091)
Co-authored-by: PsickOSSH <PsickOSSH@protonmail.com>
2026-02-07 17:23:48 +09:00
blobmasterbrian
e762262f44 add option to lint diff buffers (#3185)
Some checks failed
CI / build_image (push) Has been cancelled
CI / test_ale (--linters-only) (push) Has been cancelled
CI / test_ale (--lua-only) (push) Has been cancelled
CI / test_ale (--neovim-07-only) (push) Has been cancelled
CI / test_ale (--neovim-08-only) (push) Has been cancelled
CI / test_ale (--vim-80-only) (push) Has been cancelled
CI / test_ale (--vim-90-only) (push) Has been cancelled
* add option to lint diff buffers
* fix misaligned doc tag
* update docs
2026-02-06 18:47:52 +00:00
Mathis Bernadet
6d99629461 Add missing space to gcc linter (#4791). (#5088)
Some checks failed
CI / build_image (push) Has been cancelled
CI / test_ale (--linters-only) (push) Has been cancelled
CI / test_ale (--lua-only) (push) Has been cancelled
CI / test_ale (--neovim-07-only) (push) Has been cancelled
CI / test_ale (--neovim-08-only) (push) Has been cancelled
CI / test_ale (--vim-80-only) (push) Has been cancelled
CI / test_ale (--vim-90-only) (push) Has been cancelled
Co-authored-by: Mathis Bernadet <matbernadet@emi.u-bordeaux.fr>
2026-01-25 16:42:46 +09:00
Steve Matney
f730dedca7 Utilizing -fzf for tsserver responses along with regular lsp responses (#5084)
* Utilizing -fzf for tsserver responses along with regular lsp responses

* Refactoring FormatResponseItem in references.vim to accept response item config
2026-01-25 16:42:14 +09:00
Holger Detering
9b51f66960 Fix markdownlint output format (#5085)
* test: Add failing tests for markdownlint 0.47.0 output format

Add two new test cases to verify the markdownlint handler's ability to
parse output from version 0.47.0, which includes severity keywords
("error" or "warning"). These tests will fail with the current
implementation, demonstrating the need for a fix to handle the new
output format.

The tests specifically verify:
- Parsing of error severity keyword
- Parsing of warning severity keyword
- Correct mapping of severity to ALE type (E/W)

Backward compatibility with version 0.46.0 is already verified by
the existing ests.

* fix: Update markdownlint handler for version 0.47.0 output format

Update the markdownlint handler to support the new output format
introduced in version 0.47.0, which includes severity keywords ("error"
and "warning") after the column number.

Changes:
- Updated regex pattern to capture optional severity keyword
- Added type mapping logic (error → 'E', warning → 'W')
- Adjusted match indices for rule ID and description text
- Maintained backward compatibility with version 0.46.0

All tests now pass, including the new tests for 0.47.0 format.

* style: Fix vint linting errors in markdownlint handler

- Add blank line before if statement for better readability
- Replace `==#` with `is#` for case-sensitive comparison
2026-01-25 16:37:20 +09:00
gumballriggy
e3c1528619 fix: replace deprecated client.request method call with colon syntax (#5081)
* Update lsp.lua

replace deprecated client.request method call with colon syntax

* fixy

same as b4 but for client.notify now

* how did this even happen
2026-01-25 16:36:54 +09:00
yoan667
646d956630 fix vale option (#5086) 2026-01-25 16:30:53 +09:00
PsickOSSH
d59cb7b3c2 fix-proselint (#5074) 2026-01-25 16:29:03 +09:00
halfcrazy
c0dd8167a6 fix gopls without setting ale_go_gopls_init_options (#5059) 2026-01-25 16:25:25 +09:00
Adrian Vollmer
8eb4803da9 Add pymarkdown fixer (#5045)
Some checks failed
CI / build_image (push) Has been cancelled
CI / test_ale (--linters-only) (push) Has been cancelled
CI / test_ale (--lua-only) (push) Has been cancelled
CI / test_ale (--neovim-07-only) (push) Has been cancelled
CI / test_ale (--neovim-08-only) (push) Has been cancelled
CI / test_ale (--vim-80-only) (push) Has been cancelled
CI / test_ale (--vim-90-only) (push) Has been cancelled
2025-12-21 18:34:05 +09:00
John Jackson
0360a73644 Add ReScript support (#5072)
This adds support for both rescript format and rescript-language-server.

Closes https://github.com/dense-analysis/ale/issues/3335
2025-12-21 18:25:42 +09:00
bretello
dd6e6f1b15 ALEFindReferences: add -fzf flag to show output in fzf (#5018)
* references: add ALEFindReferences -fzf option

Allows using -fzf to show previews using fzf.vim. Includes:

- add support for opening in bufers, splits, tabs and for adding matches quickfix
- add support for -relative
- add fzf preview `--highlight-line` option
- add fzf.vim autoload module

* tests: fix references tests for fzf support update
2025-12-21 13:06:34 +09:00
Eric T. Johnson
fa3d4f2f13 cppcheck: don't pass source file if --project is specified (#5075)
This is no longer supported as of version 2.13.0.

Fixes: #4854
2025-12-21 12:59:13 +09:00
yoan667
710e1aac9c fix linter cppcheck (#5071) 2025-12-21 12:56:23 +09:00
rymdbar
281eb4808c Finalize #5055, adding SuperHTML linter for HTML (#5069)
Remove bogus test of non-existing g:ale_html_superhtml_options.

Co-authored-by: cos <cos>
2025-12-21 12:51:45 +09:00
107 changed files with 1427 additions and 251 deletions

6
AGENTS.md Normal file
View File

@@ -0,0 +1,6 @@
# ALE Agent instructions
1. Read documentation from `doc/ale-development.txt` to understand how to be an
ALE developer.
2. Run Vader/Vim tests with `./run-tests -q --fast test/path/some_file.vader`
3. When editing Lua code run Lua tests with `./run-tests -q --lua-only`

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for AsciiDoc files " Description: proselint for AsciiDoc files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('asciidoc', { call ale#linter#Define('asciidoc', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

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

View File

@@ -10,13 +10,18 @@ function! ale_linters#c#cppcheck#GetCommand(buffer) abort
\ ? 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}')
" Versions >=2.13 don't allow using --project in conjunction with an
" explicit source file.
let l:source_file = stridx(l:compile_commands_option, '--project=') < 0
\ ? ' %t'
\ : ''
return '%e -q --language=c' return '%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'))
\ . l:buffer_path_include \ . l:buffer_path_include
\ . ' %t' \ . l:source_file
endfunction endfunction
call ale#linter#Define('c', { call ale#linter#Define('c', {

View File

@@ -18,7 +18,7 @@ function! ale_linters#cpp#clazy#GetCommand(buffer) abort
return '%e' return '%e'
\ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '') \ . (!empty(l:checks) ? ' -checks=' . ale#Escape(l:checks) : '')
\ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '') \ . (!empty(l:build_dir) ? ' -p ' . ale#Escape(l:build_dir) : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' %s' \ . ' %s'
endfunction endfunction

View File

@@ -10,13 +10,18 @@ function! ale_linters#cpp#cppcheck#GetCommand(buffer) abort
\ ? 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}')
" Versions >=2.13 don't allow using --project in conjunction with an
" explicit source file.
let l:source_file = stridx(l:compile_commands_option, '--project=') < 0
\ ? ' %t'
\ : ''
return '%e -q --language=c++' return '%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'))
\ . l:buffer_path_include \ . l:buffer_path_include
\ . ' %t' \ . l:source_file
endfunction endfunction
call ale#linter#Define('cpp', { call ale#linter#Define('cpp', {

View File

@@ -4,7 +4,7 @@ function! ale_linters#cs#mcs#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'cs_mcs_options') let l:options = ale#Var(a:buffer, 'cs_mcs_options')
return 'mcs -unsafe --parse' return 'mcs -unsafe --parse'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' %t' \ . ' %t'
endfunction endfunction

View File

@@ -1,9 +1,11 @@
" Author: Jansen Mitchell https://github.com/JansenMitchell " Author: Jansen Mitchell https://github.com/JansenMitchell
" Description: proselint for Fountain files " Description: proselint for Fountain files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('fountain', { call ale#linter#Define('fountain', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

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

View File

@@ -13,11 +13,11 @@ function! ale_linters#go#staticcheck#GetCommand(buffer) abort
if l:lint_package if l:lint_package
return l:env . '%e' return l:env . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') . ' .' \ . ale#Pad(l:options) . ' .'
endif endif
return l:env . '%e' return l:env . '%e'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' %s:t' \ . ' %s:t'
endfunction endfunction

View File

@@ -8,7 +8,7 @@ function! ale_linters#groovy#npmgroovylint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'groovy_npmgroovylint_options') let l:options = ale#Var(a:buffer, 'groovy_npmgroovylint_options')
return '%e --failon none --output json' return '%e --failon none --output json'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' %t' \ . ' %t'
endfunction endfunction

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for Vim help files " Description: proselint for Vim help files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('help', { call ale#linter#Define('help', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for HTML files " Description: proselint for HTML files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('html', { call ale#linter#Define('html', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -15,7 +15,7 @@ function! ale_linters#html#stylelint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'html_stylelint_options') let l:options = ale#Var(a:buffer, 'html_stylelint_options')
return ale#Escape(l:executable) return ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --no-color --stdin-filename %s' \ . ' --no-color --stdin-filename %s'
endfunction endfunction

View File

@@ -19,7 +19,7 @@ function! ale_linters#javascript#standard#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'javascript_standard_options') let l:options = ale#Var(a:buffer, 'javascript_standard_options')
return ale#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --stdin %s' \ . ' --stdin %s'
endfunction endfunction

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for mail files " Description: proselint for mail files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('mail', { call ale#linter#Define('mail', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -14,7 +14,7 @@ function! ale_linters#markdown#markdownlint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'markdown_markdownlint_options') let l:options = ale#Var(a:buffer, 'markdown_markdownlint_options')
return ale#Escape(l:executable) return ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') . ' %s' \ . ale#Pad(l:options) . ' %s'
endfunction endfunction
call ale#linter#Define('markdown', { call ale#linter#Define('markdown', {

View File

@@ -17,7 +17,7 @@ function! ale_linters#markdown#mdl#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'markdown_mdl_options') let l:options = ale#Var(a:buffer, 'markdown_mdl_options')
return ale#Escape(l:executable) . l:exec_args return ale#Escape(l:executable) . l:exec_args
\ . ' -j' . (!empty(l:options) ? ' ' . l:options : '') \ . ' -j' . ale#Pad(l:options)
endfunction endfunction
function! ale_linters#markdown#mdl#Handle(buffer, lines) abort function! ale_linters#markdown#mdl#Handle(buffer, lines) abort

View File

@@ -1,9 +1,11 @@
" Author: poohzrn https://github.com/poohzrn " Author: poohzrn https://github.com/poohzrn
" Description: proselint for Markdown files " Description: proselint for Markdown files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('markdown', { call ale#linter#Define('markdown', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for nroff files " Description: proselint for nroff files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('nroff', { call ale#linter#Define('nroff', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -31,7 +31,7 @@ function! ale_linters#php#tlint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'php_tlint_options') let l:options = ale#Var(a:buffer, 'php_tlint_options')
return ale#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' lint %s' \ . ' lint %s'
endfunction endfunction

View File

@@ -1,9 +1,11 @@
" Author: Cian Butler https://github.com/butlerx " Author: Cian Butler https://github.com/butlerx
" Description: proselint for PO files " Description: proselint for PO files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('po', { call ale#linter#Define('po', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for Pod files " Description: proselint for Pod files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('pod', { call ale#linter#Define('pod', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -11,7 +11,7 @@ function! ale_linters#proto#buf_lint#GetCommand(buffer) abort
return '%e lint' return '%e lint'
\ . (!empty(l:config) ? ' --config=' . ale#Escape(l:config) : '') \ . (!empty(l:config) ? ' --config=' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' %s#include_package_files=true' \ . ' %s#include_package_files=true'
endfunction endfunction

View File

@@ -87,7 +87,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 ale#Escape(l:executable) . l:exec_args return ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --format=default' \ . ' --format=default'
\ . l:display_name_args . ' -' \ . l:display_name_args . ' -'
endfunction endfunction

View File

@@ -12,7 +12,7 @@ function! ale_linters#rego#opacheck#GetCommand(buffer) abort
return ale#Escape(ale_linters#rego#opacheck#GetExecutable(a:buffer)) return ale#Escape(ale_linters#rego#opacheck#GetExecutable(a:buffer))
\ . ' check %s:h --format json ' \ . ' check %s:h --format json '
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
endfunction endfunction
function! ale_linters#rego#opacheck#Handle(buffer, lines) abort function! ale_linters#rego#opacheck#Handle(buffer, lines) abort

View File

@@ -0,0 +1,24 @@
" Author: John Jackson <john@johnridesa.bike>
" Description: The official language server for ReScript.
call ale#Set('rescript_language_server_executable', 'rescript-language-server')
call ale#Set(
\ 'rescript_language_server_use_global',
\ get(g:, 'ale_use_global_executables', v:true),
\ )
function! s:GetProjectRoot(buffer) abort
let l:config_file = ale#path#FindNearestFile(a:buffer, 'rescript.json')
return !empty(l:config_file) ? fnamemodify(l:config_file, ':h') : ''
endfunction
call ale#linter#Define('rescript', {
\ 'name': 'rescript_language_server',
\ 'lsp': 'stdio',
\ 'executable': {b -> ale#path#FindExecutable(b, 'rescript_language_server', [
\ 'node_modules/.bin/rescript-language-server'
\ ])},
\ 'command': '%e --stdio',
\ 'project_root': function('s:GetProjectRoot'),
\})

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for reStructuredText files " Description: proselint for reStructuredrst files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('rst', { call ale#linter#Define('rst', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -1,5 +1,13 @@
" Author: John Nduli https://github.com/jnduli " Authors:
" Description: Rstcheck for reStructuredText files " John Nduli https://github.com/jnduli,
" Michael Goerz https://github.com/goerz
call ale#Set('rst_rstcheck_executable', 'rstcheck')
call ale#Set('rst_rstcheck_options', '')
function! ale_linters#rst#rstcheck#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'rst_rstcheck_executable')
endfunction
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
@@ -21,11 +29,35 @@ function! ale_linters#rst#rstcheck#Handle(buffer, lines) abort
return l:output return l:output
endfunction endfunction
function! ale_linters#rst#rstcheck#GetCommand(buffer, version) abort
let l:executable = ale_linters#rst#rstcheck#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'rst_rstcheck_options')
let l:dir = expand('#' . a:buffer . ':p:h')
let l:exec_args = ale#Pad(l:options)
if ale#semver#GTE(a:version, [3, 4, 0])
let l:exec_args .= ' --config ' . ale#Escape(l:dir)
endif
return ale#Escape(l:executable)
\ . l:exec_args
\ . ' %t'
endfunction
function! ale_linters#rst#rstcheck#GetCommandWithVersionCheck(buffer) abort
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ ale_linters#rst#rstcheck#GetExecutable(a:buffer),
\ '%e --version',
\ function('ale_linters#rst#rstcheck#GetCommand')
\)
endfunction
call ale#linter#Define('rst', { call ale#linter#Define('rst', {
\ 'name': 'rstcheck', \ 'name': 'rstcheck',
\ 'executable': 'rstcheck', \ 'executable': 'rstcheck',
\ 'cwd': '%s:h', \ 'cwd': '%s:h',
\ 'command': 'rstcheck %t', \ 'command': function('ale_linters#rst#rstcheck#GetCommandWithVersionCheck'),
\ 'callback': 'ale_linters#rst#rstcheck#Handle', \ 'callback': 'ale_linters#rst#rstcheck#Handle',
\ 'output_stream': 'both', \ 'output_stream': 'both',
\}) \})

View File

@@ -10,7 +10,7 @@ function! ale_linters#ruby#sorbet#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'srb') return ale#ruby#EscapeExecutable(l:executable, 'srb')
\ . ' tc' \ . ' tc'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --lsp' \ . ' --lsp'
\ . (l:enable_watchman ? '' : ' --disable-watchman') \ . (l:enable_watchman ? '' : ' --disable-watchman')
endfunction endfunction

View File

@@ -20,7 +20,7 @@ function! ale_linters#rust#rustc#RustcCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'rust_rustc_options') let l:options = ale#Var(a:buffer, 'rust_rustc_options')
return 'rustc --error-format=json' return 'rustc --error-format=json'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . l:dependencies . ' -' \ . l:dependencies . ' -'
endfunction endfunction

View File

@@ -16,7 +16,7 @@ function! ale_linters#sass#sasslint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'sass_sasslint_options') let l:options = ale#Var(a:buffer, 'sass_sasslint_options')
return ale#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' -v -q -f compact %t' \ . ' -v -q -f compact %t'
endfunction endfunction

View File

@@ -16,7 +16,7 @@ function! ale_linters#scss#sasslint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'scss_sasslint_options') let l:options = ale#Var(a:buffer, 'scss_sasslint_options')
return ale#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' -v -q -f compact %t' \ . ' -v -q -f compact %t'
endfunction endfunction

View File

@@ -1,9 +1,11 @@
" Author: poohzrn https://github.com/poohzrn " Author: poohzrn https://github.com/poohzrn
" Description: proselint for TeX files " Description: proselint for TeX files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('tex', { call ale#linter#Define('tex', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for Texinfo files " Description: proselint for Texinfo files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('texinfo', { call ale#linter#Define('texinfo', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -1,9 +1,11 @@
" Author: poohzrn https://github.com/poohzrn " Author: poohzrn https://github.com/poohzrn
" Description: proselint for text files " Description: proselint for text files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('text', { call ale#linter#Define('text', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -1,9 +1,22 @@
" Author: chew-z https://github.com/chew-z " Author: chew-z https://github.com/chew-z
" Description: vale for text files " Description: vale for text files
call ale#Set('vale_executable', 'vale')
call ale#Set('vale_options', '')
function! ale_linters#text#vale#GetCommand(buffer) abort
let l:executable = ale#Var(a:buffer, 'vale_executable')
let l:options = ale#Var(a:buffer, 'vale_options')
return ale#Escape(l:executable)
\ . ale#Pad(l:options)
\ . ' --output=JSON %t'
endfunction
call ale#linter#Define('text', { call ale#linter#Define('text', {
\ 'name': 'vale', \ 'name': 'vale',
\ 'executable': 'vale', \ 'executable': 'vale',
\ 'command': 'vale --output=JSON %t', \ 'command': function('ale_linters#text#vale#GetCommand'),
\ 'callback': 'ale#handlers#vale#Handle', \ 'callback': 'ale#handlers#vale#Handle',
\}) \})

View File

@@ -18,7 +18,7 @@ function! ale_linters#typescript#standard#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'typescript_standard_options') let l:options = ale#Var(a:buffer, 'typescript_standard_options')
return ale#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --stdin %s' \ . ' --stdin %s'
endfunction endfunction

View File

@@ -1,9 +1,11 @@
" Author: Daniel M. Capella https://github.com/polyzen " Author: Daniel M. Capella https://github.com/polyzen
" Description: proselint for XHTML files " Description: proselint for XHTML files
call ale#Set('proselint_executable', 'proselint')
call ale#linter#Define('xhtml', { call ale#linter#Define('xhtml', {
\ 'name': 'proselint', \ 'name': 'proselint',
\ 'executable': 'proselint', \ 'executable': function('ale#proselint#GetExecutable'),
\ 'command': 'proselint %t', \ 'command': function('ale#proselint#GetCommandWithVersionCheck'),
\ 'callback': 'ale#handlers#unix#HandleAsWarning', \ 'callback': 'ale#handlers#unix#HandleAsWarning',
\}) \})

View File

@@ -48,7 +48,7 @@ function! ale#ShouldDoNothing(buffer) abort
endif endif
" Do nothing for diff buffers. " Do nothing for diff buffers.
if getbufvar(a:buffer, '&diff') if getbufvar(a:buffer, '&diff') && !get(g:, 'ale_lint_diff', 0)
return 1 return 1
endif endif

View File

@@ -246,14 +246,31 @@ function! ale#c#FindCompileCommands(buffer) abort
return [fnamemodify(l:json_file, ':h'), l:json_file] return [fnamemodify(l:json_file, ':h'), l:json_file]
endif endif
" Something somewhere seems to delete this setting in tests, so ensure
" we always have a default value.
call ale#Set('c_build_dir_names', [
\ 'build',
\ 'build/Debug',
\ 'build/Release',
\ 'bin',
\])
" Search in build directories if we can't find it in the project. " Search in build directories if we can't find it in the project.
for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h')) for l:path in ale#path#Upwards(expand('#' . a:buffer . ':p:h'))
for l:dirname in ale#Var(a:buffer, 'c_build_dir_names') for l:dirname in ale#Var(a:buffer, 'c_build_dir_names')
let l:c_build_dir = l:path . s:sep . l:dirname let l:c_build_dir = ale#path#GetAbsPath(l:path, l:dirname)
let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json' let l:json_file = l:c_build_dir . s:sep . 'compile_commands.json'
if filereadable(l:json_file) if filereadable(l:json_file)
return [l:path, l:json_file] " For absolute build dir paths, use the parent
" of the build dir as the project root. For
" relative paths, use the directory found by
" searching upwards from the file.
let l:root = ale#path#IsAbsolute(l:dirname)
\ ? fnamemodify(l:c_build_dir, ':h')
\ : l:path
return [l:root, l:json_file]
endif endif
endfor endfor
endfor endfor

View File

@@ -457,6 +457,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['markdown'], \ 'suggested_filetypes': ['markdown'],
\ 'description': 'Fix markdown files with pandoc.', \ 'description': 'Fix markdown files with pandoc.',
\ }, \ },
\ 'pymarkdown': {
\ 'function': 'ale#fixers#pymarkdown#Fix',
\ 'suggested_filetypes': ['markdown'],
\ 'description': 'Fix markdown files with pymarkdown.',
\ },
\ 'shfmt': { \ 'shfmt': {
\ 'function': 'ale#fixers#shfmt#Fix', \ 'function': 'ale#fixers#shfmt#Fix',
\ 'suggested_filetypes': ['sh'], \ 'suggested_filetypes': ['sh'],
@@ -672,6 +677,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['racket'], \ 'suggested_filetypes': ['racket'],
\ 'description': 'Fix Racket files with raco fmt.', \ 'description': 'Fix Racket files with raco fmt.',
\ }, \ },
\ 'rescript_format': {
\ 'function': 'ale#fixers#rescript_format#Fix',
\ 'suggested_filetypes': ['rescript'],
\ 'description': 'Official formatter for ReScript.',
\ },
\ 'ruff': { \ 'ruff': {
\ 'function': 'ale#fixers#ruff#Fix', \ 'function': 'ale#fixers#ruff#Fix',
\ 'suggested_filetypes': ['python'], \ 'suggested_filetypes': ['python'],

View File

@@ -38,7 +38,7 @@ function! ale#fixers#autoflake#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(l:executable) . l:exec_args \ 'command': ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --in-place ' \ . ' --in-place '
\ . ' %t', \ . ' %t',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,

View File

@@ -39,7 +39,7 @@ function! ale#fixers#autoimport#Fix(buffer) abort
return { return {
\ 'cwd': '%s:h', \ 'cwd': '%s:h',
\ 'command': ale#Escape(l:executable) . l:exec_args \ 'command': ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' -', \ . ' -',
\} \}
endfunction endfunction

View File

@@ -38,7 +38,7 @@ function! ale#fixers#autopep8#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(l:executable) . l:exec_args \ 'command': ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' -', \ . ' -',
\} \}
endfunction endfunction

View File

@@ -6,6 +6,6 @@ function! ale#fixers#biome#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(l:executable) . ' check ' \ 'command': ale#Escape(l:executable) . ' check '
\ . '--write --stdin-file-path %s' . l:unsafe \ . '--write --stdin-file-path %s' . l:unsafe
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\} \}
endfunction endfunction

View File

@@ -28,7 +28,7 @@ function! ale#fixers#erblint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'eruby_erblint_options') let l:options = ale#Var(a:buffer, 'eruby_erblint_options')
return ale#ruby#EscapeExecutable(l:executable, 'erblint') return ale#ruby#EscapeExecutable(l:executable, 'erblint')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --autocorrect --stdin %s' \ . ' --autocorrect --stdin %s'
endfunction endfunction

View File

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

View File

@@ -13,7 +13,7 @@ function! ale#fixers#mix_format#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'elixir_mix_format_options') let l:options = ale#Var(a:buffer, 'elixir_mix_format_options')
return l:executable . ' format' return l:executable . ' format'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' %t' \ . ' %t'
endfunction endfunction

View File

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

View File

@@ -99,7 +99,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
return { return {
\ 'cwd': '%s:h', \ 'cwd': '%s:h',
\ 'command':ale#Escape(l:executable) \ 'command':ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
\ 'process_with': 'ale#fixers#prettier#ProcessPrettierDOutput', \ 'process_with': 'ale#fixers#prettier#ProcessPrettierDOutput',
\} \}
@@ -110,7 +110,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
return { return {
\ 'cwd': ale#fixers#prettier#GetCwd(a:buffer), \ 'cwd': ale#fixers#prettier#GetCwd(a:buffer),
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
\} \}
endif endif
@@ -118,7 +118,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . ' %t' \ . ' %t'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --write', \ . ' --write',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\} \}

View File

@@ -40,7 +40,7 @@ function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version) abort
\ 'cwd': '%s:h', \ 'cwd': '%s:h',
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . l:eslint_config_option \ . l:eslint_config_option
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --stdin-filepath %s --stdin', \ . ' --stdin-filepath %s --stdin',
\} \}
endif endif
@@ -49,7 +49,7 @@ function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version) abort
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . ' %t' \ . ' %t'
\ . l:eslint_config_option \ . l:eslint_config_option
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --write', \ . ' --write',
\ 'read_temporary_file': 1, \ 'read_temporary_file': 1,
\} \}

View File

@@ -0,0 +1,46 @@
scriptencoding utf-8
" Author: Adrian Vollmer <adrian.vollmer@syss.de>
" Description: Fix markdown files with pymarkdown.
call ale#Set('markdown_pymarkdown_executable', 'pymarkdown')
call ale#Set('markdown_pymarkdown_options', '')
call ale#Set('markdown_pymarkdown_use_global', get(g:, 'ale_use_global_executables', 0))
call ale#Set('markdown_pymarkdown_auto_pipenv', 0)
call ale#Set('markdown_pymarkdown_auto_poetry', 0)
call ale#Set('markdown_pymarkdown_auto_uv', 0)
function! ale#fixers#pymarkdown#GetExecutable(buffer) abort
if (ale#Var(a:buffer, 'python_auto_pipenv') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_pipenv'))
\ && ale#python#PipenvPresent(a:buffer)
return 'pipenv'
endif
if (ale#Var(a:buffer, 'python_auto_poetry') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_poetry'))
\ && ale#python#PoetryPresent(a:buffer)
return 'poetry'
endif
if (ale#Var(a:buffer, 'python_auto_uv') || ale#Var(a:buffer, 'markdown_pymarkdown_auto_uv'))
\ && ale#python#UvPresent(a:buffer)
return 'uv'
endif
return ale#python#FindExecutable(a:buffer, 'markdown_pymarkdown', ['pymarkdown'])
endfunction
function! ale#fixers#pymarkdown#Fix(buffer) abort
let l:executable = ale#fixers#pymarkdown#GetExecutable(a:buffer)
let l:options = ale#Var(a:buffer, 'markdown_pymarkdown_options')
let l:exec_args = l:executable =~? 'pipenv\|poetry\|uv$'
\ ? ' run pymarkdown'
\ : ''
return {
\ 'command': ale#Escape(l:executable) . l:exec_args
\ . ' fix'
\ . ale#Pad(l:options)
\ . ' %t',
\ 'read_temporary_file': 1,
\}
endfunction

View File

@@ -18,7 +18,7 @@ function! ale#fixers#remark_lint#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : ''), \ . ale#Pad(l:options),
\} \}
endfunction endfunction

View File

@@ -38,6 +38,6 @@ function! ale#fixers#reorder_python_imports#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(l:executable) . l:exec_args \ 'command': ale#Escape(l:executable) . l:exec_args
\ . (!empty(l:options) ? ' ' . l:options : '') . ' -', \ . ale#Pad(l:options) . ' -',
\} \}
endfunction endfunction

View File

@@ -0,0 +1,33 @@
" Author: John Jackson <john@johnridesa.bike>
" Description: Fix ReScript files with the ReScript formatter.
call ale#Set('rescript_format_executable', 'rescript')
call ale#Set(
\ 'rescript_format_use_global',
\ get(g:, 'ale_use_global_executables', v:false)
\ )
function! s:GetExecutable(buffer) abort
return ale#path#FindExecutable(a:buffer, 'rescript_format', [
\ 'node_modules/.bin/rescript',
\])
endfunction
function! s:FixWithVersion(buffer, version) abort
let l:exe = ale#Escape(s:GetExecutable(a:buffer))
let l:stdin = ale#semver#GTE(a:version, [12, 0, 0]) ? ' --stdin' : ' -stdin'
let l:ext = fnamemodify(bufname(a:buffer), ':e') is? 'resi'
\ ? ' .resi'
\ : ' .res'
return {'command': l:exe . ' format' . l:stdin . l:ext}
endfunction
function! ale#fixers#rescript_format#Fix(buffer) abort
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ s:GetExecutable(a:buffer),
\ '%e --version',
\ function('s:FixWithVersion'),
\)
endfunction

View File

@@ -26,7 +26,7 @@ function! ale#fixers#rubocop#GetCommand(buffer, version) abort
let l:editor_mode = ale#semver#GTE(a:version, [1, 61, 0]) let l:editor_mode = ale#semver#GTE(a:version, [1, 61, 0])
return ale#ruby#EscapeExecutable(l:executable, 'rubocop') return ale#ruby#EscapeExecutable(l:executable, 'rubocop')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct') \ . (l:auto_correct_all ? ' --auto-correct-all' : ' --auto-correct')
\ . (l:editor_mode ? ' --editor-mode' : '') \ . (l:editor_mode ? ' --editor-mode' : '')
\ . ' --force-exclusion --stdin %s' \ . ' --force-exclusion --stdin %s'

View File

@@ -7,7 +7,7 @@ function! ale#fixers#sorbet#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'srb') return ale#ruby#EscapeExecutable(l:executable, 'srb')
\ . ' tc' \ . ' tc'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --autocorrect --file %t' \ . ' --autocorrect --file %t'
endfunction endfunction

View File

@@ -10,7 +10,7 @@ function! ale#fixers#sqlformat#Fix(buffer) abort
return { return {
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' -' \ . ' -'
\} \}
endfunction endfunction

View File

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

View File

@@ -11,7 +11,7 @@ function! ale#fixers#standardrb#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'standardrb') return ale#ruby#EscapeExecutable(l:executable, 'standardrb')
\ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '') \ . (!empty(l:config) ? ' --config ' . ale#Escape(l:config) : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' --fix --force-exclusion --stdin %s' \ . ' --fix --force-exclusion --stdin %s'
endfunction endfunction

View File

@@ -7,7 +7,7 @@ function! ale#fixers#syntax_tree#GetCommand(buffer) abort
return ale#ruby#EscapeExecutable(l:executable, 'stree') return ale#ruby#EscapeExecutable(l:executable, 'stree')
\ . ' format' \ . ' format'
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' %t' \ . ' %t'
endfunction endfunction

View File

@@ -20,6 +20,6 @@ function! ale#fixers#yamlfix#Fix(buffer) abort
return { return {
\ 'cwd': '%s:h', \ 'cwd': '%s:h',
\ 'command': ale#Escape(l:executable) \ 'command': ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') . ' -', \ . ale#Pad(l:options) . ' -',
\} \}
endfunction endfunction

85
autoload/ale/fzf.vim Normal file
View File

@@ -0,0 +1,85 @@
" Author: bretello https://github.com/bretello
" Description: Functions for integrating with fzf
" Handle references found with ALEFindReferences using fzf
function! ale#fzf#ShowReferences(item_list, options) abort
let l:name = 'LSP References'
let l:capname = 'References'
let l:items = copy(a:item_list)
let l:cwd = getcwd() " no-custom-checks
let l:sep = has('win32') ? '\' : '/'
function! s:relative_paths(line) closure abort
return substitute(a:line, '^' . l:cwd . l:sep, '', '')
endfunction
if get(a:options, 'use_relative_paths')
let l:items = map(filter(l:items, 'len(v:val)'), 's:relative_paths(v:val)')
endif
let l:start_query = ''
let l:fzf_options = {
\ 'source': items,
\ 'options': ['--prompt', l:name.'> ', '--query', l:start_query,
\ '--multi', '--bind', 'alt-a:select-all,alt-d:deselect-all',
\ '--delimiter', ':', '--preview-window', '+{2}/2']
\}
call add(l:fzf_options['options'], '--highlight-line') " this only works for more recent fzf versions (TODO: handle version check?)
" wrap with #with_preview and #fzfwrap before adding the sinklist,
" otherwise --expect options are not added
let l:opts_with_preview = fzf#vim#with_preview(l:fzf_options)
let l:bang = 0 " TODO: handle bang
let l:wrapped = fzf#wrap(l:name, l:opts_with_preview, l:bang)
call remove(l:wrapped, 'sink*') " remove the default sinklist to add in our custom sinklist
function! l:wrapped.sinklist(lines) closure abort
if len(a:lines) <2
return
endif
let l:cmd = a:lines[0]
function! s:references_to_qf(line) closure abort
" mimics ag_to_qf in junegunn/fzf.vim
let l:parts = matchlist(a:line, '\(.\{-}\)\s*:\s*\(\d\+\)\%(\s*:\s*\(\d\+\)\)\?\%(\s*:\(.*\)\)\?')
let l:filename = &autochdir ? fnamemodify(l:parts[1], ':p') : l:parts[1]
return {'filename': l:filename, 'lnum': l:parts[2], 'col': l:parts[3], 'text': l:parts[4]}
endfunction
let l:references = map(filter(a:lines[1:], 'len(v:val)'), 's:references_to_qf(v:val)')
if empty(l:references)
return
endif
if get(a:options, 'open_in') is# 'quickfix'
call setqflist([], 'r')
call setqflist(l:references, 'a')
call ale#util#Execute('cc 1')
endif
function! s:action(key, file) abort
" copied from fzf.vim
let l:default_action = {
\ 'ctrl-t': 'tab split',
\ 'ctrl-x': 'split',
\ 'ctrl-v': 'vsplit' }
let fzf_actions = get(g:, 'fzf_action', l:default_action)
let l:Cmd = get(fzf_actions, a:key, 'edit')
let l:cursor_cmd = escape('call cursor(' . a:file['lnum'] . ',' . a:file['col'] . ')', ' ')
let l:fullcmd = l:Cmd . ' +' . l:cursor_cmd . ' ' . fnameescape(a:file['filename'])
silent keepjumps keepalt execute fullcmd
endfunction
return map(l:references, 's:action(cmd, v:val)')
endfunction
call fzf#run(l:wrapped)
endfunction

View File

@@ -69,11 +69,12 @@ function! ale#handlers#cppcheck#HandleCppCheckFormat(buffer, lines) abort
"test.c:1:16: style: misra violation (use --rule-texts=<file> to get proper output) [misra-c2012-2.7]\' "test.c:1:16: style: misra violation (use --rule-texts=<file> to get proper output) [misra-c2012-2.7]\'
"void test( int parm ) {} "void test( int parm ) {}
" ^ " ^
let l:pattern = '\v(\f+):(\d+):(\d+|\{column\}): (\w+):(\{inconclusive:inconclusive\})? ?(.*) \[(%(\w[-.]?)+)\]\' let l:pattern = '\v(\f+):(\d+):(\d+|\{column\}): (\w+):(\{inconclusive:inconclusive\})? ?(.*) \[(%(\w[-.]?)+)\]\\?'
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)
if ale#path#IsBufferPath(a:buffer, l:match[1]) if ale#path#IsBufferPath(a:buffer, l:match[1])
let l:text = substitute(l:match[6], '\\$', '', '')
call add(l:output, { call add(l:output, {
\ 'lnum': str2nr(l:match[2]), \ 'lnum': str2nr(l:match[2]),
\ 'col': match(l:match[3],'{column}') >= 0 ? 1 : str2nr(l:match[3]), \ 'col': match(l:match[3],'{column}') >= 0 ? 1 : str2nr(l:match[3]),

View File

@@ -39,7 +39,7 @@ function! ale#handlers#djlint#GetCommand(buffer) abort
endif endif
return ale#Escape(l:executable) return ale#Escape(l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') . ' %s' \ . ale#Pad(l:options) . ' %s'
endfunction endfunction
function! ale#handlers#djlint#Handle(buffer, lines) abort function! ale#handlers#djlint#Handle(buffer, lines) abort

View File

@@ -54,7 +54,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#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' -f json --stdin --stdin-filename %s' \ . ' -f json --stdin --stdin-filename %s'
endfunction endfunction

View File

@@ -2,15 +2,21 @@
" Description: Adds support for markdownlint " Description: Adds support for markdownlint
function! ale#handlers#markdownlint#Handle(buffer, lines) abort function! ale#handlers#markdownlint#Handle(buffer, lines) abort
let l:pattern=': \?\(\d\+\)\(:\(\d\+\)\?\)\? \(MD\d\{3}/[A-Za-z0-9-/]\+\) \(.*\)$' let l:pattern=': \?\(\d\+\)\(:\(\d\+\)\?\)\? \(error\|warning\)\? \?\(MD\d\{3}/[A-Za-z0-9-/]\+\) \(.*\)$'
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)
let l:type = 'W'
if l:match[4] is# 'error'
let l:type = 'E'
endif
let l:result = ({ let l:result = ({
\ 'lnum': l:match[1] + 0, \ 'lnum': l:match[1] + 0,
\ 'code': l:match[4], \ 'code': l:match[5],
\ 'text': l:match[5], \ 'text': l:match[6],
\ 'type': 'W', \ 'type': l:type,
\}) \})
if len(l:match[3]) > 0 if len(l:match[3]) > 0

View File

@@ -57,7 +57,7 @@ function! ale#handlers#shellcheck#GetCommand(buffer, version) abort
return '%e' return '%e'
\ . (!empty(l:dialect) ? ' -s ' . l:dialect : '') \ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '') \ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '')
\ . l:external_option \ . l:external_option
\ . ' -f ' . l:format . ' -' \ . ' -f ' . l:format . ' -'

View File

@@ -17,7 +17,7 @@ function! ale#handlers#textlint#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'textlint_options') let l:options = ale#Var(a:buffer, 'textlint_options')
return ale#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' -f json --stdin --stdin-filename %s' \ . ' -f json --stdin --stdin-filename %s'
endfunction endfunction

View File

@@ -22,7 +22,7 @@ function! ale#handlers#writegood#GetCommand(buffer) abort
let l:options = ale#Var(a:buffer, 'writegood_options') let l:options = ale#Var(a:buffer, 'writegood_options')
return ale#node#Executable(a:buffer, l:executable) return ale#node#Executable(a:buffer, l:executable)
\ . (!empty(l:options) ? ' ' . l:options : '') \ . ale#Pad(l:options)
\ . ' %t' \ . ' %t'
endfunction endfunction

View File

@@ -81,7 +81,7 @@ function! ale#preview#ShowSelection(item_list, ...) abort
\ l:filename \ l:filename
\ . ':' . l:item.line \ . ':' . l:item.line
\ . ':' . l:item.column \ . ':' . l:item.column
\ . (!empty(l:match) ? ' ' . l:match : ''), \ . ale#Pad(l:match),
\) \)
endfor endfor

View File

@@ -0,0 +1,25 @@
call ale#Set('proselint_executable', 'proselint')
function! ale#proselint#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'proselint_executable')
endfunction
function! ale#proselint#GetCommand(buffer, version) abort
let l:executable = ale#proselint#GetExecutable(a:buffer)
let l:escaped_exec = ale#Escape(l:executable)
if ale#semver#GTE(a:version, [0, 16, 0])
return l:escaped_exec . ' check %t'
else
return l:escaped_exec . ' %t'
endif
endfunction
function! ale#proselint#GetCommandWithVersionCheck(buffer) abort
return ale#semver#RunWithVersionCheck(
\ a:buffer,
\ ale#proselint#GetExecutable(a:buffer),
\ '%e version --output-format json',
\ function('ale#proselint#GetCommand')
\)
endfunction

View File

@@ -1,5 +1,6 @@
let g:ale_default_navigation = get(g:, 'ale_default_navigation', 'buffer') let g:ale_default_navigation = get(g:, 'ale_default_navigation', 'buffer')
let g:ale_references_show_contents = get(g:, 'ale_references_show_contents', 1) let g:ale_references_show_contents = get(g:, 'ale_references_show_contents', 1)
let g:ale_references_use_fzf = get(g:, 'ale_references_use_fzf', 0)
let s:references_map = {} let s:references_map = {}
@@ -17,117 +18,123 @@ function! ale#references#ClearLSPData() abort
let s:references_map = {} let s:references_map = {}
endfunction endfunction
function! ale#references#FormatTSResponseItem(response_item, options) abort function! ale#references#FormatResponseItem(response_item, options) abort
let l:match = substitute(a:response_item.lineText, '^\s*\(.\{-}\)\s*$', '\1', '') let l:filename = get(a:response_item, 'filename', '')
let l:column = get(a:response_item, 'column', 0)
let l:line = get(a:response_item, 'line', 0)
let l:line_text = get(a:response_item, 'line_text', '')
try
let l:line_text = substitute(
\ l:line_text,
\ '^\s*\(.\{-}\)\s*$', '\1', ''
\)
catch
" This happens in tests
endtry
if get(a:options, 'use_fzf') == 1
" grep-style output (filename:line:col:text) so that fzf can properly
" show matches and previews using ':' as delimiter
return l:filename . ':' . l:line . ':' . l:column . ':' . l:line_text
endif
if get(a:options, 'open_in') is# 'quickfix' if get(a:options, 'open_in') is# 'quickfix'
return { return {
\ 'filename': a:response_item.file, \ 'filename': l:filename,
\ 'lnum': a:response_item.start.line, \ 'lnum': l:line,
\ 'col': a:response_item.start.offset, \ 'col': l:column,
\ 'text': l:match, \ 'text': l:line_text,
\} \}
else else
return { return {
\ 'filename': a:response_item.file, \ 'filename': l:filename,
\ 'line': a:response_item.start.line, \ 'line': l:line,
\ 'column': a:response_item.start.offset, \ 'column': l:column,
\ 'match': l:match, \ 'match': l:line_text,
\} \}
endif endif
endfunction endfunction
function! ale#references#DisplayReferences(item_list, options) abort
if empty(a:item_list)
call ale#util#Execute('echom ''No references found.''')
else
if get(a:options, 'use_fzf') == 1
if !exists('*fzf#run')
throw 'fzf#run function not found. You also need Vim plugin from the main fzf repository (i.e. junegunn/fzf *and* junegunn/fzf.vim)'
endif
call ale#fzf#ShowReferences(a:item_list, a:options)
elseif get(a:options, 'open_in') is# 'quickfix'
call setqflist([], 'r')
call setqflist(a:item_list, 'a')
call ale#util#Execute('cc 1')
else
call ale#preview#ShowSelection(a:item_list, a:options)
endif
endif
endfunction
function! ale#references#HandleTSServerResponse(conn_id, response) abort function! ale#references#HandleTSServerResponse(conn_id, response) abort
if get(a:response, 'command', '') is# 'references' if get(a:response, 'command', '') is# 'references'
\&& has_key(s:references_map, a:response.request_seq) \&& has_key(s:references_map, a:response.request_seq)
let l:options = remove(s:references_map, a:response.request_seq) let l:options = remove(s:references_map, a:response.request_seq)
let l:format_options = copy(l:options)
if get(a:response, 'success', v:false) is v:true if get(a:response, 'success', v:false) is v:true
let l:item_list = [] let l:item_list = []
for l:response_item in a:response.body.refs for l:response_item in a:response.body.refs
let l:format_response_item = {
\ 'filename': l:response_item.file,
\ 'line': l:response_item.start.line,
\ 'column': l:response_item.start.offset,
\ 'line_text': l:response_item.lineText,
\ }
call add( call add(
\ l:item_list, \ l:item_list,
\ ale#references#FormatTSResponseItem(l:response_item, l:options) \ ale#references#FormatResponseItem(l:format_response_item, l:format_options)
\) \)
endfor endfor
if empty(l:item_list) call ale#references#DisplayReferences(l:item_list, l:format_options)
call ale#util#Execute('echom ''No references found.''')
else
if get(l:options, 'open_in') is# 'quickfix'
call setqflist([], 'r')
call setqflist(l:item_list, 'a')
call ale#util#Execute('cc 1')
else
call ale#preview#ShowSelection(l:item_list, l:options)
endif
endif
endif endif
endif endif
endfunction endfunction
function! ale#references#FormatLSPResponseItem(response_item, options) abort
let l:line_text = ''
let l:line= a:response_item.range.start.line
let l:col = a:response_item.range.start.character
let l:filename = ale#util#ToResource(a:response_item.uri)
if get(a:options, 'show_contents') == 1
try
let l:line_text = substitute(readfile(l:filename)[l:line], '^\s*\(.\{-}\)\s*$', '\1', '')
catch
" This happens in tests
endtry
endif
if get(a:options, 'open_in') is# 'quickfix'
return {
\ 'filename': l:filename,
\ 'lnum': a:response_item.range.start.line + 1,
\ 'col': a:response_item.range.start.character + 1,
\ 'text': l:line_text,
\}
else
return {
\ 'filename': l:filename,
\ 'line': l:line + 1,
\ 'column': l:col + 1,
\ 'match': l:line_text,
\}
endif
endfunction
function! ale#references#HandleLSPResponse(conn_id, response) abort function! ale#references#HandleLSPResponse(conn_id, response) abort
if has_key(a:response, 'id') if ! (has_key(a:response, 'id') && has_key(s:references_map, a:response.id))
\&& has_key(s:references_map, a:response.id) return
let l:options = remove(s:references_map, a:response.id)
" The result can be a Dictionary item, a List of the same, or null.
let l:result = get(a:response, 'result', [])
let l:item_list = []
if type(l:result) is v:t_list
for l:response_item in l:result
call add(l:item_list,
\ ale#references#FormatLSPResponseItem(l:response_item, l:options)
\)
endfor
endif
if empty(l:item_list)
call ale#util#Execute('echom ''No references found.''')
else
if get(l:options, 'open_in') is# 'quickfix'
call setqflist([], 'r')
call setqflist(l:item_list, 'a')
call ale#util#Execute('cc 1')
else
call ale#preview#ShowSelection(l:item_list, l:options)
endif
endif
endif endif
let l:options = remove(s:references_map, a:response.id)
" The result can be a Dictionary item, a List of the same, or null.
let l:result = get(a:response, 'result', [])
let l:item_list = []
if type(l:result) is v:t_list
for l:response_item in l:result
let l:filename = ale#util#ToResource(get(l:response_item, 'uri', ''))
let l:read_line = l:response_item.range.start.line
let l:line = l:read_line + 1
let l:format_response_item = {
\ 'filename': l:filename,
\ 'line': l:line,
\ 'column': l:response_item.range.start.character + 1,
\ 'line_text': get(l:options, 'show_contents') == 1
\ ? readfile(l:filename)[l:read_line]
\ : '',
\ }
call add(l:item_list,
\ ale#references#FormatResponseItem(l:format_response_item, l:options)
\)
endfor
endif
call ale#references#DisplayReferences(l:item_list, l:options)
endfunction endfunction
function! s:OnReady(line, column, options, linter, lsp_details) abort function! s:OnReady(line, column, options, linter, lsp_details) abort
@@ -165,6 +172,7 @@ function! s:OnReady(line, column, options, linter, lsp_details) abort
\ 'use_relative_paths': has_key(a:options, 'use_relative_paths') ? a:options.use_relative_paths : 0, \ 'use_relative_paths': has_key(a:options, 'use_relative_paths') ? a:options.use_relative_paths : 0,
\ 'open_in': get(a:options, 'open_in', 'current-buffer'), \ 'open_in': get(a:options, 'open_in', 'current-buffer'),
\ 'show_contents': a:options.show_contents, \ 'show_contents': a:options.show_contents,
\ 'use_fzf': get(a:options, 'use_fzf', g:ale_references_use_fzf),
\} \}
endfunction endfunction
@@ -185,6 +193,8 @@ function! ale#references#Find(...) abort
let l:options.open_in = 'quickfix' let l:options.open_in = 'quickfix'
elseif l:option is? '-contents' elseif l:option is? '-contents'
let l:options.show_contents = 1 let l:options.show_contents = 1
elseif l:option is? '-fzf'
let l:options.use_fzf = 1
endif endif
endfor endfor
endif endif

View File

@@ -6,7 +6,7 @@ ALE Go Integration *ale-go-options*
Integration Information Integration Information
ALE enables `gofmt`, `gopls` and `go vet` by default. It also supports `staticcheck`, ALE enables `gofmt`, `gopls` and `go vet` by default. It also supports `staticcheck`,
`go build, ``gosimple`, `golangserver`, and `golangci-lint. `go build, ``gosimple`, `golangserver`, `golangci-lint`, and `goimports`.
To enable `golangci-lint`, update |g:ale_linters| as appropriate. To enable `golangci-lint`, update |g:ale_linters| as appropriate.
A possible configuration is to enable golangci-lint and `gofmt: A possible configuration is to enable golangci-lint and `gofmt:
@@ -118,6 +118,30 @@ g:ale_go_gofumpt_options
Options to pass to the gofumpt fixer. Options to pass to the gofumpt fixer.
===============================================================================
goimports *ale-go-goimports*
*ale-options.go_goimports_executable*
*g:ale_go_goimports_executable*
*b:ale_go_goimports_executable*
go_goimports_executable
g:ale_go_goimports_executable
Type: |String|
Default: `'goimports'`
This variable can be set to change the executable path for goimports.
*ale-options.go_goimports_options*
*g:ale_go_goimports_options*
*b:ale_go_goimports_options*
go_goimports_options
g:ale_go_goimports_options
Type: |String|
Default: `''`
This variable can be set to pass additional options to the goimports fixer.
=============================================================================== ===============================================================================
golangci-lint *ale-go-golangci-lint* golangci-lint *ale-go-golangci-lint*

View File

@@ -111,9 +111,11 @@ See |ale-javascript-prettier| for information about the available options.
=============================================================================== ===============================================================================
pymarkdown *ale-markdown-pymarkdown* pymarkdown *ale-markdown-pymarkdown*
pymarkdown can be used both as a linter and a fixer for Markdown files.
*ale-options.markdown_pymarkdown_executable* *ale-options.markdown_pymarkdown_executable*
*g:ale_markdown_pymarkdown_executable* *g:ale_markdown_pymarkdown_executable*
*b:ale_markdown_pymarkdown_executable* *b:ale_markdown_pymarkdown_executable*
markdown_pymarkdown_executable markdown_pymarkdown_executable
g:ale_markdown_pymarkdown_executable g:ale_markdown_pymarkdown_executable
Type: |String| Type: |String|
@@ -126,7 +128,7 @@ g:ale_markdown_pymarkdown_executable
*ale-options.markdown_pymarkdown_options* *ale-options.markdown_pymarkdown_options*
*g:ale_markdown_pymarkdown_options* *g:ale_markdown_pymarkdown_options*
*b:ale_markdown_pymarkdown_options* *b:ale_markdown_pymarkdown_options*
markdown_pymarkdown_options markdown_pymarkdown_options
g:ale_markdown_pymarkdown_options g:ale_markdown_pymarkdown_options
Type: |String| Type: |String|
@@ -137,7 +139,7 @@ g:ale_markdown_pymarkdown_options
*ale-options.markdown_pymarkdown_use_global* *ale-options.markdown_pymarkdown_use_global*
*g:ale_markdown_pymarkdown_use_global* *g:ale_markdown_pymarkdown_use_global*
*b:ale_markdown_pymarkdown_use_global* *b:ale_markdown_pymarkdown_use_global*
markdown_pymarkdown_use_global markdown_pymarkdown_use_global
g:ale_markdown_pymarkdown_use_global g:ale_markdown_pymarkdown_use_global
Type: |Number| Type: |Number|
@@ -147,7 +149,7 @@ g:ale_markdown_pymarkdown_use_global
*ale-options.markdown_pymarkdown_auto_pipenv* *ale-options.markdown_pymarkdown_auto_pipenv*
*g:ale_markdown_pymarkdown_auto_pipenv* *g:ale_markdown_pymarkdown_auto_pipenv*
*b:ale_markdown_pymarkdown_auto_pipenv* *b:ale_markdown_pymarkdown_auto_pipenv*
markdown_pymarkdown_auto_pipenv markdown_pymarkdown_auto_pipenv
g:ale_markdown_pymarkdown_auto_pipenv g:ale_markdown_pymarkdown_auto_pipenv
Type: |Number| Type: |Number|
@@ -158,7 +160,7 @@ g:ale_markdown_pymarkdown_auto_pipenv
*ale-options.markdown_pymarkdown_auto_poetry* *ale-options.markdown_pymarkdown_auto_poetry*
*g:ale_markdown_pymarkdown_auto_poetry* *g:ale_markdown_pymarkdown_auto_poetry*
*b:ale_markdown_pymarkdown_auto_poetry* *b:ale_markdown_pymarkdown_auto_poetry*
markdown_pymarkdown_auto_poetry markdown_pymarkdown_auto_poetry
g:ale_markdown_pymarkdown_auto_poetry g:ale_markdown_pymarkdown_auto_poetry
Type: |Number| Type: |Number|
@@ -169,7 +171,7 @@ g:ale_markdown_pymarkdown_auto_poetry
*ale-options.markdown_pymarkdown_auto_uv* *ale-options.markdown_pymarkdown_auto_uv*
*g:ale_markdown_pymarkdown_auto_uv* *g:ale_markdown_pymarkdown_auto_uv*
*b:ale_markdown_pymarkdown_auto_uv* *b:ale_markdown_pymarkdown_auto_uv*
markdown_pymarkdown_auto_uv markdown_pymarkdown_auto_uv
g:ale_markdown_pymarkdown_auto_uv g:ale_markdown_pymarkdown_auto_uv
Type: |Number| Type: |Number|

54
doc/ale-rescript.txt Normal file
View File

@@ -0,0 +1,54 @@
===============================================================================
ALE ReScript Integration *ale-rescript-options*
===============================================================================
rescript-language-server *ale-rescript-language-server*
*ale-options.rescript_language_server_executable*
*g:ale_rescript_language_server_executable*
*b:ale_rescript_language_server_executable*
ale_rescript_language_server_executable
g:ale_rescript_language_server_executable
Type: |String|
Default: `'rescript-language-server'`
See |ale-integrations-local-executables|
*ale-options.rescript_language_server_use_global*
*g:ale_rescript_language_server_use_global*
*b:ale_rescript_language_server_use_global*
rescript_language_server_use_global
g:ale_rescript_language_server_use_global
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', v:true)`
See |ale-integrations-local-executables|
===============================================================================
rescript_format *ale-rescript-format*
*ale-options.rescript_format_executable*
*g:ale_rescript_format_executable*
*b:ale_rescript_format_executable*
rescript_format_executable
g:ale_rescript_format_executable
Type: |String|
Default: `'rescript'`
See |ale-integrations-local-executables|
*ale-options.rescript_format_use_global*
*g:ale_rescript_format_use_global*
*b:ale_rescript_format_use_global*
rescript_format_use_global
g:ale_rescript_format_use_global
Type: |Number|
Default: `get(g:, 'ale_use_global_executables', v:false)`
See |ale-integrations-local-executables|
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -582,6 +582,9 @@ Notes:
* `cspell` * `cspell`
* `opacheck` * `opacheck`
* `opafmt` * `opafmt`
* ReScript
* `rescript-language-server`
* `rescript_format`
* REST * REST
* kulala_fmt * kulala_fmt
* reStructuredText * reStructuredText

View File

@@ -28,10 +28,12 @@ CONTENTS *ale-contents*
7. Linter/Fixer Options.................|ale-integration-options| 7. Linter/Fixer Options.................|ale-integration-options|
7.1 Options for alex..................|ale-alex-options| 7.1 Options for alex..................|ale-alex-options|
7.2 Options for cspell................|ale-cspell-options| 7.2 Options for cspell................|ale-cspell-options|
7.3 Options for languagetool..........|ale-languagetool-options| 7.3 Options for dprint................|ale-dprint-options|
7.4 Options for write-good............|ale-write-good-options| 7.4 Options for languagetool..........|ale-languagetool-options|
7.5 Options for redpen................|ale-redpen-options| 7.5 Options for write-good............|ale-write-good-options|
7.6 Other Linter/Fixer Options........|ale-other-integration-options| 7.6 Options for redpen................|ale-redpen-options|
7.7 Options for vale..................|ale-vale-options|
7.8 Other Linter/Fixer Options........|ale-other-integration-options|
8. Commands/Keybinds....................|ale-commands| 8. Commands/Keybinds....................|ale-commands|
9. API..................................|ale-api| 9. API..................................|ale-api|
10. Special Thanks......................|ale-special-thanks| 10. Special Thanks......................|ale-special-thanks|
@@ -1620,10 +1622,21 @@ g:ale_lint_delay
A buffer-local option, `b:ale_lint_delay`, can be set to change the delay A buffer-local option, `b:ale_lint_delay`, can be set to change the delay
for different buffers, such as in |ftplugin| files. for different buffers, such as in |ftplugin| files.
*ale-options.ale_lint_diff*
*g:ale_lint_diff*
g:ale_lint_diff
Type: |Number|
Default: `0`
When this option is set to `1`, ALE will lint buffers where `&diff` is set.
*ale-options.lint_on_enter* *ale-options.lint_on_enter*
*g:ale_lint_on_enter* *g:ale_lint_on_enter*
lint_on_enter lint_on_enter
g:ale_lint_on_enter g:ale_lint_on_enter
Type: |Number| Type: |Number|
Default: `1` Default: `1`
@@ -2280,6 +2293,16 @@ g:ale_references_show_contents
If set to `true` or `1`, matches found by `:ALEFindReferences` will be If set to `true` or `1`, matches found by `:ALEFindReferences` will be
shown with a preview of the matching line. shown with a preview of the matching line.
*ale-options.references_use_fzf*
*g:ale_references_use_fzf*
references_use_fzf
g:ale_references_use_fzf
Type: |Boolean| or |Number|
Default: `false`
If set to `true` or `1`, matches found by `:ALEFindReferences` will be
always shown using |fzf-vim| (https://github.com/junegunn/fzf.vim).
*ale-options.rename_tsserver_find_in_comments* *ale-options.rename_tsserver_find_in_comments*
*g:ale_rename_tsserver_find_in_comments* *g:ale_rename_tsserver_find_in_comments*
rename_tsserver_find_in_comments rename_tsserver_find_in_comments
@@ -3349,7 +3372,31 @@ g:ale_redpen_options
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
7.7. Other Linter/Fixer Options *ale-other-integration-options* 7.7. Options for vale *ale-vale-options*
The following options can be used to configure the `vale` linter for text
files.
g:ale_text_vale_executable *g:ale_text_vale_executable*
Type: String
Default: 'vale'
This option controls which executable is used for running Vale. Set it to an
absolute path or a different command name if needed.
g:ale_text_vale_options *g:ale_text_vale_options*
Type: String
Default: ''
Extra command-line options to pass to the Vale executable.
Example:
let g:ale_text_vale_options = '--minAlertLevel=warning'
-------------------------------------------------------------------------------
7.8. Other Linter/Fixer Options *ale-other-integration-options*
ALE supports a very wide variety of tools. Other linter or fixer options are ALE supports a very wide variety of tools. Other linter or fixer options are
documented in additional help files. documented in additional help files.
@@ -3531,6 +3578,7 @@ documented in additional help files.
gobuild...............................|ale-go-gobuild| gobuild...............................|ale-go-gobuild|
gofmt.................................|ale-go-gofmt| gofmt.................................|ale-go-gofmt|
gofumpt...............................|ale-go-gofumpt| gofumpt...............................|ale-go-gofumpt|
goimports.............................|ale-go-goimports|
golangci-lint.........................|ale-go-golangci-lint| golangci-lint.........................|ale-go-golangci-lint|
golangserver..........................|ale-go-golangserver| golangserver..........................|ale-go-golangserver|
golines...............................|ale-go-golines| golines...............................|ale-go-golines|
@@ -3852,6 +3900,9 @@ documented in additional help files.
cspell................................|ale-rego-cspell| cspell................................|ale-rego-cspell|
opacheck..............................|ale-rego-opa-check| opacheck..............................|ale-rego-opa-check|
opafmt................................|ale-rego-opa-fmt-fixer| opafmt................................|ale-rego-opa-fmt-fixer|
rescript................................|ale-rescript-options|
rescript-language-server..............|ale-rescript-language-server|
rescript_format.......................|ale-rescript-format|
rest....................................|ale-rest-options| rest....................................|ale-rest-options|
kulala_fmt............................|ale-rest-kulala_fmt| kulala_fmt............................|ale-rest-kulala_fmt|
restructuredtext........................|ale-restructuredtext-options| restructuredtext........................|ale-restructuredtext-options|
@@ -4085,6 +4136,7 @@ documented in additional help files.
`:ALEFindReferences -vsplit` - Open the location in a vertical split. `:ALEFindReferences -vsplit` - Open the location in a vertical split.
`:ALEFindReferences -quickfix` - Put the locations into quickfix list. `:ALEFindReferences -quickfix` - Put the locations into quickfix list.
`:ALEFindReferences -contents` - Show line contents for matches. `:ALEFindReferences -contents` - Show line contents for matches.
`:ALEFindReferences -fzf` - Show matches/previews using |fzf-vim|.
The default method used for navigating to a new location can be changed The default method used for navigating to a new location can be changed
by modifying |g:ale_default_navigation|. by modifying |g:ale_default_navigation|.
@@ -4092,6 +4144,11 @@ documented in additional help files.
The default behaviour on whether to show line content for matches can The default behaviour on whether to show line content for matches can
be changed by modifying |g:ale_references_show_contents|. be changed by modifying |g:ale_references_show_contents|.
The default behaviour on whether to use `fzf` to show matches/file previews
can be changed by modifying |g:ale_references_use_fzf|. `-fzf` can be combined
with `-tab`, `-split`, `-vsplit`, `-quickfix` and `-relative`, while line
contents/file previews are always shown.
You can add `-relative` to the command to view results with relatives paths, You can add `-relative` to the command to view results with relatives paths,
instead of absolute paths. This option has no effect if `-quickfix` is used. instead of absolute paths. This option has no effect if `-quickfix` is used.

View File

@@ -8,6 +8,14 @@ module.start = function(config)
config.init_options[true] = nil config.init_options[true] = nil
end end
-- ensure init_options uses empty_dict if empty
if type(config.init_options) == "table"
and next(config.init_options) == nil
and getmetatable(config.init_options) == nil
then
config.init_options = vim.empty_dict()
end
-- If configuring LSP via a socket connection, then generate the cmd -- If configuring LSP via a socket connection, then generate the cmd
-- using vim.lsp.rpc.connect(), as defined in Neovim documentation. -- using vim.lsp.rpc.connect(), as defined in Neovim documentation.
if config.host then if config.host then
@@ -131,9 +139,19 @@ module.send_message = function(args)
end end
if args.is_notification then if args.is_notification then
-- For notifications we send a request and expect no direct response. local success
local success = client.notify(args.method, args.params)
if vim.version().minor >= 11 then
-- Supporting Neovim 0.11+
---@diagnostic disable-next-line
success = client.notify(client, args.method, args.params)
else
-- Supporting Neovim 0.10 and below
---@diagnostic disable-next-line
success = client.notify(args.method, args.params)
end
-- For notifications we send a request and expect no direct response.
if success then if success then
return -1 return -1
end end
@@ -142,24 +160,27 @@ module.send_message = function(args)
end end
local success, request_id local success, request_id
local handle_func = function(_, result, _, _)
vim.fn["ale#lsp#HandleResponse"](client.name, {
id = request_id,
result = result,
})
end
-- For request we send a request and handle the response. if vim.version().minor >= 11 then
-- -- Supporting Neovim 0.11+
-- We set the bufnr to -1 to prevent Neovim from flushing anything, as ALE
-- already flushes changes to files before sending requests. -- We send a request and handle the response.
success, request_id = client.request( --
args.method, -- We set the bufnr to -1 to prevent Neovim from flushing anything, as ALE
args.params, -- already flushes changes to files before sending requests.
---@diagnostic disable-next-line: param-type-mismatch ---@diagnostic disable-next-line
function(_, result, _, _) success, request_id = client.request(client, args.method, args.params, handle_func, -1)
vim.fn["ale#lsp#HandleResponse"](client.name, { else
id = request_id, -- Supporting Neovim 0.10 and below
result = result, ---@diagnostic disable-next-line
}) success, request_id = client.request(args.method, args.params, handle_func, -1)
end, end
---@diagnostic disable-next-line: param-type-mismatch
-1
)
if success then if success then
return request_id return request_id

View File

@@ -175,7 +175,7 @@ find test -name '*.swp' -delete
set -eu set -eu
# Check if docker un image is available locally # Check if docker un image is available locally
has_image=$(docker images --quiet "${image}:${image_tag}" | wc -l) has_image=$(docker images --quiet "denseanalysis/ale:${image_tag}" | wc -l)
if [[ "$DOCKER" == docker ]]; then if [[ "$DOCKER" == docker ]]; then
arch=$(docker info -f '{{ .Architecture }}') arch=$(docker info -f '{{ .Architecture }}')
@@ -221,7 +221,9 @@ if [ "$has_image" -eq 0 ] && ! download_image; then
docker push "${image}:${image_tag}" docker push "${image}:${image_tag}"
fi fi
else else
echo "Docker run image ${image}:${image_tag} ready" if [ -z "$quiet_flag" ]; then
echo "Docker run image ${image}:${image_tag} ready"
fi
fi fi
"$DOCKER" tag "${image}:${image_tag}" "${image}:latest" "$DOCKER" tag "${image}:${image_tag}" "${image}:latest"

View File

@@ -421,7 +421,7 @@ formatting.
* [pandoc](https://pandoc.org) * [pandoc](https://pandoc.org)
* [prettier](https://github.com/prettier/prettier) * [prettier](https://github.com/prettier/prettier)
* [proselint](http://proselint.com/) * [proselint](http://proselint.com/)
* [pymarkdown](https://github.com/jackdewinter/pymarkdown) * [pymarkdown](https://github.com/jackdewinter/pymarkdown) :floppy_disk:
* [redpen](http://redpen.cc/) * [redpen](http://redpen.cc/)
* [remark-lint](https://github.com/wooorm/remark-lint) * [remark-lint](https://github.com/wooorm/remark-lint)
* [textlint](https://textlint.github.io/) * [textlint](https://textlint.github.io/)
@@ -592,6 +592,9 @@ formatting.
* [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) * [cspell](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell)
* [opacheck](https://www.openpolicyagent.org/docs/latest/cli/#opa-check) * [opacheck](https://www.openpolicyagent.org/docs/latest/cli/#opa-check)
* [opafmt](https://www.openpolicyagent.org/docs/latest/cli/#opa-fmt) * [opafmt](https://www.openpolicyagent.org/docs/latest/cli/#opa-fmt)
* ReScript
* [rescript-language-server](https://www.npmjs.com/package/@rescript/language-server) :speech_balloon:
* [rescript_format](https://rescript-lang.org/)
* REST * REST
* [kulala_fmt](https://github.com/mistweaverco/kulala-fmt) * [kulala_fmt](https://github.com/mistweaverco/kulala-fmt)
* reStructuredText * reStructuredText

View File

@@ -0,0 +1,81 @@
Before:
Save g:ale_markdown_pymarkdown_executable
Save g:ale_markdown_pymarkdown_options
Save g:ale_markdown_pymarkdown_auto_pipenv
Save g:ale_markdown_pymarkdown_auto_poetry
Save g:ale_markdown_pymarkdown_auto_uv
After:
Restore
Execute(The pymarkdown callback should return 'pymarkdown' as default command):
AssertEqual
\ {
\ 'command': ale#Escape('pymarkdown') . ' fix %t',
\ 'read_temporary_file': 1,
\ },
\ ale#fixers#pymarkdown#Fix(bufnr(''))
Execute(The pymarkdown executable and options should be configurable):
let g:ale_markdown_pymarkdown_executable = 'foobar'
let g:ale_markdown_pymarkdown_options = '--some-option'
AssertEqual
\ {
\ 'command': ale#Escape('foobar') . ' fix --some-option %t',
\ 'read_temporary_file': 1,
\ },
\ ale#fixers#pymarkdown#Fix(bufnr(''))
Execute(Setting executable to 'pipenv' appends 'run pymarkdown'):
let g:ale_markdown_pymarkdown_executable = 'path/to/pipenv'
AssertEqual
\ {
\ 'command': ale#Escape('path/to/pipenv') . ' run pymarkdown fix %t',
\ 'read_temporary_file': 1,
\ },
\ ale#fixers#pymarkdown#Fix(bufnr(''))
Execute(Pipenv is detected when markdown_pymarkdown_auto_pipenv is set):
let g:ale_markdown_pymarkdown_auto_pipenv = 1
call ale#test#SetFilename('../test-files/python/pipenv/whatever.py')
AssertEqual
\ {
\ 'command': ale#Escape('pipenv') . ' run pymarkdown fix %t',
\ 'read_temporary_file': 1,
\ },
\ ale#fixers#pymarkdown#Fix(bufnr(''))
Execute(Setting executable to 'poetry' appends 'run pymarkdown'):
let g:ale_markdown_pymarkdown_executable = 'path/to/poetry'
AssertEqual
\ {
\ 'command': ale#Escape('path/to/poetry') . ' run pymarkdown fix %t',
\ 'read_temporary_file': 1,
\ },
\ ale#fixers#pymarkdown#Fix(bufnr(''))
Execute(Poetry is detected when markdown_pymarkdown_auto_poetry is set):
let g:ale_markdown_pymarkdown_auto_poetry = 1
call ale#test#SetFilename('../test-files/python/poetry/whatever.py')
AssertEqual
\ {
\ 'command': ale#Escape('poetry') . ' run pymarkdown fix %t',
\ 'read_temporary_file': 1,
\ },
\ ale#fixers#pymarkdown#Fix(bufnr(''))
Execute(uv is detected when markdown_pymarkdown_auto_uv is set):
let g:ale_markdown_pymarkdown_auto_uv = 1
call ale#test#SetFilename('../test-files/python/uv/whatever.py')
AssertEqual
\ {
\ 'command': ale#Escape('uv') . ' run pymarkdown fix %t',
\ 'read_temporary_file': 1,
\ },
\ ale#fixers#pymarkdown#Fix(bufnr(''))

View File

@@ -0,0 +1,46 @@
Before:
call ale#assert#SetUpFixerTest('rescript', 'rescript_format')
After:
call ale#assert#TearDownFixerTest()
Execute(The rescript callback should return the correct default values):
call ale#test#SetFilename('../test-files/rescript/testfile-noextension')
set filetype=rescript
GivenCommandOutput ['12.0.0']
AssertFixer
\ {
\ 'command':
\ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .res'
\ }
Execute(The rescript callback should correctly detect res files):
call ale#test#SetFilename('../test-files/rescript/testfile.res')
GivenCommandOutput ['12.0.0']
AssertFixer
\ {
\ 'command':
\ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .res'
\ }
Execute(The rescript callback should correctly detect resi files):
call ale#test#SetFilename('../test-files/rescript/testfile.resi')
GivenCommandOutput ['12.0.0']
AssertFixer
\ {
\ 'command':
\ ale#Escape(g:ale_rescript_format_executable) . ' format --stdin .resi'
\ }
Execute(The version check should be correct):
call ale#test#SetFilename('../test-files/rescript/testfile.res')
GivenCommandOutput ['11.0.0']
AssertFixer
\ {
\ 'command':
\ ale#Escape(g:ale_rescript_format_executable) . ' format -stdin .res'
\ }

View File

@@ -32,3 +32,33 @@ Execute(The Markdownlint handler should parse output with multiple slashes in ru
\ ale#handlers#markdownlint#Handle(0, [ \ ale#handlers#markdownlint#Handle(0, [
\ 'README.md:10 MD022/blanks-around-headings/blanks-around-headers Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Above] [Context: "### something"]' \ 'README.md:10 MD022/blanks-around-headings/blanks-around-headers Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Above] [Context: "### something"]'
\ ]) \ ])
Execute(The Markdownlint handler should parse output with error severity (0.47.0+)):
AssertEqual
\ [
\ {
\ 'lnum': 3,
\ 'col': 1,
\ 'code': 'MD051/link-fragments',
\ 'text': 'Link fragments should be valid [Context: "[Installation](#installation)"]',
\ 'type': 'E'
\ }
\ ],
\ ale#handlers#markdownlint#Handle(0, [
\ 'test.md:3:1 error MD051/link-fragments Link fragments should be valid [Context: "[Installation](#installation)"]'
\ ])
Execute(The Markdownlint handler should parse output with warning severity (0.47.0+)):
AssertEqual
\ [
\ {
\ 'lnum': 3,
\ 'col': 1,
\ 'code': 'MD051/link-fragments',
\ 'text': 'Link fragments should be valid [Context: "[Installation](#installation)"]',
\ 'type': 'W'
\ }
\ ],
\ ale#handlers#markdownlint#Handle(0, [
\ 'test.md:3:1 warning MD051/link-fragments Link fragments should be valid [Context: "[Installation](#installation)"]'
\ ])

View File

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

View File

@@ -25,7 +25,7 @@ Execute(cppcheck for C should detect compile_commands.json files):
\ . ' --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')
\ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path)) \ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path))
\ . ' --enable=style %t' \ . ' --enable=style'
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):
let b:rel_file_path = '../test-files/cppcheck/with_build_dir/foo.c' let b:rel_file_path = '../test-files/cppcheck/with_build_dir/foo.c'
@@ -37,7 +37,7 @@ Execute(cppcheck for C should detect compile_commands.json files in build direct
\ . ' --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'))
\ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path)) \ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path))
\ . ' --enable=style %t' \ . ' --enable=style'
Execute(cppcheck for C should include file dir if compile_commands.json file is not found): Execute(cppcheck for C should include file dir if compile_commands.json file is not found):
call ale#test#SetFilename('../test-files/cppcheck/foo.c') call ale#test#SetFilename('../test-files/cppcheck/foo.c')

View File

@@ -31,7 +31,7 @@ Execute(cppcheck for C++ should detect compile_commands.json files):
\ . ' --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')
\ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path)) \ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path))
\ . ' --enable=style %t' \ . ' --enable=style'
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):
let b:rel_file_path = '../test-files/cppcheck/with_build_dir/foo.cpp' let b:rel_file_path = '../test-files/cppcheck/with_build_dir/foo.cpp'
@@ -43,7 +43,7 @@ Execute(cppcheck for C++ should detect compile_commands.json files in build dire
\ . ' --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'))
\ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path)) \ . ' --file-filter=' . ale#Escape(ale#test#GetFilename(b:rel_file_path))
\ . ' --enable=style %t' \ . ' --enable=style'
Execute(cppcheck for C++ should include file dir if compile_commands.json file is not found): Execute(cppcheck for C++ should include file dir if compile_commands.json file is not found):
call ale#test#SetFilename('../test-files/cppcheck/foo.cpp') call ale#test#SetFilename('../test-files/cppcheck/foo.cpp')

View File

@@ -94,3 +94,25 @@ Execute('go.mod' should be ignored if modules are off):
call delete(b:git_dir, 'd') call delete(b:git_dir, 'd')
unlet! b:parent_dir unlet! b:parent_dir
unlet! b:git_dir unlet! b:git_dir
Execute(Init options should handle empty and non-empty values correctly):
" Regression test for: Invalid settings: invalid options type []interface {}
" This ensures empty init_options {} is passed as an object, not array
call ale#test#SetFilename('../test-files/go/go1/prj1/file.go')
" Test 1: Default empty dict
AssertLSPOptions {}
" Test 2: Explicitly set to empty
let b:ale_go_gopls_init_options = {}
AssertLSPOptions {}
" Test 3: Non-empty options should be preserved
let b:ale_go_gopls_init_options = {
\ 'ui.diagnostic.analyses': {'composites': v:false},
\ 'completeUnimported': v:true
\}
AssertLSPOptions {
\ 'ui.diagnostic.analyses': {'composites': v:false},
\ 'completeUnimported': v:true
\}

View File

@@ -0,0 +1,25 @@
Before:
call ale#assert#SetUpLinterTest('rescript', 'rescript_language_server')
Save &filetype
let &filetype = 'rescript'
After:
call ale#assert#TearDownLinterTest()
Execute(The language string should be correct):
AssertLSPLanguage 'rescript'
Execute(The project root should be detected correctly):
AssertLSPProject ''
call ale#test#SetFilename('../test-files/rescript/testfile.res')
AssertLSPProject ale#path#Simplify(g:dir . '/../test-files/rescript')
Execute(The command should be correct):
call ale#test#SetFilename('../test-files/rescript/testfile.res')
AssertLinter
\ 'rescript-language-server',
\ ale#Escape('rescript-language-server') . ' --stdio'

View File

@@ -0,0 +1,63 @@
Before:
call ale#assert#SetUpLinterTest('rst', 'rstcheck')
After:
call ale#assert#TearDownLinterTest()
Execute(The default command should include --config for rstcheck >= 3.4.0):
GivenCommandOutput ['rstcheck, version 3.4.0']
AssertLinter 'rstcheck', [
\ ale#Escape('rstcheck') . ' --version',
\ ale#Escape('rstcheck')
\ . ' --config '
\ . ale#Escape(expand('#' . bufnr('') . ':p:h'))
\ . ' %t',
\]
Execute(The version check should be cached):
GivenCommandOutput ['rstcheck, version 3.4.0']
AssertLinter 'rstcheck', [
\ ale#Escape('rstcheck') . ' --version',
\ ale#Escape('rstcheck')
\ . ' --config '
\ . ale#Escape(expand('#' . bufnr('') . ':p:h'))
\ . ' %t',
\]
GivenCommandOutput []
AssertLinter 'rstcheck', [
\ ale#Escape('rstcheck')
\ . ' --config '
\ . ale#Escape(expand('#' . bufnr('') . ':p:h'))
\ . ' %t',
\]
Execute(The default command should not include --config for older versions):
call ale#semver#ResetVersionCache()
GivenCommandOutput ['rstcheck, version 3.3.0']
AssertLinter 'rstcheck', [
\ ale#Escape('rstcheck') . ' --version',
\ ale#Escape('rstcheck') . ' %t',
\]
Execute(The command executable and options should be configurable):
call ale#semver#ResetVersionCache()
let b:ale_rst_rstcheck_executable = 'rstcheck2'
let b:ale_rst_rstcheck_options = '--ignore-language=cpp'
GivenCommandOutput ['rstcheck2, version 3.4.0']
AssertLinter 'rstcheck', [
\ ale#Escape('rstcheck2') . ' --version',
\ ale#Escape('rstcheck2')
\ . ' --ignore-language=cpp'
\ . ' --config '
\ . ale#Escape(expand('#' . bufnr('') . ':p:h'))
\ . ' %t',
\]
Execute(The linter should run with the current buffer directory as cwd):
AssertLinterCwd '%s:h'

View File

@@ -15,12 +15,6 @@ Execute(The executable should be configurable):
AssertLinter '/usr/local/bin/superhtml', AssertLinter '/usr/local/bin/superhtml',
\ ale#Escape('/usr/local/bin/superhtml') . ' check --stdin' \ ale#Escape('/usr/local/bin/superhtml') . ' check --stdin'
Execute(The options should be configurable):
let g:ale_html_superhtml_options = '--some-option'
AssertLinter 'superhtml',
\ ale#Escape('superhtml') . ' check --stdin'
Execute(The use_global option should be respected): Execute(The use_global option should be respected):
let g:ale_html_superhtml_executable = 'custom_superhtml' let g:ale_html_superhtml_executable = 'custom_superhtml'
let g:ale_html_superhtml_use_global = 1 let g:ale_html_superhtml_use_global = 1

View File

@@ -0,0 +1,15 @@
Before:
call ale#assert#SetUpLinterTest('text', 'vale')
After:
call ale#assert#TearDownLinterTest()
Execute(The Vale command should include extra options when configured):
let g:ale_vale_executable = 'vale'
let g:ale_vale_options = '--minAlertLevel=warning'
AssertLinter 'vale', ale#Escape('vale') . ' --minAlertLevel=warning --output=JSON %t'
Execute(The Vale command should not include extra options by default):
let g:ale_vale_executable = 'vale'
let g:ale_vale_options = ''
AssertLinter 'vale', ale#Escape('vale') . ' --output=JSON %t'

View File

@@ -54,13 +54,11 @@ describe("ale.get_filename_mappings", function()
eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "a")) eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "a"))
eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "")) eq({{"foo", "bar"}}, ale.get_filename_mappings(42, ""))
eq({{"foo", "bar"}}, ale.get_filename_mappings(42, nil))
buffer_map[42].ale_filename_mappings = {{"abc", "xyz"}} buffer_map[42].ale_filename_mappings = {{"abc", "xyz"}}
eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "a")) eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "a"))
eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "")) eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, ""))
eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, nil))
end) end)
it("should let you use * as a fallback", function() it("should let you use * as a fallback", function()
@@ -72,6 +70,5 @@ describe("ale.get_filename_mappings", function()
eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "a")) eq({{"foo", "bar"}}, ale.get_filename_mappings(42, "a"))
eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "b")) eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "b"))
eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, "")) eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, ""))
eq({{"abc", "xyz"}}, ale.get_filename_mappings(42, nil))
end) end)
end) end)

View File

@@ -0,0 +1,277 @@
local eq = assert.are.same
local lsp = require("ale.lsp")
describe("ale.lsp.send_message", function()
local clients
local version_minor
local get_client_by_id_calls
local vim_fn_calls
setup(function()
_G.vim = {
version = function()
return {minor = version_minor}
end,
lsp = {
get_client_by_id = function(client_id)
table.insert(get_client_by_id_calls, client_id)
return clients[client_id]
end,
},
fn = setmetatable({}, {
__index = function(_, key)
return function(...)
table.insert(vim_fn_calls, {key, ...})
if key ~= "ale#lsp#HandleResponse" then
assert(false, "Invalid ALE function: " .. key)
end
return nil
end
end,
}),
}
end)
teardown(function()
_G.vim = nil
end)
before_each(function()
clients = {}
version_minor = 11
get_client_by_id_calls = {}
vim_fn_calls = {}
end)
it("should return 0 when a client cannot be found", function()
eq(0, lsp.send_message({client_id = 999}))
eq({999}, get_client_by_id_calls)
eq({}, vim_fn_calls)
end)
it("should send notifications for Neovim 0.11+", function()
local notify_calls = {}
clients[1] = {
notify = function(...)
table.insert(notify_calls, {...})
return true
end,
}
eq(-1, lsp.send_message({
client_id = 1,
is_notification = true,
method = "workspace/didChangeConfiguration",
params = {settings = {python = {analysis = true}}},
}))
eq({1}, get_client_by_id_calls)
eq(1, #notify_calls)
assert.is_true(notify_calls[1][1] == clients[1])
eq("workspace/didChangeConfiguration", notify_calls[1][2])
eq({settings = {python = {analysis = true}}}, notify_calls[1][3])
eq({}, vim_fn_calls)
end)
it("should return 0 if a notification fails for Neovim 0.11+", function()
local notify_calls = {}
clients[1] = {
notify = function(...)
table.insert(notify_calls, {...})
return false
end,
}
eq(0, lsp.send_message({
client_id = 1,
is_notification = true,
method = "textDocument/didSave",
params = {textDocument = {uri = "file://foo.py"}},
}))
eq({1}, get_client_by_id_calls)
eq(1, #notify_calls)
assert.is_true(notify_calls[1][1] == clients[1])
eq("textDocument/didSave", notify_calls[1][2])
eq({textDocument = {uri = "file://foo.py"}}, notify_calls[1][3])
eq({}, vim_fn_calls)
end)
it("should send notifications for Neovim 0.10 and below", function()
local notify_calls = {}
version_minor = 10
clients[1] = {
notify = function(...)
table.insert(notify_calls, {...})
return true
end,
}
eq(-1, lsp.send_message({
client_id = 1,
is_notification = true,
method = "textDocument/didSave",
params = {textDocument = {uri = "file://foo.py"}},
}))
eq({1}, get_client_by_id_calls)
eq(1, #notify_calls)
eq("textDocument/didSave", notify_calls[1][1])
eq({textDocument = {uri = "file://foo.py"}}, notify_calls[1][2])
eq({}, vim_fn_calls)
end)
it("should return 0 if a notification fails for Neovim 0.10 and below", function()
local notify_calls = {}
version_minor = 10
clients[1] = {
notify = function(...)
table.insert(notify_calls, {...})
return false
end,
}
eq(0, lsp.send_message({
client_id = 1,
is_notification = true,
method = "textDocument/didSave",
params = {textDocument = {uri = "file://foo.py"}},
}))
eq({1}, get_client_by_id_calls)
eq(1, #notify_calls)
eq("textDocument/didSave", notify_calls[1][1])
eq({textDocument = {uri = "file://foo.py"}}, notify_calls[1][2])
eq({}, vim_fn_calls)
end)
it("should send requests and handle responses for Neovim 0.11+", function()
local request_calls = {}
clients[2] = {
name = "server:/code",
request = function(...)
table.insert(request_calls, {...})
return true, 347
end,
}
eq(347, lsp.send_message({
client_id = 2,
method = "textDocument/hover",
params = {line = 10, character = 5},
}))
eq({2}, get_client_by_id_calls)
eq(1, #request_calls)
assert.is_true(request_calls[1][1] == clients[2])
eq("textDocument/hover", request_calls[1][2])
eq({line = 10, character = 5}, request_calls[1][3])
eq(-1, request_calls[1][5])
eq("function", type(request_calls[1][4]))
request_calls[1][4](nil, {contents = "hello"}, nil, nil)
eq({
{
"ale#lsp#HandleResponse",
"server:/code",
{id = 347, result = {contents = "hello"}},
},
}, vim_fn_calls)
end)
it("should return 0 if a request fails for Neovim 0.11+", function()
local request_calls = {}
clients[2] = {
name = "server:/code",
request = function(...)
table.insert(request_calls, {...})
return false, 347
end,
}
eq(0, lsp.send_message({
client_id = 2,
method = "textDocument/definition",
params = {line = 10, character = 5},
}))
eq({2}, get_client_by_id_calls)
eq(1, #request_calls)
assert.is_true(request_calls[1][1] == clients[2] )
eq("textDocument/definition", request_calls[1][2])
eq({line = 10, character = 5}, request_calls[1][3])
eq(-1, request_calls[1][5])
eq("function", type(request_calls[1][4]))
eq({}, vim_fn_calls)
end)
it("should send requests and handle responses for Neovim 0.10 and below", function()
local request_calls = {}
version_minor = 10
clients[2] = {
name = "server:/code",
request = function(...)
table.insert(request_calls, {...})
return true, 12
end,
}
eq(12, lsp.send_message({
client_id = 2,
method = "textDocument/hover",
params = {line = 10, character = 5},
}))
eq({2}, get_client_by_id_calls)
eq(1, #request_calls)
eq("textDocument/hover", request_calls[1][1])
eq({line = 10, character = 5}, request_calls[1][2])
eq(-1, request_calls[1][4])
eq("function", type(request_calls[1][3]))
request_calls[1][3](nil, {contents = "legacy"}, nil, nil)
eq({
{
"ale#lsp#HandleResponse",
"server:/code",
{id = 12, result = {contents = "legacy"}},
},
}, vim_fn_calls)
end)
it("should return 0 if a request fails for Neovim 0.10 and below", function()
local request_calls = {}
version_minor = 10
clients[2] = {
name = "server:/code",
request = function(...)
table.insert(request_calls, {...})
return false, 12
end,
}
eq(0, lsp.send_message({
client_id = 2,
method = "textDocument/hover",
params = {line = 10, character = 5},
}))
eq({2}, get_client_by_id_calls)
eq(1, #request_calls)
eq("textDocument/hover", request_calls[1][1])
eq({line = 10, character = 5}, request_calls[1][2])
eq(-1, request_calls[1][4])
eq("function", type(request_calls[1][3]))
eq({}, vim_fn_calls)
end)
end)

View File

@@ -13,6 +13,10 @@ describe("ale.lsp.start", function()
defer_fn = function(func, delay) defer_fn = function(func, delay)
table.insert(defer_calls, {func, delay}) table.insert(defer_calls, {func, delay})
end, end,
empty_dict = function()
-- Returns a table with a metatable to distinguish it from arrays
return setmetatable({}, {__empty_dict = true})
end,
fn = setmetatable({}, { fn = setmetatable({}, {
__index = function(_, key) __index = function(_, key)
return function(...) return function(...)
@@ -105,6 +109,50 @@ describe("ale.lsp.start", function()
eq({}, vim_fn_calls) eq({}, vim_fn_calls)
end) end)
it("should convert empty init_options to vim.empty_dict", function()
-- Mock vim.empty_dict
local empty_dict_called = false
_G.vim.empty_dict = function()
empty_dict_called = true
return setmetatable({}, {__empty_dict = true})
end
lsp.start({
name = "gopls:/code",
cmd = "gopls",
root_dir = "/code",
-- Empty table without metatable (like from VimScript {})
init_options = {},
})
-- Verify that empty_dict was called
eq(true, empty_dict_called)
-- Verify init_options has metatable now
eq(1, #start_calls)
local init_opts = start_calls[1][1].init_options
eq(true, getmetatable(init_opts) ~= nil)
end)
it("should preserve non-empty init_options", function()
lsp.start({
name = "gopls:/code",
cmd = "gopls",
root_dir = "/code",
init_options = {foo = "bar", nested = {baz = 123}},
})
-- Remove functions we can't compare
for _, args in pairs(start_calls) do
args[1].handlers = nil
args[1].on_init = nil
args[1].get_language_id = nil
end
eq(1, #start_calls)
eq({foo = "bar", nested = {baz = 123}}, start_calls[1][1].init_options)
end)
it("should start lsp socket connections with the correct arguments", function() it("should start lsp socket connections with the correct arguments", function()
lsp.start({ lsp.start({
name = "localhost:1234:/code", name = "localhost:1234:/code",

View File

@@ -1,17 +0,0 @@
{
"name": "astro-app",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"astro": "^4.8.3",
"@astrojs/check": "^0.7.0",
"typescript": "^5.4.5"
}
}

View File

@@ -1,3 +0,0 @@
{
"extends": "astro/tsconfigs/strict"
}

View File

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