3

I have been using Vim for about 2 years on my personal C++ project on Ubuntu with great success. I build using g++ and make, as my build system. In vim, I can build the project without problem using :make. My personal project has about 200 files.

In my job, the project I'm working on has 7 millions C++ files (over 35k files) and has been, from day one, a project build for Microsoft Windows, using Visual Studio. I have installed vim at my job, trying to use it to code. So far, I have not been able to "integrate" it successfully to my workflow for two main reasons:

  1. Finding files is ridiculously slow: on my personal project, using :find is instantaneous. I can use wildcard without problems, I get nice fuzzy file search right out of the box. For finding expressions, I can use grep or vimgrep and results come out fast. On my job's code base, finding a file or an expression can take from couple seconds to 30+ seconds. We have "a lot" of nested directories.

  2. I'm unable to make :make work appropriately: I have tried using makeprg and denvenv and msbuild (see here for example), with no success. Building a single file (as Ctrl+F7 does within Visual Studio) would suffice, but I can't seem to make it work.

If I could make work both 1. and 2., I would be satisfied. I could do about 90% of my editing/compiling from vim. Is there a way to achieve this?


Notes:

  • I have used VsVim for some time. It is not so bad (in fact it's pretty great) but is not enough for me. Some options are missing (the vim help, for instance).
  • We work on Windows 10/11 and use Visual Studio 2022.
  • For the 2. I have tried a lot of things. The last thing I tried is this:
    au FileType cpp set makeprg=devenv\ MySolution.sln\ /build\ "Debug|x64"
    au FileType cpp set errorformat=\ %#%f(%l)\ :\ %#%t%[A-z]%#\ %m
    
    The command works in the terminal (it builds the solution and I see the output). From vim. When I type :make nothing seems to happen and I get the following output in the terminal:
    C:\WINDOWS\system32\cmd.exe /c (devenv MySolution.sln /build   ^>C:\Users\johndoe\AppData\Local\Temp\VIe1D01.tmp 2^>^&1)
    
    Then vim "hangs" and if I go check the specified tmp file, I see the build output. In my personal project, I see the build output directly in Vim.
12
  • 2
    Regarding problem #1, could you show us the relevant part of your config AND a reasonably realist minimal reproducible example? Regarding problem #2, could you show us what you tried? Do devenv and/or msbuild work for you outside of Vim?
    – romainl
    May 8 at 6:55
  • 1
    Please include :setlocal path? for a file from which :find is slow; it wasn't designed to be used for fuzzy-finding, so if you have lots of files and path=**/*, it can be slow.
    – D. Ben Knoble
    May 8 at 14:47
  • 1
    May I ask why :make doesn't work? Are you getting an error message? What happens if you exeucte it?
    – TornaxO7
    May 8 at 15:56
  • 1
    Do you have still something open in your question? How can we help you further? Otherwise maybe could you accept one of the solution using the v button next to the arrow voting buttons. It allow the question to rest :-) May 9 at 7:15
  • 1
    Reading the question again, it might have been a better idea to split it into two questions. One for each problem.
    – Friedrich
    May 9 at 7:38

4 Answers 4

3

Not really the answer you are looking for but I thought I'd share it in case anyone finds it useful. Whenever I have to use Visual Studio, the first thing I do is to register gVim as an external tool.

In Tools -> External Tools... -> Add

Title: Edit in Vim
Command: C:\path\to\gvim.exe
Arguments: $(ItemDir)/$(ItemFileName)$(ItemExt) +$(CurLine)
Initial Directory: $(ItemDir)

The second thing I do is to assign a keyboard shortcut so I can quickly open the current file in Vim.

This hack uses Visual Studio for what it's good at (jumping between files, building, burning RAM and CPU cycles) and Vim only for editing.

For any serious development work, I'd invest more time to make Vim work.

On the pro side, it's set up in thirty seconds and uses the real Vim instead of a compatibility layer that's broken somewhere.

1
  • 1
    I already have this setup, I confirm it is a must for big editing work.
    – BobMorane
    May 9 at 14:40
2

I don't know if this answer will satisfy you, but here are some ideas:

Use neovim with telescope

I'd recommend to switch to neovim (which should be like no effort in most cases) and install the telescope plugin. It should be very fast for fuzzy finding files.

Use neovim with overseer.nvim

overseer is a neat task runner-plugin with some predefined task-executions (in this case even for make) which works for me. You can see a demo here.

The grep problem

I don't know if this options is available for vim, but it is in neovim. I have the following setting:

set grepprg=rg\ --vimgrep\ --no-heading

it will let me use rg instead of grep if I do :grep. Doing :grep will be the same as if I'd call rg --vimgrep --no-heading in the terminal and since rg seems to be faster than grep, it should improve your experience I hope.

Using an alias to fuzzy-search and open files.

I've the following alias in my zsh config:

alias ef="fzf | read yeet; if [[ \$yeet != '' ]]; then $EDITOR \$yeet; fi"

you'll have to install fzf for this. You just need to press ef (which means "editor find"), it opens up fzf, you can fuzzy-search the file and it will automatically open up your editor with the given file you selected.

3
  • 1
    RE: rg github.com/benknoble/Dotfiles/blob/…
    – D. Ben Knoble
    May 8 at 17:50
  • 1
    @Friedrich thanks for pointing that out; I'm not sure why that file is different from the rest
    – D. Ben Knoble
    May 12 at 19:52
  • I am not using neovim, but your grep solution is neat. This is what I'll use from now on. Also, for fuzzy finding, I am not using CtrlP, but thanks for the suggestion.
    – BobMorane
    Jun 16 at 18:22
2
+100

Search an identifier

I recommend to install ripgrep (and optionally the ack.vim plugin - the answer of @TornaxO7 explains how you can make the :grep command use rg) to have a faster search engine than the builtin vimgrep.

To search your identifier youridentifier in all the source files you could use the Vim command:

:Ack! -g*.cpp -g*.h youridentifier

Remark: On a project with 5,368 file and 2,282,861 lines the search takes about 1 second on my machine.

Other solution exist:

Compile a file

To compile one file from a full solution you can do:

msbuild yoursolution.sln /p:Configuration="Release" /p:Platform="x64" /t:ClCompile /p:SelectedFiles=yourcpp.cpp

Assuming you want to compile: yourscpp.cpp for the Release configuration and the x64 platform that is part of a VisualStudio project with a solution file yoursolution.sln

I would create a make.bat file in the root of the project structure with the following content:

setlocal
set solution=yoursolution.sln
set configuration="Release"
set platform="x64"

msbuild %solution% /p:Configuration=%configuration% /p:Platform=%platform% /t:ClCompile /p:SelectedFiles="%1"

You can compile the current file with the following Vim command:

:make %:t

To avoid the miss interpretation of some of the output of msbuild I propose to run the following two commands:

set errorformat^=%+GTime\ Elapsed%.%#
set errorformat^=%+GBuild\ started%.%#

To strip the format to the bare minimum you can add run additionally the following command:

set errorformat+=%-G%.%#

In order to ease this operation, you can override the msbuild compiler by adding a msbuild.vim file into ~\vimfiles\compiler with the following content:

setlocal errorformat=%f(%l):%m

" Skip lines that starts with a whitespace
setlocal errorformat^=%-G\ %.%#

" Keep Build started
setlocal errorformat^=%+GBuild\ started%.%#
" Keep Time Elapsed
setlocal errorformat^=%+GTime\ Elapsed%.%#

" Skip all the other lines
setlocal errorformat+=%-G%.%#

Instead of executing the three set command you can just call :compiler msbuild

Language Server Protocol (LSP)

Not strictly part of the question but I can't resist to recommend coc.nvim together with clangd.

After coc.nvim installation run: :CocInstall coc-clangd

You'll get:

  • Warnings
  • Go to definition gd
  • ...
12
  • 4
    See Tornax's answer for why you don't need a plugin for ripgrep. Just set grepprg and grepformat (github.com/benknoble/Dotfiles/blob/…).
    – D. Ben Knoble
    May 8 at 17:50
  • 1
    I think you are correct. Perhaps let … ^= …, but that might only work with set
    – D. Ben Knoble
    May 8 at 21:11
  • 1
    Looks very promising, can't wait to try this.
    – BobMorane
    May 9 at 14:43
  • 1
    Do you start Vim from a develpper command line? Or do you start vsvars.bat before starting Vim. For the msbuild to work well some VS script need to run first. Jun 16 at 20:17
  • 1
    Thanks for the feedback. I believe only adding build to the path is not enough. Visual Studio comes with a special script (e.g.: C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat for Visual Studio 2022) that you have to call to make the msbuild and its friends available. I strongly advice to use it ;-) Jun 26 at 15:18
2

I have decided to post my own answer to share my actual setup, which is highly based on the discussion we have had here. Thanks to all who helped.

1. Fuzzy file search

Although ripgrep works very well for searching identifiers (I have tried it and speed no longer is an issue. It's really fast), it does not fuzzy search for files in the way I was able to do it using the :find command hack. By doing some research, I found a plugin called CtrlP which does fuzzy search for files really well. At first, I had problem with it. I did not work as expected out of the box and I had to tweak it a little bit.

Here is my current CtrlP configuration, which works well for me:

let g:ctrlp_working_path_mode=''       " Use vim's current directory as the root.
let g:ctrlp_max_files=0                " Do not apply a maximum number of files to scan.
let g:ctrlp_max_depth=10000            " Maximum number of directories to recursively search into.
let g:ctrlp_match_window='results:100' " Keep the result window dimensions, but show up to 100 results (scrollable).
let g:ctrlp_by_filename=1              " Enable filename mode by default.
let g:ctrlp_regexp=1                   " Enable regex mode by default.

We have a lot of nested directories and over 35K files, so these settings were mandatory to get workable results in the find list. The only drawback I can see it that because I am using regex mode, search is a bit slower and typing very fast and seeing results appear "real time" does not work. It's not snappy and there is even some lag as you add characters, but it's fast enough, in my opinion, for what I have to do and it's the best solution I have so far.

2. Building a single file

For this one, I have @Vivian De Smedt to thank for a lot. I came up with this custom compiler plugin which seems to work well:

" This option must be set to override the default files.
let current_compiler="MSBuild"

" Define :CompilerSet for older version of Vi, which do not have it defined by default.
if exists(":CompilerSet") != 2
  command -nargs=* CompilerSet setlocal <args>
endif

" By default, this compiler plugin builds the current file. This is similar to hitting
" Ctrl + F7 in Visual Studio. The Error format string was shamelessly stolen from
" here: https://stackoverflow.com/a/3621753/6575139 and seems to work well.
let configuration="Debug" " Other option : Release.
let platform="x64"

CompilerSet makeprg=MSBuild\ %:p:h\ /noLogo\ /p:Configuration=Debug\ /p:Platform=x64\ /t:ClCompile\ /p:SelectedFiles=%:t
CompilerSet errorformat=\ %#%f(%l\\\,%c):\ %m

This will build the current file in x64|Debug using MSBuild. Note that since the plugin makes use of the % file specifier, it must be updated on every file change the match the new current file. To get this, I added

autocmd BufFilePost compiler msbuild

to my vimrc file.

Conclusion

I know that my current solution is not perfect (and I am open to any suggestion) but it now works for me to the point that Vim has now become usable in my job context. If I refine it further in the future, I'll share my findings here.

2
  • Thanks for posting your solution. Don't you need to call the corresponding vsvars64.bat before you start Vim. Did you found an alternative solution for that? Jul 7 at 14:18
  • 1
    It seems like I was able to build without it. May be it had already been called on my setup by the ITs... Not sure.
    – BobMorane
    Jul 7 at 14:19

Your Answer

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

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