mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
zed: Improve zed:// URL handling (#57047)
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Has been skipped
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / miri_scheduler (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Has been skipped
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / miri_scheduler (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
Release Notes: - Improved `zed://` and `zed://agent` URL handling
This commit is contained in:
parent
988f083fc5
commit
d3d5fb0d15
3 changed files with 109 additions and 7 deletions
|
|
@ -670,7 +670,11 @@ fn prompt_and_open_paths(
|
|||
create_new_window: bool,
|
||||
cx: &mut App,
|
||||
) {
|
||||
if let Some(workspace_window) = local_workspace_windows(cx).into_iter().next() {
|
||||
if let Some(workspace_window) =
|
||||
workspace_windows_for_location(&SerializedWorkspaceLocation::Local, cx)
|
||||
.into_iter()
|
||||
.next()
|
||||
{
|
||||
workspace_window
|
||||
.update(cx, |multi_workspace, window, cx| {
|
||||
let workspace = multi_workspace.workspace().clone();
|
||||
|
|
@ -9471,7 +9475,7 @@ pub async fn get_any_active_multi_workspace(
|
|||
activate_any_workspace_window(&mut cx).context("could not open zed")
|
||||
}
|
||||
|
||||
fn activate_any_workspace_window(cx: &mut AsyncApp) -> Option<WindowHandle<MultiWorkspace>> {
|
||||
pub fn activate_any_workspace_window(cx: &mut AsyncApp) -> Option<WindowHandle<MultiWorkspace>> {
|
||||
cx.update(|cx| {
|
||||
if let Some(workspace_window) = cx
|
||||
.active_window()
|
||||
|
|
@ -9492,10 +9496,6 @@ fn activate_any_workspace_window(cx: &mut AsyncApp) -> Option<WindowHandle<Multi
|
|||
})
|
||||
}
|
||||
|
||||
pub fn local_workspace_windows(cx: &App) -> Vec<WindowHandle<MultiWorkspace>> {
|
||||
workspace_windows_for_location(&SerializedWorkspaceLocation::Local, cx)
|
||||
}
|
||||
|
||||
pub fn workspace_windows_for_location(
|
||||
serialized_location: &SerializedWorkspaceLocation,
|
||||
cx: &App,
|
||||
|
|
|
|||
|
|
@ -925,6 +925,14 @@ fn main() {
|
|||
.ok()
|
||||
.and_then(|request| OpenRequest::parse(request, cx).log_err())
|
||||
{
|
||||
Some(request) if request.is_focus_app_only() => cx.spawn({
|
||||
let app_state = app_state.clone();
|
||||
async move |cx| {
|
||||
if let Err(e) = restore_or_create_workspace(app_state, cx).await {
|
||||
fail_to_open_window_async(e, cx)
|
||||
}
|
||||
}
|
||||
}),
|
||||
Some(request) => {
|
||||
handle_open_request(request, app_state.clone(), cx);
|
||||
Task::ready(())
|
||||
|
|
@ -978,6 +986,15 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
|
|||
cx.spawn(async move |cx| handle_cli_connection(connection, app_state, cx).await)
|
||||
.detach();
|
||||
}
|
||||
OpenRequestKind::FocusApp => {
|
||||
cx.spawn(async move |cx| {
|
||||
if workspace::activate_any_workspace_window(cx).is_some() {
|
||||
return anyhow::Ok(());
|
||||
}
|
||||
restore_or_create_workspace(app_state, cx).await
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
OpenRequestKind::Extension { extension_id } => {
|
||||
cx.spawn(async move |cx| {
|
||||
let workspace =
|
||||
|
|
@ -1001,6 +1018,15 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
|
|||
let multi_workspace =
|
||||
workspace::get_any_active_multi_workspace(app_state, cx.clone()).await?;
|
||||
|
||||
let panels_task = multi_workspace.update(cx, |multi_workspace, _, cx| {
|
||||
multi_workspace
|
||||
.workspace()
|
||||
.update(cx, |workspace, _| workspace.take_panels_task())
|
||||
})?;
|
||||
if let Some(task) = panels_task {
|
||||
task.await.log_err();
|
||||
}
|
||||
|
||||
multi_workspace.update(cx, |multi_workspace, window, cx| {
|
||||
multi_workspace.workspace().update(cx, |workspace, cx| {
|
||||
if let Some(panel) = workspace.focus_panel::<AgentPanel>(window, cx) {
|
||||
|
|
@ -1011,6 +1037,11 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
|
|||
cx,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
log::warn!(
|
||||
"zed://agent received but the AgentPanel is not registered \
|
||||
(is `disable_ai` enabled?)"
|
||||
);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ pub enum OpenRequestKind {
|
|||
Box<dyn CliResponseSink>,
|
||||
),
|
||||
),
|
||||
FocusApp,
|
||||
Extension {
|
||||
extension_id: String,
|
||||
},
|
||||
|
|
@ -82,6 +83,7 @@ impl std::fmt::Debug for OpenRequestKind {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::CliConnection(_) => write!(f, "CliConnection(..)"),
|
||||
Self::FocusApp => write!(f, "FocusApp"),
|
||||
Self::Extension { extension_id } => f
|
||||
.debug_struct("Extension")
|
||||
.field("extension_id", extension_id)
|
||||
|
|
@ -118,6 +120,15 @@ impl std::fmt::Debug for OpenRequestKind {
|
|||
}
|
||||
|
||||
impl OpenRequest {
|
||||
pub fn is_focus_app_only(&self) -> bool {
|
||||
matches!(self.kind, Some(OpenRequestKind::FocusApp))
|
||||
&& self.open_paths.is_empty()
|
||||
&& self.diff_paths.is_empty()
|
||||
&& self.remote_connection.is_none()
|
||||
&& self.join_channel.is_none()
|
||||
&& self.open_channel_notes.is_empty()
|
||||
}
|
||||
|
||||
pub fn parse(request: RawOpenRequest, cx: &App) -> Result<Self> {
|
||||
let mut this = Self::default();
|
||||
|
||||
|
|
@ -167,6 +178,8 @@ impl OpenRequest {
|
|||
}
|
||||
} else if let Some(agent_path) = url.strip_prefix("zed://agent") {
|
||||
this.parse_agent_url(agent_path)
|
||||
} else if url == "zed://" || url == "zed://open" || url == "zed://open/" {
|
||||
this.kind = Some(OpenRequestKind::FocusApp);
|
||||
} else if let Some(schema_path) = url.strip_prefix("zed://schemas/") {
|
||||
this.kind = Some(OpenRequestKind::BuiltinJsonSchema {
|
||||
schema_path: schema_path.to_string(),
|
||||
|
|
@ -210,7 +223,8 @@ impl OpenRequest {
|
|||
}
|
||||
|
||||
fn parse_agent_url(&mut self, agent_path: &str) {
|
||||
// Format: "" or "?prompt=<text>"
|
||||
// Format: "" or "?prompt=<text>".
|
||||
let agent_path = agent_path.strip_prefix('/').unwrap_or(agent_path);
|
||||
let external_source_prompt = agent_path.strip_prefix('?').and_then(|query| {
|
||||
url::form_urlencoded::parse(query.as_bytes())
|
||||
.find_map(|(key, value)| (key == "prompt").then_some(value))
|
||||
|
|
@ -1230,6 +1244,63 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_parse_agent_url_with_trailing_slash(cx: &mut TestAppContext) {
|
||||
let _app_state = init_test(cx);
|
||||
|
||||
let request = cx.update(|cx| {
|
||||
OpenRequest::parse(
|
||||
RawOpenRequest {
|
||||
urls: vec!["zed://agent/?prompt=hello".into()],
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
match request.kind {
|
||||
Some(OpenRequestKind::AgentPanel {
|
||||
external_source_prompt,
|
||||
}) => {
|
||||
assert_eq!(
|
||||
external_source_prompt
|
||||
.as_ref()
|
||||
.map(ExternalSourcePrompt::as_str),
|
||||
Some("hello")
|
||||
);
|
||||
}
|
||||
_ => panic!("Expected AgentPanel kind"),
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_parse_focus_app_url(cx: &mut TestAppContext) {
|
||||
let _app_state = init_test(cx);
|
||||
|
||||
for url in ["zed://", "zed://open", "zed://open/"] {
|
||||
let request = cx.update(|cx| {
|
||||
OpenRequest::parse(
|
||||
RawOpenRequest {
|
||||
urls: vec![url.into()],
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
assert!(
|
||||
matches!(request.kind, Some(OpenRequestKind::FocusApp)),
|
||||
"expected FocusApp for {url}, got {:?}",
|
||||
request.kind
|
||||
);
|
||||
assert!(
|
||||
request.is_focus_app_only(),
|
||||
"expected is_focus_app_only for {url}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_parse_agent_url_with_empty_prompt(cx: &mut TestAppContext) {
|
||||
let _app_state = init_test(cx);
|
||||
|
|
|
|||
Loading…
Reference in a new issue