class RubyLex
def process_indent_level(tokens, lines, line_index, is_newline)
def process_indent_level(tokens, lines, line_index, is_newline) line_results = IRB::NestingParser.parse_by_line(tokens) result = line_results[line_index] if result _tokens, prev_opens, next_opens, min_depth = result else # When last line is empty prev_opens = next_opens = line_results.last[2] min_depth = next_opens.size end # To correctly indent line like `end.map do`, we use shortest open tokens on each line for indent calculation. # Shortest open tokens can be calculated by `opens.take(min_depth)` indent = 2 * calc_indent_level(prev_opens.take(min_depth)) preserve_indent = lines[line_index - (is_newline ? 1 : 0)][/^ */].size prev_open_token = prev_opens.last next_open_token = next_opens.last # Calculates base indent for pasted code on the line where prev_open_token is located # irb(main):001:1* if a # base_indent is 2, indent calculated from tokens is 0 # irb(main):002:1* if b # base_indent is 6, indent calculated from tokens is 2 # irb(main):003:0> c # base_indent is 6, indent calculated from tokens is 4 if prev_open_token base_indent = [0, indent_difference(lines, line_results, prev_open_token.pos[0] - 1)].max else base_indent = 0 end if free_indent_token?(prev_open_token) if is_newline && prev_open_token.pos[0] == line_index # First newline inside free-indent token base_indent + indent else # Accept any number of indent inside free-indent token preserve_indent end elsif prev_open_token&.event == :on_embdoc_beg || next_open_token&.event == :on_embdoc_beg if prev_open_token&.event == next_open_token&.event # Accept any number of indent inside embdoc content preserve_indent else # =begin or =end 0 end elsif prev_open_token&.event == :on_heredoc_beg tok = prev_open_token.tok if prev_opens.size <= next_opens.size if is_newline && lines[line_index].empty? && line_results[line_index - 1][1].last != next_open_token # First line in heredoc tok.match?(/^<<[-~]/) ? base_indent + indent : indent elsif tok.match?(/^<<~/) # Accept extra indent spaces inside `<<~` heredoc [base_indent + indent, preserve_indent].max else # Accept any number of indent inside other heredoc preserve_indent end else # Heredoc close prev_line_indent_level = calc_indent_level(prev_opens) tok.match?(/^<<[~-]/) ? base_indent + 2 * (prev_line_indent_level - 1) : 0 end else base_indent + indent end end