1

Motivation: Reduce the feedback loop when writing new code as much as possible.

Currently, I need to do a full bazel build of my project whenever I have made changes. However, often the mistakes I have made when first writing code would be evident just from compiling the current file.

For autocompletion, I build a compile_commands.json file using bazel. If I grep for the current file in that, there is a compile command in there that takes less than a second if I put it in a separate file and chmod +x it. The question is, how can I best integrate this in Vim? I was unable to find any plugins that already do this.

compile_commands.json is generated for an LSP-client plugin; I currently use CoC. So it might be logical to build this as an extension of the LSP client plugin.

I think it wouldn't be logical to set the makeprg, since that is normally used to compile the whole project.

3
  • 1
    I guess you could open the compile_command from its set/expected location, decode it with json_decode(), get the compilation command associated to the current file, and momentarily set &makeprg with this value to run :make. Jan 26, 2021 at 22:40
  • @martin-tournoij why did you remove the plugin tag? I'm asking if there are plugins that do this, and if possible, how to integrate it in some existing LSP plugins. If you know more about what that tag should and shouldn't be used for, could you write that in the tag guidance? Jan 27, 2021 at 7:20
  • 1
    Asking for plugins is explicitly off-topic; the entire "plugin" tag shouldn't even exist. Asking "how do I do X?" is on-topic, and the answer to that may be "use this plugin", but there are often also other possible answers. Jan 27, 2021 at 7:23

1 Answer 1

1

Thanks for the outline, @Luc Hermitte. Here is the result, it works for me:

" Build current file
fu! GetCompileCommand(file)
  let s:cc_db = json_decode(readfile('compile_commands.json'))
  let s:current_file = filter(s:cc_db, 'v:val.file==a:file')
  return s:current_file[0].command
endfunction

fu! Compile(file)
  let &makeprg = GetCompileCommand(a:file)
  silent execute 'make'
  silent execute 'copen'
endfunction

nnoremap <Leader>ic :call Compile(expand('%'))<CR>

This could of course be made more robustly and as a proper plugin. I am assuming here that you are already in the git-root directory, where compile_commands.json is located. (use fugitive's :Gcd if necessary first) Also, there should be a way to directly execute the command into a quickfix buffer, without clobbering the makeprg which someone might want to use. endrant

3
  • One thing to consider would be saving and restoring the makeprg. Or use cexpr or something similar. One problem you’re going to face though is getting errorformat right.
    – D. Ben Knoble
    Jan 30, 2021 at 1:52
  • 1
    @D.BenKnoble Errorformat shouldn't be an issue: I don't see why it shouldn't be the same as the one used on the project. Indeed, the compiler is the same. You're right about makeprg though. It should be saved and restored in a :finally block. Note that doing it right is a little bit complex though because this option could be global or local. Jan 30, 2021 at 2:28
  • 1
    @TamaMcGlinn, a few other improvements are possible: no need for execute as no parameter/string is passed. No need to pollute script scope with variables (local variables are perfect). It'd would also be better for the functions to not be declared in the global namespace, and to be defined with abort. Jan 30, 2021 at 2:32

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.