Skip to content

Commit e8f2911

Browse files
committed
Expand ruff.configuration to allow all config
1 parent 4d63c16 commit e8f2911

4 files changed

Lines changed: 91 additions & 22 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ruff_server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ serde = { workspace = true }
3838
serde_json = { workspace = true }
3939
shellexpand = { workspace = true }
4040
thiserror = { workspace = true }
41+
toml = { workspace = true }
4142
tracing = { workspace = true }
4243
tracing-subscriber = { workspace = true }
4344

crates/ruff_server/src/session/index/ruff_settings.rs

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ use ruff_workspace::{
1818
resolver::{ConfigurationTransformer, Relativity},
1919
};
2020

21-
use crate::session::settings::{ConfigurationPreference, ResolvedEditorSettings};
21+
use crate::session::settings::{
22+
ConfigurationPreference, ResolvedConfiguration, ResolvedEditorSettings,
23+
};
2224

2325
#[derive(Debug)]
2426
pub struct RuffSettings {
@@ -363,21 +365,39 @@ impl ConfigurationTransformer for EditorConfigurationTransformer<'_> {
363365
..Configuration::default()
364366
};
365367

366-
// Merge in the editor-specified configuration file, if it exists.
367-
let editor_configuration = if let Some(config_file_path) = configuration {
368-
tracing::debug!(
369-
"Combining settings from editor-specified configuration file at: {}",
370-
config_file_path.display()
371-
);
372-
match open_configuration_file(&config_file_path) {
373-
Ok(config_from_file) => editor_configuration.combine(config_from_file),
374-
err => {
375-
tracing::error!(
376-
"{:?}",
377-
err.context("Unable to load editor-specified configuration file")
378-
.unwrap_err()
368+
// Merge in the editor-specified configuration.
369+
let editor_configuration = if let Some(configuration) = configuration {
370+
match configuration {
371+
ResolvedConfiguration::FilePath(path) => {
372+
tracing::debug!(
373+
"Combining settings from editor-specified configuration file at: {}",
374+
path.display()
379375
);
380-
editor_configuration
376+
match open_configuration_file(&path) {
377+
Ok(config_from_file) => editor_configuration.combine(config_from_file),
378+
err => {
379+
tracing::error!(
380+
"{:?}",
381+
err.context("Unable to load editor-specified configuration file")
382+
.unwrap_err()
383+
);
384+
editor_configuration
385+
}
386+
}
387+
}
388+
ResolvedConfiguration::SettingsOverride(options) => {
389+
tracing::debug!("Combining settings from editor-specified configuration");
390+
match Configuration::from_options(options, None, project_root) {
391+
Ok(configuration) => editor_configuration.combine(configuration),
392+
err => {
393+
tracing::error!(
394+
"{:?}",
395+
err.context("Unable to load editor-specified configuration")
396+
.unwrap_err()
397+
);
398+
editor_configuration
399+
}
400+
}
381401
}
382402
}
383403
} else {

crates/ruff_server/src/session/settings.rs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ use std::{ops::Deref, path::PathBuf, str::FromStr};
33
use lsp_types::Url;
44
use rustc_hash::FxHashMap;
55
use serde::Deserialize;
6+
use serde_json::{Map, Value};
7+
use thiserror::Error;
68

79
use ruff_linter::{line_width::LineLength, RuleSelector};
10+
use ruff_workspace::options::Options;
811

912
/// Maps a workspace URI to its associated client settings. Used during server initialization.
1013
pub(crate) type WorkspaceSettingsMap = FxHashMap<Url, ClientSettings>;
@@ -31,7 +34,7 @@ pub(crate) struct ResolvedClientSettings {
3134
#[derive(Clone, Debug)]
3235
#[cfg_attr(test, derive(PartialEq, Eq))]
3336
pub(crate) struct ResolvedEditorSettings {
34-
pub(super) configuration: Option<PathBuf>,
37+
pub(super) configuration: Option<ResolvedConfiguration>,
3538
pub(super) lint_preview: Option<bool>,
3639
pub(super) format_preview: Option<bool>,
3740
pub(super) select: Option<Vec<RuleSelector>>,
@@ -42,6 +45,38 @@ pub(crate) struct ResolvedEditorSettings {
4245
pub(super) configuration_preference: ConfigurationPreference,
4346
}
4447

48+
#[derive(Clone, Debug)]
49+
#[cfg_attr(test, derive(PartialEq, Eq))]
50+
pub(crate) enum ResolvedConfiguration {
51+
FilePath(PathBuf),
52+
SettingsOverride(Options),
53+
}
54+
55+
impl TryFrom<&ClientConfiguration> for ResolvedConfiguration {
56+
type Error = ResolvedConfigurationError;
57+
58+
fn try_from(value: &ClientConfiguration) -> Result<Self, Self::Error> {
59+
match value {
60+
ClientConfiguration::String(path) => Ok(ResolvedConfiguration::FilePath(
61+
PathBuf::from(shellexpand::full(path)?.as_ref()),
62+
)),
63+
ClientConfiguration::Object(map) => Ok(ResolvedConfiguration::SettingsOverride(
64+
toml::Table::try_from(map)?.try_into::<Options>()?,
65+
)),
66+
}
67+
}
68+
}
69+
70+
#[derive(Debug, Error)]
71+
pub(crate) enum ResolvedConfigurationError {
72+
#[error(transparent)]
73+
ShellExpand(#[from] shellexpand::LookupError<std::env::VarError>),
74+
#[error(transparent)]
75+
InvalidToml(#[from] toml::ser::Error),
76+
#[error(transparent)]
77+
InvalidRuffSchema(#[from] toml::de::Error),
78+
}
79+
4580
/// Determines how multiple conflicting configurations should be resolved - in this
4681
/// case, the configuration from the client settings and configuration from local
4782
/// `.toml` files (aka 'workspace' configuration).
@@ -57,12 +92,20 @@ pub(crate) enum ConfigurationPreference {
5792
EditorOnly,
5893
}
5994

95+
#[derive(Debug, Deserialize)]
96+
#[cfg_attr(test, derive(PartialEq, Eq))]
97+
#[serde(untagged)]
98+
enum ClientConfiguration {
99+
String(String),
100+
Object(Map<String, Value>),
101+
}
102+
60103
/// This is a direct representation of the settings schema sent by the client.
61104
#[derive(Debug, Deserialize, Default)]
62105
#[cfg_attr(test, derive(PartialEq, Eq))]
63106
#[serde(rename_all = "camelCase")]
64107
pub struct ClientSettings {
65-
configuration: Option<String>,
108+
configuration: Option<ClientConfiguration>,
66109
fix_all: Option<bool>,
67110
organize_imports: Option<bool>,
68111
lint: Option<LintOptions>,
@@ -306,11 +349,15 @@ impl ResolvedClientSettings {
306349
),
307350
editor_settings: ResolvedEditorSettings {
308351
configuration: Self::resolve_optional(all_settings, |settings| {
309-
settings
310-
.configuration
311-
.as_ref()
312-
.and_then(|config_path| shellexpand::full(config_path).ok())
313-
.map(|config_path| PathBuf::from(config_path.as_ref()))
352+
settings.configuration.as_ref().and_then(|configuration| {
353+
match ResolvedConfiguration::try_from(configuration) {
354+
Ok(configuration) => Some(configuration),
355+
Err(err) => {
356+
tracing::error!("Failed to resolve configuration: {err}");
357+
None
358+
}
359+
}
360+
})
314361
}),
315362
lint_preview: Self::resolve_optional(all_settings, |settings| {
316363
settings.lint.as_ref()?.preview

0 commit comments

Comments
 (0)