git-trim 0.4.2

Automatically trims your tracking branches whose upstream branches are merged or stray
Documentation
use git_trim::args::Args;

use clap::{App, ArgSettings, IntoApp};
use man::prelude::*;
use regex::Regex;
use rson_rs::value::Value;

fn main() {
    let app: App = <Args as IntoApp>::into_app();

    let mut page = Manual::new(&app.name).flag(
        Flag::new()
            .short("-h")
            .long("--help")
            .help("Prints help information"),
    );

    if let Some(about) = app.about {
        page = page.about(about);
    }

    let malformed_values = Regex::new("(id|settings|validator): .+?, ").unwrap();
    for arg in app.args.args {
        let printed = malformed_values
            .replace_all(&format!("{:?}", arg), "")
            .replace("\\'", "'")
            .to_string();
        let parsed = match Value::from_str(&printed) {
            Ok(value) => value,
            Err(err) => panic!("{:?}", err),
        };

        let hidden = arg.is_set(ArgSettings::Hidden);
        if hidden {
            continue;
        }

        let name = arg.name;
        let short_help = arg.help;
        let long_help = get_string(&parsed, "long_help");
        let help = match (short_help, long_help) {
            (None, None) => None,
            (Some(help), None) | (None, Some(help)) => Some(help),
            (Some(_), Some(long_help)) => Some(long_help),
        };
        let short = arg.short;
        let long = arg.long;
        let flag = !arg.is_set(ArgSettings::TakesValue);
        if flag {
            page = page.flag({
                let mut flag = Flag::new();
                if let Some(short) = short {
                    flag = flag.short(&format!("-{}", short))
                }
                if let Some(long) = long {
                    flag = flag.long(&format!("--{}", long));
                }
                if let Some(help) = help {
                    flag = flag.help(&help);
                }
                flag
            });
        } else {
            page = page.option({
                let mut opt = Opt::new(name);
                if let Some(short) = short {
                    opt = opt.short(&format!("-{}", short))
                }
                if let Some(long) = long {
                    opt = opt.long(&format!("--{}", long));
                }
                if let Some(help) = help {
                    opt = opt.help(&help);
                }
                opt
            });
        }
    }

    println!("{}", page.render());
}

fn get_string<'a>(value: &'a Value, key: &str) -> Option<&'a str> {
    let map = match value {
        Value::Map(map) => map,
        _ => panic!("top level should be a map"),
    };
    match &map[&Value::String(key.to_string())] {
        Value::String(string) => return Some(string.as_str()),
        Value::Option(None) => return None,
        Value::Option(Some(value)) => {
            if let Value::String(string) = value.as_ref() {
                return Some(string.as_str());
            }
        }
        _ => {}
    }
    panic!("key not exist: {}", key)
}