aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r--crates/ra_lsp_server/Cargo.toml3
-rw-r--r--crates/ra_lsp_server/src/cargo_target_spec.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs79
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs40
-rw-r--r--crates/ra_lsp_server/src/req.rs1
-rw-r--r--crates/ra_lsp_server/src/world.rs12
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"
14serde = { version = "1.0.83", features = ["derive"] } 14serde = { version = "1.0.83", features = ["derive"] }
15crossbeam-channel = "0.4" 15crossbeam-channel = "0.4"
16log = "0.4.3" 16log = "0.4.3"
17lsp-types = { version = "0.68.0", features = ["proposed"] } 17lsp-types = { version = "0.69.0", features = ["proposed"] }
18rustc-hash = "1.0" 18rustc-hash = "1.0"
19parking_lot = "0.10.0" 19parking_lot = "0.10.0"
20jod-thread = "0.1.0" 20jod-thread = "0.1.0"
@@ -28,6 +28,7 @@ ra_prof = { path = "../ra_prof" }
28ra_vfs_glob = { path = "../ra_vfs_glob" } 28ra_vfs_glob = { path = "../ra_vfs_glob" }
29env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] } 29env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] }
30ra_cargo_watch = { path = "../ra_cargo_watch" } 30ra_cargo_watch = { path = "../ra_cargo_watch" }
31either = "1.5"
31 32
32[dev-dependencies] 33[dev-dependencies]
33tempfile = "3" 34tempfile = "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
10use crossbeam_channel::{select, unbounded, RecvError, Sender}; 10use crossbeam_channel::{select, unbounded, RecvError, Sender};
11use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; 11use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
12use lsp_types::{ClientCapabilities, NumberOrString}; 12use lsp_types::{ClientCapabilities, NumberOrString, Url};
13use ra_cargo_watch::{CheckOptions, CheckTask}; 13use ra_cargo_watch::{CheckOptions, CheckTask};
14use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; 14use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId};
15use ra_prof::profile; 15use 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
587fn 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
627fn 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
608struct PoolDispatcher<'a> { 641struct 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
4use std::{fmt::Write as _, io::Write as _}; 4use std::{fmt::Write as _, io::Write as _};
5 5
6use either::Either;
6use lsp_server::ErrorCode; 7use lsp_server::ErrorCode;
7use lsp_types::{ 8use 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)]
198pub enum InlayKind { 198pub 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;
13use lsp_types::Url; 13use lsp_types::Url;
14use parking_lot::RwLock; 14use parking_lot::RwLock;
15use ra_cargo_watch::{ 15use 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};
18use ra_ide::{ 18use 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
70impl WorldState { 70impl 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 }