Skip to main content

microcad_lang/
tree_display.rs

1// Copyright © 2025-2026 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Display trait for tree like output
5
6/// Trait for displaying a tree
7pub trait TreeDisplay {
8    /// Write item into `f` and use `{:depth$}` syntax in front of your single line
9    /// output to get proper indention.
10    fn tree_print(&self, f: &mut std::fmt::Formatter, depth: TreeState) -> std::fmt::Result;
11
12    /// Display as tree starting at depth `0`.
13    fn display_tree(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
14        self.tree_print(
15            f,
16            TreeState {
17                depth: 0,
18                debug: false,
19            },
20        )
21    }
22
23    /// Display as tree starting at given depth in debug mode
24    fn debug_tree(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25        self.tree_print(
26            f,
27            TreeState {
28                depth: 0,
29                debug: true,
30            },
31        )
32    }
33
34    /// Display as tree starting at depth `0` into a file
35    fn write_tree(&self, f: &mut impl std::io::Write) -> std::io::Result<()> {
36        write!(
37            f,
38            "{}",
39            WriteFmt(|f| self.tree_print(
40                f,
41                TreeState {
42                    depth: 0,
43                    debug: false
44                }
45            ))
46        )
47    }
48}
49
50/// Helper to write into io from fmt writers
51struct WriteFmt<F>(pub F)
52where
53    F: Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result;
54
55impl<F> std::fmt::Display for WriteFmt<F>
56where
57    F: Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result,
58{
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        self.0(f)
61    }
62}
63
64/// Indention size
65const INDENT: usize = 2;
66
67/// Indention depth counter
68#[derive(derive_more::Deref, Clone, Copy)]
69pub struct TreeState {
70    /// Current depth.
71    #[deref]
72    pub depth: usize,
73    /// Print in debug mode
74    pub debug: bool,
75}
76
77impl TreeState {
78    /// Create new tree state for std::fmt::Display
79    pub fn new_display() -> Self {
80        Self {
81            depth: 0,
82            debug: false,
83        }
84    }
85
86    /// Create new tree state for std::fmt::Debug
87    pub fn new_debug(depth: usize) -> Self {
88        Self { depth, debug: true }
89    }
90    /// Change indention one step deeper
91    pub fn indent(&mut self) {
92        self.depth += INDENT
93    }
94
95    /// Return a indention which is one step deeper
96    pub fn indented(&self) -> Self {
97        Self {
98            depth: self.depth + INDENT,
99            debug: self.debug,
100        }
101    }
102}
103
104/// print syntax via std::fmt::Display
105pub struct FormatTree<'a, T: TreeDisplay>(pub &'a T);
106
107impl<T: TreeDisplay> std::fmt::Display for FormatTree<'_, T> {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        self.0.tree_print(
110            f,
111            TreeState {
112                depth: 2,
113                debug: false,
114            },
115        )
116    }
117}
118
119impl<T: TreeDisplay> std::fmt::Debug for FormatTree<'_, T> {
120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121        self.0.tree_print(
122            f,
123            TreeState {
124                depth: 2,
125                debug: true,
126            },
127        )
128    }
129}