Skip to content

Commit 34814c8

Browse files
Sysixcamchenry
authored andcommitted
refactor(language_server)!: remove enabled configuration, the client should shutdown the server instead
1 parent 4c77b34 commit 34814c8

File tree

4 files changed

+59
-65
lines changed

4 files changed

+59
-65
lines changed

crates/oxc_language_server/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,20 @@ Initialization Options:
2525
| Option Key | Value(s) | Default | Description |
2626
| ------------ | ---------------------- | ---------------- | ---------------------------------------------------------------------------------------------------- |
2727
| `run` | `"onSave" \| "onType"` | `"onType"` | Should the server lint the files when the user is typing or saving |
28-
| `enable` | `true \| false` | `true` | Should the server lint files |
2928
| `configPath` | `<string>` | `.oxlintrc.json` | Path to a oxlint configuration file, pass '' to enable nested configuration |
3029
| `flags` | `Map<string, string>` | `<empty>` | Special oxc language server flags, currently only one flag key is supported: `disable_nested_config` |
3130

3231
### [initialized](https://microsoft.github.io/language-server-protocol/specification#initialized)
3332

3433
### [shutdown](https://microsoft.github.io/language-server-protocol/specification#shutdown)
3534

35+
The server will reset the diagnostics for all open files and send one or more [textDocument/publishDiagnostics](#textdocumentpublishdiagnostics) requests to the client.
36+
3637
### Workspace
3738

3839
#### [workspace/didChangeConfiguration](https://microsoft.github.io/language-server-protocol/specification#workspace_didChangeConfiguration)
3940

40-
The server expects this request when settings like `run`, `enable`, `flags` or `configPath` are changed.
41+
The server expects this request when settings like `run`, `flags` or `configPath` are changed.
4142
The server will revalidate or reset the diagnostics for all open files and send one or more [textDocument/publishDiagnostics](#textdocumentpublishdiagnostics) requests to the client.
4243

4344
#### [workspace/didChangeWatchedFiles](https://microsoft.github.io/language-server-protocol/specification#workspace_didChangeWatchedFiles)

crates/oxc_language_server/src/main.rs

Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,13 @@ enum Run {
5454
#[serde(rename_all = "camelCase")]
5555
struct Options {
5656
run: Run,
57-
enable: bool,
5857
config_path: String,
5958
flags: FxHashMap<String, String>,
6059
}
6160

6261
impl Default for Options {
6362
fn default() -> Self {
6463
Self {
65-
enable: true,
6664
run: Run::default(),
6765
config_path: OXC_CONFIG_FILE.into(),
6866
flags: FxHashMap::default(),
@@ -71,17 +69,6 @@ impl Default for Options {
7169
}
7270

7371
impl Options {
74-
fn get_lint_level(&self) -> SyntheticRunLevel {
75-
if self.enable {
76-
match self.run {
77-
Run::OnSave => SyntheticRunLevel::OnSave,
78-
Run::OnType => SyntheticRunLevel::OnType,
79-
}
80-
} else {
81-
SyntheticRunLevel::Disable
82-
}
83-
}
84-
8572
fn get_config_path(&self) -> Option<PathBuf> {
8673
if self.config_path.is_empty() { None } else { Some(PathBuf::from(&self.config_path)) }
8774
}
@@ -91,13 +78,6 @@ impl Options {
9178
}
9279
}
9380

94-
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy)]
95-
enum SyntheticRunLevel {
96-
Disable,
97-
OnSave,
98-
OnType,
99-
}
100-
10181
#[tower_lsp::async_trait]
10282
impl LanguageServer for Backend {
10383
async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult> {
@@ -155,40 +135,16 @@ impl LanguageServer for Backend {
155135
"
156136
);
157137

158-
if current_option.get_lint_level() != changed_options.get_lint_level()
159-
&& changed_options.get_lint_level() == SyntheticRunLevel::Disable
160-
{
161-
debug!("lint level change detected {:?}", &changed_options.get_lint_level());
162-
// clear all exists diagnostics when linter is disabled
163-
let cleared_diagnostics = self
164-
.diagnostics_report_map
165-
.pin()
166-
.keys()
167-
.map(|uri| {
168-
(
169-
// should convert successfully, case the key is from `params.document.uri`
170-
Url::from_str(uri)
171-
.ok()
172-
.and_then(|url| url.to_file_path().ok())
173-
.expect("should convert to path"),
174-
vec![],
175-
)
176-
})
177-
.collect::<Vec<_>>();
178-
self.publish_all_diagnostics(&cleared_diagnostics).await;
179-
}
180-
181138
if changed_options.disable_nested_configs() {
182139
self.nested_configs.pin().clear();
183140
}
184141

185142
*self.options.lock().await = changed_options.clone();
186143

187-
// revalidate the config and all open files, when lint level is not disabled and the config path is changed
188-
if changed_options.get_lint_level() != SyntheticRunLevel::Disable
189-
&& changed_options
190-
.get_config_path()
191-
.is_some_and(|path| path.to_str().unwrap() != current_option.config_path)
144+
// revalidate the config and all open files
145+
if changed_options
146+
.get_config_path()
147+
.is_some_and(|path| path.to_str().unwrap() != current_option.config_path)
192148
{
193149
info!("config path change detected {:?}", &changed_options.get_config_path());
194150
self.init_linter_config().await;
@@ -247,14 +203,15 @@ impl LanguageServer for Backend {
247203
}
248204

249205
async fn shutdown(&self) -> Result<()> {
206+
self.clear_all_diagnostics().await;
250207
Ok(())
251208
}
252209

253210
async fn did_save(&self, params: DidSaveTextDocumentParams) {
254211
debug!("oxc server did save");
255212
// drop as fast as possible
256-
let run_level = { self.options.lock().await.get_lint_level() };
257-
if run_level < SyntheticRunLevel::OnSave {
213+
let run_level = { self.options.lock().await.run };
214+
if run_level != Run::OnSave {
258215
return;
259216
}
260217
let uri = params.text_document.uri;
@@ -267,8 +224,8 @@ impl LanguageServer for Backend {
267224
/// When the document changed, it may not be written to disk, so we should
268225
/// get the file context from the language client
269226
async fn did_change(&self, params: DidChangeTextDocumentParams) {
270-
let run_level = { self.options.lock().await.get_lint_level() };
271-
if run_level < SyntheticRunLevel::OnType {
227+
let run_level = { self.options.lock().await.run };
228+
if run_level != Run::OnType {
272229
return;
273230
}
274231

@@ -286,10 +243,6 @@ impl LanguageServer for Backend {
286243
}
287244

288245
async fn did_open(&self, params: DidOpenTextDocumentParams) {
289-
let run_level = { self.options.lock().await.get_lint_level() };
290-
if run_level <= SyntheticRunLevel::Disable {
291-
return;
292-
}
293246
if self.is_ignored(&params.text_document.uri).await {
294247
return;
295248
}
@@ -515,6 +468,25 @@ impl Backend {
515468
}
516469
}
517470

471+
async fn clear_all_diagnostics(&self) {
472+
let cleared_diagnostics = self
473+
.diagnostics_report_map
474+
.pin()
475+
.keys()
476+
.map(|uri| {
477+
(
478+
// should convert successfully, case the key is from `params.document.uri`
479+
Url::from_str(uri)
480+
.ok()
481+
.and_then(|url| url.to_file_path().ok())
482+
.expect("should convert to path"),
483+
vec![],
484+
)
485+
})
486+
.collect::<Vec<_>>();
487+
self.publish_all_diagnostics(&cleared_diagnostics).await;
488+
}
489+
518490
#[expect(clippy::ptr_arg)]
519491
async fn publish_all_diagnostics(&self, result: &Vec<(PathBuf, Vec<Diagnostic>)>) {
520492
join_all(result.iter().map(|(path, diagnostics)| {

editors/vscode/client/Config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ export class Config implements ConfigInterface {
9898
public toLanguageServerConfig(): LanguageServerConfig {
9999
return {
100100
run: this.runTrigger,
101-
enable: this.enable,
102101
configPath: this.configPath,
103102
flags: this.flags,
104103
};
@@ -107,7 +106,6 @@ export class Config implements ConfigInterface {
107106

108107
interface LanguageServerConfig {
109108
configPath: string;
110-
enable: boolean;
111109
run: Trigger;
112110
flags: Record<string, string>;
113111
}

editors/vscode/client/extension.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,14 @@ export async function activate(context: ExtensionContext) {
5858
try {
5959
if (client.isRunning()) {
6060
await client.restart();
61+
// ToDo: refactor it on the server side.
62+
// Do not touch watchers on client side, just simplify the restart of the server.
63+
const configFiles = await findOxlintrcConfigFiles();
64+
await sendDidChangeWatchedFilesNotificationWith(client, configFiles);
6165

6266
window.showInformationMessage('oxc server restarted.');
6367
} else {
64-
await client.start();
68+
await startClient();
6569
}
6670
} catch (err) {
6771
client.error('Restarting client failed', err, 'force');
@@ -78,8 +82,18 @@ export async function activate(context: ExtensionContext) {
7882

7983
const toggleEnable = commands.registerCommand(
8084
OxcCommands.ToggleEnable,
81-
() => {
82-
configService.config.updateEnable(!configService.config.enable);
85+
async () => {
86+
await configService.config.updateEnable(!configService.config.enable);
87+
88+
if (client.isRunning()) {
89+
if (!configService.config.enable) {
90+
await client.stop();
91+
}
92+
} else {
93+
if (configService.config.enable) {
94+
await startClient();
95+
}
96+
}
8397
},
8498
);
8599

@@ -232,7 +246,7 @@ export async function activate(context: ExtensionContext) {
232246

233247
configService.onConfigChange = function onConfigChange(event) {
234248
let settings = this.config.toLanguageServerConfig();
235-
updateStatsBar(settings.enable);
249+
updateStatsBar(this.config.enable);
236250
client.sendNotification('workspace/didChangeConfiguration', { settings });
237251

238252
if (event.affectsConfiguration('oxc.configPath')) {
@@ -265,8 +279,17 @@ export async function activate(context: ExtensionContext) {
265279
myStatusBarItem.backgroundColor = bgColor;
266280
}
267281
updateStatsBar(configService.config.enable);
268-
await client.start();
269282

283+
if (configService.config.enable) {
284+
await startClient();
285+
}
286+
}
287+
288+
// Starts the client, it does not check if it is already started
289+
async function startClient() {
290+
await client.start();
291+
// ToDo: refactor it on the server side.
292+
// Do not touch watchers on client side, just simplify the start of the server.
270293
const configFiles = await findOxlintrcConfigFiles();
271294
await sendDidChangeWatchedFilesNotificationWith(client, configFiles);
272295
}

0 commit comments

Comments
 (0)