Repository: psf/black

Issue:
Crash with line-length 18 and backslash in docstring
Code:
```python
def multiline_backslash_2():
    """
    hey there \ """
```
On Black 22.12.0:

```
% black --preview --diff tests/data/miscellaneous/docstring_no_string_normalization.py -l 18
error: cannot format tests/data/miscellaneous/docstring_no_string_normalization.py: INTERNAL ERROR: Black produced code that is not equivalent to the source.  Please report a bug on https://github.com/psf/black/issues.  This diff might be helpful: /var/folders/3b/k964cnv10097wzj3h7w07fww0000gp/T/blk_jh8pb654.log

Oh no! 💥 💔 💥
1 file would fail to reformat.
% cat /var/folders/3b/k964cnv10097wzj3h7w07fww0000gp/T/blk_jh8pb654.log

--- src
+++ dst
@@ -18,11 +18,11 @@
           value=
             Constant(
               kind=
                 None,  # NoneType
               value=
-                'hey there \\',  # str
+                'hey there',  # str
             )  # /Constant
         )  # /Expr
       decorator_list=
       name=
         'multiline_backslash_2',  # str
```

Discussion:
github-actions[bot]: **diff-shades** reports zero changes comparing this PR (b5d15be22f0cc30eceb808a8e7a10dd2db0330dd) to main (cd9fef8bab3a39dfba494f1917e4158faba439f9).

---

[**What is this?**](https://black.readthedocs.io/en/latest/contributing/gauging_changes.html#diff-shades) | [Workflow run](https://github.com/psf/black/actions/runs/3727850560) | [diff-shades documentation](https://github.com/ichard26/diff-shades#readme)
Danday999: ****
JelleZijlstra: Thanks, just fixed the merge.

Patch:
diff --git a/CHANGES.md b/CHANGES.md
index 2da0fb4..17dc0d6 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -32,6 +32,7 @@
 - Long values in dict literals are now wrapped in parentheses; correspondingly
   unnecessary parentheses around short values in dict literals are now removed; long
   string lambda values are now wrapped in parentheses (#3440)
+- Fix two crashes in preview style involving edge cases with docstrings (#3451)
 - Exclude string type annotations from improved string processing; fix crash when the
   return type annotation is stringified and spans across multiple lines (#3462)
 
diff --git a/src/black/linegen.py b/src/black/linegen.py
index 4da75b2..da41886 100644
--- a/src/black/linegen.py
+++ b/src/black/linegen.py
@@ -401,6 +401,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
             else:
                 docstring = docstring.strip()
 
+            has_trailing_backslash = False
             if docstring:
                 # Add some padding if the docstring starts / ends with a quote mark.
                 if docstring[0] == quote_char:
@@ -413,6 +414,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
                         # Odd number of tailing backslashes, add some padding to
                         # avoid escaping the closing string quote.
                         docstring += " "
+                        has_trailing_backslash = True
             elif not docstring_started_empty:
                 docstring = " "
 
@@ -435,6 +437,8 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
                 if (
                     len(lines) > 1
                     and last_line_length + quote_len > self.mode.line_length
+                    and len(indent) + quote_len <= self.mode.line_length
+                    and not has_trailing_backslash
                 ):
                     leaf.value = prefix + quote + docstring + "\n" + indent + quote
                 else:


Test patch:
diff --git a/tests/data/miscellaneous/linelength6.py b/tests/data/miscellaneous/linelength6.py
new file mode 100644
index 0000000..4fb3427
--- /dev/null
+++ b/tests/data/miscellaneous/linelength6.py
@@ -0,0 +1,5 @@
+# Regression test for #3427, which reproes only with line length <= 6
+def f():
+    """
+    x
+    """
diff --git a/tests/data/simple_cases/docstring.py b/tests/data/simple_cases/docstring.py
index f08bba5..c31d6a6 100644
--- a/tests/data/simple_cases/docstring.py
+++ b/tests/data/simple_cases/docstring.py
@@ -173,6 +173,11 @@ def multiline_backslash_2():
   '''
   hey there \ '''
 
+# Regression test for #3425
+def multiline_backslash_really_long_dont_crash():
+    """
+    hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
+
 
 def multiline_backslash_3():
   '''
@@ -391,6 +396,12 @@ def multiline_backslash_2():
     hey there \ """
 
 
+# Regression test for #3425
+def multiline_backslash_really_long_dont_crash():
+    """
+    hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
+
+
 def multiline_backslash_3():
     """
     already escaped \\"""
diff --git a/tests/test_format.py b/tests/test_format.py
index 01cd61e..0816bbd 100644
--- a/tests/test_format.py
+++ b/tests/test_format.py
@@ -146,6 +146,13 @@ def test_docstring_no_string_normalization() -> None:
     assert_format(source, expected, mode)
 
 
+def test_docstring_line_length_6() -> None:
+    """Like test_docstring but with line length set to 6."""
+    source, expected = read_data("miscellaneous", "linelength6")
+    mode = black.Mode(line_length=6)
+    assert_format(source, expected, mode)
+
+
 def test_preview_docstring_no_string_normalization() -> None:
     """
     Like test_docstring but with string normalization off *and* the preview style