What is the VIM way to copy a list of variables (a list of words vertically aligned with different widths)? - vim

let(:aaaaa) { 123 }
let(:bb) { true }
let(:ccc_ccc) { "foo bar" }
I want to copy all variable names (:aaaaa, :bb, :ccc_ccc).
In VsCode, for example, I would use a multi-line selection.
How can I do it in VIM?
Block selection didn't work, once the variable names have a different length.

You could use the command :%norm f:"Qyt) to make your 'q register' contain the
following:
:aaaaa:bb:ccc_ccc
The way it works is as follows:
:%norm means 'to all lines, apply the following normal commands'
f: moves the cursor to the first colon on the line
"Qy appends yanked text to the 'q' register
t) is a motion 'till the next closing parenthesis
This assumes that the 'q' register is already empty (you can use qqq to clear
it). If you only want to do this for a subset of lines, you'd replace the %
with a range (or visual selection).
What you do with the register's contents after that is up to you.
"qp will put them into the buffer, and maybe you'd then do :s/:/\r:/g to
split the lines at the colons like this:
:aaaaa
:bb
:ccc_ccc

If your immediate goal is to have something like this in the default register:
:aaaaa
:bb
:ccc_ccc
then it won't be easy to achieve without the ability to visually select multiple non-contiguous pieces of text of arbitrary length, which Vim doesn't have out of the box.
This means that, if we don't want to use a multiple cursors plugin, we are left with more pedestrian ways involving substitutions, macros, etc.
Assuming the cursor is on the first line, you could do something like:
:,+2t+2 " copy the block below itself
:'[,s/.*(\(.*\)).*/\1 " remove everything you don't need
:'[,d " cut the three lines to the unnamed register
But Vim works best when it is used with intent. "Copy this" is rarely a goal in and of itself: it generally is one of the several low-level steps necessary to complete a higher-level task (which itself might be one of the steps of another even higher-level task). What one intends to do with the copied text often plays an important role in choosing the best strategy. Here, your actual goal may have been to get the three variable names on three lines right below their definition, something that actually doesn't imply copying them, so the two first steps would have been enough.

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

How to visually select lines based on a search pattern in vim?

I've got some method calls all over the place in a large file, I'd like to match these lines, select and then yank them as one so I can put them all in a single place.
I can find all the lines I want with :g/>set but how do I visually select each line?
You can't have multiple visual selections in Vim.
But you can clear a register and append all the matching lines to it:
:let #a = ''
:g/>set/y A
then create an empty buffer (or navigate to an existing one):
:vnew
and paste from register a:
"ap
But you probably want something like TagList or TagBar.
edit
:[something]y a
means "yank into register a".
:[something]y A
means "append to register a".
What I usually do is :
Remove all the lines without the pattern :v/pattern/d
Select the whole new file with ggyG
Paste somewhere the result with p
Use undo a few times with u to get the file back to its initial state
This is a bit cumbersome, I would welcome a simpler solution.

Remove command with matching braces

I'm using (mac)vim with tex-suite and would like to have a single regex command (or any other way) to do the following thing:
Change
\textcolor{green}{some random text}
into
some random text
This should be done for all occurrences of \textcolor{green}{} in my tex file...
Any idea?
EDIT: I need it to recognize matching braces. Here an example :
\textcolor{green}{
with $v_\text{F}\sim10^6$m.s$^{-1}$ the massless Dirac fermions
velocity in pristine graphene}.
In my experience, things like this most often crop up during editing, and you might have the search for \textcolor{green}{ already highlighted.
In such a scenario, :global is usually my weapon of choice:
:g//norm d%diBvaBp
diBvaBp: diB (delete inner block), vaB (select block), p (put)
If you have surround.vim installed (recommend it!) you could remove the pair of braces simply doing dsB (delete surrounding {})
:g//norm d%dsB
Of course, you can combine it like
:g/\\textcolor{green}{/norm d%dsB
I just noted a potential issue when the target patterns don't start at the beginning of a line. The simplest way to get around that is
:g//norm nNd%diBvaBp
A more involved way (possibly less efficient) would be using a macro:
/\\textcolor{green}{
gg
qqd%diBvaBpnq
Followed by something like 100#q to repeat the macro
:%s,\\textcolor{green}{\([^}]\+\)},\1,g
Updated as per your updated question:
:%s,\\textcolor{green},\r-HUUHAA-&,g
:g/\\textcolor{green}/normal 0f\df}lvi{xhP$xx
:%s/\n-HUUHAA-//
Quick explanation of how it works:
Put all \textcolor{green} lines onto a line of their own, with 'special' marker -HUUHAA-
Use visual selection vi{ to select everything in between the {}, paste it outside and delete the now empty {}.
Delete leftover stuff including the marker.

Vim - Search and replace the results

I'm getting more and more comfortable with Vim after a few months.
BUT, there is only one simple feature I can't get any answer from the web. That is "Search and replace the results". The problem is that I know:
:/keyword to search, and hit enter "keyword" will be highlighted (of course with set hlsearch)
n, or N to navigate
:% s/keyword/new_keyword/g to replace all occurences of keyword with new_keyword.
BUT, I would think that there must be a way to search, and replace the matched keyword (highlighted) with any new_keyword WITHOUT doing ":% s/keyword/new_keyword/g", which is a lot of typing considering search & replace is such a day-to-day feature.
Any answers/comments will be greatly appreciated!
If you've already done a search you can do a substitution for the same pattern by simply leaving out the pattern in the substitute command. eg:
/keyword
searchs for "keyword", and then:
:%s//new_keyword/g
will replace all occurrences of "keyword" with "new_keyword".
Searching and using the dot command (you didn't meantion you are using the dot command, that's why I highlight it) to repeat the last input action is my best bet here.
I use s///g for search and replace.
Well, since #keyword# and #new_keyword# account for most of the characters, and you need some way to differentiate between them (i.e., a character in vim, or tab between entry fields in dialog in a different editor), you're left with maybe four or five keystrokes beyond that.
So I think you're probably overestimating number of keystrokes and also forgetting that (1) it becomes very natural, and (2) working this way allows you also to naturally modify the action performed by specifying a different range or option flag.
But you can cut down on keystrokes. If you want you can map a key to automatically bring up the command line with '%s/' already in place. e.g.:
nmap s :%s/
The command above would remap 's' (I'm not recommending remapping to that key, but it gives the idea) and set you up to insert the keyword.
Also, you can set the 'gdefault' option to default to substituting multiple times per line. This lets you skip the ending '/g' in your keystrokes:
set gdefault
See ':h gdefault' for help section on that option.
In the end I would say just get used to the default way it works, because using it that way allows you to keep same basic operation when you want to specify different ranges or option flags, and creating a new special map is just another thing to remember. gdefault may be worth setting if you think you're going to want it majority of time, adding /g flag at end when gdefault is set has effect of turning /g off. . .
Move to the first highlighted word then record a macro for replacing the word and moving to the next one, e.g:
gg
n
qq
caw new_word^[
n
q
#q
##
##
...

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

Resources