2

I've just got the hang of the wonders of :make and the ability to cycle through the errors. Obviously, I have to do a set makeprg with the settings I need and everything is nice, but the problem is that I don't know how to run.

Basically, the problem is that I got used to something like

:!pushd build && make && popd && ./build/bin/run --args

I want to get the quickfix list populated if there are errors, and if there are not, to be able to run the program in the same command. Is there any way of achieving this? Obviously, the question is for C/C++ projects.

4 Answers 4

2

Assuming you have the makeprg set up correctly:

let &l:makeprg = 'cd build && make'

The &l: syntax for let sets local variables; you can also use setlocal but then you need to use backslashes, which is annoying.

You can make a command or keybind which 1) runs :make or :makel, which either populates or clears the quickfix window or locallist, and 2) runs your program if the quickfix window and locallist are empty.

Personally I like my MM mapping:

nnoremap <silent> MM :silent! :wa<CR>:echo &makeprg<CR>:silent make<CR>:redraw!<CR>

To extend that we can add a new b:run variable which contains a shell command to run. You probably want to set this from an autocmd as the commands are probably different per-project, and then add something like this to the mapping:

:exe get(b:, 'run') isnot 0 && len(getqflist() + getloclist('')) is 0 ? '!' .. b:run : ''<CR>

getqflist() gets the quickfix list, and getloclist('') gets the location list for the current buffer. Only of both are empty and b:run is set do we run the command.

Putting it all together:

augroup run
  au!
  au BufNewFile,BufReadPost /path/to/my/project/*.c
           \ let &l:makeprg = 'cd build && make'
           \ let b:run = './build/bin/run --args'
augroup end

nnoremap <silent> MM :silent! :wa<CR>:echo &makeprg<CR>:silent make<CR>:redraw!<CR>:exe get(b:, 'run') isnot 0 && len(getqflist() + getloclist('')) is 0 ? '!' .. b:run : ''<CR>

That mapping becomes a bit ... much, so you can also put it as a command + mapping, or function + mapping:

command -nargs=* Make
    \  silent! :wa
    \| echo &makeprg
    \| silent make <args>
    \| redraw!
    \| exe get(b:, 'run') isnot 0 && len(getqflist() + getloclist('')) is 0 ? '!' .. b:run : ''

nnoremap <silent> MM :Make<CR>
0
2

At this moment detecting whether the compilation has successfully ended to chain with something else requires scripting.

For more detailed explanations/example, see this SO Q/A: https://stackoverflow.com/questions/56988941/vim-mapping-for-running-c-with-optional-input-file/56991040#56991040

Note: we can trick Vim with :make %< && ./%< which will also send the execution results into the quickfix window. I've never tested it with interactive programs (i.e. that read from stdin/std::cin).

1

You can just add running the program to the Makefile as a target: for example, one named run. Then you just :make run. run has a dependency on the program, to make sure that the program is created or updated before execution:

.PHONY: run
run: $(the_program)
        ./$(the_program) $(run_args)

Arguments can be passed to it via the Makefile variable, e.g.

:make run run_args=...

The quoting there (separate topic) can be tricky if you have arguments with spaces.

If $(the_program) is out-of-date, and the attempt to build it results in errors, then of course the run recipe will not execute.

0

For the sake of completeness, similar to what Kaz outlined before, but even simpler. Simply add a target to your executable with the appropriate requirements:

build/bin/run:  1.cpp
    g++ -Wall $< -o $@ && ./$@

$< refers to the first requirement and $@ points to the target (in this case, build/bin/run).

Now type :make in vim. If there are no errors, the output will be shown in vim's pager. When there are no changes in the dependency graph, make will show you 'build/bin/run' is up to date. and when there are errors, those will populate the quickfix list automatically. You might need to add an appropriate errorformat string (e.g. :set errorformat=%E%f:%l:%c:%m,%-G%.%# for g++) to show one error per line.

For a more ergonomic workflow, you might want to add the following keybinding :nnoremap <silent> <leader>m :w<cr>:make<cr>:cw<cr>, which shows the quickfix window only when there are errors.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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