Refactor repl context menu (#14587)
This commit is contained in:
parent
cb6fc11abc
commit
8028e7f1b6
2 changed files with 112 additions and 88 deletions
|
@ -1,8 +1,9 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use gpui::{percentage, Animation, AnimationExt, AnyElement, Transformation};
|
use gpui::{percentage, Animation, AnimationExt, AnyElement, Transformation, View};
|
||||||
use repl::{
|
use repl::{
|
||||||
ExecutionState, JupyterSettings, Kernel, KernelSpecification, RuntimePanel, SessionSupport,
|
ExecutionState, JupyterSettings, Kernel, KernelSpecification, KernelStatus, RuntimePanel,
|
||||||
|
Session, SessionSupport,
|
||||||
};
|
};
|
||||||
use ui::{
|
use ui::{
|
||||||
prelude::*, ButtonLike, ContextMenu, IconWithIndicator, Indicator, IntoElement, PopoverMenu,
|
prelude::*, ButtonLike, ContextMenu, IconWithIndicator, Indicator, IntoElement, PopoverMenu,
|
||||||
|
@ -16,6 +17,22 @@ use crate::QuickActionBar;
|
||||||
|
|
||||||
const ZED_REPL_DOCUMENTATION: &str = "https://zed.dev/docs/repl";
|
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<Indicator>,
|
||||||
|
|
||||||
|
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 {
|
impl QuickActionBar {
|
||||||
pub fn render_repl_menu(&self, cx: &mut ViewContext<Self>) -> Option<AnyElement> {
|
pub fn render_repl_menu(&self, cx: &mut ViewContext<Self>) -> Option<AnyElement> {
|
||||||
if !JupyterSettings::enabled(cx) {
|
if !JupyterSettings::enabled(cx) {
|
||||||
|
@ -50,7 +67,7 @@ impl QuickActionBar {
|
||||||
});
|
});
|
||||||
|
|
||||||
let session = match session {
|
let session = match session {
|
||||||
SessionSupport::ActiveSession(session) => session.read(cx),
|
SessionSupport::ActiveSession(session) => session,
|
||||||
SessionSupport::Inactive(spec) => {
|
SessionSupport::Inactive(spec) => {
|
||||||
let spec = *spec;
|
let spec = *spec;
|
||||||
return self.render_repl_launch_menu(spec, cx);
|
return self.render_repl_launch_menu(spec, cx);
|
||||||
|
@ -61,101 +78,25 @@ impl QuickActionBar {
|
||||||
SessionSupport::Unsupported => return None,
|
SessionSupport::Unsupported => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let kernel_name: SharedString = session.kernel_specification.name.clone().into();
|
let menu_state = session_state(session.clone(), cx);
|
||||||
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<Indicator>,
|
|
||||||
// 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 id = "repl-menu".to_string();
|
let id = "repl-menu".to_string();
|
||||||
|
|
||||||
let element_id = |suffix| ElementId::Name(format!("{}-{}", id, suffix).into());
|
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 panel_clone = repl_panel.clone();
|
||||||
let editor_clone = editor.downgrade();
|
let editor_clone = editor.downgrade();
|
||||||
let dropdown_menu = PopoverMenu::new(element_id("menu"))
|
let dropdown_menu = PopoverMenu::new(element_id("menu"))
|
||||||
.menu(move |cx| {
|
.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 panel_clone = panel_clone.clone();
|
||||||
let editor_clone = editor_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 editor_clone = editor_clone.clone();
|
||||||
let panel_clone = panel_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(
|
menu.when_else(
|
||||||
status.is_connected(),
|
status.is_connected(),
|
||||||
|running| {
|
|running| {
|
||||||
|
@ -166,8 +107,8 @@ impl QuickActionBar {
|
||||||
.child(
|
.child(
|
||||||
Label::new(format!(
|
Label::new(format!(
|
||||||
"kernel: {} ({})",
|
"kernel: {} ({})",
|
||||||
kernel_name.clone(),
|
menu_state.kernel_name.clone(),
|
||||||
kernel_language.clone()
|
menu_state.kernel_language.clone()
|
||||||
))
|
))
|
||||||
.size(LabelSize::Small)
|
.size(LabelSize::Small)
|
||||||
.color(Color::Muted),
|
.color(Color::Muted),
|
||||||
|
@ -371,3 +312,86 @@ impl QuickActionBar {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn session_state(session: View<Session>, 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
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ mod session;
|
||||||
mod stdio;
|
mod stdio;
|
||||||
|
|
||||||
pub use jupyter_settings::JupyterSettings;
|
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::{ClearOutputs, Interrupt, Run, Shutdown};
|
||||||
pub use runtime_panel::{RuntimePanel, SessionSupport};
|
pub use runtime_panel::{RuntimePanel, SessionSupport};
|
||||||
pub use runtimelib::ExecutionState;
|
pub use runtimelib::ExecutionState;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue