Skip to content

Commit 097e4b4

Browse files
committed
chore(language_server): split options for linting and formatting
1 parent 78a1146 commit 097e4b4

File tree

5 files changed

+70
-44
lines changed

5 files changed

+70
-44
lines changed

crates/oxc_language_server/src/linter/server_linter.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use crate::linter::{
2020
isolated_lint_handler::{IsolatedLintHandler, IsolatedLintHandlerOptions},
2121
tsgo_linter::TsgoLinter,
2222
};
23-
use crate::options::{Run, UnusedDisableDirectives};
24-
use crate::{ConcurrentHashMap, OXC_CONFIG_FILE, Options};
23+
use crate::options::{LintOptions as LSPLintOptions, Run, UnusedDisableDirectives};
24+
use crate::{ConcurrentHashMap, OXC_CONFIG_FILE};
2525

2626
use super::config_walker::ConfigWalker;
2727

@@ -80,7 +80,7 @@ impl ServerLinterDiagnostics {
8080
}
8181

8282
impl ServerLinter {
83-
pub fn new(root_uri: &Uri, options: &Options) -> Self {
83+
pub fn new(root_uri: &Uri, options: &LSPLintOptions) -> Self {
8484
let root_path = root_uri.to_file_path().unwrap();
8585
let mut nested_ignore_patterns = Vec::new();
8686
let (nested_configs, mut extended_paths) =
@@ -186,7 +186,7 @@ impl ServerLinter {
186186
/// and insert them inside the nested configuration
187187
fn create_nested_configs(
188188
root_path: &Path,
189-
options: &Options,
189+
options: &LSPLintOptions,
190190
nested_ignore_patterns: &mut Vec<(Vec<String>, PathBuf)>,
191191
) -> (ConcurrentHashMap<PathBuf, Config>, Vec<PathBuf>) {
192192
let mut extended_paths = Vec::new();
@@ -394,9 +394,8 @@ mod test {
394394
use std::path::{Path, PathBuf};
395395

396396
use crate::{
397-
Options,
398397
linter::server_linter::{ServerLinter, normalize_path},
399-
options::Run,
398+
options::{LintOptions, Run},
400399
tester::{Tester, get_file_path},
401400
};
402401
use rustc_hash::FxHashMap;
@@ -417,7 +416,7 @@ mod test {
417416
let mut nested_ignore_patterns = Vec::new();
418417
let (configs, _) = ServerLinter::create_nested_configs(
419418
Path::new("/root/"),
420-
&Options { flags, ..Options::default() },
419+
&LintOptions { flags, ..LintOptions::default() },
421420
&mut nested_ignore_patterns,
422421
);
423422

@@ -429,7 +428,7 @@ mod test {
429428
let mut nested_ignore_patterns = Vec::new();
430429
let (configs, _) = ServerLinter::create_nested_configs(
431430
&get_file_path("fixtures/linter/init_nested_configs"),
432-
&Options::default(),
431+
&LintOptions::default(),
433432
&mut nested_ignore_patterns,
434433
);
435434
let configs = configs.pin();
@@ -448,7 +447,7 @@ mod test {
448447
fn test_lint_on_run_on_type_on_type() {
449448
Tester::new(
450449
"fixtures/linter/lint_on_run/on_type",
451-
Some(Options { type_aware: true, run: Run::OnType, ..Default::default() }),
450+
Some(LintOptions { type_aware: true, run: Run::OnType, ..Default::default() }),
452451
)
453452
.test_and_snapshot_single_file_with_run_type("on-type.ts", Run::OnType);
454453
}
@@ -458,7 +457,7 @@ mod test {
458457
fn test_lint_on_run_on_type_on_save() {
459458
Tester::new(
460459
"fixtures/linter/lint_on_run/on_save",
461-
Some(Options { type_aware: true, run: Run::OnType, ..Default::default() }),
460+
Some(LintOptions { type_aware: true, run: Run::OnType, ..Default::default() }),
462461
)
463462
.test_and_snapshot_single_file_with_run_type("on-save.ts", Run::OnSave);
464463
}
@@ -468,7 +467,7 @@ mod test {
468467
fn test_lint_on_run_on_save_on_type() {
469468
Tester::new(
470469
"fixtures/linter/lint_on_run/on_save",
471-
Some(Options { type_aware: true, run: Run::OnSave, ..Default::default() }),
470+
Some(LintOptions { type_aware: true, run: Run::OnSave, ..Default::default() }),
472471
)
473472
.test_and_snapshot_single_file_with_run_type("on-type.ts", Run::OnType);
474473
}
@@ -478,7 +477,7 @@ mod test {
478477
fn test_lint_on_run_on_save_on_save() {
479478
Tester::new(
480479
"fixtures/linter/lint_on_run/on_type",
481-
Some(Options { type_aware: true, run: Run::OnSave, ..Default::default() }),
480+
Some(LintOptions { type_aware: true, run: Run::OnSave, ..Default::default() }),
482481
)
483482
.test_and_snapshot_single_file_with_run_type("on-save.ts", Run::OnSave);
484483
}
@@ -553,12 +552,12 @@ mod test {
553552
fn test_multiple_suggestions() {
554553
Tester::new(
555554
"fixtures/linter/multiple_suggestions",
556-
Some(Options {
555+
Some(LintOptions {
557556
flags: FxHashMap::from_iter([(
558557
"fix_kind".to_string(),
559558
"safe_fix_or_suggestion".to_string(),
560559
)]),
561-
..Options::default()
560+
..Default::default()
562561
}),
563562
)
564563
.test_and_snapshot_single_file("forward_ref.ts");
@@ -569,7 +568,7 @@ mod test {
569568
use crate::options::UnusedDisableDirectives;
570569
Tester::new(
571570
"fixtures/linter/unused_disabled_directives",
572-
Some(Options {
571+
Some(LintOptions {
573572
unused_disable_directives: UnusedDisableDirectives::Deny,
574573
..Default::default()
575574
}),
@@ -588,7 +587,7 @@ mod test {
588587
fn test_ts_alias() {
589588
Tester::new(
590589
"fixtures/linter/ts_path_alias",
591-
Some(Options {
590+
Some(LintOptions {
592591
ts_config_path: Some("./deep/tsconfig.json".to_string()),
593592
..Default::default()
594593
}),
@@ -601,7 +600,7 @@ mod test {
601600
fn test_tsgo_lint() {
602601
let tester = Tester::new(
603602
"fixtures/linter/tsgolint",
604-
Some(Options { type_aware: true, run: Run::OnSave, ..Default::default() }),
603+
Some(LintOptions { type_aware: true, run: Run::OnSave, ..Default::default() }),
605604
);
606605
tester.test_and_snapshot_single_file("no-floating-promises/index.ts");
607606
}

crates/oxc_language_server/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ 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::Deserialize;
67
use serde_json::json;
78
use tokio::sync::{OnceCell, RwLock, SetError};
89
use tower_lsp_server::{
@@ -64,7 +65,7 @@ impl LanguageServer for Backend {
6465
return Some(new_settings);
6566
}
6667

67-
let deprecated_settings = Options::try_from(value.get_mut("settings")?.take()).ok();
68+
let deprecated_settings = Options::deserialize(value.get_mut("settings")?.take()).ok();
6869

6970
// the client has deprecated settings and has a deprecated root uri.
7071
// handle all things like the old way

crates/oxc_language_server/src/options.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,18 @@ pub enum UnusedDisableDirectives {
2222
Deny,
2323
}
2424

25-
#[derive(Debug, Default, Serialize, Clone)]
25+
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
2626
#[serde(rename_all = "camelCase")]
2727
pub struct Options {
28+
#[serde(flatten)]
29+
pub lint: LintOptions,
30+
#[serde(flatten)]
31+
pub format: FormatOptions,
32+
}
33+
34+
#[derive(Debug, Default, Serialize, Clone)]
35+
#[serde(rename_all = "camelCase")]
36+
pub struct LintOptions {
2837
pub run: Run,
2938
pub config_path: Option<String>,
3039
pub ts_config_path: Option<String>,
@@ -33,7 +42,11 @@ pub struct Options {
3342
pub flags: FxHashMap<String, String>,
3443
}
3544

36-
impl Options {
45+
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
46+
#[serde(rename_all = "camelCase")]
47+
pub struct FormatOptions;
48+
49+
impl LintOptions {
3750
pub fn use_nested_configs(&self) -> bool {
3851
!self.flags.contains_key("disable_nested_config") && self.config_path.is_none()
3952
}
@@ -54,17 +67,17 @@ impl Options {
5467
}
5568
}
5669

57-
impl<'de> Deserialize<'de> for Options {
70+
impl<'de> Deserialize<'de> for LintOptions {
5871
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
5972
where
6073
D: Deserializer<'de>,
6174
{
6275
let value = Value::deserialize(deserializer)?;
63-
Options::try_from(value).map_err(Error::custom)
76+
LintOptions::try_from(value).map_err(Error::custom)
6477
}
6578
}
6679

67-
impl TryFrom<Value> for Options {
80+
impl TryFrom<Value> for LintOptions {
6881
type Error = String;
6982

7083
fn try_from(value: Value) -> Result<Self, Self::Error> {
@@ -124,7 +137,9 @@ mod test {
124137
use rustc_hash::FxHashMap;
125138
use serde_json::json;
126139

127-
use super::{Options, Run, UnusedDisableDirectives, WorkspaceOption};
140+
use crate::options::LintOptions;
141+
142+
use super::{Run, UnusedDisableDirectives, WorkspaceOption};
128143

129144
#[test]
130145
fn test_valid_options_json() {
@@ -139,7 +154,7 @@ mod test {
139154
}
140155
});
141156

142-
let options = Options::try_from(json).unwrap();
157+
let options = LintOptions::try_from(json).unwrap();
143158
assert_eq!(options.run, Run::OnSave);
144159
assert_eq!(options.config_path, Some("./custom.json".into()));
145160
assert_eq!(options.unused_disable_directives, UnusedDisableDirectives::Warn);
@@ -152,7 +167,7 @@ mod test {
152167
fn test_empty_options_json() {
153168
let json = json!({});
154169

155-
let options = Options::try_from(json).unwrap();
170+
let options = LintOptions::try_from(json).unwrap();
156171
assert_eq!(options.run, Run::OnType);
157172
assert_eq!(options.config_path, None);
158173
assert_eq!(options.unused_disable_directives, UnusedDisableDirectives::Allow);
@@ -167,7 +182,7 @@ mod test {
167182
"configPath": "./custom.json"
168183
});
169184

170-
let options = Options::try_from(json).unwrap();
185+
let options = LintOptions::try_from(json).unwrap();
171186
assert_eq!(options.run, Run::OnType); // fallback
172187
assert_eq!(options.config_path, Some("./custom.json".into()));
173188
assert!(options.flags.is_empty());
@@ -183,7 +198,7 @@ mod test {
183198
}
184199
});
185200

186-
let options = Options::try_from(json).unwrap();
201+
let options = LintOptions::try_from(json).unwrap();
187202
assert_eq!(options.run, Run::OnType); // fallback
188203
assert_eq!(options.config_path, Some("./custom.json".into()));
189204
assert_eq!(options.flags.get("disable_nested_config"), None);
@@ -206,24 +221,24 @@ mod test {
206221
assert_eq!(workspace[0].workspace_uri.path().as_str(), "/root/");
207222

208223
let options = &workspace[0].options;
209-
assert_eq!(options.run, Run::OnType); // fallback
210-
assert_eq!(options.config_path, Some("./custom.json".into()));
211-
assert!(options.flags.is_empty());
224+
assert_eq!(options.lint.run, Run::OnType); // fallback
225+
assert_eq!(options.lint.config_path, Some("./custom.json".into()));
226+
assert!(options.lint.flags.is_empty());
212227
}
213228

214229
#[test]
215230
fn test_use_nested_configs() {
216-
let options = Options::default();
231+
let options = LintOptions::default();
217232
assert!(options.use_nested_configs());
218233

219234
let options =
220-
Options { config_path: Some("config.json".to_string()), ..Default::default() };
235+
LintOptions { config_path: Some("config.json".to_string()), ..Default::default() };
221236
assert!(!options.use_nested_configs());
222237

223238
let mut flags = FxHashMap::default();
224239
flags.insert("disable_nested_config".to_string(), "true".to_string());
225240

226-
let options = Options { flags, ..Default::default() };
241+
let options = LintOptions { flags, ..Default::default() };
227242
assert!(!options.use_nested_configs());
228243
}
229244
}

crates/oxc_language_server/src/tester.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ use tower_lsp_server::{
66
};
77

88
use crate::{
9-
Options, linter::server_linter::ServerLinterRun, options::Run, worker::WorkspaceWorker,
9+
Options,
10+
linter::server_linter::ServerLinterRun,
11+
options::{LintOptions, Run},
12+
worker::WorkspaceWorker,
1013
};
1114

1215
use super::linter::error_with_position::DiagnosticReport;
@@ -94,11 +97,11 @@ fixed: {fixed:?}
9497
/// Testing struct for the [linter server][crate::linter::server_linter::ServerLinter].
9598
pub struct Tester<'t> {
9699
relative_root_dir: &'t str,
97-
options: Option<Options>,
100+
options: Option<LintOptions>,
98101
}
99102

100103
impl Tester<'_> {
101-
pub fn new(relative_root_dir: &'static str, options: Option<Options>) -> Self {
104+
pub fn new(relative_root_dir: &'static str, options: Option<LintOptions>) -> Self {
102105
Self { relative_root_dir, options }
103106
}
104107

@@ -108,7 +111,12 @@ impl Tester<'_> {
108111
.join(self.relative_root_dir);
109112
let uri = Uri::from_file_path(absolute_path).expect("could not convert current dir to uri");
110113
let worker = WorkspaceWorker::new(uri);
111-
worker.init_linter(&self.options.clone().unwrap_or_default()).await;
114+
worker
115+
.init_linter(&Options {
116+
lint: self.options.clone().unwrap_or_default(),
117+
..Default::default()
118+
})
119+
.await;
112120

113121
worker
114122
}

crates/oxc_language_server/src/worker.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{
2020
error_with_position::{DiagnosticReport, PossibleFixContent},
2121
server_linter::{ServerLinter, ServerLinterRun, normalize_path},
2222
},
23+
options::LintOptions,
2324
};
2425

2526
pub struct WorkspaceWorker {
@@ -46,7 +47,7 @@ impl WorkspaceWorker {
4647

4748
pub async fn init_linter(&self, options: &Options) {
4849
*self.options.lock().await = options.clone();
49-
*self.server_linter.write().await = Some(ServerLinter::new(&self.root_uri, options));
50+
*self.server_linter.write().await = Some(ServerLinter::new(&self.root_uri, &options.lint));
5051
}
5152

5253
// WARNING: start all programs (linter, formatter) before calling this function
@@ -56,13 +57,14 @@ impl WorkspaceWorker {
5657

5758
// clone the options to avoid locking the mutex
5859
let options = self.options.lock().await;
59-
let use_nested_configs = options.use_nested_configs();
60+
let use_nested_configs = options.lint.use_nested_configs();
6061

6162
// append the base watcher
6263
watchers.push(FileSystemWatcher {
6364
glob_pattern: GlobPattern::Relative(RelativePattern {
6465
base_uri: OneOf::Right(self.root_uri.clone()),
6566
pattern: options
67+
.lint
6668
.config_path
6769
.as_ref()
6870
.unwrap_or(&"**/.oxlintrc.json".to_owned())
@@ -115,12 +117,12 @@ impl WorkspaceWorker {
115117

116118
async fn refresh_server_linter(&self) {
117119
let options = self.options.lock().await;
118-
let server_linter = ServerLinter::new(&self.root_uri, &options);
120+
let server_linter = ServerLinter::new(&self.root_uri, &options.lint);
119121

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

123-
fn needs_linter_restart(old_options: &Options, new_options: &Options) -> bool {
125+
fn needs_linter_restart(old_options: &LintOptions, new_options: &LintOptions) -> bool {
124126
old_options.config_path != new_options.config_path
125127
|| old_options.ts_config_path != new_options.ts_config_path
126128
|| old_options.use_nested_configs() != new_options.use_nested_configs()
@@ -306,7 +308,7 @@ impl WorkspaceWorker {
306308
*options_guard = changed_options.clone();
307309
}
308310

309-
if Self::needs_linter_restart(&current_option, changed_options) {
311+
if Self::needs_linter_restart(&current_option.lint, &changed_options.lint) {
310312
let files = {
311313
let server_linter_guard = self.server_linter.read().await;
312314
let server_linter = server_linter_guard.as_ref();
@@ -318,13 +320,14 @@ impl WorkspaceWorker {
318320
};
319321
self.refresh_server_linter().await;
320322

321-
if current_option.config_path != changed_options.config_path {
323+
if current_option.lint.config_path != changed_options.lint.config_path {
322324
return (
323325
Some(self.revalidate_diagnostics(files).await),
324326
Some(FileSystemWatcher {
325327
glob_pattern: GlobPattern::Relative(RelativePattern {
326328
base_uri: OneOf::Right(self.root_uri.clone()),
327329
pattern: changed_options
330+
.lint
328331
.config_path
329332
.as_ref()
330333
.unwrap_or(&"**/.oxlintrc.json".to_string())

0 commit comments

Comments
 (0)