Skip to content

Commit 15233fd

Browse files
committed
Add a new knob to allow logical operators to split
This comes from the issue #844 where logical operators are bin-packed if the line is too long instead of wrapping nicely one to each line
1 parent 25f8111 commit 15233fd

File tree

3 files changed

+93
-15
lines changed

3 files changed

+93
-15
lines changed

yapf/yapflib/format_decision_state.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,37 @@ def SurroundedByParens(token):
544544
if not self._FitsOnLine(previous, previous.matching_bracket):
545545
return True
546546

547+
###########################################################################
548+
# Logical Operator Splitting
549+
if style.Get('SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT'):
550+
split_before = style.Get("SPLIT_BEFORE_LOGICAL_OPERATOR")
551+
check_token = current if split_before else current.previous_token
552+
if (check_token and check_token.name == "NAME" and check_token.value in logical_line._LOGICAL_OPERATORS):
553+
opening = _GetOpeningBracket(check_token)
554+
if opening:
555+
ending = opening.matching_bracket
556+
length = ending.total_length - opening.total_length
557+
length += self.stack[-1].indent
558+
# If we're keeping it on a single line, but the next token is also
559+
# a logical operator then we have to consider that as part of the
560+
# length because we might wrap after it
561+
next_token = ending.next_token
562+
prev_token = opening.previous_token
563+
if split_before:
564+
if prev_token:
565+
clause_start = _PrevLogicalClause(prev_token)
566+
length += opening.total_length - clause_start.total_length
567+
else:
568+
if next_token:
569+
clause_end = _NextLogicalClause(next_token)
570+
length += clause_end.total_length - ending.total_length
571+
else:
572+
end_token = _LastTokenInLine(check_token)
573+
length = end_token.total_length + self.stack[-1].indent
574+
575+
if length >= self.column_limit:
576+
return True
577+
547578
###########################################################################
548579
# Original Formatting Splitting
549580
# These checks rely upon the original formatting. This is in order to
@@ -1159,6 +1190,26 @@ def _LastTokenInLine(current):
11591190
return current
11601191

11611192

1193+
def _NextLogicalClause(token):
1194+
""" Get the start of the next logical clause or the last token in the line"""
1195+
while token:
1196+
if token in logical_line._LOGICAL_OPERATORS:
1197+
return token
1198+
if not token.next_token:
1199+
return token
1200+
token = token.next_token
1201+
1202+
1203+
def _PrevLogicalClause(token):
1204+
""" Get the start of the previous logical clause or the first token"""
1205+
while token:
1206+
if token.value in logical_line._LOGICAL_OPERATORS:
1207+
return token
1208+
if not token.previous_token:
1209+
return token
1210+
token = token.previous_token
1211+
1212+
11621213
def _IsFunctionDefinition(current):
11631214
prev = current.previous_token
11641215
return current.value == '(' and prev and subtypes.FUNC_DEF in prev.subtypes

yapf/yapflib/logical_line.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -610,21 +610,40 @@ def _SplitPenalty(prev_token, cur_token):
610610
if pval == 'not':
611611
return split_penalty.UNBREAKABLE
612612

613-
if cur_token.node_split_penalty > 0:
614-
return cur_token.node_split_penalty
615-
616-
if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
617-
# Prefer to split before 'and' and 'or'.
618-
if pval in _LOGICAL_OPERATORS:
619-
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
620-
if cval in _LOGICAL_OPERATORS:
621-
return 0
622-
else:
623-
# Prefer to split after 'and' and 'or'.
624-
if pval in _LOGICAL_OPERATORS:
625-
return 0
626-
if cval in _LOGICAL_OPERATORS:
627-
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
613+
node_split_penalty = cur_token.node_split_penalty
614+
615+
logical_splitting = style.Get('SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT')
616+
617+
if logical_splitting:
618+
if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
619+
# Prefer to split before 'and' and 'or'.
620+
if pval in _LOGICAL_OPERATORS:
621+
return max(node_split_penalty, style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR'))
622+
if cval in _LOGICAL_OPERATORS:
623+
return max(node_split_penalty, 0)
624+
else:
625+
# Prefer to split after 'and' and 'or'.
626+
if pval in _LOGICAL_OPERATORS:
627+
return max(node_split_penalty, 0)
628+
if cval in _LOGICAL_OPERATORS:
629+
return max(node_split_penalty, style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR'))
630+
631+
if node_split_penalty > 0:
632+
return node_split_penalty
633+
634+
if not logical_splitting:
635+
if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
636+
# Prefer to split before 'and' and 'or'.
637+
if pval in _LOGICAL_OPERATORS:
638+
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
639+
if cval in _LOGICAL_OPERATORS:
640+
return 0
641+
else:
642+
# Prefer to split after 'and' and 'or'.
643+
if pval in _LOGICAL_OPERATORS:
644+
return 0
645+
if cval in _LOGICAL_OPERATORS:
646+
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
628647

629648
if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'):
630649
# Prefer to split before '&', '|', and '^'.

yapf/yapflib/style.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ def method():
339339
SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\
340340
Split before arguments.
341341
"""),
342+
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=textwrap.dedent("""\
343+
If a line that contains logical operators needs to be split, split on all
344+
the logical operators in that line. This will treat logical operators
345+
in sub-clauses defined by parentheses as a discrete element that will
346+
ignore wrapping unless the entire clause is longer than the column width.
347+
"""),
342348
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\
343349
Split before arguments, but do not split all subexpressions recursively
344350
(unless needed).
@@ -497,6 +503,7 @@ def CreatePEP8Style():
497503
SPACES_AROUND_TUPLE_DELIMITERS=False,
498504
SPACES_BEFORE_COMMENT=2,
499505
SPLIT_ALL_COMMA_SEPARATED_VALUES=False,
506+
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=False,
500507
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=False,
501508
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False,
502509
SPLIT_BEFORE_ARITHMETIC_OPERATOR=False,
@@ -685,6 +692,7 @@ def _IntOrIntListConverter(s):
685692
SPACES_AROUND_TUPLE_DELIMITERS=_BoolConverter,
686693
SPACES_BEFORE_COMMENT=_IntOrIntListConverter,
687694
SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter,
695+
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=_BoolConverter,
688696
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=_BoolConverter,
689697
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter,
690698
SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter,

0 commit comments

Comments
 (0)