Initial commit

This commit is contained in:
Eduard Urbach 2025-06-02 16:54:33 +02:00
commit 841f5ef294
Signed by: eduard
GPG key ID: 49226B848C78F6C8
5 changed files with 116 additions and 0 deletions

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
*
!*/
!*.rs
!*.toml
!*.lock
!*.md
!.gitignore
/target

7
Cargo.lock generated Normal file
View file

@ -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"

9
Cargo.toml Normal file
View file

@ -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"]

37
readme.md Normal file
View file

@ -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

55
src/main.rs Normal file
View file

@ -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,
}
}