internal: make project loading lazy

This commit is contained in:
David Barsky 2024-08-14 12:23:05 -04:00
parent 3723e5910c
commit 491f69abc4
5 changed files with 46 additions and 47 deletions

View file

@ -268,13 +268,6 @@ fn run_server() -> anyhow::Result<()> {
return Err(e.into()); return Err(e.into());
} }
if config.discover_workspace_config().is_none()
&& !config.has_linked_projects()
&& config.detached_files().is_empty()
{
config.rediscover_workspaces();
}
// If the io_threads have an error, there's usually an error on the main // If the io_threads have an error, there's usually an error on the main
// loop too because the channels are closed. Ensure we report both errors. // loop too because the channels are closed. Ensure we report both errors.
match (rust_analyzer::main_loop(config, connection), io_threads.join()) { match (rust_analyzer::main_loop(config, connection), io_threads.join()) {

View file

@ -15,7 +15,8 @@ pub(crate) const ARG_PLACEHOLDER: &str = "{arg}";
/// A command wrapper for getting a `rust-project.json`. /// A command wrapper for getting a `rust-project.json`.
/// ///
/// This is analogous to discovering a cargo project + running `cargo-metadata` on it, but for non-Cargo build systems. /// This is analogous to discovering a cargo project + running `cargo-metadata` on it, but for non-Cargo build systems.
pub(crate) struct DiscoverCommand { #[derive(Debug, Clone)]
pub(crate) struct DiscoverProjectJson {
command: Vec<String>, command: Vec<String>,
sender: Sender<DiscoverProjectMessage>, sender: Sender<DiscoverProjectMessage>,
} }
@ -27,15 +28,7 @@ pub(crate) enum DiscoverArgument {
Buildfile(#[serde(serialize_with = "serialize_abs_pathbuf")] AbsPathBuf), Buildfile(#[serde(serialize_with = "serialize_abs_pathbuf")] AbsPathBuf),
} }
fn serialize_abs_pathbuf<S>(path: &AbsPathBuf, se: S) -> Result<S::Ok, S::Error> impl DiscoverProjectJson {
where
S: serde::Serializer,
{
let path: &Utf8Path = path.as_ref();
se.serialize_str(path.as_str())
}
impl DiscoverCommand {
/// Create a new [DiscoverCommand]. /// Create a new [DiscoverCommand].
pub(crate) fn new(sender: Sender<DiscoverProjectMessage>, command: Vec<String>) -> Self { pub(crate) fn new(sender: Sender<DiscoverProjectMessage>, command: Vec<String>) -> Self {
Self { sender, command } Self { sender, command }
@ -126,6 +119,14 @@ impl ParseFromLine for DiscoverProjectMessage {
} }
} }
fn serialize_abs_pathbuf<S>(path: &AbsPathBuf, se: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let path: &Utf8Path = path.as_ref();
se.serialize_str(path.as_str())
}
#[test] #[test]
fn test_deserialization() { fn test_deserialization() {
let message = r#" let message = r#"

View file

@ -74,14 +74,12 @@ pub(crate) fn handle_did_open_text_document(
tracing::info!("New file content set {:?}", params.text_document.text); tracing::info!("New file content set {:?}", params.text_document.text);
state.vfs.write().0.set_file_contents(path, Some(params.text_document.text.into_bytes())); state.vfs.write().0.set_file_contents(path, Some(params.text_document.text.into_bytes()));
if state.config.discover_workspace_config().is_some() {
tracing::debug!("queuing task"); tracing::debug!("queuing task");
let _ = state let _ = state
.deferred_task_queue .deferred_task_queue
.sender .sender
.send(crate::main_loop::QueuedTask::CheckIfIndexed(params.text_document.uri)); .send(crate::main_loop::QueuedTask::CheckIfIndexed(params.text_document.uri));
} }
}
Ok(()) Ok(())
} }

View file

@ -515,7 +515,7 @@ impl Notification for ServerStatusNotification {
const METHOD: &'static str = "experimental/serverStatus"; const METHOD: &'static str = "experimental/serverStatus";
} }
#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)] #[derive(Deserialize, Serialize, PartialEq, Eq, Clone, Debug)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ServerStatusParams { pub struct ServerStatusParams {
pub health: Health, pub health: Health,

View file

@ -14,12 +14,13 @@ use lsp_server::{Connection, Notification, Request};
use lsp_types::{notification::Notification as _, TextDocumentIdentifier}; use lsp_types::{notification::Notification as _, TextDocumentIdentifier};
use stdx::thread::ThreadIntent; use stdx::thread::ThreadIntent;
use tracing::{error, span, Level}; use tracing::{error, span, Level};
use triomphe::Arc;
use vfs::{loader::LoadingProgress, AbsPathBuf, FileId}; use vfs::{loader::LoadingProgress, AbsPathBuf, FileId};
use crate::{ use crate::{
config::Config, config::Config,
diagnostics::{fetch_native_diagnostics, DiagnosticsGeneration, NativeDiagnosticsFetchKind}, diagnostics::{fetch_native_diagnostics, DiagnosticsGeneration, NativeDiagnosticsFetchKind},
discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage}, discover::{DiscoverArgument, DiscoverProjectJson, DiscoverProjectMessage},
flycheck::{self, FlycheckMessage}, flycheck::{self, FlycheckMessage},
global_state::{file_id_to_url, url_to_file_id, FetchWorkspaceRequest, GlobalState}, global_state::{file_id_to_url, url_to_file_id, FetchWorkspaceRequest, GlobalState},
hack_recover_crate_name, hack_recover_crate_name,
@ -113,6 +114,7 @@ pub(crate) enum Task {
pub(crate) enum DiscoverProjectParam { pub(crate) enum DiscoverProjectParam {
Buildfile(AbsPathBuf), Buildfile(AbsPathBuf),
Path(AbsPathBuf), Path(AbsPathBuf),
ClassicOnDisk,
} }
#[derive(Debug)] #[derive(Debug)]
@ -159,8 +161,6 @@ impl fmt::Debug for Event {
impl GlobalState { impl GlobalState {
fn run(mut self, inbox: Receiver<lsp_server::Message>) -> anyhow::Result<()> { fn run(mut self, inbox: Receiver<lsp_server::Message>) -> anyhow::Result<()> {
self.update_status_or_notify();
if self.config.did_save_text_document_dynamic_registration() { if self.config.did_save_text_document_dynamic_registration() {
let additional_patterns = self let additional_patterns = self
.config .config
@ -172,17 +172,7 @@ impl GlobalState {
self.register_did_save_capability(additional_patterns); self.register_did_save_capability(additional_patterns);
} }
if self.config.discover_workspace_config().is_none() { self.discover_workspace_queue.request_op("startup".to_owned(), ());
self.fetch_workspaces_queue.request_op(
"startup".to_owned(),
FetchWorkspaceRequest { path: None, force_crate_graph_reload: false },
);
if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
self.fetch_workspaces_queue.should_start_op()
{
self.fetch_workspaces(cause, path, force_crate_graph_reload);
}
}
while let Ok(event) = self.next_event(&inbox) { while let Ok(event) = self.next_event(&inbox) {
let Some(event) = event else { let Some(event) = event else {
@ -699,13 +689,14 @@ impl GlobalState {
self.report_progress("Fetching", state, msg, None, None); self.report_progress("Fetching", state, msg, None, None);
} }
Task::DiscoverLinkedProjects(arg) => { Task::DiscoverLinkedProjects(arg) => {
if let Some(cfg) = self.config.discover_workspace_config() {
if !self.discover_workspace_queue.op_in_progress() { if !self.discover_workspace_queue.op_in_progress() {
if let Some(cfg) = self.config.discover_workspace_config() {
// the clone is unfortunately necessary to avoid a borrowck error when // the clone is unfortunately necessary to avoid a borrowck error when
// `self.report_progress` is called later // `self.report_progress` is called later
let title = &cfg.progress_label.clone(); let title = &cfg.progress_label.clone();
let command = cfg.command.clone(); let command = cfg.command.clone();
let discover = DiscoverCommand::new(self.discover_sender.clone(), command); let discover =
DiscoverProjectJson::new(self.discover_sender.clone(), command);
self.report_progress(title, Progress::Begin, None, None, None); self.report_progress(title, Progress::Begin, None, None, None);
self.discover_workspace_queue self.discover_workspace_queue
@ -715,10 +706,19 @@ impl GlobalState {
let arg = match arg { let arg = match arg {
DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it), DiscoverProjectParam::Buildfile(it) => DiscoverArgument::Buildfile(it),
DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it), DiscoverProjectParam::Path(it) => DiscoverArgument::Path(it),
_ => return, // this is a bug; the arg should not be sent if `discover_workspace_config` is set
}; };
let handle = discover.spawn(arg).unwrap(); let handle = discover.spawn(arg).unwrap();
self.discover_handle = Some(handle); self.discover_handle = Some(handle);
} else {
let config = Arc::make_mut(&mut self.config);
config.rediscover_workspaces();
let req =
FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
self.fetch_workspaces_queue
.request_op("workspaces have been discovered".to_owned(), req);
} }
} }
} }
@ -829,12 +829,19 @@ impl GlobalState {
let id = from_proto::file_id(&snap, &uri).expect("unable to get FileId"); let id = from_proto::file_id(&snap, &uri).expect("unable to get FileId");
if let Ok(crates) = &snap.analysis.crates_for(id) { if let Ok(crates) = &snap.analysis.crates_for(id) {
if crates.is_empty() { if crates.is_empty() {
if snap.config.discover_workspace_config().is_some() { match snap.config.discover_workspace_config() {
Some(_) => {
let path = let path =
from_proto::abs_path(&uri).expect("Unable to get AbsPath"); from_proto::abs_path(&uri).expect("Unable to get AbsPath");
let arg = DiscoverProjectParam::Path(path); let arg = DiscoverProjectParam::Path(path);
sender.send(Task::DiscoverLinkedProjects(arg)).unwrap(); sender.send(Task::DiscoverLinkedProjects(arg)).unwrap();
} }
// default behavior; do standard discovery
None => {
let arg = DiscoverProjectParam::ClassicOnDisk;
sender.send(Task::DiscoverLinkedProjects(arg)).unwrap();
}
}
} else { } else {
tracing::debug!(?uri, "is indexed"); tracing::debug!(?uri, "is indexed");
} }