summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorw0rp <devw0rp@gmail.com>2017-12-20 12:20:38 +0000
committerw0rp <devw0rp@gmail.com>2017-12-20 12:20:38 +0000
commite43e7065da17f45e4cce127a319ceee0a0311883 (patch)
tree2ab29efb8171921872a0b36fab116ea9ce1f1cfb
parent2495744fc31e0041cc4ed6b7b6fdc1b1a15ffb62 (diff)
downloadale-e43e7065da17f45e4cce127a319ceee0a0311883.zip
Fix #1115 - Add support for wrapping all commands with an option
-rw-r--r--autoload/ale/engine.vim2
-rw-r--r--autoload/ale/fix.vim2
-rw-r--r--autoload/ale/job.vim43
-rw-r--r--autoload/ale/linter.vim2
-rw-r--r--doc/ale.txt33
-rw-r--r--plugin/ale.vim3
-rw-r--r--test/fix/test_ale_fix.vader6
-rw-r--r--test/test_prepare_command.vader39
-rw-r--r--test/test_wrap_comand.vader48
9 files changed, 148 insertions, 30 deletions
diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim
index 8441ad16..70b5a3ba 100644
--- a/autoload/ale/engine.vim
+++ b/autoload/ale/engine.vim
@@ -512,7 +512,7 @@ function! s:RunJob(options) abort
endif
endif
- let l:command = ale#job#PrepareCommand(l:command)
+ let l:command = ale#job#PrepareCommand(l:buffer, l:command)
let l:job_options = {
\ 'mode': 'nl',
\ 'exit_cb': function('s:HandleExit'),
diff --git a/autoload/ale/fix.vim b/autoload/ale/fix.vim
index 0a270ecc..62a4f9b1 100644
--- a/autoload/ale/fix.vim
+++ b/autoload/ale/fix.vim
@@ -222,7 +222,7 @@ function! s:RunJob(options) abort
\)
call s:CreateTemporaryFileForJob(l:buffer, l:temporary_file, l:input)
- let l:command = ale#job#PrepareCommand(l:command)
+ let l:command = ale#job#PrepareCommand(l:buffer, l:command)
let l:job_options = {
\ 'mode': 'nl',
\ 'exit_cb': function('s:HandleExit'),
diff --git a/autoload/ale/job.vim b/autoload/ale/job.vim
index e6a75c88..2e0b8ca2 100644
--- a/autoload/ale/job.vim
+++ b/autoload/ale/job.vim
@@ -165,23 +165,54 @@ function! ale#job#ValidateArguments(command, options) abort
endif
endfunction
-function! ale#job#PrepareCommand(command) abort
+function! s:PrepareWrappedCommand(original_wrapper, command) abort
+ let l:match = matchlist(a:command, '\v^(.*(\&\&|;)) *(.*)$')
+ let l:prefix = ''
+ let l:command = a:command
+
+ if !empty(l:match)
+ let l:prefix = l:match[1] . ' '
+ let l:command = l:match[3]
+ endif
+
+ let l:format = a:original_wrapper
+
+ if l:format =~# '%@'
+ let l:wrapped = substitute(l:format, '%@', ale#Escape(l:command), '')
+ else
+ if l:format !~# '%\*'
+ let l:format .= ' %*'
+ endif
+
+ let l:wrapped = substitute(l:format, '%\*', l:command, '')
+ endif
+
+ return l:prefix . l:wrapped
+endfunction
+
+function! ale#job#PrepareCommand(buffer, command) abort
+ let l:wrapper = ale#Var(a:buffer, 'command_wrapper')
+
+ let l:command = !empty(l:wrapper)
+ \ ? s:PrepareWrappedCommand(l:wrapper, a:command)
+ \ : a:command
+
" The command will be executed in a subshell. This fixes a number of
" issues, including reading the PATH variables correctly, %PATHEXT%
" expansion on Windows, etc.
"
" NeoVim handles this issue automatically if the command is a String,
- " but we'll do this explicitly, so we use thes same exact command for both
+ " but we'll do this explicitly, so we use the same exact command for both
" versions.
- if ale#Has('win32')
- return 'cmd /c ' . a:command
+ if has('win32')
+ return 'cmd /c ' . l:command
endif
if &shell =~? 'fish$'
- return ['/bin/sh', '-c', a:command]
+ return ['/bin/sh', '-c', l:command]
endif
- return split(&shell) + split(&shellcmdflag) + [a:command]
+ return split(&shell) + split(&shellcmdflag) + [l:command]
endfunction
" Start a job with options which are agnostic to Vim and NeoVim.
diff --git a/autoload/ale/linter.vim b/autoload/ale/linter.vim
index f4fa0c44..d059a12d 100644
--- a/autoload/ale/linter.vim
+++ b/autoload/ale/linter.vim
@@ -1,3 +1,4 @@
+call ale#Set('wrap_command_as_one_argument', 0)
" Author: w0rp <devw0rp@gmail.com>
" Description: Linter registration and lazy-loading
" Retrieves linters as requested by the engine, loading them if needed.
@@ -432,6 +433,7 @@ function! ale#linter#StartLSP(buffer, linter, callback) abort
endif
let l:command = ale#job#PrepareCommand(
+ \ a:buffer,
\ ale#linter#GetCommand(a:buffer, a:linter),
\)
let l:conn_id = ale#lsp#StartProgram(
diff --git a/doc/ale.txt b/doc/ale.txt
index 7cc6b22a..bec086d1 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -646,6 +646,39 @@ g:ale_change_sign_column_color *g:ale_change_sign_column_color*
windows.
+g:ale_command_wrapper *g:ale_command_wrapper*
+ *b:ale_command_wrapper*
+ Type: |String|
+ Default: `''`
+
+ An option for wrapping all commands that ALE runs, for linters, fixers,
+ and LSP commands. This option can be set globally, or for specific buffers.
+
+ This option can be used to apply nice to all commands. For example: >
+
+ " Prefix all commands with nice.
+ let g:ale_command_wrapper = 'nice -n5'
+<
+ Use the |ALEInfo| command to view the commands that are run. All of the
+ arguments for commands will be put on the end of the wrapped command by
+ default. A `%*` marker can be used to spread the arguments in the wrapped
+ command. >
+
+ " Has the same effect as the above.
+ let g:ale_command_wrapper = 'nice -n5 %*'
+<
+
+ For passing all of the arguments for a command as one argument to a wrapper,
+ `%@` can be used instead. >
+
+ " Will result in say: /bin/bash -c 'other-wrapper -c "some command" -x'
+ let g:ale_command_wrapper = 'other-wrapper -c %@ -x'
+<
+ For commands including `&&` or `;`, only the last command in the list will
+ be passed to the wrapper. `&&` is most commonly used in ALE to change the
+ working directory before running a command.
+
+
g:ale_completion_delay *g:ale_completion_delay*
Type: |Number|
diff --git a/plugin/ale.vim b/plugin/ale.vim
index 2f613b53..d75d33b0 100644
--- a/plugin/ale.vim
+++ b/plugin/ale.vim
@@ -209,6 +209,9 @@ call ale#Set('completion_enabled', 0)
call ale#Set('completion_delay', 100)
call ale#Set('completion_max_suggestions', 50)
+" A setting for wrapping commands.
+call ale#Set('command_wrapper', '')
+
if g:ale_set_balloons
call ale#balloon#Enable()
endif
diff --git a/test/fix/test_ale_fix.vader b/test/fix/test_ale_fix.vader
index fa1101eb..817c243d 100644
--- a/test/fix/test_ale_fix.vader
+++ b/test/fix/test_ale_fix.vader
@@ -581,8 +581,8 @@ Execute(Test fixing with chained callbacks):
" The buffer shouldn't be piped in for earlier commands in the chain.
AssertEqual
\ [
- \ string(ale#job#PrepareCommand('echo echoline')),
- \ string(ale#job#PrepareCommand('echo echoline')),
+ \ string(ale#job#PrepareCommand(bufnr(''), 'echo echoline')),
+ \ string(ale#job#PrepareCommand(bufnr(''), 'echo echoline')),
\ ],
\ map(ale#history#Get(bufnr(''))[-2:-1], 'string(v:val.command)')
@@ -635,7 +635,7 @@ Execute(A temporary file shouldn't be piped into the command when disabled):
ALEFix
AssertEqual
- \ string(ale#job#PrepareCommand('echo new line')),
+ \ string(ale#job#PrepareCommand(bufnr(''), 'echo new line')),
\ string(ale#history#Get(bufnr(''))[-1].command)
" Remove trailing whitespace for Windows.
diff --git a/test/test_prepare_command.vader b/test/test_prepare_command.vader
index ebb9998d..16772e82 100644
--- a/test/test_prepare_command.vader
+++ b/test/test_prepare_command.vader
@@ -4,35 +4,36 @@ Before:
After:
Restore
- let g:ale_has_override = {}
Execute(sh should be used when the shell is fish):
- " Set something else, so we will replace that too.
- let &shellcmdflag = '-f'
- let g:ale_has_override = {'win32': 0}
+ if !has('win32')
+ " Set something else, so we will replace that too.
+ let &shellcmdflag = '-f'
+ let &shell = 'fish'
- let &shell = 'fish'
+ AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar')
- AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand('foobar')
+ let &shell = '/usr/bin/fish'
- let &shell = '/usr/bin/fish'
+ AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar')
- AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand('foobar')
+ let &shell = '/usr/local/bin/fish'
- let &shell = '/usr/local/bin/fish'
-
- AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand('foobar')
+ AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar')
+ endif
Execute(Other shells should be used when set):
- let &shell = '/bin/bash'
- let &shellcmdflag = '-c'
- let g:ale_has_override = {'win32': 0}
+ if !has('win32')
+ let &shell = '/bin/bash'
+ let &shellcmdflag = '-c'
- AssertEqual ['/bin/bash', '-c', 'foobar'], ale#job#PrepareCommand('foobar')
+ AssertEqual ['/bin/bash', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar')
+ endif
Execute(cmd /c as a string should be used on Windows):
- let &shell = 'who cares'
- let &shellcmdflag = 'whatever'
- let g:ale_has_override = {'win32': 1}
+ if has('win32')
+ let &shell = 'who cares'
+ let &shellcmdflag = 'whatever'
- AssertEqual 'cmd /c foobar', ale#job#PrepareCommand('foobar')
+ AssertEqual 'cmd /c foobar', ale#job#PrepareCommand(bufnr(''), 'foobar')
+ endif
diff --git a/test/test_wrap_comand.vader b/test/test_wrap_comand.vader
new file mode 100644
index 00000000..8c1569b1
--- /dev/null
+++ b/test/test_wrap_comand.vader
@@ -0,0 +1,48 @@
+Before:
+ Save g:ale_command_wrapper
+
+ let g:ale_command_wrapper = ''
+
+ function! TestCommand(expected_part, input) abort
+ let l:expected = has('win32')
+ \ ? 'cmd /c ' . a:expected_part
+ \ : split(&shell) + split(&shellcmdflag) + [a:expected_part]
+
+ AssertEqual l:expected, ale#job#PrepareCommand(bufnr(''), a:input)
+ endfunction
+
+After:
+ Restore
+
+ unlet! b:ale_command_wrapper
+
+ delfunction TestCommand
+
+Execute(The command wrapper should work with a nice command):
+ let b:ale_command_wrapper = 'nice -n 5'
+
+ call TestCommand('nice -n 5 foo bar', 'foo bar')
+
+Execute(The command wrapper should work with a nice command with an explicit marker):
+ let b:ale_command_wrapper = 'nice -n 5 %*'
+
+ call TestCommand('nice -n 5 foo bar', 'foo bar')
+
+Execute(Wrappers with spread arguments in the middle should be suppported):
+ let b:ale_command_wrapper = 'wrap %* --'
+
+ call TestCommand('wrap foo bar --', 'foo bar')
+
+Execute(Wrappers with the command as one argument should be supported):
+ let b:ale_command_wrapper = 'wrap -c %@ -x'
+
+ call TestCommand('wrap -c ' . ale#Escape('foo bar') . ' -x', 'foo bar')
+
+Execute(&& and ; should be moved to the front):
+ let b:ale_command_wrapper = 'wrap -c %@ -x'
+
+ call TestCommand('foo && bar; wrap -c ' . ale#Escape('baz') . ' -x', 'foo && bar;baz')
+
+ let b:ale_command_wrapper = 'nice -n 5'
+
+ call TestCommand('foo && bar; nice -n 5 baz -z', 'foo && bar;baz -z')