use std::path::PathBuf;
use zalgo_codec_common::{zalgo_decode, zalgo_encode, zalgo_wrap_python};
use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand};
#[derive(Debug, Clone, Subcommand)]
enum Source {
Text { text: Vec<String> },
File { path: PathBuf },
}
#[derive(Debug, Clone, Subcommand)]
enum Mode {
Encode {
#[command(subcommand)]
source: Source,
},
Wrap {
path: PathBuf,
},
Decode {
#[command(subcommand)]
source: Source,
},
Unwrap {
path: PathBuf,
},
}
#[derive(Debug, Clone, Parser)]
#[command(
author,
version,
about = "Convert an ASCII text string into a single unicode grapheme cluster and back.\nThis program can be used to encode and decode strings from both stdin and files.",
long_about = None
)]
struct Cli {
#[command(subcommand)]
mode: Mode,
#[arg(short, long)]
out_path: Option<PathBuf>,
#[arg(short, long, required = false, requires = "out_path")]
force: bool,
}
fn main() -> Result<()> {
let config = Cli::parse();
if let Some(ref destination) = config.out_path {
if destination.exists() && !config.force {
return Err(anyhow!("the file \"{}\" already exists, to overwrite its contents you can supply the -f or --force arguments", destination.to_string_lossy()));
}
}
let output = match config.mode {
Mode::Encode { source } => {
let text = match source {
Source::Text { text } => text.join(" "),
Source::File { path } => std::fs::read_to_string(path)?.replace('\r', ""),
};
zalgo_encode(&text)?
}
Mode::Wrap { path } => {
let text = std::fs::read_to_string(path)?.replace('\r', "");
zalgo_wrap_python(&text)?
}
Mode::Decode { source } => {
let encoded = match source {
Source::Text { mut text } => {
if text.len() == 1 {
Ok(text.swap_remove(0))
} else {
Err(anyhow!("can only decode one grapheme cluster at a time"))
}?
}
Source::File { path } => std::fs::read_to_string(path)?.replace('\r', ""),
};
zalgo_decode(&encoded)?
}
Mode::Unwrap { path } => {
let contents = std::fs::read_to_string(path)?;
let mut chars = contents.chars();
for _ in 0..3 {
chars.next();
}
for _ in 0..88 {
chars.next_back();
}
let encoded: String = chars.collect();
zalgo_decode(&encoded)?
}
};
match config.out_path {
Some(dst) => Ok(std::fs::write(dst, output)?),
None => {
println!("{output}");
Ok(())
}
}
}