ratatui_toolkit/widgets/code_diff/widget/mod.rs
1//! Code diff widget for displaying side-by-side diffs.
2//!
3//! The main widget that renders diff hunks in a side-by-side or unified view,
4//! similar to VS Code's diff viewer. Optionally includes an integrated file
5//! tree sidebar for multi-file diffs.
6//!
7//! # Structure
8//!
9//! - [`CodeDiff`] - The main diff widget struct
10//! - [`constructors`] - Constructor functions (`new`, `from_unified_diff`, `from_multi_file_diff`)
11//! - [`methods`] - Instance methods for configuration and data access
12//! - [`traits`] - Trait implementations (`Widget`, `Default`)
13//!
14//! # Example
15//!
16//! ```rust
17//! use ratatui_toolkit::code_diff::CodeDiff;
18//!
19//! let diff_text = r#"
20//! --- a/file.txt
21//! +++ b/file.txt
22//! @@ -1,4 +1,5 @@
23//! context line
24//! -removed line
25//! +added line
26//! more context
27//! "#;
28//!
29//! let widget = CodeDiff::from_unified_diff(diff_text);
30//! ```
31//!
32//! # Multi-file diff with sidebar
33//!
34//! ```rust
35//! use ratatui_toolkit::code_diff::{CodeDiff, DiffConfig};
36//! use ratatui_toolkit::widgets::code_diff::diff_file_tree::FileStatus;
37//!
38//! let diff = CodeDiff::new()
39//! .with_config(DiffConfig::new().sidebar_enabled(true))
40//! .with_file("src/lib.rs", FileStatus::Modified, "--- a/src/lib.rs\n+++ b/src/lib.rs\n...")
41//! .with_file("src/new.rs", FileStatus::Added, "--- /dev/null\n+++ b/src/new.rs\n...");
42//! ```
43
44pub mod constructors;
45pub mod methods;
46pub mod traits;
47
48use std::collections::HashMap;
49
50use crate::primitives::resizable_split::ResizableSplit;
51use crate::services::theme::AppTheme;
52use crate::widgets::code_diff::diff_config::DiffConfig;
53use crate::widgets::code_diff::diff_file_tree::DiffFileTree;
54use crate::widgets::code_diff::diff_hunk::DiffHunk;
55
56/// A widget for displaying code diffs in a terminal UI.
57///
58/// `CodeDiff` renders diff hunks in a side-by-side format (like VS Code) or
59/// unified format, with support for syntax highlighting, line numbers, and
60/// visual markers for added/removed lines.
61///
62/// # Layout
63///
64/// In side-by-side mode:
65/// - Left panel shows the old/original version
66/// - Right panel shows the new/modified version
67/// - Lines are aligned horizontally for easy comparison
68/// - Empty spaces fill gaps where lines were added/removed
69///
70/// When sidebar is enabled:
71/// - Left panel shows file tree with status markers
72/// - Right panel shows the diff for the selected file
73/// - `[` key toggles sidebar visibility
74/// - `h/l` keys switch focus between sidebar and diff
75///
76/// # Visual Elements
77///
78/// - Green background for added lines (+)
79/// - Red background for removed lines (-)
80/// - Gray header bars for hunk information
81/// - Line numbers on each side
82///
83/// # Fields
84///
85/// * `file_path` - Optional path to the file being diffed (for single-file mode)
86/// * `hunks` - Collection of diff hunks to display (for single-file mode)
87/// * `config` - Display configuration (colors, style, sidebar options)
88/// * `scroll_offset` - Current vertical scroll position
89/// * `file_tree` - Internal file tree widget for sidebar
90/// * `file_diffs` - Map of file paths to their diff hunks (for multi-file mode)
91/// * `show_sidebar` - Whether sidebar is currently visible
92/// * `sidebar_split` - Resizable split for sidebar/diff area division with mouse drag support
93/// * `sidebar_focused` - Whether sidebar has focus (vs diff view)
94#[derive(Debug, Clone)]
95pub struct CodeDiff {
96 /// Optional path to the file being diffed (single-file mode).
97 pub file_path: Option<String>,
98
99 /// The diff hunks to display (single-file mode).
100 pub hunks: Vec<DiffHunk>,
101
102 /// Display configuration.
103 pub config: DiffConfig,
104
105 /// Current vertical scroll offset.
106 pub scroll_offset: usize,
107
108 /// Internal file tree widget for sidebar.
109 pub file_tree: DiffFileTree,
110
111 /// Map of file paths to their diff hunks (multi-file mode).
112 pub file_diffs: HashMap<String, Vec<DiffHunk>>,
113
114 /// Whether the sidebar is currently visible.
115 pub show_sidebar: bool,
116
117 /// Resizable split for sidebar/diff area division with mouse drag support.
118 pub sidebar_split: ResizableSplit,
119
120 /// Whether the sidebar has focus (vs diff view).
121 pub sidebar_focused: bool,
122
123 /// Application theme for styling.
124 pub theme: AppTheme,
125}