Vim - g command for deleting characters in specific columns - vim

I want to delete 5 characters starting from column 11 in the whole file.
When I type
11|5x
it works for the line the cursor is on.
But when I type
:g/.*/11|5x
the editor closes.
How should I use the g command properly?

Understanding Vi(m) modes is key to mastering it.
The | command to jump to a screen column is a normal mode command, but the :global command takes Ex commands. The :normal Ex commands interprets following arguments as normal mode commands (with !: without considering mappings (which is safer)):
:g/.*/normal! 11|5x
PS: A shorter "match anywhere" pattern for :g is ^ instead of .*.

try
:g/./norm! 11|5x
you need the normal

The normal | motion bring the cursor to a screen column, which may not be expected when you have multi-column characters like <Tab> in a line.
Substitution globally like below can avoid this problem:
%s/\%10c.\{5}/, in which \%10c matches the column position of the 10th character.

Related

Move cursor to end of line in vim (to delete last word)

I usually type the command db to remove one word backwards in Vim. Doing this at the end of a line without whitespace leaves the last character of the word since the cursor starts removing from the second last character.
I can press b followed by de instead, but I find this confusing sometimes when doing it many times in a row, leading to unneccesary mistakes. I was hoping there was a way to go to the end of the line and remove the last word backwards.
Is there a way to do this?
You should train yourself to stop using db and learn to love text objects instead. This problem happens even if you're not at the end of a line.
foo bar baz
^
and then db will give
foo r bax
^
Instead of using db or de or even dw, train yourself to use diw and daw. This might take some getting used to, but down the road it will become natural and be way more convenient to use. And once the text objects become natural to you, you can then start using other commands ('c' or 'y', etc.) or even other text objects. (I can't even count how many times I've used dap or ci()
For a short explanation of what these do, think of diw as (d)elete (i)nside this (w)ord and daw as (d)elete (a)round this (w)ord or (d)elete (a) (w)ord. For a more concrete example:
foo bar baz
^
typing diw gives
foo bar
^
(note the leading space)
But
foo bar baz
^
typing daw gives
foo bar
^
And as long as your cursor is over the same word, these will still do the same thing. So if we moved the cursor back to the 'a' or the 'b', you'll get the exact same results. This blog goes into more depth on text objects.
You can either:
use a mapping like this:
:nnoremap <silent> db :exe 'norm!' (col('.')==col('$')-1 ? 'daw' : 'db')<cr>
alternatively, you can do :set ve=onemore which allows you to go one
char past the end of line, then once your cursor is past the end (see command g$), simply use db.
EDIT (explanations)
:exe executes the string formed by its arguments as a command.
So if the cursor is at the end of line (col('.')==col('$')-1),
it will execute:
:norm! daw
otherwise it will execute:
:norm! db
:norm lets you run normal commands in the command line. For example if you're already in
normal mode, typing :norm db + return will do the same as just typing db.
It's useful inside commands. The ! prevents mappings to be used in the :norm commands.
See :h :norm.
<silent> makes a mapping silent: without it you would see
:exe 'norm!' (col('.')==col('$')-1 ? 'daw' : 'db') in the bottom of the
screen.
See :h <silent>.
<cr> is the key code for the return key. You can put this kind of codes inside mappings.
In this case, <cr> will validate the command just entered in the mapping.
See :h keycodes for details.
What about
$diw
$ - takes you to last character of the line
d - as you know is for delete
i - implies from inside. Read more on other powerful text objects :help text-objects
w - word
If you are not habituated using text-objects, start using. You will love it

Exiting exe mode in a macro

I had a large file I was trying to reformat which involved removing the 2nd to nth repeating sets on 2 to 100 lines per duplicate.
The data looked like
element1.element2.element...field.comment
I wanted to remove the repetition in elements after the first instance so of course I went complicated :) and did a macro something like
In a macro Yanked first element on current line to register p and then processed lines yanking the first element into register o and then doing, still in the macro
:if (#p=!#o)|:.s/paste register p//g|else|:norm! j|endif
Now this worked OK except when it got to a line where #p<>#o the :norm! j part stayed in : mode until I manually escaped once or twice then executed the :norm! j command.
I solved the problem an easier way but would like to know why it was only on the else portion that it wouldn't leave :ex mode.
From :help norm
:norm[al][!] {commands} *:norm* *:normal*
...
This command cannot be followed by another command,
since any '|' is considered part of the command.
...
An alternative is to use |:execute|, which uses an
expression as argument. This allows the use of
printable characters to represent special characters.
Example: >
:exe "normal \<c-w>\<c-w>"
So this would do the trick:
:if (#p=!#o)|:.s/paste register p//g|else|:exe "norm j"|endif

Run vim command on every line in a vim buffer

I want to JJ on every line in the current vim buffer. As I have very huge file, it is not possible to manually run on every line. How can I tell vim to do this for me?
Basically I have a file which has data in single column. I want to convert it to three columns
a
b
c
to:
a b c
And another one:
:%norm JJ
See :help :normal.
Use Macro and Normal mode command.
qqJJq
Recoding JJ commands to q
uu
Define q macro. undo all.
:%norm! #q
apply q to entire document.
PS : I'm not good at english
:g/^/join
joins consecutive lines (1+2, 3+4, and so on...) in the entire buffer. You can also supply a [range] to the :global command, which here is only used for its intelligent line handling; the ^ regular expression pattern matches any line.
To join three consecutive lines, use either
:g/^/.,.+2join
or
:g/^/join|join
(The former may give an error if the total amount of lines isn't divisible by 3; the latter avoids that.)

Vim: How to delete the same block of text over the whole file

I'm reviewing some logs with Java exception spam. The spam is getting is making it hard to see the other errors.
Is is possible in vim to select a block of text, using visual mode. Delete that block every place it occurs in the file.
If vim can't do it, I know silly question, vim can do everything. What other Unix tools might do it?
Sounds like you are looking for the :global command
:g/pattern/d
The :global command takes the form :g/{pat}/{cmd}. Read it as: run command, {cmd}, on every line matching pattern, {pat}.
You can even supply a range to the :delete (:d for short) command. examples:
:,+3d
:,/end_pattern/d
Put this togehter with the :global command and you can accomplish a bunch. e.g. :g/pat/,/end_pat/d
For more help see:
:h :g
:h :d
:h :range
Vim
To delete all matching lines:
:g/regex/d
To only delete the matches themselves:
:%s/regex//g
In either case, you can copy the visual selection to the command line by yanking it and then inserting it with <C-r>". For example, if your cursor (|) is positioned as follows:
hello wo|rld
Then you can select world with viw, yank the selection with y, and then :g/<C-r>"/d.
sed
To delete all matching lines:
$ sed '/regex/d' file
To only delete the matches themselves:
$ sed 's/regex//g' file
grep
To delete all matching lines:
$ grep -v 'regex' file
grep only operates line-wise, so it's not possible to only delete matches within lines.
you can try this in vim
:g/yourText/ d
Based on our discussion in the comments, I guess a "block" means several complete lines. If the first and last lines are distinctive, then the method you gave in the comments should work. (By "distinctive" I mean that there is no danger that these lines occur anywhere else in your log file.)
For simplifications, I would use "ay$ to yank the first line into register a and "by$ to yank the last line into register b instead of using Visual mode. (I was going to suggest "ayy and "byy, but that wold capture the newlines)
To be on the safe side, I would anchor the patterns: /^{text}$/ just in case the log file contains a line like "Note that {text} marks the start of the Java exception." On the command line, I would use <C-R>a and <C-R>b to paste in the contents of the two registers, as you suggested.
:g/^<C-R>a$/,/^<C-R>b$/d
What if the yanked text includes characters with special meaning for search patterns? To be on the really safe side, I would use the \V (very non-magic) modifier and escape any slashes and backslashes:
:g/\V\^<C-R>=escape(#a, '/\')<CR>\$/,/\V\^<C-R>=escape(#b, '/\')<CR>\$/d
Note that <C-R>= puts you on a fresh command line, and you return to the main one with <CR>.
It is too bad that \V was not available when matchit was written. It has to deal with text from the buffer in a search pattern, much like this.

VIM substitution: Using the current line as the search string

Assuming the following text file, which is actually a data dump of funds and price statistics:
PBCPDF
05/01/2006
0.0000
0.0000
PBCPDF
0.0000
06/01/2006
0.0000
0.0000
PBCPDF
0.0082
[… lines repeat …]
What I wanted to achieve is to delete all instances of PBCPDF except for the first one, which I could write the substitution command as :.+1,$s/PBCPDF\n//g.
However, since I wanted to program a macro to process multiple fund names, I need a means to use some sort of pattern that would retrieve the current line as the search pattern without me doing it by hand.
Is there a way to do that?
ggyy:+1,$s/<Ctrl-R>"<BS>//g
Let's see what that does, exactly.
Go to the first line
gg
Yank the entire liine
yy
Start the substitution
:+1,$s/
Get the current line from the register to which you yanked it to:
<Ctrl-R>"
Note: Don't type the ", you have to actually hold Control and press R, followed by a double quote.
Delete the end of line character:
<BS>
Note: press Backspace.
Replace with nothing.
//g
You can record this in a macro by wrapping it with a qq/q, or whatever.
If you're doing this in a macro (using the q command) it's smart enough to catch when you do some of the more esoteric keystroke commands - the one I'm specifically thinking about is CTRL-R, CTRL-W, which will insert the word under the cursor into the command line. So, for example, if you did
ESC
qw
/[CTRL-R, CTRL-W] (you should see the word under the cursor enter the command line)
[enter]
q
then you just created a macro that searches for the next word in the buffer that's the same as this one, get it? It will dynamically yank the word under the cursor into the command as part of the macro. There might be something like CTRL-W in the command above that does this for the whole line, but I don't know it offhand.
Having studied sykora's and Matt's answers, I came up with a slightly better improvement which works on a line-wise basis rather than a word-wise basis (as per Matt's solution).
This command is to be executed after the cursor is positioned on the line of which the deletion is to occur:
:.+1,$s/<CTRL-R>=getline(".")<CR>\n//g
Explanation for VIM beginners:
:.+1,$s/
Start substitution from the line after the current line (.+1) and the end-of-file ($)
<CTRL-R>=getline(".")<CR>\n
<CTRL-R> refers to the actual pressing of the CTRL and R keys, which allows you to enter special expressions. In this case, =getline(".") which retrieves the text of the current line.
<CR> refers to the pressing of the enter key, which completes the <CTRL-R> expression. I also specify the newline character (\n) at the end of the search pattern as I need to remove it.
//g
And then replace with nothing.

Resources