mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:22:24 +00:00
Add most formatter options to ruff.toml
/ pyproject.toml
(#7566)
This commit is contained in:
parent
82978ac9b5
commit
9d16e46129
24 changed files with 734 additions and 145 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -2336,6 +2336,7 @@ dependencies = [
|
|||
"ruff_source_file",
|
||||
"ruff_text_size",
|
||||
"rustc-hash",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"similar",
|
||||
|
@ -2523,7 +2524,9 @@ dependencies = [
|
|||
"ruff_formatter",
|
||||
"ruff_linter",
|
||||
"ruff_macros",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_formatter",
|
||||
"ruff_source_file",
|
||||
"rustc-hash",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
|
|
@ -15,9 +15,9 @@ use ruff_linter::fs;
|
|||
use ruff_linter::logging::LogLevel;
|
||||
use ruff_linter::warn_user_once;
|
||||
use ruff_python_ast::{PySourceType, SourceType};
|
||||
use ruff_python_formatter::{format_module, FormatModuleError, PyFormatOptions};
|
||||
use ruff_source_file::{find_newline, LineEnding};
|
||||
use ruff_python_formatter::{format_module, FormatModuleError};
|
||||
use ruff_workspace::resolver::python_files_in_path;
|
||||
use ruff_workspace::FormatterSettings;
|
||||
|
||||
use crate::args::{CliOverrides, FormatArguments};
|
||||
use crate::panic::{catch_unwind, PanicError};
|
||||
|
@ -73,15 +73,17 @@ pub(crate) fn format(
|
|||
};
|
||||
|
||||
let resolved_settings = resolver.resolve(path, &pyproject_config);
|
||||
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)) {
|
||||
Ok(inner) => inner,
|
||||
Err(error) => {
|
||||
Err(FormatCommandError::Panic(Some(path.to_path_buf()), error))
|
||||
}
|
||||
})
|
||||
Some(
|
||||
match catch_unwind(|| {
|
||||
format_path(path, &resolved_settings.formatter, source_type, mode)
|
||||
}) {
|
||||
Ok(inner) => inner,
|
||||
Err(error) => {
|
||||
Err(FormatCommandError::Panic(Some(path.to_path_buf()), error))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
Err(err) => Some(Err(FormatCommandError::Ignore(err))),
|
||||
}
|
||||
|
@ -139,19 +141,15 @@ pub(crate) fn format(
|
|||
#[tracing::instrument(skip_all, fields(path = %path.display()))]
|
||||
fn format_path(
|
||||
path: &Path,
|
||||
options: PyFormatOptions,
|
||||
settings: &FormatterSettings,
|
||||
source_type: PySourceType,
|
||||
mode: FormatMode,
|
||||
) -> Result<FormatCommandResult, FormatCommandError> {
|
||||
let unformatted = std::fs::read_to_string(path)
|
||||
.map_err(|err| FormatCommandError::Read(Some(path.to_path_buf()), err))?;
|
||||
|
||||
let line_ending = match find_newline(&unformatted) {
|
||||
Some((_, LineEnding::Lf)) | None => ruff_formatter::printer::LineEnding::LineFeed,
|
||||
Some((_, LineEnding::Cr)) => ruff_formatter::printer::LineEnding::CarriageReturn,
|
||||
Some((_, LineEnding::CrLf)) => ruff_formatter::printer::LineEnding::CarriageReturnLineFeed,
|
||||
};
|
||||
|
||||
let options = options.with_line_ending(line_ending);
|
||||
let options = settings.to_format_options(source_type, &unformatted);
|
||||
debug!("Formatting {} with {:?}", path.display(), options);
|
||||
|
||||
let formatted = format_module(&unformatted, options)
|
||||
.map_err(|err| FormatCommandError::FormatModule(Some(path.to_path_buf()), err))?;
|
||||
|
|
|
@ -5,8 +5,9 @@ use anyhow::Result;
|
|||
use log::warn;
|
||||
|
||||
use ruff_python_ast::PySourceType;
|
||||
use ruff_python_formatter::{format_module, PyFormatOptions};
|
||||
use ruff_python_formatter::format_module;
|
||||
use ruff_workspace::resolver::python_file_at_path;
|
||||
use ruff_workspace::FormatterSettings;
|
||||
|
||||
use crate::args::{CliOverrides, FormatArguments};
|
||||
use crate::commands::format::{FormatCommandError, FormatCommandResult, FormatMode};
|
||||
|
@ -37,12 +38,7 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
|||
// Format the file.
|
||||
let path = cli.stdin_filename.as_deref();
|
||||
|
||||
let options = pyproject_config
|
||||
.settings
|
||||
.formatter
|
||||
.to_format_options(path.map(PySourceType::from).unwrap_or_default());
|
||||
|
||||
match format_source(path, options, mode) {
|
||||
match format_source(path, &pyproject_config.settings.formatter, mode) {
|
||||
Ok(result) => match mode {
|
||||
FormatMode::Write => Ok(ExitStatus::Success),
|
||||
FormatMode::Check => {
|
||||
|
@ -63,11 +59,17 @@ pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> R
|
|||
/// Format source code read from `stdin`.
|
||||
fn format_source(
|
||||
path: Option<&Path>,
|
||||
options: PyFormatOptions,
|
||||
settings: &FormatterSettings,
|
||||
mode: FormatMode,
|
||||
) -> Result<FormatCommandResult, FormatCommandError> {
|
||||
let unformatted = read_from_stdin()
|
||||
.map_err(|err| FormatCommandError::Read(path.map(Path::to_path_buf), err))?;
|
||||
|
||||
let options = settings.to_format_options(
|
||||
path.map(PySourceType::from).unwrap_or_default(),
|
||||
&unformatted,
|
||||
);
|
||||
|
||||
let formatted = format_module(&unformatted, options)
|
||||
.map_err(|err| FormatCommandError::FormatModule(path.map(Path::to_path_buf), err))?;
|
||||
let formatted = formatted.as_code();
|
||||
|
|
207
crates/ruff_cli/tests/format.rs
Normal file
207
crates/ruff_cli/tests/format.rs
Normal file
|
@ -0,0 +1,207 @@
|
|||
#![cfg(not(target_family = "wasm"))]
|
||||
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use std::str;
|
||||
|
||||
use anyhow::Result;
|
||||
use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
|
||||
use tempfile::TempDir;
|
||||
|
||||
const BIN_NAME: &str = "ruff";
|
||||
|
||||
#[test]
|
||||
fn default_options() {
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["format", "--isolated"])
|
||||
.arg("-")
|
||||
.pass_stdin(r#"
|
||||
def foo(arg1, arg2,):
|
||||
print('Should\'t change quotes')
|
||||
|
||||
|
||||
if condition:
|
||||
|
||||
print('Hy "Micha"') # Should not change quotes
|
||||
|
||||
"#), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
def foo(
|
||||
arg1,
|
||||
arg2,
|
||||
):
|
||||
print("Should't change quotes")
|
||||
|
||||
|
||||
if condition:
|
||||
print('Hy "Micha"') # Should not change quotes
|
||||
|
||||
----- stderr -----
|
||||
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended only for experimentation.
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_options() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||
fs::write(
|
||||
&ruff_toml,
|
||||
r#"
|
||||
[format]
|
||||
indent-style = "tab"
|
||||
quote-style = "single"
|
||||
skip-magic-trailing-comma = true
|
||||
line-ending = "cr-lf"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["format", "--config"])
|
||||
.arg(&ruff_toml)
|
||||
.arg("-")
|
||||
.pass_stdin(r#"
|
||||
def foo(arg1, arg2,):
|
||||
print("Shouldn't change quotes")
|
||||
|
||||
|
||||
if condition:
|
||||
|
||||
print("Should change quotes")
|
||||
|
||||
"#), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
def foo(arg1, arg2):
|
||||
print("Shouldn't change quotes")
|
||||
|
||||
|
||||
if condition:
|
||||
print('Should change quotes')
|
||||
|
||||
----- stderr -----
|
||||
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended only for experimentation.
|
||||
"###);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_option_inheritance() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||
let base_toml = tempdir.path().join("base.toml");
|
||||
fs::write(
|
||||
&ruff_toml,
|
||||
r#"
|
||||
extend = "base.toml"
|
||||
|
||||
[format]
|
||||
quote-style = "single"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
fs::write(
|
||||
base_toml,
|
||||
r#"
|
||||
[format]
|
||||
indent-style = "tab"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["format", "--config"])
|
||||
.arg(&ruff_toml)
|
||||
.arg("-")
|
||||
.pass_stdin(r#"
|
||||
def foo(arg1, arg2,):
|
||||
print("Shouldn't change quotes")
|
||||
|
||||
|
||||
if condition:
|
||||
|
||||
print("Should change quotes")
|
||||
|
||||
"#), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
def foo(
|
||||
arg1,
|
||||
arg2,
|
||||
):
|
||||
print("Shouldn't change quotes")
|
||||
|
||||
|
||||
if condition:
|
||||
print('Should change quotes')
|
||||
|
||||
----- stderr -----
|
||||
warning: `ruff format` is a work-in-progress, subject to change at any time, and intended only for experimentation.
|
||||
"###);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tests that the legacy `format` option continues to work but emits a warning.
|
||||
#[test]
|
||||
fn legacy_format_option() -> Result<()> {
|
||||
let tempdir = TempDir::new()?;
|
||||
let ruff_toml = tempdir.path().join("ruff.toml");
|
||||
fs::write(
|
||||
&ruff_toml,
|
||||
r#"
|
||||
format = "json"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
|
||||
.args(["check", "--select", "F401", "--no-cache", "--config"])
|
||||
.arg(&ruff_toml)
|
||||
.arg("-")
|
||||
.pass_stdin(r#"
|
||||
import os
|
||||
"#), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
[
|
||||
{
|
||||
"code": "F401",
|
||||
"end_location": {
|
||||
"column": 10,
|
||||
"row": 2
|
||||
},
|
||||
"filename": "-",
|
||||
"fix": {
|
||||
"applicability": "Automatic",
|
||||
"edits": [
|
||||
{
|
||||
"content": "",
|
||||
"end_location": {
|
||||
"column": 1,
|
||||
"row": 3
|
||||
},
|
||||
"location": {
|
||||
"column": 1,
|
||||
"row": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"message": "Remove unused import: `os`"
|
||||
},
|
||||
"location": {
|
||||
"column": 8,
|
||||
"row": 2
|
||||
},
|
||||
"message": "`os` imported but unused",
|
||||
"noqa_row": 2,
|
||||
"url": "https://docs.astral.sh/ruff/rules/unused-import"
|
||||
}
|
||||
]
|
||||
----- stderr -----
|
||||
warning: The option `format` has been deprecated to avoid ambiguity with Ruff's upcoming formatter. Use `output-format` instead.
|
||||
"###);
|
||||
Ok(())
|
||||
}
|
|
@ -549,7 +549,6 @@ 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.formatter.line_width != LineWidth::default() {
|
||||
options = options.with_line_width(settings.formatter.line_width);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,11 @@ use ruff_macros::CacheKey;
|
|||
use ruff_text_size::{TextRange, TextSize};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, CacheKey)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
derive(serde::Serialize, serde::Deserialize),
|
||||
serde(rename_all = "kebab-case")
|
||||
)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[derive(Default)]
|
||||
pub enum IndentStyle {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
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)]
|
||||
|
@ -121,7 +120,7 @@ impl SourceMapGeneration {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, CacheKey)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||
#[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
|
||||
|
|
|
@ -30,6 +30,7 @@ memchr = { workspace = true }
|
|||
once_cell = { workspace = true }
|
||||
rustc-hash = { workspace = true }
|
||||
serde = { workspace = true, optional = true }
|
||||
schemars = { workspace = true, optional = true }
|
||||
smallvec = { workspace = true }
|
||||
static_assertions = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
@ -52,4 +53,5 @@ required-features = ["serde"]
|
|||
|
||||
[features]
|
||||
serde = ["dep:serde", "ruff_formatter/serde", "ruff_source_file/serde", "ruff_python_ast/serde"]
|
||||
default = ["serde"]
|
||||
schemars = ["dep:schemars", "ruff_formatter/schemars"]
|
||||
default = []
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
[
|
||||
{
|
||||
"indent_style": "Space",
|
||||
"indent_style": "space",
|
||||
"indent_width": 4
|
||||
},
|
||||
{
|
||||
"indent_style": "Space",
|
||||
"indent_style": "space",
|
||||
"indent_width": 2
|
||||
},
|
||||
{
|
||||
"indent_style": "Tab",
|
||||
"indent_style": "tab",
|
||||
"indent_width": 8
|
||||
},
|
||||
{
|
||||
"indent_style": "Tab",
|
||||
"indent_style": "tab",
|
||||
"indent_width": 4
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
[
|
||||
{
|
||||
"indent_style": "Space",
|
||||
"indent_style": "space",
|
||||
"indent_width": 4
|
||||
},
|
||||
{
|
||||
"indent_style": "Space",
|
||||
"indent_style": "space",
|
||||
"indent_width": 2
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
[
|
||||
{
|
||||
"indent_style": "Space",
|
||||
"indent_style": "space",
|
||||
"indent_width": 4
|
||||
},
|
||||
{
|
||||
"indent_style": "Space",
|
||||
"indent_style": "space",
|
||||
"indent_width": 1
|
||||
},
|
||||
{
|
||||
"indent_style": "Tab"
|
||||
"indent_style": "tab"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
[
|
||||
{
|
||||
"indent_style": "Space",
|
||||
"indent_style": "space",
|
||||
"indent_width": 4
|
||||
},
|
||||
{
|
||||
"indent_style": "Space",
|
||||
"indent_style": "space",
|
||||
"indent_width": 2
|
||||
},
|
||||
{
|
||||
"indent_style": "Tab"
|
||||
"indent_style": "tab"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -17,7 +17,6 @@ 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;
|
||||
|
@ -30,7 +29,6 @@ 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;
|
||||
|
|
|
@ -5,8 +5,8 @@ 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, ...)
|
||||
/// Resolved options for formatting one individual file. The difference to `FormatterSettings`
|
||||
/// is that `FormatterSettings` stores the settings for multiple files (the entire project, a subdirectory, ..)
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
|
@ -185,6 +185,7 @@ impl FormatOptions for PyFormatOptions {
|
|||
derive(serde::Serialize, serde::Deserialize),
|
||||
serde(rename_all = "kebab-case")
|
||||
)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum QuoteStyle {
|
||||
Single,
|
||||
#[default]
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
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(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -303,7 +303,7 @@ impl<'a> ParsedModule<'a> {
|
|||
// TODO(konstin): Add an options for py/pyi to the UI (2/2)
|
||||
let options = settings
|
||||
.formatter
|
||||
.to_format_options(PySourceType::default());
|
||||
.to_format_options(PySourceType::default(), self.source_code);
|
||||
|
||||
format_node(
|
||||
&self.module,
|
||||
|
|
|
@ -15,7 +15,9 @@ license = { workspace = true }
|
|||
[dependencies]
|
||||
ruff_linter = { path = "../ruff_linter" }
|
||||
ruff_formatter = { path = "../ruff_formatter" }
|
||||
ruff_python_formatter = { path = "../ruff_python_formatter" }
|
||||
ruff_python_formatter = { path = "../ruff_python_formatter", features = ["serde"] }
|
||||
ruff_python_ast = { path = "../ruff_python_ast" }
|
||||
ruff_source_file = { path = "../ruff_source_file" }
|
||||
ruff_cache = { path = "../ruff_cache" }
|
||||
ruff_macros = { path = "../ruff_macros" }
|
||||
|
||||
|
@ -43,4 +45,6 @@ tempfile = "3.6.0"
|
|||
|
||||
|
||||
[features]
|
||||
schemars = [ "dep:schemars" ]
|
||||
schemars = [ "dep:schemars", "ruff_formatter/schemars", "ruff_python_formatter/schemars" ]
|
||||
|
||||
default = []
|
||||
|
|
|
@ -16,7 +16,7 @@ use shellexpand::LookupError;
|
|||
use strum::IntoEnumIterator;
|
||||
|
||||
use ruff_cache::cache_dir;
|
||||
use ruff_formatter::LineWidth;
|
||||
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};
|
||||
|
@ -32,17 +32,20 @@ use ruff_linter::settings::{
|
|||
use ruff_linter::{
|
||||
fs, warn_user, warn_user_once, warn_user_once_by_id, RuleSelector, RUFF_PKG_VERSION,
|
||||
};
|
||||
use ruff_python_formatter::FormatterSettings;
|
||||
use ruff_python_formatter::{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,
|
||||
Flake8UnusedArgumentsOptions, FormatOptions, FormatOrOutputFormat, IsortOptions, McCabeOptions,
|
||||
Options, Pep8NamingOptions, PyUpgradeOptions, PycodestyleOptions, PydocstyleOptions,
|
||||
PyflakesOptions, PylintOptions,
|
||||
};
|
||||
use crate::settings::{
|
||||
FileResolverSettings, FormatterSettings, LineEnding, Settings, EXCLUDE, INCLUDE,
|
||||
};
|
||||
use crate::settings::{FileResolverSettings, Settings, EXCLUDE, INCLUDE};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RuleSelection {
|
||||
|
@ -113,6 +116,8 @@ pub struct Configuration {
|
|||
pub pyflakes: Option<PyflakesOptions>,
|
||||
pub pylint: Option<PylintOptions>,
|
||||
pub pyupgrade: Option<PyUpgradeOptions>,
|
||||
|
||||
pub format: FormatConfiguration,
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
|
@ -129,6 +134,28 @@ impl Configuration {
|
|||
|
||||
let target_version = self.target_version.unwrap_or_default();
|
||||
let rules = self.as_rule_table();
|
||||
let preview = self.preview.unwrap_or_default();
|
||||
|
||||
let format = self.format;
|
||||
let format_defaults = FormatterSettings::default();
|
||||
// TODO(micha): Support changing the tab-width but disallow changing the number of spaces
|
||||
let formatter = FormatterSettings {
|
||||
preview: match format.preview.unwrap_or(preview) {
|
||||
PreviewMode::Disabled => ruff_python_formatter::PreviewMode::Disabled,
|
||||
PreviewMode::Enabled => ruff_python_formatter::PreviewMode::Enabled,
|
||||
},
|
||||
line_width: self
|
||||
.line_length
|
||||
.map_or(format_defaults.line_width, |length| {
|
||||
LineWidth::from(NonZeroU16::from(length))
|
||||
}),
|
||||
line_ending: format.line_ending.unwrap_or(format_defaults.line_ending),
|
||||
indent_style: format.indent_style.unwrap_or(format_defaults.indent_style),
|
||||
quote_style: format.quote_style.unwrap_or(format_defaults.quote_style),
|
||||
magic_trailing_comma: format
|
||||
.magic_trailing_comma
|
||||
.unwrap_or(format_defaults.magic_trailing_comma),
|
||||
};
|
||||
|
||||
Ok(Settings {
|
||||
cache_dir: self
|
||||
|
@ -185,7 +212,7 @@ impl Configuration {
|
|||
.task_tags
|
||||
.unwrap_or_else(|| TASK_TAGS.iter().map(ToString::to_string).collect()),
|
||||
logger_objects: self.logger_objects.unwrap_or_default(),
|
||||
preview: self.preview.unwrap_or_default(),
|
||||
preview,
|
||||
typing_modules: self.typing_modules.unwrap_or_default(),
|
||||
// Plugins
|
||||
flake8_annotations: self
|
||||
|
@ -290,18 +317,7 @@ impl Configuration {
|
|||
.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())),
|
||||
..FormatterSettings::default()
|
||||
},
|
||||
formatter,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -395,7 +411,12 @@ impl Configuration {
|
|||
external: options.external,
|
||||
fix: options.fix,
|
||||
fix_only: options.fix_only,
|
||||
output_format: options.output_format.or(options.format),
|
||||
output_format: options.output_format.or_else(|| {
|
||||
options
|
||||
.format
|
||||
.as_ref()
|
||||
.and_then(FormatOrOutputFormat::as_output_format)
|
||||
}),
|
||||
force_exclude: options.force_exclude,
|
||||
ignore_init_module_imports: options.ignore_init_module_imports,
|
||||
include: options.include.map(|paths| {
|
||||
|
@ -459,6 +480,12 @@ impl Configuration {
|
|||
pyflakes: options.pyflakes,
|
||||
pylint: options.pylint,
|
||||
pyupgrade: options.pyupgrade,
|
||||
|
||||
format: if let Some(FormatOrOutputFormat::Format(format)) = options.format {
|
||||
FormatConfiguration::from_options(format)?
|
||||
} else {
|
||||
FormatConfiguration::default()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -782,6 +809,52 @@ impl Configuration {
|
|||
pyflakes: self.pyflakes.combine(config.pyflakes),
|
||||
pylint: self.pylint.combine(config.pylint),
|
||||
pyupgrade: self.pyupgrade.combine(config.pyupgrade),
|
||||
|
||||
format: self.format.combine(config.format),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FormatConfiguration {
|
||||
pub preview: Option<PreviewMode>,
|
||||
|
||||
pub indent_style: Option<IndentStyle>,
|
||||
|
||||
pub quote_style: Option<QuoteStyle>,
|
||||
|
||||
pub magic_trailing_comma: Option<MagicTrailingComma>,
|
||||
|
||||
pub line_ending: Option<LineEnding>,
|
||||
}
|
||||
|
||||
impl FormatConfiguration {
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn from_options(options: FormatOptions) -> Result<Self> {
|
||||
Ok(Self {
|
||||
preview: options.preview.map(PreviewMode::from),
|
||||
indent_style: options.indent_style,
|
||||
quote_style: options.quote_style,
|
||||
magic_trailing_comma: options.skip_magic_trailing_comma.map(|skip| {
|
||||
if skip {
|
||||
MagicTrailingComma::Ignore
|
||||
} else {
|
||||
MagicTrailingComma::Respect
|
||||
}
|
||||
}),
|
||||
line_ending: options.line_ending,
|
||||
})
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn combine(self, other: Self) -> Self {
|
||||
Self {
|
||||
preview: self.preview.or(other.preview),
|
||||
indent_style: self.indent_style.or(other.indent_style),
|
||||
quote_style: self.quote_style.or(other.quote_style),
|
||||
magic_trailing_comma: self.magic_trailing_comma.or(other.magic_trailing_comma),
|
||||
line_ending: self.line_ending.or(other.line_ending),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ pub mod resolver;
|
|||
pub mod options_base;
|
||||
mod settings;
|
||||
|
||||
pub use settings::Settings;
|
||||
pub use settings::{FileResolverSettings, FormatterSettings, Settings};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::hash::BuildHasherDefault;
|
||||
|
||||
use regex::Regex;
|
||||
use ruff_formatter::IndentStyle;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use ruff_linter::line_width::{LineLength, TabSize};
|
||||
use ruff_linter::rules::flake8_pytest_style::settings::SettingsError;
|
||||
use ruff_linter::rules::flake8_pytest_style::types;
|
||||
|
@ -19,11 +27,9 @@ use ruff_linter::settings::types::{
|
|||
};
|
||||
use ruff_linter::{warn_user_once, RuleSelector};
|
||||
use ruff_macros::{CombineOptions, ConfigurationOptions};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeSet;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use strum::IntoEnumIterator;
|
||||
use ruff_python_formatter::QuoteStyle;
|
||||
|
||||
use crate::settings::LineEnding;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Default, ConfigurationOptions, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
|
@ -252,17 +258,6 @@ pub struct Options {
|
|||
)]
|
||||
pub fixable: Option<Vec<RuleSelector>>,
|
||||
|
||||
/// The style in which violation messages should be formatted: `"text"`
|
||||
/// (default), `"grouped"` (group messages by file), `"json"`
|
||||
/// (machine-readable), `"junit"` (machine-readable XML), `"github"` (GitHub
|
||||
/// Actions annotations), `"gitlab"` (GitLab CI code quality report),
|
||||
/// `"pylint"` (Pylint text format) or `"azure"` (Azure Pipeline logging commands).
|
||||
///
|
||||
/// This option has been **deprecated** in favor of `output-format`
|
||||
/// to avoid ambiguity with Ruff's upcoming formatter.
|
||||
#[cfg_attr(feature = "schemars", schemars(skip))]
|
||||
pub format: Option<SerializationFormat>,
|
||||
|
||||
/// The style in which violation messages should be formatted: `"text"`
|
||||
/// (default), `"grouped"` (group messages by file), `"json"`
|
||||
/// (machine-readable), `"junit"` (machine-readable XML), `"github"` (GitHub
|
||||
|
@ -681,6 +676,20 @@ pub struct Options {
|
|||
#[option_group]
|
||||
pub pyupgrade: Option<PyUpgradeOptions>,
|
||||
|
||||
/// Options to configure the code formatting.
|
||||
///
|
||||
/// Previously:
|
||||
/// The style in which violation messages should be formatted: `"text"`
|
||||
/// (default), `"grouped"` (group messages by file), `"json"`
|
||||
/// (machine-readable), `"junit"` (machine-readable XML), `"github"` (GitHub
|
||||
/// Actions annotations), `"gitlab"` (GitLab CI code quality report),
|
||||
/// `"pylint"` (Pylint text format) or `"azure"` (Azure Pipeline logging commands).
|
||||
///
|
||||
/// This option has been **deprecated** in favor of `output-format`
|
||||
/// to avoid ambiguity with Ruff's upcoming formatter.
|
||||
#[option_group]
|
||||
pub format: Option<FormatOrOutputFormat>,
|
||||
|
||||
// Tables are required to go last.
|
||||
/// A list of mappings from file pattern to rule codes or prefixes to
|
||||
/// exclude, when considering any matching files.
|
||||
|
@ -2381,11 +2390,130 @@ impl PyUpgradeOptions {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum FormatOrOutputFormat {
|
||||
Format(FormatOptions),
|
||||
OutputFormat(SerializationFormat),
|
||||
}
|
||||
|
||||
impl FormatOrOutputFormat {
|
||||
pub const fn metadata() -> crate::options_base::OptionGroup {
|
||||
FormatOptions::metadata()
|
||||
}
|
||||
|
||||
pub const fn as_output_format(&self) -> Option<SerializationFormat> {
|
||||
match self {
|
||||
FormatOrOutputFormat::Format(_) => None,
|
||||
FormatOrOutputFormat::OutputFormat(format) => Some(*format),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, PartialEq, Eq, Default, Serialize, Deserialize, ConfigurationOptions, CombineOptions,
|
||||
)]
|
||||
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub struct FormatOptions {
|
||||
/// Whether to enable the unstable preview style formatting.
|
||||
#[option(
|
||||
default = "false",
|
||||
value_type = "bool",
|
||||
example = r#"
|
||||
# Enable preview style formatting
|
||||
preview = true
|
||||
"#
|
||||
)]
|
||||
pub preview: Option<bool>,
|
||||
|
||||
/// Whether to use 4 spaces or hard tabs for indenting code.
|
||||
///
|
||||
/// Defaults to 4 spaces. We care about accessibility; if you do not need tabs for accessibility, we do not recommend you use them.
|
||||
#[option(
|
||||
default = "space",
|
||||
value_type = r#""space" | "tab""#,
|
||||
example = r#"
|
||||
# Use tabs instead of 4 space indentation
|
||||
indent-style = "tab"
|
||||
"#
|
||||
)]
|
||||
pub indent_style: Option<IndentStyle>,
|
||||
|
||||
/// Whether to prefer single `'` or double `"` quotes for strings and docstrings.
|
||||
///
|
||||
/// Ruff may deviate from this option if using the configured quotes would require more escaped quotes:
|
||||
///
|
||||
/// ```python
|
||||
/// a = "It's monday morning"
|
||||
/// b = "a string without any quotes"
|
||||
/// ```
|
||||
///
|
||||
/// Ruff leaves `a` unchanged when using `quote-style = "single"` because it is otherwise
|
||||
/// necessary to escape the `'` which leads to less readable code: `'It\'s monday morning'`.
|
||||
/// Ruff changes the quotes of `b` to use single quotes.
|
||||
#[option(
|
||||
default = r#"double"#,
|
||||
value_type = r#""double" | "single""#,
|
||||
example = r#"
|
||||
# Prefer single quotes over double quotes
|
||||
quote-style = "single"
|
||||
"#
|
||||
)]
|
||||
pub quote_style: Option<QuoteStyle>,
|
||||
|
||||
/// Ruff uses existing trailing commas as an indication that short lines should be left separate.
|
||||
/// If this option is set to `true`, the magic trailing comma is ignored.
|
||||
///
|
||||
/// For example, Ruff leaves the arguments separate even though
|
||||
/// collapsing the arguments to a single line doesn't exceed the line width if `skip-magic-trailing-comma = false`:
|
||||
///
|
||||
/// ```python
|
||||
/// # The arguments remain on separate lines because of the trailing comma after `b`
|
||||
/// def test(
|
||||
/// a,
|
||||
/// b,
|
||||
/// ): pass
|
||||
/// ```
|
||||
///
|
||||
/// Setting `skip-magic-trailing-comma = true` changes the formatting to:
|
||||
///
|
||||
/// ```python
|
||||
/// # The arguments remain on separate lines because of the trailing comma after `b`
|
||||
/// def test(a, b):
|
||||
/// pass
|
||||
/// ```
|
||||
#[option(
|
||||
default = r#"false"#,
|
||||
value_type = r#"bool"#,
|
||||
example = "skip-magic-trailing-comma = true"
|
||||
)]
|
||||
pub skip_magic_trailing_comma: Option<bool>,
|
||||
|
||||
/// The character Ruff uses at the end of a line.
|
||||
///
|
||||
/// * `lf`: Line endings will be converted to `\n`. The default line ending on Unix.
|
||||
/// * `cr-lf`: Line endings will be converted to `\r\n`. The default line ending on Windows.
|
||||
/// * `auto`: The newline style is detected automatically on a file per file basis. Files with mixed line endings will be converted to the first detected line ending. Defaults to `\n` for files that contain no line endings.
|
||||
/// * `native`: Line endings will be converted to `\n` on Unix and `\r\n` on Windows.
|
||||
#[option(
|
||||
default = r#"lf"#,
|
||||
value_type = r#""lf" | "crlf" | "auto" | "native""#,
|
||||
example = r#"
|
||||
# Automatically detect the line ending on a file per file basis.
|
||||
quote-style = "auto"
|
||||
"#
|
||||
)]
|
||||
pub line_ending: Option<LineEnding>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::options::Flake8SelfOptions;
|
||||
use ruff_linter::rules::flake8_self;
|
||||
|
||||
use crate::options::Flake8SelfOptions;
|
||||
|
||||
#[test]
|
||||
fn flake8_self_options() {
|
||||
let default_settings = flake8_self::settings::Settings::default();
|
||||
|
|
|
@ -37,7 +37,7 @@ impl OptionGroup {
|
|||
/// ```rust
|
||||
/// # use ruff_workspace::options_base::{OptionGroup, OptionEntry, OptionField};
|
||||
///
|
||||
/// const options: [(&'static str, OptionEntry); 2] = [
|
||||
/// const OPTIONS: [(&'static str, OptionEntry); 2] = [
|
||||
/// ("ignore_names", OptionEntry::Field(OptionField {
|
||||
/// doc: "ignore_doc",
|
||||
/// default: "ignore_default",
|
||||
|
@ -53,7 +53,7 @@ impl OptionGroup {
|
|||
/// }))
|
||||
/// ];
|
||||
///
|
||||
/// let group = OptionGroup::new(&options);
|
||||
/// let group = OptionGroup::new(&OPTIONS);
|
||||
///
|
||||
/// let ignore_names = group.get("ignore_names");
|
||||
///
|
||||
|
@ -73,7 +73,7 @@ impl OptionGroup {
|
|||
/// ```rust
|
||||
/// # use ruff_workspace::options_base::{OptionGroup, OptionEntry, OptionField};
|
||||
///
|
||||
/// const ignore_options: [(&'static str, OptionEntry); 2] = [
|
||||
/// const IGNORE_OPTIONS: [(&'static str, OptionEntry); 2] = [
|
||||
/// ("names", OptionEntry::Field(OptionField {
|
||||
/// doc: "ignore_name_doc",
|
||||
/// default: "ignore_name_default",
|
||||
|
@ -89,8 +89,8 @@ impl OptionGroup {
|
|||
/// }))
|
||||
/// ];
|
||||
///
|
||||
/// const options: [(&'static str, OptionEntry); 2] = [
|
||||
/// ("ignore", OptionEntry::Group(OptionGroup::new(&ignore_options))),
|
||||
/// const OPTIONS: [(&'static str, OptionEntry); 2] = [
|
||||
/// ("ignore", OptionEntry::Group(OptionGroup::new(&IGNORE_OPTIONS))),
|
||||
///
|
||||
/// ("global_names", OptionEntry::Field(OptionField {
|
||||
/// doc: "global_doc",
|
||||
|
@ -100,7 +100,7 @@ impl OptionGroup {
|
|||
/// }))
|
||||
/// ];
|
||||
///
|
||||
/// let group = OptionGroup::new(&options);
|
||||
/// let group = OptionGroup::new(&OPTIONS);
|
||||
///
|
||||
/// let ignore_names = group.get("ignore.names");
|
||||
///
|
||||
|
|
|
@ -17,6 +17,7 @@ use ruff_linter::packaging::is_package;
|
|||
use ruff_linter::{fs, warn_user_once};
|
||||
|
||||
use crate::configuration::Configuration;
|
||||
use crate::options::FormatOrOutputFormat;
|
||||
use crate::pyproject;
|
||||
use crate::pyproject::settings_toml;
|
||||
use crate::settings::Settings;
|
||||
|
@ -220,8 +221,8 @@ fn resolve_configuration(
|
|||
let options = pyproject::load_options(&path)
|
||||
.map_err(|err| anyhow!("Failed to parse `{}`: {}", path.display(), err))?;
|
||||
|
||||
if options.format.is_some() {
|
||||
warn_user_once!("The option `format` has been deprecated to avoid ambiguity with Ruff's upcoming formatter. Use `format-output` instead.");
|
||||
if matches!(options.format, Some(FormatOrOutputFormat::OutputFormat(_))) {
|
||||
warn_user_once!("The option `format` has been deprecated to avoid ambiguity with Ruff's upcoming formatter. Use `output-format` instead.");
|
||||
}
|
||||
|
||||
let project_root = relativity.resolve(&path);
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use path_absolutize::path_dedot;
|
||||
use ruff_cache::cache_dir;
|
||||
use ruff_formatter::{FormatOptions, IndentStyle, LineWidth};
|
||||
use ruff_linter::settings::types::{FilePattern, FilePatternSet, SerializationFormat};
|
||||
use ruff_linter::settings::LinterSettings;
|
||||
use ruff_macros::CacheKey;
|
||||
use ruff_python_formatter::FormatterSettings;
|
||||
use ruff_python_ast::PySourceType;
|
||||
use ruff_python_formatter::{MagicTrailingComma, PreviewMode, PyFormatOptions, QuoteStyle};
|
||||
use ruff_source_file::find_newline;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, CacheKey)]
|
||||
|
@ -102,3 +105,88 @@ impl FileResolverSettings {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(CacheKey, Clone, Debug)]
|
||||
pub struct FormatterSettings {
|
||||
pub preview: PreviewMode,
|
||||
|
||||
pub line_width: LineWidth,
|
||||
|
||||
pub indent_style: IndentStyle,
|
||||
|
||||
pub quote_style: QuoteStyle,
|
||||
|
||||
pub magic_trailing_comma: MagicTrailingComma,
|
||||
|
||||
pub line_ending: LineEnding,
|
||||
}
|
||||
|
||||
impl FormatterSettings {
|
||||
pub fn to_format_options(&self, source_type: PySourceType, source: &str) -> PyFormatOptions {
|
||||
let line_ending = match self.line_ending {
|
||||
LineEnding::Lf => ruff_formatter::printer::LineEnding::LineFeed,
|
||||
LineEnding::CrLf => ruff_formatter::printer::LineEnding::CarriageReturnLineFeed,
|
||||
#[cfg(target_os = "windows")]
|
||||
LineEnding::Native => ruff_formatter::printer::LineEnding::CarriageReturnLineFeed,
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
LineEnding::Native => ruff_formatter::printer::LineEnding::LineFeed,
|
||||
LineEnding::Auto => match find_newline(source) {
|
||||
Some((_, ruff_source_file::LineEnding::Lf)) => {
|
||||
ruff_formatter::printer::LineEnding::LineFeed
|
||||
}
|
||||
Some((_, ruff_source_file::LineEnding::CrLf)) => {
|
||||
ruff_formatter::printer::LineEnding::CarriageReturnLineFeed
|
||||
}
|
||||
Some((_, ruff_source_file::LineEnding::Cr)) => {
|
||||
ruff_formatter::printer::LineEnding::CarriageReturn
|
||||
}
|
||||
None => ruff_formatter::printer::LineEnding::LineFeed,
|
||||
},
|
||||
};
|
||||
|
||||
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_ending(line_ending)
|
||||
.with_line_width(self.line_width)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FormatterSettings {
|
||||
fn default() -> Self {
|
||||
let default_options = PyFormatOptions::default();
|
||||
|
||||
Self {
|
||||
preview: ruff_python_formatter::PreviewMode::Disabled,
|
||||
line_width: default_options.line_width(),
|
||||
line_ending: LineEnding::Lf,
|
||||
indent_style: default_options.indent_style(),
|
||||
quote_style: default_options.quote_style(),
|
||||
magic_trailing_comma: default_options.magic_trailing_comma(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Eq, PartialEq, Default, CacheKey, serde::Serialize, serde::Deserialize,
|
||||
)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum LineEnding {
|
||||
/// Line endings will be converted to `\n` as is common on Unix.
|
||||
#[default]
|
||||
Lf,
|
||||
|
||||
/// Line endings will be converted to `\r\n` as is common on Windows.
|
||||
CrLf,
|
||||
|
||||
/// The newline style is detected automatically on a file per file basis.
|
||||
/// Files with mixed line endings will be converted to the first detected line ending.
|
||||
/// Defaults to [`LineEnding::Lf`] for a files that contain no line endings.
|
||||
Auto,
|
||||
|
||||
/// Line endings will be converted to `\n` on Unix and `\r\n` on Windows.
|
||||
Native,
|
||||
}
|
||||
|
|
131
ruff.schema.json
generated
131
ruff.schema.json
generated
|
@ -326,6 +326,17 @@
|
|||
"null"
|
||||
]
|
||||
},
|
||||
"format": {
|
||||
"description": "Options to configure the code formatting.\n\nPreviously: The style in which violation messages should be formatted: `\"text\"` (default), `\"grouped\"` (group messages by file), `\"json\"` (machine-readable), `\"junit\"` (machine-readable XML), `\"github\"` (GitHub Actions annotations), `\"gitlab\"` (GitLab CI code quality report), `\"pylint\"` (Pylint text format) or `\"azure\"` (Azure Pipeline logging commands).\n\nThis option has been **deprecated** in favor of `output-format` to avoid ambiguity with Ruff's upcoming formatter.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/FormatOrOutputFormat"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ignore": {
|
||||
"description": "A list of rule codes or prefixes to ignore. Prefixes can specify exact rules (like `F841`), entire categories (like `F`), or anything in between.\n\nWhen breaking ties between enabled and disabled rules (via `select` and `ignore`, respectively), more specific prefixes override less specific prefixes.",
|
||||
"type": [
|
||||
|
@ -1151,6 +1162,69 @@
|
|||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FormatOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"indent-style": {
|
||||
"description": "Whether to use 4 spaces or hard tabs for indenting code.\n\nDefaults to 4 spaces. We care about accessibility; if you do not need tabs for accessibility, we do not recommend you use them.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/IndentStyle"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"line-ending": {
|
||||
"description": "The character Ruff uses at the end of a line.\n\n* `lf`: Line endings will be converted to `\\n`. The default line ending on Unix. * `cr-lf`: Line endings will be converted to `\\r\\n`. The default line ending on Windows. * `auto`: The newline style is detected automatically on a file per file basis. Files with mixed line endings will be converted to the first detected line ending. Defaults to `\\n` for files that contain no line endings. * `native`: Line endings will be converted to `\\n` on Unix and `\\r\\n` on Windows.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/LineEnding"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"preview": {
|
||||
"description": "Whether to enable the unstable preview style formatting.",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"quote-style": {
|
||||
"description": "Whether to prefer single `'` or double `\"` quotes for strings and docstrings.\n\nRuff may deviate from this option if using the configured quotes would require more escaped quotes:\n\n```python a = \"It's monday morning\" b = \"a string without any quotes\" ```\n\nRuff leaves `a` unchanged when using `quote-style = \"single\"` because it is otherwise necessary to escape the `'` which leads to less readable code: `'It\\'s monday morning'`. Ruff changes the quotes of `b` to use single quotes.",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/QuoteStyle"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"skip-magic-trailing-comma": {
|
||||
"description": "Ruff uses existing trailing commas as an indication that short lines should be left separate. If this option is set to `true`, the magic trailing comma is ignored.\n\nFor example, Ruff leaves the arguments separate even though collapsing the arguments to a single line doesn't exceed the line width if `skip-magic-trailing-comma = false`:\n\n```python # The arguments remain on separate lines because of the trailing comma after `b` def test( a, b, ): pass ```\n\nSetting `skip-magic-trailing-comma = true` changes the formatting to:\n\n```python # The arguments remain on separate lines because of the trailing comma after `b` def test(a, b): pass ```",
|
||||
"type": [
|
||||
"boolean",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"FormatOrOutputFormat": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/FormatOptions"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/SerializationFormat"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ImportSection": {
|
||||
"anyOf": [
|
||||
{
|
||||
|
@ -1171,6 +1245,24 @@
|
|||
"local-folder"
|
||||
]
|
||||
},
|
||||
"IndentStyle": {
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Use tabs to indent code.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"tab"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Use [`IndentWidth`] spaces to indent code.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"space"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"IsortOptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -1404,6 +1496,38 @@
|
|||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"LineEnding": {
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Line endings will be converted to `\\n` as is common on Unix.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"lf"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Line endings will be converted to `\\r\\n` as is common on Windows.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"cr-lf"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "The newline style is detected automatically on a file per file basis. Files with mixed line endings will be converted to the first detected line ending. Defaults to [`LineEnding::Lf`] for a files that contain no line endings.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Line endings will be converted to `\\n` on Unix and `\\r\\n` on Windows.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"native"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"LineLength": {
|
||||
"description": "The length of a line of text that is considered too long.\n\nThe allowed range of values is 1..=320",
|
||||
"type": "integer",
|
||||
|
@ -1673,6 +1797,13 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"QuoteStyle": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"single",
|
||||
"double"
|
||||
]
|
||||
},
|
||||
"RelativeImportsOrder": {
|
||||
"oneOf": [
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue