pub struct CharHelper<'a>(pub &'a Vec<char>);
const NEW_LINE: char = '\n';
const TAB: char = '\t';
impl<'a> CharHelper<'a> {
pub fn find_line_start(&self, position: usize) -> usize {
let mut current_pos = usize::min(position, self.0.len() - 1);
if self.0[current_pos] == NEW_LINE {
if current_pos == 0 {
return current_pos;
}
current_pos = current_pos - 1;
}
loop {
if self.0[current_pos] == NEW_LINE {
return current_pos + 1;
}
if current_pos == 0 {
break;
}
current_pos = current_pos - 1;
}
0
}
pub fn find_line_end(&self, position: usize) -> usize {
let mut current_pos = position;
while current_pos < self.0.len() {
if self.0[current_pos] == NEW_LINE {
return current_pos;
}
current_pos = current_pos + 1;
}
self.0.len() - 1
}
pub fn find_lines_before(&self, position: usize, max_lines: usize) -> Vec<(usize, usize)> {
let mut lines = Vec::with_capacity(max_lines);
let mut last_line_start = position;
while last_line_start > 0 && (max_lines - lines.len()) > 0 {
let new_start = self.find_line_start(last_line_start - 1);
lines.push((new_start, last_line_start - new_start));
last_line_start = new_start;
}
lines.reverse();
lines
}
pub fn find_line_and_context(&self, position: usize, max_lines: usize) -> Vec<(usize, usize)> {
let this_start = self.find_line_start(position);
let this_end = self.find_line_end(position);
let mut lines = self.find_lines_before(this_start, max_lines);
lines.push((this_start, this_end - this_start + 1));
lines
}
pub fn position_to_line_col(&self, position: usize) -> (usize, usize) {
let mut current_pos: usize = 0;
let mut current_line: usize = 1;
let mut last_line_start: usize = 0;
while current_pos < position {
if self.0[current_pos] == NEW_LINE {
current_line = current_line + 1;
last_line_start = current_pos + 1;
}
current_pos = current_pos + 1;
}
(current_line, current_pos - last_line_start + 1)
}
}
pub struct StringBuilder {
parts: Vec<String>,
total_length: usize,
}
impl StringBuilder {
pub fn new() -> StringBuilder {
StringBuilder {
parts: Vec::new(),
total_length: 0,
}
}
pub fn append(&mut self, str: &impl ToString) {
let str = str.to_string();
let len = str.len();
self.parts.push(str);
self.total_length = self.total_length + len;
}
pub fn append_char(&mut self, c: char) {
self.parts.push(c.to_string());
self.total_length = self.total_length + 1;
}
}
impl ToString for StringBuilder {
fn to_string(&self) -> String {
let mut str = String::with_capacity(self.total_length);
for p in &self.parts {
str.push_str(p)
}
str
}
}
pub fn count_tabs_before(str: &String, end_index: usize) -> usize {
if end_index == 0 {
return 0;
}
str.chars()
.take(end_index - 1)
.filter(|c| c == &TAB)
.count()
}