Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
554 changes: 224 additions & 330 deletions diffr/crates/diffr-core/src/plugin/cursor.rs

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions diffr/crates/diffr-core/src/plugin/cursor/mutations.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::tests::name_pairs;
use super::*;
use crate::protocol::Span;
use crate::protocol::{FileRef, FileStatus};
Expand Down Expand Up @@ -96,14 +97,12 @@ fn entry() -> FileChange {
}

fn both(lhs: Vec<Region>, rhs: Vec<Region>) -> Cursor {
Cursor::new(
entry(),
Pairing::Both {
lhs: source(100, lhs),
rhs: source(101, rhs),
},
)
.expect("a region")
let mut sides = Pairing::Both {
lhs: source(100, lhs),
rhs: source(101, rhs),
};
name_pairs(&mut sides);
Cursor::new(entry(), sides).expect("a region")
}

type Shape = (u32, Option<u32>, u32, u32, u32, bool, String);
Expand Down
33 changes: 32 additions & 1 deletion diffr/crates/diffr-core/src/plugin/cursor/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use crate::hash::DftHashMap;
use crate::protocol::{FileRef, FileStatus};

/// A test side's root. Its id stays clear of the regions' ids and differs
Expand All @@ -8,6 +9,35 @@ pub(crate) fn test_root(regions: Vec<Region>) -> Region {
Region::root(id, regions)
}

/// Set each leaf's `pair` from the fixture's alignment ids.
pub(crate) fn name_pairs(sides: &mut Pairing<Source>) {
fn name(regions: &mut [Region], other: &DftHashMap<u32, u32>) {
for region in regions {
match &mut region.node {
Node::Leaf {
alignment_id, pair, ..
} => *pair = other.get(alignment_id).copied(),
Node::Fold { children, .. } => name(children, other),
}
}
}
let Pairing::Both { lhs, rhs } = sides else {
return;
};
let ids = |source: &Source| {
let mut ids = DftHashMap::default();
walk(top(source), &mut |region| {
if let Some(alignment) = region.alignment_id() {
ids.insert(alignment, region.id);
}
});
ids
};
let (lhs_ids, rhs_ids) = (ids(lhs), ids(rhs));
name(std::slice::from_mut(&mut lhs.root), &rhs_ids);
name(std::slice::from_mut(&mut rhs.root), &lhs_ids);
}

fn data(view: RegionView) -> RegionView {
view
}
Expand Down Expand Up @@ -37,7 +67,8 @@ fn first(ids: &RegionIds) -> u32 {
}

/// A cursor over `sides`, with a manifest entry naming the same sides.
fn cursor(sides: Pairing<Source>) -> Cursor {
fn cursor(mut sides: Pairing<Source>) -> Cursor {
name_pairs(&mut sides);
let file = match &sides {
Pairing::Both { .. } => Pairing::Both {
lhs: file_ref(),
Expand Down
39 changes: 11 additions & 28 deletions diffr/crates/diffr-core/src/present.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! What a diff looks like once the plugins have shaped it: the changed
//! lines that stay visible.
use crate::hash::DftHashSet;
use crate::pairing::Pairing;
use crate::protocol::{Diff, LineRange, Node, Region, Source, StructuralChanges, Visibility};

Expand Down Expand Up @@ -48,33 +47,18 @@ struct ChangeCoverage {
}

fn change_coverage(sides: &Pairing<Source>) -> ChangeCoverage {
fn alignments(regions: &[Region], out: &mut DftHashSet<u32>) {
for region in regions {
match &region.node {
Node::Leaf { alignment_id, .. } => {
out.insert(*alignment_id);
}
Node::Fold { children, .. } => alignments(children, out),
}
}
}
fn collect(
regions: &[Region],
other: &DftHashSet<u32>,
hidden: bool,
all: &mut Vec<LineRange>,
visible: &mut Vec<LineRange>,
) {
for region in regions {
let hidden = hidden || region.visibility.collapsed;
match &region.node {
Node::Leaf {
alignment_id,
changed,
..
} => {
Node::Leaf { pair, changed, .. } => {
let start = all.len();
if other.contains(alignment_id) {
if pair.is_some() {
all.extend(changed.iter().map(|span| [span.line, span.line + 1]));
} else {
let lines = region.range.lines();
Expand All @@ -84,20 +68,15 @@ fn change_coverage(sides: &Pairing<Source>) -> ChangeCoverage {
visible.extend_from_slice(&all[start..]);
}
}
Node::Fold { children, .. } => collect(children, other, hidden, all, visible),
Node::Fold { children, .. } => collect(children, hidden, all, visible),
}
}
}
fn side(source: Option<&Source>, other: Option<&Source>) -> (Vec<LineRange>, Vec<LineRange>) {
let mut paired = DftHashSet::default();
if let Some(other) = other {
alignments(std::slice::from_ref(&other.root), &mut paired);
}
fn side(source: Option<&Source>) -> (Vec<LineRange>, Vec<LineRange>) {
let (mut all, mut visible) = (Vec::new(), Vec::new());
if let Some(source) = source {
collect(
std::slice::from_ref(&source.root),
&paired,
false,
&mut all,
&mut visible,
Expand All @@ -110,8 +89,8 @@ fn change_coverage(sides: &Pairing<Source>) -> ChangeCoverage {
Pairing::LeftOnly { lhs } => (Some(lhs), None),
Pairing::RightOnly { rhs } => (None, Some(rhs)),
};
let (base, visible_base) = side(lhs, rhs);
let (head, visible_head) = side(rhs, lhs);
let (base, visible_base) = side(lhs);
let (head, visible_head) = side(rhs);
ChangeCoverage {
all: StructuralChanges { base, head },
initially_visible: StructuralChanges {
Expand Down Expand Up @@ -143,6 +122,7 @@ fn coalesce(mut ranges: Vec<LineRange>) -> Vec<LineRange> {
#[cfg(test)]
mod visible_tests {
use super::*;
use crate::plugin::cursor::tests::name_pairs;
use crate::protocol::{SourcePos, SourceRange, Span};

fn test_root(regions: Vec<Region>) -> Region {
Expand Down Expand Up @@ -243,7 +223,9 @@ mod visible_tests {
leaf(9, 9, (3, 4), &[], false),
leaf(10, 8, (4, 7), &[4, 5], true),
]);
let coverage = change_coverage(&Pairing::Both { lhs, rhs });
let mut sides = Pairing::Both { lhs, rhs };
name_pairs(&mut sides);
let coverage = change_coverage(&sides);
assert_eq!(coverage.all.head, vec![[0, 2], [4, 15]]);
assert_eq!(coverage.all.base, vec![[0, 1], [4, 7]]);
let counts = coverage.initially_visible.counts();
Expand All @@ -266,6 +248,7 @@ mod visible_tests {
)],
)]);
let mut sides = Pairing::Both { lhs, rhs };
name_pairs(&mut sides);
let hidden = change_coverage(&sides);
assert_eq!(hidden.all.head, vec![[0, 1], [2, 3]]);
assert!(hidden.all.base.is_empty()); // Added tokens do not imply removed tokens.
Expand Down
1 change: 1 addition & 0 deletions diffr/src/plugin/tests/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ fn a_fold_whose_matched_partner_holds_changes_stays_open() {
],
),
};
name_pairs(&mut sides);
let (file, _) = project("a.py", "", "");
run("context", json!({"lines": 1}), &file, &mut sides);
let collapsed = |source: &Source| {
Expand Down
2 changes: 2 additions & 0 deletions diffr/src/plugin/tests/deleted_bodies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ fn deleted_bodies_skip_folds_with_paired_content() {
lhs: source(vec![rewritten, removed]),
rhs: source(vec![leaf(5, 0, 0, 20)]),
};
name_pairs(&mut sides);
run(
"deleted-bodies",
json!({"min_lines": 3}),
Expand Down Expand Up @@ -113,6 +114,7 @@ fn a_matched_function_whose_lines_all_went_away_is_a_removal() {
lhs: source(vec![moved, kept]),
rhs: source(vec![kept_rhs, moved_rhs]),
};
name_pairs(&mut sides);
run(
"deleted-bodies",
json!({"min_lines": 3}),
Expand Down
30 changes: 30 additions & 0 deletions diffr/src/plugin/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::options::DiffOptions;
use crate::pairing::Pairing;
use crate::protocol::{self, project, Diff, FileChange, FileRef, FileStatus, Node, Region, Source};
use serde_json::json;
use std::collections::BTreeMap;
use std::num::NonZeroUsize;

/// A test side's root. Its id stays clear of the regions' ids and differs
Expand All @@ -21,6 +22,35 @@ pub(crate) fn test_root(regions: Vec<Region>) -> Region {
let id = 1000 + regions.iter().map(|region| region.id).min().unwrap_or(0);
Region::root(id, regions)
}

/// Set each leaf's `pair` from the fixture's alignment ids.
pub(crate) fn name_pairs(sides: &mut Pairing<Source>) {
fn name(regions: &mut [Region], other: &BTreeMap<u32, u32>) {
for region in regions {
match &mut region.node {
Node::Leaf {
alignment_id, pair, ..
} => *pair = other.get(alignment_id).copied(),
Node::Fold { children, .. } => name(children, other),
}
}
}
let Pairing::Both { lhs, rhs } = sides else {
return;
};
let ids = |source: &Source| {
let mut ids = BTreeMap::new();
walk(std::slice::from_ref(&source.root), &mut |region| {
if let Some(alignment) = region.alignment_id() {
ids.insert(alignment, region.id);
}
});
ids
};
let (lhs_ids, rhs_ids) = (ids(lhs), ids(rhs));
name(std::slice::from_mut(&mut lhs.root), &rhs_ids);
name(std::slice::from_mut(&mut rhs.root), &lhs_ids);
}
use std::path::Path;

pub(crate) fn walk(regions: &[Region], visit: &mut impl FnMut(&Region)) {
Expand Down
2 changes: 2 additions & 0 deletions diffr/src/plugin/tests/removed_runs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ fn removed_runs_skip_paired_leaves_and_collapsed_ancestors() {
]),
rhs: source(vec![paired_rhs]),
};
name_pairs(&mut sides);
run(
"removed-runs",
json!({"min_lines": 5}),
Expand Down Expand Up @@ -248,6 +249,7 @@ fn removed_runs_stay_open_under_a_paired_function() {
lhs: source(vec![rewritten, removed]),
rhs: source(vec![removed_leaf(6, 3, 0, 10, &[])]),
};
name_pairs(&mut sides);
run(
"removed-runs",
json!({"min_lines": 5}),
Expand Down
2 changes: 1 addition & 1 deletion diffr/src/plugin/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ impl Pipeline {
mailbox.send(job).await.map_err(|_| trapped())?;
}
let cursor = result.await.map_err(|_| trapped())??;
Ok(cursor.sides)
Ok(cursor.into_sides())
}

/// Give the file to the least-loaded worker whose mailbox has room. When
Expand Down
Loading