Skip to content

Commit b912715

Browse files
committed
Notify users for invalid client settings
1 parent c60924d commit b912715

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,
@@ -366,6 +370,7 @@ impl ResolvedClientSettings {
366370
match ResolvedConfiguration::try_from(configuration) {
367371
Ok(configuration) => Some(configuration),
368372
Err(err) => {
373+
contains_invalid_settings = true;
369374
tracing::error!("Failed to resolve configuration: {err}");
370375
None
371376
}
@@ -379,34 +384,25 @@ impl ResolvedClientSettings {
379384
settings.format.as_ref()?.preview
380385
}),
381386
select: Self::resolve_optional(all_settings, |settings| {
382-
settings
383-
.lint
384-
.as_ref()?
385-
.select
386-
.as_ref()?
387-
.iter()
388-
.map(|rule| RuleSelector::from_str(rule).ok())
389-
.collect()
387+
Self::resolve_rules(
388+
settings.lint.as_ref()?.select.as_ref()?,
389+
RuleSelectorKey::Select,
390+
&mut contains_invalid_settings,
391+
)
390392
}),
391393
extend_select: Self::resolve_optional(all_settings, |settings| {
392-
settings
393-
.lint
394-
.as_ref()?
395-
.extend_select
396-
.as_ref()?
397-
.iter()
398-
.map(|rule| RuleSelector::from_str(rule).ok())
399-
.collect()
394+
Self::resolve_rules(
395+
settings.lint.as_ref()?.extend_select.as_ref()?,
396+
RuleSelectorKey::ExtendSelect,
397+
&mut contains_invalid_settings,
398+
)
400399
}),
401400
ignore: Self::resolve_optional(all_settings, |settings| {
402-
settings
403-
.lint
404-
.as_ref()?
405-
.ignore
406-
.as_ref()?
407-
.iter()
408-
.map(|rule| RuleSelector::from_str(rule).ok())
409-
.collect()
401+
Self::resolve_rules(
402+
settings.lint.as_ref()?.ignore.as_ref()?,
403+
RuleSelectorKey::Ignore,
404+
&mut contains_invalid_settings,
405+
)
410406
}),
411407
exclude: Self::resolve_optional(all_settings, |settings| settings.exclude.clone()),
412408
line_length: Self::resolve_optional(all_settings, |settings| settings.line_length),
@@ -416,6 +412,37 @@ impl ResolvedClientSettings {
416412
ConfigurationPreference::EditorFirst,
417413
),
418414
},
415+
};
416+
417+
if contains_invalid_settings {
418+
show_err_msg!(
419+
"Ruff received invalid client settings. Refer to the logs for more information."
420+
);
421+
}
422+
423+
settings
424+
}
425+
426+
fn resolve_rules(
427+
rules: &[String],
428+
key: RuleSelectorKey,
429+
contains_invalid_settings: &mut bool,
430+
) -> Option<Vec<RuleSelector>> {
431+
let (mut known, mut unknown) = (vec![], vec![]);
432+
for rule in rules {
433+
match RuleSelector::from_str(rule) {
434+
Ok(selector) => known.push(selector),
435+
Err(ParseError::Unknown(_)) => unknown.push(rule),
436+
}
437+
}
438+
if !unknown.is_empty() {
439+
*contains_invalid_settings = true;
440+
tracing::error!("Unknown rule selectors found in {key}: {unknown:?}");
441+
}
442+
if known.is_empty() {
443+
None
444+
} else {
445+
Some(known)
419446
}
420447
}
421448

@@ -425,7 +452,7 @@ impl ResolvedClientSettings {
425452
/// Use [`ResolvedClientSettings::resolve_or`] for settings that should have default values.
426453
fn resolve_optional<T>(
427454
all_settings: &[&ClientSettings],
428-
get: impl Fn(&ClientSettings) -> Option<T>,
455+
get: impl FnMut(&ClientSettings) -> Option<T>,
429456
) -> Option<T> {
430457
all_settings.iter().map(Deref::deref).find_map(get)
431458
}
@@ -444,6 +471,23 @@ impl ResolvedClientSettings {
444471
}
445472
}
446473

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

0 commit comments

Comments
 (0)