repl: Rely on block decorations to size according to content (#15713)

Kyle Kelley created

We no longer have to use line height calculations now that
https://github.com/zed-industries/zed/pull/15536 is in. Blocks resize
according to their content. This fixes up some of the rendering issues
on plaintext outputs as well.

Release Notes:

- Fix repl plain text output wrapping around and covering editor text
(https://github.com/zed-industries/zed/issues/15491,
https://github.com/zed-industries/zed/issues/14855)

Change summary

crates/repl/src/outputs.rs | 81 ---------------------------------------
crates/repl/src/session.rs |  5 +
crates/repl/src/stdio.rs   | 10 ---
3 files changed, 6 insertions(+), 90 deletions(-)

Detailed changes

crates/repl/src/outputs.rs 🔗

@@ -6,7 +6,7 @@ use anyhow::Result;
 use base64::prelude::*;
 use gpui::{
     img, percentage, Animation, AnimationExt, AnyElement, FontWeight, ImageData, Render, TextRun,
-    Transformation, View,
+    Transformation,
 };
 use runtimelib::datatable::TableSchema;
 use runtimelib::media::datatable::TabularDataResource;
@@ -16,12 +16,6 @@ use settings::Settings;
 use theme::ThemeSettings;
 use ui::{div, prelude::*, v_flex, IntoElement, Styled, ViewContext};
 
-/// Given these outputs are destined for the editor with the block decorations API, all of them must report
-/// how many lines they will take up in the editor.
-pub trait LineHeight: Sized {
-    fn num_lines(&self, cx: &mut WindowContext) -> usize;
-}
-
 /// When deciding what to render from a collection of mediatypes, we need to rank them in order of importance
 fn rank_mime_type(mimetype: &MimeType) -> usize {
     match mimetype {
@@ -87,13 +81,6 @@ impl ImageView {
     }
 }
 
-impl LineHeight for ImageView {
-    fn num_lines(&self, cx: &mut WindowContext) -> usize {
-        let line_height = cx.line_height();
-        (self.height as f32 / line_height.0) as usize
-    }
-}
-
 /// TableView renders a static table inline in a buffer.
 /// It uses the https://specs.frictionlessdata.io/tabular-data-resource/ specification for data interchange.
 pub struct TableView {
@@ -250,21 +237,6 @@ impl TableView {
     }
 }
 
-impl LineHeight for TableView {
-    fn num_lines(&self, _cx: &mut WindowContext) -> usize {
-        let num_rows = match &self.table.data {
-            // Rows + header
-            Some(data) => data.len() + 1,
-            // We don't support Path based data sources, however we
-            // still render the header and padding
-            None => 1 + 1,
-        };
-
-        let num_lines = num_rows as f32 * (1.0 + TABLE_Y_PADDING_MULTIPLE) + 1.0;
-        num_lines.ceil() as usize
-    }
-}
-
 /// Userspace error from the kernel
 pub struct ErrorView {
     pub ename: String,
@@ -296,13 +268,6 @@ impl ErrorView {
     }
 }
 
-impl LineHeight for ErrorView {
-    fn num_lines(&self, cx: &mut WindowContext) -> usize {
-        // Start at 1 to account for the y padding
-        1 + self.ename.lines().count() + self.evalue.lines().count() + self.traceback.num_lines(cx)
-    }
-}
-
 pub enum OutputType {
     Plain(TerminalOutput),
     Stream(TerminalOutput),
@@ -346,21 +311,6 @@ impl OutputType {
     }
 }
 
-impl LineHeight for OutputType {
-    /// Calculates the expected number of lines
-    fn num_lines(&self, cx: &mut WindowContext) -> usize {
-        match self {
-            Self::Plain(stdio) => stdio.num_lines(cx),
-            Self::Stream(stdio) => stdio.num_lines(cx),
-            Self::Image(image) => image.num_lines(cx),
-            Self::Message(message) => message.lines().count(),
-            Self::Table(table) => table.num_lines(cx),
-            Self::ErrorOutput(error_view) => error_view.num_lines(cx),
-            Self::ClearOutputWaitMarker => 0,
-        }
-    }
-}
-
 #[derive(Default, Clone, Debug)]
 pub enum ExecutionStatus {
     #[default]
@@ -561,32 +511,3 @@ impl Render for ExecutionView {
             .into_any_element()
     }
 }
-
-impl LineHeight for ExecutionView {
-    fn num_lines(&self, cx: &mut WindowContext) -> usize {
-        if self.outputs.is_empty() {
-            return 1; // For the status message if outputs are not there
-        }
-
-        let num_lines = self
-            .outputs
-            .iter()
-            .map(|output| output.num_lines(cx))
-            .sum::<usize>()
-            .max(1);
-
-        let num_lines = match self.status {
-            // Account for the status message if the execution is still ongoing
-            ExecutionStatus::Executing => num_lines.saturating_add(1),
-            ExecutionStatus::Queued => num_lines.saturating_add(1),
-            _ => num_lines,
-        };
-        num_lines
-    }
-}
-
-impl LineHeight for View<ExecutionView> {
-    fn num_lines(&self, cx: &mut WindowContext) -> usize {
-        self.update(cx, |execution_view, cx| execution_view.num_lines(cx))
-    }
-}

crates/repl/src/session.rs 🔗

@@ -2,7 +2,7 @@ use crate::components::KernelListItem;
 use crate::KernelStatus;
 use crate::{
     kernels::{Kernel, KernelSpecification, RunningKernel},
-    outputs::{ExecutionStatus, ExecutionView, LineHeight as _},
+    outputs::{ExecutionStatus, ExecutionView},
 };
 use client::telemetry::Telemetry;
 use collections::{HashMap, HashSet};
@@ -82,7 +82,8 @@ impl EditorBlock {
             let invalidation_anchor = buffer.read(cx).read(cx).anchor_before(next_row_start);
             let block = BlockProperties {
                 position: code_range.end,
-                height: (execution_view.num_lines(cx) + 1) as u32,
+                // Take up at least one height for status, allow the editor to determine the real height based on the content from render
+                height: 1,
                 style: BlockStyle::Sticky,
                 render: Self::create_output_area_renderer(execution_view.clone(), on_close.clone()),
                 disposition: BlockDisposition::Below,

crates/repl/src/stdio.rs 🔗

@@ -1,4 +1,4 @@
-use crate::outputs::{ExecutionView, LineHeight};
+use crate::outputs::ExecutionView;
 use alacritty_terminal::vte::{
     ansi::{Attr, Color, NamedColor, Rgb},
     Params, ParamsIter, Parser, Perform,
@@ -7,7 +7,7 @@ use core::iter;
 use gpui::{font, prelude::*, AnyElement, StyledText, TextRun};
 use settings::Settings as _;
 use theme::ThemeSettings;
-use ui::{div, prelude::*, IntoElement, ViewContext, WindowContext};
+use ui::{div, prelude::*, IntoElement, ViewContext};
 
 /// Implements the most basic of terminal output for use by Jupyter outputs
 /// whether:
@@ -95,12 +95,6 @@ impl TerminalOutput {
     }
 }
 
-impl LineHeight for TerminalOutput {
-    fn num_lines(&self, _cx: &mut WindowContext) -> usize {
-        self.handler.buffer.lines().count().max(1)
-    }
-}
-
 #[derive(Clone, Default)]
 struct AnsiTextRun {
     len: usize,