Trying to understand the logic of deletions in Vim
Asked Answered
D

2

5

I Googled this but was unable to find any clear explanation.

A lot of people praise Vim for sort of being its own internally consistent language but I am failing to see the consistency.

Since hjkl are left down up right:

dh is like "delete left" and it deletes the character to the left of the cursor, makes sense so far.

dl is like "delete right" but it deletes... the current character?

dj is like "delete down" and I'd assume this just deletes the line below, but it actually deletes the current line as well!

'dk' is like "delete up" and similarly I'd expect it just clears the line above, but instead it clears the current line AND the one above it.

Can anyone explain what the logic is here? I am okay with the idea of delete + left and right handling characters on the same line, and delete + up and down handling lines, but why is the behavior so inconsistent? What's the logic I am missing here?

Or is it really more of a "there is no consistent logic here really, just memorize it" thing?

Dupleix answered 5/10, 2017 at 5:35 Comment(0)
P
7

This is consistent. Think about it as a textcursor, not as a block cursor so for example:

abc
 ^

You are here with the cursor. For the delete command it is actually like this:

a|bc

Vim always works with ranges. If you do not specify a range, only a target, the first point of the range is always the cursor position: So dh is delete from here to h, with h being the following position:

|abc

So you tell vim to delete from a|bc to |abc hence everything between the cursor positions is deleted.

dl goes to the other direction from a|bc to ab|c -> a|b|c so only the b will be deleted.

In j and k movements, it is line-based, but basically the same.

So if you press dk on the following situation:

abc

abc
 ^

You tell vim to delete every line until you reach the following position:

abc
 ^
abc

This is consistent with all other commands in vim, and is a part of what makes vim so powerful. Think about the search / command for example:

 abc
 a|bc
 abc
 dfe
 dfe 
 dfe

If you press d/dfe<CR> it will not just delete dfe, it will delete until dfe. So you will have following two cursor positions:

 abc
 a|bc
 abc
 |dfe    
 dfe 
 dfe

Everything in between will be deleted, you will end up with:

 abc
 a
 dfe    
 dfe 
 dfe

This is the case for every other movement.

Pipsissewa answered 5/10, 2017 at 6:16 Comment(5)
So if things work on ranges, why do the earlier delete commands appear to be "inclusive" such as the line deletions dj and dk, but deleting until the search item dfe seems to be "exclusive"? I would have expected it to delete one of the dfe's. Delete until vs. delete to (and including).Dupleix
first for the / search. the search command puts the cursor in the first position of the found word. You can modify that with the eflag dfe/e but that unfortunaly doesn't work with the delete command. jand k are linewise movements (you can see that with :h j or :h k) while h l and / are exclusive movements. Again see :h / or :h lPipsissewa
So the range of characters that is actually impacted by an operator depends on where the cursor begins vs. where it ends up, and then that entire range gets modified by the operatorDupleix
yeah, that makes it possible to use it much flexibler. imagine you want do delete 6 lines, it is just d6j with your logic only the 6th line from here on would be delted. This is still possible in vim with :+6d but the normal case is, that you want to delete from where your cursor is, that's why your cursor is there and not 6 lines belowPipsissewa
so the dj behaviour you expected is possible with :+1dPipsissewa
U
1

You shouldn't "assume" or "expect" anything. The behavior of all those commands is explained precisely in Vim's online documentation.

hjkl are motions and d is an operator that works on the text covered by a motion.

  • dj works on the text covered by the j motion. Since j is a linewise motion that moves the cursor to the line below, dj is "cut this line and the one below".

  • dk works on the text covered by the k motion. Since k is a linewise motion that moves the cursor to the line above, dk is "cut this line and the one above".

For horizontal motions, you must understand that the terminal's cursor is actually between two characters:

sample text:                lorem

the "current character":    lorem
                              ^

the "cursor":               lo|rem

the text covered by "h":    l|orem
                              ←

the text covered by "l":    lor|em
                              →
  • dh works on the text covered by the h motion so it cuts the character before the "cursor" which happens to also be the character before the "current character".

  • dl works on the text covered by the l motion so it cuts the character after the "cursor" which happens to be the "current character".

Unequal answered 5/10, 2017 at 6:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.