The answer has partly changed as of Vim 8.1 patch 1114, where
. is becoming obsolete. While it's not currently wrong to use
. in non-Vim9 vimscript (because backwards compatibility), you can use the
.. operator instead.
This does have a couple subjective and objective advantages. Quoting
For String concatenation ".." is preferred, since "." is ambiguous, it is also
used for |Dict| member access and floating point numbers.
In |Vim9| script and when |vimscript-version| is 2 or higher, using "." is not
In either case,
.. is the more modern option. As an aside, it's also the operator you'll want to use if you upgrade to Vim9script, though that requires a few other changes, and I'm not covering that here. See
:h Vim9 if this sounds interesting, and you have a relatively up-to-date Vim 8.2 install, or if you've installed Vim 9.0+.
With your current code, though, and Vim 8.1 with patch 1114, or newer, you can use:
let repo = $Project .. '/cfora'
This does the exact same thing as
$Project . '/cfora'; whether you want to use
. is up to you. The arguments in favor of it were mentioned earlier in this answer.
As for executing, you don't actually need to use
.. at all; by passing multiple strings, Vim concatenates them for you with a space:
exe '!cmake' repo
Vim interprets this as
exe '!cmake <content of the repo variable without brackets>'. From
Multiple arguments are concatenated, with a space in
between. To avoid the extra space use the ".."
operator to concatenate strings into one argument.
This also holds for some other similar-style keywords, including
echo (and the related
echoerr), and likely a couple others that I don't remember off the top of my head.
While I'm writing an answer, this line does nothing:
exec "!cd build"
cd in a subprocess, and because of how
cd works, the subprocess cannot change the working directory of the parent process; in your case, that's Vim. This particular subprocess also dies immediately after changing the directory, and doesn't affect any other subprocesses made afterwards.
Assuming you're using Linux, or otherwise use Vim in such a way that it can use a UNIX shell, a valid command would be:
exec "!cd" build "&& cmake" repo
Alternatively, you can use
exec 'cd' build on its own line; the main difference here is that
cd in this context changes Vim's working directory, rather than a child process that immediately dies. As Maxim also mentioned, you can use
lcd instead of
cd, but it really depends on your use.
! executes the content as a Vim command, and
:cd is indeed a valid Vim command.
Or even better, have CMake do it for you. I haven't tried this myself, but this answer outlines it; see the second or third bullet point, depending on what version of CMake you're running. Using those flags should let you fully drop any form of
cd from the command, and maintain compatibility with shells that don't support
&& (particularly stock Windows). Concatenation is still needed to supply the parameters, so you should be able to do something like this (CMake 3.13+, assuming the flags work the way I think they do):
exec "!cmake -B" build "-S" repo