Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit c3edf6d

Browse files
committed
Fix indent computation of a macro with braces.
The leading whitespace of a multine string was taken into account when computing the `min_prefix_space_width`, even if that line couldn't be trimmed. The consequence is it was always shifting the macro's content to the right.
1 parent 81a4235 commit c3edf6d

File tree

4 files changed

+354
-15
lines changed

4 files changed

+354
-15
lines changed

src/comment.rs

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,10 @@ pub enum FullCodeCharKind {
821821
InComment,
822822
/// Last character of a comment, '\n' for a line comment, '/' for a block comment.
823823
EndComment,
824+
/// Start of a mutlitine string
825+
StartString,
826+
/// End of a mutlitine string
827+
EndString,
824828
/// Inside a string.
825829
InString,
826830
}
@@ -836,7 +840,7 @@ impl FullCodeCharKind {
836840
}
837841

838842
pub fn is_string(self) -> bool {
839-
self == FullCodeCharKind::InString
843+
self == FullCodeCharKind::InString || self == FullCodeCharKind::StartString
840844
}
841845

842846
fn to_codecharkind(self) -> CodeCharKind {
@@ -924,17 +928,14 @@ where
924928
_ => CharClassesStatus::Normal, // Unreachable
925929
}
926930
}
927-
CharClassesStatus::LitString => match chr {
928-
'"' => CharClassesStatus::Normal,
929-
'\\' => {
930-
char_kind = FullCodeCharKind::InString;
931-
CharClassesStatus::LitStringEscape
932-
}
933-
_ => {
934-
char_kind = FullCodeCharKind::InString;
935-
CharClassesStatus::LitString
931+
CharClassesStatus::LitString => {
932+
char_kind = FullCodeCharKind::InString;
933+
match chr {
934+
'"' => CharClassesStatus::Normal,
935+
'\\' => CharClassesStatus::LitStringEscape,
936+
_ => CharClassesStatus::LitString,
936937
}
937-
},
938+
}
938939
CharClassesStatus::LitStringEscape => {
939940
char_kind = FullCodeCharKind::InString;
940941
CharClassesStatus::LitString
@@ -1052,9 +1053,22 @@ impl<'a> Iterator for LineClasses<'a> {
10521053

10531054
let mut line = String::new();
10541055

1056+
let start_class = match self.base.peek() {
1057+
Some((kind, _)) => *kind,
1058+
None => FullCodeCharKind::Normal,
1059+
};
1060+
10551061
while let Some((kind, c)) = self.base.next() {
1056-
self.kind = kind;
10571062
if c == '\n' {
1063+
self.kind = match (start_class, kind) {
1064+
(FullCodeCharKind::Normal, FullCodeCharKind::InString) => {
1065+
FullCodeCharKind::StartString
1066+
}
1067+
(FullCodeCharKind::InString, FullCodeCharKind::Normal) => {
1068+
FullCodeCharKind::EndString
1069+
}
1070+
_ => kind,
1071+
};
10581072
break;
10591073
} else {
10601074
line.push(c);
@@ -1227,7 +1241,10 @@ pub fn recover_comment_removed(
12271241
pub fn filter_normal_code(code: &str) -> String {
12281242
let mut buffer = String::with_capacity(code.len());
12291243
LineClasses::new(code).for_each(|(kind, line)| match kind {
1230-
FullCodeCharKind::Normal | FullCodeCharKind::InString => {
1244+
FullCodeCharKind::Normal
1245+
| FullCodeCharKind::StartString
1246+
| FullCodeCharKind::InString
1247+
| FullCodeCharKind::EndString => {
12311248
buffer.push_str(&line);
12321249
buffer.push('\n');
12331250
}

src/macros.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,7 @@ fn indent_macro_snippet(
11181118
} else {
11191119
Some(get_prefix_space_width(context, &line))
11201120
};
1121+
11211122
let line = if veto_trim || (kind.is_string() && !line.ends_with('\\')) {
11221123
veto_trim = kind.is_string() && !line.ends_with('\\');
11231124
trimmed = false;
@@ -1126,7 +1127,12 @@ fn indent_macro_snippet(
11261127
line.trim().to_owned()
11271128
};
11281129
trimmed_lines.push((trimmed, line, prefix_space_width));
1129-
prefix_space_width
1130+
1131+
// when computing the minimum, do not consider lines within a string
1132+
match kind {
1133+
FullCodeCharKind::InString | FullCodeCharKind::EndString => None,
1134+
_ => prefix_space_width,
1135+
}
11301136
}).min()?;
11311137

11321138
Some(
@@ -1139,7 +1145,7 @@ fn indent_macro_snippet(
11391145
let new_indent_width = indent.width() + original_indent_width
11401146
.saturating_sub(min_prefix_space_width);
11411147
let new_indent = Indent::from_width(context.config, new_indent_width);
1142-
format!("{}{}", new_indent.to_string(context.config), line.trim())
1148+
format!("{}{}", new_indent.to_string(context.config), line)
11431149
}
11441150
None => String::new(),
11451151
},

tests/source/issue-2973.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#[cfg(test)]
2+
mod test {
3+
summary_test! {
4+
tokenize_recipe_interpolation_eol,
5+
"foo: # some comment
6+
{{hello}}
7+
",
8+
"foo: \
9+
{{hello}} \
10+
{{ahah}}",
11+
"N:#$>^{N}$<.",
12+
}
13+
14+
summary_test! {
15+
tokenize_strings,
16+
r#"a = "'a'" + '"b"' + "'c'" + '"d"'#echo hello"#,
17+
r#"N="+'+"+'#."#,
18+
}
19+
20+
summary_test! {
21+
tokenize_recipe_interpolation_eol,
22+
"foo: # some comment
23+
{{hello}}
24+
",
25+
"N:#$>^{N}$<.",
26+
}
27+
28+
summary_test! {
29+
tokenize_recipe_interpolation_eof,
30+
"foo: # more comments
31+
{{hello}}
32+
# another comment
33+
",
34+
"N:#$>^{N}$<#$.",
35+
}
36+
37+
summary_test! {
38+
tokenize_recipe_complex_interpolation_expression,
39+
"foo: #lol\n {{a + b + \"z\" + blarg}}",
40+
"N:#$>^{N+N+\"+N}<.",
41+
}
42+
43+
summary_test! {
44+
tokenize_recipe_multiple_interpolations,
45+
"foo:,#ok\n {{a}}0{{b}}1{{c}}",
46+
"N:,#$>^{N}_{N}_{N}<.",
47+
}
48+
49+
summary_test! {
50+
tokenize_junk,
51+
"bob
52+
53+
hello blah blah blah : a b c #whatever
54+
",
55+
"N$$NNNN:NNN#$.",
56+
}
57+
58+
summary_test! {
59+
tokenize_empty_lines,
60+
"
61+
# this does something
62+
hello:
63+
asdf
64+
bsdf
65+
66+
csdf
67+
68+
dsdf # whatever
69+
70+
# yolo
71+
",
72+
"$#$N:$>^_$^_$$^_$$^_$$<#$.",
73+
}
74+
75+
summary_test! {
76+
tokenize_comment_before_variable,
77+
"
78+
#
79+
A='1'
80+
echo:
81+
echo {{A}}
82+
",
83+
"$#$N='$N:$>^_{N}$<.",
84+
}
85+
86+
summary_test! {
87+
tokenize_interpolation_backticks,
88+
"hello:\n echo {{`echo hello` + `echo goodbye`}}",
89+
"N:$>^_{`+`}<.",
90+
}
91+
92+
summary_test! {
93+
tokenize_assignment_backticks,
94+
"a = `echo hello` + `echo goodbye`",
95+
"N=`+`.",
96+
}
97+
98+
summary_test! {
99+
tokenize_multiple,
100+
"
101+
hello:
102+
a
103+
b
104+
105+
c
106+
107+
d
108+
109+
# hello
110+
bob:
111+
frank
112+
",
113+
114+
"$N:$>^_$^_$$^_$$^_$$<#$N:$>^_$<.",
115+
}
116+
117+
summary_test! {
118+
tokenize_comment,
119+
"a:=#",
120+
"N:=#."
121+
}
122+
123+
summary_test! {
124+
tokenize_comment_with_bang,
125+
"a:=#foo!",
126+
"N:=#."
127+
}
128+
129+
summary_test! {
130+
tokenize_order,
131+
r"
132+
b: a
133+
@mv a b
134+
135+
a:
136+
@touch F
137+
@touch a
138+
139+
d: c
140+
@rm c
141+
142+
c: b
143+
@mv b c",
144+
"$N:N$>^_$$<N:$>^_$^_$$<N:N$>^_$$<N:N$>^_<.",
145+
}
146+
147+
summary_test! {
148+
tokenize_parens,
149+
r"((())) )abc(+",
150+
"((())))N(+.",
151+
}
152+
153+
summary_test! {
154+
crlf_newline,
155+
"#\r\n#asdf\r\n",
156+
"#$#$.",
157+
}
158+
}

0 commit comments

Comments
 (0)