diff --git a/crates/quick_action_bar/src/repl_menu.rs b/crates/quick_action_bar/src/repl_menu.rs index a5f17ddec9fcb..ee31583388423 100644 --- a/crates/quick_action_bar/src/repl_menu.rs +++ b/crates/quick_action_bar/src/repl_menu.rs @@ -1,8 +1,9 @@ use std::time::Duration; -use gpui::{percentage, Animation, AnimationExt, AnyElement, Transformation}; +use gpui::{percentage, Animation, AnimationExt, AnyElement, Transformation, View}; use repl::{ - ExecutionState, JupyterSettings, Kernel, KernelSpecification, RuntimePanel, SessionSupport, + ExecutionState, JupyterSettings, Kernel, KernelSpecification, KernelStatus, RuntimePanel, + Session, SessionSupport, }; use ui::{ prelude::*, ButtonLike, ContextMenu, IconWithIndicator, Indicator, IntoElement, PopoverMenu, @@ -16,6 +17,22 @@ use crate::QuickActionBar; const ZED_REPL_DOCUMENTATION: &str = "https://zed.dev/docs/repl"; +struct ReplMenuState { + tooltip: SharedString, + icon: IconName, + icon_color: Color, + icon_is_animating: bool, + popover_disabled: bool, + indicator: Option, + + status: KernelStatus, + kernel_name: SharedString, + kernel_language: SharedString, + // TODO: Persist rotation state so the + // icon doesn't reset on every state change + // current_delta: Duration, +} + impl QuickActionBar { pub fn render_repl_menu(&self, cx: &mut ViewContext) -> Option { if !JupyterSettings::enabled(cx) { @@ -50,7 +67,7 @@ impl QuickActionBar { }); let session = match session { - SessionSupport::ActiveSession(session) => session.read(cx), + SessionSupport::ActiveSession(session) => session, SessionSupport::Inactive(spec) => { let spec = *spec; return self.render_repl_launch_menu(spec, cx); @@ -61,101 +78,25 @@ impl QuickActionBar { SessionSupport::Unsupported => return None, }; - let kernel_name: SharedString = session.kernel_specification.name.clone().into(); - let kernel_language: SharedString = session - .kernel_specification - .kernelspec - .language - .clone() - .into(); - - struct ReplMenuState { - tooltip: SharedString, - icon: IconName, - icon_color: Color, - icon_is_animating: bool, - popover_disabled: bool, - indicator: Option, - // TODO: Persist rotation state so the - // icon doesn't reset on every state change - // current_delta: Duration, - } - - impl Default for ReplMenuState { - fn default() -> Self { - Self { - tooltip: "Nothing running".into(), - icon: IconName::ReplNeutral, - icon_color: Color::Default, - icon_is_animating: false, - popover_disabled: false, - indicator: None, - // current_delta: Duration::default(), - } - } - } - - let menu_state = match &session.kernel { - Kernel::RunningKernel(kernel) => match &kernel.execution_state { - ExecutionState::Idle => ReplMenuState { - tooltip: format!("Run code on {} ({})", kernel_name, kernel_language).into(), - indicator: Some(Indicator::dot().color(Color::Success)), - ..Default::default() - }, - ExecutionState::Busy => ReplMenuState { - tooltip: format!("Interrupt {} ({})", kernel_name, kernel_language).into(), - icon_is_animating: true, - popover_disabled: false, - indicator: None, - ..Default::default() - }, - }, - Kernel::StartingKernel(_) => ReplMenuState { - tooltip: format!("{} is starting", kernel_name).into(), - icon_is_animating: true, - popover_disabled: true, - icon_color: Color::Muted, - indicator: Some(Indicator::dot().color(Color::Muted)), - ..Default::default() - }, - Kernel::ErroredLaunch(e) => ReplMenuState { - tooltip: format!("Error with kernel {}: {}", kernel_name, e).into(), - popover_disabled: false, - indicator: Some(Indicator::dot().color(Color::Error)), - ..Default::default() - }, - Kernel::ShuttingDown => ReplMenuState { - tooltip: format!("{} is shutting down", kernel_name).into(), - popover_disabled: true, - icon_color: Color::Muted, - indicator: Some(Indicator::dot().color(Color::Muted)), - ..Default::default() - }, - Kernel::Shutdown => ReplMenuState::default(), - }; + let menu_state = session_state(session.clone(), cx); let id = "repl-menu".to_string(); let element_id = |suffix| ElementId::Name(format!("{}-{}", id, suffix).into()); - let kernel = &session.kernel; - let status_borrow = &kernel.status(); - let status = status_borrow.clone(); let panel_clone = repl_panel.clone(); let editor_clone = editor.downgrade(); let dropdown_menu = PopoverMenu::new(element_id("menu")) .menu(move |cx| { - let kernel_name = kernel_name.clone(); - let kernel_language = kernel_language.clone(); - let status = status.clone(); let panel_clone = panel_clone.clone(); let editor_clone = editor_clone.clone(); - ContextMenu::build(cx, move |menu, _cx| { + let session = session.clone(); + ContextMenu::build(cx, move |menu, cx| { + let menu_state = session_state(session, cx); + let status = menu_state.status; let editor_clone = editor_clone.clone(); let panel_clone = panel_clone.clone(); - let kernel_name = kernel_name.clone(); - let kernel_language = kernel_language.clone(); - let status = status.clone(); + menu.when_else( status.is_connected(), |running| { @@ -166,8 +107,8 @@ impl QuickActionBar { .child( Label::new(format!( "kernel: {} ({})", - kernel_name.clone(), - kernel_language.clone() + menu_state.kernel_name.clone(), + menu_state.kernel_language.clone() )) .size(LabelSize::Small) .color(Color::Muted), @@ -371,3 +312,86 @@ impl QuickActionBar { ) } } + +fn session_state(session: View, cx: &WindowContext) -> ReplMenuState { + let session = session.read(cx); + + let kernel_name: SharedString = session.kernel_specification.name.clone().into(); + let kernel_language: SharedString = session + .kernel_specification + .kernelspec + .language + .clone() + .into(); + + let fill_fields = || { + ReplMenuState { + tooltip: "Nothing running".into(), + icon: IconName::ReplNeutral, + icon_color: Color::Default, + icon_is_animating: false, + popover_disabled: false, + indicator: None, + kernel_name: kernel_name.clone(), + kernel_language: kernel_language.clone(), + // todo!(): Technically not shutdown, but indeterminate + status: KernelStatus::Shutdown, + // current_delta: Duration::default(), + } + }; + + let menu_state = match &session.kernel { + Kernel::RunningKernel(kernel) => match &kernel.execution_state { + ExecutionState::Idle => ReplMenuState { + tooltip: format!("Run code on {} ({})", kernel_name, kernel_language).into(), + indicator: Some(Indicator::dot().color(Color::Success)), + status: session.kernel.status(), + ..fill_fields() + }, + ExecutionState::Busy => ReplMenuState { + tooltip: format!("Interrupt {} ({})", kernel_name, kernel_language).into(), + icon_is_animating: true, + popover_disabled: false, + indicator: None, + status: session.kernel.status(), + ..fill_fields() + }, + }, + Kernel::StartingKernel(_) => ReplMenuState { + tooltip: format!("{} is starting", kernel_name).into(), + icon_is_animating: true, + popover_disabled: true, + icon_color: Color::Muted, + indicator: Some(Indicator::dot().color(Color::Muted)), + status: session.kernel.status(), + ..fill_fields() + }, + Kernel::ErroredLaunch(e) => ReplMenuState { + tooltip: format!("Error with kernel {}: {}", kernel_name, e).into(), + popover_disabled: false, + indicator: Some(Indicator::dot().color(Color::Error)), + status: session.kernel.status(), + ..fill_fields() + }, + Kernel::ShuttingDown => ReplMenuState { + tooltip: format!("{} is shutting down", kernel_name).into(), + popover_disabled: true, + icon_color: Color::Muted, + indicator: Some(Indicator::dot().color(Color::Muted)), + status: session.kernel.status(), + ..fill_fields() + }, + Kernel::Shutdown => ReplMenuState { + tooltip: "Nothing running".into(), + icon: IconName::ReplNeutral, + icon_color: Color::Default, + icon_is_animating: false, + popover_disabled: false, + indicator: None, + status: KernelStatus::Shutdown, + ..fill_fields() + }, + }; + + menu_state +} diff --git a/crates/repl/src/repl.rs b/crates/repl/src/repl.rs index 3e0c3cead54c1..ac27f2581d913 100644 --- a/crates/repl/src/repl.rs +++ b/crates/repl/src/repl.rs @@ -11,7 +11,7 @@ mod session; mod stdio; pub use jupyter_settings::JupyterSettings; -pub use kernels::{Kernel, KernelSpecification}; +pub use kernels::{Kernel, KernelSpecification, KernelStatus}; pub use runtime_panel::{ClearOutputs, Interrupt, Run, Shutdown}; pub use runtime_panel::{RuntimePanel, SessionSupport}; pub use runtimelib::ExecutionState;