Luigit
repositories / smith

smith

There are many coding harnesses - but this one is fast

owned by admin

smith-ui/src/lib.rs

Raw
//! Frontend-local, read-only observer presentation state (`SMH-SPEC-SPEC0001`, Observer mode).
#![deny(unsafe_code)]

/// Maximum retained visible records and UTF-8 bytes per row.
pub const ROWS: usize = 12;
/// Byte budget for each visible line, including label and clipping marker.
pub const ROW_BYTES: usize = 512;

/// Prepared, bounded visible row; never an owned session frame.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Row {
    /// Entry identity for explicit fork/search results.
    pub id: String,
    /// One clipped UTF-8 line.
    pub text: String,
}

/// Navigation lives only in the frontend, never in persisted selection.
#[derive(Debug, Default)]
pub struct Observer {
    /// First visible record index in selected history.
    pub start: usize,
    /// Total records in most recent published snapshot.
    pub total: usize,
    /// Whether a worker has reported writer activity yet.
    pub status_known: bool,
    /// Last complete snapshot's writer activity.
    pub writer_active: bool,
    /// Follow must be explicitly enabled; browsing disables it.
    pub follow: bool,
    /// Only bounded prepared rows are retained.
    pub rows: Vec<Row>,
    /// Search query being entered, local to this frontend.
    pub search: String,
    /// Search entry, if found in most recent query.
    pub found: Option<String>,
    /// Recent operation status.
    pub notice: String,
}

impl Observer {
    /// Navigate back without changing selected history.
    pub const fn back(&mut self) {
        self.follow = false;
        self.start = self.start.saturating_sub(ROWS);
    }

    /// Navigate forward without enabling follow.
    pub fn forward(&mut self) {
        self.follow = false;
        self.start = self
            .start
            .saturating_add(ROWS)
            .min(self.total.saturating_sub(ROWS));
    }

    /// Jump to last page and toggle explicit live following.
    pub const fn toggle_follow(&mut self) {
        self.follow = !self.follow;
        if self.follow {
            self.start = self.total.saturating_sub(ROWS);
        }
    }

    /// Replace the prepared snapshot without jumping while browsing.
    pub fn publish(&mut self, total: usize, writer_active: bool, rows: Vec<Row>) {
        self.total = total;
        self.writer_active = writer_active;
        self.status_known = true;
        if self.follow {
            self.start = total.saturating_sub(ROWS);
        }
        self.rows = rows;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn published_live_rows_never_jump_while_browsing() {
        let mut ui = Observer::default();
        ui.publish(30, true, vec![]);
        assert_eq!(ui.start, 0);
        ui.toggle_follow();
        assert_eq!(ui.start, 18);
        ui.publish(32, true, vec![]);
        assert_eq!(ui.start, 20);
        ui.back();
        assert_eq!(ui.start, 8);
        ui.publish(80, false, vec![]);
        assert_eq!(ui.start, 8);
        assert!(!ui.follow);
    }
    #[test]
    fn state_is_small_without_payloads() {
        assert!(std::mem::size_of::<Observer>() <= 256);
    }
}