diff options
author | qkzk <qu3nt1n@gmail.com> | 2022-10-16 01:04:26 +0200 |
---|---|---|
committer | qkzk <qu3nt1n@gmail.com> | 2022-10-16 01:04:26 +0200 |
commit | 4db7b345d8d1439ab61d6c75938315b39b47b4d3 (patch) | |
tree | 08886251239ac3e8bd3b3414122bae3c81d9b72d | |
parent | 6e5f19310f42f2ac88f0def2779f79e9dd160943 (diff) |
basic step, can't open editor yet. Need a Mode
-rw-r--r-- | Cargo.lock | 37 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | readme.md | 2 | ||||
-rw-r--r-- | src/bulkrename.rs | 113 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/opener.rs | 38 | ||||
-rw-r--r-- | src/status.rs | 2 |
7 files changed, 178 insertions, 18 deletions
@@ -542,6 +542,7 @@ dependencies = [ "clap 4.0.2", "content_inspector", "pdf-extract", + "rand", "regex", "serde_yaml", "shellexpand", @@ -896,6 +897,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1825c05c4f9e2f781202d1a02fff5e5f722bbafca542d818364e1b1ea22575" [[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -944,6 +951,36 @@ dependencies = [ ] [[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] name = "rayon" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -17,6 +17,7 @@ chrono = "*" clap = { version = "4.0", features = ["derive"] } content_inspector = "0.2.4" pdf-extract = "0.6.4" +rand = "^0" regex = "1" serde_yaml = "0.9.13" shellexpand = "2.1.2" @@ -77,6 +77,7 @@ - [x] improve the top row - [x] confirmation display shows a list of edited files - [x] integrate fzf or another fuzzy finder +- [x] custom a file opener ## TODO @@ -90,7 +91,6 @@ - https://github.com/KillTheMule/nvim-rs/blob/master/examples/basic.rs - https://neovim.io/doc/user/api.html - [ ] display / event separation. use async and message passing between coroutines -- [ ] create a file opener ## BUGS diff --git a/src/bulkrename.rs b/src/bulkrename.rs new file mode 100644 index 00000000..e65b0da3 --- /dev/null +++ b/src/bulkrename.rs @@ -0,0 +1,113 @@ +use rand::Rng; +use std::io::{self, BufRead}; +use std::path::PathBuf; + +use crate::opener::{ExtensionKind, Opener}; + +//TODO: comme pour skim, attach a Arc<Term> and use it to display the editor + +static TMP_FOLDER: &str = "/tmp"; + +struct BulkRenamer { + original_filepath: Vec<PathBuf>, + temp_file: Option<PathBuf>, +} + +impl BulkRenamer { + pub fn new(original_filepath: Vec<PathBuf>) -> Self { + Self { + original_filepath, + temp_file: None, + } + } + + fn random_name() -> String { + let mut rand_str = String::with_capacity(10); + rand_str.push_str("fm-"); + rand::thread_rng() + .sample_iter(&rand::distributions::Alphanumeric) + .take(7) + .for_each(|ch| rand_str.push(ch as char)); + rand_str + } + + fn create_random_file(&mut self, rand_name: String) -> Result<(), io::Error> { + let mut filepath = PathBuf::from(&TMP_FOLDER); + filepath.push(rand_name); + let _ = std::fs::File::create(&filepath)?; + self.temp_file = Some(filepath); + Ok(()) + } + + fn write_original_names(&self) -> Result<(), io::Error> { + if let Some(filepath) = &self.temp_file { + for path in self.original_filepath.iter() { + if let Some(os_filename) = path.file_name() { + if let Some(filename) = os_filename.to_str() { + std::fs::write(&filepath, filename)? + } + } + } + Ok(()) + } else { + Err(io::Error::new( + io::ErrorKind::NotFound, + "Temp file hasn't been created", + )) + } + } + + fn open_temp_file_with_editor(&self, opener: &Opener) -> Result<(), io::Error> { + if let Some(filepath) = &self.temp_file { + if let Some(editor_info) = opener.get(ExtensionKind::Text) { + opener.open_with(editor_info, filepath.to_owned()) + }; + Ok(()) + } else { + Err(io::Error::new( + io::ErrorKind::NotFound, + "Couldn't open the temp file.", + )) + } + } + + fn is_file_modified( + filepath: PathBuf, + original_modification: std::time::SystemTime, + ) -> Result<bool, io::Error> { + let last_modification = std::fs::metadata(&filepath)?.modified()?; + Ok(last_modification <= original_modification) + } + + fn get_new_filenames(&self, filepath: PathBuf) -> Result<Vec<String>, io::Error> { + let file = std::fs::File::open(&filepath)?; + + let reader = std::io::BufReader::new(file); + let mut new_names = vec![]; + for line in reader.lines() { + let line2 = line?; + let line = line2.trim(); + if line.is_empty() { + return Err(io::Error::new(io::ErrorKind::Other, "empty filename")); + } + new_names.push(line2); + } + if new_names.len() < self.original_filepath.len() { + return Err(io::Error::new(io::ErrorKind::Other, "not enough filenames")); + } + Ok(new_names) + } + + fn delete_temp_file(&self, filepath: PathBuf) -> Result<(), io::Error> { + Ok(std::fs::remove_file(&filepath)?) + } + + fn rename(&self, new_filenames: Vec<String>) -> Result<(), io::Error> { + for (path, filename) in self.original_filepath.iter().zip(new_filenames.iter()) { + let mut parent = path.clone(); + parent.pop(); + std::fs::rename(path, parent.join(&filename))?; + } + Ok(()) + } +} @@ -1,5 +1,6 @@ pub mod actioner; pub mod args; +pub mod bulkrename; pub mod completion; pub mod config; pub mod content_window; @@ -10,10 +11,10 @@ pub mod help; pub mod input; pub mod last_edition; pub mod mode; +pub mod opener; pub mod preview; pub mod shortcut; pub mod skim; pub mod status; pub mod tabs; pub mod visited; -pub mod opener; diff --git a/src/opener.rs b/src/opener.rs index ad661bb0..c5dcaf1a 100644 --- a/src/opener.rs +++ b/src/opener.rs @@ -5,7 +5,7 @@ use std::process::Command; use serde_yaml; #[derive(Clone, Hash, Eq, PartialEq)] -enum ExtensionKind { +pub enum ExtensionKind { Audio, Bitmap, Office, @@ -112,7 +112,7 @@ impl ExtensionKind { } #[derive(Clone)] -struct OpenerAssociation { +pub struct OpenerAssociation { association: HashMap<ExtensionKind, OpenerInfo>, } @@ -180,7 +180,7 @@ impl OpenerAssociation { } #[derive(Clone)] -struct OpenerInfo { +pub struct OpenerInfo { opener: String, use_term: bool, } @@ -210,7 +210,7 @@ impl OpenerInfo { #[derive(Clone)] pub struct Opener { terminal: String, - opener_association: OpenerAssociation, + pub opener_association: OpenerAssociation, } impl Opener { @@ -229,21 +229,25 @@ impl Opener { if let Some(extension_os_str) = filepath.extension() { let extension = extension_os_str.to_str().unwrap(); if let Some(open_info) = self.opener_association.opener_info(extension) { - if open_info.use_term { - self.open_terminal( - open_info.opener.clone(), - filepath.to_str().unwrap().to_owned(), - ) - } else { - self.open_directly( - open_info.opener.clone(), - filepath.to_str().unwrap().to_owned(), - ) - } + self.open_with(open_info, filepath) } } } + pub fn open_with(&self, open_info: &OpenerInfo, filepath: std::path::PathBuf) { + if open_info.use_term { + self.open_terminal( + open_info.opener.clone(), + filepath.to_str().unwrap().to_owned(), + ) + } else { + self.open_directly( + open_info.opener.clone(), + filepath.to_str().unwrap().to_owned(), + ) + } + } + pub fn update_from_file(&mut self, yaml: &serde_yaml::value::Value) { self.opener_association.update_from_file(yaml) } @@ -256,6 +260,10 @@ impl Opener { fn open_terminal(&self, executable: String, filepath: String) { execute_in_child(&self.terminal, &vec!["-e", &executable, &filepath]); } + + pub fn get(&self, kind: ExtensionKind) -> Option<&OpenerInfo> { + self.opener_association.association.get(&kind) + } } /// Execute the command in a fork. diff --git a/src/status.rs b/src/status.rs index 6a58559a..7a541fb1 100644 --- a/src/status.rs +++ b/src/status.rs @@ -54,7 +54,7 @@ pub struct Status { pub history: History, /// Predefined shortcuts pub shortcut: Shortcut, - opener: Opener, + pub opener: Opener, } impl Status { |