mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-07 02:57:34 +00:00
Merge pull request #875 from zed-industries/keymap-improvements
Keymap improvements
This commit is contained in:
commit
0c587ae73c
20 changed files with 732 additions and 493 deletions
20
Cargo.lock
generated
20
Cargo.lock
generated
|
@ -2572,6 +2572,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json_comments"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41ee439ee368ba4a77ac70d04f14015415af8600d6c894dc1f11bd79758c57d5"
|
||||
|
||||
[[package]]
|
||||
name = "json_env_logger"
|
||||
version = "0.1.1"
|
||||
|
@ -2643,7 +2649,7 @@ dependencies = [
|
|||
"text",
|
||||
"theme",
|
||||
"tree-sitter",
|
||||
"tree-sitter-json",
|
||||
"tree-sitter-json 0.19.0",
|
||||
"tree-sitter-rust",
|
||||
"unindent",
|
||||
"util",
|
||||
|
@ -4304,6 +4310,7 @@ dependencies = [
|
|||
"assets",
|
||||
"collections",
|
||||
"gpui",
|
||||
"json_comments",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -5193,6 +5200,15 @@ dependencies = [
|
|||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-json"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/tree-sitter/tree-sitter-json?rev=137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8#137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-markdown"
|
||||
version = "0.0.1"
|
||||
|
@ -5837,7 +5853,7 @@ dependencies = [
|
|||
"toml",
|
||||
"tree-sitter",
|
||||
"tree-sitter-c",
|
||||
"tree-sitter-json",
|
||||
"tree-sitter-json 0.20.0",
|
||||
"tree-sitter-markdown",
|
||||
"tree-sitter-rust",
|
||||
"tree-sitter-typescript",
|
||||
|
|
|
@ -1,264 +1,339 @@
|
|||
{
|
||||
"*": {
|
||||
"ctrl-alt-cmd-f": "workspace::FollowNextCollaborator",
|
||||
"cmd-s": "workspace::Save",
|
||||
"cmd-alt-i": "zed::DebugElements",
|
||||
"cmd-k cmd-left": "workspace::ActivatePreviousPane",
|
||||
"cmd-k cmd-right": "workspace::ActivateNextPane",
|
||||
"cmd-=": "zed::IncreaseBufferFontSize",
|
||||
"cmd--": "zed::DecreaseBufferFontSize",
|
||||
"cmd-,": "zed::OpenSettings"
|
||||
[
|
||||
// Standard macOS bindings
|
||||
{
|
||||
"bindings": {
|
||||
"up": "menu::SelectPrev",
|
||||
"ctrl-p": "menu::SelectPrev",
|
||||
"down": "menu::SelectNext",
|
||||
"ctrl-n": "menu::SelectNext",
|
||||
"cmd-up": "menu::SelectFirst",
|
||||
"cmd-down": "menu::SelectLast",
|
||||
"enter": "menu::Confirm",
|
||||
"escape": "menu::Cancel",
|
||||
"ctrl-c": "menu::Cancel",
|
||||
"shift-cmd-{": "pane::ActivatePrevItem",
|
||||
"shift-cmd-}": "pane::ActivateNextItem",
|
||||
"cmd-w": "pane::CloseActiveItem",
|
||||
"alt-cmd-w": "pane::CloseInactiveItems",
|
||||
"cmd-s": "workspace::Save",
|
||||
"cmd-=": "zed::IncreaseBufferFontSize",
|
||||
"cmd--": "zed::DecreaseBufferFontSize",
|
||||
"cmd-,": "zed::OpenSettings"
|
||||
}
|
||||
},
|
||||
"menu": {
|
||||
"up": "menu::SelectPrev",
|
||||
"ctrl-p": "menu::SelectPrev",
|
||||
"down": "menu::SelectNext",
|
||||
"ctrl-n": "menu::SelectNext",
|
||||
"cmd-up": "menu::SelectFirst",
|
||||
"cmd-down": "menu::SelectLast",
|
||||
"enter": "menu::Confirm",
|
||||
"escape": "menu::Cancel"
|
||||
{
|
||||
"context": "Editor",
|
||||
"bindings": {
|
||||
"escape": "editor::Cancel",
|
||||
"backspace": "editor::Backspace",
|
||||
"ctrl-h": "editor::Backspace",
|
||||
"delete": "editor::Delete",
|
||||
"ctrl-d": "editor::Delete",
|
||||
"tab": "editor::Tab",
|
||||
"shift-tab": "editor::TabPrev",
|
||||
"ctrl-k": "editor::CutToEndOfLine",
|
||||
"cmd-backspace": "editor::DeleteToBeginningOfLine",
|
||||
"cmd-delete": "editor::DeleteToEndOfLine",
|
||||
"alt-backspace": "editor::DeleteToPreviousWordStart",
|
||||
"alt-delete": "editor::DeleteToNextWordEnd",
|
||||
"alt-h": "editor::DeleteToPreviousWordStart",
|
||||
"alt-d": "editor::DeleteToNextWordEnd",
|
||||
"cmd-x": "editor::Cut",
|
||||
"cmd-c": "editor::Copy",
|
||||
"cmd-v": "editor::Paste",
|
||||
"cmd-z": "editor::Undo",
|
||||
"cmd-shift-Z": "editor::Redo",
|
||||
"up": "editor::MoveUp",
|
||||
"down": "editor::MoveDown",
|
||||
"left": "editor::MoveLeft",
|
||||
"right": "editor::MoveRight",
|
||||
"ctrl-p": "editor::MoveUp",
|
||||
"ctrl-n": "editor::MoveDown",
|
||||
"ctrl-b": "editor::MoveLeft",
|
||||
"ctrl-f": "editor::MoveRight",
|
||||
"alt-left": "editor::MoveToPreviousWordStart",
|
||||
"alt-b": "editor::MoveToPreviousWordStart",
|
||||
"alt-right": "editor::MoveToNextWordEnd",
|
||||
"alt-f": "editor::MoveToNextWordEnd",
|
||||
"cmd-left": "editor::MoveToBeginningOfLine",
|
||||
"ctrl-a": "editor::MoveToBeginningOfLine",
|
||||
"cmd-right": "editor::MoveToEndOfLine",
|
||||
"ctrl-e": "editor::MoveToEndOfLine",
|
||||
"cmd-up": "editor::MoveToBeginning",
|
||||
"cmd-down": "editor::MoveToEnd",
|
||||
"shift-up": "editor::SelectUp",
|
||||
"ctrl-shift-P": "editor::SelectUp",
|
||||
"shift-down": "editor::SelectDown",
|
||||
"ctrl-shift-N": "editor::SelectDown",
|
||||
"shift-left": "editor::SelectLeft",
|
||||
"ctrl-shift-B": "editor::SelectLeft",
|
||||
"shift-right": "editor::SelectRight",
|
||||
"ctrl-shift-F": "editor::SelectRight",
|
||||
"alt-shift-left": "editor::SelectToPreviousWordStart",
|
||||
"alt-shift-B": "editor::SelectToPreviousWordStart",
|
||||
"alt-shift-right": "editor::SelectToNextWordEnd",
|
||||
"alt-shift-F": "editor::SelectToNextWordEnd",
|
||||
"cmd-shift-up": "editor::SelectToBeginning",
|
||||
"cmd-shift-down": "editor::SelectToEnd",
|
||||
"cmd-a": "editor::SelectAll",
|
||||
"cmd-l": "editor::SelectLine",
|
||||
"cmd-shift-left": [
|
||||
"editor::SelectToBeginningOfLine",
|
||||
{
|
||||
"stop_at_soft_wraps": true
|
||||
}
|
||||
],
|
||||
"ctrl-shift-A": [
|
||||
"editor::SelectToBeginningOfLine",
|
||||
{
|
||||
"stop_at_soft_wraps": true
|
||||
}
|
||||
],
|
||||
"cmd-shift-right": [
|
||||
"editor::SelectToEndOfLine",
|
||||
{
|
||||
"stop_at_soft_wraps": true
|
||||
}
|
||||
],
|
||||
"ctrl-shift-E": [
|
||||
"editor::SelectToEndOfLine",
|
||||
{
|
||||
"stop_at_soft_wraps": true
|
||||
}
|
||||
],
|
||||
"pageup": "editor::PageUp",
|
||||
"pagedown": "editor::PageDown"
|
||||
}
|
||||
},
|
||||
"Pane": {
|
||||
"shift-cmd-{": "pane::ActivatePrevItem",
|
||||
"shift-cmd-}": "pane::ActivateNextItem",
|
||||
"cmd-w": "pane::CloseActiveItem",
|
||||
"alt-cmd-w": "pane::CloseInactiveItems",
|
||||
"ctrl--": "pane::GoBack",
|
||||
"shift-ctrl-_": "pane::GoForward",
|
||||
"cmd-k up": [
|
||||
"pane::Split",
|
||||
"Up"
|
||||
],
|
||||
"cmd-k down": [
|
||||
"pane::Split",
|
||||
"Down"
|
||||
],
|
||||
"cmd-k left": [
|
||||
"pane::Split",
|
||||
"Left"
|
||||
],
|
||||
"cmd-k right": [
|
||||
"pane::Split",
|
||||
"Right"
|
||||
],
|
||||
"cmd-shift-F": "project_search::ToggleFocus",
|
||||
"cmd-f": "project_search::ToggleFocus",
|
||||
"cmd-g": "search::SelectNextMatch",
|
||||
"cmd-shift-G": "search::SelectPrevMatch"
|
||||
{
|
||||
"context": "Editor && mode == full",
|
||||
"bindings": {
|
||||
"enter": "editor::Newline",
|
||||
"cmd-f": [
|
||||
"buffer_search::Deploy",
|
||||
{
|
||||
"focus": true
|
||||
}
|
||||
],
|
||||
"cmd-e": [
|
||||
"buffer_search::Deploy",
|
||||
{
|
||||
"focus": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Workspace": {
|
||||
"cmd-shift-F": "project_search::Deploy",
|
||||
"cmd-k cmd-t": "theme_selector::Toggle",
|
||||
"cmd-k t": "theme_selector::Reload",
|
||||
"cmd-t": "project_symbols::Toggle",
|
||||
"cmd-p": "file_finder::Toggle",
|
||||
"cmd-shift-P": "command_palette::Toggle",
|
||||
"alt-shift-D": "diagnostics::Deploy",
|
||||
"ctrl-alt-cmd-j": "journal::NewJournalEntry",
|
||||
"cmd-1": [
|
||||
"workspace::ToggleSidebarItemFocus",
|
||||
{
|
||||
"side": "Left",
|
||||
"item_index": 0
|
||||
}
|
||||
],
|
||||
"cmd-shift-!": [
|
||||
"workspace::ToggleSidebarItem",
|
||||
{
|
||||
"side": "Left",
|
||||
"item_index": 0
|
||||
}
|
||||
]
|
||||
{
|
||||
"context": "Editor && mode == auto_height",
|
||||
"bindings": {
|
||||
"alt-enter": [
|
||||
"editor::Input",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ProjectSearchBar": {
|
||||
"enter": "project_search::Search",
|
||||
"cmd-enter": "project_search::SearchInNew"
|
||||
{
|
||||
"context": "Pane",
|
||||
"bindings": {
|
||||
"cmd-f": "project_search::ToggleFocus",
|
||||
"cmd-g": "search::SelectNextMatch",
|
||||
"cmd-shift-G": "search::SelectPrevMatch"
|
||||
}
|
||||
},
|
||||
"BufferSearchBar": {
|
||||
"escape": "buffer_search::Dismiss",
|
||||
"cmd-f": "buffer_search::FocusEditor",
|
||||
"enter": "search::SelectNextMatch",
|
||||
"shift-enter": "search::SelectPrevMatch"
|
||||
{
|
||||
"context": "BufferSearchBar",
|
||||
"bindings": {
|
||||
"escape": "buffer_search::Dismiss",
|
||||
"cmd-f": "buffer_search::FocusEditor",
|
||||
"enter": "search::SelectNextMatch",
|
||||
"shift-enter": "search::SelectPrevMatch"
|
||||
}
|
||||
},
|
||||
"Editor": {
|
||||
"escape": "editor::Cancel",
|
||||
"backspace": "editor::Backspace",
|
||||
"ctrl-h": "editor::Backspace",
|
||||
"delete": "editor::Delete",
|
||||
"ctrl-d": "editor::Delete",
|
||||
"tab": "editor::Tab",
|
||||
"shift-tab": "editor::TabPrev",
|
||||
"cmd-[": "editor::Outdent",
|
||||
"cmd-]": "editor::Indent",
|
||||
"ctrl-shift-K": "editor::DeleteLine",
|
||||
"alt-backspace": "editor::DeleteToPreviousWordStart",
|
||||
"alt-h": "editor::DeleteToPreviousWordStart",
|
||||
"ctrl-alt-backspace": "editor::DeleteToPreviousSubwordStart",
|
||||
"ctrl-alt-h": "editor::DeleteToPreviousSubwordStart",
|
||||
"alt-delete": "editor::DeleteToNextWordEnd",
|
||||
"alt-d": "editor::DeleteToNextWordEnd",
|
||||
"ctrl-alt-delete": "editor::DeleteToNextSubwordEnd",
|
||||
"ctrl-alt-d": "editor::DeleteToNextSubwordEnd",
|
||||
"cmd-backspace": "editor::DeleteToBeginningOfLine",
|
||||
"cmd-delete": "editor::DeleteToEndOfLine",
|
||||
"ctrl-k": "editor::CutToEndOfLine",
|
||||
"cmd-shift-D": "editor::DuplicateLine",
|
||||
"ctrl-cmd-up": "editor::MoveLineUp",
|
||||
"ctrl-cmd-down": "editor::MoveLineDown",
|
||||
"cmd-x": "editor::Cut",
|
||||
"cmd-c": "editor::Copy",
|
||||
"cmd-v": "editor::Paste",
|
||||
"cmd-z": "editor::Undo",
|
||||
"cmd-shift-Z": "editor::Redo",
|
||||
"up": "editor::MoveUp",
|
||||
"down": "editor::MoveDown",
|
||||
"left": "editor::MoveLeft",
|
||||
"right": "editor::MoveRight",
|
||||
"ctrl-p": "editor::MoveUp",
|
||||
"ctrl-n": "editor::MoveDown",
|
||||
"ctrl-b": "editor::MoveLeft",
|
||||
"ctrl-f": "editor::MoveRight",
|
||||
"alt-left": "editor::MoveToPreviousWordStart",
|
||||
"alt-b": "editor::MoveToPreviousWordStart",
|
||||
"ctrl-alt-left": "editor::MoveToPreviousSubwordStart",
|
||||
"ctrl-alt-b": "editor::MoveToPreviousSubwordStart",
|
||||
"alt-right": "editor::MoveToNextWordEnd",
|
||||
"alt-f": "editor::MoveToNextWordEnd",
|
||||
"ctrl-alt-right": "editor::MoveToNextSubwordEnd",
|
||||
"ctrl-alt-f": "editor::MoveToNextSubwordEnd",
|
||||
"cmd-left": "editor::MoveToBeginningOfLine",
|
||||
"ctrl-a": "editor::MoveToBeginningOfLine",
|
||||
"cmd-right": "editor::MoveToEndOfLine",
|
||||
"ctrl-e": "editor::MoveToEndOfLine",
|
||||
"cmd-up": "editor::MoveToBeginning",
|
||||
"cmd-down": "editor::MoveToEnd",
|
||||
"shift-up": "editor::SelectUp",
|
||||
"ctrl-shift-P": "editor::SelectUp",
|
||||
"shift-down": "editor::SelectDown",
|
||||
"ctrl-shift-N": "editor::SelectDown",
|
||||
"shift-left": "editor::SelectLeft",
|
||||
"ctrl-shift-B": "editor::SelectLeft",
|
||||
"shift-right": "editor::SelectRight",
|
||||
"ctrl-shift-F": "editor::SelectRight",
|
||||
"alt-shift-left": "editor::SelectToPreviousWordStart",
|
||||
"alt-shift-B": "editor::SelectToPreviousWordStart",
|
||||
"ctrl-alt-shift-left": "editor::SelectToPreviousSubwordStart",
|
||||
"ctrl-alt-shift-B": "editor::SelectToPreviousSubwordStart",
|
||||
"alt-shift-right": "editor::SelectToNextWordEnd",
|
||||
"alt-shift-F": "editor::SelectToNextWordEnd",
|
||||
"ctrl-alt-shift-right": "editor::SelectToNextSubwordEnd",
|
||||
"cmd-shift-up": "editor::SelectToBeginning",
|
||||
"cmd-shift-down": "editor::SelectToEnd",
|
||||
"cmd-a": "editor::SelectAll",
|
||||
"cmd-l": "editor::SelectLine",
|
||||
"cmd-shift-L": "editor::SplitSelectionIntoLines",
|
||||
"cmd-alt-up": "editor::AddSelectionAbove",
|
||||
"cmd-ctrl-p": "editor::AddSelectionAbove",
|
||||
"cmd-alt-down": "editor::AddSelectionBelow",
|
||||
"cmd-ctrl-n": "editor::AddSelectionBelow",
|
||||
"ctrl-alt-shift-F": "editor::SelectToNextSubwordEnd",
|
||||
"cmd-shift-left": [
|
||||
"editor::SelectToBeginningOfLine",
|
||||
{
|
||||
"stop_at_soft_wraps": true
|
||||
}
|
||||
],
|
||||
"ctrl-shift-A": [
|
||||
"editor::SelectToBeginningOfLine",
|
||||
{
|
||||
"stop_at_soft_wraps": true
|
||||
}
|
||||
],
|
||||
"cmd-shift-right": [
|
||||
"editor::SelectToEndOfLine",
|
||||
{
|
||||
"stop_at_soft_wraps": true
|
||||
}
|
||||
],
|
||||
"ctrl-shift-E": [
|
||||
"editor::SelectToEndOfLine",
|
||||
{
|
||||
"stop_at_soft_wraps": true
|
||||
}
|
||||
],
|
||||
"cmd-d": [
|
||||
"editor::SelectNext",
|
||||
{
|
||||
"replace_newest": false
|
||||
}
|
||||
],
|
||||
"cmd-k cmd-d": [
|
||||
"editor::SelectNext",
|
||||
{
|
||||
"replace_newest": true
|
||||
}
|
||||
],
|
||||
"cmd-/": "editor::ToggleComments",
|
||||
"alt-up": "editor::SelectLargerSyntaxNode",
|
||||
"ctrl-w": "editor::SelectLargerSyntaxNode",
|
||||
"alt-down": "editor::SelectSmallerSyntaxNode",
|
||||
"ctrl-shift-W": "editor::SelectSmallerSyntaxNode",
|
||||
"cmd-u": "editor::UndoSelection",
|
||||
"cmd-shift-U": "editor::RedoSelection",
|
||||
"f8": "editor::GoToNextDiagnostic",
|
||||
"shift-f8": "editor::GoToPrevDiagnostic",
|
||||
"f2": "editor::Rename",
|
||||
"f12": "editor::GoToDefinition",
|
||||
"alt-shift-f12": "editor::FindAllReferences",
|
||||
"ctrl-m": "editor::MoveToEnclosingBracket",
|
||||
"pageup": "editor::PageUp",
|
||||
"pagedown": "editor::PageDown",
|
||||
"alt-cmd-[": "editor::Fold",
|
||||
"alt-cmd-]": "editor::UnfoldLines",
|
||||
"alt-cmd-f": "editor::FoldSelectedRanges",
|
||||
"ctrl-space": "editor::ShowCompletions",
|
||||
"cmd-.": "editor::ToggleCodeActions",
|
||||
"alt-enter": "editor::OpenExcerpts",
|
||||
"cmd-f10": "editor::RestartLanguageServer"
|
||||
// Bindings from VS Code
|
||||
{
|
||||
"context": "Editor",
|
||||
"bindings": {
|
||||
"cmd-[": "editor::Outdent",
|
||||
"cmd-]": "editor::Indent",
|
||||
"cmd-alt-up": "editor::AddSelectionAbove",
|
||||
"cmd-ctrl-p": "editor::AddSelectionAbove",
|
||||
"cmd-alt-down": "editor::AddSelectionBelow",
|
||||
"cmd-ctrl-n": "editor::AddSelectionBelow",
|
||||
"cmd-d": [
|
||||
"editor::SelectNext",
|
||||
{
|
||||
"replace_newest": false
|
||||
}
|
||||
],
|
||||
"cmd-k cmd-d": [
|
||||
"editor::SelectNext",
|
||||
{
|
||||
"replace_newest": true
|
||||
}
|
||||
],
|
||||
"cmd-/": "editor::ToggleComments",
|
||||
"alt-up": "editor::SelectLargerSyntaxNode",
|
||||
"alt-down": "editor::SelectSmallerSyntaxNode",
|
||||
"cmd-u": "editor::UndoSelection",
|
||||
"cmd-shift-U": "editor::RedoSelection",
|
||||
"f8": "editor::GoToNextDiagnostic",
|
||||
"shift-f8": "editor::GoToPrevDiagnostic",
|
||||
"f2": "editor::Rename",
|
||||
"f12": "editor::GoToDefinition",
|
||||
"alt-shift-f12": "editor::FindAllReferences",
|
||||
"ctrl-m": "editor::MoveToEnclosingBracket",
|
||||
"alt-cmd-[": "editor::Fold",
|
||||
"alt-cmd-]": "editor::UnfoldLines",
|
||||
"ctrl-space": "editor::ShowCompletions",
|
||||
"cmd-.": "editor::ToggleCodeActions"
|
||||
}
|
||||
},
|
||||
"Editor && renaming": {
|
||||
"enter": "editor::ConfirmRename"
|
||||
{
|
||||
"context": "Editor && mode == full",
|
||||
"bindings": {
|
||||
"cmd-shift-O": "outline::Toggle",
|
||||
"ctrl-g": "go_to_line::Toggle"
|
||||
}
|
||||
},
|
||||
"Editor && showing_completions": {
|
||||
"enter": "editor::ConfirmCompletion",
|
||||
"tab": "editor::ConfirmCompletion"
|
||||
{
|
||||
"context": "Pane",
|
||||
"bindings": {
|
||||
"ctrl--": "pane::GoBack",
|
||||
"shift-ctrl-_": "pane::GoForward",
|
||||
"cmd-shift-F": "project_search::ToggleFocus"
|
||||
}
|
||||
},
|
||||
"Editor && showing_code_actions": {
|
||||
"enter": "editor::ConfirmCodeAction"
|
||||
{
|
||||
"context": "Workspace",
|
||||
"bindings": {
|
||||
"cmd-shift-F": "project_search::Deploy",
|
||||
"cmd-k cmd-t": "theme_selector::Toggle",
|
||||
"cmd-k t": "theme_selector::Reload",
|
||||
"cmd-t": "project_symbols::Toggle",
|
||||
"cmd-p": "file_finder::Toggle",
|
||||
"cmd-shift-P": "command_palette::Toggle"
|
||||
}
|
||||
},
|
||||
"Editor && mode == full": {
|
||||
"enter": "editor::Newline",
|
||||
"cmd-f": [
|
||||
"buffer_search::Deploy",
|
||||
{
|
||||
"focus": true
|
||||
}
|
||||
],
|
||||
"cmd-e": [
|
||||
"buffer_search::Deploy",
|
||||
{
|
||||
"focus": false
|
||||
}
|
||||
],
|
||||
"cmd-shift-O": "outline::Toggle",
|
||||
"ctrl-g": "go_to_line::Toggle"
|
||||
// Bindings from Sublime Text
|
||||
{
|
||||
"context": "Editor",
|
||||
"bindings": {
|
||||
"ctrl-shift-K": "editor::DeleteLine",
|
||||
"cmd-shift-D": "editor::DuplicateLine",
|
||||
"cmd-shift-L": "editor::SplitSelectionIntoLines",
|
||||
"ctrl-cmd-up": "editor::MoveLineUp",
|
||||
"ctrl-cmd-down": "editor::MoveLineDown",
|
||||
"ctrl-alt-backspace": "editor::DeleteToPreviousSubwordStart",
|
||||
"ctrl-alt-h": "editor::DeleteToPreviousSubwordStart",
|
||||
"ctrl-alt-delete": "editor::DeleteToNextSubwordEnd",
|
||||
"ctrl-alt-d": "editor::DeleteToNextSubwordEnd",
|
||||
"ctrl-alt-left": "editor::MoveToPreviousSubwordStart",
|
||||
"ctrl-alt-b": "editor::MoveToPreviousSubwordStart",
|
||||
"ctrl-alt-right": "editor::MoveToNextSubwordEnd",
|
||||
"ctrl-alt-f": "editor::MoveToNextSubwordEnd",
|
||||
"ctrl-alt-shift-left": "editor::SelectToPreviousSubwordStart",
|
||||
"ctrl-alt-shift-B": "editor::SelectToPreviousSubwordStart",
|
||||
"ctrl-alt-shift-right": "editor::SelectToNextSubwordEnd",
|
||||
"ctrl-alt-shift-F": "editor::SelectToNextSubwordEnd"
|
||||
}
|
||||
},
|
||||
"Editor && mode == auto_height": {
|
||||
"alt-enter": [
|
||||
"editor::Input",
|
||||
"\n"
|
||||
]
|
||||
{
|
||||
"bindings": {
|
||||
"cmd-k cmd-left": "workspace::ActivatePreviousPane",
|
||||
"cmd-k cmd-right": "workspace::ActivateNextPane"
|
||||
}
|
||||
},
|
||||
"GoToLine": {
|
||||
"escape": "go_to_line::Toggle",
|
||||
"enter": "go_to_line::Confirm"
|
||||
{
|
||||
"context": "Pane",
|
||||
"bindings": {
|
||||
"cmd-k up": [
|
||||
"pane::Split",
|
||||
"Up"
|
||||
],
|
||||
"cmd-k down": [
|
||||
"pane::Split",
|
||||
"Down"
|
||||
],
|
||||
"cmd-k left": [
|
||||
"pane::Split",
|
||||
"Left"
|
||||
],
|
||||
"cmd-k right": [
|
||||
"pane::Split",
|
||||
"Right"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ChatPanel": {
|
||||
"enter": "chat_panel::Send"
|
||||
// Bindings that should be unified with bindings for more general actions
|
||||
{
|
||||
"context": "Editor && renaming",
|
||||
"bindings": {
|
||||
"enter": "editor::ConfirmRename"
|
||||
}
|
||||
},
|
||||
"ProjectPanel": {
|
||||
"left": "project_panel::CollapseSelectedEntry",
|
||||
"right": "project_panel::ExpandSelectedEntry"
|
||||
{
|
||||
"context": "Editor && showing_completions",
|
||||
"bindings": {
|
||||
"enter": "editor::ConfirmCompletion",
|
||||
"tab": "editor::ConfirmCompletion"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "Editor && showing_code_actions",
|
||||
"bindings": {
|
||||
"enter": "editor::ConfirmCodeAction"
|
||||
}
|
||||
},
|
||||
// Custom bindings
|
||||
{
|
||||
"bindings": {
|
||||
"ctrl-alt-cmd-f": "workspace::FollowNextCollaborator",
|
||||
"cmd-alt-i": "zed::DebugElements",
|
||||
"alt-cmd-,": "zed::OpenKeymap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "Editor",
|
||||
"bindings": {
|
||||
"ctrl-w": "editor::SelectLargerSyntaxNode",
|
||||
"ctrl-shift-W": "editor::SelectSmallerSyntaxNode",
|
||||
"alt-cmd-f": "editor::FoldSelectedRanges",
|
||||
"alt-enter": "editor::OpenExcerpts",
|
||||
"cmd-f10": "editor::RestartLanguageServer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "ProjectSearchBar",
|
||||
"bindings": {
|
||||
"cmd-enter": "project_search::SearchInNew"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "Workspace",
|
||||
"bindings": {
|
||||
"alt-shift-D": "diagnostics::Deploy",
|
||||
"ctrl-alt-cmd-j": "journal::NewJournalEntry",
|
||||
"cmd-1": [
|
||||
"workspace::ToggleSidebarItemFocus",
|
||||
{
|
||||
"side": "Left",
|
||||
"item_index": 0
|
||||
}
|
||||
],
|
||||
"cmd-shift-!": [
|
||||
"workspace::ToggleSidebarItem",
|
||||
{
|
||||
"side": "Left",
|
||||
"item_index": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "ProjectPanel",
|
||||
"bindings": {
|
||||
"left": "project_panel::CollapseSelectedEntry",
|
||||
"right": "project_panel::ExpandSelectedEntry"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
|
@ -1,93 +1,111 @@
|
|||
{
|
||||
"Editor && VimControl": {
|
||||
"i": [
|
||||
"vim::SwitchMode",
|
||||
"Insert"
|
||||
],
|
||||
"g": [
|
||||
"vim::PushOperator",
|
||||
{
|
||||
"Namespace": "G"
|
||||
}
|
||||
],
|
||||
"h": "vim::Left",
|
||||
"j": "vim::Down",
|
||||
"k": "vim::Up",
|
||||
"l": "vim::Right",
|
||||
"0": "vim::StartOfLine",
|
||||
"shift-$": "vim::EndOfLine",
|
||||
"shift-G": "vim::EndOfDocument",
|
||||
"w": "vim::NextWordStart",
|
||||
"shift-W": [
|
||||
"vim::NextWordStart",
|
||||
{
|
||||
"ignorePunctuation": true
|
||||
}
|
||||
],
|
||||
"e": "vim::NextWordEnd",
|
||||
"shift-E": [
|
||||
"vim::NextWordEnd",
|
||||
{
|
||||
"ignorePunctuation": true
|
||||
}
|
||||
],
|
||||
"b": "vim::PreviousWordStart",
|
||||
"shift-B": [
|
||||
"vim::PreviousWordStart",
|
||||
{
|
||||
"ignorePunctuation": true
|
||||
}
|
||||
],
|
||||
"escape": [
|
||||
"vim::SwitchMode",
|
||||
"Normal"
|
||||
]
|
||||
[
|
||||
{
|
||||
"context": "Editor && VimControl",
|
||||
"bindings": {
|
||||
"i": [
|
||||
"vim::SwitchMode",
|
||||
"Insert"
|
||||
],
|
||||
"g": [
|
||||
"vim::PushOperator",
|
||||
{
|
||||
"Namespace": "G"
|
||||
}
|
||||
],
|
||||
"h": "vim::Left",
|
||||
"j": "vim::Down",
|
||||
"k": "vim::Up",
|
||||
"l": "vim::Right",
|
||||
"0": "vim::StartOfLine",
|
||||
"shift-$": "vim::EndOfLine",
|
||||
"shift-G": "vim::EndOfDocument",
|
||||
"w": "vim::NextWordStart",
|
||||
"shift-W": [
|
||||
"vim::NextWordStart",
|
||||
{
|
||||
"ignorePunctuation": true
|
||||
}
|
||||
],
|
||||
"e": "vim::NextWordEnd",
|
||||
"shift-E": [
|
||||
"vim::NextWordEnd",
|
||||
{
|
||||
"ignorePunctuation": true
|
||||
}
|
||||
],
|
||||
"b": "vim::PreviousWordStart",
|
||||
"shift-B": [
|
||||
"vim::PreviousWordStart",
|
||||
{
|
||||
"ignorePunctuation": true
|
||||
}
|
||||
],
|
||||
"escape": [
|
||||
"vim::SwitchMode",
|
||||
"Normal"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Editor && vim_operator == g": {
|
||||
"g": "vim::StartOfDocument"
|
||||
{
|
||||
"context": "Editor && vim_operator == g",
|
||||
"bindings": {
|
||||
"g": "vim::StartOfDocument"
|
||||
}
|
||||
},
|
||||
"Editor && vim_mode == insert": {
|
||||
"escape": "vim::NormalBefore",
|
||||
"ctrl-c": "vim::NormalBefore"
|
||||
{
|
||||
"context": "Editor && vim_mode == insert",
|
||||
"bindings": {
|
||||
"escape": "vim::NormalBefore",
|
||||
"ctrl-c": "vim::NormalBefore"
|
||||
}
|
||||
},
|
||||
"Editor && vim_mode == normal": {
|
||||
"c": [
|
||||
"vim::PushOperator",
|
||||
"Change"
|
||||
],
|
||||
"d": [
|
||||
"vim::PushOperator",
|
||||
"Delete"
|
||||
]
|
||||
{
|
||||
"context": "Editor && vim_mode == normal",
|
||||
"bindings": {
|
||||
"c": [
|
||||
"vim::PushOperator",
|
||||
"Change"
|
||||
],
|
||||
"d": [
|
||||
"vim::PushOperator",
|
||||
"Delete"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Editor && vim_operator == c": {
|
||||
"w": [
|
||||
"vim::NextWordEnd",
|
||||
{
|
||||
"ignorePunctuation": false
|
||||
}
|
||||
],
|
||||
"shift-W": [
|
||||
"vim::NextWordEnd",
|
||||
{
|
||||
"ignorePunctuation": true
|
||||
}
|
||||
]
|
||||
{
|
||||
"context": "Editor && vim_operator == c",
|
||||
"bindings": {
|
||||
"w": [
|
||||
"vim::NextWordEnd",
|
||||
{
|
||||
"ignorePunctuation": false
|
||||
}
|
||||
],
|
||||
"shift-W": [
|
||||
"vim::NextWordEnd",
|
||||
{
|
||||
"ignorePunctuation": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Editor && vim_operator == d": {
|
||||
"w": [
|
||||
"vim::NextWordStart",
|
||||
{
|
||||
"ignorePunctuation": false,
|
||||
"stopAtNewline": true
|
||||
}
|
||||
],
|
||||
"shift-W": [
|
||||
"vim::NextWordStart",
|
||||
{
|
||||
"ignorePunctuation": true,
|
||||
"stopAtNewline": true
|
||||
}
|
||||
]
|
||||
{
|
||||
"context": "Editor && vim_operator == d",
|
||||
"bindings": {
|
||||
"w": [
|
||||
"vim::NextWordStart",
|
||||
{
|
||||
"ignorePunctuation": false,
|
||||
"stopAtNewline": true
|
||||
}
|
||||
],
|
||||
"shift-W": [
|
||||
"vim::NextWordStart",
|
||||
{
|
||||
"ignorePunctuation": true,
|
||||
"stopAtNewline": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
|
@ -16,6 +16,7 @@ use settings::{Settings, SoftWrap};
|
|||
use std::sync::Arc;
|
||||
use time::{OffsetDateTime, UtcOffset};
|
||||
use util::{ResultExt, TryFutureExt};
|
||||
use workspace::menu::Confirm;
|
||||
|
||||
const MESSAGE_LOADING_THRESHOLD: usize = 50;
|
||||
|
||||
|
@ -32,7 +33,7 @@ pub struct ChatPanel {
|
|||
|
||||
pub enum Event {}
|
||||
|
||||
actions!(chat_panel, [Send, LoadMoreMessages]);
|
||||
actions!(chat_panel, [LoadMoreMessages]);
|
||||
|
||||
pub fn init(cx: &mut MutableAppContext) {
|
||||
cx.add_action(ChatPanel::send);
|
||||
|
@ -345,7 +346,7 @@ impl ChatPanel {
|
|||
.boxed()
|
||||
}
|
||||
|
||||
fn send(&mut self, _: &Send, cx: &mut ViewContext<Self>) {
|
||||
fn send(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
||||
if let Some((channel, _)) = self.active_channel.as_ref() {
|
||||
let body = self.input_editor.update(cx, |editor, cx| {
|
||||
let body = editor.text(cx);
|
||||
|
|
|
@ -5,13 +5,17 @@ use gpui::{
|
|||
};
|
||||
use settings::Settings;
|
||||
use text::{Bias, Point};
|
||||
use workspace::Workspace;
|
||||
use workspace::{
|
||||
menu::{Cancel, Confirm},
|
||||
Workspace,
|
||||
};
|
||||
|
||||
actions!(go_to_line, [Toggle, Confirm]);
|
||||
actions!(go_to_line, [Toggle]);
|
||||
|
||||
pub fn init(cx: &mut MutableAppContext) {
|
||||
cx.add_action(GoToLine::toggle);
|
||||
cx.add_action(GoToLine::confirm);
|
||||
cx.add_action(GoToLine::cancel);
|
||||
}
|
||||
|
||||
pub struct GoToLine {
|
||||
|
@ -66,6 +70,10 @@ impl GoToLine {
|
|||
}
|
||||
}
|
||||
|
||||
fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
||||
cx.emit(Event::Dismissed);
|
||||
}
|
||||
|
||||
fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
||||
self.prev_scroll_position.take();
|
||||
self.active_editor.update(cx, |active_editor, cx| {
|
||||
|
|
|
@ -1306,6 +1306,10 @@ impl MutableAppContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn all_action_names<'a>(&'a self) -> impl Iterator<Item = &'static str> + 'a {
|
||||
self.action_deserializers.keys().copied()
|
||||
}
|
||||
|
||||
pub fn available_actions(
|
||||
&self,
|
||||
window_id: usize,
|
||||
|
|
|
@ -102,6 +102,10 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
fn disk_based_diagnostics_progress_token(&self) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn id_for_language(&self, _name: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
|
|
@ -1132,7 +1132,19 @@ impl Project {
|
|||
if file.is_local() {
|
||||
let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
|
||||
let initial_snapshot = buffer.text_snapshot();
|
||||
let language_server = self.language_server_for_buffer(buffer, cx).cloned();
|
||||
|
||||
let mut language_server = None;
|
||||
let mut language_id = None;
|
||||
if let Some(language) = buffer.language() {
|
||||
let worktree_id = file.worktree_id(cx);
|
||||
if let Some(adapter) = language.lsp_adapter() {
|
||||
language_id = adapter.id_for_language(language.name().as_ref());
|
||||
language_server = self
|
||||
.language_servers
|
||||
.get(&(worktree_id, adapter.name()))
|
||||
.cloned();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(local_worktree) = file.worktree.read(cx).as_local() {
|
||||
if let Some(diagnostics) = local_worktree.diagnostics_for_path(file.path()) {
|
||||
|
@ -1147,7 +1159,7 @@ impl Project {
|
|||
lsp::DidOpenTextDocumentParams {
|
||||
text_document: lsp::TextDocumentItem::new(
|
||||
uri,
|
||||
Default::default(),
|
||||
language_id.unwrap_or_default(),
|
||||
0,
|
||||
initial_snapshot.text(),
|
||||
),
|
||||
|
@ -1437,7 +1449,7 @@ impl Project {
|
|||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.language_servers
|
||||
.insert(key.clone(), (adapter, language_server.clone()));
|
||||
.insert(key.clone(), (adapter.clone(), language_server.clone()));
|
||||
this.language_server_statuses.insert(
|
||||
server_id,
|
||||
LanguageServerStatus {
|
||||
|
@ -1494,12 +1506,13 @@ impl Project {
|
|||
.or_insert_with(|| vec![(0, buffer.text_snapshot())]);
|
||||
let (version, initial_snapshot) = versions.last().unwrap();
|
||||
let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
|
||||
let language_id = adapter.id_for_language(language.name().as_ref());
|
||||
language_server
|
||||
.notify::<lsp::notification::DidOpenTextDocument>(
|
||||
lsp::DidOpenTextDocumentParams {
|
||||
text_document: lsp::TextDocumentItem::new(
|
||||
uri,
|
||||
Default::default(),
|
||||
language_id.unwrap_or_default(),
|
||||
*version,
|
||||
initial_snapshot.text(),
|
||||
),
|
||||
|
|
|
@ -17,9 +17,11 @@ use std::{
|
|||
path::PathBuf,
|
||||
};
|
||||
use util::ResultExt as _;
|
||||
use workspace::{Item, ItemNavHistory, Pane, ToolbarItemLocation, ToolbarItemView, Workspace};
|
||||
use workspace::{
|
||||
menu::Confirm, Item, ItemNavHistory, Pane, ToolbarItemLocation, ToolbarItemView, Workspace,
|
||||
};
|
||||
|
||||
actions!(project_search, [Deploy, Search, SearchInNew, ToggleFocus]);
|
||||
actions!(project_search, [Deploy, SearchInNew, ToggleFocus]);
|
||||
|
||||
const MAX_TAB_TITLE_LEN: usize = 24;
|
||||
|
||||
|
@ -530,7 +532,7 @@ impl ProjectSearchBar {
|
|||
}
|
||||
}
|
||||
|
||||
fn search(&mut self, _: &Search, cx: &mut ViewContext<Self>) {
|
||||
fn search(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
|
||||
if let Some(search_view) = self.active_project_search.as_ref() {
|
||||
search_view.update(cx, |search_view, cx| search_view.search(cx));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ gpui = { path = "../gpui" }
|
|||
theme = { path = "../theme" }
|
||||
util = { path = "../util" }
|
||||
anyhow = "1.0.38"
|
||||
json_comments = "0.2"
|
||||
schemars = "0.8"
|
||||
serde = { version = "1", features = ["derive", "rc"] }
|
||||
serde_json = { version = "1.0.64", features = ["preserve_order"] }
|
||||
|
|
|
@ -1,20 +1,45 @@
|
|||
use crate::parse_json_with_comments;
|
||||
use anyhow::{Context, Result};
|
||||
use assets::Assets;
|
||||
use collections::BTreeMap;
|
||||
use gpui::{keymap::Binding, MutableAppContext};
|
||||
use schemars::{
|
||||
gen::{SchemaGenerator, SchemaSettings},
|
||||
schema::{InstanceType, Schema, SchemaObject, SingleOrVec, SubschemaValidation},
|
||||
JsonSchema,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::value::RawValue;
|
||||
use serde_json::{value::RawValue, Value};
|
||||
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
#[serde(transparent)]
|
||||
pub struct KeymapFileContent(Vec<KeymapBlock>);
|
||||
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct KeymapBlock {
|
||||
#[serde(default)]
|
||||
context: Option<String>,
|
||||
bindings: BTreeMap<String, KeymapAction>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[serde(transparent)]
|
||||
pub struct KeymapFile(BTreeMap<String, ActionsByKeystroke>);
|
||||
pub struct KeymapAction(Box<RawValue>);
|
||||
|
||||
type ActionsByKeystroke = BTreeMap<String, Box<RawValue>>;
|
||||
impl JsonSchema for KeymapAction {
|
||||
fn schema_name() -> String {
|
||||
"KeymapAction".into()
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
Schema::Bool(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ActionWithData<'a>(#[serde(borrow)] &'a str, #[serde(borrow)] &'a RawValue);
|
||||
struct ActionWithData(Box<str>, Box<RawValue>);
|
||||
|
||||
impl KeymapFile {
|
||||
impl KeymapFileContent {
|
||||
pub fn load_defaults(cx: &mut MutableAppContext) {
|
||||
for path in ["keymaps/default.json", "keymaps/vim.json"] {
|
||||
Self::load(path, cx).unwrap();
|
||||
|
@ -24,17 +49,16 @@ impl KeymapFile {
|
|||
pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> {
|
||||
let content = Assets::get(asset_path).unwrap().data;
|
||||
let content_str = std::str::from_utf8(content.as_ref()).unwrap();
|
||||
Ok(serde_json::from_str::<Self>(content_str)?.add(cx)?)
|
||||
Ok(parse_json_with_comments::<Self>(content_str)?.add(cx)?)
|
||||
}
|
||||
|
||||
pub fn add(self, cx: &mut MutableAppContext) -> Result<()> {
|
||||
for (context, actions) in self.0 {
|
||||
let context = if context == "*" { None } else { Some(context) };
|
||||
for KeymapBlock { context, bindings } in self.0 {
|
||||
cx.add_bindings(
|
||||
actions
|
||||
bindings
|
||||
.into_iter()
|
||||
.map(|(keystroke, action)| {
|
||||
let action = action.get();
|
||||
let action = action.0.get();
|
||||
|
||||
// This is a workaround for a limitation in serde: serde-rs/json#497
|
||||
// We want to deserialize the action data as a `RawValue` so that we can
|
||||
|
@ -42,7 +66,7 @@ impl KeymapFile {
|
|||
// string. But `RawValue` currently does not work inside of an untagged enum.
|
||||
let action = if action.starts_with('[') {
|
||||
let ActionWithData(name, data) = serde_json::from_str(action)?;
|
||||
cx.deserialize_action(name, Some(data.get()))
|
||||
cx.deserialize_action(&name, Some(data.get()))
|
||||
} else {
|
||||
let name = serde_json::from_str(action)?;
|
||||
cx.deserialize_action(name, None)
|
||||
|
@ -60,3 +84,39 @@ impl KeymapFile {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keymap_file_json_schema(action_names: &[&'static str]) -> serde_json::Value {
|
||||
let mut root_schema = SchemaSettings::draft07()
|
||||
.with(|settings| settings.option_add_null_type = false)
|
||||
.into_generator()
|
||||
.into_root_schema_for::<KeymapFileContent>();
|
||||
|
||||
let action_schema = Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(SubschemaValidation {
|
||||
one_of: Some(vec![
|
||||
Schema::Object(SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
|
||||
enum_values: Some(
|
||||
action_names
|
||||
.into_iter()
|
||||
.map(|name| Value::String(name.to_string()))
|
||||
.collect(),
|
||||
),
|
||||
..Default::default()
|
||||
}),
|
||||
Schema::Object(SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))),
|
||||
..Default::default()
|
||||
}),
|
||||
]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
root_schema
|
||||
.definitions
|
||||
.insert("KeymapAction".to_owned(), action_schema);
|
||||
|
||||
serde_json::to_value(root_schema).unwrap()
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@ use schemars::{
|
|||
},
|
||||
JsonSchema,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde_json::Value;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use theme::{Theme, ThemeRegistry};
|
||||
use util::ResultExt as _;
|
||||
|
||||
pub use keymap_file::KeymapFile;
|
||||
pub use keymap_file::{keymap_file_json_schema, KeymapFileContent};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Settings {
|
||||
|
@ -78,90 +78,6 @@ impl Settings {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn file_json_schema(
|
||||
theme_names: Vec<String>,
|
||||
language_names: Vec<String>,
|
||||
) -> serde_json::Value {
|
||||
let settings = SchemaSettings::draft07().with(|settings| {
|
||||
settings.option_add_null_type = false;
|
||||
});
|
||||
let generator = SchemaGenerator::new(settings);
|
||||
let mut root_schema = generator.into_root_schema_for::<SettingsFileContent>();
|
||||
|
||||
// Construct theme names reference type
|
||||
let theme_names = theme_names
|
||||
.into_iter()
|
||||
.map(|name| Value::String(name))
|
||||
.collect();
|
||||
let theme_names_schema = Schema::Object(SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
|
||||
enum_values: Some(theme_names),
|
||||
..Default::default()
|
||||
});
|
||||
root_schema
|
||||
.definitions
|
||||
.insert("ThemeName".to_owned(), theme_names_schema);
|
||||
|
||||
// Construct language overrides reference type
|
||||
let language_override_schema_reference = Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/LanguageOverride".to_owned()),
|
||||
..Default::default()
|
||||
});
|
||||
let language_overrides_properties = language_names
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
(
|
||||
name,
|
||||
Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(SubschemaValidation {
|
||||
all_of: Some(vec![language_override_schema_reference.clone()]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let language_overrides_schema = Schema::Object(SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))),
|
||||
object: Some(Box::new(ObjectValidation {
|
||||
properties: language_overrides_properties,
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
});
|
||||
root_schema
|
||||
.definitions
|
||||
.insert("LanguageOverrides".to_owned(), language_overrides_schema);
|
||||
|
||||
// Modify theme property to use new theme reference type
|
||||
let settings_file_schema = root_schema.schema.object.as_mut().unwrap();
|
||||
let language_overrides_schema_reference = Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/ThemeName".to_owned()),
|
||||
..Default::default()
|
||||
});
|
||||
settings_file_schema.properties.insert(
|
||||
"theme".to_owned(),
|
||||
Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(SubschemaValidation {
|
||||
all_of: Some(vec![language_overrides_schema_reference]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
|
||||
// Modify language_overrides property to use LanguageOverrides reference
|
||||
settings_file_schema.properties.insert(
|
||||
"language_overrides".to_owned(),
|
||||
Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/LanguageOverrides".to_owned()),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
serde_json::to_value(root_schema).unwrap()
|
||||
}
|
||||
|
||||
pub fn with_overrides(
|
||||
mut self,
|
||||
language_name: impl Into<Arc<str>>,
|
||||
|
@ -249,6 +165,90 @@ impl Settings {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn settings_file_json_schema(
|
||||
theme_names: Vec<String>,
|
||||
language_names: Vec<String>,
|
||||
) -> serde_json::Value {
|
||||
let settings = SchemaSettings::draft07().with(|settings| {
|
||||
settings.option_add_null_type = false;
|
||||
});
|
||||
let generator = SchemaGenerator::new(settings);
|
||||
let mut root_schema = generator.into_root_schema_for::<SettingsFileContent>();
|
||||
|
||||
// Construct theme names reference type
|
||||
let theme_names = theme_names
|
||||
.into_iter()
|
||||
.map(|name| Value::String(name))
|
||||
.collect();
|
||||
let theme_names_schema = Schema::Object(SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
|
||||
enum_values: Some(theme_names),
|
||||
..Default::default()
|
||||
});
|
||||
root_schema
|
||||
.definitions
|
||||
.insert("ThemeName".to_owned(), theme_names_schema);
|
||||
|
||||
// Construct language overrides reference type
|
||||
let language_override_schema_reference = Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/LanguageOverride".to_owned()),
|
||||
..Default::default()
|
||||
});
|
||||
let language_overrides_properties = language_names
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
(
|
||||
name,
|
||||
Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(SubschemaValidation {
|
||||
all_of: Some(vec![language_override_schema_reference.clone()]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let language_overrides_schema = Schema::Object(SchemaObject {
|
||||
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))),
|
||||
object: Some(Box::new(ObjectValidation {
|
||||
properties: language_overrides_properties,
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
});
|
||||
root_schema
|
||||
.definitions
|
||||
.insert("LanguageOverrides".to_owned(), language_overrides_schema);
|
||||
|
||||
// Modify theme property to use new theme reference type
|
||||
let settings_file_schema = root_schema.schema.object.as_mut().unwrap();
|
||||
let language_overrides_schema_reference = Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/ThemeName".to_owned()),
|
||||
..Default::default()
|
||||
});
|
||||
settings_file_schema.properties.insert(
|
||||
"theme".to_owned(),
|
||||
Schema::Object(SchemaObject {
|
||||
subschemas: Some(Box::new(SubschemaValidation {
|
||||
all_of: Some(vec![language_overrides_schema_reference]),
|
||||
..Default::default()
|
||||
})),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
|
||||
// Modify language_overrides property to use LanguageOverrides reference
|
||||
settings_file_schema.properties.insert(
|
||||
"language_overrides".to_owned(),
|
||||
Schema::Object(SchemaObject {
|
||||
reference: Some("#/definitions/LanguageOverrides".to_owned()),
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
serde_json::to_value(root_schema).unwrap()
|
||||
}
|
||||
|
||||
fn merge<T: Copy>(target: &mut T, value: Option<T>) {
|
||||
if let Some(value) = value {
|
||||
*target = value;
|
||||
|
@ -260,3 +260,9 @@ fn merge_option<T: Copy>(target: &mut Option<T>, value: Option<T>) {
|
|||
*target = value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_json_with_comments<T: DeserializeOwned>(content: &str) -> Result<T> {
|
||||
Ok(serde_json::from_reader(
|
||||
json_comments::CommentSettings::c_style().strip_comments(content.as_bytes()),
|
||||
)?)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ impl<'a> VimTestContext<'a> {
|
|||
editor::init(cx);
|
||||
crate::init(cx);
|
||||
|
||||
settings::KeymapFile::load("keymaps/vim.json", cx).unwrap();
|
||||
settings::KeymapFileContent::load("keymaps/vim.json", cx).unwrap();
|
||||
});
|
||||
|
||||
let params = cx.update(WorkspaceParams::test);
|
||||
|
|
|
@ -86,7 +86,7 @@ tiny_http = "0.8"
|
|||
toml = "0.5"
|
||||
tree-sitter = "0.20.4"
|
||||
tree-sitter-c = "0.20.1"
|
||||
tree-sitter-json = "0.19.0"
|
||||
tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8" }
|
||||
tree-sitter-rust = "0.20.1"
|
||||
tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" }
|
||||
tree-sitter-typescript = "0.20.1"
|
||||
|
|
|
@ -127,4 +127,12 @@ impl LspAdapter for JsonLspAdapter {
|
|||
"provideFormatter": true
|
||||
}))
|
||||
}
|
||||
|
||||
fn id_for_language(&self, name: &str) -> Option<String> {
|
||||
if name == "JSON" {
|
||||
Some("jsonc".into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
name = "JSON"
|
||||
path_suffixes = ["json"]
|
||||
line_comment = "// "
|
||||
autoclose_before = ",]}"
|
||||
brackets = [
|
||||
{ start = "{", end = "}", close = true, newline = true },
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
(comment) @comment
|
||||
|
||||
(string) @string
|
||||
|
||||
(pair
|
||||
|
|
|
@ -17,7 +17,7 @@ use gpui::{App, AssetSource, AsyncAppContext, Task};
|
|||
use log::LevelFilter;
|
||||
use parking_lot::Mutex;
|
||||
use project::Fs;
|
||||
use settings::{self, KeymapFile, Settings, SettingsFileContent};
|
||||
use settings::{self, KeymapFileContent, Settings, SettingsFileContent};
|
||||
use smol::process::Command;
|
||||
use std::{env, fs, path::PathBuf, sync::Arc, thread, time::Duration};
|
||||
use theme::{ThemeRegistry, DEFAULT_THEME_NAME};
|
||||
|
@ -309,7 +309,7 @@ fn load_config_files(
|
|||
fs: Arc<dyn Fs>,
|
||||
) -> oneshot::Receiver<(
|
||||
WatchedJsonFile<SettingsFileContent>,
|
||||
WatchedJsonFile<KeymapFile>,
|
||||
WatchedJsonFile<KeymapFileContent>,
|
||||
)> {
|
||||
let executor = app.background();
|
||||
let (tx, rx) = oneshot::channel();
|
||||
|
|
|
@ -4,7 +4,7 @@ use postage::sink::Sink as _;
|
|||
use postage::{prelude::Stream, watch};
|
||||
use project::Fs;
|
||||
use serde::Deserialize;
|
||||
use settings::{KeymapFile, Settings, SettingsFileContent};
|
||||
use settings::{parse_json_with_comments, KeymapFileContent, Settings, SettingsFileContent};
|
||||
use std::{path::Path, sync::Arc, time::Duration};
|
||||
use theme::ThemeRegistry;
|
||||
use util::ResultExt;
|
||||
|
@ -44,7 +44,7 @@ where
|
|||
fs.load(&path)
|
||||
.await
|
||||
.log_err()
|
||||
.and_then(|data| serde_json::from_str(&data).log_err())
|
||||
.and_then(|data| parse_json_with_comments(&data).log_err())
|
||||
} else {
|
||||
Some(T::default())
|
||||
}
|
||||
|
@ -76,11 +76,14 @@ pub fn settings_from_files(
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn watch_keymap_file(mut file: WatchedJsonFile<KeymapFile>, mut cx: AsyncAppContext) {
|
||||
pub async fn watch_keymap_file(
|
||||
mut file: WatchedJsonFile<KeymapFileContent>,
|
||||
mut cx: AsyncAppContext,
|
||||
) {
|
||||
while let Some(content) = file.0.recv().await {
|
||||
cx.update(|cx| {
|
||||
cx.clear_bindings();
|
||||
settings::KeymapFile::load_defaults(cx);
|
||||
settings::KeymapFileContent::load_defaults(cx);
|
||||
content.add(cx).log_err();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ pub use project::{self, fs};
|
|||
use project_panel::ProjectPanel;
|
||||
use search::{BufferSearchBar, ProjectSearchBar};
|
||||
use serde_json::to_string_pretty;
|
||||
use settings::Settings;
|
||||
use settings::{keymap_file_json_schema, settings_file_json_schema, Settings};
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
|
@ -41,6 +41,7 @@ actions!(
|
|||
Quit,
|
||||
DebugElements,
|
||||
OpenSettings,
|
||||
OpenKeymap,
|
||||
IncreaseBufferFontSize,
|
||||
DecreaseBufferFontSize,
|
||||
InstallCommandLineInterface,
|
||||
|
@ -78,39 +79,13 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
|||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
|
||||
let app_state = app_state.clone();
|
||||
cx.spawn(move |workspace, mut cx| async move {
|
||||
let fs = &app_state.fs;
|
||||
if !fs.is_file(&SETTINGS_PATH).await {
|
||||
fs.create_dir(&ROOT_PATH).await?;
|
||||
fs.create_file(&SETTINGS_PATH, Default::default()).await?;
|
||||
}
|
||||
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
if workspace.project().read(cx).is_local() {
|
||||
workspace.open_paths(&[SETTINGS_PATH.clone()], cx)
|
||||
} else {
|
||||
let (_, workspace) =
|
||||
cx.add_window((app_state.build_window_options)(), |cx| {
|
||||
let project = Project::local(
|
||||
app_state.client.clone(),
|
||||
app_state.user_store.clone(),
|
||||
app_state.languages.clone(),
|
||||
app_state.fs.clone(),
|
||||
cx,
|
||||
);
|
||||
(app_state.build_workspace)(project, &app_state, cx)
|
||||
});
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.open_paths(&[SETTINGS_PATH.clone()], cx)
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
Ok::<_, anyhow::Error>(())
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
open_config_file(&SETTINGS_PATH, app_state.clone(), cx);
|
||||
}
|
||||
});
|
||||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
|
||||
open_config_file(&KEYMAP_PATH, app_state.clone(), cx);
|
||||
}
|
||||
});
|
||||
cx.add_action(
|
||||
|
@ -137,8 +112,7 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut gpui::MutableAppContext) {
|
|||
);
|
||||
|
||||
workspace::lsp_status::init(cx);
|
||||
|
||||
settings::KeymapFile::load_defaults(cx);
|
||||
settings::KeymapFileContent::load_defaults(cx);
|
||||
}
|
||||
|
||||
pub fn build_workspace(
|
||||
|
@ -179,13 +153,18 @@ pub fn build_workspace(
|
|||
let theme_names = app_state.themes.list().collect();
|
||||
let language_names = app_state.languages.language_names();
|
||||
|
||||
project.update(cx, |project, _| {
|
||||
project.update(cx, |project, cx| {
|
||||
let action_names = cx.all_action_names().collect::<Vec<_>>();
|
||||
project.set_language_server_settings(serde_json::json!({
|
||||
"json": {
|
||||
"schemas": [
|
||||
{
|
||||
"fileMatch": "**/.zed/settings.json",
|
||||
"schema": Settings::file_json_schema(theme_names, language_names),
|
||||
"fileMatch": [".zed/settings.json"],
|
||||
"schema": settings_file_json_schema(theme_names, language_names),
|
||||
},
|
||||
{
|
||||
"fileMatch": [".zed/keymap.json"],
|
||||
"schema": keymap_file_json_schema(&action_names),
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -289,6 +268,44 @@ async fn install_cli(cx: &AsyncAppContext) -> Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
fn open_config_file(
|
||||
path: &'static Path,
|
||||
app_state: Arc<AppState>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) {
|
||||
cx.spawn(|workspace, mut cx| async move {
|
||||
let fs = &app_state.fs;
|
||||
if !fs.is_file(path).await {
|
||||
fs.create_dir(&ROOT_PATH).await?;
|
||||
fs.create_file(path, Default::default()).await?;
|
||||
}
|
||||
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
if workspace.project().read(cx).is_local() {
|
||||
workspace.open_paths(&[path.to_path_buf()], cx)
|
||||
} else {
|
||||
let (_, workspace) = cx.add_window((app_state.build_window_options)(), |cx| {
|
||||
let project = Project::local(
|
||||
app_state.client.clone(),
|
||||
app_state.user_store.clone(),
|
||||
app_state.languages.clone(),
|
||||
app_state.fs.clone(),
|
||||
cx,
|
||||
);
|
||||
(app_state.build_workspace)(project, &app_state, cx)
|
||||
});
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.open_paths(&[path.to_path_buf()], cx)
|
||||
})
|
||||
}
|
||||
})
|
||||
.await;
|
||||
Ok::<_, anyhow::Error>(())
|
||||
})
|
||||
.detach_and_log_err(cx)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
Loading…
Reference in a new issue