#![doc = uranus::readme_text!()]
use textwrap::{Options};
use clap::{
Parser,
ValueEnum,
};
#[derive(Debug, Clone, ValueEnum)]
enum Separator {
Ascii,
Unicode,
}
#[derive(Debug, Clone, Copy)]
enum Width {
Term,
TermPercent(f64),
Int(usize),
}
impl std::fmt::Display for Width {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Width::Term => write!(f, "term"),
Width::TermPercent(percent) => write!(f, "{percent}%"),
Width::Int(int) => write!(f, "{int}"),
}
}
}
impl Width {
fn internal_get_term_width() -> usize {
let (width, _) = crossterm::terminal::size().expect("Failed to get terminal size.");
width as usize
}
pub fn get(self) -> usize {
match self {
Width::Term => Self::internal_get_term_width(),
Width::TermPercent(percent) => {
let term_width = Self::internal_get_term_width() as f64;
let mul = percent / 100.0;
let percent_width = term_width * mul;
let term_width = percent_width.floor() as usize;
term_width
}
Width::Int(int) => int as usize,
}
}
}
impl std::str::FromStr for Width {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0"
| "term"
| "Term"
| "TERM" => {
Ok(Self::Term)
}
"half"
| "Half"
| "HALF" => {
Ok(Self::TermPercent(50.0))
}
percent if percent.ends_with('%')
&& let Ok(percent) = percent[..percent.len() - 1].parse::<f64>()
=> {
let term_width = Self::internal_get_term_width() as f64;
let mul = percent / 100.0;
let percent_width = term_width * mul;
Ok(Self::TermPercent(percent_width))
}
int if let Ok(int @ 1..) = int.parse::<usize>() => {
Ok(Self::Int(int))
}
_ => Err("Invalid argument. Expected `term` or integer width."),
}
}
}
#[derive(Debug, Clone, Parser)]
struct Reptar {
#[arg(long, short)]
break_words: bool,
#[arg(long, short, value_enum, default_value_t = Separator::Unicode)]
separator: Separator,
#[arg(long, short)]
initial_indent: Option<String>,
#[arg(
long,
short,
default_value_t = Width::Term,
)]
width: Width,
#[arg(long, short)]
file: bool,
text_or_path: String,
}
fn main() {
let args = Reptar::parse();
let width = args.width.get();
let mut opts = Options::new(width);
let separator = match args.separator {
Separator::Ascii => textwrap::WordSeparator::AsciiSpace,
Separator::Unicode => textwrap::WordSeparator::UnicodeBreakProperties,
};
opts = opts.break_words(args.break_words);
if let Some(indent) = args.initial_indent.as_deref() {
opts = opts.initial_indent(indent);
}
opts = opts.word_separator(separator);
let text = if args.file {
std::fs::read_to_string(args.text_or_path).expect("Failed to read file.\nSorry there's not a better error message.")
} else {
args.text_or_path
};
let wrapped = textwrap::fill(text.as_str(), opts);
println!("{wrapped}");
}