zyedidia / micro

A modern and intuitive terminal-based text editor

Home Page:https://micro-editor.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Multiple cursor support

montanaflynn opened this issue · comments

After using sublime and atom I can't go back to not having multiple cursor support. Any plans to introduce this into micro? Even just select all and select next would be amazing as that covers 90% of my usage.

Hey @zyedidia, if you're not currently working on this, I'd love to take a stab at implementing it

Sure, go for it!

@bentranter FWIW, I'm a huge fan of the PR you've started. 👍

@montanaflynn can you record a video of this feature to make it clear for the rest of us?

Thanks @mholt! I always wanted to finish implementing this but could never find the time, and then eventually gave up. It looks like people still want this feature, so I'll give it another stab over the weekend (unless you're actively working on this @zyedidia).

No I'm not :).

is there any new development on this ?

No unfortunately not.

There has been a new development! I have implemented multiple cursors. It's currently sitting on the multiple-cursors branch.

The bindings are

"Alt-n": "SpawnMultiCursor",
"Alt-p": "RemoveMultiCursor",
"Alt-c": "RemoveAllMultiCursors",
"Alt-x": "SkipMultiCursor",

I'm not sure if it's bug free yet so I haven't merged it into master.

Since the only multiple cursors I have used is the vim-multiple-cursors emulation, I've based it off of that but I'm not sure if sublime text does more complex things.

Let me know if you find any bugs.

That's great, I'll try to test it soon.

Since the only multiple cursors I have used is the vim-multiple-cursors emulation, I've based it off of that but I'm not sure if sublime text does more complex things.

There's a pretty multi-selection/multi-cursor in sublime/atom. Basically you select something, press ctrl+d and it selects the next corresponding selection in the text. Then you can move around with those newly created multi-cursors. Useful for refactoring !

Alright that's the behavior that my implementation has but with different keybindings. I'm also open to using different default keybindings but since you can easily rebind them it doesn't really matter.

@zyedidia in addition to the keyboard shortcuts you've implemented for it, it would also be nice to be able to Ctrl+Click a location to spawn a new cursor there. This is the behaviour in Atom.

I have not tested your new branch yet, so I'm not sure if this is the case or not in your current code.

Ok I have just added support for that (see 340cfb8 for details). If you are using macOS though you will need to rebind it to another mouse button because Ctrl-Click is used as an alternate right click.

Thanks for the update. I have found a few issues, but it's a strong start. The implementation is good once the bugs are worked out.

Issue 1: When backspacing at the beginning of a line with multiple cursors, the extra cursors do not reposition themselves correctly.
Issue 2: When multiple cursors are on the same line and you backspace, the second cursor only moves back one space, instead of two. (It should move back two, one for the character the first cursor deleted, and one for the character it deleted)

Example of issues 1 & 2:
Imgur

Issue 3: Backspacing with 3 or more cursors causes unpredictable crashes.
Example:
Imgur

Issue 4: Clicking without holding Ctrl should cancel the multiple cursors, leaving just the main cursor.
Example:
Imgur

Completely unrelated issue that I found while testing this. Clicking in one location and then quickly clicking in another is detected as a double click to select a word. A double click should only be detected if the user clicks the same location twice in a row.
Example:
Imgur

Issues 1-3 all boil down to the same issue which is that the cursors don't know about the line being modified so they don't move. This might require some more thought to fix because I think it means changing where cursors are stored.

Thanks for the fix. This is working pretty well now. I've found one more issue just by playing around with it. I haven't used this in production yet, just did some quick tests. So there very well may be edge cases I have not found.

The remaining issue is that if you delete characters until two cursors end up occupying the same space, they get stacked and basically double input / output. The expected behaviour is that these cursors should merge (All but one are removed)

Example:
Imgur

Yup I came across that problem. I've also found some other issues (with undo and selections) so this still needs some more work.

I have merged the pull request so multiple cursors should be in master now. If you can't build from source you'll be able to get the nightly tonight and try it out.

@ahoarau @zyedidia I just wanted to expand a little bit on this:

There's a pretty multi-selection/multi-cursor in sublime/atom. Basically you select something, press ctrl+d and it selects the next corresponding selection in the text. Then you can move around with those newly created multi-cursors. Useful for refactoring !

Actually they (sublime and vscode, not sure about atom) do something slightly different, that I find very useful:

  • If the cursor is at the start, in the middle or at the end of a word, ctrl+d expands the selection to the whole word and, if pressed again, places another cursor to the next match "whole word" that it finds.
  • If there is a selection of characters (even whitespaces), ctrl+d places another cursor to the exact next match.

Moreover the match can be case sensitive or not, depending on the current configuration on the search function.

e.g
Starting from: |test or test| or te|st
image
image
image

Starting from: test and pressing ctrl+d four times
image

These multiple cursors look like a limited version of macro recording abilities. Record a macro in Far Manager and replay it dozen times looks easier than wrapping the head around this feature.

@techtonik As a Sublime Text and Micro user, I'm not familiar with macros, but would love behavior as Luca described. Especially if, as it sounds, macros require a separate "recording" stage, which would kill the interactive, immediate feedback workflow that I'm productive with.

@AndydeCleyre with macros I do ctrl-. instead of alt-n to start recording, and once I complete my operation correctly, I hit ctrl-. again, press a key to assign macro and just hit that key as many times as I need. This is more productive as it doesn't require mouseclicking for multi cursor positioning.

@techtonik I never use the mouse to place multi cursors.

Whole word matching is useful to do refactoring where you want.

I personally use the exact match in this way:

  • Find a pattern in the lines you want to modify
  • Select the pattern (shift+arrows)
  • Place multiple cursors in the needed occurrences of the pattern
  • Use the home/end keys and ctrl+arrows to position the arrows maintaining the sync
  • Perform the changes

I have no idea on how to use the macros in sublime, but I don't think I could be more productive with them

Another very useful shortcut is the split line: select some contiguos lines, you can place a cursor in each one of them

Ok, there is no mouse clicking, but there is a lot of cursor moving. With macros you just chain the search for the next pattern at the end of your edit.

For sublime press ctrl-q to start recording macros, ctrl-qto stop andctrl-shift-q` to replay. http://docs.sublimetext.info/en/latest/extensibility/macros.html

I get that the macros can be useful, expecially if you are used to them from experience of vim or similar.

I think that the multi cursor approach has a big advantage: you have an immediate feedback, and if you do something wrong, you can simply ctrl+z it. If you forget something in the macro, maybe beacause you didn't notice some differences in the row... You have to redo all from scratch, and you can't know that the macro is wrong until you use it.

I have the feel to be much more in control of the situation if I have feedback on what I'm doing.

Moreover what if I don't know in which line I want to do some changes, or they are too many? I'm under the impression that, while it can surely be done using macros, it becomes messy. With cursor you just have to identify a pattern in the line, place cursors on all the lines, and modify the lines maintaining the cursor in sync. it is easier to do that than to say it

I use multiple cursors multiple times a day for everything from refactoring, editing json, creating new arrays, etc... in atom and previously sublime, and I've never used macros in sublime or atom.

This issue is for multiple cursors, not macros.

@lucamoschella when you recording macro you are doing edits as usual and see the feedback. When playing you see the result. ctr-z rollbacks the whole macro sequence. It is the same as cursors, just sequential autmation, not parallel.

Yeah, I meant that you get feedback from all the lines (immediately if all fit the screen).
If only the last N lines don't work with the macros, you have to get there to understand it. With cursors it is immediate, even more so since you can see where the cursor are placed before starting to modify the lines.

Macros are especially good if there are many lines or multiple places over the file that you can not see in one screen. As I said - at the beginning of a macro or at the end you can invoke find function to place cursor to the place that will be the starting position for the next macro invocation. How do you do that with cursors if content is not at the same screen?

Macros are especially good if there are many lines or multiple places over the file that you can not see in one screen. As I said - at the beginning of a macro or at the end you can invoke find function to place cursor to the place that will be the starting position for the next macro invocation. How do you do that with cursors if content is not at the same screen?

This is exactly what sublime and the others do in a smarter way.
The "methods" to place cursors (whole word or exact match, my first comment) can be seen as a search for where your cursors must appear in the file.

If you are referring to multiple files, yes cursors are local to a single file

Queries for automated cursor placement make sense. This way the cursor feature can be more useful than macros. Is there a way to place cursors to keywords from static analysis? For renaming methods, variables limited to the current program scope?

Like the "refactor" function of some IDE?
Maybe with some plugins in sublime, in Code some languages support the refactoring, but it must be a known programming language.

I often use the multiple cursors to format nicely something that I copied in the clipboard.
I think the best refactoring we can get on plain text is to place cursor on all occurrences of the "whole word", with the possibility to skip the next occurrence ( ctrl+k ctrl+d) and undo the last cursor placement (shift+ctrl+d).
It would be interesting a regular expression to place cursors, but I think the "simple" approach (with an extremely low learning curve) should be the main approach. Most of the time I don't need a regular expression, it's quite easy to look at the text and identify an adequate sequence of characters that most of the time appears only in the desired targets

If the refactoring is supported, it's more powerful than cursors, since it accounts for scopes and name clashes.