Compare commits
7 Commits
fix-git-ht
...
stateful-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80c2f9dc6c | ||
|
|
baf90b31c9 | ||
|
|
e8e66428f0 | ||
|
|
946ef41822 | ||
|
|
0135d1ae27 | ||
|
|
feee7b3f27 | ||
|
|
99840ce814 |
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -16012,7 +16012,6 @@ dependencies = [
|
|||||||
"outline_panel",
|
"outline_panel",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"paths",
|
"paths",
|
||||||
"picker",
|
|
||||||
"profiling",
|
"profiling",
|
||||||
"project",
|
"project",
|
||||||
"project_panel",
|
"project_panel",
|
||||||
|
|||||||
@@ -2,27 +2,29 @@ use crate::kernels::KernelSpecification;
|
|||||||
use crate::repl_store::ReplStore;
|
use crate::repl_store::ReplStore;
|
||||||
use crate::KERNEL_DOCS_URL;
|
use crate::KERNEL_DOCS_URL;
|
||||||
|
|
||||||
|
use editor::Editor;
|
||||||
use gpui::DismissEvent;
|
use gpui::DismissEvent;
|
||||||
|
|
||||||
use gpui::FontWeight;
|
use gpui::FontWeight;
|
||||||
|
use gpui::WeakView;
|
||||||
use picker::Picker;
|
use picker::Picker;
|
||||||
use picker::PickerDelegate;
|
use picker::PickerDelegate;
|
||||||
use project::WorktreeId;
|
use project::WorktreeId;
|
||||||
|
use ui::ButtonLike;
|
||||||
|
use ui::Tooltip;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ui::ListItemSpacing;
|
use ui::ListItemSpacing;
|
||||||
|
|
||||||
use gpui::SharedString;
|
use gpui::SharedString;
|
||||||
use gpui::Task;
|
use gpui::Task;
|
||||||
use ui::{prelude::*, ListItem, PopoverMenu, PopoverMenuHandle, PopoverTrigger};
|
use ui::{prelude::*, ListItem, PopoverMenu, PopoverMenuHandle};
|
||||||
|
|
||||||
type OnSelect = Box<dyn Fn(KernelSpecification, &mut WindowContext)>;
|
pub type OnSelect = Box<dyn Fn(KernelSpecification, &mut WindowContext)>;
|
||||||
|
|
||||||
#[derive(IntoElement)]
|
pub struct KernelSelector {
|
||||||
pub struct KernelSelector<T: PopoverTrigger> {
|
|
||||||
handle: Option<PopoverMenuHandle<Picker<KernelPickerDelegate>>>,
|
handle: Option<PopoverMenuHandle<Picker<KernelPickerDelegate>>>,
|
||||||
on_select: OnSelect,
|
editor: WeakView<Editor>,
|
||||||
trigger: T,
|
|
||||||
info_text: Option<SharedString>,
|
info_text: Option<SharedString>,
|
||||||
worktree_id: WorktreeId,
|
worktree_id: WorktreeId,
|
||||||
}
|
}
|
||||||
@@ -32,6 +34,7 @@ pub struct KernelPickerDelegate {
|
|||||||
filtered_kernels: Vec<KernelSpecification>,
|
filtered_kernels: Vec<KernelSpecification>,
|
||||||
selected_kernelspec: Option<KernelSpecification>,
|
selected_kernelspec: Option<KernelSpecification>,
|
||||||
on_select: OnSelect,
|
on_select: OnSelect,
|
||||||
|
group: Group,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to truncate long paths
|
// Helper function to truncate long paths
|
||||||
@@ -44,12 +47,15 @@ fn truncate_path(path: &SharedString, max_length: usize) -> SharedString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PopoverTrigger> KernelSelector<T> {
|
impl KernelSelector {
|
||||||
pub fn new(on_select: OnSelect, worktree_id: WorktreeId, trigger: T) -> Self {
|
pub fn new(
|
||||||
|
worktree_id: WorktreeId,
|
||||||
|
editor: WeakView<Editor>,
|
||||||
|
_cx: &mut ViewContext<Self>,
|
||||||
|
) -> Self {
|
||||||
KernelSelector {
|
KernelSelector {
|
||||||
on_select,
|
editor,
|
||||||
handle: None,
|
handle: None,
|
||||||
trigger,
|
|
||||||
info_text: None,
|
info_text: None,
|
||||||
worktree_id,
|
worktree_id,
|
||||||
}
|
}
|
||||||
@@ -66,6 +72,14 @@ impl<T: PopoverTrigger> KernelSelector<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum Group {
|
||||||
|
All,
|
||||||
|
Jupyter,
|
||||||
|
Python,
|
||||||
|
Remote,
|
||||||
|
}
|
||||||
|
|
||||||
impl PickerDelegate for KernelPickerDelegate {
|
impl PickerDelegate for KernelPickerDelegate {
|
||||||
type ListItem = ListItem;
|
type ListItem = ListItem;
|
||||||
|
|
||||||
@@ -204,6 +218,75 @@ impl PickerDelegate for KernelPickerDelegate {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_header(&self, cx: &mut ViewContext<Picker<Self>>) -> Option<gpui::AnyElement> {
|
||||||
|
let mode = Group::All;
|
||||||
|
|
||||||
|
Some(
|
||||||
|
h_flex()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id("all")
|
||||||
|
.px_2()
|
||||||
|
.py_1()
|
||||||
|
.cursor_pointer()
|
||||||
|
.border_b_2()
|
||||||
|
.when(mode == Group::All, |this| {
|
||||||
|
this.border_color(cx.theme().colors().border)
|
||||||
|
})
|
||||||
|
.child(Label::new("All"))
|
||||||
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
|
this.delegate.set_group(Group::All, cx);
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id("jupyter")
|
||||||
|
.px_2()
|
||||||
|
.py_1()
|
||||||
|
.cursor_pointer()
|
||||||
|
.border_b_2()
|
||||||
|
.when(mode == Group::Jupyter, |this| {
|
||||||
|
this.border_color(cx.theme().colors().border)
|
||||||
|
})
|
||||||
|
.child(Label::new("Jupyter"))
|
||||||
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
|
this.delegate.set_group(Group::Jupyter, cx);
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id("python")
|
||||||
|
.px_2()
|
||||||
|
.py_1()
|
||||||
|
.cursor_pointer()
|
||||||
|
.border_b_2()
|
||||||
|
.when(mode == Group::Python, |this| {
|
||||||
|
this.border_color(cx.theme().colors().border)
|
||||||
|
})
|
||||||
|
.child(Label::new("Python"))
|
||||||
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
|
this.delegate.set_group(Group::Python, cx);
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id("remote")
|
||||||
|
.px_2()
|
||||||
|
.py_1()
|
||||||
|
.cursor_pointer()
|
||||||
|
.border_b_2()
|
||||||
|
.when(mode == Group::Remote, |this| {
|
||||||
|
this.border_color(cx.theme().colors().border)
|
||||||
|
})
|
||||||
|
.child(Label::new("Remote"))
|
||||||
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
|
this.delegate.set_group(Group::Remote, cx);
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.into_any_element(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn render_footer(&self, cx: &mut ViewContext<Picker<Self>>) -> Option<gpui::AnyElement> {
|
fn render_footer(&self, cx: &mut ViewContext<Picker<Self>>) -> Option<gpui::AnyElement> {
|
||||||
Some(
|
Some(
|
||||||
h_flex()
|
h_flex()
|
||||||
@@ -225,8 +308,29 @@ impl PickerDelegate for KernelPickerDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PopoverTrigger> RenderOnce for KernelSelector<T> {
|
impl KernelPickerDelegate {
|
||||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
fn new(
|
||||||
|
on_select: OnSelect,
|
||||||
|
kernels: Vec<KernelSpecification>,
|
||||||
|
selected_kernelspec: Option<KernelSpecification>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
on_select,
|
||||||
|
all_kernels: kernels.clone(),
|
||||||
|
filtered_kernels: kernels,
|
||||||
|
group: Group::All,
|
||||||
|
selected_kernelspec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_group(&mut self, group: Group, cx: &mut ViewContext<Picker<Self>>) {
|
||||||
|
self.group = group;
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for KernelSelector {
|
||||||
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let store = ReplStore::global(cx).read(cx);
|
let store = ReplStore::global(cx).read(cx);
|
||||||
|
|
||||||
let all_kernels: Vec<KernelSpecification> = store
|
let all_kernels: Vec<KernelSpecification> = store
|
||||||
@@ -235,13 +339,18 @@ impl<T: PopoverTrigger> RenderOnce for KernelSelector<T> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let selected_kernelspec = store.active_kernelspec(self.worktree_id, None, cx);
|
let selected_kernelspec = store.active_kernelspec(self.worktree_id, None, cx);
|
||||||
|
let current_kernel_name = selected_kernelspec.as_ref().map(|spec| spec.name()).clone();
|
||||||
|
|
||||||
let delegate = KernelPickerDelegate {
|
let editor = self.editor.clone();
|
||||||
on_select: self.on_select,
|
let on_select: OnSelect = Box::new(move |kernelspec, cx| {
|
||||||
all_kernels: all_kernels.clone(),
|
crate::assign_kernelspec(kernelspec, editor.clone(), cx).ok();
|
||||||
filtered_kernels: all_kernels,
|
});
|
||||||
selected_kernelspec,
|
|
||||||
};
|
let menu_handle: PopoverMenuHandle<Picker<KernelPickerDelegate>> =
|
||||||
|
PopoverMenuHandle::default();
|
||||||
|
|
||||||
|
let delegate =
|
||||||
|
KernelPickerDelegate::new(on_select, all_kernels, selected_kernelspec.clone());
|
||||||
|
|
||||||
let picker_view = cx.new_view(|cx| {
|
let picker_view = cx.new_view(|cx| {
|
||||||
let picker = Picker::uniform_list(delegate, cx)
|
let picker = Picker::uniform_list(delegate, cx)
|
||||||
@@ -252,8 +361,42 @@ impl<T: PopoverTrigger> RenderOnce for KernelSelector<T> {
|
|||||||
|
|
||||||
PopoverMenu::new("kernel-switcher")
|
PopoverMenu::new("kernel-switcher")
|
||||||
.menu(move |_cx| Some(picker_view.clone()))
|
.menu(move |_cx| Some(picker_view.clone()))
|
||||||
.trigger(self.trigger)
|
.trigger(
|
||||||
|
ButtonLike::new("kernel-selector")
|
||||||
|
.style(ButtonStyle::Subtle)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.w_full()
|
||||||
|
.gap_0p5()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.overflow_x_hidden()
|
||||||
|
.flex_grow()
|
||||||
|
.whitespace_nowrap()
|
||||||
|
.child(
|
||||||
|
Label::new(if let Some(name) = current_kernel_name {
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
SharedString::from("Select Kernel")
|
||||||
|
})
|
||||||
|
.size(LabelSize::Small)
|
||||||
|
.color(if selected_kernelspec.is_some() {
|
||||||
|
Color::Default
|
||||||
|
} else {
|
||||||
|
Color::Placeholder
|
||||||
|
})
|
||||||
|
.into_any_element(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Icon::new(IconName::ChevronDown)
|
||||||
|
.color(Color::Muted)
|
||||||
|
.size(IconSize::XSmall),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.tooltip(move |cx| Tooltip::text("Select Kernel", cx)),
|
||||||
|
)
|
||||||
.attach(gpui::AnchorCorner::BottomLeft)
|
.attach(gpui::AnchorCorner::BottomLeft)
|
||||||
.when_some(self.handle, |menu, handle| menu.with_handle(handle))
|
.with_handle(menu_handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ outline.workspace = true
|
|||||||
outline_panel.workspace = true
|
outline_panel.workspace = true
|
||||||
parking_lot.workspace = true
|
parking_lot.workspace = true
|
||||||
paths.workspace = true
|
paths.workspace = true
|
||||||
picker.workspace = true
|
|
||||||
profiling.workspace = true
|
profiling.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
project_panel.workspace = true
|
project_panel.workspace = true
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ use gpui::{
|
|||||||
Action, AnchorCorner, ClickEvent, ElementId, EventEmitter, FocusHandle, FocusableView,
|
Action, AnchorCorner, ClickEvent, ElementId, EventEmitter, FocusHandle, FocusableView,
|
||||||
InteractiveElement, ParentElement, Render, Styled, Subscription, View, ViewContext, WeakView,
|
InteractiveElement, ParentElement, Render, Styled, Subscription, View, ViewContext, WeakView,
|
||||||
};
|
};
|
||||||
|
use repl::worktree_id_for_editor;
|
||||||
|
use repl_menu::ReplMenu;
|
||||||
use search::{buffer_search, BufferSearchBar};
|
use search::{buffer_search, BufferSearchBar};
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use ui::{
|
use ui::{
|
||||||
@@ -33,6 +35,7 @@ pub struct QuickActionBar {
|
|||||||
toggle_selections_handle: PopoverMenuHandle<ContextMenu>,
|
toggle_selections_handle: PopoverMenuHandle<ContextMenu>,
|
||||||
toggle_settings_handle: PopoverMenuHandle<ContextMenu>,
|
toggle_settings_handle: PopoverMenuHandle<ContextMenu>,
|
||||||
workspace: WeakView<Workspace>,
|
workspace: WeakView<Workspace>,
|
||||||
|
repl_menu: Option<View<ReplMenu>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QuickActionBar {
|
impl QuickActionBar {
|
||||||
@@ -49,6 +52,7 @@ impl QuickActionBar {
|
|||||||
toggle_selections_handle: Default::default(),
|
toggle_selections_handle: Default::default(),
|
||||||
toggle_settings_handle: Default::default(),
|
toggle_settings_handle: Default::default(),
|
||||||
workspace: workspace.weak_handle(),
|
workspace: workspace.weak_handle(),
|
||||||
|
repl_menu: None,
|
||||||
};
|
};
|
||||||
this.apply_settings(cx);
|
this.apply_settings(cx);
|
||||||
cx.observe_global::<SettingsStore>(|this, cx| this.apply_settings(cx))
|
cx.observe_global::<SettingsStore>(|this, cx| this.apply_settings(cx))
|
||||||
@@ -350,7 +354,7 @@ impl Render for QuickActionBar {
|
|||||||
h_flex()
|
h_flex()
|
||||||
.id("quick action bar")
|
.id("quick action bar")
|
||||||
.gap(DynamicSpacing::Base06.rems(cx))
|
.gap(DynamicSpacing::Base06.rems(cx))
|
||||||
.children(self.render_repl_menu(cx))
|
.children(self.repl_menu.clone())
|
||||||
.children(self.render_toggle_markdown_preview(self.workspace.clone(), cx))
|
.children(self.render_toggle_markdown_preview(self.workspace.clone(), cx))
|
||||||
.children(search_button)
|
.children(search_button)
|
||||||
.when(
|
.when(
|
||||||
@@ -425,7 +429,15 @@ impl ToolbarItemView for QuickActionBar {
|
|||||||
if let Some(active_item) = active_pane_item {
|
if let Some(active_item) = active_pane_item {
|
||||||
self._inlay_hints_enabled_subscription.take();
|
self._inlay_hints_enabled_subscription.take();
|
||||||
|
|
||||||
if let Some(editor) = active_item.downcast::<Editor>() {
|
let editor = active_item.downcast::<Editor>();
|
||||||
|
|
||||||
|
let work_tree_id = active_item
|
||||||
|
.downcast::<Editor>()
|
||||||
|
.and_then(|editor| worktree_id_for_editor(editor.downgrade(), cx));
|
||||||
|
|
||||||
|
if let (Some(editor), Some(work_tree_id)) = (editor, work_tree_id) {
|
||||||
|
self.repl_menu =
|
||||||
|
Some(cx.new_view(|cx| ReplMenu::new(work_tree_id, editor.downgrade(), cx)));
|
||||||
let mut inlay_hints_enabled = editor.read(cx).inlay_hints_enabled();
|
let mut inlay_hints_enabled = editor.read(cx).inlay_hints_enabled();
|
||||||
let mut supports_inlay_hints = editor.read(cx).supports_inlay_hints(cx);
|
let mut supports_inlay_hints = editor.read(cx).supports_inlay_hints(cx);
|
||||||
self._inlay_hints_enabled_subscription =
|
self._inlay_hints_enabled_subscription =
|
||||||
@@ -441,6 +453,8 @@ impl ToolbarItemView for QuickActionBar {
|
|||||||
cx.notify()
|
cx.notify()
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
} else {
|
||||||
|
self.repl_menu = None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.get_toolbar_item_location()
|
self.get_toolbar_item_location()
|
||||||
|
|||||||
@@ -1,24 +1,22 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use gpui::ElementId;
|
use editor::Editor;
|
||||||
use gpui::{percentage, Animation, AnimationExt, AnyElement, Transformation, View};
|
use gpui::{percentage, Animation, AnimationExt, AnyElement, Transformation, View};
|
||||||
use picker::Picker;
|
use gpui::{ElementId, WeakView};
|
||||||
|
use project::WorktreeId;
|
||||||
use repl::{
|
use repl::{
|
||||||
components::{KernelPickerDelegate, KernelSelector},
|
components::KernelSelector, ExecutionState, JupyterSettings, Kernel, KernelSpecification,
|
||||||
worktree_id_for_editor, ExecutionState, JupyterSettings, Kernel, KernelSpecification,
|
|
||||||
KernelStatus, Session, SessionSupport,
|
KernelStatus, Session, SessionSupport,
|
||||||
};
|
};
|
||||||
use ui::{
|
use ui::{
|
||||||
prelude::*, ButtonLike, ContextMenu, IconWithIndicator, Indicator, IntoElement, PopoverMenu,
|
prelude::*, ButtonLike, ContextMenu, IconWithIndicator, Indicator, IntoElement, PopoverMenu,
|
||||||
PopoverMenuHandle, Tooltip,
|
Tooltip,
|
||||||
};
|
};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
use super::QuickActionBar;
|
|
||||||
|
|
||||||
const ZED_REPL_DOCUMENTATION: &str = "https://zed.dev/docs/repl";
|
const ZED_REPL_DOCUMENTATION: &str = "https://zed.dev/docs/repl";
|
||||||
|
|
||||||
struct ReplMenuState {
|
struct ReplSessionState {
|
||||||
tooltip: SharedString,
|
tooltip: SharedString,
|
||||||
icon: IconName,
|
icon: IconName,
|
||||||
icon_color: Color,
|
icon_color: Color,
|
||||||
@@ -31,47 +29,73 @@ struct ReplMenuState {
|
|||||||
kernel_language: SharedString,
|
kernel_language: SharedString,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QuickActionBar {
|
pub struct ReplMenu {
|
||||||
pub fn render_repl_menu(&self, cx: &mut ViewContext<Self>) -> Option<AnyElement> {
|
active_editor: WeakView<Editor>,
|
||||||
|
kernel_menu: View<KernelSelector>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReplMenu {
|
||||||
|
pub fn new(
|
||||||
|
work_tree_id: WorktreeId,
|
||||||
|
editor: WeakView<Editor>,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
kernel_menu: cx.new_view(|cx| KernelSelector::new(work_tree_id, editor.clone(), cx)),
|
||||||
|
active_editor: editor.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for ReplMenu {
|
||||||
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
if !JupyterSettings::enabled(cx) {
|
if !JupyterSettings::enabled(cx) {
|
||||||
return None;
|
return div().into_any_element();
|
||||||
}
|
}
|
||||||
|
|
||||||
let editor = self.active_editor()?;
|
let editor = self.active_editor.clone();
|
||||||
|
|
||||||
let is_local_project = editor
|
let is_local_project = editor
|
||||||
.read(cx)
|
.upgrade()
|
||||||
.workspace()
|
.as_ref()
|
||||||
.map(|workspace| workspace.read(cx).project().read(cx).is_local())
|
.map(|editor| {
|
||||||
|
editor
|
||||||
|
.read(cx)
|
||||||
|
.workspace()
|
||||||
|
.map(|workspace| workspace.read(cx).project().read(cx).is_local())
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
|
||||||
if !is_local_project {
|
if !is_local_project {
|
||||||
return None;
|
return div().into_any_element();
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_nonempty_selection = {
|
let has_nonempty_selection = {
|
||||||
editor.update(cx, |this, cx| {
|
editor
|
||||||
this.selections
|
.update(cx, |this, cx| {
|
||||||
.count()
|
this.selections
|
||||||
.ne(&0)
|
.count()
|
||||||
.then(|| {
|
.ne(&0)
|
||||||
let latest = this.selections.newest_display(cx);
|
.then(|| {
|
||||||
!latest.is_empty()
|
let latest = this.selections.newest_display(cx);
|
||||||
})
|
!latest.is_empty()
|
||||||
.unwrap_or_default()
|
})
|
||||||
})
|
.unwrap_or_default()
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let session = repl::session(editor.downgrade(), cx);
|
let session = repl::session(editor.clone(), cx);
|
||||||
let session = match session {
|
let session = match session {
|
||||||
SessionSupport::ActiveSession(session) => session,
|
SessionSupport::ActiveSession(session) => session,
|
||||||
SessionSupport::Inactive(spec) => {
|
SessionSupport::Inactive(spec) => {
|
||||||
return self.render_repl_launch_menu(spec, cx);
|
return self.render_repl_launch_menu(spec, cx).into_any_element();
|
||||||
}
|
}
|
||||||
SessionSupport::RequiresSetup(language) => {
|
SessionSupport::RequiresSetup(language) => {
|
||||||
return self.render_repl_setup(&language.0, cx);
|
return self.render_repl_setup(&language.0, cx).into_any_element();
|
||||||
}
|
}
|
||||||
SessionSupport::Unsupported => return None,
|
SessionSupport::Unsupported => return div().into_any_element(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let menu_state = session_state(session.clone(), cx);
|
let menu_state = session_state(session.clone(), cx);
|
||||||
@@ -80,7 +104,7 @@ impl QuickActionBar {
|
|||||||
|
|
||||||
let element_id = |suffix| ElementId::Name(format!("{}-{}", id, suffix).into());
|
let element_id = |suffix| ElementId::Name(format!("{}-{}", id, suffix).into());
|
||||||
|
|
||||||
let editor = editor.downgrade();
|
let editor = editor.clone();
|
||||||
let dropdown_menu = PopoverMenu::new(element_id("menu"))
|
let dropdown_menu = PopoverMenu::new(element_id("menu"))
|
||||||
.menu(move |cx| {
|
.menu(move |cx| {
|
||||||
let editor = editor.clone();
|
let editor = editor.clone();
|
||||||
@@ -245,138 +269,85 @@ impl QuickActionBar {
|
|||||||
.on_click(|_, cx| cx.dispatch_action(Box::new(repl::Run {})))
|
.on_click(|_, cx| cx.dispatch_action(Box::new(repl::Run {})))
|
||||||
.into_any_element();
|
.into_any_element();
|
||||||
|
|
||||||
Some(
|
h_flex()
|
||||||
h_flex()
|
.child(self.kernel_menu.clone())
|
||||||
.child(self.render_kernel_selector(cx))
|
.child(button)
|
||||||
.child(button)
|
.child(dropdown_menu)
|
||||||
.child(dropdown_menu)
|
.into_any_element()
|
||||||
.into_any_element(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
pub fn render_repl_launch_menu(
|
|
||||||
&self,
|
|
||||||
kernel_specification: KernelSpecification,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) -> Option<AnyElement> {
|
|
||||||
let tooltip: SharedString =
|
|
||||||
SharedString::from(format!("Start REPL for {}", kernel_specification.name()));
|
|
||||||
|
|
||||||
Some(
|
|
||||||
h_flex()
|
|
||||||
.child(self.render_kernel_selector(cx))
|
|
||||||
.child(
|
|
||||||
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.dispatch_action(Box::new(repl::Run {}))),
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_kernel_selector(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
|
||||||
let editor = if let Some(editor) = self.active_editor() {
|
|
||||||
editor
|
|
||||||
} else {
|
|
||||||
return div().into_any_element();
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(worktree_id) = worktree_id_for_editor(editor.downgrade(), cx) else {
|
|
||||||
return div().into_any_element();
|
|
||||||
};
|
|
||||||
|
|
||||||
let session = repl::session(editor.downgrade(), cx);
|
|
||||||
|
|
||||||
let current_kernelspec = match session {
|
|
||||||
SessionSupport::ActiveSession(view) => Some(view.read(cx).kernel_specification.clone()),
|
|
||||||
SessionSupport::Inactive(kernel_specification) => Some(kernel_specification),
|
|
||||||
SessionSupport::RequiresSetup(_language_name) => None,
|
|
||||||
SessionSupport::Unsupported => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let current_kernel_name = current_kernelspec.as_ref().map(|spec| spec.name());
|
|
||||||
|
|
||||||
let menu_handle: PopoverMenuHandle<Picker<KernelPickerDelegate>> =
|
|
||||||
PopoverMenuHandle::default();
|
|
||||||
KernelSelector::new(
|
|
||||||
{
|
|
||||||
Box::new(move |kernelspec, cx| {
|
|
||||||
repl::assign_kernelspec(kernelspec, editor.downgrade(), cx).ok();
|
|
||||||
})
|
|
||||||
},
|
|
||||||
worktree_id,
|
|
||||||
ButtonLike::new("kernel-selector")
|
|
||||||
.style(ButtonStyle::Subtle)
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.w_full()
|
|
||||||
.gap_0p5()
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.overflow_x_hidden()
|
|
||||||
.flex_grow()
|
|
||||||
.whitespace_nowrap()
|
|
||||||
.child(
|
|
||||||
Label::new(if let Some(name) = current_kernel_name {
|
|
||||||
name
|
|
||||||
} else {
|
|
||||||
SharedString::from("Select Kernel")
|
|
||||||
})
|
|
||||||
.size(LabelSize::Small)
|
|
||||||
.color(if current_kernelspec.is_some() {
|
|
||||||
Color::Default
|
|
||||||
} else {
|
|
||||||
Color::Placeholder
|
|
||||||
})
|
|
||||||
.into_any_element(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
Icon::new(IconName::ChevronDown)
|
|
||||||
.color(Color::Muted)
|
|
||||||
.size(IconSize::XSmall),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.tooltip(move |cx| Tooltip::text("Select Kernel", cx)),
|
|
||||||
)
|
|
||||||
.with_handle(menu_handle.clone())
|
|
||||||
.into_any_element()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_repl_setup(
|
|
||||||
&self,
|
|
||||||
language: &str,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) -> Option<AnyElement> {
|
|
||||||
let tooltip: SharedString = SharedString::from(format!("Setup Zed REPL for {}", language));
|
|
||||||
Some(
|
|
||||||
h_flex()
|
|
||||||
.child(self.render_kernel_selector(cx))
|
|
||||||
.child(
|
|
||||||
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(&format!("{}#installation", ZED_REPL_DOCUMENTATION))
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.into_any_element(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn session_state(session: View<Session>, cx: &WindowContext) -> ReplMenuState {
|
impl ReplMenu {
|
||||||
|
pub fn render_repl_launch_menu(
|
||||||
|
&self,
|
||||||
|
kernel_specification: KernelSpecification,
|
||||||
|
_cx: &mut ViewContext<Self>,
|
||||||
|
) -> impl IntoElement {
|
||||||
|
let tooltip: SharedString =
|
||||||
|
SharedString::from(format!("Start REPL for {}", kernel_specification.name()));
|
||||||
|
|
||||||
|
h_flex().child(self.kernel_menu.clone()).child(
|
||||||
|
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.dispatch_action(Box::new(repl::Run {}))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_repl_setup(&self, language: &str, _cx: &mut ViewContext<Self>) -> AnyElement {
|
||||||
|
let tooltip: SharedString = SharedString::from(format!("Setup Zed REPL for {}", language));
|
||||||
|
h_flex()
|
||||||
|
.child(self.kernel_menu.clone())
|
||||||
|
.child(
|
||||||
|
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(&format!("{}#installation", ZED_REPL_DOCUMENTATION))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct KernelMenu {
|
||||||
|
// menu_handle: PopoverMenuHandle<Picker<KernelPickerDelegate>>,
|
||||||
|
// editor: WeakView<Editor>,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl KernelMenu {
|
||||||
|
// pub fn new(editor: WeakView<Editor>, cx: &mut ViewContext<Self>) -> Self {
|
||||||
|
|
||||||
|
// Self {
|
||||||
|
// editor,
|
||||||
|
// menu_handle,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// impl Render for KernelMenu {
|
||||||
|
// fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
|
// let Some(worktree_id) = worktree_id_for_editor(self.editor.clone(), cx) else {
|
||||||
|
// return div().into_any_element();
|
||||||
|
// };
|
||||||
|
|
||||||
|
// KernelSelector::new(self.editor.clone(), worktree_id)
|
||||||
|
// .with_handle(self.menu_handle.clone())
|
||||||
|
// .into_any_element()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn session_state(session: View<Session>, cx: &WindowContext) -> ReplSessionState {
|
||||||
let session = session.read(cx);
|
let session = session.read(cx);
|
||||||
|
|
||||||
let kernel_name = session.kernel_specification.name();
|
let kernel_name = session.kernel_specification.name();
|
||||||
let kernel_language: SharedString = session.kernel_specification.language();
|
let kernel_language: SharedString = session.kernel_specification.language();
|
||||||
|
|
||||||
let fill_fields = || {
|
let fill_fields = || {
|
||||||
ReplMenuState {
|
ReplSessionState {
|
||||||
tooltip: "Nothing running".into(),
|
tooltip: "Nothing running".into(),
|
||||||
icon: IconName::ReplNeutral,
|
icon: IconName::ReplNeutral,
|
||||||
icon_color: Color::Default,
|
icon_color: Color::Default,
|
||||||
@@ -392,7 +363,7 @@ fn session_state(session: View<Session>, cx: &WindowContext) -> ReplMenuState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match &session.kernel {
|
match &session.kernel {
|
||||||
Kernel::Restarting => ReplMenuState {
|
Kernel::Restarting => ReplSessionState {
|
||||||
tooltip: format!("Restarting {}", kernel_name).into(),
|
tooltip: format!("Restarting {}", kernel_name).into(),
|
||||||
icon_is_animating: true,
|
icon_is_animating: true,
|
||||||
popover_disabled: true,
|
popover_disabled: true,
|
||||||
@@ -402,13 +373,13 @@ fn session_state(session: View<Session>, cx: &WindowContext) -> ReplMenuState {
|
|||||||
..fill_fields()
|
..fill_fields()
|
||||||
},
|
},
|
||||||
Kernel::RunningKernel(kernel) => match &kernel.execution_state() {
|
Kernel::RunningKernel(kernel) => match &kernel.execution_state() {
|
||||||
ExecutionState::Idle => ReplMenuState {
|
ExecutionState::Idle => ReplSessionState {
|
||||||
tooltip: format!("Run code on {} ({})", kernel_name, kernel_language).into(),
|
tooltip: format!("Run code on {} ({})", kernel_name, kernel_language).into(),
|
||||||
indicator: Some(Indicator::dot().color(Color::Success)),
|
indicator: Some(Indicator::dot().color(Color::Success)),
|
||||||
status: session.kernel.status(),
|
status: session.kernel.status(),
|
||||||
..fill_fields()
|
..fill_fields()
|
||||||
},
|
},
|
||||||
ExecutionState::Busy => ReplMenuState {
|
ExecutionState::Busy => ReplSessionState {
|
||||||
tooltip: format!("Interrupt {} ({})", kernel_name, kernel_language).into(),
|
tooltip: format!("Interrupt {} ({})", kernel_name, kernel_language).into(),
|
||||||
icon_is_animating: true,
|
icon_is_animating: true,
|
||||||
popover_disabled: false,
|
popover_disabled: false,
|
||||||
@@ -417,7 +388,7 @@ fn session_state(session: View<Session>, cx: &WindowContext) -> ReplMenuState {
|
|||||||
..fill_fields()
|
..fill_fields()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Kernel::StartingKernel(_) => ReplMenuState {
|
Kernel::StartingKernel(_) => ReplSessionState {
|
||||||
tooltip: format!("{} is starting", kernel_name).into(),
|
tooltip: format!("{} is starting", kernel_name).into(),
|
||||||
icon_is_animating: true,
|
icon_is_animating: true,
|
||||||
popover_disabled: true,
|
popover_disabled: true,
|
||||||
@@ -426,14 +397,14 @@ fn session_state(session: View<Session>, cx: &WindowContext) -> ReplMenuState {
|
|||||||
status: session.kernel.status(),
|
status: session.kernel.status(),
|
||||||
..fill_fields()
|
..fill_fields()
|
||||||
},
|
},
|
||||||
Kernel::ErroredLaunch(e) => ReplMenuState {
|
Kernel::ErroredLaunch(e) => ReplSessionState {
|
||||||
tooltip: format!("Error with kernel {}: {}", kernel_name, e).into(),
|
tooltip: format!("Error with kernel {}: {}", kernel_name, e).into(),
|
||||||
popover_disabled: false,
|
popover_disabled: false,
|
||||||
indicator: Some(Indicator::dot().color(Color::Error)),
|
indicator: Some(Indicator::dot().color(Color::Error)),
|
||||||
status: session.kernel.status(),
|
status: session.kernel.status(),
|
||||||
..fill_fields()
|
..fill_fields()
|
||||||
},
|
},
|
||||||
Kernel::ShuttingDown => ReplMenuState {
|
Kernel::ShuttingDown => ReplSessionState {
|
||||||
tooltip: format!("{} is shutting down", kernel_name).into(),
|
tooltip: format!("{} is shutting down", kernel_name).into(),
|
||||||
popover_disabled: true,
|
popover_disabled: true,
|
||||||
icon_color: Color::Muted,
|
icon_color: Color::Muted,
|
||||||
@@ -441,7 +412,7 @@ fn session_state(session: View<Session>, cx: &WindowContext) -> ReplMenuState {
|
|||||||
status: session.kernel.status(),
|
status: session.kernel.status(),
|
||||||
..fill_fields()
|
..fill_fields()
|
||||||
},
|
},
|
||||||
Kernel::Shutdown => ReplMenuState {
|
Kernel::Shutdown => ReplSessionState {
|
||||||
tooltip: "Nothing running".into(),
|
tooltip: "Nothing running".into(),
|
||||||
icon: IconName::ReplNeutral,
|
icon: IconName::ReplNeutral,
|
||||||
icon_color: Color::Default,
|
icon_color: Color::Default,
|
||||||
|
|||||||
Reference in New Issue
Block a user