9

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?

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
    Oct 3 '19 at 7:36
  • @statox here’s the meta—i dont disagree with you though
    – D. Ben Knoble
    Oct 3 '19 at 12:13
  • Oh right I forgot about this meta
    – statox
    Oct 4 '19 at 7:27
14

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
    Oct 3 '19 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
    Oct 3 '19 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
    Oct 3 '19 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
    Oct 3 '19 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
    Oct 3 '19 at 5:54

This site is temporarily in read only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .