diff --git a/pixstrip-cli/src/main.rs b/pixstrip-cli/src/main.rs index 7759516..6217e10 100644 --- a/pixstrip-cli/src/main.rs +++ b/pixstrip-cli/src/main.rs @@ -535,13 +535,15 @@ fn cmd_undo(count: usize) { let undo_count = count.min(entries.len()); let to_undo = entries.split_off(entries.len() - undo_count); let mut total_trashed = 0; + let mut failed_entries = Vec::new(); - for entry in &to_undo { + for entry in to_undo { if entry.output_files.is_empty() { println!( "Batch from {} has no recorded output files - cannot undo", entry.timestamp ); + failed_entries.push(entry); continue; } @@ -550,11 +552,13 @@ fn cmd_undo(count: usize) { entry.total, entry.input_dir ); + let mut batch_trashed = 0; for file_path in &entry.output_files { let path = PathBuf::from(file_path); if path.exists() { match trash::delete(&path) { Ok(()) => { + batch_trashed += 1; total_trashed += 1; } Err(e) => { @@ -563,9 +567,17 @@ fn cmd_undo(count: usize) { } } } + + // Keep entry in history if no files were trashed + if batch_trashed == 0 { + failed_entries.push(entry); + } } - // Remove undone entries from history + // Re-add entries where trash failed so they can be retried + entries.extend(failed_entries); + + // Write updated history if let Err(e) = history.write_all(&entries) { eprintln!("Warning: failed to update history after undo: {}", e); } @@ -706,8 +718,17 @@ fn cmd_watch_remove(path: &str) { return; } - if let Ok(json) = serde_json::to_string_pretty(&watches) { - let _ = std::fs::write(&watches_path, json); + match serde_json::to_string_pretty(&watches) { + Ok(json) => { + if let Err(e) = std::fs::write(&watches_path, json) { + eprintln!("Failed to write watch config: {}", e); + std::process::exit(1); + } + } + Err(e) => { + eprintln!("Failed to serialize watch config: {}", e); + std::process::exit(1); + } } println!("Removed watch folder: {}", path); } diff --git a/pixstrip-core/src/executor.rs b/pixstrip-core/src/executor.rs index b4c2a31..c4f1566 100644 --- a/pixstrip-core/src/executor.rs +++ b/pixstrip-core/src/executor.rs @@ -723,10 +723,11 @@ fn paths_are_same(a: &std::path::Path, b: &std::path::Path) -> bool { } } -/// Remove a 0-byte placeholder file created by find_unique_path on error. +/// Remove a placeholder file created by find_unique_path on error. +/// Placeholders are either 0-byte (no marker) or 1-byte (marker `~`). fn cleanup_placeholder(path: &std::path::Path) { if let Ok(meta) = std::fs::metadata(path) { - if meta.len() == 0 { + if meta.len() <= 1 { let _ = std::fs::remove_file(path); } } diff --git a/pixstrip-core/src/operations/rename.rs b/pixstrip-core/src/operations/rename.rs index b2ac266..56c20bb 100644 --- a/pixstrip-core/src/operations/rename.rs +++ b/pixstrip-core/src/operations/rename.rs @@ -40,9 +40,15 @@ pub fn apply_template_full( result = result.replace("{counter}", &counter.to_string()); } - if let Some((w, h)) = dimensions { - result = result.replace("{width}", &w.to_string()); - result = result.replace("{height}", &h.to_string()); + match dimensions { + Some((w, h)) => { + result = result.replace("{width}", &w.to_string()); + result = result.replace("{height}", &h.to_string()); + } + None => { + result = result.replace("{width}", "0"); + result = result.replace("{height}", "0"); + } } // {date} - today's date diff --git a/pixstrip-core/src/operations/watermark.rs b/pixstrip-core/src/operations/watermark.rs index 0595d59..a74162d 100644 --- a/pixstrip-core/src/operations/watermark.rs +++ b/pixstrip-core/src/operations/watermark.rs @@ -168,7 +168,7 @@ fn render_text_to_image( opacity: f32, ) -> image::RgbaImage { let scale = ab_glyph::PxScale::from(font_size); - let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 0.6) as u32).saturating_add(4).min(8192); + let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 1.0) as u32).saturating_add(4).min(16384); let text_height = ((font_size.min(1000.0) * 1.4) as u32).saturating_add(4).min(4096); let alpha = (opacity * 255.0).clamp(0.0, 255.0) as u8; @@ -266,7 +266,7 @@ fn apply_text_watermark( } else { // No rotation - draw text directly (faster) let scale = ab_glyph::PxScale::from(font_size); - let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 0.6) as u32).saturating_add(4).min(8192); + let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 1.0) as u32).saturating_add(4).min(16384); let text_height = ((font_size.min(1000.0) * 1.4) as u32).saturating_add(4).min(4096); let text_dims = Dimensions { width: text_width, @@ -336,7 +336,7 @@ fn apply_tiled_text_watermark( let alpha = (opacity * 255.0).clamp(0.0, 255.0) as u8; let draw_color = Rgba([color[0], color[1], color[2], alpha]); - let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 0.6) as i64 + 4).min(8192); + let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 1.0) as i64 + 4).min(16384); let text_height = ((font_size.min(1000.0) * 1.4) as i64 + 4).min(4096); let mut y = spacing as i64;