def _CalculateNumberOfNewlines()

in tools/yapf/yapf/yapflib/reformatter.py [0:0]


def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline,
                               final_lines):
  """Calculate the number of newlines we need to add.

  Arguments:
    first_token: (format_token.FormatToken) The first token in the unwrapped
      line.
    indent_depth: (int) The line's indentation depth.
    prev_uwline: (list of unwrapped_line.UnwrappedLine) The unwrapped line
      previous to this line.
    final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines
      that have already been processed.

  Returns:
    The number of newlines needed before the first token.
  """
  # TODO(morbo): Special handling for imports.
  # TODO(morbo): Create a knob that can tune these.
  if prev_uwline is None:
    # The first line in the file. Don't add blank lines.
    # FIXME(morbo): Is this correct?
    if first_token.newlines is not None:
      pytree_utils.SetNodeAnnotation(first_token.node,
                                     pytree_utils.Annotation.NEWLINES, None)
    return 0

  if first_token.is_docstring:
    if (prev_uwline.first.value == 'class' and
        style.Get('BLANK_LINE_BEFORE_CLASS_DOCSTRING')):
      # Enforce a blank line before a class's docstring.
      return ONE_BLANK_LINE
    # The docstring shouldn't have a newline before it.
    return NO_BLANK_LINES

  prev_last_token = prev_uwline.last
  if prev_last_token.is_docstring:
    if (not indent_depth and first_token.value in {'class', 'def', 'async'}):
      # Separate a class or function from the module-level docstring with two
      # blank lines.
      return TWO_BLANK_LINES
    if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token,
                                       prev_last_token):
      return NO_BLANK_LINES
    else:
      return ONE_BLANK_LINE

  if first_token.value in {'class', 'def', 'async', '@'}:
    # TODO(morbo): This can go once the blank line calculator is more
    # sophisticated.
    if not indent_depth:
      # This is a top-level class or function.
      is_inline_comment = prev_last_token.whitespace_prefix.count('\n') == 0
      if (not prev_uwline.disable and prev_last_token.is_comment and
          not is_inline_comment):
        # This token follows a non-inline comment.
        if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token,
                                           prev_last_token):
          # Assume that the comment is "attached" to the current line.
          # Therefore, we want two blank lines before the comment.
          index = len(final_lines) - 1
          while index > 0:
            if not final_lines[index - 1].is_comment:
              break
            index -= 1
          if final_lines[index - 1].first.value == '@':
            final_lines[index].first.AdjustNewlinesBefore(NO_BLANK_LINES)
          else:
            prev_last_token.AdjustNewlinesBefore(TWO_BLANK_LINES)
          if first_token.newlines is not None:
            pytree_utils.SetNodeAnnotation(
                first_token.node, pytree_utils.Annotation.NEWLINES, None)
          return NO_BLANK_LINES
    elif prev_uwline.first.value in {'class', 'def', 'async'}:
      if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'):
        pytree_utils.SetNodeAnnotation(first_token.node,
                                       pytree_utils.Annotation.NEWLINES, None)
        return NO_BLANK_LINES

  # Calculate how many newlines were between the original lines. We want to
  # retain that formatting if it doesn't violate one of the style guide rules.
  if first_token.is_comment:
    first_token_lineno = first_token.lineno - first_token.value.count('\n')
  else:
    first_token_lineno = first_token.lineno

  prev_last_token_lineno = prev_last_token.lineno
  if prev_last_token.is_multiline_string:
    prev_last_token_lineno += prev_last_token.value.count('\n')

  if first_token_lineno - prev_last_token_lineno > 1:
    return ONE_BLANK_LINE

  return NO_BLANK_LINES