aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/global_state.rs13
-rw-r--r--crates/rust-analyzer/src/handlers.rs22
-rw-r--r--crates/rust-analyzer/src/main_loop.rs67
-rw-r--r--crates/rust-analyzer/src/to_proto.rs7
5 files changed, 78 insertions, 33 deletions
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 023c104d1..758aa1c5d 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -20,7 +20,7 @@ env_logger = { version = "0.7.1", default-features = false }
20itertools = "0.9.0" 20itertools = "0.9.0"
21jod-thread = "0.1.0" 21jod-thread = "0.1.0"
22log = "0.4.8" 22log = "0.4.8"
23lsp-types = { version = "0.77.0", features = ["proposed"] } 23lsp-types = { version = "0.78.0", features = ["proposed"] }
24parking_lot = "0.11.0" 24parking_lot = "0.11.0"
25pico-args = "0.3.1" 25pico-args = "0.3.1"
26rand = { version = "0.7.3", features = ["small_rng"] } 26rand = { version = "0.7.3", features = ["small_rng"] }
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 94973b90a..80937dbc4 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -12,7 +12,7 @@ use parking_lot::RwLock;
12use ra_db::{CrateId, VfsPath}; 12use ra_db::{CrateId, VfsPath};
13use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId}; 13use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId};
14use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; 14use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
15use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::FxHashMap;
16 16
17use crate::{ 17use crate::{
18 config::Config, 18 config::Config,
@@ -69,7 +69,7 @@ pub(crate) struct GlobalState {
69 pub(crate) config: Config, 69 pub(crate) config: Config,
70 pub(crate) analysis_host: AnalysisHost, 70 pub(crate) analysis_host: AnalysisHost,
71 pub(crate) diagnostics: DiagnosticCollection, 71 pub(crate) diagnostics: DiagnosticCollection,
72 pub(crate) mem_docs: FxHashSet<VfsPath>, 72 pub(crate) mem_docs: FxHashMap<VfsPath, Option<i64>>,
73 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, 73 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
74 pub(crate) status: Status, 74 pub(crate) status: Status,
75 pub(crate) source_root_config: SourceRootConfig, 75 pub(crate) source_root_config: SourceRootConfig,
@@ -84,6 +84,7 @@ pub(crate) struct GlobalStateSnapshot {
84 pub(crate) analysis: Analysis, 84 pub(crate) analysis: Analysis,
85 pub(crate) check_fixes: CheckFixes, 85 pub(crate) check_fixes: CheckFixes,
86 pub(crate) latest_requests: Arc<RwLock<LatestRequests>>, 86 pub(crate) latest_requests: Arc<RwLock<LatestRequests>>,
87 mem_docs: FxHashMap<VfsPath, Option<i64>>,
87 vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, 88 vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
88 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, 89 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
89} 90}
@@ -117,7 +118,7 @@ impl GlobalState {
117 config, 118 config,
118 analysis_host, 119 analysis_host,
119 diagnostics: Default::default(), 120 diagnostics: Default::default(),
120 mem_docs: FxHashSet::default(), 121 mem_docs: FxHashMap::default(),
121 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), 122 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
122 status: Status::default(), 123 status: Status::default(),
123 source_root_config: SourceRootConfig::default(), 124 source_root_config: SourceRootConfig::default(),
@@ -183,6 +184,7 @@ impl GlobalState {
183 vfs: Arc::clone(&self.vfs), 184 vfs: Arc::clone(&self.vfs),
184 latest_requests: Arc::clone(&self.latest_requests), 185 latest_requests: Arc::clone(&self.latest_requests),
185 check_fixes: Arc::clone(&self.diagnostics.check_fixes), 186 check_fixes: Arc::clone(&self.diagnostics.check_fixes),
187 mem_docs: self.mem_docs.clone(),
186 } 188 }
187 } 189 }
188 190
@@ -255,6 +257,11 @@ impl GlobalStateSnapshot {
255 self.vfs.read().1[&id] 257 self.vfs.read().1[&id]
256 } 258 }
257 259
260 pub(crate) fn url_file_version(&self, url: &Url) -> Option<i64> {
261 let path = from_proto::vfs_path(&url).ok()?;
262 self.mem_docs.get(&path).copied()?
263 }
264
258 pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url { 265 pub(crate) fn anchored_path(&self, file_id: FileId, path: &str) -> Url {
259 let mut base = self.vfs.read().0.file_path(file_id); 266 let mut base = self.vfs.read().0.file_path(file_id);
260 base.pop(); 267 base.pop();
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index d880570d2..8d8c9442b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -15,7 +15,7 @@ use lsp_types::{
15 DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location, 15 DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeParams, HoverContents, Location,
16 Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams, 16 Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensParams,
17 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, 17 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
18 TextDocumentIdentifier, Url, WorkspaceEdit, 18 SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
19}; 19};
20use ra_ide::{ 20use ra_ide::{
21 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query, 21 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
@@ -253,10 +253,17 @@ pub(crate) fn handle_document_symbol(
253 let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new(); 253 let mut parents: Vec<(DocumentSymbol, Option<usize>)> = Vec::new();
254 254
255 for symbol in snap.analysis.file_structure(file_id)? { 255 for symbol in snap.analysis.file_structure(file_id)? {
256 let mut tags = Vec::new();
257 if symbol.deprecated {
258 tags.push(SymbolTag::Deprecated)
259 };
260
261 #[allow(deprecated)]
256 let doc_symbol = DocumentSymbol { 262 let doc_symbol = DocumentSymbol {
257 name: symbol.label, 263 name: symbol.label,
258 detail: symbol.detail, 264 detail: symbol.detail,
259 kind: to_proto::symbol_kind(symbol.kind), 265 kind: to_proto::symbol_kind(symbol.kind),
266 tags: Some(tags),
260 deprecated: Some(symbol.deprecated), 267 deprecated: Some(symbol.deprecated),
261 range: to_proto::range(&line_index, symbol.node_range), 268 range: to_proto::range(&line_index, symbol.node_range),
262 selection_range: to_proto::range(&line_index, symbol.navigation_range), 269 selection_range: to_proto::range(&line_index, symbol.navigation_range),
@@ -296,9 +303,19 @@ pub(crate) fn handle_document_symbol(
296 url: &Url, 303 url: &Url,
297 res: &mut Vec<SymbolInformation>, 304 res: &mut Vec<SymbolInformation>,
298 ) { 305 ) {
306 let mut tags = Vec::new();
307
308 #[allow(deprecated)]
309 match symbol.deprecated {
310 Some(true) => tags.push(SymbolTag::Deprecated),
311 _ => {}
312 }
313
314 #[allow(deprecated)]
299 res.push(SymbolInformation { 315 res.push(SymbolInformation {
300 name: symbol.name.clone(), 316 name: symbol.name.clone(),
301 kind: symbol.kind, 317 kind: symbol.kind,
318 tags: Some(tags),
302 deprecated: symbol.deprecated, 319 deprecated: symbol.deprecated,
303 location: Location::new(url.clone(), symbol.range), 320 location: Location::new(url.clone(), symbol.range),
304 container_name, 321 container_name,
@@ -342,9 +359,12 @@ pub(crate) fn handle_workspace_symbol(
342 let mut res = Vec::new(); 359 let mut res = Vec::new();
343 for nav in snap.analysis.symbol_search(query)? { 360 for nav in snap.analysis.symbol_search(query)? {
344 let container_name = nav.container_name.as_ref().map(|v| v.to_string()); 361 let container_name = nav.container_name.as_ref().map(|v| v.to_string());
362
363 #[allow(deprecated)]
345 let info = SymbolInformation { 364 let info = SymbolInformation {
346 name: nav.name.to_string(), 365 name: nav.name.to_string(),
347 kind: to_proto::symbol_kind(nav.kind), 366 kind: to_proto::symbol_kind(nav.kind),
367 tags: None,
348 location: to_proto::location_from_nav(snap, nav)?, 368 location: to_proto::location_from_nav(snap, nav)?,
349 container_name, 369 container_name,
350 deprecated: None, 370 deprecated: None,
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index bb7c4c0c6..ac95e428e 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -97,22 +97,6 @@ impl fmt::Debug for Event {
97} 97}
98 98
99impl GlobalState { 99impl GlobalState {
100 fn next_event(&self, inbox: &Receiver<lsp_server::Message>) -> Option<Event> {
101 select! {
102 recv(inbox) -> msg =>
103 msg.ok().map(Event::Lsp),
104
105 recv(self.task_pool.receiver) -> task =>
106 Some(Event::Task(task.unwrap())),
107
108 recv(self.loader.receiver) -> task =>
109 Some(Event::Vfs(task.unwrap())),
110
111 recv(self.flycheck_receiver) -> task =>
112 Some(Event::Flycheck(task.unwrap())),
113 }
114 }
115
116 fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { 100 fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> {
117 if self.config.linked_projects.is_empty() && self.config.notifications.cargo_toml_not_found 101 if self.config.linked_projects.is_empty() && self.config.notifications.cargo_toml_not_found
118 { 102 {
@@ -169,6 +153,22 @@ impl GlobalState {
169 Err("client exited without proper shutdown sequence")? 153 Err("client exited without proper shutdown sequence")?
170 } 154 }
171 155
156 fn next_event(&self, inbox: &Receiver<lsp_server::Message>) -> Option<Event> {
157 select! {
158 recv(inbox) -> msg =>
159 msg.ok().map(Event::Lsp),
160
161 recv(self.task_pool.receiver) -> task =>
162 Some(Event::Task(task.unwrap())),
163
164 recv(self.loader.receiver) -> task =>
165 Some(Event::Vfs(task.unwrap())),
166
167 recv(self.flycheck_receiver) -> task =>
168 Some(Event::Flycheck(task.unwrap())),
169 }
170 }
171
172 fn handle_event(&mut self, event: Event) -> Result<()> { 172 fn handle_event(&mut self, event: Event) -> Result<()> {
173 let loop_start = Instant::now(); 173 let loop_start = Instant::now();
174 // NOTE: don't count blocking select! call as a loop-turn time 174 // NOTE: don't count blocking select! call as a loop-turn time
@@ -210,7 +210,7 @@ impl GlobalState {
210 let vfs = &mut self.vfs.write().0; 210 let vfs = &mut self.vfs.write().0;
211 for (path, contents) in files { 211 for (path, contents) in files {
212 let path = VfsPath::from(path); 212 let path = VfsPath::from(path);
213 if !self.mem_docs.contains(&path) { 213 if !self.mem_docs.contains_key(&path) {
214 vfs.set_file_contents(path, contents) 214 vfs.set_file_contents(path, contents)
215 } 215 }
216 } 216 }
@@ -299,7 +299,7 @@ impl GlobalState {
299 if self.status == Status::Ready && (state_changed || prev_status == Status::Loading) { 299 if self.status == Status::Ready && (state_changed || prev_status == Status::Loading) {
300 let subscriptions = self 300 let subscriptions = self
301 .mem_docs 301 .mem_docs
302 .iter() 302 .keys()
303 .map(|path| self.vfs.read().0.file_id(&path).unwrap()) 303 .map(|path| self.vfs.read().0.file_id(&path).unwrap())
304 .collect::<Vec<_>>(); 304 .collect::<Vec<_>>();
305 305
@@ -310,8 +310,12 @@ impl GlobalState {
310 for file_id in diagnostic_changes { 310 for file_id in diagnostic_changes {
311 let url = file_id_to_url(&self.vfs.read().0, file_id); 311 let url = file_id_to_url(&self.vfs.read().0, file_id);
312 let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect(); 312 let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect();
313 let version = from_proto::vfs_path(&url)
314 .map(|path| self.mem_docs.get(&path).copied().flatten())
315 .unwrap_or_default();
316
313 self.send_notification::<lsp_types::notification::PublishDiagnostics>( 317 self.send_notification::<lsp_types::notification::PublishDiagnostics>(
314 lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version: None }, 318 lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version },
315 ); 319 );
316 } 320 }
317 } 321 }
@@ -400,7 +404,11 @@ impl GlobalState {
400 })? 404 })?
401 .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| { 405 .on::<lsp_types::notification::DidOpenTextDocument>(|this, params| {
402 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) { 406 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
403 if !this.mem_docs.insert(path.clone()) { 407 if this
408 .mem_docs
409 .insert(path.clone(), Some(params.text_document.version))
410 .is_some()
411 {
404 log::error!("duplicate DidOpenTextDocument: {}", path) 412 log::error!("duplicate DidOpenTextDocument: {}", path)
405 } 413 }
406 this.vfs 414 this.vfs
@@ -412,29 +420,38 @@ impl GlobalState {
412 })? 420 })?
413 .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { 421 .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| {
414 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) { 422 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
415 assert!(this.mem_docs.contains(&path)); 423 *this.mem_docs.get_mut(&path).unwrap() = params.text_document.version;
416 let vfs = &mut this.vfs.write().0; 424 let vfs = &mut this.vfs.write().0;
417 let file_id = vfs.file_id(&path).unwrap(); 425 let file_id = vfs.file_id(&path).unwrap();
418 let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); 426 let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap();
419 apply_document_changes(&mut text, params.content_changes); 427 apply_document_changes(&mut text, params.content_changes);
420 vfs.set_file_contents(path, Some(text.into_bytes())) 428 vfs.set_file_contents(path.clone(), Some(text.into_bytes()));
429
430 this.mem_docs.insert(path, params.text_document.version);
421 } 431 }
422 Ok(()) 432 Ok(())
423 })? 433 })?
424 .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| { 434 .on::<lsp_types::notification::DidCloseTextDocument>(|this, params| {
435 let mut version = None;
425 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) { 436 if let Ok(path) = from_proto::vfs_path(&params.text_document.uri) {
426 if !this.mem_docs.remove(&path) { 437 match this.mem_docs.remove(&path) {
427 log::error!("orphan DidCloseTextDocument: {}", path) 438 Some(entry) => version = entry,
439 None => log::error!("orphan DidCloseTextDocument: {}", path),
428 } 440 }
441
429 if let Some(path) = path.as_path() { 442 if let Some(path) = path.as_path() {
430 this.loader.handle.invalidate(path.to_path_buf()); 443 this.loader.handle.invalidate(path.to_path_buf());
431 } 444 }
432 } 445 }
446
447 // Clear the diagnostics for the previously known version of the file.
448 // This prevents stale "cargo check" diagnostics if the file is
449 // closed, "cargo check" is run and then the file is reopened.
433 this.send_notification::<lsp_types::notification::PublishDiagnostics>( 450 this.send_notification::<lsp_types::notification::PublishDiagnostics>(
434 lsp_types::PublishDiagnosticsParams { 451 lsp_types::PublishDiagnosticsParams {
435 uri: params.text_document.uri, 452 uri: params.text_document.uri,
436 diagnostics: Vec::new(), 453 diagnostics: Vec::new(),
437 version: None, 454 version,
438 }, 455 },
439 ); 456 );
440 Ok(()) 457 Ok(())
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index fc94f28b9..c6935c029 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -480,9 +480,10 @@ pub(crate) fn url_from_abs_path(path: &Path) -> lsp_types::Url {
480pub(crate) fn versioned_text_document_identifier( 480pub(crate) fn versioned_text_document_identifier(
481 snap: &GlobalStateSnapshot, 481 snap: &GlobalStateSnapshot,
482 file_id: FileId, 482 file_id: FileId,
483 version: Option<i64>,
484) -> lsp_types::VersionedTextDocumentIdentifier { 483) -> lsp_types::VersionedTextDocumentIdentifier {
485 lsp_types::VersionedTextDocumentIdentifier { uri: url(snap, file_id), version } 484 let url = url(snap, file_id);
485 let version = snap.url_file_version(&url);
486 lsp_types::VersionedTextDocumentIdentifier { uri: url, version }
486} 487}
487 488
488pub(crate) fn location( 489pub(crate) fn location(
@@ -571,7 +572,7 @@ pub(crate) fn snippet_text_document_edit(
571 is_snippet: bool, 572 is_snippet: bool,
572 source_file_edit: SourceFileEdit, 573 source_file_edit: SourceFileEdit,
573) -> Result<lsp_ext::SnippetTextDocumentEdit> { 574) -> Result<lsp_ext::SnippetTextDocumentEdit> {
574 let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id, None); 575 let text_document = versioned_text_document_identifier(snap, source_file_edit.file_id);
575 let line_index = snap.analysis.file_line_index(source_file_edit.file_id)?; 576 let line_index = snap.analysis.file_line_index(source_file_edit.file_id)?;
576 let line_endings = snap.file_line_endings(source_file_edit.file_id); 577 let line_endings = snap.file_line_endings(source_file_edit.file_id);
577 let edits = source_file_edit 578 let edits = source_file_edit