zigford.org

About | Links | Scripts
Sharing linux/windows scripts and tips

Vim Quickfix and PowerShell

June 02, 2019 — Jesse Harris

Enno wrote in with a question on how Ale set's Vim's makeprg and errorformat options when working with PowerShell.


Under the hood, I'm not sure if Ale uses those Vim features for processing command output. Thus I'm not able to capture what those settings would look like for PowerShell.

However the question did pique my curiosity and I'm interested in what the options would look like if you wanted to parse PowerShell without Ale.

makeprg

Disclaimer

My understanding of many Vim features is limited, so take what you learn here with a grain of salt.

makeprg defaults to the command make. That way you can enter :make and have your current project compiled without leaving Vim. Alongside that, the output is parsed using a string option errorformat.

In order for PowerShell to produce some syntax checking output, you can run a small script over the code and parse it's output. Therefore I embedded the script into the makeprg option like so:

    set makeprg=pwsh\ -command\ \"&{
        \trap{$_.tostring();continue}&{
        \$c=gc\ '%';$c=[string]::join([environment]::newline,$c);
        \[void]$executioncontext.invokecommand.newscriptblock($c)
        \}
    \}\"

This works on win32 and you can see the resulting output by opening the quickfix window with :copen

Unfortunately, on Unix, the most likely default shell will eat the PowerShell $Variables so they must be escaped:

    set makeprg=pwsh\ -command\ \"&{
        \trap{\\$_.tostring\();continue}&{
        \\\$c=gc\ '%';\\$c=[string]::join([environment]::newline,\\$c);
        \[void]\\$executioncontext.invokecommand.newscriptblock(\\$c)
        \}
    \}\"

Now that makeprg is good to go, time to sort out the errorformat.

errorformat

Errorformat uses scanf type parsing (which I had to google) that is a parsing format used by c and other languages.

I spent a couple of hours today working this out by trial-and-error. While Vim's :help errorformat documentation is great, particularly by including so many examples, I didn't take the time to read it thoroughly initially.

Here is the winning formula:

    set errorformat=%EAt\ line:%l\ char:%c,%-C+%.%#,%Z%m,%-G\\s%#

Explanation:

  • %E tells Vim to begin capturing a multi-line message
  • At\ line:%l records the line number where %l is
  • \ char:%c records the column number where %c is
  • %-C+%.%# continues a multi-line message, but removes this line from the message if it contains + followed by .* regex
  • %Z%m tells Vim that this is the last line of a multi-line message and uses the whole line
  • %-G\\s%# tells vim to discard lines that are full whitespace

VimRC

While I'm not sure I'll use this, as I like Ale, I hope it is useful to someone out there, you could put it in your .vimrc like this:

    augroup powershell
        autocmd!
        autocmd BufNewFile,BufRead *.ps1,*.psm1 setlocal FileType=powershell
        autocmd FileType powershell setlocal errorformat=%EAt\ line:%l\ char:%c,
            \%-C+%.%#,
            \%Z%m,
            \%-G\\s%#
        if has('win32')
            autocmd FileType powershell set makeprg=pwsh\ -command\ \"&{
                \trap{$_.tostring();continue}&{
                \$c=gc\ '%';$c=[string]::join([environment]::newline,$c);
                \[void]$executioncontext.invokecommand.newscriptblock($c)
                \}
            \}\"
        else
            autocmd FileType powershell set makeprg=pwsh\ -command\ \"&{
                \trap{\\$_.tostring\();continue}&{
                \\\$c=gc\ '%';\\$c=[string]::join([environment]::newline,\\$c);
                \[void]\\$executioncontext.invokecommand.newscriptblock(\\$c)
                \}
            \}\"
        endif
    augroup END

Tags: powershell, vim