--show-settings displays active settings in a far more readable format (#9464)

<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

Fixes #8334.

`Display` has been implemented for `ruff_workspace::Settings`, which
gives a much nicer and more readable output to `--show-settings`.

Internally, a `display_settings` utility macro has been implemented to
reduce the boilerplate of the display code.

### Work to be done

- [x] A lot of formatting for `Vec<_>` and `HashSet<_>` types have been
stubbed out, using `Debug` as a fallback. There should be a way to add
generic formatting support for these types as a modifier in
`display_settings`.
- [x] Several complex types were also stubbed out and need proper
`Display` implementations rather than falling back on `Debug`.
- [x] An open question needs to be answered: how important is it that
the output be valid TOML? Some types in settings, such as a hash-map
from a glob pattern to a multi-variant enum, will be hard to rework into
valid _and_ readable TOML.
- [x] Tests need to be implemented.

## Test Plan

Tests consist of a snapshot test for the default `--show-settings`
output and a doctest for `display_settings!`.
This commit is contained in:
Jane Lewis 2024-01-12 11:30:29 -08:00 committed by GitHub
parent fee64b52ba
commit 7504bf347b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 1455 additions and 43 deletions

View file

@ -25,12 +25,10 @@ use ruff_linter::rule_selector::{PreviewOptions, Specificity};
use ruff_linter::rules::pycodestyle;
use ruff_linter::settings::rule_table::RuleTable;
use ruff_linter::settings::types::{
ExtensionMapping, FilePattern, FilePatternSet, PerFileIgnore, PreviewMode, PythonVersion,
SerializationFormat, UnsafeFixes, Version,
};
use ruff_linter::settings::{
resolve_per_file_ignores, LinterSettings, DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX, TASK_TAGS,
ExtensionMapping, FilePattern, FilePatternSet, PerFileIgnore, PerFileIgnores, PreviewMode,
PythonVersion, SerializationFormat, UnsafeFixes, Version,
};
use ruff_linter::settings::{LinterSettings, DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX, TASK_TAGS};
use ruff_linter::{
fs, warn_user, warn_user_once, warn_user_once_by_id, RuleSelector, RUFF_PKG_VERSION,
};
@ -260,7 +258,7 @@ impl Configuration {
line_length,
tab_size: self.indent_width.unwrap_or_default(),
namespace_packages: self.namespace_packages.unwrap_or_default(),
per_file_ignores: resolve_per_file_ignores(
per_file_ignores: PerFileIgnores::resolve(
lint.per_file_ignores
.unwrap_or_default()
.into_iter()

View file

@ -1,6 +1,7 @@
use path_absolutize::path_dedot;
use ruff_cache::cache_dir;
use ruff_formatter::{FormatOptions, IndentStyle, IndentWidth, LineWidth};
use ruff_linter::display_settings;
use ruff_linter::settings::types::{
ExtensionMapping, FilePattern, FilePatternSet, SerializationFormat, UnsafeFixes,
};
@ -12,6 +13,7 @@ use ruff_python_formatter::{
QuoteStyle,
};
use ruff_source_file::find_newline;
use std::fmt;
use std::path::{Path, PathBuf};
#[derive(Debug, CacheKey)]
@ -55,6 +57,30 @@ impl Default for Settings {
}
}
impl fmt::Display for Settings {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "\n# General Settings")?;
display_settings! {
formatter = f,
fields = [
// We want the quotes and lossy UTF8 conversion for this path, so
// using PathBuf's `Debug` formatter suffices.
self.cache_dir | debug,
self.fix,
self.fix_only,
self.output_format,
self.show_fixes,
self.show_source,
self.unsafe_fixes,
self.file_resolver | nested,
self.linter | nested,
self.formatter | nested
]
}
Ok(())
}
}
#[derive(Debug, CacheKey)]
pub struct FileResolverSettings {
pub exclude: FilePatternSet,
@ -66,6 +92,26 @@ pub struct FileResolverSettings {
pub project_root: PathBuf,
}
impl fmt::Display for FileResolverSettings {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "\n# File Resolver Settings")?;
display_settings! {
formatter = f,
namespace = "file_resolver",
fields = [
self.exclude,
self.extend_exclude,
self.force_exclude,
self.include,
self.extend_include,
self.respect_gitignore,
self.project_root | debug,
]
}
Ok(())
}
}
pub(crate) static EXCLUDE: &[FilePattern] = &[
FilePattern::Builtin(".bzr"),
FilePattern::Builtin(".direnv"),
@ -195,6 +241,30 @@ impl Default for FormatterSettings {
}
}
impl fmt::Display for FormatterSettings {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "\n# Formatter Settings")?;
display_settings! {
formatter = f,
namespace = "formatter",
fields = [
self.exclude,
self.target_version | debug,
self.preview,
self.line_width,
self.line_ending,
self.indent_style,
self.indent_width,
self.quote_style,
self.magic_trailing_comma,
self.docstring_code_format,
self.docstring_code_line_width,
]
}
Ok(())
}
}
#[derive(
Copy, Clone, Debug, Eq, PartialEq, Default, CacheKey, serde::Serialize, serde::Deserialize,
)]
@ -216,3 +286,14 @@ pub enum LineEnding {
/// Line endings will be converted to `\n` on Unix and `\r\n` on Windows.
Native,
}
impl fmt::Display for LineEnding {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Auto => write!(f, "auto"),
Self::Lf => write!(f, "lf"),
Self::CrLf => write!(f, "crlf"),
Self::Native => write!(f, "native"),
}
}
}