magi-code 0.64.0

Repository-aware CLI coding agent for terminal work
Documentation
use crate::tui::layout::TuiPane;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct TextPosition {
    pub(crate) byte: usize,
    pub(crate) row: usize,
    pub(crate) col: usize,
}

impl TextPosition {
    pub(crate) fn new(byte: usize, row: usize, col: usize) -> Self {
        Self { byte, row, col }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ActiveSelection {
    pub(crate) pane: TuiPane,
    pub(crate) anchor: TextPosition,
    pub(crate) current: TextPosition,
}

impl ActiveSelection {
    pub(crate) fn new(pane: TuiPane, anchor: TextPosition) -> Self {
        Self {
            pane,
            anchor,
            current: anchor,
        }
    }

    pub(crate) fn set_current(&mut self, current: TextPosition) {
        self.current = current;
    }

    pub(crate) fn byte_range(&self) -> Option<(usize, usize)> {
        let start = self.anchor.byte.min(self.current.byte);
        let end = self.anchor.byte.max(self.current.byte);
        (start < end).then_some((start, end))
    }
}

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

    #[test]
    fn reversed_selection_normalizes_range() {
        let mut selection = ActiveSelection::new(TuiPane::Prompt, TextPosition::new(8, 0, 8));
        selection.set_current(TextPosition::new(2, 0, 2));
        assert_eq!(selection.byte_range(), Some((2, 8)));
    }

    #[test]
    fn empty_selection_has_no_range() {
        let selection = ActiveSelection::new(TuiPane::Transcript, TextPosition::new(2, 0, 2));
        assert_eq!(selection.byte_range(), None);
    }
}