Skip to content

Commit ac84820

Browse files
committed
Notify users for invalid client settings
1 parent 7dad0c4 commit ac84820

File tree

1 file changed

+71
-27
lines changed

1 file changed

+71
-27
lines changed

crates/ruff_server/src/session/settings.rs

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ use serde::Deserialize;
66
use serde_json::{Map, Value};
77
use thiserror::Error;
88

9-
use ruff_linter::{line_width::LineLength, RuleSelector};
9+
use ruff_linter::line_width::LineLength;
10+
use ruff_linter::rule_selector::ParseError;
11+
use ruff_linter::RuleSelector;
1012
use ruff_workspace::options::Options;
1113

1214
/// Maps a workspace URI to its associated client settings. Used during server initialization.
@@ -319,7 +321,9 @@ impl ResolvedClientSettings {
319321
}
320322

321323
fn new_impl(all_settings: &[&ClientSettings]) -> Self {
322-
Self {
324+
let mut contains_invalid_settings = false;
325+
326+
let settings = Self {
323327
fix_all: Self::resolve_or(all_settings, |settings| settings.fix_all, true),
324328
organize_imports: Self::resolve_or(
325329
all_settings,
@@ -369,6 +373,7 @@ impl ResolvedClientSettings {
369373
tracing::error!(
370374
"Failed to load settings from `configuration`: {err}"
371375
);
376+
contains_invalid_settings = true;
372377
None
373378
}
374379
}
@@ -381,34 +386,25 @@ impl ResolvedClientSettings {
381386
settings.format.as_ref()?.preview
382387
}),
383388
select: Self::resolve_optional(all_settings, |settings| {
384-
settings
385-
.lint
386-
.as_ref()?
387-
.select
388-
.as_ref()?
389-
.iter()
390-
.map(|rule| RuleSelector::from_str(rule).ok())
391-
.collect()
389+
Self::resolve_rules(
390+
settings.lint.as_ref()?.select.as_ref()?,
391+
RuleSelectorKey::Select,
392+
&mut contains_invalid_settings,
393+
)
392394
}),
393395
extend_select: Self::resolve_optional(all_settings, |settings| {
394-
settings
395-
.lint
396-
.as_ref()?
397-
.extend_select
398-
.as_ref()?
399-
.iter()
400-
.map(|rule| RuleSelector::from_str(rule).ok())
401-
.collect()
396+
Self::resolve_rules(
397+
settings.lint.as_ref()?.extend_select.as_ref()?,
398+
RuleSelectorKey::ExtendSelect,
399+
&mut contains_invalid_settings,
400+
)
402401
}),
403402
ignore: Self::resolve_optional(all_settings, |settings| {
404-
settings
405-
.lint
406-
.as_ref()?
407-
.ignore
408-
.as_ref()?
409-
.iter()
410-
.map(|rule| RuleSelector::from_str(rule).ok())
411-
.collect()
403+
Self::resolve_rules(
404+
settings.lint.as_ref()?.ignore.as_ref()?,
405+
RuleSelectorKey::Ignore,
406+
&mut contains_invalid_settings,
407+
)
412408
}),
413409
exclude: Self::resolve_optional(all_settings, |settings| settings.exclude.clone()),
414410
line_length: Self::resolve_optional(all_settings, |settings| settings.line_length),
@@ -418,6 +414,37 @@ impl ResolvedClientSettings {
418414
ConfigurationPreference::EditorFirst,
419415
),
420416
},
417+
};
418+
419+
if contains_invalid_settings {
420+
show_err_msg!(
421+
"Ruff received invalid client settings. Refer to the logs for more information."
422+
);
423+
}
424+
425+
settings
426+
}
427+
428+
fn resolve_rules(
429+
rules: &[String],
430+
key: RuleSelectorKey,
431+
contains_invalid_settings: &mut bool,
432+
) -> Option<Vec<RuleSelector>> {
433+
let (mut known, mut unknown) = (vec![], vec![]);
434+
for rule in rules {
435+
match RuleSelector::from_str(rule) {
436+
Ok(selector) => known.push(selector),
437+
Err(ParseError::Unknown(_)) => unknown.push(rule),
438+
}
439+
}
440+
if !unknown.is_empty() {
441+
*contains_invalid_settings = true;
442+
tracing::error!("Unknown rule selectors found in `{key}`: {unknown:?}");
443+
}
444+
if known.is_empty() {
445+
None
446+
} else {
447+
Some(known)
421448
}
422449
}
423450

@@ -427,7 +454,7 @@ impl ResolvedClientSettings {
427454
/// Use [`ResolvedClientSettings::resolve_or`] for settings that should have default values.
428455
fn resolve_optional<T>(
429456
all_settings: &[&ClientSettings],
430-
get: impl Fn(&ClientSettings) -> Option<T>,
457+
get: impl FnMut(&ClientSettings) -> Option<T>,
431458
) -> Option<T> {
432459
all_settings.iter().map(Deref::deref).find_map(get)
433460
}
@@ -446,6 +473,23 @@ impl ResolvedClientSettings {
446473
}
447474
}
448475

476+
#[derive(Copy, Clone)]
477+
enum RuleSelectorKey {
478+
Select,
479+
ExtendSelect,
480+
Ignore,
481+
}
482+
483+
impl std::fmt::Display for RuleSelectorKey {
484+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
485+
match self {
486+
RuleSelectorKey::Select => f.write_str("lint.select"),
487+
RuleSelectorKey::ExtendSelect => f.write_str("lint.extendSelect"),
488+
RuleSelectorKey::Ignore => f.write_str("lint.ignore"),
489+
}
490+
}
491+
}
492+
449493
impl ResolvedClientSettings {
450494
pub(crate) fn fix_all(&self) -> bool {
451495
self.fix_all

0 commit comments

Comments
 (0)