0

Suppose I launch vim from a large project root folder and want to compile a specific example (I ll use zephyr RTOS for example). This root folder is located under /home/<user>/zephyr/

Let's say I run vim samples/basic/blinky/src/main.c. Now if I want to compile it, I would go, from another terminal to samples/basic/blinky/build/ and run make

If I want to build it without leaving vim, I could run :make -C samples/basic/blinky/build/

I would like to automate this process, pressing any key, let's say f5.

So if I have, for example, two vertical splits, v1 and v2.

In v1 I have samples/basic/blinky/src/main.c and in v2 I have samples/drivers/rtc/src/main.c.

Pressing f5 from v1 would lead to run the equivalent of :make -C samples/basic/blinky/build/, and from v2 would lead to run the equivalent of :make -C samples/drivers/rtc/build/

The common pattern is that the build folder is located in ../build/ from the current c file directory.

I don't want to "permanently" use :cd or :lcd to change working directory, even for the current split/window because:

  • My ctags tags file is located in the root folder, so I want to be able to jump to any function that samples/basic/blinky/src/main.c uses but are not necessarily defined in the same file.
    • If I want to open a new file, I want to access it using its path from the root folder and not the current file path

My current solution is to have a function in my ~/.vimrc which temporally changes the working directory to the current file equivalent build folder, so that I can run :make and then changes back the working directory to the root folder.

It looks like this:

nnoremap <F5> :call MakeTst()<CR> function! MakeTst(...) :cd %:p:h :cd ../build/ :make :cd /home/<user>/zephyr/ endfunction

While this works, the downside is that the root folder is hardcoded inside the ~/.vimrc.

How can I achieve the same result without hardcoding the root folder path?

oscillo
  • 3
  • 2
  • How is `cmake` tag related with the problem? (`make` and `cmake` are **different** things). – Tsyvarev Sep 21 '18 at 20:32
  • @Tsyvarev Thank you for your constructive comment! You are absolutely right (as you pointed out in a bold point). I added it as a "lack of thinking" as it is used by the example project to generate the Makefile. Since it is not relevant to the question, I ll remove it. Cheers – oscillo Sep 21 '18 at 20:47
  • Would `:make -C %:p:h/../build` work? – user58697 Sep 21 '18 at 23:21
  • @user58697 Well, I m really stupid for not putting the pieces together myself ... That works, thanks! – oscillo Sep 23 '18 at 19:32

1 Answers1

1

You gave the answer yourself: in your function. As long as your file structure keeps that pattern, you can use filename modifiers to make it generic:

:nnoremap <F5> :make -C %:p:h/../build

This will always build in the directory build at the same level of the directory where the current file sits. Just like your example:

a/b/c/src/file.c
a/b/c/build

It breaks in a case like this:

a/b/c/src/include/features.h

As it would try to build in:

a/b/c/src/build

There is a workaround though. If your build is always at the same level of src, then you can perform a text substitution with the :s modifier:

:nnoremap <F5> :make -C %:p:s!.*\zssrc.*!build!

This simple pattern .*\zssrc.* searches for the last src in your path and replaces it (and anything after it) with build. It does nothing if there is no src in the path.

sidyll
  • 57,726
  • 14
  • 108
  • 151