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
|
use crate::point::Point;
use std::ops::{Deref, DerefMut};
use unicode_width::UnicodeWidthChar;
/// A 2D string buffer
/// where you can insert a character to any cell on the 2D grid
/// each cell can be assigned with a string
/// taking into account utf8 code which can not be char
/// including but not limited to multi-width chars
pub struct StringBuffer(Vec<Vec<char>>);
impl Deref for StringBuffer {
type Target = Vec<Vec<char>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for StringBuffer {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl StringBuffer {
pub(in crate) fn new() -> Self {
StringBuffer(vec![])
}
/// add rows to this buffer
fn add_rows(&mut self, n: i32) {
for _i in 0..n {
self.push(vec![]);
}
}
/// add columns to the specified row of this buffer
fn add_column(&mut self, row: usize, n: i32) {
for _i in 0..n {
self[row].push(' ');
}
}
/// x and y can also be negative
pub fn add_char(&mut self, x: i32, y: i32, ch: char) {
if x >= 0 && y >= 0 {
if ch == '\0' {
println!("skipping {}", ch);
} else {
let row_index = y as usize;
let column_index = x as usize;
let row_diff = y - self.len() as i32;
if row_diff >= 0 {
self.add_rows(row_diff + 1);
}
let column = &self[y as usize];
let column_diff = x - column.len() as i32;
if column_diff >= 0 {
self.add_column(row_index as usize, column_diff + 1);
}
self[row_index][column_index] = ch;
}
}
}
pub fn add_str(&mut self, x: i32, y: i32, s: &str) {
for (i, ch) in s.chars().enumerate() {
self.add_char(x + i as i32, y, ch);
}
}
}
impl From<&str> for StringBuffer {
fn from(s: &str) -> Self {
let mut rows = vec![];
for line in s.lines() {
let mut row = vec![];
for ch in line.chars() {
// TODO: deal with multi-width , zero width, fixed with string
row.push(ch);
if let Some(2) = ch.width() {
row.push('\0');
}
}
rows.push(row);
}
StringBuffer(rows)
}
}
impl ToString for StringBuffer {
fn to_string(&self) -> String {
let mut lines = vec![];
for row in self.iter() {
let row_contents: Vec<String> = row
.iter()
.filter(|ch| **ch != '\0')
.map(ToString::to_string)
.collect();
let line = row_contents.join("").trim_end().to_string();
lines.push(line);
}
lines.join("\n")
}
}
|