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 print_tree(&self, f: &mut std::fmt::Formatter, shorten: bool) -> std::fmt::Result {
14        self.tree_print(f, TreeState { depth: 0, shorten })
15    }
16
17    /// Display as tree starting at depth `0`.
18    fn write_tree(&self, f: &mut impl std::io::Write) -> std::io::Result<()> {
19        write!(f, "{}", WriteFmt(|f| self.print_tree(f, false)))
20    }
21}
22
23/// Helper to write into io from fmt writers
24struct WriteFmt<F>(pub F)
25where
26    F: Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result;
27
28impl<F> std::fmt::Display for WriteFmt<F>
29where
30    F: Fn(&mut std::fmt::Formatter<'_>) -> std::fmt::Result,
31{
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        self.0(f)
34    }
35}
36
37/// Indention size
38const INDENT: usize = 2;
39
40/// Indention depth counter
41#[derive(derive_more::Deref, Clone, Copy)]
42pub struct TreeState {
43    #[deref]
44    depth: usize,
45    /// Data shall be shortened to one-line if `true`
46    pub shorten: bool,
47}
48
49impl TreeState {
50    /// Create new tree state
51    /// - `shorten`: If `true` content will be shortened to one line
52    pub fn new(shorten: bool) -> Self {
53        Self { depth: 0, shorten }
54    }
55
56    /// Change indention one step deeper
57    pub fn indent(&mut self) {
58        self.depth += INDENT
59    }
60
61    /// Return a indention which is one step deeper
62    pub fn indented(&self) -> Self {
63        Self {
64            depth: self.depth + INDENT,
65            shorten: self.shorten,
66        }
67    }
68}
69
70impl From<usize> for TreeState {
71    fn from(depth: usize) -> Self {
72        TreeState {
73            depth,
74            shorten: true,
75        }
76    }
77}
78
79/// print syntax via std::fmt::Display
80pub struct FormatTree<'a, T: TreeDisplay>(pub &'a T);
81
82impl<T: TreeDisplay> std::fmt::Display for FormatTree<'_, T> {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        self.0.tree_print(f, 2.into())
85    }
86}