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
use crate::style::{DiffStyle, Style};
use crate::term::{Term, Tile};
use std::io;
use unicode_width::UnicodeWidthChar;
#[derive(Debug, Clone)]
pub struct DoubleBuffer {
front: Term,
pub back: Term,
}
impl DoubleBuffer {
pub fn new(height: usize, width: usize) -> Self {
Self {
front: Term::new(height, width),
back: Term::new(height, width),
}
}
pub fn with_terminal_size() -> io::Result<Self> {
Ok(Self {
front: Term::with_terminal_size()?,
back: Term::with_terminal_size()?,
})
}
pub fn present<T: io::Write>(&mut self, out: &mut T) -> io::Result<()> {
if (self.front.height(), self.front.width()) != (self.back.height(), self.back.width()) {
self.back.draw(out)?;
} else {
write!(out, "{}", termion::cursor::Hide)?;
let mut current_style = Style::default();
write!(out, "{}", current_style)?;
for (row, (f, b)) in self
.front
.buf()
.iter()
.zip(self.back.buf().iter())
.enumerate()
{
let mut current_col = None;
for (col, (f, b)) in f.iter().zip(b.iter()).enumerate() {
match b {
Tile::Char(ch, style) => {
if b != f {
let w = ch.width().unwrap_or_default();
if current_col != Some(col) {
write!(
out,
"{}",
termion::cursor::Goto(col as u16 + 1, row as u16 + 1)
)?;
}
write!(
out,
"{}{}",
DiffStyle {
from: current_style,
to: *style
},
ch
)?;
current_style = *style;
current_col = Some(col + w);
}
}
Tile::Empty => {
if current_col != Some(col) {
write!(
out,
"{}",
termion::cursor::Goto(col as u16 + 1, row as u16 + 1)
)?;
}
write!(
out,
"{}{}",
DiffStyle {
from: current_style,
to: Style::default()
},
' '
)?;
current_style = Style::default();
current_col = Some(col + 1);
}
Tile::Occupied => {}
}
}
}
}
if let Some(cursor) = self.back.cursor {
write!(
out,
"{}{}{}",
termion::cursor::Goto(cursor.col as u16 + 1, cursor.row as u16 + 1),
cursor.shape,
termion::cursor::Show
)?;
} else {
write!(out, "{}", termion::cursor::Hide)?;
}
std::mem::swap(&mut self.front, &mut self.back);
Ok(())
}
}