1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use std::collections::HashMap;
use std::io::{stdout, Write, Stdout};
use crossterm::style::{Print};
use crossterm::execute;
use crossterm::cursor::{MoveToColumn, MoveUp, position};
use crossterm::terminal::{Clear, ClearType};
use crate::{OutputIntent};
pub struct Output {
buffer: String,
pins: HashMap<String, String>,
stdout: Stdout,
position: (u16, u16),
}
impl Output {
pub fn handle(&mut self, intent: OutputIntent) {
match intent {
OutputIntent::Write(data) => self.write(&data),
OutputIntent::Drain => self.drain(),
OutputIntent::Pin(id, data) => self.pin(&id, &data),
OutputIntent::Unpin(id) => self.unpin(&id),
OutputIntent::Flush => self.flush(),
OutputIntent::Exit => {},
}
}
fn write(&mut self, data: &str) {
self.buffer.push_str(&data);
}
fn drain(&mut self) {
self.buffer.clear();
}
fn flush(&mut self) {
self.clear_pins();
execute!(self.stdout, Print(&self.buffer)).unwrap();
self.buffer.clear();
let (left, _) = position().unwrap();
self.position = (left, 0);
self.paint_pins();
}
fn pin(&mut self, id: &str, data: &str) {
self.pins.insert(id.to_string(), data.to_string());
self.clear_pins();
self.paint_pins();
}
fn unpin(&mut self, id: &str) {
self.pins.remove(id);
self.clear_pins();
self.paint_pins();
}
fn paint_pins(&mut self) {
let stdout = &mut self.stdout;
for (_, value) in self.pins.iter() {
self.position.1 += value.matches("\n").count() as u16;
execute!(stdout, Print(value)).unwrap();
}
}
fn clear_pins(&mut self) {
if self.position.1 > 0 {
execute!(self.stdout, MoveUp(self.position.1)).unwrap();
}
execute!(self.stdout, MoveToColumn(self.position.0)).unwrap();
self.position.1 = 0;
execute!(self.stdout, Clear(ClearType::UntilNewLine)).unwrap();
execute!(self.stdout, Clear(ClearType::FromCursorDown)).unwrap();
}
}
impl Default for Output {
fn default() -> Self {
Self {
buffer: String::new(),
pins: HashMap::new(),
stdout: stdout(),
position: (0, 0),
}
}
}