问题
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