Skip to content

Commit 9cdfc20

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 8dde773 commit 9cdfc20

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
@@ -555,6 +555,37 @@ def SurroundedByParens(token):
555555
if not self._FitsOnLine(previous, previous.matching_bracket):
556556
return True
557557

558+
###########################################################################
559+
# Logical Operator Splitting
560+
if style.Get('SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT'):
561+
split_before = style.Get("SPLIT_BEFORE_LOGICAL_OPERATOR")
562+
check_token = current if split_before else current.previous_token
563+
if (check_token and check_token.name == "NAME" and check_token.value in logical_line._LOGICAL_OPERATORS):
564+
opening = _GetOpeningBracket(check_token)
565+
if opening:
566+
ending = opening.matching_bracket
567+
length = ending.total_length - opening.total_length
568+
length += self.stack[-1].indent
569+
# If we're keeping it on a single line, but the next token is also
570+
# a logical operator then we have to consider that as part of the
571+
# length because we might wrap after it
572+
next_token = ending.next_token
573+
prev_token = opening.previous_token
574+
if split_before:
575+
if prev_token:
576+
clause_start = _PrevLogicalClause(prev_token)
577+
length += opening.total_length - clause_start.total_length
578+
else:
579+
if next_token:
580+
clause_end = _NextLogicalClause(next_token)
581+
length += clause_end.total_length - ending.total_length
582+
else:
583+
end_token = _LastTokenInLine(check_token)
584+
length = end_token.total_length + self.stack[-1].indent
585+
586+
if length >= self.column_limit:
587+
return True
588+
558589
###########################################################################
559590
# Original Formatting Splitting
560591
# These checks rely upon the original formatting. This is in order to
@@ -1181,6 +1212,26 @@ def _LastTokenInLine(current):
11811212
return current
11821213

11831214

1215+
def _NextLogicalClause(token):
1216+
""" Get the start of the next logical clause or the last token in the line"""
1217+
while token:
1218+
if token in logical_line._LOGICAL_OPERATORS:
1219+
return token
1220+
if not token.next_token:
1221+
return token
1222+
token = token.next_token
1223+
1224+
1225+
def _PrevLogicalClause(token):
1226+
""" Get the start of the previous logical clause or the first token"""
1227+
while token:
1228+
if token.value in logical_line._LOGICAL_OPERATORS:
1229+
return token
1230+
if not token.previous_token:
1231+
return token
1232+
token = token.previous_token
1233+
1234+
11841235
def _IsFunctionDefinition(current):
11851236
prev = current.previous_token
11861237
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
@@ -345,6 +345,12 @@ def method():
345345
SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\
346346
Split before arguments.
347347
"""),
348+
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=textwrap.dedent("""\
349+
If a line that contains logical operators needs to be split, split on all
350+
the logical operators in that line. This will treat logical operators
351+
in sub-clauses defined by parentheses as a discrete element that will
352+
ignore wrapping unless the entire clause is longer than the column width.
353+
"""),
348354
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\
349355
Split before arguments, but do not split all subexpressions recursively
350356
(unless needed).
@@ -503,6 +509,7 @@ def CreatePEP8Style():
503509
SPACES_AROUND_TUPLE_DELIMITERS=False,
504510
SPACES_BEFORE_COMMENT=2,
505511
SPLIT_ALL_COMMA_SEPARATED_VALUES=False,
512+
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=False,
506513
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=False,
507514
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False,
508515
SPLIT_BEFORE_ARITHMETIC_OPERATOR=False,
@@ -691,6 +698,7 @@ def _IntOrIntListConverter(s):
691698
SPACES_AROUND_TUPLE_DELIMITERS=_BoolConverter,
692699
SPACES_BEFORE_COMMENT=_IntOrIntListConverter,
693700
SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter,
701+
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=_BoolConverter,
694702
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=_BoolConverter,
695703
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter,
696704
SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter,

0 commit comments

Comments
 (0)