sum_tree: Replace rayon with futures (#41586)
Release Notes: - N/A *or* Added/Fixed/Improved ... Co-authored by: Kate <kate@zed.dev>
This commit is contained in:
+184
-97
@@ -14,24 +14,29 @@ fn init_logger() {
|
||||
zlog::init_test();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edit() {
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "abc");
|
||||
#[gpui::test]
|
||||
fn test_edit(cx: &mut gpui::TestAppContext) {
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"abc",
|
||||
cx.background_executor(),
|
||||
);
|
||||
assert_eq!(buffer.text(), "abc");
|
||||
buffer.edit([(3..3, "def")]);
|
||||
buffer.edit([(3..3, "def")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "abcdef");
|
||||
buffer.edit([(0..0, "ghi")]);
|
||||
buffer.edit([(0..0, "ghi")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "ghiabcdef");
|
||||
buffer.edit([(5..5, "jkl")]);
|
||||
buffer.edit([(5..5, "jkl")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "ghiabjklcdef");
|
||||
buffer.edit([(6..7, "")]);
|
||||
buffer.edit([(6..7, "")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "ghiabjlcdef");
|
||||
buffer.edit([(4..9, "mno")]);
|
||||
buffer.edit([(4..9, "mno")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "ghiamnoef");
|
||||
}
|
||||
|
||||
#[gpui::test(iterations = 100)]
|
||||
fn test_random_edits(mut rng: StdRng) {
|
||||
fn test_random_edits(cx: &mut gpui::TestAppContext, mut rng: StdRng) {
|
||||
let operations = env::var("OPERATIONS")
|
||||
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
||||
.unwrap_or(10);
|
||||
@@ -44,6 +49,7 @@ fn test_random_edits(mut rng: StdRng) {
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
reference_string.clone(),
|
||||
cx.background_executor(),
|
||||
);
|
||||
LineEnding::normalize(&mut reference_string);
|
||||
|
||||
@@ -56,7 +62,7 @@ fn test_random_edits(mut rng: StdRng) {
|
||||
);
|
||||
|
||||
for _i in 0..operations {
|
||||
let (edits, _) = buffer.randomly_edit(&mut rng, 5);
|
||||
let (edits, _) = buffer.randomly_edit(&mut rng, 5, cx.background_executor());
|
||||
for (old_range, new_text) in edits.iter().rev() {
|
||||
reference_string.replace_range(old_range.clone(), new_text);
|
||||
}
|
||||
@@ -106,7 +112,11 @@ fn test_random_edits(mut rng: StdRng) {
|
||||
let mut text = old_buffer.visible_text.clone();
|
||||
for edit in edits {
|
||||
let new_text: String = buffer.text_for_range(edit.new.clone()).collect();
|
||||
text.replace(edit.new.start..edit.new.start + edit.old.len(), &new_text);
|
||||
text.replace(
|
||||
edit.new.start..edit.new.start + edit.old.len(),
|
||||
&new_text,
|
||||
cx.background_executor(),
|
||||
);
|
||||
}
|
||||
assert_eq!(text.to_string(), buffer.text());
|
||||
|
||||
@@ -161,14 +171,18 @@ fn test_random_edits(mut rng: StdRng) {
|
||||
let mut text = old_buffer.visible_text.clone();
|
||||
for edit in subscription_edits.into_inner() {
|
||||
let new_text: String = buffer.text_for_range(edit.new.clone()).collect();
|
||||
text.replace(edit.new.start..edit.new.start + edit.old.len(), &new_text);
|
||||
text.replace(
|
||||
edit.new.start..edit.new.start + edit.old.len(),
|
||||
&new_text,
|
||||
cx.background_executor(),
|
||||
);
|
||||
}
|
||||
assert_eq!(text.to_string(), buffer.text());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_line_endings() {
|
||||
#[gpui::test]
|
||||
fn test_line_endings(cx: &mut gpui::TestAppContext) {
|
||||
assert_eq!(LineEnding::detect(&"🍐✅\n".repeat(1000)), LineEnding::Unix);
|
||||
assert_eq!(LineEnding::detect(&"abcd\n".repeat(1000)), LineEnding::Unix);
|
||||
assert_eq!(
|
||||
@@ -184,25 +198,34 @@ fn test_line_endings() {
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"one\r\ntwo\rthree",
|
||||
cx.background_executor(),
|
||||
);
|
||||
assert_eq!(buffer.text(), "one\ntwo\nthree");
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Windows);
|
||||
buffer.check_invariants();
|
||||
|
||||
buffer.edit([(buffer.len()..buffer.len(), "\r\nfour")]);
|
||||
buffer.edit([(0..0, "zero\r\n")]);
|
||||
buffer.edit(
|
||||
[(buffer.len()..buffer.len(), "\r\nfour")],
|
||||
cx.background_executor(),
|
||||
);
|
||||
buffer.edit([(0..0, "zero\r\n")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "zero\none\ntwo\nthree\nfour");
|
||||
assert_eq!(buffer.line_ending(), LineEnding::Windows);
|
||||
buffer.check_invariants();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_line_len() {
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
buffer.edit([(0..0, "abcd\nefg\nhij")]);
|
||||
buffer.edit([(12..12, "kl\nmno")]);
|
||||
buffer.edit([(18..18, "\npqrs\n")]);
|
||||
buffer.edit([(18..21, "\nPQ")]);
|
||||
#[gpui::test]
|
||||
fn test_line_len(cx: &mut gpui::TestAppContext) {
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"",
|
||||
cx.background_executor(),
|
||||
);
|
||||
buffer.edit([(0..0, "abcd\nefg\nhij")], cx.background_executor());
|
||||
buffer.edit([(12..12, "kl\nmno")], cx.background_executor());
|
||||
buffer.edit([(18..18, "\npqrs\n")], cx.background_executor());
|
||||
buffer.edit([(18..21, "\nPQ")], cx.background_executor());
|
||||
|
||||
assert_eq!(buffer.line_len(0), 4);
|
||||
assert_eq!(buffer.line_len(1), 3);
|
||||
@@ -212,10 +235,15 @@ fn test_line_len() {
|
||||
assert_eq!(buffer.line_len(5), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_common_prefix_at_position() {
|
||||
#[gpui::test]
|
||||
fn test_common_prefix_at_position(cx: &mut gpui::TestAppContext) {
|
||||
let text = "a = str; b = δα";
|
||||
let buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), text);
|
||||
let buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
text,
|
||||
cx.background_executor(),
|
||||
);
|
||||
|
||||
let offset1 = offset_after(text, "str");
|
||||
let offset2 = offset_after(text, "δα");
|
||||
@@ -261,12 +289,13 @@ fn test_common_prefix_at_position() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_text_summary_for_range() {
|
||||
#[gpui::test]
|
||||
fn test_text_summary_for_range(cx: &mut gpui::TestAppContext) {
|
||||
let buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"ab\nefg\nhklm\nnopqrs\ntuvwxyz",
|
||||
cx.background_executor(),
|
||||
);
|
||||
assert_eq!(
|
||||
buffer.text_summary_for_range::<TextSummary, _>(0..2),
|
||||
@@ -354,13 +383,18 @@ fn test_text_summary_for_range() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chars_at() {
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
buffer.edit([(0..0, "abcd\nefgh\nij")]);
|
||||
buffer.edit([(12..12, "kl\nmno")]);
|
||||
buffer.edit([(18..18, "\npqrs")]);
|
||||
buffer.edit([(18..21, "\nPQ")]);
|
||||
#[gpui::test]
|
||||
fn test_chars_at(cx: &mut gpui::TestAppContext) {
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"",
|
||||
cx.background_executor(),
|
||||
);
|
||||
buffer.edit([(0..0, "abcd\nefgh\nij")], cx.background_executor());
|
||||
buffer.edit([(12..12, "kl\nmno")], cx.background_executor());
|
||||
buffer.edit([(18..18, "\npqrs")], cx.background_executor());
|
||||
buffer.edit([(18..21, "\nPQ")], cx.background_executor());
|
||||
|
||||
let chars = buffer.chars_at(Point::new(0, 0));
|
||||
assert_eq!(chars.collect::<String>(), "abcd\nefgh\nijkl\nmno\nPQrs");
|
||||
@@ -378,43 +412,53 @@ fn test_chars_at() {
|
||||
assert_eq!(chars.collect::<String>(), "PQrs");
|
||||
|
||||
// Regression test:
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
buffer.edit([(0..0, "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n")]);
|
||||
buffer.edit([(60..60, "\n")]);
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"",
|
||||
cx.background_executor(),
|
||||
);
|
||||
buffer.edit([(0..0, "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n")], cx.background_executor());
|
||||
buffer.edit([(60..60, "\n")], cx.background_executor());
|
||||
|
||||
let chars = buffer.chars_at(Point::new(6, 0));
|
||||
assert_eq!(chars.collect::<String>(), " \"xray_wasm\",\n]\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anchors() {
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
buffer.edit([(0..0, "abc")]);
|
||||
#[gpui::test]
|
||||
fn test_anchors(cx: &mut gpui::TestAppContext) {
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"",
|
||||
cx.background_executor(),
|
||||
);
|
||||
buffer.edit([(0..0, "abc")], cx.background_executor());
|
||||
let left_anchor = buffer.anchor_before(2);
|
||||
let right_anchor = buffer.anchor_after(2);
|
||||
|
||||
buffer.edit([(1..1, "def\n")]);
|
||||
buffer.edit([(1..1, "def\n")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "adef\nbc");
|
||||
assert_eq!(left_anchor.to_offset(&buffer), 6);
|
||||
assert_eq!(right_anchor.to_offset(&buffer), 6);
|
||||
assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
|
||||
assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 1 });
|
||||
|
||||
buffer.edit([(2..3, "")]);
|
||||
buffer.edit([(2..3, "")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "adf\nbc");
|
||||
assert_eq!(left_anchor.to_offset(&buffer), 5);
|
||||
assert_eq!(right_anchor.to_offset(&buffer), 5);
|
||||
assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
|
||||
assert_eq!(right_anchor.to_point(&buffer), Point { row: 1, column: 1 });
|
||||
|
||||
buffer.edit([(5..5, "ghi\n")]);
|
||||
buffer.edit([(5..5, "ghi\n")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "adf\nbghi\nc");
|
||||
assert_eq!(left_anchor.to_offset(&buffer), 5);
|
||||
assert_eq!(right_anchor.to_offset(&buffer), 9);
|
||||
assert_eq!(left_anchor.to_point(&buffer), Point { row: 1, column: 1 });
|
||||
assert_eq!(right_anchor.to_point(&buffer), Point { row: 2, column: 0 });
|
||||
|
||||
buffer.edit([(7..9, "")]);
|
||||
buffer.edit([(7..9, "")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "adf\nbghc");
|
||||
assert_eq!(left_anchor.to_offset(&buffer), 5);
|
||||
assert_eq!(right_anchor.to_offset(&buffer), 7);
|
||||
@@ -504,13 +548,18 @@ fn test_anchors() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anchors_at_start_and_end() {
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "");
|
||||
#[gpui::test]
|
||||
fn test_anchors_at_start_and_end(cx: &mut gpui::TestAppContext) {
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"",
|
||||
cx.background_executor(),
|
||||
);
|
||||
let before_start_anchor = buffer.anchor_before(0);
|
||||
let after_end_anchor = buffer.anchor_after(0);
|
||||
|
||||
buffer.edit([(0..0, "abc")]);
|
||||
buffer.edit([(0..0, "abc")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "abc");
|
||||
assert_eq!(before_start_anchor.to_offset(&buffer), 0);
|
||||
assert_eq!(after_end_anchor.to_offset(&buffer), 3);
|
||||
@@ -518,8 +567,8 @@ fn test_anchors_at_start_and_end() {
|
||||
let after_start_anchor = buffer.anchor_after(0);
|
||||
let before_end_anchor = buffer.anchor_before(3);
|
||||
|
||||
buffer.edit([(3..3, "def")]);
|
||||
buffer.edit([(0..0, "ghi")]);
|
||||
buffer.edit([(3..3, "def")], cx.background_executor());
|
||||
buffer.edit([(0..0, "ghi")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "ghiabcdef");
|
||||
assert_eq!(before_start_anchor.to_offset(&buffer), 0);
|
||||
assert_eq!(after_start_anchor.to_offset(&buffer), 3);
|
||||
@@ -527,15 +576,20 @@ fn test_anchors_at_start_and_end() {
|
||||
assert_eq!(after_end_anchor.to_offset(&buffer), 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_undo_redo() {
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "1234");
|
||||
#[gpui::test]
|
||||
fn test_undo_redo(cx: &mut gpui::TestAppContext) {
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"1234",
|
||||
cx.background_executor(),
|
||||
);
|
||||
// Set group interval to zero so as to not group edits in the undo stack.
|
||||
buffer.set_group_interval(Duration::from_secs(0));
|
||||
|
||||
buffer.edit([(1..1, "abx")]);
|
||||
buffer.edit([(3..4, "yzef")]);
|
||||
buffer.edit([(3..5, "cd")]);
|
||||
buffer.edit([(1..1, "abx")], cx.background_executor());
|
||||
buffer.edit([(3..4, "yzef")], cx.background_executor());
|
||||
buffer.edit([(3..5, "cd")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "1abcdef234");
|
||||
|
||||
let entries = buffer.history.undo_stack.clone();
|
||||
@@ -563,26 +617,31 @@ fn test_undo_redo() {
|
||||
assert_eq!(buffer.text(), "1234");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history() {
|
||||
#[gpui::test]
|
||||
fn test_history(cx: &mut gpui::TestAppContext) {
|
||||
let mut now = Instant::now();
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "123456");
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"123456",
|
||||
cx.background_executor(),
|
||||
);
|
||||
buffer.set_group_interval(Duration::from_millis(300));
|
||||
|
||||
let transaction_1 = buffer.start_transaction_at(now).unwrap();
|
||||
buffer.edit([(2..4, "cd")]);
|
||||
buffer.edit([(2..4, "cd")], cx.background_executor());
|
||||
buffer.end_transaction_at(now);
|
||||
assert_eq!(buffer.text(), "12cd56");
|
||||
|
||||
buffer.start_transaction_at(now);
|
||||
buffer.edit([(4..5, "e")]);
|
||||
buffer.edit([(4..5, "e")], cx.background_executor());
|
||||
buffer.end_transaction_at(now).unwrap();
|
||||
assert_eq!(buffer.text(), "12cde6");
|
||||
|
||||
now += buffer.transaction_group_interval() + Duration::from_millis(1);
|
||||
buffer.start_transaction_at(now);
|
||||
buffer.edit([(0..1, "a")]);
|
||||
buffer.edit([(1..1, "b")]);
|
||||
buffer.edit([(0..1, "a")], cx.background_executor());
|
||||
buffer.edit([(1..1, "b")], cx.background_executor());
|
||||
buffer.end_transaction_at(now).unwrap();
|
||||
assert_eq!(buffer.text(), "ab2cde6");
|
||||
|
||||
@@ -609,7 +668,7 @@ fn test_history() {
|
||||
|
||||
// Redo stack gets cleared after performing an edit.
|
||||
buffer.start_transaction_at(now);
|
||||
buffer.edit([(0..0, "X")]);
|
||||
buffer.edit([(0..0, "X")], cx.background_executor());
|
||||
buffer.end_transaction_at(now);
|
||||
assert_eq!(buffer.text(), "X12cde6");
|
||||
buffer.redo();
|
||||
@@ -630,26 +689,31 @@ fn test_history() {
|
||||
assert_eq!(buffer.text(), "X12cde6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_finalize_last_transaction() {
|
||||
#[gpui::test]
|
||||
fn test_finalize_last_transaction(cx: &mut gpui::TestAppContext) {
|
||||
let now = Instant::now();
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "123456");
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"123456",
|
||||
cx.background_executor(),
|
||||
);
|
||||
buffer.history.group_interval = Duration::from_millis(1);
|
||||
|
||||
buffer.start_transaction_at(now);
|
||||
buffer.edit([(2..4, "cd")]);
|
||||
buffer.edit([(2..4, "cd")], cx.background_executor());
|
||||
buffer.end_transaction_at(now);
|
||||
assert_eq!(buffer.text(), "12cd56");
|
||||
|
||||
buffer.finalize_last_transaction();
|
||||
buffer.start_transaction_at(now);
|
||||
buffer.edit([(4..5, "e")]);
|
||||
buffer.edit([(4..5, "e")], cx.background_executor());
|
||||
buffer.end_transaction_at(now).unwrap();
|
||||
assert_eq!(buffer.text(), "12cde6");
|
||||
|
||||
buffer.start_transaction_at(now);
|
||||
buffer.edit([(0..1, "a")]);
|
||||
buffer.edit([(1..1, "b")]);
|
||||
buffer.edit([(0..1, "a")], cx.background_executor());
|
||||
buffer.edit([(1..1, "b")], cx.background_executor());
|
||||
buffer.end_transaction_at(now).unwrap();
|
||||
assert_eq!(buffer.text(), "ab2cde6");
|
||||
|
||||
@@ -666,14 +730,19 @@ fn test_finalize_last_transaction() {
|
||||
assert_eq!(buffer.text(), "ab2cde6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edited_ranges_for_transaction() {
|
||||
#[gpui::test]
|
||||
fn test_edited_ranges_for_transaction(cx: &mut gpui::TestAppContext) {
|
||||
let now = Instant::now();
|
||||
let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), "1234567");
|
||||
let mut buffer = Buffer::new(
|
||||
ReplicaId::LOCAL,
|
||||
BufferId::new(1).unwrap(),
|
||||
"1234567",
|
||||
cx.background_executor(),
|
||||
);
|
||||
|
||||
buffer.start_transaction_at(now);
|
||||
buffer.edit([(2..4, "cd")]);
|
||||
buffer.edit([(6..6, "efg")]);
|
||||
buffer.edit([(2..4, "cd")], cx.background_executor());
|
||||
buffer.edit([(6..6, "efg")], cx.background_executor());
|
||||
buffer.end_transaction_at(now);
|
||||
assert_eq!(buffer.text(), "12cd56efg7");
|
||||
|
||||
@@ -685,7 +754,7 @@ fn test_edited_ranges_for_transaction() {
|
||||
[2..4, 6..9]
|
||||
);
|
||||
|
||||
buffer.edit([(5..5, "hijk")]);
|
||||
buffer.edit([(5..5, "hijk")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "12cd5hijk6efg7");
|
||||
assert_eq!(
|
||||
buffer
|
||||
@@ -694,7 +763,7 @@ fn test_edited_ranges_for_transaction() {
|
||||
[2..4, 10..13]
|
||||
);
|
||||
|
||||
buffer.edit([(4..4, "l")]);
|
||||
buffer.edit([(4..4, "l")], cx.background_executor());
|
||||
assert_eq!(buffer.text(), "12cdl5hijk6efg7");
|
||||
assert_eq!(
|
||||
buffer
|
||||
@@ -704,27 +773,42 @@ fn test_edited_ranges_for_transaction() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_concurrent_edits() {
|
||||
#[gpui::test]
|
||||
fn test_concurrent_edits(cx: &mut gpui::TestAppContext) {
|
||||
let text = "abcdef";
|
||||
|
||||
let mut buffer1 = Buffer::new(ReplicaId::new(1), BufferId::new(1).unwrap(), text);
|
||||
let mut buffer2 = Buffer::new(ReplicaId::new(2), BufferId::new(1).unwrap(), text);
|
||||
let mut buffer3 = Buffer::new(ReplicaId::new(3), BufferId::new(1).unwrap(), text);
|
||||
let mut buffer1 = Buffer::new(
|
||||
ReplicaId::new(1),
|
||||
BufferId::new(1).unwrap(),
|
||||
text,
|
||||
cx.background_executor(),
|
||||
);
|
||||
let mut buffer2 = Buffer::new(
|
||||
ReplicaId::new(2),
|
||||
BufferId::new(1).unwrap(),
|
||||
text,
|
||||
cx.background_executor(),
|
||||
);
|
||||
let mut buffer3 = Buffer::new(
|
||||
ReplicaId::new(3),
|
||||
BufferId::new(1).unwrap(),
|
||||
text,
|
||||
cx.background_executor(),
|
||||
);
|
||||
|
||||
let buf1_op = buffer1.edit([(1..2, "12")]);
|
||||
let buf1_op = buffer1.edit([(1..2, "12")], cx.background_executor());
|
||||
assert_eq!(buffer1.text(), "a12cdef");
|
||||
let buf2_op = buffer2.edit([(3..4, "34")]);
|
||||
let buf2_op = buffer2.edit([(3..4, "34")], cx.background_executor());
|
||||
assert_eq!(buffer2.text(), "abc34ef");
|
||||
let buf3_op = buffer3.edit([(5..6, "56")]);
|
||||
let buf3_op = buffer3.edit([(5..6, "56")], cx.background_executor());
|
||||
assert_eq!(buffer3.text(), "abcde56");
|
||||
|
||||
buffer1.apply_op(buf2_op.clone());
|
||||
buffer1.apply_op(buf3_op.clone());
|
||||
buffer2.apply_op(buf1_op.clone());
|
||||
buffer2.apply_op(buf3_op);
|
||||
buffer3.apply_op(buf1_op);
|
||||
buffer3.apply_op(buf2_op);
|
||||
buffer1.apply_op(buf2_op.clone(), Some(cx.background_executor()));
|
||||
buffer1.apply_op(buf3_op.clone(), Some(cx.background_executor()));
|
||||
buffer2.apply_op(buf1_op.clone(), Some(cx.background_executor()));
|
||||
buffer2.apply_op(buf3_op, Some(cx.background_executor()));
|
||||
buffer3.apply_op(buf1_op, Some(cx.background_executor()));
|
||||
buffer3.apply_op(buf2_op, Some(cx.background_executor()));
|
||||
|
||||
assert_eq!(buffer1.text(), "a12c34e56");
|
||||
assert_eq!(buffer2.text(), "a12c34e56");
|
||||
@@ -732,7 +816,7 @@ fn test_concurrent_edits() {
|
||||
}
|
||||
|
||||
#[gpui::test(iterations = 100)]
|
||||
fn test_random_concurrent_edits(mut rng: StdRng) {
|
||||
fn test_random_concurrent_edits(mut rng: StdRng, cx: &mut gpui::TestAppContext) {
|
||||
let peers = env::var("PEERS")
|
||||
.map(|i| i.parse().expect("invalid `PEERS` variable"))
|
||||
.unwrap_or(5);
|
||||
@@ -753,6 +837,7 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
|
||||
ReplicaId::new(i as u16),
|
||||
BufferId::new(1).unwrap(),
|
||||
base_text.clone(),
|
||||
cx.background_executor(),
|
||||
);
|
||||
buffer.history.group_interval = Duration::from_millis(rng.random_range(0..=200));
|
||||
buffers.push(buffer);
|
||||
@@ -769,7 +854,9 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
|
||||
let buffer = &mut buffers[replica_index];
|
||||
match rng.random_range(0..=100) {
|
||||
0..=50 if mutation_count != 0 => {
|
||||
let op = buffer.randomly_edit(&mut rng, 5).1;
|
||||
let op = buffer
|
||||
.randomly_edit(&mut rng, 5, cx.background_executor())
|
||||
.1;
|
||||
network.broadcast(buffer.replica_id, vec![op]);
|
||||
log::info!("buffer {:?} text: {:?}", buffer.replica_id, buffer.text());
|
||||
mutation_count -= 1;
|
||||
@@ -787,7 +874,7 @@ fn test_random_concurrent_edits(mut rng: StdRng) {
|
||||
replica_id,
|
||||
ops.len()
|
||||
);
|
||||
buffer.apply_ops(ops);
|
||||
buffer.apply_ops(ops, Some(cx.background_executor()));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
+63
-17
@@ -15,6 +15,7 @@ use anyhow::{Context as _, Result};
|
||||
use clock::Lamport;
|
||||
pub use clock::ReplicaId;
|
||||
use collections::{HashMap, HashSet};
|
||||
use gpui::BackgroundExecutor;
|
||||
use locator::Locator;
|
||||
use operation_queue::OperationQueue;
|
||||
pub use patch::Patch;
|
||||
@@ -709,11 +710,41 @@ impl FromIterator<char> for LineIndent {
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new(replica_id: ReplicaId, remote_id: BufferId, base_text: impl Into<String>) -> Buffer {
|
||||
/// Create a new buffer from a string.
|
||||
pub fn new(
|
||||
replica_id: ReplicaId,
|
||||
remote_id: BufferId,
|
||||
base_text: impl Into<String>,
|
||||
executor: &BackgroundExecutor,
|
||||
) -> Buffer {
|
||||
let mut base_text = base_text.into();
|
||||
let line_ending = LineEnding::detect(&base_text);
|
||||
LineEnding::normalize(&mut base_text);
|
||||
Self::new_normalized(replica_id, remote_id, line_ending, Rope::from(&*base_text))
|
||||
Self::new_normalized(
|
||||
replica_id,
|
||||
remote_id,
|
||||
line_ending,
|
||||
Rope::from_str(&base_text, executor),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new buffer from a string.
|
||||
///
|
||||
/// Unlike [`Buffer::new`], this does not construct the backing rope in parallel if it is large enough.
|
||||
pub fn new_slow(
|
||||
replica_id: ReplicaId,
|
||||
remote_id: BufferId,
|
||||
base_text: impl Into<String>,
|
||||
) -> Buffer {
|
||||
let mut base_text = base_text.into();
|
||||
let line_ending = LineEnding::detect(&base_text);
|
||||
LineEnding::normalize(&mut base_text);
|
||||
Self::new_normalized(
|
||||
replica_id,
|
||||
remote_id,
|
||||
line_ending,
|
||||
Rope::from_str_small(&base_text),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_normalized(
|
||||
@@ -808,7 +839,7 @@ impl Buffer {
|
||||
self.history.group_interval
|
||||
}
|
||||
|
||||
pub fn edit<R, I, S, T>(&mut self, edits: R) -> Operation
|
||||
pub fn edit<R, I, S, T>(&mut self, edits: R, cx: &BackgroundExecutor) -> Operation
|
||||
where
|
||||
R: IntoIterator<IntoIter = I>,
|
||||
I: ExactSizeIterator<Item = (Range<S>, T)>,
|
||||
@@ -821,7 +852,7 @@ impl Buffer {
|
||||
|
||||
self.start_transaction();
|
||||
let timestamp = self.lamport_clock.tick();
|
||||
let operation = Operation::Edit(self.apply_local_edit(edits, timestamp));
|
||||
let operation = Operation::Edit(self.apply_local_edit(edits, timestamp, cx));
|
||||
|
||||
self.history.push(operation.clone());
|
||||
self.history.push_undo(operation.timestamp());
|
||||
@@ -834,6 +865,7 @@ impl Buffer {
|
||||
&mut self,
|
||||
edits: impl ExactSizeIterator<Item = (Range<S>, T)>,
|
||||
timestamp: clock::Lamport,
|
||||
executor: &BackgroundExecutor,
|
||||
) -> EditOperation {
|
||||
let mut edits_patch = Patch::default();
|
||||
let mut edit_op = EditOperation {
|
||||
@@ -922,7 +954,7 @@ impl Buffer {
|
||||
});
|
||||
insertion_slices.push(InsertionSlice::from_fragment(timestamp, &fragment));
|
||||
new_insertions.push(InsertionFragment::insert_new(&fragment));
|
||||
new_ropes.push_str(new_text.as_ref());
|
||||
new_ropes.push_str(new_text.as_ref(), executor);
|
||||
new_fragments.push(fragment, &None);
|
||||
insertion_offset += new_text.len();
|
||||
}
|
||||
@@ -1001,22 +1033,26 @@ impl Buffer {
|
||||
self.snapshot.line_ending = line_ending;
|
||||
}
|
||||
|
||||
pub fn apply_ops<I: IntoIterator<Item = Operation>>(&mut self, ops: I) {
|
||||
pub fn apply_ops<I: IntoIterator<Item = Operation>>(
|
||||
&mut self,
|
||||
ops: I,
|
||||
executor: Option<&BackgroundExecutor>,
|
||||
) {
|
||||
let mut deferred_ops = Vec::new();
|
||||
for op in ops {
|
||||
self.history.push(op.clone());
|
||||
if self.can_apply_op(&op) {
|
||||
self.apply_op(op);
|
||||
self.apply_op(op, executor);
|
||||
} else {
|
||||
self.deferred_replicas.insert(op.replica_id());
|
||||
deferred_ops.push(op);
|
||||
}
|
||||
}
|
||||
self.deferred_ops.insert(deferred_ops);
|
||||
self.flush_deferred_ops();
|
||||
self.flush_deferred_ops(executor);
|
||||
}
|
||||
|
||||
fn apply_op(&mut self, op: Operation) {
|
||||
fn apply_op(&mut self, op: Operation, executor: Option<&BackgroundExecutor>) {
|
||||
match op {
|
||||
Operation::Edit(edit) => {
|
||||
if !self.version.observed(edit.timestamp) {
|
||||
@@ -1025,6 +1061,7 @@ impl Buffer {
|
||||
&edit.ranges,
|
||||
&edit.new_text,
|
||||
edit.timestamp,
|
||||
executor,
|
||||
);
|
||||
self.snapshot.version.observe(edit.timestamp);
|
||||
self.lamport_clock.observe(edit.timestamp);
|
||||
@@ -1055,6 +1092,7 @@ impl Buffer {
|
||||
ranges: &[Range<FullOffset>],
|
||||
new_text: &[Arc<str>],
|
||||
timestamp: clock::Lamport,
|
||||
executor: Option<&BackgroundExecutor>,
|
||||
) {
|
||||
if ranges.is_empty() {
|
||||
return;
|
||||
@@ -1170,7 +1208,10 @@ impl Buffer {
|
||||
});
|
||||
insertion_slices.push(InsertionSlice::from_fragment(timestamp, &fragment));
|
||||
new_insertions.push(InsertionFragment::insert_new(&fragment));
|
||||
new_ropes.push_str(new_text);
|
||||
match executor {
|
||||
Some(executor) => new_ropes.push_str(new_text, executor),
|
||||
None => new_ropes.push_str_small(new_text),
|
||||
}
|
||||
new_fragments.push(fragment, &None);
|
||||
insertion_offset += new_text.len();
|
||||
}
|
||||
@@ -1348,12 +1389,12 @@ impl Buffer {
|
||||
self.subscriptions.publish_mut(&edits);
|
||||
}
|
||||
|
||||
fn flush_deferred_ops(&mut self) {
|
||||
fn flush_deferred_ops(&mut self, executor: Option<&BackgroundExecutor>) {
|
||||
self.deferred_replicas.clear();
|
||||
let mut deferred_ops = Vec::new();
|
||||
for op in self.deferred_ops.drain().iter().cloned() {
|
||||
if self.can_apply_op(&op) {
|
||||
self.apply_op(op);
|
||||
self.apply_op(op, executor);
|
||||
} else {
|
||||
self.deferred_replicas.insert(op.replica_id());
|
||||
deferred_ops.push(op);
|
||||
@@ -1711,9 +1752,9 @@ impl Buffer {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl Buffer {
|
||||
#[track_caller]
|
||||
pub fn edit_via_marked_text(&mut self, marked_string: &str) {
|
||||
pub fn edit_via_marked_text(&mut self, marked_string: &str, cx: &BackgroundExecutor) {
|
||||
let edits = self.edits_for_marked_text(marked_string);
|
||||
self.edit(edits);
|
||||
self.edit(edits, cx);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
@@ -1850,6 +1891,7 @@ impl Buffer {
|
||||
&mut self,
|
||||
rng: &mut T,
|
||||
edit_count: usize,
|
||||
executor: &BackgroundExecutor,
|
||||
) -> (Vec<(Range<usize>, Arc<str>)>, Operation)
|
||||
where
|
||||
T: rand::Rng,
|
||||
@@ -1857,7 +1899,7 @@ impl Buffer {
|
||||
let mut edits = self.get_random_edits(rng, edit_count);
|
||||
log::info!("mutating buffer {:?} with {:?}", self.replica_id, edits);
|
||||
|
||||
let op = self.edit(edits.iter().cloned());
|
||||
let op = self.edit(edits.iter().cloned(), executor);
|
||||
if let Operation::Edit(edit) = &op {
|
||||
assert_eq!(edits.len(), edit.new_text.len());
|
||||
for (edit, new_text) in edits.iter_mut().zip(&edit.new_text) {
|
||||
@@ -2692,8 +2734,12 @@ impl<'a> RopeBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn push_str(&mut self, text: &str) {
|
||||
self.new_visible.push(text);
|
||||
fn push_str(&mut self, text: &str, cx: &BackgroundExecutor) {
|
||||
self.new_visible.push(text, cx);
|
||||
}
|
||||
|
||||
fn push_str_small(&mut self, text: &str) {
|
||||
self.new_visible.push_small(text);
|
||||
}
|
||||
|
||||
fn finish(mut self) -> (Rope, Rope) {
|
||||
|
||||
Reference in New Issue
Block a user