|
|
|
use crate::{
|
|
|
|
backend::Backend,
|
|
|
|
buffer::{Buffer, Cell},
|
|
|
|
};
|
|
|
|
use helix_view::graphics::{CursorKind, Rect};
|
|
|
|
use std::{fmt::Write, io};
|
|
|
|
use unicode_width::UnicodeWidthStr;
|
|
|
|
|
|
|
|
/// A backend used for the integration tests.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct TestBackend {
|
|
|
|
width: u16,
|
|
|
|
buffer: Buffer,
|
|
|
|
height: u16,
|
|
|
|
cursor: bool,
|
|
|
|
pos: (u16, u16),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a string representation of the given buffer for debugging purpose.
|
|
|
|
fn buffer_view(buffer: &Buffer) -> String {
|
|
|
|
let mut view = String::with_capacity(buffer.content.len() + buffer.area.height as usize * 3);
|
|
|
|
for cells in buffer.content.chunks(buffer.area.width as usize) {
|
|
|
|
let mut overwritten = vec![];
|
|
|
|
let mut skip: usize = 0;
|
|
|
|
view.push('"');
|
|
|
|
for (x, c) in cells.iter().enumerate() {
|
|
|
|
if skip == 0 {
|
|
|
|
view.push_str(&c.symbol);
|
|
|
|
} else {
|
|
|
|
overwritten.push((x, &c.symbol))
|
|
|
|
}
|
|
|
|
skip = std::cmp::max(skip, c.symbol.width()).saturating_sub(1);
|
|
|
|
}
|
|
|
|
view.push('"');
|
|
|
|
if !overwritten.is_empty() {
|
|
|
|
write!(
|
|
|
|
&mut view,
|
|
|
|
" Hidden by multi-width symbols: {:?}",
|
|
|
|
overwritten
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
view.push('\n');
|
|
|
|
}
|
|
|
|
view
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TestBackend {
|
|
|
|
pub fn new(width: u16, height: u16) -> TestBackend {
|
|
|
|
TestBackend {
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
buffer: Buffer::empty(Rect::new(0, 0, width, height)),
|
|
|
|
cursor: false,
|
|
|
|
pos: (0, 0),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn buffer(&self) -> &Buffer {
|
|
|
|
&self.buffer
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn resize(&mut self, width: u16, height: u16) {
|
|
|
|
self.buffer.resize(Rect::new(0, 0, width, height));
|
|
|
|
self.width = width;
|
|
|
|
self.height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn assert_buffer(&self, expected: &Buffer) {
|
|
|
|
assert_eq!(expected.area, self.buffer.area);
|
|
|
|
let diff = expected.diff(&self.buffer);
|
|
|
|
if diff.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut debug_info = String::from("Buffers are not equal");
|
|
|
|
debug_info.push('\n');
|
|
|
|
debug_info.push_str("Expected:");
|
|
|
|
debug_info.push('\n');
|
|
|
|
let expected_view = buffer_view(expected);
|
|
|
|
debug_info.push_str(&expected_view);
|
|
|
|
debug_info.push('\n');
|
|
|
|
debug_info.push_str("Got:");
|
|
|
|
debug_info.push('\n');
|
|
|
|
let view = buffer_view(&self.buffer);
|
|
|
|
debug_info.push_str(&view);
|
|
|
|
debug_info.push('\n');
|
|
|
|
|
|
|
|
debug_info.push_str("Diff:");
|
|
|
|
debug_info.push('\n');
|
|
|
|
let nice_diff = diff
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, (x, y, cell))| {
|
|
|
|
let expected_cell = expected.get(*x, *y);
|
|
|
|
format!(
|
|
|
|
"{}: at ({}, {}) expected {:?} got {:?}",
|
|
|
|
i, x, y, expected_cell, cell
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
.join("\n");
|
|
|
|
debug_info.push_str(&nice_diff);
|
|
|
|
panic!("{}", debug_info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Backend for TestBackend {
|
|
|
|
fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error>
|
|
|
|
where
|
|
|
|
I: Iterator<Item = (u16, u16, &'a Cell)>,
|
|
|
|
{
|
|
|
|
for (x, y, c) in content {
|
|
|
|
let cell = self.buffer.get_mut(x, y);
|
|
|
|
*cell = c.clone();
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn hide_cursor(&mut self) -> Result<(), io::Error> {
|
|
|
|
self.cursor = false;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn show_cursor(&mut self, _kind: CursorKind) -> Result<(), io::Error> {
|
|
|
|
self.cursor = true;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_cursor(&mut self) -> Result<(u16, u16), io::Error> {
|
|
|
|
Ok(self.pos)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), io::Error> {
|
|
|
|
self.pos = (x, y);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clear(&mut self) -> Result<(), io::Error> {
|
|
|
|
self.buffer.reset();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn size(&self) -> Result<Rect, io::Error> {
|
|
|
|
Ok(Rect::new(0, 0, self.width, self.height))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn flush(&mut self) -> Result<(), io::Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|