diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index fc871c9862..e99df6b0a2 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -6,7 +6,10 @@ mod wrap_map; use block_map::{BlockMap, BlockPoint}; use fold_map::{FoldMap, ToFoldPoint as _}; use gpui::{fonts::FontId, ElementBox, Entity, ModelContext, ModelHandle}; -use language::{Anchor, Buffer, Point, Subscription as BufferSubscription, ToOffset, ToPoint}; +use language::{ + multi_buffer::{Anchor, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint}, + Point, Subscription as BufferSubscription, +}; use std::{ collections::{HashMap, HashSet}, ops::Range, @@ -26,7 +29,7 @@ pub trait ToDisplayPoint { } pub struct DisplayMap { - buffer: ModelHandle, + buffer: ModelHandle, buffer_subscription: BufferSubscription, fold_map: FoldMap, tab_map: TabMap, @@ -40,7 +43,7 @@ impl Entity for DisplayMap { impl DisplayMap { pub fn new( - buffer: ModelHandle, + buffer: ModelHandle, tab_size: usize, font_id: FontId, font_size: f32, @@ -48,7 +51,7 @@ impl DisplayMap { cx: &mut ModelContext, ) -> Self { let buffer_subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); - let (fold_map, snapshot) = FoldMap::new(buffer.read(cx).snapshot()); + let (fold_map, snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx)); let (tab_map, snapshot) = TabMap::new(snapshot, tab_size); let (wrap_map, snapshot) = WrapMap::new(snapshot, font_id, font_size, wrap_width, cx); let block_map = BlockMap::new(buffer.clone(), snapshot); @@ -64,7 +67,7 @@ impl DisplayMap { } pub fn snapshot(&self, cx: &mut ModelContext) -> DisplaySnapshot { - let buffer_snapshot = self.buffer.read(cx).snapshot(); + let buffer_snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let (folds_snapshot, edits) = self.fold_map.read(buffer_snapshot, edits); let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits); @@ -74,7 +77,7 @@ impl DisplayMap { let blocks_snapshot = self.block_map.read(wraps_snapshot.clone(), edits, cx); DisplaySnapshot { - buffer_snapshot: self.buffer.read(cx).snapshot(), + buffer_snapshot: self.buffer.read(cx).snapshot(cx), folds_snapshot, tabs_snapshot, wraps_snapshot, @@ -87,7 +90,7 @@ impl DisplayMap { ranges: impl IntoIterator>, cx: &mut ModelContext, ) { - let snapshot = self.buffer.read(cx).snapshot(); + let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits); let (snapshot, edits) = self.tab_map.sync(snapshot, edits); @@ -108,7 +111,7 @@ impl DisplayMap { ranges: impl IntoIterator>, cx: &mut ModelContext, ) { - let snapshot = self.buffer.read(cx).snapshot(); + let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits); let (snapshot, edits) = self.tab_map.sync(snapshot, edits); @@ -132,7 +135,7 @@ impl DisplayMap { where P: ToOffset + Clone, { - let snapshot = self.buffer.read(cx).snapshot(); + let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let (snapshot, edits) = self.fold_map.read(snapshot, edits); let (snapshot, edits) = self.tab_map.sync(snapshot, edits); @@ -151,7 +154,7 @@ impl DisplayMap { } pub fn remove_blocks(&mut self, ids: HashSet, cx: &mut ModelContext) { - let snapshot = self.buffer.read(cx).snapshot(); + let snapshot = self.buffer.read(cx).snapshot(cx); let edits = self.buffer_subscription.consume().into_inner(); let (snapshot, edits) = self.fold_map.read(snapshot, edits); let (snapshot, edits) = self.tab_map.sync(snapshot, edits); @@ -179,7 +182,7 @@ impl DisplayMap { } pub struct DisplaySnapshot { - pub buffer_snapshot: language::BufferSnapshot, + pub buffer_snapshot: MultiBufferSnapshot, folds_snapshot: fold_map::FoldSnapshot, tabs_snapshot: tab_map::TabSnapshot, wraps_snapshot: wrap_map::WrapSnapshot, @@ -457,7 +460,7 @@ mod tests { use super::*; use crate::{movement, test::*}; use gpui::{color::Color, MutableAppContext}; - use language::{Language, LanguageConfig, RandomCharIter, SelectionGoal}; + use language::{Buffer, Language, LanguageConfig, RandomCharIter, SelectionGoal}; use rand::{prelude::StdRng, Rng}; use std::{env, sync::Arc}; use theme::SyntaxTheme; @@ -489,10 +492,10 @@ mod tests { log::info!("tab size: {}", tab_size); log::info!("wrap width: {:?}", wrap_width); - let buffer = cx.add_model(|cx| { + let buffer = cx.update(|cx| { let len = rng.gen_range(0..10); let text = RandomCharIter::new(&mut rng).take(len).collect::(); - Buffer::new(0, text, cx) + MultiBuffer::build_simple(&text, cx) }); let map = cx.add_model(|cx| { @@ -563,8 +566,10 @@ mod tests { assert_eq!(prev_display_bound.column(), 0); if next_display_bound < snapshot.max_point() { assert_eq!( - buffer - .read_with(&cx, |buffer, _| buffer.chars_at(next_buffer_bound).next()), + buffer.read_with(&cx, |buffer, _| buffer + .as_snapshot() + .chars_at(next_buffer_bound) + .next()), Some('\n') ) } @@ -651,7 +656,7 @@ mod tests { let wrap_width = Some(64.); let text = "one two three four five\nsix seven eight"; - let buffer = cx.add_model(|cx| Buffer::new(0, text.to_string(), cx)); + let buffer = MultiBuffer::build_simple(text, cx); let map = cx.add_model(|cx| { DisplayMap::new(buffer.clone(), tab_size, font_id, font_size, wrap_width, cx) }); @@ -724,7 +729,7 @@ mod tests { #[gpui::test] fn test_text_chunks(cx: &mut gpui::MutableAppContext) { let text = sample_text(6, 6, 'a'); - let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + let buffer = MultiBuffer::build_simple(&text, cx); let tab_size = 4; let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); let font_id = cx @@ -803,6 +808,7 @@ mod tests { let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Some(lang), None, cx)); buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let tab_size = 2; let font_cache = cx.font_cache(); @@ -890,6 +896,7 @@ mod tests { let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(Some(lang), None, cx)); buffer.condition(&cx, |buf, _| !buf.is_parsing()).await; + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let font_cache = cx.font_cache(); @@ -935,7 +942,7 @@ mod tests { let text = "\n'a', 'α',\t'✋',\t'❎', '🍐'\n"; let display_text = "\n'a', 'α', '✋', '❎', '🍐'\n"; - let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + let buffer = MultiBuffer::build_simple(text, cx); let tab_size = 4; let font_cache = cx.font_cache(); @@ -979,7 +986,7 @@ mod tests { #[gpui::test] fn test_tabs_with_multibyte_chars(cx: &mut gpui::MutableAppContext) { let text = "✅\t\tα\nβ\t\n🏀β\t\tγ"; - let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + let buffer = MultiBuffer::build_simple(text, cx); let tab_size = 4; let font_cache = cx.font_cache(); let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); @@ -1038,7 +1045,7 @@ mod tests { #[gpui::test] fn test_max_point(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "aaa\n\t\tbbb", cx)); + let buffer = MultiBuffer::build_simple("aaa\n\t\tbbb", cx); let tab_size = 4; let font_cache = cx.font_cache(); let family_id = font_cache.load_family(&["Helvetica"]).unwrap(); diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 71aa383857..00c70c361f 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -1,6 +1,9 @@ use super::wrap_map::{self, WrapEdit, WrapPoint, WrapSnapshot}; use gpui::{AppContext, ElementBox, ModelHandle}; -use language::{Buffer, Chunk}; +use language::{ + multi_buffer::{Anchor, MultiBuffer, ToOffset, ToPoint as _}, + Chunk, +}; use parking_lot::Mutex; use std::{ cmp::{self, Ordering}, @@ -12,14 +15,14 @@ use std::{ Arc, }, }; -use sum_tree::SumTree; -use text::{Anchor, Bias, Edit, Point, ToOffset, ToPoint as _}; +use sum_tree::{Bias, SumTree}; +use text::{Edit, Point}; use theme::SyntaxTheme; const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize]; pub struct BlockMap { - buffer: ModelHandle, + buffer: ModelHandle, next_block_id: AtomicUsize, wrap_snapshot: Mutex, blocks: Vec>, @@ -109,7 +112,7 @@ pub struct BlockBufferRows<'a> { } impl BlockMap { - pub fn new(buffer: ModelHandle, wrap_snapshot: WrapSnapshot) -> Self { + pub fn new(buffer: ModelHandle, wrap_snapshot: WrapSnapshot) -> Self { Self { buffer, next_block_id: AtomicUsize::new(0), @@ -153,6 +156,7 @@ impl BlockMap { } let buffer = self.buffer.read(cx); + let buffer = buffer.as_snapshot(); let mut transforms = self.transforms.lock(); let mut new_transforms = SumTree::new(); let old_row_count = transforms.summary().input_rows; @@ -241,7 +245,7 @@ impl BlockMap { let start_block_ix = match self.blocks[last_block_ix..].binary_search_by(|probe| { probe .position - .cmp(&start_anchor, buffer) + .cmp(&start_anchor, &buffer) .unwrap() .then(Ordering::Greater) }) { @@ -255,7 +259,7 @@ impl BlockMap { match self.blocks[start_block_ix..].binary_search_by(|probe| { probe .position - .cmp(&end_anchor, buffer) + .cmp(&end_anchor, &buffer) .unwrap() .then(Ordering::Greater) }) { @@ -268,7 +272,7 @@ impl BlockMap { self.blocks[start_block_ix..end_block_ix] .iter() .map(|block| { - let mut position = block.position.to_point(buffer); + let mut position = block.position.to_point(&buffer); let column = wrap_snapshot.from_point(position, Bias::Left).column(); match block.disposition { BlockDisposition::Above => position.column = 0, @@ -380,6 +384,7 @@ impl<'a> BlockMapWriter<'a> { P: ToOffset + Clone, { let buffer = self.0.buffer.read(cx); + let buffer = buffer.as_snapshot(); let mut ids = Vec::new(); let mut edits = Vec::>::new(); let wrap_snapshot = &*self.0.wrap_snapshot.lock(); @@ -389,7 +394,7 @@ impl<'a> BlockMapWriter<'a> { ids.push(id); let position = buffer.anchor_after(block.position); - let point = position.to_point(buffer); + let point = position.to_point(&buffer); let start_row = wrap_snapshot .from_point(Point::new(point.row, 0), Bias::Left) .row(); @@ -404,7 +409,7 @@ impl<'a> BlockMapWriter<'a> { let block_ix = match self .0 .blocks - .binary_search_by(|probe| probe.position.cmp(&position, buffer).unwrap()) + .binary_search_by(|probe| probe.position.cmp(&position, &buffer).unwrap()) { Ok(ix) | Err(ix) => ix, }; @@ -436,12 +441,13 @@ impl<'a> BlockMapWriter<'a> { pub fn remove(&mut self, block_ids: HashSet, cx: &AppContext) { let buffer = self.0.buffer.read(cx); + let buffer = buffer.as_snapshot(); let wrap_snapshot = &*self.0.wrap_snapshot.lock(); let mut edits = Vec::new(); let mut last_block_buffer_row = None; self.0.blocks.retain(|block| { if block_ids.contains(&block.id) { - let buffer_row = block.position.to_point(buffer).row; + let buffer_row = block.position.to_point(&buffer).row; if last_block_buffer_row != Some(buffer_row) { last_block_buffer_row = Some(buffer_row); let start_row = wrap_snapshot @@ -877,7 +883,6 @@ mod tests { use super::*; use crate::display_map::{fold_map::FoldMap, tab_map::TabMap, wrap_map::WrapMap}; use gpui::{elements::Empty, Element}; - use language::Buffer; use rand::prelude::*; use std::env; use text::RandomCharIter; @@ -906,8 +911,9 @@ mod tests { let text = "aaa\nbbb\nccc\nddd"; - let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); - let (fold_map, folds_snapshot) = FoldMap::new(buffer.read(cx).snapshot()); + let buffer = MultiBuffer::build_simple(text, cx); + let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); + let (fold_map, folds_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx)); let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1); let (wrap_map, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, None, cx); let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone()); @@ -1050,15 +1056,14 @@ mod tests { ] ); - // Insert a line break, separating two block decorations into separate - // lines. - let (buffer_snapshot, buffer_edits) = buffer.update(cx, |buffer, cx| { - let v0 = buffer.version(); + // Insert a line break, separating two block decorations into separate lines. + let buffer_snapshot = buffer.update(cx, |buffer, cx| { buffer.edit([Point::new(1, 1)..Point::new(1, 1)], "!!!\n", cx); - (buffer.snapshot(), buffer.edits_since(&v0).collect()) + buffer.snapshot(cx) }); - let (folds_snapshot, fold_edits) = fold_map.read(buffer_snapshot, buffer_edits); + let (folds_snapshot, fold_edits) = + fold_map.read(buffer_snapshot, subscription.consume().into_inner()); let (tabs_snapshot, tab_edits) = tab_map.sync(folds_snapshot, fold_edits); let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| { wrap_map.sync(tabs_snapshot, tab_edits, cx) @@ -1077,8 +1082,8 @@ mod tests { let text = "one two three\nfour five six\nseven eight"; - let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); - let (_, folds_snapshot) = FoldMap::new(buffer.read(cx).snapshot()); + let buffer = MultiBuffer::build_simple(text, cx); + let (_, folds_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx)); let (_, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), 1); let (_, wraps_snapshot) = WrapMap::new(tabs_snapshot, font_id, 14.0, Some(60.), cx); let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone()); @@ -1132,13 +1137,12 @@ mod tests { log::info!("Wrap width: {:?}", wrap_width); - let buffer = cx.add_model(|cx| { - let len = rng.gen_range(0..10); - let text = RandomCharIter::new(&mut rng).take(len).collect::(); - log::info!("initial buffer text: {:?}", text); - Buffer::new(0, text, cx) - }); - let mut buffer_snapshot = buffer.read(cx).snapshot(); + let len = rng.gen_range(0..10); + let text = RandomCharIter::new(&mut rng).take(len).collect::(); + log::info!("initial buffer text: {:?}", text); + let buffer = MultiBuffer::build_simple(&text, cx); + + let mut buffer_snapshot = buffer.read(cx).snapshot(cx); let (fold_map, folds_snapshot) = FoldMap::new(buffer_snapshot.clone()); let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size); let (wrap_map, wraps_snapshot) = @@ -1176,7 +1180,7 @@ mod tests { log::info!( "inserting block {:?} {:?} with height {}", disposition, - position.to_point(buffer), + position.to_point(&buffer.as_snapshot()), height ); BlockProperties { @@ -1221,12 +1225,12 @@ mod tests { } _ => { buffer.update(cx, |buffer, cx| { - let v0 = buffer.version(); let edit_count = rng.gen_range(1..=5); + let subscription = buffer.subscribe(); buffer.randomly_edit(&mut rng, edit_count, cx); log::info!("buffer text: {:?}", buffer.text()); - buffer_edits.extend(buffer.edits_since(&v0)); - buffer_snapshot = buffer.snapshot(); + buffer_edits.extend(subscription.consume()); + buffer_snapshot = buffer.snapshot(cx); }); } } @@ -1248,7 +1252,7 @@ mod tests { .iter() .cloned() .map(|(id, block)| { - let mut position = block.position.to_point(buffer); + let mut position = block.position.to_point(&buffer.as_snapshot()); let column = wraps_snapshot.from_point(position, Bias::Left).column(); match block.disposition { BlockDisposition::Above => { diff --git a/crates/editor/src/display_map/fold_map.rs b/crates/editor/src/display_map/fold_map.rs index bdbe002dc1..1b9402bcc5 100644 --- a/crates/editor/src/display_map/fold_map.rs +++ b/crates/editor/src/display_map/fold_map.rs @@ -1,5 +1,6 @@ use language::{ - Anchor, AnchorRangeExt, BufferSnapshot, Chunk, Edit, Point, PointUtf16, TextSummary, ToOffset, + multi_buffer::{Anchor, AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot, ToOffset}, + Chunk, Edit, Point, PointUtf16, TextSummary, }; use parking_lot::Mutex; use std::{ @@ -189,14 +190,14 @@ impl<'a> FoldMapWriter<'a> { } pub struct FoldMap { - buffer: Mutex, + buffer: Mutex, transforms: Mutex>, folds: SumTree, version: AtomicUsize, } impl FoldMap { - pub fn new(buffer: BufferSnapshot) -> (Self, FoldSnapshot) { + pub fn new(buffer: MultiBufferSnapshot) -> (Self, FoldSnapshot) { let this = Self { buffer: Mutex::new(buffer.clone()), folds: Default::default(), @@ -224,7 +225,7 @@ impl FoldMap { pub fn read( &self, - buffer: BufferSnapshot, + buffer: MultiBufferSnapshot, edits: Vec>, ) -> (FoldSnapshot, Vec) { let edits = self.sync(buffer, edits); @@ -240,7 +241,7 @@ impl FoldMap { pub fn write( &mut self, - buffer: BufferSnapshot, + buffer: MultiBufferSnapshot, edits: Vec>, ) -> (FoldMapWriter, FoldSnapshot, Vec) { let (snapshot, edits) = self.read(buffer, edits); @@ -259,7 +260,7 @@ impl FoldMap { fn sync( &self, - new_buffer: BufferSnapshot, + new_buffer: MultiBufferSnapshot, buffer_edits: Vec>, ) -> Vec { if buffer_edits.is_empty() { @@ -476,7 +477,7 @@ impl FoldMap { pub struct FoldSnapshot { transforms: SumTree, folds: SumTree, - buffer_snapshot: language::BufferSnapshot, + buffer_snapshot: MultiBufferSnapshot, pub version: usize, } @@ -699,7 +700,7 @@ impl FoldSnapshot { } fn intersecting_folds<'a, T>( - buffer: &'a text::BufferSnapshot, + buffer: &'a MultiBufferSnapshot, folds: &'a SumTree, range: Range, inclusive: bool, @@ -850,9 +851,9 @@ impl Default for FoldSummary { } impl sum_tree::Summary for FoldSummary { - type Context = text::BufferSnapshot; + type Context = MultiBufferSnapshot; - fn add_summary(&mut self, other: &Self, buffer: &text::BufferSnapshot) { + fn add_summary(&mut self, other: &Self, buffer: &MultiBufferSnapshot) { if other.min_start.cmp(&self.min_start, buffer).unwrap() == Ordering::Less { self.min_start = other.min_start.clone(); } @@ -876,20 +877,20 @@ impl sum_tree::Summary for FoldSummary { } impl<'a> sum_tree::Dimension<'a, FoldSummary> for Fold { - fn add_summary(&mut self, summary: &'a FoldSummary, _: &text::BufferSnapshot) { + fn add_summary(&mut self, summary: &'a FoldSummary, _: &MultiBufferSnapshot) { self.0.start = summary.start.clone(); self.0.end = summary.end.clone(); } } impl<'a> sum_tree::SeekTarget<'a, FoldSummary, Fold> for Fold { - fn cmp(&self, other: &Self, buffer: &text::BufferSnapshot) -> Ordering { + fn cmp(&self, other: &Self, buffer: &MultiBufferSnapshot) -> Ordering { self.0.cmp(&other.0, buffer).unwrap() } } impl<'a> sum_tree::Dimension<'a, FoldSummary> for usize { - fn add_summary(&mut self, summary: &'a FoldSummary, _: &text::BufferSnapshot) { + fn add_summary(&mut self, summary: &'a FoldSummary, _: &MultiBufferSnapshot) { *self += summary.count; } } @@ -924,7 +925,7 @@ impl<'a> Iterator for FoldBufferRows<'a> { pub struct FoldChunks<'a> { transform_cursor: Cursor<'a, Transform, (FoldOffset, usize)>, - buffer_chunks: language::BufferChunks<'a>, + buffer_chunks: MultiBufferChunks<'a>, buffer_chunk: Option<(usize, Chunk<'a>)>, buffer_offset: usize, output_offset: usize, @@ -1053,7 +1054,7 @@ pub type FoldEdit = Edit; mod tests { use super::*; use crate::ToPoint; - use language::Buffer; + use language::multi_buffer::MultiBuffer; use rand::prelude::*; use std::{env, mem}; use text::RandomCharIter; @@ -1062,8 +1063,9 @@ mod tests { #[gpui::test] fn test_basic_folds(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6, 'a'), cx)); - let buffer_snapshot = buffer.read(cx).snapshot(); + let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); + let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); + let buffer_snapshot = buffer.read(cx).snapshot(cx); let mut map = FoldMap::new(buffer_snapshot.clone()).0; let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); @@ -1086,8 +1088,7 @@ mod tests { ] ); - let (buffer_snapshot, edits) = buffer.update(cx, |buffer, cx| { - let v0 = buffer.version(); + let buffer_snapshot = buffer.update(cx, |buffer, cx| { buffer.edit( vec![ Point::new(0, 0)..Point::new(0, 1), @@ -1096,9 +1097,10 @@ mod tests { "123", cx, ); - (buffer.snapshot(), buffer.edits_since(&v0).collect()) + buffer.snapshot(cx) }); - let (snapshot3, edits) = map.read(buffer_snapshot.clone(), edits); + let (snapshot3, edits) = + map.read(buffer_snapshot.clone(), subscription.consume().into_inner()); assert_eq!(snapshot3.text(), "123a…c123c…eeeee"); assert_eq!( edits, @@ -1114,12 +1116,11 @@ mod tests { ] ); - let (buffer_snapshot, edits) = buffer.update(cx, |buffer, cx| { - let v0 = buffer.version(); + let buffer_snapshot = buffer.update(cx, |buffer, cx| { buffer.edit(vec![Point::new(2, 6)..Point::new(4, 3)], "456", cx); - (buffer.snapshot(), buffer.edits_since(&v0).collect()) + buffer.snapshot(cx) }); - let (snapshot4, _) = map.read(buffer_snapshot.clone(), edits); + let (snapshot4, _) = map.read(buffer_snapshot.clone(), subscription.consume().into_inner()); assert_eq!(snapshot4.text(), "123a…c123456eee"); let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); @@ -1130,8 +1131,9 @@ mod tests { #[gpui::test] fn test_adjacent_folds(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "abcdefghijkl", cx)); - let buffer_snapshot = buffer.read(cx).snapshot(); + let buffer = MultiBuffer::build_simple("abcdefghijkl", cx); + let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); + let buffer_snapshot = buffer.read(cx).snapshot(cx); { let mut map = FoldMap::new(buffer_snapshot.clone()).0; @@ -1164,20 +1166,20 @@ mod tests { assert_eq!(snapshot.text(), "…fghijkl"); // Edit within one of the folds. - let (buffer_snapshot, edits) = buffer.update(cx, |buffer, cx| { - let v0 = buffer.version(); + let buffer_snapshot = buffer.update(cx, |buffer, cx| { buffer.edit(vec![0..1], "12345", cx); - (buffer.snapshot(), buffer.edits_since(&v0).collect()) + buffer.snapshot(cx) }); - let (snapshot, _) = map.read(buffer_snapshot.clone(), edits); + let (snapshot, _) = + map.read(buffer_snapshot.clone(), subscription.consume().into_inner()); assert_eq!(snapshot.text(), "12345…fghijkl"); } } #[gpui::test] fn test_overlapping_folds(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6, 'a'), cx)); - let buffer_snapshot = buffer.read(cx).snapshot(); + let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); + let buffer_snapshot = buffer.read(cx).snapshot(cx); let mut map = FoldMap::new(buffer_snapshot.clone()).0; let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); writer.fold(vec![ @@ -1192,8 +1194,9 @@ mod tests { #[gpui::test] fn test_merging_folds_via_edit(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6, 'a'), cx)); - let buffer_snapshot = buffer.read(cx).snapshot(); + let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); + let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); + let buffer_snapshot = buffer.read(cx).snapshot(cx); let mut map = FoldMap::new(buffer_snapshot.clone()).0; let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); @@ -1204,19 +1207,18 @@ mod tests { let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); assert_eq!(snapshot.text(), "aa…cccc\nd…eeeee"); - let (buffer_snapshot, edits) = buffer.update(cx, |buffer, cx| { - let v0 = buffer.version(); + let buffer_snapshot = buffer.update(cx, |buffer, cx| { buffer.edit(Some(Point::new(2, 2)..Point::new(3, 1)), "", cx); - (buffer.snapshot(), buffer.edits_since(&v0).collect()) + buffer.snapshot(cx) }); - let (snapshot, _) = map.read(buffer_snapshot.clone(), edits); + let (snapshot, _) = map.read(buffer_snapshot.clone(), subscription.consume().into_inner()); assert_eq!(snapshot.text(), "aa…eeeee"); } #[gpui::test] fn test_folds_in_range(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(5, 6, 'a'), cx)); - let buffer_snapshot = buffer.read(cx).snapshot(); + let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); + let buffer_snapshot = buffer.read(cx).snapshot(cx); let mut map = FoldMap::new(buffer_snapshot.clone()).0; let buffer = buffer.read(cx); @@ -1230,7 +1232,9 @@ mod tests { let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); let fold_ranges = snapshot .folds_in_range(Point::new(1, 0)..Point::new(1, 3)) - .map(|fold| fold.start.to_point(buffer)..fold.end.to_point(buffer)) + .map(|fold| { + fold.start.to_point(&buffer.as_snapshot())..fold.end.to_point(&buffer.as_snapshot()) + }) .collect::>(); assert_eq!( fold_ranges, @@ -1247,12 +1251,10 @@ mod tests { .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) .unwrap_or(10); - let buffer = cx.add_model(|cx| { - let len = rng.gen_range(0..10); - let text = RandomCharIter::new(&mut rng).take(len).collect::(); - Buffer::new(0, text, cx) - }); - let buffer_snapshot = buffer.read(cx).snapshot(); + let len = rng.gen_range(0..10); + let text = RandomCharIter::new(&mut rng).take(len).collect::(); + let buffer = MultiBuffer::build_simple(&text, cx); + let buffer_snapshot = buffer.read(cx).snapshot(cx); let mut map = FoldMap::new(buffer_snapshot.clone()).0; let (mut initial_snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); @@ -1260,23 +1262,21 @@ mod tests { for _ in 0..operations { log::info!("text: {:?}", buffer.read(cx).text()); - let buffer_edits = match rng.gen_range(0..=100) { + let mut buffer_edits = Vec::new(); + match rng.gen_range(0..=100) { 0..=59 => { snapshot_edits.extend(map.randomly_mutate(&mut rng)); - vec![] } _ => buffer.update(cx, |buffer, cx| { - let start_version = buffer.version.clone(); + let subscription = buffer.subscribe(); let edit_count = rng.gen_range(1..=5); buffer.randomly_edit(&mut rng, edit_count, cx); - let edits = buffer - .edits_since::(&start_version) - .collect::>(); + let edits = subscription.consume().into_inner(); log::info!("editing {:?}", edits); - buffer.edits_since::(&start_version).collect() + buffer_edits.extend(edits); }), }; - let buffer_snapshot = buffer.read(cx).snapshot(); + let buffer_snapshot = buffer.read(cx).snapshot(cx); let (snapshot, edits) = map.read(buffer_snapshot.clone(), buffer_edits); snapshot_edits.push((snapshot.clone(), edits)); @@ -1285,8 +1285,8 @@ mod tests { let mut expected_buffer_rows = Vec::new(); let mut next_row = buffer_snapshot.max_point().row; for fold_range in map.merged_fold_ranges().into_iter().rev() { - let fold_start = buffer_snapshot.point_for_offset(fold_range.start).unwrap(); - let fold_end = buffer_snapshot.point_for_offset(fold_range.end).unwrap(); + let fold_start = buffer_snapshot.offset_to_point(fold_range.start); + let fold_end = buffer_snapshot.offset_to_point(fold_range.end); expected_buffer_rows.extend((fold_end.row + 1..=next_row).rev()); next_row = fold_start.row; @@ -1458,9 +1458,9 @@ mod tests { #[gpui::test] fn test_buffer_rows(cx: &mut gpui::MutableAppContext) { let text = sample_text(6, 6, 'a') + "\n"; - let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + let buffer = MultiBuffer::build_simple(&text, cx); - let buffer_snapshot = buffer.read(cx).snapshot(); + let buffer_snapshot = buffer.read(cx).snapshot(cx); let mut map = FoldMap::new(buffer_snapshot.clone()).0; let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); diff --git a/crates/editor/src/display_map/tab_map.rs b/crates/editor/src/display_map/tab_map.rs index c0c67097ba..52b4c3e6a2 100644 --- a/crates/editor/src/display_map/tab_map.rs +++ b/crates/editor/src/display_map/tab_map.rs @@ -435,7 +435,7 @@ impl<'a> Iterator for TabChunks<'a> { mod tests { use super::*; use crate::display_map::fold_map::FoldMap; - use language::Buffer; + use language::multi_buffer::MultiBuffer; use rand::{prelude::StdRng, Rng}; use text::{RandomCharIter, Rope}; @@ -449,12 +449,10 @@ mod tests { #[gpui::test(iterations = 100)] fn test_random(cx: &mut gpui::MutableAppContext, mut rng: StdRng) { let tab_size = rng.gen_range(1..=4); - let buffer = cx.add_model(|cx| { - let len = rng.gen_range(0..30); - let text = RandomCharIter::new(&mut rng).take(len).collect::(); - Buffer::new(0, text, cx) - }); - let buffer_snapshot = buffer.read(cx).snapshot(); + let len = rng.gen_range(0..30); + let text = RandomCharIter::new(&mut rng).take(len).collect::(); + let buffer = MultiBuffer::build_simple(&text, cx); + let buffer_snapshot = buffer.read(cx).snapshot(cx); log::info!("Buffer text: {:?}", buffer.read(cx).text()); let (mut fold_map, _) = FoldMap::new(buffer_snapshot.clone()); diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index d51f8373ad..c346ab03c3 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -974,7 +974,7 @@ mod tests { display_map::{fold_map::FoldMap, tab_map::TabMap}, test::Observer, }; - use language::{Buffer, RandomCharIter}; + use language::{multi_buffer::MultiBuffer, RandomCharIter}; use rand::prelude::*; use std::{cmp, env}; use text::Rope; @@ -1004,12 +1004,12 @@ mod tests { log::info!("Tab size: {}", tab_size); log::info!("Wrap width: {:?}", wrap_width); - let buffer = cx.add_model(|cx| { + let buffer = cx.update(|cx| { let len = rng.gen_range(0..10); let text = RandomCharIter::new(&mut rng).take(len).collect::(); - Buffer::new(0, text, cx) + MultiBuffer::build_simple(&text, cx) }); - let buffer_snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot()); + let buffer_snapshot = buffer.read_with(&cx, |buffer, cx| buffer.snapshot(cx)); let (mut fold_map, folds_snapshot) = FoldMap::new(buffer_snapshot.clone()); let (tab_map, tabs_snapshot) = TabMap::new(folds_snapshot.clone(), tab_size); log::info!( @@ -1074,15 +1074,15 @@ mod tests { } _ => { buffer.update(&mut cx, |buffer, cx| { - let v0 = buffer.version(); + let subscription = buffer.subscribe(); let edit_count = rng.gen_range(1..=5); buffer.randomly_edit(&mut rng, edit_count, cx); - buffer_edits.extend(buffer.edits_since(&v0)); + buffer_edits.extend(subscription.consume()); }); } } - let buffer_snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot()); + let buffer_snapshot = buffer.read_with(&cx, |buffer, cx| buffer.snapshot(cx)); log::info!("Unwrapped text (no folds): {:?}", buffer_snapshot.text()); let (folds_snapshot, fold_edits) = fold_map.read(buffer_snapshot, buffer_edits); log::info!( diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 848edc643f..a88d962ba9 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -20,7 +20,14 @@ use gpui::{ MutableAppContext, RenderContext, View, ViewContext, WeakViewHandle, }; use items::BufferItemHandle; -use language::*; +use language::{ + multi_buffer::{ + Anchor, AnchorRangeExt, AnchorRangeSet, MultiBuffer, MultiBufferSnapshot, SelectionSet, + ToOffset, ToPoint, + }, + BracketPair, Buffer, Diagnostic, DiagnosticSeverity, Language, Point, Selection, SelectionGoal, + SelectionSetId, +}; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use smol::Timer; @@ -29,7 +36,7 @@ use std::{ cmp, collections::HashMap, iter, mem, - ops::{Deref, Range, RangeInclusive}, + ops::{Deref, Range, RangeInclusive, Sub}, rc::Rc, sync::Arc, time::Duration, @@ -273,6 +280,8 @@ pub fn init(cx: &mut MutableAppContext, entry_openers: &mut Vec Range; + fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range; fn display_range(&self, map: &DisplaySnapshot) -> Range; fn spanned_rows( &self, @@ -347,7 +356,7 @@ pub enum SoftWrap { pub struct Editor { handle: WeakViewHandle, - buffer: ModelHandle, + buffer: ModelHandle, display_map: ModelHandle, selection_set_id: SelectionSetId, pending_selection: Option, @@ -422,6 +431,7 @@ impl Editor { cx: &mut ViewContext, ) -> Self { let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx)); + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let mut view = Self::for_buffer(buffer, build_settings, cx); view.mode = EditorMode::SingleLine; view @@ -433,13 +443,14 @@ impl Editor { cx: &mut ViewContext, ) -> Self { let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx)); + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let mut view = Self::for_buffer(buffer, build_settings, cx); view.mode = EditorMode::AutoHeight { max_lines }; view } pub fn for_buffer( - buffer: ModelHandle, + buffer: ModelHandle, build_settings: impl 'static + Fn(&AppContext) -> EditorSettings, cx: &mut ViewContext, ) -> Self { @@ -454,7 +465,7 @@ impl Editor { } pub fn new( - buffer: ModelHandle, + buffer: ModelHandle, build_settings: Rc EditorSettings>>, cx: &mut ViewContext, ) -> Self { @@ -522,6 +533,7 @@ impl Editor { let buffer = cx.add_model(|cx| { Buffer::new(0, "", cx).with_language(Some(language::PLAIN_TEXT.clone()), None, cx) }); + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); workspace.add_item(BufferItemHandle(buffer), cx); } @@ -529,7 +541,7 @@ impl Editor { self.buffer.read(cx).replica_id() } - pub fn buffer(&self) -> &ModelHandle { + pub fn buffer(&self) -> &ModelHandle { &self.buffer } @@ -628,9 +640,9 @@ impl Editor { first_cursor_top = newest_selection.head().to_display_point(&display_map).row() as f32; last_cursor_bottom = first_cursor_top + 1.; } else { - let mut selections = self.selections::(cx).peekable(); + let selections = self.selections::(cx); first_cursor_top = selections - .peek() + .first() .unwrap() .head() .to_display_point(&display_map) @@ -756,11 +768,10 @@ impl Editor { click_count: usize, cx: &mut ViewContext, ) { + let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let tail = self.newest_selection::(cx).tail(); - self.begin_selection(position, false, click_count, cx); - let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let position = position.to_offset(&display_map, Bias::Left); let tail_anchor = buffer.anchor_before(tail); @@ -842,13 +853,9 @@ impl Editor { } else if click_count > 1 { // Remove the newest selection since it was only added as part of this multi-click. let newest_selection = self.newest_selection::(cx); - self.update_selections::( - self.selections(cx) - .filter(|selection| selection.id != newest_selection.id) - .collect(), - None, - cx, - ) + let mut selections = self.selections(cx); + selections.retain(|selection| selection.id != newest_selection.id); + self.update_selections::(selections, None, cx) } self.pending_selection = Some(PendingSelection { selection, mode }); @@ -895,13 +902,13 @@ impl Editor { let tail = tail.to_display_point(&display_map); self.select_columns(tail, position, overshoot, &display_map, cx); } else if let Some(PendingSelection { selection, mode }) = self.pending_selection.as_mut() { - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let head; let tail; match mode { SelectMode::Character => { head = position.to_point(&display_map); - tail = selection.tail().to_point(buffer); + tail = selection.tail().to_point(&buffer); } SelectMode::Word(original_range) => { let original_display_range = original_range.start.to_display_point(&display_map) @@ -976,7 +983,7 @@ impl Editor { fn end_selection(&mut self, cx: &mut ViewContext) { self.columnar_selection_tail.take(); if self.pending_selection.is_some() { - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); self.update_selections(selections, None, cx); } } @@ -1029,19 +1036,20 @@ impl Editor { if self.active_diagnostics.is_some() { self.dismiss_diagnostics(cx); } else if let Some(PendingSelection { selection, .. }) = self.pending_selection.take() { - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let selection = Selection { id: selection.id, - start: selection.start.to_point(buffer), - end: selection.end.to_point(buffer), + start: selection.start.to_point(&buffer), + end: selection.end.to_point(&buffer), reversed: selection.reversed, goal: selection.goal, }; - if self.selections::(cx).next().is_none() { + if self.selections::(cx).is_empty() { self.update_selections(vec![selection], Some(Autoscroll::Fit), cx); } } else { - let mut oldest_selection = self.oldest_selection::(cx); + let buffer = self.buffer.read(cx).snapshot(cx); + let mut oldest_selection = self.oldest_selection::(&buffer, cx); if self.selection_count(cx) == 1 { oldest_selection.start = oldest_selection.head().clone(); oldest_selection.end = oldest_selection.head().clone(); @@ -1059,12 +1067,12 @@ impl Editor { I: IntoIterator>, T: ToOffset, { - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let selections = ranges .into_iter() .map(|range| { - let mut start = range.start.to_offset(buffer); - let mut end = range.end.to_offset(buffer); + let mut start = range.start.to_offset(&buffer); + let mut end = range.end.to_offset(&buffer); let reversed = if start > end { mem::swap(&mut start, &mut end); true @@ -1131,15 +1139,15 @@ impl Editor { self.start_transaction(cx); let mut old_selections = SmallVec::<[_; 32]>::new(); { - let selections = self.selections::(cx).collect::>(); - let buffer = self.buffer.read(cx); + let selections = self.selections::(cx); + let buffer = self.buffer.read(cx).snapshot(cx); for selection in selections.iter() { let start_point = selection.start; let indent = buffer .indent_column_for_line(start_point.row) .min(start_point.column); - let start = selection.start.to_offset(buffer); - let end = selection.end.to_offset(buffer); + let start = selection.start.to_offset(&buffer); + let end = selection.end.to_offset(&buffer); let mut insert_extra_newline = false; if let Some(language) = buffer.language() { @@ -1253,7 +1261,7 @@ impl Editor { fn insert(&mut self, text: &str, cx: &mut ViewContext) { self.start_transaction(cx); - let old_selections = self.selections::(cx).collect::>(); + let old_selections = self.selections::(cx); let mut new_selections = Vec::new(); self.buffer.update(cx, |buffer, cx| { let edit_ranges = old_selections.iter().map(|s| s.start..s.end); @@ -1284,19 +1292,20 @@ impl Editor { } fn autoclose_pairs(&mut self, cx: &mut ViewContext) { - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let new_autoclose_pair_state = self.buffer.update(cx, |buffer, cx| { - let autoclose_pair = buffer.language().and_then(|language| { + let buffer_snapshot = buffer.snapshot(cx); + let autoclose_pair = buffer_snapshot.language().and_then(|language| { let first_selection_start = selections.first().unwrap().start; let pair = language.brackets().iter().find(|pair| { - buffer.contains_str_at( + buffer_snapshot.contains_str_at( first_selection_start.saturating_sub(pair.start.len()), &pair.start, ) }); pair.and_then(|pair| { let should_autoclose = selections[1..].iter().all(|selection| { - buffer.contains_str_at( + buffer_snapshot.contains_str_at( selection.start.saturating_sub(pair.start.len()), &pair.start, ) @@ -1314,7 +1323,7 @@ impl Editor { let selection_ranges = selections .iter() .map(|selection| { - let start = selection.start.to_offset(&*buffer); + let start = selection.start.to_offset(&buffer_snapshot); start..start }) .collect::>(); @@ -1344,7 +1353,7 @@ impl Editor { } fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext) -> bool { - let old_selections = self.selections::(cx).collect::>(); + let old_selections = self.selections::(cx); let autoclose_pair_state = if let Some(autoclose_pair_state) = self.autoclose_stack.last() { autoclose_pair_state } else { @@ -1356,12 +1365,12 @@ impl Editor { debug_assert_eq!(old_selections.len(), autoclose_pair_state.ranges.len()); - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); if old_selections .iter() - .zip(autoclose_pair_state.ranges.ranges::(buffer)) + .zip(autoclose_pair_state.ranges.ranges::(&buffer)) .all(|(selection, autoclose_range)| { - let autoclose_range_end = autoclose_range.end.to_offset(buffer); + let autoclose_range_end = autoclose_range.end.to_offset(&buffer); selection.is_empty() && selection.start == autoclose_range_end }) { @@ -1395,7 +1404,7 @@ impl Editor { pub fn backspace(&mut self, _: &Backspace, cx: &mut ViewContext) { self.start_transaction(cx); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); for selection in &mut selections { if selection.is_empty() { @@ -1415,7 +1424,7 @@ impl Editor { pub fn delete(&mut self, _: &Delete, cx: &mut ViewContext) { self.start_transaction(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { if selection.is_empty() { let head = selection.head().to_display_point(&display_map); @@ -1434,13 +1443,15 @@ impl Editor { pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext) { self.start_transaction(cx); let tab_size = self.build_settings.borrow()(cx).tab_size; - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); let mut last_indent = None; self.buffer.update(cx, |buffer, cx| { for selection in &mut selections { if selection.is_empty() { let char_column = buffer - .chars_for_range(Point::new(selection.start.row, 0)..selection.start) + .as_snapshot() + .text_for_range(Point::new(selection.start.row, 0)..selection.start) + .flat_map(str::chars) .count(); let chars_to_next_tab_stop = tab_size - (char_column % tab_size); buffer.edit( @@ -1504,7 +1515,7 @@ impl Editor { pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext) { self.start_transaction(cx); let tab_size = self.build_settings.borrow()(cx).tab_size; - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let mut deletion_ranges = Vec::new(); let mut last_outdent = None; self.buffer.update(cx, |buffer, cx| { @@ -1541,20 +1552,16 @@ impl Editor { buffer.edit(deletion_ranges, "", cx); }); - self.update_selections( - self.selections::(cx).collect(), - Some(Autoscroll::Fit), - cx, - ); + self.update_selections(self.selections::(cx), Some(Autoscroll::Fit), cx); self.end_transaction(cx); } pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext) { self.start_transaction(cx); - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let mut row_delta = 0; let mut new_cursors = Vec::new(); @@ -1575,13 +1582,13 @@ impl Editor { } } - let mut edit_start = Point::new(rows.start, 0).to_offset(buffer); + let mut edit_start = Point::new(rows.start, 0).to_offset(&buffer); let edit_end; let cursor_buffer_row; if buffer.max_point().row >= rows.end { // If there's a line after the range, delete the \n from the end of the row range // and position the cursor on the next line. - edit_end = Point::new(rows.end, 0).to_offset(buffer); + edit_end = Point::new(rows.end, 0).to_offset(&buffer); cursor_buffer_row = rows.start; } else { // If there isn't a line after the range, delete the \n from the line before the @@ -1621,7 +1628,7 @@ impl Editor { pub fn duplicate_line(&mut self, _: &DuplicateLine, cx: &mut ViewContext) { self.start_transaction(cx); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); @@ -1679,9 +1686,9 @@ impl Editor { pub fn move_line_up(&mut self, _: &MoveLineUp, cx: &mut ViewContext) { self.start_transaction(cx); - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let mut edits = Vec::new(); let mut new_selection_ranges = Vec::new(); @@ -1692,7 +1699,7 @@ impl Editor { let mut contiguous_selections = Vec::new(); while let Some(selection) = selections.next() { // Accumulate contiguous regions of rows that we want to move. - contiguous_selections.push(selection.point_range(buffer)); + contiguous_selections.push(selection.point_range(&buffer)); let SpannedRows { mut buffer_rows, mut display_rows, @@ -1706,7 +1713,7 @@ impl Editor { if next_buffer_rows.start <= buffer_rows.end { buffer_rows.end = next_buffer_rows.end; display_rows.end = next_display_rows.end; - contiguous_selections.push(next_selection.point_range(buffer)); + contiguous_selections.push(next_selection.point_range(&buffer)); selections.next().unwrap(); } else { break; @@ -1715,13 +1722,13 @@ impl Editor { // Cut the text from the selected rows and paste it at the start of the previous line. if display_rows.start != 0 { - let start = Point::new(buffer_rows.start, 0).to_offset(buffer); + let start = Point::new(buffer_rows.start, 0).to_offset(&buffer); let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1)) - .to_offset(buffer); + .to_offset(&buffer); let prev_row_display_start = DisplayPoint::new(display_rows.start - 1, 0); let prev_row_buffer_start = display_map.prev_row_boundary(prev_row_display_start).1; - let prev_row_buffer_start_offset = prev_row_buffer_start.to_offset(buffer); + let prev_row_buffer_start_offset = prev_row_buffer_start.to_offset(&buffer); let mut text = String::new(); text.extend(buffer.text_for_range(start..end)); @@ -1743,8 +1750,8 @@ impl Editor { // Move folds up. old_folds.push(start..end); for fold in display_map.folds_in_range(start..end) { - let mut start = fold.start.to_point(buffer); - let mut end = fold.end.to_point(buffer); + let mut start = fold.start.to_point(&buffer); + let mut end = fold.end.to_point(&buffer); start.row -= row_delta; end.row -= row_delta; new_folds.push(start..end); @@ -1769,9 +1776,9 @@ impl Editor { pub fn move_line_down(&mut self, _: &MoveLineDown, cx: &mut ViewContext) { self.start_transaction(cx); - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let mut edits = Vec::new(); let mut new_selection_ranges = Vec::new(); @@ -1782,7 +1789,7 @@ impl Editor { let mut contiguous_selections = Vec::new(); while let Some(selection) = selections.next() { // Accumulate contiguous regions of rows that we want to move. - contiguous_selections.push(selection.point_range(buffer)); + contiguous_selections.push(selection.point_range(&buffer)); let SpannedRows { mut buffer_rows, mut display_rows, @@ -1795,7 +1802,7 @@ impl Editor { if next_buffer_rows.start <= buffer_rows.end { buffer_rows.end = next_buffer_rows.end; display_rows.end = next_display_rows.end; - contiguous_selections.push(next_selection.point_range(buffer)); + contiguous_selections.push(next_selection.point_range(&buffer)); selections.next().unwrap(); } else { break; @@ -1804,14 +1811,14 @@ impl Editor { // Cut the text from the selected rows and paste it at the end of the next line. if display_rows.end <= display_map.max_point().row() { - let start = Point::new(buffer_rows.start, 0).to_offset(buffer); + let start = Point::new(buffer_rows.start, 0).to_offset(&buffer); let end = Point::new(buffer_rows.end - 1, buffer.line_len(buffer_rows.end - 1)) - .to_offset(buffer); + .to_offset(&buffer); let next_row_display_end = DisplayPoint::new(display_rows.end, display_map.line_len(display_rows.end)); let next_row_buffer_end = display_map.next_row_boundary(next_row_display_end).1; - let next_row_buffer_end_offset = next_row_buffer_end.to_offset(buffer); + let next_row_buffer_end_offset = next_row_buffer_end.to_offset(&buffer); let mut text = String::new(); text.push('\n'); @@ -1830,8 +1837,8 @@ impl Editor { // Move folds down. old_folds.push(start..end); for fold in display_map.folds_in_range(start..end) { - let mut start = fold.start.to_point(buffer); - let mut end = fold.end.to_point(buffer); + let mut start = fold.start.to_point(&buffer); + let mut end = fold.end.to_point(&buffer); start.row += row_delta; end.row += row_delta; new_folds.push(start..end); @@ -1856,7 +1863,7 @@ impl Editor { pub fn cut(&mut self, _: &Cut, cx: &mut ViewContext) { self.start_transaction(cx); let mut text = String::new(); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); let mut clipboard_selections = Vec::with_capacity(selections.len()); { let buffer = self.buffer.read(cx); @@ -1887,7 +1894,7 @@ impl Editor { } pub fn copy(&mut self, _: &Copy, cx: &mut ViewContext) { - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let buffer = self.buffer.read(cx); let max_point = buffer.max_point(); let mut text = String::new(); @@ -1919,7 +1926,7 @@ impl Editor { if let Some(item) = cx.as_mut().read_from_clipboard() { let clipboard_text = item.text(); if let Some(mut clipboard_selections) = item.metadata::>() { - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); let all_selections_were_entire_line = clipboard_selections.iter().all(|s| s.is_entire_line); if clipboard_selections.len() != selections.len() { @@ -1950,7 +1957,8 @@ impl Editor { // selection was copied. If this selection is also currently empty, // then paste the line before the current line of the buffer. let range = if selection.is_empty() && entire_line { - let column = selection.start.to_point(&*buffer).column as usize; + let column = + selection.start.to_point(&*buffer.as_snapshot()).column as usize; let line_start = selection.start - column; line_start..line_start } else { @@ -1982,7 +1990,7 @@ impl Editor { pub fn move_left(&mut self, _: &MoveLeft, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let start = selection.start.to_display_point(&display_map); let end = selection.end.to_display_point(&display_map); @@ -2004,7 +2012,7 @@ impl Editor { pub fn select_left(&mut self, _: &SelectLeft, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let cursor = movement::left(&display_map, head) @@ -2018,7 +2026,7 @@ impl Editor { pub fn move_right(&mut self, _: &MoveRight, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let start = selection.start.to_display_point(&display_map); let end = selection.end.to_display_point(&display_map); @@ -2040,7 +2048,7 @@ impl Editor { pub fn select_right(&mut self, _: &SelectRight, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let cursor = movement::right(&display_map, head) @@ -2059,7 +2067,7 @@ impl Editor { } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let start = selection.start.to_display_point(&display_map); let end = selection.end.to_display_point(&display_map); @@ -2079,7 +2087,7 @@ impl Editor { pub fn select_up(&mut self, _: &SelectUp, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let (head, goal) = movement::up(&display_map, head, selection.goal).unwrap(); @@ -2097,7 +2105,7 @@ impl Editor { } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let start = selection.start.to_display_point(&display_map); let end = selection.end.to_display_point(&display_map); @@ -2117,7 +2125,7 @@ impl Editor { pub fn select_down(&mut self, _: &SelectDown, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let (head, goal) = movement::down(&display_map, head, selection.goal).unwrap(); @@ -2134,7 +2142,7 @@ impl Editor { cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let cursor = movement::prev_word_boundary(&display_map, head).to_point(&display_map); @@ -2152,7 +2160,7 @@ impl Editor { cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let cursor = movement::prev_word_boundary(&display_map, head).to_point(&display_map); @@ -2169,7 +2177,7 @@ impl Editor { ) { self.start_transaction(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { if selection.is_empty() { let head = selection.head().to_display_point(&display_map); @@ -2190,7 +2198,7 @@ impl Editor { cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let cursor = movement::next_word_boundary(&display_map, head).to_point(&display_map); @@ -2208,7 +2216,7 @@ impl Editor { cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let cursor = movement::next_word_boundary(&display_map, head).to_point(&display_map); @@ -2225,7 +2233,7 @@ impl Editor { ) { self.start_transaction(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { if selection.is_empty() { let head = selection.head().to_display_point(&display_map); @@ -2246,7 +2254,7 @@ impl Editor { cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let new_head = movement::line_beginning(&display_map, head, true); @@ -2265,7 +2273,7 @@ impl Editor { cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let new_head = movement::line_beginning(&display_map, head, *toggle_indent); @@ -2288,7 +2296,7 @@ impl Editor { pub fn move_to_end_of_line(&mut self, _: &MoveToEndOfLine, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); { for selection in &mut selections { let head = selection.head().to_display_point(&display_map); @@ -2305,7 +2313,7 @@ impl Editor { pub fn select_to_end_of_line(&mut self, _: &SelectToEndOfLine, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); let new_head = movement::line_end(&display_map, head); @@ -2378,7 +2386,7 @@ impl Editor { pub fn select_line(&mut self, _: &SelectLine, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); let buffer = self.buffer.read(cx); let max_point = buffer.max_point(); for selection in &mut selections { @@ -2395,7 +2403,7 @@ impl Editor { _: &SplitSelectionIntoLines, cx: &mut ViewContext, ) { - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let buffer = self.buffer.read(cx); let mut to_unfold = Vec::new(); @@ -2434,7 +2442,7 @@ impl Editor { fn add_selection(&mut self, above: bool, cx: &mut ViewContext) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); let mut state = self.add_selections_state.take().unwrap_or_else(|| { let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone(); let range = oldest_selection.display_range(&display_map).sorted(); @@ -2529,7 +2537,7 @@ impl Editor { let replace_newest = action.0; let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = &display_map.buffer_snapshot; - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); if let Some(mut select_next_state) = self.select_next_state.take() { let query = &select_next_state.query; if !select_next_state.done { @@ -2636,11 +2644,12 @@ impl Editor { let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..]; self.start_transaction(cx); - let mut selections = self.selections::(cx).collect::>(); + let mut selections = self.selections::(cx); let mut all_selection_lines_are_comments = true; let mut edit_ranges = Vec::new(); let mut last_toggled_row = None; self.buffer.update(cx, |buffer, cx| { + let buffer_snapshot = buffer.snapshot(cx); for selection in &mut selections { edit_ranges.clear(); @@ -2660,12 +2669,12 @@ impl Editor { last_toggled_row = Some(row); } - if buffer.is_line_blank(row) { + if buffer_snapshot.is_line_blank(row) { continue; } - let start = Point::new(row, buffer.indent_column_for_line(row)); - let mut line_bytes = buffer + let start = Point::new(row, buffer_snapshot.indent_column_for_line(row)); + let mut line_bytes = buffer_snapshot .bytes_in_range(start..buffer.max_point()) .flatten() .copied(); @@ -2712,11 +2721,7 @@ impl Editor { } }); - self.update_selections( - self.selections::(cx).collect(), - Some(Autoscroll::Fit), - cx, - ); + self.update_selections(self.selections::(cx), Some(Autoscroll::Fit), cx); self.end_transaction(cx); } @@ -2725,9 +2730,9 @@ impl Editor { _: &SelectLargerSyntaxNode, cx: &mut ViewContext, ) { - let old_selections = self.selections::(cx).collect::>(); + let old_selections = self.selections::(cx).into_boxed_slice(); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); let mut selected_larger_node = false; @@ -2783,8 +2788,8 @@ impl Editor { _: &MoveToEnclosingBracket, cx: &mut ViewContext, ) { - let mut selections = self.selections::(cx).collect::>(); - let buffer = self.buffer.read(cx.as_ref()); + let mut selections = self.selections::(cx); + let buffer = self.buffer.read(cx).snapshot(cx); for selection in &mut selections { if let Some((open_range, close_range)) = buffer.enclosing_bracket_ranges(selection.start..selection.end) @@ -2806,12 +2811,12 @@ impl Editor { } pub fn show_next_diagnostic(&mut self, _: &ShowNextDiagnostic, cx: &mut ViewContext) { + let buffer = self.buffer.read(cx).snapshot(cx); let selection = self.newest_selection::(cx); - let buffer = self.buffer.read(cx.as_ref()); let active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| { active_diagnostics .primary_range - .to_offset(buffer) + .to_offset(&buffer) .to_inclusive() }); let mut search_start = if let Some(active_primary_range) = active_primary_range.as_ref() { @@ -2863,8 +2868,8 @@ impl Editor { fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext) { if let Some(active_diagnostics) = self.active_diagnostics.as_mut() { - let buffer = self.buffer.read(cx); - let primary_range_start = active_diagnostics.primary_range.start.to_offset(buffer); + let buffer = self.buffer.read(cx).snapshot(cx); + let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer); let is_valid = buffer .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone()) .any(|(range, diagnostic)| { @@ -2895,7 +2900,7 @@ impl Editor { fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext) { self.dismiss_diagnostics(cx); self.active_diagnostics = self.display_map.update(cx, |display_map, cx| { - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let mut primary_range = None; let mut primary_message = None; @@ -3010,7 +3015,7 @@ impl Editor { set_id: SelectionSetId, range: Range, cx: &'a mut MutableAppContext, - ) -> impl 'a + Iterator> { + ) -> Vec> { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); @@ -3036,14 +3041,10 @@ impl Editor { let range = (range.start.to_offset(&display_map, Bias::Left), Bias::Left) ..(range.end.to_offset(&display_map, Bias::Left), Bias::Right); - let selections = self - .buffer - .read(cx) + buffer .selection_set(set_id) .unwrap() - .intersecting_selections::(range, buffer); - - selections + .intersecting_selections::(range, &buffer.as_snapshot()) .map(move |s| Selection { id: s.id, start: s.start.to_display_point(&display_map), @@ -3052,15 +3053,17 @@ impl Editor { goal: s.goal, }) .chain(pending_selection) + .collect() } - pub fn selections<'a, D>(&self, cx: &'a AppContext) -> impl 'a + Iterator> + pub fn selections<'a, D>(&self, cx: &'a AppContext) -> Vec> where - D: 'a + TextDimension + Ord, + D: 'a + TextDimension + Ord + Sub, { - let buffer = self.buffer.read(cx); - let mut selections = self.selection_set(cx).selections::(buffer).peekable(); + let buffer = self.buffer.read(cx).snapshot(cx); + let mut selections = self.selection_set(cx).selections::(&buffer).peekable(); let mut pending_selection = self.pending_selection(cx); + iter::from_fn(move || { if let Some(pending) = pending_selection.as_mut() { while let Some(next_selection) = selections.peek() { @@ -3084,14 +3087,18 @@ impl Editor { selections.next() } }) + .collect() } - fn pending_selection(&self, cx: &AppContext) -> Option> { - let buffer = self.buffer.read(cx); + fn pending_selection>( + &self, + cx: &AppContext, + ) -> Option> { + let buffer = self.buffer.read(cx).as_snapshot(); self.pending_selection.as_ref().map(|pending| Selection { id: pending.selection.id, - start: pending.selection.start.summary::(buffer), - end: pending.selection.end.summary::(buffer), + start: pending.selection.start.summary::(&buffer), + end: pending.selection.end.summary::(&buffer), reversed: pending.selection.reversed, goal: pending.selection.goal, }) @@ -3105,18 +3112,26 @@ impl Editor { selection_count } - pub fn oldest_selection(&self, cx: &AppContext) -> Selection { - let buffer = self.buffer.read(cx); + pub fn oldest_selection>( + &self, + snapshot: &MultiBufferSnapshot, + cx: &AppContext, + ) -> Selection { self.selection_set(cx) - .oldest_selection(buffer) + .oldest_selection(snapshot) .or_else(|| self.pending_selection(cx)) .unwrap() } - pub fn newest_selection(&self, cx: &AppContext) -> Selection { - let buffer = self.buffer.read(cx); + pub fn newest_selection>( + &self, + cx: &AppContext, + ) -> Selection { self.pending_selection(cx) - .or_else(|| self.selection_set(cx).newest_selection(buffer)) + .or_else(|| { + self.selection_set(cx) + .newest_selection(&self.buffer.read(cx).as_snapshot()) + }) .unwrap() } @@ -3136,7 +3151,7 @@ impl Editor { T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug, { // Merge overlapping selections. - let buffer = self.buffer.read(cx); + let buffer = self.buffer.read(cx).snapshot(cx); let mut i = 1; while i < selections.len() { if selections[i - 1].end >= selections[i].start { @@ -3161,9 +3176,9 @@ impl Editor { if selections.len() == autoclose_pair_state.ranges.len() { selections .iter() - .zip(autoclose_pair_state.ranges.ranges::(buffer)) + .zip(autoclose_pair_state.ranges.ranges::(&buffer)) .all(|(selection, autoclose_range)| { - let head = selection.head().to_point(&*buffer); + let head = selection.head().to_point(&buffer); autoclose_range.start <= head && autoclose_range.end >= head }) } else { @@ -3222,7 +3237,7 @@ impl Editor { pub fn fold(&mut self, _: &Fold, cx: &mut ViewContext) { let mut fold_ranges = Vec::new(); - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); for selection in selections { let range = selection.display_range(&display_map).sorted(); @@ -3245,7 +3260,7 @@ impl Editor { } pub fn unfold(&mut self, _: &Unfold, cx: &mut ViewContext) { - let selections = self.selections::(cx).collect::>(); + let selections = self.selections::(cx); let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); let buffer = self.buffer.read(cx); let ranges = selections @@ -3306,12 +3321,17 @@ impl Editor { pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext) { let selections = self.selections::(cx); - let ranges = selections.map(|s| s.start..s.end).collect(); + let ranges = selections.into_iter().map(|s| s.start..s.end); self.fold_ranges(ranges, cx); } - fn fold_ranges(&mut self, ranges: Vec>, cx: &mut ViewContext) { - if !ranges.is_empty() { + fn fold_ranges( + &mut self, + ranges: impl IntoIterator>, + cx: &mut ViewContext, + ) { + let mut ranges = ranges.into_iter().peekable(); + if ranges.peek().is_some() { self.display_map.update(cx, |map, cx| map.fold(ranges, cx)); self.request_autoscroll(Autoscroll::Fit, cx); cx.notify(); @@ -3414,14 +3434,14 @@ impl Editor { self.show_local_cursors } - fn on_buffer_changed(&mut self, _: ModelHandle, cx: &mut ViewContext) { + fn on_buffer_changed(&mut self, _: ModelHandle, cx: &mut ViewContext) { self.refresh_active_diagnostics(cx); cx.notify(); } fn on_buffer_event( &mut self, - _: ModelHandle, + _: ModelHandle, event: &language::Event, cx: &mut ViewContext, ) { @@ -3596,10 +3616,36 @@ impl View for Editor { } } -impl SelectionExt for Selection { +impl SelectionExt for Selection { + fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range { + let start = self.start.to_point(buffer); + let end = self.end.to_point(buffer); + if self.reversed { + end..start + } else { + start..end + } + } + + fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range { + let start = self.start.to_offset(buffer); + let end = self.end.to_offset(buffer); + if self.reversed { + end..start + } else { + start..end + } + } + fn display_range(&self, map: &DisplaySnapshot) -> Range { - let start = self.start.to_display_point(map); - let end = self.end.to_display_point(map); + let start = self + .start + .to_point(&map.buffer_snapshot) + .to_display_point(map); + let end = self + .end + .to_point(&map.buffer_snapshot) + .to_display_point(map); if self.reversed { end..start } else { @@ -3612,8 +3658,14 @@ impl SelectionExt for Selection { include_end_if_at_line_start: bool, map: &DisplaySnapshot, ) -> SpannedRows { - let display_start = self.start.to_display_point(map); - let mut display_end = self.end.to_display_point(map); + let display_start = self + .start + .to_point(&map.buffer_snapshot) + .to_display_point(map); + let mut display_end = self + .end + .to_point(&map.buffer_snapshot) + .to_display_point(map); if !include_end_if_at_line_start && display_end.row() != map.max_point().row() && display_start.row() != display_end.row() @@ -3667,13 +3719,14 @@ pub fn diagnostic_style( #[cfg(test)] mod tests { use super::*; + use language::LanguageConfig; use text::Point; use unindent::Unindent; use util::test::sample_text; #[gpui::test] fn test_selection_with_mouse(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx)); + let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); let settings = EditorSettings::test(cx); let (_, editor) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); @@ -3740,7 +3793,7 @@ mod tests { #[gpui::test] fn test_canceling_pending_selection(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx)); + let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); let settings = EditorSettings::test(cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); @@ -3772,7 +3825,7 @@ mod tests { #[gpui::test] fn test_cancel(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx)); + let buffer = MultiBuffer::build_simple("aaaaaa\nbbbbbb\ncccccc\ndddddd\n", cx); let settings = EditorSettings::test(cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); @@ -3812,30 +3865,27 @@ mod tests { #[gpui::test] fn test_fold(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| { - Buffer::new( - 0, - " - impl Foo { - // Hello! + let buffer = MultiBuffer::build_simple( + &" + impl Foo { + // Hello! - fn a() { - 1 - } - - fn b() { - 2 - } - - fn c() { - 3 - } + fn a() { + 1 } - " - .unindent(), - cx, - ) - }); + + fn b() { + 2 + } + + fn c() { + 3 + } + } + " + .unindent(), + cx, + ); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -3903,7 +3953,7 @@ mod tests { #[gpui::test] fn test_move_cursor(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx)); + let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -3980,7 +4030,7 @@ mod tests { #[gpui::test] fn test_move_cursor_multibyte(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx)); + let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -4038,7 +4088,7 @@ mod tests { #[gpui::test] fn test_move_cursor_different_line_lengths(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx)); + let buffer = MultiBuffer::build_simple("ⓐⓑⓒⓓⓔ\nabcd\nαβγ\nabcd\nⓐⓑⓒⓓⓔ\n", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -4069,7 +4119,7 @@ mod tests { #[gpui::test] fn test_beginning_end_of_line(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "abc\n def", cx)); + let buffer = MultiBuffer::build_simple("abc\n def", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { @@ -4211,8 +4261,7 @@ mod tests { #[gpui::test] fn test_prev_next_word_boundary(cx: &mut gpui::MutableAppContext) { - let buffer = - cx.add_model(|cx| Buffer::new(0, "use std::str::{foo, bar}\n\n {baz.qux()}", cx)); + let buffer = MultiBuffer::build_simple("use std::str::{foo, bar}\n\n {baz.qux()}", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { @@ -4351,8 +4400,7 @@ mod tests { #[gpui::test] fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut gpui::MutableAppContext) { - let buffer = - cx.add_model(|cx| Buffer::new(0, "use one::{\n two::three::four::five\n};", cx)); + let buffer = MultiBuffer::build_simple("use one::{\n two::three::four::five\n};", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); @@ -4406,7 +4454,7 @@ mod tests { #[gpui::test] fn test_delete_to_word_boundary(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "one two three four", cx)); + let buffer = MultiBuffer::build_simple("one two three four", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -4447,7 +4495,7 @@ mod tests { #[gpui::test] fn test_newline(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "aaaa\n bbbb\n", cx)); + let buffer = MultiBuffer::build_simple("aaaa\n bbbb\n", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -4471,7 +4519,7 @@ mod tests { #[gpui::test] fn test_indent_outdent(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, " one two\nthree\n four", cx)); + let buffer = MultiBuffer::build_simple(" one two\nthree\n four", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -4532,13 +4580,8 @@ mod tests { #[gpui::test] fn test_backspace(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| { - Buffer::new( - 0, - "one two three\nfour five six\nseven eight nine\nten\n", - cx, - ) - }); + let buffer = + MultiBuffer::build_simple("one two three\nfour five six\nseven eight nine\nten\n", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -4568,13 +4611,8 @@ mod tests { #[gpui::test] fn test_delete(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| { - Buffer::new( - 0, - "one two three\nfour five six\nseven eight nine\nten\n", - cx, - ) - }); + let buffer = + MultiBuffer::build_simple("one two three\nfour five six\nseven eight nine\nten\n", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| { build_editor(buffer.clone(), settings, cx) @@ -4605,7 +4643,7 @@ mod tests { #[gpui::test] fn test_delete_line(cx: &mut gpui::MutableAppContext) { let settings = EditorSettings::test(&cx); - let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { view.select_display_ranges( @@ -4629,7 +4667,7 @@ mod tests { }); let settings = EditorSettings::test(&cx); - let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { view.select_display_ranges(&[DisplayPoint::new(2, 0)..DisplayPoint::new(0, 1)], cx) @@ -4646,7 +4684,7 @@ mod tests { #[gpui::test] fn test_duplicate_line(cx: &mut gpui::MutableAppContext) { let settings = EditorSettings::test(&cx); - let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { view.select_display_ranges( @@ -4673,7 +4711,7 @@ mod tests { }); let settings = EditorSettings::test(&cx); - let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndef\nghi\n", cx)); + let buffer = MultiBuffer::build_simple("abc\ndef\nghi\n", cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { view.select_display_ranges( @@ -4699,7 +4737,7 @@ mod tests { #[gpui::test] fn test_move_line_up_down(cx: &mut gpui::MutableAppContext) { let settings = EditorSettings::test(&cx); - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(10, 5, 'a'), cx)); + let buffer = MultiBuffer::build_simple(&sample_text(10, 5, 'a'), cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { view.fold_ranges( @@ -4795,7 +4833,7 @@ mod tests { #[gpui::test] fn test_clipboard(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "one✅ two three four five six ", cx)); + let buffer = MultiBuffer::build_simple("one✅ two three four five six ", cx); let settings = EditorSettings::test(&cx); let view = cx .add_window(Default::default(), |cx| { @@ -4930,7 +4968,7 @@ mod tests { #[gpui::test] fn test_select_all(cx: &mut gpui::MutableAppContext) { - let buffer = cx.add_model(|cx| Buffer::new(0, "abc\nde\nfgh", cx)); + let buffer = MultiBuffer::build_simple("abc\nde\nfgh", cx); let settings = EditorSettings::test(&cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { @@ -4945,7 +4983,7 @@ mod tests { #[gpui::test] fn test_select_line(cx: &mut gpui::MutableAppContext) { let settings = EditorSettings::test(&cx); - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 5, 'a'), cx)); + let buffer = MultiBuffer::build_simple(&sample_text(6, 5, 'a'), cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { view.select_display_ranges( @@ -4991,7 +5029,7 @@ mod tests { #[gpui::test] fn test_split_selection_into_lines(cx: &mut gpui::MutableAppContext) { let settings = EditorSettings::test(&cx); - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(9, 5, 'a'), cx)); + let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { view.fold_ranges( @@ -5059,7 +5097,7 @@ mod tests { #[gpui::test] fn test_add_selection_above_below(cx: &mut gpui::MutableAppContext) { let settings = EditorSettings::test(&cx); - let buffer = cx.add_model(|cx| Buffer::new(0, "abc\ndefghi\n\njk\nlmno\n", cx)); + let buffer = MultiBuffer::build_simple("abc\ndefghi\n\njk\nlmno\n", cx); let (_, view) = cx.add_window(Default::default(), |cx| build_editor(buffer, settings, cx)); view.update(cx, |view, cx| { @@ -5247,8 +5285,9 @@ mod tests { .unindent(); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx)); + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx)); - view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing()) + view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; view.update(&mut cx, |view, cx| { @@ -5403,8 +5442,9 @@ mod tests { .unindent(); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx)); + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx)); - view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing()) + view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; view.update(&mut cx, |view, cx| { @@ -5503,6 +5543,7 @@ mod tests { .unindent(); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx)); + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx)); view.update(&mut cx, |editor, cx| { @@ -5600,8 +5641,9 @@ mod tests { ); let buffer = cx.add_model(|cx| Buffer::new(0, text, cx).with_language(language, None, cx)); + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); let (_, view) = cx.add_window(|cx| build_editor(buffer, settings, cx)); - view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing()) + view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing(cx)) .await; view.update(&mut cx, |view, cx| { @@ -5659,7 +5701,7 @@ mod tests { } fn build_editor( - buffer: ModelHandle, + buffer: ModelHandle, settings: EditorSettings, cx: &mut ViewContext, ) -> Editor { diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index a53fdd3a8b..a878bc4a17 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -19,7 +19,7 @@ use gpui::{ MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle, }; use json::json; -use language::{Chunk, ToPoint}; +use language::{multi_buffer::ToPoint, Chunk}; use smallvec::SmallVec; use std::{ cmp::{self, Ordering}, @@ -738,13 +738,11 @@ impl Element for EditorElement { self.update_view(cx.app, |view, cx| { highlighted_row = view.highlighted_row(); for selection_set_id in view.active_selection_sets(cx).collect::>() { - let replica_selections = view - .intersecting_selections( - selection_set_id, - DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0), - cx, - ) - .collect::>(); + let replica_selections = view.intersecting_selections( + selection_set_id, + DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0), + cx, + ); for selection in &replica_selections { if selection_set_id == view.selection_set_id { let is_empty = selection.start == selection.end; @@ -1165,14 +1163,13 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 { mod tests { use super::*; use crate::{Editor, EditorSettings}; - use language::Buffer; + use language::{MultiBuffer}; use util::test::sample_text; #[gpui::test] fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) { let settings = EditorSettings::test(cx); - - let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6, 'a'), cx)); + let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx); let (window_id, editor) = cx.add_window(Default::default(), |cx| { Editor::for_buffer( buffer, diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index f4261c30bb..1c7b4a25f5 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -5,12 +5,15 @@ use gpui::{ MutableAppContext, RenderContext, Subscription, Task, View, ViewContext, ViewHandle, WeakModelHandle, }; -use language::{Buffer, Diagnostic, File as _}; +use language::{ + multi_buffer::{MultiBuffer, ToPoint as _}, + Diagnostic, File as _, +}; use postage::watch; use project::{ProjectPath, Worktree}; use std::fmt::Write; use std::path::Path; -use text::{Point, Selection, ToPoint}; +use text::{Point, Selection}; use workspace::{ settings, EntryOpener, ItemHandle, ItemView, ItemViewHandle, Settings, StatusItemView, WeakItemHandle, @@ -19,10 +22,10 @@ use workspace::{ pub struct BufferOpener; #[derive(Clone)] -pub struct BufferItemHandle(pub ModelHandle); +pub struct BufferItemHandle(pub ModelHandle); #[derive(Clone)] -struct WeakBufferItemHandle(WeakModelHandle); +struct WeakBufferItemHandle(WeakModelHandle); impl EntryOpener for BufferOpener { fn open( @@ -32,10 +35,10 @@ impl EntryOpener for BufferOpener { cx: &mut ModelContext, ) -> Option>>> { let buffer = worktree.open_buffer(project_path.path, cx); - let task = cx.spawn(|_, _| async move { - buffer - .await - .map(|buffer| Box::new(BufferItemHandle(buffer)) as Box) + let task = cx.spawn(|_, mut cx| async move { + let buffer = buffer.await?; + let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx)); + Ok(Box::new(BufferItemHandle(buffer)) as Box) }); Some(task) } @@ -102,7 +105,7 @@ impl ItemHandle for BufferItemHandle { } fn project_path(&self, cx: &AppContext) -> Option { - self.0.read(cx).file().map(|f| ProjectPath { + self.0.read(cx).file(cx).map(|f| ProjectPath { worktree_id: f.worktree_id(), path: f.path().clone(), }) @@ -137,7 +140,7 @@ impl ItemView for Editor { let filename = self .buffer() .read(cx) - .file() + .file(cx) .and_then(|file| file.file_name()); if let Some(name) = filename { name.to_string_lossy().into() @@ -147,7 +150,7 @@ impl ItemView for Editor { } fn project_path(&self, cx: &AppContext) -> Option { - self.buffer().read(cx).file().map(|file| ProjectPath { + self.buffer().read(cx).file(cx).map(|file| ProjectPath { worktree_id: file.worktree_id(), path: file.path().clone(), }) @@ -174,7 +177,14 @@ impl ItemView for Editor { path: &Path, cx: &mut ViewContext, ) -> Task> { - self.buffer().update(cx, |buffer, cx| { + let buffer = self + .buffer() + .read(cx) + .as_singleton() + .expect("cannot call save_as on an excerpt list") + .clone(); + + buffer.update(cx, |buffer, cx| { let handle = cx.handle(); let text = buffer.as_rope().clone(); let version = buffer.version(); @@ -237,7 +247,7 @@ impl CursorPosition { fn update_position(&mut self, editor: ViewHandle, cx: &mut ViewContext) { let editor = editor.read(cx); - let buffer = editor.buffer().read(cx); + let buffer = editor.buffer().read(cx).snapshot(cx); self.selected_count = 0; let mut last_selection: Option> = None; @@ -250,7 +260,7 @@ impl CursorPosition { last_selection = Some(selection); } } - self.position = last_selection.map(|s| s.head().to_point(buffer)); + self.position = last_selection.map(|s| s.head().to_point(&buffer)); cx.notify(); } diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 9ba6cbc08d..44cb1ebcf5 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -1,7 +1,7 @@ use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint}; use anyhow::Result; +use language::multi_buffer::ToPoint; use std::{cmp, ops::Range}; -use text::ToPoint; pub fn left(map: &DisplaySnapshot, mut point: DisplayPoint) -> Result { if point.column() > 0 { @@ -244,7 +244,8 @@ fn char_kind(c: char) -> CharKind { #[cfg(test)] mod tests { use super::*; - use crate::{display_map::DisplayMap, Buffer}; + use crate::display_map::DisplayMap; + use language::MultiBuffer; #[gpui::test] fn test_prev_next_word_boundary_multibyte(cx: &mut gpui::MutableAppContext) { @@ -256,7 +257,7 @@ mod tests { .unwrap(); let font_size = 14.0; - let buffer = cx.add_model(|cx| Buffer::new(0, "a bcΔ defγ hi—jk", cx)); + let buffer = MultiBuffer::build_simple("a bcΔ defγ hi—jk", cx); let display_map = cx.add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, cx)); let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx)); @@ -312,7 +313,7 @@ mod tests { .select_font(family_id, &Default::default()) .unwrap(); let font_size = 14.0; - let buffer = cx.add_model(|cx| Buffer::new(0, "lorem ipsum dolor\n sit", cx)); + let buffer = MultiBuffer::build_simple("lorem ipsum dolor\n sit", cx); let display_map = cx.add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, cx)); let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx)); diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index dbd36b1139..b35a6fe002 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -67,7 +67,7 @@ impl GoToLine { let (restore_state, cursor_point, max_point) = active_editor.update(cx, |editor, cx| { let restore_state = Some(RestoreState { scroll_position: editor.scroll_position(cx), - selections: editor.selections::(cx).collect(), + selections: editor.selections::(cx), }); ( diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 16dbd1c140..3fa611ee04 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -1,6 +1,6 @@ mod buffer; mod highlight_map; -mod multi_buffer; +pub mod multi_buffer; pub mod proto; #[cfg(test)] mod tests; @@ -12,6 +12,7 @@ use gpui::{executor::Background, AppContext}; use highlight_map::HighlightMap; use lazy_static::lazy_static; use lsp::LanguageServer; +pub use multi_buffer::MultiBuffer; use parking_lot::Mutex; use serde::Deserialize; use std::{collections::HashSet, path::Path, str, sync::Arc}; diff --git a/crates/language/src/multi_buffer.rs b/crates/language/src/multi_buffer.rs index 6e545e3fd2..12834a53d3 100644 --- a/crates/language/src/multi_buffer.rs +++ b/crates/language/src/multi_buffer.rs @@ -5,20 +5,25 @@ mod selection; use self::location::*; use crate::{ buffer::{self, Buffer, Chunk, ToOffset as _, ToPoint as _}, - BufferSnapshot, + BufferSnapshot, Diagnostic, File, Language, }; +use anyhow::Result; +use clock::ReplicaId; use collections::HashMap; -use gpui::{AppContext, Entity, ModelContext, ModelHandle}; -use parking_lot::Mutex; -use std::{cmp, ops::Range}; +use gpui::{AppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task}; +use parking_lot::{Mutex, MutexGuard}; +use std::{cmp, io, ops::Range, sync::Arc, time::SystemTime}; use sum_tree::{Bias, Cursor, SumTree}; use text::{ rope::TextDimension, subscription::{Subscription, Topic}, - AnchorRangeExt, Edit, Point, PointUtf16, TextSummary, + AnchorRangeExt as _, Edit, Point, PointUtf16, Selection, SelectionSetId, TextSummary, }; use theme::SyntaxTheme; +pub use anchor::{Anchor, AnchorRangeExt, AnchorRangeMap, AnchorRangeSet}; +pub use selection::SelectionSet; + const NEWLINES: &'static [u8] = &[b'\n'; u8::MAX as usize]; #[derive(Default)] @@ -28,11 +33,11 @@ pub struct MultiBuffer { subscriptions: Topic, } -pub trait ToOffset { +pub trait ToOffset: 'static { fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize; } -pub trait ToPoint { +pub trait ToPoint: 'static { fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point; } @@ -69,7 +74,7 @@ struct ExcerptSummary { text: TextSummary, } -pub struct Chunks<'a> { +pub struct MultiBufferChunks<'a> { range: Range, cursor: Cursor<'a, Excerpt, usize>, header_height: u8, @@ -77,20 +82,155 @@ pub struct Chunks<'a> { theme: Option<&'a SyntaxTheme>, } +pub struct MultiBufferBytes<'a> { + chunks: MultiBufferChunks<'a>, +} + impl MultiBuffer { pub fn new() -> Self { Self::default() } + pub fn singleton(buffer: ModelHandle, cx: &mut ModelContext) -> Self { + let mut this = Self::new(); + this.push( + ExcerptProperties { + buffer: &buffer, + range: text::Anchor::min()..text::Anchor::max(), + header_height: 0, + }, + cx, + ); + this + } + + pub fn build_simple(text: &str, cx: &mut MutableAppContext) -> ModelHandle { + let buffer = cx.add_model(|cx| Buffer::new(0, text, cx)); + cx.add_model(|cx| Self::singleton(buffer, cx)) + } + pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot { self.sync(cx); self.snapshot.lock().clone() } + pub fn as_snapshot(&self) -> MutexGuard { + self.snapshot.lock() + } + + pub fn as_singleton(&self) -> Option<&ModelHandle> { + if self.buffers.len() == 1 { + return Some(&self.buffers.values().next().unwrap().buffer); + } else { + None + } + } + pub fn subscribe(&mut self) -> Subscription { self.subscriptions.subscribe() } + pub fn edit(&mut self, ranges_iter: I, new_text: T, cx: &mut ModelContext) + where + I: IntoIterator>, + S: ToOffset, + T: Into, + { + self.edit_internal(ranges_iter, new_text, false, cx) + } + + pub fn edit_with_autoindent( + &mut self, + ranges_iter: I, + new_text: T, + cx: &mut ModelContext, + ) where + I: IntoIterator>, + S: ToOffset, + T: Into, + { + self.edit_internal(ranges_iter, new_text, true, cx) + } + + pub fn edit_internal( + &mut self, + ranges_iter: I, + new_text: T, + autoindent: bool, + cx: &mut ModelContext, + ) where + I: IntoIterator>, + S: ToOffset, + T: Into, + { + todo!() + } + + pub fn start_transaction( + &mut self, + selection_set_ids: impl IntoIterator, + ) -> Result<()> { + todo!() + } + + pub fn end_transaction( + &mut self, + selection_set_ids: impl IntoIterator, + cx: &mut ModelContext, + ) -> Result<()> { + todo!() + } + + pub fn undo(&mut self, cx: &mut ModelContext) { + todo!() + } + + pub fn redo(&mut self, cx: &mut ModelContext) { + todo!() + } + + pub fn selection_set(&self, set_id: SelectionSetId) -> Result<&SelectionSet> { + todo!() + } + + pub fn add_selection_set( + &mut self, + selections: &[Selection], + cx: &mut ModelContext, + ) -> SelectionSetId { + todo!() + } + + pub fn remove_selection_set( + &mut self, + set_id: SelectionSetId, + cx: &mut ModelContext, + ) -> Result<()> { + todo!() + } + + pub fn update_selection_set( + &mut self, + set_id: SelectionSetId, + selections: &[Selection], + cx: &mut ModelContext, + ) -> Result<()> { + todo!() + } + + pub fn set_active_selection_set( + &mut self, + set_id: Option, + cx: &mut ModelContext, + ) -> Result<()> { + todo!() + } + + pub fn selection_sets(&self) -> impl Iterator { + todo!(); + None.into_iter() + } + pub fn push(&mut self, props: ExcerptProperties, cx: &mut ModelContext) -> ExcerptId where O: text::ToOffset, @@ -125,6 +265,30 @@ impl MultiBuffer { id } + pub fn save( + &mut self, + cx: &mut ModelContext, + ) -> Result>> { + todo!() + } + + pub fn file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn File> { + self.as_singleton() + .and_then(|buffer| buffer.read(cx).file()) + } + + pub fn is_dirty(&self) -> bool { + todo!() + } + + pub fn has_conflict(&self) -> bool { + todo!() + } + + pub fn is_parsing(&self, _: &AppContext) -> bool { + todo!() + } + fn sync(&self, cx: &AppContext) { let mut snapshot = self.snapshot.lock(); let mut excerpts_to_edit = Vec::new(); @@ -194,17 +358,141 @@ impl MultiBuffer { } } +// Methods delegating to the snapshot +impl MultiBuffer { + pub fn replica_id(&self) -> ReplicaId { + self.snapshot.lock().replica_id() + } + + pub fn text(&self) -> String { + self.snapshot.lock().text() + } + + pub fn text_for_range<'a, T: ToOffset>( + &'a self, + range: Range, + ) -> impl Iterator { + todo!(); + [].into_iter() + } + + pub fn max_point(&self) -> Point { + self.snapshot.lock().max_point() + } + + pub fn len(&self) -> usize { + self.snapshot.lock().len() + } + + pub fn line_len(&self, row: u32) -> u32 { + self.snapshot.lock().line_len(row) + } + + pub fn is_line_blank(&self, row: u32) -> bool { + self.snapshot.lock().is_line_blank(row) + } + + pub fn indent_column_for_line(&self, row: u32) -> u32 { + self.snapshot.lock().indent_column_for_line(row) + } + + pub fn anchor_before(&self, position: T) -> Anchor { + self.snapshot.lock().anchor_before(position) + } + + pub fn anchor_after(&self, position: T) -> Anchor { + self.snapshot.lock().anchor_after(position) + } + + pub fn anchor_at(&self, position: T, bias: Bias) -> Anchor { + self.snapshot.lock().anchor_at(position, bias) + } + + pub fn anchor_range_set( + &self, + start_bias: Bias, + end_bias: Bias, + entries: E, + ) -> AnchorRangeSet + where + E: IntoIterator>, + { + todo!() + } + + pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize { + self.snapshot.lock().clip_offset(offset, bias) + } + + pub fn clip_point(&self, point: Point, bias: Bias) -> Point { + self.snapshot.lock().clip_point(point, bias) + } + + pub fn language<'a>(&self) -> Option<&'a Arc> { + todo!() + } + + pub fn parse_count(&self) -> usize { + self.snapshot.lock().parse_count() + } + + pub fn diagnostics_update_count(&self) -> usize { + self.snapshot.lock().diagnostics_update_count() + } + + pub fn diagnostics_in_range<'a, T, O>( + &'a self, + search_range: Range, + ) -> impl Iterator, &Diagnostic)> + 'a + where + T: 'a + ToOffset, + O: 'a, + { + todo!(); + None.into_iter() + } +} + +#[cfg(any(test, feature = "test-support"))] +impl MultiBuffer { + pub fn randomly_edit(&mut self, _: &mut R, _: usize, _: &mut ModelContext) { + todo!() + } + + pub fn randomly_mutate(&mut self, rng: &mut R, cx: &mut ModelContext) { + todo!() + } +} + impl Entity for MultiBuffer { - type Event = (); + type Event = super::Event; } impl MultiBufferSnapshot { + pub fn replica_id(&self) -> ReplicaId { + todo!() + } + pub fn text(&self) -> String { self.chunks(0..self.len(), None) .map(|chunk| chunk.text) .collect() } + pub fn reversed_chars_at<'a, T: ToOffset>( + &'a self, + position: T, + ) -> impl Iterator + 'a { + todo!(); + None.into_iter() + } + + pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator + 'a { + let offset = position.to_offset(self); + self.text_for_range(offset..self.len()) + .flat_map(|chunk| chunk.chars()) + } + pub fn text_for_range<'a, T: ToOffset>( &'a self, range: Range, @@ -212,6 +500,18 @@ impl MultiBufferSnapshot { self.chunks(range, None).map(|chunk| chunk.text) } + pub fn is_line_blank(&self, row: u32) -> bool { + self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row))) + .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none()) + } + + pub fn contains_str_at(&self, _: T, _: &str) -> bool + where + T: ToOffset, + { + todo!() + } + pub fn len(&self) -> usize { self.excerpts.summary().text.bytes } @@ -291,11 +591,15 @@ impl MultiBufferSnapshot { } } + pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range) -> MultiBufferBytes<'a> { + todo!() + } + pub fn chunks<'a, T: ToOffset>( &'a self, range: Range, theme: Option<&'a SyntaxTheme>, - ) -> Chunks<'a> { + ) -> MultiBufferChunks<'a> { let range = range.start.to_offset(self)..range.end.to_offset(self); let mut cursor = self.excerpts.cursor::(); cursor.seek(&range.start, Bias::Right, &()); @@ -331,7 +635,7 @@ impl MultiBufferSnapshot { excerpt.buffer.chunks(buffer_start..buffer_end, theme) }); - Chunks { + MultiBufferChunks { range, cursor, header_height, @@ -413,6 +717,10 @@ impl MultiBufferSnapshot { } } + pub fn indent_column_for_line(&self, row: u32) -> u32 { + todo!() + } + pub fn line_len(&self, row: u32) -> u32 { let mut cursor = self.excerpts.cursor::(); cursor.seek(&Point::new(row, 0), Bias::Right, &()); @@ -534,18 +842,62 @@ impl MultiBufferSnapshot { summary } - fn resolve_excerpt<'a, D: TextDimension>( + pub fn anchor_before(&self, position: T) -> Anchor { + self.anchor_at(position, Bias::Left) + } + + pub fn anchor_after(&self, position: T) -> Anchor { + self.anchor_at(position, Bias::Right) + } + + pub fn anchor_at(&self, position: T, bias: Bias) -> Anchor { + todo!() + } + + pub fn parse_count(&self) -> usize { + todo!() + } + + pub fn enclosing_bracket_ranges( + &self, + range: Range, + ) -> Option<(Range, Range)> { + todo!() + } + + pub fn diagnostics_update_count(&self) -> usize { + todo!() + } + + pub fn language<'a>(&self) -> Option<&'a Arc> { + todo!() + } + + pub fn diagnostic_group<'a, O>( &'a self, - excerpt_id: &ExcerptId, - ) -> Option<(D, &'a BufferSnapshot)> { - let mut cursor = self.excerpts.cursor::<(ExcerptId, TextSummary)>(); - cursor.seek(excerpt_id, Bias::Left, &()); - if let Some(excerpt) = cursor.item() { - if cursor.start().0 == *excerpt_id { - return Some((D::from_text_summary(&cursor.start().1), &excerpt.buffer)); - } - } - None + group_id: usize, + ) -> impl Iterator, &Diagnostic)> + 'a + where + O: 'a, + { + todo!(); + None.into_iter() + } + + pub fn diagnostics_in_range<'a, T, O>( + &'a self, + search_range: Range, + ) -> impl Iterator, &Diagnostic)> + 'a + where + T: 'a + ToOffset, + O: 'a, + { + todo!(); + None.into_iter() + } + + pub fn range_for_syntax_ancestor(&self, range: Range) -> Option> { + todo!() } fn buffer_snapshot_for_excerpt<'a>( @@ -672,7 +1024,17 @@ impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Location { } } -impl<'a> Iterator for Chunks<'a> { +impl<'a> MultiBufferChunks<'a> { + pub fn offset(&self) -> usize { + todo!() + } + + pub fn seek(&mut self, offset: usize) { + todo!() + } +} + +impl<'a> Iterator for MultiBufferChunks<'a> { type Item = Chunk<'a>; fn next(&mut self) -> Option { @@ -726,6 +1088,20 @@ impl<'a> Iterator for Chunks<'a> { } } +impl<'a> Iterator for MultiBufferBytes<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option { + todo!() + } +} + +impl<'a> io::Read for MultiBufferBytes<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + todo!() + } +} + impl ToOffset for Point { fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize { snapshot.point_to_offset(*self) diff --git a/crates/language/src/multi_buffer/anchor.rs b/crates/language/src/multi_buffer/anchor.rs index e6b78eeefe..752308604b 100644 --- a/crates/language/src/multi_buffer/anchor.rs +++ b/crates/language/src/multi_buffer/anchor.rs @@ -1,9 +1,12 @@ -use super::{location::*, ExcerptSummary, MultiBufferSnapshot, ToOffset}; +use super::{location::*, ExcerptSummary, MultiBufferSnapshot, ToOffset, ToPoint}; use anyhow::{anyhow, Result}; use smallvec::SmallVec; -use std::{cmp::Ordering, ops::Range}; +use std::{ + cmp::Ordering, + ops::{Range, Sub}, +}; use sum_tree::Bias; -use text::{rope::TextDimension, AnchorRangeExt, ToOffset as _}; +use text::{rope::TextDimension, AnchorRangeExt as _, Point}; #[derive(Clone, Eq, PartialEq, Debug, Hash)] pub struct Anchor { @@ -16,6 +19,9 @@ pub struct AnchorRangeMap { entries: SmallVec<[(ExcerptId, text::AnchorRangeMap); 1]>, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct AnchorRangeSet(AnchorRangeMap<()>); + impl Anchor { pub fn min() -> Self { Self { @@ -68,6 +74,27 @@ impl Anchor { } self.clone() } + + pub fn summary<'a, D>(&self, snapshot: &'a MultiBufferSnapshot) -> D + where + D: TextDimension + Ord + Sub, + { + let mut cursor = snapshot.excerpts.cursor::(); + cursor.seek(&self.excerpt_id, Bias::Left, &()); + if let Some(excerpt) = cursor.item() { + if excerpt.id == self.excerpt_id { + let mut excerpt_start = D::from_text_summary(&cursor.start().text); + excerpt_start.add_summary(&excerpt.header_summary(), &()); + let excerpt_buffer_start = excerpt.range.start.summary::(&excerpt.buffer); + let buffer_point = self.text_anchor.summary::(&excerpt.buffer); + if buffer_point > excerpt_buffer_start { + excerpt_start.add_assign(&(buffer_point - excerpt_buffer_start)); + } + return excerpt_start; + } + } + D::from_text_summary(&cursor.start().text) + } } impl AnchorRangeMap { @@ -263,18 +290,48 @@ impl AnchorRangeMap { } } -impl ToOffset for Anchor { - fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize { - let mut cursor = snapshot.excerpts.cursor::(); - cursor.seek(&self.excerpt_id, Bias::Left, &()); - if let Some(excerpt) = cursor.item() { - if excerpt.id == self.excerpt_id { - let buffer_offset = self.text_anchor.to_offset(&excerpt.buffer); - return cursor.start().text.bytes - + excerpt.header_height as usize - + buffer_offset.saturating_sub(excerpt.range.start.to_offset(&excerpt.buffer)); - } - } - cursor.start().text.bytes +impl AnchorRangeSet { + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn ranges<'a, D>( + &'a self, + content: &'a MultiBufferSnapshot, + ) -> impl 'a + Iterator> + where + D: TextDimension, + { + self.0.ranges(content).map(|(range, _)| range) + } +} + +impl ToOffset for Anchor { + fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize { + self.summary(snapshot) + } +} + +impl ToPoint for Anchor { + fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point { + self.summary(snapshot) + } +} + +pub trait AnchorRangeExt { + fn cmp(&self, b: &Range, buffer: &MultiBufferSnapshot) -> Result; + fn to_offset(&self, content: &MultiBufferSnapshot) -> Range; +} + +impl AnchorRangeExt for Range { + fn cmp(&self, other: &Range, buffer: &MultiBufferSnapshot) -> Result { + Ok(match self.start.cmp(&other.start, buffer)? { + Ordering::Equal => other.end.cmp(&self.end, buffer)?, + ord @ _ => ord, + }) + } + + fn to_offset(&self, content: &MultiBufferSnapshot) -> Range { + self.start.to_offset(&content)..self.end.to_offset(&content) } } diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index 9a52322c22..c7c5670103 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -376,7 +376,7 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) { .selection_set(selection_set_id) .unwrap() .selections::(&buffer) - .map(|selection| selection.point_range(&buffer)) + .map(|selection| selection.start.to_point(&buffer)..selection.end.to_point(&buffer)) .collect::>(); assert_eq!(selection_ranges[0], empty(Point::new(1, 4))); diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index 96949d05ff..970a739981 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -948,7 +948,7 @@ mod tests { fs::{FakeFs, Fs as _}, language::{ tree_sitter_rust, Diagnostic, Language, LanguageConfig, LanguageRegistry, - LanguageServerConfig, Point, + LanguageServerConfig, MultiBuffer, Point, }, lsp, project::{ProjectPath, Worktree}, @@ -1035,6 +1035,7 @@ mod tests { .update(&mut cx_b, |worktree, cx| worktree.open_buffer("b.txt", cx)) .await .unwrap(); + let buffer_b = cx_b.add_model(|cx| MultiBuffer::singleton(buffer_b, cx)); buffer_b.read_with(&cx_b, |buf, _| assert_eq!(buf.text(), "b-contents")); worktree_a.read_with(&cx_a, |tree, cx| assert!(tree.has_open_buffer("b.txt", cx))); let buffer_a = worktree_a diff --git a/crates/text/src/patch.rs b/crates/text/src/patch.rs index f5592cefd0..8e68b2545c 100644 --- a/crates/text/src/patch.rs +++ b/crates/text/src/patch.rs @@ -201,6 +201,15 @@ where } } +impl IntoIterator for Patch { + type Item = Edit; + type IntoIter = std::vec::IntoIter>; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + impl<'a, T: Clone> IntoIterator for &'a Patch { type Item = Edit; type IntoIter = std::iter::Cloned>>; diff --git a/crates/text/src/selection.rs b/crates/text/src/selection.rs index 6c04da016a..184118b78b 100644 --- a/crates/text/src/selection.rs +++ b/crates/text/src/selection.rs @@ -1,6 +1,4 @@ -use crate::{ - rope::TextDimension, AnchorRangeMap, Buffer, BufferSnapshot, Point, ToOffset, ToPoint, -}; +use crate::{rope::TextDimension, AnchorRangeMap, BufferSnapshot, ToOffset, ToPoint}; use std::{cmp::Ordering, ops::Range, sync::Arc}; use sum_tree::Bias; @@ -75,26 +73,6 @@ impl Selection { self.end = head; } } - - pub fn point_range(&self, buffer: &Buffer) -> Range { - let start = self.start.to_point(buffer); - let end = self.end.to_point(buffer); - if self.reversed { - end..start - } else { - start..end - } - } - - pub fn offset_range(&self, buffer: &Buffer) -> Range { - let start = self.start.to_offset(buffer); - let end = self.end.to_offset(buffer); - if self.reversed { - end..start - } else { - start..end - } - } } impl SelectionSet { diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 5a4ee1ad93..597649af49 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -1850,13 +1850,13 @@ impl BufferSnapshot { self.visible_text.clip_point_utf16(point, bias) } - pub fn point_for_offset(&self, offset: usize) -> Result { - if offset <= self.len() { - Ok(self.text_summary_for_range(0..offset)) - } else { - Err(anyhow!("offset out of bounds")) - } - } + // pub fn point_for_offset(&self, offset: usize) -> Result { + // if offset <= self.len() { + // Ok(self.text_summary_for_range(0..offset)) + // } else { + // Err(anyhow!("offset out of bounds")) + // } + // } pub fn edits_since<'a, D>( &'a self,