plot/lib/job/gens/
item_list.rs1use crate::lib::job::ModeListForValidColumnItem;
2use crate::lib::{job::ValidResultMainRow, logic::NodeIs};
14
15pub struct TreeLast;
16impl TreeLast {
17 pub const DIR_NO_CHILDREN: &'static str = "└───";
18 pub const DIR_WITH_CHILDREN: &'static str = "└──┬";
19 pub const FILE: &'static str = "└──•";
20 pub const INDENT: &'static str = " ";
21 pub const BRIDGE_START: &'static str = "└──•";
22 pub const BRIDGE_NEXT: &'static str = "──•";
23 pub const BRIDGE_LAST: &'static str = "───";
24}
25
26pub struct TreeMid;
27impl TreeMid {
28 pub const DIR_NO_CHILDREN: &'static str = "├───";
29 pub const DIR_WITH_CHILDREN: &'static str = "├──┬";
30 pub const FILE: &'static str = "├──•";
31 pub const INDENT: &'static str = "│ ";
32 pub const BRIDGE_START: &'static str = "├──•";
33 pub const BRIDGE_NEXT: &'static str = "──•";
34 pub const BRIDGE_LAST: &'static str = "───";
35}
36
37pub struct DrawTree;
38impl DrawTree {
39 pub const ITEM_BETWEEN: &'static str = " ├──•";
40 pub const ITEM_FIRST: &'static str = " ┌──•";
41 pub const ITEM_LAST: &'static str = " └──•";
42 pub const ITEM_ONEFOLD: &'static str = " ──•";
43
44 pub fn list(index: usize, total: usize) -> &'static str {
45 if total <= 1 {
46 Self::ITEM_ONEFOLD
47 } else if index == 0 {
48 Self::ITEM_FIRST
49 } else if index == total - 1 {
50 Self::ITEM_LAST
51 } else {
52 Self::ITEM_BETWEEN
53 }
54 }
55}
56
57pub fn draw_list(
58 mode: &ModeListForValidColumnItem,
59 index: usize,
60 tab: &[ValidResultMainRow],
61 _tier_max: usize,
62) -> String {
63 match mode {
64 ModeListForValidColumnItem::Flat => DrawTree::list(index, tab.len()).to_string(),
65 ModeListForValidColumnItem::Tree => {
66 let node = &tab[index].node;
67 let t = node.tier;
68
69 let is_dir = node.node == NodeIs::Dir;
71 let has_children = if is_dir {
72 if index + 1 < tab.len() { tab[index + 1].node.tier > t } else { false }
73 } else {
74 false
75 };
76
77 let mut is_last = vec![true; t + 1];
79 let mut active_levels = t;
80
81 for j in (index + 1)..tab.len() {
82 let next_tier = tab[j].node.tier;
83 if next_tier <= active_levels {
84 is_last[next_tier] = false;
85 active_levels = next_tier - 1;
86 }
87 if active_levels == 0 {
88 break;
89 }
90 }
91
92 let mut vis_parent_tier = 0;
94 for i_prev in (0..index).rev() {
95 if node.path.str.starts_with(&tab[i_prev].node.path.str) && tab[i_prev].node.node == NodeIs::Dir {
96 vis_parent_tier = tab[i_prev].node.tier;
97 break;
98 }
99 }
100
101 let mut result = String::new();
102 let has_bridge = t > vis_parent_tier + 1;
103
104 for l in 1..t {
106 if has_bridge && l > vis_parent_tier {
107 if l == vis_parent_tier + 1 {
109 result.push_str(if is_last[l] { TreeLast::BRIDGE_START } else { TreeMid::BRIDGE_START });
110 } else {
111 result.push_str(TreeMid::BRIDGE_NEXT);
112 }
113 } else {
114 if is_last[l] {
116 result.push_str(TreeLast::INDENT);
117 } else {
118 result.push_str(TreeMid::INDENT);
119 }
120 }
121 }
122
123 let am_i_last = is_last[t];
125 let branch = if is_dir {
126 match (am_i_last, has_children) {
127 (true, true) => TreeLast::DIR_WITH_CHILDREN,
128 (false, true) => TreeMid::DIR_WITH_CHILDREN,
129 (true, false) => TreeLast::DIR_NO_CHILDREN,
130 (false, false) => TreeMid::DIR_NO_CHILDREN,
131 }
132 } else if am_i_last {
133 TreeLast::FILE
134 } else {
135 TreeMid::FILE
136 };
137
138 if has_bridge {
140 let tail: String = branch.chars().skip(1).collect();
141 result.push_str(""); result.push_str(&tail);
143 } else {
144 result.push_str(branch);
145 }
146
147 result
148 }
149 ModeListForValidColumnItem::None => unreachable!("None jest obsługiwane lokalnie przed wywołaniem"),
150 }
151}