term_rustdoc/tree/impls/
show.rs1use crate::{
2 tree::{IDMap, IdAsStr, Tag, TextTag, ID},
3 util::XString,
4};
5use std::fmt;
6use termtree::Tree;
7
8macro_rules! icon {
11 () => {
12 ::termtree::GlyphPalette::new()
13 };
14 ("") => {
15 ::termtree::GlyphPalette::new()
16 };
17 ($s:literal) => {
18 ::termtree::GlyphPalette {
19 item_indent: ::constcat::concat!("── ", $s, " "),
20 ..Default::default()
21 }
22 };
23 (@fold $s:literal) => {
24 ::termtree::GlyphPalette {
25 item_indent: ::constcat::concat!("─➤ ", $s, " "),
26 last_item: "╰",
27 ..Default::default()
28 }
29 };
30}
31
32#[derive(Clone)]
34pub struct DocTree {
35 pub tree: Tree<TextTag>,
36}
37
38impl fmt::Display for DocTree {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(f, "{}", self.tree)
41 }
42}
43
44impl Default for DocTree {
45 fn default() -> Self {
46 DocTree {
47 tree: Tree::new(TextTag::default()),
48 }
49 }
50}
51
52impl std::iter::Extend<DocTree> for DocTree {
53 fn extend<T: IntoIterator<Item = DocTree>>(&mut self, iter: T) {
54 self.tree.extend(iter.into_iter().map(|t| t.tree));
55 }
56}
57
58impl DocTree {
59 pub fn new(text: XString, tag: Tag, id: Option<XString>) -> Self {
60 Self {
61 tree: Tree::new(TextTag { text, tag, id }).with_glyphs(tag.glyph()),
62 }
63 }
64 pub fn with_leaves(mut self, leaves: impl IntoIterator<Item = Self>) -> Self {
65 self.tree = self.tree.with_leaves(leaves.into_iter().map(|t| t.tree));
66 self
67 }
68 pub fn push(&mut self, node: Self) {
69 self.tree.push(node.tree);
70 }
71}
72
73pub trait Show {
75 fn show(&self) -> DocTree;
77
78 fn show_prettier(&self, map: &IDMap) -> DocTree;
80}
81
82impl Show for str {
83 fn show(&self) -> DocTree {
84 DocTree::new(self.into(), Tag::Unknown, None)
85 }
86
87 fn show_prettier(&self, _: &IDMap) -> DocTree {
89 self.show()
90 }
91}
92
93macro_rules! node {
95 ($tag:ident : $map:ident, $id:expr) => {
97 $crate::tree::DocTree::new($map.path($id), $crate::tree::Tag::$tag, Some($id.into()))
98 };
99 ($tag:ident : $map:ident, $kind:ident, $id:expr) => {
100 $crate::tree::DocTree::new($map.path($id), $crate::tree::Tag::$tag, Some($id.into()))
101 };
102 (@name $tag:ident : $map:ident, $id:expr) => {
103 $crate::tree::DocTree::new($map.name($id), $crate::tree::Tag::$tag, Some($id.into()))
104 };
105}
106
107pub fn show_names<'id, S: 'id + ?Sized + IdAsStr>(
108 ids: impl 'id + IntoIterator<Item = &'id S>,
109 tag: Tag,
110 map: &'id IDMap,
111) -> impl 'id + Iterator<Item = DocTree> {
112 ids.into_iter()
113 .map(move |id| DocTree::new(map.name(id), tag, Some(id.id_str().into())))
114}
115
116macro_rules! names_node {
140 (
141 $self:ident $map:ident $root:expr ,
142 $( $node:ident $field:ident $tag:ident , )+ $(,)?
143 ) => {{
144 if $( $self.$field.is_empty() )&&+ { return $root }
145 ::std::iter::empty()
146 $(
147 .chain(names_node!(@chain $node $field $tag $self $map))
148 )+
149 }};
150 (@chain $node:ident $field:ident $tag:ident $self:ident $map:ident) => {
151 (!$self.$field.is_empty()).then(|| {
152 $crate::tree::Tag::$node.show().with_leaves($crate::tree::impls::show::show_names(
153 &*$self.$field, $crate::tree::Tag::$tag, $map
154 ))
155 })
156 };
157 (@single $self:ident $map:ident $root:ident , $node:ident $field:ident $tag:ident) => {
158 if $self.$field.is_empty() {
159 $crate::tree::Tag::$root.show()
160 } else {
161 $crate::tree::Tag::$node.show().with_leaves($crate::tree::impls::show::show_names(
162 &*$self.$field, $crate::tree::Tag::$tag, $map
163 ))
164 }
165 };
166 (@iter $self:ident $map:ident $root:ident
169 $( $field:ident $tag:ident ),+ $(,)?) => {$(
170 if !$self.$field.is_empty() {
171 $root.extend($crate::tree::impls::show::show_names(
172 &*$self.$field, $crate::tree::Tag::$tag, $map
173 ));
174 }
175 )+};
176}
177
178pub fn show_ids(ids: &[ID]) -> impl '_ + Iterator<Item = DocTree> {
189 ids.iter().map(|id| id.as_str().show())
190}