kutil_cli/debug/
context.rs

1use super::{format::*, theme::*};
2
3use std::io::*;
4
5const INDENTATION: &str = "  ";
6const BRANCH_CONTINUATION_LAST: &str = "  ";
7const BRANCH_CONTINUATION_ONGOING: &str = "│ ";
8const BRANCH_CONTINUATION_ONGOING_THICK: &str = "┃ ";
9const BRANCH_CONTINUATION_ONGOING_DOUBLE: &str = "║ ";
10const BRANCH_INTO_LAST: &str = "└─";
11const BRANCH_INTO_LAST_THICK: &str = "┗━";
12const BRANCH_INTO_LAST_DOUBLE: &str = "╚═";
13const BRANCH_INTO_ONGOING: &str = "├─";
14const BRANCH_INTO_ONGOING_THICK: &str = "┣━";
15const BRANCH_INTO_ONGOING_DOUBLE: &str = "╠═";
16
17//
18// DebugContext
19//
20
21/// Debug context.
22///
23/// Used with [Debuggable](super::debuggable::Debuggable) to keep track of the mode and graphical
24/// structure.
25#[derive(Clone)]
26pub struct DebugContext<'own> {
27    /// Theme.
28    pub theme: &'own Theme,
29
30    /// Format.
31    ///
32    /// Defaults to [DebugFormat::Reduced].
33    pub format: DebugFormat,
34
35    /// Whether we are continuing a single-line representation.
36    ///
37    /// Defaults to false.
38    pub inline: bool,
39
40    /// Whether we should insert a separator before the representation.
41    ///
42    /// Defaults to false.
43    pub separator: bool,
44
45    /// Indentation for multi-line representations.
46    pub indentation: String,
47}
48
49impl<'own> DebugContext<'own> {
50    /// Constructor.
51    pub fn new(theme: &'own Theme) -> Self {
52        Self { theme, format: DebugFormat::default(), inline: false, separator: false, indentation: String::new() }
53    }
54
55    /// Create child context.
56    ///
57    /// Will set inline to false and clone the other fields.
58    pub fn child(&self) -> Self {
59        Self {
60            theme: self.theme,
61            format: self.format.clone(),
62            inline: false,
63            separator: self.separator,
64            indentation: self.indentation.clone(),
65        }
66    }
67
68    /// Change the theme.
69    pub fn with_theme(mut self, theme: &'own Theme) -> Self {
70        self.theme = theme;
71        self
72    }
73
74    /// Change the format.
75    pub fn with_format(mut self, format: DebugFormat) -> Self {
76        self.format = format;
77        self
78    }
79
80    /// Change the inline flag.
81    ///
82    /// Note that the other "with_" functions set inline to false, so make sure to call
83    /// this function at the end of "with_" chains.
84    pub fn with_inline(mut self, inline: bool) -> Self {
85        self.inline = inline;
86        self
87    }
88
89    /// Change the separator.
90    pub fn with_separator(mut self, separator: bool) -> Self {
91        self.separator = separator;
92        self
93    }
94
95    /// Increase the indentation with spaces.
96    pub fn increase_indentation(mut self) -> Self {
97        self.indentation = self.indentation + INDENTATION;
98        self
99    }
100
101    /// Increase the indentation with a branch continuation.
102    pub fn increase_indentation_branch(mut self, last: bool) -> Self {
103        if last {
104            self.indentation = self.indentation + BRANCH_CONTINUATION_LAST;
105        } else {
106            self.indentation = self.indentation + BRANCH_CONTINUATION_ONGOING;
107        }
108        self
109    }
110
111    /// Increase the indentation with a thick branch continuation.
112    pub fn increase_indentation_thick_branch(mut self, last: bool) -> Self {
113        if last {
114            self.indentation = self.indentation + BRANCH_CONTINUATION_LAST;
115        } else {
116            self.indentation = self.indentation + BRANCH_CONTINUATION_ONGOING_THICK;
117        }
118        self
119    }
120
121    /// Increase the indentation with a double branch continuation.
122    pub fn increase_indentation_double_branch(mut self, last: bool) -> Self {
123        if last {
124            self.indentation = self.indentation + BRANCH_CONTINUATION_LAST;
125        } else {
126            self.indentation = self.indentation + BRANCH_CONTINUATION_ONGOING_DOUBLE;
127        }
128        self
129    }
130
131    /// If the separate flag is true, write the separator.
132    pub fn separate<WriteT>(&self, writer: &mut WriteT) -> Result<()>
133    where
134        WriteT: Write,
135    {
136        match self.separator {
137            true => write!(writer, " "),
138            false => Ok(()),
139        }
140    }
141
142    /// Write a newline plus the indentation.
143    pub fn indent<WriteT>(&self, writer: &mut WriteT) -> Result<()>
144    where
145        WriteT: Write,
146    {
147        write!(writer, "\n{}", self.theme.delimiter(&self.indentation))
148    }
149
150    /// Write a newline plus the indentation. Then write a custom delimiter.
151    pub fn indent_into<WriteT>(&self, writer: &mut WriteT, delimiter: &str) -> Result<()>
152    where
153        WriteT: Write,
154    {
155        write!(writer, "\n{}", self.theme.delimiter(format!("{}{}", self.indentation, delimiter)))
156    }
157
158    /// Write a newline plus the indentation plus a branch-into delimiter.
159    pub fn indent_into_branch<WriteT>(&self, writer: &mut WriteT, last: bool) -> Result<()>
160    where
161        WriteT: Write,
162    {
163        if last {
164            self.indent_into(writer, BRANCH_INTO_LAST)
165        } else {
166            self.indent_into(writer, BRANCH_INTO_ONGOING)
167        }
168    }
169
170    /// Write a newline plus the indentation plus a thick branch-into delimiter.
171    pub fn indent_into_thick_branch<WriteT>(&self, writer: &mut WriteT, last: bool) -> Result<()>
172    where
173        WriteT: Write,
174    {
175        if last {
176            self.indent_into(writer, BRANCH_INTO_LAST_THICK)
177        } else {
178            self.indent_into(writer, BRANCH_INTO_ONGOING_THICK)
179        }
180    }
181
182    /// Write a newline plus the indentation plus a double branch-into delimiter.
183    pub fn indent_into_double_branch<WriteT>(&self, writer: &mut WriteT, last: bool) -> Result<()>
184    where
185        WriteT: Write,
186    {
187        if last {
188            self.indent_into(writer, BRANCH_INTO_LAST_DOUBLE)
189        } else {
190            self.indent_into(writer, BRANCH_INTO_ONGOING_DOUBLE)
191        }
192    }
193
194    /// If the inline flag is false and first is true, write the separator. Otherwise write a
195    /// newline plus the indentation.
196    pub fn separate_or_indent<WriteT>(&self, writer: &mut WriteT, first: bool) -> Result<()>
197    where
198        WriteT: Write,
199    {
200        if first && !self.inline {
201            self.separate(writer)
202        } else {
203            self.indent(writer)
204        }
205    }
206
207    /// If the inline flag is false and first is true write the separator. Otherwise write a
208    /// newline plus the indentation. Then write a custom delimiter.
209    pub fn separate_or_indent_into<WriteT>(&self, writer: &mut WriteT, delimiter: &str, first: bool) -> Result<()>
210    where
211        WriteT: Write,
212    {
213        if first && !self.inline {
214            self.separate(writer)?;
215            self.theme.write_delimiter(writer, delimiter)
216        } else {
217            self.indent_into(writer, delimiter)
218        }
219    }
220}