use crate::nvim_bridge::GridLineSegment;
#[cfg(test)]
use crate::nvim_bridge;
#[derive(Clone)]
pub struct Cell {
pub text: String,
pub hl_id: u64,
pub double_width: bool,
}
/// Wrapper for a leaf, that tells the leaf's position.
pub struct Segment {
//pub cell: &'a Cell,
pub text: String,
pub hl_id: u64,
pub start: usize,
pub len: usize,
}
/// Row, as in one row in a grid. Internally has a rope/tree structure.
#[derive(Clone)]
pub struct Row {
cells: Box<[Cell]>,
pub len: usize,
}
impl Row {
/// Creates a new row.
///
/// * `len` - Length of the row.
pub fn new(len: usize) -> Self {
Row {
cells: Row::create_empty_cells(len).into_boxed_slice(),
len,
}
}
fn create_empty_cells(len: usize) -> Vec<Cell> {
let mut cells = vec![];
for _ in 0..len {
cells.push(Cell {
text: String::from(" "),
hl_id: 0,
double_width: false,
})
}
cells
}
/// Returns a leaf at a position.
#[inline]
pub fn cell_at(&self, at: usize) -> Option<&Cell> {
self.cells.get(at)
}
#[allow(unused)] // Not used currently, but tested.
pub fn len(&self) -> usize {
self.len
}
/// Clears (resets) the row.
pub fn clear(&mut self) {
self.cells = Row::create_empty_cells(self.len).into_boxed_slice();
}
pub fn resize(&mut self, new_size: usize) {
let mut n = self.cells.clone().into_vec();
n.resize_with(new_size, || Cell {
text: String::from(" "),
hl_id: 0,
double_width: false,
});
self.cells = n.into_boxed_slice();
self.len = self.cells.len();
}
/// Clears range from `from` to `to`.
pub fn clear_range(&mut self, from: usize, to: usize) {
for i in from..to {
self.cells[i] = Cell {
text: String::from(" "),
hl_id: 0,
double_width: false,
}
}
}
/// Copies range from `from` to `to`.
pub fn copy_range(&self, from: usize, to: usize) -> Vec<Cell> {
self.cells[from..to].to_vec()
}
/// Inserts rope to `at`. What ever is between `at` and `rope.len()` is
/// replaced.
pub fn insert_at(&mut self, at: usize, cells: Vec<Cell>) {
for (i, cell) in cells.into_iter().enumerate() {
self.cells[at + i] = cell;
}
assert_eq!(self.cells.len(), self.len);
}
/// Updates row. `line` should be coming straight from nvim's 'grid_line'.
/// event.
pub fn update(&mut self, line: GridLineSegment) -> Vec<Segment> {
let col_start = line.col_start as usize;
let mut offset = col_start;
for cell in line.cells.iter() {
for r in 0..cell.repeat as usize {
self.cells[offset + r] = Cell {
// TODO(ville): Avoid clone here?
text: cell.text.clone(),
hl_id: cell.hl_id,
double_width: cell.double_width,
};
}
offset += cell.repeat as usize;
}
assert_eq!(self.cells.len(), self.len);
self.as_segments(col_start, offset)
}
pub fn as_segments(&self, cell_start: usize, end: usize) -> Vec<Segment> {
let base_hl = self.cells[cell_start].hl_id;
let base = if let Some((i, _)) = self
.cells
.iter()
.take(cell_start)
.enumerate()
.rev()
.find(|(_, c)| c.hl_id != base_hl)
{
// Plus one because we're already "past" from our
// segment's start.
i + 1
} else {
0
};
let mut segs: Vec<Segment> = vec![];
let mut start