Detailed changes
@@ -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>,
+ buffer: ModelHandle<MultiBuffer>,
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>,
+ buffer: ModelHandle<MultiBuffer>,
tab_size: usize,
font_id: FontId,
font_size: f32,
@@ -48,7 +51,7 @@ impl DisplayMap {
cx: &mut ModelContext<Self>,
) -> 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<Self>) -> 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<Item = Range<T>>,
cx: &mut ModelContext<Self>,
) {
- 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<Item = Range<T>>,
cx: &mut ModelContext<Self>,
) {
- 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<BlockId>, cx: &mut ModelContext<Self>) {
- 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::<String>();
- 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();
@@ -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>,
+ buffer: ModelHandle<MultiBuffer>,
next_block_id: AtomicUsize,
wrap_snapshot: Mutex<WrapSnapshot>,
blocks: Vec<Arc<Block>>,
@@ -109,7 +112,7 @@ pub struct BlockBufferRows<'a> {
}
impl BlockMap {
- pub fn new(buffer: ModelHandle<Buffer>, wrap_snapshot: WrapSnapshot) -> Self {
+ pub fn new(buffer: ModelHandle<MultiBuffer>, 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::<Edit<u32>>::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<BlockId>, 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::<String>();
- 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::<String>();
+ 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 => {
@@ -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<BufferSnapshot>,
+ buffer: Mutex<MultiBufferSnapshot>,
transforms: Mutex<SumTree<Transform>>,
folds: SumTree<Fold>,
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<Edit<usize>>,
) -> (FoldSnapshot, Vec<FoldEdit>) {
let edits = self.sync(buffer, edits);
@@ -240,7 +241,7 @@ impl FoldMap {
pub fn write(
&mut self,
- buffer: BufferSnapshot,
+ buffer: MultiBufferSnapshot,
edits: Vec<Edit<usize>>,
) -> (FoldMapWriter, FoldSnapshot, Vec<FoldEdit>) {
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<text::Edit<usize>>,
) -> Vec<FoldEdit> {
if buffer_edits.is_empty() {
@@ -476,7 +477,7 @@ impl FoldMap {
pub struct FoldSnapshot {
transforms: SumTree<Transform>,
folds: SumTree<Fold>,
- 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<Fold>,
range: Range<T>,
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<FoldOffset>;
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::<Vec<_>>();
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::<String>();
- 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::<String>();
+ 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::<Point>(&start_version)
- .collect::<Vec<_>>();
+ let edits = subscription.consume().into_inner();
log::info!("editing {:?}", edits);
- buffer.edits_since::<usize>(&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![]);
@@ -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::<String>();
- 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::<String>();
+ 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());
@@ -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::<String>();
- 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!(
@@ -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<Box<dyn EntryOpe
}
trait SelectionExt {
+ fn offset_range(&self, buffer: &MultiBufferSnapshot) -> Range<usize>;
+ fn point_range(&self, buffer: &MultiBufferSnapshot) -> Range<Point>;
fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
fn spanned_rows(
&self,
@@ -347,7 +356,7 @@ pub enum SoftWrap {
pub struct Editor {
handle: WeakViewHandle<Self>,
- buffer: ModelHandle<Buffer>,
+ buffer: ModelHandle<MultiBuffer>,
display_map: ModelHandle<DisplayMap>,
selection_set_id: SelectionSetId,
pending_selection: Option<PendingSelection>,
@@ -422,6 +431,7 @@ impl Editor {
cx: &mut ViewContext<Self>,
) -> 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>,
) -> 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>,
+ buffer: ModelHandle<MultiBuffer>,
build_settings: impl 'static + Fn(&AppContext) -> EditorSettings,
cx: &mut ViewContext<Self>,
) -> Self {
@@ -454,7 +465,7 @@ impl Editor {
}
pub fn new(
- buffer: ModelHandle<Buffer>,
+ buffer: ModelHandle<MultiBuffer>,
build_settings: Rc<RefCell<dyn Fn(&AppContext) -> EditorSettings>>,
cx: &mut ViewContext<Self>,
) -> 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<Buffer> {
+ pub fn buffer(&self) -> &ModelHandle<MultiBuffer> {
&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::<Point>(cx).peekable();
+ let selections = self.selections::<Point>(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<Self>,
) {
+ let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let tail = self.newest_selection::<usize>(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::<usize>(cx);
- self.update_selections::<usize>(
- 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::<usize>(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>) {
self.columnar_selection_tail.take();
if self.pending_selection.is_some() {
- let selections = self.selections::<usize>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<usize>(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::<Point>(cx).next().is_none() {
+ if self.selections::<Point>(cx).is_empty() {
self.update_selections(vec![selection], Some(Autoscroll::Fit), cx);
}
} else {
- let mut oldest_selection = self.oldest_selection::<usize>(cx);
+ let buffer = self.buffer.read(cx).snapshot(cx);
+ let mut oldest_selection = self.oldest_selection::<usize>(&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<Item = Range<T>>,
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::<Point>(cx).collect::<Vec<_>>();
- let buffer = self.buffer.read(cx);
+ let selections = self.selections::<Point>(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>) {
self.start_transaction(cx);
- let old_selections = self.selections::<usize>(cx).collect::<SmallVec<[_; 32]>>();
+ let old_selections = self.selections::<usize>(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<Self>) {
- let selections = self.selections::<usize>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<usize>(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::<SmallVec<[_; 32]>>();
@@ -1344,7 +1353,7 @@ impl Editor {
}
fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext<Self>) -> bool {
- let old_selections = self.selections::<usize>(cx).collect::<Vec<_>>();
+ let old_selections = self.selections::<usize>(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::<usize>(buffer))
+ .zip(autoclose_pair_state.ranges.ranges::<usize>(&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>) {
self.start_transaction(cx);
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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>) {
self.start_transaction(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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>) {
self.start_transaction(cx);
let tab_size = self.build_settings.borrow()(cx).tab_size;
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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>) {
self.start_transaction(cx);
let tab_size = self.build_settings.borrow()(cx).tab_size;
- let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<Point>(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::<usize>(cx).collect(),
- Some(Autoscroll::Fit),
- cx,
- );
+ self.update_selections(self.selections::<usize>(cx), Some(Autoscroll::Fit), cx);
self.end_transaction(cx);
}
pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
self.start_transaction(cx);
- let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<Point>(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>) {
self.start_transaction(cx);
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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>) {
self.start_transaction(cx);
- let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<Point>(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>) {
self.start_transaction(cx);
- let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<Point>(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>) {
self.start_transaction(cx);
let mut text = String::new();
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
- let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<Point>(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::<Vec<ClipboardSelection>>() {
- let mut selections = self.selections::<usize>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<usize>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>,
) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>,
) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>,
) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>,
) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>,
) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>,
) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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<Self>,
) {
- let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<Point>(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<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let mut selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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::<usize>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<usize>(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::<Point>(cx).collect::<Vec<_>>();
+ let mut selections = self.selections::<Point>(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::<usize>(cx).collect(),
- Some(Autoscroll::Fit),
- cx,
- );
+ self.update_selections(self.selections::<usize>(cx), Some(Autoscroll::Fit), cx);
self.end_transaction(cx);
}
@@ -2725,9 +2730,9 @@ impl Editor {
_: &SelectLargerSyntaxNode,
cx: &mut ViewContext<Self>,
) {
- let old_selections = self.selections::<usize>(cx).collect::<Box<_>>();
+ let old_selections = self.selections::<usize>(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<Self>,
) {
- let mut selections = self.selections::<usize>(cx).collect::<Vec<_>>();
- let buffer = self.buffer.read(cx.as_ref());
+ let mut selections = self.selections::<usize>(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<Self>) {
+ let buffer = self.buffer.read(cx).snapshot(cx);
let selection = self.newest_selection::<usize>(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<Editor>) {
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>) {
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<DisplayPoint>,
cx: &'a mut MutableAppContext,
- ) -> impl 'a + Iterator<Item = Selection<DisplayPoint>> {
+ ) -> Vec<Selection<DisplayPoint>> {
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::<Point, _>(range, buffer);
-
- selections
+ .intersecting_selections::<Point, _>(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<Item = Selection<D>>
+ pub fn selections<'a, D>(&self, cx: &'a AppContext) -> Vec<Selection<D>>
where
- D: 'a + TextDimension + Ord,
+ D: 'a + TextDimension + Ord + Sub<D, Output = D>,
{
- let buffer = self.buffer.read(cx);
- let mut selections = self.selection_set(cx).selections::<D>(buffer).peekable();
+ let buffer = self.buffer.read(cx).snapshot(cx);
+ let mut selections = self.selection_set(cx).selections::<D>(&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<D: TextDimension>(&self, cx: &AppContext) -> Option<Selection<D>> {
- let buffer = self.buffer.read(cx);
+ fn pending_selection<D: TextDimension + Ord + Sub<D, Output = D>>(
+ &self,
+ cx: &AppContext,
+ ) -> Option<Selection<D>> {
+ 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::<D>(buffer),
- end: pending.selection.end.summary::<D>(buffer),
+ start: pending.selection.start.summary::<D>(&buffer),
+ end: pending.selection.end.summary::<D>(&buffer),
reversed: pending.selection.reversed,
goal: pending.selection.goal,
})
@@ -3105,18 +3112,26 @@ impl Editor {
selection_count
}
- pub fn oldest_selection<T: TextDimension>(&self, cx: &AppContext) -> Selection<T> {
- let buffer = self.buffer.read(cx);
+ pub fn oldest_selection<D: TextDimension + Ord + Sub<D, Output = D>>(
+ &self,
+ snapshot: &MultiBufferSnapshot,
+ cx: &AppContext,
+ ) -> Selection<D> {
self.selection_set(cx)
- .oldest_selection(buffer)
+ .oldest_selection(snapshot)
.or_else(|| self.pending_selection(cx))
.unwrap()
}
- pub fn newest_selection<T: TextDimension>(&self, cx: &AppContext) -> Selection<T> {
- let buffer = self.buffer.read(cx);
+ pub fn newest_selection<D: TextDimension + Ord + Sub<D, Output = D>>(
+ &self,
+ cx: &AppContext,
+ ) -> Selection<D> {
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::<Point>(buffer))
+ .zip(autoclose_pair_state.ranges.ranges::<Point>(&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<Self>) {
let mut fold_ranges = Vec::new();
- let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<Point>(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<Self>) {
- let selections = self.selections::<Point>(cx).collect::<Vec<_>>();
+ let selections = self.selections::<Point>(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<Self>) {
let selections = self.selections::<Point>(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<T: ToOffset>(&mut self, ranges: Vec<Range<T>>, cx: &mut ViewContext<Self>) {
- if !ranges.is_empty() {
+ fn fold_ranges<T: ToOffset>(
+ &mut self,
+ ranges: impl IntoIterator<Item = Range<T>>,
+ cx: &mut ViewContext<Self>,
+ ) {
+ 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();
@@ -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::<Vec<_>>() {
- let replica_selections = view
- .intersecting_selections(
- selection_set_id,
- DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
- cx,
- )
- .collect::<Vec<_>>();
+ 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,
@@ -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<Buffer>);
+pub struct BufferItemHandle(pub ModelHandle<MultiBuffer>);
#[derive(Clone)]
-struct WeakBufferItemHandle(WeakModelHandle<Buffer>);
+struct WeakBufferItemHandle(WeakModelHandle<MultiBuffer>);
impl EntryOpener for BufferOpener {
fn open(
@@ -32,10 +35,10 @@ impl EntryOpener for BufferOpener {
cx: &mut ModelContext<Worktree>,
) -> Option<Task<Result<Box<dyn ItemHandle>>>> {
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<dyn ItemHandle>)
+ 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<dyn ItemHandle>)
});
Some(task)
}
@@ -102,7 +105,7 @@ impl ItemHandle for BufferItemHandle {
}
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
- 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<ProjectPath> {
- 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<Self>,
) -> Task<Result<()>> {
- 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<Editor>, cx: &mut ViewContext<Self>) {
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<Selection<usize>> = 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();
}
@@ -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<DisplayPoint> {
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));
@@ -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::<usize>(cx).collect(),
+ selections: editor.selections::<usize>(cx),
});
(
@@ -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};
@@ -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<usize>,
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<Buffer>, cx: &mut ModelContext<Self>) -> 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<Self> {
+ 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<MultiBufferSnapshot> {
+ self.snapshot.lock()
+ }
+
+ pub fn as_singleton(&self) -> Option<&ModelHandle<Buffer>> {
+ 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<I, S, T>(&mut self, ranges_iter: I, new_text: T, cx: &mut ModelContext<Self>)
+ where
+ I: IntoIterator<Item = Range<S>>,
+ S: ToOffset,
+ T: Into<String>,
+ {
+ self.edit_internal(ranges_iter, new_text, false, cx)
+ }
+
+ pub fn edit_with_autoindent<I, S, T>(
+ &mut self,
+ ranges_iter: I,
+ new_text: T,
+ cx: &mut ModelContext<Self>,
+ ) where
+ I: IntoIterator<Item = Range<S>>,
+ S: ToOffset,
+ T: Into<String>,
+ {
+ self.edit_internal(ranges_iter, new_text, true, cx)
+ }
+
+ pub fn edit_internal<I, S, T>(
+ &mut self,
+ ranges_iter: I,
+ new_text: T,
+ autoindent: bool,
+ cx: &mut ModelContext<Self>,
+ ) where
+ I: IntoIterator<Item = Range<S>>,
+ S: ToOffset,
+ T: Into<String>,
+ {
+ todo!()
+ }
+
+ pub fn start_transaction(
+ &mut self,
+ selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
+ ) -> Result<()> {
+ todo!()
+ }
+
+ pub fn end_transaction(
+ &mut self,
+ selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
+ cx: &mut ModelContext<Self>,
+ ) -> Result<()> {
+ todo!()
+ }
+
+ pub fn undo(&mut self, cx: &mut ModelContext<Self>) {
+ todo!()
+ }
+
+ pub fn redo(&mut self, cx: &mut ModelContext<Self>) {
+ todo!()
+ }
+
+ pub fn selection_set(&self, set_id: SelectionSetId) -> Result<&SelectionSet> {
+ todo!()
+ }
+
+ pub fn add_selection_set<T: ToOffset>(
+ &mut self,
+ selections: &[Selection<T>],
+ cx: &mut ModelContext<Self>,
+ ) -> SelectionSetId {
+ todo!()
+ }
+
+ pub fn remove_selection_set(
+ &mut self,
+ set_id: SelectionSetId,
+ cx: &mut ModelContext<Self>,
+ ) -> Result<()> {
+ todo!()
+ }
+
+ pub fn update_selection_set<T: ToOffset>(
+ &mut self,
+ set_id: SelectionSetId,
+ selections: &[Selection<T>],
+ cx: &mut ModelContext<Self>,
+ ) -> Result<()> {
+ todo!()
+ }
+
+ pub fn set_active_selection_set(
+ &mut self,
+ set_id: Option<SelectionSetId>,
+ cx: &mut ModelContext<Self>,
+ ) -> Result<()> {
+ todo!()
+ }
+
+ pub fn selection_sets(&self) -> impl Iterator<Item = (&SelectionSetId, &SelectionSet)> {
+ todo!();
+ None.into_iter()
+ }
+
pub fn push<O>(&mut self, props: ExcerptProperties<O>, cx: &mut ModelContext<Self>) -> ExcerptId
where
O: text::ToOffset,
@@ -125,6 +265,30 @@ impl MultiBuffer {
id
}
+ pub fn save(
+ &mut self,
+ cx: &mut ModelContext<Self>,
+ ) -> Result<Task<Result<(clock::Global, SystemTime)>>> {
+ 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<T>,
+ ) -> impl Iterator<Item = &'a str> {
+ 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<T: ToOffset>(&self, position: T) -> Anchor {
+ self.snapshot.lock().anchor_before(position)
+ }
+
+ pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
+ self.snapshot.lock().anchor_after(position)
+ }
+
+ pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
+ self.snapshot.lock().anchor_at(position, bias)
+ }
+
+ pub fn anchor_range_set<E>(
+ &self,
+ start_bias: Bias,
+ end_bias: Bias,
+ entries: E,
+ ) -> AnchorRangeSet
+ where
+ E: IntoIterator<Item = Range<usize>>,
+ {
+ 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<Language>> {
+ 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<T>,
+ ) -> impl Iterator<Item = (Range<O>, &Diagnostic)> + 'a
+ where
+ T: 'a + ToOffset,
+ O: 'a,
+ {
+ todo!();
+ None.into_iter()
+ }
+}
+
+#[cfg(any(test, feature = "test-support"))]
+impl MultiBuffer {
+ pub fn randomly_edit<R: rand::Rng>(&mut self, _: &mut R, _: usize, _: &mut ModelContext<Self>) {
+ todo!()
+ }
+
+ pub fn randomly_mutate<R: rand::Rng>(&mut self, rng: &mut R, cx: &mut ModelContext<Self>) {
+ 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<Item = char> + 'a {
+ todo!();
+ None.into_iter()
+ }
+
+ pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + '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<T>,
@@ -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<T>(&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<T>) -> MultiBufferBytes<'a> {
+ todo!()
+ }
+
pub fn chunks<'a, T: ToOffset>(
&'a self,
range: Range<T>,
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::<usize>();
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::<Point>();
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<T: ToOffset>(&self, position: T) -> Anchor {
+ self.anchor_at(position, Bias::Left)
+ }
+
+ pub fn anchor_after<T: ToOffset>(&self, position: T) -> Anchor {
+ self.anchor_at(position, Bias::Right)
+ }
+
+ pub fn anchor_at<T: ToOffset>(&self, position: T, bias: Bias) -> Anchor {
+ todo!()
+ }
+
+ pub fn parse_count(&self) -> usize {
+ todo!()
+ }
+
+ pub fn enclosing_bracket_ranges<T: ToOffset>(
+ &self,
+ range: Range<T>,
+ ) -> Option<(Range<usize>, Range<usize>)> {
+ todo!()
+ }
+
+ pub fn diagnostics_update_count(&self) -> usize {
+ todo!()
+ }
+
+ pub fn language<'a>(&self) -> Option<&'a Arc<Language>> {
+ 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<Item = (Range<O>, &Diagnostic)> + 'a
+ where
+ O: 'a,
+ {
+ todo!();
+ None.into_iter()
+ }
+
+ pub fn diagnostics_in_range<'a, T, O>(
+ &'a self,
+ search_range: Range<T>,
+ ) -> impl Iterator<Item = (Range<O>, &Diagnostic)> + 'a
+ where
+ T: 'a + ToOffset,
+ O: 'a,
+ {
+ todo!();
+ None.into_iter()
+ }
+
+ pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
+ 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<Self::Item> {
@@ -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<Self::Item> {
+ todo!()
+ }
+}
+
+impl<'a> io::Read for MultiBufferBytes<'a> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ todo!()
+ }
+}
+
impl ToOffset for Point {
fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
snapshot.point_to_offset(*self)
@@ -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<T> {
entries: SmallVec<[(ExcerptId, text::AnchorRangeMap<T>); 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<D, Output = D>,
+ {
+ let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
+ 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::<D>(&excerpt.buffer);
+ let buffer_point = self.text_anchor.summary::<D>(&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<T> AnchorRangeMap<T> {
@@ -263,18 +290,48 @@ impl<T> AnchorRangeMap<T> {
}
}
+impl AnchorRangeSet {
+ pub fn len(&self) -> usize {
+ self.0.len()
+ }
+
+ pub fn ranges<'a, D>(
+ &'a self,
+ content: &'a MultiBufferSnapshot,
+ ) -> impl 'a + Iterator<Item = Range<Point>>
+ where
+ D: TextDimension,
+ {
+ self.0.ranges(content).map(|(range, _)| range)
+ }
+}
+
impl ToOffset for Anchor {
fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
- let mut cursor = snapshot.excerpts.cursor::<ExcerptSummary>();
- 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
+ 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<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering>;
+ fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
+}
+
+impl AnchorRangeExt for Range<Anchor> {
+ fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering> {
+ 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<usize> {
+ self.start.to_offset(&content)..self.end.to_offset(&content)
}
}
@@ -376,7 +376,7 @@ fn test_autoindent_moves_selections(cx: &mut MutableAppContext) {
.selection_set(selection_set_id)
.unwrap()
.selections::<Point>(&buffer)
- .map(|selection| selection.point_range(&buffer))
+ .map(|selection| selection.start.to_point(&buffer)..selection.end.to_point(&buffer))
.collect::<Vec<_>>();
assert_eq!(selection_ranges[0], empty(Point::new(1, 4)));
@@ -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
@@ -201,6 +201,15 @@ where
}
}
+impl<T: Clone> IntoIterator for Patch<T> {
+ type Item = Edit<T>;
+ type IntoIter = std::vec::IntoIter<Edit<T>>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.0.into_iter()
+ }
+}
+
impl<'a, T: Clone> IntoIterator for &'a Patch<T> {
type Item = Edit<T>;
type IntoIter = std::iter::Cloned<std::slice::Iter<'a, Edit<T>>>;
@@ -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<T: ToOffset + ToPoint + Copy + Ord> Selection<T> {
self.end = head;
}
}
-
- pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
- 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<usize> {
- let start = self.start.to_offset(buffer);
- let end = self.end.to_offset(buffer);
- if self.reversed {
- end..start
- } else {
- start..end
- }
- }
}
impl SelectionSet {
@@ -1850,13 +1850,13 @@ impl BufferSnapshot {
self.visible_text.clip_point_utf16(point, bias)
}
- pub fn point_for_offset(&self, offset: usize) -> Result<Point> {
- 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<Point> {
+ // 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,