use std::sync::{Arc, Mutex, OnceLock};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SelectionSource {
TextInput,
TextArea,
StaticText,
}
#[derive(Debug, Clone, Default)]
pub struct TextSelection {
pub text: Option<String>,
pub source: Option<SelectionSource>,
pub can_cut: bool,
}
impl TextSelection {
pub fn empty() -> Self {
Self::default()
}
pub fn new(text: String, source: SelectionSource, can_cut: bool) -> Self {
Self {
text: Some(text),
source: Some(source),
can_cut,
}
}
pub fn has_selection(&self) -> bool {
self.text.as_ref().is_some_and(|t| !t.is_empty())
}
pub fn selected_text(&self) -> Option<&str> {
self.text.as_deref()
}
pub fn clear(&mut self) {
self.text = None;
self.source = None;
self.can_cut = false;
}
}
pub type SharedTextSelection = Arc<Mutex<TextSelection>>;
pub fn global_selection() -> SharedTextSelection {
static GLOBAL_SELECTION: OnceLock<SharedTextSelection> = OnceLock::new();
Arc::clone(GLOBAL_SELECTION.get_or_init(|| Arc::new(Mutex::new(TextSelection::empty()))))
}
pub fn set_selection(text: String, source: SelectionSource, can_cut: bool) {
let selection = global_selection();
let mut guard = selection.lock().unwrap();
*guard = TextSelection::new(text, source, can_cut);
}
pub fn clear_selection() {
let selection = global_selection();
let mut guard = selection.lock().unwrap();
guard.clear();
}
pub fn get_selected_text() -> Option<String> {
let selection = global_selection();
let guard = selection.lock().unwrap();
guard.text.clone()
}
pub fn can_cut_selection() -> bool {
let selection = global_selection();
let guard = selection.lock().unwrap();
guard.can_cut
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_selection_empty() {
let sel = TextSelection::empty();
assert!(!sel.has_selection());
assert!(sel.selected_text().is_none());
}
#[test]
fn test_selection_with_text() {
let sel = TextSelection::new("hello".to_string(), SelectionSource::TextInput, true);
assert!(sel.has_selection());
assert_eq!(sel.selected_text(), Some("hello"));
assert!(sel.can_cut);
}
#[test]
fn test_global_selection() {
clear_selection();
assert!(get_selected_text().is_none());
set_selection("test text".to_string(), SelectionSource::TextInput, true);
assert_eq!(get_selected_text(), Some("test text".to_string()));
assert!(can_cut_selection());
clear_selection();
assert!(get_selected_text().is_none());
}
}