mod attrs;
pub mod bridge;
pub mod cell;
pub mod color;
pub mod compositor;
pub mod diff;
pub mod layer;
pub mod md;
pub mod paint;
pub mod present;
pub mod rich;
pub mod scroll;
mod sgr;
pub mod snapshot;
pub mod style;
pub mod surface;
mod surface_ops;
mod validate;
pub use cell::{Attrs, Cell, Glyph, GlyphPool, GLYPH_INLINE_CAP, GLYPH_POOL_CAP};
pub use compositor::Compositor;
pub use diff::{FrameDiff, Run};
pub use layer::{Blend, CellShader, ColorTransform, Layer};
pub use present::{ColorDepth, PresentCaps, Presenter, PresenterOpts};
pub use rich::{HAlign, RichLine, RichText, Span};
pub use scroll::{ScrolledRuns, Shift};
pub use snapshot::{snapshot, snapshot_styles};
pub use style::Style;
pub use surface::Surface;
#[cfg(test)]
mod pipeline_tests {
use super::*;
use crate::base::{Point, Rect, Rgba, Size};
#[test]
fn full_pipeline_small_damage_small_bytes() {
let size = Size::new(80, 24);
let mut frame = Surface::new(size, Cell::EMPTY);
let mut prev = Surface::new(size, Cell::EMPTY);
let mut comp = Compositor::new();
let mut diff = FrameDiff::new();
let mut presenter = Presenter::new();
let mut layers = vec![Layer::new(Surface::new(size, Cell::EMPTY), Point::ZERO, 0)];
layers[0]
.surface_mut()
.draw_text(0, 0, "status: ready", Style::new());
let mut out = Vec::new();
let damage = comp.flatten(&mut frame, &mut layers).to_vec();
let runs = diff.compute(&prev, &frame, &damage).to_vec();
presenter.emit(&runs, &frame, &PresentCaps::FULL, &mut out);
assert!(!out.is_empty());
prev.blit(&frame, Rect::from_size(size), Point::ZERO);
layers[0]
.surface_mut()
.draw_text(8, 0, "R", Style::new().fg(Rgba::rgb(255, 0, 0)));
let damage = comp.flatten(&mut frame, &mut layers).to_vec();
let runs = diff.compute(&prev, &frame, &damage).to_vec();
assert_eq!(runs.len(), 1, "one damaged cell, one run: {runs:?}");
assert!(
runs[0].len <= 3,
"run stays near the changed cell: {runs:?}"
);
out.clear();
presenter.emit(&runs, &frame, &PresentCaps::FULL, &mut out);
assert!(out.len() < 80, "small change, small bytes: {}", out.len());
prev.blit(&frame, Rect::from_size(size), Point::ZERO);
let damage = comp.flatten(&mut frame, &mut layers).to_vec();
assert!(damage.is_empty());
let runs = diff.compute(&prev, &frame, &damage).to_vec();
assert!(runs.is_empty());
out.clear();
presenter.emit(&runs, &frame, &PresentCaps::FULL, &mut out);
assert!(out.is_empty(), "idle frames emit zero bytes");
}
#[test]
fn wide_glyphs_survive_the_whole_pipeline() {
let size = Size::new(10, 2);
let mut frame = Surface::new(size, Cell::EMPTY);
let prev = Surface::new(size, Cell::EMPTY);
let mut comp = Compositor::new();
let mut diff = FrameDiff::new();
let mut presenter = Presenter::new();
let mut layers = vec![Layer::new(Surface::new(size, Cell::EMPTY), Point::ZERO, 0)];
layers[0]
.surface_mut()
.draw_text(0, 0, "世界", Style::new());
let damage = comp.flatten(&mut frame, &mut layers).to_vec();
let runs = diff.compute(&prev, &frame, &damage).to_vec();
let mut out = Vec::new();
presenter.emit(&runs, &frame, &PresentCaps::FULL, &mut out);
let text = String::from_utf8_lossy(&out);
assert_eq!(text.matches('世').count(), 1);
assert_eq!(text.matches('界').count(), 1);
}
}