Vim Quickfix and PowerShell

Enno wrote in with a question on how [Ale](https://github.com/w0rp/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
