Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/logical split #1126

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions yapf/yapflib/format_decision_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,36 @@ def SurroundedByParens(token):
if not self._FitsOnLine(previous, previous.matching_bracket):
return True

###########################################################################
# Logical Operator Splitting
if style.Get('SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT'):
split_before = style.Get("SPLIT_BEFORE_LOGICAL_OPERATOR")
check_token = current if split_before else current.previous_token
if (check_token and check_token.name == "NAME" and
check_token.value in logical_line._LOGICAL_OPERATORS):
opening = _GetOpeningBracket(check_token)
if opening:
ending = opening.matching_bracket
length = ending.total_length - opening.total_length
length += self.stack[-1].indent
# If we're keeping it on a single line, but the next token is also
# a logical operator then we have to consider that as part of the
# length because we might wrap after it
next_token = ending.next_token
prev_token = opening.previous_token
if split_before and prev_token:
clause_start = _PrevLogicalClause(prev_token)
length += opening.total_length - clause_start.total_length
elif not split_before and next_token:
clause_end = _NextLogicalClause(next_token)
length += clause_end.total_length - ending.total_length
else:
end_token = _LastTokenInLine(check_token)
length = end_token.total_length + self.stack[-1].indent

if length >= self.column_limit:
return True

###########################################################################
# Original Formatting Splitting
# These checks rely upon the original formatting. This is in order to
Expand Down Expand Up @@ -1181,6 +1211,26 @@ def _LastTokenInLine(current):
return current


def _NextLogicalClause(token):
""" Get the start of the next logical clause or the last token in the line"""
while token:
if token in logical_line._LOGICAL_OPERATORS:
return token
if not token.next_token:
return token
token = token.next_token


def _PrevLogicalClause(token):
""" Get the start of the previous logical clause or the first token"""
while token:
if token.value in logical_line._LOGICAL_OPERATORS:
return token
if not token.previous_token:
return token
token = token.previous_token


def _IsFunctionDefinition(current):
prev = current.previous_token
return current.value == '(' and prev and subtypes.FUNC_DEF in prev.subtypes
Expand Down
51 changes: 36 additions & 15 deletions yapf/yapflib/logical_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,21 +610,42 @@ def _SplitPenalty(prev_token, cur_token):
if pval == 'not':
return split_penalty.UNBREAKABLE

if cur_token.node_split_penalty > 0:
return cur_token.node_split_penalty

if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
# Prefer to split before 'and' and 'or'.
if pval in _LOGICAL_OPERATORS:
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
if cval in _LOGICAL_OPERATORS:
return 0
else:
# Prefer to split after 'and' and 'or'.
if pval in _LOGICAL_OPERATORS:
return 0
if cval in _LOGICAL_OPERATORS:
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
node_split_penalty = cur_token.node_split_penalty

logical_splitting = style.Get('SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT')

if logical_splitting:
if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
# Prefer to split before 'and' and 'or'.
if pval in _LOGICAL_OPERATORS:
return max(node_split_penalty,
style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR'))
if cval in _LOGICAL_OPERATORS:
return max(node_split_penalty, 0)
else:
# Prefer to split after 'and' and 'or'.
if pval in _LOGICAL_OPERATORS:
return max(node_split_penalty, 0)
if cval in _LOGICAL_OPERATORS:
return max(node_split_penalty,
style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR'))

if node_split_penalty > 0:
return node_split_penalty

if not logical_splitting:
if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
# Prefer to split before 'and' and 'or'.
if pval in _LOGICAL_OPERATORS:
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
if cval in _LOGICAL_OPERATORS:
return 0
else:
# Prefer to split after 'and' and 'or'.
if pval in _LOGICAL_OPERATORS:
return 0
if cval in _LOGICAL_OPERATORS:
return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')

if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'):
# Prefer to split before '&', '|', and '^'.
Expand Down
8 changes: 8 additions & 0 deletions yapf/yapflib/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,12 @@ def method():
SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\
Split before arguments.
"""),
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=textwrap.dedent("""\
If a line that contains logical operators needs to be split, split on all
the logical operators in that line. This will treat logical operators
in sub-clauses defined by parentheses as a discrete element that will
ignore wrapping unless the entire clause is longer than the column width.
"""),
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\
Split before arguments, but do not split all subexpressions recursively
(unless needed).
Expand Down Expand Up @@ -514,6 +520,7 @@ def CreatePEP8Style():
SPACES_AROUND_TUPLE_DELIMITERS=False,
SPACES_BEFORE_COMMENT=2,
SPLIT_ALL_COMMA_SEPARATED_VALUES=False,
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=False,
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=False,
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False,
SPLIT_BEFORE_ARITHMETIC_OPERATOR=False,
Expand Down Expand Up @@ -703,6 +710,7 @@ def _IntOrIntListConverter(s):
SPACES_AROUND_TUPLE_DELIMITERS=_BoolConverter,
SPACES_BEFORE_COMMENT=_IntOrIntListConverter,
SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter,
SPLIT_ALL_LOGICAL_OPERATORS_IF_ANY_SPLIT=_BoolConverter,
SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=_BoolConverter,
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter,
SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter,
Expand Down