microcad_lang/
tree_display.rs

1// Copyright © 2025 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    #[deref]
71    depth: usize,
72    /// Print in debug mode
73    pub debug: bool,
74}
75
76impl TreeState {
77    /// Create new tree state for std::fmt::Display
78    pub fn new_display() -> Self {
79        Self {
80            depth: 0,
81            debug: false,
82        }
83    }
84
85    /// Create new tree state for std::fmt::Debug
86    pub fn new_debug(depth: usize) -> Self {
87        Self { depth, debug: true }
88    }
89    /// Change indention one step deeper
90    pub fn indent(&mut self) {
91        self.depth += INDENT
92    }
93
94    /// Return a indention which is one step deeper
95    pub fn indented(&self) -> Self {
96        Self {
97            depth: self.depth + INDENT,
98            debug: self.debug,
99        }
100    }
101}
102
103/// print syntax via std::fmt::Display
104pub struct FormatTree<'a, T: TreeDisplay>(pub &'a T);
105
106impl<T: TreeDisplay> std::fmt::Display for FormatTree<'_, T> {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        self.0.tree_print(
109            f,
110            TreeState {
111                depth: 2,
112                debug: false,
113            },
114        )
115    }
116}
117
118impl<T: TreeDisplay> std::fmt::Debug for FormatTree<'_, T> {
119    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120        self.0.tree_print(
121            f,
122            TreeState {
123                depth: 2,
124                debug: true,
125            },
126        )
127    }
128}