Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): fix workspace scanner in LSP #5286

Merged
merged 1 commit into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/biome_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ pub(crate) trait CommandRunner: Sized {
project_key,
path: Some(project_path),
watch: cli_options.use_server,
force: false, // TODO: Maybe we'll want a CLI flag for this.
})?;
for diagnostic in result.diagnostics {
if diagnostic.severity() >= Severity::Error {
Expand Down
1 change: 0 additions & 1 deletion crates/biome_lsp/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,6 @@ impl LanguageServer for LSPServer {
params.workspace_folders,
);

//
let init = InitializeResult {
capabilities: server_capabilities,
server_info: Some(ServerInfo {
Expand Down
2 changes: 2 additions & 0 deletions crates/biome_lsp/src/server.tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3042,6 +3042,7 @@ export function bar() {
project_key,
path: None,
watch: true,
force: false,
},
)
.await?
Expand Down Expand Up @@ -3253,6 +3254,7 @@ export function bar() {
project_key,
path: None,
watch: true,
force: false,
},
)
.await?
Expand Down
28 changes: 17 additions & 11 deletions crates/biome_lsp/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use std::sync::Arc;
use std::sync::RwLock;
use std::sync::atomic::Ordering;
use std::sync::atomic::{AtomicBool, AtomicU8};
use tokio::spawn;
use tokio::sync::Notify;
use tokio::sync::OnceCell;
use tokio::sync::watch;
Expand Down Expand Up @@ -572,31 +573,36 @@ impl Session {
project_path: BiomePath,
) {
let session = self.clone();
let scan_project = async move || {
let scan_project = move || {
let result = session
.workspace
.scan_project_folder(ScanProjectFolderParams {
project_key,
path: Some(project_path),
watch: true,
force: false,
});

match result {
Ok(result) => {
for diagnostic in result.diagnostics {
let message = PrintDescription(&diagnostic).to_string();
spawn(async move {
for diagnostic in result.diagnostics {
let message = PrintDescription(&diagnostic).to_string();
session
.client
.log_message(MessageType::ERROR, message)
.await;
}
});
}
Err(err) => {
let message = PrintDescription(&err).to_string();
spawn(async move {
session
.client
.log_message(MessageType::ERROR, message)
.await;
}
}
Err(err) => {
let message = PrintDescription(&err).to_string();
session
.client
.log_message(MessageType::ERROR, message)
.await;
});
}
}
};
Expand Down
3 changes: 3 additions & 0 deletions crates/biome_service/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,9 @@ pub struct ScanProjectFolderParams {
///
/// Does nothing if the watcher is already watching this path.
pub watch: bool,

/// Forces scanning of the folder, even if it is already being watched.
pub force: bool,
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
Expand Down
3 changes: 3 additions & 0 deletions crates/biome_service/src/workspace.tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ fn files_loaded_by_the_scanner_are_only_unloaded_when_the_project_is_unregistere
project_key,
path: None,
watch: false,
force: false,
})
.unwrap();

Expand Down Expand Up @@ -414,6 +415,7 @@ fn too_large_files_are_tracked_but_not_parsed() {
project_key,
path: None,
watch: false,
force: false,
})
.unwrap();

Expand Down Expand Up @@ -470,6 +472,7 @@ fn plugins_are_loaded_and_used_during_analysis() {
project_key,
path: None,
watch: false,
force: false,
})
.unwrap();

Expand Down
36 changes: 32 additions & 4 deletions crates/biome_service/src/workspace/server.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::panic::RefUnwindSafe;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;

use append_only_vec::AppendOnlyVec;
use biome_analyze::AnalyzerPluginVec;
Expand All @@ -26,7 +27,7 @@ use biome_project_layout::ProjectLayout;
use biome_rowan::NodeCache;
use camino::{Utf8Path, Utf8PathBuf};
use crossbeam::channel::Sender;
use papaya::{Compute, HashMap, Operation};
use papaya::{Compute, HashMap, HashSet, Operation};
use rustc_hash::{FxBuildHasher, FxHashMap};
use tokio::sync::watch;
use tracing::{error, info, instrument, warn};
Expand Down Expand Up @@ -109,6 +110,9 @@ pub struct WorkspaceServer {
/// Channel sender for instructions to the [crate::WorkspaceWatcher].
watcher_tx: Sender<WatcherInstruction>,

/// Set containing all the watched folders.
watched_folders: HashSet<Utf8PathBuf>,

/// Channel sender for sending notifications of service data updates.
pub(super) notification_tx: watch::Sender<ServiceDataNotification>,
}
Expand Down Expand Up @@ -142,6 +146,7 @@ impl WorkspaceServer {
node_cache: Default::default(),
fs,
watcher_tx,
watched_folders: Default::default(),
notification_tx,
}
}
Expand Down Expand Up @@ -819,7 +824,23 @@ impl Workspace for WorkspaceServer {
.or_else(|| self.projects.get_project_path(params.project_key))
.ok_or_else(WorkspaceError::no_project)?;

let should_scan = params.force
|| !self
.watched_folders
.pin()
.iter()
.any(|watched_folder| path.starts_with(watched_folder));
if !should_scan {
// No need to scan folders that are already being watched.
return Ok(ScanProjectFolderResult {
diagnostics: Vec::new(),
duration: Duration::from_millis(0),
});
}

if params.watch {
self.watched_folders.pin().insert(path.clone());

let _ = self
.watcher_tx
.try_send(WatcherInstruction::WatchFolder(path.clone()));
Expand All @@ -839,9 +860,16 @@ impl Workspace for WorkspaceServer {
.get_project_path(params.project_key)
.ok_or_else(WorkspaceError::no_project)?;

let _ = self
.watcher_tx
.try_send(WatcherInstruction::UnwatchFolder(project_path.clone()));
self.watched_folders.pin().retain(|watched_folder| {
if watched_folder.starts_with(&project_path) {
let _ = self
.watcher_tx
.try_send(WatcherInstruction::UnwatchFolder(watched_folder.clone()));
false
} else {
true
}
});

// Limit the scope of the pin and the lock inside.
{
Expand Down
1 change: 1 addition & 0 deletions crates/biome_service/src/workspace/server.tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fn commonjs_file_rejects_import_statement() {
project_key,
path: Some(BiomePath::new("/")),
watch: false,
force: false,
})
.unwrap();

Expand Down
1 change: 1 addition & 0 deletions crates/biome_service/src/workspace/watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ impl WorkspaceServer {
project_key,
path: Some(path.into()),
watch: false, // It's already being watched.
force: true,
})
.map(|_| ())
}
Expand Down