Skip to content
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
6 changes: 4 additions & 2 deletions crates/oxc_language_server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ impl LanguageServer for Backend {

// ToDo: add support for multiple workspace folders
// maybe fallback when the client does not support it
let root_worker =
WorkspaceWorker::new(&params.root_uri.unwrap(), options.clone().unwrap_or_default());
let root_worker = WorkspaceWorker::new(&params.root_uri.unwrap());
// ToDo: only call init_linter when the client passed a valid Options struct
// if not and the client supports `workspace/configuration`, we should request them in `initialized`
root_worker.init_linter(&options.clone().unwrap_or_default()).await;

*self.workspace_workers.lock().await = vec![root_worker];

Expand Down
8 changes: 6 additions & 2 deletions crates/oxc_language_server/src/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,15 @@ impl Tester<'_> {
Self { relative_root_dir, options }
}

fn create_workspace_worker(&self) -> WorkspaceWorker {
async fn create_workspace_worker(&self) -> WorkspaceWorker {
let absolute_path = std::env::current_dir()
.expect("could not get current dir")
.join(self.relative_root_dir);
let uri = Uri::from_file_path(absolute_path).expect("could not convert current dir to uri");
WorkspaceWorker::new(&uri, self.options.clone().unwrap_or_default())
let worker = WorkspaceWorker::new(&uri);
worker.init_linter(&self.options.clone().unwrap_or_default()).await;

worker
}

/// Given a relative file path (relative to `oxc_language_server` crate root), run the linter
Expand All @@ -111,6 +114,7 @@ impl Tester<'_> {
let uri = get_file_uri(&format!("{}/{}", self.relative_root_dir, relative_file_path));
let reports = tokio::runtime::Runtime::new().unwrap().block_on(async {
self.create_workspace_worker()
.await
.lint_file(&uri, None)
.await
.expect("lint file is ignored")
Expand Down
40 changes: 25 additions & 15 deletions crates/oxc_language_server/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,21 @@ use crate::{

pub struct WorkspaceWorker {
root_uri: OnceCell<Uri>,
server_linter: RwLock<ServerLinter>,
server_linter: RwLock<Option<ServerLinter>>,
diagnostics_report_map: RwLock<ConcurrentHashMap<String, Vec<DiagnosticReport>>>,
options: Mutex<Options>,
}

impl WorkspaceWorker {
pub fn new(root_uri: &Uri, options: Options) -> Self {
pub fn new(root_uri: &Uri) -> Self {
let root_uri_cell = OnceCell::new();
root_uri_cell.set(root_uri.clone()).unwrap();

let server_linter = ServerLinter::new(root_uri, &options);
Self {
root_uri: root_uri_cell,
server_linter: RwLock::new(server_linter),
server_linter: RwLock::new(None),
diagnostics_report_map: RwLock::new(ConcurrentHashMap::default()),
options: Mutex::new(options),
options: Mutex::new(Options::default()),
}
}

Expand All @@ -51,6 +50,12 @@ impl WorkspaceWorker {
false
}

pub async fn init_linter(&self, options: &Options) {
*self.options.lock().await = options.clone();
*self.server_linter.write().await =
Some(ServerLinter::new(self.root_uri.get().unwrap(), options));
}

pub async fn remove_diagnostics(&self, uri: &Uri) {
self.diagnostics_report_map.read().await.pin().remove(&uri.to_string());
}
Expand All @@ -59,7 +64,7 @@ impl WorkspaceWorker {
let options = self.options.lock().await;
let server_linter = ServerLinter::new(self.root_uri.get().unwrap(), &options);

*self.server_linter.write().await = server_linter;
*self.server_linter.write().await = Some(server_linter);
}

fn needs_linter_restart(old_options: &Options, new_options: &Options) -> bool {
Expand Down Expand Up @@ -93,7 +98,11 @@ impl WorkspaceWorker {
uri: &Uri,
content: Option<String>,
) -> Option<Vec<DiagnosticReport>> {
self.server_linter.read().await.run_single(uri, content)
let Some(server_linter) = &*self.server_linter.read().await else {
return None;
};

server_linter.run_single(uri, content)
}

async fn update_diagnostics(&self, uri: &Uri, diagnostics: &[DiagnosticReport]) {
Expand All @@ -109,9 +118,14 @@ impl WorkspaceWorker {
self.diagnostics_report_map.read().await.len(),
FxBuildHasher,
);
let linter = self.server_linter.read().await;
let server_linter = self.server_linter.read().await;
let Some(server_linter) = &*server_linter else {
debug!("no server_linter initialized in the worker");
return diagnostics_map;
};
for uri in self.diagnostics_report_map.read().await.pin().keys() {
if let Some(diagnostics) = linter.run_single(&Uri::from_str(uri).unwrap(), None) {
if let Some(diagnostics) = server_linter.run_single(&Uri::from_str(uri).unwrap(), None)
{
diagnostics_map.pin().insert(uri.clone(), diagnostics);
}
}
Expand Down Expand Up @@ -250,18 +264,14 @@ mod tests {

#[test]
fn test_get_root_uri() {
let worker =
WorkspaceWorker::new(&Uri::from_str("file:///root/").unwrap(), Options::default());
let worker = WorkspaceWorker::new(&Uri::from_str("file:///root/").unwrap());

assert_eq!(worker.get_root_uri(), Some(Uri::from_str("file:///root/").unwrap()));
}

#[test]
fn test_is_responsible() {
let worker = WorkspaceWorker::new(
&Uri::from_str("file:///path/to/root").unwrap(),
Options::default(),
);
let worker = WorkspaceWorker::new(&Uri::from_str("file:///path/to/root").unwrap());

assert!(
worker.is_responsible_for_uri(&Uri::from_str("file:///path/to/root/file.js").unwrap())
Expand Down
Loading