format_strings: take into account newline occurring within a rewritten line
This commit is contained in:
parent
4c1b0c2241
commit
4b26723e55
5 changed files with 105 additions and 3 deletions
|
@ -19,12 +19,19 @@ use utils::wrap_str;
|
||||||
|
|
||||||
const MIN_STRING: usize = 10;
|
const MIN_STRING: usize = 10;
|
||||||
|
|
||||||
|
/// Describes the layout of a piece of text.
|
||||||
pub struct StringFormat<'a> {
|
pub struct StringFormat<'a> {
|
||||||
|
/// The opening sequence of characters for the piece of text
|
||||||
pub opener: &'a str,
|
pub opener: &'a str,
|
||||||
|
/// The closing sequence of characters for the piece of text
|
||||||
pub closer: &'a str,
|
pub closer: &'a str,
|
||||||
|
/// The opening sequence of characters for a line
|
||||||
pub line_start: &'a str,
|
pub line_start: &'a str,
|
||||||
|
/// The closing sequence of characters for a line
|
||||||
pub line_end: &'a str,
|
pub line_end: &'a str,
|
||||||
|
/// The allocated box to fit the text into
|
||||||
pub shape: Shape,
|
pub shape: Shape,
|
||||||
|
/// Trim trailing whitespaces
|
||||||
pub trim_end: bool,
|
pub trim_end: bool,
|
||||||
pub config: &'a Config,
|
pub config: &'a Config,
|
||||||
}
|
}
|
||||||
|
@ -129,6 +136,9 @@ enum SnippetState {
|
||||||
EndOfInput(String),
|
EndOfInput(String),
|
||||||
/// The input could be broken and the returned snippet should be ended with a
|
/// The input could be broken and the returned snippet should be ended with a
|
||||||
/// `[StringFormat::line_end]`. The next snippet needs to be indented.
|
/// `[StringFormat::line_end]`. The next snippet needs to be indented.
|
||||||
|
/// The returned string is the line to print out and the number is the length that got read in
|
||||||
|
/// the text being rewritten. That length may be greater than the returned string if trailing
|
||||||
|
/// whitespaces got trimmed.
|
||||||
LineEnd(String, usize),
|
LineEnd(String, usize),
|
||||||
/// The input could be broken but the returned snippet should not be ended with a
|
/// The input could be broken but the returned snippet should not be ended with a
|
||||||
/// `[StringFormat::line_end]` because the whitespace is significant. Therefore, the next
|
/// `[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
|
||||||
// check if there is a line feed, in which case whitespaces needs to be kept.
|
// check if there is a line feed, in which case whitespaces needs to be kept.
|
||||||
let mut index_minus_ws = index;
|
let mut index_minus_ws = index;
|
||||||
for (i, grapheme) in input[0..=index].iter().enumerate().rev() {
|
for (i, grapheme) in input[0..=index].iter().enumerate().rev() {
|
||||||
if !trim_end && is_line_feed(grapheme) {
|
if !is_whitespace(grapheme) {
|
||||||
return SnippetState::Overflow(input[0..=i].join("").to_string(), i + 1);
|
|
||||||
} else if !is_whitespace(grapheme) {
|
|
||||||
index_minus_ws = i;
|
index_minus_ws = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Take into account newlines occuring in input[0..=index], i.e., the possible next new
|
||||||
|
// line. If there is one, then text after it could be rewritten in a way that the available
|
||||||
|
// space is fully used.
|
||||||
|
for (i, grapheme) in input[0..=index].iter().enumerate() {
|
||||||
|
if is_line_feed(grapheme) {
|
||||||
|
if i < index_minus_ws || !trim_end {
|
||||||
|
return SnippetState::Overflow(input[0..=i].join("").to_string(), i + 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut index_plus_ws = index;
|
let mut index_plus_ws = index;
|
||||||
for (i, grapheme) in input[index + 1..].iter().enumerate() {
|
for (i, grapheme) in input[index + 1..].iter().enumerate() {
|
||||||
if !trim_end && is_line_feed(grapheme) {
|
if !trim_end && is_line_feed(grapheme) {
|
||||||
|
@ -224,6 +244,7 @@ fn is_punctuation(grapheme: &str) -> bool {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{break_string, rewrite_string, SnippetState, StringFormat};
|
use super::{break_string, rewrite_string, SnippetState, StringFormat};
|
||||||
|
use config::Config;
|
||||||
use shape::{Indent, Shape};
|
use shape::{Indent, Shape};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
|
@ -318,4 +339,28 @@ mod test {
|
||||||
SnippetState::LineEnd("Neque in sem.".to_string(), 25)
|
SnippetState::LineEnd("Neque in sem.".to_string(), 25)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newline_in_candidate_line() {
|
||||||
|
let string = "Nulla\nconsequat erat at massa. Vivamus id mi.";
|
||||||
|
|
||||||
|
let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
|
||||||
|
assert_eq!(
|
||||||
|
break_string(25, false, &graphemes[..]),
|
||||||
|
SnippetState::Overflow("Nulla\n".to_string(), 6)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
break_string(25, true, &graphemes[..]),
|
||||||
|
SnippetState::Overflow("Nulla\n".to_string(), 6)
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut config: Config = Default::default();
|
||||||
|
config.set().max_width(27);
|
||||||
|
let fmt = StringFormat::new(Shape::legacy(25, Indent::empty()), &config);
|
||||||
|
let rewritten_string = rewrite_string(string, &fmt);
|
||||||
|
assert_eq!(
|
||||||
|
rewritten_string,
|
||||||
|
Some("\"Nulla\nconsequat erat at massa. \\\n Vivamus id mi.\"".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
25
tests/target/format_strings/issue-202.rs
Normal file
25
tests/target/format_strings/issue-202.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// rustfmt-format_strings: true
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compile_empty_program() {
|
||||||
|
let result = get_result();
|
||||||
|
let expected = "; ModuleID = \'foo\'
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
declare void @llvm.memset.p0i8.i32(i8* nocapture, i8, i32, i32, i1) #0
|
||||||
|
|
||||||
|
declare i32 @write(i32, i8*, i32)
|
||||||
|
|
||||||
|
declare i32 @putchar(i32)
|
||||||
|
|
||||||
|
declare i32 @getchar()
|
||||||
|
|
||||||
|
define i32 @main() {
|
||||||
|
entry:
|
||||||
|
ret i32 0
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes #0 = { nounwind }
|
||||||
|
";
|
||||||
|
assert_eq!(result, CString::new(expected).unwrap());
|
||||||
|
}
|
15
tests/target/format_strings/issue-2833.rs
Normal file
15
tests/target/format_strings/issue-2833.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// rustfmt-format_strings: true
|
||||||
|
// rustfmt-max_width: 80
|
||||||
|
|
||||||
|
fn test1() {
|
||||||
|
let expected = "\
|
||||||
|
but Doctor Watson has to have it taken out for him and dusted,
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test2() {
|
||||||
|
let expected = "\
|
||||||
|
[Omitted long matching line]
|
||||||
|
but Doctor Watson has to have it taken out for him and dusted,
|
||||||
|
";
|
||||||
|
}
|
10
tests/target/format_strings/issue-687.rs
Normal file
10
tests/target/format_strings/issue-687.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// rustfmt-format_strings: true
|
||||||
|
|
||||||
|
fn foo() -> &'static str {
|
||||||
|
let sql = "ATTACH DATABASE ':memory:' AS my_attached;
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE my_attached.foo(x INTEGER);
|
||||||
|
INSERT INTO my_attached.foo VALUES(42);
|
||||||
|
END;";
|
||||||
|
sql
|
||||||
|
}
|
7
tests/target/format_strings/issue564.rs
Normal file
7
tests/target/format_strings/issue564.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// rustfmt-format_strings: true
|
||||||
|
|
||||||
|
const USAGE: &'static str = "
|
||||||
|
Usage: codegen project <name> <digits> <len> <codes> <prizes> <step> <shift>
|
||||||
|
codegen regenerate <name>
|
||||||
|
codegen verify <name> <code>
|
||||||
|
";
|
Loading…
Reference in a new issue