Extract outline rendering to `outline` crate (#20179)

Marshall Bowers created

This PR extracts the `render_item` implementation for outlines to the
`outline` crate to help reduce `language`'s dependence on `theme`.

Release Notes:

- N/A

Change summary

Cargo.lock                                |  2 
crates/language/src/outline.rs            | 40 ----------------
crates/outline/Cargo.toml                 |  1 
crates/outline/src/outline.rs             | 59 ++++++++++++++++++++----
crates/outline_panel/Cargo.toml           |  1 
crates/outline_panel/src/outline_panel.rs |  4 
6 files changed, 56 insertions(+), 51 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -7795,6 +7795,7 @@ dependencies = [
  "project",
  "rope",
  "serde_json",
+ "settings",
  "smol",
  "theme",
  "tree-sitter-rust",
@@ -7819,6 +7820,7 @@ dependencies = [
  "language",
  "log",
  "menu",
+ "outline",
  "pretty_assertions",
  "project",
  "schemars",

crates/language/src/outline.rs 🔗

@@ -1,9 +1,7 @@
 use crate::{BufferSnapshot, Point, ToPoint};
 use fuzzy::{StringMatch, StringMatchCandidate};
-use gpui::{relative, AppContext, BackgroundExecutor, HighlightStyle, StyledText, TextStyle};
-use settings::Settings;
+use gpui::{BackgroundExecutor, HighlightStyle};
 use std::ops::Range;
-use theme::{color_alpha, ActiveTheme, ThemeSettings};
 
 /// An outline of all the symbols contained in a buffer.
 #[derive(Debug)]
@@ -193,42 +191,6 @@ impl<T> Outline<T> {
     }
 }
 
-pub fn render_item<T>(
-    outline_item: &OutlineItem<T>,
-    match_ranges: impl IntoIterator<Item = Range<usize>>,
-    cx: &AppContext,
-) -> StyledText {
-    let highlight_style = HighlightStyle {
-        background_color: Some(color_alpha(cx.theme().colors().text_accent, 0.3)),
-        ..Default::default()
-    };
-    let custom_highlights = match_ranges
-        .into_iter()
-        .map(|range| (range, highlight_style));
-
-    let settings = ThemeSettings::get_global(cx);
-
-    // TODO: We probably shouldn't need to build a whole new text style here
-    // but I'm not sure how to get the current one and modify it.
-    // Before this change TextStyle::default() was used here, which was giving us the wrong font and text color.
-    let text_style = TextStyle {
-        color: cx.theme().colors().text,
-        font_family: settings.buffer_font.family.clone(),
-        font_features: settings.buffer_font.features.clone(),
-        font_fallbacks: settings.buffer_font.fallbacks.clone(),
-        font_size: settings.buffer_font_size(cx).into(),
-        font_weight: settings.buffer_font.weight,
-        line_height: relative(1.),
-        ..Default::default()
-    };
-    let highlights = gpui::combine_highlights(
-        custom_highlights,
-        outline_item.highlight_ranges.iter().cloned(),
-    );
-
-    StyledText::new(outline_item.text.clone()).with_highlights(&text_style, highlights)
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;

crates/outline/Cargo.toml 🔗

@@ -19,6 +19,7 @@ gpui.workspace = true
 language.workspace = true
 ordered-float.workspace = true
 picker.workspace = true
+settings.workspace = true
 smol.workspace = true
 theme.workspace = true
 ui.workspace = true

crates/outline/src/outline.rs 🔗

@@ -1,20 +1,23 @@
+use std::ops::Range;
+use std::{
+    cmp::{self, Reverse},
+    sync::Arc,
+};
+
 use editor::{
     actions::ToggleOutline, scroll::Autoscroll, Anchor, AnchorRangeExt, Editor, EditorMode,
 };
 use fuzzy::StringMatch;
 use gpui::{
-    div, rems, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, ParentElement,
-    Point, Render, Styled, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
+    div, rems, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, HighlightStyle,
+    ParentElement, Point, Render, Styled, StyledText, Task, TextStyle, View, ViewContext,
+    VisualContext, WeakView, WindowContext,
 };
-use language::Outline;
+use language::{Outline, OutlineItem};
 use ordered_float::OrderedFloat;
 use picker::{Picker, PickerDelegate};
-use std::{
-    cmp::{self, Reverse},
-    sync::Arc,
-};
-
-use theme::ActiveTheme;
+use settings::Settings;
+use theme::{color_alpha, ActiveTheme, ThemeSettings};
 use ui::{prelude::*, ListItem, ListItemSpacing};
 use util::ResultExt;
 use workspace::{DismissDecision, ModalView};
@@ -282,12 +285,48 @@ impl PickerDelegate for OutlineViewDelegate {
                     div()
                         .text_ui(cx)
                         .pl(rems(outline_item.depth as f32))
-                        .child(language::render_item(outline_item, mat.ranges(), cx)),
+                        .child(render_item(outline_item, mat.ranges(), cx)),
                 ),
         )
     }
 }
 
+pub fn render_item<T>(
+    outline_item: &OutlineItem<T>,
+    match_ranges: impl IntoIterator<Item = Range<usize>>,
+    cx: &AppContext,
+) -> StyledText {
+    let highlight_style = HighlightStyle {
+        background_color: Some(color_alpha(cx.theme().colors().text_accent, 0.3)),
+        ..Default::default()
+    };
+    let custom_highlights = match_ranges
+        .into_iter()
+        .map(|range| (range, highlight_style));
+
+    let settings = ThemeSettings::get_global(cx);
+
+    // TODO: We probably shouldn't need to build a whole new text style here
+    // but I'm not sure how to get the current one and modify it.
+    // Before this change TextStyle::default() was used here, which was giving us the wrong font and text color.
+    let text_style = TextStyle {
+        color: cx.theme().colors().text,
+        font_family: settings.buffer_font.family.clone(),
+        font_features: settings.buffer_font.features.clone(),
+        font_fallbacks: settings.buffer_font.fallbacks.clone(),
+        font_size: settings.buffer_font_size(cx).into(),
+        font_weight: settings.buffer_font.weight,
+        line_height: relative(1.),
+        ..Default::default()
+    };
+    let highlights = gpui::combine_highlights(
+        custom_highlights,
+        outline_item.highlight_ranges.iter().cloned(),
+    );
+
+    StyledText::new(outline_item.text.clone()).with_highlights(&text_style, highlights)
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;

crates/outline_panel/Cargo.toml 🔗

@@ -24,6 +24,7 @@ gpui.workspace = true
 language.workspace = true
 log.workspace = true
 menu.workspace = true
+outline.workspace = true
 project.workspace = true
 schemars.workspace = true
 search.workspace = true

crates/outline_panel/src/outline_panel.rs 🔗

@@ -1672,7 +1672,7 @@ impl OutlinePanel {
                 "{buffer_id:?}|{excerpt_id:?}{:?}|{:?}",
                 rendered_outline.range, &rendered_outline.text,
             ))),
-            language::render_item(
+            outline::render_item(
                 rendered_outline,
                 string_match
                     .map(|string_match| string_match.ranges().collect::<Vec<_>>())
@@ -1911,7 +1911,7 @@ impl OutlinePanel {
         } else {
             &search_matches
         };
-        let label_element = language::render_item(
+        let label_element = outline::render_item(
             &OutlineItem {
                 depth,
                 annotation_range: None,