1use gpui::AnyElement;
2use repl::{
3 ExecutionState, JupyterSettings, Kernel, KernelSpecification, RuntimePanel, Session,
4 SessionSupport,
5};
6use ui::{prelude::*, ButtonLike, IconWithIndicator, IntoElement, Tooltip};
7
8use crate::QuickActionBar;
9
10const ZED_REPL_DOCUMENTATION: &str = "https://zed.dev/docs/repl";
11
12impl QuickActionBar {
13 pub fn render_repl_menu(&self, cx: &mut ViewContext<Self>) -> Option<AnyElement> {
14 if !JupyterSettings::enabled(cx) {
15 return None;
16 }
17
18 let workspace = self.workspace.upgrade()?.read(cx);
19
20 let (editor, repl_panel) = if let (Some(editor), Some(repl_panel)) =
21 (self.active_editor(), workspace.panel::<RuntimePanel>(cx))
22 {
23 (editor, repl_panel)
24 } else {
25 return None;
26 };
27
28 let session = repl_panel.update(cx, |repl_panel, cx| {
29 repl_panel.session(editor.downgrade(), cx)
30 });
31
32 let session = match session {
33 SessionSupport::ActiveSession(session) => session.read(cx),
34 SessionSupport::Inactive(spec) => {
35 return self.render_repl_launch_menu(spec, cx);
36 }
37 SessionSupport::RequiresSetup(language) => {
38 return self.render_repl_setup(&language, cx);
39 }
40 SessionSupport::Unsupported => return None,
41 };
42
43 let kernel_name: SharedString = session.kernel_specification.name.clone().into();
44 let kernel_language: SharedString = session
45 .kernel_specification
46 .kernelspec
47 .language
48 .clone()
49 .into();
50
51 let tooltip = |session: &Session| match &session.kernel {
52 Kernel::RunningKernel(kernel) => match &kernel.execution_state {
53 ExecutionState::Idle => {
54 format!("Run code on {} ({})", kernel_name, kernel_language)
55 }
56 ExecutionState::Busy => format!("Interrupt {} ({})", kernel_name, kernel_language),
57 },
58 Kernel::StartingKernel(_) => format!("{} is starting", kernel_name),
59 Kernel::ErroredLaunch(e) => format!("Error with kernel {}: {}", kernel_name, e),
60 Kernel::ShuttingDown => format!("{} is shutting down", kernel_name),
61 Kernel::Shutdown => "Nothing running".to_string(),
62 };
63
64 let tooltip_text: SharedString = SharedString::from(tooltip(&session).clone());
65
66 let button = ButtonLike::new("toggle_repl_icon")
67 .child(
68 IconWithIndicator::new(Icon::new(IconName::Play), Some(session.kernel.dot()))
69 .indicator_border_color(Some(cx.theme().colors().border)),
70 )
71 .size(ButtonSize::Compact)
72 .style(ButtonStyle::Subtle)
73 .tooltip(move |cx| Tooltip::text(tooltip_text.clone(), cx))
74 .on_click(|_, cx| cx.dispatch_action(Box::new(repl::Run {})))
75 .on_click(|_, cx| cx.dispatch_action(Box::new(repl::Run {})))
76 .into_any_element();
77
78 Some(button)
79 }
80
81 pub fn render_repl_launch_menu(
82 &self,
83 kernel_specification: KernelSpecification,
84 _cx: &mut ViewContext<Self>,
85 ) -> Option<AnyElement> {
86 let tooltip: SharedString =
87 SharedString::from(format!("Start REPL for {}", kernel_specification.name));
88
89 Some(
90 IconButton::new("toggle_repl_icon", IconName::Play)
91 .size(ButtonSize::Compact)
92 .icon_color(Color::Muted)
93 .style(ButtonStyle::Subtle)
94 .tooltip(move |cx| Tooltip::text(tooltip.clone(), cx))
95 .on_click(|_, cx| cx.dispatch_action(Box::new(repl::Run {})))
96 .into_any_element(),
97 )
98 }
99
100 pub fn render_repl_setup(
101 &self,
102 language: &str,
103 _cx: &mut ViewContext<Self>,
104 ) -> Option<AnyElement> {
105 let tooltip: SharedString = SharedString::from(format!("Setup Zed REPL for {}", language));
106 Some(
107 IconButton::new("toggle_repl_icon", IconName::Play)
108 .size(ButtonSize::Compact)
109 .icon_color(Color::Muted)
110 .style(ButtonStyle::Subtle)
111 .tooltip(move |cx| Tooltip::text(tooltip.clone(), cx))
112 .on_click(|_, cx| cx.open_url(ZED_REPL_DOCUMENTATION))
113 .into_any_element(),
114 )
115 }
116}