gmi2html 0.1.8

Convert text/gemini into HTML
Documentation
use gmi2html::GeminiConverter;
use std::env;
use std::ffi::OsString;
use std::io::{self, Read};

use std::path::PathBuf;
use std::process::exit;
use std::str::FromStr;

fn main() {
    let mut buffer = String::new();
    // Basic CLI with hard-coded defaults TODO add cli
    let args = Args::from_env();
    io::stdin().read_to_string(&mut buffer).unwrap();
    let res = GeminiConverter::new(&buffer)
        .proxy_url(&args.proxy_url)
        .inline_images(args.inline_images)
        .to_html();
    println!("{}", res);
}

// Arg parser.

fn usage() -> ! {
    let name = env::args().next().unwrap();
    eprintln!(
        "usage: {} [-i] [-p PROXY_URL]

Reads gemtext from stdin, outputs html to stdout

FLAGS
-i  include in-line images (default: false)

ARGS:
-p  proxy URL (default https://portal.mozz.us/gemini/)",
        name
    );
    exit(1)
}

#[derive(Default)]
pub struct Args {
    pub inline_images: bool,
    pub proxy_url: String,
}

impl Args {
    pub fn default() -> Self {
        Args {
            inline_images: false,
            proxy_url: "https://portal.mozz.us/gemini".to_owned(),
        }
    }

    pub fn from_env() -> Self {
        let mut out = Self::default();
        let mut args = env::args_os().skip(1);
        while let Some(arg) = args.next() {
            let s = arg.to_string_lossy();
            let mut ch_iter = s.chars();
            if ch_iter.next() != Some('-') {
                // out.positional.push(arg);
                continue;
            }
            ch_iter.for_each(|m| match m {
                // Edit these lines //
                'p' => out.proxy_url = parse_arg(args.next()),
                'i' => out.inline_images = true,
                // Stop editing //
                _ => {
                    usage();
                }
            })
        }
        out
    }
}

#[allow(dead_code)]
fn parse_arg<T: FromStr>(a: Option<OsString>) -> T {
    a.and_then(|a| a.into_string().ok())
        .and_then(|a| a.parse().ok())
        .unwrap_or_else(|| usage())
}

#[allow(dead_code)]
fn parse_os_arg<T: From<OsString>>(a: Option<OsString>) -> T {
    match a {
        Some(s) => T::from(s),
        None => usage(),
    }
}