sql_cli/debug/
debug_trace.rs

1use std::fmt;
2
3/// A section of debug information with a title and content
4#[derive(Debug, Clone)]
5pub struct DebugSection {
6    /// The title of this debug section (e.g., "VIEWPORT STATE", "DATAVIEW STATE")
7    pub title: String,
8    /// The content of this debug section
9    pub content: String,
10    /// Priority for ordering (lower values appear first)
11    pub priority: u32,
12}
13
14impl DebugSection {
15    /// Create a new debug section
16    pub fn new(title: impl Into<String>, content: impl Into<String>, priority: u32) -> Self {
17        Self {
18            title: title.into(),
19            content: content.into(),
20            priority,
21        }
22    }
23
24    /// Create a section with a formatted title
25    pub fn with_header(
26        title: impl Into<String>,
27        content: impl Into<String>,
28        priority: u32,
29    ) -> Self {
30        let title_str = title.into();
31        let header = format!("\n========== {title_str} ==========\n");
32        Self {
33            title: title_str,
34            content: format!("{}{}", header, content.into()),
35            priority,
36        }
37    }
38}
39
40impl fmt::Display for DebugSection {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(f, "{}", self.content)
43    }
44}
45
46/// Trait for components that can provide debug information
47pub trait DebugTrace: Send + Sync {
48    /// Get the name of this debug provider
49    fn name(&self) -> &str;
50
51    /// Generate debug sections for the current state
52    /// Returns a vector of debug sections that can be displayed
53    fn debug_sections(&self) -> Vec<DebugSection>;
54
55    /// Optional method to get a quick summary (one-liner)
56    fn debug_summary(&self) -> Option<String> {
57        None
58    }
59
60    /// Check if this provider is currently active/relevant
61    fn is_active(&self) -> bool {
62        true
63    }
64}
65
66/// Priority constants for standard sections
67pub mod Priority {
68    pub const PARSER: u32 = 100;
69    pub const BUFFER: u32 = 200;
70    pub const RESULTS: u32 = 300;
71    pub const DATATABLE: u32 = 400;
72    pub const DATAVIEW: u32 = 500;
73    pub const VIEWPORT: u32 = 600;
74    pub const MEMORY: u32 = 700;
75    pub const NAVIGATION: u32 = 800;
76    pub const RENDER: u32 = 900;
77    pub const TRACE: u32 = 1000;
78    pub const STATE_LOGS: u32 = 1100;
79}
80
81/// Helper builder for creating debug sections
82pub struct DebugSectionBuilder {
83    sections: Vec<DebugSection>,
84}
85
86impl DebugSectionBuilder {
87    #[must_use]
88    pub fn new() -> Self {
89        Self {
90            sections: Vec::new(),
91        }
92    }
93
94    pub fn add_section(
95        &mut self,
96        title: impl Into<String>,
97        content: impl Into<String>,
98        priority: u32,
99    ) -> &mut Self {
100        self.sections
101            .push(DebugSection::with_header(title, content, priority));
102        self
103    }
104
105    pub fn add_raw(&mut self, section: DebugSection) -> &mut Self {
106        self.sections.push(section);
107        self
108    }
109
110    pub fn add_field(&mut self, name: &str, value: impl fmt::Display) -> &mut Self {
111        if let Some(last) = self.sections.last_mut() {
112            last.content.push_str(&format!("{name}: {value}\n"));
113        }
114        self
115    }
116
117    pub fn add_line(&mut self, line: impl Into<String>) -> &mut Self {
118        if let Some(last) = self.sections.last_mut() {
119            last.content.push_str(&format!("{}\n", line.into()));
120        }
121        self
122    }
123
124    #[must_use]
125    pub fn build(self) -> Vec<DebugSection> {
126        self.sections
127    }
128}
129
130impl Default for DebugSectionBuilder {
131    fn default() -> Self {
132        Self::new()
133    }
134}