Skip to content
Closed
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
Fixed an issue with inline display where unchanged lines between two
nearby changes were not shown.

Fixed difft panicking when the process reading its output exits early
(e.g. `difft | head`, or quitting `less`), on platforms without
SIGPIPE such as Windows.

## 0.71 (released 18th September 2026)

### Diffing
Expand Down
33 changes: 21 additions & 12 deletions src/display/inline.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Inline, or "unified" diff display.

use std::io::{self, Write};

use crate::constants::Side;
use crate::display::context::{
calculate_after_context, calculate_before_context, opposite_positions,
Expand All @@ -21,7 +23,8 @@ pub(crate) fn print(
display_path: &str,
extra_info: &Option<String>,
file_format: &FileFormat,
) {
out: &mut impl Write,
) -> io::Result<()> {
let (lhs_colored_lines, rhs_colored_lines) = if display_options.use_color {
(
apply_colors(
Expand Down Expand Up @@ -71,7 +74,8 @@ pub(crate) fn print(
let rhs_line_nums_width = format_line_num(rhs_max_line).len();

for (i, hunk) in hunks.iter().enumerate() {
println!(
writeln!(
out,
"{}",
style::header(
display_path,
Expand All @@ -81,7 +85,7 @@ pub(crate) fn print(
file_format,
display_options
)
);
)?;

let hunk_lines = extract_lines(hunk);

Expand All @@ -102,7 +106,8 @@ pub(crate) fn print(

for (lhs_line, _) in before_lines {
if let Some(lhs_line) = lhs_line {
print!(
write!(
out,
"{} {}",
apply_line_number_color(
&format_line_num_padded(lhs_line, lhs_line_nums_width),
Expand All @@ -111,14 +116,15 @@ pub(crate) fn print(
display_options,
),
lhs_colored_lines[lhs_line.as_usize()]
);
)?;
}
}

for (lhs_line, _) in &hunk_lines {
if let Some(lhs_line) = lhs_line {
let is_novel = hunk.novel_lhs.contains(lhs_line);
print!(
write!(
out,
"{} {}",
apply_line_number_color(
&format_line_num_padded(*lhs_line, lhs_line_nums_width),
Expand All @@ -127,13 +133,14 @@ pub(crate) fn print(
display_options,
),
lhs_colored_lines[lhs_line.as_usize()]
);
)?;
}
}
for (_, rhs_line) in &hunk_lines {
if let Some(rhs_line) = rhs_line {
let is_novel = hunk.novel_rhs.contains(rhs_line);
print!(
write!(
out,
" {}{}",
apply_line_number_color(
&format_line_num_padded(*rhs_line, rhs_line_nums_width),
Expand All @@ -142,13 +149,14 @@ pub(crate) fn print(
display_options,
),
rhs_colored_lines[rhs_line.as_usize()]
);
)?;
}
}

for (_, rhs_line) in &after_lines {
if let Some(rhs_line) = rhs_line {
print!(
write!(
out,
" {}{}",
apply_line_number_color(
&format_line_num_padded(*rhs_line, rhs_line_nums_width),
Expand All @@ -157,9 +165,10 @@ pub(crate) fn print(
display_options,
),
rhs_colored_lines[rhs_line.as_usize()]
);
)?;
}
}
println!();
writeln!(out)?;
}
Ok(())
}
17 changes: 12 additions & 5 deletions src/display/json.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::BTreeMap;
use std::io::{self, Write};

use line_numbers::LineNumber;
use serde::ser::SerializeStruct;
Expand Down Expand Up @@ -293,21 +294,27 @@ impl Highlight {
}
}

pub(crate) fn print_directory(diffs: Vec<DiffResult>, print_unchanged: bool) {
pub(crate) fn print_directory(
diffs: Vec<DiffResult>,
print_unchanged: bool,
out: &mut impl Write,
) -> io::Result<()> {
let files = diffs
.iter()
.map(File::from)
.filter(|f| print_unchanged || f.status != Status::Unchanged)
.collect::<Vec<File>>();
println!(
writeln!(
out,
"{}",
serde_json::to_string(&files).expect("failed to serialize files")
);
)
}

pub(crate) fn print(diff: &DiffResult) {
pub(crate) fn print(diff: &DiffResult, out: &mut impl Write) -> io::Result<()> {
let file = File::from(diff);
println!(
writeln!(
out,
"{}",
serde_json::to_string(&file).expect("failed to serialize file")
)
Expand Down
52 changes: 32 additions & 20 deletions src/display/side_by_side.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Side-by-side (two column) display of diffs.

use std::cmp::{max, min};
use std::io::{self, Write};

use line_numbers::{LineNumber, SingleLineSpan};
use owo_colors::{OwoColorize, Style};
Expand Down Expand Up @@ -434,7 +435,8 @@ pub(crate) fn print(
rhs_src: &str,
lhs_mps: &[MatchedPos],
rhs_mps: &[MatchedPos],
) {
out: &mut impl Write,
) -> io::Result<()> {
let (lhs_content_max_width, rhs_content_max_width) = visible_content_max_display_width(
lhs_src,
rhs_src,
Expand Down Expand Up @@ -498,10 +500,10 @@ pub(crate) fn print(
Side::Right,
display_options,
) {
print!("{}", line);
write!(out, "{}", line)?;
}
println!();
return;
writeln!(out)?;
return Ok(());
}
if rhs_src.is_empty()
&& !matches!(
Expand All @@ -517,10 +519,10 @@ pub(crate) fn print(
Side::Left,
display_options,
) {
print!("{}", line);
write!(out, "{}", line)?;
}
println!();
return;
writeln!(out)?;
return Ok(());
}

// TODO: this is largely duplicating the `apply_colors` logic.
Expand Down Expand Up @@ -602,7 +604,8 @@ pub(crate) fn print(
);

for (i, hunk) in hunks.iter().enumerate() {
println!(
writeln!(
out,
"{}",
style::header(
display_path,
Expand All @@ -612,7 +615,7 @@ pub(crate) fn print(
file_format,
display_options
)
);
)?;

let (start_i, end_i) = matched_lines_indexes_for_hunk(
matched_lines_to_print,
Expand Down Expand Up @@ -665,36 +668,38 @@ pub(crate) fn print(
Some(rhs_line_num) => {
let rhs_line = &rhs_colored_lines[rhs_line_num.as_usize()];
if same_lines {
print!("{}{}", display_rhs_line_num, rhs_line);
write!(out, "{}{}", display_rhs_line_num, rhs_line)?;
} else {
print!(
write!(
out,
"{}{}{}",
display_lhs_line_num, display_rhs_line_num, rhs_line
);
)?;
}
}
None => {
// We didn't have any changed RHS lines in the
// hunk, but we had some contextual lines that
// only occurred on the LHS (e.g. extra newlines).
println!("{}{}", display_lhs_line_num, display_rhs_line_num);
writeln!(out, "{}{}", display_lhs_line_num, display_rhs_line_num)?;
}
}
} else if no_rhs_changes && !show_both {
match lhs_line_num {
Some(lhs_line_num) => {
let lhs_line = &lhs_colored_lines[lhs_line_num.as_usize()];
if same_lines {
print!("{}{}", display_lhs_line_num, lhs_line);
write!(out, "{}{}", display_lhs_line_num, lhs_line)?;
} else {
print!(
write!(
out,
"{}{}{}",
display_lhs_line_num, display_rhs_line_num, lhs_line
);
)?;
}
}
None => {
println!("{}{}", display_lhs_line_num, display_rhs_line_num);
writeln!(out, "{}{}", display_lhs_line_num, display_rhs_line_num)?;
}
}
} else {
Expand Down Expand Up @@ -769,7 +774,11 @@ pub(crate) fn print(
s
};

println!("{}{}{}{}{}", lhs_num, lhs_line, SPACER, rhs_num, rhs_line);
writeln!(
out,
"{}{}{}{}{}",
lhs_num, lhs_line, SPACER, rhs_num, rhs_line
)?;
}
}

Expand All @@ -780,8 +789,9 @@ pub(crate) fn print(
prev_rhs_line_num = *rhs_line_num;
}
}
println!();
writeln!(out)?;
}
Ok(())
}

#[cfg(test)]
Expand Down Expand Up @@ -914,6 +924,8 @@ mod tests {
"bar",
&lhs_mps,
&rhs_mps,
);
&mut Vec::new(),
)
.unwrap();
}
}
Loading
Loading