JSON Schema URIs (#38916)

Closes #ISSUE

Improves the efficiency of our interactions with the Zed language
server. Previously, on startup and after every workspace configuration
changed notification, we would send >1MB of JSON Schemas to the JSON
LSP. The only reason this had to happen was due to the case where an
extension was installed that would result in a change to the JSON schema
for settings (i.e. added language, theme, etc).

This PR changes the behavior to use the URI LSP extensions of
`vscode-json-language-server` in order to send the server URI's that it
can then use to fetch the schemas as needed (i.e. the settings schema is
only generated and sent when `settings.json` is opened. This brings the
JSON we send to on startup and after every workspace configuration
changed notification down to a couple of KB.

Additionally, using another LSP extension request we can notify the
server when a schema has changed using the URI as a key, so we no longer
have to send a workspace configuration changed notification, and the
schema contents will only be re-requested and regenerated if the schema
is in use.

Release Notes:

- Improved the efficiency of communication with the builtin JSON LSP.
JSON Schemas are no longer sent to the JSON language server in their
full form. If you wish to view a builtin JSON schema in the language
server info tab of the language server logs (`dev: open language server
logs`), you must now use the `editor: open url` action with your cursor
over the URL that is sent to the server.
- Made it so that Zed urls (`zed://...`) are resolved locally when
opened within the editor instead of being resolved through the OS. Users
who could not previously open `zed://*` URLs in the editor can now do so
by pasting the link into a buffer and using the `editor: open url`
action (please open an issue if this is the case for you!).

---------

Co-authored-by: Michael <michael@zed.dev>
This commit is contained in:
Ben Kunkle
2025-09-26 11:41:26 -04:00
committed by GitHub
co-authored by Michael
parent 30b49cfbf5
commit 4aac5642c1
28 changed files with 743 additions and 489 deletions
+54
View File
@@ -619,6 +619,7 @@ pub fn main() {
extensions_ui::init(cx);
zeta::init(cx);
inspector_ui::init(app_state.clone(), cx);
json_schema_store::init(cx);
cx.observe_global::<SettingsStore>({
let fs = fs.clone();
@@ -779,6 +780,59 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
OpenRequestKind::DockMenuAction { index } => {
cx.perform_dock_menu_action(index);
}
OpenRequestKind::BuiltinJsonSchema { schema_path } => {
workspace::with_active_or_new_workspace(cx, |_workspace, window, cx| {
cx.spawn_in(window, async move |workspace, cx| {
let res = async move {
let json = app_state.languages.language_for_name("JSONC").await.ok();
let json_schema_content =
json_schema_store::resolve_schema_request_inner(
&app_state.languages,
&schema_path,
cx,
)?;
let json_schema_content =
serde_json::to_string_pretty(&json_schema_content)
.context("Failed to serialize JSON Schema as JSON")?;
let buffer_task = workspace.update(cx, |workspace, cx| {
workspace
.project()
.update(cx, |project, cx| project.create_buffer(false, cx))
})?;
let buffer = buffer_task.await?;
workspace.update_in(cx, |workspace, window, cx| {
buffer.update(cx, |buffer, cx| {
buffer.set_language(json, cx);
buffer.edit([(0..0, json_schema_content)], None, cx);
buffer.edit(
[(0..0, format!("// {} JSON Schema\n", schema_path))],
None,
cx,
);
});
workspace.add_item_to_active_pane(
Box::new(cx.new(|cx| {
let mut editor =
editor::Editor::for_buffer(buffer, None, window, cx);
editor.set_read_only(true);
editor
})),
None,
true,
window,
cx,
);
})
}
.await;
res.context("Failed to open builtin JSON Schema").log_err();
})
.detach();
});
}
}
return;
+5
View File
@@ -46,6 +46,7 @@ pub enum OpenRequestKind {
Extension { extension_id: String },
AgentPanel,
DockMenuAction { index: usize },
BuiltinJsonSchema { schema_path: String },
}
impl OpenRequest {
@@ -88,6 +89,10 @@ impl OpenRequest {
});
} else if url == "zed://agent" {
this.kind = Some(OpenRequestKind::AgentPanel);
} else if let Some(schema_path) = url.strip_prefix("zed://schemas/") {
this.kind = Some(OpenRequestKind::BuiltinJsonSchema {
schema_path: schema_path.to_string(),
});
} else if url.starts_with("ssh://") {
this.parse_ssh_file_path(&url, cx)?
} else if let Some(request_path) = parse_zed_link(&url, cx) {