Skip to content

diff: mark every line of a change block with ! in context format - #311

Open
jayhemnani9910 wants to merge 1 commit into
uutils:mainfrom
jayhemnani9910:context-diff-change-blocks
Open

jayhemnani9910 wants to merge 1 commit into
uutils:mainfrom
jayhemnani9910:context-diff-change-blocks

Conversation

@jayhemnani9910

Copy link
Copy Markdown

In context format (-c, -C), when a block of lines is replaced by a block of a different length, only as many lines as pair up get !; the rest are shown as plain deletions or insertions. GNU diff marks every line of the block with !:

$ printf 'a\nb\nc\nd\n' > foo; printf 'a\nx\nd\n' > bar
$ diff -c foo bar
GNU diff 3.12         uutils
*** 1,4 ****          *** 1,4 ****
  a                     a
! b                   - b
! c                   ! c
  d                     d
--- 1,3 ----          --- 1,3 ----
  a                     a
! x                   ! x
  d                     d

Both versions apply with patch, but the output differs from GNU's for any change that isn't line-for-line, and tools that read context diffs see a deletion plus a change instead of one change.

make_diff now tracks each run of changed lines with no common line in between. When the run both deletes and inserts lines, all of its lines on both sides become Change. Runs that only delete or only insert keep - and +. This replaces the one-to-one pairing through expected_lines_change_idx.

New test test_change_block_lines_all_changed (2 lines replaced by 1, 1 replaced by 3) fails without the change. cargo test: 287 passed, clippy unchanged, fmt clean. On 6000 random file pairs with 0, 1 and 3 context lines, wherever uutils -U output equals GNU's (the same alignment), -C output now also equals GNU's in all 14682 cases; before, 3381 of 7373 differed.

Copilot AI balanced review requested due to automatic review settings October 22, 2026 05:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

Comment thread src/context_diff.rs
if (line_number_actual > actual_lines_count)
&& (line_number_expected > expected_lines_count)
{
if let Some(block) = block.take() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same 3 lines if let Some(block) = block.take() { block.finish(...) } appear 3 times, could be dedup, no?

Comment thread src/context_diff.rs
mismatch.expected.push(DiffLine::Context(line.to_vec()));
mismatch.actual.push(DiffLine::Context(line.to_vec()));
}
let block = block.get_or_insert_with(|| ChangeBlock::new(&mismatch));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, these 3 lines are duplicated just below
maybe a small helper on ChangeBlock?

Comment thread src/context_diff.rs
}
}

if let Some(block) = block.take() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

take() isn't needed here, block isn't used after

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants