editor: Newtype WrapRow (#41843)
Makes a better distinction between `WrapRow` and `BlockRow` Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
@@ -17,6 +17,9 @@
|
||||
//! [Editor]: crate::Editor
|
||||
//! [EditorElement]: crate::element::EditorElement
|
||||
|
||||
#[macro_use]
|
||||
mod dimensions;
|
||||
|
||||
mod block_map;
|
||||
mod crease_map;
|
||||
mod custom_highlights;
|
||||
@@ -167,11 +170,12 @@ impl DisplayMap {
|
||||
}
|
||||
|
||||
pub fn snapshot(&mut self, cx: &mut Context<Self>) -> DisplaySnapshot {
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
|
||||
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let (inlay_snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits);
|
||||
let (fold_snapshot, edits) = self.fold_map.read(inlay_snapshot, edits);
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (tab_snapshot, edits) = self.tab_map.sync(fold_snapshot, edits, tab_size);
|
||||
let (wrap_snapshot, edits) = self
|
||||
.wrap_map
|
||||
@@ -915,7 +919,7 @@ impl DisplaySnapshot {
|
||||
pub fn text_chunks(&self, display_row: DisplayRow) -> impl Iterator<Item = &str> {
|
||||
self.block_snapshot
|
||||
.chunks(
|
||||
display_row.0..self.max_point().row().next_row().0,
|
||||
BlockRow(display_row.0)..BlockRow(self.max_point().row().next_row().0),
|
||||
false,
|
||||
self.masked,
|
||||
Highlights::default(),
|
||||
@@ -927,7 +931,12 @@ impl DisplaySnapshot {
|
||||
pub fn reverse_text_chunks(&self, display_row: DisplayRow) -> impl Iterator<Item = &str> {
|
||||
(0..=display_row.0).rev().flat_map(move |row| {
|
||||
self.block_snapshot
|
||||
.chunks(row..row + 1, false, self.masked, Highlights::default())
|
||||
.chunks(
|
||||
BlockRow(row)..BlockRow(row + 1),
|
||||
false,
|
||||
self.masked,
|
||||
Highlights::default(),
|
||||
)
|
||||
.map(|h| h.text)
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
@@ -942,7 +951,7 @@ impl DisplaySnapshot {
|
||||
highlight_styles: HighlightStyles,
|
||||
) -> DisplayChunks<'_> {
|
||||
self.block_snapshot.chunks(
|
||||
display_rows.start.0..display_rows.end.0,
|
||||
BlockRow(display_rows.start.0)..BlockRow(display_rows.end.0),
|
||||
language_aware,
|
||||
self.masked,
|
||||
Highlights {
|
||||
@@ -1178,8 +1187,8 @@ impl DisplaySnapshot {
|
||||
rows: Range<DisplayRow>,
|
||||
) -> impl Iterator<Item = (DisplayRow, &Block)> {
|
||||
self.block_snapshot
|
||||
.blocks_in_range(rows.start.0..rows.end.0)
|
||||
.map(|(row, block)| (DisplayRow(row), block))
|
||||
.blocks_in_range(BlockRow(rows.start.0)..BlockRow(rows.end.0))
|
||||
.map(|(row, block)| (DisplayRow(row.0), block))
|
||||
}
|
||||
|
||||
pub fn sticky_header_excerpt(&self, row: f64) -> Option<StickyHeaderExcerpt<'_>> {
|
||||
@@ -1211,7 +1220,7 @@ impl DisplaySnapshot {
|
||||
pub fn soft_wrap_indent(&self, display_row: DisplayRow) -> Option<u32> {
|
||||
let wrap_row = self
|
||||
.block_snapshot
|
||||
.to_wrap_point(BlockPoint::new(display_row.0, 0), Bias::Left)
|
||||
.to_wrap_point(BlockPoint::new(BlockRow(display_row.0), 0), Bias::Left)
|
||||
.row();
|
||||
self.wrap_snapshot().soft_wrap_indent(wrap_row)
|
||||
}
|
||||
@@ -1242,7 +1251,7 @@ impl DisplaySnapshot {
|
||||
}
|
||||
|
||||
pub fn longest_row(&self) -> DisplayRow {
|
||||
DisplayRow(self.block_snapshot.longest_row())
|
||||
DisplayRow(self.block_snapshot.longest_row().0)
|
||||
}
|
||||
|
||||
pub fn longest_row_in_range(&self, range: Range<DisplayRow>) -> DisplayRow {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
pub struct RowDelta(pub u32);
|
||||
|
||||
impl RowDelta {
|
||||
pub fn saturating_sub(self, other: RowDelta) -> RowDelta {
|
||||
RowDelta(self.0.saturating_sub(other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Add for RowDelta {
|
||||
type Output = RowDelta;
|
||||
|
||||
fn add(self, rhs: RowDelta) -> Self::Output {
|
||||
RowDelta(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Sub for RowDelta {
|
||||
type Output = RowDelta;
|
||||
|
||||
fn sub(self, rhs: RowDelta) -> Self::Output {
|
||||
RowDelta(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::AddAssign for RowDelta {
|
||||
fn add_assign(&mut self, rhs: RowDelta) {
|
||||
self.0 += rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::SubAssign for RowDelta {
|
||||
fn sub_assign(&mut self, rhs: RowDelta) {
|
||||
self.0 -= rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_for_row_types {
|
||||
($row:ident => $row_delta:ident) => {
|
||||
impl $row {
|
||||
pub fn saturating_sub(self, other: $row_delta) -> $row {
|
||||
$row(self.0.saturating_sub(other.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Add for $row {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Add<$row_delta> for $row {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: $row_delta) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Sub for $row {
|
||||
type Output = $row_delta;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
$row_delta(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Sub<$row_delta> for $row {
|
||||
type Output = $row;
|
||||
|
||||
fn sub(self, rhs: $row_delta) -> Self::Output {
|
||||
$row(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::AddAssign for $row {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 += rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::AddAssign<$row_delta> for $row {
|
||||
fn add_assign(&mut self, rhs: $row_delta) {
|
||||
self.0 += rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::SubAssign<$row_delta> for $row {
|
||||
fn sub_assign(&mut self, rhs: $row_delta) {
|
||||
self.0 -= rhs.0;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::{
|
||||
Highlights,
|
||||
dimensions::RowDelta,
|
||||
fold_map::{Chunk, FoldRows},
|
||||
tab_map::{self, TabEdit, TabPoint, TabSnapshot},
|
||||
};
|
||||
@@ -7,13 +8,20 @@ use gpui::{App, AppContext as _, Context, Entity, Font, LineWrapper, Pixels, Tas
|
||||
use language::Point;
|
||||
use multi_buffer::{MultiBufferSnapshot, RowInfo};
|
||||
use smol::future::yield_now;
|
||||
use std::sync::LazyLock;
|
||||
use std::{cmp, collections::VecDeque, mem, ops::Range, time::Duration};
|
||||
use std::{cmp, collections::VecDeque, mem, ops::Range, sync::LazyLock, time::Duration};
|
||||
use sum_tree::{Bias, Cursor, Dimensions, SumTree};
|
||||
use text::Patch;
|
||||
|
||||
pub use super::tab_map::TextSummary;
|
||||
pub type WrapEdit = text::Edit<u32>;
|
||||
pub type WrapEdit = text::Edit<WrapRow>;
|
||||
pub type WrapPatch = text::Patch<WrapRow>;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
pub struct WrapRow(pub u32);
|
||||
|
||||
impl_for_row_types! {
|
||||
WrapRow => RowDelta
|
||||
}
|
||||
|
||||
/// Handles soft wrapping of text.
|
||||
///
|
||||
@@ -21,8 +29,8 @@ pub type WrapEdit = text::Edit<u32>;
|
||||
pub struct WrapMap {
|
||||
snapshot: WrapSnapshot,
|
||||
pending_edits: VecDeque<(TabSnapshot, Vec<TabEdit>)>,
|
||||
interpolated_edits: Patch<u32>,
|
||||
edits_since_sync: Patch<u32>,
|
||||
interpolated_edits: WrapPatch,
|
||||
edits_since_sync: WrapPatch,
|
||||
wrap_width: Option<Pixels>,
|
||||
background_task: Option<Task<()>>,
|
||||
font_with_size: (Font, Pixels),
|
||||
@@ -54,7 +62,7 @@ pub struct WrapChunks<'a> {
|
||||
input_chunks: tab_map::TabChunks<'a>,
|
||||
input_chunk: Chunk<'a>,
|
||||
output_position: WrapPoint,
|
||||
max_output_row: u32,
|
||||
max_output_row: WrapRow,
|
||||
transforms: Cursor<'a, 'static, Transform, Dimensions<WrapPoint, TabPoint>>,
|
||||
snapshot: &'a WrapSnapshot,
|
||||
}
|
||||
@@ -63,19 +71,19 @@ pub struct WrapChunks<'a> {
|
||||
pub struct WrapRows<'a> {
|
||||
input_buffer_rows: FoldRows<'a>,
|
||||
input_buffer_row: RowInfo,
|
||||
output_row: u32,
|
||||
output_row: WrapRow,
|
||||
soft_wrapped: bool,
|
||||
max_output_row: u32,
|
||||
max_output_row: WrapRow,
|
||||
transforms: Cursor<'a, 'static, Transform, Dimensions<WrapPoint, TabPoint>>,
|
||||
}
|
||||
|
||||
impl WrapRows<'_> {
|
||||
pub(crate) fn seek(&mut self, start_row: u32) {
|
||||
pub(crate) fn seek(&mut self, start_row: WrapRow) {
|
||||
self.transforms
|
||||
.seek(&WrapPoint::new(start_row, 0), Bias::Left);
|
||||
let mut input_row = self.transforms.start().1.row();
|
||||
if self.transforms.item().is_some_and(|t| t.is_isomorphic()) {
|
||||
input_row += start_row - self.transforms.start().0.row();
|
||||
input_row += (start_row - self.transforms.start().0.row()).0;
|
||||
}
|
||||
self.soft_wrapped = self.transforms.item().is_some_and(|t| !t.is_isomorphic());
|
||||
self.input_buffer_rows.seek(input_row);
|
||||
@@ -120,7 +128,7 @@ impl WrapMap {
|
||||
tab_snapshot: TabSnapshot,
|
||||
edits: Vec<TabEdit>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> (WrapSnapshot, Patch<u32>) {
|
||||
) -> (WrapSnapshot, WrapPatch) {
|
||||
if self.wrap_width.is_some() {
|
||||
self.pending_edits.push_back((tab_snapshot, edits));
|
||||
self.flush_edits(cx);
|
||||
@@ -226,8 +234,8 @@ impl WrapMap {
|
||||
let new_rows = self.snapshot.transforms.summary().output.lines.row + 1;
|
||||
self.snapshot.interpolated = false;
|
||||
self.edits_since_sync = self.edits_since_sync.compose(Patch::new(vec![WrapEdit {
|
||||
old: 0..old_rows,
|
||||
new: 0..new_rows,
|
||||
old: WrapRow(0)..WrapRow(old_rows),
|
||||
new: WrapRow(0)..WrapRow(new_rows),
|
||||
}]));
|
||||
}
|
||||
}
|
||||
@@ -331,7 +339,7 @@ impl WrapSnapshot {
|
||||
self.tab_snapshot.buffer_snapshot()
|
||||
}
|
||||
|
||||
fn interpolate(&mut self, new_tab_snapshot: TabSnapshot, tab_edits: &[TabEdit]) -> Patch<u32> {
|
||||
fn interpolate(&mut self, new_tab_snapshot: TabSnapshot, tab_edits: &[TabEdit]) -> WrapPatch {
|
||||
let mut new_transforms;
|
||||
if tab_edits.is_empty() {
|
||||
new_transforms = self.transforms.clone();
|
||||
@@ -401,7 +409,7 @@ impl WrapSnapshot {
|
||||
tab_edits: &[TabEdit],
|
||||
wrap_width: Pixels,
|
||||
line_wrapper: &mut LineWrapper,
|
||||
) -> Patch<u32> {
|
||||
) -> WrapPatch {
|
||||
#[derive(Debug)]
|
||||
struct RowEdit {
|
||||
old_rows: Range<u32>,
|
||||
@@ -554,7 +562,7 @@ impl WrapSnapshot {
|
||||
old_snapshot.compute_edits(tab_edits, self)
|
||||
}
|
||||
|
||||
fn compute_edits(&self, tab_edits: &[TabEdit], new_snapshot: &WrapSnapshot) -> Patch<u32> {
|
||||
fn compute_edits(&self, tab_edits: &[TabEdit], new_snapshot: &WrapSnapshot) -> WrapPatch {
|
||||
let mut wrap_edits = Vec::with_capacity(tab_edits.len());
|
||||
let mut old_cursor = self.transforms.cursor::<TransformSummary>(());
|
||||
let mut new_cursor = new_snapshot.transforms.cursor::<TransformSummary>(());
|
||||
@@ -581,8 +589,8 @@ impl WrapSnapshot {
|
||||
new_end += tab_edit.new.end.0 - new_cursor.start().input.lines;
|
||||
|
||||
wrap_edits.push(WrapEdit {
|
||||
old: old_start.row..old_end.row,
|
||||
new: new_start.row..new_end.row,
|
||||
old: WrapRow(old_start.row)..WrapRow(old_end.row),
|
||||
new: WrapRow(new_start.row)..WrapRow(new_end.row),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -592,7 +600,7 @@ impl WrapSnapshot {
|
||||
|
||||
pub(crate) fn chunks<'a>(
|
||||
&'a self,
|
||||
rows: Range<u32>,
|
||||
rows: Range<WrapRow>,
|
||||
language_aware: bool,
|
||||
highlights: Highlights<'a>,
|
||||
) -> WrapChunks<'a> {
|
||||
@@ -627,17 +635,17 @@ impl WrapSnapshot {
|
||||
WrapPoint(self.transforms.summary().output.lines)
|
||||
}
|
||||
|
||||
pub fn line_len(&self, row: u32) -> u32 {
|
||||
pub fn line_len(&self, row: WrapRow) -> u32 {
|
||||
let (start, _, item) = self.transforms.find::<Dimensions<WrapPoint, TabPoint>, _>(
|
||||
(),
|
||||
&WrapPoint::new(row + 1, 0),
|
||||
&WrapPoint::new(row + WrapRow(1), 0),
|
||||
Bias::Left,
|
||||
);
|
||||
if item.is_some_and(|transform| transform.is_isomorphic()) {
|
||||
let overshoot = row - start.0.row();
|
||||
let tab_row = start.1.row() + overshoot;
|
||||
let tab_row = start.1.row() + overshoot.0;
|
||||
let tab_line_len = self.tab_snapshot.line_len(tab_row);
|
||||
if overshoot == 0 {
|
||||
if overshoot.0 == 0 {
|
||||
start.0.column() + (tab_line_len - start.1.column())
|
||||
} else {
|
||||
tab_line_len
|
||||
@@ -647,7 +655,7 @@ impl WrapSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, rows: Range<u32>) -> TextSummary {
|
||||
pub fn text_summary_for_range(&self, rows: Range<WrapRow>) -> TextSummary {
|
||||
let mut summary = TextSummary::default();
|
||||
|
||||
let start = WrapPoint::new(rows.start, 0);
|
||||
@@ -708,10 +716,12 @@ impl WrapSnapshot {
|
||||
summary
|
||||
}
|
||||
|
||||
pub fn soft_wrap_indent(&self, row: u32) -> Option<u32> {
|
||||
let (.., item) =
|
||||
self.transforms
|
||||
.find::<WrapPoint, _>((), &WrapPoint::new(row + 1, 0), Bias::Right);
|
||||
pub fn soft_wrap_indent(&self, row: WrapRow) -> Option<u32> {
|
||||
let (.., item) = self.transforms.find::<WrapPoint, _>(
|
||||
(),
|
||||
&WrapPoint::new(row + WrapRow(1), 0),
|
||||
Bias::Right,
|
||||
);
|
||||
item.and_then(|transform| {
|
||||
if transform.is_isomorphic() {
|
||||
None
|
||||
@@ -725,14 +735,14 @@ impl WrapSnapshot {
|
||||
self.transforms.summary().output.longest_row
|
||||
}
|
||||
|
||||
pub fn row_infos(&self, start_row: u32) -> WrapRows<'_> {
|
||||
pub fn row_infos(&self, start_row: WrapRow) -> WrapRows<'_> {
|
||||
let mut transforms = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<WrapPoint, TabPoint>>(());
|
||||
transforms.seek(&WrapPoint::new(start_row, 0), Bias::Left);
|
||||
let mut input_row = transforms.start().1.row();
|
||||
if transforms.item().is_some_and(|t| t.is_isomorphic()) {
|
||||
input_row += start_row - transforms.start().0.row();
|
||||
input_row += (start_row - transforms.start().0.row()).0;
|
||||
}
|
||||
let soft_wrapped = transforms.item().is_some_and(|t| !t.is_isomorphic());
|
||||
let mut input_buffer_rows = self.tab_snapshot.rows(input_row);
|
||||
@@ -787,9 +797,9 @@ impl WrapSnapshot {
|
||||
self.tab_point_to_wrap_point(self.tab_snapshot.clip_point(self.to_tab_point(point), bias))
|
||||
}
|
||||
|
||||
pub fn prev_row_boundary(&self, mut point: WrapPoint) -> u32 {
|
||||
pub fn prev_row_boundary(&self, mut point: WrapPoint) -> WrapRow {
|
||||
if self.transforms.is_empty() {
|
||||
return 0;
|
||||
return WrapRow(0);
|
||||
}
|
||||
|
||||
*point.column_mut() = 0;
|
||||
@@ -813,7 +823,7 @@ impl WrapSnapshot {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn next_row_boundary(&self, mut point: WrapPoint) -> Option<u32> {
|
||||
pub fn next_row_boundary(&self, mut point: WrapPoint) -> Option<WrapRow> {
|
||||
point.0 += Point::new(1, 0);
|
||||
|
||||
let mut cursor = self
|
||||
@@ -833,13 +843,13 @@ impl WrapSnapshot {
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn text(&self) -> String {
|
||||
self.text_chunks(0).collect()
|
||||
self.text_chunks(WrapRow(0)).collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn text_chunks(&self, wrap_row: u32) -> impl Iterator<Item = &str> {
|
||||
pub fn text_chunks(&self, wrap_row: WrapRow) -> impl Iterator<Item = &str> {
|
||||
self.chunks(
|
||||
wrap_row..self.max_point().row() + 1,
|
||||
wrap_row..self.max_point().row() + WrapRow(1),
|
||||
false,
|
||||
Highlights::default(),
|
||||
)
|
||||
@@ -867,21 +877,22 @@ impl WrapSnapshot {
|
||||
let mut input_buffer_rows = self.tab_snapshot.rows(0);
|
||||
let mut expected_buffer_rows = Vec::new();
|
||||
let mut prev_tab_row = 0;
|
||||
for display_row in 0..=self.max_point().row() {
|
||||
for display_row in 0..=self.max_point().row().0 {
|
||||
let display_row = WrapRow(display_row);
|
||||
let tab_point = self.to_tab_point(WrapPoint::new(display_row, 0));
|
||||
if tab_point.row() == prev_tab_row && display_row != 0 {
|
||||
if tab_point.row() == prev_tab_row && display_row != WrapRow(0) {
|
||||
expected_buffer_rows.push(None);
|
||||
} else {
|
||||
expected_buffer_rows.push(input_buffer_rows.next().unwrap().buffer_row);
|
||||
}
|
||||
|
||||
prev_tab_row = tab_point.row();
|
||||
assert_eq!(self.line_len(display_row), text.line_len(display_row));
|
||||
assert_eq!(self.line_len(display_row), text.line_len(display_row.0));
|
||||
}
|
||||
|
||||
for start_display_row in 0..expected_buffer_rows.len() {
|
||||
assert_eq!(
|
||||
self.row_infos(start_display_row as u32)
|
||||
self.row_infos(WrapRow(start_display_row as u32))
|
||||
.map(|row_info| row_info.buffer_row)
|
||||
.collect::<Vec<_>>(),
|
||||
&expected_buffer_rows[start_display_row..],
|
||||
@@ -894,7 +905,7 @@ impl WrapSnapshot {
|
||||
}
|
||||
|
||||
impl WrapChunks<'_> {
|
||||
pub(crate) fn seek(&mut self, rows: Range<u32>) {
|
||||
pub(crate) fn seek(&mut self, rows: Range<WrapRow>) {
|
||||
let output_start = WrapPoint::new(rows.start, 0);
|
||||
let output_end = WrapPoint::new(rows.end, 0);
|
||||
self.transforms.seek(&output_start, Bias::Right);
|
||||
@@ -931,7 +942,7 @@ impl<'a> Iterator for WrapChunks<'a> {
|
||||
// Exclude newline starting prior to the desired row.
|
||||
start_ix = 1;
|
||||
summary.row = 0;
|
||||
} else if self.output_position.row() + 1 >= self.max_output_row {
|
||||
} else if self.output_position.row() + WrapRow(1) >= self.max_output_row {
|
||||
// Exclude soft indentation ending after the desired row.
|
||||
end_ix = 1;
|
||||
summary.column = 0;
|
||||
@@ -997,7 +1008,7 @@ impl Iterator for WrapRows<'_> {
|
||||
let soft_wrapped = self.soft_wrapped;
|
||||
let diff_status = self.input_buffer_row.diff_status;
|
||||
|
||||
self.output_row += 1;
|
||||
self.output_row += WrapRow(1);
|
||||
self.transforms
|
||||
.seek_forward(&WrapPoint::new(self.output_row, 0), Bias::Left);
|
||||
if self.transforms.item().is_some_and(|t| t.is_isomorphic()) {
|
||||
@@ -1107,12 +1118,12 @@ impl SumTreeExt for SumTree<Transform> {
|
||||
}
|
||||
|
||||
impl WrapPoint {
|
||||
pub fn new(row: u32, column: u32) -> Self {
|
||||
Self(Point::new(row, column))
|
||||
pub fn new(row: WrapRow, column: u32) -> Self {
|
||||
Self(Point::new(row.0, column))
|
||||
}
|
||||
|
||||
pub fn row(self) -> u32 {
|
||||
self.0.row
|
||||
pub fn row(self) -> WrapRow {
|
||||
WrapRow(self.0.row)
|
||||
}
|
||||
|
||||
pub fn row_mut(&mut self) -> &mut u32 {
|
||||
@@ -1417,14 +1428,14 @@ mod tests {
|
||||
for (snapshot, patch) in edits {
|
||||
let snapshot_text = Rope::from(snapshot.text().as_str());
|
||||
for edit in &patch {
|
||||
let old_start = initial_text.point_to_offset(Point::new(edit.new.start, 0));
|
||||
let old_start = initial_text.point_to_offset(Point::new(edit.new.start.0, 0));
|
||||
let old_end = initial_text.point_to_offset(cmp::min(
|
||||
Point::new(edit.new.start + edit.old.len() as u32, 0),
|
||||
Point::new(edit.new.start.0 + (edit.old.end - edit.old.start).0, 0),
|
||||
initial_text.max_point(),
|
||||
));
|
||||
let new_start = snapshot_text.point_to_offset(Point::new(edit.new.start, 0));
|
||||
let new_start = snapshot_text.point_to_offset(Point::new(edit.new.start.0, 0));
|
||||
let new_end = snapshot_text.point_to_offset(cmp::min(
|
||||
Point::new(edit.new.end, 0),
|
||||
Point::new(edit.new.end.0, 0),
|
||||
snapshot_text.max_point(),
|
||||
));
|
||||
let new_text = snapshot_text
|
||||
@@ -1484,11 +1495,11 @@ mod tests {
|
||||
impl WrapSnapshot {
|
||||
fn verify_chunks(&mut self, rng: &mut impl Rng) {
|
||||
for _ in 0..5 {
|
||||
let mut end_row = rng.random_range(0..=self.max_point().row());
|
||||
let mut end_row = rng.random_range(0..=self.max_point().row().0);
|
||||
let start_row = rng.random_range(0..=end_row);
|
||||
end_row += 1;
|
||||
|
||||
let mut expected_text = self.text_chunks(start_row).collect::<String>();
|
||||
let mut expected_text = self.text_chunks(WrapRow(start_row)).collect::<String>();
|
||||
if expected_text.ends_with('\n') {
|
||||
expected_text.push('\n');
|
||||
}
|
||||
@@ -1497,12 +1508,16 @@ mod tests {
|
||||
.take((end_row - start_row) as usize)
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
if end_row <= self.max_point().row() {
|
||||
if end_row <= self.max_point().row().0 {
|
||||
expected_text.push('\n');
|
||||
}
|
||||
|
||||
let actual_text = self
|
||||
.chunks(start_row..end_row, true, Highlights::default())
|
||||
.chunks(
|
||||
WrapRow(start_row)..WrapRow(end_row),
|
||||
true,
|
||||
Highlights::default(),
|
||||
)
|
||||
.map(|c| c.text)
|
||||
.collect::<String>();
|
||||
assert_eq!(
|
||||
|
||||
+44
-41
@@ -9,15 +9,7 @@ pub struct Patch<T>(Vec<Edit<T>>);
|
||||
|
||||
impl<T> Patch<T>
|
||||
where
|
||||
T: 'static
|
||||
+ Clone
|
||||
+ Copy
|
||||
+ Ord
|
||||
+ Sub<T, Output = T>
|
||||
+ Add<T, Output = T>
|
||||
+ AddAssign
|
||||
+ Default
|
||||
+ PartialEq,
|
||||
T: 'static + Clone + Copy + Ord + Default,
|
||||
{
|
||||
pub fn new(edits: Vec<Edit<T>>) -> Self {
|
||||
#[cfg(debug_assertions)]
|
||||
@@ -41,7 +33,50 @@ where
|
||||
pub fn into_inner(self) -> Vec<Edit<T>> {
|
||||
self.0
|
||||
}
|
||||
pub fn invert(&mut self) -> &mut Self {
|
||||
for edit in &mut self.0 {
|
||||
mem::swap(&mut edit.old, &mut edit.new);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear();
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, edit: Edit<T>) {
|
||||
if edit.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(last) = self.0.last_mut() {
|
||||
if last.old.end >= edit.old.start {
|
||||
last.old.end = edit.old.end;
|
||||
last.new.end = edit.new.end;
|
||||
} else {
|
||||
self.0.push(edit);
|
||||
}
|
||||
} else {
|
||||
self.0.push(edit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, TDelta> Patch<T>
|
||||
where
|
||||
T: 'static
|
||||
+ Copy
|
||||
+ Ord
|
||||
+ Sub<T, Output = TDelta>
|
||||
+ Add<TDelta, Output = T>
|
||||
+ AddAssign<TDelta>
|
||||
+ Default,
|
||||
TDelta: Ord + Copy,
|
||||
{
|
||||
#[must_use]
|
||||
pub fn compose(&self, new_edits_iter: impl IntoIterator<Item = Edit<T>>) -> Self {
|
||||
let mut old_edits_iter = self.0.iter().cloned().peekable();
|
||||
@@ -169,38 +204,6 @@ where
|
||||
composed
|
||||
}
|
||||
|
||||
pub fn invert(&mut self) -> &mut Self {
|
||||
for edit in &mut self.0 {
|
||||
mem::swap(&mut edit.old, &mut edit.new);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.0.clear();
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, edit: Edit<T>) {
|
||||
if edit.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(last) = self.0.last_mut() {
|
||||
if last.old.end >= edit.old.start {
|
||||
last.old.end = edit.old.end;
|
||||
last.new.end = edit.new.end;
|
||||
} else {
|
||||
self.0.push(edit);
|
||||
}
|
||||
} else {
|
||||
self.0.push(edit);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn old_to_new(&self, old: T) -> T {
|
||||
let ix = match self.0.binary_search_by(|probe| probe.old.start.cmp(&old)) {
|
||||
Ok(ix) => ix,
|
||||
|
||||
+12
-8
@@ -496,22 +496,26 @@ pub struct Edit<D> {
|
||||
pub old: Range<D>,
|
||||
pub new: Range<D>,
|
||||
}
|
||||
|
||||
impl<D> Edit<D>
|
||||
where
|
||||
D: Sub<D, Output = D> + PartialEq + Copy,
|
||||
D: PartialEq,
|
||||
{
|
||||
pub fn old_len(&self) -> D {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.old.start == self.old.end && self.new.start == self.new.end
|
||||
}
|
||||
}
|
||||
|
||||
impl<D, DDelta> Edit<D>
|
||||
where
|
||||
D: Sub<D, Output = DDelta> + Copy,
|
||||
{
|
||||
pub fn old_len(&self) -> DDelta {
|
||||
self.old.end - self.old.start
|
||||
}
|
||||
|
||||
pub fn new_len(&self) -> D {
|
||||
pub fn new_len(&self) -> DDelta {
|
||||
self.new.end - self.new.start
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.old.start == self.old.end && self.new.start == self.new.end
|
||||
}
|
||||
}
|
||||
|
||||
impl<D1, D2> Edit<(D1, D2)> {
|
||||
|
||||
Reference in New Issue
Block a user