class Rufo::Formatter

def consume_end_of_line(at_prefix: false, want_semicolon: false, want_multiline: true, needs_two_lines_on_comment: false, first_space: nil)

- want_multiline: do we want multiple lines to appear, or at most one?
- want_semicolon: do we want do print a semicolon to separate expressions?
- at_prefix: are we at a point before an expression? (if so, we don't need a space before the first comment)

Consume and print an end of line, handling semicolons and comments
def consume_end_of_line(at_prefix: false, want_semicolon: false, want_multiline: true, needs_two_lines_on_comment: false, first_space: nil)
  found_newline = false               # Did we find any newline during this method?
  found_comment_after_newline = false # Did we find a comment after some newline?
  last = nil                          # Last token kind found
  multilple_lines = false             # Did we pass through more than one newline?
  last_comment_has_newline = false    # Does the last comment has a newline?
  newline_count = 0                   # Number of newlines we passed
  last_space = first_space            # Last found space
  loop do
    case current_token_kind
    when :on_sp
      # Ignore spaces
      last_space = current_token
      next_token
    when :on_nl, :on_ignored_nl
      # I don't know why but sometimes a on_ignored_nl
      # can appear with nil as the "text", and that's wrong
      if current_token[2].nil?
        next_token
        next
      end
      if last == :newline
        # If we pass through consecutive newlines, don't print them
        # yet, but remember this fact
        multilple_lines = true unless last_comment_has_newline
      else
        # If we just printed a comment that had a newline,
        # we must print two newlines because we remove newlines from comments (rstrip call)
        write_line
        if last == :comment && last_comment_has_newline
          multilple_lines = true
        else
          multilple_lines = false
        end
      end
      found_newline = true
      next_token
      last = :newline
      newline_count += 1
    when :on_semicolon
      next_token
      # If we want to print semicolons and we didn't find a newline yet,
      # print it, but only if it's not followed by a newline
      if !found_newline && want_semicolon && last != :semicolon
        skip_space
        kind = current_token_kind
        case kind
        when :on_ignored_nl, :on_eof
        else
          return if (kind == :on_kw) &&
                    (%w[class module def].include?(current_token_value))
          write "; "
          last = :semicolon
        end
      end
      multilple_lines = false
    when :on_comment
      if last == :comment
        # Since we remove newlines from comments, we must add the last
        # one if it was a comment
        write_line
        # If the last comment is in the previous line and it was already
        # aligned to this comment, keep it aligned. This is useful for
        # this:
        #
        # ```
        # a = 1 # some comment
        #       # that continues here
        # ```
        #
        # We want to preserve it like that and not change it to:
        #
        # ```
        # a = 1 # some comment
        # # that continues here
        # ```
        if current_comment_aligned_to_previous_one?
          write_indent(@last_comment_column)
          track_comment(match_previous_id: true)
        else
          write_indent
        end
      else
        if found_newline
          if newline_count == 1 && needs_two_lines_on_comment
            if multilple_lines
              write_line
              multilple_lines = false
            else
              multilple_lines = true
            end
            needs_two_lines_on_comment = false
          end
          # Write line or second line if needed
          write_line if last != :newline || multilple_lines
          write_indent
          track_comment(id: @last_was_newline ? true : nil)
        else
          # If we didn't find any newline yet, this is the first comment,
          # so append a space if needed (for example after an expression)
          unless at_prefix
            # Preserve whitespace before comment unless we need to align them
            if last_space
              write last_space[2]
            else
              write_space
            end
          end
          # First we check if the comment was aligned to the previous comment
          # in the previous line, in order to keep them like that.
          if current_comment_aligned_to_previous_one?
            track_comment(match_previous_id: true)
          else
            # We want to distinguish comments that appear at the beginning
            # of a line (which means the line has only a comment) and comments
            # that appear after some expression. We don't want to align these
            # and consider them separate entities. So, we use `@last_was_newline`
            # as an id to distinguish that.
            #
            # For example, this:
            #
            #     # comment 1
            #       # comment 2
            #     call # comment 3
            #
            # Should format to:
            #
            #     # comment 1
            #     # comment 2
            #     call # comment 3
            #
            # Instead of:
            #
            #          # comment 1
            #          # comment 2
            #     call # comment 3
            #
            # We still want to track the first two comments to align to the
            # beginning of the line according to indentation in case they
            # are not already there.
            track_comment(id: @last_was_newline ? true : nil)
          end
        end
      end
      @last_comment = current_token
      @last_comment_column = @column
      last_comment_has_newline = current_token_value.end_with?("\n")
      last = :comment
      found_comment_after_newline = found_newline
      multilple_lines = false
      write current_token_value.rstrip
      next_token
    when :on_embdoc_beg
      if multilple_lines || last == :comment
        write_line
      end
      consume_embedded_comment
      last = :comment
      last_comment_has_newline = true
    else
      break
    end
  end
  # Output a newline if we didn't do so yet:
  # either we didn't find a newline and we are at the end of a line (and we didn't just pass a semicolon),
  # or the last thing was a comment (from which we removed the newline)
  # or we just passed multiple lines (but printed only one)
  if (!found_newline && !at_prefix && !(want_semicolon && last == :semicolon)) ||
     last == :comment ||
     (multilple_lines && (want_multiline || found_comment_after_newline))
    write_line
  end
end