summaryrefslogtreecommitdiff
path: root/ale_linters
diff options
context:
space:
mode:
authorJesse Harris <zigford@gmail.com>2019-04-13 21:24:56 +1000
committerw0rp <w0rp@users.noreply.github.com>2019-04-13 12:24:56 +0100
commit2ed53108c4f000e0a36a79c4317dad4fdfb545fe (patch)
tree85c7e046cab44b4e4a776b215c1378aaeec528a0 /ale_linters
parentd7395906ba0f9aca2fb1a6c32df236bfd4ab32f6 (diff)
downloadale-2ed53108c4f000e0a36a79c4317dad4fdfb545fe.zip
Linter for powershell syntax errors (#2413)
* Linter for powershell syntax errors
Diffstat (limited to 'ale_linters')
-rwxr-xr-xale_linters/powershell/powershell.vim91
-rw-r--r--ale_linters/powershell/psscriptanalyzer.vim37
2 files changed, 95 insertions, 33 deletions
diff --git a/ale_linters/powershell/powershell.vim b/ale_linters/powershell/powershell.vim
new file mode 100755
index 00000000..51ded71d
--- /dev/null
+++ b/ale_linters/powershell/powershell.vim
@@ -0,0 +1,91 @@
+" Author: Jesse Harris - https://github.com/zigford
+" Description: This file adds support for powershell scripts synatax errors
+
+call ale#Set('powershell_powershell_executable', 'pwsh')
+
+function! ale_linters#powershell#powershell#GetExecutable(buffer) abort
+ return ale#Var(a:buffer, 'powershell_powershell_executable')
+endfunction
+
+" Some powershell magic to show syntax errors without executing the script
+" thanks to keith hill:
+" https://rkeithhill.wordpress.com/2007/10/30/powershell-quicktip-preparsing-scripts-to-check-for-syntax-errors/
+function! ale_linters#powershell#powershell#GetCommand(buffer) abort
+ let l:script = ['Param($Script);
+ \ trap {$_;continue} & {
+ \ $Contents = Get-Content -Path $Script;
+ \ $Contents = [string]::Join([Environment]::NewLine, $Contents);
+ \ [void]$ExecutionContext.InvokeCommand.NewScriptBlock($Contents);
+ \ };']
+
+ return ale#powershell#RunPowerShell(
+ \ a:buffer, 'powershell_powershell', l:script)
+endfunction
+
+" Parse powershell error output using regex into a list of dicts
+function! ale_linters#powershell#powershell#Handle(buffer, lines) abort
+ let l:output = []
+ " Our 3 patterns we need to scrape the data for the dicts
+ let l:patterns = [
+ \ '\v^At line:(\d+) char:(\d+)',
+ \ '\v^(At|\+| )@!.*',
+ \ '\vFullyQualifiedErrorId : (\w+)',
+ \]
+
+ let l:matchcount = 0
+
+ for l:match in ale#util#GetMatches(a:lines, l:patterns)
+ " We want to work with 3 matches per syntax error
+ let l:matchcount = l:matchcount + 1
+
+ if l:matchcount == 1 || str2nr(l:match[1])
+ " First match consists of 2 capture groups, and
+ " can capture the line and col
+ if exists('l:item')
+ " We may be here because the last syntax
+ " didn't emit a code, and so only had 2
+ " matches
+ call add(l:output, l:item)
+ let l:matchcount = 1
+ endif
+
+ let l:item = {
+ \ 'lnum': str2nr(l:match[1]),
+ \ 'col': str2nr(l:match[2]),
+ \ 'type': 'E',
+ \}
+ elseif l:matchcount == 2
+ " Second match[0] grabs the full line in order
+ " to handles the text
+ let l:item['text'] = l:match[0]
+ else
+ " Final match handles the code, however
+ " powershell only emits 1 code for all errors
+ " so, we get the final code on the last error
+ " and loop over the previously added items to
+ " append the code we now know
+ call add(l:output, l:item)
+ unlet l:item
+
+ if len(l:match[1]) > 0
+ for l:i in l:output
+ let l:i['code'] = l:match[1]
+ endfor
+ endif
+
+ " Reset the matchcount so we can begin gathering
+ " matches for the next syntax error
+ let l:matchcount = 0
+ endif
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('powershell', {
+\ 'name': 'powershell',
+\ 'executable_callback': 'ale_linters#powershell#powershell#GetExecutable',
+\ 'command_callback': 'ale_linters#powershell#powershell#GetCommand',
+\ 'output_stream': 'stdout',
+\ 'callback': 'ale_linters#powershell#powershell#Handle',
+\})
diff --git a/ale_linters/powershell/psscriptanalyzer.vim b/ale_linters/powershell/psscriptanalyzer.vim
index 8440d771..4794d9d8 100644
--- a/ale_linters/powershell/psscriptanalyzer.vim
+++ b/ale_linters/powershell/psscriptanalyzer.vim
@@ -13,37 +13,6 @@ function! ale_linters#powershell#psscriptanalyzer#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'powershell_psscriptanalyzer_executable')
endfunction
-" Write a powershell script to a temp file for execution
-" return the command used to execute it
-function! s:TemporaryPSScript(buffer, input) abort
- let l:filename = 'script.ps1'
- " Create a temp dir to house our temp .ps1 script
- " a temp dir is needed as powershell needs the .ps1
- " extension
- let l:tempdir = ale#util#Tempname() . (has('win32') ? '\' : '/')
- let l:tempscript = l:tempdir . l:filename
- " Create the temporary directory for the file, unreadable by 'other'
- " users.
- call mkdir(l:tempdir, '', 0750)
- " Automatically delete the directory later.
- call ale#command#ManageDirectory(a:buffer, l:tempdir)
- " Write the script input out to a file.
- call ale#util#Writefile(a:buffer, a:input, l:tempscript)
-
- return l:tempscript
-endfunction
-
-function! ale_linters#powershell#psscriptanalyzer#RunPowerShell(buffer, command) abort
- let l:executable = ale_linters#powershell#psscriptanalyzer#GetExecutable(
- \ a:buffer)
- let l:tempscript = s:TemporaryPSScript(a:buffer, a:command)
-
- return ale#Escape(l:executable)
- \ . ' -Exe Bypass -NoProfile -File '
- \ . ale#Escape(l:tempscript)
- \ . ' %t'
-endfunction
-
" Run Invoke-ScriptAnalyzer and output each linting message as 4 seperate lines
" for each parsing
function! ale_linters#powershell#psscriptanalyzer#GetCommand(buffer) abort
@@ -60,8 +29,10 @@ function! ale_linters#powershell#psscriptanalyzer#GetCommand(buffer) abort
\ $_.Message;
\ $_.RuleName}']
- return ale_linters#powershell#psscriptanalyzer#RunPowerShell(
- \ a:buffer, l:script)
+ return ale#powershell#RunPowerShell(
+ \ a:buffer,
+ \ 'powershell_psscriptanalyzer',
+ \ l:script)
endfunction
" add every 4 lines to an item(Dict) and every item to a list