ratatui_toolkit/widgets/code_diff/extensions/file_tree/mod.rs
1//! Diff file tree widget for displaying changed files.
2//!
3//! A tree view widget for displaying changed files in a diff, similar to
4//! gitui's unstaged changes panel or VS Code's source control view.
5//!
6//! This implementation wraps the generic TreeView component for simplified code.
7//!
8//! # Features
9//!
10//! - **Hierarchical display**: Groups files by directory structure
11//! - **Status markers**: Visual indicators for file status (M, +, -, R)
12//! - **Collapsible directories**: Expand/collapse with keyboard
13//! - **Color coding**: Green (added), yellow (modified), red (deleted), blue (renamed)
14//! - **Keyboard navigation**: Uses TreeView's navigation
15//!
16//! # Structure
17//!
18//! - [`DiffFileTree`] - The main tree widget (wraps TreeView)
19//! - [`DiffFileEntry`] - Data type for tree nodes (path + status)
20//! - [`FileStatus`] - File modification status enum
21//!
22//! # Example
23//!
24//! ```rust
25//! use ratatui_toolkit::widgets::code_diff::diff_file_tree::{DiffFileTree, FileStatus};
26//!
27//! let files = vec![
28//! ("src/lib.rs", FileStatus::Modified),
29//! ("src/utils/helper.rs", FileStatus::Added),
30//! ("src/old_module.rs", FileStatus::Deleted),
31//! ];
32//!
33//! let tree = DiffFileTree::from_paths(&files);
34//!
35//! // Render with ratatui Widget trait...
36//! // frame.render_widget(&tree, area);
37//! ```
38//!
39//! # Visual Style
40//!
41//! ```text
42//! M src/
43//! lib.rs
44//! + utils/
45//! + helper.rs
46//! - old_module.rs
47//! ```
48
49pub mod constructors;
50pub mod helpers;
51pub mod methods;
52pub mod traits;
53
54pub use helpers::file_icon;
55
56use crate::primitives::tree_view::{TreeNode, TreeViewState};
57use crate::services::theme::AppTheme;
58use ratatui::style::Color;
59
60/// The modification status of a file in a diff.
61///
62/// Each status has an associated color and prefix character
63/// for display in the file tree.
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
65pub enum FileStatus {
66 /// File was added (new file).
67 Added,
68 /// File was modified (existing file changed).
69 #[default]
70 Modified,
71 /// File was deleted.
72 Deleted,
73 /// File was renamed.
74 Renamed,
75}
76
77impl FileStatus {
78 /// Returns the prefix character for this status.
79 #[must_use]
80 pub fn prefix(&self) -> &'static str {
81 match self {
82 Self::Added => "+",
83 Self::Modified => "M",
84 Self::Deleted => "-",
85 Self::Renamed => "R",
86 }
87 }
88
89 /// Returns the color associated with this status.
90 #[must_use]
91 pub fn color(&self) -> Color {
92 match self {
93 Self::Added => Color::Green,
94 Self::Modified => Color::Yellow,
95 Self::Deleted => Color::Red,
96 Self::Renamed => Color::Blue,
97 }
98 }
99}
100
101/// A single file or directory entry in a diff tree.
102///
103/// This is the data type stored in each [`TreeNode`](crate::primitives::tree_view::TreeNode).
104#[derive(Debug, Clone, PartialEq, Eq)]
105pub struct DiffFileEntry {
106 /// The display name (filename or directory name).
107 pub name: String,
108 /// The full path to this file/directory.
109 pub full_path: String,
110 /// Whether this entry is a directory.
111 pub is_dir: bool,
112 /// The modification status (None for directories).
113 pub status: Option<FileStatus>,
114}
115
116impl DiffFileEntry {
117 /// Creates a new file entry.
118 #[must_use]
119 pub fn file(name: &str, full_path: &str, status: FileStatus) -> Self {
120 Self {
121 name: name.to_string(),
122 full_path: full_path.to_string(),
123 is_dir: false,
124 status: Some(status),
125 }
126 }
127
128 /// Creates a new directory entry.
129 #[must_use]
130 pub fn directory(name: &str, full_path: &str) -> Self {
131 Self {
132 name: name.to_string(),
133 full_path: full_path.to_string(),
134 is_dir: true,
135 status: None,
136 }
137 }
138}
139
140/// A tree widget for displaying changed files in a diff.
141///
142/// Renders a hierarchical view of files with their modification status,
143/// similar to gitui's file tree in the changes panel.
144///
145/// This is a wrapper around [`TreeView`](crate::primitives::tree_view::TreeView) that
146/// provides a specialized API for diff file trees.
147#[derive(Debug, Clone)]
148pub struct DiffFileTree {
149 /// The tree nodes containing diff file entries.
150 pub nodes: Vec<TreeNode<DiffFileEntry>>,
151 /// State for selection and expansion (managed by TreeView).
152 pub state: TreeViewState,
153 /// Currently selected visible row index.
154 pub selected_index: usize,
155 /// Whether this widget currently has focus.
156 pub focused: bool,
157 /// Application theme for styling.
158 pub theme: AppTheme,
159}