debugger: Parse and highlight text with ANSI escape sequences (#32915)

Relanding #32817 with an improved approach, bugs fixed, and a test.

Release Notes:

- N/A
This commit is contained in:
Cole Miller 2025-06-17 23:39:31 -04:00 committed by GitHub
parent 4da58188fb
commit bfffc293a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 606 additions and 80 deletions

View file

@ -197,7 +197,7 @@ pub use sum_tree::Bias;
use sum_tree::TreeMap;
use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
use theme::{
ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
observe_buffer_font_size_adjustment,
};
use ui::{
@ -708,7 +708,7 @@ impl EditorActionId {
// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
#[derive(Default)]
@ -1017,7 +1017,7 @@ pub struct Editor {
placeholder_text: Option<Arc<str>>,
highlight_order: usize,
highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
background_highlights: TreeMap<TypeId, BackgroundHighlight>,
background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
gutter_highlights: TreeMap<TypeId, GutterHighlight>,
scrollbar_marker_state: ScrollbarMarkerState,
active_indent_guides_state: ActiveIndentGuidesState,
@ -6180,7 +6180,7 @@ impl Editor {
editor.update(cx, |editor, cx| {
editor.highlight_background::<Self>(
&ranges_to_highlight,
|theme| theme.editor_highlighted_line_background,
|theme| theme.colors().editor_highlighted_line_background,
cx,
);
});
@ -6535,12 +6535,12 @@ impl Editor {
this.highlight_background::<DocumentHighlightRead>(
&read_ranges,
|theme| theme.editor_document_highlight_read_background,
|theme| theme.colors().editor_document_highlight_read_background,
cx,
);
this.highlight_background::<DocumentHighlightWrite>(
&write_ranges,
|theme| theme.editor_document_highlight_write_background,
|theme| theme.colors().editor_document_highlight_write_background,
cx,
);
cx.notify();
@ -6642,7 +6642,7 @@ impl Editor {
if !match_ranges.is_empty() {
editor.highlight_background::<SelectedTextHighlight>(
&match_ranges,
|theme| theme.editor_document_highlight_bracket_background,
|theme| theme.colors().editor_document_highlight_bracket_background,
cx,
)
}
@ -15397,7 +15397,7 @@ impl Editor {
}
editor.highlight_background::<Self>(
&ranges,
|theme| theme.editor_highlighted_line_background,
|theme| theme.colors().editor_highlighted_line_background,
cx,
);
}
@ -18552,7 +18552,7 @@ impl Editor {
pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
self.highlight_background::<SearchWithinRange>(
ranges,
|colors| colors.editor_document_highlight_read_background,
|colors| colors.colors().editor_document_highlight_read_background,
cx,
)
}
@ -18568,11 +18568,28 @@ impl Editor {
pub fn highlight_background<T: 'static>(
&mut self,
ranges: &[Range<Anchor>],
color_fetcher: fn(&ThemeColors) -> Hsla,
color_fetcher: fn(&Theme) -> Hsla,
cx: &mut Context<Self>,
) {
self.background_highlights
.insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
self.background_highlights.insert(
HighlightKey::Type(TypeId::of::<T>()),
(color_fetcher, Arc::from(ranges)),
);
self.scrollbar_marker_state.dirty = true;
cx.notify();
}
pub fn highlight_background_key<T: 'static>(
&mut self,
key: usize,
ranges: &[Range<Anchor>],
color_fetcher: fn(&Theme) -> Hsla,
cx: &mut Context<Self>,
) {
self.background_highlights.insert(
HighlightKey::TypePlus(TypeId::of::<T>(), key),
(color_fetcher, Arc::from(ranges)),
);
self.scrollbar_marker_state.dirty = true;
cx.notify();
}
@ -18581,7 +18598,9 @@ impl Editor {
&mut self,
cx: &mut Context<Self>,
) -> Option<BackgroundHighlight> {
let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
let text_highlights = self
.background_highlights
.remove(&HighlightKey::Type(TypeId::of::<T>()))?;
if !text_highlights.1.is_empty() {
self.scrollbar_marker_state.dirty = true;
cx.notify();
@ -18667,6 +18686,30 @@ impl Editor {
.insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
}
#[cfg(feature = "test-support")]
pub fn all_text_highlights(
&self,
window: &mut Window,
cx: &mut Context<Self>,
) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
let snapshot = self.snapshot(window, cx);
self.display_map.update(cx, |display_map, _| {
display_map
.all_text_highlights()
.map(|highlight| {
let (style, ranges) = highlight.as_ref();
(
*style,
ranges
.iter()
.map(|range| range.clone().to_display_points(&snapshot))
.collect(),
)
})
.collect()
})
}
#[cfg(feature = "test-support")]
pub fn all_text_background_highlights(
&self,
@ -18677,8 +18720,7 @@ impl Editor {
let buffer = &snapshot.buffer_snapshot;
let start = buffer.anchor_before(0);
let end = buffer.anchor_after(buffer.len());
let theme = cx.theme().colors();
self.background_highlights_in_range(start..end, &snapshot, theme)
self.background_highlights_in_range(start..end, &snapshot, cx.theme())
}
#[cfg(feature = "test-support")]
@ -18687,7 +18729,9 @@ impl Editor {
let highlights = self
.background_highlights
.get(&TypeId::of::<items::BufferSearchHighlights>());
.get(&HighlightKey::Type(TypeId::of::<
items::BufferSearchHighlights,
>()));
if let Some((_color, ranges)) = highlights {
ranges
@ -18706,11 +18750,11 @@ impl Editor {
) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
let read_highlights = self
.background_highlights
.get(&TypeId::of::<DocumentHighlightRead>())
.get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
.map(|h| &h.1);
let write_highlights = self
.background_highlights
.get(&TypeId::of::<DocumentHighlightWrite>())
.get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
.map(|h| &h.1);
let left_position = position.bias_left(buffer);
let right_position = position.bias_right(buffer);
@ -18737,7 +18781,7 @@ impl Editor {
pub fn has_background_highlights<T: 'static>(&self) -> bool {
self.background_highlights
.get(&TypeId::of::<T>())
.get(&HighlightKey::Type(TypeId::of::<T>()))
.map_or(false, |(_, highlights)| !highlights.is_empty())
}
@ -18745,7 +18789,7 @@ impl Editor {
&self,
search_range: Range<Anchor>,
display_snapshot: &DisplaySnapshot,
theme: &ThemeColors,
theme: &Theme,
) -> Vec<(Range<DisplayPoint>, Hsla)> {
let mut results = Vec::new();
for (color_fetcher, ranges) in self.background_highlights.values() {
@ -18786,7 +18830,10 @@ impl Editor {
count: usize,
) -> Vec<RangeInclusive<DisplayPoint>> {
let mut results = Vec::new();
let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
let Some((_, ranges)) = self
.background_highlights
.get(&HighlightKey::Type(TypeId::of::<T>()))
else {
return vec![];
};
@ -18923,6 +18970,23 @@ impl Editor {
.collect()
}
pub fn highlight_text_key<T: 'static>(
&mut self,
key: usize,
ranges: Vec<Range<Anchor>>,
style: HighlightStyle,
cx: &mut Context<Self>,
) {
self.display_map.update(cx, |map, _| {
map.highlight_text(
HighlightKey::TypePlus(TypeId::of::<T>(), key),
ranges,
style,
);
});
cx.notify();
}
pub fn highlight_text<T: 'static>(
&mut self,
ranges: Vec<Range<Anchor>>,
@ -18930,7 +18994,7 @@ impl Editor {
cx: &mut Context<Self>,
) {
self.display_map.update(cx, |map, _| {
map.highlight_text(TypeId::of::<T>(), ranges, style)
map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
});
cx.notify();
}