bat

概要

github.com

出力の整形や構文ハイライトをしてくれるツール。

プロジェクト構成

src構成

▾  src/
  ▾  bin/bat/
       ツールファイル一式
       app.rs
       assets.rs
       clap_app.rs
       config.rs
       directories.rs
       input.rs
       main.rs
     lib.rs
     ソースファイル一式

main関数

fn main() {
    // 実行
    let result = run();

    // 最後にエラーをハンドリングする
    match result {
        Err(error) => {
            let stderr = std::io::stderr();
            default_error_handler(&error, &mut stderr.lock());
            process::exit(1);
        }
        Ok(false) => {
            process::exit(1);
        }
        Ok(true) => {
            process::exit(0);
        }
    }
}

run関数概要

/// Returns `Err(..)` upon fatal errors. Otherwise, returns `Ok(true)` on full success and
/// `Ok(false)` if any intermediate errors occurred (were printed).
fn run() -> Result<bool> {
    // エラーをプロパゲーションしていく
    let app = App::new()?;

    省略

その他

エラーハンドリング

error_chainを使っている

error_chain! {
    foreign_links {
        Clap(::clap::Error) #[cfg(feature = "application")];
        Io(::std::io::Error);
        SyntectError(::syntect::LoadingError);
        ParseIntError(::std::num::ParseIntError);
        GlobParsingError(::globset::Error);
        SerdeYamlError(::serde_yaml::Error);
    }

    errors {
        UndetectedSyntax(input: String) {
            description("unable to detect syntax"),
            display("unable to detect syntax for {}", input)
        }
        UnknownSyntax(name: String) {
            description("unknown syntax"),
            display("unknown syntax: '{}'", name)
        }
        InvalidPagerValueBat {
            description("invalid value `bat` for pager property"),
            display("Use of bat as a pager is disallowed in order to avoid infinite recursion problems")
        }
    }
}
コマンドライン引数のパース

clapを使用している

use clap::ArgMatches;

fn matches(interactive_output: bool) -> Result<ArgMatches<'static>> {
    let args = if wild::args_os().nth(1) == Some("cache".into())
        || wild::args_os().any(|arg| arg == "--no-config")
    {
        // Skip the arguments in bats config file

        wild::args_os().collect::<Vec<_>>()
    } else {
        let mut cli_args = wild::args_os();

        // Read arguments from bats config file
        let mut args = get_args_from_env_var()
            .unwrap_or_else(get_args_from_config_file)
            .chain_err(|| "Could not parse configuration file")?;

        // Put the zero-th CLI argument (program name) first
        args.insert(0, cli_args.next().unwrap());

        // .. and the rest at the end
        cli_args.for_each(|a| args.push(a));

        args
    };

    Ok(clap_app::build_app(interactive_output).get_matches_from(args))
}

関連

Rust のエラーまわりの変遷 - Qiita

  • error_chain 開発中止