building from vim with fish

make, makeprg, pipes, and more

I've recently started following Casey Muratori's excellent Handmade Hero series using OSX instead of Windows and Vim instead of Emacs. To further complicate matters, I recently started using the friendly interactive shell (fish). The following documents the additions I used to make compilation work from Vim with fish.

Casey advocates using a batch file to build a project instead of a build system such as make. Vim by default uses make as defined in the makeprg variable. This can be confirmed by typing :echo &makeprg, which should report make. Adding the following function and mapping to ~/.vimrc will map ;m on OSX to searching the current file's directory and up to 9 parent directories for, execute it, and display any errors in a "quickfix" window:

" Executes filename in the current directory if found or " recursively searches up to 10 parent directories. " Based on function! ExecBuildScript(filename) let buildFile = a:filename let buildPath = expand("%:p:h") . "/" let depth = 0 while depth < 10 if filereadable(buildPath . buildFile) let &makeprg = "\"" . buildPath . buildFile . "\"" make cwindow echo "Executed " . buildFile return 0 endif let depth += 1 let buildPath = buildPath . "../" endwhile echo "Missing " . buildFile endfunction if has('macunix') nmap <silent> ;m :call ExecBuildScript('')<CR> endif

This code was modified from the original to start searching from the current file's location instead of wherever Vim was started and to accept arbitrary filenames as an argument, which I plan to use for compiling on different platforms.

We need one more change for this to work in fish. By default, Vim only reads standard out when opening quickfix windows unless the shell is sh, ksh, mksh, pdksh, zsh, or bash, in which case it changes the shellpipe option to 2>&1| tee. We need to manually make this change for fish by adding the following to .vimrc:

let &shellpipe="2>&1| tee"

The ;m command should now work. We can make things a bit nicer by automatically closing the quickfix window if it's the last one open with the following function and autocommand from the Vim wiki:

" Automatically quit the last window if it's a quickfix " window. " function! CloseQuickfix() if &buftype=="quickfix" if winnr('$') < 2 quit! endif endif endfunction au BufEnter * call CloseQuickfix()