diff options
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 3 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/cargo_target_spec.rs | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 79 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 40 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/req.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/world.rs | 12 |
6 files changed, 96 insertions, 41 deletions
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index cdde5122e..579158780 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -14,7 +14,7 @@ serde_json = "1.0.34" | |||
14 | serde = { version = "1.0.83", features = ["derive"] } | 14 | serde = { version = "1.0.83", features = ["derive"] } |
15 | crossbeam-channel = "0.4" | 15 | crossbeam-channel = "0.4" |
16 | log = "0.4.3" | 16 | log = "0.4.3" |
17 | lsp-types = { version = "0.68.0", features = ["proposed"] } | 17 | lsp-types = { version = "0.69.0", features = ["proposed"] } |
18 | rustc-hash = "1.0" | 18 | rustc-hash = "1.0" |
19 | parking_lot = "0.10.0" | 19 | parking_lot = "0.10.0" |
20 | jod-thread = "0.1.0" | 20 | jod-thread = "0.1.0" |
@@ -28,6 +28,7 @@ ra_prof = { path = "../ra_prof" } | |||
28 | ra_vfs_glob = { path = "../ra_vfs_glob" } | 28 | ra_vfs_glob = { path = "../ra_vfs_glob" } |
29 | env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] } | 29 | env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] } |
30 | ra_cargo_watch = { path = "../ra_cargo_watch" } | 30 | ra_cargo_watch = { path = "../ra_cargo_watch" } |
31 | either = "1.5" | ||
31 | 32 | ||
32 | [dev-dependencies] | 33 | [dev-dependencies] |
33 | tempfile = "3" | 34 | tempfile = "3" |
diff --git a/crates/ra_lsp_server/src/cargo_target_spec.rs b/crates/ra_lsp_server/src/cargo_target_spec.rs index c4a9e7101..594caffe2 100644 --- a/crates/ra_lsp_server/src/cargo_target_spec.rs +++ b/crates/ra_lsp_server/src/cargo_target_spec.rs | |||
@@ -63,7 +63,7 @@ impl CargoTargetSpec { | |||
63 | None => return Ok(None), | 63 | None => return Ok(None), |
64 | }; | 64 | }; |
65 | let file_id = world.analysis().crate_root(crate_id)?; | 65 | let file_id = world.analysis().crate_root(crate_id)?; |
66 | let path = world.vfs.read().file2path(ra_vfs::VfsFile(file_id.0)); | 66 | let path = world.file_id_to_path(file_id); |
67 | let res = world.workspaces.iter().find_map(|ws| match ws { | 67 | let res = world.workspaces.iter().find_map(|ws| match ws { |
68 | ProjectWorkspace::Cargo { cargo, .. } => { | 68 | ProjectWorkspace::Cargo { cargo, .. } => { |
69 | let tgt = cargo.target_by_root(&path)?; | 69 | let tgt = cargo.target_by_root(&path)?; |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 84012b99d..7822be2e2 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -9,7 +9,7 @@ use std::{error::Error, fmt, panic, path::PathBuf, sync::Arc, time::Instant}; | |||
9 | 9 | ||
10 | use crossbeam_channel::{select, unbounded, RecvError, Sender}; | 10 | use crossbeam_channel::{select, unbounded, RecvError, Sender}; |
11 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; | 11 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; |
12 | use lsp_types::{ClientCapabilities, NumberOrString}; | 12 | use lsp_types::{ClientCapabilities, NumberOrString, Url}; |
13 | use ra_cargo_watch::{CheckOptions, CheckTask}; | 13 | use ra_cargo_watch::{CheckOptions, CheckTask}; |
14 | use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; | 14 | use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; |
15 | use ra_prof::profile; | 15 | use ra_prof::profile; |
@@ -336,28 +336,7 @@ fn loop_turn( | |||
336 | world_state.maybe_collect_garbage(); | 336 | world_state.maybe_collect_garbage(); |
337 | loop_state.in_flight_libraries -= 1; | 337 | loop_state.in_flight_libraries -= 1; |
338 | } | 338 | } |
339 | Event::CheckWatcher(task) => match task { | 339 | Event::CheckWatcher(task) => on_check_task(task, world_state, task_sender)?, |
340 | CheckTask::Update(uri) => { | ||
341 | // We manually send a diagnostic update when the watcher asks | ||
342 | // us to, to avoid the issue of having to change the file to | ||
343 | // receive updated diagnostics. | ||
344 | let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; | ||
345 | if let Some(file_id) = world_state.vfs.read().path2file(&path) { | ||
346 | let params = | ||
347 | handlers::publish_diagnostics(&world_state.snapshot(), FileId(file_id.0))?; | ||
348 | let not = notification_new::<req::PublishDiagnostics>(params); | ||
349 | task_sender.send(Task::Notify(not)).unwrap(); | ||
350 | } | ||
351 | } | ||
352 | CheckTask::Status(progress) => { | ||
353 | let params = req::ProgressParams { | ||
354 | token: req::ProgressToken::String("rustAnalyzer/cargoWatcher".to_string()), | ||
355 | value: req::ProgressParamsValue::WorkDone(progress), | ||
356 | }; | ||
357 | let not = notification_new::<req::Progress>(params); | ||
358 | task_sender.send(Task::Notify(not)).unwrap(); | ||
359 | } | ||
360 | }, | ||
361 | Event::Msg(msg) => match msg { | 340 | Event::Msg(msg) => match msg { |
362 | Message::Request(req) => on_request( | 341 | Message::Request(req) => on_request( |
363 | world_state, | 342 | world_state, |
@@ -605,6 +584,60 @@ fn on_notification( | |||
605 | Ok(()) | 584 | Ok(()) |
606 | } | 585 | } |
607 | 586 | ||
587 | fn on_check_task( | ||
588 | task: CheckTask, | ||
589 | world_state: &WorldState, | ||
590 | task_sender: &Sender<Task>, | ||
591 | ) -> Result<()> { | ||
592 | match task { | ||
593 | CheckTask::ClearDiagnostics => { | ||
594 | let cleared_files = world_state.check_watcher.state.write().clear(); | ||
595 | |||
596 | // Send updated diagnostics for each cleared file | ||
597 | for url in cleared_files { | ||
598 | publish_diagnostics_for_url(&url, world_state, task_sender)?; | ||
599 | } | ||
600 | } | ||
601 | |||
602 | CheckTask::AddDiagnostic(url, diagnostic) => { | ||
603 | world_state | ||
604 | .check_watcher | ||
605 | .state | ||
606 | .write() | ||
607 | .add_diagnostic_with_fixes(url.clone(), diagnostic); | ||
608 | |||
609 | // We manually send a diagnostic update when the watcher asks | ||
610 | // us to, to avoid the issue of having to change the file to | ||
611 | // receive updated diagnostics. | ||
612 | publish_diagnostics_for_url(&url, world_state, task_sender)?; | ||
613 | } | ||
614 | |||
615 | CheckTask::Status(progress) => { | ||
616 | let params = req::ProgressParams { | ||
617 | token: req::ProgressToken::String("rustAnalyzer/cargoWatcher".to_string()), | ||
618 | value: req::ProgressParamsValue::WorkDone(progress), | ||
619 | }; | ||
620 | let not = notification_new::<req::Progress>(params); | ||
621 | task_sender.send(Task::Notify(not)).unwrap(); | ||
622 | } | ||
623 | } | ||
624 | Ok(()) | ||
625 | } | ||
626 | |||
627 | fn publish_diagnostics_for_url( | ||
628 | url: &Url, | ||
629 | world_state: &WorldState, | ||
630 | task_sender: &Sender<Task>, | ||
631 | ) -> Result<()> { | ||
632 | let path = url.to_file_path().map_err(|()| format!("invalid uri: {}", url))?; | ||
633 | if let Some(file_id) = world_state.vfs.read().path2file(&path) { | ||
634 | let params = handlers::publish_diagnostics(&world_state.snapshot(), FileId(file_id.0))?; | ||
635 | let not = notification_new::<req::PublishDiagnostics>(params); | ||
636 | task_sender.send(Task::Notify(not)).unwrap(); | ||
637 | } | ||
638 | Ok(()) | ||
639 | } | ||
640 | |||
608 | struct PoolDispatcher<'a> { | 641 | struct PoolDispatcher<'a> { |
609 | req: Option<Request>, | 642 | req: Option<Request>, |
610 | pool: &'a ThreadPool, | 643 | pool: &'a ThreadPool, |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index a592f0a12..8e43f0575 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | use std::{fmt::Write as _, io::Write as _}; | 4 | use std::{fmt::Write as _, io::Write as _}; |
5 | 5 | ||
6 | use either::Either; | ||
6 | use lsp_server::ErrorCode; | 7 | use lsp_server::ErrorCode; |
7 | use lsp_types::{ | 8 | use lsp_types::{ |
8 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, | 9 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, |
@@ -644,7 +645,6 @@ pub fn handle_code_action( | |||
644 | let line_index = world.analysis().file_line_index(file_id)?; | 645 | let line_index = world.analysis().file_line_index(file_id)?; |
645 | let range = params.range.conv_with(&line_index); | 646 | let range = params.range.conv_with(&line_index); |
646 | 647 | ||
647 | let assists = world.analysis().assists(FileRange { file_id, range })?.into_iter(); | ||
648 | let diagnostics = world.analysis().diagnostics(file_id)?; | 648 | let diagnostics = world.analysis().diagnostics(file_id)?; |
649 | let mut res = CodeActionResponse::default(); | 649 | let mut res = CodeActionResponse::default(); |
650 | 650 | ||
@@ -681,10 +681,12 @@ pub fn handle_code_action( | |||
681 | continue; | 681 | continue; |
682 | } | 682 | } |
683 | 683 | ||
684 | let edits = vec![TextEdit::new(fix.location.range, fix.replacement.clone())]; | 684 | let edit = { |
685 | let mut edit_map = std::collections::HashMap::new(); | 685 | let edits = vec![TextEdit::new(fix.location.range, fix.replacement.clone())]; |
686 | edit_map.insert(fix.location.uri.clone(), edits); | 686 | let mut edit_map = std::collections::HashMap::new(); |
687 | let edit = WorkspaceEdit::new(edit_map); | 687 | edit_map.insert(fix.location.uri.clone(), edits); |
688 | WorkspaceEdit::new(edit_map) | ||
689 | }; | ||
688 | 690 | ||
689 | let action = CodeAction { | 691 | let action = CodeAction { |
690 | title: fix.title.clone(), | 692 | title: fix.title.clone(), |
@@ -697,19 +699,32 @@ pub fn handle_code_action( | |||
697 | res.push(action.into()); | 699 | res.push(action.into()); |
698 | } | 700 | } |
699 | 701 | ||
700 | for assist in assists { | 702 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { |
701 | let title = assist.change.label.clone(); | 703 | let title = assist.label.clone(); |
702 | let edit = assist.change.try_conv_with(&world)?; | ||
703 | 704 | ||
704 | let command = Command { | 705 | let command = match assist.change_data { |
705 | title, | 706 | Either::Left(change) => Command { |
706 | command: "rust-analyzer.applySourceChange".to_string(), | 707 | title, |
707 | arguments: Some(vec![to_value(edit).unwrap()]), | 708 | command: "rust-analyzer.applySourceChange".to_string(), |
709 | arguments: Some(vec![to_value(change.try_conv_with(&world)?)?]), | ||
710 | }, | ||
711 | Either::Right(changes) => Command { | ||
712 | title, | ||
713 | command: "rust-analyzer.selectAndApplySourceChange".to_string(), | ||
714 | arguments: Some(vec![to_value( | ||
715 | changes | ||
716 | .into_iter() | ||
717 | .map(|change| change.try_conv_with(&world)) | ||
718 | .collect::<Result<Vec<_>>>()?, | ||
719 | )?]), | ||
720 | }, | ||
708 | }; | 721 | }; |
722 | |||
709 | let action = CodeAction { | 723 | let action = CodeAction { |
710 | title: command.title.clone(), | 724 | title: command.title.clone(), |
711 | kind: match assist.id { | 725 | kind: match assist.id { |
712 | AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), | 726 | AssistId("introduce_variable") => Some("refactor.extract.variable".to_string()), |
727 | AssistId("add_custom_impl") => Some("refactor.rewrite.add_custom_impl".to_string()), | ||
713 | _ => None, | 728 | _ => None, |
714 | }, | 729 | }, |
715 | diagnostics: None, | 730 | diagnostics: None, |
@@ -952,6 +967,7 @@ pub fn handle_inlay_hints( | |||
952 | range: api_type.range.conv_with(&line_index), | 967 | range: api_type.range.conv_with(&line_index), |
953 | kind: match api_type.kind { | 968 | kind: match api_type.kind { |
954 | ra_ide::InlayKind::TypeHint => InlayKind::TypeHint, | 969 | ra_ide::InlayKind::TypeHint => InlayKind::TypeHint, |
970 | ra_ide::InlayKind::ParameterHint => InlayKind::ParameterHint, | ||
955 | }, | 971 | }, |
956 | }) | 972 | }) |
957 | .collect()) | 973 | .collect()) |
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index 8098ff31d..dc327f53d 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs | |||
@@ -197,6 +197,7 @@ pub struct InlayHintsParams { | |||
197 | #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | 197 | #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] |
198 | pub enum InlayKind { | 198 | pub enum InlayKind { |
199 | TypeHint, | 199 | TypeHint, |
200 | ParameterHint, | ||
200 | } | 201 | } |
201 | 202 | ||
202 | #[derive(Debug, Deserialize, Serialize)] | 203 | #[derive(Debug, Deserialize, Serialize)] |
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs index c0175c726..e7a0acfc7 100644 --- a/crates/ra_lsp_server/src/world.rs +++ b/crates/ra_lsp_server/src/world.rs | |||
@@ -13,7 +13,7 @@ use lsp_server::ErrorCode; | |||
13 | use lsp_types::Url; | 13 | use lsp_types::Url; |
14 | use parking_lot::RwLock; | 14 | use parking_lot::RwLock; |
15 | use ra_cargo_watch::{ | 15 | use ra_cargo_watch::{ |
16 | url_from_path_with_drive_lowercasing, CheckOptions, CheckWatcher, CheckWatcherSharedState, | 16 | url_from_path_with_drive_lowercasing, CheckOptions, CheckState, CheckWatcher, |
17 | }; | 17 | }; |
18 | use ra_ide::{ | 18 | use ra_ide::{ |
19 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData, | 19 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData, |
@@ -62,9 +62,9 @@ pub struct WorldSnapshot { | |||
62 | pub options: Options, | 62 | pub options: Options, |
63 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 63 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
64 | pub analysis: Analysis, | 64 | pub analysis: Analysis, |
65 | pub vfs: Arc<RwLock<Vfs>>, | ||
66 | pub latest_requests: Arc<RwLock<LatestRequests>>, | 65 | pub latest_requests: Arc<RwLock<LatestRequests>>, |
67 | pub check_watcher: Arc<RwLock<CheckWatcherSharedState>>, | 66 | pub check_watcher: Arc<RwLock<CheckState>>, |
67 | vfs: Arc<RwLock<Vfs>>, | ||
68 | } | 68 | } |
69 | 69 | ||
70 | impl WorldState { | 70 | impl WorldState { |
@@ -220,7 +220,7 @@ impl WorldState { | |||
220 | analysis: self.analysis_host.analysis(), | 220 | analysis: self.analysis_host.analysis(), |
221 | vfs: Arc::clone(&self.vfs), | 221 | vfs: Arc::clone(&self.vfs), |
222 | latest_requests: Arc::clone(&self.latest_requests), | 222 | latest_requests: Arc::clone(&self.latest_requests), |
223 | check_watcher: self.check_watcher.shared.clone(), | 223 | check_watcher: self.check_watcher.state.clone(), |
224 | } | 224 | } |
225 | } | 225 | } |
226 | 226 | ||
@@ -265,6 +265,10 @@ impl WorldSnapshot { | |||
265 | Ok(url) | 265 | Ok(url) |
266 | } | 266 | } |
267 | 267 | ||
268 | pub fn file_id_to_path(&self, id: FileId) -> PathBuf { | ||
269 | self.vfs.read().file2path(VfsFile(id.0)) | ||
270 | } | ||
271 | |||
268 | pub fn file_line_endings(&self, id: FileId) -> LineEndings { | 272 | pub fn file_line_endings(&self, id: FileId) -> LineEndings { |
269 | self.vfs.read().file_line_endings(VfsFile(id.0)) | 273 | self.vfs.read().file_line_endings(VfsFile(id.0)) |
270 | } | 274 | } |