Join implicit concatenated strings when they fit on a line (#13663)

This commit is contained in:
Micha Reiser
2024-10-24 11:52:22 +02:00
committed by GitHub
parent e402e27a09
commit 73ee72b665
50 changed files with 3907 additions and 363 deletions

View File

@@ -9,7 +9,7 @@ use std::{borrow::Cow, collections::VecDeque};
use regex::Regex;
use ruff_formatter::printer::SourceMapGeneration;
use ruff_python_ast::{str::Quote, StringFlags};
use ruff_python_ast::{str::Quote, AnyStringFlags, StringFlags};
use ruff_python_trivia::CommentRanges;
use {
ruff_formatter::{write, FormatOptions, IndentStyle, LineWidth, Printed},
@@ -19,7 +19,10 @@ use {
};
use super::NormalizedString;
use crate::preview::is_docstring_code_block_in_docstring_indent_enabled;
use crate::preview::{
is_docstring_code_block_in_docstring_indent_enabled,
is_join_implicit_concatenated_string_enabled,
};
use crate::string::StringQuotes;
use crate::{prelude::*, DocstringCodeLineWidth, FormatModuleError};
@@ -167,7 +170,7 @@ pub(crate) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form
if docstring[first.len()..].trim().is_empty() {
// For `"""\n"""` or other whitespace between the quotes, black keeps a single whitespace,
// but `""""""` doesn't get one inserted.
if needs_chaperone_space(normalized, trim_end)
if needs_chaperone_space(normalized.flags(), trim_end, f.context())
|| (trim_end.is_empty() && !docstring.is_empty())
{
space().fmt(f)?;
@@ -207,7 +210,7 @@ pub(crate) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form
let trim_end = docstring
.as_ref()
.trim_end_matches(|c: char| c.is_whitespace() && c != '\n');
if needs_chaperone_space(normalized, trim_end) {
if needs_chaperone_space(normalized.flags(), trim_end, f.context()) {
space().fmt(f)?;
}
@@ -1604,9 +1607,18 @@ fn docstring_format_source(
/// If the last line of the docstring is `content" """` or `content\ """`, we need a chaperone space
/// that avoids `content""""` and `content\"""`. This does only applies to un-escaped backslashes,
/// so `content\\ """` doesn't need a space while `content\\\ """` does.
fn needs_chaperone_space(normalized: &NormalizedString, trim_end: &str) -> bool {
trim_end.ends_with(normalized.flags().quote_style().as_char())
|| trim_end.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1
pub(super) fn needs_chaperone_space(
flags: AnyStringFlags,
trim_end: &str,
context: &PyFormatContext,
) -> bool {
if trim_end.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1 {
true
} else if is_join_implicit_concatenated_string_enabled(context) {
flags.is_triple_quoted() && trim_end.ends_with(flags.quote_style().as_char())
} else {
trim_end.ends_with(flags.quote_style().as_char())
}
}
#[derive(Copy, Clone, Debug)]