Skip to content

Commit 74ad10b

Browse files
committed
refactor(language_server): improve file watching for different tools
1 parent 4283fd8 commit 74ad10b

File tree

4 files changed

+364
-406
lines changed

4 files changed

+364
-406
lines changed

crates/oxc_language_server/src/backend.rs

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,17 @@ use std::{str::FromStr, sync::Arc};
33
use futures::future::join_all;
44
use log::{debug, info, warn};
55
use rustc_hash::FxBuildHasher;
6-
use serde_json::json;
76
use tokio::sync::{OnceCell, RwLock, SetError};
87
use tower_lsp_server::{
98
Client, LanguageServer,
109
jsonrpc::{Error, ErrorCode, Result},
1110
lsp_types::{
1211
CodeActionParams, CodeActionResponse, ConfigurationItem, Diagnostic,
1312
DidChangeConfigurationParams, DidChangeTextDocumentParams, DidChangeWatchedFilesParams,
14-
DidChangeWatchedFilesRegistrationOptions, DidChangeWorkspaceFoldersParams,
15-
DidCloseTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams,
16-
DocumentFormattingParams, ExecuteCommandParams, InitializeParams, InitializeResult,
17-
InitializedParams, Registration, ServerInfo, TextEdit, Unregistration, Uri, WorkspaceEdit,
13+
DidChangeWorkspaceFoldersParams, DidCloseTextDocumentParams, DidOpenTextDocumentParams,
14+
DidSaveTextDocumentParams, DocumentFormattingParams, ExecuteCommandParams,
15+
InitializeParams, InitializeResult, InitializedParams, Registration, ServerInfo, TextEdit,
16+
Unregistration, Uri, WorkspaceEdit,
1817
},
1918
};
2019

@@ -204,13 +203,7 @@ impl LanguageServer for Backend {
204203
// init all file watchers
205204
if capabilities.dynamic_watchers {
206205
for worker in workers {
207-
registrations.push(Registration {
208-
id: format!("watcher-{}", worker.get_root_uri().as_str()),
209-
method: "workspace/didChangeWatchedFiles".to_string(),
210-
register_options: Some(json!(DidChangeWatchedFilesRegistrationOptions {
211-
watchers: worker.init_watchers().await
212-
})),
213-
});
206+
registrations.extend(worker.init_watchers().await);
214207
}
215208
}
216209

@@ -326,7 +319,7 @@ impl LanguageServer for Backend {
326319
continue;
327320
};
328321

329-
let (diagnostics, watchers, formatter_activated) =
322+
let (diagnostics, registrations, unregistrations, formatter_activated) =
330323
worker.did_change_configuration(&option.options).await;
331324

332325
if formatter_activated && self.capabilities.get().is_some_and(|c| c.dynamic_formatting)
@@ -338,23 +331,8 @@ impl LanguageServer for Backend {
338331
new_diagnostics.extend(diagnostics);
339332
}
340333

341-
if let Some(watchers) = watchers
342-
&& self.capabilities.get().is_some_and(|capabilities| capabilities.dynamic_watchers)
343-
{
344-
// remove the old watcher
345-
removing_registrations.push(Unregistration {
346-
id: format!("watcher-{}", worker.get_root_uri().as_str()),
347-
method: "workspace/didChangeWatchedFiles".to_string(),
348-
});
349-
// add the new watcher
350-
adding_registrations.push(Registration {
351-
id: format!("watcher-{}", worker.get_root_uri().as_str()),
352-
method: "workspace/didChangeWatchedFiles".to_string(),
353-
register_options: Some(json!(DidChangeWatchedFilesRegistrationOptions {
354-
watchers
355-
})),
356-
});
357-
}
334+
removing_registrations.extend(unregistrations);
335+
adding_registrations.extend(registrations);
358336
}
359337

360338
if !new_diagnostics.is_empty() {
@@ -464,13 +442,7 @@ impl LanguageServer for Backend {
464442

465443
worker.start_worker(options).await;
466444

467-
added_registrations.push(Registration {
468-
id: format!("watcher-{}", worker.get_root_uri().as_str()),
469-
method: "workspace/didChangeWatchedFiles".to_string(),
470-
register_options: Some(json!(DidChangeWatchedFilesRegistrationOptions {
471-
watchers: worker.init_watchers().await
472-
})),
473-
});
445+
added_registrations.extend(worker.init_watchers().await);
474446
workers.push(worker);
475447
}
476448
// client does not support the request

crates/oxc_language_server/src/formatter/server_formatter.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use oxc_formatter::{
99
use oxc_parser::{ParseOptions, Parser};
1010
use tower_lsp_server::{
1111
UriExt,
12-
lsp_types::{Position, Range, TextEdit, Uri},
12+
lsp_types::{Pattern, Position, Range, TextEdit, Uri},
1313
};
1414

1515
use crate::formatter::options::FormatOptions as LSPFormatOptions;
@@ -103,6 +103,23 @@ impl ServerFormatter {
103103
}
104104
}
105105
}
106+
107+
#[expect(clippy::unused_self)]
108+
pub fn get_watcher_patterns(&self, options: &LSPFormatOptions) -> Pattern {
109+
options.config_path.as_ref().map_or(FORMAT_CONFIG_FILE, |v| v).to_owned()
110+
}
111+
112+
pub fn get_changed_watch_patterns(
113+
&self,
114+
old_options: &LSPFormatOptions,
115+
new_options: &LSPFormatOptions,
116+
) -> Option<Pattern> {
117+
if old_options != new_options && new_options.experimental {
118+
return Some(self.get_watcher_patterns(new_options));
119+
}
120+
121+
None
122+
}
106123
}
107124

108125
/// Returns the minimal text edit (start, end, replacement) to transform `source_text` into `formatted_text`

crates/oxc_language_server/src/linter/server_linter.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use log::{debug, warn};
77
use oxc_linter::{AllowWarnDeny, LintIgnoreMatcher};
88
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
99
use tokio::sync::Mutex;
10-
use tower_lsp_server::lsp_types::{Diagnostic, Uri};
10+
use tower_lsp_server::lsp_types::{Diagnostic, Pattern, Uri};
1111

1212
use oxc_linter::{
1313
Config, ConfigStore, ConfigStoreBuilder, ExternalPluginStore, LintOptions, Oxlintrc,
@@ -40,7 +40,7 @@ pub struct ServerLinter {
4040
gitignore_glob: Vec<Gitignore>,
4141
lint_on_run: Run,
4242
diagnostics: ServerLinterDiagnostics,
43-
pub extended_paths: FxHashSet<PathBuf>,
43+
extended_paths: FxHashSet<PathBuf>,
4444
}
4545

4646
#[derive(Debug, Default)]
@@ -378,6 +378,39 @@ impl ServerLinter {
378378
// TODO: only the TsgoLinter needs to be dropped or created
379379
|| old_options.type_aware != new_options.type_aware
380380
}
381+
382+
pub fn get_watch_patterns(&self, options: &LSPLintOptions, root_path: &Path) -> Vec<Pattern> {
383+
let mut watchers = vec![
384+
options.config_path.as_ref().unwrap_or(&"**/.oxlintrc.json".to_string()).to_owned(),
385+
];
386+
387+
for path in &self.extended_paths {
388+
// ignore .oxlintrc.json files when using nested configs
389+
if path.ends_with(".oxlintrc.json") && options.use_nested_configs() {
390+
continue;
391+
}
392+
393+
let pattern = path.strip_prefix(root_path).unwrap_or(path);
394+
395+
watchers.push(normalize_path(pattern).to_string_lossy().to_string());
396+
}
397+
watchers
398+
}
399+
400+
pub fn get_changed_watch_patterns(
401+
&self,
402+
old_options: &LSPLintOptions,
403+
new_options: &LSPLintOptions,
404+
root_path: &Path,
405+
) -> Option<Vec<Pattern>> {
406+
if old_options.config_path == new_options.config_path
407+
&& old_options.use_nested_configs() == new_options.use_nested_configs()
408+
{
409+
return None;
410+
}
411+
412+
Some(self.get_watch_patterns(new_options, root_path))
413+
}
381414
}
382415

383416
#[cfg(test)]

0 commit comments

Comments
 (0)