aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cli/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_cli/src/main.rs')
-rw-r--r--crates/ra_cli/src/main.rs143
1 files changed, 85 insertions, 58 deletions
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index de8191ca3..e6334cf56 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -1,10 +1,11 @@
1mod analysis_stats; 1mod analysis_stats;
2mod analysis_bench; 2mod analysis_bench;
3mod help;
3 4
4use std::{error::Error, io::Read}; 5use std::{error::Error, fmt::Write, io::Read};
5 6
6use clap::{App, Arg, SubCommand};
7use flexi_logger::Logger; 7use flexi_logger::Logger;
8use pico_args::Arguments;
8use ra_ide_api::{file_structure, Analysis}; 9use ra_ide_api::{file_structure, Analysis};
9use ra_prof::profile; 10use ra_prof::profile;
10use ra_syntax::{AstNode, SourceFile}; 11use ra_syntax::{AstNode, SourceFile};
@@ -13,77 +14,89 @@ type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
13 14
14fn main() -> Result<()> { 15fn main() -> Result<()> {
15 Logger::with_env().start()?; 16 Logger::with_env().start()?;
16 let matches = App::new("ra-cli") 17
17 .setting(clap::AppSettings::SubcommandRequiredElseHelp) 18 let subcommand = match std::env::args_os().nth(1) {
18 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) 19 None => {
19 .subcommand(SubCommand::with_name("symbols")) 20 eprintln!("{}", help::GLOBAL_HELP);
20 .subcommand( 21 return Ok(());
21 SubCommand::with_name("highlight") 22 }
22 .arg(Arg::with_name("rainbow").short("r").long("rainbow")), 23 Some(s) => s,
23 ) 24 };
24 .subcommand( 25 let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());
25 SubCommand::with_name("analysis-stats") 26
26 .arg(Arg::with_name("verbose").short("v").long("verbose")) 27 match &*subcommand.to_string_lossy() {
27 .arg(Arg::with_name("memory-usage").long("memory-usage")) 28 "parse" => {
28 .arg(Arg::with_name("only").short("o").takes_value(true)) 29 if matches.contains(["-h", "--help"]) {
29 .arg(Arg::with_name("path")), 30 eprintln!("{}", help::PARSE_HELP);
30 ) 31 return Ok(());
31 .subcommand( 32 }
32 SubCommand::with_name("analysis-bench") 33 let no_dump = matches.contains("--no-dump");
33 .arg(Arg::with_name("verbose").short("v").long("verbose")) 34 matches.finish().or_else(handle_extra_flags)?;
34 .arg( 35
35 Arg::with_name("highlight")
36 .long("highlight")
37 .takes_value(true)
38 .conflicts_with("complete")
39 .value_name("PATH")
40 .help("highlight this file"),
41 )
42 .arg(
43 Arg::with_name("complete")
44 .long("complete")
45 .takes_value(true)
46 .conflicts_with("highlight")
47 .value_name("PATH:LINE:COLUMN")
48 .help("compute completions at this location"),
49 )
50 .arg(Arg::with_name("path").value_name("PATH").help("project to analyze")),
51 )
52 .get_matches();
53 match matches.subcommand() {
54 ("parse", Some(matches)) => {
55 let _p = profile("parsing"); 36 let _p = profile("parsing");
56 let file = file()?; 37 let file = file()?;
57 if !matches.is_present("no-dump") { 38 if !no_dump {
58 println!("{:#?}", file.syntax()); 39 println!("{:#?}", file.syntax());
59 } 40 }
60 std::mem::forget(file); 41 std::mem::forget(file);
61 } 42 }
62 ("symbols", _) => { 43 "symbols" => {
44 if matches.contains(["-h", "--help"]) {
45 eprintln!("{}", help::SYMBOLS_HELP);
46 return Ok(());
47 }
48 matches.finish().or_else(handle_extra_flags)?;
63 let file = file()?; 49 let file = file()?;
64 for s in file_structure(&file) { 50 for s in file_structure(&file) {
65 println!("{:?}", s); 51 println!("{:?}", s);
66 } 52 }
67 } 53 }
68 ("highlight", Some(matches)) => { 54 "highlight" => {
55 if matches.contains(["-h", "--help"]) {
56 eprintln!("{}", help::HIGHLIGHT_HELP);
57 return Ok(());
58 }
59 let rainbow_opt = matches.contains(["-r", "--rainbow"]);
60 matches.finish().or_else(handle_extra_flags)?;
69 let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); 61 let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
70 let html = analysis.highlight_as_html(file_id, matches.is_present("rainbow")).unwrap(); 62 let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap();
71 println!("{}", html); 63 println!("{}", html);
72 } 64 }
73 ("analysis-stats", Some(matches)) => { 65 "analysis-stats" => {
74 let verbose = matches.is_present("verbose"); 66 if matches.contains(["-h", "--help"]) {
75 let memory_usage = matches.is_present("memory-usage"); 67 eprintln!("{}", help::ANALYSIS_STATS_HELP);
76 let path = matches.value_of("path").unwrap_or(""); 68 return Ok(());
77 let only = matches.value_of("only"); 69 }
78 analysis_stats::run(verbose, memory_usage, path.as_ref(), only)?; 70 let verbose = matches.contains(["-v", "--verbose"]);
71 let memory_usage = matches.contains("--memory-usage");
72 let path: String = matches.value_from_str("--path")?.unwrap_or_default();
73 let only = matches.value_from_str(["-o", "--only"])?.map(|v: String| v.to_owned());
74 matches.finish().or_else(handle_extra_flags)?;
75 analysis_stats::run(
76 verbose,
77 memory_usage,
78 path.as_ref(),
79 only.as_ref().map(String::as_ref),
80 )?;
79 } 81 }
80 ("analysis-bench", Some(matches)) => { 82 "analysis-bench" => {
81 let verbose = matches.is_present("verbose"); 83 if matches.contains(["-h", "--help"]) {
82 let path = matches.value_of("path").unwrap_or(""); 84 eprintln!("{}", help::ANALYSIS_BENCH_HELP);
83 let op = if let Some(path) = matches.value_of("highlight") { 85 return Ok(());
86 }
87 let verbose = matches.contains(["-v", "--verbose"]);
88 let path: String = matches.value_from_str("--path")?.unwrap_or_default();
89 let highlight_path = matches.value_from_str("--highlight")?;
90 let complete_path = matches.value_from_str("--complete")?;
91 if highlight_path.is_some() && complete_path.is_some() {
92 panic!("either --highlight or --complete must be set, not both")
93 }
94 let op = if let Some(path) = highlight_path {
95 let path: String = path;
84 analysis_bench::Op::Highlight { path: path.into() } 96 analysis_bench::Op::Highlight { path: path.into() }
85 } else if let Some(path_line_col) = matches.value_of("complete") { 97 } else if let Some(path_line_col) = complete_path {
86 let (path_line, column) = rsplit_at_char(path_line_col, ':')?; 98 let path_line_col: String = path_line_col;
99 let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?;
87 let (path, line) = rsplit_at_char(path_line, ':')?; 100 let (path, line) = rsplit_at_char(path_line, ':')?;
88 analysis_bench::Op::Complete { 101 analysis_bench::Op::Complete {
89 path: path.into(), 102 path: path.into(),
@@ -93,13 +106,27 @@ fn main() -> Result<()> {
93 } else { 106 } else {
94 panic!("either --highlight or --complete must be set") 107 panic!("either --highlight or --complete must be set")
95 }; 108 };
109 matches.finish().or_else(handle_extra_flags)?;
96 analysis_bench::run(verbose, path.as_ref(), op)?; 110 analysis_bench::run(verbose, path.as_ref(), op)?;
97 } 111 }
98 _ => unreachable!(), 112 _ => eprintln!("{}", help::GLOBAL_HELP),
99 } 113 }
100 Ok(()) 114 Ok(())
101} 115}
102 116
117fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
118 if let pico_args::Error::UnusedArgsLeft(flags) = e {
119 let mut invalid_flags = String::new();
120 for flag in flags {
121 write!(&mut invalid_flags, "{}, ", flag)?;
122 }
123 let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
124 Err(format!("Invalid flags: {}", invalid_flags).into())
125 } else {
126 Err(e.to_string().into())
127 }
128}
129
103fn file() -> Result<SourceFile> { 130fn file() -> Result<SourceFile> {
104 let text = read_stdin()?; 131 let text = read_stdin()?;
105 Ok(SourceFile::parse(&text).tree()) 132 Ok(SourceFile::parse(&text).tree())