use std::{mem, ops::Range, sync::Arc}; use collections::HashSet;use gpui::{App, AppContext, Context, Entity};use itertools::Itertools;use language::{Buffer, BufferSnapshot};use rope::Point;use text::{Bias, OffsetRangeExt, locator::Locator};use util::{post_inc, rel_path::RelPath};use ztracing::instrument; use crate::{ Anchor, ExcerptId, ExcerptRange, ExpandExcerptDirection, MultiBuffer, build_excerpt_ranges,}; #[derive(Debug, Clone)]pub struct PathExcerptInsertResult { pub excerpt_ids: Vec<ExcerptId>, pub added_new_excerpt: bool,} #[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)]pub struct PathKey { // Used by the derived PartialOrd & Ord pub sort_prefix: Option<u64>, pub path: Arc<RelPath>,} impl PathKey { pub fn sorted(sort_prefix: u64) -> Self { Self { sort_prefix: Some(sort_prefix), path: RelPath::empty().into_arc(), } } pub fn with_sort_prefix(sort_prefix: u64, path: Arc<RelPath>) -> Self { Self { sort_prefix: Some(sort_prefix), path, } } pub fn for_buffer(buffer: &Entity<Buffer>, cx: &App) -> Self { if let Some(file) = buffer.read(cx).file() { Self::with_sort_prefix(file.worktree_id(cx).to_proto(), file.path().clone()) } else { Self { sort_prefix: None, path: RelPath::unix(&buffer.entity_id().to_string()) .unwrap() .into_arc(), } } }} impl MultiBuffer { pub fn paths(&self) -> impl Iterator<Item = &PathKey> + '_ { self.excerpts_by_path.keys() } pub fn excerpts_for_path(&self, path: &PathKey) -> impl '_ + Iterator<Item = ExcerptId> { self.excerpts_by_path .get(path) .map(|excerpts| excerpts.as_slice()) .unwrap_or_default() .iter() .copied() } pub fn path_for_excerpt(&self, excerpt: ExcerptId) -> Option<PathKey> { self.paths_by_excerpt.get(&excerpt).cloned() } pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context<Self>) { if let Some(to_remove) = self.excerpts_by_path.remove(&path) { self.remove_excerpts(to_remove, cx) } } pub fn buffer_for_path(&self, path: &PathKey, cx: &App) -> Option<Entity<Buffer>> { let excerpt_id = self.excerpts_by_path.get(path)?.first()?; let snapshot = self.read(cx); let excerpt = snapshot.excerpt(*excerpt_id)?; self.buffer(excerpt.buffer_id) } pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option<Anchor> { let excerpt_id = self.excerpts_by_path.get(path)?.first()?; let snapshot = self.read(cx); let excerpt = snapshot.excerpt(*excerpt_id)?; Some(Anchor::in_buffer(excerpt.id, excerpt.range.context.start)) } pub fn set_excerpts_for_buffer( &mut self, buffer: Entity<Buffer>, ranges: impl IntoIterator<Item = Range<Point>>, context_line_count: u32, cx: &mut Context<Self>, ) -> (Vec<Range<Anchor>>, bool) { let path = PathKey::for_buffer(&buffer, cx); self.set_excerpts_for_path(path, buffer, ranges, context_line_count, cx) } /// Sets excerpts, returns `true` if at least one new excerpt was added. #[instrument(skip_all)] pub fn set_excerpts_for_path( &mut self, path: PathKey, buffer: Entity<Buffer>, ranges: impl IntoIterator<Item = Range<Point>>, context_line_count: u32, cx: &mut Context<Self>, ) -> (Vec<Range<Anchor>>, bool) { let buffer_snapshot = buffer.read(cx).snapshot(); let excerpt_ranges = build_excerpt_ranges(ranges, context_line_count, &buffer_snapshot); let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); self.set_merged_excerpt_ranges_for_path( path, buffer, excerpt_ranges, &buffer_snapshot, new, counts, cx, ) } pub fn set_excerpt_ranges_for_path( &mut self, path: PathKey, buffer: Entity<Buffer>, buffer_snapshot: &BufferSnapshot, excerpt_ranges: Vec<ExcerptRange<Point>>, cx: &mut Context<Self>, ) -> (Vec<Range<Anchor>>, bool) { let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); self.set_merged_excerpt_ranges_for_path( path, buffer, excerpt_ranges, buffer_snapshot, new, counts, cx, ) } pub fn set_anchored_excerpts_for_path( &self, path_key: PathKey, buffer: Entity<Buffer>, ranges: Vec<Range<text::Anchor>>, context_line_count: u32, cx: &Context<Self>, ) -> impl Future<Output = Vec<Range<Anchor>>> + use<> { let buffer_snapshot = buffer.read(cx).snapshot(); let multi_buffer = cx.weak_entity(); let mut app = cx.to_async(); async move { let snapshot = buffer_snapshot.clone(); let (excerpt_ranges, new, counts) = app .background_spawn(async move { let ranges = ranges.into_iter().map(|range| range.to_point(&snapshot)); let excerpt_ranges = build_excerpt_ranges(ranges, context_line_count, &snapshot); let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); (excerpt_ranges, new, counts) }) .await; multi_buffer .update(&mut app, move |multi_buffer, cx| { let (ranges, _) = multi_buffer.set_merged_excerpt_ranges_for_path( path_key, buffer, excerpt_ranges, &buffer_snapshot, new, counts, cx, ); ranges }) .ok() .unwrap_or_default() } } pub(super) fn expand_excerpts_with_paths( &mut self, ids: impl IntoIterator<Item = ExcerptId>, line_count: u32, direction: ExpandExcerptDirection, cx: &mut Context<Self>, ) { let mut sorted_ids: Vec<ExcerptId> = ids.into_iter().collect(); sorted_ids.sort_by(|a, b| { let path_a = self.paths_by_excerpt.get(a); let path_b = self.paths_by_excerpt.get(b); path_a.cmp(&path_b) }); let grouped = sorted_ids .into_iter() .chunk_by(|id| self.paths_by_excerpt.get(id).cloned()) .into_iter() .filter_map(|(k, v)| Some((k?, v.into_iter().collect::<Vec<_>>()))) .collect::<Vec<_>>(); let snapshot = self.snapshot(cx); for (path, ids) in grouped.into_iter() { let Some(excerpt_ids) = self.excerpts_by_path.get(&path) else { continue; }; let ids_to_expand = HashSet::from_iter(ids); let mut excerpt_id_ = None; let expanded_ranges = excerpt_ids.iter().filter_map(|excerpt_id| { let excerpt = snapshot.excerpt(*excerpt_id)?; let excerpt_id = excerpt.id; if excerpt_id_.is_none() { excerpt_id_ = Some(excerpt_id); } let mut context = excerpt.range.context.to_point(&excerpt.buffer); if ids_to_expand.contains(&excerpt_id) { match direction { ExpandExcerptDirection::Up => { context.start.row = context.start.row.saturating_sub(line_count); context.start.column = 0; } ExpandExcerptDirection::Down => { context.end.row = (context.end.row + line_count).min(excerpt.buffer.max_point().row); context.end.column = excerpt.buffer.line_len(context.end.row); } ExpandExcerptDirection::UpAndDown => { context.start.row = context.start.row.saturating_sub(line_count); context.start.column = 0; context.end.row = (context.end.row + line_count).min(excerpt.buffer.max_point().row); context.end.column = excerpt.buffer.line_len(context.end.row); } } } Some(ExcerptRange { context, primary: excerpt.range.primary.to_point(&excerpt.buffer), }) }); let mut merged_ranges: Vec<ExcerptRange<Point>> = Vec::new(); for range in expanded_ranges { if let Some(last_range) = merged_ranges.last_mut() && last_range.context.end >= range.context.start { last_range.context.end = range.context.end; continue; } merged_ranges.push(range) } let Some(excerpt_id) = excerpt_id_ else { continue; }; let Some(buffer_id) = &snapshot.buffer_id_for_excerpt(excerpt_id) else { continue; }; let Some(buffer) = self.buffers.get(buffer_id).map(|b| b.buffer.clone()) else { continue; }; let buffer_snapshot = buffer.read(cx).snapshot(); self.update_path_excerpts(path.clone(), buffer, &buffer_snapshot, merged_ranges, cx); } } /// Sets excerpts, returns `true` if at least one new excerpt was added. fn set_merged_excerpt_ranges_for_path( &mut self, path: PathKey, buffer: Entity<Buffer>, ranges: Vec<ExcerptRange<Point>>, buffer_snapshot: &BufferSnapshot, new: Vec<ExcerptRange<Point>>, counts: Vec<usize>, cx: &mut Context<Self>, ) -> (Vec<Range<Anchor>>, bool) { let insert_result = self.update_path_excerpts(path, buffer, buffer_snapshot, new, cx); let mut result = Vec::new(); let mut ranges = ranges.into_iter(); for (excerpt_id, range_count) in insert_result .excerpt_ids .into_iter() .zip(counts.into_iter()) { for range in ranges.by_ref().take(range_count) { let range = Anchor::range_in_buffer( excerpt_id, buffer_snapshot.anchor_before(&range.primary.start) ..buffer_snapshot.anchor_after(&range.primary.end), ); result.push(range) } } (result, insert_result.added_new_excerpt) } pub fn update_path_excerpts( &mut self, path: PathKey, buffer: Entity<Buffer>, buffer_snapshot: &BufferSnapshot, new: Vec<ExcerptRange<Point>>, cx: &mut Context<Self>, ) -> PathExcerptInsertResult { let mut insert_after = self .excerpts_by_path .range(..path.clone()) .next_back() .and_then(|(_, value)| value.last().copied()) .unwrap_or(ExcerptId::min()); let existing = self .excerpts_by_path .get(&path) .cloned() .unwrap_or_default(); let mut new_iter = new.into_iter().peekable(); let mut existing_iter = existing.into_iter().peekable(); let mut excerpt_ids = Vec::new(); let mut to_remove = Vec::new(); let mut to_insert: Vec<(ExcerptId, ExcerptRange<Point>)> = Vec::new(); let mut added_a_new_excerpt = false; let snapshot = self.snapshot(cx); let mut next_excerpt_id = if let Some(last_entry) = self.snapshot.get_mut().excerpt_ids.last() { last_entry.id.0 + 1 } else { 1 }; let mut next_excerpt_id = move || ExcerptId(post_inc(&mut next_excerpt_id)); let mut excerpts_cursor = snapshot.excerpts.cursor::<Option<&Locator>>(()); excerpts_cursor.next(); loop { let existing = if let Some(&existing_id) = existing_iter.peek() { let locator = snapshot.excerpt_locator_for_id(existing_id); excerpts_cursor.seek_forward(&Some(locator), Bias::Left); if let Some(excerpt) = excerpts_cursor.item() { if excerpt.buffer_id != buffer_snapshot.remote_id() { to_remove.push(existing_id); existing_iter.next(); continue; } Some((existing_id, excerpt.range.context.to_point(buffer_snapshot))) } else { None } } else { None }; let new = new_iter.peek(); // Try to merge the next new range or existing excerpt into the last // queued insert. if let Some((last_id, last)) = to_insert.last_mut() { // Next new range overlaps the last queued insert: absorb it by // extending the insert's end. if let Some(new) = new && last.context.end >= new.context.start { last.context.end = last.context.end.max(new.context.end); excerpt_ids.push(*last_id); new_iter.next(); continue; } // Next existing excerpt overlaps the last queued insert: absorb // it by extending the insert's end, and record the existing // excerpt as replaced so anchors in it resolve to the new one. if let Some((existing_id, existing_range)) = &existing && last.context.end >= existing_range.start { last.context.end = last.context.end.max(existing_range.end); to_remove.push(*existing_id); Arc::make_mut(&mut self.snapshot.get_mut().replaced_excerpts) .insert(*existing_id, *last_id); existing_iter.next(); continue; } } match (new, existing) { (None, None) => break, // No more new ranges; remove the remaining existing excerpt. (None, Some((existing_id, _))) => { existing_iter.next(); to_remove.push(existing_id); } // No more existing excerpts; queue the new range for insertion. (Some(_), None) => { added_a_new_excerpt = true; let new_id = next_excerpt_id(); excerpt_ids.push(new_id); to_insert.push((new_id, new_iter.next().unwrap())); } // Existing excerpt ends before the new range starts, so it // has no corresponding new range and must be removed. Flush // pending inserts and advance `insert_after` past it so that // future inserts receive locators *after* this excerpt's // locator, preserving forward ordering. (Some(new), Some((_, existing_range))) if existing_range.end < new.context.start => { self.insert_excerpts_with_ids_after( insert_after, buffer.clone(), mem::take(&mut to_insert), cx, ); insert_after = existing_iter.next().unwrap(); to_remove.push(insert_after); } // New range ends before the existing excerpt starts, so the // new range has no corresponding existing excerpt. Queue it // for insertion at the current `insert_after` position // (before the existing excerpt), which is the correct // spatial ordering. (Some(new), Some((_, existing_range))) if existing_range.start > new.context.end => { let new_id = next_excerpt_id(); excerpt_ids.push(new_id); to_insert.push((new_id, new_iter.next().unwrap())); } // Exact match: keep the existing excerpt in place, flush // any pending inserts before it, and use it as the new // `insert_after` anchor. (Some(new), Some((_, existing_range))) if existing_range.start == new.context.start && existing_range.end == new.context.end => { self.insert_excerpts_with_ids_after( insert_after, buffer.clone(), mem::take(&mut to_insert), cx, ); insert_after = existing_iter.next().unwrap(); excerpt_ids.push(insert_after); new_iter.next(); } // Partial overlap: replace the existing excerpt with a new // one whose range is the union of both, and record the // replacement so that anchors in the old excerpt resolve to // the new one. (Some(_), Some((_, existing_range))) => { let existing_id = existing_iter.next().unwrap(); let new_id = next_excerpt_id(); Arc::make_mut(&mut self.snapshot.get_mut().replaced_excerpts) .insert(existing_id, new_id); to_remove.push(existing_id); let mut range = new_iter.next().unwrap(); range.context.start = range.context.start.min(existing_range.start); range.context.end = range.context.end.max(existing_range.end); excerpt_ids.push(new_id); to_insert.push((new_id, range)); } }; } self.insert_excerpts_with_ids_after(insert_after, buffer, to_insert, cx); // todo(lw): There is a logic bug somewhere that causes the to_remove vector to be not ordered correctly to_remove.sort_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id)); self.remove_excerpts(to_remove, cx); if excerpt_ids.is_empty() { self.excerpts_by_path.remove(&path); } else { let snapshot = &*self.snapshot.get_mut(); let excerpt_ids = excerpt_ids .iter() .dedup() .cloned() // todo(lw): There is a logic bug somewhere that causes excerpt_ids to not necessarily be in order by locator .sorted_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id)) .collect(); for &excerpt_id in &excerpt_ids { self.paths_by_excerpt.insert(excerpt_id, path.clone());Lines 1–500 of 510. Load more
use std::{mem, ops::Range, sync::Arc}; use collections::HashSet; use gpui::{App, AppContext, Context, Entity}; use itertools::Itertools; use language::{Buffer, BufferSnapshot}; use rope::Point; use text::{Bias, OffsetRangeExt, locator::Locator}; use util::{post_inc, rel_path::RelPath}; use ztracing::instrument; use crate::{ Anchor, ExcerptId, ExcerptRange, ExpandExcerptDirection, MultiBuffer, build_excerpt_ranges, }; #[derive(Debug, Clone)] pub struct PathExcerptInsertResult { pub excerpt_ids: Vec<ExcerptId>, pub added_new_excerpt: bool, } #[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)] pub struct PathKey { // Used by the derived PartialOrd & Ord pub sort_prefix: Option<u64>, pub path: Arc<RelPath>, } impl PathKey { pub fn sorted(sort_prefix: u64) -> Self { Self { sort_prefix: Some(sort_prefix), path: RelPath::empty().into_arc(), } } pub fn with_sort_prefix(sort_prefix: u64, path: Arc<RelPath>) -> Self { Self { sort_prefix: Some(sort_prefix), path, } } pub fn for_buffer(buffer: &Entity<Buffer>, cx: &App) -> Self { if let Some(file) = buffer.read(cx).file() { Self::with_sort_prefix(file.worktree_id(cx).to_proto(), file.path().clone()) } else { Self { sort_prefix: None, path: RelPath::unix(&buffer.entity_id().to_string()) .unwrap() .into_arc(), } } } } impl MultiBuffer { pub fn paths(&self) -> impl Iterator<Item = &PathKey> + '_ { self.excerpts_by_path.keys() } pub fn excerpts_for_path(&self, path: &PathKey) -> impl '_ + Iterator<Item = ExcerptId> { self.excerpts_by_path .get(path) .map(|excerpts| excerpts.as_slice()) .unwrap_or_default() .iter() .copied() } pub fn path_for_excerpt(&self, excerpt: ExcerptId) -> Option<PathKey> { self.paths_by_excerpt.get(&excerpt).cloned() } pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context<Self>) { if let Some(to_remove) = self.excerpts_by_path.remove(&path) { self.remove_excerpts(to_remove, cx) } } pub fn buffer_for_path(&self, path: &PathKey, cx: &App) -> Option<Entity<Buffer>> { let excerpt_id = self.excerpts_by_path.get(path)?.first()?; let snapshot = self.read(cx); let excerpt = snapshot.excerpt(*excerpt_id)?; self.buffer(excerpt.buffer_id) } pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option<Anchor> { let excerpt_id = self.excerpts_by_path.get(path)?.first()?; let snapshot = self.read(cx); let excerpt = snapshot.excerpt(*excerpt_id)?; Some(Anchor::in_buffer(excerpt.id, excerpt.range.context.start)) } pub fn set_excerpts_for_buffer( &mut self, buffer: Entity<Buffer>, ranges: impl IntoIterator<Item = Range<Point>>, context_line_count: u32, cx: &mut Context<Self>, ) -> (Vec<Range<Anchor>>, bool) { let path = PathKey::for_buffer(&buffer, cx); self.set_excerpts_for_path(path, buffer, ranges, context_line_count, cx) } /// Sets excerpts, returns `true` if at least one new excerpt was added. #[instrument(skip_all)] pub fn set_excerpts_for_path( &mut self, path: PathKey, buffer: Entity<Buffer>, ranges: impl IntoIterator<Item = Range<Point>>, context_line_count: u32, cx: &mut Context<Self>, ) -> (Vec<Range<Anchor>>, bool) { let buffer_snapshot = buffer.read(cx).snapshot(); let excerpt_ranges = build_excerpt_ranges(ranges, context_line_count, &buffer_snapshot); let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); self.set_merged_excerpt_ranges_for_path( path, buffer, excerpt_ranges, &buffer_snapshot, new, counts, cx, ) } pub fn set_excerpt_ranges_for_path( &mut self, path: PathKey, buffer: Entity<Buffer>, buffer_snapshot: &BufferSnapshot, excerpt_ranges: Vec<ExcerptRange<Point>>, cx: &mut Context<Self>, ) -> (Vec<Range<Anchor>>, bool) { let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); self.set_merged_excerpt_ranges_for_path( path, buffer, excerpt_ranges, buffer_snapshot, new, counts, cx, ) } pub fn set_anchored_excerpts_for_path( &self, path_key: PathKey, buffer: Entity<Buffer>, ranges: Vec<Range<text::Anchor>>, context_line_count: u32, cx: &Context<Self>, ) -> impl Future<Output = Vec<Range<Anchor>>> + use<> { let buffer_snapshot = buffer.read(cx).snapshot(); let multi_buffer = cx.weak_entity(); let mut app = cx.to_async(); async move { let snapshot = buffer_snapshot.clone(); let (excerpt_ranges, new, counts) = app .background_spawn(async move { let ranges = ranges.into_iter().map(|range| range.to_point(&snapshot)); let excerpt_ranges = build_excerpt_ranges(ranges, context_line_count, &snapshot); let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); (excerpt_ranges, new, counts) }) .await; multi_buffer .update(&mut app, move |multi_buffer, cx| { let (ranges, _) = multi_buffer.set_merged_excerpt_ranges_for_path( path_key, buffer, excerpt_ranges, &buffer_snapshot, new, counts, cx, ); ranges }) .ok() .unwrap_or_default() } } pub(super) fn expand_excerpts_with_paths( &mut self, ids: impl IntoIterator<Item = ExcerptId>, line_count: u32, direction: ExpandExcerptDirection, cx: &mut Context<Self>, ) { let mut sorted_ids: Vec<ExcerptId> = ids.into_iter().collect(); sorted_ids.sort_by(|a, b| { let path_a = self.paths_by_excerpt.get(a); let path_b = self.paths_by_excerpt.get(b); path_a.cmp(&path_b) }); let grouped = sorted_ids .into_iter() .chunk_by(|id| self.paths_by_excerpt.get(id).cloned()) .into_iter() .filter_map(|(k, v)| Some((k?, v.into_iter().collect::<Vec<_>>()))) .collect::<Vec<_>>(); let snapshot = self.snapshot(cx); for (path, ids) in grouped.into_iter() { let Some(excerpt_ids) = self.excerpts_by_path.get(&path) else { continue; }; let ids_to_expand = HashSet::from_iter(ids); let mut excerpt_id_ = None; let expanded_ranges = excerpt_ids.iter().filter_map(|excerpt_id| { let excerpt = snapshot.excerpt(*excerpt_id)?; let excerpt_id = excerpt.id; if excerpt_id_.is_none() { excerpt_id_ = Some(excerpt_id); } let mut context = excerpt.range.context.to_point(&excerpt.buffer); if ids_to_expand.contains(&excerpt_id) { match direction { ExpandExcerptDirection::Up => { context.start.row = context.start.row.saturating_sub(line_count); context.start.column = 0; } ExpandExcerptDirection::Down => { context.end.row = (context.end.row + line_count).min(excerpt.buffer.max_point().row); context.end.column = excerpt.buffer.line_len(context.end.row); } ExpandExcerptDirection::UpAndDown => { context.start.row = context.start.row.saturating_sub(line_count); context.start.column = 0; context.end.row = (context.end.row + line_count).min(excerpt.buffer.max_point().row); context.end.column = excerpt.buffer.line_len(context.end.row); } } } Some(ExcerptRange { context, primary: excerpt.range.primary.to_point(&excerpt.buffer), }) }); let mut merged_ranges: Vec<ExcerptRange<Point>> = Vec::new(); for range in expanded_ranges { if let Some(last_range) = merged_ranges.last_mut() && last_range.context.end >= range.context.start { last_range.context.end = range.context.end; continue; } merged_ranges.push(range) } let Some(excerpt_id) = excerpt_id_ else { continue; }; let Some(buffer_id) = &snapshot.buffer_id_for_excerpt(excerpt_id) else { continue; }; let Some(buffer) = self.buffers.get(buffer_id).map(|b| b.buffer.clone()) else { continue; }; let buffer_snapshot = buffer.read(cx).snapshot(); self.update_path_excerpts(path.clone(), buffer, &buffer_snapshot, merged_ranges, cx); } } /// Sets excerpts, returns `true` if at least one new excerpt was added. fn set_merged_excerpt_ranges_for_path( &mut self, path: PathKey, buffer: Entity<Buffer>, ranges: Vec<ExcerptRange<Point>>, buffer_snapshot: &BufferSnapshot, new: Vec<ExcerptRange<Point>>, counts: Vec<usize>, cx: &mut Context<Self>, ) -> (Vec<Range<Anchor>>, bool) { let insert_result = self.update_path_excerpts(path, buffer, buffer_snapshot, new, cx); let mut result = Vec::new(); let mut ranges = ranges.into_iter(); for (excerpt_id, range_count) in insert_result .excerpt_ids .into_iter() .zip(counts.into_iter()) { for range in ranges.by_ref().take(range_count) { let range = Anchor::range_in_buffer( excerpt_id, buffer_snapshot.anchor_before(&range.primary.start) ..buffer_snapshot.anchor_after(&range.primary.end), ); result.push(range) } } (result, insert_result.added_new_excerpt) } pub fn update_path_excerpts( &mut self, path: PathKey, buffer: Entity<Buffer>, buffer_snapshot: &BufferSnapshot, new: Vec<ExcerptRange<Point>>, cx: &mut Context<Self>, ) -> PathExcerptInsertResult { let mut insert_after = self .excerpts_by_path .range(..path.clone()) .next_back() .and_then(|(_, value)| value.last().copied()) .unwrap_or(ExcerptId::min()); let existing = self .excerpts_by_path .get(&path) .cloned() .unwrap_or_default(); let mut new_iter = new.into_iter().peekable(); let mut existing_iter = existing.into_iter().peekable(); let mut excerpt_ids = Vec::new(); let mut to_remove = Vec::new(); let mut to_insert: Vec<(ExcerptId, ExcerptRange<Point>)> = Vec::new(); let mut added_a_new_excerpt = false; let snapshot = self.snapshot(cx); let mut next_excerpt_id = if let Some(last_entry) = self.snapshot.get_mut().excerpt_ids.last() { last_entry.id.0 + 1 } else { 1 }; let mut next_excerpt_id = move || ExcerptId(post_inc(&mut next_excerpt_id)); let mut excerpts_cursor = snapshot.excerpts.cursor::<Option<&Locator>>(()); excerpts_cursor.next(); loop { let existing = if let Some(&existing_id) = existing_iter.peek() { let locator = snapshot.excerpt_locator_for_id(existing_id); excerpts_cursor.seek_forward(&Some(locator), Bias::Left); if let Some(excerpt) = excerpts_cursor.item() { if excerpt.buffer_id != buffer_snapshot.remote_id() { to_remove.push(existing_id); existing_iter.next(); continue; } Some((existing_id, excerpt.range.context.to_point(buffer_snapshot))) } else { None } } else { None }; let new = new_iter.peek(); // Try to merge the next new range or existing excerpt into the last // queued insert. if let Some((last_id, last)) = to_insert.last_mut() { // Next new range overlaps the last queued insert: absorb it by // extending the insert's end. if let Some(new) = new && last.context.end >= new.context.start { last.context.end = last.context.end.max(new.context.end); excerpt_ids.push(*last_id); new_iter.next(); continue; } // Next existing excerpt overlaps the last queued insert: absorb // it by extending the insert's end, and record the existing // excerpt as replaced so anchors in it resolve to the new one. if let Some((existing_id, existing_range)) = &existing && last.context.end >= existing_range.start { last.context.end = last.context.end.max(existing_range.end); to_remove.push(*existing_id); Arc::make_mut(&mut self.snapshot.get_mut().replaced_excerpts) .insert(*existing_id, *last_id); existing_iter.next(); continue; } } match (new, existing) { (None, None) => break, // No more new ranges; remove the remaining existing excerpt. (None, Some((existing_id, _))) => { existing_iter.next(); to_remove.push(existing_id); } // No more existing excerpts; queue the new range for insertion. (Some(_), None) => { added_a_new_excerpt = true; let new_id = next_excerpt_id(); excerpt_ids.push(new_id); to_insert.push((new_id, new_iter.next().unwrap())); } // Existing excerpt ends before the new range starts, so it // has no corresponding new range and must be removed. Flush // pending inserts and advance `insert_after` past it so that // future inserts receive locators *after* this excerpt's // locator, preserving forward ordering. (Some(new), Some((_, existing_range))) if existing_range.end < new.context.start => { self.insert_excerpts_with_ids_after( insert_after, buffer.clone(), mem::take(&mut to_insert), cx, ); insert_after = existing_iter.next().unwrap(); to_remove.push(insert_after); } // New range ends before the existing excerpt starts, so the // new range has no corresponding existing excerpt. Queue it // for insertion at the current `insert_after` position // (before the existing excerpt), which is the correct // spatial ordering. (Some(new), Some((_, existing_range))) if existing_range.start > new.context.end => { let new_id = next_excerpt_id(); excerpt_ids.push(new_id); to_insert.push((new_id, new_iter.next().unwrap())); } // Exact match: keep the existing excerpt in place, flush // any pending inserts before it, and use it as the new // `insert_after` anchor. (Some(new), Some((_, existing_range))) if existing_range.start == new.context.start && existing_range.end == new.context.end => { self.insert_excerpts_with_ids_after( insert_after, buffer.clone(), mem::take(&mut to_insert), cx, ); insert_after = existing_iter.next().unwrap(); excerpt_ids.push(insert_after); new_iter.next(); } // Partial overlap: replace the existing excerpt with a new // one whose range is the union of both, and record the // replacement so that anchors in the old excerpt resolve to // the new one. (Some(_), Some((_, existing_range))) => { let existing_id = existing_iter.next().unwrap(); let new_id = next_excerpt_id(); Arc::make_mut(&mut self.snapshot.get_mut().replaced_excerpts) .insert(existing_id, new_id); to_remove.push(existing_id); let mut range = new_iter.next().unwrap(); range.context.start = range.context.start.min(existing_range.start); range.context.end = range.context.end.max(existing_range.end); excerpt_ids.push(new_id); to_insert.push((new_id, range)); } }; } self.insert_excerpts_with_ids_after(insert_after, buffer, to_insert, cx); // todo(lw): There is a logic bug somewhere that causes the to_remove vector to be not ordered correctly to_remove.sort_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id)); self.remove_excerpts(to_remove, cx); if excerpt_ids.is_empty() { self.excerpts_by_path.remove(&path); } else { let snapshot = &*self.snapshot.get_mut(); let excerpt_ids = excerpt_ids .iter() .dedup() .cloned() // todo(lw): There is a logic bug somewhere that causes excerpt_ids to not necessarily be in order by locator .sorted_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id)) .collect(); for &excerpt_id in &excerpt_ids { self.paths_by_excerpt.insert(excerpt_id, path.clone());