12

I have a variable foo with let foo='value', and a function F like

function F()
  return 'value'
endfunction

and I want to use them

  • in an option: :set option=foo, :set option=F(); or
  • in a command: :edit foo, :edit F(); or
  • in a mapping: :nnoremap f :foo<CR>, :nnoremap f :F()<CR>

How can I do this? In other words, how can I reference variables as command arguments?

3
  • Thank you for the work you put on your answer but isn't the question a duplicate of this one? Clearly your answer is more complete than mine but I think the question is still the same :)
    – statox
    Commented Oct 3, 2019 at 7:36
  • 1
    @statox here’s the meta—i dont disagree with you though
    – D. Ben Knoble
    Commented Oct 3, 2019 at 12:13
  • Oh right I forgot about this meta
    – statox
    Commented Oct 4, 2019 at 7:27

1 Answer 1

22

The reason your example attempts don't work is that in many locations text is simply seen as a literal string, rather than VimScript. So functions, variables, and the like don't work.

For example, if you do:

:let var='value'
:set option=var

Then Vim will simply set the value of option to the literal value var, since it doesn't recognize VimScript in :set. The same applies to :map and many other locations.

In general, most colon/Ex/: commands do not evaluate VimScript.

:execute

Not all is lost, since you can still build a string with :execute:

:let var='value'
:execute ':set option=' . var

The :execute command executes the given VimScript expression. In this case, we build a string using the variable, and what :execute sees is :set option=value.


You can use any Vim expression; some more examples:

" Function return value
:execute 'set option=' . Fun()

" You don't need to use string concatenation; all arguments are 
" concatenated automatically. A space is added.
:execute 'edit' var
:execute 'edit' Fun()

map expands special key sequences like <CR>. To get them in an execute, you need to prepend the < with a \: "\<CR>". You need to use double quotes, single quotes won't work:

:let key = 'h'
:execute 'nnoremap ' . key . " :echo 'hello'\<CR>"

Because you're building VimScript code in a VimScript string things tend to look rather ugly. C'est la vie. Depending on your personal tastes, printf() can make things a bit easier on the eyes:

:execute printf("nnoremap %s :echo 'hello'\<CR>", key)

Note: it's very common to abbreviate :execute to :exe.

See :help :execute for more information.

Expression mappings

Finally, you can use expression mappings to use a Vim expression for the entire right-hand side.

" Execute the contents of the current line as a Vim command.
:nnoremap <expr> f getline('.')

The biggest difference with :execute is that the expression is run when the key is pressed, and not when the command is defined. So every time you press f in the above example getline() gets the value of the current line. If we had used:

:execute ':nnoremap f' getline('.')

Then it would get the value of the line once. So if you had been on the line gg it would be the same as typing:

:nnoremap f gg

See :help :map-<expr> for more information.

Interactively and in mappings, the expression register "= can be used to achieve similar effects. Its usage stands out as

:nnoremap keys :put =Fun()<CR>

or

:inoremap keys <C-r>=Fun()<CR>

:let-&

As a special case with options, you can use

:let &option = 'value'

syntax to have a similar effect as

:execute 'set option='.value
9
  • 3
    A few random remarks: 1. You can also use the &, &l:, &g: scopes to assign the contents of a variable to an option: :let &option = var (see :h expr-option). 2. If you want to know whether you can pass the contents of a variable to a command without :exe, check out its synopsis in the help.
    – user938271
    Commented Oct 3, 2019 at 3:02
  • 1
    E.g.: at :h :let-&, you can see that the rhs is {expr1}. And a variable is an expression (because it's listed in the expr9 block at :h expression-syntax, and expr9 is listed in the expr8 block, and the expr8 block is listed in the expr7 block, and so on until the expr1 block; IOW expr1 is the most general type of expressions which includes all types of expressions including simple variables). OTOH, the synopsis of :set given at :h set-args doesn't mention {expr} but {value}. A variable is not a value, so you can't directly pass a variable name to :set.
    – user938271
    Commented Oct 3, 2019 at 3:02
  • 1
    3. The string concatenation operator can be implicit, but fwiw, I always write it explicitly (using it implicitly made me write it in places where it doesn't work; e.g. :let v='x' 'y'). And if your Vim is recent enough, use .. instead of . (see :h scriptversion-2 for the reason why).
    – user938271
    Commented Oct 3, 2019 at 3:02
  • 1
    @filbranden You're right, it's specific to :exe. I still prefer an explicit concatenation operator to be consistent with other commands which don't concatenate their arguments; just my two cents. Edit: Ah no, :echo does it too, so it's not specific to :exe.
    – user938271
    Commented Oct 3, 2019 at 5:18
  • 2
    As the question does not ask specifically about scripting, I think that interactive input using expression register is worth mentioning.
    – Matt
    Commented Oct 3, 2019 at 5:54

Your Answer

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

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