1use std::fmt;
2use crate::Node;
3
4pub struct Repeat {
5 pub node: Box<dyn Node>,
6 pub min: usize,
7 pub max: Option<usize>,
8}
9
10impl Repeat {
11 pub fn new(node: Box<dyn Node>) -> Self {
12 Self {
13 node,
14 min: 0,
15 max: None,
16 }
17 }
18
19 pub fn min(mut self, min: usize) -> Self {
20 self.min = min;
21 self
22 }
23
24 pub fn max(mut self, max: usize) -> Self {
25 self.max = Some(max);
26 self
27 }
28
29 fn caption(&self) -> String {
30 if let Some(max) = self.max {
31 if max == self.min {
32 format!("{} time{}", self.min, if self.min == 1 { "" } else { "s" })
33 } else {
34 format!("{}-{} times", self.min, max)
35 }
36 } else {
37 format!("{}+ times", self.min)
38 }
39 }
40}
41
42impl Node for Repeat {
43 fn get_width(&self) -> usize {
44 self.node.get_width().max(self.caption().len()) + 2
45 }
46
47 fn get_height(&self) -> usize {
48 self.node.get_height() + 1
49 }
50
51 fn as_str(&self) -> String {
52 let mut ret = String::new();
53 let width = self.get_width();
54
55 let s = self.node.as_str();
56 let lines = s.lines().collect::<Vec<_>>();
57 for y in 0..lines.len() {
58 let sep = if y == 0 { " " }
59 else if y == 1 { "┬" }
60 else { "│" };
61 ret += sep;
62
63 let offset = (width - 2 - lines[y].chars().count()) / 2;
64 for _ in 0..offset { ret += if y == 1 { "─" } else { " " }; }
65 ret += lines[y];
66 for _ in 0..(width - 2 - lines[y].chars().count() - offset) { ret += if y == 1 { "─" } else { " " }; }
67
68 ret += sep;
69 ret += "\n";
70 }
71
72 let caption = self.caption();
73 let offset = (width - 2 - caption.len()) / 2;
74
75 ret += "╰";
76 for _ in 0..offset { ret += "─" }
77 ret += &caption;
78 for _ in 0..(width - 2 - caption.len() - offset) { ret += "─" }
79 ret += "╯";
80
81 ret
82 }
83}
84
85impl fmt::Display for Repeat {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 write!(f, "{}", self.as_str())
88 }
89}