xhtml_minimizer 0.1.4

Minimize XHTML files.
Documentation
use std::env;
use std::fs;
use std::path::Path;
use xhtml_minimizer::*;
use xml_tokens::Tokenizer;

fn main() {
    let clargs = CLArgs::new();

    if clargs.verbose {
        println!("XHTML Minimizer\n");
        clargs.print();
    }

    if clargs.help {
        clargs.print_usage();
        std::process::exit(0);
    }

    let input_path = Path::new(&clargs.input_filename);
    let output_path = Path::new(&clargs.output_filename);

    match fs::read_to_string(input_path) {
        Ok(input) => {
            let mut tok = Tokenizer::new(input);
            let szr = XHTMLSerializer::new(false, false, false, false);

            if tok.tokenize_document() {
                match fs::write(output_path, szr.serialize(&tok.tokens)) {
                    Ok(_result) => {
                        if clargs.verbose {
                            print_statistics(
                                fs::metadata(clargs.input_filename).unwrap().len(),
                                fs::metadata(clargs.output_filename).unwrap().len(),
                            );
                        }
                    }
                    Err(_error) => println!("Failed to save output."),
                }
            } else {
                println!("{:?}", tok.error_messages);
            }
        }
        Err(_error) => panic!("Error reading input path into string."),
    }
}

fn print_statistics(input_size: u64, output_size: u64) {
    println!("Input file size: {} bytes", input_size);
    println!("Output file size: {} bytes", output_size);
    println!(
        "Absolute size reduction: {} bytes",
        input_size - output_size
    );
    println!(
        "Percentage size reduction: {:.0}%",
        100.0 * (1.0 - (output_size as f64 / input_size as f64))
    );
}

struct CLArgs {
    help: bool,
    input_filename: String,
    keep_comments: bool,
    keep_references: bool,
    keep_whitespace: bool,
    keep_xml_declaration: bool,
    output_filename: String,
    verbose: bool,
}
impl CLArgs {
    pub fn new() -> CLArgs {
        let mut help = false;
        let mut input_filename = String::from("index.xhtml");
        let mut keep_comments = false;
        let mut keep_references = false;
        let mut keep_whitespace = false;
        let mut keep_xml_declaration = false;
        let mut output_filename = String::from("output.xhtml");
        let mut verbose = false;

        let mut args: Vec<String> = env::args().collect();
        let mut i = 0;

        while i < args.len() {
            match args[i].as_ref() {
                "--help" | "-h" => {
                    help = true;
                }
                "--keep-comments" | "-c" => {
                    keep_comments = true;
                }
                "--keep-references" | "-r" => {
                    keep_references = true;
                }
                "--keep-whitespace" | "-w" => {
                    keep_whitespace = true;
                }
                "--keep-xml-declaration" | "-x" => {
                    keep_xml_declaration = true;
                }
                "--output" | "-o" => {
                    if i + 1 < args.len() {
                        output_filename = args.remove(i + 1);
                    } else {
                        panic!("Syntax error. Expected output filename.")
                    }
                }
                "--verbose" | "-v" => {
                    verbose = true;
                }

                _ => {
                    if i == args.len() - 1 {
                        input_filename = args.remove(i);
                    }
                }
            }

            i += 1;
        }

        CLArgs {
            help,
            input_filename,
            keep_comments,
            keep_references,
            keep_whitespace,
            keep_xml_declaration,
            output_filename,
            verbose,
        }
    }

    fn print(&self) {
        println!("Help: {}", self.help);
        println!("Input filename: {}", self.input_filename);
        println!("Keep comments: {}", self.keep_comments);
        println!("Keep references: {}", self.keep_references);
        println!("Keep whitespace: {}", self.keep_whitespace);
        println!("Keep XML declaration: {}", self.keep_xml_declaration);
        println!("Output filename: {}", self.output_filename);
        println!("Verbose: {}", self.verbose);
        println!("");
    }

    fn print_usage(&self) {
        println!("Usage: xhtml-minimizer [OPTIONS] INPUT_XHTML_FILE");
        println!("Options:");
        println!(" -h, --help\t\t\tshow this message and exit");
        println!(" -c, --keep-comments\t\tdo not omit XHTML comments");
        println!(" -r, --keep-references\t\tdo not replace entity and character references");
        println!(" -w, --keep-whitespace\t\tkeep all whitespace");
        println!(" -x, --keep-xml-declaration\tkeep any XML declaration");
        println!(" -o FILE, --output FILE\t\toutput to FILE");
        println!(" -v, --verbose\t\t\tprint messages");
        println!("\nFor more information see <https://gitlab.com/danieljrmay/xhtml_minimizer>")
    }
}