Hello, I am having a great time setting up the editor, but with a few problems related to the Emacs keymap. In this PR I have compiled changes in the default `emacs.json` that I believe make the onboarding smoother for incoming emacs users. This includes points that may need further discussion and some breaking changes, although nothing that cannot be reverted with a quick `keymap.json` overwrite. (Please let me know if it is better to split up the PR) ### 1. Avoid fallbacks to the default keymap all platforms: - `ctrl-g` activating `go_to_line::Toggle` when there is nothing to cancel linux / windows: - `ctrl-x` activating `editor::Cut` on the 1 second timeout - `ctrl-p` activating `file_finder::Toggle` when the cursor is on the first character of the buffer - `ctrl-n` activating `workspace::NewFile` when the cursor is on the last character of the buffer ### 2. Make all move commands operate on full words In the current Zed implementation some commands run on full words and others on subwords. Although ultimately a matter of user preference, I think it is sensible to use full words as the default, since that is what is shipped with emacs. ### ~~3. Cancel selections after copy/cut commands~~ Moved to #40904 Canceling the selection is the default emacs behavior, but the way to achieve it might need some brushing. Currently I am using `workspace::SendKeystrokes` to copy -> cancel(`ctrl-g`), but this has the following problems: - can only be used in the main buffer (since `editor::Cancel` would typically close secondary buffers) - may cause problems downstream if the user overwrites the `ctrl-g` binding ### ~~4. Replace killring with normal cut/paste commands~~ Moved to #40905 Ideally Zed would support emacs-like killrings (#25270 and #22490). However, I understand that making an emacs emulator is not a project goal, and the Zed team should have a bunch of tasks with higher priority. By using a unified clipboard and standard cut/paste commands, we can provide an experience that is closer to the out-of-the-box emacs behavior (#33351) while also avoiding some pitfalls of the current killring implementation (#28715). ### 5. Promote some bindings to workspace commands - `alt-x` as `command_palette::Toggle` - `ctrl-x b` and `ctrl-x ctrl-b` as `tab_switcher::Toggle` --- Release Notes: - emacs: Fixed a problem where keys would fallback to their default keymap binding on certain conditions - emacs: Changed `alt-f` and `alt-b` to operate on full words, as in the emacs default - emacs: `alt-x`, `ctrl-x b`, and `ctrl-x ctrl-b` are now Workspace bindings
207 lines
9.7 KiB
JSON
Executable File
207 lines
9.7 KiB
JSON
Executable File
// documentation: https://zed.dev/docs/key-bindings
|
|
//
|
|
// To see the default key bindings run `zed: open default keymap`
|
|
// from the command palette.
|
|
[
|
|
{
|
|
"bindings": {
|
|
"ctrl-g": "menu::Cancel"
|
|
}
|
|
},
|
|
{
|
|
// Workaround to avoid falling back to default bindings.
|
|
// Unbind so Zed ignores these keys and lets emacs handle them.
|
|
// NOTE: must be declared before the `Editor` override.
|
|
// NOTE: in macos the 'ctrl-x' 'ctrl-p' and 'ctrl-n' rebindings are not needed, since they default to 'cmd'.
|
|
"context": "Editor",
|
|
"bindings": {
|
|
"ctrl-g": null, // currently activates `go_to_line::Toggle` when there is nothing to cancel
|
|
"ctrl-x": null, // currently activates `editor::Cut` if no following key is pressed for 1 second
|
|
"ctrl-p": null, // currently activates `file_finder::Toggle` when the cursor is on the first character of the buffer
|
|
"ctrl-n": null // currently activates `workspace::NewFile` when the cursor is on the last character of the buffer
|
|
}
|
|
},
|
|
{
|
|
"context": "Editor",
|
|
"bindings": {
|
|
"ctrl-g": "editor::Cancel",
|
|
"alt-g g": "go_to_line::Toggle", // goto-line
|
|
"alt-g alt-g": "go_to_line::Toggle", // goto-line
|
|
"ctrl-space": "editor::SetMark", // set-mark
|
|
"ctrl-@": "editor::SetMark", // set-mark
|
|
"ctrl-x ctrl-x": "editor::SwapSelectionEnds", // exchange-point-and-mark
|
|
"ctrl-f": "editor::MoveRight", // forward-char
|
|
"ctrl-b": "editor::MoveLeft", // backward-char
|
|
"ctrl-n": "editor::MoveDown", // next-line
|
|
"ctrl-p": "editor::MoveUp", // previous-line
|
|
"home": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": false }], // move-beginning-of-line
|
|
"end": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": false }], // move-end-of-line
|
|
"ctrl-a": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": false }], // move-beginning-of-line
|
|
"ctrl-e": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": false }], // move-end-of-line
|
|
"shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": false }], // move-beginning-of-line
|
|
"shift-end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": false }], // move-end-of-line
|
|
"alt-m": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": false, "stop_at_indent": true }], // back-to-indentation
|
|
"alt-left": "editor::MoveToPreviousWordStart", // left-word
|
|
"alt-right": "editor::MoveToNextWordEnd", // right-word
|
|
"alt-f": "editor::MoveToNextWordEnd", // forward-word
|
|
"alt-b": "editor::MoveToPreviousWordStart", // backward-word
|
|
"alt-u": "editor::ConvertToUpperCase", // upcase-word
|
|
"alt-l": "editor::ConvertToLowerCase", // downcase-word
|
|
"alt-c": "editor::ConvertToUpperCamelCase", // capitalize-word
|
|
"ctrl-t": "editor::Transpose", // transpose-chars
|
|
"alt-;": ["editor::ToggleComments", { "advance_downwards": false }],
|
|
"ctrl-x ctrl-;": "editor::ToggleComments",
|
|
"alt-.": "editor::GoToDefinition", // xref-find-definitions
|
|
"alt-?": "editor::FindAllReferences", // xref-find-references
|
|
"alt-,": "pane::GoBack", // xref-pop-marker-stack
|
|
"ctrl-x h": "editor::SelectAll", // mark-whole-buffer
|
|
"ctrl-d": "editor::Delete", // delete-char
|
|
"alt-d": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }], // kill-word
|
|
"alt-backspace": "editor::DeleteToPreviousWordStart", // backward-kill-word
|
|
"alt-delete": "editor::DeleteToPreviousWordStart", // backward-kill-word
|
|
"ctrl-k": "editor::KillRingCut", // kill-line
|
|
"ctrl-w": "editor::Cut", // kill-region
|
|
"alt-w": "editor::Copy", // kill-ring-save
|
|
"ctrl-y": "editor::KillRingYank", // yank
|
|
"ctrl-_": "editor::Undo", // undo
|
|
"ctrl-/": "editor::Undo", // undo
|
|
"ctrl-x u": "editor::Undo", // undo
|
|
"alt-{": "editor::MoveToStartOfParagraph", // backward-paragraph
|
|
"alt-}": "editor::MoveToEndOfParagraph", // forward-paragraph
|
|
"ctrl-up": "editor::MoveToStartOfParagraph", // backward-paragraph
|
|
"ctrl-down": "editor::MoveToEndOfParagraph", // forward-paragraph
|
|
"ctrl-v": "editor::MovePageDown", // scroll-up
|
|
"alt-v": "editor::MovePageUp", // scroll-down
|
|
"ctrl-x [": "editor::MoveToBeginning", // beginning-of-buffer
|
|
"ctrl-x ]": "editor::MoveToEnd", // end-of-buffer
|
|
"alt-<": "editor::MoveToBeginning", // beginning-of-buffer
|
|
"alt->": "editor::MoveToEnd", // end-of-buffer
|
|
"ctrl-home": "editor::MoveToBeginning", // beginning-of-buffer
|
|
"ctrl-end": "editor::MoveToEnd", // end-of-buffer
|
|
"ctrl-l": "editor::ScrollCursorCenterTopBottom", // recenter-top-bottom
|
|
"ctrl-s": "buffer_search::Deploy", // isearch-forward
|
|
"ctrl-r": "buffer_search::Deploy", // isearch-backward
|
|
"alt-^": "editor::JoinLines", // join-line
|
|
"alt-q": "editor::Rewrap" // fill-paragraph
|
|
}
|
|
},
|
|
{
|
|
"context": "Editor && selection_mode", // region selection
|
|
"bindings": {
|
|
"right": "editor::SelectRight",
|
|
"left": "editor::SelectLeft",
|
|
"down": "editor::SelectDown",
|
|
"up": "editor::SelectUp",
|
|
"alt-left": "editor::SelectToPreviousWordStart",
|
|
"alt-right": "editor::SelectToNextWordEnd",
|
|
"pagedown": "editor::SelectPageDown",
|
|
"ctrl-v": "editor::SelectPageDown",
|
|
"pageup": "editor::SelectPageUp",
|
|
"alt-v": "editor::SelectPageUp",
|
|
"ctrl-f": "editor::SelectRight",
|
|
"ctrl-b": "editor::SelectLeft",
|
|
"ctrl-n": "editor::SelectDown",
|
|
"ctrl-p": "editor::SelectUp",
|
|
"home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": false }],
|
|
"end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": false }],
|
|
"ctrl-a": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": false }],
|
|
"ctrl-e": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": false }],
|
|
"alt-m": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": false, "stop_at_indent": true }],
|
|
"alt-f": "editor::SelectToNextWordEnd",
|
|
"alt-b": "editor::SelectToPreviousWordStart",
|
|
"alt-{": "editor::SelectToStartOfParagraph",
|
|
"alt-}": "editor::SelectToEndOfParagraph",
|
|
"ctrl-up": "editor::SelectToStartOfParagraph",
|
|
"ctrl-down": "editor::SelectToEndOfParagraph",
|
|
"ctrl-x [": "editor::SelectToBeginning",
|
|
"ctrl-x ]": "editor::SelectToEnd",
|
|
"alt-<": "editor::SelectToBeginning",
|
|
"alt->": "editor::SelectToEnd",
|
|
"ctrl-home": "editor::SelectToBeginning",
|
|
"ctrl-end": "editor::SelectToEnd",
|
|
"ctrl-g": "editor::Cancel"
|
|
}
|
|
},
|
|
{
|
|
"context": "Editor && (showing_code_actions || showing_completions)",
|
|
"bindings": {
|
|
"ctrl-p": "editor::ContextMenuPrevious",
|
|
"ctrl-n": "editor::ContextMenuNext"
|
|
}
|
|
},
|
|
{
|
|
"context": "Editor && showing_signature_help && !showing_completions",
|
|
"bindings": {
|
|
"ctrl-p": "editor::SignatureHelpPrevious",
|
|
"ctrl-n": "editor::SignatureHelpNext"
|
|
}
|
|
},
|
|
// Example setting for using emacs-style tab
|
|
// (i.e. indent the current line / selection or perform symbol completion depending on context)
|
|
// {
|
|
// "context": "Editor && !showing_code_actions && !showing_completions",
|
|
// "bindings": {
|
|
// "tab": "editor::AutoIndent" // indent-for-tab-command
|
|
// }
|
|
// },
|
|
{
|
|
"context": "Workspace",
|
|
"bindings": {
|
|
"alt-x": "command_palette::Toggle", // execute-extended-command
|
|
"ctrl-x b": "tab_switcher::Toggle", // switch-to-buffer
|
|
"ctrl-x ctrl-b": "tab_switcher::Toggle", // list-buffers
|
|
// "ctrl-x ctrl-c": "workspace::CloseWindow" // in case you only want to exit the current Zed instance
|
|
"ctrl-x ctrl-c": "zed::Quit", // save-buffers-kill-terminal
|
|
"ctrl-x 5 0": "workspace::CloseWindow", // delete-frame
|
|
"ctrl-x 5 2": "workspace::NewWindow", // make-frame-command
|
|
"ctrl-x o": "workspace::ActivateNextPane", // other-window
|
|
"ctrl-x k": "pane::CloseActiveItem", // kill-buffer
|
|
"ctrl-x 0": "pane::CloseActiveItem", // delete-window
|
|
// "ctrl-x 1": "pane::JoinAll", // in case you prefer to delete the splits but keep the buffers open
|
|
"ctrl-x 1": "pane::CloseOtherItems", // delete-other-windows
|
|
"ctrl-x 2": "pane::SplitDown", // split-window-below
|
|
"ctrl-x 3": "pane::SplitRight", // split-window-right
|
|
"ctrl-x ctrl-f": "file_finder::Toggle", // find-file
|
|
"ctrl-x ctrl-s": "workspace::Save", // save-buffer
|
|
"ctrl-x ctrl-w": "workspace::SaveAs", // write-file
|
|
"ctrl-x s": "workspace::SaveAll" // save-some-buffers
|
|
}
|
|
},
|
|
{
|
|
// Workaround to enable using native emacs from the Zed terminal.
|
|
// Unbind so Zed ignores these keys and lets emacs handle them.
|
|
// NOTE:
|
|
// "terminal::SendKeystroke" only works for a single key stroke (e.g. ctrl-x),
|
|
// so override with null for compound sequences (e.g. ctrl-x ctrl-c).
|
|
"context": "Terminal",
|
|
"bindings": {
|
|
// If you want to perfect your emacs-in-zed setup, also consider the following.
|
|
// You may need to enable "option_as_meta" from the Zed settings for "alt-x" to work.
|
|
// "alt-x": ["terminal::SendKeystroke", "alt-x"],
|
|
// "ctrl-x": ["terminal::SendKeystroke", "ctrl-x"],
|
|
// "ctrl-n": ["terminal::SendKeystroke", "ctrl-n"],
|
|
// ...
|
|
"ctrl-x ctrl-c": null, // save-buffers-kill-terminal
|
|
"ctrl-x ctrl-f": null, // find-file
|
|
"ctrl-x ctrl-s": null, // save-buffer
|
|
"ctrl-x ctrl-w": null, // write-file
|
|
"ctrl-x s": null // save-some-buffers
|
|
}
|
|
},
|
|
{
|
|
"context": "BufferSearchBar > Editor",
|
|
"bindings": {
|
|
"ctrl-s": "search::SelectNextMatch",
|
|
"ctrl-r": "search::SelectPreviousMatch",
|
|
"ctrl-g": "buffer_search::Dismiss"
|
|
}
|
|
},
|
|
{
|
|
"context": "Pane",
|
|
"bindings": {
|
|
"ctrl-alt-left": "pane::GoBack",
|
|
"ctrl-alt-right": "pane::GoForward"
|
|
}
|
|
}
|
|
]
|