Is there a way to emulate ReSharper's “extend

2019-03-20 03:03发布

问题:

ReSharper has a nice feature called "extend selection": by pressing CTRL+W (I think this is the default) repeatedly, you select more and more from your current caret location. First it's a word, then more and more words, a line, inner then outer block of lines (for example an if-block), then a function, etc...

Basically, by pressing the key combination repeatedly, you can end up selecting the entire file. I'm sure at least some of you will be familiar with it.

I have just started learning all the intricacies of vim and I don't have enough experience to see how something like this could be implemented in Vim (although I assume it's possible). So my question is meant for Vim gurus out there: can this be done and how?

Update: a bit of a background story. I've been talking to my ex-boss about all the benefits of Vim, and he thinks it's all great. His only question/problem was: does it have "extend selection"? My question so far has been no. So, if someone knows the answer, I'll finally win a discussion :P (and maybe create a new Vim convert:-))

回答1:

I had a quick go at this problem. It doesn't work as is. Feel Free to make edits and post on the vim wiki or as a plugin if you get it refined.

chances are you'd want to make a g:resharp_list for each language (eg. one for paranthesised languages, etc.)

All that is needed is a marker for the original cursor position :he markers and a timeout autocommand that resets the index.

"resharp emulator
"TODO this needs a marker
"also c-w is bad mapping as it has a lag with all the other-
"window mappings
"
let g:resharp_index = 0

let g:resharp_select =  ['iw', 'is', 'ip', 'ggVG']

func! ResharpSelect()
    if g:resharp_index >= len (g:resharp_select)
        let g:resharp_index = 0
    endif

    exe "norm \<esc>v" . g:resharp_select[g:resharp_index]
    let g:resharp_index = g:resharp_index + 1
endfun

nnoremap <c-w>  :call ResharpSelect()<cr>
vnoremap <c-w>  :call ResharpSelect()<cr>

"Something to reset on timeout. TODO this doesn't work
au CursorHold :let g:resharp_index = 0<cr>


回答2:

The answer is yes. Once in Visual mode you can use all the regular navigation methods as well as some extra ones.

Some of my favourites? First hit v while in normal mode to get to visual mode then hit:

  1. iw - to select the inner word. Great for selecting a word while excluding surrounding braces or quotes
  2. w - hit multiple times to keep selecting each subsequent word.
  3. b - select wordwise backwords
  4. ^ - select all from current position to beginning of text on line
  5. $ - select all from current position to end of line

I'm sure others here could add to this list as well. Oh and don't forget Visual Block mode C-v try it out in vim with the above commands it works in two dimensions :-)



回答3:

If you're talking about Vim (and you should be :-), you can start marking text with the v command, then you have all the standard cursor movement commands (and, as you know, there are a lot of them) which will extend the selection, as well as moving the cursor.

Then you just do whatever you want with the selected text.

See here for the gory details.



回答4:

One would need to write a function that would save the current selection, then try increasingly wide selections, until the new selection exceeds the saved one or selects all text. Some possible selections are:

  • viW - select word
  • vis - select sentence
  • vip - select paragraph
  • viB - select text within the innermost brackets
  • v2iB - select text within the next most innermost brackets
  • ggVG - select all text


回答5:

I think Jeremy Wall's heading in the right direction. And to get a little further in that direction, you might look at the "surround.vim" script from Tim Pope. A good description is available on github. Or, if you'd rather, get it from vim.org. It'll probably help you do some of the things you'd like to do, though it doesn't seem to have a feature for say, simply selecting within a tag. Let me know if I'm wrong.

Ultimately, what you'd really like is a hierarchy of enclosing text-objects. You should read up on text-objects if you haven't. A nice overview is here. Note that you can grab multiple objects in one go using counts, or do this iteratively (try vawasap}}} from normal mode).

You can also get scripts which define other text-objects, like this one that uses indentation to define a text-object. It'll work for many languages if you're formatting according to common standards, and guaranteed for python.

One annoyance is that the cursor ends up at the end of the visual block, so, for example, you can't easily select everything between some ()'s, then get the function name that precedes them...

...BUT, I just found in this post that you can change this behavior with o. Cool!

I suspect you'll find yourself more efficient being able to skip over intermediate selections in the long run.

Anyway, I'll be curious to see if anyone else comes up with a more general solution as well!