assemble_excerpts.rs

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