Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T04:44:35.454Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

custom_highlights.rs

422 lines · 15.5 KB · rust
1use collections::BTreeMap;
2use gpui::HighlightStyle;
3use language::{Chunk, LanguageAwareStyling};
4use multi_buffer::{MultiBufferChunks, MultiBufferOffset, MultiBufferSnapshot};
5use std::{cmp, ops::Range};
6
7use crate::display_map::{HighlightKey, SemanticTokensHighlights, TextHighlights};
8
9pub struct CustomHighlightsChunks<'a> {
10    buffer_chunks: MultiBufferChunks<'a>,
11    buffer_chunk: Option<Chunk<'a>>,
12    offset: MultiBufferOffset,
13    multibuffer_snapshot: &'a MultiBufferSnapshot,
14
15    highlight_endpoints: Vec<HighlightEndpoint>,
16    active_highlights: BTreeMap<HighlightKey, HighlightStyle>,
17    text_highlights: Option<&'a TextHighlights>,
18    semantic_token_highlights: Option<&'a SemanticTokensHighlights>,
19}
20
21#[derive(Debug, Copy, Clone, Eq, PartialEq)]
22struct HighlightEndpoint {
23    offset: MultiBufferOffset,
24    tag: HighlightKey,
25    style: Option<HighlightStyle>,
26}
27
28impl<'a> CustomHighlightsChunks<'a> {
29    #[ztracing::instrument(skip_all)]
30    pub fn new(
31        range: Range<MultiBufferOffset>,
32        language_aware: LanguageAwareStyling,
33        text_highlights: Option<&'a TextHighlights>,
34        semantic_token_highlights: Option<&'a SemanticTokensHighlights>,
35        multibuffer_snapshot: &'a MultiBufferSnapshot,
36    ) -> Self {
37        let mut highlight_endpoints = Vec::new();
38        create_highlight_endpoints(
39            &range,
40            text_highlights,
41            semantic_token_highlights,
42            multibuffer_snapshot,
43            &mut highlight_endpoints,
44        );
45        Self {
46            buffer_chunks: multibuffer_snapshot.chunks(range.clone(), language_aware),
47            buffer_chunk: None,
48            offset: range.start,
49            text_highlights,
50            highlight_endpoints,
51            active_highlights: Default::default(),
52            multibuffer_snapshot,
53            semantic_token_highlights,
54        }
55    }
56
57    #[ztracing::instrument(skip_all)]
58    pub fn seek(&mut self, new_range: Range<MultiBufferOffset>) {
59        create_highlight_endpoints(
60            &new_range,
61            self.text_highlights,
62            self.semantic_token_highlights,
63            self.multibuffer_snapshot,
64            &mut self.highlight_endpoints,
65        );
66        self.offset = new_range.start;
67        self.buffer_chunks.seek(new_range);
68        self.buffer_chunk.take();
69        self.active_highlights.clear()
70    }
71}
72
73fn create_highlight_endpoints(
74    range: &Range<MultiBufferOffset>,
75    text_highlights: Option<&TextHighlights>,
76    semantic_token_highlights: Option<&SemanticTokensHighlights>,
77    buffer: &MultiBufferSnapshot,
78    highlight_endpoints: &mut Vec<HighlightEndpoint>,
79) {
80    highlight_endpoints.clear();
81    if let Some(text_highlights) = text_highlights {
82        let start = buffer.anchor_after(range.start);
83        let end = buffer.anchor_after(range.end);
84        let mut text_highlights_scratch = Vec::new();
85
86        for (&tag, text_highlights) in text_highlights.iter() {
87            let style = text_highlights.0;
88            let ranges = &text_highlights.1;
89
90            let start_ix = ranges
91                .binary_search_by(|probe| probe.end.cmp(&start, buffer).then(cmp::Ordering::Less))
92                .unwrap_or_else(|i| i);
93            let end_ix = ranges[start_ix..]
94                .binary_search_by(|probe| {
95                    probe.start.cmp(&end, buffer).then(cmp::Ordering::Greater)
96                })
97                .unwrap_or_else(|i| i);
98
99            let ranges_ = &ranges[start_ix..][..end_ix];
100            text_highlights_scratch.clear();
101            text_highlights_scratch.reserve(ranges_.len());
102            highlight_endpoints.reserve(2 * ranges_.len());
103
104            let mut iter = ranges_.iter();
105            buffer.summaries_for_anchors_cb(
106                ranges_.iter().map(|r| &r.start),
107                |start: MultiBufferOffset| {
108                    text_highlights_scratch.push((start, iter.next().unwrap().end));
109                },
110            );
111            text_highlights_scratch.sort_by(|a, b| a.1.cmp(&b.1, buffer));
112            let mut iter = text_highlights_scratch.iter();
113            buffer.summaries_for_anchors_cb(
114                text_highlights_scratch.iter().map(|(_, end)| end),
115                |end: MultiBufferOffset| {
116                    let start = iter.next().unwrap().0;
117                    if start == end {
118                        return;
119                    }
120                    highlight_endpoints.push(HighlightEndpoint {
121                        offset: start,
122                        tag,
123                        style: Some(style),
124                    });
125                    highlight_endpoints.push(HighlightEndpoint {
126                        offset: end,
127                        tag,
128                        style: None,
129                    });
130                },
131            );
132        }
133    }
134    if let Some(semantic_token_highlights) = semantic_token_highlights {
135        let start = buffer.anchor_after(range.start);
136        let end = buffer.anchor_after(range.end);
137        let mut semantic_highlights_scratch = Vec::new();
138        for buffer_id in buffer.buffer_ids_for_range(range.clone()) {
139            let Some((semantic_token_highlights, interner)) =
140                semantic_token_highlights.get(&buffer_id)
141            else {
142                continue;
143            };
144            let start_ix = semantic_token_highlights
145                .binary_search_by(|probe| {
146                    probe
147                        .range
148                        .end
149                        .cmp(&start, buffer)
150                        .then(cmp::Ordering::Less)
151                })
152                .unwrap_or_else(|i| i);
153            let end_ix = semantic_token_highlights[start_ix..]
154                .binary_search_by(|probe| {
155                    probe
156                        .range
157                        .start
158                        .cmp(&end, buffer)
159                        .then(cmp::Ordering::Greater)
160                })
161                .unwrap_or_else(|i| i);
162
163            let ranges_ = &semantic_token_highlights[start_ix..][..end_ix];
164            semantic_highlights_scratch.clear();
165            semantic_highlights_scratch.reserve(ranges_.len());
166            highlight_endpoints.reserve(2 * ranges_.len());
167
168            let mut iter = ranges_.iter();
169            buffer.summaries_for_anchors_cb(
170                ranges_.iter().map(|token| &token.range.start),
171                |start: MultiBufferOffset| {
172                    semantic_highlights_scratch.push((start, iter.next().unwrap()));
173                },
174            );
175            semantic_highlights_scratch.sort_by(|a, b| a.1.range.end.cmp(&b.1.range.end, buffer));
176            let mut iter = semantic_highlights_scratch.iter();
177            buffer.summaries_for_anchors_cb(
178                semantic_highlights_scratch
179                    .iter()
180                    .map(|(_, token)| &token.range.end),
181                |end: MultiBufferOffset| {
182                    let (start, token) = iter.next().unwrap();
183                    if *start == end {
184                        return;
185                    }
186                    highlight_endpoints.push(HighlightEndpoint {
187                        offset: *start,
188                        tag: HighlightKey::SemanticToken,
189                        style: Some(interner[token.style]),
190                    });
191                    highlight_endpoints.push(HighlightEndpoint {
192                        offset: end,
193                        tag: HighlightKey::SemanticToken,
194                        style: None,
195                    });
196                },
197            );
198        }
199    }
200    highlight_endpoints.sort_by(|a, b| a.cmp(b).reverse());
201}
202
203impl<'a> Iterator for CustomHighlightsChunks<'a> {
204    type Item = Chunk<'a>;
205
206    #[ztracing::instrument(skip_all)]
207    fn next(&mut self) -> Option<Self::Item> {
208        let mut next_highlight_endpoint = MultiBufferOffset(usize::MAX);
209        while let Some(endpoint) = self.highlight_endpoints.last().copied() {
210            if endpoint.offset <= self.offset {
211                if let Some(style) = endpoint.style {
212                    self.active_highlights.insert(endpoint.tag, style);
213                } else {
214                    self.active_highlights.remove(&endpoint.tag);
215                }
216                self.highlight_endpoints.pop();
217            } else {
218                next_highlight_endpoint = endpoint.offset;
219                break;
220            }
221        }
222
223        let chunk = match &mut self.buffer_chunk {
224            Some(it) => it,
225            slot => slot.insert(self.buffer_chunks.next()?),
226        };
227        while chunk.text.is_empty() {
228            *chunk = self.buffer_chunks.next()?;
229        }
230
231        let split_idx = chunk.text.len().min(next_highlight_endpoint - self.offset);
232        let (prefix, suffix) = chunk.text.split_at(split_idx);
233        self.offset += prefix.len();
234
235        let mask = 1u128.unbounded_shl(split_idx as u32).wrapping_sub(1);
236        let chars = chunk.chars & mask;
237        let tabs = chunk.tabs & mask;
238        let newlines = chunk.newlines & mask;
239        let mut prefix = Chunk {
240            text: prefix,
241            chars,
242            tabs,
243            newlines,
244            ..chunk.clone()
245        };
246
247        chunk.chars = chunk.chars.unbounded_shr(split_idx as u32);
248        chunk.tabs = chunk.tabs.unbounded_shr(split_idx as u32);
249        chunk.newlines = chunk.newlines.unbounded_shr(split_idx as u32);
250        chunk.text = suffix;
251        if !self.active_highlights.is_empty() {
252            prefix.highlight_style = self
253                .active_highlights
254                .values()
255                .copied()
256                .reduce(|acc, active_highlight| acc.highlight(active_highlight));
257        }
258        Some(prefix)
259    }
260}
261
262impl PartialOrd for HighlightEndpoint {
263    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
264        Some(self.cmp(other))
265    }
266}
267
268impl Ord for HighlightEndpoint {
269    fn cmp(&self, other: &Self) -> cmp::Ordering {
270        self.offset
271            .cmp(&other.offset)
272            .then_with(|| self.style.is_some().cmp(&other.style.is_some()))
273            .then_with(|| self.tag.cmp(&other.tag))
274    }
275}
276
277#[cfg(test)]
278mod tests {
279    use std::sync::Arc;
280
281    use super::*;
282    use crate::MultiBuffer;
283    use gpui::App;
284    use rand::prelude::*;
285    use util::RandomCharIter;
286
287    #[gpui::test(iterations = 100)]
288    fn test_random_chunk_bitmaps(cx: &mut App, mut rng: StdRng) {
289        // Generate random buffer using existing test infrastructure
290        let len = rng.random_range(10..10000);
291        let buffer = if rng.random() {
292            let text = RandomCharIter::new(&mut rng).take(len).collect::<String>();
293            MultiBuffer::build_simple(&text, cx)
294        } else {
295            MultiBuffer::build_random(&mut rng, cx)
296        };
297
298        let buffer_snapshot = buffer.read(cx).snapshot(cx);
299
300        // Create random highlights
301        let mut highlights = sum_tree::TreeMap::default();
302        let highlight_count = rng.random_range(1..10);
303
304        for _i in 0..highlight_count {
305            let style = HighlightStyle {
306                color: Some(gpui::Hsla {
307                    h: rng.random::<f32>(),
308                    s: rng.random::<f32>(),
309                    l: rng.random::<f32>(),
310                    a: 1.0,
311                }),
312                ..Default::default()
313            };
314
315            let mut ranges = Vec::new();
316            let range_count = rng.random_range(1..10);
317            let text = buffer_snapshot.text();
318            for _ in 0..range_count {
319                if buffer_snapshot.len() == MultiBufferOffset(0) {
320                    continue;
321                }
322
323                let mut start = rng.random_range(
324                    MultiBufferOffset(0)..=buffer_snapshot.len().saturating_sub_usize(10),
325                );
326
327                while !text.is_char_boundary(start.0) {
328                    start = start.saturating_sub_usize(1);
329                }
330
331                let end_end = buffer_snapshot.len().min(start + 100usize);
332                let mut end = rng.random_range(start..=end_end);
333                while !text.is_char_boundary(end.0) {
334                    end = end.saturating_sub_usize(1);
335                }
336
337                if start < end {
338                    start = end;
339                }
340                let start_anchor = buffer_snapshot.anchor_before(start);
341                let end_anchor = buffer_snapshot.anchor_after(end);
342                ranges.push(start_anchor..end_anchor);
343            }
344
345            highlights.insert(HighlightKey::Editor, Arc::new((style, ranges)));
346        }
347
348        // Get all chunks and verify their bitmaps
349        let chunks = CustomHighlightsChunks::new(
350            MultiBufferOffset(0)..buffer_snapshot.len(),
351            LanguageAwareStyling {
352                tree_sitter: false,
353                diagnostics: false,
354            },
355            None,
356            None,
357            &buffer_snapshot,
358        );
359
360        for chunk in chunks {
361            let chunk_text = chunk.text;
362            let chars_bitmap = chunk.chars;
363            let tabs_bitmap = chunk.tabs;
364
365            // Check empty chunks have empty bitmaps
366            if chunk_text.is_empty() {
367                assert_eq!(
368                    chars_bitmap, 0,
369                    "Empty chunk should have empty chars bitmap"
370                );
371                assert_eq!(tabs_bitmap, 0, "Empty chunk should have empty tabs bitmap");
372                continue;
373            }
374
375            // Verify that chunk text doesn't exceed 128 bytes
376            assert!(
377                chunk_text.len() <= 128,
378                "Chunk text length {} exceeds 128 bytes",
379                chunk_text.len()
380            );
381
382            // Verify chars bitmap
383            let char_indices = chunk_text
384                .char_indices()
385                .map(|(i, _)| i)
386                .collect::<Vec<_>>();
387
388            for byte_idx in 0..chunk_text.len() {
389                let should_have_bit = char_indices.contains(&byte_idx);
390                let has_bit = chars_bitmap & (1 << byte_idx) != 0;
391
392                if has_bit != should_have_bit {
393                    eprintln!("Chunk text bytes: {:?}", chunk_text.as_bytes());
394                    eprintln!("Char indices: {:?}", char_indices);
395                    eprintln!("Chars bitmap: {:#b}", chars_bitmap);
396                    assert_eq!(
397                        has_bit, should_have_bit,
398                        "Chars bitmap mismatch at byte index {} in chunk {:?}. Expected bit: {}, Got bit: {}",
399                        byte_idx, chunk_text, should_have_bit, has_bit
400                    );
401                }
402            }
403
404            // Verify tabs bitmap
405            for (byte_idx, byte) in chunk_text.bytes().enumerate() {
406                let is_tab = byte == b'\t';
407                let has_bit = tabs_bitmap & (1 << byte_idx) != 0;
408
409                if has_bit != is_tab {
410                    eprintln!("Chunk text bytes: {:?}", chunk_text.as_bytes());
411                    eprintln!("Tabs bitmap: {:#b}", tabs_bitmap);
412                    assert_eq!(
413                        has_bit, is_tab,
414                        "Tabs bitmap mismatch at byte index {} in chunk {:?}. Byte: {:?}, Expected bit: {}, Got bit: {}",
415                        byte_idx, chunk_text, byte as char, is_tab, has_bit
416                    );
417                }
418            }
419        }
420    }
421}
422
Served at tenant.openagents/omega Member data and write actions are omitted.