delete from end of lines using block select in vim - vim

I'm getting an unusual behavior when I try to delete from end of lines using block selection in vim.
So let's say I have a text as such:
delete this char:x
and this:x
also this:x
and then this:x
lastly this:x
If I want to append y to every line I can:
start block selection with C-v
select all the lines with 4j
go to ends of lines with $
start appending with A
type the desired text y
in order to get:
delete this char:xy
and this:xy
also this:xy
and then this:xy
lastly this:xy
but if I try to delete x in the last step instead of appending I would expect to get:
delete this char:
and this:
also this:
and then this:
lastly this:
although I end up with:
delete this char:
and this:x:
also this:x:
and then this:x:
lastly this:x:
As far as I understand it appends the last char in the first line to all other lines (in this case :) rather than deleting the missing ones (in this case x).
I can do this with macros or substitutes but I don't quite understand the rationale behind such behavior. Is there a way I can do this with block selection?

Have you tried :{range}normal? This should work:
:'<,'>normal $x
(The '<,'> bit is filled in for you when you type :.)

$ C-v 4j x
go to end of line with $
toggle visual block C-v
go down (in your case 4x) 4j
delete that stuff with x
Edit: (reacting on your comment for arbitrary indentation)
That can be done with simple macro. Macros are not so hard as you can think:
start recording a macro, we will name it 'a', so qa
go to the end of line $
delete one character x
go down by one line with j
end our macro q
Now apply our macro: 20#a - will do the same you did while you was recording the macro, 20x.

If I have a small number of lines I typically do Abackspaceesc. Then repeatedly do j. until done. Not the fastest way but easy to remember.
For a large amount of lines I typically visually select the lines via V then do a substitution or a normal command on the range.
:'<,'>s/.$//
:'<,'>norm $x
Note: you do not have to type '<,'>. It will be inserted automatically when you start a command when some text is visually selected.
The substitution command is pretty simple, match the last character (.$) and then replace it with nothing.
The normal command is just how you would delete the last character in normal mode via $x for a single line except it will apply it to each line in the range.
For more help see:
:h range
:h :s
:h :norm

as you said yourself, to achieve your goal, there are other ways, in fact better ways to go. :s or q(macro) or :g/.../norm $x. :s/.$//g is pretty straightforward.
Ctrl-V is not suitable for this job. As for its name: Visual BLOCK. You want to remove the last x, and they (only x) are not in a block.
However if you really want to stick with ctrl-v, you have to do some extra work, to make those 'x' in a block. If you have Align plugin installed, you could :
Select (V) all lines you want to do the trick,
<leader>t:
then your text looks like:
delete this char : x
and this : x
also this : x
and then this : x
lastly this : x
Ctrl-V to remove x, you should know how to do it.
then
:%s/ *:/:/g
to remove padded spaces before ':'
However I don't think it is a good way to go.

Related

VIM Select Entire Line

How do you select a single line in VIM, when your cursor as at some random point along that line?
I know you can do (v, $) to get to the end of the line, or (v, ^) to get to the start, but when you do (v,$,^) it logically doesn't select the whole line, it selects from cursor, until end, then switches it to cursor until beginning... So this approach fails of course.
Capital V selects the current line in one key stroke; two, if you include the "shift" in shift+v.
V would be direct answer. However, I rarely need to do this because "selecting the current line" is generally part of a larger task. Example of such tasks includes copying the line and deleting the line. There's generally a better way to accomplish the task as a whole. The following are some of the tasks I can think of:
copy the line: yy
delete the line: dd
indent the line: >> or <<
select the current paragraph: vap or vip
delete from the current line to the end of the file 0dG
highlight the current line to see where my cursor is: use :set cursorline in .vimrc file
One case in which I do use V is to select multiple lines that are not a paragraph or some other text object. In this case, there's a tip that might be useful for you: once in the selection mode, you can use o to jump the cursor between the start and the end of the selection.
While this might be more keystrokes.
If you are already in visual mode you can use o to go to the other end of the visual selection.
So you can type
v0o$
To select the whole line. Take a look at :h visual-change
However from the comments it seems you just want to copy the whole line.
Which would just be yy
Just change your order of operations. You almost have it.
^,v,$
Or as suggested by #Kent: because ^ goes to the first non-empty char, if the line has leading spaces:
0,v,$
I know this thread is super old, but I just had the same question. This thread came up first, but I found a different answer than any found here. Use 'V' to select whole lines. That easy. One character to select the whole current line.

Vim: substitution in a range that is less than a line

Let's say I have the following line of code:
something:somethingElse:anotherThing:woahYetAnotherThing
And I want to replace each : with a ; except the first one, such that the line looks like this:
something:somethingElse;anotherThing;woahYetAnotherThing
Is there a way to do this with the :[range]s/[search]/[replace]/[options] command without using the c option to confirm each replace operation?
As far as I can tell, the smallest range that s acts on is a single line. If this is true, then what is the fastest way to do the above task?
I'm fairly new to vim myself; I think you're right about range being lines-only (not 100% certain), but for this specific example you might try replacing all of the instances with a global flag, and then putting back the first one by omitting the global -- something like :s/:/;/g|s/;/:/.
Note: if the line contains a ; before the first : then this will not work.
Here you go...
:%s/\(:.*\):/\1;/|&|&|&|&
This is a simple regex substitute that takes care of one single not-the-first :.
The & command repeats the last substitute.
The | syntax separates multiple commands on one line. So, each substitute is repeated as many times as there are |& things.
Here is how you could use a single keystroke to do what you want (by mapping capital Q):
map Q :s/:/;/g\|:s/;/:<Enter>j
Every time you press Q the current line will be modified and the cursor will move to the next line.
In other words, you could just keep hitting Q multiple times to edit each successive line.
Explanation:
This will operate globally on the current line:
:s/:/;/g
This will switch the first semi-colon back to a colon:
:s/;/:
The answer by #AlliedEnvy combines these into one statement.
My map command assigns #AlliedEnvy's answer to the capital Q character.
Another approach (what I would probably do if I only had to do this once):
f:;r;;.
Then you can repeatedly press ;. until you reach the end of the line.
(Your choice to replace a semi-colon makes this somewhat comfusing)
Explanation:
f: - go to the first colon
; - go to the next colon (repeat in-line search)
r; - replace the current character with a semi-colon
; - repeat the last in-line search (again)
. - repeat the last command (replace current character with a semi-colon)
Long story short:
fx - moves to the next occurrence of x on the current line
; repeats the last inline search
While the other answers work well for this particular case, here's a more general solution:
Create a visual selection starting from the second element to the end of the line. Then, limit the substitution to the visual area by including \%V:
:'<,'>s/\%V:/;/g
Alternatively, you can use the vis.vim plugin
:'<,'>B s/:/;/g

Prepending a character followed by the line number to every line

I'm hand-editing CNC Gcode text files and need a way to reference locations in the file and on the toolpath.
I want to modify every line in the text file so that it begins with the the upper case letter N followed by the line number, incremented in tens for each successive line, then a whitespace followed by the original text on that line. How can I do this in Vim?
I'm not sure about vi, but (since you're using the vim tag) Vim allows you to accomplish your task as follows:
Adjust the first line by hand (insert a N10 at the beginning of the line), then put the cursor at the beginning of the next line.
Press qb to start recording a macro (the b names the register used to store the macro; feel free to use a different letter -- and definitely do use a different letter if you've got something useful stashed away in b).
Move the cursor upward to the beginning of the previous line (which you have adjusted by hand). Press v to start visual selection mode, then f to move the cursor to the next space on the line (if you use a single space as your whitespace separator, that is; adjust this step if you're using a tab or multiple spaces).
Press y to yank the selected text. This will also remove the visual selection.
Move the cursor to the beginning of the next line. Press P to insert the previously yanked text before the cursor, that is, on the very beginning of the line.
Move the cursor to the numeric part of the line header. Press 10 C-a (1, 0, control + A) to increment that number by 10.
Move the cursor to the beginning of the next line. Press q to stop recording the macro.
Press 10000000 #b to execute the macro 10000000 times or until it hits the end of the file. This should be enough to take care of all the lines in your file, unless it is really huge, in which case use a bigger number.
...or use Vim to write a simple script to do the job in whichever language you like best, then run it from a terminal (or from withing Vim with something like :!./your-script-name). ;-)
The following command will prepend ‘N<line number * 10>’ to every line:
:g/^/exe 'normal! 0iN' . (line('.')*10) . ' '
You can do it easily in Vim with this:
:%s/^/\=line(".")*10 . " "/
This replaces the start of every line with the result of an expression that gives the line number times ten, followed by a space.
I have not timed it, but I suspect it might be noticeably faster than the other Vim solutions.
Cheating answer:
:%!awk '{print "N" NR "0", $0}'
There are two ways to implement that without resorting to external
tools: via a macro or by using Vimscript. In my opinion, the first way
is a little cumbersome (and probably not as effective as the solution
listed below).
The second way can be implemented like this (put the code into your
.vimrc or source it some other way):
function! NumberLines(format) range
let lfmt = (empty(a:format) ? 'N%04d' : a:format[0]) . ' %s'
for lnum in range(a:firstline, a:lastline)
call setline(lnum, printf(lfmt, lnum, getline(lnum)))
endfor
endfunction
The NumberLines function enumerates all lines of the file in a given
range and prepends to each line its number according to the provided
printf-format (N%04d, by default).
To simplify the usage of this function, it is convenient to create
a command that accepting a range of lines to process (the whole file,
by default) and a optional argument for the line number format:
command! -range=% -nargs=? NumberLines <line1>,<line2>call NumberLines([<f-args>])

How to remove quotes surrounding the first two columns in Vim?

Say I have the following style of lines in a text file:
"12" "34" "some text "
"56" "78" "some more text"
.
.
.
etc.
I want to be able to remove the quotes surrounding the first two columns. What is the best way to do this with Vim (I'm currently using gVim)?
I figured out how to at least delete the beginning quote of each line by using visual mode and then enter the command '<,'>s!^"!!
I'm wondering if there is a way to select an entire column of text (one character going straight down the file... or more than 1, but in this case I would only want one). If it is possible, then would you be able to apply the x command (delete the character) to the entire column.
There could be better ways to do it. I'm looking for any suggestions.
Update
Just and FYI, I combined a couple of the suggestions. My _vimrc file now has the following line in it:
let #q=':%s/"\([0-9]*\)"/\1/g^M'
(Note: THE ^M is CTRLQ + Enter to emulate pressing the Enter key after running the command)
Now I can use a macro via #q to remove all of the quotes from both number columns in the file.
use visual block commands:
start mode with Ctrl-v
specify a motion, e.g. G (to the end of the file),
or use up / down keys
for the selected block specify an action, e.g. 'd' for delete
For more see
:h visual-mode
Control-V is used for block select. That would let you select things in the same character column.
It seems like you want to remove the quotes around the numbers. For that use,
:%s/"\([0-9]*\)"/\1/g
Here is a list of what patterns you can do with vim.
There is one more (sort of ugly) form that will restrict to 4 replacements per line.
:%s/^\( *\)"\([ 0-9]*\)"\([ 0-9]*\)"\([ 0-9]*\)"/\1\2\3\4/g
And, if you have sed handy, you can try these from the shell too.
head -4 filename.txt | sed 's/pattern/replacement/g'
that will try your command on the first 4 lines of the file.
Say if you want to delete all columns but the first one, the simple and easy way is to input this in Vim:
:%!awk '{print $1}'
Or you want all columns but the first one, you can also do this:
:%!awk '{$1="";$0=$0;$1=$1;print}'
Indeed it requires external tool to accomplish the quest, but awk is installed in Linux and Mac by default, and I think folks with no UNIX-like system experience rarely use Vim in Windows, otherwise you probably known how to get a Windows version of awk.
Although this case was pretty simple to fix with a regex, if you want to do something even a bit more advanced I also recommend recording a macro like Bryan Ward. Also macros come easier to me than remembering which characters need to be escaped in vim's regexes. And macros are nice because you can see your changes take place immediately and work on your line transformation in smaller bits at a time.
So in your case you would have pressed qw to start recording a macro in register w (you can of course use any letter you want). I usually start my macros with a ^ to move to the start of the line so the macro doesn't rely on the location of the cursor. Then you could do a f" to jump to the first ", x to delete it, f" to jump to the next " and x to delete that too. Then q to finish recording.
Instead of making your macro end on the next line I actually as late as today figured out you can just V (visually line select) all lines you want to apply your macro to and execute :normal #w which applies your macro in register w to each visually selected line.
See column editing in vim. It describes column insert, but basically it should work in the same way for removing.
You could also create a macro (q) that deletes the quotes and then drops down to the next line. Then you can run it a bunch of times by telling vi how many times to execute it. So if you store the macro to say the letter m, then you can run 100#m and it will delete the quotes for 100 lines. For some more information on macros:
http://vim.wikia.com/wiki/Macros
The other solutions are good. You can also try...
:1,$s/^"\(\w\+\)"/\1/gc
For more Vim regex help also see http://vim.wikia.com/wiki/Search_patterns.
Start visual-block by Ctrl+v.
Jump at the end and select first two columns by pressing: G, EE.
Type: :s/\%V"//g which would result in the following command:
:'<,'>s/\%V"//g
Press Enter and this will remove all " occurrences in the selected block.
See: Applying substitutes to a visual block at Vim Wikia

Swap text around equal sign

Is there an easy way to flip code around an equal sign in vi/vim?
Eg: I want to turn this:
value._1 = return_val.delta_clear_flags;
value._2._1 = return_val.delta_inactive_time_ts.tv_sec;
value._2._2 = return_val.delta_inactive_time_ts.tv_nsec;
value._3 = return_val.delta_inactive_distance_km;
(...)
into this:
return_val.delta_clear_flags = value._1;
return_val.delta_inactive_time_ts.tv_sec = value._2._1;
return_val.delta_inactive_time_ts.tv_nsec = value._2._2;
return_val.delta_inactive_distance_km = value._3;
(...)
on A LOT of lines in a file.
I know this seems a little trivial, but I've been running into lots of cases when coding where I've needed to do this in the past, and I've never had a good idea/way to do it that didn't require a lot of typing in vim, or writing a awk script. I would think this would be possible via a one liner in vi.
Explanations of the one-liners is very welcome and will be looked upon highly when I select my accepted answer. :)
Something like this:
:%s/\([^=]*\)\s\+=\s\+\([^;]*\)/\2 = \1
You might have to fiddle with it a bit if you have more complex code than what you have shown in the example.
EDIT: Explanation
We use the s/find/replace comand. The find part gets us this:
longest possible string consisting of anything-but-equal-signs, expressed by [^=]* ...
... followed by one or more spaces, \s\+ (the extra \ in front of + is a vim oddity)
... followed by = and again any number of spaces, =\s\+
... followed by the longest possible string of non-semicolon characters, [^;]*
Then we throw in a couple of capturing parentheses to save the stuff we'll need to construct the replacement string, that's the \(stuff\) syntax
And finally, we use the captured strings in the replace part of the s/find/replace command: that's \1 and \2.
For interest's sake, here's how I did it as a recorded macro:
qq0"+df=xA<BACKSPACE> = <ESC>"+pxi;<ESC>jq
Peforming that on the first line sets the "q" macro to do what's required. Then on each subsequent line you can execute the macro by typing:
#q
or, say you want to apply the macro to the next 10 lines:
10#q
I always find macros easier for a quick switch like this than figuring out the regex, because they're essentially an extension of how I would do it by hand.
Edit: Dan Olson points out in his comment that if you want to then apply the macro to a range of lines, for instance lines 6-100, you can enter the following. I don't know if there's a more concise syntax that doesn't require the ".*" pattern match.
:6,100g/.*/normal #q
Explanation of the macro
qq
start recording in register q
0
go to beginning of line
"+df=
delete up to the '=' and put the text into the '+' register
x
delete extra space
A
go to end of line and enter insert mode
<BACKSPACE> = <ESC>
Delete the semicolon, insert an equals sign and a space
"+p
insert the test copied earlier into register '+'
xi;<ESC>
reinsert the trailing semicolon
j
move down to the next line, ready to reapply the macro
q
stop recording
:%s/^\s*\(.\{-}\)\s*=\s*\(.\{-}\)\s*;\s*$/\2 = \1;/
should work nicely.
:%s/\([^ =]*\)\s*=\s*\([^;]*\);/\2 = \1;/

Resources