tui_dispatch_core/debug/
table.rs

1//! Debug table types and builder
2//!
3//! Provides a builder pattern for constructing debug information tables
4//! with sections and key-value entries.
5
6use super::cell::CellPreview;
7
8/// A row in a debug table - either a section header or a key-value entry
9#[derive(Debug, Clone)]
10pub enum DebugTableRow {
11    /// Section header (e.g., "Connection", "Keys", "UI")
12    Section(String),
13    /// Key-value entry (e.g., "host" -> "localhost")
14    Entry { key: String, value: String },
15}
16
17/// A debug table overlay with title, rows, and optional cell preview
18#[derive(Debug, Clone)]
19pub struct DebugTableOverlay {
20    /// Title displayed at the top of the overlay
21    pub title: String,
22    /// Table rows (sections and entries)
23    pub rows: Vec<DebugTableRow>,
24    /// Optional cell preview for inspect overlays
25    pub cell_preview: Option<CellPreview>,
26}
27
28impl DebugTableOverlay {
29    /// Create a new overlay with the given title and rows
30    pub fn new(title: impl Into<String>, rows: Vec<DebugTableRow>) -> Self {
31        Self {
32            title: title.into(),
33            rows,
34            cell_preview: None,
35        }
36    }
37
38    /// Create a new overlay with cell preview
39    pub fn with_cell_preview(
40        title: impl Into<String>,
41        rows: Vec<DebugTableRow>,
42        preview: CellPreview,
43    ) -> Self {
44        Self {
45            title: title.into(),
46            rows,
47            cell_preview: Some(preview),
48        }
49    }
50}
51
52/// Type of debug overlay
53#[derive(Debug, Clone)]
54pub enum DebugOverlay {
55    /// Inspect overlay - shows info about a specific position/cell
56    Inspect(DebugTableOverlay),
57    /// State overlay - shows full application state
58    State(DebugTableOverlay),
59}
60
61impl DebugOverlay {
62    /// Get the underlying table from the overlay
63    pub fn table(&self) -> &DebugTableOverlay {
64        match self {
65            DebugOverlay::Inspect(table) | DebugOverlay::State(table) => table,
66        }
67    }
68
69    /// Get the overlay kind as a string
70    pub fn kind(&self) -> &'static str {
71        match self {
72            DebugOverlay::Inspect(_) => "inspect",
73            DebugOverlay::State(_) => "state",
74        }
75    }
76}
77
78/// Builder for constructing debug tables
79///
80/// # Example
81///
82/// ```
83/// use tui_dispatch_core::debug::{DebugTableBuilder, DebugTableRow};
84///
85/// let table = DebugTableBuilder::new()
86///     .section("Connection")
87///     .entry("host", "localhost")
88///     .entry("port", "6379")
89///     .section("Status")
90///     .entry("connected", "true")
91///     .finish("Connection Info");
92///
93/// assert_eq!(table.title, "Connection Info");
94/// assert_eq!(table.rows.len(), 5);
95/// ```
96#[derive(Debug, Default)]
97pub struct DebugTableBuilder {
98    rows: Vec<DebugTableRow>,
99    cell_preview: Option<CellPreview>,
100}
101
102impl DebugTableBuilder {
103    /// Create a new empty builder
104    pub fn new() -> Self {
105        Self::default()
106    }
107
108    /// Add a section header
109    pub fn section(mut self, title: impl Into<String>) -> Self {
110        self.rows.push(DebugTableRow::Section(title.into()));
111        self
112    }
113
114    /// Add a key-value entry
115    pub fn entry(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
116        self.rows.push(DebugTableRow::Entry {
117            key: key.into(),
118            value: value.into(),
119        });
120        self
121    }
122
123    /// Add a section header (mutable reference version)
124    pub fn push_section(&mut self, title: impl Into<String>) {
125        self.rows.push(DebugTableRow::Section(title.into()));
126    }
127
128    /// Add a key-value entry (mutable reference version)
129    pub fn push_entry(&mut self, key: impl Into<String>, value: impl Into<String>) {
130        self.rows.push(DebugTableRow::Entry {
131            key: key.into(),
132            value: value.into(),
133        });
134    }
135
136    /// Set the cell preview for inspect overlays
137    pub fn cell_preview(mut self, preview: CellPreview) -> Self {
138        self.cell_preview = Some(preview);
139        self
140    }
141
142    /// Set the cell preview (mutable reference version)
143    pub fn set_cell_preview(&mut self, preview: CellPreview) {
144        self.cell_preview = Some(preview);
145    }
146
147    /// Build the final table overlay with the given title
148    pub fn finish(self, title: impl Into<String>) -> DebugTableOverlay {
149        DebugTableOverlay {
150            title: title.into(),
151            rows: self.rows,
152            cell_preview: self.cell_preview,
153        }
154    }
155
156    /// Build as an inspect overlay
157    pub fn finish_inspect(self, title: impl Into<String>) -> DebugOverlay {
158        DebugOverlay::Inspect(self.finish(title))
159    }
160
161    /// Build as a state overlay
162    pub fn finish_state(self, title: impl Into<String>) -> DebugOverlay {
163        DebugOverlay::State(self.finish(title))
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn test_builder_basic() {
173        let table = DebugTableBuilder::new()
174            .section("Test")
175            .entry("key1", "value1")
176            .entry("key2", "value2")
177            .finish("Test Table");
178
179        assert_eq!(table.title, "Test Table");
180        assert_eq!(table.rows.len(), 3);
181        assert!(table.cell_preview.is_none());
182    }
183
184    #[test]
185    fn test_builder_multiple_sections() {
186        let table = DebugTableBuilder::new()
187            .section("Section 1")
188            .entry("a", "1")
189            .section("Section 2")
190            .entry("b", "2")
191            .finish("Multi-Section");
192
193        assert_eq!(table.rows.len(), 4);
194
195        match &table.rows[0] {
196            DebugTableRow::Section(s) => assert_eq!(s, "Section 1"),
197            _ => panic!("Expected section"),
198        }
199        match &table.rows[2] {
200            DebugTableRow::Section(s) => assert_eq!(s, "Section 2"),
201            _ => panic!("Expected section"),
202        }
203    }
204
205    #[test]
206    fn test_overlay_kinds() {
207        let table = DebugTableBuilder::new().finish("Test");
208
209        let inspect = DebugOverlay::Inspect(table.clone());
210        assert_eq!(inspect.kind(), "inspect");
211
212        let state = DebugOverlay::State(table);
213        assert_eq!(state.kind(), "state");
214    }
215}