rewrote pipeline as draggable card strip with per-rule config popovers, added right-click menus to pipeline cards, sidebar tree, and file list, preset import/export with BRU format support, new rules (hash, swap, truncate, sanitize, padding, randomize, text editor, folder name, transliterate), settings dialog with all sections, overlay collision containment, tooltips on icon buttons, empty pipeline default
117 lines
2.7 KiB
Rust
117 lines
2.7 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::{RenameContext, RenameRule};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
|
|
pub enum SwapOccurrence {
|
|
#[default]
|
|
First,
|
|
Last,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct SwapRule {
|
|
pub delimiter: String,
|
|
pub occurrence: SwapOccurrence,
|
|
#[serde(default)]
|
|
pub new_delimiter: Option<String>,
|
|
pub enabled: bool,
|
|
}
|
|
|
|
impl SwapRule {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
delimiter: ", ".into(),
|
|
occurrence: SwapOccurrence::First,
|
|
new_delimiter: None,
|
|
enabled: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl RenameRule for SwapRule {
|
|
fn apply(&self, filename: &str, _context: &RenameContext) -> String {
|
|
if self.delimiter.is_empty() {
|
|
return filename.to_string();
|
|
}
|
|
|
|
let pos = match self.occurrence {
|
|
SwapOccurrence::First => filename.find(&self.delimiter),
|
|
SwapOccurrence::Last => filename.rfind(&self.delimiter),
|
|
};
|
|
|
|
let pos = match pos {
|
|
Some(p) => p,
|
|
None => return filename.to_string(),
|
|
};
|
|
|
|
let left = &filename[..pos];
|
|
let right = &filename[pos + self.delimiter.len()..];
|
|
let joiner = self.new_delimiter.as_deref().unwrap_or(&self.delimiter);
|
|
|
|
format!("{}{}{}", right, joiner, left)
|
|
}
|
|
|
|
fn display_name(&self) -> &str {
|
|
"Swap"
|
|
}
|
|
|
|
fn rule_type(&self) -> &str {
|
|
"swap"
|
|
}
|
|
|
|
fn is_enabled(&self) -> bool {
|
|
self.enabled
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn ctx() -> RenameContext {
|
|
RenameContext::dummy(0)
|
|
}
|
|
|
|
#[test]
|
|
fn swap_comma_space() {
|
|
let rule = SwapRule::new();
|
|
assert_eq!(rule.apply("LastName, FirstName", &ctx()), "FirstName, LastName");
|
|
}
|
|
|
|
#[test]
|
|
fn swap_with_new_delimiter() {
|
|
let rule = SwapRule {
|
|
new_delimiter: Some(" ".into()),
|
|
..SwapRule::new()
|
|
};
|
|
assert_eq!(rule.apply("LastName, FirstName", &ctx()), "FirstName LastName");
|
|
}
|
|
|
|
#[test]
|
|
fn swap_first_occurrence() {
|
|
let rule = SwapRule {
|
|
delimiter: "-".into(),
|
|
occurrence: SwapOccurrence::First,
|
|
..SwapRule::new()
|
|
};
|
|
assert_eq!(rule.apply("a-b-c", &ctx()), "b-c-a");
|
|
}
|
|
|
|
#[test]
|
|
fn swap_last_occurrence() {
|
|
let rule = SwapRule {
|
|
delimiter: "-".into(),
|
|
occurrence: SwapOccurrence::Last,
|
|
..SwapRule::new()
|
|
};
|
|
assert_eq!(rule.apply("a-b-c", &ctx()), "c-a-b");
|
|
}
|
|
|
|
#[test]
|
|
fn no_delimiter_found() {
|
|
let rule = SwapRule::new();
|
|
assert_eq!(rule.apply("nodelimiter", &ctx()), "nodelimiter");
|
|
}
|
|
}
|