class Rufo::Formatter

def initialize(code, **options)

def initialize(code, **options)
  @code = code
  @tokens = Rufo::Parser.lex(code).reverse!
  @sexp = Rufo::Parser.sexp(code)
  # sexp being nil means that the code is not valid.
  # Parse the code so we get better error messages.
  if @sexp.nil?
    Rufo::Parser.parse(code)
    raise Rufo::UnknownSyntaxError # Sometimes parsing does not raise an error
  end
  @indent = 0
  @line = 0
  @column = 0
  @last_was_newline = true
  @output = +""
  # The column of a `obj.method` call, so we can align
  # calls to that dot
  @dot_column = nil
  # Same as above, but the column of the original dot, not
  # the one we finally wrote
  @original_dot_column = nil
  # Did this line already set the `@dot_column` variable?
  @line_has_dot_column = nil
  # The column of a `obj.method` call, but only the name part,
  # so we can also align arguments accordingly
  @name_dot_column = nil
  # Heredocs list, associated with calls ([heredoc, tilde])
  @heredocs = []
  # Current node, to be able to associate it to heredocs
  @current_node = nil
  # The current heredoc being printed
  @current_heredoc = nil
  # The current hash or call or method that has hash-like parameters
  @current_hash = nil
  @current_type = nil
  # Are we inside a type body?
  @inside_type_body = false
  # Map lines to commands that start at the begining of a line with the following info:
  # - line indent
  # - first param indent
  # - first line ends with '(', '[' or '{'?
  # - line of matching pair of the previous item
  # - last line of that call
  #
  # This is needed to dedent some calls that look like this:
  #
  # foo bar(
  #   2,
  # )
  #
  # Without the dedent it would normally look like this:
  #
  # foo bar(
  #       2,
  #     )
  #
  # Because the formatter aligns this to the first parameter in the call.
  # However, for these cases it's better to not align it like that.
  @line_to_call_info = {}
  # Lists [first_line, last_line, indent] of lines that need an indent because
  # of alignment of literals. For example this:#
  #
  #     foo [
  #           1,
  #         ]
  #
  # is normally formatted to:
  #
  #     foo [
  #       1,
  #     ]
  #
  # However, if it's already formatted like the above we preserve it.
  @literal_indents = []
  # First non-space token in this line
  @first_token_in_line = nil
  # Do we want to compute the above?
  @want_first_token_in_line = false
  # Each line that belongs to a string literal besides the first
  # go here, so we don't break them when indenting/dedenting stuff
  @unmodifiable_string_lines = {}
  # Position of comments that occur at the end of a line
  @comments_positions = []
  # Token for the last comment found
  @last_comment = nil
  # Actual column of the last comment written
  @last_comment_column = nil
  # Associate lines to alignments
  # Associate a line to an index inside @comments_position
  # becuase when aligning something to the left of a comment
  # we need to adjust the relative comment
  @line_to_alignments_positions = Hash.new { |h, k| h[k] = [] }
  # Position of assignments
  @assignments_positions = []
  # Range of assignment (line => end_line)
  #
  # We need this because when we have to format:
  #
  # ```
  # abc = 1
  # a = foo bar: 2
  #         baz: #
  # ```
  #
  # Because we'll insert two spaces after `a`, this will
  # result in a mis-alignment for baz (and possibly other lines
  # below it). So, we remember the line ranges of an assignment,
  # and once we align the first one we fix the other ones.
  @assignments_ranges = {}
  # Case when positions
  @case_when_positions = []
  # Declarations that are written in a single line, like:
  #
  #    def foo; 1; end
  #
  # We want to track these because we allow consecutive inline defs
  # to be together (without an empty line between them)
  #
  # This is [[line, original_line], ...]
  @inline_declarations = []
  # This is used to track how far deep we are in the AST.
  # This is useful as it allows you to check if you are inside an array
  # when dealing with heredocs.
  @node_level = 0
  # This represents the node level of the most recent literal elements list.
  # It is used to track if we are in a list of elements so that commas
  # can be added appropriately for heredocs for example.
  @literal_elements_level = nil
  init_settings(options)
end