From f6974294563253f27cf83508eed3e2227c3eb839 Mon Sep 17 00:00:00 2001 From: Cole Miller Date: Fri, 1 Aug 2025 18:09:20 -0400 Subject: [PATCH] wip --- Cargo.lock | 15 +++ Cargo.toml | 2 + crates/lsp/src/lsp.rs | 6 ++ crates/python_ui/Cargo.toml | 31 ++++++ crates/python_ui/LICENSE-GPL | 1 + crates/python_ui/src/python_ui.rs | 150 ++++++++++++++++++++++++++++++ crates/zed/Cargo.toml | 1 + crates/zed/src/zed.rs | 3 + 8 files changed, 209 insertions(+) create mode 100644 crates/python_ui/Cargo.toml create mode 120000 crates/python_ui/LICENSE-GPL create mode 100644 crates/python_ui/src/python_ui.rs diff --git a/Cargo.lock b/Cargo.lock index 69876ef92d..1b16956cd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12806,6 +12806,20 @@ dependencies = [ "wasmtime-math", ] +[[package]] +name = "python_ui" +version = "0.1.0" +dependencies = [ + "anyhow", + "db", + "editor", + "gpui", + "project", + "ui", + "util", + "workspace", +] + [[package]] name = "qoi" version = "0.4.1" @@ -20306,6 +20320,7 @@ dependencies = [ "project_symbols", "prompt_store", "proto", + "python_ui", "recent_projects", "release_channel", "remote", diff --git a/Cargo.toml b/Cargo.toml index cf1ee5956f..6721fcf097 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,6 +124,7 @@ members = [ "crates/project_symbols", "crates/prompt_store", "crates/proto", + "crates/python_ui", "crates/recent_projects", "crates/refineable", "crates/refineable/derive_refineable", @@ -347,6 +348,7 @@ project_panel = { path = "crates/project_panel" } project_symbols = { path = "crates/project_symbols" } prompt_store = { path = "crates/prompt_store" } proto = { path = "crates/proto" } +python_ui = { path = "crates/python_ui" } recent_projects = { path = "crates/recent_projects" } refineable = { path = "crates/refineable" } release_channel = { path = "crates/release_channel" } diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index b9701a83d2..7ca6bb29bc 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -166,6 +166,12 @@ impl<'a> From<&'a str> for LanguageServerName { } } +impl PartialEq for LanguageServerName { + fn eq(&self, other: &str) -> bool { + self.0 == other + } +} + /// Handle to a language server RPC activity subscription. pub enum Subscription { Notification { diff --git a/crates/python_ui/Cargo.toml b/crates/python_ui/Cargo.toml new file mode 100644 index 0000000000..ca0528dca6 --- /dev/null +++ b/crates/python_ui/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "python_ui" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "GPL-3.0-or-later" + +[lints] +workspace = true + +[lib] +path = "src/python_ui.rs" + +[features] +default = [] + +[dependencies] +anyhow.workspace = true +db.workspace = true +editor.workspace = true +gpui.workspace = true +project.workspace = true +ui.workspace = true +util.workspace = true +workspace.workspace = true + +# Uncomment other workspace dependencies as needed +# assistant.workspace = true +# client.workspace = true +# project.workspace = true +# settings.workspace = true diff --git a/crates/python_ui/LICENSE-GPL b/crates/python_ui/LICENSE-GPL new file mode 120000 index 0000000000..89e542f750 --- /dev/null +++ b/crates/python_ui/LICENSE-GPL @@ -0,0 +1 @@ +../../LICENSE-GPL \ No newline at end of file diff --git a/crates/python_ui/src/python_ui.rs b/crates/python_ui/src/python_ui.rs new file mode 100644 index 0000000000..7ada5b8293 --- /dev/null +++ b/crates/python_ui/src/python_ui.rs @@ -0,0 +1,150 @@ +use db::kvp::Dismissable; +use editor::Editor; +use gpui::{App, AppContext as _, Context, EventEmitter, Subscription}; +use ui::{ + Banner, Button, Clickable, FluentBuilder as _, IconButton, IconName, InteractiveElement as _, + IntoElement, ParentElement as _, Render, Window, div, h_flex, +}; +use workspace::{ + ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, + notifications::{NotificationId, simple_message_notification::MessageNotification}, +}; + +impl Dismissable for BasedPyrightNote { + const KEY: &str = "basedpyright-note"; +} + +// pub fn init(cx: &mut App) { +// cx.observe_new(move |workspace: &mut Workspace, window, cx| { +// let Some(window) = window else { +// return; +// }; + +// cx.subscribe_in(workspace.project(), window, |_, _, event, window, cx| { +// if let project::Event::LanguageServerAdded(_, name, _) = event +// && name == "basedpyright" +// { +// if BasedPyrightNote::dismissed() { +// return; +// } + +// cx.on_next_frame(window, move |workspace, _, cx| { +// workspace.show_notification( +// NotificationId::unique::(), +// cx, +// |cx| { +// cx.new(move |cx| { +// MessageNotification::new( +// "basedpyright is now the default language server for Python", +// cx, +// ) +// .more_info_message("Learn More") +// .more_info_url("https://zed.dev/FIXME") +// // .primary_message("Yes, install extension") +// // .primary_icon(IconName::Check) +// // .primary_icon_color(Color::Success) +// // .primary_on_click({ +// // let extension_id = extension_id.clone(); +// // move |_window, cx| { +// // let extension_id = extension_id.clone(); +// // let extension_store = ExtensionStore::global(cx); +// // extension_store.update(cx, move |store, cx| { +// // store.install_latest_extension(extension_id, cx); +// // }); +// // } +// // }) +// // .secondary_message("No, don't install it") +// // .secondary_icon(IconName::Close) +// // .secondary_icon_color(Color::Error) +// // .secondary_on_click(move |_window, cx| { +// // let key = language_extension_key(&extension_id); +// // db::write_and_log(cx, move || { +// // KEY_VALUE_STORE.write_kvp(key, "dismissed".to_string()) +// // }); +// // }) +// }) +// }, +// ); +// }) +// } +// }) +// .detach(); +// }) +// .detach(); +// } + +pub struct BasedPyrightBanner { + dismissed: bool, + have_basedpyright: bool, + _subscriptions: [Subscription; 1], +} + +impl BasedPyrightBanner { + pub fn new(workspace: &Workspace, cx: &mut Context) -> Self { + let subscription = cx.subscribe(workspace.project(), |this, _, event, cx| { + if let project::Event::LanguageServerAdded(_, name, _) = event + && name == "basedpyright" + { + this.have_basedpyright = true; + } + }); + Self { + dismissed: false, + have_basedpyright: false, + _subscriptions: [subscription], + } + } +} + +impl EventEmitter for BasedPyrightBanner {} + +impl Render for BasedPyrightBanner { + fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { + div() + .id("basedpyright-banner") + .when(!self.dismissed && self.have_basedpyright, |el| { + el.child( + Banner::new() + .severity(ui::Severity::Info) + .child( + h_flex() + .child("Basedpyright is now the default language server for Python") + .child( + Button::new("learn-more", "Learn More") + .icon(IconName::ArrowUpRight), + ), + ) + .action_slot(IconButton::new("dismiss", IconName::Close).on_click( + cx.listener(|this, _, _, cx| { + this.dismissed = true; + cx.notify(); + }), + )) + .into_any_element(), + ) + }) + } +} + +impl ToolbarItemView for BasedPyrightBanner { + fn set_active_pane_item( + &mut self, + active_pane_item: Option<&dyn workspace::ItemHandle>, + window: &mut ui::Window, + cx: &mut Context, + ) -> ToolbarItemLocation { + if let Some(item) = active_pane_item + && let Some(editor) = item.downcast::() + && let Some(buffer) = editor.read(cx).buffer().read(cx).as_singleton() + && let Some(file) = buffer.read(cx).file() + && file + .file_name(cx) + .as_encoded_bytes() + .ends_with(".py".as_bytes()) + { + return ToolbarItemLocation::Secondary; + } + + ToolbarItemLocation::Hidden + } +} diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 5835ba4db1..036c8f5866 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -112,6 +112,7 @@ project_panel.workspace = true project_symbols.workspace = true prompt_store.workspace = true proto.workspace = true +python_ui.workspace = true recent_projects.workspace = true release_channel.workspace = true remote.workspace = true diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index c72fe39d2d..7b561c9988 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -43,6 +43,7 @@ use paths::{ use project::{DirectoryLister, ProjectItem}; use project_panel::ProjectPanel; use prompt_store::PromptBuilder; +use python_ui::BasedPyrightBanner; use quick_action_bar::QuickActionBar; use recent_projects::open_ssh_project; use release_channel::{AppCommitSha, ReleaseChannel}; @@ -971,6 +972,8 @@ fn initialize_pane( toolbar.add_item(project_diff_toolbar, window, cx); let agent_diff_toolbar = cx.new(AgentDiffToolbar::new); toolbar.add_item(agent_diff_toolbar, window, cx); + let basedpyright_banner = cx.new(|cx| BasedPyrightBanner::new(workspace, cx)); + toolbar.add_item(basedpyright_banner, window, cx); }) }); }