From a53c6f6feef231ecfb4e66d0e446e4148e816a2c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 26 Aug 2020 12:21:12 +0200 Subject: Allow redirecting logs to a specific file There's a surprising lack of crates which are like env_logger, but also allow writing to a file. Let's write our own then! --- crates/rust-analyzer/src/bin/args.rs | 14 +++++-- crates/rust-analyzer/src/bin/logger.rs | 73 ++++++++++++++++++++++++++++++++++ crates/rust-analyzer/src/bin/main.rs | 25 +++++++++--- 3 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 crates/rust-analyzer/src/bin/logger.rs (limited to 'crates') diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs index 0bc92431a..45dc62ea7 100644 --- a/crates/rust-analyzer/src/bin/args.rs +++ b/crates/rust-analyzer/src/bin/args.rs @@ -13,6 +13,7 @@ use vfs::AbsPathBuf; pub(crate) struct Args { pub(crate) verbosity: Verbosity, + pub(crate) log_file: Option, pub(crate) command: Command, } @@ -53,7 +54,11 @@ impl Args { if matches.contains("--version") { matches.finish().or_else(handle_extra_flags)?; - return Ok(Args { verbosity: Verbosity::Normal, command: Command::Version }); + return Ok(Args { + verbosity: Verbosity::Normal, + log_file: None, + command: Command::Version, + }); } let verbosity = match ( @@ -68,8 +73,9 @@ impl Args { (false, true, false) => Verbosity::Verbose, (false, true, true) => bail!("Invalid flags: -q conflicts with -v"), }; + let log_file = matches.opt_value_from_str("--log-file")?; - let help = Ok(Args { verbosity, command: Command::Help }); + let help = Ok(Args { verbosity, log_file: None, command: Command::Help }); let subcommand = match matches.subcommand()? { Some(it) => it, None => { @@ -78,7 +84,7 @@ impl Args { return help; } matches.finish().or_else(handle_extra_flags)?; - return Ok(Args { verbosity, command: Command::RunServer }); + return Ok(Args { verbosity, log_file, command: Command::RunServer }); } }; let command = match subcommand.as_str() { @@ -345,7 +351,7 @@ ARGS: return help; } }; - Ok(Args { verbosity, command }) + Ok(Args { verbosity, log_file, command }) } } diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs new file mode 100644 index 000000000..3bcb1ae37 --- /dev/null +++ b/crates/rust-analyzer/src/bin/logger.rs @@ -0,0 +1,73 @@ +//! Simple logger that logs either to stderr or to a file, using `env_logger` +//! filter syntax. Amusingly, there's no crates.io crate that can do this and +//! only this. + +use std::{ + fs::File, + io::{BufWriter, Write}, +}; + +use env_logger::filter::{Builder, Filter}; +use log::{Log, Metadata, Record}; +use parking_lot::Mutex; + +pub(crate) struct Logger { + filter: Filter, + file: Option>>, +} + +impl Logger { + pub(crate) fn new(log_file: Option, filter: Option<&str>) -> Logger { + let filter = { + let mut builder = Builder::new(); + if let Some(filter) = filter { + builder.parse(filter); + } + builder.build() + }; + + let file = log_file.map(|it| Mutex::new(BufWriter::new(it))); + + Logger { filter, file } + } + + pub(crate) fn install(self) { + let max_level = self.filter.filter(); + let _ = log::set_boxed_logger(Box::new(self)).map(|()| log::set_max_level(max_level)); + } +} + +impl Log for Logger { + fn enabled(&self, metadata: &Metadata) -> bool { + self.filter.enabled(metadata) + } + + fn log(&self, record: &Record) { + if !self.filter.matches(record) { + return; + } + match &self.file { + Some(w) => { + let _ = writeln!( + w.lock(), + "[{} {}] {}", + record.level(), + record.module_path().unwrap_or_default(), + record.args(), + ); + } + None => eprintln!( + "[{} {}] {}", + record.level(), + record.module_path().unwrap_or_default(), + record.args(), + ), + } + } + + fn flush(&self) { + if let Some(w) = &self.file { + let _ = w.lock().flush(); + } + } +} diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 0e03a0ca8..266768970 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -2,8 +2,9 @@ //! //! Based on cli flags, either spawns an LSP server, or runs a batch analysis mod args; +mod logger; -use std::{convert::TryFrom, process}; +use std::{convert::TryFrom, env, fs, path::PathBuf, process}; use lsp_server::Connection; use project_model::ProjectManifest; @@ -26,8 +27,8 @@ fn main() { } fn try_main() -> Result<()> { - setup_logging()?; let args = args::Args::parse()?; + setup_logging(args.log_file)?; match args.command { args::Command::RunServer => run_server()?, args::Command::ProcMacro => proc_macro_srv::cli::run()?, @@ -52,9 +53,21 @@ fn try_main() -> Result<()> { Ok(()) } -fn setup_logging() -> Result<()> { - std::env::set_var("RUST_BACKTRACE", "short"); - env_logger::try_init_from_env("RA_LOG")?; +fn setup_logging(log_file: Option) -> Result<()> { + env::set_var("RUST_BACKTRACE", "short"); + + let log_file = match log_file { + Some(path) => { + if let Some(parent) = path.parent() { + let _ = fs::create_dir_all(parent); + } + Some(fs::File::create(path)?) + } + None => None, + }; + let filter = env::var("RA_LOG").ok(); + logger::Logger::new(log_file, filter.as_deref()).install(); + profile::init(); Ok(()) } @@ -95,7 +108,7 @@ fn run_server() -> Result<()> { { Some(it) => it, None => { - let cwd = std::env::current_dir()?; + let cwd = env::current_dir()?; AbsPathBuf::assert(cwd) } }; -- cgit v1.2.3 From bb50614d8871f55ad4f0306cba289681a29c14ef Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 26 Aug 2020 12:52:42 +0200 Subject: Simplify help --- crates/rust-analyzer/src/bin/args.rs | 312 +++++++++------------------- crates/rust-analyzer/src/bin/main.rs | 4 +- crates/rust-analyzer/src/cli/diagnostics.rs | 7 +- 3 files changed, 99 insertions(+), 224 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs index 45dc62ea7..b724ae454 100644 --- a/crates/rust-analyzer/src/bin/args.rs +++ b/crates/rust-analyzer/src/bin/args.rs @@ -18,36 +18,93 @@ pub(crate) struct Args { } pub(crate) enum Command { - Parse { - no_dump: bool, - }, + Parse { no_dump: bool }, Symbols, - Highlight { - rainbow: bool, - }, + Highlight { rainbow: bool }, AnalysisStats(AnalysisStatsCmd), Bench(BenchCmd), - Diagnostics { - path: PathBuf, - load_output_dirs: bool, - with_proc_macro: bool, - /// Include files which are not modules. In rust-analyzer - /// this would include the parser test files. - all: bool, - }, - Ssr { - rules: Vec, - }, - StructuredSearch { - debug_snippet: Option, - patterns: Vec, - }, + Diagnostics { path: PathBuf, load_output_dirs: bool, with_proc_macro: bool }, + Ssr { rules: Vec }, + StructuredSearch { debug_snippet: Option, patterns: Vec }, ProcMacro, RunServer, Version, Help, } +const HELP: &str = "\ +rust-analyzer + +USAGE: + rust-analyzer [FLAGS] [COMMAND] [COMMAND_OPTIONS] + +FLAGS: + --version Print version + -h, --help Print this help + + -v, --verbose + -vv, --spammy + -q, --quiet Set verbosity + + --log-file Log to the specified filed instead of stderr + +ENVIRONMENTAL VARIABLES: + RA_LOG Set log filter in env_logger format + RA_PROFILE Enable hierarchical profiler + +COMMANDS: + +not specified Launch LSP server + +parse < main.rs Parse tree + --no-dump Suppress printing + +symbols < main.rs Parse input an print the list of symbols + +highlight < main.rs Highlight input as html + --rainbow Enable rainbow highlighting of identifiers + +analysis-stats Batch typecheck project and print summary statistics + Directory with Cargo.toml + --randomize Randomize order in which crates, modules, and items are processed + --parallel Run type inference in parallel + --memory-usage Collect memory usage statistics + -o, --only Only analyze items matching this path + --with-deps Also analyze all dependencies + --load-output-dirs + Load OUT_DIR values by running `cargo check` before analysis + --with-proc-macro Use proc-macro-srv for proc-macro expanding + +analysis-bench Benchmark specific analysis operation + Directory with Cargo.toml + --highlight + Compute syntax highlighting for this file + --complete + Compute completions at this location + --goto-def + Compute goto definition at this location + --memory-usage Collect memory usage statistics + --load-output-dirs + Load OUT_DIR values by running `cargo check` before analysis + --with-proc-macro Use proc-macro-srv for proc-macro expanding + +diagnostics + Directory with Cargo.toml + --load-output-dirs + Load OUT_DIR values by running `cargo check` before analysis + --with-proc-macro Use proc-macro-srv for proc-macro expanding + +ssr [RULE...] + A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`) + --debug Prints debug information for any nodes with source exactly + equal to + +search [PATTERN..] + A structured search replace pattern (`$a.foo($b)`) + --debug Prints debug information for any nodes with source exactly + equal to +"; + impl Args { pub(crate) fn parse() -> Result { let mut matches = Arguments::from_env(); @@ -75,108 +132,34 @@ impl Args { }; let log_file = matches.opt_value_from_str("--log-file")?; - let help = Ok(Args { verbosity, log_file: None, command: Command::Help }); + if matches.contains(["-h", "--help"]) { + eprintln!("{}", HELP); + return Ok(Args { verbosity, log_file: None, command: Command::Help }); + } + let subcommand = match matches.subcommand()? { Some(it) => it, None => { - if matches.contains(["-h", "--help"]) { - print_subcommands(); - return help; - } matches.finish().or_else(handle_extra_flags)?; return Ok(Args { verbosity, log_file, command: Command::RunServer }); } }; let command = match subcommand.as_str() { "parse" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ -rust-analyzer parse - -USAGE: - rust-analyzer parse [FLAGS] - -FLAGS: - -h, --help Prints help information - --no-dump" - ); - return help; - } - let no_dump = matches.contains("--no-dump"); matches.finish().or_else(handle_extra_flags)?; Command::Parse { no_dump } } "symbols" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ -rust-analyzer symbols - -USAGE: - rust-analyzer highlight [FLAGS] - -FLAGS: - -h, --help Prints help inforamtion" - ); - return help; - } - matches.finish().or_else(handle_extra_flags)?; - Command::Symbols } "highlight" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ -rust-analyzer highlight - -USAGE: - rust-analyzer highlight [FLAGS] - -FLAGS: - -h, --help Prints help information - -r, --rainbow" - ); - return help; - } - - let rainbow = matches.contains(["-r", "--rainbow"]); + let rainbow = matches.contains("--rainbow"); matches.finish().or_else(handle_extra_flags)?; Command::Highlight { rainbow } } "analysis-stats" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ -rust-analyzer analysis-stats - -USAGE: - rust-analyzer analysis-stats [FLAGS] [OPTIONS] [PATH] - -FLAGS: - -o, --only Only analyze items matching this path - -h, --help Prints help information - --memory-usage Collect memory usage statistics - --randomize Randomize order in which crates, modules, and items are processed - --parallel Run type inference in parallel - --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis - --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding - --with-deps Also analyze all dependencies - -v, --verbose - -q, --quiet - -OPTIONS: - -o - -ARGS: - " - ); - return help; - } - let randomize = matches.contains("--randomize"); let parallel = matches.contains("--parallel"); let memory_usage = matches.contains("--memory-usage"); @@ -204,34 +187,6 @@ ARGS: }) } "analysis-bench" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ -rust-analyzer analysis-bench - -USAGE: - rust-analyzer analysis-bench [FLAGS] [OPTIONS] - -FLAGS: - -h, --help Prints help information - --memory-usage Collect memory usage statistics - --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis - --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding - -v, --verbose - -OPTIONS: - --project Path to directory with Cargo.toml - --complete Compute completions at this location - --goto-def Compute goto definition at this location - --highlight Hightlight this file - -ARGS: - Project to analyse" - ); - return help; - } - - let path: PathBuf = matches.opt_value_from_str("--project")?.unwrap_or_default(); let highlight_path: Option = matches.opt_value_from_str("--highlight")?; let complete_path: Option = matches.opt_value_from_str("--complete")?; let goto_def_path: Option = matches.opt_value_from_str("--goto-def")?; @@ -249,6 +204,15 @@ ARGS: let memory_usage = matches.contains("--memory-usage"); let load_output_dirs = matches.contains("--load-output-dirs"); let with_proc_macro = matches.contains("--with-proc-macro"); + + let path = { + let mut trailing = matches.free()?; + if trailing.len() != 1 { + bail!("Invalid flags"); + } + trailing.pop().unwrap().into() + }; + Command::Bench(BenchCmd { memory_usage, path, @@ -258,28 +222,8 @@ ARGS: }) } "diagnostics" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ -rust-analyzer diagnostics - -USAGE: - rust-analyzer diagnostics [FLAGS] [PATH] - -FLAGS: - -h, --help Prints help information - --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis - --all Include all files rather than only modules - -ARGS: - " - ); - return help; - } - let load_output_dirs = matches.contains("--load-output-dirs"); let with_proc_macro = matches.contains("--with-proc-macro"); - let all = matches.contains("--all"); let path = { let mut trailing = matches.free()?; if trailing.len() != 1 { @@ -288,30 +232,10 @@ ARGS: trailing.pop().unwrap().into() }; - Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } + Command::Diagnostics { path, load_output_dirs, with_proc_macro } } "proc-macro" => Command::ProcMacro, "ssr" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ -rust-analyzer ssr - -USAGE: - rust-analyzer ssr [FLAGS] [RULE...] - -EXAMPLE: - rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)' - -FLAGS: - --debug Prints debug information for any nodes with source exactly equal to - -h, --help Prints help information - -ARGS: - A structured search replace rule" - ); - return help; - } let mut rules = Vec::new(); while let Some(rule) = matches.free_from_str()? { rules.push(rule); @@ -319,26 +243,6 @@ ARGS: Command::Ssr { rules } } "search" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ -rust-analyzer search - -USAGE: - rust-analyzer search [FLAGS] [PATTERN...] - -EXAMPLE: - rust-analyzer search '$a.foo($b)' - -FLAGS: - --debug Prints debug information for any nodes with source exactly equal to - -h, --help Prints help information - -ARGS: - A structured search pattern" - ); - return help; - } let debug_snippet = matches.opt_value_from_str("--debug")?; let mut patterns = Vec::new(); while let Some(rule) = matches.free_from_str()? { @@ -347,38 +251,14 @@ ARGS: Command::StructuredSearch { patterns, debug_snippet } } _ => { - print_subcommands(); - return help; + eprintln!("{}", HELP); + return Ok(Args { verbosity, log_file: None, command: Command::Help }); } }; Ok(Args { verbosity, log_file, command }) } } -fn print_subcommands() { - eprintln!( - "\ -rust-analyzer - -USAGE: - rust-analyzer - -FLAGS: - -h, --help Prints help information - -SUBCOMMANDS: - analysis-bench - analysis-stats - highlight - diagnostics - proc-macro - parse - search - ssr - symbols" - ) -} - fn handle_extra_flags(e: pico_args::Error) -> Result<()> { if let pico_args::Error::UnusedArgsLeft(flags) = e { let mut invalid_flags = String::new(); diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 266768970..ba4402ade 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -38,8 +38,8 @@ fn try_main() -> Result<()> { args::Command::Highlight { rainbow } => cli::highlight(rainbow)?, args::Command::AnalysisStats(cmd) => cmd.run(args.verbosity)?, args::Command::Bench(cmd) => cmd.run(args.verbosity)?, - args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { - cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? + args::Command::Diagnostics { path, load_output_dirs, with_proc_macro } => { + cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro)? } args::Command::Ssr { rules } => { cli::apply_ssr_rules(rules)?; diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index c424aa6e2..f3b6c900e 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs @@ -12,12 +12,7 @@ use ide::{DiagnosticsConfig, Severity}; use crate::cli::{load_cargo::load_cargo, Result}; -pub fn diagnostics( - path: &Path, - load_output_dirs: bool, - with_proc_macro: bool, - _all: bool, -) -> Result<()> { +pub fn diagnostics(path: &Path, load_output_dirs: bool, with_proc_macro: bool) -> Result<()> { let (host, _vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?; let db = host.raw_database(); let analysis = host.analysis(); -- cgit v1.2.3 From ed6304131a5a738da72b88d5deb67be4555b4c7f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 26 Aug 2020 13:06:43 +0200 Subject: Simplify --- crates/rust-analyzer/src/bin/args.rs | 175 ++++++++++++++--------------------- 1 file changed, 69 insertions(+), 106 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs index b724ae454..41ce5cae9 100644 --- a/crates/rust-analyzer/src/bin/args.rs +++ b/crates/rust-analyzer/src/bin/args.rs @@ -5,7 +5,7 @@ use std::{env, fmt::Write, path::PathBuf}; -use anyhow::{bail, Result}; +use anyhow::{bail, format_err, Result}; use pico_args::Arguments; use rust_analyzer::cli::{AnalysisStatsCmd, BenchCmd, BenchWhat, Position, Verbosity}; use ssr::{SsrPattern, SsrRule}; @@ -96,8 +96,6 @@ diagnostics ssr [RULE...] A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`) - --debug Prints debug information for any nodes with source exactly - equal to search [PATTERN..] A structured search replace pattern (`$a.foo($b)`) @@ -145,116 +143,81 @@ impl Args { } }; let command = match subcommand.as_str() { - "parse" => { - let no_dump = matches.contains("--no-dump"); - matches.finish().or_else(handle_extra_flags)?; - Command::Parse { no_dump } - } - "symbols" => { - matches.finish().or_else(handle_extra_flags)?; - Command::Symbols - } - "highlight" => { - let rainbow = matches.contains("--rainbow"); - matches.finish().or_else(handle_extra_flags)?; - Command::Highlight { rainbow } - } - "analysis-stats" => { - let randomize = matches.contains("--randomize"); - let parallel = matches.contains("--parallel"); - let memory_usage = matches.contains("--memory-usage"); - let only: Option = matches.opt_value_from_str(["-o", "--only"])?; - let with_deps: bool = matches.contains("--with-deps"); - let load_output_dirs = matches.contains("--load-output-dirs"); - let with_proc_macro = matches.contains("--with-proc-macro"); - let path = { - let mut trailing = matches.free()?; - if trailing.len() != 1 { - bail!("Invalid flags"); - } - trailing.pop().unwrap().into() - }; - - Command::AnalysisStats(AnalysisStatsCmd { - randomize, - parallel, - memory_usage, - only, - with_deps, - path, - load_output_dirs, - with_proc_macro, - }) - } - "analysis-bench" => { - let highlight_path: Option = matches.opt_value_from_str("--highlight")?; - let complete_path: Option = matches.opt_value_from_str("--complete")?; - let goto_def_path: Option = matches.opt_value_from_str("--goto-def")?; - let what = match (highlight_path, complete_path, goto_def_path) { - (Some(path), None, None) => { - let path = env::current_dir().unwrap().join(path); - BenchWhat::Highlight { path: AbsPathBuf::assert(path) } - } - (None, Some(position), None) => BenchWhat::Complete(position), - (None, None, Some(position)) => BenchWhat::GotoDef(position), - _ => panic!( - "exactly one of `--highlight`, `--complete` or `--goto-def` must be set" - ), - }; - let memory_usage = matches.contains("--memory-usage"); - let load_output_dirs = matches.contains("--load-output-dirs"); - let with_proc_macro = matches.contains("--with-proc-macro"); - - let path = { - let mut trailing = matches.free()?; - if trailing.len() != 1 { - bail!("Invalid flags"); + "parse" => Command::Parse { no_dump: matches.contains("--no-dump") }, + "symbols" => Command::Symbols, + "highlight" => Command::Highlight { rainbow: matches.contains("--rainbow") }, + "analysis-stats" => Command::AnalysisStats(AnalysisStatsCmd { + randomize: matches.contains("--randomize"), + parallel: matches.contains("--parallel"), + memory_usage: matches.contains("--memory-usage"), + only: matches.opt_value_from_str(["-o", "--only"])?, + with_deps: matches.contains("--with-deps"), + load_output_dirs: matches.contains("--load-output-dirs"), + with_proc_macro: matches.contains("--with-proc-macro"), + path: matches + .free_from_str()? + .ok_or_else(|| format_err!("expected positional argument"))?, + }), + "analysis-bench" => Command::Bench(BenchCmd { + what: { + let highlight_path: Option = + matches.opt_value_from_str("--highlight")?; + let complete_path: Option = + matches.opt_value_from_str("--complete")?; + let goto_def_path: Option = + matches.opt_value_from_str("--goto-def")?; + match (highlight_path, complete_path, goto_def_path) { + (Some(path), None, None) => { + let path = env::current_dir().unwrap().join(path); + BenchWhat::Highlight { path: AbsPathBuf::assert(path) } + } + (None, Some(position), None) => BenchWhat::Complete(position), + (None, None, Some(position)) => BenchWhat::GotoDef(position), + _ => panic!( + "exactly one of `--highlight`, `--complete` or `--goto-def` must be set" + ), + } + }, + memory_usage: matches.contains("--memory-usage"), + load_output_dirs: matches.contains("--load-output-dirs"), + with_proc_macro: matches.contains("--with-proc-macro"), + path: matches + .free_from_str()? + .ok_or_else(|| format_err!("expected positional argument"))?, + }), + "diagnostics" => Command::Diagnostics { + load_output_dirs: matches.contains("--load-output-dirs"), + with_proc_macro: matches.contains("--with-proc-macro"), + path: matches + .free_from_str()? + .ok_or_else(|| format_err!("expected positional argument"))?, + }, + "proc-macro" => Command::ProcMacro, + "ssr" => Command::Ssr { + rules: { + let mut acc = Vec::new(); + while let Some(rule) = matches.free_from_str()? { + acc.push(rule); } - trailing.pop().unwrap().into() - }; - - Command::Bench(BenchCmd { - memory_usage, - path, - what, - load_output_dirs, - with_proc_macro, - }) - } - "diagnostics" => { - let load_output_dirs = matches.contains("--load-output-dirs"); - let with_proc_macro = matches.contains("--with-proc-macro"); - let path = { - let mut trailing = matches.free()?; - if trailing.len() != 1 { - bail!("Invalid flags"); + acc + }, + }, + "search" => Command::StructuredSearch { + debug_snippet: matches.opt_value_from_str("--debug")?, + patterns: { + let mut acc = Vec::new(); + while let Some(rule) = matches.free_from_str()? { + acc.push(rule); } - trailing.pop().unwrap().into() - }; - - Command::Diagnostics { path, load_output_dirs, with_proc_macro } - } - "proc-macro" => Command::ProcMacro, - "ssr" => { - let mut rules = Vec::new(); - while let Some(rule) = matches.free_from_str()? { - rules.push(rule); - } - Command::Ssr { rules } - } - "search" => { - let debug_snippet = matches.opt_value_from_str("--debug")?; - let mut patterns = Vec::new(); - while let Some(rule) = matches.free_from_str()? { - patterns.push(rule); - } - Command::StructuredSearch { patterns, debug_snippet } - } + acc + }, + }, _ => { eprintln!("{}", HELP); return Ok(Args { verbosity, log_file: None, command: Command::Help }); } }; + matches.finish().or_else(handle_extra_flags)?; Ok(Args { verbosity, log_file, command }) } } -- cgit v1.2.3