@@ -6,6 +6,7 @@ use std::sync::OnceLock;
use std::time::Duration;
use std::{ops::Range, sync::Arc};
+use anyhow::Context as _;
use client::{ExtensionMetadata, ExtensionProvides};
use collections::{BTreeMap, BTreeSet};
use editor::{Editor, EditorElement, EditorStyle};
@@ -80,16 +81,24 @@ pub fn init(cx: &mut App) {
.find_map(|item| item.downcast::<ExtensionsPage>());
if let Some(existing) = existing {
- if provides_filter.is_some() {
- existing.update(cx, |extensions_page, cx| {
+ existing.update(cx, |extensions_page, cx| {
+ if provides_filter.is_some() {
extensions_page.change_provides_filter(provides_filter, cx);
- });
- }
+ }
+ if let Some(id) = action.id.as_ref() {
+ extensions_page.focus_extension(id, window, cx);
+ }
+ });
workspace.activate_item(&existing, true, true, window, cx);
} else {
- let extensions_page =
- ExtensionsPage::new(workspace, provides_filter, window, cx);
+ let extensions_page = ExtensionsPage::new(
+ workspace,
+ provides_filter,
+ action.id.as_deref(),
+ window,
+ cx,
+ );
workspace.add_item_to_active_pane(
Box::new(extensions_page),
None,
@@ -287,6 +296,7 @@ impl ExtensionsPage {
pub fn new(
workspace: &Workspace,
provides_filter: Option<ExtensionProvides>,
+ focus_extension_id: Option<&str>,
window: &mut Window,
cx: &mut Context<Workspace>,
) -> Entity<Self> {
@@ -317,6 +327,9 @@ impl ExtensionsPage {
let query_editor = cx.new(|cx| {
let mut input = Editor::single_line(window, cx);
input.set_placeholder_text("Search extensions...", cx);
+ if let Some(id) = focus_extension_id {
+ input.set_text(format!("id:{id}"), window, cx);
+ }
input
});
cx.subscribe(&query_editor, Self::on_query_change).detach();
@@ -340,7 +353,7 @@ impl ExtensionsPage {
scrollbar_state: ScrollbarState::new(scroll_handle),
};
this.fetch_extensions(
- None,
+ this.search_query(cx),
Some(BTreeSet::from_iter(this.provides_filter)),
None,
cx,
@@ -464,9 +477,23 @@ impl ExtensionsPage {
.cloned()
.collect::<Vec<_>>();
- let remote_extensions = extension_store.update(cx, |store, cx| {
- store.fetch_extensions(search.as_deref(), provides_filter.as_ref(), cx)
- });
+ let remote_extensions =
+ if let Some(id) = search.as_ref().and_then(|s| s.strip_prefix("id:")) {
+ let versions =
+ extension_store.update(cx, |store, cx| store.fetch_extension_versions(id, cx));
+ cx.foreground_executor().spawn(async move {
+ let versions = versions.await?;
+ let latest = versions
+ .into_iter()
+ .max_by_key(|v| v.published_at)
+ .context("no extension found")?;
+ Ok(vec![latest])
+ })
+ } else {
+ extension_store.update(cx, |store, cx| {
+ store.fetch_extensions(search.as_deref(), provides_filter.as_ref(), cx)
+ })
+ };
cx.spawn(async move |this, cx| {
let dev_extensions = if let Some(search) = search {
@@ -1165,6 +1192,13 @@ impl ExtensionsPage {
self.refresh_feature_upsells(cx);
}
+ pub fn focus_extension(&mut self, id: &str, window: &mut Window, cx: &mut Context<Self>) {
+ self.query_editor.update(cx, |editor, cx| {
+ editor.set_text(format!("id:{id}"), window, cx)
+ });
+ self.refresh_search(cx);
+ }
+
pub fn change_provides_filter(
&mut self,
provides_filter: Option<ExtensionProvides>,
@@ -746,6 +746,23 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
return;
}
+ if let Some(extension) = request.extension_id {
+ cx.spawn(async move |cx| {
+ let workspace = workspace::get_any_active_workspace(app_state, cx.clone()).await?;
+ workspace.update(cx, |_, window, cx| {
+ window.dispatch_action(
+ Box::new(zed_actions::Extensions {
+ category_filter: None,
+ id: Some(extension),
+ }),
+ cx,
+ );
+ })
+ })
+ .detach_and_log_err(cx);
+ return;
+ }
+
if let Some(connection_options) = request.ssh_connection {
cx.spawn(async move |mut cx| {
let paths: Vec<PathBuf> = request.open_paths.into_iter().map(PathBuf::from).collect();
@@ -37,6 +37,7 @@ pub struct OpenRequest {
pub join_channel: Option<u64>,
pub ssh_connection: Option<SshConnectionOptions>,
pub dock_menu_action: Option<usize>,
+ pub extension_id: Option<String>,
}
impl OpenRequest {
@@ -54,6 +55,8 @@ impl OpenRequest {
} else if let Some(file) = url.strip_prefix("zed://ssh") {
let ssh_url = "ssh:/".to_string() + file;
this.parse_ssh_file_path(&ssh_url, cx)?
+ } else if let Some(file) = url.strip_prefix("zed://extension/") {
+ this.extension_id = Some(file.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) {