commit 841f5ef294a51b8211d7a65a7fc6ffb3e69dfaed Author: Eduard Urbach Date: Mon Jun 2 16:54:33 2025 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d889207 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +* +!*/ +!*.rs +!*.toml +!*.lock +!*.md +!.gitignore +/target \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..11352f5 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "fnl" +version = "0.1.0" \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b63cdd9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "fnl" +version = "0.1.0" +edition = "2024" +description = "Add or remove final newlines" +repository = "https://git.urbach.dev/cli/fnl" +license-file = "readme.md" +readme = "readme.md" +categories = ["command-line-utilities"] \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..bbb3f87 --- /dev/null +++ b/readme.md @@ -0,0 +1,37 @@ +# fnl + +Add or remove final newlines. + +## Installation + +```shell +cargo install fnl +``` + +## Usage + +Show status: + +```shell +find . -type f -name "*.txt" | xargs fnl +``` + +Add final newlines: + +```shell +find . -type f -name "*.txt" | xargs fnl --add +``` + +Remove final newlines: + +```shell +find . -type f -name "*.txt" | xargs fnl --remove +``` + +## License + +Please see the [license documentation](https://urbach.dev/license). + +## Copyright + +© 2025 Eduard Urbach \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b3d41c5 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,55 @@ +use std::env; +use std::fs; + +enum Mode { + Info, + Add, + Remove, +} + +fn main() { + let mut mode = Mode::Info; + + for arg in env::args().skip(1) { + match arg.as_str() { + "--add" => { mode = Mode::Add; } + "--remove" => { mode = Mode::Remove; } + _ => { process_file(&arg, &mode); } + } + } +} + +fn process_file(path: &str, mode: &Mode) { + let mut content = fs::read_to_string(path).expect("could not read file"); + + if ends_with_newline(&content) { + match mode { + Mode::Remove => { + content.pop(); + fs::write(path, content).expect("could not write file"); + println!("\x1B[1m{}\x1B[0m: \x1B[31mno final newline [removed]\x1B[0m", path); + } + _ => { + println!("\x1B[1m{}\x1B[0m: \x1B[32mfinal newline\x1B[0m", path); + } + } + } else { + match mode { + Mode::Add => { + content.push('\n'); + fs::write(path, content).expect("could not write file"); + println!("\x1B[1m{}\x1B[0m: \x1B[32mfinal newline [added]\x1B[0m", path); + } + _ => { + println!("\x1B[1m{}\x1B[0m: \x1B[31mno final newline\x1B[0m", path); + } + } + } +} + +fn ends_with_newline(s: &str) -> bool { + match s.chars().last() { + Some('\n') => true, + _ => false, + } +} \ No newline at end of file