Skip to main content

justerm_core/
damage.rs

1//! Damage tracking — what changed since the last reset, as line + column spans.
2//! See ADR-0003 for the model (incremental bounds, ack-gated reset).
3
4/// The damaged column span of a single line.
5#[derive(Clone, Copy, PartialEq, Eq, Debug)]
6pub struct LineDamage {
7    pub line: usize,
8    pub left: usize,
9    pub right: usize,
10}
11
12/// A first-class scroll: rows `[top..=bottom]` shifted by `count` lines
13/// (positive = up, negative = down). The renderer moves the rows instead of
14/// redrawing them. Recorded by the engine — which executes the scroll — rather
15/// than diff-detected (ADR-0003).
16#[derive(Clone, Copy, PartialEq, Eq, Debug)]
17pub struct ScrollOp {
18    pub top: usize,
19    pub bottom: usize,
20    pub count: isize,
21}
22
23/// What changed since the last `reset_damage()`.
24#[derive(Clone, PartialEq, Eq, Debug)]
25pub enum TermDamage {
26    /// The whole screen must be redrawn (flood / resize / alt-screen clear).
27    Full,
28    /// Only these lines changed, each carrying its damaged column span.
29    Partial(Vec<LineDamage>),
30}
31
32/// Per-line damage bounds. "Undamaged" is encoded as `left > right`, so an
33/// untouched line never reports as damaged and the first `expand` sets a real
34/// span. (Mirrors Alacritty's `LineDamageBounds`.)
35#[derive(Clone, Copy)]
36pub(crate) struct LineBounds {
37    left: usize,
38    right: usize,
39    cols: usize,
40}
41
42impl LineBounds {
43    pub(crate) fn undamaged(cols: usize) -> Self {
44        LineBounds {
45            left: cols,
46            right: 0,
47            cols,
48        }
49    }
50
51    /// A line damaged across its full width (a newly exposed scroll line).
52    pub(crate) fn fully_damaged(cols: usize) -> Self {
53        LineBounds {
54            left: 0,
55            right: cols.saturating_sub(1),
56            cols,
57        }
58    }
59
60    /// Widen the span to include columns `[left, right]`.
61    pub(crate) fn expand(&mut self, left: usize, right: usize) {
62        self.left = self.left.min(left);
63        self.right = self.right.max(right);
64    }
65
66    pub(crate) fn is_damaged(&self) -> bool {
67        self.left <= self.right
68    }
69
70    pub(crate) fn reset(&mut self) {
71        self.left = self.cols;
72        self.right = 0;
73    }
74
75    pub(crate) fn span(&self) -> (usize, usize) {
76        (self.left, self.right)
77    }
78}