use std::fmt;
mod error;
pub use error::SelectionError;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "windows")]
pub mod windows;
#[cfg(target_os = "linux")]
pub mod linux;
#[derive(Debug, Clone, PartialEq)]
pub enum ContentType {
Text,
File,
Other(String),
}
impl fmt::Display for ContentType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ContentType::Text => write!(f, "text"),
ContentType::File => write!(f, "file"),
ContentType::Other(format) => write!(f, "other/{}", format),
}
}
}
#[derive(Debug, Clone)]
pub struct Selection {
pub content_type: ContentType,
pub data: Vec<u8>,
}
impl Selection {
pub fn new_text(text: String) -> Self {
Self {
content_type: ContentType::Text,
data: text.into_bytes(),
}
}
pub fn new_file(path: String) -> Self {
Self {
content_type: ContentType::File,
data: path.into_bytes(),
}
}
pub fn new_other(format: &str, data: Vec<u8>) -> Self {
Self {
content_type: ContentType::Other(format.to_string()),
data,
}
}
pub fn as_text(&self) -> Option<String> {
if let ContentType::Text = self.content_type {
String::from_utf8(self.data.clone()).ok()
} else {
None
}
}
pub fn as_file_path(&self) -> Option<String> {
if let ContentType::File = self.content_type {
String::from_utf8(self.data.clone()).ok()
} else {
None
}
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
}
pub trait Selector {
fn get_selection(&self) -> Result<Selection, SelectionError>;
}
pub fn get_selection() -> Result<Selection, SelectionError> {
#[cfg(target_os = "macos")]
{
let selector = macos::MacOSSelector::new();
selector.get_selection()
}
#[cfg(target_os = "windows")]
{
let selector = windows::WindowsSelector::new();
selector.get_selection()
}
#[cfg(target_os = "linux")]
{
let selector = linux::LinuxSelector::new();
selector.get_selection()
}
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
{
Err(SelectionError::UnsupportedPlatform)
}
}
pub fn get_text() -> Result<String, SelectionError> {
match get_selection() {
Ok(selection) => selection
.as_text()
.ok_or(SelectionError::InvalidContentType {
expected: "text".to_string(),
received: selection.content_type.to_string(),
}),
Err(err) => Err(err),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_selection_text() {
let text = get_text();
println!("selection_text is {:?}", text);
}
#[test]
fn test_selection_file() {
let path = "/path/to/file.txt".to_string();
let selection = Selection::new_file(path.clone());
assert_eq!(selection.content_type, ContentType::File);
assert_eq!(selection.data, path.as_bytes());
assert_eq!(selection.as_text(), None);
assert_eq!(selection.as_file_path(), Some(path));
assert!(!selection.is_empty());
}
#[test]
fn test_get_text_function() {
let text = "Test text".to_string();
let selection = Selection::new_text(text.clone());
let text_result = selection
.as_text()
.ok_or(SelectionError::InvalidContentType {
expected: "text".to_string(),
received: selection.content_type.to_string(),
});
assert!(text_result.is_ok());
assert_eq!(text_result.unwrap(), text);
}
#[test]
fn test_platform_selection() {
#[cfg(test)]
fn mock_get_selection() -> Result<Selection, SelectionError> {
Ok(Selection::new_text("Mock platform selection".to_string()))
}
#[cfg(test)]
{
let result = mock_get_selection();
assert!(result.is_ok());
assert_eq!(
result.unwrap().as_text(),
Some("Mock platform selection".to_string())
);
}
}
#[test]
fn test_non_utf8_data() {
let invalid_utf8 = vec![0, 159, 146, 150]; let selection = Selection {
content_type: ContentType::Text,
data: invalid_utf8,
};
assert_eq!(selection.as_text(), None);
}
}