Introduce FormatterSettings (#7545)

This commit is contained in:
Micha Reiser 2023-09-21 08:01:24 +02:00 committed by GitHub
parent 87a0cd219f
commit f8f1cd5016
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 159 additions and 75 deletions

6
Cargo.lock generated
View file

@ -2178,6 +2178,8 @@ version = "0.0.0"
dependencies = [
"drop_bomb",
"insta",
"ruff_cache",
"ruff_macros",
"ruff_text_size",
"rustc-hash",
"schemars",
@ -2336,7 +2338,9 @@ dependencies = [
"itertools 0.11.0",
"memchr",
"once_cell",
"ruff_cache",
"ruff_formatter",
"ruff_macros",
"ruff_python_ast",
"ruff_python_index",
"ruff_python_parser",
@ -2528,8 +2532,10 @@ dependencies = [
"pep440_rs",
"regex",
"ruff_cache",
"ruff_formatter",
"ruff_linter",
"ruff_macros",
"ruff_python_formatter",
"rustc-hash",
"schemars",
"serde",

View file

@ -1,7 +1,10 @@
use std::borrow::Cow;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::num::NonZeroU8;
use std::num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU128, NonZeroU16,
NonZeroU32, NonZeroU64, NonZeroU8,
};
use std::path::{Path, PathBuf};
use glob::Pattern;
@ -177,13 +180,28 @@ impl CacheKey for i8 {
state.write_i8(*self);
}
}
impl CacheKey for NonZeroU8 {
macro_rules! impl_cache_key_non_zero {
($name:ident) => {
impl CacheKey for $name {
#[inline]
fn cache_key(&self, state: &mut CacheKeyHasher) {
state.write_u8(self.get());
self.get().cache_key(state)
}
}
};
}
impl_cache_key_non_zero!(NonZeroU8);
impl_cache_key_non_zero!(NonZeroU16);
impl_cache_key_non_zero!(NonZeroU32);
impl_cache_key_non_zero!(NonZeroU64);
impl_cache_key_non_zero!(NonZeroU128);
impl_cache_key_non_zero!(NonZeroI8);
impl_cache_key_non_zero!(NonZeroI16);
impl_cache_key_non_zero!(NonZeroI32);
impl_cache_key_non_zero!(NonZeroI64);
impl_cache_key_non_zero!(NonZeroI128);
macro_rules! impl_cache_key_tuple {
() => (

View file

@ -1,6 +1,5 @@
use std::fmt::{Display, Formatter};
use std::io;
use std::num::NonZeroU16;
use std::path::{Path, PathBuf};
use std::time::Instant;
@ -10,12 +9,10 @@ use log::error;
use rayon::iter::Either::{Left, Right};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use thiserror::Error;
use tracing::{debug, warn};
use tracing::debug;
use ruff_formatter::LineWidth;
use ruff_linter::fs;
use ruff_linter::logging::LogLevel;
use ruff_linter::settings::types::PreviewMode;
use ruff_linter::warn_user_once;
use ruff_python_ast::{PySourceType, SourceType};
use ruff_python_formatter::{format_module, FormatModuleError, PyFormatOptions};
@ -76,17 +73,7 @@ pub(crate) fn format(
};
let resolved_settings = resolver.resolve(path, &pyproject_config);
// TODO(micha): Use `formatter` settings instead
let preview = match resolved_settings.linter.preview {
PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled,
PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled,
};
let line_length = resolved_settings.linter.line_length;
let options = PyFormatOptions::from_source_type(source_type)
.with_line_width(LineWidth::from(NonZeroU16::from(line_length)))
.with_preview(preview);
let options = resolved_settings.formatter.to_format_options(source_type);
debug!("Formatting {} with {:?}", path.display(), options);
Some(match catch_unwind(|| format_path(path, options, mode)) {

View file

@ -1,12 +1,10 @@
use std::io::{stdout, Write};
use std::num::NonZeroU16;
use std::path::Path;
use anyhow::Result;
use log::warn;
use ruff_formatter::LineWidth;
use ruff_linter::settings::types::PreviewMode;
use ruff_python_ast::PySourceType;
use ruff_python_formatter::{format_module, PyFormatOptions};
use ruff_workspace::resolver::python_file_at_path;
@ -39,18 +37,10 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
// Format the file.
let path = cli.stdin_filename.as_deref();
// TODO(micha): Use Formatter settings
let preview = match pyproject_config.settings.linter.preview {
PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled,
PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled,
};
let line_length = pyproject_config.settings.linter.line_length;
let options = path
.map(PyFormatOptions::from_extension)
.unwrap_or_default()
.with_line_width(LineWidth::from(NonZeroU16::from(line_length)))
.with_preview(preview);
let options = pyproject_config
.settings
.formatter
.to_format_options(path.map(PySourceType::from).unwrap_or_default());
match format_source(path, options, mode) {
Ok(result) => match mode {

View file

@ -18,7 +18,6 @@ use imara_diff::{diff, Algorithm};
use indicatif::ProgressStyle;
#[cfg_attr(feature = "singlethreaded", allow(unused_imports))]
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use ruff_linter::line_width::LineLength;
use serde::Deserialize;
use similar::{ChangeTag, TextDiff};
use tempfile::NamedTempFile;
@ -551,10 +550,8 @@ fn format_dir_entry(
let settings = resolver.resolve(&path, pyproject_config);
// That's a bad way of doing this but it's not worth doing something better for format_dev
// TODO(micha) use formatter settings instead
if settings.linter.line_length != LineLength::default() {
options = options.with_line_width(LineWidth::from(NonZeroU16::from(
settings.linter.line_length,
)));
if settings.formatter.line_width != LineWidth::default() {
options = options.with_line_width(settings.formatter.line_width);
}
// Handle panics (mostly in `debug_assert!`)

View file

@ -11,6 +11,8 @@ repository = { workspace = true }
license = { workspace = true }
[dependencies]
ruff_cache = { path = "../ruff_cache" }
ruff_macros = { path = "../ruff_macros" }
ruff_text_size = { path = "../ruff_text_size" }
drop_bomb = { version = "0.1.5" }

View file

@ -51,9 +51,10 @@ pub use source_code::{SourceCode, SourceCodeSlice};
pub use crate::diagnostics::{ActualStart, FormatError, InvalidDocumentError, PrintError};
pub use format_element::{normalize_newlines, FormatElement, LINE_TERMINATORS};
pub use group_id::GroupId;
use ruff_macros::CacheKey;
use ruff_text_size::{TextRange, TextSize};
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, CacheKey)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Default)]
@ -116,8 +117,14 @@ impl TryFrom<u8> for IndentWidth {
}
}
impl From<NonZeroU8> for IndentWidth {
fn from(value: NonZeroU8) -> Self {
Self(value)
}
}
/// The maximum visual width to which the formatter should try to limit a line.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, CacheKey)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct LineWidth(NonZeroU16);

View file

@ -1,4 +1,5 @@
use crate::{FormatOptions, IndentStyle, IndentWidth, LineWidth};
use ruff_macros::CacheKey;
/// Options that affect how the [`crate::Printer`] prints the format tokens
#[derive(Clone, Debug, Eq, PartialEq, Default)]
@ -120,7 +121,7 @@ impl SourceMapGeneration {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, CacheKey)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LineEnding {
/// Line Feed only (\n), common on Linux and macOS as well as inside git repos

View file

@ -11,7 +11,9 @@ repository = { workspace = true }
license = { workspace = true }
[dependencies]
ruff_cache = { path = "../ruff_cache" }
ruff_formatter = { path = "../ruff_formatter" }
ruff_macros = { path = "../ruff_macros" }
ruff_python_trivia = { path = "../ruff_python_trivia" }
ruff_source_file = { path = "../ruff_source_file" }
ruff_python_ast = { path = "../ruff_python_ast" }

View file

@ -17,6 +17,7 @@ use crate::comments::{
pub use crate::context::PyFormatContext;
pub use crate::options::{MagicTrailingComma, PreviewMode, PyFormatOptions, QuoteStyle};
use crate::verbatim::suppressed_node;
pub use settings::FormatterSettings;
pub(crate) mod builders;
pub mod cli;
@ -29,6 +30,7 @@ mod options;
pub(crate) mod other;
pub(crate) mod pattern;
mod prelude;
mod settings;
pub(crate) mod statement;
pub(crate) mod type_param;
mod verbatim;

View file

@ -1,9 +1,12 @@
use ruff_formatter::printer::{LineEnding, PrinterOptions, SourceMapGeneration};
use ruff_formatter::{FormatOptions, IndentStyle, IndentWidth, LineWidth};
use ruff_macros::CacheKey;
use ruff_python_ast::PySourceType;
use std::path::Path;
use std::str::FromStr;
/// Resolved options for formatting one individual file. This is different from [`crate::FormatterSettings`] which
/// represents the formatting settings for multiple files (the whole project, a subdirectory, ...)
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "serde",
@ -176,7 +179,7 @@ impl FormatOptions for PyFormatOptions {
}
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, CacheKey)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
@ -230,7 +233,7 @@ impl FromStr for QuoteStyle {
}
}
#[derive(Copy, Clone, Debug, Default)]
#[derive(Copy, Clone, Debug, Default, CacheKey)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
@ -261,7 +264,7 @@ impl FromStr for MagicTrailingComma {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, CacheKey)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
pub enum PreviewMode {

View file

@ -0,0 +1,49 @@
use std::path::PathBuf;
use ruff_formatter::{FormatOptions, IndentStyle, LineWidth};
use ruff_macros::CacheKey;
use ruff_python_ast::PySourceType;
use crate::{MagicTrailingComma, PreviewMode, PyFormatOptions, QuoteStyle};
#[derive(CacheKey, Clone, Debug)]
pub struct FormatterSettings {
/// The files that are excluded from formatting (but may be linted).
pub exclude: Vec<PathBuf>,
pub preview: PreviewMode,
pub line_width: LineWidth,
pub indent_style: IndentStyle,
pub quote_style: QuoteStyle,
pub magic_trailing_comma: MagicTrailingComma,
}
impl FormatterSettings {
pub fn to_format_options(&self, source_type: PySourceType) -> PyFormatOptions {
PyFormatOptions::from_source_type(source_type)
.with_indent_style(self.indent_style)
.with_quote_style(self.quote_style)
.with_magic_trailing_comma(self.magic_trailing_comma)
.with_preview(self.preview)
.with_line_width(self.line_width)
}
}
impl Default for FormatterSettings {
fn default() -> Self {
let default_options = PyFormatOptions::default();
Self {
exclude: Vec::default(),
preview: PreviewMode::Disabled,
line_width: default_options.line_width(),
indent_style: default_options.indent_style(),
quote_style: default_options.quote_style(),
magic_trailing_comma: default_options.magic_trailing_comma(),
}
}
}

View file

@ -1,21 +1,20 @@
use std::num::NonZeroU16;
use std::path::Path;
use js_sys::Error;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;
use ruff_formatter::{FormatResult, Formatted, LineWidth};
use ruff_formatter::{FormatResult, Formatted};
use ruff_linter::directives;
use ruff_linter::line_width::{LineLength, TabSize};
use ruff_linter::linter::{check_path, LinterResult};
use ruff_linter::registry::AsRule;
use ruff_linter::settings::types::{PreviewMode, PythonVersion};
use ruff_linter::settings::types::PythonVersion;
use ruff_linter::settings::{flags, DUMMY_VARIABLE_RGX, PREFIXES};
use ruff_linter::source_kind::SourceKind;
use ruff_python_ast::{Mod, PySourceType};
use ruff_python_codegen::Stylist;
use ruff_python_formatter::{format_node, pretty_comments, PyFormatContext, PyFormatOptions};
use ruff_python_formatter::{format_node, pretty_comments, PyFormatContext};
use ruff_python_index::{CommentRangesBuilder, Indexer};
use ruff_python_parser::lexer::LexResult;
use ruff_python_parser::{parse_tokens, AsMode, Mode};
@ -302,15 +301,9 @@ impl<'a> ParsedModule<'a> {
fn format(&self, settings: &Settings) -> FormatResult<Formatted<PyFormatContext>> {
// TODO(konstin): Add an options for py/pyi to the UI (2/2)
// TODO(micha): Use formatter settings instead
let options = PyFormatOptions::from_source_type(PySourceType::default())
.with_preview(match settings.linter.preview {
PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled,
PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled,
})
.with_line_width(LineWidth::from(NonZeroU16::from(
settings.linter.line_length,
)));
let options = settings
.formatter
.to_format_options(PySourceType::default());
format_node(
&self.module,

View file

@ -14,6 +14,8 @@ license = { workspace = true }
[dependencies]
ruff_linter = { path = "../ruff_linter" }
ruff_formatter = { path = "../ruff_formatter" }
ruff_python_formatter = { path = "../ruff_python_formatter" }
ruff_cache = { path = "../ruff_cache" }
ruff_macros = { path = "../ruff_macros" }

View file

@ -4,21 +4,19 @@
use std::borrow::Cow;
use std::env::VarError;
use std::num::NonZeroU16;
use std::path::{Path, PathBuf};
use crate::options::{
Flake8AnnotationsOptions, Flake8BanditOptions, Flake8BugbearOptions, Flake8BuiltinsOptions,
Flake8ComprehensionsOptions, Flake8CopyrightOptions, Flake8ErrMsgOptions, Flake8GetTextOptions,
Flake8ImplicitStrConcatOptions, Flake8ImportConventionsOptions, Flake8PytestStyleOptions,
Flake8QuotesOptions, Flake8SelfOptions, Flake8TidyImportsOptions, Flake8TypeCheckingOptions,
Flake8UnusedArgumentsOptions, IsortOptions, McCabeOptions, Options, Pep8NamingOptions,
PyUpgradeOptions, PycodestyleOptions, PydocstyleOptions, PyflakesOptions, PylintOptions,
};
use crate::settings::{FileResolverSettings, Settings, EXCLUDE, INCLUDE};
use anyhow::{anyhow, Result};
use glob::{glob, GlobError, Paths, PatternError};
use regex::Regex;
use rustc_hash::{FxHashMap, FxHashSet};
use shellexpand;
use shellexpand::LookupError;
use strum::IntoEnumIterator;
use ruff_cache::cache_dir;
use ruff_formatter::{IndentStyle, LineWidth};
use ruff_linter::line_width::{LineLength, TabSize};
use ruff_linter::registry::RuleNamespace;
use ruff_linter::registry::{Rule, RuleSet, INCOMPATIBLE_CODES};
@ -34,10 +32,17 @@ use ruff_linter::settings::{
use ruff_linter::{
fs, warn_user, warn_user_once, warn_user_once_by_id, RuleSelector, RUFF_PKG_VERSION,
};
use rustc_hash::{FxHashMap, FxHashSet};
use shellexpand;
use shellexpand::LookupError;
use strum::IntoEnumIterator;
use ruff_python_formatter::{FormatterSettings, MagicTrailingComma, QuoteStyle};
use crate::options::{
Flake8AnnotationsOptions, Flake8BanditOptions, Flake8BugbearOptions, Flake8BuiltinsOptions,
Flake8ComprehensionsOptions, Flake8CopyrightOptions, Flake8ErrMsgOptions, Flake8GetTextOptions,
Flake8ImplicitStrConcatOptions, Flake8ImportConventionsOptions, Flake8PytestStyleOptions,
Flake8QuotesOptions, Flake8SelfOptions, Flake8TidyImportsOptions, Flake8TypeCheckingOptions,
Flake8UnusedArgumentsOptions, IsortOptions, McCabeOptions, Options, Pep8NamingOptions,
PyUpgradeOptions, PycodestyleOptions, PydocstyleOptions, PyflakesOptions, PylintOptions,
};
use crate::settings::{FileResolverSettings, Settings, EXCLUDE, INCLUDE};
#[derive(Debug, Default)]
pub struct RuleSelection {
@ -149,6 +154,7 @@ impl Configuration {
respect_gitignore: self.respect_gitignore.unwrap_or(true),
project_root: project_root.to_path_buf(),
},
linter: LinterSettings {
target_version,
project_root: project_root.to_path_buf(),
@ -283,6 +289,21 @@ impl Configuration {
.map(PyUpgradeOptions::into_settings)
.unwrap_or_default(),
},
formatter: FormatterSettings {
exclude: vec![],
preview: self
.preview
.map(|preview| match preview {
PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled,
PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled,
})
.unwrap_or_default(),
line_width: LineWidth::from(NonZeroU16::from(self.line_length.unwrap_or_default())),
indent_style: IndentStyle::default(),
quote_style: QuoteStyle::default(),
magic_trailing_comma: MagicTrailingComma::default(),
},
})
}
@ -805,12 +826,13 @@ pub fn resolve_src(src: &[String], project_root: &Path) -> Result<Vec<PathBuf>>
#[cfg(test)]
mod tests {
use crate::configuration::{Configuration, RuleSelection};
use ruff_linter::codes::{Flake8Copyright, Pycodestyle, Refurb};
use ruff_linter::registry::{Linter, Rule, RuleSet};
use ruff_linter::settings::types::PreviewMode;
use ruff_linter::RuleSelector;
use crate::configuration::{Configuration, RuleSelection};
const NURSERY_RULES: &[Rule] = &[
Rule::MissingCopyrightNotice,
Rule::IndentationWithInvalidMultiple,

View file

@ -3,6 +3,7 @@ use ruff_cache::cache_dir;
use ruff_linter::settings::types::{FilePattern, FilePatternSet, SerializationFormat};
use ruff_linter::settings::LinterSettings;
use ruff_macros::CacheKey;
use ruff_python_formatter::FormatterSettings;
use std::path::{Path, PathBuf};
#[derive(Debug, CacheKey)]
@ -23,6 +24,7 @@ pub struct Settings {
pub file_resolver: FileResolverSettings,
pub linter: LinterSettings,
pub formatter: FormatterSettings,
}
impl Default for Settings {
@ -37,6 +39,7 @@ impl Default for Settings {
show_source: false,
linter: LinterSettings::new(project_root),
file_resolver: FileResolverSettings::new(project_root),
formatter: FormatterSettings::default(),
}
}
}