use std::cmp;
use unicode_segmentation::UnicodeSegmentation;
use crate::highlighting;
#[derive(Default)]
pub struct Row {
string: String,
len: usize,
highlighting: Vec<highlighting::Type>
}
impl From<&str> for Row {
fn from(slice: &str) -> Self {
Self {
string: String::from(slice),
len: slice.graphemes(true).count(),
highlighting: vec![highlighting::Type::None; slice.len()],
}
}
}
impl Row {
#[must_use]
pub fn render(&self, start: usize, end: usize) -> String {
let end = cmp::min(end, self.string.len());
let start = cmp::min(start, end);
let mut result = String::new();
let mut current_highlighting = &highlighting::Type::None;
#[allow(clippy::integer_arithmetic)]
for (index, grapheme) in self.string[..]
.graphemes(true)
.enumerate()
.skip(start)
.take(end - start)
{
if let Some(c) = grapheme.chars().next() {
let highlighting_type = self
.highlighting
.get(index)
.unwrap_or(&highlighting::Type::None);
if highlighting_type != current_highlighting {
current_highlighting = highlighting_type;
let highlight = highlighting_type.to_color();
let start_highlight;
if *highlighting_type == highlighting::Type::None {
start_highlight =
format!("{}{}", termion::color::Bg(termion::color::Reset), termion::color::Fg(termion::color::Reset));
} else {
start_highlight =
format!("{}{}", termion::color::Bg(highlight.bg_color), termion::color::Fg(highlight.fg_color));
}
result.push_str(&start_highlight[..]);
}
if c == '\t' {
result.push_str(" ");
} else {
result.push(c);
}
}
}
let end_highlight = format!("{}{}", termion::color::Bg(termion::color::Reset), termion::color::Fg(termion::color::Reset));
result.push_str(&end_highlight[..]);
result
}
#[must_use] pub fn len(&self) -> usize {
self.len
}
#[must_use] pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn insert(&mut self, at: usize, c: char) {
if at >= self.len() {
self.string.push(c);
self.len = self.len.saturating_add(1);
return;
}
let mut result: String = String::new();
let mut length: usize = 0;
for (index, grapheme) in self.string[..].graphemes(true).enumerate() {
length = length.saturating_add(1);
if index == at {
length = length.saturating_add(1);
result.push(c);
}
result.push_str(grapheme);
}
self.len = length;
self.string = result;
}
pub fn delete(&mut self, at: usize) {
if at >= self.len() {
return;
}
let mut result: String = String::new();
let mut length: usize = 0;
for (index, grapheme) in self.string[..].graphemes(true).enumerate() {
if index != at {
length = length.saturating_add(1);
result.push_str(grapheme);
}
}
self.len = length;
self.string = result;
}
pub fn append(&mut self, new: &Self) {
self.string = format!("{}{}", self.string, new.string);
self.len = self.len.saturating_add(new.len);
}
pub fn split(&mut self, at: usize) -> Self {
let mut row: String = String::new();
let mut length: usize = 0;
let mut split_row: String = String::new();
let mut split_length: usize = 0;
for (index, grapheme) in self.string[..].graphemes(true).enumerate() {
if index < at {
length = length.saturating_add(1);
row.push_str(grapheme);
} else {
split_length = split_length.saturating_add(1);
split_row.push_str(grapheme);
}
}
self.string = row;
self.len = length;
Self {
string: split_row,
len: split_length,
highlighting: vec!(),
}
}
#[must_use] pub fn find(&self, query: &str) -> Option<usize> {
self.string.find(query)
}
#[must_use] pub fn as_bytes(&self) -> &[u8] {
self.string.as_bytes()
}
#[allow(clippy::indexing_slicing)]
pub fn add_highlighting(&mut self, highlight_type: highlighting::Type, index: usize) {
self.highlighting[index] = highlight_type;
}
pub fn reset_highlighting(&mut self) {
self.highlighting = vec![highlighting::Type::None; self.string.len()];
}
}