aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cli
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_cli')
-rw-r--r--crates/ra_cli/Cargo.toml1
-rw-r--r--crates/ra_cli/src/analysis_bench.rs62
-rw-r--r--crates/ra_cli/src/load_cargo.rs7
-rw-r--r--crates/ra_cli/src/main.rs314
4 files changed, 216 insertions, 168 deletions
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index 03494a809..ce88a76b1 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -13,6 +13,7 @@ log = "0.4.5"
13pico-args = "0.3.0" 13pico-args = "0.3.0"
14rand = { version = "0.7.0", features = ["small_rng"] } 14rand = { version = "0.7.0", features = ["small_rng"] }
15rustc-hash = "1.0" 15rustc-hash = "1.0"
16anyhow = "1.0"
16 17
17hir = { path = "../ra_hir", package = "ra_hir" } 18hir = { path = "../ra_hir", package = "ra_hir" }
18hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } 19hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs
index 3f10ed400..91fc55fe2 100644
--- a/crates/ra_cli/src/analysis_bench.rs
+++ b/crates/ra_cli/src/analysis_bench.rs
@@ -1,47 +1,17 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ 3use std::{path::Path, sync::Arc, time::Instant};
4 path::{Path, PathBuf},
5 str::FromStr,
6 sync::Arc,
7 time::Instant,
8};
9 4
5use anyhow::format_err;
10use ra_db::{ 6use ra_db::{
11 salsa::{Database, Durability}, 7 salsa::{Database, Durability},
12 FileId, SourceDatabaseExt, 8 FileId, SourceDatabaseExt,
13}; 9};
14use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol}; 10use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol};
15 11
16use crate::{load_cargo::load_cargo, Result}; 12use crate::{load_cargo::load_cargo, BenchWhat, Result, Verbosity};
17
18pub(crate) struct Position {
19 path: PathBuf,
20 line: u32,
21 column: u32,
22}
23
24impl FromStr for Position {
25 type Err = Box<dyn std::error::Error + Send + Sync>;
26 fn from_str(s: &str) -> Result<Self> {
27 let (path_line, column) = rsplit_at_char(s, ':')?;
28 let (path, line) = rsplit_at_char(path_line, ':')?;
29 Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? })
30 }
31}
32
33fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
34 let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
35 Ok((&s[..idx], &s[idx + 1..]))
36}
37
38pub(crate) enum Op {
39 Highlight { path: PathBuf },
40 Complete(Position),
41 GotoDef(Position),
42}
43 13
44pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { 14pub(crate) fn run(verbosity: Verbosity, path: &Path, what: BenchWhat) -> Result<()> {
45 ra_prof::init(); 15 ra_prof::init();
46 16
47 let start = Instant::now(); 17 let start = Instant::now();
@@ -51,9 +21,9 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
51 eprintln!("{:?}\n", start.elapsed()); 21 eprintln!("{:?}\n", start.elapsed());
52 22
53 let file_id = { 23 let file_id = {
54 let path = match &op { 24 let path = match &what {
55 Op::Highlight { path } => path, 25 BenchWhat::Highlight { path } => path,
56 Op::Complete(pos) | Op::GotoDef(pos) => &pos.path, 26 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => &pos.path,
57 }; 27 };
58 let path = std::env::current_dir()?.join(path).canonicalize()?; 28 let path = std::env::current_dir()?.join(path).canonicalize()?;
59 roots 29 roots
@@ -70,22 +40,22 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
70 } 40 }
71 None 41 None
72 }) 42 })
73 .ok_or_else(|| format!("Can't find {:?}", path))? 43 .ok_or_else(|| format_err!("Can't find {}", path.display()))?
74 }; 44 };
75 45
76 match &op { 46 match &what {
77 Op::Highlight { .. } => { 47 BenchWhat::Highlight { .. } => {
78 let res = do_work(&mut host, file_id, |analysis| { 48 let res = do_work(&mut host, file_id, |analysis| {
79 analysis.diagnostics(file_id).unwrap(); 49 analysis.diagnostics(file_id).unwrap();
80 analysis.highlight_as_html(file_id, false).unwrap() 50 analysis.highlight_as_html(file_id, false).unwrap()
81 }); 51 });
82 if verbose { 52 if verbosity.is_verbose() {
83 println!("\n{}", res); 53 println!("\n{}", res);
84 } 54 }
85 } 55 }
86 Op::Complete(pos) | Op::GotoDef(pos) => { 56 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => {
87 let is_completion = match op { 57 let is_completion = match what {
88 Op::Complete(..) => true, 58 BenchWhat::Complete(..) => true,
89 _ => false, 59 _ => false,
90 }; 60 };
91 61
@@ -98,13 +68,13 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
98 if is_completion { 68 if is_completion {
99 let res = 69 let res =
100 do_work(&mut host, file_id, |analysis| analysis.completions(file_postion)); 70 do_work(&mut host, file_id, |analysis| analysis.completions(file_postion));
101 if verbose { 71 if verbosity.is_verbose() {
102 println!("\n{:#?}", res); 72 println!("\n{:#?}", res);
103 } 73 }
104 } else { 74 } else {
105 let res = 75 let res =
106 do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion)); 76 do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion));
107 if verbose { 77 if verbosity.is_verbose() {
108 println!("\n{:#?}", res); 78 println!("\n{:#?}", res);
109 } 79 }
110 } 80 }
diff --git a/crates/ra_cli/src/load_cargo.rs b/crates/ra_cli/src/load_cargo.rs
index 2d6433f18..b9a4e6aba 100644
--- a/crates/ra_cli/src/load_cargo.rs
+++ b/crates/ra_cli/src/load_cargo.rs
@@ -1,8 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{collections::HashSet, error::Error, path::Path}; 3use std::{collections::HashSet, path::Path};
4
5use rustc_hash::FxHashMap;
6 4
7use crossbeam_channel::{unbounded, Receiver}; 5use crossbeam_channel::{unbounded, Receiver};
8use ra_db::{CrateGraph, FileId, SourceRootId}; 6use ra_db::{CrateGraph, FileId, SourceRootId};
@@ -10,8 +8,9 @@ use ra_ide::{AnalysisChange, AnalysisHost, FeatureFlags};
10use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace}; 8use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace};
11use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; 9use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
12use ra_vfs_glob::RustPackageFilterBuilder; 10use ra_vfs_glob::RustPackageFilterBuilder;
11use rustc_hash::FxHashMap;
13 12
14type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; 13use anyhow::Result;
15 14
16fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId { 15fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId {
17 FileId(f.0) 16 FileId(f.0)
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 4a428faff..4cf062f47 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -5,14 +5,82 @@ mod analysis_stats;
5mod analysis_bench; 5mod analysis_bench;
6mod progress_report; 6mod progress_report;
7 7
8use std::{error::Error, fmt::Write, io::Read}; 8use std::{fmt::Write, io::Read, path::PathBuf, str::FromStr};
9 9
10use pico_args::Arguments; 10use pico_args::Arguments;
11use ra_ide::{file_structure, Analysis}; 11use ra_ide::{file_structure, Analysis};
12use ra_prof::profile; 12use ra_prof::profile;
13use ra_syntax::{AstNode, SourceFile}; 13use ra_syntax::{AstNode, SourceFile};
14 14
15type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; 15use anyhow::{bail, format_err, Result};
16
17fn main() -> Result<()> {
18 env_logger::try_init()?;
19
20 let command = match Command::from_env_args()? {
21 Ok(it) => it,
22 Err(HelpPrinted) => return Ok(()),
23 };
24 match command {
25 Command::Parse { no_dump } => {
26 let _p = profile("parsing");
27 let file = file()?;
28 if !no_dump {
29 println!("{:#?}", file.syntax());
30 }
31 std::mem::forget(file);
32 }
33 Command::Symbols => {
34 let file = file()?;
35 for s in file_structure(&file) {
36 println!("{:?}", s);
37 }
38 }
39 Command::Highlight { rainbow } => {
40 let (analysis, file_id) = Analysis::from_single_file(read_stdin()?);
41 let html = analysis.highlight_as_html(file_id, rainbow).unwrap();
42 println!("{}", html);
43 }
44 Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path } => {
45 analysis_stats::run(
46 verbosity,
47 memory_usage,
48 path.as_ref(),
49 only.as_ref().map(String::as_ref),
50 with_deps,
51 randomize,
52 )?;
53 }
54 Command::Bench { verbosity, path, what } => {
55 analysis_bench::run(verbosity, path.as_ref(), what)?;
56 }
57 }
58
59 Ok(())
60}
61
62enum Command {
63 Parse {
64 no_dump: bool,
65 },
66 Symbols,
67 Highlight {
68 rainbow: bool,
69 },
70 Stats {
71 verbosity: Verbosity,
72 randomize: bool,
73 memory_usage: bool,
74 only: Option<String>,
75 with_deps: bool,
76 path: PathBuf,
77 },
78 Bench {
79 verbosity: Verbosity,
80 path: PathBuf,
81 what: BenchWhat,
82 },
83}
16 84
17#[derive(Clone, Copy)] 85#[derive(Clone, Copy)]
18pub enum Verbosity { 86pub enum Verbosity {
@@ -37,17 +105,57 @@ impl Verbosity {
37 } 105 }
38} 106}
39 107
40fn main() -> Result<()> { 108enum BenchWhat {
41 env_logger::try_init()?; 109 Highlight { path: PathBuf },
110 Complete(Position),
111 GotoDef(Position),
112}
42 113
43 let mut matches = Arguments::from_env(); 114pub(crate) struct Position {
44 let subcommand = matches.subcommand()?.unwrap_or_default(); 115 path: PathBuf,
116 line: u32,
117 column: u32,
118}
45 119
46 match subcommand.as_str() { 120impl FromStr for Position {
47 "parse" => { 121 type Err = anyhow::Error;
48 if matches.contains(["-h", "--help"]) { 122 fn from_str(s: &str) -> Result<Self> {
49 eprintln!( 123 let (path_line, column) = rsplit_at_char(s, ':')?;
50 "\ 124 let (path, line) = rsplit_at_char(path_line, ':')?;
125 Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? })
126 }
127}
128
129fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
130 let idx = s.rfind(c).ok_or_else(|| format_err!("no `{}` in {}", c, s))?;
131 Ok((&s[..idx], &s[idx + 1..]))
132}
133
134struct HelpPrinted;
135
136impl Command {
137 fn from_env_args() -> Result<Result<Command, HelpPrinted>> {
138 let mut matches = Arguments::from_env();
139 let subcommand = matches.subcommand()?.unwrap_or_default();
140
141 let verbosity = match (
142 matches.contains(["-vv", "--spammy"]),
143 matches.contains(["-v", "--verbose"]),
144 matches.contains(["-q", "--quiet"]),
145 ) {
146 (true, _, true) => bail!("Invalid flags: -q conflicts with -vv"),
147 (true, _, false) => Verbosity::Spammy,
148 (false, false, false) => Verbosity::Normal,
149 (false, false, true) => Verbosity::Quiet,
150 (false, true, false) => Verbosity::Verbose,
151 (false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
152 };
153
154 let command = match subcommand.as_str() {
155 "parse" => {
156 if matches.contains(["-h", "--help"]) {
157 eprintln!(
158 "\
51ra-cli-parse 159ra-cli-parse
52 160
53USAGE: 161USAGE:
@@ -56,24 +164,18 @@ USAGE:
56FLAGS: 164FLAGS:
57 -h, --help Prints help inforamtion 165 -h, --help Prints help inforamtion
58 --no-dump" 166 --no-dump"
59 ); 167 );
60 return Ok(()); 168 return Ok(Err(HelpPrinted));
61 } 169 }
62
63 let no_dump = matches.contains("--no-dump");
64 matches.finish().or_else(handle_extra_flags)?;
65 170
66 let _p = profile("parsing"); 171 let no_dump = matches.contains("--no-dump");
67 let file = file()?; 172 matches.finish().or_else(handle_extra_flags)?;
68 if !no_dump { 173 Command::Parse { no_dump }
69 println!("{:#?}", file.syntax());
70 } 174 }
71 std::mem::forget(file); 175 "symbols" => {
72 } 176 if matches.contains(["-h", "--help"]) {
73 "symbols" => { 177 eprintln!(
74 if matches.contains(["-h", "--help"]) { 178 "\
75 eprintln!(
76 "\
77ra-cli-symbols 179ra-cli-symbols
78 180
79USAGE: 181USAGE:
@@ -81,21 +183,18 @@ USAGE:
81 183
82FLAGS: 184FLAGS:
83 -h, --help Prints help inforamtion" 185 -h, --help Prints help inforamtion"
84 ); 186 );
85 return Ok(()); 187 return Ok(Err(HelpPrinted));
86 } 188 }
87 189
88 matches.finish().or_else(handle_extra_flags)?; 190 matches.finish().or_else(handle_extra_flags)?;
89 191
90 let file = file()?; 192 Command::Symbols
91 for s in file_structure(&file) {
92 println!("{:?}", s);
93 } 193 }
94 } 194 "highlight" => {
95 "highlight" => { 195 if matches.contains(["-h", "--help"]) {
96 if matches.contains(["-h", "--help"]) { 196 eprintln!(
97 eprintln!( 197 "\
98 "\
99ra-cli-highlight 198ra-cli-highlight
100 199
101USAGE: 200USAGE:
@@ -104,21 +203,18 @@ USAGE:
104FLAGS: 203FLAGS:
105 -h, --help Prints help information 204 -h, --help Prints help information
106 -r, --rainbow" 205 -r, --rainbow"
107 ); 206 );
108 return Ok(()); 207 return Ok(Err(HelpPrinted));
109 } 208 }
110
111 let rainbow_opt = matches.contains(["-r", "--rainbow"]);
112 matches.finish().or_else(handle_extra_flags)?;
113 209
114 let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); 210 let rainbow = matches.contains(["-r", "--rainbow"]);
115 let html = analysis.highlight_as_html(file_id, rainbow_opt).unwrap(); 211 matches.finish().or_else(handle_extra_flags)?;
116 println!("{}", html); 212 Command::Highlight { rainbow }
117 } 213 }
118 "analysis-stats" => { 214 "analysis-stats" => {
119 if matches.contains(["-h", "--help"]) { 215 if matches.contains(["-h", "--help"]) {
120 eprintln!( 216 eprintln!(
121 "\ 217 "\
122ra-cli-analysis-stats 218ra-cli-analysis-stats
123 219
124USAGE: 220USAGE:
@@ -135,47 +231,28 @@ OPTIONS:
135 231
136ARGS: 232ARGS:
137 <PATH>" 233 <PATH>"
138 ); 234 );
139 return Ok(()); 235 return Ok(Err(HelpPrinted));
140 }
141
142 let verbosity = match (
143 matches.contains(["-vv", "--spammy"]),
144 matches.contains(["-v", "--verbose"]),
145 matches.contains(["-q", "--quiet"]),
146 ) {
147 (true, _, true) => Err("Invalid flags: -q conflicts with -vv")?,
148 (true, _, false) => Verbosity::Spammy,
149 (false, false, false) => Verbosity::Normal,
150 (false, false, true) => Verbosity::Quiet,
151 (false, true, false) => Verbosity::Verbose,
152 (false, true, true) => Err("Invalid flags: -q conflicts with -v")?,
153 };
154 let randomize = matches.contains("--randomize");
155 let memory_usage = matches.contains("--memory-usage");
156 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
157 let with_deps: bool = matches.contains("--with-deps");
158 let path = {
159 let mut trailing = matches.free()?;
160 if trailing.len() != 1 {
161 Err("Invalid flags")?;
162 } 236 }
163 trailing.pop().unwrap()
164 };
165 237
166 analysis_stats::run( 238 let randomize = matches.contains("--randomize");
167 verbosity, 239 let memory_usage = matches.contains("--memory-usage");
168 memory_usage, 240 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
169 path.as_ref(), 241 let with_deps: bool = matches.contains("--with-deps");
170 only.as_ref().map(String::as_ref), 242 let path = {
171 with_deps, 243 let mut trailing = matches.free()?;
172 randomize, 244 if trailing.len() != 1 {
173 )?; 245 bail!("Invalid flags");
174 } 246 }
175 "analysis-bench" => { 247 trailing.pop().unwrap().into()
176 if matches.contains(["-h", "--help"]) { 248 };
177 eprintln!( 249
178 "\ 250 Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path }
251 }
252 "analysis-bench" => {
253 if matches.contains(["-h", "--help"]) {
254 eprintln!(
255 "\
179ra_cli-analysis-bench 256ra_cli-analysis-bench
180 257
181USAGE: 258USAGE:
@@ -191,29 +268,27 @@ OPTIONS:
191 268
192ARGS: 269ARGS:
193 <PATH> Project to analyse" 270 <PATH> Project to analyse"
194 ); 271 );
195 return Ok(()); 272 return Ok(Err(HelpPrinted));
196 } 273 }
197 274
198 let verbose = matches.contains(["-v", "--verbose"]); 275 let path: PathBuf = matches.opt_value_from_str("--path")?.unwrap_or_default();
199 let path: String = matches.opt_value_from_str("--path")?.unwrap_or_default(); 276 let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?;
200 let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?; 277 let complete_path: Option<Position> = matches.opt_value_from_str("--complete")?;
201 let complete_path: Option<String> = matches.opt_value_from_str("--complete")?; 278 let goto_def_path: Option<Position> = matches.opt_value_from_str("--goto-def")?;
202 let goto_def_path: Option<String> = matches.opt_value_from_str("--goto-def")?; 279 let what = match (highlight_path, complete_path, goto_def_path) {
203 let op = match (highlight_path, complete_path, goto_def_path) { 280 (Some(path), None, None) => BenchWhat::Highlight { path: path.into() },
204 (Some(path), None, None) => analysis_bench::Op::Highlight { path: path.into() }, 281 (None, Some(position), None) => BenchWhat::Complete(position),
205 (None, Some(position), None) => analysis_bench::Op::Complete(position.parse()?), 282 (None, None, Some(position)) => BenchWhat::GotoDef(position),
206 (None, None, Some(position)) => analysis_bench::Op::GotoDef(position.parse()?), 283 _ => panic!(
207 _ => panic!( 284 "exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
208 "exactly one of `--highlight`, `--complete` or `--goto-def` must be set" 285 ),
209 ), 286 };
210 }; 287 Command::Bench { verbosity, path, what }
211 matches.finish().or_else(handle_extra_flags)?; 288 }
212 289 _ => {
213 analysis_bench::run(verbose, path.as_ref(), op)?; 290 eprintln!(
214 } 291 "\
215 _ => eprintln!(
216 "\
217ra-cli 292ra-cli
218 293
219USAGE: 294USAGE:
@@ -228,9 +303,12 @@ SUBCOMMANDS:
228 highlight 303 highlight
229 parse 304 parse
230 symbols" 305 symbols"
231 ), 306 );
307 return Ok(Err(HelpPrinted));
308 }
309 };
310 Ok(Ok(command))
232 } 311 }
233 Ok(())
234} 312}
235 313
236fn handle_extra_flags(e: pico_args::Error) -> Result<()> { 314fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
@@ -240,9 +318,9 @@ fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
240 write!(&mut invalid_flags, "{}, ", flag)?; 318 write!(&mut invalid_flags, "{}, ", flag)?;
241 } 319 }
242 let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2); 320 let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
243 Err(format!("Invalid flags: {}", invalid_flags).into()) 321 bail!("Invalid flags: {}", invalid_flags);
244 } else { 322 } else {
245 Err(e.to_string().into()) 323 bail!(e);
246 } 324 }
247} 325}
248 326