Detailed changes
@@ -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::*;