2

When working with Jinja templates and YAML for Ansible configuration, I often copy+paste a variable name (say, nginx_root) and then need to wrap it in double curly braces: {{ nginx_root }}. This gets cumbersome to do manually, so I want to be able to type a Vim key binding to wrap the current word under the cursor in double curly braces.

Using the vim-surround plugin, I can add the desired curly braces to the word under the cursor via ysiw}lysiw{, but that is many more key strokes than I would prefer. I have tried the following Vim key binding, but invoking it in normal mode has no visible effect at all:

" Wrap text under cursor with double curly braces (e.g., for Jinja variables)
nnoremap <C-J> ysiw}lysiw{

Ergo, my questions are:

  1. Using stock Vim functionality, the vim-surround plugin, and/or any other combination of tooling, how can one bind a key that will wrap the current word under the cursor with space-padded double curly braces? e.g., nginx_root{{ nginx_root }}

  2. Is there a way to also achieve this in insert mode, with the cursor just to the right of the word? (nginx_root*, where * is the cursor position)

  3. How would one bind a key (preferably available in both normal and insert modes) to insert {{ * }} at the current cursor position, where * is the position of the cursor after insertion? (This would facilitate entering new Jinja variables, versus operating on copy+pasted variables as noted above.)

Justin Mayer
  • 2,063
  • 11
  • 15

2 Answers2

3

Fixing your mapping

Your mapping does not work because it uses :noremap. It is correct to avoid remapping (via the nore part of the command) as much as possible, but as you're invoking surround.vim's ys mapping in there, there's no (easy) way around it:

nmap <C-J> ysiw}lysiw{

A surround.vim alternative

That double surrounding is awkward, and actually not necessary, because the plugin allows to define custom replacements, as per :help surround-customizing.

The following defines a new replacement on d (for "double"; 100 = char2nr('d')); with it, you can add double curlies to a word via ysiwd:

let g:surround_100 = "{{ \r }}"

To only define the mapping for certain filetype(s), replace the g: with b:. I would recommend putting this then into ~/.vim/ftplugin/{filetype}_whatever.vim (or {filetype}/whatever.vim; cp. :help ftplugin-name) instead of defining lots of :autocmd FileType {filetype} ...; it's cleaner and scales better; requires that you have :filetype plugin on, though.

Your other questions

The surround.vim plugin also offers an insert mode <C-g>s mapping. I would recommend against insert mode mappings for these kinds of edits; it's against Vim's mode-based model, and only few (and awkward key combinations with Ctrl or Alt) keys are available there.

To insert a template, a simple mapping will do. You can position the cursor in between the added curlies via the special <Left> keys:

:nnoremap <C-g>d a{{  }}<Left><Left><Left>
:inoremap <C-g>d {{  }}<Left><Left><Left>
Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
  • Brilliant suggestions! While not as clean/scalable, for the wrapper I opted for a one-liner: `autocmd FileType ansible,ansible_template,htmljinja,htmldjango let b:surround_100 = "{{ \r }}"` – Justin Mayer Sep 14 '18 at 13:02
  • Yeah, in that case, nothings beats the conciseness of that one-liner! If this answers your question, please don't forget to accept the answer. – Ingo Karkat Sep 14 '18 at 13:07
  • 1
    Accepted! Thanks for the detailed and spot-on answers. You rock! – Justin Mayer Sep 14 '18 at 13:14
0

In order to execute normal mode commands, try

nnoremap <C-J> :normal ysiw}lysiw{<CR>

See :help normal for details.

Hans Hohenfeld
  • 1,729
  • 11
  • 14