Skip to content

Commit e568362

Browse files
committed
Add a UnindexedProject notification and a corresponding setting.
1 parent e402c49 commit e568362

File tree

16 files changed

+300
-41
lines changed

16 files changed

+300
-41
lines changed

Cargo.lock

Lines changed: 1 addition & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ debug = 0
3737
# chalk-derive = { path = "../chalk/chalk-derive" }
3838
# line-index = { path = "lib/line-index" }
3939
# la-arena = { path = "lib/la-arena" }
40-
# lsp-server = { path = "lib/lsp-server" }
40+
lsp-server = { path = "lib/lsp-server" }
4141

4242

4343
# ungrammar = { path = "../ungrammar" }

crates/rust-analyzer/src/config.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,9 @@ config_data! {
461461
/// Whether to show `can't find Cargo.toml` error message.
462462
notifications_cargoTomlNotFound: bool = "true",
463463

464+
/// Whether to send an UnindexedProject notification to the client.
465+
notifications_unindexedProject: bool = "false",
466+
464467
/// How many worker threads in the main loop. The default `null` means to pick automatically.
465468
numThreads: Option<usize> = "null",
466469

@@ -721,6 +724,7 @@ pub enum FilesWatcher {
721724
#[derive(Debug, Clone)]
722725
pub struct NotificationsConfig {
723726
pub cargo_toml_not_found: bool,
727+
pub unindexed_project: bool,
724728
}
725729

726730
#[derive(Debug, Clone)]
@@ -1193,7 +1197,10 @@ impl Config {
11931197
}
11941198

11951199
pub fn notifications(&self) -> NotificationsConfig {
1196-
NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound }
1200+
NotificationsConfig {
1201+
cargo_toml_not_found: self.data.notifications_cargoTomlNotFound,
1202+
unindexed_project: self.data.notifications_unindexedProject,
1203+
}
11971204
}
11981205

11991206
pub fn cargo_autoreload(&self) -> bool {

crates/rust-analyzer/src/global_state.rs

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use crate::{
3232
mem_docs::MemDocs,
3333
op_queue::OpQueue,
3434
reload,
35-
task_pool::TaskPool,
35+
task_pool::{TaskPool, TaskQueue},
3636
};
3737

3838
// Enforces drop order
@@ -53,8 +53,7 @@ type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>;
5353
/// Note that this struct has more than one impl in various modules!
5454
#[doc(alias = "GlobalMess")]
5555
pub(crate) struct GlobalState {
56-
sender: Sender<lsp_server::Message>,
57-
req_queue: ReqQueue,
56+
pub(crate) conn: Conn,
5857

5958
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
6059
pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>,
@@ -83,7 +82,7 @@ pub(crate) struct GlobalState {
8382
pub(crate) last_flycheck_error: Option<String>,
8483

8584
// VFS
86-
pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
85+
pub(crate) loader: Handle<Box<dyn vfs::loader::Handle + Send>, Receiver<vfs::loader::Message>>,
8786
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, IntMap<FileId, LineEndings>)>>,
8887
pub(crate) vfs_config_version: u32,
8988
pub(crate) vfs_progress_config_version: u32,
@@ -125,6 +124,16 @@ pub(crate) struct GlobalState {
125124
OpQueue<(), (Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>,
126125
pub(crate) fetch_proc_macros_queue: OpQueue<Vec<ProcMacroPaths>, bool>,
127126
pub(crate) prime_caches_queue: OpQueue,
127+
128+
/// a deferred task queue. this should only be used if the enqueued Task
129+
/// can only run *after* [`GlobalState::process_changes`] has been called.
130+
pub(crate) task_queue: TaskQueue,
131+
}
132+
133+
#[derive(Clone)]
134+
pub(crate) struct Conn {
135+
pub(crate) sender: Sender<lsp_server::Message>,
136+
req_queue: Arc<ReqQueue>,
128137
}
129138

130139
/// An immutable snapshot of the world's state at a point in time.
@@ -145,11 +154,13 @@ impl std::panic::UnwindSafe for GlobalStateSnapshot {}
145154

146155
impl GlobalState {
147156
pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> GlobalState {
157+
let conn = Conn { sender, req_queue: Arc::new(ReqQueue::default()) };
158+
148159
let loader = {
149160
let (sender, receiver) = unbounded::<vfs::loader::Message>();
150161
let handle: vfs_notify::NotifyHandle =
151162
vfs::loader::Handle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
152-
let handle = Box::new(handle) as Box<dyn vfs::loader::Handle>;
163+
let handle = Box::new(handle) as Box<dyn vfs::loader::Handle + Send>;
153164
Handle { handle, receiver }
154165
};
155166

@@ -164,14 +175,18 @@ impl GlobalState {
164175
Handle { handle, receiver }
165176
};
166177

178+
let task_queue = {
179+
let (sender, receiver) = unbounded();
180+
TaskQueue { sender, receiver }
181+
};
182+
167183
let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity());
168184
if let Some(capacities) = config.lru_query_capacities() {
169185
analysis_host.update_lru_capacities(capacities);
170186
}
171187
let (flycheck_sender, flycheck_receiver) = unbounded();
172188
let mut this = GlobalState {
173-
sender,
174-
req_queue: ReqQueue::default(),
189+
conn,
175190
task_pool,
176191
fmt_pool,
177192
loader,
@@ -209,6 +224,8 @@ impl GlobalState {
209224
fetch_proc_macros_queue: OpQueue::default(),
210225

211226
prime_caches_queue: OpQueue::default(),
227+
228+
task_queue,
212229
};
213230
// Apply any required database inputs from the config.
214231
this.update_configuration(config);
@@ -376,13 +393,13 @@ impl GlobalState {
376393
params: R::Params,
377394
handler: ReqHandler,
378395
) {
379-
let request = self.req_queue.outgoing.register(R::METHOD.to_string(), params, handler);
380-
self.send(request.into());
396+
self.conn.send_request::<R>(params, handler);
381397
}
382398

383399
pub(crate) fn complete_request(&mut self, response: lsp_server::Response) {
384-
let handler = self
385-
.req_queue
400+
let req_queue = Arc::make_mut(&mut self.conn.req_queue);
401+
402+
let handler = req_queue
386403
.outgoing
387404
.complete(response.id.clone())
388405
.expect("received response for unknown request");
@@ -393,22 +410,20 @@ impl GlobalState {
393410
&self,
394411
params: N::Params,
395412
) {
396-
let not = lsp_server::Notification::new(N::METHOD.to_string(), params);
397-
self.send(not.into());
413+
self.conn.send_notification::<N>(params);
398414
}
399415

400416
pub(crate) fn register_request(
401417
&mut self,
402418
request: &lsp_server::Request,
403419
request_received: Instant,
404420
) {
405-
self.req_queue
406-
.incoming
407-
.register(request.id.clone(), (request.method.clone(), request_received));
421+
self.conn.register_request(request, request_received);
408422
}
409423

410424
pub(crate) fn respond(&mut self, response: lsp_server::Response) {
411-
if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) {
425+
let req_queue = Arc::make_mut(&mut self.conn.req_queue);
426+
if let Some((method, start)) = req_queue.incoming.complete(response.id.clone()) {
412427
if let Some(err) = &response.error {
413428
if err.message.starts_with("server panicked") {
414429
self.poke_rust_analyzer_developer(format!("{}, check the log", err.message))
@@ -417,17 +432,51 @@ impl GlobalState {
417432

418433
let duration = start.elapsed();
419434
tracing::debug!("handled {} - ({}) in {:0.2?}", method, response.id, duration);
420-
self.send(response.into());
435+
self.conn.send(response.into());
421436
}
422437
}
423438

424439
pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) {
425-
if let Some(response) = self.req_queue.incoming.cancel(request_id) {
440+
self.conn.cancel(request_id);
441+
}
442+
443+
pub(crate) fn is_completed(&self, request: &lsp_server::Request) -> bool {
444+
self.conn.is_completed(&request)
445+
}
446+
}
447+
448+
impl Conn {
449+
pub(crate) fn send_request<R: lsp_types::request::Request>(
450+
&mut self,
451+
params: R::Params,
452+
handler: ReqHandler,
453+
) {
454+
let req_queue = Arc::make_mut(&mut self.req_queue);
455+
let request = req_queue.outgoing.register(R::METHOD.to_string(), params, handler);
456+
self.send(request.into());
457+
}
458+
459+
pub(crate) fn send_notification<N: lsp_types::notification::Notification>(
460+
&self,
461+
params: N::Params,
462+
) {
463+
let not = lsp_server::Notification::new(N::METHOD.to_string(), params);
464+
self.send(not.into());
465+
}
466+
467+
fn register_request(&mut self, request: &lsp_server::Request, request_received: Instant) {
468+
let req_queue = Arc::make_mut(&mut self.req_queue);
469+
req_queue.incoming.register(request.id.clone(), (request.method.clone(), request_received));
470+
}
471+
472+
fn cancel(&mut self, request_id: lsp_server::RequestId) {
473+
let req_queue = Arc::make_mut(&mut self.req_queue);
474+
if let Some(response) = req_queue.incoming.cancel(request_id) {
426475
self.send(response.into());
427476
}
428477
}
429478

430-
pub(crate) fn is_completed(&self, request: &lsp_server::Request) -> bool {
479+
fn is_completed(&self, request: &lsp_server::Request) -> bool {
431480
self.req_queue.incoming.is_completed(&request.id)
432481
}
433482

crates/rust-analyzer/src/handlers/notification.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,15 @@ pub(crate) fn handle_did_open_text_document(
6464
if already_exists {
6565
tracing::error!("duplicate DidOpenTextDocument: {}", path);
6666
}
67+
6768
state.vfs.write().0.set_file_contents(path, Some(params.text_document.text.into_bytes()));
69+
if state.config.notifications().unindexed_project {
70+
tracing::debug!("queuing task");
71+
let _ = state
72+
.task_queue
73+
.sender
74+
.send(crate::main_loop::QueuedTask::CheckIfIndexed(params.text_document.uri));
75+
}
6876
}
6977
Ok(())
7078
}

crates/rust-analyzer/src/lsp/ext.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,3 +696,16 @@ pub struct CompletionImport {
696696
pub struct ClientCommandOptions {
697697
pub commands: Vec<String>,
698698
}
699+
700+
pub enum UnindexedProject {}
701+
702+
impl Notification for UnindexedProject {
703+
type Params = UnindexedProjectParams;
704+
const METHOD: &'static str = "rust-analyzer/unindexedProject";
705+
}
706+
707+
#[derive(Deserialize, Serialize, Debug)]
708+
#[serde(rename_all = "camelCase")]
709+
pub struct UnindexedProjectParams {
710+
pub text_documents: Vec<TextDocumentIdentifier>,
711+
}

crates/rust-analyzer/src/main_loop.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! The main loop of `rust-analyzer` responsible for dispatching LSP
22
//! requests/replies and notifications back to the client.
3+
use crate::lsp::ext;
34
use std::{
45
fmt,
56
time::{Duration, Instant},
@@ -56,10 +57,16 @@ pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> {
5657
enum Event {
5758
Lsp(lsp_server::Message),
5859
Task(Task),
60+
QueuedTask(QueuedTask),
5961
Vfs(vfs::loader::Message),
6062
Flycheck(flycheck::Message),
6163
}
6264

65+
#[derive(Debug)]
66+
pub(crate) enum QueuedTask {
67+
CheckIfIndexed(lsp_types::Url),
68+
}
69+
6370
#[derive(Debug)]
6471
pub(crate) enum Task {
6572
Response(lsp_server::Response),
@@ -104,6 +111,7 @@ impl fmt::Debug for Event {
104111
match self {
105112
Event::Lsp(it) => fmt::Debug::fmt(it, f),
106113
Event::Task(it) => fmt::Debug::fmt(it, f),
114+
Event::QueuedTask(it) => fmt::Debug::fmt(it, f),
107115
Event::Vfs(it) => fmt::Debug::fmt(it, f),
108116
Event::Flycheck(it) => fmt::Debug::fmt(it, f),
109117
}
@@ -182,6 +190,9 @@ impl GlobalState {
182190
recv(self.task_pool.receiver) -> task =>
183191
Some(Event::Task(task.unwrap())),
184192

193+
recv(self.task_queue.receiver) -> task =>
194+
Some(Event::QueuedTask(task.unwrap())),
195+
185196
recv(self.fmt_pool.receiver) -> task =>
186197
Some(Event::Task(task.unwrap())),
187198

@@ -199,7 +210,7 @@ impl GlobalState {
199210
let _p = profile::span("GlobalState::handle_event");
200211

201212
let event_dbg_msg = format!("{event:?}");
202-
tracing::debug!("{:?} handle_event({})", loop_start, event_dbg_msg);
213+
tracing::debug!(?loop_start, ?event, "handle_event");
203214
if tracing::enabled!(tracing::Level::INFO) {
204215
let task_queue_len = self.task_pool.handle.len();
205216
if task_queue_len > 0 {
@@ -214,6 +225,10 @@ impl GlobalState {
214225
lsp_server::Message::Notification(not) => self.on_notification(not)?,
215226
lsp_server::Message::Response(resp) => self.complete_request(resp),
216227
},
228+
Event::QueuedTask(task) => {
229+
let _p = profile::span("GlobalState::handle_event/queued_task");
230+
self.handle_queued_task(task);
231+
}
217232
Event::Task(task) => {
218233
let _p = profile::span("GlobalState::handle_event/task");
219234
let mut prime_caches_progress = Vec::new();
@@ -607,6 +622,32 @@ impl GlobalState {
607622
}
608623
}
609624

625+
fn handle_queued_task(&mut self, task: QueuedTask) {
626+
match task {
627+
QueuedTask::CheckIfIndexed(uri) => {
628+
let snap = self.snapshot();
629+
let conn = self.conn.clone();
630+
631+
self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |_| {
632+
tracing::debug!(?uri, "handling uri");
633+
let id = from_proto::file_id(&snap, &uri).expect("unable to get FileId");
634+
if let Ok(crates) = &snap.analysis.crates_for(id) {
635+
if crates.is_empty() {
636+
conn.send_notification::<ext::UnindexedProject>(
637+
ext::UnindexedProjectParams {
638+
text_documents: vec![lsp_types::TextDocumentIdentifier { uri }],
639+
},
640+
);
641+
tracing::debug!("sent notification");
642+
} else {
643+
tracing::debug!(?uri, "is indexed");
644+
}
645+
}
646+
});
647+
}
648+
}
649+
}
650+
610651
fn handle_flycheck_msg(&mut self, message: flycheck::Message) {
611652
match message {
612653
flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => {

0 commit comments

Comments
 (0)