Re-enable wrap_map module and fix compile errors

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra
2021-07-19 18:40:57 +02:00
co-authored by Nathan Sobo
parent 359132ac19
commit 631a6a2f45
4 changed files with 249 additions and 150 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
mod fold_map;
mod tab_map;
// mod wrap_map;
mod wrap_map;
use super::{buffer, Anchor, Bias, Buffer, Point, ToOffset, ToPoint};
use fold_map::FoldMap;
+7 -5
View File
@@ -483,14 +483,14 @@ impl Snapshot {
summary
}
pub fn len(&self) -> usize {
self.transforms.summary().output.bytes
pub fn len(&self) -> OutputOffset {
OutputOffset(self.transforms.summary().output.bytes)
}
pub fn line_len(&self, row: u32) -> u32 {
let line_start = self.to_output_offset(OutputPoint::new(row, 0)).0;
let line_end = if row >= self.max_point().row() {
self.len()
self.len().0
} else {
self.to_output_offset(OutputPoint::new(row + 1, 0)).0 - 1
};
@@ -1442,8 +1442,10 @@ mod tests {
}
for _ in 0..5 {
let offset = snapshot
.clip_offset(OutputOffset(rng.gen_range(0..=snapshot.len())), Bias::Right);
let offset = snapshot.clip_offset(
OutputOffset(rng.gen_range(0..=snapshot.len().0)),
Bias::Right,
);
assert_eq!(
snapshot.chunks_at(offset).collect::<String>(),
&expected_text[offset.0..],
+94 -21
View File
@@ -47,6 +47,35 @@ pub struct Snapshot {
}
impl Snapshot {
pub fn text_summary(&self) -> TextSummary {
// TODO: expand tabs on first and last line, ignoring the longest row.
let summary = self.input.text_summary();
TextSummary {
lines: summary.lines,
first_line_chars: summary.first_line_chars,
last_line_chars: summary.last_line_chars,
longest_row: summary.longest_row,
longest_row_chars: summary.longest_row_chars,
}
}
pub fn text_summary_for_rows(&self, rows: Range<u32>) -> TextSummary {
// TODO: expand tabs on first and last line, ignoring the longest row.
let range = InputPoint::new(rows.start, 0)..InputPoint::new(rows.end, 0);
let summary = self.input.text_summary_for_range(range);
TextSummary {
lines: summary.lines,
first_line_chars: summary.first_line_chars,
last_line_chars: summary.last_line_chars,
longest_row: summary.longest_row,
longest_row_chars: summary.longest_row_chars,
}
}
pub fn version(&self) -> usize {
self.input.version
}
pub fn chunks_at(&self, point: OutputPoint) -> Chunks {
let (point, expanded_char_column, to_next_stop) = self.to_input_point(point, Bias::Left);
let fold_chunks = self.input.chunks_at(self.input.to_output_offset(point));
@@ -73,6 +102,15 @@ impl Snapshot {
}
}
#[cfg(test)]
pub fn text(&self) -> String {
self.chunks_at(Default::default()).collect()
}
pub fn len(&self) -> OutputOffset {
self.to_output_offset(self.input.len())
}
pub fn line_len(&self, row: u32) -> u32 {
self.to_output_point(InputPoint::new(row, self.input.line_len(row)))
.column()
@@ -184,27 +222,7 @@ impl Snapshot {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct OutputOffset(usize);
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Edit {
pub old_bytes: Range<OutputOffset>,
pub new_bytes: Range<OutputOffset>,
}
impl Edit {
pub fn delta(&self) -> isize {
self.inserted_bytes() as isize - self.deleted_bytes() as isize
}
pub fn deleted_bytes(&self) -> usize {
self.old_bytes.end.0 - self.old_bytes.start.0
}
pub fn inserted_bytes(&self) -> usize {
self.new_bytes.end.0 - self.new_bytes.start.0
}
}
pub struct OutputOffset(pub usize);
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
pub struct OutputPoint(super::Point);
@@ -235,6 +253,61 @@ impl OutputPoint {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Edit {
pub old_bytes: Range<OutputOffset>,
pub new_bytes: Range<OutputOffset>,
}
impl Edit {
pub fn delta(&self) -> isize {
self.inserted_bytes() as isize - self.deleted_bytes() as isize
}
pub fn deleted_bytes(&self) -> usize {
self.old_bytes.end.0 - self.old_bytes.start.0
}
pub fn inserted_bytes(&self) -> usize {
self.new_bytes.end.0 - self.new_bytes.start.0
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct TextSummary {
pub lines: super::Point,
pub first_line_chars: u32,
pub last_line_chars: u32,
pub longest_row: u32,
pub longest_row_chars: u32,
}
impl<'a> std::ops::AddAssign<&'a Self> for TextSummary {
fn add_assign(&mut self, other: &'a Self) {
let joined_chars = self.last_line_chars + other.first_line_chars;
if joined_chars > self.longest_row_chars {
self.longest_row = self.lines.row;
self.longest_row_chars = joined_chars;
}
if other.longest_row_chars > self.longest_row_chars {
self.longest_row = self.lines.row + other.longest_row;
self.longest_row_chars = other.longest_row_chars;
}
if self.lines.row == 0 {
self.first_line_chars += other.first_line_chars;
}
if other.lines.row == 0 {
self.last_line_chars += other.first_line_chars;
} else {
self.last_line_chars = other.last_line_chars;
}
self.lines += &other.lines;
}
}
// Handles a tab width <= 16
const SPACES: &'static str = " ";
+147 -123
View File
@@ -1,24 +1,22 @@
use std::sync::Arc;
use super::tab_map::{
Edit as InputEdit, OutputOffset as InputOffset, Snapshot as InputSnapshot, TextSummary,
};
use crate::{
editor::{
display_map::fold_map::{self, DisplayOffset, FoldedPoint},
Point, TextSummary,
},
editor::Point,
sum_tree::{self, SumTree},
util::Bias,
};
use gpui::{font_cache::FamilyId, AppContext, FontCache, FontSystem, Task};
use parking_lot::Mutex;
use postage::{prelude::Sink, watch};
use smol::channel;
use std::sync::Arc;
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
pub struct WrappedPoint(Point);
pub struct OutputPoint(super::Point);
impl WrappedPoint {
impl OutputPoint {
pub fn new(row: u32, column: u32) -> Self {
Self(Point::new(row, column))
Self(super::Point::new(row, column))
}
pub fn zero() -> Self {
@@ -42,13 +40,32 @@ impl WrappedPoint {
}
}
#[derive(Clone, Default)]
#[derive(Clone)]
pub struct Snapshot {
transforms: SumTree<Transform>,
folds_snapshot: fold_map::Snapshot,
input: InputSnapshot,
version: usize,
}
impl Snapshot {
fn new(input: InputSnapshot) -> Self {
Self {
transforms: SumTree::from_item(
Transform {
summary: TransformSummary {
input: input.text_summary(),
output: input.text_summary(),
},
display_text: None,
},
&(),
),
version: input.version(),
input,
}
}
}
struct State {
snapshot: Snapshot,
interpolated_version: usize,
@@ -63,38 +80,26 @@ pub struct Config {
pub struct WrapMap {
state: Mutex<State>,
edits_tx: channel::Sender<(fold_map::Snapshot, Vec<fold_map::Edit>)>,
edits_tx: channel::Sender<(InputSnapshot, Vec<InputEdit>)>,
background_snapshots: watch::Receiver<Snapshot>,
_background_task: Task<()>,
}
impl WrapMap {
pub fn new(folds_snapshot: fold_map::Snapshot, config: Config, cx: &AppContext) -> Self {
pub fn new(input: InputSnapshot, config: Config, cx: &AppContext) -> Self {
let font_cache = cx.font_cache().clone();
let font_system = cx.platform().fonts();
let snapshot = Snapshot {
transforms: SumTree::from_item(
Transform {
summary: TransformSummary {
folded: folds_snapshot.text_summary(),
wrapped: folds_snapshot.text_summary(),
},
display_text: None,
},
&(),
),
folds_snapshot,
version: folds_snapshot.version,
};
let snapshot = Snapshot::new(input.clone());
let (background_snapshots_tx, background_snapshots_rx) =
watch::channel_with(snapshot.clone());
let (edits_tx, edits_rx) = channel::unbounded();
let background_task = cx.background().spawn(async move {
let mut wrapper = BackgroundWrapper::new(config, font_cache, font_system);
wrapper
.run(folds_snapshot, edits_rx, background_snapshots_tx)
.await;
});
let background_task = {
let snapshot = snapshot.clone();
cx.background().spawn(async move {
let mut wrapper = BackgroundWrapper::new(snapshot, config, font_cache, font_system);
wrapper.run(input, edits_rx, background_snapshots_tx).await;
})
};
Self {
state: Mutex::new(State {
@@ -107,9 +112,9 @@ impl WrapMap {
}
}
pub fn sync(&self, folds_snapshot: fold_map::Snapshot, edits: Vec<fold_map::Edit>) -> Snapshot {
pub fn sync(&self, input: InputSnapshot, edits: Vec<InputEdit>) -> Snapshot {
// TODO: interpolate
self.edits_tx.try_send((folds_snapshot, edits)).unwrap();
self.edits_tx.try_send((input, edits)).unwrap();
self.state.lock().snapshot.clone()
}
}
@@ -122,24 +127,29 @@ struct BackgroundWrapper {
}
impl BackgroundWrapper {
fn new(config: Config, font_cache: Arc<FontCache>, font_system: Arc<dyn FontSystem>) -> Self {
fn new(
snapshot: Snapshot,
config: Config,
font_cache: Arc<FontCache>,
font_system: Arc<dyn FontSystem>,
) -> Self {
Self {
config,
font_cache,
font_system,
snapshot: Snapshot::default(),
snapshot,
}
}
async fn run(
&mut self,
snapshot: fold_map::Snapshot,
edits_rx: channel::Receiver<(fold_map::Snapshot, Vec<fold_map::Edit>)>,
snapshot: InputSnapshot,
edits_rx: channel::Receiver<(InputSnapshot, Vec<InputEdit>)>,
mut snapshots_tx: watch::Sender<Snapshot>,
) {
let edit = fold_map::Edit {
old_bytes: DisplayOffset(0)..DisplayOffset(0),
new_bytes: DisplayOffset(0)..DisplayOffset(snapshot.len()),
let edit = InputEdit {
old_bytes: InputOffset(0)..InputOffset(0),
new_bytes: InputOffset(0)..snapshot.len(),
};
self.sync(snapshot, vec![edit]);
if snapshots_tx.send(self.snapshot.clone()).await.is_err() {
@@ -154,7 +164,7 @@ impl BackgroundWrapper {
}
}
fn sync(&mut self, snapshot: fold_map::Snapshot, edits: Vec<fold_map::Edit>) {
fn sync(&mut self, snapshot: InputSnapshot, edits: Vec<InputEdit>) {
let font_id = self
.font_cache
.select_font(self.config.font_family, &Default::default());
@@ -163,76 +173,76 @@ impl BackgroundWrapper {
let mut new_transforms = SumTree::new();
{
let mut old_cursor = self.snapshot.transforms.cursor::<DisplayPoint, ()>();
let mut position = DisplayPoint::zero();
for edit in edits {
let old_start = DisplayPoint::new(
edit.old_bytes.start.to_display_point(&self.snapshot).row(),
0,
);
let old_end = DisplayPoint::new(
edit.old_bytes.end.to_display_point(&self.snapshot).row() + 1,
0,
);
let new_start =
DisplayPoint::new(edit.new_bytes.start.to_display_point(&snapshot).row(), 0);
let new_end =
DisplayPoint::new(edit.new_bytes.end.to_display_point(&snapshot).row() + 1, 0);
// let mut old_cursor = self.snapshot.transforms.cursor::<DisplayPoint, ()>();
// let mut position = DisplayPoint::zero();
// for edit in edits {
// let old_start = DisplayPoint::new(
// edit.old_bytes.start.to_display_point(&self.snapshot).row(),
// 0,
// );
// let old_end = DisplayPoint::new(
// edit.old_bytes.end.to_display_point(&self.snapshot).row() + 1,
// 0,
// );
// let new_start =
// DisplayPoint::new(edit.new_bytes.start.to_display_point(&snapshot).row(), 0);
// let new_end =
// DisplayPoint::new(edit.new_bytes.end.to_display_point(&snapshot).row() + 1, 0);
if position > old_cursor.seek_start() && old_start >= old_cursor.seek_end(&()) {
old_cursor.next(&());
}
// if position > old_cursor.seek_start() && old_start >= old_cursor.seek_end(&()) {
// old_cursor.next(&());
// }
let prefix = old_cursor.slice(&old_start, Bias::Right, &());
new_transforms.push_tree(prefix, &());
new_transforms.push(
Transform::isomorphic(
self.snapshot
.folds_snapshot
.text_summary_for_range(position..old_start),
),
&(),
);
// let prefix = old_cursor.slice(&old_start, Bias::Right, &());
// new_transforms.push_tree(prefix, &());
// new_transforms.push(
// Transform::isomorphic(
// self.snapshot
// .folds_snapshot
// .text_summary_for_range(position..old_start),
// ),
// &(),
// );
let mut row = new_start.row();
let mut line = String::new();
'outer: for chunk in snapshot.chunks_at(snapshot.to_display_offset(new_start)) {
for (ix, line_chunk) in chunk.split('\n').enumerate() {
if ix > 0 {
let mut prev_boundary_ix = 0;
for boundary_ix in self
.font_system
.wrap_line(&line, font_id, font_size, wrap_width)
{
let wrapped = &line[prev_boundary_ix..boundary_ix];
new_transforms
.push(Transform::isomorphic(TextSummary::from(wrapped)));
new_transforms.push(Transform::newline());
prev_boundary_ix = boundary_ix;
}
// let mut row = new_start.row();
// let mut line = String::new();
// 'outer: for chunk in snapshot.chunks_at(snapshot.to_display_offset(new_start)) {
// for (ix, line_chunk) in chunk.split('\n').enumerate() {
// if ix > 0 {
// let mut prev_boundary_ix = 0;
// for boundary_ix in self
// .font_system
// .wrap_line(&line, font_id, font_size, wrap_width)
// {
// let wrapped = &line[prev_boundary_ix..boundary_ix];
// new_transforms
// .push(Transform::isomorphic(TextSummary::from(wrapped)));
// new_transforms.push(Transform::newline());
// prev_boundary_ix = boundary_ix;
// }
line.clear();
row += 1;
if row == new_end.row() {
break 'outer;
}
}
// line.clear();
// row += 1;
// if row == new_end.row() {
// break 'outer;
// }
// }
line.push_str(line_chunk);
}
}
// line.push_str(line_chunk);
// }
// }
old_cursor.seek_forward(&old_end, Bias::Right, &());
position = old_end;
}
// old_cursor.seek_forward(&old_end, Bias::Right, &());
// position = old_end;
// }
if position > old_cursor.seek_start() && old_start >= old_cursor.seek_end(&()) {
old_cursor.next(&());
}
// if position > old_cursor.seek_start() && old_start >= old_cursor.seek_end(&()) {
// old_cursor.next(&());
// }
}
self.snapshot.transforms = new_transforms;
self.snapshot.version = snapshot.version;
self.snapshot.version = snapshot.version();
}
}
@@ -246,8 +256,8 @@ impl Transform {
fn isomorphic(summary: TextSummary) -> Self {
Self {
summary: TransformSummary {
folded: summary.clone(),
wrapped: summary,
input: summary.clone(),
output: summary,
},
display_text: None,
}
@@ -256,8 +266,14 @@ impl Transform {
fn newline() -> Self {
Self {
summary: TransformSummary {
folded: TextSummary::default(),
wrapped: TextSummary::from("\n"),
input: TextSummary::default(),
output: TextSummary {
lines: Point::new(1, 0),
first_line_chars: 0,
last_line_chars: 0,
longest_row: 0,
longest_row_chars: 0,
},
},
display_text: Some("\n"),
}
@@ -274,22 +290,22 @@ impl sum_tree::Item for Transform {
#[derive(Clone, Debug, Default, Eq, PartialEq)]
struct TransformSummary {
folded: TextSummary,
wrapped: TextSummary,
input: TextSummary,
output: TextSummary,
}
impl sum_tree::Summary for TransformSummary {
type Context = ();
fn add_summary(&mut self, other: &Self, _: &()) {
self.folded += &other.folded;
self.wrapped += &other.wrapped;
self.input += &other.input;
self.output += &other.output;
}
}
impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
*self += &summary.folded.lines;
*self += &summary.input.lines;
}
}
@@ -297,12 +313,14 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
mod tests {
use super::*;
use crate::{
editor::{display_map::fold_map::FoldMap, Buffer},
editor::{
display_map::{fold_map::FoldMap, tab_map::TabMap},
Buffer,
},
util::RandomCharIter,
};
use rand::prelude::*;
use std::env;
use Bias::{Left, Right};
#[gpui::test]
fn test_random_wraps(cx: &mut gpui::MutableAppContext) {
@@ -329,7 +347,9 @@ mod tests {
Buffer::new(0, text, cx)
});
let fold_map = FoldMap::new(buffer.clone(), cx.as_ref());
let (snapshot, _) = fold_map.read(cx.as_ref());
let (folds_snapshot, edits) = fold_map.read(cx.as_ref());
let tab_map = TabMap::new(folds_snapshot.clone(), rng.gen_range(1..=4));
let (tabs_snapshot, _) = tab_map.sync(folds_snapshot, edits);
let font_cache = cx.font_cache().clone();
let font_system = cx.platform().fonts();
let config = Config {
@@ -340,16 +360,20 @@ mod tests {
let font_id = font_cache
.select_font(config.font_family, &Default::default())
.unwrap();
let mut wrapper =
BackgroundWrapper::new(config.clone(), font_cache.clone(), font_system.clone());
let edit = fold_map::Edit {
old_bytes: DisplayOffset(0)..DisplayOffset(0),
new_bytes: DisplayOffset(0)..DisplayOffset(snapshot.len()),
let mut wrapper = BackgroundWrapper::new(
Snapshot::new(tabs_snapshot.clone()),
config.clone(),
font_cache.clone(),
font_system.clone(),
);
let edit = InputEdit {
old_bytes: InputOffset(0)..InputOffset(0),
new_bytes: InputOffset(0)..tabs_snapshot.len(),
};
wrapper.sync(snapshot.clone(), vec![edit]);
wrapper.sync(tabs_snapshot.clone(), vec![edit]);
let mut expected_text = String::new();
for line in snapshot.text().lines() {
for line in tabs_snapshot.text().lines() {
let mut prev_ix = 0;
for ix in font_system.wrap_line(line, font_id, 14.0, config.wrap_width) {
expected_text.push_str(&line[prev_ix..ix]);