From 870925e2ac64c1777b7151f77079285c44485273 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 26 Apr 2021 14:29:33 -0600 Subject: [PATCH] Rerender tabs when buffers' file handles change Co-Authored-By: Nathan Sobo --- zed/src/editor/buffer/mod.rs | 1021 +++++++++++++----------- zed/src/editor/buffer_view.rs | 29 +- zed/src/editor/display_map/fold_map.rs | 12 +- zed/src/editor/display_map/mod.rs | 4 +- zed/src/workspace/workspace.rs | 14 +- zed/src/worktree.rs | 50 +- 6 files changed, 636 insertions(+), 494 deletions(-) diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index d8f808334c63dbac270dd2a9798fdfb20dea8a04..597990fbb34155e0ca5ea0ff5ad113dd7607281f 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -353,15 +353,29 @@ pub struct UndoOperation { } impl Buffer { - pub fn new>>(replica_id: ReplicaId, base_text: T) -> Self { - Self::build(replica_id, None, History::new(base_text.into())) - } - - pub fn from_history(replica_id: ReplicaId, file: FileHandle, history: History) -> Self { - Self::build(replica_id, Some(file), history) - } - - fn build(replica_id: ReplicaId, file: Option, history: History) -> Self { + pub fn new>>( + replica_id: ReplicaId, + base_text: T, + ctx: &mut ModelContext, + ) -> Self { + Self::build(replica_id, None, History::new(base_text.into()), ctx) + } + + pub fn from_history( + replica_id: ReplicaId, + file: FileHandle, + history: History, + ctx: &mut ModelContext, + ) -> Self { + Self::build(replica_id, Some(file), history, ctx) + } + + fn build( + replica_id: ReplicaId, + file: Option, + history: History, + ctx: &mut ModelContext, + ) -> Self { let mut insertion_splits = HashMap::default(); let mut fragments = SumTree::new(); @@ -410,6 +424,10 @@ impl Buffer { }); } + if let Some(file) = file.as_ref() { + file.observe_from_model(ctx, |_, _, ctx| ctx.emit(Event::FileHandleChanged)); + } + Self { file, fragments, @@ -445,6 +463,8 @@ impl Buffer { pub fn save(&mut self, ctx: &mut ModelContext) -> LocalBoxFuture<'static, Result<()>> { if let Some(file) = &self.file { + dbg!(file.path()); + let snapshot = self.snapshot(); let version = self.version.clone(); let save_task = file.save(snapshot, ctx.as_ref()); @@ -1772,6 +1792,7 @@ pub enum Event { Edited(Vec), Dirtied, Saved, + FileHandleChanged, } impl Entity for Buffer { @@ -2305,21 +2326,24 @@ mod tests { use std::{cell::RefCell, rc::Rc}; #[test] - fn test_edit() -> Result<()> { - let mut buffer = Buffer::new(0, "abc"); - assert_eq!(buffer.text(), "abc"); - buffer.edit(vec![3..3], "def", None)?; - assert_eq!(buffer.text(), "abcdef"); - buffer.edit(vec![0..0], "ghi", None)?; - assert_eq!(buffer.text(), "ghiabcdef"); - buffer.edit(vec![5..5], "jkl", None)?; - assert_eq!(buffer.text(), "ghiabjklcdef"); - buffer.edit(vec![6..7], "", None)?; - assert_eq!(buffer.text(), "ghiabjlcdef"); - buffer.edit(vec![4..9], "mno", None)?; - assert_eq!(buffer.text(), "ghiamnoef"); - - Ok(()) + fn test_edit() { + App::test((), |ctx| { + ctx.add_model(|ctx| { + let mut buffer = Buffer::new(0, "abc", ctx); + assert_eq!(buffer.text(), "abc"); + buffer.edit(vec![3..3], "def", None).unwrap(); + assert_eq!(buffer.text(), "abcdef"); + buffer.edit(vec![0..0], "ghi", None).unwrap(); + assert_eq!(buffer.text(), "ghiabcdef"); + buffer.edit(vec![5..5], "jkl", None).unwrap(); + assert_eq!(buffer.text(), "ghiabjklcdef"); + buffer.edit(vec![6..7], "", None).unwrap(); + assert_eq!(buffer.text(), "ghiabjlcdef"); + buffer.edit(vec![4..9], "mno", None).unwrap(); + assert_eq!(buffer.text(), "ghiamnoef"); + buffer + }); + }) } #[test] @@ -2329,8 +2353,8 @@ mod tests { let buffer_1_events = Rc::new(RefCell::new(Vec::new())); let buffer_2_events = Rc::new(RefCell::new(Vec::new())); - let buffer1 = app.add_model(|_| Buffer::new(0, "abcdef")); - let buffer2 = app.add_model(|_| Buffer::new(1, "abcdef")); + let buffer1 = app.add_model(|ctx| Buffer::new(0, "abcdef", ctx)); + let buffer2 = app.add_model(|ctx| Buffer::new(1, "abcdef", ctx)); let mut buffer_ops = Vec::new(); buffer1.update(app, |buffer, ctx| { let buffer_1_events = buffer_1_events.clone(); @@ -2408,187 +2432,207 @@ mod tests { #[test] fn test_random_edits() { for seed in 0..100 { - println!("{:?}", seed); - let mut rng = &mut StdRng::seed_from_u64(seed); + App::test((), |ctx| { + println!("{:?}", seed); + let mut rng = &mut StdRng::seed_from_u64(seed); + + let reference_string_len = rng.gen_range(0..3); + let mut reference_string = RandomCharIter::new(&mut rng) + .take(reference_string_len) + .collect::(); + ctx.add_model(|ctx| { + let mut buffer = Buffer::new(0, reference_string.as_str(), ctx); + let mut buffer_versions = Vec::new(); + for _i in 0..10 { + let (old_ranges, new_text, _) = buffer.randomly_mutate(rng, None); + for old_range in old_ranges.iter().rev() { + reference_string = [ + &reference_string[0..old_range.start], + new_text.as_str(), + &reference_string[old_range.end..], + ] + .concat(); + } + assert_eq!(buffer.text(), reference_string); - let reference_string_len = rng.gen_range(0..3); - let mut reference_string = RandomCharIter::new(&mut rng) - .take(reference_string_len) - .collect::(); - let mut buffer = Buffer::new(0, reference_string.as_str()); - let mut buffer_versions = Vec::new(); - - for _i in 0..10 { - let (old_ranges, new_text, _) = buffer.randomly_mutate(rng, None); - for old_range in old_ranges.iter().rev() { - reference_string = [ - &reference_string[0..old_range.start], - new_text.as_str(), - &reference_string[old_range.end..], - ] - .concat(); - } - assert_eq!(buffer.text(), reference_string); + if rng.gen_bool(0.25) { + buffer.randomly_undo_redo(rng); + reference_string = buffer.text(); + } - if rng.gen_bool(0.25) { - buffer.randomly_undo_redo(rng); - reference_string = buffer.text(); - } + { + let line_lengths = line_lengths_in_range(&buffer, 0..buffer.len()); - { - let line_lengths = line_lengths_in_range(&buffer, 0..buffer.len()); + for (len, rows) in &line_lengths { + for row in rows { + assert_eq!(buffer.line_len(*row).unwrap(), *len); + } + } - for (len, rows) in &line_lengths { - for row in rows { - assert_eq!(buffer.line_len(*row).unwrap(), *len); + let (longest_column, longest_rows) = + line_lengths.iter().next_back().unwrap(); + let rightmost_point = buffer.rightmost_point(); + assert_eq!(rightmost_point.column, *longest_column); + assert!(longest_rows.contains(&rightmost_point.row)); } - } - let (longest_column, longest_rows) = line_lengths.iter().next_back().unwrap(); - let rightmost_point = buffer.rightmost_point(); - assert_eq!(rightmost_point.column, *longest_column); - assert!(longest_rows.contains(&rightmost_point.row)); - } + for _ in 0..5 { + let end = rng.gen_range(0..buffer.len() + 1); + let start = rng.gen_range(0..end + 1); + + let line_lengths = line_lengths_in_range(&buffer, start..end); + let (longest_column, longest_rows) = + line_lengths.iter().next_back().unwrap(); + let range_sum = buffer.text_summary_for_range(start..end); + assert_eq!(range_sum.rightmost_point.column, *longest_column); + assert!(longest_rows.contains(&range_sum.rightmost_point.row)); + let range_text = &buffer.text()[start..end]; + assert_eq!(range_sum.chars, range_text.chars().count()); + assert_eq!(range_sum.bytes, range_text.len()); + } - for _ in 0..5 { - let end = rng.gen_range(0..buffer.len() + 1); - let start = rng.gen_range(0..end + 1); - - let line_lengths = line_lengths_in_range(&buffer, start..end); - let (longest_column, longest_rows) = line_lengths.iter().next_back().unwrap(); - let range_sum = buffer.text_summary_for_range(start..end); - assert_eq!(range_sum.rightmost_point.column, *longest_column); - assert!(longest_rows.contains(&range_sum.rightmost_point.row)); - let range_text = &buffer.text()[start..end]; - assert_eq!(range_sum.chars, range_text.chars().count()); - assert_eq!(range_sum.bytes, range_text.len()); - } + if rng.gen_bool(0.3) { + buffer_versions.push(buffer.clone()); + } + } - if rng.gen_bool(0.3) { - buffer_versions.push(buffer.clone()); - } - } + for mut old_buffer in buffer_versions { + let mut delta = 0_isize; + for Edit { + old_range, + new_range, + } in buffer.edits_since(old_buffer.version.clone()) + { + let old_len = old_range.end - old_range.start; + let new_len = new_range.end - new_range.start; + let old_start = (old_range.start as isize + delta) as usize; + let new_text: String = + buffer.text_for_range(new_range).unwrap().collect(); + old_buffer + .edit(Some(old_start..old_start + old_len), new_text, None) + .unwrap(); + + delta += new_len as isize - old_len as isize; + } + assert_eq!(old_buffer.text(), buffer.text()); + } - for mut old_buffer in buffer_versions { - let mut delta = 0_isize; - for Edit { - old_range, - new_range, - } in buffer.edits_since(old_buffer.version.clone()) - { - let old_len = old_range.end - old_range.start; - let new_len = new_range.end - new_range.start; - let old_start = (old_range.start as isize + delta) as usize; - let new_text: String = buffer.text_for_range(new_range).unwrap().collect(); - old_buffer - .edit(Some(old_start..old_start + old_len), new_text, None) - .unwrap(); - - delta += new_len as isize - old_len as isize; - } - assert_eq!(old_buffer.text(), buffer.text()); - } + buffer + }) + }); } } #[test] - fn test_line_len() -> Result<()> { - let mut buffer = Buffer::new(0, ""); - buffer.edit(vec![0..0], "abcd\nefg\nhij", None)?; - buffer.edit(vec![12..12], "kl\nmno", None)?; - buffer.edit(vec![18..18], "\npqrs\n", None)?; - buffer.edit(vec![18..21], "\nPQ", None)?; - - assert_eq!(buffer.line_len(0)?, 4); - assert_eq!(buffer.line_len(1)?, 3); - assert_eq!(buffer.line_len(2)?, 5); - assert_eq!(buffer.line_len(3)?, 3); - assert_eq!(buffer.line_len(4)?, 4); - assert_eq!(buffer.line_len(5)?, 0); - assert!(buffer.line_len(6).is_err()); - - Ok(()) + fn test_line_len() { + App::test((), |ctx| { + ctx.add_model(|ctx| { + let mut buffer = Buffer::new(0, "", ctx); + buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap(); + buffer.edit(vec![12..12], "kl\nmno", None).unwrap(); + buffer.edit(vec![18..18], "\npqrs\n", None).unwrap(); + buffer.edit(vec![18..21], "\nPQ", None).unwrap(); + + assert_eq!(buffer.line_len(0).unwrap(), 4); + assert_eq!(buffer.line_len(1).unwrap(), 3); + assert_eq!(buffer.line_len(2).unwrap(), 5); + assert_eq!(buffer.line_len(3).unwrap(), 3); + assert_eq!(buffer.line_len(4).unwrap(), 4); + assert_eq!(buffer.line_len(5).unwrap(), 0); + assert!(buffer.line_len(6).is_err()); + buffer + }); + }); } #[test] - fn test_rightmost_point() -> Result<()> { - let mut buffer = Buffer::new(0, ""); - assert_eq!(buffer.rightmost_point().row, 0); - buffer.edit(vec![0..0], "abcd\nefg\nhij", None)?; - assert_eq!(buffer.rightmost_point().row, 0); - buffer.edit(vec![12..12], "kl\nmno", None)?; - assert_eq!(buffer.rightmost_point().row, 2); - buffer.edit(vec![18..18], "\npqrs", None)?; - assert_eq!(buffer.rightmost_point().row, 2); - buffer.edit(vec![10..12], "", None)?; - assert_eq!(buffer.rightmost_point().row, 0); - buffer.edit(vec![24..24], "tuv", None)?; - assert_eq!(buffer.rightmost_point().row, 4); - - println!("{:?}", buffer.text()); - - Ok(()) + fn test_rightmost_point() { + App::test((), |ctx| { + ctx.add_model(|ctx| { + let mut buffer = Buffer::new(0, "", ctx); + assert_eq!(buffer.rightmost_point().row, 0); + buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap(); + assert_eq!(buffer.rightmost_point().row, 0); + buffer.edit(vec![12..12], "kl\nmno", None).unwrap(); + assert_eq!(buffer.rightmost_point().row, 2); + buffer.edit(vec![18..18], "\npqrs", None).unwrap(); + assert_eq!(buffer.rightmost_point().row, 2); + buffer.edit(vec![10..12], "", None).unwrap(); + assert_eq!(buffer.rightmost_point().row, 0); + buffer.edit(vec![24..24], "tuv", None).unwrap(); + assert_eq!(buffer.rightmost_point().row, 4); + buffer + }); + }); } #[test] fn test_text_summary_for_range() { - let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz"); - let text = Text::from(buffer.text()); - - assert_eq!( - buffer.text_summary_for_range(1..3), - text.slice(1..3).summary() - ); - assert_eq!( - buffer.text_summary_for_range(1..12), - text.slice(1..12).summary() - ); - assert_eq!( - buffer.text_summary_for_range(0..20), - text.slice(0..20).summary() - ); - assert_eq!( - buffer.text_summary_for_range(0..22), - text.slice(0..22).summary() - ); - assert_eq!( - buffer.text_summary_for_range(7..22), - text.slice(7..22).summary() - ); + App::test((), |ctx| { + ctx.add_model(|ctx| { + let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz", ctx); + let text = Text::from(buffer.text()); + assert_eq!( + buffer.text_summary_for_range(1..3), + text.slice(1..3).summary() + ); + assert_eq!( + buffer.text_summary_for_range(1..12), + text.slice(1..12).summary() + ); + assert_eq!( + buffer.text_summary_for_range(0..20), + text.slice(0..20).summary() + ); + assert_eq!( + buffer.text_summary_for_range(0..22), + text.slice(0..22).summary() + ); + assert_eq!( + buffer.text_summary_for_range(7..22), + text.slice(7..22).summary() + ); + buffer + }); + }); } #[test] - fn test_chars_at() -> Result<()> { - let mut buffer = Buffer::new(0, ""); - buffer.edit(vec![0..0], "abcd\nefgh\nij", None)?; - buffer.edit(vec![12..12], "kl\nmno", None)?; - buffer.edit(vec![18..18], "\npqrs", None)?; - buffer.edit(vec![18..21], "\nPQ", None)?; + fn test_chars_at() { + App::test((), |ctx| { + ctx.add_model(|ctx| { + let mut buffer = Buffer::new(0, "", ctx); + buffer.edit(vec![0..0], "abcd\nefgh\nij", None).unwrap(); + buffer.edit(vec![12..12], "kl\nmno", None).unwrap(); + buffer.edit(vec![18..18], "\npqrs", None).unwrap(); + buffer.edit(vec![18..21], "\nPQ", None).unwrap(); - let chars = buffer.chars_at(Point::new(0, 0))?; - assert_eq!(chars.collect::(), "abcd\nefgh\nijkl\nmno\nPQrs"); + let chars = buffer.chars_at(Point::new(0, 0)).unwrap(); + assert_eq!(chars.collect::(), "abcd\nefgh\nijkl\nmno\nPQrs"); - let chars = buffer.chars_at(Point::new(1, 0))?; - assert_eq!(chars.collect::(), "efgh\nijkl\nmno\nPQrs"); + let chars = buffer.chars_at(Point::new(1, 0)).unwrap(); + assert_eq!(chars.collect::(), "efgh\nijkl\nmno\nPQrs"); - let chars = buffer.chars_at(Point::new(2, 0))?; - assert_eq!(chars.collect::(), "ijkl\nmno\nPQrs"); + let chars = buffer.chars_at(Point::new(2, 0)).unwrap(); + assert_eq!(chars.collect::(), "ijkl\nmno\nPQrs"); - let chars = buffer.chars_at(Point::new(3, 0))?; - assert_eq!(chars.collect::(), "mno\nPQrs"); + let chars = buffer.chars_at(Point::new(3, 0)).unwrap(); + assert_eq!(chars.collect::(), "mno\nPQrs"); - let chars = buffer.chars_at(Point::new(4, 0))?; - assert_eq!(chars.collect::(), "PQrs"); + let chars = buffer.chars_at(Point::new(4, 0)).unwrap(); + assert_eq!(chars.collect::(), "PQrs"); - // Regression test: - let mut buffer = Buffer::new(0, ""); - buffer.edit(vec![0..0], "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n", None)?; - buffer.edit(vec![60..60], "\n", None)?; + // Regression test: + let mut buffer = Buffer::new(0, "", ctx); + buffer.edit(vec![0..0], "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n", None).unwrap(); + buffer.edit(vec![60..60], "\n", None).unwrap(); - let chars = buffer.chars_at(Point::new(6, 0))?; - assert_eq!(chars.collect::(), " \"xray_wasm\",\n]\n"); + let chars = buffer.chars_at(Point::new(6, 0)).unwrap(); + assert_eq!(chars.collect::(), " \"xray_wasm\",\n]\n"); - Ok(()) + buffer + }); + }); } // #[test] @@ -2706,177 +2750,202 @@ mod tests { } #[test] - fn test_anchors() -> Result<()> { - let mut buffer = Buffer::new(0, ""); - buffer.edit(vec![0..0], "abc", None)?; - let left_anchor = buffer.anchor_before(2).unwrap(); - let right_anchor = buffer.anchor_after(2).unwrap(); - - buffer.edit(vec![1..1], "def\n", None)?; - assert_eq!(buffer.text(), "adef\nbc"); - assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 6); - assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 6); - assert_eq!( - left_anchor.to_point(&buffer).unwrap(), - Point { row: 1, column: 1 } - ); - assert_eq!( - right_anchor.to_point(&buffer).unwrap(), - Point { row: 1, column: 1 } - ); + fn test_anchors() { + App::test((), |ctx| { + ctx.add_model(|ctx| { + let mut buffer = Buffer::new(0, "", ctx); + buffer.edit(vec![0..0], "abc", None).unwrap(); + let left_anchor = buffer.anchor_before(2).unwrap(); + let right_anchor = buffer.anchor_after(2).unwrap(); + + buffer.edit(vec![1..1], "def\n", None).unwrap(); + assert_eq!(buffer.text(), "adef\nbc"); + assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 6); + assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 6); + assert_eq!( + left_anchor.to_point(&buffer).unwrap(), + Point { row: 1, column: 1 } + ); + assert_eq!( + right_anchor.to_point(&buffer).unwrap(), + Point { row: 1, column: 1 } + ); - buffer.edit(vec![2..3], "", None)?; - assert_eq!(buffer.text(), "adf\nbc"); - assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5); - assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 5); - assert_eq!( - left_anchor.to_point(&buffer).unwrap(), - Point { row: 1, column: 1 } - ); - assert_eq!( - right_anchor.to_point(&buffer).unwrap(), - Point { row: 1, column: 1 } - ); + buffer.edit(vec![2..3], "", None).unwrap(); + assert_eq!(buffer.text(), "adf\nbc"); + assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5); + assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 5); + assert_eq!( + left_anchor.to_point(&buffer).unwrap(), + Point { row: 1, column: 1 } + ); + assert_eq!( + right_anchor.to_point(&buffer).unwrap(), + Point { row: 1, column: 1 } + ); - buffer.edit(vec![5..5], "ghi\n", None)?; - assert_eq!(buffer.text(), "adf\nbghi\nc"); - assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5); - assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 9); - assert_eq!( - left_anchor.to_point(&buffer).unwrap(), - Point { row: 1, column: 1 } - ); - assert_eq!( - right_anchor.to_point(&buffer).unwrap(), - Point { row: 2, column: 0 } - ); + buffer.edit(vec![5..5], "ghi\n", None).unwrap(); + assert_eq!(buffer.text(), "adf\nbghi\nc"); + assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5); + assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 9); + assert_eq!( + left_anchor.to_point(&buffer).unwrap(), + Point { row: 1, column: 1 } + ); + assert_eq!( + right_anchor.to_point(&buffer).unwrap(), + Point { row: 2, column: 0 } + ); - buffer.edit(vec![7..9], "", None)?; - assert_eq!(buffer.text(), "adf\nbghc"); - assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5); - assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 7); - assert_eq!( - left_anchor.to_point(&buffer).unwrap(), - Point { row: 1, column: 1 }, - ); - assert_eq!( - right_anchor.to_point(&buffer).unwrap(), - Point { row: 1, column: 3 } - ); + buffer.edit(vec![7..9], "", None).unwrap(); + assert_eq!(buffer.text(), "adf\nbghc"); + assert_eq!(left_anchor.to_offset(&buffer).unwrap(), 5); + assert_eq!(right_anchor.to_offset(&buffer).unwrap(), 7); + assert_eq!( + left_anchor.to_point(&buffer).unwrap(), + Point { row: 1, column: 1 }, + ); + assert_eq!( + right_anchor.to_point(&buffer).unwrap(), + Point { row: 1, column: 3 } + ); - // Ensure anchoring to a point is equivalent to anchoring to an offset. - assert_eq!( - buffer.anchor_before(Point { row: 0, column: 0 })?, - buffer.anchor_before(0)? - ); - assert_eq!( - buffer.anchor_before(Point { row: 0, column: 1 })?, - buffer.anchor_before(1)? - ); - assert_eq!( - buffer.anchor_before(Point { row: 0, column: 2 })?, - buffer.anchor_before(2)? - ); - assert_eq!( - buffer.anchor_before(Point { row: 0, column: 3 })?, - buffer.anchor_before(3)? - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 0 })?, - buffer.anchor_before(4)? - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 1 })?, - buffer.anchor_before(5)? - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 2 })?, - buffer.anchor_before(6)? - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 3 })?, - buffer.anchor_before(7)? - ); - assert_eq!( - buffer.anchor_before(Point { row: 1, column: 4 })?, - buffer.anchor_before(8)? - ); + // Ensure anchoring to a point is equivalent to anchoring to an offset. + assert_eq!( + buffer.anchor_before(Point { row: 0, column: 0 }).unwrap(), + buffer.anchor_before(0).unwrap() + ); + assert_eq!( + buffer.anchor_before(Point { row: 0, column: 1 }).unwrap(), + buffer.anchor_before(1).unwrap() + ); + assert_eq!( + buffer.anchor_before(Point { row: 0, column: 2 }).unwrap(), + buffer.anchor_before(2).unwrap() + ); + assert_eq!( + buffer.anchor_before(Point { row: 0, column: 3 }).unwrap(), + buffer.anchor_before(3).unwrap() + ); + assert_eq!( + buffer.anchor_before(Point { row: 1, column: 0 }).unwrap(), + buffer.anchor_before(4).unwrap() + ); + assert_eq!( + buffer.anchor_before(Point { row: 1, column: 1 }).unwrap(), + buffer.anchor_before(5).unwrap() + ); + assert_eq!( + buffer.anchor_before(Point { row: 1, column: 2 }).unwrap(), + buffer.anchor_before(6).unwrap() + ); + assert_eq!( + buffer.anchor_before(Point { row: 1, column: 3 }).unwrap(), + buffer.anchor_before(7).unwrap() + ); + assert_eq!( + buffer.anchor_before(Point { row: 1, column: 4 }).unwrap(), + buffer.anchor_before(8).unwrap() + ); - // Comparison between anchors. - let anchor_at_offset_0 = buffer.anchor_before(0).unwrap(); - let anchor_at_offset_1 = buffer.anchor_before(1).unwrap(); - let anchor_at_offset_2 = buffer.anchor_before(2).unwrap(); + // Comparison between anchors. + let anchor_at_offset_0 = buffer.anchor_before(0).unwrap(); + let anchor_at_offset_1 = buffer.anchor_before(1).unwrap(); + let anchor_at_offset_2 = buffer.anchor_before(2).unwrap(); - assert_eq!( - anchor_at_offset_0.cmp(&anchor_at_offset_0, &buffer)?, - Ordering::Equal - ); - assert_eq!( - anchor_at_offset_1.cmp(&anchor_at_offset_1, &buffer)?, - Ordering::Equal - ); - assert_eq!( - anchor_at_offset_2.cmp(&anchor_at_offset_2, &buffer)?, - Ordering::Equal - ); + assert_eq!( + anchor_at_offset_0 + .cmp(&anchor_at_offset_0, &buffer) + .unwrap(), + Ordering::Equal + ); + assert_eq!( + anchor_at_offset_1 + .cmp(&anchor_at_offset_1, &buffer) + .unwrap(), + Ordering::Equal + ); + assert_eq!( + anchor_at_offset_2 + .cmp(&anchor_at_offset_2, &buffer) + .unwrap(), + Ordering::Equal + ); - assert_eq!( - anchor_at_offset_0.cmp(&anchor_at_offset_1, &buffer)?, - Ordering::Less - ); - assert_eq!( - anchor_at_offset_1.cmp(&anchor_at_offset_2, &buffer)?, - Ordering::Less - ); - assert_eq!( - anchor_at_offset_0.cmp(&anchor_at_offset_2, &buffer)?, - Ordering::Less - ); + assert_eq!( + anchor_at_offset_0 + .cmp(&anchor_at_offset_1, &buffer) + .unwrap(), + Ordering::Less + ); + assert_eq!( + anchor_at_offset_1 + .cmp(&anchor_at_offset_2, &buffer) + .unwrap(), + Ordering::Less + ); + assert_eq!( + anchor_at_offset_0 + .cmp(&anchor_at_offset_2, &buffer) + .unwrap(), + Ordering::Less + ); - assert_eq!( - anchor_at_offset_1.cmp(&anchor_at_offset_0, &buffer)?, - Ordering::Greater - ); - assert_eq!( - anchor_at_offset_2.cmp(&anchor_at_offset_1, &buffer)?, - Ordering::Greater - ); - assert_eq!( - anchor_at_offset_2.cmp(&anchor_at_offset_0, &buffer)?, - Ordering::Greater - ); - Ok(()) + assert_eq!( + anchor_at_offset_1 + .cmp(&anchor_at_offset_0, &buffer) + .unwrap(), + Ordering::Greater + ); + assert_eq!( + anchor_at_offset_2 + .cmp(&anchor_at_offset_1, &buffer) + .unwrap(), + Ordering::Greater + ); + assert_eq!( + anchor_at_offset_2 + .cmp(&anchor_at_offset_0, &buffer) + .unwrap(), + Ordering::Greater + ); + buffer + }); + }); } #[test] - fn test_anchors_at_start_and_end() -> Result<()> { - let mut buffer = Buffer::new(0, ""); - let before_start_anchor = buffer.anchor_before(0).unwrap(); - let after_end_anchor = buffer.anchor_after(0).unwrap(); - - buffer.edit(vec![0..0], "abc", None)?; - assert_eq!(buffer.text(), "abc"); - assert_eq!(before_start_anchor.to_offset(&buffer).unwrap(), 0); - assert_eq!(after_end_anchor.to_offset(&buffer).unwrap(), 3); - - let after_start_anchor = buffer.anchor_after(0).unwrap(); - let before_end_anchor = buffer.anchor_before(3).unwrap(); - - buffer.edit(vec![3..3], "def", None)?; - buffer.edit(vec![0..0], "ghi", None)?; - assert_eq!(buffer.text(), "ghiabcdef"); - assert_eq!(before_start_anchor.to_offset(&buffer).unwrap(), 0); - assert_eq!(after_start_anchor.to_offset(&buffer).unwrap(), 3); - assert_eq!(before_end_anchor.to_offset(&buffer).unwrap(), 6); - assert_eq!(after_end_anchor.to_offset(&buffer).unwrap(), 9); - - Ok(()) + fn test_anchors_at_start_and_end() { + App::test((), |ctx| { + ctx.add_model(|ctx| { + let mut buffer = Buffer::new(0, "", ctx); + let before_start_anchor = buffer.anchor_before(0).unwrap(); + let after_end_anchor = buffer.anchor_after(0).unwrap(); + + buffer.edit(vec![0..0], "abc", None).unwrap(); + assert_eq!(buffer.text(), "abc"); + assert_eq!(before_start_anchor.to_offset(&buffer).unwrap(), 0); + assert_eq!(after_end_anchor.to_offset(&buffer).unwrap(), 3); + + let after_start_anchor = buffer.anchor_after(0).unwrap(); + let before_end_anchor = buffer.anchor_before(3).unwrap(); + + buffer.edit(vec![3..3], "def", None).unwrap(); + buffer.edit(vec![0..0], "ghi", None).unwrap(); + assert_eq!(buffer.text(), "ghiabcdef"); + assert_eq!(before_start_anchor.to_offset(&buffer).unwrap(), 0); + assert_eq!(after_start_anchor.to_offset(&buffer).unwrap(), 3); + assert_eq!(before_end_anchor.to_offset(&buffer).unwrap(), 6); + assert_eq!(after_end_anchor.to_offset(&buffer).unwrap(), 9); + buffer + }); + }); } #[test] - fn test_is_modified() -> Result<()> { + fn test_is_modified() { App::test((), |app| { - let model = app.add_model(|_| Buffer::new(0, "abc")); + let model = app.add_model(|ctx| Buffer::new(0, "abc", ctx)); let events = Rc::new(RefCell::new(Vec::new())); // initially, the buffer isn't dirty. @@ -2958,94 +3027,113 @@ mod tests { ); }); }); - Ok(()) } #[test] - fn test_undo_redo() -> Result<()> { - let mut buffer = Buffer::new(0, "1234"); - - let edit1 = buffer.edit(vec![1..1], "abx", None)?; - let edit2 = buffer.edit(vec![3..4], "yzef", None)?; - let edit3 = buffer.edit(vec![3..5], "cd", None)?; - assert_eq!(buffer.text(), "1abcdef234"); - - buffer.undo_or_redo(edit1[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1cdef234"); - buffer.undo_or_redo(edit1[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1abcdef234"); - - buffer.undo_or_redo(edit2[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1abcdx234"); - buffer.undo_or_redo(edit3[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1abx234"); - buffer.undo_or_redo(edit2[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1abyzef234"); - buffer.undo_or_redo(edit3[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1abcdef234"); - - buffer.undo_or_redo(edit3[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1abyzef234"); - buffer.undo_or_redo(edit1[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1yzef234"); - buffer.undo_or_redo(edit2[0].edit_id().unwrap())?; - assert_eq!(buffer.text(), "1234"); - - Ok(()) + fn test_undo_redo() { + App::test((), |app| { + app.add_model(|ctx| { + let mut buffer = Buffer::new(0, "1234", ctx); + + let edit1 = buffer.edit(vec![1..1], "abx", None).unwrap(); + let edit2 = buffer.edit(vec![3..4], "yzef", None).unwrap(); + let edit3 = buffer.edit(vec![3..5], "cd", None).unwrap(); + assert_eq!(buffer.text(), "1abcdef234"); + + buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1cdef234"); + buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1abcdef234"); + + buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1abcdx234"); + buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1abx234"); + buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1abyzef234"); + buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1abcdef234"); + + buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1abyzef234"); + buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1yzef234"); + buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap(); + assert_eq!(buffer.text(), "1234"); + + buffer + }); + }); } #[test] - fn test_history() -> Result<()> { - let mut now = Instant::now(); - let mut buffer = Buffer::new(0, "123456"); - - let (set_id, _) = - buffer.add_selection_set(buffer.selections_from_ranges(vec![4..4])?, None); - buffer.start_transaction_at(Some(set_id), now)?; - buffer.edit(vec![2..4], "cd", None)?; - buffer.end_transaction_at(Some(set_id), now, None)?; - assert_eq!(buffer.text(), "12cd56"); - assert_eq!(buffer.selection_ranges(set_id)?, vec![4..4]); - - buffer.start_transaction_at(Some(set_id), now)?; - buffer.update_selection_set(set_id, buffer.selections_from_ranges(vec![1..3])?, None)?; - buffer.edit(vec![4..5], "e", None)?; - buffer.end_transaction_at(Some(set_id), now, None)?; - assert_eq!(buffer.text(), "12cde6"); - assert_eq!(buffer.selection_ranges(set_id)?, vec![1..3]); - - now += UNDO_GROUP_INTERVAL + Duration::from_millis(1); - buffer.start_transaction_at(Some(set_id), now)?; - buffer.update_selection_set(set_id, buffer.selections_from_ranges(vec![2..2])?, None)?; - buffer.edit(vec![0..1], "a", None)?; - buffer.edit(vec![1..1], "b", None)?; - buffer.end_transaction_at(Some(set_id), now, None)?; - assert_eq!(buffer.text(), "ab2cde6"); - assert_eq!(buffer.selection_ranges(set_id)?, vec![3..3]); - - // Last transaction happened past the group interval, undo it on its - // own. - buffer.undo(None); - assert_eq!(buffer.text(), "12cde6"); - assert_eq!(buffer.selection_ranges(set_id)?, vec![1..3]); - - // First two transactions happened within the group interval, undo them - // together. - buffer.undo(None); - assert_eq!(buffer.text(), "123456"); - assert_eq!(buffer.selection_ranges(set_id)?, vec![4..4]); - - // Redo the first two transactions together. - buffer.redo(None); - assert_eq!(buffer.text(), "12cde6"); - assert_eq!(buffer.selection_ranges(set_id)?, vec![1..3]); - - // Redo the last transaction on its own. - buffer.redo(None); - assert_eq!(buffer.text(), "ab2cde6"); - assert_eq!(buffer.selection_ranges(set_id)?, vec![3..3]); - - Ok(()) + fn test_history() { + App::test((), |app| { + app.add_model(|ctx| { + let mut now = Instant::now(); + let mut buffer = Buffer::new(0, "123456", ctx); + + let (set_id, _) = buffer + .add_selection_set(buffer.selections_from_ranges(vec![4..4]).unwrap(), None); + buffer.start_transaction_at(Some(set_id), now).unwrap(); + buffer.edit(vec![2..4], "cd", None).unwrap(); + buffer.end_transaction_at(Some(set_id), now, None).unwrap(); + assert_eq!(buffer.text(), "12cd56"); + assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]); + + buffer.start_transaction_at(Some(set_id), now).unwrap(); + buffer + .update_selection_set( + set_id, + buffer.selections_from_ranges(vec![1..3]).unwrap(), + None, + ) + .unwrap(); + buffer.edit(vec![4..5], "e", None).unwrap(); + buffer.end_transaction_at(Some(set_id), now, None).unwrap(); + assert_eq!(buffer.text(), "12cde6"); + assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]); + + now += UNDO_GROUP_INTERVAL + Duration::from_millis(1); + buffer.start_transaction_at(Some(set_id), now).unwrap(); + buffer + .update_selection_set( + set_id, + buffer.selections_from_ranges(vec![2..2]).unwrap(), + None, + ) + .unwrap(); + buffer.edit(vec![0..1], "a", None).unwrap(); + buffer.edit(vec![1..1], "b", None).unwrap(); + buffer.end_transaction_at(Some(set_id), now, None).unwrap(); + assert_eq!(buffer.text(), "ab2cde6"); + assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]); + + // Last transaction happened past the group interval, undo it on its + // own. + buffer.undo(None); + assert_eq!(buffer.text(), "12cde6"); + assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]); + + // First two transactions happened within the group interval, undo them + // together. + buffer.undo(None); + assert_eq!(buffer.text(), "123456"); + assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]); + + // Redo the first two transactions together. + buffer.redo(None); + assert_eq!(buffer.text(), "12cde6"); + assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]); + + // Redo the last transaction on its own. + buffer.redo(None); + assert_eq!(buffer.text(), "ab2cde6"); + assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]); + + buffer + }); + }); } #[test] @@ -3058,61 +3146,66 @@ mod tests { println!("{:?}", seed); let mut rng = &mut StdRng::seed_from_u64(seed); - let base_text_len = rng.gen_range(0..10); - let base_text = RandomCharIter::new(&mut rng) - .take(base_text_len) - .collect::(); - let mut replica_ids = Vec::new(); - let mut buffers = Vec::new(); - let mut network = Network::new(); - for i in 0..PEERS { - let buffer = Buffer::new(i as ReplicaId, base_text.as_str()); - buffers.push(buffer); - replica_ids.push(i as u16); - network.add_peer(i as u16); - } + App::test((), |ctx| { + let base_text_len = rng.gen_range(0..10); + let base_text = RandomCharIter::new(&mut rng) + .take(base_text_len) + .collect::(); + let mut replica_ids = Vec::new(); + let mut buffers = Vec::new(); + let mut network = Network::new(); + for i in 0..PEERS { + let buffer = + ctx.add_model(|ctx| Buffer::new(i as ReplicaId, base_text.as_str(), ctx)); + buffers.push(buffer); + replica_ids.push(i as u16); + network.add_peer(i as u16); + } - let mut mutation_count = 10; - loop { - let replica_index = rng.gen_range(0..PEERS); - let replica_id = replica_ids[replica_index]; - let buffer = &mut buffers[replica_index]; - - match rng.gen_range(0..=100) { - 0..=50 if mutation_count != 0 => { - let (_, _, ops) = buffer.randomly_mutate(&mut rng, None); - network.broadcast(replica_id, ops, &mut rng); - mutation_count -= 1; - } - 51..=70 if mutation_count != 0 => { - let ops = buffer.randomly_undo_redo(&mut rng); - network.broadcast(replica_id, ops, &mut rng); - mutation_count -= 1; - } - 71..=100 if network.has_unreceived(replica_id) => { - buffer - .apply_ops(network.receive(replica_id, &mut rng), None) - .unwrap(); + let mut mutation_count = 10; + loop { + let replica_index = rng.gen_range(0..PEERS); + let replica_id = replica_ids[replica_index]; + buffers[replica_index].update(ctx, |buffer, _| match rng.gen_range(0..=100) { + 0..=50 if mutation_count != 0 => { + let (_, _, ops) = buffer.randomly_mutate(&mut rng, None); + network.broadcast(replica_id, ops, &mut rng); + mutation_count -= 1; + } + 51..=70 if mutation_count != 0 => { + let ops = buffer.randomly_undo_redo(&mut rng); + network.broadcast(replica_id, ops, &mut rng); + mutation_count -= 1; + } + 71..=100 if network.has_unreceived(replica_id) => { + buffer + .apply_ops(network.receive(replica_id, &mut rng), None) + .unwrap(); + } + _ => {} + }); + + if mutation_count == 0 && network.is_idle() { + break; } - _ => {} } - if mutation_count == 0 && network.is_idle() { - break; + let first_buffer = buffers[0].read(ctx); + for buffer in &buffers[1..] { + let buffer = buffer.read(ctx); + assert_eq!(buffer.text(), first_buffer.text()); + assert_eq!( + buffer.all_selections().collect::>(), + first_buffer.all_selections().collect::>() + ); + assert_eq!( + buffer.all_selection_ranges().collect::>(), + first_buffer + .all_selection_ranges() + .collect::>() + ); } - } - - for buffer in &buffers[1..] { - assert_eq!(buffer.text(), buffers[0].text()); - assert_eq!( - buffer.all_selections().collect::>(), - buffers[0].all_selections().collect::>() - ); - assert_eq!( - buffer.all_selection_ranges().collect::>(), - buffers[0].all_selection_ranges().collect::>() - ); - } + }); } } diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index b3c2eb04967bb0cea97fb90f29259f2936c8d848..c13198f7a65a25238d80da6520f0e870decf7a4b 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -119,7 +119,7 @@ struct ClipboardSelection { impl BufferView { pub fn single_line(settings: watch::Receiver, ctx: &mut ViewContext) -> Self { - let buffer = ctx.add_model(|_| Buffer::new(0, String::new())); + let buffer = ctx.add_model(|ctx| Buffer::new(0, String::new(), ctx)); let mut view = Self::for_buffer(buffer, settings, ctx); view.single_line = true; view @@ -1316,6 +1316,7 @@ impl BufferView { buffer::Event::Edited(_) => ctx.emit(Event::Edited), buffer::Event::Dirtied => ctx.emit(Event::Dirtied), buffer::Event::Saved => ctx.emit(Event::Saved), + buffer::Event::FileHandleChanged => ctx.emit(Event::FileHandleChanged), } } } @@ -1326,6 +1327,7 @@ pub enum Event { Blurred, Dirtied, Saved, + FileHandleChanged, } impl Entity for BufferView { @@ -1372,7 +1374,10 @@ impl workspace::ItemView for BufferView { } fn should_update_tab_on_event(event: &Self::Event) -> bool { - matches!(event, Event::Saved | Event::Dirtied) + matches!( + event, + Event::Saved | Event::Dirtied | Event::FileHandleChanged + ) } fn title(&self, app: &AppContext) -> std::string::String { @@ -1419,7 +1424,8 @@ mod tests { #[test] fn test_selection_with_mouse() { App::test((), |app| { - let buffer = app.add_model(|_| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n")); + let buffer = + app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); let settings = settings::channel(&app.font_cache()).unwrap().1; let (_, buffer_view) = app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx)); @@ -1533,7 +1539,7 @@ mod tests { let layout_cache = TextLayoutCache::new(app.platform().fonts()); let font_cache = app.font_cache().clone(); - let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6))); + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); let settings = settings::channel(&font_cache).unwrap().1; let (_, view) = @@ -1550,7 +1556,7 @@ mod tests { #[test] fn test_fold() { App::test((), |app| { - let buffer = app.add_model(|_| { + let buffer = app.add_model(|ctx| { Buffer::new( 0, " @@ -1571,6 +1577,7 @@ mod tests { } " .unindent(), + ctx, ) }); let settings = settings::channel(&app.font_cache()).unwrap().1; @@ -1644,7 +1651,7 @@ mod tests { #[test] fn test_move_cursor() -> Result<()> { App::test((), |app| { - let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6))); + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); let settings = settings::channel(&app.font_cache()).unwrap().1; let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)); @@ -1681,8 +1688,12 @@ mod tests { #[test] fn test_backspace() { App::test((), |app| { - let buffer = app.add_model(|_| { - Buffer::new(0, "one two three\nfour five six\nseven eight nine\nten\n") + let buffer = app.add_model(|ctx| { + Buffer::new( + 0, + "one two three\nfour five six\nseven eight nine\nten\n", + ctx, + ) }); let settings = settings::channel(&app.font_cache()).unwrap().1; let (_, view) = @@ -1714,7 +1725,7 @@ mod tests { #[test] fn test_clipboard() { App::test((), |app| { - let buffer = app.add_model(|_| Buffer::new(0, "one two three four five six ")); + let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx)); let settings = settings::channel(&app.font_cache()).unwrap().1; let view = app .add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx)) diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 58f51cee94096d5c256ddce7804fef9e5be8d781..536971a87d13cffc33fc9e63a0d64ae3e2f02099 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -471,7 +471,7 @@ mod tests { #[test] fn test_basic_folds() { App::test((), |app| { - let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); map.fold( @@ -522,7 +522,7 @@ mod tests { #[test] fn test_overlapping_folds() { App::test((), |app| { - let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); map.fold( vec![ @@ -541,7 +541,7 @@ mod tests { #[test] fn test_merging_folds_via_edit() { App::test((), |app| { - let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); map.fold( @@ -589,10 +589,10 @@ mod tests { let mut rng = StdRng::seed_from_u64(seed); App::test((), |app| { - let buffer = app.add_model(|_| { + let buffer = app.add_model(|ctx| { let len = rng.gen_range(0..10); let text = RandomCharIter::new(&mut rng).take(len).collect::(); - Buffer::new(0, text) + Buffer::new(0, text, ctx) }); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); @@ -664,7 +664,7 @@ mod tests { fn test_buffer_rows() { App::test((), |app| { let text = sample_text(6, 6) + "\n"; - let buffer = app.add_model(|_| Buffer::new(0, text)); + let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); diff --git a/zed/src/editor/display_map/mod.rs b/zed/src/editor/display_map/mod.rs index 8142a8925cc9d4b92862276ff92d6048941f75b1..c44f3ca302396f95159b1540d8bf507b1cfcceb5 100644 --- a/zed/src/editor/display_map/mod.rs +++ b/zed/src/editor/display_map/mod.rs @@ -298,7 +298,7 @@ mod tests { fn test_chars_at() { App::test((), |app| { let text = sample_text(6, 6); - let buffer = app.add_model(|_| Buffer::new(0, text)); + let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx)); buffer .update(app, |buffer, ctx| { @@ -365,7 +365,7 @@ mod tests { #[test] fn test_max_point() { App::test((), |app| { - let buffer = app.add_model(|_| Buffer::new(0, "aaa\n\t\tbbb")); + let buffer = app.add_model(|ctx| Buffer::new(0, "aaa\n\t\tbbb", ctx)); let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx)); assert_eq!( map.read(app).max_point(app.as_ref()), diff --git a/zed/src/workspace/workspace.rs b/zed/src/workspace/workspace.rs index d98bd9c7981027b8fb0799752665a3df42766ee5..925781e34070324c21dd2dfe0e6aa5012f81f06f 100644 --- a/zed/src/workspace/workspace.rs +++ b/zed/src/workspace/workspace.rs @@ -1,6 +1,6 @@ use super::{ItemView, ItemViewHandle}; use crate::{ - editor::Buffer, + editor::{Buffer, History}, settings::Settings, time::ReplicaId, watch, @@ -174,15 +174,17 @@ impl Workspace { let replica_id = self.replica_id; let file = worktree.file(path.clone(), ctx.as_ref())?; let history = file.load_history(ctx.as_ref()); - let buffer = async move { Ok(Buffer::from_history(replica_id, file, history.await?)) }; + // let buffer = async move { Ok(Buffer::from_history(replica_id, file, history.await?)) }; let (mut tx, rx) = watch::channel(None); self.items.insert(item_key, OpenedItem::Loading(rx)); ctx.spawn( - buffer, - move |me, buffer: anyhow::Result, ctx| match buffer { - Ok(buffer) => { - let handle = Box::new(ctx.add_model(|_| buffer)) as Box; + history, + move |me, history: anyhow::Result, ctx| match history { + Ok(history) => { + let handle = Box::new( + ctx.add_model(|ctx| Buffer::from_history(replica_id, file, history, ctx)), + ) as Box; me.items .insert(item_key, OpenedItem::Loaded(handle.clone())); ctx.spawn( diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index b623c0e0e3e08ef13e8e173da604d498360ec3d7..fb7ea918f1a527c451c9524b6d55c9fd8a1e6448 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -59,7 +59,7 @@ pub struct FileHandle { state: Arc>, } -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] struct FileHandleState { path: Arc, is_deleted: bool, @@ -403,6 +403,32 @@ impl FileHandle { pub fn entry_id(&self) -> (usize, Arc) { (self.worktree.id(), self.path()) } + + pub fn observe_from_model( + &self, + ctx: &mut ModelContext, + mut callback: impl FnMut(&mut T, FileHandle, &mut ModelContext) + 'static, + ) { + let mut prev_state = self.state.lock().clone(); + let cur_state = Arc::downgrade(&self.state); + ctx.observe(&self.worktree, move |observer, worktree, ctx| { + if let Some(cur_state) = cur_state.upgrade() { + let cur_state_unlocked = cur_state.lock(); + if *cur_state_unlocked != prev_state { + prev_state = cur_state_unlocked.clone(); + drop(cur_state_unlocked); + callback( + observer, + FileHandle { + worktree, + state: cur_state, + }, + ctx, + ); + } + } + }); + } } #[derive(Clone, Debug)] @@ -818,7 +844,12 @@ impl BackgroundScanner { handles.retain(|handle_path, handle_state| { if let Ok(path_suffix) = handle_path.strip_prefix(&old_path) { let new_handle_path: Arc = - new_path.join(path_suffix).into(); + if path_suffix.file_name().is_some() { + new_path.join(path_suffix) + } else { + new_path.to_path_buf() + } + .into(); if let Some(handle_state) = Weak::upgrade(&handle_state) { handle_state.lock().path = new_handle_path.clone(); updated_handles @@ -1266,20 +1297,24 @@ mod tests { app.read(|ctx| tree.read(ctx).scan_complete()).await; app.read(|ctx| assert_eq!(tree.read(ctx).file_count(), 1)); - let buffer = Buffer::new(1, "a line of text.\n".repeat(10 * 1024)); + let buffer = + app.add_model(|ctx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), ctx)); let path = tree.update(&mut app, |tree, ctx| { let path = tree.files(0).next().unwrap().path().clone(); assert_eq!(path.file_name().unwrap(), "file1"); - smol::block_on(tree.save(&path, buffer.snapshot(), ctx.as_ref())).unwrap(); + smol::block_on(tree.save(&path, buffer.read(ctx).snapshot(), ctx.as_ref())) + .unwrap(); path }); - let loaded_history = app + let history = app .read(|ctx| tree.read(ctx).load_history(&path, ctx)) .await .unwrap(); - assert_eq!(loaded_history.base_text.as_ref(), buffer.text()); + app.read(|ctx| { + assert_eq!(history.base_text.as_ref(), buffer.read(ctx).text()); + }); }); } @@ -1335,7 +1370,8 @@ mod tests { "d/file4" ] ); - assert_eq!(file2.path().as_ref(), Path::new("a/file2.new")); + + assert_eq!(file2.path().to_str().unwrap(), "a/file2.new"); assert_eq!(file4.path().as_ref(), Path::new("d/file4")); assert_eq!(file5.path().as_ref(), Path::new("d/file5")); assert!(!file2.is_deleted());