mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-23 10:33:10 +00:00

## Summary This PR adds support for PEP 701 in Ruff. This is a rollup PR of all the other individual PRs. The separate PRs were created for logic separation and code reviews. Refer to each pull request for a detail description on the change. Refer to the PR description for the list of pull requests within this PR. ## Test Plan ### Formatter ecosystem checks Explanation for the change in ecosystem check: https://github.com/astral-sh/ruff/pull/7597#issue-1908878183 #### `main` ``` | project | similarity index | total files | changed files | |--------------|------------------:|------------------:|------------------:| | cpython | 0.76083 | 1789 | 1631 | | django | 0.99983 | 2760 | 36 | | transformers | 0.99963 | 2587 | 319 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99983 | 3496 | 18 | | warehouse | 0.99967 | 648 | 15 | | zulip | 0.99972 | 1437 | 21 | ``` #### `dhruv/pep-701` ``` | project | similarity index | total files | changed files | |--------------|------------------:|------------------:|------------------:| | cpython | 0.76051 | 1789 | 1632 | | django | 0.99983 | 2760 | 36 | | transformers | 0.99963 | 2587 | 319 | | twine | 1.00000 | 33 | 0 | | typeshed | 0.99983 | 3496 | 18 | | warehouse | 0.99967 | 648 | 15 | | zulip | 0.99972 | 1437 | 21 | ```
87 lines
2.9 KiB
Rust
87 lines
2.9 KiB
Rust
#![allow(clippy::print_stdout)]
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use anyhow::{format_err, Context, Result};
|
|
use clap::{command, Parser, ValueEnum};
|
|
|
|
use ruff_formatter::SourceCode;
|
|
use ruff_python_index::tokens_and_ranges;
|
|
use ruff_python_parser::{parse_ok_tokens, Mode};
|
|
use ruff_text_size::Ranged;
|
|
|
|
use crate::comments::collect_comments;
|
|
use crate::{format_module_ast, PyFormatOptions};
|
|
|
|
#[derive(ValueEnum, Clone, Debug)]
|
|
pub enum Emit {
|
|
/// Write back to the original files
|
|
Files,
|
|
/// Write to stdout
|
|
Stdout,
|
|
}
|
|
|
|
#[derive(Parser)]
|
|
#[command(author, version, about, long_about = None)]
|
|
pub struct Cli {
|
|
/// Python files to format. If there are none, stdin will be used. `-` as stdin is not supported
|
|
pub files: Vec<PathBuf>,
|
|
#[clap(long)]
|
|
pub emit: Option<Emit>,
|
|
/// Run in 'check' mode. Exits with 0 if input is formatted correctly. Exits with 1 and prints
|
|
/// a diff if formatting is required.
|
|
#[clap(long)]
|
|
pub check: bool,
|
|
#[clap(long)]
|
|
pub print_ir: bool,
|
|
#[clap(long)]
|
|
pub print_comments: bool,
|
|
}
|
|
|
|
pub fn format_and_debug_print(source: &str, cli: &Cli, source_type: &Path) -> Result<String> {
|
|
let (tokens, comment_ranges) = tokens_and_ranges(source)
|
|
.map_err(|err| format_err!("Source contains syntax errors {err:?}"))?;
|
|
|
|
// Parse the AST.
|
|
let module = parse_ok_tokens(tokens, source, Mode::Module, "<filename>")
|
|
.context("Syntax error in input")?;
|
|
|
|
let options = PyFormatOptions::from_extension(source_type);
|
|
|
|
let source_code = SourceCode::new(source);
|
|
let formatted = format_module_ast(&module, &comment_ranges, source, options)
|
|
.context("Failed to format node")?;
|
|
if cli.print_ir {
|
|
println!("{}", formatted.document().display(source_code));
|
|
}
|
|
if cli.print_comments {
|
|
// Print preceding, following and enclosing nodes
|
|
let decorated_comments = collect_comments(&module, source_code, &comment_ranges);
|
|
if !decorated_comments.is_empty() {
|
|
println!("# Comment decoration: Range, Preceding, Following, Enclosing, Comment");
|
|
}
|
|
for comment in decorated_comments {
|
|
println!(
|
|
"{:?}, {:?}, {:?}, {:?}, {:?}",
|
|
comment.slice().range(),
|
|
comment
|
|
.preceding_node()
|
|
.map(|node| (node.kind(), node.range())),
|
|
comment
|
|
.following_node()
|
|
.map(|node| (node.kind(), node.range())),
|
|
(
|
|
comment.enclosing_node().kind(),
|
|
comment.enclosing_node().range()
|
|
),
|
|
comment.slice().text(source_code),
|
|
);
|
|
}
|
|
println!("{:#?}", formatted.context().comments().debug(source_code));
|
|
}
|
|
Ok(formatted
|
|
.print()
|
|
.context("Failed to print the formatter IR")?
|
|
.as_code()
|
|
.to_string())
|
|
}
|