Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve single \ in raw string literals #5941

Closed
Tracked by #6069 ...
MichaReiser opened this issue Jul 21, 2023 · 2 comments · Fixed by #6152
Closed
Tracked by #6069 ...

Preserve single \ in raw string literals #5941

MichaReiser opened this issue Jul 21, 2023 · 2 comments · Fixed by #6152
Assignees
Labels
formatter Related to the formatter

Comments

@MichaReiser
Copy link
Member

MichaReiser commented Jul 21, 2023

# Input
pattern_esc = r"'\', '\\'"

# Ruff
pattern_esc = r"'', '\\'"

Expected: Same as input

Probably relevant code:

fn normalize_string(input: &str, quotes: StringQuotes) -> (Cow<str>, ContainsNewlines) {
// The normalized string if `input` is not yet normalized.
// `output` must remain empty if `input` is already normalized.
let mut output = String::new();
// Tracks the last index of `input` that has been written to `output`.
// If `last_index` is `0` at the end, then the input is already normalized and can be returned as is.
let mut last_index = 0;
let mut newlines = ContainsNewlines::No;
let style = quotes.style;
let preferred_quote = style.as_char();
let opposite_quote = style.invert().as_char();
let mut chars = input.char_indices();
while let Some((index, c)) = chars.next() {
if c == '\r' {
output.push_str(&input[last_index..index]);
// Skip over the '\r' character, keep the `\n`
if input.as_bytes().get(index + 1).copied() == Some(b'\n') {
chars.next();
}
// Replace the `\r` with a `\n`
else {
output.push('\n');
}
last_index = index + '\r'.len_utf8();
newlines = ContainsNewlines::Yes;
} else if c == '\n' {
newlines = ContainsNewlines::Yes;
} else if !quotes.triple {
if c == '\\' {
if let Some(next) = input.as_bytes().get(index + 1).copied().map(char::from) {
#[allow(clippy::if_same_then_else)]
if next == opposite_quote {
// Remove the escape by ending before the backslash and starting again with the quote
chars.next();
output.push_str(&input[last_index..index]);
last_index = index + '\\'.len_utf8();
} else if next == preferred_quote {
// Quote is already escaped, skip over it.
chars.next();
} else if next == '\\' {
// Skip over escaped backslashes
chars.next();
}
}
} else if c == preferred_quote {
// Escape the quote
output.push_str(&input[last_index..index]);
output.push('\\');
output.push(c);
last_index = index + preferred_quote.len_utf8();
}
}
}
let normalized = if last_index == 0 {
Cow::Borrowed(input)
} else {
output.push_str(&input[last_index..]);
Cow::Owned(output)
};
(normalized, newlines)
}

Playground

@MichaReiser MichaReiser added the formatter Related to the formatter label Jul 21, 2023
@harupy
Copy link
Contributor

harupy commented Jul 28, 2023

@MichaReiser Can I work on this?

@MichaReiser
Copy link
Member Author

@MichaReiser Can I work on this?

Sure!

@konstin konstin changed the title Preserve single \ in string literals Preserve single \ in raw string literals Jul 31, 2023
@MichaReiser MichaReiser added this to the Formatter: Alpha milestone Aug 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
formatter Related to the formatter
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants