1use duat_core::{
2 context::{self, FileReader},
3 form::{self, Form},
4 text::{Text, text},
5 ui::{Area as UiArea, PushSpecs},
6 widgets::{Widget, WidgetCfg},
7};
8
9use crate::{Area, Ui};
10
11pub struct VertRule {
17 reader: Option<FileReader<Ui>>,
18 text: Text,
19 sep_char: SepChar,
20}
21
22impl Widget<Ui> for VertRule {
23 type Cfg = VertRuleCfg;
24
25 fn cfg() -> Self::Cfg {
26 VertRuleCfg::new()
27 }
28
29 fn update(&mut self, area: &Area) {
30 self.text = if let Some(reader) = self.reader.as_ref()
31 && let SepChar::ThreeWay(..) | SepChar::TwoWay(..) = self.sep_char
32 {
33 reader.inspect(|file, _| {
34 let lines = file.printed_lines();
35 let cursors = file.cursors().unwrap();
36 let (upper, middle, lower) = if let Some(main) = cursors.get_main() {
37 let main = main.line();
38 let upper = lines.iter().filter(|&(line, _)| *line < main).count();
39 let middle = lines.iter().filter(|&(line, _)| *line == main).count();
40 let lower = lines.iter().filter(|&(line, _)| *line > main).count();
41 (upper, middle, lower)
42 } else {
43 (0, lines.len(), 0)
44 };
45
46 let chars = self.sep_char.chars();
47
48 text!(
49 [UpperVertRule] { form_string(chars[0], upper) }
50 [VertRule] { form_string(chars[1], middle) }
51 [LowerVertRule] { form_string(chars[2], lower) }
52 )
53 })
54 } else {
55 let full_line =
56 format!("{}\n", self.sep_char.chars()[1]).repeat(area.height() as usize);
57
58 text!([VertRule] full_line)
59 }
60 }
61
62 fn text(&self) -> &Text {
63 &self.text
64 }
65
66 fn text_mut(&mut self) -> &mut Text {
67 &mut self.text
68 }
69
70 fn once() -> Result<(), duat_core::Error<()>> {
71 form::set_weak("VertRule", Form::dark_grey());
72 form::set_weak("UpperVertRule", "VertRule");
73 form::set_weak("LowerVertRule", "VertRule");
74 Ok(())
75 }
76}
77
78#[derive(Clone)]
81enum SepChar {
82 Uniform(char),
83 TwoWay(char, char),
85 ThreeWay(char, char, char),
87}
88
89impl SepChar {
90 fn chars(&self) -> [char; 3] {
93 match self {
94 SepChar::Uniform(uniform) => [*uniform, *uniform, *uniform],
95 SepChar::TwoWay(main, other) => [*other, *main, *other],
96 SepChar::ThreeWay(main, upper, lower) => [*upper, *main, *lower],
97 }
98 }
99}
100
101#[derive(Clone)]
103pub struct VertRuleCfg {
104 sep_char: SepChar,
105 specs: PushSpecs,
106}
107
108impl VertRuleCfg {
109 pub fn new() -> Self {
111 Self {
112 sep_char: SepChar::Uniform('│'),
113 specs: PushSpecs::left().with_hor_len(1.0),
114 }
115 }
116
117 pub fn on_the_right(self) -> Self {
118 Self {
119 specs: PushSpecs::right().with_ver_len(1.0),
120 ..self
121 }
122 }
123
124 pub fn with_char(self, char: char) -> Self {
125 Self { sep_char: SepChar::Uniform(char), ..self }
126 }
127
128 pub fn with_main_char(self, main: char) -> Self {
129 Self {
130 sep_char: match self.sep_char {
131 SepChar::Uniform(other) => SepChar::TwoWay(main, other),
132 SepChar::TwoWay(_, other) => SepChar::TwoWay(main, other),
133 SepChar::ThreeWay(_, above, below) => SepChar::ThreeWay(main, above, below),
134 },
135 ..self
136 }
137 }
138
139 pub fn with_char_above(self, above: char) -> Self {
140 Self {
141 sep_char: match self.sep_char {
142 SepChar::Uniform(other) => SepChar::ThreeWay(other, above, other),
143 SepChar::TwoWay(main, below) => SepChar::ThreeWay(main, above, below),
144 SepChar::ThreeWay(main, _, below) => SepChar::ThreeWay(main, above, below),
145 },
146 ..self
147 }
148 }
149
150 pub fn with_char_below(self, below: char) -> Self {
151 Self {
152 sep_char: match self.sep_char {
153 SepChar::Uniform(other) => SepChar::ThreeWay(other, other, below),
154 SepChar::TwoWay(main, above) => SepChar::ThreeWay(main, above, below),
155 SepChar::ThreeWay(main, above, _) => SepChar::ThreeWay(main, above, below),
156 },
157 ..self
158 }
159 }
160}
161
162impl Default for VertRuleCfg {
163 fn default() -> Self {
164 Self::new()
165 }
166}
167
168impl WidgetCfg<Ui> for VertRuleCfg {
169 type Widget = VertRule;
170
171 fn build(self, on_file: bool) -> (Self::Widget, impl Fn() -> bool, PushSpecs) {
172 let reader = on_file.then_some(context::fixed_reader().unwrap());
173
174 let widget = VertRule {
175 reader: reader.clone(),
176 text: Text::default(),
177 sep_char: self.sep_char,
178 };
179
180 let checker = if let Some(reader) = reader {
181 Box::new(move || reader.has_changed()) as Box<dyn Fn() -> bool + Send + Sync>
182 } else {
183 Box::new(move || false)
184 };
185
186 (widget, checker, self.specs)
187 }
188}
189
190fn form_string(char: char, count: usize) -> String {
191 [char, '\n'].repeat(count).iter().collect()
192}