From 59e1207dac8eb9cc56a72ee685bd4f143683d2bb Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 18 Feb 2020 11:56:18 +0100 Subject: Better folder structure --- crates/ra_lsp_server/src/bin/args.rs | 242 +++++++++++++++++++++++++++++++++++ crates/ra_lsp_server/src/bin/main.rs | 96 ++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 crates/ra_lsp_server/src/bin/args.rs create mode 100644 crates/ra_lsp_server/src/bin/main.rs (limited to 'crates/ra_lsp_server/src/bin') diff --git a/crates/ra_lsp_server/src/bin/args.rs b/crates/ra_lsp_server/src/bin/args.rs new file mode 100644 index 000000000..3890fe13a --- /dev/null +++ b/crates/ra_lsp_server/src/bin/args.rs @@ -0,0 +1,242 @@ +//! Command like parsing for rust-analyzer. +//! +//! If run started args, we run the LSP server loop. With a subcommand, we do a +//! one-time batch processing. + +use anyhow::{bail, Result}; +use pico_args::Arguments; +use ra_lsp_server::cli::{BenchWhat, Position, Verbosity}; + +use std::{fmt::Write, path::PathBuf}; + +pub(crate) struct Args { + pub(crate) verbosity: Verbosity, + pub(crate) command: Command, +} + +pub(crate) enum Command { + Parse { + no_dump: bool, + }, + Symbols, + Highlight { + rainbow: bool, + }, + Stats { + randomize: bool, + memory_usage: bool, + only: Option, + with_deps: bool, + path: PathBuf, + }, + Bench { + path: PathBuf, + what: BenchWhat, + }, + RunServer, + Version, +} + +impl Args { + pub(crate) fn parse() -> Result> { + let mut matches = Arguments::from_env(); + + 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"]), + 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 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"]) { + eprintln!( + "\ +ra-cli-parse + +USAGE: + ra_lsp_server parse [FLAGS] + +FLAGS: + -h, --help Prints help inforamtion + --no-dump" + ); + return Ok(Err(HelpPrinted)); + } + + 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!( + "\ +ra-cli-symbols + +USAGE: + ra_lsp_server highlight [FLAGS] + +FLAGS: + -h, --help Prints help inforamtion" + ); + return Ok(Err(HelpPrinted)); + } + + matches.finish().or_else(handle_extra_flags)?; + + Command::Symbols + } + "highlight" => { + if matches.contains(["-h", "--help"]) { + eprintln!( + "\ +ra-cli-highlight + +USAGE: + ra_lsp_server highlight [FLAGS] + +FLAGS: + -h, --help Prints help information + -r, --rainbow" + ); + return Ok(Err(HelpPrinted)); + } + + let rainbow = matches.contains(["-r", "--rainbow"]); + matches.finish().or_else(handle_extra_flags)?; + Command::Highlight { rainbow } + } + "analysis-stats" => { + if matches.contains(["-h", "--help"]) { + eprintln!( + "\ +ra-cli-analysis-stats + +USAGE: + ra_lsp_server analysis-stats [FLAGS] [OPTIONS] [PATH] + +FLAGS: + -h, --help Prints help information + --memory-usage + -v, --verbose + -q, --quiet + +OPTIONS: + -o + +ARGS: + " + ); + return Ok(Err(HelpPrinted)); + } + + let randomize = matches.contains("--randomize"); + 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 path = { + let mut trailing = matches.free()?; + if trailing.len() != 1 { + bail!("Invalid flags"); + } + trailing.pop().unwrap().into() + }; + + Command::Stats { randomize, memory_usage, only, with_deps, path } + } + "analysis-bench" => { + if matches.contains(["-h", "--help"]) { + eprintln!( + "\ +ra_lsp_server-analysis-bench + +USAGE: + ra_lsp_server analysis-bench [FLAGS] [OPTIONS] [PATH] + +FLAGS: + -h, --help Prints help information + -v, --verbose + +OPTIONS: + --complete Compute completions at this location + --highlight Hightlight this file + +ARGS: + Project to analyse" + ); + return Ok(Err(HelpPrinted)); + } + + let path: PathBuf = matches.opt_value_from_str("--path")?.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")?; + 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 { path, what } + } + _ => { + eprintln!( + "\ +ra-cli + +USAGE: + ra_lsp_server + +FLAGS: + -h, --help Prints help information + +SUBCOMMANDS: + analysis-bench + analysis-stats + highlight + parse + symbols" + ); + return Ok(Err(HelpPrinted)); + } + }; + 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(); + for flag in flags { + write!(&mut invalid_flags, "{}, ", flag)?; + } + let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2); + bail!("Invalid flags: {}", invalid_flags); + } else { + bail!(e); + } +} diff --git a/crates/ra_lsp_server/src/bin/main.rs b/crates/ra_lsp_server/src/bin/main.rs new file mode 100644 index 000000000..a549e5ff1 --- /dev/null +++ b/crates/ra_lsp_server/src/bin/main.rs @@ -0,0 +1,96 @@ +//! `ra_lsp_server` binary +mod args; + +use lsp_server::Connection; +use ra_lsp_server::{cli, from_json, show_message, Result, ServerConfig}; +use ra_prof; + +use crate::args::HelpPrinted; + +fn main() -> Result<()> { + setup_logging()?; + 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(()) +} + +fn setup_logging() -> Result<()> { + std::env::set_var("RUST_BACKTRACE", "short"); + env_logger::try_init()?; + ra_prof::init(); + Ok(()) +} + +fn run_server() -> Result<()> { + log::info!("lifecycle: server started"); + + let (connection, io_threads) = Connection::stdio(); + let server_capabilities = serde_json::to_value(ra_lsp_server::server_capabilities()).unwrap(); + + let initialize_params = connection.initialize(server_capabilities)?; + let initialize_params = + from_json::("InitializeParams", initialize_params)?; + + if let Some(client_info) = initialize_params.client_info { + log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); + } + + let cwd = std::env::current_dir()?; + let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); + + let workspace_roots = initialize_params + .workspace_folders + .map(|workspaces| { + workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::>() + }) + .filter(|workspaces| !workspaces.is_empty()) + .unwrap_or_else(|| vec![root]); + + let server_config = initialize_params + .initialization_options + .and_then(|v| { + from_json::("config", v) + .map_err(|e| { + log::error!("{}", e); + show_message(lsp_types::MessageType::Error, e.to_string(), &connection.sender); + }) + .ok() + }) + .unwrap_or_default(); + + ra_lsp_server::main_loop( + workspace_roots, + initialize_params.capabilities, + server_config, + connection, + )?; + + log::info!("shutting down IO..."); + io_threads.join()?; + log::info!("... IO is down"); + Ok(()) +} -- cgit v1.2.3 From 93b969003d0a9448d4207d9d5df9dde63f9444be Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 18 Feb 2020 12:11:32 +0100 Subject: Some docs --- crates/ra_lsp_server/src/bin/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'crates/ra_lsp_server/src/bin') diff --git a/crates/ra_lsp_server/src/bin/main.rs b/crates/ra_lsp_server/src/bin/main.rs index a549e5ff1..e25d54a0d 100644 --- a/crates/ra_lsp_server/src/bin/main.rs +++ b/crates/ra_lsp_server/src/bin/main.rs @@ -1,4 +1,6 @@ -//! `ra_lsp_server` binary +//! Driver for rust-analyzer. +//! +//! Based on cli flags, either spawns an LSP server, or runs a batch analysis mod args; use lsp_server::Connection; -- cgit v1.2.3