Add REPL dropdown menu to toolbar (#14493)
TODO: - [x] Actions run from menu not firing - [x] Menu differentiates idle and busy for running kernel Menu States: - [x] No session && no support known No session && no kernel installed for languages of known support - (TODO after) Intro to REPL - [x] Link to docs No session but can start one - [x] Start REPL - (TODO after) More info -> Docs? Yes Session - [x] Info: Kernel name, language example: chatlab-3.7-adsf87fsa (Python) example: condapy-3.7 (Python) - [x] Change Kernel -> https://zed.dev/docs/repl#change-kernel - --- - [x] Run - [x] Interrupt - [x] Clear Outputs - --- - [x] Shutdown (Release notes left empty as the change will be documented in the REPL release!) Reserved for a follow on PR: ``` - [ ] Status should update when the menu is open (missing `cx.notify`?) - [ ] Shutdown all kernels action - [ ] Restart action - [ ] [Default kernel changed - restart (this kernel) to apply] // todo!(kyle): need some kind of state thing that says if this has happened ``` Release Notes: - N/A --------- Co-authored-by: Marshall Bowers <elliott.codes@gmail.com> Co-authored-by: Kyle Kelley <rgbkrk@gmail.com> Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
This commit is contained in:
co-authored by
Marshall Bowers
Kyle Kelley
Piotr Osiewicz
parent
1856320516
commit
fa3d29087d
@@ -19,8 +19,10 @@ gpui.workspace = true
|
||||
search.workspace = true
|
||||
settings.workspace = true
|
||||
ui.workspace = true
|
||||
util.workspace = true
|
||||
workspace.workspace = true
|
||||
repl.workspace = true
|
||||
zed_actions.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
editor = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -304,7 +304,7 @@ impl Render for QuickActionBar {
|
||||
.child(
|
||||
h_flex()
|
||||
.gap(Spacing::Medium.rems(cx))
|
||||
.children(search_button)
|
||||
.children(self.render_repl_menu(cx))
|
||||
.when(
|
||||
AssistantSettings::get_global(cx).enabled
|
||||
&& AssistantSettings::get_global(cx).button,
|
||||
@@ -314,7 +314,11 @@ impl Render for QuickActionBar {
|
||||
.child(
|
||||
h_flex()
|
||||
.gap(Spacing::Medium.rems(cx))
|
||||
.children(self.render_repl_menu(cx))
|
||||
.children(search_button),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap(Spacing::Medium.rems(cx))
|
||||
.children(editor_selections_dropdown)
|
||||
.child(editor_settings_dropdown),
|
||||
)
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
use gpui::AnyElement;
|
||||
use std::time::Duration;
|
||||
|
||||
use gpui::{percentage, Animation, AnimationExt, AnyElement, Transformation};
|
||||
use repl::{
|
||||
ExecutionState, JupyterSettings, Kernel, KernelSpecification, RuntimePanel, Session,
|
||||
SessionSupport,
|
||||
ExecutionState, JupyterSettings, Kernel, KernelSpecification, RuntimePanel, SessionSupport,
|
||||
};
|
||||
use ui::{prelude::*, ButtonLike, IconWithIndicator, IntoElement, Tooltip};
|
||||
use ui::{
|
||||
prelude::*, ButtonLike, ContextMenu, IconWithIndicator, Indicator, IntoElement, PopoverMenu,
|
||||
Tooltip,
|
||||
};
|
||||
|
||||
use gpui::ElementId;
|
||||
use util::ResultExt;
|
||||
|
||||
use crate::QuickActionBar;
|
||||
|
||||
@@ -25,6 +32,19 @@ impl QuickActionBar {
|
||||
return None;
|
||||
};
|
||||
|
||||
let has_nonempty_selection = {
|
||||
editor.update(cx, |this, cx| {
|
||||
this.selections
|
||||
.count()
|
||||
.ne(&0)
|
||||
.then(|| {
|
||||
let latest = this.selections.newest_display(cx);
|
||||
!latest.is_empty()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
})
|
||||
};
|
||||
|
||||
let session = repl_panel.update(cx, |repl_panel, cx| {
|
||||
repl_panel.session(editor.downgrade(), cx)
|
||||
});
|
||||
@@ -32,6 +52,7 @@ impl QuickActionBar {
|
||||
let session = match session {
|
||||
SessionSupport::ActiveSession(session) => session.read(cx),
|
||||
SessionSupport::Inactive(spec) => {
|
||||
let spec = *spec;
|
||||
return self.render_repl_launch_menu(spec, cx);
|
||||
}
|
||||
SessionSupport::RequiresSetup(language) => {
|
||||
@@ -48,34 +69,270 @@ impl QuickActionBar {
|
||||
.clone()
|
||||
.into();
|
||||
|
||||
let tooltip = |session: &Session| match &session.kernel {
|
||||
Kernel::RunningKernel(kernel) => match &kernel.execution_state {
|
||||
ExecutionState::Idle => {
|
||||
format!("Run code on {} ({})", kernel_name, kernel_language)
|
||||
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(),
|
||||
}
|
||||
ExecutionState::Busy => format!("Interrupt {} ({})", kernel_name, kernel_language),
|
||||
}
|
||||
}
|
||||
|
||||
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(_) => format!("{} is starting", kernel_name),
|
||||
Kernel::ErroredLaunch(e) => format!("Error with kernel {}: {}", kernel_name, e),
|
||||
Kernel::ShuttingDown => format!("{} is shutting down", kernel_name),
|
||||
Kernel::Shutdown => "Nothing running".to_string(),
|
||||
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 tooltip_text: SharedString = SharedString::from(tooltip(&session).clone());
|
||||
let id = "repl-menu".to_string();
|
||||
|
||||
let button = ButtonLike::new("toggle_repl_icon")
|
||||
.child(
|
||||
IconWithIndicator::new(Icon::new(IconName::Play), Some(session.kernel.dot()))
|
||||
.indicator_border_color(Some(cx.theme().colors().border)),
|
||||
)
|
||||
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 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| {
|
||||
let status = status.clone();
|
||||
running
|
||||
.custom_row(move |_cx| {
|
||||
h_flex()
|
||||
.child(
|
||||
Label::new(format!(
|
||||
"kernel: {} ({})",
|
||||
kernel_name.clone(),
|
||||
kernel_language.clone()
|
||||
))
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.into_any_element()
|
||||
})
|
||||
.custom_row(move |_cx| {
|
||||
h_flex()
|
||||
.child(
|
||||
Label::new(status.clone().to_string())
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.into_any_element()
|
||||
})
|
||||
},
|
||||
|not_running| {
|
||||
let status = status.clone();
|
||||
not_running.custom_row(move |_cx| {
|
||||
h_flex()
|
||||
.child(
|
||||
Label::new(format!("{}...", status.clone().to_string()))
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.into_any_element()
|
||||
})
|
||||
},
|
||||
)
|
||||
.separator()
|
||||
// Run
|
||||
.custom_entry(
|
||||
move |_cx| {
|
||||
Label::new(if has_nonempty_selection {
|
||||
"Run Selection"
|
||||
} else {
|
||||
"Run Line"
|
||||
})
|
||||
.into_any_element()
|
||||
},
|
||||
{
|
||||
let panel_clone = panel_clone.clone();
|
||||
let editor_clone = editor_clone.clone();
|
||||
move |cx| {
|
||||
let editor_clone = editor_clone.clone();
|
||||
panel_clone.update(cx, |this, cx| {
|
||||
this.run(editor_clone.clone(), cx).log_err();
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
// Interrupt
|
||||
.custom_entry(
|
||||
move |_cx| {
|
||||
Label::new("Interrupt")
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Error)
|
||||
.into_any_element()
|
||||
},
|
||||
{
|
||||
let panel_clone = panel_clone.clone();
|
||||
let editor_clone = editor_clone.clone();
|
||||
move |cx| {
|
||||
let editor_clone = editor_clone.clone();
|
||||
panel_clone.update(cx, |this, cx| {
|
||||
this.interrupt(editor_clone, cx);
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
// Clear Outputs
|
||||
.custom_entry(
|
||||
move |_cx| {
|
||||
Label::new("Clear Outputs")
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted)
|
||||
.into_any_element()
|
||||
},
|
||||
{
|
||||
let panel_clone = panel_clone.clone();
|
||||
let editor_clone = editor_clone.clone();
|
||||
move |cx| {
|
||||
let editor_clone = editor_clone.clone();
|
||||
panel_clone.update(cx, |this, cx| {
|
||||
this.clear_outputs(editor_clone, cx);
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
.separator()
|
||||
.link(
|
||||
"Change Kernel",
|
||||
Box::new(zed_actions::OpenBrowser {
|
||||
url: format!("{}#change-kernel", ZED_REPL_DOCUMENTATION),
|
||||
}),
|
||||
)
|
||||
// TODO: Add Restart action
|
||||
// .action("Restart", Box::new(gpui::NoAction))
|
||||
// Shut down kernel
|
||||
.custom_entry(
|
||||
move |_cx| {
|
||||
Label::new("Shut Down Kernel")
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Error)
|
||||
.into_any_element()
|
||||
},
|
||||
{
|
||||
let panel_clone = panel_clone.clone();
|
||||
let editor_clone = editor_clone.clone();
|
||||
move |cx| {
|
||||
let editor_clone = editor_clone.clone();
|
||||
panel_clone.update(cx, |this, cx| {
|
||||
this.shutdown(editor_clone, cx);
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
// .separator()
|
||||
// TODO: Add shut down all kernels action
|
||||
// .action("Shut Down all Kernels", Box::new(gpui::NoAction))
|
||||
})
|
||||
.into()
|
||||
})
|
||||
.trigger(
|
||||
ButtonLike::new_rounded_right(element_id("dropdown"))
|
||||
.child(
|
||||
Icon::new(IconName::ChevronDownSmall)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.tooltip(move |cx| Tooltip::text("REPL Menu", cx))
|
||||
.width(rems(1.).into())
|
||||
.disabled(menu_state.popover_disabled),
|
||||
);
|
||||
|
||||
let button = ButtonLike::new_rounded_left("toggle_repl_icon")
|
||||
.child(if menu_state.icon_is_animating {
|
||||
Icon::new(menu_state.icon)
|
||||
.color(menu_state.icon_color)
|
||||
.with_animation(
|
||||
"arrow-circle",
|
||||
Animation::new(Duration::from_secs(5)).repeat(),
|
||||
|icon, delta| icon.transform(Transformation::rotate(percentage(delta))),
|
||||
)
|
||||
.into_any_element()
|
||||
} else {
|
||||
IconWithIndicator::new(
|
||||
Icon::new(IconName::ReplNeutral).color(menu_state.icon_color),
|
||||
menu_state.indicator,
|
||||
)
|
||||
.indicator_border_color(Some(cx.theme().colors().toolbar_background))
|
||||
.into_any_element()
|
||||
})
|
||||
.size(ButtonSize::Compact)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.tooltip(move |cx| Tooltip::text(tooltip_text.clone(), cx))
|
||||
.on_click(|_, cx| cx.dispatch_action(Box::new(repl::Run {})))
|
||||
.tooltip(move |cx| Tooltip::text(menu_state.tooltip.clone(), cx))
|
||||
.on_click(|_, cx| cx.dispatch_action(Box::new(repl::Run {})))
|
||||
.into_any_element();
|
||||
|
||||
Some(button)
|
||||
Some(
|
||||
h_flex()
|
||||
.child(button)
|
||||
.child(dropdown_menu)
|
||||
.into_any_element(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn render_repl_launch_menu(
|
||||
@@ -87,7 +344,7 @@ impl QuickActionBar {
|
||||
SharedString::from(format!("Start REPL for {}", kernel_specification.name));
|
||||
|
||||
Some(
|
||||
IconButton::new("toggle_repl_icon", IconName::Play)
|
||||
IconButton::new("toggle_repl_icon", IconName::ReplNeutral)
|
||||
.size(ButtonSize::Compact)
|
||||
.icon_color(Color::Muted)
|
||||
.style(ButtonStyle::Subtle)
|
||||
@@ -104,12 +361,12 @@ impl QuickActionBar {
|
||||
) -> Option<AnyElement> {
|
||||
let tooltip: SharedString = SharedString::from(format!("Setup Zed REPL for {}", language));
|
||||
Some(
|
||||
IconButton::new("toggle_repl_icon", IconName::Play)
|
||||
IconButton::new("toggle_repl_icon", IconName::ReplNeutral)
|
||||
.size(ButtonSize::Compact)
|
||||
.icon_color(Color::Muted)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.tooltip(move |cx| Tooltip::text(tooltip.clone(), cx))
|
||||
.on_click(|_, cx| cx.open_url(ZED_REPL_DOCUMENTATION))
|
||||
.on_click(|_, cx| cx.open_url(&format!("{}#installation", ZED_REPL_DOCUMENTATION)))
|
||||
.into_any_element(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -81,6 +81,52 @@ pub enum Kernel {
|
||||
Shutdown,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum KernelStatus {
|
||||
Idle,
|
||||
Busy,
|
||||
Starting,
|
||||
Error,
|
||||
ShuttingDown,
|
||||
Shutdown,
|
||||
}
|
||||
impl KernelStatus {
|
||||
pub fn is_connected(&self) -> bool {
|
||||
match self {
|
||||
KernelStatus::Idle | KernelStatus::Busy => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for KernelStatus {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
KernelStatus::Idle => "Idle".to_string(),
|
||||
KernelStatus::Busy => "Busy".to_string(),
|
||||
KernelStatus::Starting => "Starting".to_string(),
|
||||
KernelStatus::Error => "Error".to_string(),
|
||||
KernelStatus::ShuttingDown => "Shutting Down".to_string(),
|
||||
KernelStatus::Shutdown => "Shutdown".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Kernel> for KernelStatus {
|
||||
fn from(kernel: &Kernel) -> Self {
|
||||
match kernel {
|
||||
Kernel::RunningKernel(kernel) => match kernel.execution_state {
|
||||
ExecutionState::Idle => KernelStatus::Idle,
|
||||
ExecutionState::Busy => KernelStatus::Busy,
|
||||
},
|
||||
Kernel::StartingKernel(_) => KernelStatus::Starting,
|
||||
Kernel::ErroredLaunch(_) => KernelStatus::Error,
|
||||
Kernel::ShuttingDown => KernelStatus::ShuttingDown,
|
||||
Kernel::Shutdown => KernelStatus::Shutdown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Kernel {
|
||||
pub fn dot(&self) -> Indicator {
|
||||
match self {
|
||||
@@ -95,6 +141,10 @@ impl Kernel {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn status(&self) -> KernelStatus {
|
||||
self.into()
|
||||
}
|
||||
|
||||
pub fn set_execution_state(&mut self, status: &ExecutionState) {
|
||||
match self {
|
||||
Kernel::RunningKernel(running_kernel) => {
|
||||
|
||||
@@ -12,7 +12,7 @@ mod stdio;
|
||||
|
||||
pub use jupyter_settings::JupyterSettings;
|
||||
pub use kernels::{Kernel, KernelSpecification};
|
||||
pub use runtime_panel::Run;
|
||||
pub use runtime_panel::{ClearOutputs, Interrupt, Run, Shutdown};
|
||||
pub use runtime_panel::{RuntimePanel, SessionSupport};
|
||||
pub use runtimelib::ExecutionState;
|
||||
pub use session::Session;
|
||||
|
||||
@@ -23,7 +23,7 @@ use workspace::{
|
||||
Workspace,
|
||||
};
|
||||
|
||||
actions!(repl, [Run, ClearOutputs]);
|
||||
actions!(repl, [Run, ClearOutputs, Interrupt, Shutdown]);
|
||||
actions!(repl_panel, [ToggleFocus]);
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
@@ -51,6 +51,8 @@ pub struct RuntimePanel {
|
||||
pub enum ReplEvent {
|
||||
Run(WeakView<Editor>),
|
||||
ClearOutputs(WeakView<Editor>),
|
||||
Interrupt(WeakView<Editor>),
|
||||
Shutdown(WeakView<Editor>),
|
||||
}
|
||||
|
||||
impl RuntimePanel {
|
||||
@@ -108,6 +110,40 @@ impl RuntimePanel {
|
||||
},
|
||||
)
|
||||
.detach();
|
||||
|
||||
editor
|
||||
.register_action({
|
||||
let editor = cx.view().downgrade();
|
||||
let repl_editor_event_tx = repl_editor_event_tx.clone();
|
||||
|
||||
move |_: &Interrupt, cx: &mut WindowContext| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
repl_editor_event_tx
|
||||
.unbounded_send(ReplEvent::Interrupt(
|
||||
editor.clone(),
|
||||
))
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
editor
|
||||
.register_action({
|
||||
let editor = cx.view().downgrade();
|
||||
let repl_editor_event_tx = repl_editor_event_tx.clone();
|
||||
|
||||
move |_: &Shutdown, cx: &mut WindowContext| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
repl_editor_event_tx
|
||||
.unbounded_send(ReplEvent::Shutdown(editor.clone()))
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
},
|
||||
),
|
||||
];
|
||||
@@ -123,6 +159,12 @@ impl RuntimePanel {
|
||||
ReplEvent::ClearOutputs(editor) => {
|
||||
runtime_panel.clear_outputs(editor, cx);
|
||||
}
|
||||
ReplEvent::Interrupt(editor) => {
|
||||
runtime_panel.interrupt(editor, cx);
|
||||
}
|
||||
ReplEvent::Shutdown(editor) => {
|
||||
runtime_panel.shutdown(editor, cx);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
@@ -320,11 +362,31 @@ impl RuntimePanel {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interrupt(&mut self, editor: WeakView<Editor>, cx: &mut ViewContext<Self>) {
|
||||
let entity_id = editor.entity_id();
|
||||
if let Some(session) = self.sessions.get_mut(&entity_id) {
|
||||
session.update(cx, |session, cx| {
|
||||
session.interrupt(cx);
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shutdown(&self, editor: WeakView<Editor>, cx: &mut ViewContext<RuntimePanel>) {
|
||||
let entity_id = editor.entity_id();
|
||||
if let Some(session) = self.sessions.get(&entity_id) {
|
||||
session.update(cx, |session, cx| {
|
||||
session.shutdown(cx);
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SessionSupport {
|
||||
ActiveSession(View<Session>),
|
||||
Inactive(KernelSpecification),
|
||||
Inactive(Box<KernelSpecification>),
|
||||
RequiresSetup(Arc<str>),
|
||||
Unsupported,
|
||||
}
|
||||
@@ -350,7 +412,7 @@ impl RuntimePanel {
|
||||
let kernelspec = self.kernelspec(&language, cx);
|
||||
|
||||
match kernelspec {
|
||||
Some(kernelspec) => SessionSupport::Inactive(kernelspec),
|
||||
Some(kernelspec) => SessionSupport::Inactive(Box::new(kernelspec)),
|
||||
None => {
|
||||
// If no kernelspec but language is one of typescript or python
|
||||
// then we return RequiresSetup
|
||||
|
||||
@@ -370,6 +370,14 @@ impl ButtonLike {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_rounded_left(id: impl Into<ElementId>) -> Self {
|
||||
Self::new(id).rounding(ButtonLikeRounding::Left)
|
||||
}
|
||||
|
||||
pub fn new_rounded_right(id: impl Into<ElementId>) -> Self {
|
||||
Self::new(id).rounding(ButtonLikeRounding::Right)
|
||||
}
|
||||
|
||||
pub(crate) fn height(mut self, height: DefiniteLength) -> Self {
|
||||
self.height = Some(height);
|
||||
self
|
||||
|
||||
@@ -91,7 +91,7 @@ impl IconSize {
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Eq, PartialEq, Copy, Clone, EnumIter, EnumString, IntoStaticStr, Serialize, Deserialize,
|
||||
Debug, PartialEq, Eq, Copy, Clone, EnumIter, EnumString, IntoStaticStr, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum IconName {
|
||||
Ai,
|
||||
@@ -118,6 +118,8 @@ pub enum IconName {
|
||||
CaseSensitive,
|
||||
Check,
|
||||
ChevronDown,
|
||||
/// This chevron indicates a popover menu.
|
||||
ChevronDownSmall,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
ChevronUp,
|
||||
@@ -160,11 +162,11 @@ pub enum IconName {
|
||||
Font,
|
||||
FontSize,
|
||||
FontWeight,
|
||||
GenericClose,
|
||||
GenericMaximize,
|
||||
GenericMinimize,
|
||||
GenericRestore,
|
||||
Github,
|
||||
GenericMinimize,
|
||||
GenericMaximize,
|
||||
GenericClose,
|
||||
GenericRestore,
|
||||
Hash,
|
||||
HistoryRerun,
|
||||
Indicator,
|
||||
@@ -194,9 +196,6 @@ pub enum IconName {
|
||||
PullRequest,
|
||||
Quote,
|
||||
Regex,
|
||||
ReplPlay,
|
||||
ReplOff,
|
||||
ReplPause,
|
||||
ReplNeutral,
|
||||
Replace,
|
||||
ReplaceAll,
|
||||
@@ -235,12 +234,12 @@ pub enum IconName {
|
||||
Trash,
|
||||
TriangleRight,
|
||||
Update,
|
||||
Visible,
|
||||
WholeWord,
|
||||
XCircle,
|
||||
ZedAssistant,
|
||||
ZedAssistantFilled,
|
||||
ZedXCopilot,
|
||||
Visible,
|
||||
}
|
||||
|
||||
impl IconName {
|
||||
@@ -270,6 +269,7 @@ impl IconName {
|
||||
IconName::CaseSensitive => "icons/case_insensitive.svg",
|
||||
IconName::Check => "icons/check.svg",
|
||||
IconName::ChevronDown => "icons/chevron_down.svg",
|
||||
IconName::ChevronDownSmall => "icons/chevron_down_small.svg",
|
||||
IconName::ChevronLeft => "icons/chevron_left.svg",
|
||||
IconName::ChevronRight => "icons/chevron_right.svg",
|
||||
IconName::ChevronUp => "icons/chevron_up.svg",
|
||||
@@ -312,11 +312,11 @@ impl IconName {
|
||||
IconName::Font => "icons/font.svg",
|
||||
IconName::FontSize => "icons/font_size.svg",
|
||||
IconName::FontWeight => "icons/font_weight.svg",
|
||||
IconName::GenericClose => "icons/generic_close.svg",
|
||||
IconName::GenericMaximize => "icons/generic_maximize.svg",
|
||||
IconName::GenericMinimize => "icons/generic_minimize.svg",
|
||||
IconName::GenericRestore => "icons/generic_restore.svg",
|
||||
IconName::Github => "icons/github.svg",
|
||||
IconName::GenericMinimize => "icons/generic_minimize.svg",
|
||||
IconName::GenericMaximize => "icons/generic_maximize.svg",
|
||||
IconName::GenericClose => "icons/generic_close.svg",
|
||||
IconName::GenericRestore => "icons/generic_restore.svg",
|
||||
IconName::Hash => "icons/hash.svg",
|
||||
IconName::HistoryRerun => "icons/history_rerun.svg",
|
||||
IconName::Indicator => "icons/indicator.svg",
|
||||
@@ -346,10 +346,7 @@ impl IconName {
|
||||
IconName::PullRequest => "icons/pull_request.svg",
|
||||
IconName::Quote => "icons/quote.svg",
|
||||
IconName::Regex => "icons/regex.svg",
|
||||
IconName::ReplPlay => "icons/repl_play.svg",
|
||||
IconName::ReplPause => "icons/repl_pause.svg",
|
||||
IconName::ReplNeutral => "icons/repl_neutral.svg",
|
||||
IconName::ReplOff => "icons/repl_off.svg",
|
||||
IconName::Replace => "icons/replace.svg",
|
||||
IconName::ReplaceAll => "icons/replace_all.svg",
|
||||
IconName::ReplaceNext => "icons/replace_next.svg",
|
||||
@@ -387,12 +384,12 @@ impl IconName {
|
||||
IconName::Trash => "icons/trash.svg",
|
||||
IconName::TriangleRight => "icons/triangle_right.svg",
|
||||
IconName::Update => "icons/update.svg",
|
||||
IconName::Visible => "icons/visible.svg",
|
||||
IconName::WholeWord => "icons/word_search.svg",
|
||||
IconName::XCircle => "icons/error.svg",
|
||||
IconName::ZedAssistant => "icons/zed_assistant.svg",
|
||||
IconName::ZedAssistantFilled => "icons/zed_assistant_filled.svg",
|
||||
IconName::ZedXCopilot => "icons/zed_x_copilot.svg",
|
||||
IconName::Visible => "icons/visible.svg",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user