mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-22 20:45:11 +00:00
Use new formatter infrastructure in CLI and test (#4767)
* Use dummy verbatim formatter for all nodes * Use new formatter infrastructure in CLI and test * Expose the new formatter in the CLI * Merge import blocks
This commit is contained in:
parent
9bf168c0a4
commit
d4027d8b65
6 changed files with 64 additions and 41 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1864,6 +1864,7 @@ dependencies = [
|
|||
"ruff_cache",
|
||||
"ruff_diagnostics",
|
||||
"ruff_python_ast",
|
||||
"ruff_python_formatter",
|
||||
"ruff_python_stdlib",
|
||||
"ruff_text_size",
|
||||
"ruff_textwrap",
|
||||
|
|
|
@ -26,6 +26,7 @@ ruff = { path = "../ruff", features = ["clap"] }
|
|||
ruff_cache = { path = "../ruff_cache" }
|
||||
ruff_diagnostics = { path = "../ruff_diagnostics" }
|
||||
ruff_python_ast = { path = "../ruff_python_ast" }
|
||||
ruff_python_formatter = { path = "../ruff_python_formatter" }
|
||||
ruff_text_size = { workspace = true }
|
||||
ruff_textwrap = { path = "../ruff_textwrap" }
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use ruff::logging::{set_up_logging, LogLevel};
|
|||
use ruff::settings::types::SerializationFormat;
|
||||
use ruff::settings::{flags, CliSettings};
|
||||
use ruff::{fs, warn_user_once};
|
||||
use ruff_python_formatter::format_module;
|
||||
|
||||
use crate::args::{Args, CheckArgs, Command};
|
||||
use crate::commands::run_stdin::read_from_stdin;
|
||||
|
@ -131,22 +132,26 @@ fn format(files: &[PathBuf]) -> Result<ExitStatus> {
|
|||
internal use only."
|
||||
);
|
||||
|
||||
// dummy
|
||||
let format_code = |code: &str| code.replace("# DEL", "");
|
||||
let format_code = |code: &str| {
|
||||
// dummy, to check that the function was actually called
|
||||
let contents = code.replace("# DEL", "");
|
||||
// real formatting that is currently a passthrough
|
||||
format_module(&contents)
|
||||
};
|
||||
|
||||
match &files {
|
||||
// Check if we should read from stdin
|
||||
[path] if path == Path::new("-") => {
|
||||
let unformatted = read_from_stdin()?;
|
||||
let formatted = format_code(&unformatted);
|
||||
stdout().lock().write_all(formatted.as_bytes())?;
|
||||
let formatted = format_code(&unformatted)?;
|
||||
stdout().lock().write_all(formatted.as_code().as_bytes())?;
|
||||
}
|
||||
_ => {
|
||||
for file in files {
|
||||
let unformatted = std::fs::read_to_string(file)
|
||||
.with_context(|| format!("Could not read {}: ", file.display()))?;
|
||||
let formatted = format_code(&unformatted);
|
||||
std::fs::write(file, formatted)
|
||||
let formatted = format_code(&unformatted)?;
|
||||
std::fs::write(file, formatted.as_code().as_bytes())
|
||||
.with_context(|| format!("Could not write to {}, exiting", file.display()))?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ use ruff_python_ast::source_code::{CommentRanges, CommentRangesBuilder, Locator}
|
|||
|
||||
use crate::comments::Comments;
|
||||
use crate::context::PyFormatContext;
|
||||
use crate::module::FormatModule;
|
||||
|
||||
pub mod cli;
|
||||
mod comments;
|
||||
|
@ -130,9 +129,9 @@ pub fn format_node<'a>(
|
|||
line_width: 88.try_into().unwrap(),
|
||||
},
|
||||
locator.contents(),
|
||||
comments
|
||||
comments,
|
||||
),
|
||||
[FormatModule::new(root)]
|
||||
[root.format()]
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -165,13 +164,33 @@ mod tests {
|
|||
use insta::assert_snapshot;
|
||||
use rustpython_parser::lexer::lex;
|
||||
use rustpython_parser::{parse_tokens, Mode};
|
||||
use similar::TextDiff;
|
||||
|
||||
use ruff_python_ast::source_code::CommentRangesBuilder;
|
||||
use ruff_testing_macros::fixture;
|
||||
use similar::TextDiff;
|
||||
|
||||
use crate::{format_module, format_node};
|
||||
|
||||
/// Very basic test intentionally kept very similar to the CLI
|
||||
#[test]
|
||||
fn basic() -> Result<()> {
|
||||
let input = r#"
|
||||
# preceding
|
||||
if True:
|
||||
print( "hi" )
|
||||
# trailing
|
||||
"#;
|
||||
let expected = r#"
|
||||
# preceding
|
||||
if True:
|
||||
print( "hi" )
|
||||
# trailing
|
||||
"#;
|
||||
let actual = format_module(input)?.as_code().to_string();
|
||||
assert_eq!(expected, actual);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[fixture(pattern = "resources/test/fixtures/black/**/*.py")]
|
||||
#[test]
|
||||
fn black_test(input_path: &Path) -> Result<()> {
|
||||
|
|
|
@ -6,12 +6,10 @@ use clap::Parser as ClapParser;
|
|||
use ruff_python_formatter::cli::Cli;
|
||||
use ruff_python_formatter::format_module;
|
||||
|
||||
#[allow(clippy::print_stdout)]
|
||||
fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
let contents = fs::read_to_string(cli.file)?;
|
||||
#[allow(clippy::print_stdout)]
|
||||
{
|
||||
println!("{}", format_module(&contents)?.as_code());
|
||||
}
|
||||
println!("{}", format_module(&contents)?.as_code());
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,38 +1,37 @@
|
|||
use crate::context::PyFormatContext;
|
||||
use crate::{AsFormat, IntoFormat, PyFormatter};
|
||||
use ruff_formatter::{Format, FormatOwnedWithRule, FormatRefWithRule, FormatResult, FormatRule};
|
||||
use rustpython_parser::ast::Mod;
|
||||
|
||||
pub(crate) mod mod_expression;
|
||||
pub(crate) mod mod_function_type;
|
||||
pub(crate) mod mod_interactive;
|
||||
pub(crate) mod mod_module;
|
||||
|
||||
use crate::context::PyFormatContext;
|
||||
use ruff_formatter::format_element::tag::VerbatimKind;
|
||||
use ruff_formatter::prelude::*;
|
||||
use ruff_formatter::write;
|
||||
use rustpython_parser::ast::{Mod, Ranged};
|
||||
#[derive(Default)]
|
||||
pub struct FormatMod;
|
||||
|
||||
pub(crate) struct FormatModule<'a> {
|
||||
module: &'a Mod,
|
||||
}
|
||||
|
||||
impl<'a> FormatModule<'a> {
|
||||
pub(crate) fn new(module: &'a Mod) -> Self {
|
||||
Self { module }
|
||||
impl FormatRule<Mod, PyFormatContext<'_>> for FormatMod {
|
||||
fn fmt(&self, item: &Mod, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
match item {
|
||||
Mod::Module(x) => x.format().fmt(f),
|
||||
Mod::Interactive(x) => x.format().fmt(f),
|
||||
Mod::Expression(x) => x.format().fmt(f),
|
||||
Mod::FunctionType(x) => x.format().fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Format<PyFormatContext<'_>> for FormatModule<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
||||
let range = self.module.range();
|
||||
|
||||
write!(f, [source_position(range.start())])?;
|
||||
|
||||
f.write_element(FormatElement::Tag(Tag::StartVerbatim(
|
||||
VerbatimKind::Verbatim {
|
||||
length: range.len(),
|
||||
},
|
||||
)))?;
|
||||
write!(f, [source_text_slice(range, ContainsNewlines::Detect)])?;
|
||||
f.write_element(FormatElement::Tag(Tag::EndVerbatim))?;
|
||||
|
||||
write!(f, [source_position(range.end())])
|
||||
impl<'ast> AsFormat<PyFormatContext<'ast>> for Mod {
|
||||
type Format<'a> = FormatRefWithRule<'a, Mod, FormatMod, PyFormatContext<'ast>>;
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
FormatRefWithRule::new(self, FormatMod::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> IntoFormat<PyFormatContext<'ast>> for Mod {
|
||||
type Format = FormatOwnedWithRule<Mod, FormatMod, PyFormatContext<'ast>>;
|
||||
fn into_format(self) -> Self::Format {
|
||||
FormatOwnedWithRule::new(self, FormatMod::default())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue