feat(input): support custom text highlights

This commit is contained in:
Daniel Bulant 2026-08-19 00:48:55 +02:00
parent 420d333eb5
commit 4d0dde1f23
No known key found for this signature in database
2 changed files with 45 additions and 22 deletions

View file

@ -752,11 +752,11 @@ impl TextElement {
} => (highlighter.borrow(), diagnostics),
_ => return None,
};
let highlighter = highlighter.as_ref()?;
let mut offset = visible_byte_range.start;
let highlighter = highlighter.as_ref();
let mut styles = vec![];
if let Some(highlighter) = highlighter {
let mut offset = visible_byte_range.start;
for line in text
.iter_lines()
.skip(visible_range.start)
@ -775,6 +775,12 @@ impl TextElement {
offset = range.end;
}
}
let custom_styles = state.custom_highlights.iter().filter(|(range, _)| {
range.start < visible_byte_range.end && range.end > visible_byte_range.start
});
styles = gpui::combine_highlights(styles, custom_styles.cloned()).collect();
let diagnostic_styles = diagnostics.styles_for_range(&visible_byte_range, cx);

View file

@ -5,10 +5,11 @@
use anyhow::Result;
use gpui::{
Action, App, AppContext, Bounds, ClipboardItem, Context, Entity, EntityInputHandler,
EventEmitter, FocusHandle, Focusable, InteractiveElement as _, IntoElement, KeyBinding,
KeyDownEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _,
Pixels, Point, Render, ScrollHandle, ScrollWheelEvent, SharedString, Styled as _, Subscription,
Task, UTF16Selection, Window, actions, div, point, prelude::FluentBuilder as _, px,
EventEmitter, FocusHandle, Focusable, HighlightStyle, InteractiveElement as _, IntoElement,
KeyBinding, KeyDownEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
ParentElement as _, Pixels, Point, Render, ScrollHandle, ScrollWheelEvent, SharedString,
Styled as _, Subscription, Task, UTF16Selection, Window, actions, div, point,
prelude::FluentBuilder as _, px,
};
use ropey::{Rope, RopeSlice};
use serde::Deserialize;
@ -298,6 +299,8 @@ pub struct InputState {
pub(crate) deferred_scroll_offset: Option<Point<Pixels>>,
/// The size of the scrollable content.
pub(crate) scroll_size: gpui::Size<Pixels>,
/// Additional presentation-only styles keyed by UTF-8 byte range.
pub(super) custom_highlights: Vec<(Range<usize>, HighlightStyle)>,
/// The mask pattern for formatting the input text
pub(crate) mask_pattern: MaskPattern,
@ -395,6 +398,7 @@ impl InputState {
scroll_handle: ScrollHandle::new(),
scroll_size: gpui::size(px(0.), px(0.)),
deferred_scroll_offset: None,
custom_highlights: Vec::new(),
preferred_column: None,
placeholder: SharedString::default(),
mask_pattern: MaskPattern::default(),
@ -529,6 +533,19 @@ impl InputState {
cx.notify();
}
/// Replace presentation-only text styles keyed by UTF-8 byte range.
///
/// Custom highlights are combined with syntax and diagnostic highlights and do not alter
/// the editor text, selection, or history.
pub fn set_custom_highlights(
&mut self,
highlights: Vec<(Range<usize>, HighlightStyle)>,
cx: &mut Context<Self>,
) {
self.custom_highlights = highlights;
cx.notify();
}
fn reset_highlighter(&mut self, cx: &mut Context<Self>) {
match &mut self.mode {
InputMode::CodeEditor { highlighter, .. } => {