mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
repl: Push button to clear outputs (#14873)
This commit is contained in:
parent
a1670551bf
commit
6dfb0a4a70
@ -503,29 +503,38 @@ impl ExecutionView {
|
|||||||
impl Render for ExecutionView {
|
impl Render for ExecutionView {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
if self.outputs.len() == 0 {
|
if self.outputs.len() == 0 {
|
||||||
return match &self.status {
|
return v_flex()
|
||||||
ExecutionStatus::ConnectingToKernel => {
|
.min_h(cx.line_height())
|
||||||
div().child(Label::new("Connecting to kernel...").color(Color::Muted))
|
.justify_center()
|
||||||
}
|
.child(match &self.status {
|
||||||
ExecutionStatus::Executing => {
|
ExecutionStatus::ConnectingToKernel => Label::new("Connecting to kernel...")
|
||||||
div().child(Label::new("Executing...").color(Color::Muted))
|
.color(Color::Muted)
|
||||||
}
|
.into_any_element(),
|
||||||
ExecutionStatus::Finished => div().child(Icon::new(IconName::Check)),
|
ExecutionStatus::Executing => Label::new("Executing...")
|
||||||
ExecutionStatus::Unknown => {
|
.color(Color::Muted)
|
||||||
div().child(div().child(Label::new("Unknown status").color(Color::Muted)))
|
.into_any_element(),
|
||||||
}
|
ExecutionStatus::Finished => Icon::new(IconName::Check)
|
||||||
ExecutionStatus::ShuttingDown => {
|
.size(IconSize::Small)
|
||||||
div().child(Label::new("Kernel shutting down...").color(Color::Muted))
|
.into_any_element(),
|
||||||
}
|
ExecutionStatus::Unknown => Label::new("Unknown status")
|
||||||
ExecutionStatus::Shutdown => {
|
.color(Color::Muted)
|
||||||
div().child(Label::new("Kernel shutdown").color(Color::Muted))
|
.into_any_element(),
|
||||||
}
|
ExecutionStatus::ShuttingDown => Label::new("Kernel shutting down...")
|
||||||
ExecutionStatus::Queued => div().child(Label::new("Queued").color(Color::Muted)),
|
.color(Color::Muted)
|
||||||
ExecutionStatus::KernelErrored(error) => {
|
.into_any_element(),
|
||||||
div().child(Label::new(format!("Kernel error: {}", error)).color(Color::Error))
|
ExecutionStatus::Shutdown => Label::new("Kernel shutdown")
|
||||||
}
|
.color(Color::Muted)
|
||||||
}
|
.into_any_element(),
|
||||||
.into_any_element();
|
ExecutionStatus::Queued => {
|
||||||
|
Label::new("Queued").color(Color::Muted).into_any_element()
|
||||||
|
}
|
||||||
|
ExecutionStatus::KernelErrored(error) => {
|
||||||
|
Label::new(format!("Kernel error: {}", error))
|
||||||
|
.color(Color::Error)
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into_any_element();
|
||||||
}
|
}
|
||||||
|
|
||||||
div()
|
div()
|
||||||
|
@ -5,14 +5,16 @@ use crate::{
|
|||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use editor::{
|
use editor::{
|
||||||
display_map::{
|
display_map::{
|
||||||
BlockContext, BlockDisposition, BlockProperties, BlockStyle, CustomBlockId, RenderBlock,
|
BlockContext, BlockDisposition, BlockId, BlockProperties, BlockStyle, CustomBlockId,
|
||||||
|
RenderBlock,
|
||||||
},
|
},
|
||||||
scroll::Autoscroll,
|
scroll::Autoscroll,
|
||||||
Anchor, AnchorRangeExt as _, Editor, MultiBuffer, ToPoint,
|
Anchor, AnchorRangeExt as _, Editor, MultiBuffer, ToPoint,
|
||||||
};
|
};
|
||||||
use futures::{FutureExt as _, StreamExt as _};
|
use futures::{FutureExt as _, StreamExt as _};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::*, EventEmitter, Model, Render, Subscription, Task, View, ViewContext, WeakView,
|
div, prelude::*, EntityId, EventEmitter, Model, Render, Subscription, Task, View, ViewContext,
|
||||||
|
WeakView,
|
||||||
};
|
};
|
||||||
use language::Point;
|
use language::Point;
|
||||||
use project::Fs;
|
use project::Fs;
|
||||||
@ -22,7 +24,7 @@ use runtimelib::{
|
|||||||
use settings::Settings as _;
|
use settings::Settings as _;
|
||||||
use std::{env::temp_dir, ops::Range, path::PathBuf, sync::Arc, time::Duration};
|
use std::{env::temp_dir, ops::Range, path::PathBuf, sync::Arc, time::Duration};
|
||||||
use theme::{ActiveTheme, ThemeSettings};
|
use theme::{ActiveTheme, ThemeSettings};
|
||||||
use ui::{h_flex, prelude::*, v_flex, ButtonLike, ButtonStyle, Label};
|
use ui::{h_flex, prelude::*, v_flex, ButtonLike, ButtonStyle, IconButtonShape, Label, Tooltip};
|
||||||
|
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
pub editor: WeakView<Editor>,
|
pub editor: WeakView<Editor>,
|
||||||
@ -39,13 +41,18 @@ struct EditorBlock {
|
|||||||
invalidation_anchor: Anchor,
|
invalidation_anchor: Anchor,
|
||||||
block_id: CustomBlockId,
|
block_id: CustomBlockId,
|
||||||
execution_view: View<ExecutionView>,
|
execution_view: View<ExecutionView>,
|
||||||
|
on_close: CloseBlockFn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CloseBlockFn =
|
||||||
|
Arc<dyn for<'a> Fn(CustomBlockId, &'a mut WindowContext) + Send + Sync + 'static>;
|
||||||
|
|
||||||
impl EditorBlock {
|
impl EditorBlock {
|
||||||
fn new(
|
fn new(
|
||||||
editor: WeakView<Editor>,
|
editor: WeakView<Editor>,
|
||||||
code_range: Range<Anchor>,
|
code_range: Range<Anchor>,
|
||||||
status: ExecutionStatus,
|
status: ExecutionStatus,
|
||||||
|
on_close: CloseBlockFn,
|
||||||
cx: &mut ViewContext<Session>,
|
cx: &mut ViewContext<Session>,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let execution_view = cx.new_view(|cx| ExecutionView::new(status, cx));
|
let execution_view = cx.new_view(|cx| ExecutionView::new(status, cx));
|
||||||
@ -73,7 +80,7 @@ impl EditorBlock {
|
|||||||
position: code_range.end,
|
position: code_range.end,
|
||||||
height: execution_view.num_lines(cx).saturating_add(1),
|
height: execution_view.num_lines(cx).saturating_add(1),
|
||||||
style: BlockStyle::Sticky,
|
style: BlockStyle::Sticky,
|
||||||
render: Self::create_output_area_render(execution_view.clone()),
|
render: Self::create_output_area_render(execution_view.clone(), on_close.clone()),
|
||||||
disposition: BlockDisposition::Below,
|
disposition: BlockDisposition::Below,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -87,6 +94,7 @@ impl EditorBlock {
|
|||||||
invalidation_anchor,
|
invalidation_anchor,
|
||||||
block_id,
|
block_id,
|
||||||
execution_view,
|
execution_view,
|
||||||
|
on_close,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,11 +106,15 @@ impl EditorBlock {
|
|||||||
self.editor
|
self.editor
|
||||||
.update(cx, |editor, cx| {
|
.update(cx, |editor, cx| {
|
||||||
let mut replacements = HashMap::default();
|
let mut replacements = HashMap::default();
|
||||||
|
|
||||||
replacements.insert(
|
replacements.insert(
|
||||||
self.block_id,
|
self.block_id,
|
||||||
(
|
(
|
||||||
Some(self.execution_view.num_lines(cx).saturating_add(1)),
|
Some(self.execution_view.num_lines(cx).saturating_add(1)),
|
||||||
Self::create_output_area_render(self.execution_view.clone()),
|
Self::create_output_area_render(
|
||||||
|
self.execution_view.clone(),
|
||||||
|
self.on_close.clone(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
editor.replace_blocks(replacements, None, cx);
|
editor.replace_blocks(replacements, None, cx);
|
||||||
@ -110,31 +122,74 @@ impl EditorBlock {
|
|||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_output_area_render(execution_view: View<ExecutionView>) -> RenderBlock {
|
fn create_output_area_render(
|
||||||
|
execution_view: View<ExecutionView>,
|
||||||
|
on_close: CloseBlockFn,
|
||||||
|
) -> RenderBlock {
|
||||||
let render = move |cx: &mut BlockContext| {
|
let render = move |cx: &mut BlockContext| {
|
||||||
let execution_view = execution_view.clone();
|
let execution_view = execution_view.clone();
|
||||||
let text_font = ThemeSettings::get_global(cx).buffer_font.family.clone();
|
let text_font = ThemeSettings::get_global(cx).buffer_font.family.clone();
|
||||||
let text_font_size = ThemeSettings::get_global(cx).buffer_font_size;
|
let text_font_size = ThemeSettings::get_global(cx).buffer_font_size;
|
||||||
// Note: we'll want to use `cx.anchor_x` when someone runs something with no output -- just show a checkmark and not make the full block below the line
|
|
||||||
|
|
||||||
let gutter_width = cx.gutter_dimensions.width;
|
let gutter = cx.gutter_dimensions;
|
||||||
|
let close_button_size = IconSize::XSmall;
|
||||||
|
|
||||||
h_flex()
|
let block_id = cx.block_id;
|
||||||
|
let on_close = on_close.clone();
|
||||||
|
|
||||||
|
let rem_size = cx.rem_size();
|
||||||
|
let line_height = cx.text_style().line_height_in_pixels(rem_size);
|
||||||
|
|
||||||
|
let (close_button_width, close_button_padding) =
|
||||||
|
close_button_size.square_components(cx);
|
||||||
|
|
||||||
|
div()
|
||||||
|
.min_h(line_height)
|
||||||
|
.flex()
|
||||||
|
.flex_row()
|
||||||
|
.items_start()
|
||||||
.w_full()
|
.w_full()
|
||||||
.bg(cx.theme().colors().background)
|
.bg(cx.theme().colors().background)
|
||||||
.border_y_1()
|
.border_y_1()
|
||||||
.border_color(cx.theme().colors().border)
|
.border_color(cx.theme().colors().border)
|
||||||
.pl(gutter_width)
|
.child(
|
||||||
|
v_flex().min_h(cx.line_height()).justify_center().child(
|
||||||
|
h_flex()
|
||||||
|
.w(gutter.full_width())
|
||||||
|
.justify_end()
|
||||||
|
.pt(line_height / 2.)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.pr(gutter.width / 2. - close_button_width
|
||||||
|
+ close_button_padding / 2.)
|
||||||
|
.child(
|
||||||
|
IconButton::new(
|
||||||
|
("close_output_area", EntityId::from(cx.block_id)),
|
||||||
|
IconName::Close,
|
||||||
|
)
|
||||||
|
.shape(IconButtonShape::Square)
|
||||||
|
.icon_size(close_button_size)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.tooltip(|cx| Tooltip::text("Close output area", cx))
|
||||||
|
.on_click(
|
||||||
|
move |_, cx| {
|
||||||
|
if let BlockId::Custom(block_id) = block_id {
|
||||||
|
(on_close)(block_id, cx)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
|
.flex_1()
|
||||||
|
.size_full()
|
||||||
|
.my_2()
|
||||||
|
.mr(gutter.width)
|
||||||
.text_size(text_font_size)
|
.text_size(text_font_size)
|
||||||
.font_family(text_font)
|
.font_family(text_font)
|
||||||
// .ml(gutter_width)
|
|
||||||
.mx_1()
|
|
||||||
.my_2()
|
|
||||||
.h_full()
|
|
||||||
.w_full()
|
|
||||||
.mr(gutter_width)
|
|
||||||
.child(execution_view),
|
.child(execution_view),
|
||||||
)
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
@ -373,8 +428,30 @@ impl Session {
|
|||||||
Kernel::Shutdown => ExecutionStatus::Shutdown,
|
Kernel::Shutdown => ExecutionStatus::Shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let parent_message_id = message.header.msg_id.clone();
|
||||||
|
let session_view = cx.view().downgrade();
|
||||||
|
let weak_editor = self.editor.clone();
|
||||||
|
|
||||||
|
let on_close: CloseBlockFn =
|
||||||
|
Arc::new(move |block_id: CustomBlockId, cx: &mut WindowContext| {
|
||||||
|
if let Some(session) = session_view.upgrade() {
|
||||||
|
session.update(cx, |session, cx| {
|
||||||
|
session.blocks.remove(&parent_message_id);
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(editor) = weak_editor.upgrade() {
|
||||||
|
editor.update(cx, |editor, cx| {
|
||||||
|
let mut block_ids = HashSet::default();
|
||||||
|
block_ids.insert(block_id);
|
||||||
|
editor.remove_blocks(block_ids, None, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let editor_block = if let Ok(editor_block) =
|
let editor_block = if let Ok(editor_block) =
|
||||||
EditorBlock::new(self.editor.clone(), anchor_range, status, cx)
|
EditorBlock::new(self.editor.clone(), anchor_range, status, on_close, cx)
|
||||||
{
|
{
|
||||||
editor_block
|
editor_block
|
||||||
} else {
|
} else {
|
||||||
|
@ -76,8 +76,12 @@ impl IconSize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the length of a side of the square that contains this [`IconSize`], with padding.
|
/// Returns the individual components of the square that contains this [`IconSize`].
|
||||||
pub(crate) fn square(&self, cx: &mut WindowContext) -> Pixels {
|
///
|
||||||
|
/// The returned tuple contains:
|
||||||
|
/// 1. The length of one side of the square
|
||||||
|
/// 2. The padding of one side of the square
|
||||||
|
pub fn square_components(&self, cx: &mut WindowContext) -> (Pixels, Pixels) {
|
||||||
let icon_size = self.rems() * cx.rem_size();
|
let icon_size = self.rems() * cx.rem_size();
|
||||||
let padding = match self {
|
let padding = match self {
|
||||||
IconSize::Indicator => Spacing::None.px(cx),
|
IconSize::Indicator => Spacing::None.px(cx),
|
||||||
@ -86,6 +90,13 @@ impl IconSize {
|
|||||||
IconSize::Medium => Spacing::XSmall.px(cx),
|
IconSize::Medium => Spacing::XSmall.px(cx),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(icon_size, padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the length of a side of the square that contains this [`IconSize`], with padding.
|
||||||
|
pub fn square(&self, cx: &mut WindowContext) -> Pixels {
|
||||||
|
let (icon_size, padding) = self.square_components(cx);
|
||||||
|
|
||||||
icon_size + padding * 2.
|
icon_size + padding * 2.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user