Skip to main content

graphs_tui/
types.rs

1use std::collections::HashMap;
2use std::fmt;
3
4/// Node identifier type
5pub type NodeId = String;
6
7/// Flow direction for the diagram
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum Direction {
10    /// Left to Right
11    LR,
12    /// Right to Left
13    RL,
14    /// Top to Bottom
15    TB,
16    /// Bottom to Top
17    BT,
18}
19
20impl Direction {
21    /// Parse direction from string
22    pub fn parse(s: &str) -> Option<Direction> {
23        match s.to_uppercase().as_str() {
24            "LR" => Some(Direction::LR),
25            "RL" => Some(Direction::RL),
26            "TB" | "TD" => Some(Direction::TB),
27            "BT" => Some(Direction::BT),
28            _ => None,
29        }
30    }
31
32    /// Check if direction is horizontal (LR or RL)
33    pub fn is_horizontal(&self) -> bool {
34        matches!(self, Direction::LR | Direction::RL)
35    }
36}
37
38/// Shape of a node
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
40pub enum NodeShape {
41    /// Rectangle [Label]
42    #[default]
43    Rectangle,
44    /// Rounded rectangle (Label)
45    Rounded,
46    /// Circle ((Label))
47    Circle,
48    /// Diamond/rhombus {Label}
49    Diamond,
50    /// Cylinder/database [(Label)]
51    Cylinder,
52    /// Stadium shape ([Label])
53    Stadium,
54    /// Subroutine [[Label]]
55    Subroutine,
56    /// Hexagon {{Label}}
57    Hexagon,
58    /// Parallelogram [/Label/]
59    Parallelogram,
60    /// Reverse Parallelogram [\Label\]
61    ParallelogramAlt,
62    /// Trapezoid [/Label\]
63    Trapezoid,
64    /// Reverse Trapezoid [\Label/]
65    TrapezoidAlt,
66    /// Table (D2 sql_table)
67    Table,
68}
69
70/// Style of an edge/link
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
72pub enum EdgeStyle {
73    /// Solid arrow -->
74    #[default]
75    Arrow,
76    /// Solid line ---
77    Line,
78    /// Dotted arrow -.->
79    DottedArrow,
80    /// Dotted line -.-
81    DottedLine,
82    /// Thick arrow ==>
83    ThickArrow,
84    /// Thick line ===
85    ThickLine,
86}
87
88/// A subgraph/group of nodes
89#[derive(Debug, Clone)]
90pub struct Subgraph {
91    pub id: String,
92    pub label: String,
93    pub nodes: Vec<NodeId>,
94    pub x: usize,
95    pub y: usize,
96    pub width: usize,
97    pub height: usize,
98}
99
100impl Subgraph {
101    pub fn new(id: String, label: String) -> Self {
102        Self {
103            id,
104            label,
105            nodes: Vec::new(),
106            x: 0,
107            y: 0,
108            width: 0,
109            height: 0,
110        }
111    }
112}
113
114/// A node in the flowchart
115#[derive(Debug, Clone)]
116pub struct Node {
117    pub id: NodeId,
118    pub label: String,
119    pub shape: NodeShape,
120    pub subgraph: Option<String>,
121    pub width: usize,
122    pub height: usize,
123    pub x: usize,
124    pub y: usize,
125}
126
127impl Node {
128    /// Create a new node with given id and label
129    pub fn new(id: NodeId, label: String) -> Self {
130        Self {
131            id,
132            label,
133            shape: NodeShape::default(),
134            subgraph: None,
135            width: 0,
136            height: 0,
137            x: 0,
138            y: 0,
139        }
140    }
141
142    /// Create a new node with shape
143    pub fn with_shape(id: NodeId, label: String, shape: NodeShape) -> Self {
144        Self {
145            id,
146            label,
147            shape,
148            subgraph: None,
149            width: 0,
150            height: 0,
151            x: 0,
152            y: 0,
153        }
154    }
155}
156
157/// An edge connecting two nodes
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct Edge {
160    pub from: NodeId,
161    pub to: NodeId,
162    pub label: Option<String>,
163    pub style: EdgeStyle,
164}
165
166/// The complete graph structure
167#[derive(Debug, Clone)]
168pub struct Graph {
169    pub direction: Direction,
170    pub nodes: HashMap<NodeId, Node>,
171    pub edges: Vec<Edge>,
172    pub subgraphs: Vec<Subgraph>,
173}
174
175impl Graph {
176    /// Create a new empty graph with given direction
177    pub fn new(direction: Direction) -> Self {
178        Self {
179            direction,
180            nodes: HashMap::new(),
181            edges: Vec::new(),
182            subgraphs: Vec::new(),
183        }
184    }
185}
186
187/// Options for rendering the diagram
188#[derive(Debug, Clone, Default)]
189pub struct RenderOptions {
190    /// Use ASCII characters instead of Unicode
191    pub ascii: bool,
192    /// Maximum width (not yet implemented)
193    pub max_width: Option<usize>,
194}
195
196/// Structured warning emitted during layout or rendering
197#[derive(Debug, Clone, PartialEq, Eq)]
198pub enum DiagramWarning {
199    /// A cycle was detected involving the listed nodes
200    CycleDetected { nodes: Vec<String> },
201    /// An edge label was too long to render inline and was moved to a legend
202    LabelDropped {
203        marker: String,
204        edge_from: String,
205        edge_to: String,
206        label: String,
207    },
208}
209
210impl fmt::Display for DiagramWarning {
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        match self {
213            DiagramWarning::CycleDetected { nodes } => {
214                write!(f, "Cycle detected involving nodes: {}", nodes.join(", "))
215            }
216            DiagramWarning::LabelDropped {
217                marker,
218                edge_from,
219                edge_to,
220                label,
221            } => {
222                write!(
223                    f,
224                    "Label '{}' on edge {} -> {} moved to legend as {}",
225                    label, edge_from, edge_to, marker
226                )
227            }
228        }
229    }
230}
231
232/// Result of rendering a diagram
233#[derive(Debug, Clone, PartialEq, Eq)]
234pub struct RenderResult {
235    /// The rendered diagram output
236    pub output: String,
237    /// Warnings generated during layout/rendering
238    pub warnings: Vec<DiagramWarning>,
239}