Using multiple cursor isn't a Vimmer thing
As I said in the comments using multi cursors (even with a plugin) isn't really "following the Vim way", I totally understand that it is attractive for someone coming from Sublime-Text but you can often find alternatives which are at least as efficient with Vim built-in features.
Of course, finding these alternative solutions isn't always easy and sometimes it takes time but it will get easier with your Vim experience and you'll see that with time multiple cursors will seem totally useless to you.
That's cool but how can I find an alternative way?
There is no universal answer since it depends a lot on what you're trying to do, I'll just try to give some hints about the first things to try:
The dot command .
The Dot command is probably one of the most powerful tools in Vim, it simply
allows us to repeat the last change. I couldn't explain it better than Drew
Neil in his Practical Vim. I
think that every Vimmer should consider reading this book.
The strength of this command is that the last change can be an action working on
a character, a line or a whole file. For example, a change can be delimited by
the moment you enter insert mode and the moment you go back to normal mode.
With that in mind it is easy to do what you wanted to do with multicursor:
First let's set up our environment: Let's write as you suggested
\section[]{}
Then make a repeatable change
The cursor is now on }
,hit F[
to go back on the [
character.
Then enter insert mode with i
and type My first section in this book
and go
back to normal mode with ESC
:
\section[My first section in this book]{}
And here comes the magic part:
Let's type f{
to put the cursor on the {
character and hit .
to repeat
the last change:
\section[My first section in this book]{My first section in this book}
All the challenge of the dot command is to learn how to make repeatable changes:
it will come with grokking Vim but the basic is to understand how to make your
change in a repeatable way.
For example to insert a semi colon at the end of a line you'll prefer using
A;
instead of $a;
. Why?
Because A;
creates an atomic action so when you'll use .
on another line, no
matter where you are in the line you'll insert the semi colon at the end.
Whereas when using $a;
you split your change in two parts $a
and the
insertion of ;
so if you use .
it will insert the semi colon on the current
position of the cursor.
NOTE The magic formula in Vim is n.
. A really cool workflow is:
- search for the place you want to make an edit with
/pattern
- make your repeatable edit
- use
n
to go to the next place to edit
- use
.
to repeat the edit
- repeat the last two steps: You're the king of the world (or at least of
edits)
macros
Macros are another extremely important tool in Vim since it allows you to record
a sequence of keystrokes and repeat it as if you typed it again.
I'll use, as an example, your second use case:
variable1 = 2
my_variable2 = 12
var3 = 14
Once again the important is to learn how to make your macros efficient (I'll
give a counter example just after):
variable1.someStuff = 2
my_variable2 = 12
var3 = 14
- Now you can use the macro to repeat your edit. As you are on the right line to
edit you can simply execute the macro with
@q
. As we want to execute it twice you can use 2@q
and you'll get the following result:
variable1.someStuff = 2
my_variable2.someStuff = 12
var3.someStuff = 14
NOTE 1 As you may have noticed, using 0ea
at the beginning of the macro
was really important. Indeed, if you had put your cursor at the end of the first
word before recording the macro and executing it again your result would have
been:
variable1.someStuff = 2
my_variable2 = 12.someStuff
var3 = 14.someStuff
As your cursor the text would have been inserted at the position of the cursor
after changing of line (i.e. the end of the line in this case)
NOTE 2 Macros are extremely powerful and you can even create recursive
macros when you are comfortable with them. Here your macro could have been:
`0ea.someStuff<Esc>j@q`
The final @q
would have called the macro by itself instead of using 2@q
; you'd
just have used @q
and all the work would have been done.
visual block
Here comes another trick that doesn't directly apply to your use case but can
be really useful to edit a large number of line at the same time. Let's get this
extract of CSS code:
li.one a{ background-image: url('/images/sprite.png'); }
li.two a{ background-image: url('/images/sprite.png'); }
li.three a{ background-image: url('/images/sprite.png'); }
What if you moved the sprites from images
to components
?
Well you can put your cursor on the i
of images
and press <C-v>
. This will
start the visual block mode which allows to select blocks. Now you can type t/
to select the word you want to change and 2j
to select all the occurrences of the
word.
After that you simply have to type c
to change the word and then components
.
When you'll go out of insert mode you'll see:
li.one a{ background-image: url('/components/sprite.png'); }
li.two a{ background-image: url('/components/sprite.png'); }
li.three a{ background-image: url('/components/sprite.png'); }
The global command
The global command is a tool which allows to apply an ex mode command on lines
matching a pattern, once again that's a good way to apply the same change on
different place without needing multiple cursors.
The syntax is the following:
:[range] g / pattern / command
For more details on the [range]
parameter please see :h :range
. I won't detail
it here, I'll simply remind that %
represents the whole file, '<,'>
represents the last selection, and 1,5
represents the lines 1 to 5 of the
file.
This parameter defines the lines which will be treated by the global command. If
no range is specified, then the global command will use %
by default.
The [pattern] argument is a search pattern as you are used to use with the search
engine. As it integrates the search history you can leave this field blank and
the global command will then use the last search pattern in the search history.
Finally the [command] parameter is an ex command as you are probably used to.
Now the behavior of the global command is pretty simple:
- Iterate through all the lines defined in the [range] parameter
- If the current line matches the defined pattern, apply the command
As the [command] parameter is an ex command, you can do a lot of things. Let's
take the following pseudo code which isn't pretty interesting and have a lot of
debugging messages:
var myList = null
var i = 0
myList = new List()
echo "List instantiated"
for (i=0; i<10; i++)
myList.Add(i)
echo i . " added to the list"
echo "end of for loop"
Now let's say that you're sure this code works and you want to delete these
useless echo
statements:
You can apply your global command on the whole file so you'll have to prepend
the command with %
(or with nothing since %
is the default range).
You know that the lines you want delete all matches the pattern echo
You want to delete these lines so you'll have to use the command :delete
which can also be abbreviated as d
So you'll simply have to use the following function:
:%global/echo/delete
Which can also be abbreviated as
:g/echo/d
Note that %
disappeared, global
is abbreviated as g
and delete
as d
.
As you might imagine the result is:
var myList = null
var i = 0
myList = new List()
for (i=0; i<10; i++)
myList.Add(i)
NOTE 1 An important point that took me some time to realize is that the
normal
command is an ex command which means that you can use it with the
global command. That can be really powerful: let's say that I want to duplicate
all the lines which contains echo, I don't need a macro or even the magic
formula n.
. I can simply use
:g/echo/normal YP
And voila:
var myList = null
var i = 0
myList = new List()
echo "List instantiated"
echo "List instantiated"
for (i=0; i<10; i++)
myList.Add(i)
echo i . " added to the list"
echo i . " added to the list"
echo "end of for loop"
echo "end of for loop"
NOTE 2 "Hey what if I want to use my command on lines which doesn't match a
specific pattern?"
global
has an opposite command vglobal
abbreviated v
which works exactly
like global
except that the command will be applied on lines which don't
match the [pattern] parameter. This way if we apply
:v/echo/d
On our previous example we get:
echo "List instantiated"
echo i . " added to the list"
echo "end of for loop"
The delete
command has been applied on lines which didn't contained echo
.
Here I hope that those few hints will give you ideas on how to get rid of your
multi cursor plugin and use Vim in the Vim way ;-)
As you can imagine these examples are pretty simple and are just made to
demonstrate that when you follow the Vim way you really rarely need several
cursors. My advice would be when you encounter a situation where you think it
would be useful, write it down and take some time later to find a better
solution. 99% of the time you'll eventually find a faster/more efficient way to
do it.
Also I will repeat myself one more time but I really encourage you to read
Practical Vim by Drew Neil
because this book is not about "How to do that or this in Vim" it is about "How
to learn to think in the Vim way" which will allow you to built your own
solution to your future problems in a good way.
PS Special thanks to @Alex Stragies for his editing work and the corrections
he made to this long post.