diff --git a/Cargo.lock b/Cargo.lock index 4ec105f..d350e49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.45" @@ -46,6 +55,7 @@ dependencies = [ "anyhow", "clipboard", "dirs", + "regex", "serde", "serde_derive", "toml", @@ -115,6 +125,12 @@ dependencies = [ "libc", ] +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "objc" version = "0.2.7" @@ -181,6 +197,23 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "serde" version = "1.0.130" diff --git a/Cargo.toml b/Cargo.toml index 470298b..ceb83e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ readme = "README.md" anyhow = "1.0.45" clipboard = "0.5.0" dirs = "4.0.0" +regex = "1.5.4" serde = "1.0.130" serde_derive = "1.0.130" toml = "0.5.8" diff --git a/src/config.rs b/src/config.rs index 5b6addf..b268f9e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,7 @@ #![allow(dead_code)] +use std::str::FromStr; + +use regex::Regex; use serde_derive::Deserialize; #[derive(Clone, Debug, Default, Deserialize)] @@ -13,6 +16,14 @@ pub struct Substitutor { pub action: Action, } +pub trait Match { + fn check_match<'a>(self: Self, string: &'a str) -> bool; +} + +pub trait Act { + fn apply_action(self: Self, input: String) -> String; +} + #[derive(Clone, Debug, Deserialize)] pub enum Matcher { #[serde(rename = "starts_with")] @@ -25,6 +36,20 @@ pub enum Matcher { Regex { pattern: String }, } +impl Match for Matcher { + fn check_match<'a>(self: Self, string: &'a str) -> bool { + return match self { + Matcher::StartsWith { prefix } => string.starts_with(&prefix), + Matcher::EndsWith { suffix } => string.ends_with(&suffix), + Matcher::Contains { substring } => string.contains(&substring), + Matcher::Regex { pattern } => { + let regex = Regex::from_str(&pattern).expect("Failed to parse regex"); + regex.is_match(&string) + } + }; + } +} + #[derive(Clone, Debug, Deserialize)] pub enum Action { #[serde(rename = "replace")] @@ -36,3 +61,14 @@ pub enum Action { #[serde(rename = "remove")] Remove { substring: String }, } + +impl Act for Action { + fn apply_action(self: Self, input: String) -> String { + return match self { + Action::Replace { from, to } => input.replace(&from, &to), + Action::Prefix { prefix } => format!("{}{}", prefix, input), + Action::Suffix { suffix } => format!("{}{}", input, suffix), + Action::Remove { substring } => input.replace(&substring, ""), + }; + } +} diff --git a/src/main.rs b/src/main.rs index 4dc1c25..53dc390 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,10 @@ mod config; use anyhow::{anyhow, Result}; +use clipboard::{ClipboardContext, ClipboardProvider}; use dirs::config_dir; -use crate::config::Replacements; +use crate::config::{Act, Match, Replacements}; fn main() -> Result<()> { let mut config_path = config_dir().ok_or(anyhow!("Failed to get config dir"))?; @@ -16,5 +17,16 @@ fn main() -> Result<()> { } else { Replacements::default() }; - Ok(()) + let mut clipboard: ClipboardContext = ClipboardProvider::new().expect("Failed to get clipboard"); + loop { + let contents = clipboard.get_contents().expect("Failed to read clipboard"); + if let Some(subst) = config + .substitutors + .iter() + .find(|subst| subst.matcher.clone().check_match(&contents)) + { + let result = subst.action.clone().apply_action(contents); + let _ = clipboard.set_contents(result); + }; + } }