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.