diff --git a/Cargo.lock b/Cargo.lock index 82f910c1b701..ccdcfbee3742 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -941,30 +941,6 @@ dependencies = [ "rustc-hash", ] -[[package]] -name = "ra_cli" -version = "0.1.0" -dependencies = [ - "anyhow", - "crossbeam-channel", - "env_logger", - "itertools", - "log", - "pico-args", - "ra_db", - "ra_hir", - "ra_hir_def", - "ra_hir_ty", - "ra_ide", - "ra_prof", - "ra_project_model", - "ra_syntax", - "ra_vfs", - "ra_vfs_glob", - "rand", - "rustc-hash", -] - [[package]] name = "ra_db" version = "0.1.0" @@ -1122,15 +1098,22 @@ dependencies = [ name = "ra_lsp_server" version = "0.1.0" dependencies = [ + "anyhow", "crossbeam-channel", "either", "env_logger", + "itertools", "jod-thread", "log", "lsp-server", "lsp-types", "parking_lot", + "pico-args", "ra_cargo_watch", + "ra_db", + "ra_hir", + "ra_hir_def", + "ra_hir_ty", "ra_ide", "ra_prof", "ra_project_model", @@ -1138,6 +1121,7 @@ dependencies = [ "ra_text_edit", "ra_vfs", "ra_vfs_glob", + "rand", "relative-path", "rustc-hash", "serde", diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml deleted file mode 100644 index ce88a76b1d7f..000000000000 --- a/crates/ra_cli/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -edition = "2018" -name = "ra_cli" -version = "0.1.0" -authors = ["rust-analyzer developers"] -publish = false - -[dependencies] -crossbeam-channel = "0.4.0" -env_logger = { version = "0.7.1", default-features = false } -itertools = "0.8.0" -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" } -hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } -ra_db = { path = "../ra_db" } -ra_ide = { path = "../ra_ide" } -ra_project_model = { path = "../ra_project_model" } -ra_syntax = { path = "../ra_syntax" } -ra_vfs = "0.5.0" -ra_vfs_glob = { path = "../ra_vfs_glob" } - -[dependencies.ra_prof] -path = "../ra_prof" -# features = [ "cpu_profiler" ] -# features = [ "jemalloc" ] diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index 0066929c0c10..be7982b2ab55 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml @@ -8,13 +8,17 @@ authors = ["rust-analyzer developers"] doctest = false [dependencies] +anyhow = "1.0" crossbeam-channel = "0.4" either = "1.5" env_logger = { version = "0.7.1", default-features = false } +itertools = "0.8.0" jod-thread = "0.1.0" log = "0.4.3" lsp-types = { version = "0.70.0", features = ["proposed"] } parking_lot = "0.10.0" +pico-args = "0.3.0" +rand = { version = "0.7.0", features = ["small_rng"] } relative-path = "1.0.0" rustc-hash = "1.0" serde = { version = "1.0.83", features = ["derive"] } @@ -31,6 +35,13 @@ ra_text_edit = { path = "../ra_text_edit" } ra_vfs = "0.5.0" ra_vfs_glob = { path = "../ra_vfs_glob" } +# This should only be used in CLI +ra_db = { path = "../ra_db" } +hir = { path = "../ra_hir", package = "ra_hir" } +hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } +hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } + + [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/crates/ra_cli/src/main.rs b/crates/ra_lsp_server/src/args.rs similarity index 63% rename from crates/ra_cli/src/main.rs rename to crates/ra_lsp_server/src/args.rs index 4cf062f472d8..41959797ccad 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_lsp_server/src/args.rs @@ -1,65 +1,15 @@ -//! FIXME: write short doc here - -mod load_cargo; -mod analysis_stats; -mod analysis_bench; -mod progress_report; - -use std::{fmt::Write, io::Read, path::PathBuf, str::FromStr}; - +use anyhow::{bail, Result}; use pico_args::Arguments; -use ra_ide::{file_structure, Analysis}; -use ra_prof::profile; -use ra_syntax::{AstNode, SourceFile}; +use ra_lsp_server::cli::{BenchWhat, Position, Verbosity}; -use anyhow::{bail, format_err, Result}; +use std::{fmt::Write, path::PathBuf}; -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(()) +pub(crate) struct Args { + pub(crate) verbosity: Verbosity, + pub(crate) command: Command, } -enum Command { +pub(crate) enum Command { Parse { no_dump: bool, }, @@ -68,7 +18,6 @@ enum Command { rainbow: bool, }, Stats { - verbosity: Verbosity, randomize: bool, memory_usage: bool, only: Option, @@ -76,67 +25,21 @@ enum Command { path: PathBuf, }, Bench { - verbosity: Verbosity, path: PathBuf, what: BenchWhat, }, + RunServer, + Version, } -#[derive(Clone, Copy)] -pub enum Verbosity { - Spammy, - Verbose, - Normal, - Quiet, -} - -impl Verbosity { - fn is_verbose(self) -> bool { - match self { - Verbosity::Verbose | Verbosity::Spammy => true, - _ => false, - } - } - fn is_spammy(self) -> bool { - match self { - Verbosity::Spammy => true, - _ => false, - } - } -} - -enum BenchWhat { - Highlight { path: PathBuf }, - Complete(Position), - GotoDef(Position), -} - -pub(crate) struct Position { - path: PathBuf, - line: u32, - column: u32, -} - -impl FromStr for Position { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result { - 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> { +impl Args { + pub(crate) fn parse() -> Result> { let mut matches = Arguments::from_env(); - let subcommand = matches.subcommand()?.unwrap_or_default(); + + if matches.contains("--version") { + matches.finish().or_else(handle_extra_flags)?; + return Ok(Ok(Args { verbosity: Verbosity::Normal, command: Command::Version })); + } let verbosity = match ( matches.contains(["-vv", "--spammy"]), @@ -151,6 +54,13 @@ impl Command { (false, true, true) => bail!("Invalid flags: -q conflicts with -v"), }; + let subcommand = match matches.subcommand()? { + Some(it) => it, + None => { + matches.finish().or_else(handle_extra_flags)?; + return Ok(Ok(Args { verbosity, command: Command::RunServer })); + } + }; let command = match subcommand.as_str() { "parse" => { if matches.contains(["-h", "--help"]) { @@ -247,7 +157,7 @@ ARGS: trailing.pop().unwrap().into() }; - Command::Stats { verbosity, randomize, memory_usage, only, with_deps, path } + Command::Stats { randomize, memory_usage, only, with_deps, path } } "analysis-bench" => { if matches.contains(["-h", "--help"]) { @@ -284,7 +194,7 @@ ARGS: "exactly one of `--highlight`, `--complete` or `--goto-def` must be set" ), }; - Command::Bench { verbosity, path, what } + Command::Bench { path, what } } _ => { eprintln!( @@ -307,10 +217,12 @@ SUBCOMMANDS: return Ok(Err(HelpPrinted)); } }; - Ok(Ok(command)) + Ok(Ok(Args { verbosity, command })) } } +pub(crate) struct HelpPrinted; + fn handle_extra_flags(e: pico_args::Error) -> Result<()> { if let pico_args::Error::UnusedArgsLeft(flags) = e { let mut invalid_flags = String::new(); @@ -323,14 +235,3 @@ fn handle_extra_flags(e: pico_args::Error) -> Result<()> { bail!(e); } } - -fn file() -> Result { - let text = read_stdin()?; - Ok(SourceFile::parse(&text).tree()) -} - -fn read_stdin() -> Result { - let mut buff = String::new(); - std::io::stdin().read_to_string(&mut buff)?; - Ok(buff) -} diff --git a/crates/ra_lsp_server/src/cli.rs b/crates/ra_lsp_server/src/cli.rs new file mode 100644 index 000000000000..3c7b8e2509a6 --- /dev/null +++ b/crates/ra_lsp_server/src/cli.rs @@ -0,0 +1,75 @@ +//! FIXME: write short doc here + +mod load_cargo; +mod analysis_stats; +mod analysis_bench; +mod progress_report; + +use std::io::Read; + +use anyhow::Result; +use ra_ide::{file_structure, Analysis}; +use ra_prof::profile; +use ra_syntax::{AstNode, SourceFile}; + +#[derive(Clone, Copy)] +pub enum Verbosity { + Spammy, + Verbose, + Normal, + Quiet, +} + +impl Verbosity { + pub fn is_verbose(self) -> bool { + match self { + Verbosity::Verbose | Verbosity::Spammy => true, + _ => false, + } + } + pub fn is_spammy(self) -> bool { + match self { + Verbosity::Spammy => true, + _ => false, + } + } +} + +pub fn parse(no_dump: bool) -> Result<()> { + let _p = profile("parsing"); + let file = file()?; + if !no_dump { + println!("{:#?}", file.syntax()); + } + std::mem::forget(file); + Ok(()) +} + +pub fn symbols() -> Result<()> { + let file = file()?; + for s in file_structure(&file) { + println!("{:?}", s); + } + Ok(()) +} + +pub fn highlight(rainbow: bool) -> Result<()> { + let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); + let html = analysis.highlight_as_html(file_id, rainbow).unwrap(); + println!("{}", html); + Ok(()) +} + +pub use analysis_bench::{analysis_bench, BenchWhat, Position}; +pub use analysis_stats::analysis_stats; + +fn file() -> Result { + let text = read_stdin()?; + Ok(SourceFile::parse(&text).tree()) +} + +fn read_stdin() -> Result { + let mut buff = String::new(); + std::io::stdin().read_to_string(&mut buff)?; + Ok(buff) +} diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_lsp_server/src/cli/analysis_bench.rs similarity index 81% rename from crates/ra_cli/src/analysis_bench.rs rename to crates/ra_lsp_server/src/cli/analysis_bench.rs index 91fc55fe2000..e00f8107348e 100644 --- a/crates/ra_cli/src/analysis_bench.rs +++ b/crates/ra_lsp_server/src/cli/analysis_bench.rs @@ -1,17 +1,48 @@ //! FIXME: write short doc here -use std::{path::Path, sync::Arc, time::Instant}; +use std::{ + path::{Path, PathBuf}, + str::FromStr, + sync::Arc, + time::Instant, +}; -use anyhow::format_err; +use anyhow::{format_err, Result}; use ra_db::{ salsa::{Database, Durability}, FileId, SourceDatabaseExt, }; use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol}; -use crate::{load_cargo::load_cargo, BenchWhat, Result, Verbosity}; +use crate::cli::{load_cargo::load_cargo, Verbosity}; -pub(crate) fn run(verbosity: Verbosity, path: &Path, what: BenchWhat) -> Result<()> { +pub enum BenchWhat { + Highlight { path: PathBuf }, + Complete(Position), + GotoDef(Position), +} + +pub struct Position { + pub path: PathBuf, + pub line: u32, + pub column: u32, +} + +impl FromStr for Position { + type Err = anyhow::Error; + fn from_str(s: &str) -> Result { + 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..])) +} + +pub fn analysis_bench(verbosity: Verbosity, path: &Path, what: BenchWhat) -> Result<()> { ra_prof::init(); let start = Instant::now(); diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_lsp_server/src/cli/analysis_stats.rs similarity index 98% rename from crates/ra_cli/src/analysis_stats.rs rename to crates/ra_lsp_server/src/cli/analysis_stats.rs index d40f04391995..c27fabe3c4bc 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_lsp_server/src/cli/analysis_stats.rs @@ -13,9 +13,9 @@ use ra_db::SourceDatabaseExt; use ra_syntax::AstNode; use rand::{seq::SliceRandom, thread_rng}; -use crate::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity}; +use crate::cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity}; -pub fn run( +pub fn analysis_stats( verbosity: Verbosity, memory_usage: bool, path: &Path, diff --git a/crates/ra_cli/src/load_cargo.rs b/crates/ra_lsp_server/src/cli/load_cargo.rs similarity index 100% rename from crates/ra_cli/src/load_cargo.rs rename to crates/ra_lsp_server/src/cli/load_cargo.rs diff --git a/crates/ra_cli/src/progress_report.rs b/crates/ra_lsp_server/src/cli/progress_report.rs similarity index 100% rename from crates/ra_cli/src/progress_report.rs rename to crates/ra_lsp_server/src/cli/progress_report.rs diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index a3464a5a3c68..2832b260576e 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs @@ -7,6 +7,8 @@ //! state, and `main_loop` module defines the rules for modifying it. #![recursion_limit = "512"] +pub mod cli; + #[allow(unused)] macro_rules! println { ($($tt:tt)*) => { diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index ed2eaabd4ca9..a549e5ff1249 100644 --- a/crates/ra_lsp_server/src/main.rs +++ b/crates/ra_lsp_server/src/main.rs @@ -1,14 +1,39 @@ //! `ra_lsp_server` binary +mod args; use lsp_server::Connection; -use ra_lsp_server::{from_json, show_message, Result, ServerConfig}; +use ra_lsp_server::{cli, from_json, show_message, Result, ServerConfig}; use ra_prof; +use crate::args::HelpPrinted; + fn main() -> Result<()> { setup_logging()?; - match Args::parse()? { - Args::Version => println!("rust-analyzer {}", env!("REV")), - Args::Run => run_server()?, + let args = match args::Args::parse()? { + Ok(it) => it, + Err(HelpPrinted) => return Ok(()), + }; + match args.command { + args::Command::Parse { no_dump } => cli::parse(no_dump)?, + args::Command::Symbols => cli::symbols()?, + args::Command::Highlight { rainbow } => cli::highlight(rainbow)?, + args::Command::Stats { randomize, memory_usage, only, with_deps, path } => { + cli::analysis_stats( + args.verbosity, + memory_usage, + path.as_ref(), + only.as_ref().map(String::as_ref), + with_deps, + randomize, + )? + } + + args::Command::Bench { path, what } => { + cli::analysis_bench(args.verbosity, path.as_ref(), what)? + } + + args::Command::RunServer => run_server()?, + args::Command::Version => println!("rust-analyzer {}", env!("REV")), } Ok(()) } @@ -20,19 +45,6 @@ fn setup_logging() -> Result<()> { Ok(()) } -enum Args { - Version, - Run, -} - -impl Args { - fn parse() -> Result { - let res = - if std::env::args().any(|it| it == "--version") { Args::Version } else { Args::Run }; - Ok(res) - } -} - fn run_server() -> Result<()> { log::info!("lifecycle: server started");