Vim fastest way to select a block of text lines until a specific character - vim

I have a page with some wikicode (tikiwiki) which includes html like such :
{DIV(class="Act PersonInterested")}
{HTML()}
multiple
lines
of
html (svg)
code
{HTML}
{DIV}
{DIV(class="Act CHActivePFOnly")}
{HTML()}
multiple
lines
of
html (svg)
code
{HTML}
{DIV}
I want with vim to delete the text between the {HTML()}{HTML} wiki tags. dt{ doesn't work...
The most handy option I found is to record a macro, like that one :
qa -> Records macro in register a
v/{ -> Visual selects text until next '{' symbol
q -> Stops recording
#a -> Applies macro from the current line
Then I move to the next line and reapply the macro with '#a' and so on until I finish to empty all the tags.
My question is, there must be somehow a faster approach, that I overlooked... Like a g: one or even simpler. I would be pleased to learn about it, and also, I didn't find much answers here or duckducking about that specific issue.
Thanks !

Following would suffice
g/{HTML/,/{HTML/ d_
This assumes, as do the other answers, you don't have a {HTML... anywhere between your real tags. If you do, the only reliable way to do this is to use a parser.
Breakdown
g : start a global command
/ : separator
{HTML : search for {HTML
/ : separator
,/{HTML/ : set a range from the previous search result up until the next {HTML tag
d_ : delete to the empty register. As I have my clipboard synchronized with deletes, without the `_`, each delete goes to my windows clipboard slowing things down a lot in large files.

You could do it with:
:g/{HTML(/norm jd/HTML^M
or:
:g/{HTML(/norm jV/HTML^Mkd
if you are more confident with visual mode.
Press Ctrl+V, followed by Enter to obtain ^M.

did I understand the question right?
%s/{HTML()}\zs\_.\{-}\ze{HTML}//g
does the above command work for you?

You can also just record more complex macro ond then repeat it.
qa -> Records macro in register a
/{html()<cr> -> Find next
j -> Go down one line
d/{html}<cr> -> delete to closing html tag
q -> Stops recording
100#a -> Applies macro 100 times or less if there is no matches

Related

Vim : How to insert a / after certain length in multiple line

Here is following piece of text (a c++ code) which I am trying to edit in vim,
#define MACRO(X) /
{ /
if(x)
{
"some action performed here"
}
}
I want to complete this macro syntax by introducing / at each line. For aesthetic reasons I want the / to be aligned at same line length like how it is done for first two lines. How to achieve this in a single or few Vim commands. Assume that macro is very big in line count and I cant manually introduce space and / at every line
First of all, I am confused that the "macro" you meant in your question is a vim macro or your function named "MACRO(X)"?
To solve the problem you need set ve=all read :h 've' for detail.
If you meant the "macro" is a vim one, that is, you want to extend an existing vim macro, it is hard to tell how to do that. That's because we cannot see the existing macro, what does it do.
I list here two ways to do it, one is using a vim macro, you can put it into your existing one and test if it is required. The other one is using :normal command.
Assume that you've set ve=all
Assume that you want to add a / on column 50
vim macro
First record a macro a:
qa050lr/jq
Then you can replay it x times, e.g. 99#a
normal command
%norm! 50lr\
Two more ways to do the same thing.
If set ve=all or set ve=block using blockwise-visual mode.
$<C-V>6jr/
That is, go to an existing "/" at top line. Then enter blockwise-visual mode. Then extend selection downwards. Then replace everything with "/"
Using just :s
1,7s/$/\=repeat(' ', 49 - strlen(getline('.')))..nr2char(47)
That is, substitute "end of lines" 1 through 7 with an expression (variable number of spaces followed by slash).

Append general buffer to the end of every line in VI

I'm trying to add the contents of the general buffer to the end of every line. I'm sure this is fairly simple, however, an hour of google searches have lead me nowhere.
This is what my file looks like
::Things to bring camping
--matches
--tent
--sleeping bags
--inflatable bed
--firewood
--camping stove
--skillet
I want to add "::Things to bring camping" to the end of every line.
This is i have figured out so far.
/:: -> brings me to the line in question
Y -> yanks the entire line to the general buffer
I tried :%s/$/\p -> this added a "p" to the end of every line.
My problem is with step 3. How do I tell the "search and replace command" to used the "p" (the contents of the general buffer) instead of the "p" the character
Thank you so much for your help.
Just a suggestion: If you try doing it with a macro, you will be able to use 'p' to add the contents of the general buffer.
Sorry, I had to go into vim and find out.
The way to copy your entire line while in command mode, is:
^r "
(that's CTRL and r, then " )
That should paste the entire line you yanked into your search and replace command
For step three, instead of \p, you should use ctrl-R-a. Hold down the control key and type an uppercase "R", continue holding control, and type a lowercase "a".
For a line with multiple words, use ctrl-R-" instead.
I agree with using a macro - they're very powerful.
In this case I took your list example and positioned it at the first colon.
I used y$ to grab the remainder of the line in the buffer.
Then I recorded the macro - I chose 1.
q1
j$pq
Then you can call it for any number of rows in your list. E.g. 10#1
Learned something figuring this one out ...
:%s/$/\=getreg()/
The \= says that what follows is an expression to be evaluated, and the getreg() call gets the contents of the register, by default the "general buffer" as it used to be called by vi.

Vim: Edit multi aleatory lines

I'm aware of the possibility to edit multiple lines on the same column by doing:
CTRL+V down...down..down... SHIFT+I type_string_wanted
But I'd like to edit multiple specific locals addin new strings (maybe using cursor (h j k l) or mouse (with :set mouse=a)).
Like on this example, where I want to add the string 'XX' to specific locations. I.e.,
from this:
Hi.
My name is Mario!
to this:
XXHi.
My XXname is XXMario!
Any ideas?
Edit the first location and then use . to repeat the action at each additional location.
I'd reverse the order of your steps.
Instead of marking each location, then performing the change on all at once, just edit the first location, then use . to do the same to each of the others.
This doesn't add any keystrokes to your use case; instead of hitting some key to mark a spot beforehand, you hit . afterward.
If you suspect you might accidentally do some other things in between usages, you could record a macro using q<register> the first time, and play it back with #<register> each of the others.

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