]> git.madduck.net Git - etc/vim.git/blob - src/black/lines.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

48fde88820853deec0e5b6405a8b4bf116bf9fe4
[etc/vim.git] / src / black / lines.py
1 import itertools
2 import math
3 import sys
4 from dataclasses import dataclass, field
5 from typing import (
6     Callable,
7     Dict,
8     Iterator,
9     List,
10     Optional,
11     Sequence,
12     Tuple,
13     TypeVar,
14     Union,
15     cast,
16 )
17
18 from black.brackets import COMMA_PRIORITY, DOT_PRIORITY, BracketTracker
19 from black.mode import Mode, Preview
20 from black.nodes import (
21     BRACKETS,
22     CLOSING_BRACKETS,
23     OPENING_BRACKETS,
24     STANDALONE_COMMENT,
25     TEST_DESCENDANTS,
26     child_towards,
27     is_import,
28     is_multiline_string,
29     is_one_sequence_between,
30     is_type_comment,
31     is_type_ignore_comment,
32     is_with_or_async_with_stmt,
33     replace_child,
34     syms,
35     whitespace,
36 )
37 from black.strings import str_width
38 from blib2to3.pgen2 import token
39 from blib2to3.pytree import Leaf, Node
40
41 # types
42 T = TypeVar("T")
43 Index = int
44 LeafID = int
45 LN = Union[Leaf, Node]
46
47
48 @dataclass
49 class Line:
50     """Holds leaves and comments. Can be printed with `str(line)`."""
51
52     mode: Mode = field(repr=False)
53     depth: int = 0
54     leaves: List[Leaf] = field(default_factory=list)
55     # keys ordered like `leaves`
56     comments: Dict[LeafID, List[Leaf]] = field(default_factory=dict)
57     bracket_tracker: BracketTracker = field(default_factory=BracketTracker)
58     inside_brackets: bool = False
59     should_split_rhs: bool = False
60     magic_trailing_comma: Optional[Leaf] = None
61
62     def append(
63         self, leaf: Leaf, preformatted: bool = False, track_bracket: bool = False
64     ) -> None:
65         """Add a new `leaf` to the end of the line.
66
67         Unless `preformatted` is True, the `leaf` will receive a new consistent
68         whitespace prefix and metadata applied by :class:`BracketTracker`.
69         Trailing commas are maybe removed, unpacked for loop variables are
70         demoted from being delimiters.
71
72         Inline comments are put aside.
73         """
74         has_value = leaf.type in BRACKETS or bool(leaf.value.strip())
75         if not has_value:
76             return
77
78         if token.COLON == leaf.type and self.is_class_paren_empty:
79             del self.leaves[-2:]
80         if self.leaves and not preformatted:
81             # Note: at this point leaf.prefix should be empty except for
82             # imports, for which we only preserve newlines.
83             leaf.prefix += whitespace(
84                 leaf,
85                 complex_subscript=self.is_complex_subscript(leaf),
86                 mode=self.mode,
87             )
88         if self.inside_brackets or not preformatted or track_bracket:
89             self.bracket_tracker.mark(leaf)
90             if self.mode.magic_trailing_comma:
91                 if self.has_magic_trailing_comma(leaf):
92                     self.magic_trailing_comma = leaf
93             elif self.has_magic_trailing_comma(leaf, ensure_removable=True):
94                 self.remove_trailing_comma()
95         if not self.append_comment(leaf):
96             self.leaves.append(leaf)
97
98     def append_safe(self, leaf: Leaf, preformatted: bool = False) -> None:
99         """Like :func:`append()` but disallow invalid standalone comment structure.
100
101         Raises ValueError when any `leaf` is appended after a standalone comment
102         or when a standalone comment is not the first leaf on the line.
103         """
104         if self.bracket_tracker.depth == 0:
105             if self.is_comment:
106                 raise ValueError("cannot append to standalone comments")
107
108             if self.leaves and leaf.type == STANDALONE_COMMENT:
109                 raise ValueError(
110                     "cannot append standalone comments to a populated line"
111                 )
112
113         self.append(leaf, preformatted=preformatted)
114
115     @property
116     def is_comment(self) -> bool:
117         """Is this line a standalone comment?"""
118         return len(self.leaves) == 1 and self.leaves[0].type == STANDALONE_COMMENT
119
120     @property
121     def is_decorator(self) -> bool:
122         """Is this line a decorator?"""
123         return bool(self) and self.leaves[0].type == token.AT
124
125     @property
126     def is_import(self) -> bool:
127         """Is this an import line?"""
128         return bool(self) and is_import(self.leaves[0])
129
130     @property
131     def is_with_or_async_with_stmt(self) -> bool:
132         """Is this a with_stmt line?"""
133         return bool(self) and is_with_or_async_with_stmt(self.leaves[0])
134
135     @property
136     def is_class(self) -> bool:
137         """Is this line a class definition?"""
138         return (
139             bool(self)
140             and self.leaves[0].type == token.NAME
141             and self.leaves[0].value == "class"
142         )
143
144     @property
145     def is_stub_class(self) -> bool:
146         """Is this line a class definition with a body consisting only of "..."?"""
147         return self.is_class and self.leaves[-3:] == [
148             Leaf(token.DOT, ".") for _ in range(3)
149         ]
150
151     @property
152     def is_def(self) -> bool:
153         """Is this a function definition? (Also returns True for async defs.)"""
154         try:
155             first_leaf = self.leaves[0]
156         except IndexError:
157             return False
158
159         try:
160             second_leaf: Optional[Leaf] = self.leaves[1]
161         except IndexError:
162             second_leaf = None
163         return (first_leaf.type == token.NAME and first_leaf.value == "def") or (
164             first_leaf.type == token.ASYNC
165             and second_leaf is not None
166             and second_leaf.type == token.NAME
167             and second_leaf.value == "def"
168         )
169
170     @property
171     def is_stub_def(self) -> bool:
172         """Is this line a function definition with a body consisting only of "..."?"""
173         return self.is_def and self.leaves[-4:] == [Leaf(token.COLON, ":")] + [
174             Leaf(token.DOT, ".") for _ in range(3)
175         ]
176
177     @property
178     def is_class_paren_empty(self) -> bool:
179         """Is this a class with no base classes but using parentheses?
180
181         Those are unnecessary and should be removed.
182         """
183         return (
184             bool(self)
185             and len(self.leaves) == 4
186             and self.is_class
187             and self.leaves[2].type == token.LPAR
188             and self.leaves[2].value == "("
189             and self.leaves[3].type == token.RPAR
190             and self.leaves[3].value == ")"
191         )
192
193     @property
194     def is_triple_quoted_string(self) -> bool:
195         """Is the line a triple quoted string?"""
196         if not self or self.leaves[0].type != token.STRING:
197             return False
198         value = self.leaves[0].value
199         if value.startswith(('"""', "'''")):
200             return True
201         if Preview.accept_raw_docstrings in self.mode and value.startswith(
202             ("r'''", 'r"""', "R'''", 'R"""')
203         ):
204             return True
205         return False
206
207     @property
208     def opens_block(self) -> bool:
209         """Does this line open a new level of indentation."""
210         if len(self.leaves) == 0:
211             return False
212         return self.leaves[-1].type == token.COLON
213
214     def is_fmt_pass_converted(
215         self, *, first_leaf_matches: Optional[Callable[[Leaf], bool]] = None
216     ) -> bool:
217         """Is this line converted from fmt off/skip code?
218
219         If first_leaf_matches is not None, it only returns True if the first
220         leaf of converted code matches.
221         """
222         if len(self.leaves) != 1:
223             return False
224         leaf = self.leaves[0]
225         if (
226             leaf.type != STANDALONE_COMMENT
227             or leaf.fmt_pass_converted_first_leaf is None
228         ):
229             return False
230         return first_leaf_matches is None or first_leaf_matches(
231             leaf.fmt_pass_converted_first_leaf
232         )
233
234     def contains_standalone_comments(self, depth_limit: int = sys.maxsize) -> bool:
235         """If so, needs to be split before emitting."""
236         for leaf in self.leaves:
237             if leaf.type == STANDALONE_COMMENT and leaf.bracket_depth <= depth_limit:
238                 return True
239
240         return False
241
242     def contains_uncollapsable_type_comments(self) -> bool:
243         ignored_ids = set()
244         try:
245             last_leaf = self.leaves[-1]
246             ignored_ids.add(id(last_leaf))
247             if last_leaf.type == token.COMMA or (
248                 last_leaf.type == token.RPAR and not last_leaf.value
249             ):
250                 # When trailing commas or optional parens are inserted by Black for
251                 # consistency, comments after the previous last element are not moved
252                 # (they don't have to, rendering will still be correct).  So we ignore
253                 # trailing commas and invisible.
254                 last_leaf = self.leaves[-2]
255                 ignored_ids.add(id(last_leaf))
256         except IndexError:
257             return False
258
259         # A type comment is uncollapsable if it is attached to a leaf
260         # that isn't at the end of the line (since that could cause it
261         # to get associated to a different argument) or if there are
262         # comments before it (since that could cause it to get hidden
263         # behind a comment.
264         comment_seen = False
265         for leaf_id, comments in self.comments.items():
266             for comment in comments:
267                 if is_type_comment(comment):
268                     if comment_seen or (
269                         not is_type_ignore_comment(comment)
270                         and leaf_id not in ignored_ids
271                     ):
272                         return True
273
274                 comment_seen = True
275
276         return False
277
278     def contains_unsplittable_type_ignore(self) -> bool:
279         if not self.leaves:
280             return False
281
282         # If a 'type: ignore' is attached to the end of a line, we
283         # can't split the line, because we can't know which of the
284         # subexpressions the ignore was meant to apply to.
285         #
286         # We only want this to apply to actual physical lines from the
287         # original source, though: we don't want the presence of a
288         # 'type: ignore' at the end of a multiline expression to
289         # justify pushing it all onto one line. Thus we
290         # (unfortunately) need to check the actual source lines and
291         # only report an unsplittable 'type: ignore' if this line was
292         # one line in the original code.
293
294         # Grab the first and last line numbers, skipping generated leaves
295         first_line = next((leaf.lineno for leaf in self.leaves if leaf.lineno != 0), 0)
296         last_line = next(
297             (leaf.lineno for leaf in reversed(self.leaves) if leaf.lineno != 0), 0
298         )
299
300         if first_line == last_line:
301             # We look at the last two leaves since a comma or an
302             # invisible paren could have been added at the end of the
303             # line.
304             for node in self.leaves[-2:]:
305                 for comment in self.comments.get(id(node), []):
306                     if is_type_ignore_comment(comment):
307                         return True
308
309         return False
310
311     def contains_multiline_strings(self) -> bool:
312         return any(is_multiline_string(leaf) for leaf in self.leaves)
313
314     def has_magic_trailing_comma(
315         self, closing: Leaf, ensure_removable: bool = False
316     ) -> bool:
317         """Return True if we have a magic trailing comma, that is when:
318         - there's a trailing comma here
319         - it's not a one-tuple
320         - it's not a single-element subscript
321         Additionally, if ensure_removable:
322         - it's not from square bracket indexing
323         (specifically, single-element square bracket indexing)
324         """
325         if not (
326             closing.type in CLOSING_BRACKETS
327             and self.leaves
328             and self.leaves[-1].type == token.COMMA
329         ):
330             return False
331
332         if closing.type == token.RBRACE:
333             return True
334
335         if closing.type == token.RSQB:
336             if (
337                 closing.parent
338                 and closing.parent.type == syms.trailer
339                 and closing.opening_bracket
340                 and is_one_sequence_between(
341                     closing.opening_bracket,
342                     closing,
343                     self.leaves,
344                     brackets=(token.LSQB, token.RSQB),
345                 )
346             ):
347                 return False
348
349             if not ensure_removable:
350                 return True
351
352             comma = self.leaves[-1]
353             if comma.parent is None:
354                 return False
355             return (
356                 comma.parent.type != syms.subscriptlist
357                 or closing.opening_bracket is None
358                 or not is_one_sequence_between(
359                     closing.opening_bracket,
360                     closing,
361                     self.leaves,
362                     brackets=(token.LSQB, token.RSQB),
363                 )
364             )
365
366         if self.is_import:
367             return True
368
369         if closing.opening_bracket is not None and not is_one_sequence_between(
370             closing.opening_bracket, closing, self.leaves
371         ):
372             return True
373
374         return False
375
376     def append_comment(self, comment: Leaf) -> bool:
377         """Add an inline or standalone comment to the line."""
378         if (
379             comment.type == STANDALONE_COMMENT
380             and self.bracket_tracker.any_open_brackets()
381         ):
382             comment.prefix = ""
383             return False
384
385         if comment.type != token.COMMENT:
386             return False
387
388         if not self.leaves:
389             comment.type = STANDALONE_COMMENT
390             comment.prefix = ""
391             return False
392
393         last_leaf = self.leaves[-1]
394         if (
395             last_leaf.type == token.RPAR
396             and not last_leaf.value
397             and last_leaf.parent
398             and len(list(last_leaf.parent.leaves())) <= 3
399             and not is_type_comment(comment)
400         ):
401             # Comments on an optional parens wrapping a single leaf should belong to
402             # the wrapped node except if it's a type comment. Pinning the comment like
403             # this avoids unstable formatting caused by comment migration.
404             if len(self.leaves) < 2:
405                 comment.type = STANDALONE_COMMENT
406                 comment.prefix = ""
407                 return False
408
409             last_leaf = self.leaves[-2]
410         self.comments.setdefault(id(last_leaf), []).append(comment)
411         return True
412
413     def comments_after(self, leaf: Leaf) -> List[Leaf]:
414         """Generate comments that should appear directly after `leaf`."""
415         return self.comments.get(id(leaf), [])
416
417     def remove_trailing_comma(self) -> None:
418         """Remove the trailing comma and moves the comments attached to it."""
419         trailing_comma = self.leaves.pop()
420         trailing_comma_comments = self.comments.pop(id(trailing_comma), [])
421         self.comments.setdefault(id(self.leaves[-1]), []).extend(
422             trailing_comma_comments
423         )
424
425     def is_complex_subscript(self, leaf: Leaf) -> bool:
426         """Return True iff `leaf` is part of a slice with non-trivial exprs."""
427         open_lsqb = self.bracket_tracker.get_open_lsqb()
428         if open_lsqb is None:
429             return False
430
431         subscript_start = open_lsqb.next_sibling
432
433         if isinstance(subscript_start, Node):
434             if subscript_start.type == syms.listmaker:
435                 return False
436
437             if subscript_start.type == syms.subscriptlist:
438                 subscript_start = child_towards(subscript_start, leaf)
439         return subscript_start is not None and any(
440             n.type in TEST_DESCENDANTS for n in subscript_start.pre_order()
441         )
442
443     def enumerate_with_length(
444         self, reversed: bool = False
445     ) -> Iterator[Tuple[Index, Leaf, int]]:
446         """Return an enumeration of leaves with their length.
447
448         Stops prematurely on multiline strings and standalone comments.
449         """
450         op = cast(
451             Callable[[Sequence[Leaf]], Iterator[Tuple[Index, Leaf]]],
452             enumerate_reversed if reversed else enumerate,
453         )
454         for index, leaf in op(self.leaves):
455             length = len(leaf.prefix) + len(leaf.value)
456             if "\n" in leaf.value:
457                 return  # Multiline strings, we can't continue.
458
459             for comment in self.comments_after(leaf):
460                 length += len(comment.value)
461
462             yield index, leaf, length
463
464     def clone(self) -> "Line":
465         return Line(
466             mode=self.mode,
467             depth=self.depth,
468             inside_brackets=self.inside_brackets,
469             should_split_rhs=self.should_split_rhs,
470             magic_trailing_comma=self.magic_trailing_comma,
471         )
472
473     def __str__(self) -> str:
474         """Render the line."""
475         if not self:
476             return "\n"
477
478         indent = "    " * self.depth
479         leaves = iter(self.leaves)
480         first = next(leaves)
481         res = f"{first.prefix}{indent}{first.value}"
482         for leaf in leaves:
483             res += str(leaf)
484         for comment in itertools.chain.from_iterable(self.comments.values()):
485             res += str(comment)
486
487         return res + "\n"
488
489     def __bool__(self) -> bool:
490         """Return True if the line has leaves or comments."""
491         return bool(self.leaves or self.comments)
492
493
494 @dataclass
495 class RHSResult:
496     """Intermediate split result from a right hand split."""
497
498     head: Line
499     body: Line
500     tail: Line
501     opening_bracket: Leaf
502     closing_bracket: Leaf
503
504
505 @dataclass
506 class LinesBlock:
507     """Class that holds information about a block of formatted lines.
508
509     This is introduced so that the EmptyLineTracker can look behind the standalone
510     comments and adjust their empty lines for class or def lines.
511     """
512
513     mode: Mode
514     previous_block: Optional["LinesBlock"]
515     original_line: Line
516     before: int = 0
517     content_lines: List[str] = field(default_factory=list)
518     after: int = 0
519
520     def all_lines(self) -> List[str]:
521         empty_line = str(Line(mode=self.mode))
522         return (
523             [empty_line * self.before] + self.content_lines + [empty_line * self.after]
524         )
525
526
527 @dataclass
528 class EmptyLineTracker:
529     """Provides a stateful method that returns the number of potential extra
530     empty lines needed before and after the currently processed line.
531
532     Note: this tracker works on lines that haven't been split yet.  It assumes
533     the prefix of the first leaf consists of optional newlines.  Those newlines
534     are consumed by `maybe_empty_lines()` and included in the computation.
535     """
536
537     mode: Mode
538     previous_line: Optional[Line] = None
539     previous_block: Optional[LinesBlock] = None
540     previous_defs: List[Line] = field(default_factory=list)
541     semantic_leading_comment: Optional[LinesBlock] = None
542
543     def maybe_empty_lines(self, current_line: Line) -> LinesBlock:
544         """Return the number of extra empty lines before and after the `current_line`.
545
546         This is for separating `def`, `async def` and `class` with extra empty
547         lines (two on module-level).
548         """
549         before, after = self._maybe_empty_lines(current_line)
550         previous_after = self.previous_block.after if self.previous_block else 0
551         before = (
552             # Black should not insert empty lines at the beginning
553             # of the file
554             0
555             if self.previous_line is None
556             else before - previous_after
557         )
558         if (
559             Preview.module_docstring_newlines in current_line.mode
560             and self.previous_block
561             and self.previous_block.previous_block is None
562             and len(self.previous_block.original_line.leaves) == 1
563             and self.previous_block.original_line.is_triple_quoted_string
564         ):
565             before = 1
566
567         block = LinesBlock(
568             mode=self.mode,
569             previous_block=self.previous_block,
570             original_line=current_line,
571             before=before,
572             after=after,
573         )
574
575         # Maintain the semantic_leading_comment state.
576         if current_line.is_comment:
577             if self.previous_line is None or (
578                 not self.previous_line.is_decorator
579                 # `or before` means this comment already has an empty line before
580                 and (not self.previous_line.is_comment or before)
581                 and (self.semantic_leading_comment is None or before)
582             ):
583                 self.semantic_leading_comment = block
584         # `or before` means this decorator already has an empty line before
585         elif not current_line.is_decorator or before:
586             self.semantic_leading_comment = None
587
588         self.previous_line = current_line
589         self.previous_block = block
590         return block
591
592     def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
593         max_allowed = 1
594         if current_line.depth == 0:
595             max_allowed = 1 if self.mode.is_pyi else 2
596         if current_line.leaves:
597             # Consume the first leaf's extra newlines.
598             first_leaf = current_line.leaves[0]
599             before = first_leaf.prefix.count("\n")
600             before = min(before, max_allowed)
601             first_leaf.prefix = ""
602         else:
603             before = 0
604
605         user_had_newline = bool(before)
606         depth = current_line.depth
607
608         previous_def = None
609         while self.previous_defs and self.previous_defs[-1].depth >= depth:
610             previous_def = self.previous_defs.pop()
611
612         if previous_def is not None:
613             assert self.previous_line is not None
614             if self.mode.is_pyi:
615                 if depth and not current_line.is_def and self.previous_line.is_def:
616                     # Empty lines between attributes and methods should be preserved.
617                     before = 1 if user_had_newline else 0
618                 elif (
619                     Preview.blank_line_after_nested_stub_class in self.mode
620                     and previous_def.is_class
621                     and not previous_def.is_stub_class
622                 ):
623                     before = 1
624                 elif depth:
625                     before = 0
626                 else:
627                     before = 1
628             else:
629                 if depth:
630                     before = 1
631                 elif (
632                     not depth
633                     and previous_def.depth
634                     and current_line.leaves[-1].type == token.COLON
635                     and (
636                         current_line.leaves[0].value
637                         not in ("with", "try", "for", "while", "if", "match")
638                     )
639                 ):
640                     # We shouldn't add two newlines between an indented function and
641                     # a dependent non-indented clause. This is to avoid issues with
642                     # conditional function definitions that are technically top-level
643                     # and therefore get two trailing newlines, but look weird and
644                     # inconsistent when they're followed by elif, else, etc. This is
645                     # worse because these functions only get *one* preceding newline
646                     # already.
647                     before = 1
648                 else:
649                     before = 2
650
651         if current_line.is_decorator or current_line.is_def or current_line.is_class:
652             return self._maybe_empty_lines_for_class_or_def(
653                 current_line, before, user_had_newline
654             )
655
656         if (
657             self.previous_line
658             and self.previous_line.is_import
659             and not current_line.is_import
660             and not current_line.is_fmt_pass_converted(first_leaf_matches=is_import)
661             and depth == self.previous_line.depth
662         ):
663             return (before or 1), 0
664
665         if (
666             self.previous_line
667             and self.previous_line.is_class
668             and current_line.is_triple_quoted_string
669         ):
670             if Preview.no_blank_line_before_class_docstring in current_line.mode:
671                 return 0, 1
672             return before, 1
673
674         if self.previous_line and self.previous_line.opens_block:
675             return 0, 0
676         return before, 0
677
678     def _maybe_empty_lines_for_class_or_def(  # noqa: C901
679         self, current_line: Line, before: int, user_had_newline: bool
680     ) -> Tuple[int, int]:
681         if not current_line.is_decorator:
682             self.previous_defs.append(current_line)
683         if self.previous_line is None:
684             # Don't insert empty lines before the first line in the file.
685             return 0, 0
686
687         if self.previous_line.is_decorator:
688             if self.mode.is_pyi and current_line.is_stub_class:
689                 # Insert an empty line after a decorated stub class
690                 return 0, 1
691
692             return 0, 0
693
694         if self.previous_line.depth < current_line.depth and (
695             self.previous_line.is_class or self.previous_line.is_def
696         ):
697             return 0, 0
698
699         comment_to_add_newlines: Optional[LinesBlock] = None
700         if (
701             self.previous_line.is_comment
702             and self.previous_line.depth == current_line.depth
703             and before == 0
704         ):
705             slc = self.semantic_leading_comment
706             if (
707                 slc is not None
708                 and slc.previous_block is not None
709                 and not slc.previous_block.original_line.is_class
710                 and not slc.previous_block.original_line.opens_block
711                 and slc.before <= 1
712             ):
713                 comment_to_add_newlines = slc
714             else:
715                 return 0, 0
716
717         if self.mode.is_pyi:
718             if current_line.is_class or self.previous_line.is_class:
719                 if self.previous_line.depth < current_line.depth:
720                     newlines = 0
721                 elif self.previous_line.depth > current_line.depth:
722                     newlines = 1
723                 elif current_line.is_stub_class and self.previous_line.is_stub_class:
724                     # No blank line between classes with an empty body
725                     newlines = 0
726                 else:
727                     newlines = 1
728             # Remove case `self.previous_line.depth > current_line.depth` below when
729             # this becomes stable.
730             #
731             # Don't inspect the previous line if it's part of the body of the previous
732             # statement in the same level, we always want a blank line if there's
733             # something with a body preceding.
734             elif (
735                 Preview.blank_line_between_nested_and_def_stub_file in current_line.mode
736                 and self.previous_line.depth > current_line.depth
737             ):
738                 newlines = 1
739             elif (
740                 current_line.is_def or current_line.is_decorator
741             ) and not self.previous_line.is_def:
742                 if current_line.depth:
743                     # In classes empty lines between attributes and methods should
744                     # be preserved.
745                     newlines = min(1, before)
746                 else:
747                     # Blank line between a block of functions (maybe with preceding
748                     # decorators) and a block of non-functions
749                     newlines = 1
750             elif self.previous_line.depth > current_line.depth:
751                 newlines = 1
752             else:
753                 newlines = 0
754         else:
755             newlines = 1 if current_line.depth else 2
756             # If a user has left no space after a dummy implementation, don't insert
757             # new lines. This is useful for instance for @overload or Protocols.
758             if (
759                 Preview.dummy_implementations in self.mode
760                 and self.previous_line.is_stub_def
761                 and not user_had_newline
762             ):
763                 newlines = 0
764         if comment_to_add_newlines is not None:
765             previous_block = comment_to_add_newlines.previous_block
766             if previous_block is not None:
767                 comment_to_add_newlines.before = (
768                     max(comment_to_add_newlines.before, newlines) - previous_block.after
769                 )
770                 newlines = 0
771         return newlines, 0
772
773
774 def enumerate_reversed(sequence: Sequence[T]) -> Iterator[Tuple[Index, T]]:
775     """Like `reversed(enumerate(sequence))` if that were possible."""
776     index = len(sequence) - 1
777     for element in reversed(sequence):
778         yield (index, element)
779         index -= 1
780
781
782 def append_leaves(
783     new_line: Line, old_line: Line, leaves: List[Leaf], preformatted: bool = False
784 ) -> None:
785     """
786     Append leaves (taken from @old_line) to @new_line, making sure to fix the
787     underlying Node structure where appropriate.
788
789     All of the leaves in @leaves are duplicated. The duplicates are then
790     appended to @new_line and used to replace their originals in the underlying
791     Node structure. Any comments attached to the old leaves are reattached to
792     the new leaves.
793
794     Pre-conditions:
795         set(@leaves) is a subset of set(@old_line.leaves).
796     """
797     for old_leaf in leaves:
798         new_leaf = Leaf(old_leaf.type, old_leaf.value)
799         replace_child(old_leaf, new_leaf)
800         new_line.append(new_leaf, preformatted=preformatted)
801
802         for comment_leaf in old_line.comments_after(old_leaf):
803             new_line.append(comment_leaf, preformatted=True)
804
805
806 def is_line_short_enough(  # noqa: C901
807     line: Line, *, mode: Mode, line_str: str = ""
808 ) -> bool:
809     """For non-multiline strings, return True if `line` is no longer than `line_length`.
810     For multiline strings, looks at the context around `line` to determine
811     if it should be inlined or split up.
812     Uses the provided `line_str` rendering, if any, otherwise computes a new one.
813     """
814     if not line_str:
815         line_str = line_to_string(line)
816
817     width = str_width if mode.preview else len
818
819     if Preview.multiline_string_handling not in mode:
820         return (
821             width(line_str) <= mode.line_length
822             and "\n" not in line_str  # multiline strings
823             and not line.contains_standalone_comments()
824         )
825
826     if line.contains_standalone_comments():
827         return False
828     if "\n" not in line_str:
829         # No multiline strings (MLS) present
830         return width(line_str) <= mode.line_length
831
832     first, *_, last = line_str.split("\n")
833     if width(first) > mode.line_length or width(last) > mode.line_length:
834         return False
835
836     # Traverse the AST to examine the context of the multiline string (MLS),
837     # tracking aspects such as depth and comma existence,
838     # to determine whether to split the MLS or keep it together.
839     # Depth (which is based on the existing bracket_depth concept)
840     # is needed to determine nesting level of the MLS.
841     # Includes special case for trailing commas.
842     commas: List[int] = []  # tracks number of commas per depth level
843     multiline_string: Optional[Leaf] = None
844     # store the leaves that contain parts of the MLS
845     multiline_string_contexts: List[LN] = []
846
847     max_level_to_update: Union[int, float] = math.inf  # track the depth of the MLS
848     for i, leaf in enumerate(line.leaves):
849         if max_level_to_update == math.inf:
850             had_comma: Optional[int] = None
851             if leaf.bracket_depth + 1 > len(commas):
852                 commas.append(0)
853             elif leaf.bracket_depth + 1 < len(commas):
854                 had_comma = commas.pop()
855             if (
856                 had_comma is not None
857                 and multiline_string is not None
858                 and multiline_string.bracket_depth == leaf.bracket_depth + 1
859             ):
860                 # Have left the level with the MLS, stop tracking commas
861                 max_level_to_update = leaf.bracket_depth
862                 if had_comma > 0:
863                     # MLS was in parens with at least one comma - force split
864                     return False
865
866         if leaf.bracket_depth <= max_level_to_update and leaf.type == token.COMMA:
867             # Ignore non-nested trailing comma
868             # directly after MLS/MLS-containing expression
869             ignore_ctxs: List[Optional[LN]] = [None]
870             ignore_ctxs += multiline_string_contexts
871             if not (leaf.prev_sibling in ignore_ctxs and i == len(line.leaves) - 1):
872                 commas[leaf.bracket_depth] += 1
873         if max_level_to_update != math.inf:
874             max_level_to_update = min(max_level_to_update, leaf.bracket_depth)
875
876         if is_multiline_string(leaf):
877             if len(multiline_string_contexts) > 0:
878                 # >1 multiline string cannot fit on a single line - force split
879                 return False
880             multiline_string = leaf
881             ctx: LN = leaf
882             # fetch the leaf components of the MLS in the AST
883             while str(ctx) in line_str:
884                 multiline_string_contexts.append(ctx)
885                 if ctx.parent is None:
886                     break
887                 ctx = ctx.parent
888
889     # May not have a triple-quoted multiline string at all,
890     # in case of a regular string with embedded newlines and line continuations
891     if len(multiline_string_contexts) == 0:
892         return True
893
894     return all(val == 0 for val in commas)
895
896
897 def can_be_split(line: Line) -> bool:
898     """Return False if the line cannot be split *for sure*.
899
900     This is not an exhaustive search but a cheap heuristic that we can use to
901     avoid some unfortunate formattings (mostly around wrapping unsplittable code
902     in unnecessary parentheses).
903     """
904     leaves = line.leaves
905     if len(leaves) < 2:
906         return False
907
908     if leaves[0].type == token.STRING and leaves[1].type == token.DOT:
909         call_count = 0
910         dot_count = 0
911         next = leaves[-1]
912         for leaf in leaves[-2::-1]:
913             if leaf.type in OPENING_BRACKETS:
914                 if next.type not in CLOSING_BRACKETS:
915                     return False
916
917                 call_count += 1
918             elif leaf.type == token.DOT:
919                 dot_count += 1
920             elif leaf.type == token.NAME:
921                 if not (next.type == token.DOT or next.type in OPENING_BRACKETS):
922                     return False
923
924             elif leaf.type not in CLOSING_BRACKETS:
925                 return False
926
927             if dot_count > 1 and call_count > 1:
928                 return False
929
930     return True
931
932
933 def can_omit_invisible_parens(
934     rhs: RHSResult,
935     line_length: int,
936 ) -> bool:
937     """Does `rhs.body` have a shape safe to reformat without optional parens around it?
938
939     Returns True for only a subset of potentially nice looking formattings but
940     the point is to not return false positives that end up producing lines that
941     are too long.
942     """
943     line = rhs.body
944     bt = line.bracket_tracker
945     if not bt.delimiters:
946         # Without delimiters the optional parentheses are useless.
947         return True
948
949     max_priority = bt.max_delimiter_priority()
950     delimiter_count = bt.delimiter_count_with_priority(max_priority)
951     if delimiter_count > 1:
952         # With more than one delimiter of a kind the optional parentheses read better.
953         return False
954
955     if delimiter_count == 1:
956         if (
957             Preview.wrap_multiple_context_managers_in_parens in line.mode
958             and max_priority == COMMA_PRIORITY
959             and rhs.head.is_with_or_async_with_stmt
960         ):
961             # For two context manager with statements, the optional parentheses read
962             # better. In this case, `rhs.body` is the context managers part of
963             # the with statement. `rhs.head` is the `with (` part on the previous
964             # line.
965             return False
966         # Otherwise it may also read better, but we don't do it today and requires
967         # careful considerations for all possible cases. See
968         # https://github.com/psf/black/issues/2156.
969
970     if max_priority == DOT_PRIORITY:
971         # A single stranded method call doesn't require optional parentheses.
972         return True
973
974     assert len(line.leaves) >= 2, "Stranded delimiter"
975
976     # With a single delimiter, omit if the expression starts or ends with
977     # a bracket.
978     first = line.leaves[0]
979     second = line.leaves[1]
980     if first.type in OPENING_BRACKETS and second.type not in CLOSING_BRACKETS:
981         if _can_omit_opening_paren(line, first=first, line_length=line_length):
982             return True
983
984         # Note: we are not returning False here because a line might have *both*
985         # a leading opening bracket and a trailing closing bracket.  If the
986         # opening bracket doesn't match our rule, maybe the closing will.
987
988     penultimate = line.leaves[-2]
989     last = line.leaves[-1]
990
991     if (
992         last.type == token.RPAR
993         or last.type == token.RBRACE
994         or (
995             # don't use indexing for omitting optional parentheses;
996             # it looks weird
997             last.type == token.RSQB
998             and last.parent
999             and last.parent.type != syms.trailer
1000         )
1001     ):
1002         if penultimate.type in OPENING_BRACKETS:
1003             # Empty brackets don't help.
1004             return False
1005
1006         if is_multiline_string(first):
1007             # Additional wrapping of a multiline string in this situation is
1008             # unnecessary.
1009             return True
1010
1011         if _can_omit_closing_paren(line, last=last, line_length=line_length):
1012             return True
1013
1014     return False
1015
1016
1017 def _can_omit_opening_paren(line: Line, *, first: Leaf, line_length: int) -> bool:
1018     """See `can_omit_invisible_parens`."""
1019     remainder = False
1020     length = 4 * line.depth
1021     _index = -1
1022     for _index, leaf, leaf_length in line.enumerate_with_length():
1023         if leaf.type in CLOSING_BRACKETS and leaf.opening_bracket is first:
1024             remainder = True
1025         if remainder:
1026             length += leaf_length
1027             if length > line_length:
1028                 break
1029
1030             if leaf.type in OPENING_BRACKETS:
1031                 # There are brackets we can further split on.
1032                 remainder = False
1033
1034     else:
1035         # checked the entire string and line length wasn't exceeded
1036         if len(line.leaves) == _index + 1:
1037             return True
1038
1039     return False
1040
1041
1042 def _can_omit_closing_paren(line: Line, *, last: Leaf, line_length: int) -> bool:
1043     """See `can_omit_invisible_parens`."""
1044     length = 4 * line.depth
1045     seen_other_brackets = False
1046     for _index, leaf, leaf_length in line.enumerate_with_length():
1047         length += leaf_length
1048         if leaf is last.opening_bracket:
1049             if seen_other_brackets or length <= line_length:
1050                 return True
1051
1052         elif leaf.type in OPENING_BRACKETS:
1053             # There are brackets we can further split on.
1054             seen_other_brackets = True
1055
1056     return False
1057
1058
1059 def line_to_string(line: Line) -> str:
1060     """Returns the string representation of @line.
1061
1062     WARNING: This is known to be computationally expensive.
1063     """
1064     return str(line).strip("\n")