Houl/repmo-vim

How can I expand a visual selection with text objects provided by targets.vim?

kiryph opened this issue · 6 comments

My vimrc

source $VIMRUNTIME/defaults.vim

map <expr> ; repmo#LastKey(';')|sunmap ;
map <expr> , repmo#LastRevKey(',')|sunmap ,

" Still repeat fFtT (now with counts):
noremap <expr> f repmo#ZapKey('f')|sunmap f
noremap <expr> F repmo#ZapKey('F')|sunmap F
noremap <expr> t repmo#ZapKey('t')|sunmap t
noremap <expr> T repmo#ZapKey('T')|sunmap T

" Now following can also be repeated with `,` and `;`:
for keys in [ ['[[', ']]'], ['[]', ']['], ['[m', ']m'], ['[M', ']M'], ['[c', ']c'] ]
    execute 'noremap <expr> '.keys[0]." repmo#SelfKey('".keys[0]."', '".keys[1]."')|sunmap ".keys[0]
    execute 'noremap <expr> '.keys[1]." repmo#SelfKey('".keys[1]."', '".keys[0]."')|sunmap ".keys[1]
endfor

" Question: how to use the variants from targets.vim in visual mode
for keys in [ ['aB', 'iB'], ['a{', 'i{'], ['a}', 'i}'],  ]
    execute 'xnoremap <expr> '.keys[0]." repmo#SelfKey('".keys[0]."', '".keys[1]."')"
    execute 'xnoremap <expr> '.keys[1]." repmo#SelfKey('".keys[1]."', '".keys[0]."')"
endfor

Installation of repmo-vim and targets.vim into vim8 pack path:

❯ tree -L 5 ~/.vim
.
├── pack
│   └── repeat-text-objects
│       └── start
│           ├── repmo-vim
│           │   ├── README.markdown
│           │   └── autoload
│           └── targets.vim
│               ├── LICENSE
│               ├── README.md
│               ├── autoload
│               ├── cheatsheet.md
│               ├── doc
│               ├── plugin
│               ├── plugins.md
│               └── test
└── vimrc

Running :xnoremap a shows
x a targets#e('x', 'a', 'a').

Repeating builtin aB works with repmo. However, using the text objects of targets.vim allows you to decrease the visual selection by pressing iB.

I suspect this has something to do how targets.vim has implemented them. However, I would prefer to get feedback here first.

Houl commented

You should check out how targets.vim defines iB (I haven't!). I just assume the {rhs} is <Plug>(targets-iB) (and similar for aB). Then (here Visual mode only): xmap <expr> iB repmo#Key('<Plug>(targets-iB)', '<Plug>(targets-aB)') should do it. Then it depends on how and when targets.vim defines keys. Maybe for a start, let targets.vim define its keys first, then execute above map definitions.

I was hoping you might use targets.vim as well. Anyhow:

targets.vim provides quite a lot text objects, see e.g. here https://github.com/wellle/targets.vim/blob/master/cheatsheet.md.
To speed up start up time text object mappings are not setup explicitly:

Quote by the author wellle:

One thing which targets.vim does differently than most plugins is how it actually uses an expression mapping on i. In there I use getchar() to read additional characters to see if that's one of the mappings targets.vim should handle. Otherwise it hands them back for Vim to handle (which properly picks up other custom mappings like ii (inner indent object) for example).

(lervag/vimtex#1294 (comment))

This means iB is not defined. After pressing i targets.vim uses getchar to get the next character.

I guess I have to ask the autor of targets.vim if it is possible to combine with repmo-vim. Maybe, I have to use the legacy mappings or at least activate the legacy mappings for those I would like to expand with ,.

Houl commented

I've tried targets.vim quite some time ago, but was a bit scared by the vast number of mappings created. The getchar() thing is new to me ... Ok I've tried the following and it seems to work:

omap <expr> <Plug>(targets-i) targets#e('o', 'i', 'i')
xmap <expr> <Plug>(targets-i) targets#e('x', 'i', 'i')
omap <expr> <Plug>(targets-a) targets#e('o', 'a', 'a')
xmap <expr> <Plug>(targets-a) targets#e('x', 'a', 'a')

map <expr> iB repmo#Key('<Plug>(targets-i)B', '<Plug>(targets-a)B')|nunmap iB|sunmap iB
map <expr> aB repmo#Key('<Plug>(targets-a)B', '<Plug>(targets-i)B')|nunmap aB|sunmap aB

map <expr> <Space> repmo#LastKey('')|sunmap <Space>
map <expr> <BS>    repmo#LastRevKey('')|sunmap <BS>
Houl commented

Anyway: Making aB and iB opposite keys for repmo looks weird to me, there is no clear repeatable forward/backward direction. Is that actually useful? repmo deals with motions, targets with text-objects.

Thank you for your help. Sometimes the obvious and easy answer is more difficult to see.

As far as I have tested it, it does not work perfectly

Consider this:

{ 

    a
    {
        CURSOR

    }

    c
}
  • vab gives you as expected following selection:
    screenshot 2019-02-17 at 13 40 44

  • To extend the selection I press ;. However, at first it does nothing. I need to press ; a second time to get:

screenshot 2019-02-17 at 13 40 50

  • Finally, I have observed when I hit , to shrink the selection after vab;;, vim switches to visual-line mode which should not happen and is stuck with this selection:
    screenshot 2019-02-17 at 13 40 58

Since it does not work reliable it is certainly not helpful.

I thought about this when I encountered someone who uses a foreign keyboard where pressing a] is difficult and he was looking for a key to repeat the text object to speed up the selection process.

Houl commented

I added

map <expr> ib repmo#Key('<Plug>(targets-i)b', '<Plug>(targets-a)b')|nunmap ib|sunmap ib
map <expr> ab repmo#Key('<Plug>(targets-a)b', '<Plug>(targets-i)b')|nunmap ab|sunmap ab

and the usual mappings for ;, ,, f, F, t and T.
With your example text, vab; works for me, I don't need to hit ; twice after vab.
And the switch to linewise mode you mention later also happens without repmo.