mirror of
https://github.com/dense-analysis/ale.git
synced 2026-01-09 13:02:28 +08:00
Close #2281 - Separate cwd commands from commands
Working directories are now set seperately from the commands so they can later be swapped out when running linters over projects is supported, and also better support filename mapping for running linters on other machines in future.
This commit is contained in:
@@ -23,19 +23,23 @@ function! ale#ant#FindExecutable(buffer) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, build a command to print the classpath of the root
|
||||
" project. Returns an empty string if cannot build the command.
|
||||
" Given a buffer number, get a working directory and command to print the
|
||||
" classpath of the root project.
|
||||
"
|
||||
" Returns an empty string for the command if Ant is not detected.
|
||||
function! ale#ant#BuildClasspathCommand(buffer) abort
|
||||
let l:executable = ale#ant#FindExecutable(a:buffer)
|
||||
let l:project_root = ale#ant#FindProjectRoot(a:buffer)
|
||||
|
||||
if !empty(l:executable) && !empty(l:project_root)
|
||||
return ale#path#CdString(l:project_root)
|
||||
\ . ale#Escape(l:executable)
|
||||
\ . ' classpath'
|
||||
\ . ' -S'
|
||||
\ . ' -q'
|
||||
if !empty(l:executable)
|
||||
let l:project_root = ale#ant#FindProjectRoot(a:buffer)
|
||||
|
||||
if !empty(l:project_root)
|
||||
return [
|
||||
\ l:project_root,
|
||||
\ ale#Escape(l:executable) .' classpath -S -q'
|
||||
\]
|
||||
endif
|
||||
endif
|
||||
|
||||
return ''
|
||||
return ['', '']
|
||||
endfunction
|
||||
|
||||
@@ -52,6 +52,36 @@ function! s:ProcessDeferredCommands(initial_result) abort
|
||||
return l:command
|
||||
endfunction
|
||||
|
||||
function! s:ProcessDeferredCwds(initial_command, initial_cwd) abort
|
||||
let l:result = a:initial_command
|
||||
let l:last_cwd = v:null
|
||||
let l:command_index = 0
|
||||
let l:cwd_list = []
|
||||
|
||||
while ale#command#IsDeferred(l:result)
|
||||
call add(l:cwd_list, l:result.cwd)
|
||||
|
||||
if get(g:, 'ale_run_synchronously_emulate_commands')
|
||||
" Don't run commands, but simulate the results.
|
||||
let l:Callback = g:ale_run_synchronously_callbacks[0]
|
||||
let l:output = get(s:command_output, l:command_index, [])
|
||||
call l:Callback(0, l:output)
|
||||
unlet g:ale_run_synchronously_callbacks
|
||||
|
||||
let l:command_index += 1
|
||||
else
|
||||
" Run the commands in the shell, synchronously.
|
||||
call ale#test#FlushJobs()
|
||||
endif
|
||||
|
||||
let l:result = l:result.value
|
||||
endwhile
|
||||
|
||||
call add(l:cwd_list, a:initial_cwd is v:null ? l:last_cwd : a:initial_cwd)
|
||||
|
||||
return l:cwd_list
|
||||
endfunction
|
||||
|
||||
" Load the currently loaded linter for a test case, and check that the command
|
||||
" matches the given string.
|
||||
function! ale#assert#Linter(expected_executable, expected_command) abort
|
||||
@@ -85,6 +115,38 @@ function! ale#assert#Linter(expected_executable, expected_command) abort
|
||||
\ [l:executable, l:command]
|
||||
endfunction
|
||||
|
||||
function! ale#assert#LinterCwd(expected_cwd) abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:linter = s:GetLinter()
|
||||
|
||||
let l:initial_cwd = ale#linter#GetCwd(l:buffer, l:linter)
|
||||
call ale#command#SetCwd(l:buffer, l:initial_cwd)
|
||||
|
||||
let l:cwd = s:ProcessDeferredCwds(
|
||||
\ ale#linter#GetCommand(l:buffer, l:linter),
|
||||
\ l:initial_cwd,
|
||||
\)
|
||||
|
||||
call ale#command#ResetCwd(l:buffer)
|
||||
|
||||
if type(a:expected_cwd) isnot v:t_list
|
||||
let l:cwd = l:cwd[-1]
|
||||
endif
|
||||
|
||||
AssertEqual a:expected_cwd, l:cwd
|
||||
endfunction
|
||||
|
||||
function! ale#assert#FixerCwd(expected_cwd) abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:cwd = s:ProcessDeferredCwds(s:FixerFunction(l:buffer), v:null)
|
||||
|
||||
if type(a:expected_cwd) isnot v:t_list
|
||||
let l:cwd = l:cwd[-1]
|
||||
endif
|
||||
|
||||
AssertEqual a:expected_cwd, l:cwd
|
||||
endfunction
|
||||
|
||||
function! ale#assert#Fixer(expected_result) abort
|
||||
let l:buffer = bufnr('')
|
||||
let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer))
|
||||
@@ -153,6 +215,7 @@ endfunction
|
||||
|
||||
function! ale#assert#SetUpLinterTestCommands() abort
|
||||
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
|
||||
command! -nargs=+ AssertLinterCwd :call ale#assert#LinterCwd(<args>)
|
||||
command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>)
|
||||
command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
|
||||
command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>)
|
||||
@@ -164,10 +227,35 @@ endfunction
|
||||
|
||||
function! ale#assert#SetUpFixerTestCommands() abort
|
||||
command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput(<args>)
|
||||
command! -nargs=+ AssertFixerCwd :call ale#assert#FixerCwd(<args>)
|
||||
command! -nargs=+ AssertFixer :call ale#assert#Fixer(<args>)
|
||||
command! -nargs=0 AssertFixerNotExecuted :call ale#assert#FixerNotExecuted()
|
||||
endfunction
|
||||
|
||||
function! ale#assert#ResetVariables(filetype, name, ...) abort
|
||||
" If the suffix of the option names format is different, an additional
|
||||
" argument can be used for that instead.
|
||||
if a:0 > 1
|
||||
throw 'Too many arguments'
|
||||
endif
|
||||
|
||||
let l:option_suffix = get(a:000, 0, a:name)
|
||||
let l:prefix = 'ale_' . a:filetype . '_'
|
||||
\ . substitute(l:option_suffix, '-', '_', 'g')
|
||||
let l:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
|
||||
|
||||
" Save and clear linter variables.
|
||||
" We'll load the runtime file to reset them to defaults.
|
||||
for l:key in filter(keys(g:), l:filter_expr)
|
||||
execute 'Save g:' . l:key
|
||||
unlet g:[l:key]
|
||||
endfor
|
||||
|
||||
for l:key in filter(keys(b:), l:filter_expr)
|
||||
unlet b:[l:key]
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" A dummy function for making sure this module is loaded.
|
||||
function! ale#assert#SetUpLinterTest(filetype, name) abort
|
||||
" Set up a marker so ALE doesn't create real random temporary filenames.
|
||||
@@ -177,31 +265,18 @@ function! ale#assert#SetUpLinterTest(filetype, name) abort
|
||||
call ale#linter#Reset()
|
||||
call ale#linter#PreventLoading(a:filetype)
|
||||
|
||||
let l:prefix = 'ale_' . a:filetype . '_' . a:name
|
||||
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
|
||||
|
||||
Save g:ale_lsp_root
|
||||
let g:ale_lsp_root = {}
|
||||
|
||||
Save b:ale_lsp_root
|
||||
unlet! b:ale_lsp_root
|
||||
|
||||
call ale#assert#ResetVariables(a:filetype, a:name)
|
||||
|
||||
Save g:ale_c_build_dir
|
||||
unlet! g:ale_c_build_dir
|
||||
|
||||
" Save and clear linter variables.
|
||||
" We'll load the runtime file to reset them to defaults.
|
||||
for l:key in filter(keys(g:), b:filter_expr)
|
||||
execute 'Save g:' . l:key
|
||||
unlet g:[l:key]
|
||||
endfor
|
||||
|
||||
unlet! b:ale_c_build_dir
|
||||
|
||||
for l:key in filter(keys(b:), b:filter_expr)
|
||||
unlet b:[l:key]
|
||||
endfor
|
||||
|
||||
execute 'runtime ale_linters/' . a:filetype . '/' . a:name . '.vim'
|
||||
|
||||
if !exists('g:dir')
|
||||
@@ -226,6 +301,10 @@ function! ale#assert#TearDownLinterTest() abort
|
||||
delcommand GivenCommandOutput
|
||||
endif
|
||||
|
||||
if exists(':AssertLinterCwd')
|
||||
delcommand AssertLinterCwd
|
||||
endif
|
||||
|
||||
if exists(':AssertLinter')
|
||||
delcommand AssertLinter
|
||||
endif
|
||||
@@ -281,18 +360,7 @@ function! ale#assert#SetUpFixerTest(filetype, name, ...) abort
|
||||
let s:FixerFunction = function(l:function_name)
|
||||
|
||||
let l:option_suffix = get(a:000, 0, a:name)
|
||||
let l:prefix = 'ale_' . a:filetype . '_'
|
||||
\ . substitute(l:option_suffix, '-', '_', 'g')
|
||||
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
|
||||
|
||||
for l:key in filter(keys(g:), b:filter_expr)
|
||||
execute 'Save g:' . l:key
|
||||
unlet g:[l:key]
|
||||
endfor
|
||||
|
||||
for l:key in filter(keys(b:), b:filter_expr)
|
||||
unlet b:[l:key]
|
||||
endfor
|
||||
call ale#assert#ResetVariables(a:filetype, a:name, l:option_suffix)
|
||||
|
||||
execute 'runtime autoload/ale/fixers/' . substitute(a:name, '-', '_', 'g') . '.vim'
|
||||
|
||||
@@ -329,6 +397,10 @@ function! ale#assert#TearDownFixerTest() abort
|
||||
delcommand GivenCommandOutput
|
||||
endif
|
||||
|
||||
if exists(':AssertFixerCwd')
|
||||
delcommand AssertFixerCwd
|
||||
endif
|
||||
|
||||
if exists(':AssertFixer')
|
||||
delcommand AssertFixer
|
||||
endif
|
||||
|
||||
@@ -513,16 +513,18 @@ function! ale#c#GetMakeCommand(buffer) abort
|
||||
if !empty(l:path)
|
||||
let l:always_make = ale#Var(a:buffer, 'c_always_make')
|
||||
|
||||
return ale#path#CdString(fnamemodify(l:path, ':h'))
|
||||
\ . 'make -n' . (l:always_make ? ' --always-make' : '')
|
||||
return [
|
||||
\ fnamemodify(l:path, ':h'),
|
||||
\ 'make -n' . (l:always_make ? ' --always-make' : ''),
|
||||
\]
|
||||
endif
|
||||
endif
|
||||
|
||||
return ''
|
||||
return ['', '']
|
||||
endfunction
|
||||
|
||||
function! ale#c#RunMakeCommand(buffer, Callback) abort
|
||||
let l:command = ale#c#GetMakeCommand(a:buffer)
|
||||
let [l:cwd, l:command] = ale#c#GetMakeCommand(a:buffer)
|
||||
|
||||
if empty(l:command)
|
||||
return a:Callback(a:buffer, [])
|
||||
@@ -532,6 +534,7 @@ function! ale#c#RunMakeCommand(buffer, Callback) abort
|
||||
\ a:buffer,
|
||||
\ l:command,
|
||||
\ {b, output -> a:Callback(a:buffer, output)},
|
||||
\ {'cwd': l:cwd},
|
||||
\)
|
||||
endfunction
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ if !exists('s:buffer_data')
|
||||
let s:buffer_data = {}
|
||||
endif
|
||||
|
||||
" The regular expression used for formatting filenames with modifiers.
|
||||
let s:path_format_regex = '\v\%s(%(:h|:t|:r|:e)*)'
|
||||
|
||||
" Used to get the data in tests.
|
||||
function! ale#command#GetData() abort
|
||||
return deepcopy(s:buffer_data)
|
||||
@@ -26,6 +29,19 @@ function! ale#command#InitData(buffer) abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Set the cwd for commands that are about to run.
|
||||
" Used internally.
|
||||
function! ale#command#SetCwd(buffer, cwd) abort
|
||||
call ale#command#InitData(a:buffer)
|
||||
let s:buffer_data[a:buffer].cwd = a:cwd
|
||||
endfunction
|
||||
|
||||
function! ale#command#ResetCwd(buffer) abort
|
||||
if has_key(s:buffer_data, a:buffer)
|
||||
let s:buffer_data[a:buffer].cwd = v:null
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! ale#command#ManageFile(buffer, file) abort
|
||||
call ale#command#InitData(a:buffer)
|
||||
call add(s:buffer_data[a:buffer].file_list, a:file)
|
||||
@@ -151,6 +167,24 @@ function! s:FormatFilename(filename, mappings, modifiers) abort
|
||||
return ale#Escape(l:filename)
|
||||
endfunction
|
||||
|
||||
" Produce a command prefix to check to a particular directory for a command.
|
||||
" %s format markers with filename-modifiers can be used as the directory, and
|
||||
" will be returned verbatim for formatting in paths relative to files.
|
||||
function! ale#command#CdString(directory) abort
|
||||
let l:match = matchstrpos(a:directory, s:path_format_regex)
|
||||
" Do not escape the directory here if it's a valid format string.
|
||||
" This allows us to use sequences like %s:h, %s:h:h, etc.
|
||||
let l:directory = l:match[1:] == [0, len(a:directory)]
|
||||
\ ? a:directory
|
||||
\ : ale#Escape(a:directory)
|
||||
|
||||
if has('win32')
|
||||
return 'cd /d ' . l:directory . ' && '
|
||||
endif
|
||||
|
||||
return 'cd ' . l:directory . ' && '
|
||||
endfunction
|
||||
|
||||
" Given a command string, replace every...
|
||||
" %s -> with the current filename
|
||||
" %t -> with the name of an unused file in a temporary directory
|
||||
@@ -161,11 +195,16 @@ function! ale#command#FormatCommand(
|
||||
\ command,
|
||||
\ pipe_file_if_needed,
|
||||
\ input,
|
||||
\ cwd,
|
||||
\ mappings,
|
||||
\) abort
|
||||
let l:temporary_file = ''
|
||||
let l:command = a:command
|
||||
|
||||
if !empty(a:cwd)
|
||||
let l:command = ale#command#CdString(a:cwd) . l:command
|
||||
endif
|
||||
|
||||
" First replace all uses of %%, used for literal percent characters,
|
||||
" with an ugly string.
|
||||
let l:command = substitute(l:command, '%%', '<<PERCENTS>>', 'g')
|
||||
@@ -181,7 +220,7 @@ function! ale#command#FormatCommand(
|
||||
let l:filename = fnamemodify(bufname(a:buffer), ':p')
|
||||
let l:command = substitute(
|
||||
\ l:command,
|
||||
\ '\v\%s(%(:h|:t|:r|:e)*)',
|
||||
\ s:path_format_regex,
|
||||
\ '\=s:FormatFilename(l:filename, a:mappings, submatch(1))',
|
||||
\ 'g'
|
||||
\)
|
||||
@@ -279,9 +318,16 @@ function! s:ExitCallback(buffer, line_list, Callback, data) abort
|
||||
let l:result = a:data.result
|
||||
let l:result.value = l:value
|
||||
|
||||
if get(l:result, 'result_callback', v:null) isnot v:null
|
||||
call call(l:result.result_callback, [l:value])
|
||||
endif
|
||||
" Set the default cwd for this buffer in this call stack.
|
||||
call ale#command#SetCwd(a:buffer, l:result.cwd)
|
||||
|
||||
try
|
||||
if get(l:result, 'result_callback', v:null) isnot v:null
|
||||
call call(l:result.result_callback, [l:value])
|
||||
endif
|
||||
finally
|
||||
call ale#command#ResetCwd(a:buffer)
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! ale#command#Run(buffer, command, Callback, ...) abort
|
||||
@@ -293,6 +339,13 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
|
||||
|
||||
let l:output_stream = get(l:options, 'output_stream', 'stdout')
|
||||
let l:line_list = []
|
||||
let l:cwd = get(l:options, 'cwd', v:null)
|
||||
|
||||
if l:cwd is v:null
|
||||
" Default the working directory to whatever it was for the last
|
||||
" command run in the chain.
|
||||
let l:cwd = get(get(s:buffer_data, a:buffer, {}), 'cwd', v:null)
|
||||
endif
|
||||
|
||||
let [l:temporary_file, l:command, l:file_created] = ale#command#FormatCommand(
|
||||
\ a:buffer,
|
||||
@@ -300,6 +353,7 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
|
||||
\ a:command,
|
||||
\ get(l:options, 'read_buffer', 0),
|
||||
\ get(l:options, 'input', v:null),
|
||||
\ l:cwd,
|
||||
\ get(l:options, 'filename_mappings', []),
|
||||
\)
|
||||
let l:command = ale#job#PrepareCommand(a:buffer, l:command)
|
||||
@@ -366,10 +420,14 @@ function! ale#command#Run(buffer, command, Callback, ...) abort
|
||||
" The `_deferred_job_id` is used for both checking the type of object, and
|
||||
" for checking the job ID and status.
|
||||
"
|
||||
" The cwd is kept and used as the default value for the next command in
|
||||
" the chain.
|
||||
"
|
||||
" The original command here is used in tests.
|
||||
let l:result = {
|
||||
\ '_deferred_job_id': l:job_id,
|
||||
\ 'executable': get(l:options, 'executable', ''),
|
||||
\ 'cwd': l:cwd,
|
||||
\ 'command': a:command,
|
||||
\}
|
||||
|
||||
|
||||
@@ -413,6 +413,7 @@ function! s:RunJob(command, options) abort
|
||||
return 0
|
||||
endif
|
||||
|
||||
let l:cwd = a:options.cwd
|
||||
let l:executable = a:options.executable
|
||||
let l:buffer = a:options.buffer
|
||||
let l:linter = a:options.linter
|
||||
@@ -425,6 +426,7 @@ function! s:RunJob(command, options) abort
|
||||
\ 'executable': l:executable,
|
||||
\}])
|
||||
let l:result = ale#command#Run(l:buffer, l:command, l:Callback, {
|
||||
\ 'cwd': l:cwd,
|
||||
\ 'output_stream': l:output_stream,
|
||||
\ 'executable': l:executable,
|
||||
\ 'read_buffer': l:read_buffer,
|
||||
@@ -541,8 +543,22 @@ function! s:RunIfExecutable(buffer, linter, lint_file, executable) abort
|
||||
let l:job_type = a:lint_file ? 'file_linter' : 'linter'
|
||||
call setbufvar(a:buffer, 'ale_job_type', l:job_type)
|
||||
|
||||
" Get the cwd for the linter and set it before we call GetCommand.
|
||||
" This will ensure that ale#command#Run uses it by default.
|
||||
let l:cwd = ale#linter#GetCwd(a:buffer, a:linter)
|
||||
|
||||
if l:cwd isnot v:null
|
||||
call ale#command#SetCwd(a:buffer, l:cwd)
|
||||
endif
|
||||
|
||||
let l:command = ale#linter#GetCommand(a:buffer, a:linter)
|
||||
|
||||
if l:cwd isnot v:null
|
||||
call ale#command#ResetCwd(a:buffer)
|
||||
endif
|
||||
|
||||
let l:options = {
|
||||
\ 'cwd': l:cwd,
|
||||
\ 'executable': a:executable,
|
||||
\ 'buffer': a:buffer,
|
||||
\ 'linter': a:linter,
|
||||
|
||||
@@ -172,6 +172,7 @@ function! s:RunJob(result, options) abort
|
||||
let l:read_temporary_file = get(a:result, 'read_temporary_file', 0)
|
||||
let l:read_buffer = get(a:result, 'read_buffer', 1)
|
||||
let l:output_stream = get(a:result, 'output_stream', 'stdout')
|
||||
let l:cwd = get(a:result, 'cwd', v:null)
|
||||
|
||||
if l:read_temporary_file
|
||||
let l:output_stream = 'none'
|
||||
@@ -190,6 +191,7 @@ function! s:RunJob(result, options) abort
|
||||
\ 'read_buffer': l:read_buffer,
|
||||
\ 'input': l:input,
|
||||
\ 'log_output': 0,
|
||||
\ 'cwd': l:cwd,
|
||||
\ 'filename_mappings': ale#GetFilenameMappings(l:buffer, l:fixer_name),
|
||||
\})
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ function! ale#fixers#autoimport#Fix(buffer) abort
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
|
||||
\ 'cwd': '%s:h',
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' -',
|
||||
\}
|
||||
endfunction
|
||||
|
||||
@@ -17,25 +17,25 @@ function! ale#fixers#black#GetExecutable(buffer) abort
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#black#Fix(buffer) abort
|
||||
let l:cd_string = ale#Var(a:buffer, 'python_black_change_directory')
|
||||
\ ? ale#path#BufferCdString(a:buffer)
|
||||
\ : ''
|
||||
|
||||
let l:executable = ale#fixers#black#GetExecutable(a:buffer)
|
||||
|
||||
let l:exec_args = l:executable =~? 'pipenv$'
|
||||
\ ? ' run black'
|
||||
\ : ''
|
||||
|
||||
let l:options = ale#Var(a:buffer, 'python_black_options')
|
||||
|
||||
if expand('#' . a:buffer . ':e') is? 'pyi'
|
||||
let l:options .= '--pyi'
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': l:cd_string . ale#Escape(l:executable) . l:exec_args
|
||||
let l:result = {
|
||||
\ 'command': ale#Escape(l:executable) . l:exec_args
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' -',
|
||||
\}
|
||||
|
||||
if ale#Var(a:buffer, 'python_black_change_directory')
|
||||
let l:result.cwd = '%s:h'
|
||||
endif
|
||||
|
||||
return l:result
|
||||
endfunction
|
||||
|
||||
@@ -53,8 +53,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
|
||||
" Use --fix-to-stdout with eslint_d
|
||||
if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0])
|
||||
return {
|
||||
\ 'command': ale#handlers#eslint#GetCdString(a:buffer)
|
||||
\ . ale#node#Executable(a:buffer, l:executable)
|
||||
\ 'cwd': ale#handlers#eslint#GetCwd(a:buffer),
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ale#Pad(l:options)
|
||||
\ . ' --stdin-filename %s --stdin --fix-to-stdout',
|
||||
\ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput',
|
||||
@@ -64,8 +64,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
|
||||
" 4.9.0 is the first version with --fix-dry-run
|
||||
if ale#semver#GTE(a:version, [4, 9, 0])
|
||||
return {
|
||||
\ 'command': ale#handlers#eslint#GetCdString(a:buffer)
|
||||
\ . ale#node#Executable(a:buffer, l:executable)
|
||||
\ 'cwd': ale#handlers#eslint#GetCwd(a:buffer),
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ale#Pad(l:options)
|
||||
\ . ' --stdin-filename %s --stdin --fix-dry-run --format=json',
|
||||
\ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput',
|
||||
@@ -73,8 +73,8 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#handlers#eslint#GetCdString(a:buffer)
|
||||
\ . ale#node#Executable(a:buffer, l:executable)
|
||||
\ 'cwd': ale#handlers#eslint#GetCwd(a:buffer),
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ale#Pad(l:options)
|
||||
\ . (!empty(l:config) ? ' -c ' . ale#Escape(l:config) : '')
|
||||
\ . ' --fix %t',
|
||||
|
||||
@@ -17,9 +17,7 @@ endfunction
|
||||
|
||||
function! ale#fixers#isort#Fix(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'python_isort_options')
|
||||
|
||||
let l:executable = ale#fixers#isort#GetExecutable(a:buffer)
|
||||
|
||||
let l:exec_args = l:executable =~? 'pipenv$'
|
||||
\ ? ' run isort'
|
||||
\ : ''
|
||||
@@ -29,8 +27,8 @@ function! ale#fixers#isort#Fix(buffer) abort
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable) . l:exec_args
|
||||
\ 'cwd': '%s:h',
|
||||
\ 'command': ale#Escape(l:executable) . l:exec_args
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '') . ' -',
|
||||
\}
|
||||
endfunction
|
||||
|
||||
@@ -34,19 +34,11 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort
|
||||
return a:output
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#prettier#GetProjectRoot(buffer) abort
|
||||
function! ale#fixers#prettier#GetCwd(buffer) abort
|
||||
let l:config = ale#path#FindNearestFile(a:buffer, '.prettierignore')
|
||||
|
||||
if !empty(l:config)
|
||||
return fnamemodify(l:config, ':h')
|
||||
endif
|
||||
|
||||
" Fall back to the directory of the buffer
|
||||
return fnamemodify(bufname(a:buffer), ':p:h')
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#prettier#CdProjectRoot(buffer) abort
|
||||
return ale#path#CdString(ale#fixers#prettier#GetProjectRoot(a:buffer))
|
||||
return !empty(l:config) ? fnamemodify(l:config, ':h') : '%s:h'
|
||||
endfunction
|
||||
|
||||
function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
|
||||
@@ -103,8 +95,8 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
|
||||
" Special error handling needed for prettier_d
|
||||
if l:executable =~# 'prettier_d$'
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable)
|
||||
\ 'cwd': '%s:h',
|
||||
\ 'command':ale#Escape(l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --stdin-filepath %s --stdin',
|
||||
\ 'process_with': 'ale#fixers#prettier#ProcessPrettierDOutput',
|
||||
@@ -114,8 +106,8 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort
|
||||
" 1.4.0 is the first version with --stdin-filepath
|
||||
if ale#semver#GTE(a:version, [1, 4, 0])
|
||||
return {
|
||||
\ 'command': ale#fixers#prettier#CdProjectRoot(a:buffer)
|
||||
\ . ale#Escape(l:executable)
|
||||
\ 'cwd': ale#fixers#prettier#GetCwd(a:buffer),
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --stdin-filepath %s --stdin',
|
||||
\}
|
||||
|
||||
@@ -37,8 +37,8 @@ function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version) abort
|
||||
" 4.4.0 is the first version with --stdin-filepath
|
||||
if ale#semver#GTE(a:version, [4, 4, 0])
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable)
|
||||
\ 'cwd': '%s:h',
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . l:eslint_config_option
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' --stdin-filepath %s --stdin',
|
||||
|
||||
@@ -17,8 +17,8 @@ function! ale#fixers#stylelint#Fix(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'stylelint_options')
|
||||
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#node#Executable(a:buffer, l:executable)
|
||||
\ 'cwd': '%s:h',
|
||||
\ 'command': ale#node#Executable(a:buffer, l:executable)
|
||||
\ . ' %t'
|
||||
\ . ale#Pad(l:options)
|
||||
\ . ' --fix',
|
||||
|
||||
@@ -7,7 +7,6 @@ call ale#Set('yaml_yamlfix_use_global', get(g:, 'ale_use_global_executables', 0)
|
||||
|
||||
function! ale#fixers#yamlfix#Fix(buffer) abort
|
||||
let l:options = ale#Var(a:buffer, 'yaml_yamlfix_options')
|
||||
|
||||
let l:executable = ale#python#FindExecutable(
|
||||
\ a:buffer,
|
||||
\ 'yaml_yamlfix',
|
||||
@@ -19,7 +18,8 @@ function! ale#fixers#yamlfix#Fix(buffer) abort
|
||||
endif
|
||||
|
||||
return {
|
||||
\ 'command': ale#path#BufferCdString(a:buffer)
|
||||
\ . ale#Escape(l:executable) . (!empty(l:options) ? ' ' . l:options : '') . ' -',
|
||||
\ 'cwd': '%s:h',
|
||||
\ 'command': ale#Escape(l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '') . ' -',
|
||||
\}
|
||||
endfunction
|
||||
|
||||
@@ -50,18 +50,25 @@ function! ale#gradle#FindExecutable(buffer) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, build a command to print the classpath of the root
|
||||
" project. Returns an empty string if cannot build the command.
|
||||
" Given a buffer number, get a working directory and command to print the
|
||||
" classpath of the root project.
|
||||
"
|
||||
" Returns an empty string for the command if Gradle is not detected.
|
||||
function! ale#gradle#BuildClasspathCommand(buffer) abort
|
||||
let l:executable = ale#gradle#FindExecutable(a:buffer)
|
||||
let l:project_root = ale#gradle#FindProjectRoot(a:buffer)
|
||||
|
||||
if !empty(l:executable) && !empty(l:project_root)
|
||||
return ale#path#CdString(l:project_root)
|
||||
\ . ale#Escape(l:executable)
|
||||
\ . ' -I ' . ale#Escape(s:init_path)
|
||||
\ . ' -q printClasspath'
|
||||
if !empty(l:executable)
|
||||
let l:project_root = ale#gradle#FindProjectRoot(a:buffer)
|
||||
|
||||
if !empty(l:project_root)
|
||||
return [
|
||||
\ l:project_root,
|
||||
\ ale#Escape(l:executable)
|
||||
\ . ' -I ' . ale#Escape(s:init_path)
|
||||
\ . ' -q printClasspath'
|
||||
\]
|
||||
endif
|
||||
endif
|
||||
|
||||
return ''
|
||||
return ['', '']
|
||||
endfunction
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
" Description: Handle errors for cppcheck.
|
||||
|
||||
function! ale#handlers#cppcheck#GetCdCommand(buffer) abort
|
||||
function! ale#handlers#cppcheck#GetCwd(buffer) abort
|
||||
let [l:dir, l:json_path] = ale#c#FindCompileCommands(a:buffer)
|
||||
let l:cd_command = !empty(l:dir) ? ale#path#CdString(l:dir) : ''
|
||||
|
||||
return l:cd_command
|
||||
return !empty(l:dir) ? l:dir : ''
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#cppcheck#GetBufferPathIncludeOptions(buffer) abort
|
||||
|
||||
@@ -39,9 +39,8 @@ function! ale#handlers#eslint#GetExecutable(buffer) abort
|
||||
return ale#node#FindExecutable(a:buffer, 'javascript_eslint', s:executables)
|
||||
endfunction
|
||||
|
||||
" Given a buffer, return a command prefix string which changes directory
|
||||
" as necessary for running ESLint.
|
||||
function! ale#handlers#eslint#GetCdString(buffer) abort
|
||||
" Given a buffer, return an appropriate working directory for ESLint.
|
||||
function! ale#handlers#eslint#GetCwd(buffer) abort
|
||||
" ESLint 6 loads plugins/configs/parsers from the project root
|
||||
" By default, the project root is simply the CWD of the running process.
|
||||
" https://github.com/eslint/rfcs/blob/master/designs/2018-simplified-package-loading/README.md
|
||||
@@ -60,7 +59,7 @@ function! ale#handlers#eslint#GetCdString(buffer) abort
|
||||
let l:project_dir = !empty(l:modules_dir) ? fnamemodify(l:modules_dir, ':h:h') : ''
|
||||
endif
|
||||
|
||||
return !empty(l:project_dir) ? ale#path#CdString(l:project_dir) : ''
|
||||
return !empty(l:project_dir) ? l:project_dir : ''
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#eslint#GetCommand(buffer) abort
|
||||
@@ -68,8 +67,7 @@ function! ale#handlers#eslint#GetCommand(buffer) abort
|
||||
|
||||
let l:options = ale#Var(a:buffer, 'javascript_eslint_options')
|
||||
|
||||
return ale#handlers#eslint#GetCdString(a:buffer)
|
||||
\ . ale#node#Executable(a:buffer, l:executable)
|
||||
return ale#node#Executable(a:buffer, l:executable)
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . ' -f json --stdin --stdin-filename %s'
|
||||
endfunction
|
||||
|
||||
@@ -40,21 +40,21 @@ function! ale#handlers#shellcheck#GetDialectArgument(buffer) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#shellcheck#GetCwd(buffer) abort
|
||||
return ale#Var(a:buffer, 'sh_shellcheck_change_directory') ? '%s:h' : ''
|
||||
endfunction
|
||||
|
||||
function! ale#handlers#shellcheck#GetCommand(buffer, version) abort
|
||||
let l:options = ale#Var(a:buffer, 'sh_shellcheck_options')
|
||||
let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions')
|
||||
let l:dialect = ale#Var(a:buffer, 'sh_shellcheck_dialect')
|
||||
let l:external_option = ale#semver#GTE(a:version, [0, 4, 0]) ? ' -x' : ''
|
||||
let l:cd_string = ale#Var(a:buffer, 'sh_shellcheck_change_directory')
|
||||
\ ? ale#path#BufferCdString(a:buffer)
|
||||
\ : ''
|
||||
|
||||
if l:dialect is# 'auto'
|
||||
let l:dialect = ale#handlers#shellcheck#GetDialectArgument(a:buffer)
|
||||
endif
|
||||
|
||||
return l:cd_string
|
||||
\ . '%e'
|
||||
return '%e'
|
||||
\ . (!empty(l:dialect) ? ' -s ' . l:dialect : '')
|
||||
\ . (!empty(l:options) ? ' ' . l:options : '')
|
||||
\ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '')
|
||||
@@ -111,6 +111,7 @@ function! ale#handlers#shellcheck#DefineLinter(filetype) abort
|
||||
call ale#linter#Define(a:filetype, {
|
||||
\ 'name': 'shellcheck',
|
||||
\ 'executable': {buffer -> ale#Var(buffer, 'sh_shellcheck_executable')},
|
||||
\ 'cwd': function('ale#handlers#shellcheck#GetCwd'),
|
||||
\ 'command': {buffer -> ale#semver#RunWithVersionCheck(
|
||||
\ buffer,
|
||||
\ ale#Var(buffer, 'sh_shellcheck_executable'),
|
||||
|
||||
@@ -151,17 +151,30 @@ function! ale#linter#PreProcess(filetype, linter) abort
|
||||
endif
|
||||
|
||||
let l:obj.address = a:linter.address
|
||||
|
||||
if has_key(a:linter, 'cwd')
|
||||
throw '`cwd` makes no sense for socket LSP connections'
|
||||
endif
|
||||
else
|
||||
throw '`address` must be defined for getting the LSP address'
|
||||
endif
|
||||
|
||||
if has_key(a:linter, 'cwd')
|
||||
let l:obj.cwd = a:linter.cwd
|
||||
|
||||
if type(l:obj.cwd) isnot v:t_string
|
||||
\&& type(l:obj.cwd) isnot v:t_func
|
||||
throw '`cwd` must be a String or Function if defined'
|
||||
endif
|
||||
endif
|
||||
|
||||
if l:needs_lsp_details
|
||||
" Default to using the filetype as the language.
|
||||
let l:obj.language = get(a:linter, 'language', a:filetype)
|
||||
|
||||
if type(l:obj.language) isnot v:t_string
|
||||
\&& type(l:obj.language) isnot v:t_func
|
||||
throw '`language` must be a String or Funcref if defined'
|
||||
throw '`language` must be a String or Function if defined'
|
||||
endif
|
||||
|
||||
if has_key(a:linter, 'project_root')
|
||||
@@ -415,6 +428,12 @@ function! ale#linter#GetExecutable(buffer, linter) abort
|
||||
\ : l:Executable
|
||||
endfunction
|
||||
|
||||
function! ale#linter#GetCwd(buffer, linter) abort
|
||||
let l:Cwd = get(a:linter, 'cwd', v:null)
|
||||
|
||||
return type(l:Cwd) is v:t_func ? l:Cwd(a:buffer) : l:Cwd
|
||||
endfunction
|
||||
|
||||
" Given a buffer and linter, get the command String for the linter.
|
||||
function! ale#linter#GetCommand(buffer, linter) abort
|
||||
let l:Command = a:linter.command
|
||||
|
||||
@@ -290,6 +290,7 @@ function! s:StartLSP(options, address, executable, command) abort
|
||||
\ a:command,
|
||||
\ 0,
|
||||
\ v:false,
|
||||
\ v:null,
|
||||
\ [],
|
||||
\)[1]
|
||||
let l:command = ale#job#PrepareCommand(l:buffer, l:command)
|
||||
|
||||
@@ -17,7 +17,6 @@ function! ale#maven#FindProjectRoot(buffer) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
|
||||
" Given a buffer number, find the path to the executable.
|
||||
" First search on the path for 'mvnw' (mvnw.cmd on Windows), if nothing is found,
|
||||
" try the global command. Returns an empty string if cannot find the executable.
|
||||
@@ -36,16 +35,23 @@ function! ale#maven#FindExecutable(buffer) abort
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
" Given a buffer number, build a command to print the classpath of the root
|
||||
" project. Returns an empty string if cannot build the command.
|
||||
" Given a buffer number, get a working directory and command to print the
|
||||
" classpath of the root project.
|
||||
"
|
||||
" Returns an empty string for the command if Maven is not detected.
|
||||
function! ale#maven#BuildClasspathCommand(buffer) abort
|
||||
let l:executable = ale#maven#FindExecutable(a:buffer)
|
||||
let l:project_root = ale#maven#FindProjectRoot(a:buffer)
|
||||
|
||||
if !empty(l:executable) && !empty(l:project_root)
|
||||
return ale#path#CdString(l:project_root)
|
||||
\ . l:executable . ' dependency:build-classpath'
|
||||
if !empty(l:executable)
|
||||
let l:project_root = ale#maven#FindProjectRoot(a:buffer)
|
||||
|
||||
if !empty(l:project_root)
|
||||
return [
|
||||
\ l:project_root,
|
||||
\ ale#Escape(l:executable) . ' dependency:build-classpath'
|
||||
\]
|
||||
endif
|
||||
endif
|
||||
|
||||
return ''
|
||||
return ['', '']
|
||||
endfunction
|
||||
|
||||
@@ -77,26 +77,6 @@ function! ale#path#ResolveLocalPath(buffer, search_string, global_fallback) abor
|
||||
return l:path
|
||||
endfunction
|
||||
|
||||
" Output 'cd <directory> && '
|
||||
" This function can be used changing the directory for a linter command.
|
||||
function! ale#path#CdString(directory) abort
|
||||
if has('win32')
|
||||
return 'cd /d ' . ale#Escape(a:directory) . ' && '
|
||||
endif
|
||||
|
||||
return 'cd ' . ale#Escape(a:directory) . ' && '
|
||||
endfunction
|
||||
|
||||
" Output 'cd <buffer_filename_directory> && '
|
||||
" This function can be used changing the directory for a linter command.
|
||||
function! ale#path#BufferCdString(buffer) abort
|
||||
if has('win32')
|
||||
return 'cd /d %s:h && '
|
||||
endif
|
||||
|
||||
return 'cd %s:h && '
|
||||
endfunction
|
||||
|
||||
" Return 1 if a path is an absolute path.
|
||||
function! ale#path#IsAbsolute(filename) abort
|
||||
if has('win32') && a:filename[:0] is# '\'
|
||||
|
||||
Reference in New Issue
Block a user