annotui 0.1.0

Mouse-first terminal UI for commenting on files and piped text.
Documentation
use ratatui::layout::Rect;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HitTarget {
    SourceLine(usize),
    Comment(u64),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HitArea {
    pub rect: Rect,
    pub target: HitTarget,
}

impl HitArea {
    #[must_use]
    pub fn new(rect: Rect, target: HitTarget) -> Self {
        Self { rect, target }
    }

    #[must_use]
    pub fn contains(self, column: u16, row: u16) -> bool {
        column >= self.rect.x
            && column < self.rect.x.saturating_add(self.rect.width)
            && row >= self.rect.y
            && row < self.rect.y.saturating_add(self.rect.height)
    }
}

#[must_use]
pub fn hit_test(areas: &[HitArea], column: u16, row: u16) -> Option<HitTarget> {
    areas
        .iter()
        .rev()
        .find(|area| area.contains(column, row))
        .map(|area| area.target)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn later_hit_areas_win_like_render_z_order() {
        let areas = [
            HitArea::new(Rect::new(0, 0, 10, 2), HitTarget::SourceLine(1)),
            HitArea::new(Rect::new(2, 0, 4, 1), HitTarget::Comment(7)),
        ];
        assert_eq!(hit_test(&areas, 3, 0), Some(HitTarget::Comment(7)));
        assert_eq!(hit_test(&areas, 9, 1), Some(HitTarget::SourceLine(1)));
        assert_eq!(hit_test(&areas, 10, 1), None);
    }
}