2

Given the following code in visual mode :

{
  {
    some text
    ^ cursor
  }
}

if I type a{ this will be selected :

{
  { < selection start
    some text
  } < selection end
}

I'd like to repeat the last selection command to expand my selection to include the enclosing brackets with .

{ < selection start
  { 
    some text
  } 
} < selection end

I know I can do it by repeating a{ but I prefer to use .

I have installed vim-repeat

4
  • 2
    . is indended to repeat changes, not selections, movements and so on. Do you really want to break this concept to save one keystroke? If you know you want the second next brace level you can even type 2a{ and have the same keystrokes as a{. would have.
    – Philippos
    Apr 5, 2017 at 13:41
  • But I can repeat other selection moves like t with .
    – sylvain
    Apr 5, 2017 at 13:46
  • It does? Brrrr. Did vim-repeat do this to you? So you can never do a new selection and perform the same change to it with .? Sad, but if you are happy with it ...
    – Philippos
    Apr 5, 2017 at 13:55
  • I thought it was by default and vim-repeat only added this behaviour to other plugins related moves
    – sylvain
    Apr 5, 2017 at 18:20

5 Answers 5

2

You can fake it with this:

vnoremap <expr> . expand('<cword>') =~# '[(){}\[\]]' ? 'a'.expand('<cword>') : ''

The character under the cursor is used to expand the selection if it's one of the brace characters. Since an expression map is being used, you never leave visual mode, which avoids breaking the normal mode . repeat.

Visual repeat of all text objects

This method gives you a much broader coverage of text objects:

function! s:repeat_block(key) abort
  if a:key ==# '.'
    return get(s:, 'v_repeat_count', '').get(s:, 'v_repeat_key', '')
  endif

  let s:v_repeat_count = v:count1
  let s:v_repeat_key = a:key
  return a:key
endfunction

for k in ['w', 'W', 's', 'p', '[', ']', '(', ')', 'b', '<', '>', 't', '{', '}', 'B', '"', "'", '`']
  execute printf('vnoremap <expr> a%s <sid>repeat_block(''a%s'')', k, k)
  execute printf('vnoremap <expr> i%s <sid>repeat_block(''i%s'')', k, k)
endfor

unlet! k

vnoremap <expr> . <sid>repeat_block('.')

This very lightly uses the same method as vim-repeat and covers both a and i text object prefixes. The side effect of this is that the visual repetition is remembered after you leave and re-enter visual mode. Whether or not that's a good thing is up to you.

3
  • with a french keyboard it does as { and [ are uncomfortables 2 keystrokes combinations.
    – sylvain
    Apr 10, 2017 at 10:48
  • it works ! is it possible to make it work for html tags too ?
    – sylvain
    Apr 10, 2017 at 10:50
  • @sylvain I take back what I said about saving time after I looked up the French keyboard. That doesn't look comfortable at all! I updated the answer with something that will cover all text objects.
    – Tommy A
    Apr 10, 2017 at 13:41
1

There's also a handy plugin for that : smartpairs

  • hit vav to select surroundings matching ' / " / ( / { / tags etc.
  • expand your selection by typing vav again
1

Recommendation: do not do it

I strongly recommend not to remap . to extend visual selections. . is meant to repeat the last change.

You break an essential workflow pattern of vim.

Also plugins are designed around this pattern: for example, consider the plugin visualrepeat: its purpose is to make it possible to press . to apply the last change to the current visual selection. If . extends the selection, this plugin does not work as intended. This is only a single example. There are plenty more of them.

If you really need a single key to extend the last applied text object in visual mode, extending , might be a better choice. But I am also not entirely convinced of this choice.

I would recommend to get used to pressing va{a{ or v2a{. It is not that bad.

{ on a French keyboard

If the motivation is the French keyboard layout, I would consider following options

  • simply use aB instead of a{
  • a% from vim-matchup might also be helpful
  • repeat the motions { and } with ; and , with the help of https://github.com/Houl/repmo-vim
  • learn the English layout (I've done this myself coming from a German layout; I switch to German layout when writing German text otherwise I use the English layout)
0

V4j (shift-v) works. I'm not sure repeat will work for you here.

Alternatively, from the top brace, you can simply hit Enter/Return, which will visually select the inner block. Then press Enter/Return again, and it'll expand to the outer braces as well.

1
  • Thanks but that's not what I'm looking for. Maybe my question isn't clear enough. I want to expand the selection to matching brackets from the inside.
    – sylvain
    Apr 5, 2017 at 6:13
0

By using matchup with textobj-user which provides the % text object for code blocks you can select the first block with vi%. Incrementally selecting outer blocks are done by hitting i%, i%, ... (or a%).

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.