Skip to main content

beamterm_core/gl/
selection.rs

1use std::{cell::Cell, fmt::Debug, rc::Rc};
2
3use crate::gl::cell_query::CellQuery;
4
5/// Tracks the active text selection in the terminal grid.
6///
7/// Manages the current selection query and provides methods to update or clear
8/// the selection. Uses `Cell` for interior mutability since `CellQuery` is `Copy`.
9#[derive(Clone)]
10pub struct SelectionTracker {
11    inner: Rc<Cell<Option<CellQuery>>>,
12}
13
14impl Debug for SelectionTracker {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        f.debug_struct("SelectionTracker")
17            .field("query", &self.inner.get())
18            .finish()
19    }
20}
21
22impl SelectionTracker {
23    /// Creates a new selection tracker with no active selection.
24    pub(crate) fn new() -> Self {
25        Self { inner: Rc::new(Cell::new(None)) }
26    }
27
28    /// Clears the current selection.
29    ///
30    /// Removes any active selection from the terminal grid.
31    pub fn clear(&self) {
32        self.inner.set(None);
33    }
34
35    /// Returns the current selection query.
36    ///
37    /// # Panics
38    /// Panics if no selection is active. This is internal-only API where
39    /// a selection is guaranteed to exist when called.
40    #[must_use]
41    pub fn query(&self) -> CellQuery {
42        self.get_query()
43            .expect("query to be a value due to internal-only usage")
44    }
45
46    /// Returns the current selection query or `None` if no selection is active.
47    ///
48    /// Safe version that doesn't panic when no selection exists.
49    #[must_use]
50    pub fn get_query(&self) -> Option<CellQuery> {
51        self.inner.get()
52    }
53
54    /// Sets a new selection query.
55    ///
56    /// Replaces any existing selection with the provided query.
57    pub fn set_query(&self, query: CellQuery) {
58        self.inner.set(Some(query));
59    }
60
61    /// Updates the end position of the current selection.
62    ///
63    /// Used during mouse drag operations to extend the selection.
64    pub fn update_selection_end(&self, end: (u16, u16)) {
65        if let Some(query) = self.inner.get() {
66            self.inner.set(Some(query.end(end)));
67        }
68    }
69
70    /// Sets the content hash on the current query.
71    ///
72    /// The hash is stored with the query to detect if underlying content changes.
73    pub fn set_content_hash(&self, hash: u64) {
74        if let Some(query) = self.inner.get() {
75            self.inner
76                .set(Some(query.with_content_hash(hash)));
77        }
78    }
79}