diff options
-rw-r--r-- | crates/rust-analyzer/src/benchmarks.rs | 69 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/flags.rs | 53 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 13 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/analysis_bench.rs | 196 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lib.rs | 3 | ||||
-rw-r--r-- | docs/dev/README.md | 73 |
7 files changed, 111 insertions, 300 deletions
diff --git a/crates/rust-analyzer/src/benchmarks.rs b/crates/rust-analyzer/src/benchmarks.rs new file mode 100644 index 000000000..a6f997af8 --- /dev/null +++ b/crates/rust-analyzer/src/benchmarks.rs | |||
@@ -0,0 +1,69 @@ | |||
1 | //! Fully integrated benchmarks for rust-analyzer, which load real cargo | ||
2 | //! projects. | ||
3 | //! | ||
4 | //! The benchmark here is used to debug specific performance regressions. If you | ||
5 | //! notice that, eg, completion is slow in some specific case, you can modify | ||
6 | //! code here exercise this specific completion, and thus have a fast | ||
7 | //! edit/compile/test cycle. | ||
8 | //! | ||
9 | //! Note that "Rust Analyzer: Run" action does not allow running a single test | ||
10 | //! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line" | ||
11 | //! which you can use to paste the command in terminal and add `--release` manually. | ||
12 | |||
13 | use std::sync::Arc; | ||
14 | |||
15 | use ide::Change; | ||
16 | use test_utils::project_root; | ||
17 | use vfs::{AbsPathBuf, VfsPath}; | ||
18 | |||
19 | use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig}; | ||
20 | |||
21 | #[test] | ||
22 | fn benchmark_integrated_highlighting() { | ||
23 | // Don't run slow benchmark by default | ||
24 | if true { | ||
25 | return; | ||
26 | } | ||
27 | |||
28 | // Load rust-analyzer itself. | ||
29 | let workspace_to_load = project_root(); | ||
30 | let file = "./crates/ide_db/src/apply_change.rs"; | ||
31 | |||
32 | let cargo_config = Default::default(); | ||
33 | let load_cargo_config = | ||
34 | LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: false }; | ||
35 | |||
36 | let (mut host, vfs, _proc_macro) = { | ||
37 | let _it = stdx::timeit("workspace loading"); | ||
38 | load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap() | ||
39 | }; | ||
40 | |||
41 | let file_id = { | ||
42 | let file = workspace_to_load.join(file); | ||
43 | let path = VfsPath::from(AbsPathBuf::assert(file)); | ||
44 | vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path)) | ||
45 | }; | ||
46 | |||
47 | { | ||
48 | let _it = stdx::timeit("initial"); | ||
49 | let analysis = host.analysis(); | ||
50 | analysis.highlight_as_html(file_id, false).unwrap(); | ||
51 | } | ||
52 | |||
53 | profile::init_from("*>100"); | ||
54 | |||
55 | { | ||
56 | let _it = stdx::timeit("change"); | ||
57 | let mut text = host.analysis().file_text(file_id).unwrap().to_string(); | ||
58 | text.push_str("\npub fn _dummy() {}\n"); | ||
59 | let mut change = Change::new(); | ||
60 | change.change_file(file_id, Some(Arc::new(text))); | ||
61 | host.apply_change(change); | ||
62 | } | ||
63 | |||
64 | { | ||
65 | let _it = stdx::timeit("after change"); | ||
66 | let analysis = host.analysis(); | ||
67 | analysis.highlight_as_html(file_id, false).unwrap(); | ||
68 | } | ||
69 | } | ||
diff --git a/crates/rust-analyzer/src/bin/flags.rs b/crates/rust-analyzer/src/bin/flags.rs index d8987633d..b05fc00b9 100644 --- a/crates/rust-analyzer/src/bin/flags.rs +++ b/crates/rust-analyzer/src/bin/flags.rs | |||
@@ -1,10 +1,9 @@ | |||
1 | //! Grammar for the command-line arguments. | 1 | //! Grammar for the command-line arguments. |
2 | #![allow(unreachable_pub)] | 2 | #![allow(unreachable_pub)] |
3 | use std::{env, path::PathBuf}; | 3 | use std::path::PathBuf; |
4 | 4 | ||
5 | use ide_ssr::{SsrPattern, SsrRule}; | 5 | use ide_ssr::{SsrPattern, SsrRule}; |
6 | use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; | 6 | use rust_analyzer::cli::Verbosity; |
7 | use vfs::AbsPathBuf; | ||
8 | 7 | ||
9 | xflags::xflags! { | 8 | xflags::xflags! { |
10 | src "./src/bin/flags.rs" | 9 | src "./src/bin/flags.rs" |
@@ -74,27 +73,6 @@ xflags::xflags! { | |||
74 | optional --with-proc-macro | 73 | optional --with-proc-macro |
75 | } | 74 | } |
76 | 75 | ||
77 | /// Benchmark specific analysis operation | ||
78 | cmd analysis-bench | ||
79 | /// Directory with Cargo.toml. | ||
80 | required path: PathBuf | ||
81 | { | ||
82 | /// Collect memory usage statistics. | ||
83 | optional --memory-usage | ||
84 | |||
85 | /// Compute syntax highlighting for this file | ||
86 | optional --highlight path: PathBuf | ||
87 | /// Compute completions at file:line:column location. | ||
88 | optional --complete location: Position | ||
89 | /// Compute goto definition at file:line:column location. | ||
90 | optional --goto-def location: Position | ||
91 | |||
92 | /// Load OUT_DIR values by running `cargo check` before analysis. | ||
93 | optional --load-output-dirs | ||
94 | /// Use proc-macro-srv for proc-macro expanding. | ||
95 | optional --with-proc-macro | ||
96 | } | ||
97 | |||
98 | cmd diagnostics | 76 | cmd diagnostics |
99 | /// Directory with Cargo.toml. | 77 | /// Directory with Cargo.toml. |
100 | required path: PathBuf | 78 | required path: PathBuf |
@@ -142,7 +120,6 @@ pub enum RustAnalyzerCmd { | |||
142 | Symbols(Symbols), | 120 | Symbols(Symbols), |
143 | Highlight(Highlight), | 121 | Highlight(Highlight), |
144 | AnalysisStats(AnalysisStats), | 122 | AnalysisStats(AnalysisStats), |
145 | AnalysisBench(AnalysisBench), | ||
146 | Diagnostics(Diagnostics), | 123 | Diagnostics(Diagnostics), |
147 | Ssr(Ssr), | 124 | Ssr(Ssr), |
148 | Search(Search), | 125 | Search(Search), |
@@ -184,18 +161,6 @@ pub struct AnalysisStats { | |||
184 | } | 161 | } |
185 | 162 | ||
186 | #[derive(Debug)] | 163 | #[derive(Debug)] |
187 | pub struct AnalysisBench { | ||
188 | pub path: PathBuf, | ||
189 | |||
190 | pub memory_usage: bool, | ||
191 | pub highlight: Option<PathBuf>, | ||
192 | pub complete: Option<Position>, | ||
193 | pub goto_def: Option<Position>, | ||
194 | pub load_output_dirs: bool, | ||
195 | pub with_proc_macro: bool, | ||
196 | } | ||
197 | |||
198 | #[derive(Debug)] | ||
199 | pub struct Diagnostics { | 164 | pub struct Diagnostics { |
200 | pub path: PathBuf, | 165 | pub path: PathBuf, |
201 | 166 | ||
@@ -239,17 +204,3 @@ impl RustAnalyzer { | |||
239 | } | 204 | } |
240 | } | 205 | } |
241 | } | 206 | } |
242 | |||
243 | impl AnalysisBench { | ||
244 | pub(crate) fn what(&self) -> BenchWhat { | ||
245 | match (&self.highlight, &self.complete, &self.goto_def) { | ||
246 | (Some(path), None, None) => { | ||
247 | let path = env::current_dir().unwrap().join(path); | ||
248 | BenchWhat::Highlight { path: AbsPathBuf::assert(path) } | ||
249 | } | ||
250 | (None, Some(position), None) => BenchWhat::Complete(position.clone()), | ||
251 | (None, None, Some(position)) => BenchWhat::GotoDef(position.clone()), | ||
252 | _ => panic!("exactly one of `--highlight`, `--complete` or `--goto-def` must be set"), | ||
253 | } | ||
254 | } | ||
255 | } | ||
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index a0b611bff..ae99eefe3 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -9,7 +9,7 @@ use std::{convert::TryFrom, env, fs, path::Path, process}; | |||
9 | use lsp_server::Connection; | 9 | use lsp_server::Connection; |
10 | use project_model::ProjectManifest; | 10 | use project_model::ProjectManifest; |
11 | use rust_analyzer::{ | 11 | use rust_analyzer::{ |
12 | cli::{self, AnalysisStatsCmd, BenchCmd}, | 12 | cli::{self, AnalysisStatsCmd}, |
13 | config::Config, | 13 | config::Config, |
14 | from_json, | 14 | from_json, |
15 | lsp_ext::supports_utf8, | 15 | lsp_ext::supports_utf8, |
@@ -80,17 +80,6 @@ fn try_main() -> Result<()> { | |||
80 | with_proc_macro: cmd.with_proc_macro, | 80 | with_proc_macro: cmd.with_proc_macro, |
81 | } | 81 | } |
82 | .run(verbosity)?, | 82 | .run(verbosity)?, |
83 | flags::RustAnalyzerCmd::AnalysisBench(cmd) => { | ||
84 | let what = cmd.what(); | ||
85 | BenchCmd { | ||
86 | memory_usage: cmd.memory_usage, | ||
87 | path: cmd.path, | ||
88 | load_output_dirs: cmd.load_output_dirs, | ||
89 | with_proc_macro: cmd.with_proc_macro, | ||
90 | what, | ||
91 | } | ||
92 | .run(verbosity)? | ||
93 | } | ||
94 | 83 | ||
95 | flags::RustAnalyzerCmd::Diagnostics(cmd) => { | 84 | flags::RustAnalyzerCmd::Diagnostics(cmd) => { |
96 | cli::diagnostics(&cmd.path, cmd.load_output_dirs, cmd.with_proc_macro)? | 85 | cli::diagnostics(&cmd.path, cmd.load_output_dirs, cmd.with_proc_macro)? |
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index ed732eb38..76b666dc2 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs | |||
@@ -1,8 +1,7 @@ | |||
1 | //! Various batch processing tasks, intended primarily for debugging. | 1 | //! Various batch processing tasks, intended primarily for debugging. |
2 | 2 | ||
3 | mod load_cargo; | 3 | pub(crate) mod load_cargo; |
4 | mod analysis_stats; | 4 | mod analysis_stats; |
5 | mod analysis_bench; | ||
6 | mod diagnostics; | 5 | mod diagnostics; |
7 | mod progress_report; | 6 | mod progress_report; |
8 | mod ssr; | 7 | mod ssr; |
@@ -15,7 +14,6 @@ use syntax::{AstNode, SourceFile}; | |||
15 | use vfs::Vfs; | 14 | use vfs::Vfs; |
16 | 15 | ||
17 | pub use self::{ | 16 | pub use self::{ |
18 | analysis_bench::{BenchCmd, BenchWhat, Position}, | ||
19 | analysis_stats::AnalysisStatsCmd, | 17 | analysis_stats::AnalysisStatsCmd, |
20 | diagnostics::diagnostics, | 18 | diagnostics::diagnostics, |
21 | load_cargo::{load_workspace, load_workspace_at, LoadCargoConfig}, | 19 | load_cargo::{load_workspace, load_workspace_at, LoadCargoConfig}, |
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs deleted file mode 100644 index 49994824f..000000000 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ /dev/null | |||
@@ -1,196 +0,0 @@ | |||
1 | //! Benchmark operations like highlighting or goto definition. | ||
2 | |||
3 | use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; | ||
4 | |||
5 | use anyhow::{bail, format_err, Result}; | ||
6 | use hir::PrefixKind; | ||
7 | use ide::{ | ||
8 | Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, | ||
9 | }; | ||
10 | use ide_db::{ | ||
11 | base_db::{ | ||
12 | salsa::{Database, Durability}, | ||
13 | FileId, | ||
14 | }, | ||
15 | helpers::{insert_use::InsertUseConfig, SnippetCap}, | ||
16 | }; | ||
17 | use vfs::AbsPathBuf; | ||
18 | |||
19 | use crate::cli::{ | ||
20 | load_cargo::{load_workspace_at, LoadCargoConfig}, | ||
21 | print_memory_usage, Verbosity, | ||
22 | }; | ||
23 | |||
24 | pub struct BenchCmd { | ||
25 | pub path: PathBuf, | ||
26 | pub what: BenchWhat, | ||
27 | pub memory_usage: bool, | ||
28 | pub load_output_dirs: bool, | ||
29 | pub with_proc_macro: bool, | ||
30 | } | ||
31 | |||
32 | pub enum BenchWhat { | ||
33 | Highlight { path: AbsPathBuf }, | ||
34 | Complete(Position), | ||
35 | GotoDef(Position), | ||
36 | } | ||
37 | |||
38 | #[derive(Debug, Clone)] | ||
39 | pub struct Position { | ||
40 | pub path: AbsPathBuf, | ||
41 | pub line: u32, | ||
42 | pub column: u32, | ||
43 | } | ||
44 | |||
45 | impl FromStr for Position { | ||
46 | type Err = anyhow::Error; | ||
47 | fn from_str(s: &str) -> Result<Self> { | ||
48 | let mut split = s.rsplitn(3, ':'); | ||
49 | match (split.next(), split.next(), split.next()) { | ||
50 | (Some(column), Some(line), Some(path)) => { | ||
51 | let path = env::current_dir().unwrap().join(path); | ||
52 | let path = AbsPathBuf::assert(path); | ||
53 | Ok(Position { path, line: line.parse()?, column: column.parse()? }) | ||
54 | } | ||
55 | _ => bail!("position should be in file:line:column format: {:?}", s), | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
60 | impl BenchCmd { | ||
61 | pub fn run(self, verbosity: Verbosity) -> Result<()> { | ||
62 | profile::init(); | ||
63 | |||
64 | let start = Instant::now(); | ||
65 | eprint!("loading: "); | ||
66 | |||
67 | let cargo_config = Default::default(); | ||
68 | let load_cargo_config = LoadCargoConfig { | ||
69 | load_out_dirs_from_check: self.load_output_dirs, | ||
70 | with_proc_macro: self.with_proc_macro, | ||
71 | }; | ||
72 | let (mut host, vfs, _proc_macro) = | ||
73 | load_workspace_at(&self.path, &cargo_config, &load_cargo_config, &|_| {})?; | ||
74 | eprintln!("{:?}\n", start.elapsed()); | ||
75 | |||
76 | let file_id = { | ||
77 | let path = match &self.what { | ||
78 | BenchWhat::Highlight { path } => path, | ||
79 | BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => &pos.path, | ||
80 | }; | ||
81 | let path = path.clone().into(); | ||
82 | vfs.file_id(&path).ok_or_else(|| format_err!("Can't find {}", path))? | ||
83 | }; | ||
84 | |||
85 | match &self.what { | ||
86 | BenchWhat::Highlight { .. } => { | ||
87 | let res = do_work(&mut host, file_id, |analysis| { | ||
88 | analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); | ||
89 | analysis.highlight_as_html(file_id, false).unwrap() | ||
90 | }); | ||
91 | if verbosity.is_verbose() { | ||
92 | println!("\n{}", res); | ||
93 | } | ||
94 | } | ||
95 | BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => { | ||
96 | let is_completion = matches!(self.what, BenchWhat::Complete(..)); | ||
97 | |||
98 | let offset = host | ||
99 | .analysis() | ||
100 | .file_line_index(file_id)? | ||
101 | .offset(LineCol { line: pos.line - 1, col: pos.column }); | ||
102 | let file_position = FilePosition { file_id, offset }; | ||
103 | |||
104 | if is_completion { | ||
105 | let options = CompletionConfig { | ||
106 | enable_postfix_completions: true, | ||
107 | enable_imports_on_the_fly: true, | ||
108 | add_call_parenthesis: true, | ||
109 | add_call_argument_snippets: true, | ||
110 | snippet_cap: SnippetCap::new(true), | ||
111 | insert_use: InsertUseConfig { | ||
112 | merge: None, | ||
113 | prefix_kind: PrefixKind::Plain, | ||
114 | group: true, | ||
115 | }, | ||
116 | }; | ||
117 | let res = do_work(&mut host, file_id, |analysis| { | ||
118 | analysis.completions(&options, file_position) | ||
119 | }); | ||
120 | if verbosity.is_verbose() { | ||
121 | println!("\n{:#?}", res); | ||
122 | } | ||
123 | } else { | ||
124 | let res = do_work(&mut host, file_id, |analysis| { | ||
125 | analysis.goto_definition(file_position) | ||
126 | }); | ||
127 | if verbosity.is_verbose() { | ||
128 | println!("\n{:#?}", res); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | if self.memory_usage { | ||
135 | print_memory_usage(host, vfs); | ||
136 | } | ||
137 | |||
138 | Ok(()) | ||
139 | } | ||
140 | } | ||
141 | |||
142 | fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, work: F) -> T { | ||
143 | { | ||
144 | let start = Instant::now(); | ||
145 | eprint!("from scratch: "); | ||
146 | work(&host.analysis()); | ||
147 | eprintln!("{:?}", start.elapsed()); | ||
148 | } | ||
149 | { | ||
150 | let start = Instant::now(); | ||
151 | eprint!("no change: "); | ||
152 | work(&host.analysis()); | ||
153 | eprintln!("{:?}", start.elapsed()); | ||
154 | } | ||
155 | { | ||
156 | let start = Instant::now(); | ||
157 | eprint!("trivial change: "); | ||
158 | host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::LOW); | ||
159 | work(&host.analysis()); | ||
160 | eprintln!("{:?}", start.elapsed()); | ||
161 | } | ||
162 | { | ||
163 | let start = Instant::now(); | ||
164 | eprint!("comment change: "); | ||
165 | { | ||
166 | let mut text = host.analysis().file_text(file_id).unwrap().to_string(); | ||
167 | text.push_str("\n/* Hello world */\n"); | ||
168 | let mut change = Change::new(); | ||
169 | change.change_file(file_id, Some(Arc::new(text))); | ||
170 | host.apply_change(change); | ||
171 | } | ||
172 | work(&host.analysis()); | ||
173 | eprintln!("{:?}", start.elapsed()); | ||
174 | } | ||
175 | { | ||
176 | let start = Instant::now(); | ||
177 | eprint!("item change: "); | ||
178 | { | ||
179 | let mut text = host.analysis().file_text(file_id).unwrap().to_string(); | ||
180 | text.push_str("\npub fn _dummy() {}\n"); | ||
181 | let mut change = Change::new(); | ||
182 | change.change_file(file_id, Some(Arc::new(text))); | ||
183 | host.apply_change(change); | ||
184 | } | ||
185 | work(&host.analysis()); | ||
186 | eprintln!("{:?}", start.elapsed()); | ||
187 | } | ||
188 | { | ||
189 | let start = Instant::now(); | ||
190 | eprint!("const change: "); | ||
191 | host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::HIGH); | ||
192 | let res = work(&host.analysis()); | ||
193 | eprintln!("{:?}", start.elapsed()); | ||
194 | res | ||
195 | } | ||
196 | } | ||
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 8b874239c..d9a5030a0 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -39,6 +39,9 @@ mod op_queue; | |||
39 | pub mod lsp_ext; | 39 | pub mod lsp_ext; |
40 | pub mod config; | 40 | pub mod config; |
41 | 41 | ||
42 | #[cfg(test)] | ||
43 | mod benchmarks; | ||
44 | |||
42 | use serde::de::DeserializeOwned; | 45 | use serde::de::DeserializeOwned; |
43 | use std::fmt; | 46 | use std::fmt; |
44 | 47 | ||
diff --git a/docs/dev/README.md b/docs/dev/README.md index dcbab1a1d..eab21a765 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -1,7 +1,7 @@ | |||
1 | # Contributing Quick Start | 1 | # Contributing Quick Start |
2 | 2 | ||
3 | Rust Analyzer is an ordinary Rust project, which is organized as a Cargo | 3 | Rust Analyzer is an ordinary Rust project, which is organized as a Cargo workspace, builds on stable and doesn't depend on C libraries. |
4 | workspace, builds on stable and doesn't depend on C libraries. So, just | 4 | So, just |
5 | 5 | ||
6 | ``` | 6 | ``` |
7 | $ cargo test | 7 | $ cargo test |
@@ -13,9 +13,8 @@ To learn more about how rust-analyzer works, see [./architecture.md](./architect | |||
13 | It also explains the high-level layout of the source code. | 13 | It also explains the high-level layout of the source code. |
14 | Do skim through that document. | 14 | Do skim through that document. |
15 | 15 | ||
16 | We also publish rustdoc docs to pages: | 16 | We also publish rustdoc docs to pages: https://rust-analyzer.github.io/rust-analyzer/ide/. |
17 | 17 | Note though, that internal documentation is very incomplete. | |
18 | https://rust-analyzer.github.io/rust-analyzer/ide/ | ||
19 | 18 | ||
20 | Various organizational and process issues are discussed in this document. | 19 | Various organizational and process issues are discussed in this document. |
21 | 20 | ||
@@ -49,21 +48,28 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 | |||
49 | Also a kind of fun. | 48 | Also a kind of fun. |
50 | These issues should generally include a link to a Zulip discussion thread. | 49 | These issues should generally include a link to a Zulip discussion thread. |
51 | 50 | ||
52 | # CI | 51 | # Code Style & Review Process |
52 | |||
53 | Do see [./style.md](./style.md). | ||
53 | 54 | ||
54 | We use GitHub Actions for CI. Most of the things, including formatting, are checked by | 55 | # Cookbook |
55 | `cargo test` so, if `cargo test` passes locally, that's a good sign that CI will | 56 | |
56 | be green as well. The only exception is that some long-running tests are skipped locally by default. | 57 | ## CI |
58 | |||
59 | We use GitHub Actions for CI. | ||
60 | Most of the things, including formatting, are checked by `cargo test`. | ||
61 | If `cargo test` passes locally, that's a good sign that CI will be green as well. | ||
62 | The only exception is that some long-running tests are skipped locally by default. | ||
57 | Use `env RUN_SLOW_TESTS=1 cargo test` to run the full suite. | 63 | Use `env RUN_SLOW_TESTS=1 cargo test` to run the full suite. |
58 | 64 | ||
59 | We use bors-ng to enforce the [not rocket science](https://graydon2.dreamwidth.org/1597.html) rule. | 65 | We use bors-ng to enforce the [not rocket science](https://graydon2.dreamwidth.org/1597.html) rule. |
60 | 66 | ||
61 | # Launching rust-analyzer | 67 | ## Launching rust-analyzer |
62 | 68 | ||
63 | Debugging the language server can be tricky. | 69 | Debugging the language server can be tricky. |
64 | LSP is rather chatty, so driving it from the command line is not really feasible, driving it via VS Code requires interacting with two processes. | 70 | LSP is rather chatty, so driving it from the command line is not really feasible, driving it via VS Code requires interacting with two processes. |
65 | 71 | ||
66 | For this reason, the best way to see how rust-analyzer works is to find a relevant test and execute it. | 72 | For this reason, the best way to see how rust-analyzer works is to **find a relevant test and execute it**. |
67 | VS Code & Emacs include an action for running a single test. | 73 | VS Code & Emacs include an action for running a single test. |
68 | 74 | ||
69 | Launching a VS Code instance with a locally built language server is also possible. | 75 | Launching a VS Code instance with a locally built language server is also possible. |
@@ -107,12 +113,7 @@ cd editors/code | |||
107 | npm ci | 113 | npm ci |
108 | npm run lint | 114 | npm run lint |
109 | ``` | 115 | ``` |
110 | 116 | ## How to ... | |
111 | # Code Style & Review Process | ||
112 | |||
113 | Do see [./style.md](./style.md). | ||
114 | |||
115 | # How to ... | ||
116 | 117 | ||
117 | * ... add an assist? [#7535](https://github.com/rust-analyzer/rust-analyzer/pull/7535) | 118 | * ... add an assist? [#7535](https://github.com/rust-analyzer/rust-analyzer/pull/7535) |
118 | * ... add a new protocol extension? [#4569](https://github.com/rust-analyzer/rust-analyzer/pull/4569) | 119 | * ... add a new protocol extension? [#4569](https://github.com/rust-analyzer/rust-analyzer/pull/4569) |
@@ -120,18 +121,17 @@ Do see [./style.md](./style.md). | |||
120 | * ... add a new completion? [#6964](https://github.com/rust-analyzer/rust-analyzer/pull/6964) | 121 | * ... add a new completion? [#6964](https://github.com/rust-analyzer/rust-analyzer/pull/6964) |
121 | * ... allow new syntax in the parser? [#7338](https://github.com/rust-analyzer/rust-analyzer/pull/7338) | 122 | * ... allow new syntax in the parser? [#7338](https://github.com/rust-analyzer/rust-analyzer/pull/7338) |
122 | 123 | ||
123 | # Logging | 124 | ## Logging |
124 | 125 | ||
125 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to | 126 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to figure out where logs go. |
126 | figure out where logs go. | ||
127 | 127 | ||
128 | Inside rust-analyzer, we use the standard `log` crate for logging, and | 128 | Inside rust-analyzer, we use the standard `log` crate for logging, and `env_logger` for logging frontend. |
129 | `env_logger` for logging frontend. By default, log goes to stderr, but the | 129 | By default, log goes to stderr, but the stderr itself is processed by VS Code. |
130 | stderr itself is processed by VS Code. | 130 | `--log-file <PATH>` CLI argument allows logging to file. |
131 | 131 | ||
132 | To see stderr in the running VS Code instance, go to the "Output" tab of the | 132 | To see stderr in the running VS Code instance, go to the "Output" tab of the panel and select `rust-analyzer`. |
133 | panel and select `rust-analyzer`. This shows `eprintln!` as well. Note that | 133 | This shows `eprintln!` as well. |
134 | `stdout` is used for the actual protocol, so `println!` will break things. | 134 | Note that `stdout` is used for the actual protocol, so `println!` will break things. |
135 | 135 | ||
136 | To log all communication between the server and the client, there are two choices: | 136 | To log all communication between the server and the client, there are two choices: |
137 | 137 | ||
@@ -139,17 +139,12 @@ To log all communication between the server and the client, there are two choice | |||
139 | ``` | 139 | ``` |
140 | env RA_LOG=lsp_server=debug code . | 140 | env RA_LOG=lsp_server=debug code . |
141 | ``` | 141 | ``` |
142 | * You can log on the client side, by enabling `"rust-analyzer.trace.server": "verbose"` workspace setting. | ||
143 | These logs are shown in a separate tab in the output and could be used with LSP inspector. | ||
144 | Kudos to [@DJMcNab](https://github.com/DJMcNab) for setting this awesome infra up! | ||
142 | 145 | ||
143 | By default, logs go to stderr, `--log-file <PATH>` CLI argument overrides | ||
144 | that. | ||
145 | 146 | ||
146 | * You can log on the client side, by enabling `"rust-analyzer.trace.server": | 147 | There are also several VS Code commands which might be of interest: |
147 | "verbose"` workspace setting. These logs are shown in a separate tab in the | ||
148 | output and could be used with LSP inspector. Kudos to | ||
149 | [@DJMcNab](https://github.com/DJMcNab) for setting this awesome infra up! | ||
150 | |||
151 | |||
152 | There are also two VS Code commands which might be of interest: | ||
153 | 148 | ||
154 | * `Rust Analyzer: Status` shows some memory-usage statistics. | 149 | * `Rust Analyzer: Status` shows some memory-usage statistics. |
155 | 150 | ||
@@ -167,7 +162,7 @@ There are also two VS Code commands which might be of interest: | |||
167 | 162 | ||
168 | ![demo](https://user-images.githubusercontent.com/36276403/78225773-6636a480-74d3-11ea-9d9f-1c9d42da03b0.png) | 163 | ![demo](https://user-images.githubusercontent.com/36276403/78225773-6636a480-74d3-11ea-9d9f-1c9d42da03b0.png) |
169 | 164 | ||
170 | # Profiling | 165 | ## Profiling |
171 | 166 | ||
172 | We have a built-in hierarchical profiler, you can enable it by using `RA_PROFILE` env-var: | 167 | We have a built-in hierarchical profiler, you can enable it by using `RA_PROFILE` env-var: |
173 | 168 | ||
@@ -195,7 +190,9 @@ $ cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --highlight . | |||
195 | $ cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --complete ../chalk/chalk-engine/src/logic.rs:94:0 | 190 | $ cargo run --release -p rust-analyzer -- analysis-bench ../chalk/ --complete ../chalk/chalk-engine/src/logic.rs:94:0 |
196 | ``` | 191 | ``` |
197 | 192 | ||
198 | # Release Process | 193 | Look for `fn benchmark_xxx` tests for a quick way to reproduce performance problems. |
194 | |||
195 | ## Release Process | ||
199 | 196 | ||
200 | Release process is handled by `release`, `dist` and `promote` xtasks, `release` being the main one. | 197 | Release process is handled by `release`, `dist` and `promote` xtasks, `release` being the main one. |
201 | 198 | ||
@@ -232,7 +229,7 @@ Make sure to remove the new changelog post created when running `cargo xtask rel | |||
232 | We release "nightly" every night automatically and promote the latest nightly to "stable" manually, every week. | 229 | We release "nightly" every night automatically and promote the latest nightly to "stable" manually, every week. |
233 | We don't do "patch" releases, unless something truly egregious comes up. | 230 | We don't do "patch" releases, unless something truly egregious comes up. |
234 | 231 | ||
235 | # Permissions | 232 | ## Permissions |
236 | 233 | ||
237 | There are three sets of people with extra permissions: | 234 | There are three sets of people with extra permissions: |
238 | 235 | ||