Multicursor is amazing.
One thing it's been great for:
I have code like:
byte b1 = array[0];
And I want to do this for 16 bytes. Control + D to duplicate 15x. Double tap control, hit up 15 times - now there's a cursor at every row. Hold control, hit right (jump by word), index to end of 'b1' on each line. Ctrl + shift + a, 'increment duplicates' - now every line is 1, 2, 3, 4... 16. `ctrl + right` my way to the index key and do the same thing.
It's awesome.
edit: I just found 'duplicate and increment' :o
But I wasn't doing this for a loop unroll.
I had a fixed size array that I wanted to serialize/ deserialize to/ from capnproto - there are no fixed size arrays in capnproto, so I wrote a message that just had b1, b2, b3... b16, and then some code to pull it out into a statically sized array. It allowed me to pull a bunch of bytes into a much larger statically allocated array without any allocation or bounds checking.
You must do some kind of programming I've not encountered in my many years. While my editor of choice can do this, I would have no idea how, because a feature like "increment duplicates" is needed so infrequently that I would never remember the shortcut.
There are appropriate plugins available for my editor, but I've never felt the need to install them.
Formatting is another.
Boilerplate code, for example today I had to implemented code like this:
impl Into<Node> for ProcessNode {
fn into(self) -> Node {
Node {some_boilerplate(self)}
}
}
I had 6 node types. Using multiple cursors I:* Implemented it once
* Duplicated it 5x
* Copied the names of the types I needed to impl for
* Attached a cursor to each impl
* Used ctrl + left/ right to word-jump, and past in the appropriate area
Now it's not like this saved me more than a minute or two, but this sort of thing is extremely common in my experience, across languages.
for x in type1 type2 type3 type4 type5 type6 ; do
cat <<!
impl Into<$x> for ProcessNode {
fn into(self) -> $x {
$x {some_boilerplate(self)}
}
}
!
done
Now do a line-oriented visual select of all the lines from for to done (using V + cursor movements). Then pipe to shell with !sh[Enter].Poof! The above is replaced with the following:
impl Into<type1> for ProcessNode {
fn into(self) -> type1 {
type1 {some_boilerplate(self)}
}
}
impl Into<type2> for ProcessNode {
fn into(self) -> type2 {
type2 {some_boilerplate(self)}
}
}
impl Into<type3> for ProcessNode {
fn into(self) -> type3 {
type3 {some_boilerplate(self)}
}
}
impl Into<type4> for ProcessNode {
fn into(self) -> type4 {
type4 {some_boilerplate(self)}
}
}
impl Into<type5> for ProcessNode {
fn into(self) -> type5 {
type5 {some_boilerplate(self)}
}
}
impl Into<type6> for ProcessNode {
fn into(self) -> type6 {
type6 {some_boilerplate(self)}
}
}
Don't write in some insane boilerplate-driven programming language in the first place. Anyone proliferating this kind of duplication (whether with multi-cursors or shell here docs or any other way) should be flogged.I've been using it in editors since well before VSCode existed. It's very nearly a requirement for me to use an editor now.
For your example, this is the kmacro I ended up with:
;; Keyboard Macro Editor. Press C-c C-c to finish; press C-x k RET to cancel.
;; Original keys: 2*M-f M-DEL b C-x C-k TAB C-a 2*C-k 2*C-y C-p
Command: last-kbd-macro
Key: none
Macro:
2*M-f ;; forward-word
M-DEL ;; backward-kill-word
b ;; self-insert-command
C-x C-k TAB ;; kmacro-insert-counter
C-a ;; move-beginning-of-line
2*C-k ;; kill-line
2*C-y ;; yank
C-p ;; previous-line
(after you've created a macro, you can get the above by doing M-x kmacro-edit-macro.) YP<Ctrl-A>l<Ctrl-A>
That can be recorded into a register (say "a") with qaYP<Ctrl-A>l<Ctrl-A>q
then replayed with @a, and further repeated with @@.This is nothing new; I was doing this in Vim 20 years ago.
That and arbitrary window splitting (split any pane horizontally or vertically) are two features I really miss when they're not present. The latter's surprisingly hard to find; Sublime and VS Code don't do it (Atom does).
You can for example put your cursor on a word, spam ctrl+d (of press alt+f3) to select all instances of that word, and start editing them all at ones, no matter where they are. They don't have to be perfectly in a column. You can also copy X items from anywhere, and if you have X cursors again somewhere else and paste, they'll each go in their respective slot.
Alt + Shift + A
I've had issues in IDEs where they have shitty implementations of multicursor that break that example.
Super handy when you want multiple cursors to line up at the start of every line (by default vscode will wrap the cursor around to the end of the longer lines if you try to move around with the arrow keys).
There's about 20 other extensions I routinely use, which I documented at https://nickjanetakis.com/blog/switching-to-vscode-from-subl....
Additionally, there is a case where if you don't select the last line until the end, you end up in a state where the last cursor is already at the beginning. If you press "Home" now, you end up having that last cursor at the beginning of the line - and the other ones at the indentation level (see https://github.com/Microsoft/vscode/issues/14919#issuecommen...)
(Disclaimer: Author of the mentioned plugin, so I am heavily biased against my own workflow and saving-keypresses-obsession :P)
Pressing home doesn't always put you at the true beginning of the line. It will put you at the first non-whitespace character.
It only took using a keyboard for about 22 years to learn pressing home more than once has benefits.
Thanks!
https://visualstudio.uservoice.com/forums/121579-visual-stud...
(Option)Alt-Cmd + Down or Up arrow key
From there, you can use arrow keys as normal, but instead of controlling one carrot, you control all the ones you created. So if I use the shortcut key to move to the next word, they all do, same with end of line, or what have you. In the past I had to use regex in my editors to extract quoted text in each line... now I just use multi-select. Each carrot can also be created with the mouse in the Selection menu.
Edit: Apparently it's a feature lifted from Sublime and in other IDEs - thanks!