4

I have multiple lines like the once below in .vimrc file.

nnoremap \html :-1read $HOME/.vim/snippets/html_basic.snippet<CR>
nnoremap \bs   :-1read $HOME/.vim/snippets/bootstrap.snippet<CR>
...
more snippets like these

Problem is if I want to change my snippet directory $HOME/.vim/snippets to something else like $HOME/.vim/templates/ I would have to edit all the map commands above.

How can I refactor and execute the same map commands using variables containing snippet directory path? For instance, something like this ...

# variable holding snippet directory path
let snippet_home = "$HOME/.vim/templates/"

# map commands using $snippet_home variable value to read file contents
nnoremap \html :-1read $snippet_home/html_basic.snippet<CR>
nnoremap \bs   :-1read $snippet_home/bootstrap.snippet<CR>
...
more snippets like these

This way if I move or rename my snippet directory I would have to simple update snippet_home variable and all map commands remain the same.

Kindly suggest how do I achieve this in vimscript?

1
  • 1
    Im thinking either execute, the expression register, or expression mappings. Will experiment later and see what I find.
    – D. Ben Knoble
    Apr 27, 2018 at 19:33

2 Answers 2

6

One method is to use a <expr> mapping which evaluates the RHS of the mapping as Vimscript rather than use it literally as for regular mappings. The tricky part of this is the fact that we have two levels of variable expansion: snippet_home and the environment variable contained within, $HOME.

The first approach expands the env var when the containing variable is initialized...

let snippet_home = $HOME . '/.vim/templates'
nnoremap <expr> \html ':-1read ' . snippet_home . '/html_basic.snippet<CR>'

This works best with an environment variable that is static (doesn't change often). $HOME certainly qualifies as such.

The second approach will expand the environment variable each time you execute the mapped command...

let snippet_home = '$HOME/.vim/templates'
nnoremap <expr> \html ':-1read ' . expand(snippet_home)  . '/html_basic.snippet<CR>'

The <expr> mapping will evaluate snippet_home as $HOME/.vim/templates so we need to evaluate it again. Thus, the call to expand() which, among other things, will "expand environment variables". See :h expand() (you'll have to scroll down a bit to find the part about env vars).

2
  • Both approaches works perfectly. Thankyou for such an amazing answer. My vimrc looks much better now. If you are using VIM, can I take a look at your vimrc? if you dont mind of course xd Apr 27, 2018 at 22:36
  • 1
    @AviMehenwal Heh. My vimrc isn't published anywhere. It's just not in a user-friendly state right now. Lots of experimental stuff, things that make sense only to me...controlled chaos. Maybe, someday. In the meantime, glad you found my answer useful.
    – B Layer
    Apr 28, 2018 at 2:38
1

You can also use <c-r>=variable<cr> to expand variable.

let snippet_home = "$HOME/.vim/templates/"
nnoremap \html :-1read <c-r>=snippet_home<cr>/html_basic.snippet<CR>

For more example,

let text = "Hello I am from Bangladesh"
inoremap <f5> <c-r>=text<cr>

When you press F5 in insert mode, this will put Hello I am from Bangladesh under your cursor.

N.B: Using <bar> in the variable won't work as expected. You will need to use actual pipe ( | ) instead of <bar>.

Your Answer

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

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