tree_house/
injections_query.rs

1use std::cmp::Reverse;
2use std::iter::{self, Peekable};
3use std::mem::take;
4use std::sync::Arc;
5
6use arc_swap::ArcSwap;
7use hashbrown::{HashMap, HashSet};
8use once_cell::sync::Lazy;
9use regex_cursor::engines::meta::Regex;
10use ropey::RopeSlice;
11
12use crate::config::{LanguageConfig, LanguageLoader};
13use crate::highlighter::Highlight;
14use crate::locals::Locals;
15use crate::parse::LayerUpdateFlags;
16use crate::{Injection, Language, Layer, LayerData, Range, Syntax, TREE_SITTER_MATCH_LIMIT};
17use tree_sitter::{
18    query::{self, InvalidPredicateError, UserPredicate},
19    Capture, Grammar, InactiveQueryCursor, MatchedNodeIdx, Node, Pattern, Query, QueryMatch,
20};
21
22const SHEBANG: &str = r"#!\s*(?:\S*[/\\](?:env\s+(?:\-\S+\s+)*)?)?([^\s\.\d]+)";
23static SHEBANG_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(SHEBANG).unwrap());
24
25#[derive(Clone, Default, Debug)]
26pub struct InjectionProperties {
27    include_children: IncludedChildren,
28    language: Option<Box<str>>,
29    combined: bool,
30}
31
32/// An indicator in the document or query source file which used by the loader to know which
33/// language an injection should use.
34///
35/// For example if a query sets a property `(#set! injection.language "rust")` then the loader
36/// should load the Rust language. Alternatively the loader might be asked to load a language
37/// based on some text in the document, for example a markdown code fence language name.
38#[derive(Debug, Clone, Copy)]
39pub enum InjectionLanguageMarker<'a> {
40    /// The language is specified by name in the injection query itself.
41    ///
42    /// For example `(#set! injection.language "rust")`. These names should match exactly and so
43    /// they can be looked up by equality - very efficiently.
44    Name(&'a str),
45    /// The language is specified by name - or similar - within the parsed document.
46    ///
47    /// This is slightly different than the `ExactName` variant: within a document you might
48    /// specify Markdown as "md" or "markdown" for example. The loader should look up the language
49    /// name by longest matching regex.
50    Match(RopeSlice<'a>),
51    Filename(RopeSlice<'a>),
52    Shebang(RopeSlice<'a>),
53}
54
55#[derive(Clone, Debug)]
56pub struct InjectionQueryMatch<'tree> {
57    include_children: IncludedChildren,
58    language: Language,
59    scope: Option<InjectionScope>,
60    node: Node<'tree>,
61    last_match: bool,
62    pattern: Pattern,
63}
64
65#[derive(Clone, Debug, Hash, PartialEq, Eq)]
66enum InjectionScope {
67    Match {
68        id: u32,
69    },
70    Pattern {
71        pattern: Pattern,
72        language: Language,
73    },
74}
75
76#[derive(Clone, Default, Debug, PartialEq, Eq)]
77enum IncludedChildren {
78    #[default]
79    None,
80    All,
81    Unnamed,
82}
83
84#[derive(Debug)]
85pub struct InjectionsQuery {
86    injection_query: Query,
87    injection_properties: HashMap<Pattern, InjectionProperties>,
88    injection_content_capture: Option<Capture>,
89    injection_language_capture: Option<Capture>,
90    injection_filename_capture: Option<Capture>,
91    injection_shebang_capture: Option<Capture>,
92    // Note that the injections query is concatenated with the locals query.
93    pub(crate) local_query: Query,
94    // TODO: Use a Vec<bool> instead?
95    pub(crate) not_scope_inherits: HashSet<Pattern>,
96    pub(crate) local_scope_capture: Option<Capture>,
97    pub(crate) local_definition_captures: ArcSwap<HashMap<Capture, Highlight>>,
98}
99
100impl InjectionsQuery {
101    pub fn new(
102        grammar: Grammar,
103        injection_query_text: &str,
104        local_query_text: &str,
105    ) -> Result<Self, query::ParseError> {
106        let mut query_source =
107            String::with_capacity(injection_query_text.len() + local_query_text.len());
108        query_source.push_str(injection_query_text);
109        query_source.push_str(local_query_text);
110
111        let mut injection_properties: HashMap<Pattern, InjectionProperties> = HashMap::new();
112        let mut not_scope_inherits = HashSet::new();
113        let injection_query = Query::new(grammar, injection_query_text, |pattern, predicate| {
114            match predicate {
115                // injections
116                UserPredicate::SetProperty {
117                    key: "injection.include-unnamed-children",
118                    val: None,
119                } => {
120                    injection_properties
121                        .entry(pattern)
122                        .or_default()
123                        .include_children = IncludedChildren::Unnamed
124                }
125                UserPredicate::SetProperty {
126                    key: "injection.include-children",
127                    val: None,
128                } => {
129                    injection_properties
130                        .entry(pattern)
131                        .or_default()
132                        .include_children = IncludedChildren::All
133                }
134                UserPredicate::SetProperty {
135                    key: "injection.language",
136                    val: Some(lang),
137                } => injection_properties.entry(pattern).or_default().language = Some(lang.into()),
138                UserPredicate::SetProperty {
139                    key: "injection.combined",
140                    val: None,
141                } => injection_properties.entry(pattern).or_default().combined = true,
142                predicate => {
143                    return Err(InvalidPredicateError::unknown(predicate));
144                }
145            }
146            Ok(())
147        })?;
148        let mut local_query = Query::new(grammar, local_query_text, |pattern, predicate| {
149            match predicate {
150                UserPredicate::SetProperty {
151                    key: "local.scope-inherits",
152                    val,
153                } => {
154                    if val.is_some_and(|val| val != "true") {
155                        not_scope_inherits.insert(pattern);
156                    }
157                }
158                predicate => {
159                    return Err(InvalidPredicateError::unknown(predicate));
160                }
161            }
162            Ok(())
163        })?;
164
165        // The injection queries do not track references - these are read by the highlight
166        // query instead.
167        local_query.disable_capture("local.reference");
168
169        Ok(InjectionsQuery {
170            injection_properties,
171            injection_content_capture: injection_query.get_capture("injection.content"),
172            injection_language_capture: injection_query.get_capture("injection.language"),
173            injection_filename_capture: injection_query.get_capture("injection.filename"),
174            injection_shebang_capture: injection_query.get_capture("injection.shebang"),
175            injection_query,
176            not_scope_inherits,
177            local_scope_capture: local_query.get_capture("local.scope"),
178            local_definition_captures: ArcSwap::from_pointee(HashMap::new()),
179            local_query,
180        })
181    }
182
183    pub(crate) fn configure(&self, f: &mut impl FnMut(&str) -> Option<Highlight>) {
184        let local_definition_captures = self
185            .local_query
186            .captures()
187            .filter_map(|(capture, name)| {
188                let suffix = name.strip_prefix("local.definition.")?;
189                Some((capture, f(suffix)?))
190            })
191            .collect();
192        self.local_definition_captures
193            .store(Arc::new(local_definition_captures));
194    }
195
196    fn process_match<'a, 'tree>(
197        &self,
198        query_match: &QueryMatch<'a, 'tree>,
199        node_idx: MatchedNodeIdx,
200        source: RopeSlice<'a>,
201        loader: impl LanguageLoader,
202    ) -> Option<InjectionQueryMatch<'tree>> {
203        let properties = self
204            .injection_properties
205            .get(&query_match.pattern())
206            .cloned()
207            .unwrap_or_default();
208
209        let mut marker = None;
210        let mut last_content_node = 0;
211        let mut content_nodes = 0;
212        for (i, matched_node) in query_match.matched_nodes().enumerate() {
213            let capture = Some(matched_node.capture);
214            if capture == self.injection_language_capture {
215                let range = matched_node.node.byte_range();
216                marker = Some(InjectionLanguageMarker::Match(
217                    source.byte_slice(range.start as usize..range.end as usize),
218                ));
219            } else if capture == self.injection_filename_capture {
220                let range = matched_node.node.byte_range();
221                marker = Some(InjectionLanguageMarker::Filename(
222                    source.byte_slice(range.start as usize..range.end as usize),
223                ));
224            } else if capture == self.injection_shebang_capture {
225                let range = matched_node.node.byte_range();
226                let node_slice = source.byte_slice(range.start as usize..range.end as usize);
227
228                // some languages allow space and newlines before the actual string content
229                // so a shebang could be on either the first or second line
230                let lines = if let Ok(end) = node_slice.try_line_to_byte(2) {
231                    node_slice.byte_slice(..end)
232                } else {
233                    node_slice
234                };
235
236                marker = SHEBANG_REGEX
237                    .captures_iter(regex_cursor::Input::new(lines))
238                    .map(|cap| {
239                        let cap = lines.byte_slice(cap.get_group(1).unwrap().range());
240                        InjectionLanguageMarker::Shebang(cap)
241                    })
242                    .next()
243            } else if capture == self.injection_content_capture {
244                content_nodes += 1;
245
246                last_content_node = i as u32;
247            }
248        }
249        let marker = marker.or(properties
250            .language
251            .as_deref()
252            .map(InjectionLanguageMarker::Name))?;
253
254        let language = loader.language_for_marker(marker)?;
255        let scope = if properties.combined {
256            Some(InjectionScope::Pattern {
257                pattern: query_match.pattern(),
258                language,
259            })
260        } else if content_nodes != 1 {
261            Some(InjectionScope::Match {
262                id: query_match.id(),
263            })
264        } else {
265            None
266        };
267
268        Some(InjectionQueryMatch {
269            language,
270            scope,
271            include_children: properties.include_children,
272            node: query_match.matched_node(node_idx).node.clone(),
273            last_match: last_content_node == node_idx,
274            pattern: query_match.pattern(),
275        })
276    }
277
278    /// Executes the query on the given input and return an iterator of
279    /// injection ranges together with their injection properties
280    ///
281    /// The ranges yielded by the iterator have an ascending start range.
282    /// The ranges do not overlap exactly (matches of the exact same node are
283    /// resolved with normal precedence rules). However, ranges can be nested.
284    /// For example:
285    ///
286    /// ``` no-compile
287    ///   | range 2 |
288    /// |   range 1  |
289    /// ```
290    /// is possible and will always result in iteration order [range1, range2].
291    /// This case should be handled by the calling function
292    fn execute<'a>(
293        &'a self,
294        node: &Node<'a>,
295        source: RopeSlice<'a>,
296        loader: &'a impl LanguageLoader,
297    ) -> impl Iterator<Item = InjectionQueryMatch<'a>> + 'a {
298        let mut cursor = InactiveQueryCursor::new();
299        cursor.set_byte_range(0..u32::MAX);
300        cursor.set_match_limit(TREE_SITTER_MATCH_LIMIT);
301        let mut cursor = cursor.execute_query(&self.injection_query, node, source);
302        let injection_content_capture = self.injection_content_capture.unwrap();
303        let iter = iter::from_fn(move || loop {
304            let (query_match, node_idx) = cursor.next_matched_node()?;
305            if query_match.matched_node(node_idx).capture != injection_content_capture {
306                continue;
307            }
308            let Some(mat) = self.process_match(&query_match, node_idx, source, loader) else {
309                query_match.remove();
310                continue;
311            };
312            let range = query_match.matched_node(node_idx).node.byte_range();
313            if mat.last_match {
314                query_match.remove();
315            }
316            if range.is_empty() {
317                continue;
318            }
319            break Some(mat);
320        });
321        let mut buf = Vec::new();
322        let mut iter = iter.peekable();
323        // handle identical/overlapping matches to correctly account for precedence
324        iter::from_fn(move || {
325            if let Some(mat) = buf.pop() {
326                return Some(mat);
327            }
328            let mut res = iter.next()?;
329            // if children are not included then nested injections don't
330            // interfere with each other unless exactly identical. Since
331            // this is the default setting we have a fastpath for it
332            if res.include_children == IncludedChildren::None {
333                let mut fast_return = true;
334                while let Some(overlap) =
335                    iter.next_if(|mat| mat.node.byte_range() == res.node.byte_range())
336                {
337                    if overlap.include_children != IncludedChildren::None {
338                        buf.push(overlap);
339                        fast_return = false;
340                        break;
341                    }
342                    // Prefer the last capture which matches this exact node.
343                    res = overlap;
344                }
345                if fast_return {
346                    return Some(res);
347                }
348            }
349
350            // we if can't use the fastpath we accumulate all overlapping matches
351            // and then sort them according to precedence rules...
352            while let Some(overlap) = iter.next_if(|mat| mat.node.end_byte() <= res.node.end_byte())
353            {
354                buf.push(overlap)
355            }
356            if buf.is_empty() {
357                return Some(res);
358            }
359            buf.push(res);
360            buf.sort_unstable_by_key(|mat| (mat.pattern, Reverse(mat.node.start_byte())));
361            buf.pop()
362        })
363    }
364}
365
366impl Syntax {
367    pub(crate) fn run_injection_query(
368        &mut self,
369        layer: Layer,
370        edits: &[tree_sitter::InputEdit],
371        source: RopeSlice<'_>,
372        loader: &impl LanguageLoader,
373        mut parse_layer: impl FnMut(Layer),
374    ) {
375        self.map_injections(layer, None, edits);
376        let layer_data = &mut self.layer_mut(layer);
377        let Some(LanguageConfig {
378            injection_query: ref injections_query,
379            ..
380        }) = loader.get_config(layer_data.language)
381        else {
382            return;
383        };
384        if injections_query.injection_content_capture.is_none() {
385            return;
386        }
387
388        // work around borrow checker
389        let parent_ranges = take(&mut layer_data.ranges);
390        let parse_tree = layer_data.parse_tree.take().unwrap();
391        let mut injections: Vec<Injection> = Vec::with_capacity(layer_data.injections.len());
392        let mut old_injections = take(&mut layer_data.injections).into_iter().peekable();
393
394        let injection_query = injections_query.execute(&parse_tree.root_node(), source, loader);
395
396        let mut combined_injections: HashMap<InjectionScope, Layer> = HashMap::with_capacity(32);
397        for mat in injection_query {
398            let matched_node_range = mat.node.byte_range();
399            let mut insert_position = injections.len();
400            // if a parent node already has an injection ignore this injection
401            // in theory the first condition would be enough to detect that
402            // however in case the parent node does not include children it
403            // is possible that one of these children is another separate
404            // injection. In these cases we cannot skip the injection
405            //
406            // also the precedence sorting (and rare intersection) means that
407            // overlapping injections may be sorted not by position but by
408            // precedence (highest precedence first). the code here ensures
409            // that injections get sorted to the correct position
410            if let Some(last_injection) = injections
411                .last()
412                .filter(|injection| ranges_intersect(&injection.range, &matched_node_range))
413            {
414                // this condition is not needed but serves as fast path
415                // for common cases
416                if last_injection.range.start <= matched_node_range.start {
417                    continue;
418                } else {
419                    insert_position = injections.partition_point(|injection| {
420                        injection.range.end <= matched_node_range.start
421                    });
422                    if injections[insert_position].range.start < matched_node_range.end {
423                        continue;
424                    }
425                }
426            }
427
428            let language = mat.language;
429            let reused_injection =
430                self.reuse_injection(language, matched_node_range.clone(), &mut old_injections);
431            let layer = match mat.scope {
432                Some(scope @ InjectionScope::Match { .. }) if mat.last_match => {
433                    combined_injections.remove(&scope).unwrap_or_else(|| {
434                        self.init_injection(layer, mat.language, reused_injection.clone())
435                    })
436                }
437                Some(scope) => *combined_injections.entry(scope).or_insert_with(|| {
438                    self.init_injection(layer, mat.language, reused_injection.clone())
439                }),
440                None => self.init_injection(layer, mat.language, reused_injection.clone()),
441            };
442            let mut layer_data = self.layer_mut(layer);
443            if !layer_data.flags.touched {
444                layer_data.flags.touched = true;
445                parse_layer(layer)
446            }
447            if layer_data.flags.reused {
448                layer_data.flags.modified |= reused_injection.as_ref().map_or(true, |injection| {
449                    injection.matched_node_range != matched_node_range || injection.layer != layer
450                });
451            } else if let Some(reused_injection) = reused_injection {
452                layer_data.flags.reused = true;
453                layer_data.flags.modified = true;
454                let reused_parse_tree = self.layer(reused_injection.layer).tree().cloned();
455                layer_data = self.layer_mut(layer);
456                layer_data.parse_tree = reused_parse_tree;
457            }
458
459            let old_len = injections.len();
460            intersect_ranges(mat.include_children, mat.node, &parent_ranges, |range| {
461                layer_data.ranges.push(tree_sitter::Range {
462                    start_point: tree_sitter::Point::ZERO,
463                    end_point: tree_sitter::Point::ZERO,
464                    start_byte: range.start,
465                    end_byte: range.end,
466                });
467                injections.push(Injection {
468                    range,
469                    layer,
470                    matched_node_range: matched_node_range.clone(),
471                });
472            });
473            if old_len != insert_position {
474                let inserted = injections.len() - old_len;
475                injections[insert_position..].rotate_right(inserted);
476                layer_data.ranges[insert_position..].rotate_right(inserted);
477            }
478        }
479
480        let layer_data = &mut self.layer_mut(layer);
481        layer_data.ranges = parent_ranges;
482        layer_data.parse_tree = Some(parse_tree);
483        layer_data.injections = injections;
484    }
485
486    /// Maps the layers injection ranges through edits to enable incremental re-parsing.
487    fn map_injections(
488        &mut self,
489        layer: Layer,
490        // TODO: drop this parameter?
491        offset: Option<i32>,
492        mut edits: &[tree_sitter::InputEdit],
493    ) {
494        if edits.is_empty() && offset.unwrap_or(0) == 0 {
495            return;
496        }
497        let layer_data = self.layer_mut(layer);
498        let first_relevant_injection = layer_data
499            .injections
500            .partition_point(|injection| injection.range.end < edits[0].start_byte);
501        if first_relevant_injection == layer_data.injections.len() {
502            return;
503        }
504        let mut offset = if let Some(offset) = offset {
505            let first_relevant_edit = edits.partition_point(|edit| {
506                (edit.old_end_byte as i32) < (layer_data.ranges[0].end_byte as i32 - offset)
507            });
508            edits = &edits[first_relevant_edit..];
509            offset
510        } else {
511            0
512        };
513        // injections and edits are non-overlapping and sorted so we can
514        // apply edits in O(M+N) instead of O(NM)
515        let mut edits = edits.iter().peekable();
516        let mut injections = take(&mut layer_data.injections);
517        for injection in &mut injections[first_relevant_injection..] {
518            let injection_range = &mut injection.range;
519            let matched_node_range = &mut injection.matched_node_range;
520            let flags = &mut self.layer_mut(injection.layer).flags;
521
522            debug_assert!(matched_node_range.start <= injection_range.start);
523            debug_assert!(matched_node_range.end >= injection_range.end);
524
525            while let Some(edit) =
526                edits.next_if(|edit| edit.old_end_byte < matched_node_range.start)
527            {
528                offset += edit.offset();
529            }
530            let mut mapped_node_range_start = (matched_node_range.start as i32 + offset) as u32;
531            if let Some(edit) = edits
532                .peek()
533                .filter(|edit| edit.start_byte <= matched_node_range.start)
534            {
535                mapped_node_range_start = (edit.new_end_byte as i32 + offset) as u32;
536            }
537            while let Some(edit) = edits.next_if(|edit| edit.old_end_byte < injection_range.start) {
538                offset += edit.offset();
539            }
540            flags.moved = offset != 0;
541            let mut mapped_start = (injection_range.start as i32 + offset) as u32;
542            if let Some(edit) = edits.next_if(|edit| edit.old_end_byte <= injection_range.end) {
543                if edit.start_byte < injection_range.start {
544                    flags.moved = true;
545                    mapped_start = (edit.new_end_byte as i32 + offset) as u32;
546                } else {
547                    flags.modified = true;
548                }
549                offset += edit.offset();
550                while let Some(edit) =
551                    edits.next_if(|edit| edit.old_end_byte <= injection_range.end)
552                {
553                    offset += edit.offset();
554                }
555            }
556            let mut mapped_end = (injection_range.end as i32 + offset) as u32;
557            if let Some(edit) = edits
558                .peek()
559                .filter(|edit| edit.start_byte <= injection_range.end)
560            {
561                flags.modified = true;
562
563                if edit.start_byte < injection_range.start {
564                    mapped_start = (edit.new_end_byte as i32 + offset) as u32;
565                    mapped_end = mapped_start;
566                }
567            }
568            let mut mapped_node_range_end = (matched_node_range.end as i32 + offset) as u32;
569            if let Some(edit) = edits
570                .peek()
571                .filter(|edit| edit.start_byte <= matched_node_range.end)
572            {
573                if edit.start_byte < matched_node_range.start {
574                    mapped_node_range_start = (edit.new_end_byte as i32 + offset) as u32;
575                    mapped_node_range_end = mapped_node_range_start;
576                }
577            }
578            *injection_range = mapped_start..mapped_end;
579            *matched_node_range = mapped_node_range_start..mapped_node_range_end;
580        }
581        self.layer_mut(layer).injections = injections;
582    }
583
584    fn init_injection(
585        &mut self,
586        parent: Layer,
587        language: Language,
588        reuse: Option<Injection>,
589    ) -> Layer {
590        match reuse {
591            Some(old_injection) => {
592                let layer_data = self.layer_mut(old_injection.layer);
593                debug_assert_eq!(layer_data.parent, Some(parent));
594                layer_data.flags.reused = true;
595                layer_data.ranges.clear();
596                old_injection.layer
597            }
598            None => {
599                let layer = self.layers.insert(LayerData {
600                    language,
601                    parse_tree: None,
602                    ranges: Vec::new(),
603                    injections: Vec::new(),
604                    flags: LayerUpdateFlags::default(),
605                    parent: Some(parent),
606                    locals: Locals::default(),
607                });
608                Layer(layer as u32)
609            }
610        }
611    }
612
613    // TODO: only reuse if same pattern is matched
614    fn reuse_injection(
615        &mut self,
616        language: Language,
617        new_range: Range,
618        injections: &mut Peekable<impl Iterator<Item = Injection>>,
619    ) -> Option<Injection> {
620        loop {
621            let skip = injections.next_if(|injection| injection.range.end <= new_range.start);
622            if skip.is_none() {
623                break;
624            }
625        }
626        injections
627            .next_if(|injection| {
628                injection.range.start < new_range.end
629                    && self.layer(injection.layer).language == language
630                    && !self.layer(injection.layer).flags.reused
631            })
632            .clone()
633    }
634}
635
636fn intersect_ranges(
637    include_children: IncludedChildren,
638    node: Node,
639    parent_ranges: &[tree_sitter::Range],
640    push_range: impl FnMut(Range),
641) {
642    let range = node.byte_range();
643    let i = parent_ranges.partition_point(|parent_range| parent_range.end_byte <= range.start);
644    let parent_ranges = parent_ranges[i..]
645        .iter()
646        .map(|range| range.start_byte..range.end_byte);
647    match include_children {
648        IncludedChildren::None => intersect_ranges_impl(
649            range,
650            node.children().map(|node| node.byte_range()),
651            parent_ranges,
652            push_range,
653        ),
654        IncludedChildren::All => {
655            intersect_ranges_impl(range, [].into_iter(), parent_ranges, push_range)
656        }
657        IncludedChildren::Unnamed => intersect_ranges_impl(
658            range,
659            node.children()
660                .filter(|node| node.is_named())
661                .map(|node| node.byte_range()),
662            parent_ranges,
663            push_range,
664        ),
665    }
666}
667
668fn intersect_ranges_impl(
669    range: Range,
670    excluded_ranges: impl Iterator<Item = Range>,
671    parent_ranges: impl Iterator<Item = Range>,
672    mut push_range: impl FnMut(Range),
673) {
674    let mut start = range.start;
675    let mut excluded_ranges = excluded_ranges.filter(|range| !range.is_empty()).peekable();
676    let mut parent_ranges = parent_ranges.peekable();
677    loop {
678        let parent_range = parent_ranges.peek().unwrap().clone();
679        if let Some(excluded_range) =
680            excluded_ranges.next_if(|range| range.start <= parent_range.end)
681        {
682            if excluded_range.start >= range.end {
683                break;
684            }
685            if start != excluded_range.start {
686                push_range(start..excluded_range.start)
687            }
688            start = excluded_range.end;
689        } else {
690            parent_ranges.next();
691            if parent_range.end >= range.end {
692                break;
693            }
694            if start != parent_range.end {
695                push_range(start..parent_range.end)
696            }
697            let Some(next_parent_range) = parent_ranges.peek() else {
698                return;
699            };
700            start = next_parent_range.start;
701        }
702    }
703    if start != range.end {
704        push_range(start..range.end)
705    }
706}
707
708fn ranges_intersect(a: &Range, b: &Range) -> bool {
709    // Adapted from <https://github.com/helix-editor/helix/blob/8df58b2e1779dcf0046fb51ae1893c1eebf01e7c/helix-core/src/selection.rs#L156-L163>
710    a.start == b.start || (a.end > b.start && b.end > a.start)
711}