4

I'm familiar with vertical blocks, and I often ctrl+v down down down shift+I foobar esc to write foobar in various locations at once. This is useful if I want to replace <td> to <th> in a chain, for instance.

Since not all the text blocks are of equal size, I don't know how to do the same for </td> to </th>. I can think of selecting multiple lines as I did earlier, move to the end of the line with shift+a, maybe, move one to the left, delete a character with x, and type my h, but I don't know how to move my position(s) when I am in visual block mode.

Is there a way to select a position as active, and move as I usually would with my marker, choosing where to write?

In SublimeText3 I would do something like ctrl+d to select the cases I'm looking for (skipping with ctrl+k+d if necessary), moving to the end-of-line with end (home for the beginning of the line), and then moving with the arrow keys (alternatively with ctrl+arrow keys).

An example scenario:

<tr>
    <th>Language</th>
    <th>Oral</th>
    <th>Written</th>
    <th>Diplomas</th>
    <th>Notes</th>
</tr>

which I want to be

<tr>
    <td>Language</td>
    <td>Oral</td>
    <td>Written</td>
    <td>Diplomas</td>
    <td>Notes</td>
</tr>
jamessan
  • 11,045
  • 2
  • 38
  • 53
mazunki
  • 143
  • 1
  • 5

5 Answers5

3

Aside from the suggested plugin vim-multiple-cursors, you have different options:

For example you can go on the parent tag (tr I guess?) and visual select in the tag:

vit

Then do a substitution in the tr tag only:

:'<,'>s/td/th/g

If you want to do a more complex change than a substitution, you can search for a pattern matching all the places you want to apply a change, go to the first one, do your change, and for all the other, if the change is atomic, use . to repeat it:

/td>
ceth<esc>
n.n.n.

The first command searches for a td> tag, the second cut until the end (ce) and types th, then leaves the insert mode. The third line goes to the next td (n), execute the second command (.) and this 3 times (do it as many times as you need of course, it is just an example).

If the change is more complex, you can also create a macro.

There is an interesting article about multiple cursor (or rather lack of) in Vim: https://medium.com/@schtoeffel/you-don-t-need-more-than-one-cursor-in-vim-2c44117d51db

padawin
  • 1,333
  • 4
  • 8
  • I neither know how to do a substitution in a selected mode (vit is great to select my tags to apply it too, though!), nor how to use move my cursor after having found my matches with n Can you explain this? – mazunki Apr 16 '19 at 13:59
  • For the first one, do a visual selection, then press : to enter in command mode, it will show: :\<,\> which means "type a command that I will run in a range (\< being the beginning of the selection and \> being the end. Your command would look like: :\<,\>s/td/th/g. – padawin Apr 16 '19 at 14:01
  • When you do a search in Vim, you can then go from result to result of your search with the n key. I am updating my answer with an example. – padawin Apr 16 '19 at 14:04
  • Interesting. Knowing RegEx, I find the substitution method really nice. What effect does the last /g mean? I assume global. – mazunki Apr 16 '19 at 14:15
  • yes, global, especially in his case where he wants to replace both start and end td tags of the lines – padawin Apr 16 '19 at 14:16
  • @padawin thanks for the link, never know cgn – dedowsdi Apr 16 '19 at 14:22
  • Actually, the range is '<,'> – D. Ben Knoble Apr 17 '19 at 02:41
2

I know there has already answers. But i couldn't help to try something i just learned from @padawin's link.

  1. /th> search th>
  2. cgntd> change th> to td>
  3. ......... repeat 9 times with 9 dots. You can just press the button, don't lift it.

check :h gn

update

If your text doesn't contain th, place your cursor under th, you can replace word under cursor like this:

  1. *#cgntd
    • * set @/ to \v<th>, search forward
    • # search backward, restore cursor, you can also use N if you want.
    • cgntd replace next match (or the one under cursor) to td
  2. .........
    • repeat, You can hold . , don't release
dedowsdi
  • 6,248
  • 1
  • 18
  • 31
  • Indeed, I just played a bit with it too, it is definitely promising! I'll try to keep it in mind. – padawin Apr 16 '19 at 14:45
1

Building on padawin’s answer, I would go to the <tr> tag, vit, and then

:s-<\(/\)?th>-<\1td>-g

To do the replacement. If your text doesn’t contain th, then :s/th/td/g is simpler.

Alternately, with tpope’s surround plugin, on each th, do cst<td>. Combined with tpope’s repeat, you can do this for one line and repeat on each with the . command, or even :g/<th>/normal f>lcst<td>

D. Ben Knoble
  • 26,070
  • 3
  • 29
  • 65
1

I use surround.vim which makes changing tags easier, e.g. cst<td>. Combine this with :normal and a visual mode makes this pretty easy. Just visually select the lines with V then run:

:norm cst<td>

For more help see:

:h :range
:h :norm
:h V
Peter Rincker
  • 15,854
  • 1
  • 36
  • 45
0

Note: Not an answer anymore after your last update to the question, but perhaps still useful to know.


Try it like this:

  1. Goto end of first line.
  2. Hit <Ctrl-V>$
  3. Move down
  4. Hit Afoobar<esc>

With the $ you hit in step 2, the visual block selection is always till end-of-line. Even if one of the following lines is shorter.

Ralf
  • 9,197
  • 1
  • 11
  • 30
  • This works if I delete all the end-of-line > tags in the html, and add them in the foobar. I tried tricking it with I, but that worked out wrong. Can I somehow tell it to move one position to the left? – mazunki Apr 16 '19 at 13:52
  • @mazunki I don't think this is possible. I would do it with search/replace. See the answer from D. Ben Knoble. – Ralf Apr 16 '19 at 14:25