Skip to content

Commit f43f884

Browse files
authored
Merge pull request #29 from rust-scraper/display
impl Display for Tree
2 parents c6dd38e + 129ad48 commit f43f884

File tree

4 files changed

+154
-1
lines changed

4 files changed

+154
-1
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
target
22
Cargo.lock
3+
.vscode

src/display.rs

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use std::fmt::Display;
2+
3+
/// Indentation token
4+
#[derive(Debug)]
5+
struct Token {
6+
/// Is followed by a brother
7+
siblings: bool,
8+
/// Is intermediate while printing children
9+
children: bool,
10+
}
11+
12+
impl Display for Token {
13+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
14+
let Token { siblings, children } = self;
15+
16+
write!(
17+
f,
18+
"{}",
19+
match (siblings, children) {
20+
(true, true) => "│ ",
21+
(true, false) => "├── ",
22+
(false, true) => " ",
23+
(false, false) => "└── ",
24+
}
25+
)
26+
}
27+
}
28+
29+
impl Token {
30+
/// Create a new indentation token
31+
fn new(siblings: bool) -> Self {
32+
Token {
33+
siblings,
34+
children: false,
35+
}
36+
}
37+
38+
/// Set children flag before starting displaying children
39+
fn set_children(&mut self) {
40+
self.children = true;
41+
}
42+
}
43+
44+
/// Manages the state during the display operation
45+
#[derive(Debug)]
46+
pub struct Indentation {
47+
tokens: Vec<Token>,
48+
ignore_root: bool,
49+
}
50+
51+
impl Display for Indentation {
52+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
53+
let first: usize = if self.ignore_root { 1 } else { 0 };
54+
55+
for token in &self.tokens[first..] {
56+
write!(f, "{token}")?;
57+
}
58+
59+
Ok(())
60+
}
61+
}
62+
63+
impl Indentation {
64+
/// Creates a new indentation handler
65+
pub fn new(ignore_root: bool) -> Self {
66+
Indentation {
67+
tokens: Vec::new(),
68+
ignore_root,
69+
}
70+
}
71+
72+
/// Adds a new layer of indentation
73+
pub fn indent(&mut self, siblings: bool) -> &mut Self {
74+
// Setup children mode for previous tokens
75+
let len = self.tokens.len();
76+
if len > 0 {
77+
self.tokens[len - 1].set_children();
78+
}
79+
80+
self.tokens.push(Token::new(siblings));
81+
self
82+
}
83+
84+
/// Removes the last layer of indentation
85+
pub fn deindent(&mut self) -> &mut Self {
86+
self.tokens.pop();
87+
self
88+
}
89+
}

src/lib.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
missing_copy_implementations
3636
)]
3737

38-
use std::fmt::{self, Debug, Formatter};
38+
use std::fmt::{self, Debug, Display, Formatter};
3939
use std::num::NonZeroUsize;
4040

4141
/// Vec-backed ID-tree.
@@ -718,3 +718,34 @@ impl<T: Debug> Debug for Tree<T> {
718718
}
719719
}
720720
}
721+
722+
// Handles display
723+
mod display;
724+
725+
impl<T: Display> Display for Tree<T> {
726+
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
727+
use display::Indentation;
728+
use iter::Edge;
729+
730+
let mut indent: Indentation = Indentation::new(true);
731+
732+
for edge in self.root().traverse() {
733+
match edge {
734+
Edge::Open(node) if node.has_children() => {
735+
indent.indent(node.next_sibling().is_some());
736+
writeln!(f, "{indent}{}", node.value())?;
737+
}
738+
Edge::Open(node) => {
739+
indent.indent(node.next_sibling().is_some());
740+
writeln!(f, "{indent}{}", node.value())?;
741+
indent.deindent();
742+
}
743+
Edge::Close(node) if node.has_children() => {
744+
indent.deindent();
745+
}
746+
_ => {}
747+
}
748+
}
749+
Ok(())
750+
}
751+
}

tests/tree.rs

+32
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,35 @@ fn insert_id_before() {
156156
);
157157
assert_eq!(3, tree.root().children().count());
158158
}
159+
160+
#[test]
161+
fn test_display() {
162+
let tree = tree! {
163+
"root" => {
164+
"a" => {
165+
"child 1",
166+
},
167+
"b" => {
168+
"child 2",
169+
},
170+
}
171+
};
172+
173+
let repr = format!("{tree}");
174+
let expected = "root\n├── a\n│ └── child 1\n└── b\n └── child 2\n";
175+
176+
assert_eq!(repr, expected);
177+
178+
let tree = tree! {
179+
"root" => {
180+
"a", "b" => {
181+
"x", "y"
182+
}, "c"
183+
}
184+
};
185+
186+
let repr = format!("{tree}");
187+
let expected = "root\n├── a\n├── b\n│ ├── x\n│ └── y\n└── c\n";
188+
189+
assert_eq!(repr, expected);
190+
}

0 commit comments

Comments
 (0)