Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add emacs keybindings for mark emulation #22904

Merged
merged 7 commits into from
Jan 13, 2025

Conversation

ozanmakes
Copy link
Contributor

@ozanmakes ozanmakes commented Jan 9, 2025

These keybindings extend the already selected text. This allows closer emacs emulation where subsequent movement commands extend / shrink the current selection instead of dismissing it.

This is a follow up on

Release Notes:

  • Added emacs movement keybindings that extend/shrink the current selection

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Jan 9, 2025
These keybindings extend the already selected text. This allows closer
emacs emulation where subsequent movement commands extend / shrink the
current selection instead of dismissing it.
@ozanmakes ozanmakes force-pushed the emacs-mark-movement branch from e8e46f1 to 4e6c580 Compare January 10, 2025 10:42
@ozanmakes
Copy link
Contributor Author

I've updated this PR to

  • Add set-mark-command emulation (ctrl-space + movement)
  • Apply the same changes to macos/emacs.json

@ozanmakes ozanmakes mentioned this pull request Jan 10, 2025
1 task
@notpeter notpeter self-assigned this Jan 10, 2025
@notpeter
Copy link
Member

I love this. Particularly the elegance of "mark mode" being activate whenever there is a selection. It's obviously not perfect (you have to rapidly press a navigation key after ctrl-space) but it's a lot of functionality for very little code.

I've added ctrl-space + native navigation keys (left,right,home,end,pageup,pagedown,alt-left,alt-right) to further match the behavior of emacs.

Currently ctrl-space in macos/linux is bound to editor::ShowCompletions which will now be slightly delayed. I wonder if there's an emacs equivalent we should consider binding to that in the future to support manually triggering the completions menu without delay.

@notpeter
Copy link
Member

I've tried to test this in various Editor context other than regular buffers (command palette, assistant panel, project panel) and it works pretty well.

  • Renaming a file in the project panel is awkward (selects the entire filename by default, so it's difficult to deselect without cancelling the rename). Pressing right does not deselect and place you at the end of the filename.
  • Similar issue when spawning the buffer search / project search since it selects your query string by default.

In a buffer I think these behaviors are fine but I think in the single line editors (search, modals, etC) I think this behavior is a little too jank to ship.

How would you feel about changing the keybind contexts to:

    "context": "Editor && (mode == full) && selection",
    "context": "Editor && (mode == full) && !selection",

Would it be an acceptable compromise to add support for emacs style "mark mode" but only in Full Editor buffers, not in line editors?

I also noticed a difference between this an emacs behavior:
In a buffer, hold shift and press right a few times to mark some text and release shift.

  • In emacs, adding to the selection requires holding shift again; pressing right without shift cancels the selection.
  • In Zed, pressing right without shift expands the selection.

Alternatively we could conceivably split the arrow/home/end binds I added to only be used in mode == full while the supporting the emacs style navigations everywhere.

Thoughts?

@ozanmakes
Copy link
Contributor Author

I love this. Particularly the elegance of "mark mode" being activate whenever there is a selection. It's obviously not perfect (you have to rapidly press a navigation key after ctrl-space) but it's a lot of functionality for very little code.

Thank you!

I've added ctrl-space + native navigation keys (left,right,home,end,pageup,pagedown,alt-left,alt-right) to further match the behavior of emacs.

This is great, thanks for adding these.

Currently ctrl-space in macos/linux is bound to editor::ShowCompletions which will now be slightly delayed. I wonder if there's an emacs equivalent we should consider binding to that in the future to support manually triggering the completions menu without delay.

Alt-/ would be a natural keybinding for this as it is used in Emacs for various text completion mechanisms (by default dabbrev-expand).

In Zed, pressing right without shift expands the selection.

You're right, in Emacs selecting text with Shift + arrow keys does not set the mark. But I can't think of a way to replicate this behavior. For users who use Emacs keymap but prefer selecting text with classic Shift + arrow keys this could be a regression and a bit annoying.

Would it be an acceptable compromise to add support for emacs style "mark mode" but only in Full Editor buffers, not in line editors?

I think this is a good compromise. These keybindings are most valuable in file and assistant buffers, and we can omit line editors to keep this PR simple and not introduce counter-intuitive edge cases. I will update the context in this PR accordingly.

@gold

This comment was marked as off-topic.

@notpeter
Copy link
Member

notpeter commented Jan 13, 2025

@ozanmakes This looks good and I'm going to go ahead and merge.

We're definitely at an inflection point here. Prior to this change we were just mapping Zed actions to their emacs equivalent keybinds, but selections in emacs behave differently than most GUI editors (VSCode, Zed, etc) and are implemented as an explicit mode. I'm sure some users will not like the changes here, but let's give it a whirl and get some feedback.

Thank you!

@notpeter notpeter enabled auto-merge January 13, 2025 14:36
@ozanmakes
Copy link
Contributor Author

Excited to have this in Zed, thank you for merging it and for your great feedback!

@notpeter notpeter disabled auto-merge January 13, 2025 14:46
@notpeter notpeter added this pull request to the merge queue Jan 13, 2025
Merged via the queue into zed-industries:main with commit 13405ed Jan 13, 2025
13 checks passed
@notpeter
Copy link
Member

I've been using this for a day and I personally hate it.
The "implicit mark mode" when selecting means I'm constantly having to explicitly unselect (escape, ctrl-g) when I want to keyboard navigate without selections.

I'm reverting and am revisiting the creation of a mark mode which requires an explicit ctrl-space to enter into.

In the meantime anyone who wishes to use this mode can paste the following into their user keymap:

  // Emacs set-mark-command emulation (ctrl-space + movement bindings)
  {
    "context": "Editor && (mode == full) && !selection",
    "bindings": {
      "ctrl-space right": "editor::SelectRight",
      "ctrl-space left": "editor::SelectLeft",
      "ctrl-space down": "editor::SelectDown",
      "ctrl-space up": "editor::SelectUp",
      "ctrl-space home": "editor::SelectToBeginningOfLine",
      "ctrl-space end": "editor::SelectToEndOfLine",
      "ctrl-space alt-left": "editor::SelectToPreviousWordStart",
      "ctrl-space alt-right": "editor::SelectToNextWordEnd",
      "ctrl-space pagedown": "editor::SelectPageDown",
      "ctrl-space pageup": "editor::SelectPageUp",
      "ctrl-space ctrl-f": "editor::SelectRight",
      "ctrl-space ctrl-b": "editor::SelectLeft",
      "ctrl-space ctrl-n": "editor::SelectDown",
      "ctrl-space ctrl-p": "editor::SelectUp",
      "ctrl-space ctrl-a": "editor::SelectToBeginningOfLine",
      "ctrl-space ctrl-e": "editor::SelectToEndOfLine",
      "ctrl-space alt-f": "editor::SelectToNextWordEnd",
      "ctrl-space alt-b": "editor::SelectToPreviousWordStart",
      "ctrl-space alt-<": "editor::SelectToBeginning",
      "ctrl-space alt->": "editor::SelectToEnd",
      "ctrl-space alt-v": "editor::SelectPageUp",
      "ctrl-space ctrl-v": "editor::SelectPageDown",
      "ctrl-space alt-{": "editor::SelectToStartOfParagraph",
      "ctrl-space alt-}": "editor::SelectToEndOfParagraph"
    }
  },
  {
    "context": "Editor && (mode == full) && selection",
    "bindings": {
      "right": "editor::SelectRight",
      "left": "editor::SelectLeft",
      "down": "editor::SelectDown",
      "up": "editor::SelectUp",
      "home": "editor::SelectToBeginningOfLine",
      "end": "editor::SelectToEndOfLine",
      "alt-left": "editor::SelectToPreviousWordStart",
      "alt-right": "editor::SelectToNextWordEnd",
      "pagedown": "editor::SelectPageDown",
      "pageup": "editor::SelectPageUp",
      "ctrl-f": "editor::SelectRight",
      "ctrl-b": "editor::SelectLeft",
      "ctrl-n": "editor::SelectDown",
      "ctrl-p": "editor::SelectUp",
      "ctrl-a": "editor::SelectToBeginningOfLine",
      "ctrl-e": "editor::SelectToEndOfLine",
      "alt-f": "editor::SelectToNextWordEnd",
      "alt-b": "editor::SelectToPreviousSubwordStart",
      "alt-<": "editor::SelectToBeginning",
      "alt->": "editor::SelectToEnd",
      "ctrl-space": "editor::Cancel" // clear mark
    }
  },

notpeter added a commit that referenced this pull request Jan 14, 2025
github-merge-queue bot pushed a commit that referenced this pull request Jan 14, 2025
- Reverts #22904
- See also: #8580

After using it full-time for a day I very much think an implicit "mark
mode" when the emacs base keymap is enabled is the wrong approach.

Release Notes:

- Reverted "Add emacs keybindings for mark emulation" #23146 (main only)
@ozanmakes
Copy link
Contributor Author

Understood, too bad it didn't hit the mark for you (no pun intended).

An explicit mark mode would indeed be great. Editors often have super intricate VIM emulation but only rudimentary Emacs bindings; if Zed team is open to introducing this, it would make me, and I presume many others, very happy.

@notpeter
Copy link
Member

notpeter commented Jan 17, 2025

@ozanmakes Can you check this out and let me know if you have any feedback:

@notpeter notpeter mentioned this pull request Jan 17, 2025
notpeter added a commit that referenced this pull request Jan 21, 2025
Updates #21927
Replaces #22904
Closes #8580

Adds actions (default keybinds with emacs keymap):
- editor::SetMark (`ctrl-space` and `ctrl-@`)
- editor::ExchangeMark (`ctrl-x ctrl-x`)

Co-Authored-By: Peter <[email protected]>

Release Notes:

- Add Emacs mark mode (`ctrl-space` / `ctrl-@` to set mark; `ctrl-x
ctrl-x` to swap mark/cursor)
- Breaking change: `selection` keyboard context has been replaced with
`selection_mode`

---------

Co-authored-by: Peter <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla-signed The user has signed the Contributor License Agreement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants