Revert "debugger: Process ANSI color escape codes in console" (#32906)

Reverts zed-industries/zed#32817

Release Notes:
- N/A
This commit is contained in:
Cole Miller 2025-06-17 18:13:12 -04:00 committed by GitHub
parent 0cda28f786
commit 2f1d25d7f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 234 additions and 558 deletions

1
Cargo.lock generated
View file

@ -4268,7 +4268,6 @@ dependencies = [
name = "debugger_ui" name = "debugger_ui"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"alacritty_terminal",
"anyhow", "anyhow",
"client", "client",
"collections", "collections",

View file

@ -1350,18 +1350,11 @@ impl InlineAssistant {
editor.clear_highlights::<InlineAssist>(cx); editor.clear_highlights::<InlineAssist>(cx);
} else { } else {
editor.highlight_text::<InlineAssist>( editor.highlight_text::<InlineAssist>(
foreground_ranges foreground_ranges,
.into_iter() HighlightStyle {
.map(|range| { fade_out: Some(0.6),
( ..Default::default()
range, },
HighlightStyle {
fade_out: Some(0.6),
..Default::default()
},
)
})
.collect(),
cx, cx,
); );
} }

View file

@ -193,10 +193,10 @@ impl MessageEditor {
let highlights = editor.text_highlights::<Self>(cx); let highlights = editor.text_highlights::<Self>(cx);
let text = editor.text(cx); let text = editor.text(cx);
let snapshot = editor.buffer().read(cx).snapshot(cx); let snapshot = editor.buffer().read(cx).snapshot(cx);
let mentions = if let Some(ranges) = highlights { let mentions = if let Some((_, ranges)) = highlights {
ranges ranges
.iter() .iter()
.map(|(range, _)| range.to_offset(&snapshot)) .map(|range| range.to_offset(&snapshot))
.zip(self.mentions.iter().copied()) .zip(self.mentions.iter().copied())
.collect() .collect()
} else { } else {
@ -483,19 +483,20 @@ impl MessageEditor {
let end = multi_buffer.anchor_after(range.end); let end = multi_buffer.anchor_after(range.end);
mentioned_user_ids.push(user.id); mentioned_user_ids.push(user.id);
anchor_ranges.push(( anchor_ranges.push(start..end);
start..end,
HighlightStyle {
font_weight: Some(FontWeight::BOLD),
..Default::default()
},
));
} }
} }
} }
editor.clear_highlights::<Self>(cx); editor.clear_highlights::<Self>(cx);
editor.highlight_text::<Self>(anchor_ranges, cx) editor.highlight_text::<Self>(
anchor_ranges,
HighlightStyle {
font_weight: Some(FontWeight::BOLD),
..Default::default()
},
cx,
)
}); });
this.mentions = mentioned_user_ids; this.mentions = mentioned_user_ids;

View file

@ -26,7 +26,6 @@ test-support = [
] ]
[dependencies] [dependencies]
alacritty_terminal.workspace = true
anyhow.workspace = true anyhow.workspace = true
client.workspace = true client.workspace = true
collections.workspace = true collections.workspace = true

View file

@ -2,17 +2,13 @@ use super::{
stack_frame_list::{StackFrameList, StackFrameListEvent}, stack_frame_list::{StackFrameList, StackFrameListEvent},
variable_list::VariableList, variable_list::VariableList,
}; };
use alacritty_terminal::vte::ansi;
use anyhow::Result; use anyhow::Result;
use collections::HashMap; use collections::HashMap;
use dap::OutputEvent; use dap::OutputEvent;
use editor::{ use editor::{Bias, CompletionProvider, Editor, EditorElement, EditorStyle, ExcerptId};
BackgroundHighlight, Bias, CompletionProvider, Editor, EditorElement, EditorStyle, ExcerptId,
};
use fuzzy::StringMatchCandidate; use fuzzy::StringMatchCandidate;
use gpui::{ use gpui::{
Context, Entity, FocusHandle, Focusable, HighlightStyle, Hsla, Render, Subscription, Task, Context, Entity, FocusHandle, Focusable, Render, Subscription, Task, TextStyle, WeakEntity,
TextStyle, WeakEntity,
}; };
use language::{Buffer, CodeLabel, ToOffset}; use language::{Buffer, CodeLabel, ToOffset};
use menu::Confirm; use menu::Confirm;
@ -21,8 +17,8 @@ use project::{
debugger::session::{CompletionsQuery, OutputToken, Session, SessionEvent}, debugger::session::{CompletionsQuery, OutputToken, Session, SessionEvent},
}; };
use settings::Settings; use settings::Settings;
use std::{cell::RefCell, ops::Range, rc::Rc, usize}; use std::{cell::RefCell, rc::Rc, usize};
use theme::{Theme, ThemeSettings}; use theme::ThemeSettings;
use ui::{Divider, prelude::*}; use ui::{Divider, prelude::*};
pub struct Console { pub struct Console {
@ -34,8 +30,6 @@ pub struct Console {
stack_frame_list: Entity<StackFrameList>, stack_frame_list: Entity<StackFrameList>,
last_token: OutputToken, last_token: OutputToken,
update_output_task: Task<()>, update_output_task: Task<()>,
ansi_handler: ConsoleHandler,
ansi_processor: ansi::Processor<ansi::StdSyncHandler>,
focus_handle: FocusHandle, focus_handle: FocusHandle,
} }
@ -106,8 +100,6 @@ impl Console {
stack_frame_list, stack_frame_list,
update_output_task: Task::ready(()), update_output_task: Task::ready(()),
last_token: OutputToken(0), last_token: OutputToken(0),
ansi_handler: Default::default(),
ansi_processor: Default::default(),
focus_handle, focus_handle,
} }
} }
@ -143,185 +135,17 @@ impl Console {
window: &mut Window, window: &mut Window,
cx: &mut App, cx: &mut App,
) { ) {
let mut to_insert = String::default();
for event in events {
use std::fmt::Write;
_ = write!(to_insert, "{}\n", event.output.trim_end());
}
let len = self.ansi_handler.pos;
self.ansi_processor
.advance(&mut self.ansi_handler, to_insert.as_bytes());
let output = std::mem::take(&mut self.ansi_handler.output);
let mut spans = std::mem::take(&mut self.ansi_handler.spans);
let mut background_spans = std::mem::take(&mut self.ansi_handler.background_spans);
if self.ansi_handler.current_range_start < len + output.len() {
spans.push((
self.ansi_handler.current_range_start..len + output.len(),
self.ansi_handler.current_color,
));
self.ansi_handler.current_range_start = len + output.len();
}
if self.ansi_handler.current_background_range_start < len + output.len() {
background_spans.push((
self.ansi_handler.current_background_range_start..len + output.len(),
self.ansi_handler.current_background_color,
));
self.ansi_handler.current_background_range_start = len + output.len();
}
self.console.update(cx, |console, cx| { self.console.update(cx, |console, cx| {
struct ConsoleAnsiHighlight; let mut to_insert = String::default();
for event in events {
use std::fmt::Write;
_ = write!(to_insert, "{}\n", event.output.trim_end());
}
console.set_read_only(false); console.set_read_only(false);
console.move_to_end(&editor::actions::MoveToEnd, window, cx); console.move_to_end(&editor::actions::MoveToEnd, window, cx);
console.insert(&output, window, cx); console.insert(&to_insert, window, cx);
let buffer = console.buffer().read(cx).snapshot(cx);
let mut highlights = console
.remove_text_highlights::<ConsoleAnsiHighlight>(cx)
.unwrap_or_default();
for (range, color) in spans {
let Some(color) = color else { continue };
let start = range.start + len;
let range = start..range.end + len;
let range = buffer.anchor_after(range.start)..buffer.anchor_before(range.end);
let style = HighlightStyle {
color: Some(terminal_view::terminal_element::convert_color(
&color,
cx.theme(),
)),
..Default::default()
};
highlights.push((range, style));
}
console.highlight_text::<ConsoleAnsiHighlight>(highlights, cx);
let mut background_highlights = console
.clear_background_highlights::<ConsoleAnsiHighlight>(cx)
.unwrap_or_default();
for (range, color) in background_spans {
let Some(color) = color else { continue };
let start = range.start + len;
let range = start..range.end + len;
let range = buffer.anchor_after(range.start)..buffer.anchor_before(range.end);
let color_fetcher: fn(&Theme) -> Hsla = match color {
// Named and theme defined colors
ansi::Color::Named(n) => match n {
ansi::NamedColor::Black => |theme| theme.colors().terminal_ansi_black,
ansi::NamedColor::Red => |theme| theme.colors().terminal_ansi_red,
ansi::NamedColor::Green => |theme| theme.colors().terminal_ansi_green,
ansi::NamedColor::Yellow => |theme| theme.colors().terminal_ansi_yellow,
ansi::NamedColor::Blue => |theme| theme.colors().terminal_ansi_blue,
ansi::NamedColor::Magenta => |theme| theme.colors().terminal_ansi_magenta,
ansi::NamedColor::Cyan => |theme| theme.colors().terminal_ansi_cyan,
ansi::NamedColor::White => |theme| theme.colors().terminal_ansi_white,
ansi::NamedColor::BrightBlack => {
|theme| theme.colors().terminal_ansi_bright_black
}
ansi::NamedColor::BrightRed => {
|theme| theme.colors().terminal_ansi_bright_red
}
ansi::NamedColor::BrightGreen => {
|theme| theme.colors().terminal_ansi_bright_green
}
ansi::NamedColor::BrightYellow => {
|theme| theme.colors().terminal_ansi_bright_yellow
}
ansi::NamedColor::BrightBlue => {
|theme| theme.colors().terminal_ansi_bright_blue
}
ansi::NamedColor::BrightMagenta => {
|theme| theme.colors().terminal_ansi_bright_magenta
}
ansi::NamedColor::BrightCyan => {
|theme| theme.colors().terminal_ansi_bright_cyan
}
ansi::NamedColor::BrightWhite => {
|theme| theme.colors().terminal_ansi_bright_white
}
ansi::NamedColor::Foreground => |theme| theme.colors().terminal_foreground,
ansi::NamedColor::Background => |theme| theme.colors().terminal_background,
ansi::NamedColor::Cursor => |theme| theme.players().local().cursor,
ansi::NamedColor::DimBlack => {
|theme| theme.colors().terminal_ansi_dim_black
}
ansi::NamedColor::DimRed => |theme| theme.colors().terminal_ansi_dim_red,
ansi::NamedColor::DimGreen => {
|theme| theme.colors().terminal_ansi_dim_green
}
ansi::NamedColor::DimYellow => {
|theme| theme.colors().terminal_ansi_dim_yellow
}
ansi::NamedColor::DimBlue => |theme| theme.colors().terminal_ansi_dim_blue,
ansi::NamedColor::DimMagenta => {
|theme| theme.colors().terminal_ansi_dim_magenta
}
ansi::NamedColor::DimCyan => |theme| theme.colors().terminal_ansi_dim_cyan,
ansi::NamedColor::DimWhite => {
|theme| theme.colors().terminal_ansi_dim_white
}
ansi::NamedColor::BrightForeground => {
|theme| theme.colors().terminal_bright_foreground
}
ansi::NamedColor::DimForeground => {
|theme| theme.colors().terminal_dim_foreground
}
},
// 'True' colors
ansi::Color::Spec(_) => |theme| theme.colors().editor_background,
// 8 bit, indexed colors
ansi::Color::Indexed(i) => {
match i {
// 0-15 are the same as the named colors above
0 => |theme| theme.colors().terminal_ansi_black,
1 => |theme| theme.colors().terminal_ansi_red,
2 => |theme| theme.colors().terminal_ansi_green,
3 => |theme| theme.colors().terminal_ansi_yellow,
4 => |theme| theme.colors().terminal_ansi_blue,
5 => |theme| theme.colors().terminal_ansi_magenta,
6 => |theme| theme.colors().terminal_ansi_cyan,
7 => |theme| theme.colors().terminal_ansi_white,
8 => |theme| theme.colors().terminal_ansi_bright_black,
9 => |theme| theme.colors().terminal_ansi_bright_red,
10 => |theme| theme.colors().terminal_ansi_bright_green,
11 => |theme| theme.colors().terminal_ansi_bright_yellow,
12 => |theme| theme.colors().terminal_ansi_bright_blue,
13 => |theme| theme.colors().terminal_ansi_bright_magenta,
14 => |theme| theme.colors().terminal_ansi_bright_cyan,
15 => |theme| theme.colors().terminal_ansi_bright_white,
// 16-231 are a 6x6x6 RGB color cube, mapped to 0-255 using steps defined by XTerm.
// See: https://github.com/xterm-x11/xterm-snapshots/blob/master/256colres.pl
// 16..=231 => {
// let (r, g, b) = rgb_for_index(index as u8);
// rgba_color(
// if r == 0 { 0 } else { r * 40 + 55 },
// if g == 0 { 0 } else { g * 40 + 55 },
// if b == 0 { 0 } else { b * 40 + 55 },
// )
// }
// 232-255 are a 24-step grayscale ramp from (8, 8, 8) to (238, 238, 238).
// 232..=255 => {
// let i = index as u8 - 232; // Align index to 0..24
// let value = i * 10 + 8;
// rgba_color(value, value, value)
// }
// For compatibility with the alacritty::Colors interface
// See: https://github.com/alacritty/alacritty/blob/master/alacritty_terminal/src/term/color.rs
_ => |_| gpui::black(),
}
}
};
background_highlights.push(BackgroundHighlight {
range,
color_fetcher,
});
}
console.highlight_background_ranges::<ConsoleAnsiHighlight>(background_highlights, cx);
console.set_read_only(true); console.set_read_only(true);
cx.notify(); cx.notify();
@ -635,69 +459,3 @@ impl ConsoleQueryBarCompletionProvider {
}) })
} }
} }
#[derive(Default)]
struct ConsoleHandler {
output: String,
spans: Vec<(Range<usize>, Option<ansi::Color>)>,
background_spans: Vec<(Range<usize>, Option<ansi::Color>)>,
current_range_start: usize,
current_background_range_start: usize,
current_color: Option<ansi::Color>,
current_background_color: Option<ansi::Color>,
pos: usize,
}
impl ConsoleHandler {
fn break_span(&mut self, color: Option<ansi::Color>) {
self.spans.push((
self.current_range_start..self.output.len(),
self.current_color,
));
self.current_color = color;
self.current_range_start = self.pos;
}
fn break_background_span(&mut self, color: Option<ansi::Color>) {
self.background_spans.push((
self.current_background_range_start..self.output.len(),
self.current_background_color,
));
self.current_background_color = color;
self.current_background_range_start = self.pos;
}
}
impl ansi::Handler for ConsoleHandler {
fn input(&mut self, c: char) {
self.output.push(c);
self.pos += 1;
}
fn linefeed(&mut self) {
self.output.push('\n');
self.pos += 1;
}
fn put_tab(&mut self, count: u16) {
self.output
.extend(std::iter::repeat('\t').take(count as usize));
self.pos += count as usize;
}
fn terminal_attribute(&mut self, attr: ansi::Attr) {
match attr {
ansi::Attr::Foreground(color) => {
self.break_span(Some(color));
}
ansi::Attr::Background(color) => {
self.break_background_span(Some(color));
}
ansi::Attr::Reset => {
self.break_span(None);
self.break_background_span(None);
}
_ => {}
}
}
}

View file

@ -110,7 +110,7 @@ async fn test_handle_output_event(executor: BackgroundExecutor, cx: &mut TestApp
client client
.fake_event(dap::messages::Events::Output(dap::OutputEvent { .fake_event(dap::messages::Events::Output(dap::OutputEvent {
category: Some(dap::OutputEventCategory::Stdout), category: Some(dap::OutputEventCategory::Stdout),
output: "\tSecond output line after thread stopped!".to_string(), output: "Second output line after thread stopped!".to_string(),
data: None, data: None,
variables_reference: None, variables_reference: None,
source: None, source: None,
@ -124,7 +124,7 @@ async fn test_handle_output_event(executor: BackgroundExecutor, cx: &mut TestApp
client client
.fake_event(dap::messages::Events::Output(dap::OutputEvent { .fake_event(dap::messages::Events::Output(dap::OutputEvent {
category: Some(dap::OutputEventCategory::Console), category: Some(dap::OutputEventCategory::Console),
output: "\tSecond console output line after thread stopped!".to_string(), output: "Second console output line after thread stopped!".to_string(),
data: None, data: None,
variables_reference: None, variables_reference: None,
source: None, source: None,
@ -150,7 +150,7 @@ async fn test_handle_output_event(executor: BackgroundExecutor, cx: &mut TestApp
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
"First console output line before thread stopped!\nFirst output line before thread stopped!\n\tSecond output line after thread stopped!\n\tSecond console output line after thread stopped!\n", "First console output line before thread stopped!\nFirst output line before thread stopped!\nSecond output line after thread stopped!\nSecond console output line after thread stopped!\n",
active_session_panel.read(cx).running_state().read(cx).console().read(cx).editor().read(cx).text(cx).as_str() active_session_panel.read(cx).running_state().read(cx).console().read(cx).editor().read(cx).text(cx).as_str()
); );
}) })

View file

@ -80,7 +80,7 @@ pub trait ToDisplayPoint {
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint; fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint;
} }
type TextHighlights = TreeMap<TypeId, Vec<(Range<Anchor>, HighlightStyle)>>; type TextHighlights = TreeMap<TypeId, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>;
type InlayHighlights = TreeMap<TypeId, TreeMap<InlayId, (HighlightStyle, InlayHighlight)>>; type InlayHighlights = TreeMap<TypeId, TreeMap<InlayId, (HighlightStyle, InlayHighlight)>>;
/// Decides how text in a [`MultiBuffer`] should be displayed in a buffer, handling inlay hints, /// Decides how text in a [`MultiBuffer`] should be displayed in a buffer, handling inlay hints,
@ -474,9 +474,11 @@ impl DisplayMap {
pub fn highlight_text( pub fn highlight_text(
&mut self, &mut self,
type_id: TypeId, type_id: TypeId,
ranges: Vec<(Range<Anchor>, HighlightStyle)>, ranges: Vec<Range<Anchor>>,
style: HighlightStyle,
) { ) {
self.text_highlights.insert(type_id, ranges); self.text_highlights
.insert(type_id, Arc::new((style, ranges)));
} }
pub(crate) fn highlight_inlays( pub(crate) fn highlight_inlays(
@ -498,25 +500,16 @@ impl DisplayMap {
} }
} }
pub fn text_highlights(&self, type_id: TypeId) -> Option<&[(Range<Anchor>, HighlightStyle)]> { pub fn text_highlights(&self, type_id: TypeId) -> Option<(HighlightStyle, &[Range<Anchor>])> {
self.text_highlights let highlights = self.text_highlights.get(&type_id)?;
.get(&type_id) Some((highlights.0, &highlights.1))
.map(|highlights| highlights.as_slice())
} }
pub fn clear_highlights(&mut self, type_id: TypeId) -> bool { pub fn clear_highlights(&mut self, type_id: TypeId) -> bool {
let mut cleared = self.text_highlights.remove(&type_id).is_some(); let mut cleared = self.text_highlights.remove(&type_id).is_some();
cleared |= self.inlay_highlights.remove(&type_id).is_some(); cleared |= self.inlay_highlights.remove(&type_id).is_some();
cleared cleared
} }
pub fn remove_text_highlights(
&mut self,
type_id: TypeId,
) -> Option<Vec<(Range<Anchor>, HighlightStyle)>> {
self.text_highlights.remove(&type_id)
}
pub fn set_font(&self, font: Font, font_size: Pixels, cx: &mut Context<Self>) -> bool { pub fn set_font(&self, font: Font, font_size: Pixels, cx: &mut Context<Self>) -> bool {
self.wrap_map self.wrap_map
.update(cx, |map, cx| map.set_font_with_size(font, font_size, cx)) .update(cx, |map, cx| map.set_font_with_size(font, font_size, cx))
@ -1338,7 +1331,7 @@ impl DisplaySnapshot {
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub fn text_highlight_ranges<Tag: ?Sized + 'static>( pub fn text_highlight_ranges<Tag: ?Sized + 'static>(
&self, &self,
) -> Option<Vec<(Range<Anchor>, HighlightStyle)>> { ) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
let type_id = TypeId::of::<Tag>(); let type_id = TypeId::of::<Tag>();
self.text_highlights.get(&type_id).cloned() self.text_highlights.get(&type_id).cloned()
} }
@ -2303,17 +2296,12 @@ pub mod tests {
map.highlight_text( map.highlight_text(
TypeId::of::<usize>(), TypeId::of::<usize>(),
vec![ vec![
( buffer_snapshot.anchor_before(Point::new(3, 9))
buffer_snapshot.anchor_before(Point::new(3, 9)) ..buffer_snapshot.anchor_after(Point::new(3, 14)),
..buffer_snapshot.anchor_after(Point::new(3, 14)), buffer_snapshot.anchor_before(Point::new(3, 17))
red.into(), ..buffer_snapshot.anchor_after(Point::new(3, 18)),
),
(
buffer_snapshot.anchor_before(Point::new(3, 17))
..buffer_snapshot.anchor_after(Point::new(3, 18)),
red.into(),
),
], ],
red.into(),
); );
map.insert_blocks( map.insert_blocks(
[BlockProperties { [BlockProperties {
@ -2632,13 +2620,11 @@ pub mod tests {
highlighted_ranges highlighted_ranges
.into_iter() .into_iter()
.map(|range| { .map(|range| {
( buffer_snapshot.anchor_before(range.start)
buffer_snapshot.anchor_before(range.start) ..buffer_snapshot.anchor_before(range.end)
..buffer_snapshot.anchor_before(range.end),
style,
)
}) })
.collect(), .collect(),
style,
); );
}); });

View file

@ -1,16 +1,16 @@
use collections::BTreeMap; use collections::BTreeMap;
use gpui::HighlightStyle; use gpui::HighlightStyle;
use language::Chunk; use language::Chunk;
use multi_buffer::{MultiBufferChunks, MultiBufferSnapshot, ToOffset as _}; use multi_buffer::{Anchor, MultiBufferChunks, MultiBufferSnapshot, ToOffset as _};
use std::{ use std::{
any::TypeId, any::TypeId,
cmp, cmp,
iter::{self, Peekable}, iter::{self, Peekable},
ops::Range, ops::Range,
sync::Arc,
vec, vec,
}; };
use sum_tree::TreeMap;
use crate::display_map::TextHighlights;
pub struct CustomHighlightsChunks<'a> { pub struct CustomHighlightsChunks<'a> {
buffer_chunks: MultiBufferChunks<'a>, buffer_chunks: MultiBufferChunks<'a>,
@ -19,15 +19,15 @@ pub struct CustomHighlightsChunks<'a> {
multibuffer_snapshot: &'a MultiBufferSnapshot, multibuffer_snapshot: &'a MultiBufferSnapshot,
highlight_endpoints: Peekable<vec::IntoIter<HighlightEndpoint>>, highlight_endpoints: Peekable<vec::IntoIter<HighlightEndpoint>>,
active_highlights: BTreeMap<(TypeId, usize), HighlightStyle>, active_highlights: BTreeMap<TypeId, HighlightStyle>,
text_highlights: Option<&'a TextHighlights>, text_highlights: Option<&'a TreeMap<TypeId, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>>,
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct HighlightEndpoint { struct HighlightEndpoint {
offset: usize, offset: usize,
is_start: bool, is_start: bool,
tag: (TypeId, usize), tag: TypeId,
style: HighlightStyle, style: HighlightStyle,
} }
@ -35,7 +35,7 @@ impl<'a> CustomHighlightsChunks<'a> {
pub fn new( pub fn new(
range: Range<usize>, range: Range<usize>,
language_aware: bool, language_aware: bool,
text_highlights: Option<&'a TextHighlights>, text_highlights: Option<&'a TreeMap<TypeId, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>>,
multibuffer_snapshot: &'a MultiBufferSnapshot, multibuffer_snapshot: &'a MultiBufferSnapshot,
) -> Self { ) -> Self {
Self { Self {
@ -66,7 +66,7 @@ impl<'a> CustomHighlightsChunks<'a> {
fn create_highlight_endpoints( fn create_highlight_endpoints(
range: &Range<usize>, range: &Range<usize>,
text_highlights: Option<&TextHighlights>, text_highlights: Option<&TreeMap<TypeId, Arc<(HighlightStyle, Vec<Range<Anchor>>)>>>,
buffer: &MultiBufferSnapshot, buffer: &MultiBufferSnapshot,
) -> iter::Peekable<vec::IntoIter<HighlightEndpoint>> { ) -> iter::Peekable<vec::IntoIter<HighlightEndpoint>> {
let mut highlight_endpoints = Vec::new(); let mut highlight_endpoints = Vec::new();
@ -74,7 +74,10 @@ fn create_highlight_endpoints(
let start = buffer.anchor_after(range.start); let start = buffer.anchor_after(range.start);
let end = buffer.anchor_after(range.end); let end = buffer.anchor_after(range.end);
for (&tag, text_highlights) in text_highlights.iter() { for (&tag, text_highlights) in text_highlights.iter() {
let start_ix = match text_highlights.binary_search_by(|(probe, _)| { let style = text_highlights.0;
let ranges = &text_highlights.1;
let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe.end.cmp(&start, &buffer); let cmp = probe.end.cmp(&start, &buffer);
if cmp.is_gt() { if cmp.is_gt() {
cmp::Ordering::Greater cmp::Ordering::Greater
@ -85,7 +88,7 @@ fn create_highlight_endpoints(
Ok(i) | Err(i) => i, Ok(i) | Err(i) => i,
}; };
for (ix, (range, style)) in text_highlights[start_ix..].iter().enumerate() { for range in &ranges[start_ix..] {
if range.start.cmp(&end, &buffer).is_ge() { if range.start.cmp(&end, &buffer).is_ge() {
break; break;
} }
@ -93,14 +96,14 @@ fn create_highlight_endpoints(
highlight_endpoints.push(HighlightEndpoint { highlight_endpoints.push(HighlightEndpoint {
offset: range.start.to_offset(&buffer), offset: range.start.to_offset(&buffer),
is_start: true, is_start: true,
tag: (tag, ix), tag,
style: *style, style,
}); });
highlight_endpoints.push(HighlightEndpoint { highlight_endpoints.push(HighlightEndpoint {
offset: range.end.to_offset(&buffer), offset: range.end.to_offset(&buffer),
is_start: false, is_start: false,
tag: (tag, ix), tag,
style: *style, style,
}); });
} }
} }

View file

@ -1122,7 +1122,7 @@ mod tests {
use project::{InlayHint, InlayHintLabel, ResolveState}; use project::{InlayHint, InlayHintLabel, ResolveState};
use rand::prelude::*; use rand::prelude::*;
use settings::SettingsStore; use settings::SettingsStore;
use std::{any::TypeId, cmp::Reverse, env}; use std::{any::TypeId, cmp::Reverse, env, sync::Arc};
use sum_tree::TreeMap; use sum_tree::TreeMap;
use text::Patch; use text::Patch;
use util::post_inc; use util::post_inc;
@ -1630,16 +1630,16 @@ mod tests {
log::info!("highlighting text ranges {text_highlight_ranges:?}"); log::info!("highlighting text ranges {text_highlight_ranges:?}");
text_highlights.insert( text_highlights.insert(
TypeId::of::<()>(), TypeId::of::<()>(),
text_highlight_ranges Arc::new((
.into_iter() HighlightStyle::default(),
.map(|range| { text_highlight_ranges
( .into_iter()
.map(|range| {
buffer_snapshot.anchor_before(range.start) buffer_snapshot.anchor_before(range.start)
..buffer_snapshot.anchor_after(range.end), ..buffer_snapshot.anchor_after(range.end)
HighlightStyle::default(), })
) .collect(),
}) )),
.collect(),
); );
let mut inlay_highlights = InlayHighlights::default(); let mut inlay_highlights = InlayHighlights::default();

View file

@ -197,7 +197,7 @@ pub use sum_tree::Bias;
use sum_tree::TreeMap; use sum_tree::TreeMap;
use text::{BufferId, FromAnchor, OffsetUtf16, Rope}; use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
use theme::{ use theme::{
ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
observe_buffer_font_size_adjustment, observe_buffer_font_size_adjustment,
}; };
use ui::{ use ui::{
@ -708,12 +708,7 @@ impl EditorActionId {
// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor; // type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>; // type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
#[derive(Clone)] type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
pub struct BackgroundHighlight {
pub range: Range<Anchor>,
pub color_fetcher: fn(&Theme) -> Hsla,
}
type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>); type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
#[derive(Default)] #[derive(Default)]
@ -1022,7 +1017,7 @@ pub struct Editor {
placeholder_text: Option<Arc<str>>, placeholder_text: Option<Arc<str>>,
highlight_order: usize, highlight_order: usize,
highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>, highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
background_highlights: TreeMap<TypeId, Vec<BackgroundHighlight>>, background_highlights: TreeMap<TypeId, BackgroundHighlight>,
gutter_highlights: TreeMap<TypeId, GutterHighlight>, gutter_highlights: TreeMap<TypeId, GutterHighlight>,
scrollbar_marker_state: ScrollbarMarkerState, scrollbar_marker_state: ScrollbarMarkerState,
active_indent_guides_state: ActiveIndentGuidesState, active_indent_guides_state: ActiveIndentGuidesState,
@ -6185,7 +6180,7 @@ impl Editor {
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
editor.highlight_background::<Self>( editor.highlight_background::<Self>(
&ranges_to_highlight, &ranges_to_highlight,
|theme| theme.colors().editor_highlighted_line_background, |theme| theme.editor_highlighted_line_background,
cx, cx,
); );
}); });
@ -6540,12 +6535,12 @@ impl Editor {
this.highlight_background::<DocumentHighlightRead>( this.highlight_background::<DocumentHighlightRead>(
&read_ranges, &read_ranges,
|theme| theme.colors().editor_document_highlight_read_background, |theme| theme.editor_document_highlight_read_background,
cx, cx,
); );
this.highlight_background::<DocumentHighlightWrite>( this.highlight_background::<DocumentHighlightWrite>(
&write_ranges, &write_ranges,
|theme| theme.colors().editor_document_highlight_write_background, |theme| theme.editor_document_highlight_write_background,
cx, cx,
); );
cx.notify(); cx.notify();
@ -6647,7 +6642,7 @@ impl Editor {
if !match_ranges.is_empty() { if !match_ranges.is_empty() {
editor.highlight_background::<SelectedTextHighlight>( editor.highlight_background::<SelectedTextHighlight>(
&match_ranges, &match_ranges,
|theme| theme.colors().editor_document_highlight_bracket_background, |theme| theme.editor_document_highlight_bracket_background,
cx, cx,
) )
} }
@ -7523,15 +7518,12 @@ impl Editor {
self.splice_inlays(&[], inlays, cx); self.splice_inlays(&[], inlays, cx);
} else { } else {
let background_color = cx.theme().status().deleted_background; let background_color = cx.theme().status().deleted_background;
let style = HighlightStyle {
background_color: Some(background_color),
..Default::default()
};
self.highlight_text::<InlineCompletionHighlight>( self.highlight_text::<InlineCompletionHighlight>(
edits edits.iter().map(|(range, _)| range.clone()).collect(),
.iter() HighlightStyle {
.map(|(range, _)| (range.clone(), style)) background_color: Some(background_color),
.collect(), ..Default::default()
},
cx, cx,
); );
} }
@ -15405,7 +15397,7 @@ impl Editor {
} }
editor.highlight_background::<Self>( editor.highlight_background::<Self>(
&ranges, &ranges,
|theme| theme.colors().editor_highlighted_line_background, |theme| theme.editor_highlighted_line_background,
cx, cx,
); );
} }
@ -15560,28 +15552,25 @@ impl Editor {
}) })
.detach(); .detach();
let write_highlights = this let write_highlights =
.clear_background_highlights::<DocumentHighlightWrite>(cx) this.clear_background_highlights::<DocumentHighlightWrite>(cx);
.unwrap_or_default(); let read_highlights =
let read_highlights = this this.clear_background_highlights::<DocumentHighlightRead>(cx);
.clear_background_highlights::<DocumentHighlightRead>(cx)
.unwrap_or_default();
let ranges = write_highlights let ranges = write_highlights
.iter() .iter()
.chain(read_highlights.iter()) .flat_map(|(_, ranges)| ranges.iter())
.chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
.cloned() .cloned()
.map(|highlight| {
(
highlight.range,
HighlightStyle {
fade_out: Some(0.6),
..Default::default()
},
)
})
.collect(); .collect();
this.highlight_text::<Rename>(ranges, cx); this.highlight_text::<Rename>(
ranges,
HighlightStyle {
fade_out: Some(0.6),
..Default::default()
},
cx,
);
let rename_focus_handle = rename_editor.focus_handle(cx); let rename_focus_handle = rename_editor.focus_handle(cx);
window.focus(&rename_focus_handle); window.focus(&rename_focus_handle);
let block_id = this.insert_blocks( let block_id = this.insert_blocks(
@ -18563,7 +18552,7 @@ impl Editor {
pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) { pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
self.highlight_background::<SearchWithinRange>( self.highlight_background::<SearchWithinRange>(
ranges, ranges,
|theme| theme.colors().editor_document_highlight_read_background, |colors| colors.editor_document_highlight_read_background,
cx, cx,
) )
} }
@ -18579,29 +18568,11 @@ impl Editor {
pub fn highlight_background<T: 'static>( pub fn highlight_background<T: 'static>(
&mut self, &mut self,
ranges: &[Range<Anchor>], ranges: &[Range<Anchor>],
color_fetcher: fn(&Theme) -> Hsla, color_fetcher: fn(&ThemeColors) -> Hsla,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
let highlights = ranges
.iter()
.map(|range| BackgroundHighlight {
range: range.clone(),
color_fetcher,
})
.collect();
self.background_highlights self.background_highlights
.insert(TypeId::of::<T>(), highlights); .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
self.scrollbar_marker_state.dirty = true;
cx.notify();
}
pub fn highlight_background_ranges<T: 'static>(
&mut self,
background_highlights: Vec<BackgroundHighlight>,
cx: &mut Context<'_, Editor>,
) {
self.background_highlights
.insert(TypeId::of::<T>(), background_highlights);
self.scrollbar_marker_state.dirty = true; self.scrollbar_marker_state.dirty = true;
cx.notify(); cx.notify();
} }
@ -18609,9 +18580,9 @@ impl Editor {
pub fn clear_background_highlights<T: 'static>( pub fn clear_background_highlights<T: 'static>(
&mut self, &mut self,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Option<Vec<BackgroundHighlight>> { ) -> Option<BackgroundHighlight> {
let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?; let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
if !text_highlights.is_empty() { if !text_highlights.1.is_empty() {
self.scrollbar_marker_state.dirty = true; self.scrollbar_marker_state.dirty = true;
cx.notify(); cx.notify();
} }
@ -18706,7 +18677,7 @@ impl Editor {
let buffer = &snapshot.buffer_snapshot; let buffer = &snapshot.buffer_snapshot;
let start = buffer.anchor_before(0); let start = buffer.anchor_before(0);
let end = buffer.anchor_after(buffer.len()); let end = buffer.anchor_after(buffer.len());
let theme = cx.theme(); let theme = cx.theme().colors();
self.background_highlights_in_range(start..end, &snapshot, theme) self.background_highlights_in_range(start..end, &snapshot, theme)
} }
@ -18718,13 +18689,10 @@ impl Editor {
.background_highlights .background_highlights
.get(&TypeId::of::<items::BufferSearchHighlights>()); .get(&TypeId::of::<items::BufferSearchHighlights>());
if let Some(highlights) = highlights { if let Some((_color, ranges)) = highlights {
highlights ranges
.iter() .iter()
.map(|highlight| { .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
highlight.range.start.to_point(&snapshot)
..highlight.range.end.to_point(&snapshot)
})
.collect_vec() .collect_vec()
} else { } else {
vec![] vec![]
@ -18738,18 +18706,20 @@ impl Editor {
) -> impl 'a + Iterator<Item = &'a Range<Anchor>> { ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
let read_highlights = self let read_highlights = self
.background_highlights .background_highlights
.get(&TypeId::of::<DocumentHighlightRead>()); .get(&TypeId::of::<DocumentHighlightRead>())
.map(|h| &h.1);
let write_highlights = self let write_highlights = self
.background_highlights .background_highlights
.get(&TypeId::of::<DocumentHighlightWrite>()); .get(&TypeId::of::<DocumentHighlightWrite>())
.map(|h| &h.1);
let left_position = position.bias_left(buffer); let left_position = position.bias_left(buffer);
let right_position = position.bias_right(buffer); let right_position = position.bias_right(buffer);
read_highlights read_highlights
.into_iter() .into_iter()
.chain(write_highlights) .chain(write_highlights)
.flat_map(move |highlights| { .flat_map(move |ranges| {
let start_ix = match highlights.binary_search_by(|probe| { let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe.range.end.cmp(&left_position, buffer); let cmp = probe.end.cmp(&left_position, buffer);
if cmp.is_ge() { if cmp.is_ge() {
Ordering::Greater Ordering::Greater
} else { } else {
@ -18759,32 +18729,29 @@ impl Editor {
Ok(i) | Err(i) => i, Ok(i) | Err(i) => i,
}; };
highlights[start_ix..] ranges[start_ix..]
.iter() .iter()
.take_while(move |highlight| { .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
highlight.range.start.cmp(&right_position, buffer).is_le()
})
.map(|highlight| &highlight.range)
}) })
} }
pub fn has_background_highlights<T: 'static>(&self) -> bool { pub fn has_background_highlights<T: 'static>(&self) -> bool {
self.background_highlights self.background_highlights
.get(&TypeId::of::<T>()) .get(&TypeId::of::<T>())
.map_or(false, |highlights| !highlights.is_empty()) .map_or(false, |(_, highlights)| !highlights.is_empty())
} }
pub fn background_highlights_in_range( pub fn background_highlights_in_range(
&self, &self,
search_range: Range<Anchor>, search_range: Range<Anchor>,
display_snapshot: &DisplaySnapshot, display_snapshot: &DisplaySnapshot,
theme: &Theme, theme: &ThemeColors,
) -> Vec<(Range<DisplayPoint>, Hsla)> { ) -> Vec<(Range<DisplayPoint>, Hsla)> {
let mut results = Vec::new(); let mut results = Vec::new();
for highlights in self.background_highlights.values() { for (color_fetcher, ranges) in self.background_highlights.values() {
let start_ix = match highlights.binary_search_by(|probe| { let color = color_fetcher(theme);
let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe let cmp = probe
.range
.end .end
.cmp(&search_range.start, &display_snapshot.buffer_snapshot); .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
if cmp.is_gt() { if cmp.is_gt() {
@ -18795,9 +18762,8 @@ impl Editor {
}) { }) {
Ok(i) | Err(i) => i, Ok(i) | Err(i) => i,
}; };
for highlight in &highlights[start_ix..] { for range in &ranges[start_ix..] {
if highlight if range
.range
.start .start
.cmp(&search_range.end, &display_snapshot.buffer_snapshot) .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
.is_ge() .is_ge()
@ -18805,9 +18771,8 @@ impl Editor {
break; break;
} }
let start = highlight.range.start.to_display_point(display_snapshot); let start = range.start.to_display_point(display_snapshot);
let end = highlight.range.end.to_display_point(display_snapshot); let end = range.end.to_display_point(display_snapshot);
let color = (highlight.color_fetcher)(theme);
results.push((start..end, color)) results.push((start..end, color))
} }
} }
@ -18821,13 +18786,12 @@ impl Editor {
count: usize, count: usize,
) -> Vec<RangeInclusive<DisplayPoint>> { ) -> Vec<RangeInclusive<DisplayPoint>> {
let mut results = Vec::new(); let mut results = Vec::new();
let Some(highlights) = self.background_highlights.get(&TypeId::of::<T>()) else { let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
return vec![]; return vec![];
}; };
let start_ix = match highlights.binary_search_by(|probe| { let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe let cmp = probe
.range
.end .end
.cmp(&search_range.start, &display_snapshot.buffer_snapshot); .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
if cmp.is_gt() { if cmp.is_gt() {
@ -18848,31 +18812,24 @@ impl Editor {
}; };
let mut start_row: Option<Point> = None; let mut start_row: Option<Point> = None;
let mut end_row: Option<Point> = None; let mut end_row: Option<Point> = None;
if highlights.len() > count { if ranges.len() > count {
return Vec::new(); return Vec::new();
} }
for highlight in &highlights[start_ix..] { for range in &ranges[start_ix..] {
if highlight if range
.range
.start .start
.cmp(&search_range.end, &display_snapshot.buffer_snapshot) .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
.is_ge() .is_ge()
{ {
break; break;
} }
let end = highlight let end = range.end.to_point(&display_snapshot.buffer_snapshot);
.range
.end
.to_point(&display_snapshot.buffer_snapshot);
if let Some(current_row) = &end_row { if let Some(current_row) = &end_row {
if end.row == current_row.row { if end.row == current_row.row {
continue; continue;
} }
} }
let start = highlight let start = range.start.to_point(&display_snapshot.buffer_snapshot);
.range
.start
.to_point(&display_snapshot.buffer_snapshot);
if start_row.is_none() { if start_row.is_none() {
assert_eq!(end_row, None); assert_eq!(end_row, None);
start_row = Some(start); start_row = Some(start);
@ -18968,11 +18925,13 @@ impl Editor {
pub fn highlight_text<T: 'static>( pub fn highlight_text<T: 'static>(
&mut self, &mut self,
ranges: Vec<(Range<Anchor>, HighlightStyle)>, ranges: Vec<Range<Anchor>>,
style: HighlightStyle,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
self.display_map self.display_map.update(cx, |map, _| {
.update(cx, |map, _| map.highlight_text(TypeId::of::<T>(), ranges)); map.highlight_text(TypeId::of::<T>(), ranges, style)
});
cx.notify(); cx.notify();
} }
@ -18991,7 +18950,7 @@ impl Editor {
pub fn text_highlights<'a, T: 'static>( pub fn text_highlights<'a, T: 'static>(
&'a self, &'a self,
cx: &'a App, cx: &'a App,
) -> Option<&'a [(Range<Anchor>, HighlightStyle)]> { ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
self.display_map.read(cx).text_highlights(TypeId::of::<T>()) self.display_map.read(cx).text_highlights(TypeId::of::<T>())
} }
@ -19004,14 +18963,6 @@ impl Editor {
} }
} }
pub fn remove_text_highlights<T: 'static>(
&mut self,
cx: &mut Context<Self>,
) -> Option<Vec<(Range<Anchor>, HighlightStyle)>> {
self.display_map
.update(cx, |map, _| map.remove_text_highlights(TypeId::of::<T>()))
}
pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool { pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
(self.read_only(cx) || self.blink_manager.read(cx).visible()) (self.read_only(cx) || self.blink_manager.read(cx).visible())
&& self.focus_handle.is_focused(window) && self.focus_handle.is_focused(window)
@ -19682,11 +19633,11 @@ impl Editor {
fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> { fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
let snapshot = self.buffer.read(cx).read(cx); let snapshot = self.buffer.read(cx).read(cx);
let ranges = self.text_highlights::<InputComposition>(cx)?; let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
Some( Some(
ranges ranges
.iter() .iter()
.map(move |(range, _)| { .map(move |range| {
range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot) range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
}) })
.collect(), .collect(),
@ -19997,12 +19948,9 @@ impl Editor {
pending = "".to_string(); pending = "".to_string();
} }
let existing_pending = self.text_highlights::<PendingInput>(cx).map(|ranges| { let existing_pending = self
ranges .text_highlights::<PendingInput>(cx)
.iter() .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
.map(|(range, _)| range.clone())
.collect::<Vec<_>>()
});
if existing_pending.is_none() && pending.is_empty() { if existing_pending.is_none() && pending.is_empty() {
return; return;
} }
@ -20030,27 +19978,28 @@ impl Editor {
.all::<usize>(cx) .all::<usize>(cx)
.into_iter() .into_iter()
.map(|selection| { .map(|selection| {
( snapshot.buffer_snapshot.anchor_after(selection.end)
snapshot.buffer_snapshot.anchor_after(selection.end) ..snapshot
..snapshot .buffer_snapshot
.buffer_snapshot .anchor_before(selection.end + pending.len())
.anchor_before(selection.end + pending.len()),
HighlightStyle {
underline: Some(UnderlineStyle {
thickness: px(1.),
color: None,
wavy: false,
}),
..Default::default()
},
)
}) })
.collect(); .collect();
if pending.is_empty() { if pending.is_empty() {
self.clear_highlights::<PendingInput>(cx); self.clear_highlights::<PendingInput>(cx);
} else { } else {
self.highlight_text::<PendingInput>(ranges, cx); self.highlight_text::<PendingInput>(
ranges,
HighlightStyle {
underline: Some(UnderlineStyle {
thickness: px(1.),
color: None,
wavy: false,
}),
..Default::default()
},
cx,
);
} }
self.ime_transaction = self.ime_transaction.or(transaction); self.ime_transaction = self.ime_transaction.or(transaction);
@ -22050,7 +21999,7 @@ impl EntityInputHandler for Editor {
fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> { fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
let snapshot = self.buffer.read(cx).read(cx); let snapshot = self.buffer.read(cx).read(cx);
let (range, _) = self.text_highlights::<InputComposition>(cx)?.first()?; let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0) Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
} }
@ -22187,18 +22136,7 @@ impl EntityInputHandler for Editor {
.disjoint_anchors() .disjoint_anchors()
.iter() .iter()
.map(|selection| { .map(|selection| {
( selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
selection.start.bias_left(&snapshot)
..selection.end.bias_right(&snapshot),
HighlightStyle {
underline: Some(UnderlineStyle {
thickness: px(1.),
color: None,
wavy: false,
}),
..Default::default()
},
)
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
}; };
@ -22206,7 +22144,18 @@ impl EntityInputHandler for Editor {
if text.is_empty() { if text.is_empty() {
this.unmark_text(window, cx); this.unmark_text(window, cx);
} else { } else {
this.highlight_text::<InputComposition>(marked_ranges.clone(), cx); this.highlight_text::<InputComposition>(
marked_ranges.clone(),
HighlightStyle {
underline: Some(UnderlineStyle {
thickness: px(1.),
color: None,
wavy: false,
}),
..Default::default()
},
cx,
);
} }
// Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard) // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
@ -22222,7 +22171,7 @@ impl EntityInputHandler for Editor {
let snapshot = this.buffer.read(cx).read(cx); let snapshot = this.buffer.read(cx).read(cx);
let new_selected_ranges = marked_ranges let new_selected_ranges = marked_ranges
.into_iter() .into_iter()
.map(|(marked_range, _)| { .map(|marked_range| {
let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0; let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
let new_start = OffsetUtf16(new_selected_range.start + insertion_start); let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
let new_end = OffsetUtf16(new_selected_range.end + insertion_start); let new_end = OffsetUtf16(new_selected_range.end + insertion_start);

View file

@ -13697,7 +13697,7 @@ fn test_highlighted_ranges(cx: &mut TestAppContext) {
let mut highlighted_ranges = editor.background_highlights_in_range( let mut highlighted_ranges = editor.background_highlights_in_range(
anchor_range(Point::new(3, 4)..Point::new(7, 4)), anchor_range(Point::new(3, 4)..Point::new(7, 4)),
&snapshot, &snapshot,
cx.theme(), cx.theme().colors(),
); );
// Enforce a consistent ordering based on color without relying on the ordering of the // Enforce a consistent ordering based on color without relying on the ordering of the
// highlight's `TypeId` which is non-executor. // highlight's `TypeId` which is non-executor.
@ -13727,7 +13727,7 @@ fn test_highlighted_ranges(cx: &mut TestAppContext) {
editor.background_highlights_in_range( editor.background_highlights_in_range(
anchor_range(Point::new(5, 6)..Point::new(6, 4)), anchor_range(Point::new(5, 6)..Point::new(6, 4)),
&snapshot, &snapshot,
cx.theme(), cx.theme().colors(),
), ),
&[( &[(
DisplayPoint::new(DisplayRow(6), 3)..DisplayPoint::new(DisplayRow(6), 5), DisplayPoint::new(DisplayRow(6), 3)..DisplayPoint::new(DisplayRow(6), 5),
@ -19392,10 +19392,8 @@ async fn test_folding_buffer_when_multibuffer_has_only_one_excerpt(cx: &mut Test
let multi_buffer_snapshot = editor.buffer().read(cx).snapshot(cx); let multi_buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
let highlight_range = selection_range.clone().to_anchors(&multi_buffer_snapshot); let highlight_range = selection_range.clone().to_anchors(&multi_buffer_snapshot);
editor.highlight_text::<TestHighlight>( editor.highlight_text::<TestHighlight>(
vec![( vec![highlight_range.clone()],
highlight_range.clone(), HighlightStyle::color(Hsla::green()),
HighlightStyle::color(Hsla::green()),
)],
cx, cx,
); );
editor.change_selections(None, window, cx, |s| s.select_ranges(Some(highlight_range))); editor.change_selections(None, window, cx, |s| s.select_ranges(Some(highlight_range)));
@ -20336,7 +20334,7 @@ async fn test_rename_with_duplicate_edits(cx: &mut TestAppContext) {
let highlight_range = highlight_range.to_anchors(&editor.buffer().read(cx).snapshot(cx)); let highlight_range = highlight_range.to_anchors(&editor.buffer().read(cx).snapshot(cx));
editor.highlight_background::<DocumentHighlightRead>( editor.highlight_background::<DocumentHighlightRead>(
&[highlight_range], &[highlight_range],
|c| c.colors().editor_document_highlight_read_background, |c| c.editor_document_highlight_read_background,
cx, cx,
); );
}); });
@ -20414,7 +20412,7 @@ async fn test_rename_without_prepare(cx: &mut TestAppContext) {
let highlight_range = highlight_range.to_anchors(&editor.buffer().read(cx).snapshot(cx)); let highlight_range = highlight_range.to_anchors(&editor.buffer().read(cx).snapshot(cx));
editor.highlight_background::<DocumentHighlightRead>( editor.highlight_background::<DocumentHighlightRead>(
&[highlight_range], &[highlight_range],
|c| c.colors().editor_document_highlight_read_background, |c| c.editor_document_highlight_read_background,
cx, cx,
); );
}); });

View file

@ -6162,7 +6162,7 @@ impl EditorElement {
); );
} }
for (background_highlight_id, background_highlights) in for (background_highlight_id, (_, background_ranges)) in
background_highlights.iter() background_highlights.iter()
{ {
let is_search_highlights = *background_highlight_id let is_search_highlights = *background_highlight_id
@ -6181,22 +6181,18 @@ impl EditorElement {
if is_symbol_occurrences { if is_symbol_occurrences {
color.fade_out(0.5); color.fade_out(0.5);
} }
let marker_row_ranges = let marker_row_ranges = background_ranges.iter().map(|range| {
background_highlights.iter().map(|highlight| { let display_start = range
let display_start = highlight .start
.range .to_display_point(&snapshot.display_snapshot);
.start let display_end =
.to_display_point(&snapshot.display_snapshot); range.end.to_display_point(&snapshot.display_snapshot);
let display_end = highlight ColoredRange {
.range start: display_start.row(),
.end end: display_end.row(),
.to_display_point(&snapshot.display_snapshot); color,
ColoredRange { }
start: display_start.row(), });
end: display_end.row(),
color,
}
});
marker_quads.extend( marker_quads.extend(
scrollbar_layout scrollbar_layout
.marker_quads_for_ranges(marker_row_ranges, Some(1)), .marker_quads_for_ranges(marker_row_ranges, Some(1)),
@ -8095,7 +8091,7 @@ impl Element for EditorElement {
editor.read(cx).background_highlights_in_range( editor.read(cx).background_highlights_in_range(
start_anchor..end_anchor, start_anchor..end_anchor,
&snapshot.display_snapshot, &snapshot.display_snapshot,
cx.theme(), cx.theme().colors(),
) )
}) })
.unwrap_or_default(); .unwrap_or_default();

View file

@ -40,7 +40,7 @@ pub fn refresh_matching_bracket_highlights(
opening_range.to_anchors(&snapshot.buffer_snapshot), opening_range.to_anchors(&snapshot.buffer_snapshot),
closing_range.to_anchors(&snapshot.buffer_snapshot), closing_range.to_anchors(&snapshot.buffer_snapshot),
], ],
|theme| theme.colors().editor_document_highlight_bracket_background, |theme| theme.editor_document_highlight_bracket_background,
cx, cx,
) )
} }

View file

@ -635,7 +635,7 @@ pub fn show_link_definition(
match highlight_range { match highlight_range {
RangeInEditor::Text(text_range) => editor RangeInEditor::Text(text_range) => editor
.highlight_text::<HoveredLinkState>(vec![(text_range, style)], cx), .highlight_text::<HoveredLinkState>(vec![text_range], style, cx),
RangeInEditor::Inlay(highlight) => editor RangeInEditor::Inlay(highlight) => editor
.highlight_inlays::<HoveredLinkState>(vec![highlight], style, cx), .highlight_inlays::<HoveredLinkState>(vec![highlight], style, cx),
} }
@ -1403,6 +1403,7 @@ mod tests {
let snapshot = editor.snapshot(window, cx); let snapshot = editor.snapshot(window, cx);
let actual_ranges = snapshot let actual_ranges = snapshot
.text_highlight_ranges::<HoveredLinkState>() .text_highlight_ranges::<HoveredLinkState>()
.map(|ranges| ranges.as_ref().clone().1)
.unwrap_or_default(); .unwrap_or_default();
assert!(actual_ranges.is_empty(), "When no cmd is pressed, should have no hint label selected, but got: {actual_ranges:?}"); assert!(actual_ranges.is_empty(), "When no cmd is pressed, should have no hint label selected, but got: {actual_ranges:?}");
@ -1634,6 +1635,7 @@ mod tests {
.snapshot(window, cx) .snapshot(window, cx)
.text_highlight_ranges::<HoveredLinkState>() .text_highlight_ranges::<HoveredLinkState>()
.unwrap_or_default() .unwrap_or_default()
.1
.is_empty() .is_empty()
); );
}); });
@ -1840,6 +1842,7 @@ mod tests {
.snapshot(window, cx) .snapshot(window, cx)
.text_highlight_ranges::<HoveredLinkState>() .text_highlight_ranges::<HoveredLinkState>()
.unwrap_or_default() .unwrap_or_default()
.1
.is_empty() .is_empty()
); );
}); });

View file

@ -520,7 +520,7 @@ fn show_hover(
// Highlight the selected symbol using a background highlight // Highlight the selected symbol using a background highlight
editor.highlight_background::<HoverState>( editor.highlight_background::<HoverState>(
&hover_highlights, &hover_highlights,
|theme| theme.colors().element_hover, // todo update theme |theme| theme.element_hover, // todo update theme
cx, cx,
); );
} }

View file

@ -1432,11 +1432,8 @@ impl SearchableItem for Editor {
fn get_matches(&self, _window: &mut Window, _: &mut App) -> Vec<Range<Anchor>> { fn get_matches(&self, _window: &mut Window, _: &mut App) -> Vec<Range<Anchor>> {
self.background_highlights self.background_highlights
.get(&TypeId::of::<BufferSearchHighlights>()) .get(&TypeId::of::<BufferSearchHighlights>())
.map_or(Vec::new(), |highlights| { .map_or(Vec::new(), |(_color, ranges)| {
highlights ranges.iter().cloned().collect()
.iter()
.map(|highlight| highlight.range.clone())
.collect()
}) })
} }
@ -1455,14 +1452,14 @@ impl SearchableItem for Editor {
_: &mut Window, _: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
let existing_ranges = self let existing_range = self
.background_highlights .background_highlights
.get(&TypeId::of::<BufferSearchHighlights>()) .get(&TypeId::of::<BufferSearchHighlights>())
.map(|highlights| highlights.iter().map(|highlight| &highlight.range)); .map(|(_, range)| range.as_ref());
let updated = !existing_ranges.is_some_and(|existing_ranges| existing_ranges.eq(matches)); let updated = existing_range != Some(matches);
self.highlight_background::<BufferSearchHighlights>( self.highlight_background::<BufferSearchHighlights>(
matches, matches,
|theme| theme.colors().search_match_background, |theme| theme.search_match_background,
cx, cx,
); );
if updated { if updated {
@ -1483,12 +1480,7 @@ impl SearchableItem for Editor {
if self.has_filtered_search_ranges() { if self.has_filtered_search_ranges() {
self.previous_search_ranges = self self.previous_search_ranges = self
.clear_background_highlights::<SearchWithinRange>(cx) .clear_background_highlights::<SearchWithinRange>(cx)
.map(|highlights| { .map(|(_, ranges)| ranges)
highlights
.iter()
.map(|highlight| highlight.range.clone())
.collect()
})
} }
if !enabled { if !enabled {
@ -1710,11 +1702,8 @@ impl SearchableItem for Editor {
let search_within_ranges = self let search_within_ranges = self
.background_highlights .background_highlights
.get(&TypeId::of::<SearchWithinRange>()) .get(&TypeId::of::<SearchWithinRange>())
.map_or(vec![], |highlights| { .map_or(vec![], |(_color, ranges)| {
highlights ranges.iter().cloned().collect::<Vec<_>>()
.iter()
.map(|highlight| highlight.range.clone())
.collect::<Vec<_>>()
}); });
cx.background_spawn(async move { cx.background_spawn(async move {

View file

@ -510,9 +510,10 @@ impl EditorTestContext {
editor editor
.background_highlights .background_highlights
.get(&TypeId::of::<Tag>()) .get(&TypeId::of::<Tag>())
.into_iter() .map(|h| h.1.clone())
.flat_map(|highlights| highlights.as_slice()) .unwrap_or_default()
.map(|highlight| highlight.range.to_offset(&snapshot.buffer_snapshot)) .iter()
.map(|range| range.to_offset(&snapshot.buffer_snapshot))
.collect() .collect()
}); });
assert_set_eq!(actual_ranges, expected_ranges); assert_set_eq!(actual_ranges, expected_ranges);
@ -524,12 +525,7 @@ impl EditorTestContext {
let snapshot = self.update_editor(|editor, window, cx| editor.snapshot(window, cx)); let snapshot = self.update_editor(|editor, window, cx| editor.snapshot(window, cx));
let actual_ranges: Vec<Range<usize>> = snapshot let actual_ranges: Vec<Range<usize>> = snapshot
.text_highlight_ranges::<Tag>() .text_highlight_ranges::<Tag>()
.map(|ranges| { .map(|ranges| ranges.as_ref().clone().1)
ranges
.iter()
.map(|(range, _)| range.clone())
.collect::<Vec<_>>()
})
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
.map(|range| range.to_offset(&snapshot.buffer_snapshot)) .map(|range| range.to_offset(&snapshot.buffer_snapshot))

View file

@ -358,7 +358,7 @@ impl Render for SyntaxTreeView {
editor.clear_background_highlights::<Self>( cx); editor.clear_background_highlights::<Self>( cx);
editor.highlight_background::<Self>( editor.highlight_background::<Self>(
&[range], &[range],
|theme| theme.colors().editor_document_highlight_write_background, |theme| theme.editor_document_highlight_write_background,
cx, cx,
); );
}); });

View file

@ -1547,7 +1547,7 @@ fn dap_client_capabilities(adapter_id: String) -> InitializeRequestArguments {
supports_memory_event: Some(false), supports_memory_event: Some(false),
supports_args_can_be_interpreted_by_shell: Some(false), supports_args_can_be_interpreted_by_shell: Some(false),
supports_start_debugging_request: Some(true), supports_start_debugging_request: Some(true),
supports_ansistyling: Some(true), supports_ansistyling: Some(false),
} }
} }

View file

@ -1377,7 +1377,7 @@ impl ProjectSearchView {
} }
editor.highlight_background::<Self>( editor.highlight_background::<Self>(
&match_ranges, &match_ranges,
|theme| theme.colors().search_match_background, |theme| theme.search_match_background,
cx, cx,
); );
}); });

View file

@ -222,7 +222,7 @@ impl Vim {
editor.highlight_background::<HighlightOnYank>( editor.highlight_background::<HighlightOnYank>(
&ranges_to_highlight, &ranges_to_highlight,
|theme| theme.colors().editor_document_highlight_read_background, |colors| colors.editor_document_highlight_read_background,
cx, cx,
); );
cx.spawn(async move |this, cx| { cx.spawn(async move |this, cx| {

View file

@ -217,8 +217,8 @@ impl Vim {
window: &mut Window, window: &mut Window,
cx: &mut Context<Editor>, cx: &mut Context<Editor>,
) { ) {
if let Some(highlights) = editor.clear_background_highlights::<VimExchange>(cx) { if let Some((_, ranges)) = editor.clear_background_highlights::<VimExchange>(cx) {
let previous_range = highlights[0].range.clone(); let previous_range = ranges[0].clone();
let new_range_start = new_range.start.to_offset(&snapshot.buffer_snapshot); let new_range_start = new_range.start.to_offset(&snapshot.buffer_snapshot);
let new_range_end = new_range.end.to_offset(&snapshot.buffer_snapshot); let new_range_end = new_range.end.to_offset(&snapshot.buffer_snapshot);
@ -261,7 +261,7 @@ impl Vim {
let ranges = [new_range]; let ranges = [new_range];
editor.highlight_background::<VimExchange>( editor.highlight_background::<VimExchange>(
&ranges, &ranges,
|theme| theme.colors().editor_document_highlight_read_background, |theme| theme.editor_document_highlight_read_background,
cx, cx,
); );
} }

View file

@ -864,13 +864,16 @@ async fn test_jk(cx: &mut gpui::TestAppContext) {
fn assert_pending_input(cx: &mut VimTestContext, expected: &str) { fn assert_pending_input(cx: &mut VimTestContext, expected: &str) {
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx); let snapshot = editor.snapshot(window, cx);
let highlights = editor.text_highlights::<editor::PendingInput>(cx).unwrap(); let highlights = editor
.text_highlights::<editor::PendingInput>(cx)
.unwrap()
.1;
let (_, ranges) = marked_text_ranges(expected, false); let (_, ranges) = marked_text_ranges(expected, false);
assert_eq!( assert_eq!(
highlights highlights
.iter() .iter()
.map(|(highlight, _)| highlight.to_offset(&snapshot.buffer_snapshot)) .map(|highlight| highlight.to_offset(&snapshot.buffer_snapshot))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
ranges ranges
) )
@ -920,12 +923,15 @@ async fn test_jk_delay(cx: &mut gpui::TestAppContext) {
cx.assert_state("ˇjhello", Mode::Insert); cx.assert_state("ˇjhello", Mode::Insert);
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
let snapshot = editor.snapshot(window, cx); let snapshot = editor.snapshot(window, cx);
let highlights = editor.text_highlights::<editor::PendingInput>(cx).unwrap(); let highlights = editor
.text_highlights::<editor::PendingInput>(cx)
.unwrap()
.1;
assert_eq!( assert_eq!(
highlights highlights
.iter() .iter()
.map(|(highlight, _)| highlight.to_offset(&snapshot.buffer_snapshot)) .map(|highlight| highlight.to_offset(&snapshot.buffer_snapshot))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
vec![0..1] vec![0..1]
) )