Skip to content

Commit 383a23d

Browse files
authored
Merge pull request #3073 from scampi/format_strings
format_strings: take into account newline occurring within a rewritten line
2 parents 4c1b0c2 + 4b26723 commit 383a23d

File tree

5 files changed

+105
-3
lines changed

5 files changed

+105
-3
lines changed

src/string.rs

+48-3
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,19 @@ use utils::wrap_str;
1919

2020
const MIN_STRING: usize = 10;
2121

22+
/// Describes the layout of a piece of text.
2223
pub struct StringFormat<'a> {
24+
/// The opening sequence of characters for the piece of text
2325
pub opener: &'a str,
26+
/// The closing sequence of characters for the piece of text
2427
pub closer: &'a str,
28+
/// The opening sequence of characters for a line
2529
pub line_start: &'a str,
30+
/// The closing sequence of characters for a line
2631
pub line_end: &'a str,
32+
/// The allocated box to fit the text into
2733
pub shape: Shape,
34+
/// Trim trailing whitespaces
2835
pub trim_end: bool,
2936
pub config: &'a Config,
3037
}
@@ -129,6 +136,9 @@ enum SnippetState {
129136
EndOfInput(String),
130137
/// The input could be broken and the returned snippet should be ended with a
131138
/// `[StringFormat::line_end]`. The next snippet needs to be indented.
139+
/// The returned string is the line to print out and the number is the length that got read in
140+
/// the text being rewritten. That length may be greater than the returned string if trailing
141+
/// whitespaces got trimmed.
132142
LineEnd(String, usize),
133143
/// The input could be broken but the returned snippet should not be ended with a
134144
/// `[StringFormat::line_end]` because the whitespace is significant. Therefore, the next
@@ -144,13 +154,23 @@ fn break_string(max_chars: usize, trim_end: bool, input: &[&str]) -> SnippetStat
144154
// check if there is a line feed, in which case whitespaces needs to be kept.
145155
let mut index_minus_ws = index;
146156
for (i, grapheme) in input[0..=index].iter().enumerate().rev() {
147-
if !trim_end && is_line_feed(grapheme) {
148-
return SnippetState::Overflow(input[0..=i].join("").to_string(), i + 1);
149-
} else if !is_whitespace(grapheme) {
157+
if !is_whitespace(grapheme) {
150158
index_minus_ws = i;
151159
break;
152160
}
153161
}
162+
// Take into account newlines occuring in input[0..=index], i.e., the possible next new
163+
// line. If there is one, then text after it could be rewritten in a way that the available
164+
// space is fully used.
165+
for (i, grapheme) in input[0..=index].iter().enumerate() {
166+
if is_line_feed(grapheme) {
167+
if i < index_minus_ws || !trim_end {
168+
return SnippetState::Overflow(input[0..=i].join("").to_string(), i + 1);
169+
}
170+
break;
171+
}
172+
}
173+
154174
let mut index_plus_ws = index;
155175
for (i, grapheme) in input[index + 1..].iter().enumerate() {
156176
if !trim_end && is_line_feed(grapheme) {
@@ -224,6 +244,7 @@ fn is_punctuation(grapheme: &str) -> bool {
224244
#[cfg(test)]
225245
mod test {
226246
use super::{break_string, rewrite_string, SnippetState, StringFormat};
247+
use config::Config;
227248
use shape::{Indent, Shape};
228249
use unicode_segmentation::UnicodeSegmentation;
229250

@@ -318,4 +339,28 @@ mod test {
318339
SnippetState::LineEnd("Neque in sem.".to_string(), 25)
319340
);
320341
}
342+
343+
#[test]
344+
fn newline_in_candidate_line() {
345+
let string = "Nulla\nconsequat erat at massa. Vivamus id mi.";
346+
347+
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
348+
assert_eq!(
349+
break_string(25, false, &graphemes[..]),
350+
SnippetState::Overflow("Nulla\n".to_string(), 6)
351+
);
352+
assert_eq!(
353+
break_string(25, true, &graphemes[..]),
354+
SnippetState::Overflow("Nulla\n".to_string(), 6)
355+
);
356+
357+
let mut config: Config = Default::default();
358+
config.set().max_width(27);
359+
let fmt = StringFormat::new(Shape::legacy(25, Indent::empty()), &config);
360+
let rewritten_string = rewrite_string(string, &fmt);
361+
assert_eq!(
362+
rewritten_string,
363+
Some("\"Nulla\nconsequat erat at massa. \\\n Vivamus id mi.\"".to_string())
364+
);
365+
}
321366
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// rustfmt-format_strings: true
2+
3+
#[test]
4+
fn compile_empty_program() {
5+
let result = get_result();
6+
let expected = "; ModuleID = \'foo\'
7+
8+
; Function Attrs: nounwind
9+
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) #0
10+
11+
declare i32 @write(i32, i8*, i32)
12+
13+
declare i32 @putchar(i32)
14+
15+
declare i32 @getchar()
16+
17+
define i32 @main() {
18+
entry:
19+
ret i32 0
20+
}
21+
22+
attributes #0 = { nounwind }
23+
";
24+
assert_eq!(result, CString::new(expected).unwrap());
25+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// rustfmt-format_strings: true
2+
// rustfmt-max_width: 80
3+
4+
fn test1() {
5+
let expected = "\
6+
but Doctor Watson has to have it taken out for him and dusted,
7+
";
8+
}
9+
10+
fn test2() {
11+
let expected = "\
12+
[Omitted long matching line]
13+
but Doctor Watson has to have it taken out for him and dusted,
14+
";
15+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// rustfmt-format_strings: true
2+
3+
fn foo() -> &'static str {
4+
let sql = "ATTACH DATABASE ':memory:' AS my_attached;
5+
BEGIN;
6+
CREATE TABLE my_attached.foo(x INTEGER);
7+
INSERT INTO my_attached.foo VALUES(42);
8+
END;";
9+
sql
10+
}
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// rustfmt-format_strings: true
2+
3+
const USAGE: &'static str = "
4+
Usage: codegen project <name> <digits> <len> <codes> <prizes> <step> <shift>
5+
codegen regenerate <name>
6+
codegen verify <name> <code>
7+
";

0 commit comments

Comments
 (0)