From 735845d86e6ab94891e421823158f374e2f3412a Mon Sep 17 00:00:00 2001 From: Geobert Quach Date: Tue, 10 Sep 2019 11:31:40 +0100 Subject: refactor(args): Switch to pico-args --- crates/ra_cli/Cargo.toml | 2 +- crates/ra_cli/src/help.rs | 96 ++++++++++++++++++++++++ crates/ra_cli/src/main.rs | 186 +++++++++++++++++++++++++++------------------- 3 files changed, 206 insertions(+), 78 deletions(-) create mode 100644 crates/ra_cli/src/help.rs (limited to 'crates/ra_cli') diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index 205dd223b..d42ac3ad4 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml @@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"] publish = false [dependencies] -clap = { version = "2.32.0", default-features = false } +pico-args = "0.2.0" flexi_logger = "0.14.0" indicatif = "0.11.0" diff --git a/crates/ra_cli/src/help.rs b/crates/ra_cli/src/help.rs new file mode 100644 index 000000000..bf31472ac --- /dev/null +++ b/crates/ra_cli/src/help.rs @@ -0,0 +1,96 @@ +pub fn print_global_help() { + println!( + "ra-cli + +USAGE: + ra_cli + +FLAGS: + -h, --help Prints help information + +SUBCOMMANDS: + analysis-bench + analysis-stats + highlight + parse + symbols" + ) +} + +pub fn print_analysis_bench_help() { + println!( + "ra_cli-analysis-bench + +USAGE: + ra_cli analysis-bench [FLAGS] [OPTIONS] [PATH] + +FLAGS: + -h, --help Prints help information + -v, --verbose + +OPTIONS: + --complete Compute completions at this location + --highlight Hightlight this file + +ARGS: + Project to analyse" + ) +} + +pub fn print_analysis_stats_help() { + println!( + "ra-cli-analysis-stats + +USAGE: + ra_cli analysis-stats [FLAGS] [OPTIONS] [PATH] + +FLAGS: + -h, --help Prints help information + --memory-usage + -v, --verbose + +OPTIONS: + -o + +ARGS: + " + ) +} + +pub fn print_highlight_help() { + println!( + "ra-cli-highlight + +USAGE: + ra_cli highlight [FLAGS] + +FLAGS: + -h, --help Prints help information + -r, --rainbow" + ) +} + +pub fn print_symbols_help() { + println!( + "ra-cli-symbols + +USAGE: + ra_cli highlight [FLAGS] + +FLAGS: + -h, --help Prints help inforamtion" + ) +} + +pub fn print_parse_help() { + println!( + "ra-cli-parse + +USAGE: + ra_cli parse [FLAGS] + +FLAGS: + -h, --help Prints help inforamtion + --no-dump" + ) +} diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index de8191ca3..9e6f869c1 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs @@ -1,10 +1,11 @@ mod analysis_stats; mod analysis_bench; +mod help; -use std::{error::Error, io::Read}; +use std::{error::Error, fmt::Write, io::Read}; -use clap::{App, Arg, SubCommand}; use flexi_logger::Logger; +use pico_args::Arguments; use ra_ide_api::{file_structure, Analysis}; use ra_prof::profile; use ra_syntax::{AstNode, SourceFile}; @@ -13,93 +14,124 @@ type Result = std::result::Result>; fn main() -> Result<()> { Logger::with_env().start()?; - let matches = App::new("ra-cli") - .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) - .subcommand(SubCommand::with_name("symbols")) - .subcommand( - SubCommand::with_name("highlight") - .arg(Arg::with_name("rainbow").short("r").long("rainbow")), - ) - .subcommand( - SubCommand::with_name("analysis-stats") - .arg(Arg::with_name("verbose").short("v").long("verbose")) - .arg(Arg::with_name("memory-usage").long("memory-usage")) - .arg(Arg::with_name("only").short("o").takes_value(true)) - .arg(Arg::with_name("path")), - ) - .subcommand( - SubCommand::with_name("analysis-bench") - .arg(Arg::with_name("verbose").short("v").long("verbose")) - .arg( - Arg::with_name("highlight") - .long("highlight") - .takes_value(true) - .conflicts_with("complete") - .value_name("PATH") - .help("highlight this file"), - ) - .arg( - Arg::with_name("complete") - .long("complete") - .takes_value(true) - .conflicts_with("highlight") - .value_name("PATH:LINE:COLUMN") - .help("compute completions at this location"), - ) - .arg(Arg::with_name("path").value_name("PATH").help("project to analyze")), - ) - .get_matches(); - match matches.subcommand() { - ("parse", Some(matches)) => { - let _p = profile("parsing"); - let file = file()?; - if !matches.is_present("no-dump") { - println!("{:#?}", file.syntax()); + + let subcommand = std::env::args_os().nth(1); + if subcommand.is_none() { + help::print_global_help(); + return Ok(()); + } + let subcommand = subcommand.unwrap(); + let mut args: Vec<_> = std::env::args_os().collect(); + let mut matches = Arguments::from_vec(args.drain(2..).collect()); + + match &*subcommand.to_string_lossy() { + "parse" => { + if matches.contains(["-h", "--help"]) { + help::print_parse_help(); + return Ok(()); + } else { + let no_dump = matches.contains("--no-dump"); + matches.finish().or_else(handle_extra_flags)?; + + let _p = profile("parsing"); + let file = file()?; + if !no_dump { + println!("{:#?}", file.syntax()); + } + std::mem::forget(file); } - std::mem::forget(file); } - ("symbols", _) => { - let file = file()?; - for s in file_structure(&file) { - println!("{:?}", s); + "symbols" => { + if matches.contains(["-h", "--help"]) { + help::print_symbols_help(); + return Ok(()); + } else { + matches.finish().or_else(handle_extra_flags)?; + let file = file()?; + for s in file_structure(&file) { + println!("{:?}", s); + } } } - ("highlight", Some(matches)) => { - let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); - let html = analysis.highlight_as_html(file_id, matches.is_present("rainbow")).unwrap(); - println!("{}", html); + "highlight" => { + if matches.contains(["-h", "--help"]) { + help::print_highlight_help(); + return Ok(()); + } else { + let rainbow_opt = matches.contains(["-r", "--rainbow"]); + matches.finish().or_else(handle_extra_flags)?; + let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); + let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap(); + println!("{}", html); + } } - ("analysis-stats", Some(matches)) => { - let verbose = matches.is_present("verbose"); - let memory_usage = matches.is_present("memory-usage"); - let path = matches.value_of("path").unwrap_or(""); - let only = matches.value_of("only"); - analysis_stats::run(verbose, memory_usage, path.as_ref(), only)?; + "analysis-stats" => { + if matches.contains(["-h", "--help"]) { + help::print_analysis_stats_help(); + return Ok(()); + } else { + let verbose = matches.contains(["-v", "--verbose"]); + let memory_usage = matches.contains("--memory-usage"); + let path = matches.value_from_str("--path")?.unwrap_or("".to_string()); + let only = matches.value_from_str(["-o", "--only"])?.map(|v: String| v.to_owned()); + matches.finish().or_else(handle_extra_flags)?; + analysis_stats::run( + verbose, + memory_usage, + path.as_ref(), + only.as_ref().map(String::as_ref), + )?; + } } - ("analysis-bench", Some(matches)) => { - let verbose = matches.is_present("verbose"); - let path = matches.value_of("path").unwrap_or(""); - let op = if let Some(path) = matches.value_of("highlight") { - analysis_bench::Op::Highlight { path: path.into() } - } else if let Some(path_line_col) = matches.value_of("complete") { - let (path_line, column) = rsplit_at_char(path_line_col, ':')?; - let (path, line) = rsplit_at_char(path_line, ':')?; - analysis_bench::Op::Complete { - path: path.into(), - line: line.parse()?, - column: column.parse()?, - } + "analysis-bench" => { + if matches.contains(["-h", "--help"]) { + help::print_analysis_bench_help(); + return Ok(()); } else { - panic!("either --highlight or --complete must be set") - }; - analysis_bench::run(verbose, path.as_ref(), op)?; + let verbose = matches.contains(["-v", "--verbose"]); + let path = matches.value_from_str("--path")?.unwrap_or("".to_string()); + let highlight_path = matches.value_from_str("--highlight")?; + let complete_path = matches.value_from_str("--complete")?; + if highlight_path.is_some() && complete_path.is_some() { + panic!("either --highlight or --complete must be set, not both") + } + let op = if let Some(path) = highlight_path { + let path: String = path; + analysis_bench::Op::Highlight { path: path.into() } + } else if let Some(path_line_col) = complete_path { + let path_line_col: String = path_line_col; + let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?; + let (path, line) = rsplit_at_char(path_line, ':')?; + analysis_bench::Op::Complete { + path: path.into(), + line: line.parse()?, + column: column.parse()?, + } + } else { + panic!("either --highlight or --complete must be set") + }; + matches.finish().or_else(handle_extra_flags)?; + analysis_bench::run(verbose, path.as_ref(), op)?; + } } - _ => unreachable!(), + _ => help::print_global_help(), } Ok(()) } +fn handle_extra_flags(e: pico_args::Error) -> Result<()> { + if let pico_args::Error::UnusedArgsLeft(flags) = e { + let mut invalid_flags = String::new(); + for flag in flags { + write!(&mut invalid_flags, "{}, ", flag).expect("Error on write"); + } + let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2); + Err(format!("Invalid flags: {}", invalid_flags).into()) + } else { + Err(e.to_string().into()) + } +} + fn file() -> Result { let text = read_stdin()?; Ok(SourceFile::parse(&text).tree()) -- cgit v1.2.3