-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b1e389d
Showing
5 changed files
with
380 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/target |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[package] | ||
name = "quiren" | ||
version = "0.1.0" | ||
edition = "2018" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
edit = "0.1.3" | ||
osstrtools = "0.2" | ||
thiserror = "1" | ||
main_error = "0.1.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Quiren (Quick Editor Renamer) | ||
|
||
Edits the filenames of the current directory on the editor of your choice. | ||
|
||
## Installation | ||
|
||
```shell | ||
$ git clone https://github.com/Sinono3/quiren.git | ||
$ cargo install --path quiren | ||
``` | ||
|
||
## Usage | ||
|
||
```shell | ||
# On the current directory | ||
$ quiren | ||
# On another directory | ||
$ quiren books | ||
$ quiren /home/dude/abc/ | ||
``` | ||
|
||
## Origin | ||
|
||
I was looking for a tool that would let me edit filenames for the current directory in Vim. I found `massren` on the AUR, and I didn't like it at all. It was so bloated to fulfill such a simple task. Why does it automatically create a config file. Why does it a create an SQLite database (For undoing renames, but still, it should have been on the cache directory). Why do I have to scroll through a huge wall of warning texts to actually edit the filenames. Why does it take so long to actually save the changes. | ||
|
||
Well, enough rant about that tool. If I looked a little bit more into it I probably would have found something that suited my needs, but I thought trying to make it myself would be a fun project, so here we are. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
use osstrtools::OsStrConcat; | ||
use std::env; | ||
use std::ffi::{OsStr, OsString}; | ||
use std::fs; | ||
use std::path::PathBuf; | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug)] | ||
enum QuirenError { | ||
#[error("the entry '{0}' was assigned an empty name")] | ||
EmptyName(String), | ||
#[error("the filename {0} is duplicated")] | ||
DuplicateName(String), | ||
#[error("lines cannot be deleted or added: {0} -> {1}")] | ||
EntryCountMismatch(usize, usize), | ||
#[error("I/O error {0}")] | ||
IoError(#[from] std::io::Error), | ||
} | ||
|
||
fn main() -> Result<(), main_error::MainError> { | ||
let arg = env::args().nth(1); | ||
let dir = arg | ||
.filter(|a| !a.is_empty()) | ||
.map(|a| PathBuf::from(a)) | ||
.or_else(|| env::current_dir().ok()) | ||
.unwrap(); | ||
|
||
// TODO: clap arguments | ||
// TODO: add retry until correct option | ||
|
||
Ok(quiren(dir)?) | ||
} | ||
|
||
fn quiren(dir: PathBuf) -> Result<(), QuirenError> { | ||
let mut entries: Vec<_> = dir.read_dir()?.map(|e| e.unwrap()).collect(); | ||
|
||
entries.sort_by_key(|e| e.file_name()); | ||
|
||
let text: OsString = entries | ||
.iter() | ||
.map(|e| e.file_name()) | ||
.collect::<Vec<OsString>>() | ||
.concat("\n"); | ||
|
||
let text = text.to_string_lossy().into_owned(); | ||
|
||
let edited = edit::edit(&text)?; | ||
|
||
// check if linecount = entry count | ||
let new_count = edited.lines().count(); | ||
|
||
if new_count != entries.len() { | ||
return Err(QuirenError::EntryCountMismatch(entries.len(), new_count)); | ||
} | ||
|
||
// Other checks | ||
for (i, a) in edited.lines().enumerate() { | ||
// Check for empty names | ||
if a.is_empty() { | ||
return Err(QuirenError::EmptyName( | ||
entries[i].file_name().to_string_lossy().to_string(), | ||
)); | ||
} | ||
|
||
// Check for duplicates | ||
for (j, b) in edited.lines().enumerate() { | ||
if i != j && a == b { | ||
return Err(QuirenError::DuplicateName(a.to_string())); | ||
} | ||
} | ||
} | ||
|
||
for (i, line) in edited | ||
.lines() | ||
.enumerate() | ||
// Only rename files with modified names | ||
.filter(|(i, line)| { | ||
let name = OsStr::new(line); | ||
name != entries[*i].file_name() | ||
}) | ||
{ | ||
let mut new_path = dir.clone(); | ||
new_path.push(line); | ||
fs::rename(&entries[i].path(), new_path)?; | ||
} | ||
|
||
Ok(()) | ||
} |