Skip to main content

rich_ext/diff/
mod.rs

1//! Diffs: an engine, terminal views and the inputs they read.
2//!
3//! - [`engine`]: Myers' O(ND) diff in linear space over any hashable
4//!   elements ([`diff_lines`], [`diff_slices`]), word and character diffs for
5//!   intra-line emphasis ([`diff_words`], [`diff_chars`]), [`Hunk`] grouping
6//!   and [`TextDiff`], whose [`unified`](TextDiff::unified) output matches
7//!   `diff -u` minus timestamps.
8//! - [`DiffView`]: a renderable diff, unified or side by side, of plain text,
9//!   ANSI text ([`DiffView::ansi`], which also reports style-only changes) or,
10//!   with the `testing` feature, render snapshots.
11//! - [`SourceDiff`]: a syntax-highlighted source diff with optional line links.
12//! - [`ConflictFile`] and [`ConflictView`]: three-way merge conflicts parsed
13//!   from the markers a merge leaves (diff3's base included) and shown ours,
14//!   base and theirs side by side or stacked.
15//! - [`git`]: a `git diff` parser and [`PatchView`](git::PatchView), a
16//!   review-style renderer with a file tree, annotations and links.
17//! - `test_report` (feature `test-report`): JUnit XML and libtest JSON test
18//!   results and the `TestReport` renderable.
19//! - `assert_rich_eq!` and friends (feature `testing`): assertions that
20//!   panic with a rendered diff.
21//!
22//! With colour off every change stays visible: `-`, `+` and `~` (style only)
23//! markers lead each changed line.
24
25mod conflict;
26pub mod engine;
27pub mod git;
28mod render;
29mod source;
30pub mod transform;
31mod view;
32
33#[cfg(feature = "testing")]
34pub mod assert;
35#[cfg(feature = "test-report")]
36pub mod test_report;
37
38pub use conflict::{
39    Conflict, ConflictError, ConflictFile, ConflictLayout, ConflictSide, ConflictView, Pick,
40    MAX_CONFLICTS, MAX_CONFLICT_SOURCE,
41};
42pub use engine::{
43    diff_chars, diff_lines, diff_slices, diff_words, group_hunks, hunk_header, tokenize, Hunk, Op,
44    TextDiff,
45};
46pub use source::SourceDiff;
47pub use view::{DiffView, Side};
48
49use rich::{Console, Style};
50
51/// The default styles for diff and test-report keys. [`extended_theme`]
52/// includes them; renderers fall back to them when a theme lacks a key.
53///
54/// [`extended_theme`]: crate::theme::extended_theme
55pub const STYLES: &[(&str, &str)] = &[
56    ("diff.added", "green"),
57    ("diff.removed", "red"),
58    ("diff.added.emphasis", "bold underline green"),
59    ("diff.removed.emphasis", "bold underline red"),
60    ("diff.hunk", "cyan"),
61    ("diff.header", "bold"),
62    ("diff.line_number", "dim"),
63    ("diff.context", "none"),
64    ("diff.conflict.ours", "green"),
65    ("diff.conflict.base", "yellow"),
66    ("diff.conflict.theirs", "blue"),
67    ("diff.conflict.label", "bold"),
68    ("test.passed", "green"),
69    ("test.failed", "bold red"),
70    ("test.errored", "bold magenta"),
71    ("test.skipped", "yellow"),
72];
73
74/// The console theme's style for `key`, else its default from [`STYLES`].
75pub(crate) fn style(console: &Console, key: &str) -> Style {
76    let fallback = STYLES
77        .iter()
78        .find(|(name, _)| *name == key)
79        .map_or("none", |(_, spec)| spec);
80    crate::event::theme_style(console, key, fallback)
81}
82
83/// How a diff is laid out.
84#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
85pub enum Layout {
86    /// One column, removed lines before added ones (the default).
87    #[default]
88    Unified,
89    /// Old on the left, new on the right, each half the width.
90    SideBySide,
91}