diff --git a/src/comment.rs b/src/comment.rs index f9d8a0fa70c..eb195b1f762 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -796,7 +796,7 @@ impl<'a> CommentRewrite<'a> { // 1) wrap_comments = true is configured // 2) The comment is not the start of a markdown header doc comment // 3) The comment width exceeds the shape's width - // 4) No URLS were found in the commnet + // 4) No URLS were found in the comment let should_wrap_comment = self.fmt.config.wrap_comments() && !is_markdown_header_doc_comment && unicode_str_width(line) > self.fmt.shape.width diff --git a/src/string.rs b/src/string.rs index b65aa5b33b2..78b72a50cb2 100644 --- a/src/string.rs +++ b/src/string.rs @@ -315,20 +315,21 @@ fn break_string(max_width: usize, trim_end: bool, line_end: &str, input: &[&str] // Found a whitespace and what is on its left side is big enough. Some(index) if index >= MIN_STRING => break_at(index), // No whitespace found, try looking for a punctuation instead - _ => match input[0..max_width_index_in_input] - .iter() - .rposition(|grapheme| is_punctuation(grapheme)) + _ => match (0..max_width_index_in_input) + .rev() + .skip_while(|pos| !is_valid_linebreak(input, *pos)) + .next() { // Found a punctuation and what is on its left side is big enough. Some(index) if index >= MIN_STRING => break_at(index), // Either no boundary character was found to the left of `input[max_chars]`, or the line // got too small. We try searching for a boundary character to the right. - _ => match input[max_width_index_in_input..] - .iter() - .position(|grapheme| is_whitespace(grapheme) || is_punctuation(grapheme)) + _ => match (max_width_index_in_input..input.len()) + .skip_while(|pos| !is_valid_linebreak(input, *pos)) + .next() { // A boundary was found after the line limit - Some(index) => break_at(max_width_index_in_input + index), + Some(index) => break_at(index), // No boundary to the right, the input cannot be broken None => SnippetState::EndOfInput(input.concat()), }, @@ -336,6 +337,23 @@ fn break_string(max_width: usize, trim_end: bool, line_end: &str, input: &[&str] } } +fn is_valid_linebreak(input: &[&str], pos: usize) -> bool { + let is_whitespace = is_whitespace(input[pos]); + if is_whitespace { + return true; + } + let is_punctuation = is_punctuation(input[pos]); + if is_punctuation && !is_part_of_type(input, pos) { + return true; + } + false +} + +fn is_part_of_type(input: &[&str], pos: usize) -> bool { + input.get(pos..=pos + 1) == Some(&[":", ":"]) + || input.get(pos.saturating_sub(1)..=pos) == Some(&[":", ":"]) +} + fn is_new_line(grapheme: &str) -> bool { let bytes = grapheme.as_bytes(); bytes.starts_with(b"\n") || bytes.starts_with(b"\r\n") @@ -369,6 +387,19 @@ mod test { rewrite_string("eq_", &fmt, 2); } + #[test] + fn line_break_at_valid_points_test() { + let string = "[TheName](Dont::break::my::type::That::would::be::very::nice) break here"; + let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>(); + assert_eq!( + break_string(20, false, "", &graphemes[..]), + SnippetState::LineEnd( + "[TheName](Dont::break::my::type::That::would::be::very::nice) ".to_string(), + 62 + ) + ); + } + #[test] fn should_break_on_whitespace() { let string = "Placerat felis. Mauris porta ante sagittis purus."; diff --git a/src/test/mod.rs b/src/test/mod.rs index 4191e3e96b0..2e674702c13 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -90,9 +90,15 @@ where } fn is_file_skip(path: &Path) -> bool { - SKIP_FILE_WHITE_LIST - .iter() - .any(|file_path| is_subpath(path, file_path)) + let filter_file = std::env::var("TEST_FILE").ok(); + let skip_file = filter_file + .map(|filter_file| !path.to_str().unwrap().contains(&filter_file)) + .unwrap_or(false); + + skip_file + || SKIP_FILE_WHITE_LIST + .iter() + .any(|file_path| is_subpath(path, file_path)) } // Returns a `Vec` containing `PathBuf`s of files with an `rs` extension in the diff --git a/tests/source/issue-5260.rs b/tests/source/issue-5260.rs new file mode 100644 index 00000000000..c52571a5623 --- /dev/null +++ b/tests/source/issue-5260.rs @@ -0,0 +1,7 @@ +// rustfmt-wrap_comments: true + +/// [MyType](VeryLongPathToMyType::NoLineBreak::Here::Okay::ThatWouldBeNice::Thanks) +fn documented_with_longtype() { + // # We're using a markdown header in an inline comment. rustfmt should be + // able to wrap this comment when `wrap_comments = true` +} diff --git a/tests/target/issue-5260.rs b/tests/target/issue-5260.rs new file mode 100644 index 00000000000..c52571a5623 --- /dev/null +++ b/tests/target/issue-5260.rs @@ -0,0 +1,7 @@ +// rustfmt-wrap_comments: true + +/// [MyType](VeryLongPathToMyType::NoLineBreak::Here::Okay::ThatWouldBeNice::Thanks) +fn documented_with_longtype() { + // # We're using a markdown header in an inline comment. rustfmt should be + // able to wrap this comment when `wrap_comments = true` +}