From 041e90a8f28472cebe454eac4f8c12fe5b7c7577 Mon Sep 17 00:00:00 2001 From: zeefaad Date: Thu, 21 May 2026 09:39:12 +0200 Subject: [PATCH] opti --- Cargo.toml | 3 + profile.json.gz | Bin 0 -> 38858 bytes rklipd/Cargo.toml | 3 + rklipd/profile.json.gz | Bin 0 -> 31383 bytes rklipd/src/config.rs | 34 +++++---- rklipd/src/database.rs | 26 ++++--- rklipd/src/main.rs | 16 ++-- rklipd/src/monitor.rs | 24 ++++-- rklipd/src/ws/wayland.rs | 48 ++++++++---- rklipd/src/ws/x11.rs | 52 ++++++------- src/app.rs | 159 ++++++++++++++++++++++++++++----------- src/crypto.rs | 8 ++ src/ipc.rs | 7 +- src/main.rs | 10 ++- src/ui.rs | 86 ++------------------- 15 files changed, 269 insertions(+), 207 deletions(-) create mode 100644 profile.json.gz create mode 100644 rklipd/profile.json.gz diff --git a/Cargo.toml b/Cargo.toml index 12d5aa3..f12773a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,6 @@ serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" syntect = "5.3.0" uuid = "1.22.0" + +[profile.release] +debug = true diff --git a/profile.json.gz b/profile.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..e7234fd6ca2c33703fce9bbdd7c04a801af85ea1 GIT binary patch literal 38858 zcmZ^~V{~Rg(=Hs_wr%H*ZBLwu?cA|#+s4GUjft&^J+ZBCp66ZXob_q{sMTGos`u{Q zwW_MSuOg0yfdTo?^9^)zFt@TbW3qO3um`#5`Lw4TOJshb3%+-+#MnVy*J2=PVd!_i z&c%)4@A8Kk93l0jK{amjmT6@)7>aLUu2*V(G0UxVF1K$rja^AQY~18eRoB+eOuS7^ zOholx@8RXYa%cW(?AjC}>h<&WclKE8dAVcm>iVo2x*ECKA?oAVy#8}__jq~!z7@T- z`W!Cwue*0SlKeL2W$@Wj)Y4&j`!)&dT!9NwY;}~x!Q%j`o0k^wn5nI&A%zI+1=|6;=}ZW z9RB?g|K00-d!%XS?#%hUO?1`k_hJ4V^as_@!0&OjwX5Tw__w2fm-hgA%U1ULQ1<(3 zdU$yF&~o2SUvF=Rz(;<#H%GVkUfjvS9`V=5F^i6u^Y`1?<b%l?8ejX5y63$#$r|wY+qM9{t4dol?b@%oR z=o-`jJ)8XBf$eX|{pjs?>KmVqxN%w=J-z_`kBzO%{O`-Fn~{UByA4m>_-6-XyXTv? z%g>{|qw}hvYvQlR$Ai8tU&pl_13%}_x2~;*(W=kSw(xgmraqqTKl$YQRhsYIU9DZ6 zo*wLBFGmf>Qt3Mv*Tn92w1QX6_Q+jzf3Dt+f!>@4cWu!9riLyXTUX3TZC%)1vq%L>qE35yIy^+l+cb%{j1>jn zYWIulPxl@vx>~)Ppv^A?{oaA!x0ll+W3y`bfaf~)7T@xTzVG&9rYq!khnhoiCzwEQ`egsP!(-PI(Y0d==r}{&0WA zT|8kHLN7|6+RvZ2$oH!p{V=s$g?1`ChcE5!Ogfh;~nny z{j_(>IOmYL=%C-n>+{ivwEA8ZUnWvQY_PfM+pWPzyuX+|`Qld)NGJXtbvl_YoAYpY^s3BCJ&Umabi98De%~a>cm46ocks3Fjae~^=euy~gPXr- zL6IL->1S`7{~cGcrmrLWeQ|U>!`DMzSk*oww+zp^V$&rUGm&2I?VJ-u+PJixA_yq zQ84klMM(fO-`6@T|M*&Pd{*ZCK0SYUa%bJ*TyidLC|k=$KTiE|X_Vxa&E5#Y*f&$5H{it%7dD0_(BHhK;*K>OH zGoeVcWHlV#7b!Sk?4NBslb~c}?92}AXr2;K&1!1R9p%_>ziub*ss6QC`E<|sTRHmm z=UT9ER;XcCzZYY2R!B99dgwXWwWsK>lcQO<+}7gbb}bY0$laSPZLLBrGy4Vj(D&QF zWgySA3=_tjAGRR4u0EJu`XC|^R67@#^C*2oPe@^v=x$Cgkzp39*m=C5#L6F~&QCZ* zFIv;nfl$pnro4=1LLQsIZrCYqbnSxa4UqL1z3^I@#k56deYQ< z4i7JWb9Q$3c6NWcxPbyAew$O_{<_!YwaOX8Uv;=U?1rX$`2D!=A|YVfhzR>y?&e6l03^?F`pk2rlV59`N!QzfvZ$l=l6m6a-wp-AX+KmE10 z7RWB)5_8r5g(J(PLBNgtZQ}3z9A3D<)Va^|(7TgNjSdkYwB6nNzJKgbDD-a*x9?q5 zL+;McX+)oxXkYIWm-saAU4KV7mpZk73ONn5_>XNE_}o9;o;~JY9nWWF;9x49jhk0h zenU22wK*Kia@3*DtbqI*x6}mgDB1qrvk9L09j*

VBP5c{9WFm~K7xk$ws@@rW9p4BXR#1A4 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 literal 0 HcmV?d00001 diff --git a/rklipd/src/config.rs b/rklipd/src/config.rs index 2bc5d02..ce3b556 100644 --- a/rklipd/src/config.rs +++ b/rklipd/src/config.rs @@ -24,27 +24,31 @@ impl Config { while i < args.len() { match args[i].as_str() { "--max-entries" => { - if let Some(v) = args.get(i + 1).and_then(|s| s.parse().ok()) { - cfg.max_entries = v; - i += 1; - } else { - eprintln!("--max-entries requiert une valeur entière positive"); + i += 1; + match args.get(i).and_then(|s| s.parse::().ok()) { + Some(0) => eprintln!("--max-entries doit être > 0"), + Some(v) => cfg.max_entries = v, + None => eprintln!("--max-entries requiert une valeur entière positive"), } } "--max-entry-size-kb" => { - if let Some(v) = args.get(i + 1).and_then(|s| s.parse().ok()) { - cfg.max_entry_size_kb = v; - i += 1; - } else { - eprintln!("--max-entry-size-kb requiert une valeur entière positive"); + i += 1; + match args.get(i).and_then(|s| s.parse::().ok()) { + Some(0) => eprintln!("--max-entry-size-kb doit être > 0"), + Some(v) => cfg.max_entry_size_kb = v, + None => { + eprintln!("--max-entry-size-kb requiert une valeur entière positive") + } } } "--expiry-days" => { - if let Some(v) = args.get(i + 1).and_then(|s| s.parse::().ok()) { - cfg.expiry_days = Some(v); - i += 1; - } else { - eprintln!("--expiry-days requiert une valeur entière positive"); + i += 1; + match args.get(i).and_then(|s| s.parse::().ok()) { + Some(0) => eprintln!( + "--expiry-days doit être > 0 (0 supprimerait tout immédiatement)" + ), + Some(v) => cfg.expiry_days = Some(v), + None => eprintln!("--expiry-days requiert une valeur entière positive"), } } "--help" | "-h" => { diff --git a/rklipd/src/database.rs b/rklipd/src/database.rs index e3f7069..cbfd2ac 100644 --- a/rklipd/src/database.rs +++ b/rklipd/src/database.rs @@ -101,9 +101,7 @@ impl Database { ExtendedColorType::Rgb8, )?; } - None => { - return Ok(()); - } + None => return Ok(()), } ("image", format!("{}.jpg", img.id)) } @@ -115,7 +113,6 @@ impl Database { )?; self.trim_to_max()?; - Ok(()) } @@ -124,8 +121,10 @@ impl Database { return Ok(()); } + let tx = self.conn.unchecked_transaction()?; + let image_files: Vec = { - let mut stmt = self.conn.prepare( + let mut stmt = tx.prepare( "SELECT content FROM history WHERE type = 'image' AND id NOT IN ( @@ -137,13 +136,15 @@ impl Database { .collect() }; - self.conn.execute( + tx.execute( "DELETE FROM history WHERE id NOT IN ( SELECT id FROM history ORDER BY timestamp DESC LIMIT ?1 )", [self.max_entries as i64], )?; + tx.commit()?; + for filename in image_files { let path = Path::new(&self.dir_path).join("images").join(&filename); if path.exists() { @@ -213,18 +214,19 @@ impl Database { let cutoff_ms = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis() as i64 - (days as i64 * 86_400_000); + let tx = self.conn.unchecked_transaction()?; + let image_files: Vec = { - let mut stmt = self - .conn - .prepare("SELECT content FROM history WHERE type = 'image' AND timestamp < ?1")?; + let mut stmt = + tx.prepare("SELECT content FROM history WHERE type = 'image' AND timestamp < ?1")?; stmt.query_map([cutoff_ms], |row| row.get(0))? .filter_map(|r| r.ok()) .collect() }; - let count = self - .conn - .execute("DELETE FROM history WHERE timestamp < ?1", [cutoff_ms])?; + let count = tx.execute("DELETE FROM history WHERE timestamp < ?1", [cutoff_ms])?; + + tx.commit()?; for filename in image_files { let path = Path::new(&self.dir_path).join("images").join(&filename); diff --git a/rklipd/src/main.rs b/rklipd/src/main.rs index 24bb575..a41d82e 100644 --- a/rklipd/src/main.rs +++ b/rklipd/src/main.rs @@ -48,13 +48,17 @@ fn main() -> Result<(), Box> { let db_for_expiry = Arc::clone(&db); std::thread::spawn(move || { loop { - std::thread::sleep(Duration::from_secs(3600)); - let lock = db_for_expiry.lock().unwrap(); - match lock.delete_entries_older_than(days) { - Ok(0) => {} - Ok(n) => println!("Expiration : {n} entrée(s) supprimée(s) (> {days} jours)"), - Err(e) => eprintln!("Erreur expiration : {e}"), + { + let lock = db_for_expiry.lock().unwrap(); + match lock.delete_entries_older_than(days) { + Ok(0) => {} + Ok(n) => { + println!("Expiration : {n} entrée(s) supprimée(s) (> {days} jours)") + } + Err(e) => eprintln!("Erreur expiration : {e}"), + } } + std::thread::sleep(Duration::from_secs(3600)); } }); } diff --git a/rklipd/src/monitor.rs b/rklipd/src/monitor.rs index 5964fa4..05f1d07 100644 --- a/rklipd/src/monitor.rs +++ b/rklipd/src/monitor.rs @@ -1,28 +1,42 @@ use crate::database::Database; +use crate::models::ClipboardEntry; use arboard::Clipboard; use std::error::Error; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, mpsc}; pub fn start(db: Arc>, clipboard: Clipboard) -> Result<(), Box> { + let (tx, rx) = mpsc::channel::(); + + std::thread::spawn(move || { + for entry in rx { + let lock = db.lock().unwrap(); + if let Err(e) = lock.append(entry) { + eprintln!("SQLite write error: {e}"); + } else { + println!("SQLite updated!"); + } + } + }); + #[cfg(all(feature = "wayland", not(feature = "x11")))] { - crate::ws::wayland::start(db, clipboard) + crate::ws::wayland::start(tx, clipboard) } #[cfg(all(feature = "x11", not(feature = "wayland")))] { - crate::ws::x11::start(db, clipboard) + crate::ws::x11::start(tx, clipboard) } #[cfg(all(feature = "x11", feature = "wayland"))] { - let _ = (db, clipboard); + let _ = (tx, clipboard); Err("Les features 'x11' et 'wayland' sont mutuellement exclusives".into()) } #[cfg(not(any(feature = "x11", feature = "wayland")))] { - let _ = (db, clipboard); + let _ = (tx, clipboard); Err("Aucune feature de système de fenêtrage activée (--features x11 ou wayland)".into()) } } diff --git a/rklipd/src/ws/wayland.rs b/rklipd/src/ws/wayland.rs index d56045e..1b1b804 100644 --- a/rklipd/src/ws/wayland.rs +++ b/rklipd/src/ws/wayland.rs @@ -1,15 +1,22 @@ -use crate::database::Database; use crate::models::{ClipboardData, ClipboardEntry, Image}; +use std::collections::hash_map::DefaultHasher; use std::error::Error; -use std::sync::{Arc, Mutex}; +use std::hash::{Hash, Hasher}; +use std::sync::mpsc; use std::time::SystemTime; use uuid::Uuid; use wayland_clipboard_listener::{WlClipboardPasteStream, WlListenType}; const MAX_IMAGE_PIXELS: usize = 3840 * 2160; +fn hash_bytes(data: &[u8]) -> u64 { + let mut hasher = DefaultHasher::new(); + data.hash(&mut hasher); + hasher.finish() +} + pub fn start( - db: Arc>, + tx: mpsc::Sender, _clipboard: arboard::Clipboard, ) -> Result<(), Box> { let mut stream = WlClipboardPasteStream::init(WlListenType::ListenOnCopy) @@ -17,9 +24,11 @@ pub fn start( println!("Écoute du presse-papier Wayland..."); + let mut last_text: Option = None; + let mut last_image_hash: Option = None; + for msg in stream.paste_stream().flatten() { - let context = &msg.context; - let data: &[u8] = context.context.as_slice(); + let data: &[u8] = msg.context.context.as_slice(); if data.is_empty() { continue; @@ -27,14 +36,22 @@ pub fn start( let entry = if let Ok(text) = String::from_utf8(data.to_vec()) { let text = text.trim_end_matches('\n').to_string(); - if text.is_empty() { + if text.is_empty() || Some(&text) == last_text.as_ref() { continue; } + last_text = Some(text.clone()); + last_image_hash = None; + println!("Clipboard update (texte)"); ClipboardEntry { content: ClipboardData::Text(text), timestamp: SystemTime::now(), } } else { + let hash = hash_bytes(data); + if Some(hash) == last_image_hash { + continue; + } + match image::load_from_memory(data) { Ok(img) => { let (width, height) = (img.width(), img.height()); @@ -48,9 +65,15 @@ pub fn start( 3840, 2160 ); + last_image_hash = Some(hash); + last_text = None; continue; } + last_image_hash = Some(hash); + last_text = None; + println!("Clipboard update (image)"); + let rgba = img.into_rgba8(); ClipboardEntry { content: ClipboardData::Image(Image { @@ -69,15 +92,10 @@ pub fn start( } }; - println!("Clipboard update détecté"); - - let db_clone = Arc::clone(&db); - std::thread::spawn(move || { - let db_lock = db_clone.lock().unwrap(); - if let Err(e) = db_lock.append(entry) { - eprintln!("SQLite error : {e}"); - } - }); + if tx.send(entry).is_err() { + eprintln!("Wayland : writer thread disparu, arrêt"); + break; + } } Ok(()) diff --git a/rklipd/src/ws/x11.rs b/rklipd/src/ws/x11.rs index 11fe6c8..357f44b 100644 --- a/rklipd/src/ws/x11.rs +++ b/rklipd/src/ws/x11.rs @@ -1,10 +1,9 @@ -use crate::database::Database; use crate::models::{ClipboardData, ClipboardEntry, Image}; use arboard::Clipboard; use std::collections::hash_map::DefaultHasher; use std::error::Error; use std::hash::{Hash, Hasher}; -use std::sync::{Arc, Mutex}; +use std::sync::mpsc; use std::thread; use std::time::{Duration, SystemTime}; use uuid::Uuid; @@ -22,7 +21,10 @@ fn hash_bytes(data: &[u8]) -> u64 { hasher.finish() } -pub fn start(db: Arc>, mut clipboard: Clipboard) -> Result<(), Box> { +pub fn start( + tx: mpsc::Sender, + mut clipboard: Clipboard, +) -> Result<(), Box> { let (conn, screen_num) = RustConnection::connect(None).map_err(|e| format!("Connexion X11 impossible : {e}"))?; @@ -49,15 +51,14 @@ pub fn start(db: Arc>, mut clipboard: Clipboard) -> Result<(), B .reply()?; let clipboard_atom = conn.intern_atom(false, b"CLIPBOARD")?.reply()?.atom; - conn.xfixes_select_selection_input( win, clipboard_atom, SelectionEventMask::SET_SELECTION_OWNER, )? .check()?; - conn.flush()?; + println!("Clipboard monitor démarré (X11 XFIXES — zéro polling)"); let mut last_text: Option = None; @@ -68,14 +69,14 @@ pub fn start(db: Arc>, mut clipboard: Clipboard) -> Result<(), B if let Event::XfixesSelectionNotify(_) = event { thread::sleep(Duration::from_millis(50)); - handle_clipboard_event(&mut clipboard, &db, &mut last_text, &mut last_image_hash); + handle_clipboard_event(&mut clipboard, &tx, &mut last_text, &mut last_image_hash); } } } fn handle_clipboard_event( clipboard: &mut Clipboard, - db: &Arc>, + tx: &mpsc::Sender, last_text: &mut Option, last_image_hash: &mut Option, ) { @@ -89,13 +90,15 @@ fn handle_clipboard_event( *last_image_hash = None; println!("Clipboard update (texte)"); - spawn_db_write( - Arc::clone(db), - ClipboardEntry { + if tx + .send(ClipboardEntry { content: ClipboardData::Text(text), timestamp: SystemTime::now(), - }, - ); + }) + .is_err() + { + eprintln!("X11 : writer thread disparu"); + } } Err(_) => { @@ -124,29 +127,20 @@ fn handle_clipboard_event( *last_text = None; println!("Clipboard update (image)"); - spawn_db_write( - Arc::clone(db), - ClipboardEntry { - content: ClipboardData::Image(crate::models::Image { + if tx + .send(ClipboardEntry { + content: ClipboardData::Image(Image { raw_pixels: Some(img_data.bytes.into_owned()), width: img_data.width as u32, height: img_data.height as u32, id: Uuid::new_v4(), }), timestamp: SystemTime::now(), - }, - ); + }) + .is_err() + { + eprintln!("X11 : writer thread disparu"); + } } } } - -fn spawn_db_write(db: Arc>, entry: ClipboardEntry) { - thread::spawn(move || { - let lock = db.lock().unwrap(); - if let Err(e) = lock.append(entry) { - eprintln!("SQLite write error: {e}"); - } else { - println!("SQLite updated!"); - } - }); -} diff --git a/src/app.rs b/src/app.rs index e9f05d5..eb82c79 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,19 +3,22 @@ use crate::ipc::{self, HistoryItem}; use chrono::{Local, NaiveDate, TimeZone}; use fuzzy_matcher::{FuzzyMatcher, skim::SkimMatcherV2}; use image::DynamicImage; +use ratatui::style::{Color, Modifier, Style}; +use ratatui::text::{Line, Span}; use ratatui::widgets::ListState; use ratatui_image::{picker::Picker, protocol}; use regex::Regex; use std::collections::{HashMap, VecDeque}; +use std::sync::Arc; use std::time::{Duration, Instant}; -use syntect::highlighting::ThemeSet; +use syntect::easy::HighlightLines; +use syntect::highlighting::{FontStyle as SynFontStyle, ThemeSet}; use syntect::parsing::SyntaxSet; +use syntect::util::LinesWithEndings; const PREVIEW_MAX_WIDTH: u32 = 1280; const PREVIEW_MAX_HEIGHT: u32 = 720; - const IMAGE_CACHE_MAX: usize = 8; - const PAGE_SIZE: usize = 50; #[derive(PartialEq, Clone)] @@ -56,7 +59,9 @@ pub struct App { pub type_filter: TypeFilter, pub loaded_count: usize, pub has_more: bool, - image_cache: HashMap, + pub preview_highlighted: Option>>, + pub preview_lang: Option, + image_cache: HashMap>, image_cache_order: VecDeque, } @@ -85,6 +90,53 @@ impl TypeFilter { } } +fn syn_color(c: syntect::highlighting::Color) -> Color { + Color::Rgb(c.r, c.g, c.b) +} + +pub fn highlight_code( + content: &str, + syntax_set: &SyntaxSet, + theme_set: &ThemeSet, +) -> Vec> { + let theme = &theme_set.themes["base16-ocean.dark"]; + let syntax = syntax_set + .find_syntax_by_first_line(content) + .unwrap_or_else(|| syntax_set.find_syntax_plain_text()); + + let mut h = HighlightLines::new(syntax, theme); + let mut lines = Vec::new(); + + for (no, line) in LinesWithEndings::from(content).enumerate() { + let ranges = h.highlight_line(line, syntax_set).unwrap_or_default(); + let mut spans = vec![Span::styled( + format!("{:>4} │ ", no + 1), + Style::default().fg(Color::Rgb(80, 80, 100)), + )]; + for (style, text) in &ranges { + let mut s = Style::default().fg(syn_color(style.foreground)); + if style.font_style.contains(SynFontStyle::BOLD) { + s = s.add_modifier(Modifier::BOLD); + } + if style.font_style.contains(SynFontStyle::ITALIC) { + s = s.add_modifier(Modifier::ITALIC); + } + spans.push(Span::styled(text.trim_end_matches('\n').to_string(), s)); + } + lines.push(Line::from(spans)); + } + lines +} + +pub fn detect_lang(content: &str, syntax_set: &SyntaxSet) -> Option { + let s = syntax_set.find_syntax_by_first_line(content)?; + if s.name == "Plain Text" { + None + } else { + Some(s.name.clone()) + } +} + impl App { pub fn new() -> Self { let items = ipc::fetch_history(PAGE_SIZE).unwrap_or_default(); @@ -94,9 +146,19 @@ impl App { let picker = Picker::from_query_stdio().unwrap_or_else(|_| Picker::halfblocks()); - let salt = directories::ProjectDirs::from("com", "zefad", "rklipd") - .and_then(|d| Crypto::load_or_create_salt(d.data_dir()).ok()) - .unwrap_or_else(|| vec![0u8; 32]); + let salt = match directories::ProjectDirs::from("com", "zefad", "rklipd") { + Some(dirs) => match Crypto::load_or_create_salt(dirs.data_dir()) { + Ok(s) => s, + Err(e) => { + eprintln!("Erreur sel cryptographique : {e}"); + vec![0u8; 32] + } + }, + None => { + eprintln!("Impossible de déterminer le répertoire de données"); + vec![0u8; 32] + } + }; let mut app = Self { mode: Mode::Normal, @@ -120,6 +182,8 @@ impl App { type_filter: TypeFilter::All, loaded_count: PAGE_SIZE, has_more, + preview_highlighted: None, + preview_lang: None, image_cache: HashMap::new(), image_cache_order: VecDeque::new(), }; @@ -169,29 +233,34 @@ impl App { &mut self, filename: &str, base_dir: &std::path::Path, - ) -> Option { - if !self.image_cache.contains_key(filename) { - let path = base_dir.join("images").join(filename); - if !path.exists() { - return None; - } - let img = image::open(&path).ok()?; - let img = if img.width() > PREVIEW_MAX_WIDTH || img.height() > PREVIEW_MAX_HEIGHT { - img.thumbnail(PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT) - } else { - img - }; - - if self.image_cache.len() >= IMAGE_CACHE_MAX { - if let Some(oldest) = self.image_cache_order.pop_front() { - self.image_cache.remove(&oldest); - } - } + ) -> Option> { + if self.image_cache.contains_key(filename) { + self.image_cache_order.retain(|k| k != filename); self.image_cache_order.push_back(filename.to_string()); - self.image_cache.insert(filename.to_string(), img); + return self.image_cache.get(filename).cloned(); } - self.image_cache.get(filename).cloned() + let path = base_dir.join("images").join(filename); + if !path.exists() { + return None; + } + let img = image::open(&path).ok()?; + let img = if img.width() > PREVIEW_MAX_WIDTH || img.height() > PREVIEW_MAX_HEIGHT { + img.thumbnail(PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT) + } else { + img + }; + + if self.image_cache.len() >= IMAGE_CACHE_MAX { + if let Some(oldest) = self.image_cache_order.pop_front() { + self.image_cache.remove(&oldest); + } + } + let arc = Arc::new(img); + self.image_cache_order.push_back(filename.to_string()); + self.image_cache + .insert(filename.to_string(), Arc::clone(&arc)); + Some(arc) } pub fn format_timestamp(ts_ms: i64) -> String { @@ -238,7 +307,15 @@ impl App { return false; } } - true + match self.type_filter { + TypeFilter::All => true, + TypeFilter::Text => { + !item.content.ends_with(".jpg") && !item.content.ends_with(".png") + } + TypeFilter::Image => { + item.content.ends_with(".jpg") || item.content.ends_with(".png") + } + } }) .cloned() .collect(); @@ -289,12 +366,6 @@ impl App { matched.into_iter().map(|(_, i)| i).collect() }; - self.filtered_items.retain(|item| match self.type_filter { - TypeFilter::All => true, - TypeFilter::Text => !item.content.ends_with(".jpg") && !item.content.ends_with(".png"), - TypeFilter::Image => item.content.ends_with(".jpg") || item.content.ends_with(".png"), - }); - self.list_state.select(if self.filtered_items.is_empty() { None } else { @@ -313,16 +384,12 @@ impl App { if current >= last { if self.try_load_more() { - // try_load_more restaure la sélection sur le même item ; - // on peut maintenant avancer d'un cran let current = self.list_state.selected().unwrap_or(0); if current + 1 < self.filtered_items.len() { self.list_state.select(Some(current + 1)); self.update_preview(); } - // Sinon (le filtre actif masque les nouveaux items) : on reste } else { - // Fin réelle — wrap vers le haut self.list_state.select(Some(0)); self.update_preview(); } @@ -367,13 +434,13 @@ impl App { self.list_state.select(new_sel); } } + self.last_selected_index = None; self.update_preview(); } pub fn undo_delete(&mut self) { if let Some(item) = self.undo_stack.pop() { ipc::add_entry(item.content.clone()); - // Re-sync depuis le daemon pour avoir l'ordre chronologique correct if let Some(new_items) = ipc::fetch_history(self.loaded_count) { self.has_more = new_items.len() == self.loaded_count; self.all_items = new_items; @@ -545,6 +612,8 @@ impl App { self.current_image = None; self.image_cache.clear(); self.image_cache_order.clear(); + self.preview_highlighted = None; + self.preview_lang = None; self.loaded_count = PAGE_SIZE; self.has_more = false; self.set_status("Historique effacé".into()); @@ -561,6 +630,8 @@ impl App { self.last_selected_index = idx; self.current_image = None; self.preview_scroll = 0; + self.preview_highlighted = None; + self.preview_lang = None; let content = match self.get_selected_item().map(|i| i.content.clone()) { Some(c) => c, @@ -569,12 +640,15 @@ impl App { if content.ends_with(".jpg") || content.ends_with(".png") { if let Some(dirs) = directories::ProjectDirs::from("com", "zefad", "rklipd") { - if let Some(img) = self.get_cached_image(&content, dirs.data_dir()) { - // new_resize_protocol attend un DynamicImage — on clone depuis le cache - // (l'image est déjà redimensionnée ≤ 1280×720, clone = ~3,5 Mo max) + if let Some(arc_img) = self.get_cached_image(&content, dirs.data_dir()) { + let img = (*arc_img).clone(); self.current_image = Some(self.picker.new_resize_protocol(img)); } } + } else if !Crypto::is_any_encrypted(&content) { + self.preview_lang = detect_lang(&content, &self.syntax_set); + self.preview_highlighted = + Some(highlight_code(&content, &self.syntax_set, &self.theme_set)); } } @@ -596,7 +670,6 @@ impl App { return; }; - // Mise à jour du flag has_more lors de chaque sync self.has_more = new.len() == self.loaded_count; let changed = self.all_items.len() != new.len() diff --git a/src/crypto.rs b/src/crypto.rs index 1cf243f..8425fc7 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -34,6 +34,14 @@ impl Crypto { if bytes.len() == SALT_LEN { return Ok(bytes); } + return Err(format!( + "Fichier sel corrompu ({} octets au lieu de {}). \ + Supprimez {:?} manuellement si vous souhaitez réinitialiser le chiffrement.", + bytes.len(), + SALT_LEN, + path + ) + .into()); } let mut salt = vec![0u8; SALT_LEN]; OsRng.fill_bytes(&mut salt); diff --git a/src/ipc.rs b/src/ipc.rs index 3b4a482..53549f5 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -63,8 +63,11 @@ pub fn set_clipboard(content: String) -> bool { ) } -pub fn delete_entry(content: String) { - let _ = send_request(&IpcRequest::DeleteEntry { content }); +pub fn delete_entry(content: String) -> bool { + matches!( + send_request(&IpcRequest::DeleteEntry { content }), + Some(IpcResponse::Ok) + ) } pub fn update_entry(old_content: String, new_content: String) -> bool { diff --git a/src/main.rs b/src/main.rs index 177d5ee..74296c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -177,8 +177,14 @@ fn run_app(terminal: &mut Terminal>, app: &mut App) Mode::ConfirmDelete => match key.code { KeyCode::Char('y') | KeyCode::Char('Y') | KeyCode::Enter => { if let Some(item) = app.get_selected_item() { - ipc::delete_entry(item.content.clone()); - app.delete_selected(); + let content = item.content.clone(); + if ipc::delete_entry(content) { + app.delete_selected(); + } else { + app.set_error( + "Erreur : daemon injoignable, entrée non supprimée".into(), + ); + } } app.mode = Mode::Normal; } diff --git a/src/ui.rs b/src/ui.rs index 94eb52b..ba9100a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,4 +1,4 @@ -use crate::app::{App, Mode}; +use crate::app::{App, Mode, detect_lang, highlight_code}; use crate::crypto::Crypto; use ratatui::{ Frame, @@ -8,55 +8,6 @@ use ratatui::{ widgets::{Block, BorderType, Borders, List, ListItem, Padding, Paragraph}, }; use ratatui_image::StatefulImage; -use syntect::easy::HighlightLines; -use syntect::highlighting::FontStyle as SynFontStyle; -use syntect::util::LinesWithEndings; - -fn syn_color(c: syntect::highlighting::Color) -> Color { - Color::Rgb(c.r, c.g, c.b) -} - -fn highlight_code(content: &str, app: &App) -> Vec> { - let ps = &app.syntax_set; - let ts = &app.theme_set; - let theme = &ts.themes["base16-ocean.dark"]; - - let syntax = ps - .find_syntax_by_first_line(content) - .unwrap_or_else(|| ps.find_syntax_plain_text()); - - let mut h = HighlightLines::new(syntax, theme); - let mut lines = Vec::new(); - - for (no, line) in LinesWithEndings::from(content).enumerate() { - let ranges = h.highlight_line(line, ps).unwrap_or_default(); - let mut spans = vec![Span::styled( - format!("{:>4} │ ", no + 1), - Style::default().fg(Color::Rgb(80, 80, 100)), - )]; - for (style, text) in &ranges { - let mut s = Style::default().fg(syn_color(style.foreground)); - if style.font_style.contains(SynFontStyle::BOLD) { - s = s.add_modifier(Modifier::BOLD); - } - if style.font_style.contains(SynFontStyle::ITALIC) { - s = s.add_modifier(Modifier::ITALIC); - } - spans.push(Span::styled(text.trim_end_matches('\n').to_string(), s)); - } - lines.push(Line::from(spans)); - } - lines -} - -fn detect_lang(content: &str, app: &App) -> Option { - let s = app.syntax_set.find_syntax_by_first_line(content)?; - if s.name == "Plain Text" { - None - } else { - Some(s.name.clone()) - } -} pub fn render(f: &mut Frame, app: &mut App) { let outer = Layout::default() @@ -103,7 +54,7 @@ pub fn render(f: &mut Frame, app: &mut App) { let preview: String = item .content .lines() - .next() + .find(|l| !l.trim().is_empty()) .unwrap_or("") .chars() .take(28) @@ -139,12 +90,7 @@ pub fn render(f: &mut Frame, app: &mut App) { let selected_content = app.get_selected_item().map(|i| i.content.clone()); - let lang = selected_content - .as_deref() - .filter(|c| !Crypto::is_any_encrypted(c) && !c.ends_with(".jpg") && !c.ends_with(".png")) - .and_then(|c| detect_lang(c, app)); - - let preview_title = match &lang { + let preview_title = match &app.preview_lang { Some(l) => format!(" Prévisualisation — {} ", l), None => " Prévisualisation ".to_string(), }; @@ -165,20 +111,19 @@ pub fn render(f: &mut Frame, app: &mut App) { let inner = preview_block.inner(panels[1]); f.render_widget(preview_block, panels[1]); - if app.current_image.is_some() { - let state = app.current_image.as_mut().unwrap(); + let scroll = (app.preview_scroll, 0); + + if let Some(state) = app.current_image.as_mut() { f.render_stateful_widget(StatefulImage::default(), inner, state); } else if let Some(content) = &selected_content { - let scroll = (app.preview_scroll, 0); if Crypto::is_any_encrypted(content) { f.render_widget( Paragraph::new("🔒 Contenu chiffré\n\nAppuyez sur [e] pour déchiffrer.") .scroll(scroll), inner, ); - } else { - let lines = highlight_code(content, app); - f.render_widget(Paragraph::new(lines).scroll(scroll), inner); + } else if let Some(lines) = &app.preview_highlighted { + f.render_widget(Paragraph::new(lines.clone()).scroll(scroll), inner); } } @@ -190,20 +135,6 @@ pub fn render(f: &mut Frame, app: &mut App) { Mode::PasswordInput => (" MOT DE PASSE ", Color::Magenta), }; - let extra = match &app.mode { - Mode::Search => format!(" /{}", app.input_buffer), - Mode::Command => format!(" :{}", app.input_buffer), - Mode::PasswordInput => format!(" {}", "●".repeat(app.input_buffer.len())), - _ => String::new(), - }; - - // let msg_span = if let Some((msg, _)) = &app.error_message { - // Span::styled(format!(" ⚠ {msg}"), Style::default().fg(Color::Red)) - // } else if let Some((msg, _)) = &app.status_message { - // Span::styled(format!(" ✓ {msg}"), Style::default().fg(Color::Green)) - // } else { - // Span::raw(extra) - // }; let filter_hint = match app.type_filter { crate::app::TypeFilter::All => String::new(), f => format!(" [{}]", f.label()), @@ -216,7 +147,6 @@ pub fn render(f: &mut Frame, app: &mut App) { } else { let extra = match &app.mode { Mode::Search => { - // Indicateur visuel du mode de recherche actif (fuzzy vs regexp) let mode_hint = if app.input_buffer.trim_start().starts_with('/') { "re" } else {