It sounds like you would benefit from a custom quickfix window. I too tried many different ways to use the built-in make command, and while it's a great feature, it can't do everything. It really isn't customizable like a normal window is, or even the preview window. I found the preview window far more effective at displaying output (though my solution doesn't have colored output). If the preview window doesn't give you the output you want, you could try just using a normal split pane.
The following code assumes the output file (in C at least) is a *.cmp
file in a directory like C:\TEMP
or some other directory indicated by your $TMP
environment variable.
Now you can just call CompileModule in your autocommand. The provided code also maps double-click to the double click handler so that double-clicking in this custom window takes you to the exact file, line, and column where the compiler choked. I realize the quickfix window does this automatically for you, but as stated earlier, it is very difficult to customize.
let s:vimdbg_file = $VIMRUNTIME . "\\vimdebug.out"
let s:show_err_type = 0 " set to 1 to include error indicator in output
let s:output_window_height = 12 " maximum size of output window, uses less space if there is less output
map <silent> <2-LeftMouse> :call HandleDoubleLeftClick()<CR>
function! CompileModule()
if expand('%:t') == 'vimdebug.out' | exe "wincmd k" | endif
" adjust compile below to your actual command line build tool
" (this executes a shell command to change to the directory of the current file and then build)
exe "silent !( cd %:p:h ; compile %:r )"
let s:last_built = tolower(expand('%:t'))
call ShowOutFile()
endf
function! ShowOutFile()
let tmp_dir = $TMPDIR
if tmp_dir == ""
let tmp_dir = $TEMP
endif
if tmp_dir == ""
let tmp_dir = $TMP
endif
let outfile = tmp_dir . '/' . expand( '%:t:r' ) . '.cmp'
if getfsize( outfile ) == 0 || !filereadable( outfile )
let outfile = expand( '%:r' ) . '.out'
" stash this in msg history and hide so it's not disruptive
echom ".cmp not found, using .out"
redraw
endif
if getfsize( outfile ) > 0 && filereadable( outfile )
let outbuff = readfile( outfile )
let dispbuff = []
let index = 0
let num_errors = 0
for errline in outbuff
if match( errline, ' error \| warning\|informational\|severe' ) >= 0
if match( errline, ' error ' ) >= 0
let num_errors += 1
endif
let index = stridx( errline, "(" )
let index2 = stridx( errline, ")", index )
let index3 = stridx( errline, ":", index2 )
let index4 = stridx( errline, ":", index3 + 1 )
" get the entire filename
let search_idx = index
while ( errline[search_idx] != '\' && errline[search_idx] != '/' && search_idx >= 0 )
let search_idx -= 1
endw
" if filename is different, include it in output
if ( ( tolower(expand('%:t')) == strpart( errline, search_idx + 1, index - (search_idx + 1) ) ) || ( s:always_include_filename == 1 ) )
let startidx = index
let startlen = (index2 + 1) - index
else
let startidx = search_idx + 1
let startlen = index2 - search_idx
endif
" include error type indicator in output
if s:show_err_type == 1
if match( errline, 'error' ) >= 0
let c_err_ind = " E"
elseif match( errline, 'warning' ) >= 0
let c_err_ind = " W"
elseif match( errline, 'informational' ) >= 0
let c_err_ind = " I"
else
let c_err_ind = " "
endif
else
let c_err_ind = " "
endif
let startline = strpart( errline, startidx, startlen )
let endline = strpart( errline, index4 )
if c_err_ind == " "
call add( dispbuff, startline . endline )
else
call add( dispbuff, startline . c_err_ind . endline )
endif
endif
endfor
if dispbuff == [] || len(dispbuff) == 0
redraw " Erase any existing messages - gets rid of ENTER prompt
echom expand('%:t') . ' compiled successfully!'
" Close preview window if it's open
try
sil exe "pc"
catch /^Vim(\a\+):E441:/
endtry
return
else
redraw " Erase any existing messages - gets rid of ENTER prompt
if num_errors > 0
echohl ErrorMsg
echom num_errors . ' compile errors found!'
echohl Normal
else
echohl WarningMsg
echom 'Compile successful, see warnings...'
echohl Normal
endif
endif
" Write to a special output file
call writefile( dispbuff, s:vimdbg_file )
" Load (or re-load) the output file
sil exe "ped " . s:vimdbg_file
" Move preview window to the bottom
try
exe "wincmd P"
exe "wincmd J"
catch /^Vim(\a\+):E441:/ " no preview window open
endtry
" Determine size of output (preview) window
set previewheight=1
let i = 1
let owh = s:output_window_height
let ph = ( owh < len(dispbuff) ) ? owh : len(dispbuff)
while i < ph
set previewheight+=1
let i += 1
endw
" Resize window
try
exe "wincmd P"
catch /^Vim(\a\+):E441:/
endtry
exe "res " ph
else
redraw " Erase any existing messages - gets rid of ENTER prompt
echohl WarningMsg
" (no way to tell a difference between the two)
echom "Build successful (or output file not found)."
echohl Normal
" Close preview window if it's open
try
sil exe "pc"
catch /^Vim(\a\+):E441:/
endtry
endif
endf
function! HandleDoubleLeftClick()
let err_line = 0
let err_col = 0
if expand('%:t') == "vimdebug.out"
let curr_line = getline('.')
let index1 = stridx( curr_line, '(' )
let index2 = stridx( curr_line, ':', index1 )
let index1 += 1
let int1len = index2 - index1
let index3 = stridx( curr_line, ')', index2 )
let index2 += 1
let int2len = index3 - index2
let err_line = str2nr( strpart( curr_line, index1, int1len ) )
let err_col = str2nr( strpart( curr_line, index2, int2len ) )
" if there are characters in front of the first '(' then
" we have a filename to parse first
if index1 > 1
let buf_name = strpart( curr_line, 0, index1 - 1 )
else
if exists( s:last_built )
let buf_name = s:last_built
else
" set buf_name to buffer name of other file (upper window?)
wincmd k
let buf_name = tolower(expand('%:t'))
endif
endif
redraw
" switches to the appropriate file if open; if not, opens it
exe "dr " . buf_name
" now go to the located line and column
exe "normal " . err_line . "G"
exe "normal 0"
if err_col > 1
exe "normal " . (err_col - 1) . "l"
endif
redraw
else
" put code here to do whatever you'd like double click to normally do
endif
endf