use std::collections::VecDeque;
use std::time::Instant;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClipboardType {
CommitHash,
FilePath,
BranchName,
Text,
}
#[derive(Debug, Clone)]
pub struct ClipboardEntry {
pub content: String,
pub content_type: ClipboardType,
pub copied_at: Instant,
}
pub struct ClipboardManager {
current: Option<ClipboardEntry>,
history: VecDeque<ClipboardEntry>,
max_history: usize,
}
impl ClipboardManager {
pub fn new(max_history: usize) -> Self {
Self {
current: None,
history: VecDeque::with_capacity(max_history),
max_history,
}
}
pub fn copy(&mut self, content: impl Into<String>, content_type: ClipboardType) {
let entry = ClipboardEntry {
content: content.into(),
content_type,
copied_at: Instant::now(),
};
if let Some(old) = self.current.take() {
if self.history.len() >= self.max_history {
self.history.pop_front();
}
self.history.push_back(old);
}
self.current = Some(entry);
}
pub fn copy_hash(&mut self, hash: impl Into<String>) {
self.copy(hash, ClipboardType::CommitHash);
}
pub fn copy_path(&mut self, path: impl Into<String>) {
self.copy(path, ClipboardType::FilePath);
}
pub fn copy_branch(&mut self, branch: impl Into<String>) {
self.copy(branch, ClipboardType::BranchName);
}
pub fn get(&self) -> Option<&str> {
self.current.as_ref().map(|e| e.content.as_str())
}
pub fn current(&self) -> Option<&ClipboardEntry> {
self.current.as_ref()
}
pub fn history(&self) -> impl Iterator<Item = &ClipboardEntry> {
self.history.iter().rev()
}
pub fn restore(&mut self, index: usize) -> bool {
let history_vec: Vec<_> = self.history.iter().rev().cloned().collect();
if let Some(entry) = history_vec.get(index).cloned() {
self.copy(entry.content, entry.content_type);
true
} else {
false
}
}
pub fn has_content(&self) -> bool {
self.current.is_some()
}
pub fn clear(&mut self) {
self.current = None;
}
pub fn history_count(&self) -> usize {
self.history.len()
}
}
impl Default for ClipboardManager {
fn default() -> Self {
Self::new(20) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_copy_and_get() {
let mut cm = ClipboardManager::default();
cm.copy_hash("abc123");
assert_eq!(cm.get(), Some("abc123"));
assert!(matches!(cm.current().unwrap().content_type, ClipboardType::CommitHash));
}
#[test]
fn test_history() {
let mut cm = ClipboardManager::default();
cm.copy_hash("hash1");
cm.copy_hash("hash2");
cm.copy_hash("hash3");
assert_eq!(cm.get(), Some("hash3"));
assert_eq!(cm.history_count(), 2);
}
}