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}