vscode-modal-editor icon indicating copy to clipboard operation
vscode-modal-editor copied to clipboard

Allow multi-cursor selections via Helix-style `s` inside a selection

Open ambv opened this issue 6 months ago • 15 comments

Thanks for the extension, it works great! The one feature that I was missing from Helix was doing search/replaces straight from selections. Hopefully this is in line with your goals for the plugin.

2025-06-09 15 25 38

ambv avatar Jun 09 '25 13:06 ambv

Hi, thanks for the contribution. Do you know what the original keymap is in Helix? Just want to try it out first to better understand your changes.

DCsunset avatar Jun 11 '25 01:06 DCsunset

The equivalent in Helix would be:

  • x in NOR to mark lines (I use Enter in the GIF since I find it more natural; all other bindings are the same as Helix)
  • s to switch to SEL
  • type in the regex, Enter to confirm and get back to NOR
  • c to "change" switches to INS
  • type in the new contents
  • Esc to get back to NOR
  • ; to clear selection
  • , to clear other cursors

For the last two bindings in your preset, you'd need https://github.com/ambv/.dot_files/blob/7fd1d0ce9d9e7f33c7cc5e2fb6cc47bfa834426e/.config/code/helix.js#L62-L63. I can add that to the PR if you want for completion.

ambv avatar Jun 11 '25 07:06 ambv

I also wanted this functionality, and it is possible with the existing features and VSCode abilities. With my config I can do the following:

  • select text any way that you would normally do so
  • open the search box and type your pattern
  • press alt+enter to select all matches

I have the following keybinding:

    {
        "key": "alt+enter",
        "command": "runCommands",
        "args": {
            "commands": [
                "editor.action.selectAllMatches",
                "closeFindWidget",
            ]
        },
        "when": "findWidgetVisible"
    },

anthonyjclark avatar Jun 12 '25 16:06 anthonyjclark

Interesting, I never knew about "editor.action.selectAllMatches"! And that's sort of the point, relying on every new user to know to add a custom keybinding to achieve this is not a great experience. Having this built in will make it available to everybody.

It's also a different UX paradigm. With your configuration you search first, select later. Helix philosophically is "select first" and with my change you see the matches select as you type, which I think is a more fluid experience.

ambv avatar Jun 12 '25 17:06 ambv

The solution posted by @anthonyjclark seems like a good way to achieve the feature. We can always update the helix preset (or refer to other people's config in examples) so new users know how to use it.

As for your second point, there's an option called. autoFindInSelection, which you can enable to achieve select first and search later. Also, I believe VS Code by default highlight the text as you type.

Is the above config good enough for you use case (if so, we can try to avoid adding too much logic to the code for easier maintenance. But if not we can discuss it further)

DCsunset avatar Jun 13 '25 01:06 DCsunset

Ultimately this is your extension, so you decide whether the additional 116 lines of TypeScript will make maintenance harder.

From my perspective, this functionality brings your extension on par with the Helix editor, providing its main search/replace functionality in a virtually 1:1 fashion. In my opinion, for people who don't know how this works in Helix it brings no additional cognitive burden: they never have to use s to search in selections. They can use the regular Find/Replace dialog, possibly extended with what Anthony suggests above. But for Helix users with muscle memory of its functionality, who would like to switch to VSCode and your extension, this essentially puts it on par with the best Helix extension for VScode.

In fact, in the README of vscode-helix, the author laments that the main missing feature is configurable bindings. Your extension is literally that: Helix that you can remap to your will.

As an aside, I just added a crucial additional bit to the PR from Helix: the ability to travel through selections with ( and ) and to unselect some of them (via Alt+,). This allows you to audit that the searches aren't overly broad before you make changes. This completes the functionality found in Helix and provides the entire workflow from that editor.

So this is the essence of the question: are you open to your extension being a Helix replacement or do you want it to be less than that? I'm not going to push you in either direction, it's really up to you.

ambv avatar Jun 17 '25 14:06 ambv

I see your point. I'm open to PRs that add features which cannot be implemented without the changes. So I just wanted to know whether the feature you proposed is already achievable without this PR.

Could you further explain what this extension can't do without this PR? It seems to me that the multi-cursor selections can already be achieved by the vscode native search by binding corresponding keys (as mentioned in my previous comment).

DCsunset avatar Jun 18 '25 01:06 DCsunset

Could you further explain what this extension can't do without this PR?

I look at it this way: Visual Studio Code is perfectly capable of editing text without external plugins. You can insert text, make selections, and you can modify text using the internal commands palette and find/replace. However, the reason you and I are both excited about modal editing plugins isn't to enable things that are otherwise impossible to achieve in VScode! Rather, it's to make editing more ergonomic. We like modal editing, because it makes more sense to use.

This is how I see searching inside selections. It enables me to do the thing in a way that makes more sense to me:

  • select the range of interest,
  • search within it to see all matches,
  • browse through the matches to unselect the ones you don't intend to alter,
  • then visually change the text.

By the way, the reason I submitted the PR here was because your README itself says "the design of this extension mainly follows helix", so I thought this final piece of it belongs in the extension. There is no other "search/replace" in Helix. This is how you do it.

In the end this is your decision 😎

ambv avatar Jun 19 '25 20:06 ambv

I think you might misunderstand my point. I was trying to know why the current extension can't do it in this same ergonomic way. It seems that what you describe is already doable with the exact same keybindings in helix using the unmodified extension.

It would be helpful if you can point out what this extension cannot achieve in an ergonomic way

DCsunset avatar Jun 20 '25 13:06 DCsunset

It seems that what you describe is already doable with the exact same keybindings in helix using the unmodified extension.

If so then I was unable to make it work. Can you demonstrate how I can use the unmodified extension to make s on a selection allow me to type in a regular expression seeing selections as I type, press Enter to confirm, use ( and ) to navigate to one of the selections, then Alt+; to unselect that one selection you don't want while leaving other selections and multiple cursors intact, then c to make changes on those remaining selections?

ambv avatar Jun 22 '25 08:06 ambv

Can you demonstrate how I can use the unmodified extension to make s on a selection allow me to type in a regular expression seeing selections as I type, press Enter to confirm

This should be doable with autoFindInSelection set to always or multi-line as mentioned above. and with the command editor.action.selectAllMatches.

use ( and ) to navigate to one of the selections, then Alt+; to unselect that one selection you don't want while leaving other selections and multiple cursors intact, then c to make changes on those remaining selections?

This part doesn't seem to be doable with the current extension. So I think it's reasonable to add new commands to support the selection manipulation (which dpesn't seem to be specific to selection mode).

DCsunset avatar Jun 23 '25 00:06 DCsunset

This should be doable with autoFindInSelection set to always or multi-line as mentioned above. and with the command editor.action.selectAllMatches.

This isn't the same. You can't use Helix keyboard bindings when you have a Find/Replace dialog open. As Anthony said, you need to define a new extra keybinding. Similarly, saving a file is "doable" with Cmd+S and yet you implemented the ":" command mode purely to support ":w". Selection search is analogous to your command mode. It's supposed to help with muscle memory.

ambv avatar Jun 24 '25 17:06 ambv

You can't use Helix keyboard bindings when you have a Find/Replace dialog open

This is good point and exactly the info I'm looking for to justify this change.

Similarly, saving a file is "doable" with Cmd+S and yet you implemented the ":" command mode purely to support ":w". Selection search is analogous to your command mode

All the "doable"'s I mentioned above means using exactly the same keybindings, either through keybindings.json or this extension. The point in your previous comment is fair enough to make the feature you proposed not doable in the current extension.

Besides, I also want to remove the hard-coded command mode by making users able to create their own mode by intercepting the keys. Then some of the changes in this PR can also go to the preset instead of being hard-coded. This makes it easier to add more modes in the future for different use cases.

Any thoughts on the above idea?

DCsunset avatar Jun 25 '25 03:06 DCsunset

Any thoughts on the above idea?

I don't actually use the vscode-modal-editor command mode myself, so I wouldn't mind if it went away, but you have to take into account how breaking changes will affect other existing users. Some people will miss it and will be surprised the functionality silently stopped working after an upgrade. I imagine telling them they have to make non-trivial edits to their preset.js file will be unwelcome friction.

In general, I appreciate the flexibility the preset file gives the user, and it's a reason I use your extension, but I also don't think many users will be interested in designing their own modes from scratch. The one in this PR is literally providing a missing mode that exists in Helix, so I went and shared it.

If you provide me a different way of achieving the same thing in a future version, that's probably fine, but again, it all boils down to how your existing users are meant to migrate their preset files to a new version.

By the way, this is also why I opened more PRs with command definitions that I think belong in the base extension. Users can design their own, sure, but I feel providing a sensibly rich foundation in the extension decreases friction and allows people to reuse the same solution instead of each and every user having to reimplement it on their own.

ambv avatar Jun 25 '25 09:06 ambv

For the command mode, I will try deprecating the old use first instead of removing it directly (let it last for a reasonable amount of time). As for the migration, the command mode will be added to the default preset as a good reference, which should make migration trivial enough (just need to copy the definition).

I'm not a veteran user of Helix so I may not know some important features in Helix. That's why I feel that in the future more and more features will need changes like this. Letting the user able to make their own modes more easily is better than hard-coded changes.

I'll try to review all the PRs when I get some time.

DCsunset avatar Jun 27 '25 02:06 DCsunset