Get simple unit test passing for soft-wrap in DisplayMap
This commit is contained in:
+16
-3
@@ -9,6 +9,7 @@ use std::{
|
||||
fmt::{self, Debug},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::RangeInclusive,
|
||||
pin::Pin,
|
||||
rc::Rc,
|
||||
sync::{
|
||||
@@ -46,6 +47,7 @@ struct DeterministicState {
|
||||
scheduled: Vec<(Runnable, Backtrace)>,
|
||||
spawned_from_foreground: Vec<(Runnable, Backtrace)>,
|
||||
forbid_parking: bool,
|
||||
block_on_ticks: RangeInclusive<usize>,
|
||||
}
|
||||
|
||||
pub struct Deterministic {
|
||||
@@ -62,6 +64,7 @@ impl Deterministic {
|
||||
scheduled: Default::default(),
|
||||
spawned_from_foreground: Default::default(),
|
||||
forbid_parking: false,
|
||||
block_on_ticks: 0..=1000,
|
||||
})),
|
||||
parker: Default::default(),
|
||||
}
|
||||
@@ -330,13 +333,19 @@ impl Foreground {
|
||||
|
||||
pub fn forbid_parking(&self) {
|
||||
match self {
|
||||
Self::Platform { .. } => panic!("can't call this method on a platform executor"),
|
||||
Self::Test(_) => panic!("can't call this method on a test executor"),
|
||||
Self::Deterministic(executor) => {
|
||||
let mut state = executor.state.lock();
|
||||
state.forbid_parking = true;
|
||||
state.rng = StdRng::seed_from_u64(state.seed);
|
||||
}
|
||||
_ => panic!("this method can only be called on a deterministic executor"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_block_on_ticks(&self, range: RangeInclusive<usize>) {
|
||||
match self {
|
||||
Self::Deterministic(executor) => executor.state.lock().block_on_ticks = range,
|
||||
_ => panic!("this method can only be called on a deterministic executor"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -386,7 +395,11 @@ impl Background {
|
||||
smol::block_on(async move { util::timeout(timeout, future).await.ok() })
|
||||
}
|
||||
Self::Deterministic(executor) => {
|
||||
let max_ticks = executor.state.lock().rng.gen_range(1..=1000);
|
||||
let max_ticks = {
|
||||
let mut state = executor.state.lock();
|
||||
let range = state.block_on_ticks.clone();
|
||||
state.rng.gen_range(range)
|
||||
};
|
||||
executor.block_on(max_ticks, future)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,12 @@ impl DisplayMap {
|
||||
pub fn snapshot(&self, cx: &AppContext) -> DisplayMapSnapshot {
|
||||
let (folds_snapshot, edits) = self.fold_map.read(cx);
|
||||
let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits);
|
||||
let wraps_snapshot = self.wrap_map.sync(tabs_snapshot.clone(), edits, cx);
|
||||
DisplayMapSnapshot {
|
||||
buffer_snapshot: self.buffer.read(cx).snapshot(),
|
||||
folds_snapshot,
|
||||
tabs_snapshot,
|
||||
wraps_snapshot,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +53,11 @@ impl DisplayMap {
|
||||
cx: &AppContext,
|
||||
) {
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(cx);
|
||||
let edits = fold_map.fold(ranges, cx);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
||||
self.wrap_map.sync(snapshot, edits, cx);
|
||||
let (snapshot, edits) = fold_map.fold(ranges, cx);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
||||
self.wrap_map.sync(snapshot, edits, cx);
|
||||
}
|
||||
|
||||
pub fn unfold<T: ToOffset>(
|
||||
@@ -60,7 +66,11 @@ impl DisplayMap {
|
||||
cx: &AppContext,
|
||||
) {
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(cx);
|
||||
let edits = fold_map.unfold(ranges, cx);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
||||
self.wrap_map.sync(snapshot, edits, cx);
|
||||
let (snapshot, edits) = fold_map.unfold(ranges, cx);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
||||
self.wrap_map.sync(snapshot, edits, cx);
|
||||
}
|
||||
|
||||
pub fn set_wrap_width(&self, width: Option<f32>) {
|
||||
@@ -72,6 +82,7 @@ pub struct DisplayMapSnapshot {
|
||||
buffer_snapshot: buffer::Snapshot,
|
||||
folds_snapshot: fold_map::Snapshot,
|
||||
tabs_snapshot: tab_map::Snapshot,
|
||||
wraps_snapshot: wrap_map::Snapshot,
|
||||
}
|
||||
|
||||
impl DisplayMapSnapshot {
|
||||
@@ -80,11 +91,11 @@ impl DisplayMapSnapshot {
|
||||
}
|
||||
|
||||
pub fn max_point(&self) -> DisplayPoint {
|
||||
DisplayPoint(self.tabs_snapshot.max_point())
|
||||
DisplayPoint(self.wraps_snapshot.max_point())
|
||||
}
|
||||
|
||||
pub fn chunks_at(&self, point: DisplayPoint) -> tab_map::Chunks {
|
||||
self.tabs_snapshot.chunks_at(point.0)
|
||||
pub fn chunks_at(&self, point: DisplayPoint) -> wrap_map::Chunks {
|
||||
self.wraps_snapshot.chunks_at(point.0)
|
||||
}
|
||||
|
||||
pub fn highlighted_chunks_for_rows(&mut self, rows: Range<u32>) -> tab_map::HighlightedChunks {
|
||||
@@ -122,7 +133,7 @@ impl DisplayMapSnapshot {
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, point: DisplayPoint, bias: Bias) -> DisplayPoint {
|
||||
DisplayPoint(self.tabs_snapshot.clip_point(point.0, bias))
|
||||
DisplayPoint(self.wraps_snapshot.clip_point(point.0, bias))
|
||||
}
|
||||
|
||||
pub fn folds_in_range<'a, T>(
|
||||
@@ -194,11 +205,11 @@ impl DisplayMapSnapshot {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
pub struct DisplayPoint(tab_map::OutputPoint);
|
||||
pub struct DisplayPoint(wrap_map::OutputPoint);
|
||||
|
||||
impl DisplayPoint {
|
||||
pub fn new(row: u32, column: u32) -> Self {
|
||||
Self(tab_map::OutputPoint::new(row, column))
|
||||
Self(wrap_map::OutputPoint::new(row, column))
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
@@ -222,22 +233,24 @@ impl DisplayPoint {
|
||||
}
|
||||
|
||||
pub fn to_buffer_point(self, map: &DisplayMapSnapshot, bias: Bias) -> Point {
|
||||
map.folds_snapshot
|
||||
.to_input_point(map.tabs_snapshot.to_input_point(self.0, bias).0)
|
||||
let unwrapped_point = map.wraps_snapshot.to_input_point(self.0);
|
||||
let unexpanded_point = map.tabs_snapshot.to_input_point(unwrapped_point, bias).0;
|
||||
map.folds_snapshot.to_input_point(unexpanded_point)
|
||||
}
|
||||
|
||||
pub fn to_buffer_offset(self, map: &DisplayMapSnapshot, bias: Bias) -> usize {
|
||||
map.folds_snapshot
|
||||
.to_input_offset(map.tabs_snapshot.to_input_point(self.0, bias).0)
|
||||
let unwrapped_point = map.wraps_snapshot.to_input_point(self.0);
|
||||
let unexpanded_point = map.tabs_snapshot.to_input_point(unwrapped_point, bias).0;
|
||||
map.folds_snapshot.to_input_offset(unexpanded_point)
|
||||
}
|
||||
}
|
||||
|
||||
impl Point {
|
||||
pub fn to_display_point(self, map: &DisplayMapSnapshot) -> DisplayPoint {
|
||||
DisplayPoint(
|
||||
map.tabs_snapshot
|
||||
.to_output_point(map.folds_snapshot.to_output_point(self)),
|
||||
)
|
||||
let folded_point = map.folds_snapshot.to_output_point(self);
|
||||
let expanded_point = map.tabs_snapshot.to_output_point(folded_point);
|
||||
let wrapped_point = map.wraps_snapshot.to_output_point(expanded_point);
|
||||
DisplayPoint(wrapped_point)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,6 +271,48 @@ mod tests {
|
||||
use buffer::History;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_soft_wraps(mut cx: gpui::TestAppContext) {
|
||||
cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
|
||||
|
||||
let font_cache = cx.font_cache();
|
||||
|
||||
let settings = Settings {
|
||||
buffer_font_family: font_cache.load_family(&["Helvetica"]).unwrap(),
|
||||
ui_font_family: font_cache.load_family(&["Helvetica"]).unwrap(),
|
||||
buffer_font_size: 12.0,
|
||||
ui_font_size: 12.0,
|
||||
tab_size: 4,
|
||||
theme: Arc::new(Theme::default()),
|
||||
};
|
||||
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 map = cx.read(|cx| DisplayMap::new(buffer.clone(), settings, wrap_width, cx));
|
||||
|
||||
let snapshot = cx.read(|cx| map.snapshot(cx));
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.chunks_at(DisplayPoint::new(0, 3))
|
||||
.collect::<String>(),
|
||||
" two \nthree four \nfive\nsix seven \neight"
|
||||
);
|
||||
|
||||
buffer.update(&mut cx, |buffer, cx| {
|
||||
let ix = buffer.text().find("seven").unwrap();
|
||||
buffer.edit(vec![ix..ix], "and ", cx);
|
||||
});
|
||||
|
||||
let snapshot = cx.read(|cx| map.snapshot(cx));
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.chunks_at(DisplayPoint::new(1, 0))
|
||||
.collect::<String>(),
|
||||
"three four \nfive\nsix and \nseven eight"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_chunks_at(cx: &mut gpui::MutableAppContext) {
|
||||
let text = sample_text(6, 6);
|
||||
|
||||
@@ -14,7 +14,7 @@ use parking_lot::Mutex;
|
||||
use std::{
|
||||
cmp::{self, Ordering},
|
||||
iter,
|
||||
ops::{Range, Sub},
|
||||
ops::Range,
|
||||
sync::atomic::{AtomicUsize, Ordering::SeqCst},
|
||||
};
|
||||
|
||||
@@ -47,14 +47,6 @@ impl OutputPoint {
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Self> for OutputPoint {
|
||||
type Output = OutputPoint;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Self(self.0 - other.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FoldMapWriter<'a>(&'a mut FoldMap);
|
||||
|
||||
impl<'a> FoldMapWriter<'a> {
|
||||
@@ -906,8 +898,8 @@ impl<'a> Iterator for InputRows<'a> {
|
||||
}
|
||||
|
||||
if self.cursor.item().is_some() {
|
||||
let overshoot = self.output_point - *self.cursor.seek_start();
|
||||
let input_point = *self.cursor.sum_start() + overshoot.0;
|
||||
let overshoot = self.output_point.0 - self.cursor.seek_start().0;
|
||||
let input_point = *self.cursor.sum_start() + overshoot;
|
||||
*self.output_point.row_mut() += 1;
|
||||
Some(input_point.row)
|
||||
} else {
|
||||
|
||||
@@ -5,10 +5,7 @@ use super::fold_map::{
|
||||
OutputOffset as InputOffset, OutputPoint as InputPoint, Snapshot as InputSnapshot,
|
||||
};
|
||||
use crate::{editor::rope, settings::StyleId, util::Bias};
|
||||
use std::{
|
||||
mem,
|
||||
ops::{Add, AddAssign, Range},
|
||||
};
|
||||
use std::{mem, ops::Range};
|
||||
|
||||
pub struct TabMap(Mutex<Snapshot>);
|
||||
|
||||
@@ -268,20 +265,6 @@ impl From<super::Point> for OutputPoint {
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Self> for OutputPoint {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 += &rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Self> for OutputPoint {
|
||||
type Output = OutputPoint;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
Self(self.0 + other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Edit {
|
||||
pub old_lines: Range<OutputPoint>,
|
||||
|
||||
@@ -14,12 +14,7 @@ use postage::{
|
||||
watch,
|
||||
};
|
||||
use smol::channel;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
ops::{AddAssign, Range, Sub},
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
};
|
||||
use std::{collections::VecDeque, ops::Range, sync::Arc, time::Duration};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
pub struct OutputPoint(super::Point);
|
||||
@@ -50,20 +45,6 @@ impl OutputPoint {
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Self> for OutputPoint {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 += &rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Self> for OutputPoint {
|
||||
type Output = OutputPoint;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
Self(self.0 - other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Snapshot {
|
||||
transforms: SumTree<Transform>,
|
||||
@@ -145,10 +126,10 @@ impl Snapshot {
|
||||
}
|
||||
|
||||
pub fn chunks_at(&self, point: OutputPoint) -> Chunks {
|
||||
let mut transforms = self.transforms.cursor();
|
||||
let mut transforms = self.transforms.cursor::<OutputPoint, InputPoint>();
|
||||
transforms.seek(&point, Bias::Right, &());
|
||||
let input_position =
|
||||
*transforms.sum_start() + InputPoint((point - *transforms.seek_start()).0);
|
||||
InputPoint(transforms.sum_start().0 + (point.0 - transforms.seek_start().0));
|
||||
let input_chunks = self.input.chunks_at(input_position);
|
||||
Chunks {
|
||||
input_chunks,
|
||||
@@ -157,6 +138,26 @@ impl Snapshot {
|
||||
input_chunk: "",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_point(&self) -> OutputPoint {
|
||||
self.to_output_point(self.input.max_point())
|
||||
}
|
||||
|
||||
pub fn to_input_point(&self, point: OutputPoint) -> InputPoint {
|
||||
let mut cursor = self.transforms.cursor::<OutputPoint, InputPoint>();
|
||||
cursor.seek(&point, Bias::Right, &());
|
||||
InputPoint(cursor.sum_start().0 + (point.0 - cursor.seek_start().0))
|
||||
}
|
||||
|
||||
pub fn to_output_point(&self, point: InputPoint) -> OutputPoint {
|
||||
let mut cursor = self.transforms.cursor::<InputPoint, OutputPoint>();
|
||||
cursor.seek(&point, Bias::Right, &());
|
||||
OutputPoint(cursor.sum_start().0 + (point.0 - cursor.seek_start().0))
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, point: OutputPoint, bias: Bias) -> OutputPoint {
|
||||
self.to_output_point(self.input.clip_point(self.to_input_point(point), bias))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Chunks<'a> {
|
||||
@@ -558,13 +559,13 @@ impl sum_tree::Summary for TransformSummary {
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for InputPoint {
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
|
||||
*self += InputPoint(summary.input.lines);
|
||||
self.0 += summary.input.lines;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for OutputPoint {
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
|
||||
*self += OutputPoint(summary.output.lines);
|
||||
self.0 += summary.output.lines;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,7 +579,6 @@ mod tests {
|
||||
},
|
||||
util::RandomCharIter,
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use gpui::fonts::FontId;
|
||||
use rand::prelude::*;
|
||||
use std::env;
|
||||
|
||||
Reference in New Issue
Block a user