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
use crate::row::Row;
use std::collections::HashMap;
use unicode_width::UnicodeWidthChar;
const WHITESPACE: [char; 2] = [' ', '\t'];
#[macro_export]
macro_rules! st {
($value:expr) => {
$value.to_string()
};
}
#[macro_export]
macro_rules! regex {
($re:literal $(,)?) => {{
static RE: once_cell::sync::OnceCell<regex::Regex> = once_cell::sync::OnceCell::new();
RE.get_or_init(|| regex::Regex::new($re).unwrap())
}};
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Loc {
pub x: usize,
pub y: usize,
}
impl From<(usize, usize)> for Loc {
fn from(loc: (usize, usize)) -> Loc {
let (x, y) = loc;
Loc { x, y }
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Size {
pub w: usize,
pub h: usize,
}
impl From<(usize, usize)> for Size {
fn from(size: (usize, usize)) -> Size {
let (w, h) = size;
Size { w, h }
}
}
#[must_use]
pub fn raw_indices(s: &str, i: &[usize]) -> HashMap<usize, usize> {
let mut raw = 0;
let mut indices = HashMap::new();
indices.insert(0, 0);
for (c, ch) in s.chars().enumerate() {
raw += ch.len_utf8();
indices.insert(i[c + 1], raw);
}
indices
}
#[must_use]
pub fn words(row: &Row) -> Vec<usize> {
let tabs = row.get_tab_width();
let mut result = vec![];
let mut dis = 0;
let mut chr = 0;
let mut pad = true;
while chr < row.text.len() {
let c = row.text[chr];
match c {
' ' => dis += 1,
'\t' => {
if pad {
result.push(dis);
}
dis += tabs;
}
_ => {
pad = false;
result.push(dis);
while chr < row.text.len() && !WHITESPACE.contains(&row.text[chr]) {
dis += row.text[chr].width().unwrap_or(0);
chr += 1;
}
continue;
}
}
chr += 1;
}
result.push(row.width());
result
}