add input and output args to CLI

This commit also adds a help text, accessible with the `--help` flag, as
well as a version text, available by using `--version`. My hope is that
this commit will make the jotdown CLI a bit friendlier to use.
This commit is contained in:
kmaasrud 2023-02-08 22:43:07 +01:00 committed by Noah Hellman
parent b572790ac9
commit 896c7004c4
2 changed files with 92 additions and 8 deletions

10
src/help.txt Normal file
View file

@ -0,0 +1,10 @@
usage: jotdown [option] [file]
arguments:
file a djot source file. use a dash (`-`) or no argument
to read from stdin
options:
-h --help show this text
-v --version show the version number
-o --output a file to write the output to. stdout if omitted

View file

@ -1,12 +1,86 @@
use std::ffi::OsString;
use std::fs::File;
use std::io::BufWriter;
use std::io::Read;
use std::process::exit;
#[derive(Default)]
struct App {
input: Option<OsString>,
output: Option<OsString>,
}
fn parse_args() -> App {
let mut app = App::default();
let mut args = std::env::args_os().skip(1).peekable();
while let Some(arg) = args.next() {
match (arg.to_string_lossy().as_ref(), args.peek()) {
("-h" | "--help", _) => {
eprint!("{}", include_str!("./help.txt"));
exit(0);
}
("-v" | "--version", _) => {
eprintln!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
exit(0);
}
(flag @ ("-o" | "--output"), o) => match o {
Some(o) => {
app.output = Some(o.into());
args.next();
}
None => {
eprintln!("please supply an argument to {}", flag);
exit(1);
}
},
("-", _) => {}
(file, _) if !file.starts_with('-') => {
if app.input.is_some() {
eprint!("too many arguments\n\n{}", include_str!("./help.txt"));
exit(1)
}
app.input = Some(file.into());
}
(flag, _) => {
eprint!("unknown flag: {}\n\n{}", flag, include_str!("./help.txt"));
exit(1)
}
}
}
app
}
fn run() -> Result<(), std::io::Error> {
let app = parse_args();
let content = match app.input {
Some(path) => std::fs::read_to_string(path)?,
None => {
let mut s = String::new();
std::io::stdin().read_to_string(&mut s)?;
s
}
};
let parser = jotdown::Parser::new(&content);
match app.output {
Some(path) => jotdown::html::write(parser, File::create(path)?)?,
None => jotdown::html::write(parser, BufWriter::new(std::io::stdout()))?,
}
Ok(())
}
fn main() {
let mut src = String::new();
std::io::stdin()
.read_to_string(&mut src)
.expect("failed to read utf-8 file");
let events = jotdown::Parser::new(&src);
let mut out = std::io::BufWriter::new(std::io::stdout());
jotdown::html::write(events, &mut out).unwrap();
match run() {
Ok(()) => {}
Err(e) => {
eprintln!("{}", e);
exit(1);
}
}
}