Trying to understand the logic of deletions in Vim - vim

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?

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.

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".

Related

Insert visual vim selection in the line below at the same position

I have a tedious task of converting chords from leadsheets into an inline format.
The format I have
G A
Never gonna give you up
F#m Bm
Never gonna let you down
G A F# Bm
Never gonna run around and desert you
And the format I need would b
Never gonna g[G]ive you [A]up
Never gonna l[F#m]et you do[Bm]wn
Never gonna r[G]un a[A]round and d[F#]esert [Bm]you
The problem with a script in Ruby or Python is, that the format isn't very consistent. So there could be newlines, weird characters, sometimes the chords are seperated with a dash... I haven't looked through all of the files, but I suspect more malformed stuff.
So I thought, if I have to go through of every leadsheet by hand, at least I can save some time using vim. This is the mapping I've come up with so far:
nmap <C-X> viWc[]<ESC>PviWx<down>p
Select the chord: viW
delete it and go into insert mode: c
add brackets
exit insert mode: <ESC>
paste the register to the left: P
select the chord again, including the brackets: viW
delete the selection: x
move cursor down, and paste it: p
But I few things I can't figure out is:
Sometimes the chords already have brackets, then I don't want to surround them with more brackets. Any idea how to only add brackets, if the chord isn't already surrounded with them?
It would be cool to do this with whole lines of chords. Sometimes there are multiple chords on the same line, and selecting them one by one is tedious. Any idea on how to operate the mapping above on a whole line?
well point 1 could be solved by adding the brackets around the chords on every second line:
:g/^/s/\[\=\zs[a-zA-Z#]\+\ze]\=/\[\0\]/g|+t+|-d
Credits: https://vi.stackexchange.com/questions/34785/search-and-replace-on-odd-even-numbered-lines-using-g
This however sucks, because it moves arround the chords, so we have to remove all brackets first and replace them with space
:%s/\[\([a-zA-Z#]\+\)\]/\1 /g
Then we can do the first line again, but remove some space too. Since there are no brackets left, it gets simpler (Note we use other brackets to get ride of some side effect the following code has):
:g/^/s/\([a-zA-Z#]\+\) \{0,3\}/\{\1\} /g|+t+|-d
Also we add a trailing whitespace at the end of the line so that the df} command will not move the cursor to a wrong place
Now that we have curly brackets everywhere, we can use reverse search with ?{ and then create a macro that jumps from results to result and moves it down, replaces the curly brackets with normal brackets and then calls itself (recursive macro):
gg0
qqq
?{<CR>
qq
df}jPr]F{r[n#qq
#q
And nearly all should be done.
The result:
Never gonna g[G]ive you [A]up
Never gonna l[F#m]et you dow[Bm]n
Never gonna r[G]un a[A]round and d[F#]esert [Bm]you
Note, we have to search backwards (? instead of /) so we can delete the chords directly.
If you have problems understanding what I did, feel free to ask.

Changing case at the end of a word in Vim

I know gUw will turn properties to PROPERTIES and stay at the first character of the word.
But if I use gUb, it will be PROPERTIEs and cursor at the first charactoer.
If I use gUge, it will be PROPERTIES but cursor at last word.
What should I do if I want to turn the word to upper case, and stay at the end of the word(so that i can keep on typing without a w)
All operator+motion edits will leave the cursor on the first character of the motion. From :help motion.txt:
After applying the operator the cursor is mostly left at the start of the text that was operated upon. For example, "yfe" doesn't move the cursor, but "yFe" moves the cursor leftwards to the "e" where the yank started.
So, assuming your cursor is on the last character of the current word:
properties
^
there is no built-in way to ensure that the cursor will stay there after an operator+motion edit.
One can leave a mark and jump back to it after the edit:
m'gUiw``
but that's more work than just pressing w. It could be turned into a mapping, though, if that's a common need:
nnoremap <key> m'gUiw``
but that doesn't sound very scalable.
Another approach would be to record your edit:
qq
m'gUiw``
q
and play it back as needed:
#q
But your last sentence is puzzling:
What should I do if I want to turn the word to upper case, and stay at the end of the word(so that i can keep on typing without a w)
If you are at the end of:
properties
^
and your edit leaves the cursor at the beginning of:
PROPERTIES
^
w will move the cursor to the beginning of the next word:
PROPERTIES foo
^
and not to the end of the current word.
We are missing some context, here.

what's the difference between command cw and ciw in Vim?

Here's a link I find in stackoverflow about this question.
but I still cannot understand without a specific example about what's the difference between "change inner word" and "change word".
I test these two commands in my vim and finally find no differences ,Please give me an example to help me understand, thank you!
Here is an example:
foo bar baz
^
Typing cw and ciw will give the same result in this case (with the cursor positioned on the 'b' of 'bar').
Consider this:
foo bar baz
^
cw will yield
foo b baz
^
where ciw will yield
foo baz
^
so it changes the whole word, regardless of the cursor position. Very useful, i love this command.
Very useful is also the caw (or the aw) command:
foo bar baz
^
-> caw
foo baz
^
aw also contains the space. Try these commands with the v (visual) command, to see what they all do. Also, read motion.txt, part 6.
Above answers addressed HOW they behave different, i would like to share some idea on WHY they behave different.
First, in vim's world, w and iw have different semantics and can both be seen as target(see below):
w in cw refers to a Motion Object
while iw in ciw refers to a TextObject
Secondly, in Vim editing, Operator (c/change in your case, and y/yank, d/delete, =/indenting, >/shifting etc) and Target (w and iw in your case) helps you achieve what you want to do with less keystrokes compared to using visual selection + operator.
TextObject defines target range (start and end position).
Motion is essentially used to move cursor, so it only define final-target-position (destination to move).
Some good materials to read:
:h motion.txt part 4, 5
AdvancedTopicTutorial from atom-vim-mode-plus
someword
^ (cursor)
cw
some_
^ (cursor)
Changes from cursor to end of word. Leaves the start of the word.
Compared to
someword
^ (cursor)
ciw
_
^ (cursor)
Changes the entire word from start to end.
Mind you, cw has a bit 'unstandard' behavior by default in that it is behaves exactly like ce: It only works up until the end of the current word (like e, ce, de, ye) instead of including the whitespace up before the beginning of the next word (like w, dw, yw).
Therefore I recommend adding these mappings to your vimrc:
" Have `cw` adhere to its actual movement `w`, instead of duplicating `ce`.
nnoremap cw dwi
nnoremap cW dWi
and getting used to usually using ce. Typing ce is actually more efficient and less awkward than cw if you form the habit of pressing the e with your ring finger instead of middle finger when it comes right after c.
If you prefer to leave cw with its default assignment duplicating ce, then you can access its 'proper' functionality with an additional keystroke: dwi (or vwc).
(Mind you, I find dwi even more efficient to type than cw because of the positions of the keys, in spite of the additional key.)
Explanation of the second mapping: W (Shift+w) works on what vim calls "WORDS", which counts every non-blank character, e.g. punctuation, as part of a WORD; while w works on "words", which only consist of uninterrupted sequences of letters, digits and underscores (by default).

vim - How to delete a large block of text without counting the lines?

In vim, I often find myself deleting (or copying) large blocks of text. One can count the lines of text and say (for example) 50dd to delete 50 lines.
But how would one delete this large block of text without having to know how many lines to delete?
Go to the starting line and type ma (mark "a"). Then go to the last line and enter d'a (delete to mark "a").
That will delete all lines from the current to the marked one (inclusive). It's also compatible with vi as well as vim, on the off chance that your environment is not blessed with the latter.
I'm no vim guru, but what I use in this circumstance is "visual mode". In command mode, type V (capital). Then move up/down to highlight the block you want deleted (all the usual movement commands work). Then remove it with x or d.
You can use the visual mode also (some commands are usable with the delete option also)
vip vap to select paragraph, v2ap to select two paragraphs
dap works, d2ap also. You can delete within blocks of [ ] like da[
For reference: the types of objects.
From vim documentation : section 4. http://vimdoc.sourceforge.net/htmldoc/visual.html
4. Operating on the Visual area *visual-operators*
...
The objects that can be used are:
aw a word (with white space)
iw inner word
aW a WORD (with white space)
iW inner WORD
as a sentence (with white space)
is inner sentence
ap a paragraph (with white space)
ip inner paragraph
ab a () block (with parenthesis)
ib inner () block
aB a {} block (with braces)
iB inner {} block
a< a <> block (with <>)
i< inner <> block
a[ a [] block (with [])
i[ inner [] block
There are many better answers here, but for completeness I will mention the method I used to use before reading some of the great answers mentioned above.
Suppose you want to delete from lines 24-39. You can use the ex command
:24,39d
You can also yank lines using
:24,39y
And find and replace just over lines 24-39 using
:24,39s/find/replace/g
It sort of depends on what that large block is. Maybe you just mean to delete a paragraph in which case a dip would do.
If you turn on line numbers via set number you can simply dNNG which will delete to line NN from the current position. So you can navigate to the start of the line you wish to delete and simply d50G assuming that is the last line you wish to delete.
There are several possibilities, what's best depends on the text you work on.
Two possibilities come to mind:
switch to visual mode (V, S-V,
...), select the text with cursor
movement and press d
delete a whole paragraph with: dap
If the entire block is visible on the screen, you can use relativenumber setting. See :help relativenumber. Available in 7.3
Counting lines is too tedious for me, but counting 'paragraphs' isn't so bad. '{' and '}' move the cursor to the first empty line before and after the cursor, respectively. Cursor moving operations can be combined with deletion, and several other answers used a similar approach (dd for a line, dG for the end of the document, etc.)
For example:
/* Lorem ipsum dolor sit amet, consectetur adipiscing elit. */
Lorem *ipsum(void) {
return dolor(sit, amet);
}
If your cursor starts above the comment block, 'd}' deletes the comment block, and 'd2}' deletes both the comment block and the code block. If your cursor starts below the code block, 'd{' deletes the code, and 'd2{' deletes both. Of course, you can skip over one block by moving the cursor first: '{d{' or '}d}'.
If you're consistent with your whitespace, or you can count the paragraphs at a glance, this should work. The Vim help file has more cursor tricks if you're interested.
You could place your cursor at the beginning or end of the block and enter visual mode (shift-v). Then simply move up or down until the desired block is highlighted. Finally, copy the text by pressing y or cut the text by pressing d.
Alongside with other motions that are already mentioned here, there is also /{pattern}<CR> motion, so if you know that you want to delete to line that contains foo, you could do dV/foo<CR>. V is here to force motion be line-wise because by default / is characterwise.
You can also enter a very large number, and then press dd if you wish to delete all the lines below the cursor.
Deleting a block of text
Assuming your cursor sits at the beginning of the block:
V/^$<CR>d (where <CR> is the enter/return key)
Explanation
Enter "linewise-visual" mode: V
Highlight until the next empty line: /^$<CR>
Delete: d
Key binding
A more robust solution:
:set nowrapscan
:nnoremap D V/^\s*$\\|\%$<CR>d
Explanation
Disable search wrap: :set nowrapscan
Remap the D key (to the following commands): :nnoremap D
Enter "linewise-visual" mode: V
Highlight until the next empty/whitespace line or EOF: /^\s*$\\|\%$<CR>
Delete: d

Vim yanking range of lines

I'm a C# developer who has just recently decided to expand my knowledge of the tools available to me. The first tool I've decided to learn is Vi/Vim. Everything has been going well so far, but there are a couple of questions I can't seem to find the answer to:
Lets say I wanted to yank a range of lines. I know there are many ways of doing so, but I would like to do it by line number. I figured it would be similar to how the substitute commands work, something like 81,91y. Is there a way to do this?
I'm a little confused about the g command in normal mode. It seems to do a myriad of things and I can't really determine what the g command does at its core. I'm confused on whether or not it's a motion command or a kind of "catch all" for other commands ran through normal mode. Can someone please explain this or point me to a reference that gives a good explanation of the g command?
Yank lines 81-91
:81,91y<enter>
If your fingers don't like to find the : and , keys, this would work as well (go to line 81, yank 11 lines)
81gg11yy
My only use of g is 5gg. To go to the 5th line. 22gg: 22nd line. As jimbo said, it's really only a modifier for some other commands.
For completeness, (http://vim.wikia.com/wiki/Power_of_g) explains a lot of how g works in command mode.
You can also copy the current lines to your present cursor location using 't'.
:81,91t.<enter>
This will paste the lines 81-91 under the line the cursor is on.
I learned this from http://vimcasts.org which is an excellent resource on VIM.
I also like to use vim's relative line number option which means I can just enter:
:-10,-7ya a
to yank the text into named buffer a.
N.B. Specifying A will append what you're yanking to the current contents of buffer a.
Don't forget you can also copy blocks of text and move blocks of text around as well with the similar commands:
:-10,-7co .
means copy the four lines of text 10 lines above to below the current line, and
:-10,-7mo .
means move the four lines of text 10 lines above to below the current line.
The G command goes to a certain line number, if it's accompanied by a count value. 81G puts you on line 81.
The y command can be combined with a movement, like G. So to yank everything until line 91 you can use y91G.
Together you get:
81Gy91G
Go to line 81, then yank while going to line 91.
g doesn't do anything by itself. It's one of a couple meta-commands that holds a bunch of sorta-unrelated commands.
z is yet another command like that.
In addition to :91,96y a which yanks (y) lines 91 through 96 into register a, (pasted with "ap), the yanked lines can be appended to the register with:
:91,96y A
I.e. the capitalization of the A register causes an appending operation into register a instead of an overwrite. Capitalization of the register always works like this, e.g. :let #A=';' appends a ; to register a.
Using plus (+) or minus (-) references lines relative to the current cursor position:
:-10,+10y b
I.e. it would yank(y) 21 lines around the current cursor position and put them in register b.
An absence of input actually represents the current cursor position as well, which means that this:
:-5,y a
would yank the text from 5 lines above to current cursor position into named buffer a, and:
:,+5y a
would yank the 5 lines after the current cursor position into buffer a.
Note: If you have a macro in buffer a it was just overwritten by the previous yank, as yank registers and macro registers are really the same thing. Which is why, coincidentally, you can paste a macro, edit it, and then yank it back into it's register. I personally use letters reached by my left hand for yanks, and letters reached by my right hand for macros.
Moving blocks of text around, looks like this:
:+10,+13m.
which means move the four lines positioned 10 lines ahead of current cursor, to below the current line.
Addendum
I previously confused ya in :91,95ya a to be somehow synonymous with ya{motion} where the motion was supplied by 91,95. This was incorrect and the "a" in ya is completely unnecessary. In my defense, my help yank does not convey that ya is a possible alias of yank.
The best solution would be to enter "visual mode", by pressing v. And after selecting lines just copy them by pressing y. Then paste copied lines by pressing p.
Vim's :help index describes g as:
|g| g{char} extended commands, see |g| below
Scroll down (or :help g) for a list.
As a long time Vi/Vim user I tend to use 'marks' instead of line numbers (or 'line markers'). It works like this: m is the 'mark' character; then use any letter to identify/name the mark. To return to a mark preface the named mark with a single quote ( 'a)These marks can be used as the range. Examples:
File:
<line 1>
<line 2>
<line 3>
<line 4>
<line 5>
When in command mode move cursor to line 2, typema. scroll to line 4, typemb.
To yank from mark a to mark b type:
:'a,'byank
To delete from mark a to mark b type:
:'a,'bdel
To search from mark a to mark b and replace 'ine' with 'ink':
:'a,'bs/ine/ink/g
To copy mark a through mark b and paste below the current position (the 'dot' always references the line where the cursor currently is positioned):
:'a,'bco .
Shift lines of code, between mark a through mark b, one tab to the right (use opposite chevron, <, to move left):
:'a,'b>
In command mode you can move back to marks by simply typing 'a to move back to the line marked a. Typing '' moves you back to previous position (unfortuantely only remembers the previous position, not two back).
You can yank to named buffers, copy, delete lines, search&replace just portions of your code, etc. without needing to know the line numbers.
To yank lines from line number 81 to 91 :
approach 1: 81gg11yy
not bad but you have to do little bit of math to find out how many lines to yank
approach 2: 81gg then shift+v then 91gg then y
BEST IN MY OPINION because this is straight forward, you only have to know the obvious thing i.e from which line number to which line number you want to yank

Resources