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 :h expr-..
:
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
allowed.
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 ..
over .
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 .
or ..
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 :h :execute
:
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 echom
and 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"
You're using 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. exec
without !
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