4

I would like to use vim as a c++ IDE. Is there a possibility to run "make" and see the "make" progression in a separate (newly opened) pane. Also, the consecutive execution of the binary would be nice.

  • If you use tmux your available options grow somewhat. (If you don't use tmux you should check it out....even if you don't use it for the above purposes.) – B Layer Apr 12 at 17:54
  • Try term make , if you need quickfix, execute cgetbuffer from the terminal buffer later. To be honest, I prefer the colored raw make output. The quickfix for make result of c++ looks awful to me. – dedowsdi Apr 13 at 3:25
  • Personally, I found C++ external compilation to be a PITA. Some silly mistake (like forgetting to define stream operators) are quick to generate hundred of useless messages. That's why I found that the best user experience is achieved with integrated compilation -- which could is synchronous (default), or could be make asynchronous (with plugins). Can't we use Christian's plugin to highlight in qf windows the coloured make outputs? – Luc Hermitte Apr 13 at 3:34
5

Yes, Vim has the built in :make command which executes make by default, but you can set up other build systems by setting makeprg. There’s no progress visualisation by default, but once :make is done you can move through errors an earnings encountered with :cnext and :cprev. Calling :copen will show you all of them.

One disadvantage though is that :make is synchronous so your Vim instance will be blocked until compilation finish. There are plugins like Neomake that implement similar functionality using the asynchronous API.

There’s no default way to run your compiled program, but you can define a custom mapping or command to run it after compilation

| improve this answer | |
  • 2
    vim-makejob is another alternative for async :make. – Martin Tournoij Apr 13 at 4:37
  • 2
    A further alternative would be vim-dispatch which provides an async :Make command. I have written an answer describing vim-dispatch for another question which might offer some bits for the OP as well: vi.stackexchange.com/a/22432/1292 – Hotschke Apr 13 at 5:37
  • 1
    Or my build-tools-wrappers that does much more for C++ (e.g. it supports multiple build directories: debug, release, sanatize, whatever...). There are indeed many solutions. – Luc Hermitte Apr 13 at 10:12
2

You can make use of vim terminal in vim 8.0 and later to handle asynchronous jobs.

Thus, to launch make in a vertical split, you can do:

:vertical terminal make

I have a small function (with a command) to do exactly this:

command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand(<q-args>)
function! s:RunShellCommand(cmdline) abort
    exe 'vert terminal '. a:cmdline
endfunction

So you can do :Shell any_command to launch a command in a vertical split (i.e :Shell find /).

For make specifically, I use it in conjunction with those mappings:

nnoremap <leader>csm :Shell make<cr><cr>
nnoremap <leader>csr :Shell make re<cr><cr>
nnoremap <leader>cst :Shell make ex<cr><cr>

ex is a rule in my Makefile that launches my tests.

One caveat is that make rules auto-completion does not work.

| improve this answer | |
1

Throw away make

make is synchronous, that's it, just throw it away.

Async tool

One can use :h :terminal or :h term_start() to do async stuff in vim. We will use term_start here as the basic async tool.

Goal

  • Async make, update quickfix after it, user should see the making progress just like make in terminal.
  • Show make successful message if no error, no warning happens.
  • Show found n qf entries if there exists quickfix entry with specific buffer number and line number.
  • Toggle making buffer if user request make again during making.
  • Spawn new make, delete last making buffer if user request make during idle.

Interface

nnoremap <f7> :Make<cr>
command -nargs=* Make call s:make(<q-args>)

Spawn async job

let s:making = 0

function s:make(args) abort

  if s:making
    if bufwinid(s:make_buf) == -1
      " show making buffer
      exe 'sbuffer' s:make_buf
      wincmd p
    else
      " hide making buffer
      exe printf('%d wincmd q', bufwinnr(s:make_buf))
    endif
    return
  endif

  " delete last result
  if exists('s:make_buf') && bufexists(s:make_buf)
    silent! exe 'bdelete' s:make_buf
  endif

  " spawn new make
  let cmd = 'make'
  if !empty(a:args)
    let cmd .= ' ' . a:args
  endif

  let options = {'close_cb': function('s:make_callback'), 'term_rows': 16}

  let s:make_buf = term_start(cmd, options)
  let s:making = 1

  wincmd p

endfunction

The subtle handler

func s:make_callback(channel)

  " look, you can not get buffer content directly here.
  call timer_start(10, function('s:make_callback_impl'))
endfunction

function s:make_callback_impl(timer) abort

  exe 'cgetbuffer' s:make_buf

  " consider entry with num zero bufnr and lnum an error or warning
  let qfl = filter(getqflist(), {k,v -> v.bufnr != 0 && v.lnum != 0})

  if empty(qfl)
    echo "make successful"
  else
    echohl WarningMsg
    echom printf('found %d qf entries', len(qfl))
    echohl None
  endif

  let s:making = 0

endfunction

Be careful here, one might try to get buffer directly at s:make_callback, that won't work, see this question for detail.

| improve this answer | |
  • 2
    At this point, why not just use Dispatch? – D. Ben Knoble Apr 13 at 14:12
  • @D.BenKnoble It's a small task, I prefer to do it by myself with built in async tool. – dedowsdi Apr 13 at 23:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.