use std::fs;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
const PASTE_THRESHOLD: usize = 500;
pub struct PasteFile {
path: Option<PathBuf>,
char_count: usize,
preview: String,
}
impl PasteFile {
#[must_use]
pub fn new() -> Self {
Self {
path: None,
char_count: 0,
preview: String::new(),
}
}
pub fn try_store(&mut self, text: &str) -> bool {
if text.len() <= PASTE_THRESHOLD {
return false;
}
let dir = std::env::temp_dir().join("claudette");
let _ = fs::create_dir_all(&dir);
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_or(0, |d| d.subsec_nanos());
let file_path = dir.join(format!("paste-{nanos}.txt"));
if fs::write(&file_path, text).is_ok() {
self.char_count = text.len();
let preview: String = text
.chars()
.take(60)
.map(|c| if c == '\n' || c == '\r' { ' ' } else { c })
.collect();
self.preview = preview;
self.path = Some(file_path);
true
} else {
false
}
}
#[must_use]
pub fn retrieve(&self) -> Option<String> {
self.path.as_ref().and_then(|p| fs::read_to_string(p).ok())
}
#[must_use]
pub fn is_active(&self) -> bool {
self.path.is_some()
}
#[must_use]
pub fn display(&self) -> String {
format!("{}… [{} chars from paste]", self.preview, self.char_count)
}
pub fn clear(&mut self) {
if let Some(path) = self.path.take() {
let _ = fs::remove_file(path);
}
self.char_count = 0;
self.preview.clear();
}
}
impl Default for PasteFile {
fn default() -> Self {
Self::new()
}
}
impl Drop for PasteFile {
fn drop(&mut self) {
self.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn small_text_not_stored() {
let mut pf = PasteFile::new();
let stored = pf.try_store("short");
assert!(!stored);
assert!(!pf.is_active());
}
#[test]
fn large_text_stored_and_retrieved() {
let mut pf = PasteFile::new();
let big: String = "x".repeat(600);
let stored = pf.try_store(&big);
assert!(stored);
assert!(pf.is_active());
assert_eq!(pf.retrieve(), Some(big));
}
#[test]
fn clear_removes_active_state() {
let mut pf = PasteFile::new();
let big: String = "y".repeat(600);
pf.try_store(&big);
pf.clear();
assert!(!pf.is_active());
assert_eq!(pf.retrieve(), None);
}
#[test]
fn display_shows_preview_and_count() {
let mut pf = PasteFile::new();
let big: String = "a".repeat(600);
pf.try_store(&big);
let disp = pf.display();
assert!(disp.contains("600 chars from paste"));
}
}