diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb index 68751b4de..9ae9f16cb 100644 --- a/lib/irb/ruby-lex.rb +++ b/lib/irb/ruby-lex.rb @@ -124,6 +124,7 @@ def set_auto_indent(context) prev_spaces = md.nil? ? 0 : md[1].count(' ') @tokens = ripper_lex_without_warning(lines[0..line_index].join("\n")) depth_difference = check_newline_depth_difference + depth_difference = 0 if depth_difference < 0 prev_spaces + depth_difference * 2 else code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join @@ -360,14 +361,8 @@ def process_nesting_level(tokens = @tokens) next if index > 0 and tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] when 'do' - if index > 0 and tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG) - # method_with_block do; end - indent += 1 - else - # while cond do; end # also "until" or "for" - # This "do" doesn't increment indent because "while" already - # incremented. - end + syntax_of_do = take_corresponding_syntax_to_kw_do(tokens, index) + indent += 1 if syntax_of_do == :method_calling when 'def', 'case', 'for', 'begin', 'class', 'module' indent += 1 when 'if', 'unless', 'while', 'until' @@ -382,6 +377,40 @@ def process_nesting_level(tokens = @tokens) indent end + def take_corresponding_syntax_to_kw_do(tokens, index) + syntax_of_do = nil + # Finding a syntax correnponding to "do". + index.downto(0) do |i| + tk = tokens[i] + # In "continue", the token isn't the corresponding syntax to "do". + #is_continue = process_continue(@tokens[0..(i - 1)]) + # continue ではなく、直前に (:on_ignored_nl|:on_nl|:on_comment):on_sp* みたいなのがあるかどうかを調べる + non_sp_index = tokens[0..(i - 1)].rindex{ |t| t[1] != :on_sp } + first_in_fomula = false + if non_sp_index.nil? + first_in_fomula = true + elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index][1]) + first_in_fomula = true + end + if tk[3].anybits?(Ripper::EXPR_CMDARG) and tk[1] == :on_ident + # The target method call to pass the block with "do". + syntax_of_do = :method_calling + break if first_in_fomula + elsif tk[1] == :on_kw && %w{while until for}.include?(tk[2]) + # A loop syntax in front of "do" found. + # + # while cond do # also "until" or "for" + # end + # + # This "do" doesn't increment indent because the loop syntax already + # incremented. + syntax_of_do = :loop_syntax + break if first_in_fomula + end + end + syntax_of_do + end + def check_newline_depth_difference depth_difference = 0 open_brace_on_line = 0 @@ -428,14 +457,8 @@ def check_newline_depth_difference next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] when 'do' - if index > 0 and @tokens[index - 1][3].anybits?(Ripper::EXPR_CMDARG | Ripper::EXPR_ENDFN | Ripper::EXPR_ARG) - # method_with_block do; end - depth_difference += 1 - else - # while cond do; end # also "until" or "for" - # This "do" doesn't increment indent because "while" already - # incremented. - end + syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index) + depth_difference += 1 if syntax_of_do == :method_calling when 'def', 'case', 'for', 'begin', 'class', 'module' depth_difference += 1 when 'if', 'unless', 'while', 'until', 'rescue' @@ -445,6 +468,8 @@ def check_newline_depth_difference end when 'else', 'elsif', 'ensure', 'when', 'in' depth_difference += 1 + when 'end' + depth_difference -= 1 end end end @@ -516,7 +541,12 @@ def check_corresponding_token_depth when :on_kw next if index > 0 and @tokens[index - 1][3].allbits?(Ripper::EXPR_FNAME) case t[2] - when 'def', 'do', 'case', 'for', 'begin', 'class', 'module' + when 'do' + syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index) + if syntax_of_do == :method_calling + spaces_of_nest.push(spaces_at_line_head) + end + when 'def', 'case', 'for', 'begin', 'class', 'module' spaces_of_nest.push(spaces_at_line_head) when 'rescue' unless t[3].allbits?(Ripper::EXPR_LABEL) diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb index 30bae1e4e..fa2f0492f 100644 --- a/test/irb/test_ruby_lex.rb +++ b/test/irb/test_ruby_lex.rb @@ -263,6 +263,76 @@ def test_tlambda end end + def test_corresponding_syntax_to_keyword_do_in_class + input_with_correct_indents = [ + Row.new(%q(class C), nil, 2, 1), + Row.new(%q( while method_name do), nil, 4, 2), + Row.new(%q( 3), nil, 4, 2), + Row.new(%q( end), 2, 2, 1), + Row.new(%q( foo do), nil, 4, 2), + Row.new(%q( 3), nil, 4, 2), + Row.new(%q( end), 2, 2, 1), + Row.new(%q(end), 0, 0, 0), + ] + + lines = [] + input_with_correct_indents.each do |row| + lines << row.content + assert_indenting(lines, row.current_line_spaces, false) + assert_indenting(lines, row.new_line_spaces, true) + assert_nesting_level(lines, row.nesting_level) + end + end + + def test_corresponding_syntax_to_keyword_do + input_with_correct_indents = [ + Row.new(%q(while i > 0), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(while true), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(while ->{i > 0}.call), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(while ->{true}.call), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(while i > 0 do), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(while true do), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(while ->{i > 0}.call do), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(while ->{true}.call do), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(foo do), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(foo true do), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(foo ->{true} do), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(foo ->{i > 0} do), nil, 2, 1), + Row.new(%q( 3), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + ] + + lines = [] + input_with_correct_indents.each do |row| + lines << row.content + assert_indenting(lines, row.current_line_spaces, false) + assert_indenting(lines, row.new_line_spaces, true) + assert_nesting_level(lines, row.nesting_level) + end + end + def test_oneliner_def_in_multiple_lines input_with_correct_indents = [ Row.new(%q(def a()=[), nil, 4, 2),