aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src/bin
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-02-18 10:56:18 +0000
committerAleksey Kladov <[email protected]>2020-02-18 10:56:18 +0000
commit59e1207dac8eb9cc56a72ee685bd4f143683d2bb (patch)
treeb0e50ea24a14dcc165de87f1df4b09c0a984483e /crates/ra_lsp_server/src/bin
parenta349e5d4fcda1a6b96a09491a59d1ec940a48654 (diff)
Better folder structure
Diffstat (limited to 'crates/ra_lsp_server/src/bin')
-rw-r--r--crates/ra_lsp_server/src/bin/args.rs242
-rw-r--r--crates/ra_lsp_server/src/bin/main.rs96
2 files changed, 338 insertions, 0 deletions
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 @@
1//! Command like parsing for rust-analyzer.
2//!
3//! If run started args, we run the LSP server loop. With a subcommand, we do a
4//! one-time batch processing.
5
6use anyhow::{bail, Result};
7use pico_args::Arguments;
8use ra_lsp_server::cli::{BenchWhat, Position, Verbosity};
9
10use std::{fmt::Write, path::PathBuf};
11
12pub(crate) struct Args {
13 pub(crate) verbosity: Verbosity,
14 pub(crate) command: Command,
15}
16
17pub(crate) enum Command {
18 Parse {
19 no_dump: bool,
20 },
21 Symbols,
22 Highlight {
23 rainbow: bool,
24 },
25 Stats {
26 randomize: bool,
27 memory_usage: bool,
28 only: Option<String>,
29 with_deps: bool,
30 path: PathBuf,
31 },
32 Bench {
33 path: PathBuf,
34 what: BenchWhat,
35 },
36 RunServer,
37 Version,
38}
39
40impl Args {
41 pub(crate) fn parse() -> Result<Result<Args, HelpPrinted>> {
42 let mut matches = Arguments::from_env();
43
44 if matches.contains("--version") {
45 matches.finish().or_else(handle_extra_flags)?;
46 return Ok(Ok(Args { verbosity: Verbosity::Normal, command: Command::Version }));
47 }
48
49 let verbosity = match (
50 matches.contains(["-vv", "--spammy"]),
51 matches.contains(["-v", "--verbose"]),
52 matches.contains(["-q", "--quiet"]),
53 ) {
54 (true, _, true) => bail!("Invalid flags: -q conflicts with -vv"),
55 (true, _, false) => Verbosity::Spammy,
56 (false, false, false) => Verbosity::Normal,
57 (false, false, true) => Verbosity::Quiet,
58 (false, true, false) => Verbosity::Verbose,
59 (false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
60 };
61
62 let subcommand = match matches.subcommand()? {
63 Some(it) => it,
64 None => {
65 matches.finish().or_else(handle_extra_flags)?;
66 return Ok(Ok(Args { verbosity, command: Command::RunServer }));
67 }
68 };
69 let command = match subcommand.as_str() {
70 "parse" => {
71 if matches.contains(["-h", "--help"]) {
72 eprintln!(
73 "\
74ra-cli-parse
75
76USAGE:
77 ra_lsp_server parse [FLAGS]
78
79FLAGS:
80 -h, --help Prints help inforamtion
81 --no-dump"
82 );
83 return Ok(Err(HelpPrinted));
84 }
85
86 let no_dump = matches.contains("--no-dump");
87 matches.finish().or_else(handle_extra_flags)?;
88 Command::Parse { no_dump }
89 }
90 "symbols" => {
91 if matches.contains(["-h", "--help"]) {
92 eprintln!(
93 "\
94ra-cli-symbols
95
96USAGE:
97 ra_lsp_server highlight [FLAGS]
98
99FLAGS:
100 -h, --help Prints help inforamtion"
101 );
102 return Ok(Err(HelpPrinted));
103 }
104
105 matches.finish().or_else(handle_extra_flags)?;
106
107 Command::Symbols
108 }
109 "highlight" => {
110 if matches.contains(["-h", "--help"]) {
111 eprintln!(
112 "\
113ra-cli-highlight
114
115USAGE:
116 ra_lsp_server highlight [FLAGS]
117
118FLAGS:
119 -h, --help Prints help information
120 -r, --rainbow"
121 );
122 return Ok(Err(HelpPrinted));
123 }
124
125 let rainbow = matches.contains(["-r", "--rainbow"]);
126 matches.finish().or_else(handle_extra_flags)?;
127 Command::Highlight { rainbow }
128 }
129 "analysis-stats" => {
130 if matches.contains(["-h", "--help"]) {
131 eprintln!(
132 "\
133ra-cli-analysis-stats
134
135USAGE:
136 ra_lsp_server analysis-stats [FLAGS] [OPTIONS] [PATH]
137
138FLAGS:
139 -h, --help Prints help information
140 --memory-usage
141 -v, --verbose
142 -q, --quiet
143
144OPTIONS:
145 -o <ONLY>
146
147ARGS:
148 <PATH>"
149 );
150 return Ok(Err(HelpPrinted));
151 }
152
153 let randomize = matches.contains("--randomize");
154 let memory_usage = matches.contains("--memory-usage");
155 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
156 let with_deps: bool = matches.contains("--with-deps");
157 let path = {
158 let mut trailing = matches.free()?;
159 if trailing.len() != 1 {
160 bail!("Invalid flags");
161 }
162 trailing.pop().unwrap().into()
163 };
164
165 Command::Stats { randomize, memory_usage, only, with_deps, path }
166 }
167 "analysis-bench" => {
168 if matches.contains(["-h", "--help"]) {
169 eprintln!(
170 "\
171ra_lsp_server-analysis-bench
172
173USAGE:
174 ra_lsp_server analysis-bench [FLAGS] [OPTIONS] [PATH]
175
176FLAGS:
177 -h, --help Prints help information
178 -v, --verbose
179
180OPTIONS:
181 --complete <PATH:LINE:COLUMN> Compute completions at this location
182 --highlight <PATH> Hightlight this file
183
184ARGS:
185 <PATH> Project to analyse"
186 );
187 return Ok(Err(HelpPrinted));
188 }
189
190 let path: PathBuf = matches.opt_value_from_str("--path")?.unwrap_or_default();
191 let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?;
192 let complete_path: Option<Position> = matches.opt_value_from_str("--complete")?;
193 let goto_def_path: Option<Position> = matches.opt_value_from_str("--goto-def")?;
194 let what = match (highlight_path, complete_path, goto_def_path) {
195 (Some(path), None, None) => BenchWhat::Highlight { path: path.into() },
196 (None, Some(position), None) => BenchWhat::Complete(position),
197 (None, None, Some(position)) => BenchWhat::GotoDef(position),
198 _ => panic!(
199 "exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
200 ),
201 };
202 Command::Bench { path, what }
203 }
204 _ => {
205 eprintln!(
206 "\
207ra-cli
208
209USAGE:
210 ra_lsp_server <SUBCOMMAND>
211
212FLAGS:
213 -h, --help Prints help information
214
215SUBCOMMANDS:
216 analysis-bench
217 analysis-stats
218 highlight
219 parse
220 symbols"
221 );
222 return Ok(Err(HelpPrinted));
223 }
224 };
225 Ok(Ok(Args { verbosity, command }))
226 }
227}
228
229pub(crate) struct HelpPrinted;
230
231fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
232 if let pico_args::Error::UnusedArgsLeft(flags) = e {
233 let mut invalid_flags = String::new();
234 for flag in flags {
235 write!(&mut invalid_flags, "{}, ", flag)?;
236 }
237 let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
238 bail!("Invalid flags: {}", invalid_flags);
239 } else {
240 bail!(e);
241 }
242}
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 @@
1//! `ra_lsp_server` binary
2mod args;
3
4use lsp_server::Connection;
5use ra_lsp_server::{cli, from_json, show_message, Result, ServerConfig};
6use ra_prof;
7
8use crate::args::HelpPrinted;
9
10fn main() -> Result<()> {
11 setup_logging()?;
12 let args = match args::Args::parse()? {
13 Ok(it) => it,
14 Err(HelpPrinted) => return Ok(()),
15 };
16 match args.command {
17 args::Command::Parse { no_dump } => cli::parse(no_dump)?,
18 args::Command::Symbols => cli::symbols()?,
19 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
20 args::Command::Stats { randomize, memory_usage, only, with_deps, path } => {
21 cli::analysis_stats(
22 args.verbosity,
23 memory_usage,
24 path.as_ref(),
25 only.as_ref().map(String::as_ref),
26 with_deps,
27 randomize,
28 )?
29 }
30
31 args::Command::Bench { path, what } => {
32 cli::analysis_bench(args.verbosity, path.as_ref(), what)?
33 }
34
35 args::Command::RunServer => run_server()?,
36 args::Command::Version => println!("rust-analyzer {}", env!("REV")),
37 }
38 Ok(())
39}
40
41fn setup_logging() -> Result<()> {
42 std::env::set_var("RUST_BACKTRACE", "short");
43 env_logger::try_init()?;
44 ra_prof::init();
45 Ok(())
46}
47
48fn run_server() -> Result<()> {
49 log::info!("lifecycle: server started");
50
51 let (connection, io_threads) = Connection::stdio();
52 let server_capabilities = serde_json::to_value(ra_lsp_server::server_capabilities()).unwrap();
53
54 let initialize_params = connection.initialize(server_capabilities)?;
55 let initialize_params =
56 from_json::<lsp_types::InitializeParams>("InitializeParams", initialize_params)?;
57
58 if let Some(client_info) = initialize_params.client_info {
59 log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default());
60 }
61
62 let cwd = std::env::current_dir()?;
63 let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);
64
65 let workspace_roots = initialize_params
66 .workspace_folders
67 .map(|workspaces| {
68 workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::<Vec<_>>()
69 })
70 .filter(|workspaces| !workspaces.is_empty())
71 .unwrap_or_else(|| vec![root]);
72
73 let server_config = initialize_params
74 .initialization_options
75 .and_then(|v| {
76 from_json::<ServerConfig>("config", v)
77 .map_err(|e| {
78 log::error!("{}", e);
79 show_message(lsp_types::MessageType::Error, e.to_string(), &connection.sender);
80 })
81 .ok()
82 })
83 .unwrap_or_default();
84
85 ra_lsp_server::main_loop(
86 workspace_roots,
87 initialize_params.capabilities,
88 server_config,
89 connection,
90 )?;
91
92 log::info!("shutting down IO...");
93 io_threads.join()?;
94 log::info!("... IO is down");
95 Ok(())
96}