summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorw0rp <devw0rp@gmail.com>2016-09-15 20:20:41 +0100
committerw0rp <devw0rp@gmail.com>2016-09-15 20:20:41 +0100
commit8cc28cdfbd34dd76bd1cd392747c266be7833494 (patch)
treec136f8753293246f8d837607268250eab41c8820
parentd3047c9cf643cb80418b394c6cf16bc9dcec916d (diff)
downloadale-8cc28cdfbd34dd76bd1cd392747c266be7833494.zip
Add support for Bash and other shells. Add support for reading from stderr, and for generating the executable from functions. Both were needed to support shell linting.
-rw-r--r--README.md2
-rw-r--r--ale_linters/javascript/eslint.vim1
-rw-r--r--ale_linters/python/flake8.vim1
-rw-r--r--ale_linters/sh/shell.vim75
-rw-r--r--plugin/ale/zmain.vim68
5 files changed, 133 insertions, 14 deletions
diff --git a/README.md b/README.md
index f85ae38b..af452c63 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,8 @@ follow later.
| Language | Tools |
| -------- | ----- |
+| Bash | -n flag |
+| Bourne Shell | -n flag |
| JavaScript | [eslint](http://eslint.org/) |
| Python | [flake8](http://flake8.pycqa.org/en/latest/) |
diff --git a/ale_linters/javascript/eslint.vim b/ale_linters/javascript/eslint.vim
index 96dfef9b..43e32c9b 100644
--- a/ale_linters/javascript/eslint.vim
+++ b/ale_linters/javascript/eslint.vim
@@ -43,6 +43,7 @@ function! ale_linters#javascript#eslint#Handle(buffer, lines)
endfunction
call ALEAddLinter('javascript', {
+\ 'name': 'eslint',
\ 'executable': 'eslint',
\ 'command': 'eslint -f unix --stdin',
\ 'callback': 'ale_linters#javascript#eslint#Handle',
diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim
index 437bc01d..19dfc22e 100644
--- a/ale_linters/python/flake8.vim
+++ b/ale_linters/python/flake8.vim
@@ -45,6 +45,7 @@ function! ale_linters#python#flake8#Handle(buffer, lines)
endfunction
call ALEAddLinter('python', {
+\ 'name': 'flake8',
\ 'executable': 'flake8',
\ 'command': 'flake8 -',
\ 'callback': 'ale_linters#python#flake8#Handle',
diff --git a/ale_linters/sh/shell.vim b/ale_linters/sh/shell.vim
new file mode 100644
index 00000000..6c93933a
--- /dev/null
+++ b/ale_linters/sh/shell.vim
@@ -0,0 +1,75 @@
+if exists('g:loaded_ale_linters_sh_shell')
+ finish
+endif
+
+let g:loaded_ale_linters_sh_shell = 1
+
+" This option can be changed to change the default shell when the shell
+" cannot be taken from the hashbang line.
+if !exists('g:ale_linters_sh_shell_default_shell')
+ let g:ale_linters_sh_shell_default_shell = 'bash'
+endif
+
+function! ale_linters#sh#shell#GetExecutable(buffer)
+ let shell = g:ale_linters_sh_shell_default_shell
+
+ let banglines = getbufline(a:buffer, 1)
+
+ " Take the shell executable from the hashbang, if we can.
+ if len(banglines) == 1
+ let bangmatch = matchlist(banglines[0], '^#!\([^ ]\+\)')
+
+ if len(bangmatch) > 0
+ let shell = bangmatch[1]
+ endif
+ endif
+
+ return shell
+endfunction
+
+function! ale_linters#sh#shell#GetCommand(buffer)
+ return ale_linters#sh#shell#GetExecutable(a:buffer) . ' -n'
+endfunction
+
+function! ale_linters#sh#shell#Handle(buffer, lines)
+ " Matches patterns line the following:
+ "
+ " bash: line 13: syntax error near unexpected token `d'
+ " sh: 11: Syntax error: "(" unexpected
+ let pattern = '^[^:]\+: \%(line \|\)\(\d\+\): \(.\+\)'
+ let output = []
+
+ for line in a:lines
+ let l:match = matchlist(line, pattern)
+
+ if len(l:match) == 0
+ continue
+ endif
+
+ let line = l:match[1] + 0
+ let column = 1
+ let text = l:match[2]
+ let type = 'E'
+
+ " vcol is Needed to indicate that the column is a character.
+ call add(output, {
+ \ 'bufnr': a:buffer,
+ \ 'lnum': line,
+ \ 'vcol': 0,
+ \ 'col': column,
+ \ 'text': text,
+ \ 'type': type,
+ \ 'nr': -1,
+ \})
+ endfor
+
+ return output
+endfunction
+
+call ALEAddLinter('sh', {
+\ 'name': 'shell',
+\ 'output_stream': 'stderr',
+\ 'executable_callback': 'ale_linters#sh#shell#GetExecutable',
+\ 'command_callback': 'ale_linters#sh#shell#GetCommand',
+\ 'callback': 'ale_linters#sh#shell#Handle',
+\})
diff --git a/plugin/ale/zmain.vim b/plugin/ale/zmain.vim
index 548ae290..5547f695 100644
--- a/plugin/ale/zmain.vim
+++ b/plugin/ale/zmain.vim
@@ -141,20 +141,36 @@ function! s:ApplyLinter(buffer, linter)
endif
if has('nvim')
- let a:linter.job = jobstart(command, {
- \ 'on_stdout': 's:GatherOutputNeoVim',
- \ 'on_exit': 's:HandleExitNeoVim',
- \})
+ if a:linter.output_stream ==# 'stderr'
+ " Read from stderr instead of stdout.
+ let a:linter.job = jobstart(command, {
+ \ 'on_stderr': 's:GatherOutputNeoVim',
+ \ 'on_exit': 's:HandleExitNeoVim',
+ \})
+ else
+ let a:linter.job = jobstart(command, {
+ \ 'on_stdout': 's:GatherOutputNeoVim',
+ \ 'on_exit': 's:HandleExitNeoVim',
+ \})
+ endif
else
- " Vim 8 will read the stdin from the file's buffer.
- let a:linter.job = job_start(command, {
+ let job_options = {
\ 'out_mode': 'nl',
\ 'err_mode': 'nl',
- \ 'out_cb': function('s:GatherOutputVim'),
\ 'close_cb': function('s:HandleExitVim'),
\ 'in_io': 'buffer',
\ 'in_buf': a:buffer,
- \})
+ \}
+
+ if a:linter.output_stream ==# 'stderr'
+ " Read from stderr instead of stdout.
+ let job_options.err_cb = function('s:GatherOutputVim')
+ else
+ let job_options.out_cb = function('s:GatherOutputVim')
+ endif
+
+ " Vim 8 will read the stdin from the file's buffer.
+ let a:linter.job = job_start(l:command, l:job_options)
call ch_close_in(job_getchannel(a:linter.job))
endif
@@ -182,6 +198,18 @@ function! s:TimerHandler(...)
let g:ale_buffer_should_reset_map[buffer] = 1
for linter in linters
+ " Check if a given linter has a program which can be executed.
+ if has_key(linter, 'executable_callback')
+ let l:executable = s:GetFunction(linter.executable_callback)(buffer)
+ else
+ let l:executable = linter.executable
+ endif
+
+ if !executable(l:executable)
+ " The linter's program cannot be executed, so skip it.
+ continue
+ endif
+
call s:ApplyLinter(buffer, linter)
endfor
endfunction
@@ -197,16 +225,20 @@ function s:BufferCleanup(buffer)
endfunction
function! ALEAddLinter(filetype, linter)
- " Check if the linter program is executable before adding it.
- if !executable(a:linter.executable)
- return
- endif
-
if !has_key(s:linters, a:filetype)
let s:linters[a:filetype] = []
endif
- let new_linter = {'callback': a:linter.callback}
+ let new_linter = {
+ \ 'name': a:linter.name,
+ \ 'callback': a:linter.callback,
+ \}
+
+ if has_key(a:linter, 'executable_callback')
+ let new_linter.executable_callback = a:linter.executable_callback
+ else
+ let new_linter.executable = a:linter.executable
+ endif
if has_key(a:linter, 'command_callback')
let new_linter.command_callback = a:linter.command_callback
@@ -214,6 +246,14 @@ function! ALEAddLinter(filetype, linter)
let new_linter.command = a:linter.command
endif
+ if has_key(a:linter, 'output_stream')
+ let new_linter.output_stream = a:linter.output_stream
+ else
+ let new_linter.output_stream = 'stdout'
+ endif
+
+ " TODO: Assert the value of the output_stream to be something sensible.
+
call add(s:linters[a:filetype], new_linter)
endfunction