diff --git a/crates/repl/src/outputs.rs b/crates/repl/src/outputs.rs index 4182a5b4b6..c3e54385ac 100644 --- a/crates/repl/src/outputs.rs +++ b/crates/repl/src/outputs.rs @@ -250,7 +250,7 @@ pub struct ErrorView { } impl ErrorView { - fn render(&self, cx: &ViewContext) -> Option { + fn render(&self, cx: &mut ViewContext) -> Option { let theme = cx.theme(); let padding = cx.line_height() / 2.; @@ -358,7 +358,7 @@ pub enum OutputContent { } impl OutputContent { - fn render(&self, cx: &ViewContext) -> Option { + fn render(&self, cx: &mut ViewContext) -> Option { let el = match self { // Note: in typical frontends we would show the execute_result.execution_count // Here we can just handle either diff --git a/crates/repl/src/session.rs b/crates/repl/src/session.rs index ba1d70020c..baf7325ae8 100644 --- a/crates/repl/src/session.rs +++ b/crates/repl/src/session.rs @@ -1,9 +1,9 @@ use crate::components::KernelListItem; -use crate::KernelStatus; use crate::{ kernels::{Kernel, KernelSpecification, RunningKernel}, outputs::{ExecutionStatus, ExecutionView}, }; +use crate::{stdio, KernelStatus}; use client::telemetry::Telemetry; use collections::{HashMap, HashSet}; use editor::{ @@ -26,9 +26,8 @@ use runtimelib::{ ExecuteRequest, ExecutionState, InterruptRequest, JupyterMessage, JupyterMessageContent, ShutdownRequest, }; -use settings::Settings as _; use std::{env::temp_dir, ops::Range, sync::Arc, time::Duration}; -use theme::{ActiveTheme, ThemeSettings}; +use theme::ActiveTheme; use ui::{prelude::*, IconButtonShape, Tooltip}; pub struct Session { @@ -114,68 +113,68 @@ impl EditorBlock { ) -> RenderBlock { let render = move |cx: &mut BlockContext| { let execution_view = execution_view.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_style = stdio::text_style(cx); let gutter = cx.gutter_dimensions; - let close_button_size = IconSize::XSmall; 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); + let text_line_height = text_style.line_height_in_pixels(rem_size); + + let close_button = h_flex() + .flex_none() + .items_center() + .justify_center() + .absolute() + .top(text_line_height / 2.) + .right( + // 2px is a magic number to nudge the button just a bit closer to + // the line number start + gutter.full_width() / 2.0 - text_line_height / 2.0 - px(2.), + ) + .w(text_line_height) + .h(text_line_height) + .child( + IconButton::new( + ("close_output_area", EntityId::from(cx.block_id)), + IconName::Close, + ) + .icon_size(IconSize::Small) + .icon_color(Color::Muted) + .size(ButtonSize::Compact) + .shape(IconButtonShape::Square) + .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) + } + }), + ); div() - .min_h(line_height) .flex() - .flex_row() .items_start() + .min_h(text_line_height) .w_full() - .bg(cx.theme().colors().background) .border_y_1() .border_color(cx.theme().colors().border) + .bg(cx.theme().colors().background) .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) - } - }, - ), - ), - ), - ), + div() + .relative() + .w(gutter.full_width()) + .h(text_line_height * 2) + .child(close_button), ) .child( div() .flex_1() .size_full() - .my_2() + .py(text_line_height / 2.) .mr(gutter.width) - .text_size(text_font_size) - .font_family(text_font) .child(execution_view), ) .into_any_element() diff --git a/crates/repl/src/stdio.rs b/crates/repl/src/stdio.rs index 2be0bfa2a7..9bbd07a2ac 100644 --- a/crates/repl/src/stdio.rs +++ b/crates/repl/src/stdio.rs @@ -1,9 +1,11 @@ use crate::outputs::ExecutionView; use alacritty_terminal::{term::Config, vte::ansi::Processor}; -use gpui::{canvas, size, AnyElement}; +use gpui::{canvas, size, AnyElement, FontStyle, TextStyle, WhiteSpace}; +use settings::Settings as _; use std::mem; use terminal::ZedListener; use terminal_view::terminal_element::TerminalElement; +use theme::ThemeSettings; use ui::{prelude::*, IntoElement, ViewContext}; /// Implements the most basic of terminal output for use by Jupyter outputs @@ -22,8 +24,38 @@ pub struct TerminalOutput { const DEFAULT_NUM_LINES: usize = 32; const DEFAULT_NUM_COLUMNS: usize = 128; +pub fn text_style(cx: &mut WindowContext) -> TextStyle { + let settings = ThemeSettings::get_global(cx).clone(); + + let font_family = settings.buffer_font.family; + let font_features = settings.buffer_font.features; + let font_weight = settings.buffer_font.weight; + let font_fallbacks = settings.buffer_font.fallbacks; + + let theme = cx.theme(); + + let text_style = TextStyle { + font_family, + font_features, + font_weight, + font_fallbacks, + font_size: theme::get_buffer_font_size(cx).into(), + font_style: FontStyle::Normal, + // todo + line_height: cx.line_height().into(), + background_color: Some(theme.colors().terminal_background), + white_space: WhiteSpace::Normal, + // These are going to be overridden per-cell + underline: None, + strikethrough: None, + color: theme.colors().terminal_foreground, + }; + + text_style +} + pub fn terminal_size(cx: &mut WindowContext) -> terminal::TerminalSize { - let text_style = cx.text_style(); + let text_style = text_style(cx); let text_system = cx.text_system(); let line_height = cx.line_height(); @@ -86,8 +118,8 @@ impl TerminalOutput { } } - pub fn render(&self, cx: &ViewContext) -> AnyElement { - let text_style = cx.text_style(); + pub fn render(&self, cx: &mut ViewContext) -> AnyElement { + let text_style = text_style(cx); let text_system = cx.text_system(); let grid = self @@ -101,10 +133,9 @@ impl TerminalOutput { let (cells, rects) = TerminalElement::layout_grid(grid, &text_style, text_system, None, cx); // lines are 0-indexed, so we must add 1 to get the number of lines + let text_line_height = text_style.line_height_in_pixels(cx.rem_size()); let num_lines = cells.iter().map(|c| c.point.line).max().unwrap_or(0) + 1; - let height = num_lines as f32 * cx.line_height(); - - let line_height = cx.line_height(); + let height = num_lines as f32 * text_line_height; let font_pixels = text_style.font_size.to_pixels(cx.rem_size()); let font_id = text_system.resolve_font(&text_style.font()); @@ -124,7 +155,7 @@ impl TerminalOutput { bounds.origin, &terminal::TerminalSize { cell_width, - line_height, + line_height: text_line_height, size: bounds.size, }, cx, @@ -136,7 +167,7 @@ impl TerminalOutput { bounds.origin, &terminal::TerminalSize { cell_width, - line_height, + line_height: text_line_height, size: bounds.size, }, bounds,