]> git.lizzy.rs Git - rust.git/blobdiff - src/string.rs
Merge commit 'c4416f20dcaec5d93077f72470e83e150fb923b1' into sync-rustfmt
[rust.git] / src / string.rs
index 080c4f17788237879a01a27657b5d1bbe05562e8..78b72a50cb2f96250ec94b1c86579d1246798424 100644 (file)
@@ -57,7 +57,7 @@ fn max_width_with_indent(&self) -> Option<usize> {
     /// This allows to fit more graphemes from the string on a line when
     /// SnippetState::EndWithLineFeed.
     fn max_width_without_indent(&self) -> Option<usize> {
-        Some(self.config.max_width().checked_sub(self.line_end.len())?)
+        self.config.max_width().checked_sub(self.line_end.len())
     }
 }
 
@@ -99,7 +99,7 @@ pub(crate) fn rewrite_string<'a>(
                 if is_new_line(grapheme) {
                     // take care of blank lines
                     result = trim_end_but_line_feed(fmt.trim_end, result);
-                    result.push_str("\n");
+                    result.push('\n');
                     if !is_bareline_ok && cur_start + i + 1 < graphemes.len() {
                         result.push_str(&indent_without_newline);
                         result.push_str(fmt.line_start);
@@ -153,7 +153,7 @@ pub(crate) fn rewrite_string<'a>(
     wrap_str(result, fmt.config.max_width(), fmt.shape)
 }
 
-/// Returns the index to the end of the URL if the split at index of the given string includes an
+/// Returns the index to the end of the URL if the split at index of the given string includes a
 /// URL or alike. Otherwise, returns `None`.
 fn detect_url(s: &[&str], index: usize) -> Option<usize> {
     let start = match s[..=index].iter().rposition(|g| is_whitespace(g)) {
@@ -278,6 +278,9 @@ fn break_string(max_width: usize, trim_end: bool, line_end: &str, input: &[&str]
         }
         cur_index
     };
+    if max_width_index_in_input == 0 {
+        return SnippetState::EndOfInput(input.concat());
+    }
 
     // Find the position in input for breaking the string
     if line_end.is_empty()
@@ -301,7 +304,7 @@ fn break_string(max_width: usize, trim_end: bool, line_end: &str, input: &[&str]
         return if trim_end {
             SnippetState::LineEnd(input[..=url_index_end].concat(), index_plus_ws + 1)
         } else {
-            return SnippetState::LineEnd(input[..=index_plus_ws].concat(), index_plus_ws + 1);
+            SnippetState::LineEnd(input[..=index_plus_ws].concat(), index_plus_ws + 1)
         };
     }
 
@@ -312,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()),
             },
@@ -333,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")
@@ -366,6 +387,19 @@ fn issue343() {
         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.";