assemble_excerpts.rs

  1use language::{BufferSnapshot, OffsetRangeExt as _, Point};
  2use std::ops::Range;
  3
  4#[cfg(not(test))]
  5const MAX_OUTLINE_ITEM_BODY_SIZE: usize = 512;
  6#[cfg(test)]
  7const MAX_OUTLINE_ITEM_BODY_SIZE: usize = 24;
  8
  9pub fn assemble_excerpt_ranges(
 10    buffer: &BufferSnapshot,
 11    mut input_ranges: Vec<Range<Point>>,
 12) -> Vec<Range<u32>> {
 13    merge_ranges(&mut input_ranges);
 14
 15    let mut outline_ranges = Vec::new();
 16    let outline_items = buffer.outline_items_as_points_containing(0..buffer.len(), false, None);
 17    let mut outline_ix = 0;
 18    for input_range in &mut input_ranges {
 19        *input_range = clip_range_to_lines(input_range, false, buffer);
 20
 21        while let Some(outline_item) = outline_items.get(outline_ix) {
 22            let item_range = clip_range_to_lines(&outline_item.range, false, buffer);
 23
 24            if item_range.start > input_range.start {
 25                break;
 26            }
 27
 28            if item_range.end > input_range.start {
 29                let body_range = outline_item
 30                    .body_range(buffer)
 31                    .map(|body| clip_range_to_lines(&body, true, buffer))
 32                    .filter(|body_range| {
 33                        body_range.to_offset(buffer).len() > MAX_OUTLINE_ITEM_BODY_SIZE
 34                    });
 35
 36                add_outline_item(
 37                    item_range.clone(),
 38                    body_range.clone(),
 39                    buffer,
 40                    &mut outline_ranges,
 41                );
 42
 43                if let Some(body_range) = body_range
 44                    && input_range.start < body_range.start
 45                {
 46                    let mut child_outline_ix = outline_ix + 1;
 47                    while let Some(next_outline_item) = outline_items.get(child_outline_ix) {
 48                        if next_outline_item.range.end > body_range.end {
 49                            break;
 50                        }
 51                        if next_outline_item.depth == outline_item.depth + 1 {
 52                            let next_item_range =
 53                                clip_range_to_lines(&next_outline_item.range, false, buffer);
 54
 55                            add_outline_item(
 56                                next_item_range,
 57                                next_outline_item
 58                                    .body_range(buffer)
 59                                    .map(|body| clip_range_to_lines(&body, true, buffer)),
 60                                buffer,
 61                                &mut outline_ranges,
 62                            );
 63                        }
 64                        child_outline_ix += 1;
 65                    }
 66                }
 67            }
 68
 69            outline_ix += 1;
 70        }
 71    }
 72
 73    input_ranges.extend_from_slice(&outline_ranges);
 74    merge_ranges(&mut input_ranges);
 75
 76    input_ranges
 77        .into_iter()
 78        .map(|range| range.start.row..range.end.row)
 79        .collect()
 80}
 81
 82fn clip_range_to_lines(
 83    range: &Range<Point>,
 84    inward: bool,
 85    buffer: &BufferSnapshot,
 86) -> Range<Point> {
 87    let mut range = range.clone();
 88    if inward {
 89        if range.start.column > 0 {
 90            range.start.column = buffer.line_len(range.start.row);
 91        }
 92        range.end.column = 0;
 93    } else {
 94        range.start.column = 0;
 95        if range.end.column > 0 {
 96            range.end.column = buffer.line_len(range.end.row);
 97        }
 98    }
 99    range
100}
101
102fn add_outline_item(
103    mut item_range: Range<Point>,
104    body_range: Option<Range<Point>>,
105    buffer: &BufferSnapshot,
106    outline_ranges: &mut Vec<Range<Point>>,
107) {
108    if let Some(mut body_range) = body_range {
109        if body_range.start.column > 0 {
110            body_range.start.column = buffer.line_len(body_range.start.row);
111        }
112        body_range.end.column = 0;
113
114        let head_range = item_range.start..body_range.start;
115        if head_range.start < head_range.end {
116            outline_ranges.push(head_range);
117        }
118
119        let tail_range = body_range.end..item_range.end;
120        if tail_range.start < tail_range.end {
121            outline_ranges.push(tail_range);
122        }
123    } else {
124        item_range.start.column = 0;
125        item_range.end.column = buffer.line_len(item_range.end.row);
126        outline_ranges.push(item_range);
127    }
128}
129
130pub fn merge_ranges(ranges: &mut Vec<Range<Point>>) {
131    ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start).then(b.end.cmp(&a.end)));
132
133    let mut index = 1;
134    while index < ranges.len() {
135        let mut prev_range_end = ranges[index - 1].end;
136        if prev_range_end.column > 0 {
137            prev_range_end += Point::new(1, 0);
138        }
139
140        if (prev_range_end + Point::new(1, 0))
141            .cmp(&ranges[index].start)
142            .is_ge()
143        {
144            let removed = ranges.remove(index);
145            if removed.end.cmp(&ranges[index - 1].end).is_gt() {
146                ranges[index - 1].end = removed.end;
147            }
148        } else {
149            index += 1;
150        }
151    }
152}