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}