diff --git a/Cargo.lock b/Cargo.lock index 4ae611a6bc0..82f910c1b70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -945,6 +945,7 @@ dependencies = [ name = "ra_cli" version = "0.1.0" dependencies = [ + "anyhow", "crossbeam-channel", "env_logger", "itertools", diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index 03494a809fd..ce88a76b1d7 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml @@ -13,6 +13,7 @@ log = "0.4.5" pico-args = "0.3.0" rand = { version = "0.7.0", features = ["small_rng"] } rustc-hash = "1.0" +anyhow = "1.0" hir = { path = "../ra_hir", package = "ra_hir" } hir_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 3f10ed4002b..91fc55fe200 100644 --- a/crates/ra_cli/src/analysis_bench.rs +++ b/crates/ra_cli/src/analysis_bench.rs @@ -1,47 +1,17 @@ //! FIXME: write short doc here -use std::{ - path::{Path, PathBuf}, - str::FromStr, - sync::Arc, - time::Instant, -}; +use std::{path::Path, sync::Arc, time::Instant}; +use anyhow::format_err; use ra_db::{ salsa::{Database, Durability}, FileId, SourceDatabaseExt, }; use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol}; -use crate::{load_cargo::load_cargo, Result}; +use crate::{load_cargo::load_cargo, BenchWhat, Result, Verbosity}; -pub(crate) struct Position { - path: PathBuf, - line: u32, - column: u32, -} - -impl FromStr for Position { - type Err = Box<dyn std::error::Error + Send + Sync>; - fn from_str(s: &str) -> Result<Self> { - let (path_line, column) = rsplit_at_char(s, ':')?; - let (path, line) = rsplit_at_char(path_line, ':')?; - Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? }) - } -} - -fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> { - let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?; - Ok((&s[..idx], &s[idx + 1..])) -} - -pub(crate) enum Op { - Highlight { path: PathBuf }, - Complete(Position), - GotoDef(Position), -} - -pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { +pub(crate) fn run(verbosity: Verbosity, path: &Path, what: BenchWhat) -> Result<()> { ra_prof::init(); let start = Instant::now(); @@ -51,9 +21,9 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { eprintln!("{:?}\n", start.elapsed()); let file_id = { - let path = match &op { - Op::Highlight { path } => path, - Op::Complete(pos) | Op::GotoDef(pos) => &pos.path, + let path = match &what { + BenchWhat::Highlight { path } => path, + BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => &pos.path, }; let path = std::env::current_dir()?.join(path).canonicalize()?; roots @@ -70,22 +40,22 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { } None }) - .ok_or_else(|| format!("Can't find {:?}", path))? + .ok_or_else(|| format_err!("Can't find {}", path.display()))? }; - match &op { - Op::Highlight { .. } => { + match &what { + BenchWhat::Highlight { .. } => { let res = do_work(&mut host, file_id, |analysis| { analysis.diagnostics(file_id).unwrap(); analysis.highlight_as_html(file_id, false).unwrap() }); - if verbose { + if verbosity.is_verbose() { println!("\n{}", res); } } - Op::Complete(pos) | Op::GotoDef(pos) => { - let is_completion = match op { - Op::Complete(..) => true, + BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => { + let is_completion = match what { + BenchWhat::Complete(..) => true, _ => false, }; @@ -98,13 +68,13 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { if is_completion { let res = do_work(&mut host, file_id, |analysis| analysis.completions(file_postion)); - if verbose { + if verbosity.is_verbose() { println!("\n{:#?}", res); } } else { let res = do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion)); - if verbose { + if verbosity.is_verbose() { println!("\n{:#?}", res); } } diff --git a/crates/ra_cli/src/load_cargo.rs b/crates/ra_cli/src/load_cargo.rs index 2d6433f184a..b9a4e6abad3 100644 --- a/crates/ra_cli/src/load_cargo.rs +++ b/crates/ra_cli/src/load_cargo.rs @@ -1,8 +1,6 @@ //! FIXME: write short doc here -use std::{collections::HashSet, error::Error, path::Path}; - -use rustc_hash::FxHashMap; +use std::{collections::HashSet, path::Path}; use crossbeam_channel::{unbounded, Receiver}; use ra_db::{CrateGraph, FileId, SourceRootId}; @@ -10,8 +8,9 @@ use ra_ide::{AnalysisChange, AnalysisHost, FeatureFlags}; use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace}; use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; use ra_vfs_glob::RustPackageFilterBuilder; +use rustc_hash::FxHashMap; -type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; +use anyhow::Result; fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId { FileId(f.0) diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index 4a428faff89..4cf062f472d 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs @@ -5,14 +5,82 @@ mod analysis_stats; mod analysis_bench; mod progress_report; -use std::{error::Error, fmt::Write, io::Read}; +use std::{fmt::Write, io::Read, path::PathBuf, str::FromStr}; use pico_args::Arguments; use ra_ide::{file_structure, Analysis}; use ra_prof::profile; use ra_syntax::{AstNode, SourceFile}; -type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; +use anyhow::{bail, format_err, Result}; + +fn main() -> Result<()> { + env_logger::try_init()?; + + let command = match Command::from_env_args()? { + Ok(it) => it, + Err(HelpPrinted) => return Ok(()), + }; + match command { + Command::Parse { no_dump } => { + let _p = profile("parsing"); + let file = file()?; + if !no_dump { + println!("{:#?}", file.syntax()); + } + std::mem::forget(file); + } + Command::Symbols => { + let file = file()?; + for s in file_structure(&file) { + println!("{:?}", s); + } + } + Command::Highlight { rainbow } => { + let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); + let html = analysis.highlight_as_html(file_id, rainbow).unwrap(); + println!("{}", html); + } + Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path } => { + analysis_stats::run( + verbosity, + memory_usage, + path.as_ref(), + only.as_ref().map(String::as_ref), + with_deps, + randomize, + )?; + } + Command::Bench { verbosity, path, what } => { + analysis_bench::run(verbosity, path.as_ref(), what)?; + } + } + + Ok(()) +} + +enum Command { + Parse { + no_dump: bool, + }, + Symbols, + Highlight { + rainbow: bool, + }, + Stats { + verbosity: Verbosity, + randomize: bool, + memory_usage: bool, + only: Option<String>, + with_deps: bool, + path: PathBuf, + }, + Bench { + verbosity: Verbosity, + path: PathBuf, + what: BenchWhat, + }, +} #[derive(Clone, Copy)] pub enum Verbosity { @@ -37,17 +105,57 @@ impl Verbosity { } } -fn main() -> Result<()> { - env_logger::try_init()?; +enum BenchWhat { + Highlight { path: PathBuf }, + Complete(Position), + GotoDef(Position), +} - let mut matches = Arguments::from_env(); - let subcommand = matches.subcommand()?.unwrap_or_default(); +pub(crate) struct Position { + path: PathBuf, + line: u32, + column: u32, +} - match subcommand.as_str() { - "parse" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ +impl FromStr for Position { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result<Self> { + let (path_line, column) = rsplit_at_char(s, ':')?; + let (path, line) = rsplit_at_char(path_line, ':')?; + Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? }) + } +} + +fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> { + let idx = s.rfind(c).ok_or_else(|| format_err!("no `{}` in {}", c, s))?; + Ok((&s[..idx], &s[idx + 1..])) +} + +struct HelpPrinted; + +impl Command { + fn from_env_args() -> Result<Result<Command, HelpPrinted>> { + let mut matches = Arguments::from_env(); + let subcommand = matches.subcommand()?.unwrap_or_default(); + + let verbosity = match ( + matches.contains(["-vv", "--spammy"]), + matches.contains(["-v", "--verbose"]), + matches.contains(["-q", "--quiet"]), + ) { + (true, _, true) => bail!("Invalid flags: -q conflicts with -vv"), + (true, _, false) => Verbosity::Spammy, + (false, false, false) => Verbosity::Normal, + (false, false, true) => Verbosity::Quiet, + (false, true, false) => Verbosity::Verbose, + (false, true, true) => bail!("Invalid flags: -q conflicts with -v"), + }; + + let command = match subcommand.as_str() { + "parse" => { + if matches.contains(["-h", "--help"]) { + eprintln!( + "\ ra-cli-parse USAGE: @@ -56,24 +164,18 @@ USAGE: FLAGS: -h, --help Prints help inforamtion --no-dump" - ); - return Ok(()); - } + ); + return Ok(Err(HelpPrinted)); + } - 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()); + let no_dump = matches.contains("--no-dump"); + matches.finish().or_else(handle_extra_flags)?; + Command::Parse { no_dump } } - std::mem::forget(file); - } - "symbols" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ + "symbols" => { + if matches.contains(["-h", "--help"]) { + eprintln!( + "\ ra-cli-symbols USAGE: @@ -81,21 +183,18 @@ USAGE: FLAGS: -h, --help Prints help inforamtion" - ); - return Ok(()); - } + ); + return Ok(Err(HelpPrinted)); + } - matches.finish().or_else(handle_extra_flags)?; + matches.finish().or_else(handle_extra_flags)?; - let file = file()?; - for s in file_structure(&file) { - println!("{:?}", s); + Command::Symbols } - } - "highlight" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ + "highlight" => { + if matches.contains(["-h", "--help"]) { + eprintln!( + "\ ra-cli-highlight USAGE: @@ -104,21 +203,18 @@ USAGE: FLAGS: -h, --help Prints help information -r, --rainbow" - ); - return Ok(()); + ); + return Ok(Err(HelpPrinted)); + } + + let rainbow = matches.contains(["-r", "--rainbow"]); + matches.finish().or_else(handle_extra_flags)?; + Command::Highlight { rainbow } } - - 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" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ + "analysis-stats" => { + if matches.contains(["-h", "--help"]) { + eprintln!( + "\ ra-cli-analysis-stats USAGE: @@ -135,47 +231,28 @@ OPTIONS: ARGS: <PATH>" - ); - return Ok(()); - } - - let verbosity = match ( - matches.contains(["-vv", "--spammy"]), - matches.contains(["-v", "--verbose"]), - matches.contains(["-q", "--quiet"]), - ) { - (true, _, true) => Err("Invalid flags: -q conflicts with -vv")?, - (true, _, false) => Verbosity::Spammy, - (false, false, false) => Verbosity::Normal, - (false, false, true) => Verbosity::Quiet, - (false, true, false) => Verbosity::Verbose, - (false, true, true) => Err("Invalid flags: -q conflicts with -v")?, - }; - let randomize = matches.contains("--randomize"); - let memory_usage = matches.contains("--memory-usage"); - let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?; - let with_deps: bool = matches.contains("--with-deps"); - let path = { - let mut trailing = matches.free()?; - if trailing.len() != 1 { - Err("Invalid flags")?; + ); + return Ok(Err(HelpPrinted)); } - trailing.pop().unwrap() - }; - analysis_stats::run( - verbosity, - memory_usage, - path.as_ref(), - only.as_ref().map(String::as_ref), - with_deps, - randomize, - )?; - } - "analysis-bench" => { - if matches.contains(["-h", "--help"]) { - eprintln!( - "\ + let randomize = matches.contains("--randomize"); + let memory_usage = matches.contains("--memory-usage"); + let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?; + let with_deps: bool = matches.contains("--with-deps"); + let path = { + let mut trailing = matches.free()?; + if trailing.len() != 1 { + bail!("Invalid flags"); + } + trailing.pop().unwrap().into() + }; + + Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path } + } + "analysis-bench" => { + if matches.contains(["-h", "--help"]) { + eprintln!( + "\ ra_cli-analysis-bench USAGE: @@ -191,29 +268,27 @@ OPTIONS: ARGS: <PATH> Project to analyse" - ); - return Ok(()); + ); + return Ok(Err(HelpPrinted)); + } + + let path: PathBuf = matches.opt_value_from_str("--path")?.unwrap_or_default(); + let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?; + let complete_path: Option<Position> = matches.opt_value_from_str("--complete")?; + let goto_def_path: Option<Position> = matches.opt_value_from_str("--goto-def")?; + let what = match (highlight_path, complete_path, goto_def_path) { + (Some(path), None, None) => BenchWhat::Highlight { path: path.into() }, + (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" + ), + }; + Command::Bench { verbosity, path, what } } - - let verbose = matches.contains(["-v", "--verbose"]); - let path: String = matches.opt_value_from_str("--path")?.unwrap_or_default(); - let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?; - let complete_path: Option<String> = matches.opt_value_from_str("--complete")?; - let goto_def_path: Option<String> = matches.opt_value_from_str("--goto-def")?; - let op = match (highlight_path, complete_path, goto_def_path) { - (Some(path), None, None) => analysis_bench::Op::Highlight { path: path.into() }, - (None, Some(position), None) => analysis_bench::Op::Complete(position.parse()?), - (None, None, Some(position)) => analysis_bench::Op::GotoDef(position.parse()?), - _ => panic!( - "exactly one of `--highlight`, `--complete` or `--goto-def` must be set" - ), - }; - matches.finish().or_else(handle_extra_flags)?; - - analysis_bench::run(verbose, path.as_ref(), op)?; - } - _ => eprintln!( - "\ + _ => { + eprintln!( + "\ ra-cli USAGE: @@ -228,9 +303,12 @@ SUBCOMMANDS: highlight parse symbols" - ), + ); + return Ok(Err(HelpPrinted)); + } + }; + Ok(Ok(command)) } - Ok(()) } fn handle_extra_flags(e: pico_args::Error) -> Result<()> { @@ -240,9 +318,9 @@ fn handle_extra_flags(e: pico_args::Error) -> Result<()> { write!(&mut invalid_flags, "{}, ", flag)?; } let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2); - Err(format!("Invalid flags: {}", invalid_flags).into()) + bail!("Invalid flags: {}", invalid_flags); } else { - Err(e.to_string().into()) + bail!(e); } } diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index fdf81ed87c9..0066929c0c1 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml @@ -8,27 +8,28 @@ authors = ["rust-analyzer developers"] doctest = false [dependencies] -threadpool = "1.7.1" -relative-path = "1.0.0" -serde_json = "1.0.34" -serde = { version = "1.0.83", features = ["derive"] } crossbeam-channel = "0.4" +either = "1.5" +env_logger = { version = "0.7.1", default-features = false } +jod-thread = "0.1.0" log = "0.4.3" lsp-types = { version = "0.70.0", features = ["proposed"] } -rustc-hash = "1.0" parking_lot = "0.10.0" -jod-thread = "0.1.0" -ra_vfs = "0.5.0" +relative-path = "1.0.0" +rustc-hash = "1.0" +serde = { version = "1.0.83", features = ["derive"] } +serde_json = "1.0.34" +threadpool = "1.7.1" + +lsp-server = "0.3.0" +ra_cargo_watch = { path = "../ra_cargo_watch" } +ra_ide = { path = "../ra_ide" } +ra_prof = { path = "../ra_prof" } +ra_project_model = { path = "../ra_project_model" } ra_syntax = { path = "../ra_syntax" } ra_text_edit = { path = "../ra_text_edit" } -ra_ide = { path = "../ra_ide" } -lsp-server = "0.3.0" -ra_project_model = { path = "../ra_project_model" } -ra_prof = { path = "../ra_prof" } +ra_vfs = "0.5.0" ra_vfs_glob = { path = "../ra_vfs_glob" } -env_logger = { version = "0.7.1", default-features = false } -ra_cargo_watch = { path = "../ra_cargo_watch" } -either = "1.5" [target.'cfg(windows)'.dependencies] winapi = "0.3"