Render a multi-line text diff with context trimming. When inline highlighting is enabled, changed words within changed lines are reverse-video'd (delta-style), making it obvious *what* in the line changed — particularly useful for store-path hash changes.
(&self, output: &mut Vec<u8>, old: &[u8], new: &[u8], indent: usize)
| 485 | /// reverse-video'd (delta-style), making it obvious *what* in the line |
| 486 | /// changed — particularly useful for store-path hash changes. |
| 487 | fn format_text_diff(&self, output: &mut Vec<u8>, old: &[u8], new: &[u8], indent: usize) { |
| 488 | let diff = SimilarTextDiff::from_lines(old, new); |
| 489 | |
| 490 | for (idx, group) in diff.grouped_ops(self.context_lines).iter().enumerate() { |
| 491 | if idx > 0 { |
| 492 | self.write_indent(output, indent); |
| 493 | extend!(output, b"...\n"); |
| 494 | } |
| 495 | for op in group { |
| 496 | if self.inline_highlight { |
| 497 | for change in diff.iter_inline_changes(op) { |
| 498 | let (color, sign): (&[u8], &[u8]) = match change.tag() { |
| 499 | ChangeTag::Delete => (self.red(), b"- "), |
| 500 | ChangeTag::Insert => (self.green(), b"+ "), |
| 501 | ChangeTag::Equal => (b"", b" "), |
| 502 | }; |
| 503 | self.write_indent(output, indent); |
| 504 | extend!(output, color, sign); |
| 505 | for (emphasized, value) in change.iter_strings_lossy() { |
| 506 | let bytes = value.as_bytes(); |
| 507 | // Strip trailing newline so reset comes before \n |
| 508 | // (avoids color bleed in some pagers). |
| 509 | let body = bytes.strip_suffix(b"\n").unwrap_or(bytes); |
| 510 | if emphasized { |
| 511 | extend!(output, REVERSE, body, NOREVERSE); |
| 512 | } else { |
| 513 | output.extend_from_slice(body); |
| 514 | } |
| 515 | } |
| 516 | extend!(output, self.reset(), b"\n"); |
| 517 | } |
| 518 | } else { |
| 519 | for change in diff.iter_changes(op) { |
| 520 | let (color, sign): (&[u8], &[u8]) = match change.tag() { |
| 521 | ChangeTag::Delete => (self.red(), b"- "), |
| 522 | ChangeTag::Insert => (self.green(), b"+ "), |
| 523 | ChangeTag::Equal => (b"", b" "), |
| 524 | }; |
| 525 | self.write_indent(output, indent); |
| 526 | let val = change.value(); |
| 527 | let body = val.strip_suffix(b"\n").unwrap_or(val); |
| 528 | extend!(output, color, sign, body, self.reset(), b"\n"); |
| 529 | } |
| 530 | } |
| 531 | } |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | /// Write a list of store paths, truncating to `input_list_limit` entries |
| 536 | /// and summarizing the remainder. Large add/remove lists (e.g., after a |