Skip to content

Commit 8de14a9

Browse files
committed
Remove fancy-regex dependency
1 parent 05afb6d commit 8de14a9

File tree

3 files changed

+59
-57
lines changed

3 files changed

+59
-57
lines changed

Cargo.lock

Lines changed: 0 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

librubyfmt/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ edition = "2024"
77
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
88

99
[dependencies]
10-
fancy-regex = "0.14.0"
1110
log = { version = "0.4.8", features = ["max_level_debug", "release_max_level_warn"] }
1211
memchr = "2.7"
1312
simplelog = "0.12"

librubyfmt/src/string_escape.rs

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use std::borrow::Cow;
22

3-
use fancy_regex::Regex;
4-
53
pub fn single_to_double_quoted<'src>(
64
content: &'src str,
75
start_delim: &'src str,
@@ -15,38 +13,70 @@ pub fn single_to_double_quoted<'src>(
1513
)
1614
.into()
1715
} else {
18-
// For percent literals, we only care about the delimiter
19-
// e.g. for `%<` we're looking for the `<`
20-
let start_delim = if let Some(stripped) = start_delim.strip_prefix('%') {
21-
stripped
22-
} else {
23-
start_delim
24-
};
16+
let start_delim_char = start_delim.chars().last().unwrap();
17+
let end_delim_char = end_delim.chars().last().unwrap();
18+
convert_percent_literal_escapes(content, start_delim_char, end_delim_char)
19+
}
20+
}
21+
22+
/// Converts escape sequences in a percent-literal string's content so they are
23+
/// valid inside a double-quoted string.
24+
fn convert_percent_literal_escapes(
25+
content: &str,
26+
start_delim: char,
27+
end_delim: char,
28+
) -> Cow<'_, str> {
29+
let first_change_pos = {
30+
let mut pos = None;
31+
let mut chars = content.char_indices().peekable();
32+
while let Some((i, c)) = chars.next() {
33+
if c == '"' {
34+
pos = Some(i);
35+
break;
36+
} else if c == '\\'
37+
&& let Some(&(_, next)) = chars.peek()
38+
{
39+
if next == start_delim || next == end_delim {
40+
pos = Some(i);
41+
break;
42+
}
43+
chars.next(); // skip next char — treat \X as a unit
44+
}
45+
}
46+
pos
47+
};
48+
49+
let Some(start) = first_change_pos else {
50+
return Cow::Borrowed(content); // No changes
51+
};
2552

26-
let regexp = Regex::new(&format!(
27-
r#"(?<!\\)(\\\\)*(\"|\\{}|\\{})"#,
28-
fancy_regex::escape(start_delim),
29-
fancy_regex::escape(end_delim)
30-
))
31-
.unwrap();
53+
let mut output = content[..start].to_string();
54+
let mut chars = content[start..].chars().peekable();
3255

33-
regexp.replace_all(content, |captures: &fancy_regex::Captures| {
34-
// first capture is the entire match
35-
let val = captures.get(0).unwrap();
36-
let val_str = val.as_str();
37-
if val_str.ends_with("\"") {
38-
// Ends with a quote, which we transform to `\"`
39-
format!("{}\\\"", &val_str[0..(val_str.len() - 1)])
56+
while let Some(c) = chars.next() {
57+
if c == '\\' {
58+
if let Some(&next) = chars.peek() {
59+
if next == start_delim || next == end_delim {
60+
// Drop the delimiter escape: \( → (
61+
output.push(next);
62+
chars.next();
63+
} else {
64+
// Write back the original with no changes
65+
output.push('\\');
66+
output.push(next);
67+
chars.next();
68+
}
4069
} else {
41-
// drop unnecessary escape
42-
format!(
43-
"{}{}",
44-
&val_str[0..(val_str.len() - 2)],
45-
val_str.chars().last().unwrap()
46-
)
70+
output.push('\\');
4771
}
48-
})
72+
} else if c == '"' {
73+
output.push_str("\\\"");
74+
} else {
75+
output.push(c);
76+
}
4977
}
78+
79+
Cow::Owned(output)
5080
}
5181

5282
/// Escapes content for word arrays when converting to bracket delimiters.

0 commit comments

Comments
 (0)