2

I am trying to create a command which compares the current file with another by calling :DiffWith(foo.rb). See the following code:

function DiffWith(file)
  botright vsplit a:file
  windo diffthis
endfunction
command -nargs=1 -complete=file Diffwith call DiffWith(<f-args>)

However, it opens a new file named a:file instead of the file I state. What do I do wrong?

  • 2
    Would this work :botright vertical diffpsplit foo.rb? – Peter Rincker Aug 8 '17 at 19:23
2

Many commands in Vim, including :botright and :vsplit, expect plain text, no variables or expressions ( see :help 41.3 and :help expression to know what a expression means). But there are commands that do expect variables and/or expressions, such as :echo and :execute.

String interpolation is common in many programming languages such as Groovy, Kotlin, Perl, PHP, Python, Ruby, Scala, and Swift, and most Unix shells, but not Vimscript. However, when a Vim command expects an expression, it can evaluate variables and use the concatenation operator (the dot .) to obtain the same effect.

So it would be great if we could use the content of a variable, rather than just plain text, to issue commands such as :botright vsplit a:file. For that purpose, Vim gives us the :execute command, from :help :execute:

:exe[cute] {expr1} ..    Executes the string that results from the
                         evaluation of {expr1} as an Ex command.  Multiple
                         arguments are concatenated, with a space in
                         between.  To avoid the extra space use the "."
                         operator to concatenate strings into one 
                         argument.

In that way, you can take advantage of the :execute command to get the intended result, as follows:

function DiffWith(file)
  execute "botright vsplit" a:file
  windo diffthis
endfunction
command -nargs=1 -complete=file Diffwith call DiffWith(<f-args>)

and then you can call it by typing in:

:Diffwith foo.rb

Bonus

As Peter Rincker pointed out, Vim includes a similar functionality, see below:

:botright vertical diffsplit foo.rb

and you can rewrite your command in this way:

:command! -nargs=1 -complete=file Diffwith botright vertical diffsplit <args>
  • Thanks! However, I don't understand why vim is handling both things different. I would have expected that botright vsplit "a:file" would be the form to open a file named “a:file”, witthout quotes should it be a variable… – Ben Aug 8 '17 at 21:14
  • @Ben Please read the new content, does it help? – Jair López Aug 9 '17 at 2:08
  • 2
    @Ben because this would traditionally try to edit a file "a:file" and since this is a valid name, it would not be possible to edit such a file. So this would have broken backwards compatibility when vimscript was added so it was decided against it, and only a very limited number of commands added, that expect expressions instead of literals. Therefore you have to use exe – Christian Brabandt Aug 9 '17 at 5:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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