Repository: psf/black
File: src/black/linegen.py (Python)

Code before:
                if docstring[0] == quote_char:
                    docstring = " " + docstring
                if docstring[-1] == quote_char:
                    docstring += " "
                if docstring[-1] == "\\":
                    backslash_count = len(docstring) - len(docstring.rstrip("\\"))
                    if backslash_count % 2:
                        # Odd number of tailing backslashes, add some padding to
                        # avoid escaping the closing string quote.
                        docstring += " "
            elif not docstring_started_empty:
                docstring = " "

            # We could enforce triple quotes at this point.
            quote = quote_char * quote_len

            if Preview.long_docstring_quotes_on_newline in self.mode:
                # Put closing quotes on new line if max line length exceeded
                last_line_length = len(docstring.splitlines()[-1]) if docstring else 0

                # Make the docstring apart from the closing quotes, which happen below
                docstring = prefix + quote + docstring
                if (
                    len(indent) + len(prefix) + 2 * len(quote) + last_line_length
                    <= self.mode.line_length
                ):
                    docstring += quote
                else:
                    docstring += "\n" + indent + quote

                leaf.value = docstring
            else:
                leaf.value = prefix + quote + docstring + quote

        yield from self.visit_default(leaf)

    def __post_init__(self) -> None:
        """You are in a twisty little maze of passages."""
        self.current_line = Line(mode=self.mode)

        v = self.visit_stmt
        Ø: Set[str] = set()
        self.visit_assert_stmt = partial(v, keywords={"assert"}, parens={"assert", ","})
        self.visit_if_stmt = partial(
            v, keywords={"if", "else", "elif"}, parens={"if", "elif"}
        )
        self.visit_while_stmt = partial(v, keywords={"while", "else"}, parens={"while"})
        self.visit_for_stmt = partial(v, keywords={"for", "else"}, parens={"for", "in"})
        self.visit_try_stmt = partial(
            v, keywords={"try", "except", "else", "finally"}, parens=Ø
        )

Review comment (bug):
I've tried to think this through, but I'm not 100 % still. Wouldn't this be incorrect if we had a multiline docstring whose last line was just acceptable? We would sum the prefix and quote length to it and refuse to add quotes at the end.

```python
def foo():
    """first line---------------------------------------------------------------

    second line--------------------------------------------------------------"""
```

In any case, a test about this would be nice too.

Code after:
                if docstring[0] == quote_char:
                    docstring = " " + docstring
                if docstring[-1] == quote_char:
                    docstring += " "
                if docstring[-1] == "\\":
                    backslash_count = len(docstring) - len(docstring.rstrip("\\"))
                    if backslash_count % 2:
                        # Odd number of tailing backslashes, add some padding to
                        # avoid escaping the closing string quote.
                        docstring += " "
            elif not docstring_started_empty:
                docstring = " "

            # We could enforce triple quotes at this point.
            quote = quote_char * quote_len

            if Preview.long_docstring_quotes_on_newline in self.mode:
                # We need to find the length of the last line of the docstring
                # to find if we can add the closing quotes to the line without
                # exceeding the maximum line length.
                # If docstring is one line, then we need to add the length
                # of the indent, prefix, and starting quotes. Ending quote are
                # handled later
                lines = docstring.splitlines()
                last_line_length = len(lines[-1]) if docstring else 0

                if len(lines) == 1:
                    last_line_length += len(indent) + len(prefix) + quote_len

                # If adding closing quotes would cause the last line to exceed
                # the maximum line length then put a line break before the
                # closing quotes
                if last_line_length + quote_len > self.mode.line_length:
                    leaf.value = prefix + quote + docstring + "\n" + indent + quote
                else:
                    leaf.value = prefix + quote + docstring + quote
            else:
                leaf.value = prefix + quote + docstring + quote

        yield from self.visit_default(leaf)

    def __post_init__(self) -> None:
        """You are in a twisty little maze of passages."""
        self.current_line = Line(mode=self.mode)

        v = self.visit_stmt
        Ø: Set[str] = set()
        self.visit_assert_stmt = partial(v, keywords={"assert"}, parens={"assert", ","})
        self.visit_if_stmt = partial(
            v, keywords={"if", "else", "elif"}, parens={"if", "elif"}
        )