#![deny(unsafe_code)] #![warn(clippy::all)] mod cli; mod config; mod generator; mod parser; mod types; #[macro_use] extern crate log; use cli::{Command, ConfigCommand}; use generator::generate; use anyhow::{Context, Result}; use codemap::CodeMap; use codemap_diagnostic::{Diagnostic, Emitter, Level}; use structopt::StructOpt; fn into_diagnostic(err: &anyhow::Error) -> Diagnostic { if let Some(err) = err.downcast_ref::() { err.into() } else { Diagnostic { level: Level::Error, message: err.to_string(), code: None, spans: vec![], } } } fn main() { let mut codemap = CodeMap::new(); match start(&mut codemap) { Ok(()) => {} Err(err) => { let mut emitter = Emitter::stderr(codemap_diagnostic::ColorConfig::Auto, Some(&codemap)); let mut diagnostics = Vec::new(); diagnostics.push(into_diagnostic(&err)); if let Some(mut source) = err.source() { diagnostics.push(Diagnostic { level: Level::Note, message: format!("Caused by: {}", source), code: None, spans: vec![], }); while let Some(source2) = source.source() { source = source2; diagnostics.push(Diagnostic { level: Level::Note, message: format!("Caused by: {}", source), code: None, spans: vec![], }); } } emitter.emit(&diagnostics); } } } fn start(codemap: &mut CodeMap) -> Result<()> { let cli = cli::Cli::from_args(); pretty_env_logger::formatted_builder() .filter( None, match cli.verbosity { // Warnings and errors for internal warnings / errors 0 => log::LevelFilter::Warn, 1 => log::LevelFilter::Info, 2 => log::LevelFilter::Debug, _ => log::LevelFilter::Trace, }, ) .try_init()?; std::env::set_current_dir(&cli.directory) .with_context(|| format!("Cannot change current directory to: {:?}", cli.directory))?; match &cli.command { Command::Generate { file } => { let file = file.clone(); let config = load_effective_config(cli, codemap)?; let entities = if let Some(file) = file { parser::clang::parse_file(file, &config.clang)? } else { parser::clang::parse_compile_commands(&config.clang)? }; let base_output_dir = std::path::Path::new("doc"); generate(&base_output_dir, entities, &config.generator)?; } Command::Inspect { file } => { let file = file.clone(); let config = load_effective_config(cli, codemap)?; let entities = if let Some(file) = file { parser::clang::parse_file(file, &config.clang)? } else { parser::clang::parse_compile_commands(&config.clang)? }; serde_json::to_writer_pretty(std::io::stdout().lock(), &entities)?; } Command::Config { command: ConfigCommand::Default, } => { print!("{}", toml::to_string_pretty(&config::Config::default())?); } Command::Config { command: ConfigCommand::Show, } => { print!( "{}", toml::to_string_pretty(&load_effective_config(cli, codemap)?)? ); } } Ok(()) } fn load_effective_config(cli: cli::Cli, codemap: &mut CodeMap) -> Result { let conf_file_conf = config::load_config(".", codemap)?; Ok(config::Config::from_merge(cli, conf_file_conf)?) }