How to run commands against block-wise visual mode selection?

╄→尐↘猪︶ㄣ 提交于 2021-01-29 12:25:36

问题


I have a testing file with the content:

var a = f
        ff
        fff

Then I moved the cursor on the f character in line 1, ctrl+v selected the two f below it (■ means selection).

var a = ■
        ■f
        ■ff

I want to change the text to this:

var a = "f"
        "ff"
        "fff"

So I executed this command:

:normal i"ctrl+vEscA"

But the quotes were added to the whole line. Is it possible to do operations on only block-wise visual selection (not the whole line)? Note that this example was made only for discussing Vim skills. I'm not trying to solving any problems, just want to learn Vim skills.


回答1:


The problem is that all :-commands can take linewise range only. Recall that after pressing : in Visual mode you got :'<,'>_ which is a hint strong enough (see :h mark-motions in case you don't remember about backtick vs. single-quote).

So you can't process visually selected text directly but have to yank it into register first.

One solution is to yank-put the text into the lines of its own. Then you can apply your command(s) and move the new text where it should be.

This is how it's done in that "vis" plugin mentioned in the comment by @phd and the linked answer. But it's so big and bloated that we'd better implement such functionality ourselves.

" apply command to a visual selection
" a:cmd - any "range" command
" a:mods - :h command-modifiers
" a:trim - true if we need to trim trailing spaces from selection text
function s:block(cmd, mods, trim) abort
    " save last line no
    let l:last = line('$')
    " yank selected text into the register "9"
    silent normal! gv"9y
    " put it at buffer's end
    call append(l:last, getreg(9, 1, 1))
    " trim trailing spaces
    if a:trim
        execute 'keepj keepp' l:last..'+,$s/\s\+$//e'
    endif
    " apply our command
    " note: we assume that the command never enters Visual mode
    execute a:mods l:last..'+,$' a:cmd
    " get the changed text back into the register "9"
    call setreg(9, getline(l:last + 1, '$'), visualmode())
    " clean up
    call deletebufline('%', l:last + 1, '$')
    " replace the selection
    " note: the old text goes into the register "1", "1" into "2", and so on.
    " old register "9" is lost anyway, see :h v_p
    silent normal! gv"9p
endfunction

" our interface is a user command
command! -bang -range -nargs=1 -complete=command B call s:block(<q-args>, <q-mods>, <bang>0)

Now you can select your block (do not forget about extending it until lines' ends!), and execute:

:'<,'>B! normal! i"^CA"

Note: ^C stands for Ctrl-VCtrl-C




回答2:


On possible solution:

:'<,'>norm $ciw"ctrl-v ctrl-r""

OBS: Ctrl-v Ctrl-r should be typed literally

Another solution:

:'<,'>s/\w\+$/"&"


来源:https://stackoverflow.com/questions/61736620/how-to-run-commands-against-block-wise-visual-mode-selection

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!