diff --git a/lib/ruby_lsp/requests/on_type_formatting.rb b/lib/ruby_lsp/requests/on_type_formatting.rb index 6ce2bcee8..e9a1a802a 100644 --- a/lib/ruby_lsp/requests/on_type_formatting.rb +++ b/lib/ruby_lsp/requests/on_type_formatting.rb @@ -53,6 +53,10 @@ def run elsif @document.syntax_error? handle_statement_end end + when "d" + if @previous_line.strip == "end" + auto_indent_after_end_keyword + end end @edits @@ -171,6 +175,25 @@ def find_indentation(line) count end + + sig { void } + def auto_indent_after_end_keyword + start_line_index = (@position[:line] - 2).downto(0).find do |i| + END_REGEXES.any? { |regex| regex.match?(@lines[i]) } + end + + return unless start_line_index + + start_line_indentation = find_indentation(@lines[start_line_index]) + + (start_line_index + 1...@position[:line] - 1).each do |i| + add_edit_with_text(" ", { line: i, character: 0 }) + end + + move_cursor_to(@position[:line] - 1, 3) + + add_edit_with_text("\n" + (" " * (start_line_indentation + 2)), @position) + end end end end diff --git a/test/requests/on_type_formatting_test.rb b/test/requests/on_type_formatting_test.rb index ea242f7e5..4a36c69e5 100644 --- a/test/requests/on_type_formatting_test.rb +++ b/test/requests/on_type_formatting_test.rb @@ -363,4 +363,36 @@ def test_breaking_line_immediately_after_keyword assert_equal(expected_edits.to_json, T.must(edits).to_json) end + + def test_auto_indent_after_end_keyword + document = RubyLsp::Document.new(source: +"", version: 1, uri: URI("file:///fake.rb")) + + document.push_edits( + [{ + range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } }, + text: "if true\nputs \"a\"\nend", + }], + version: 2, + ) + document.parse + + edits = RubyLsp::Requests::OnTypeFormatting.new(document, { line: 3, character: 0 }, "d").run + + expected_edits = [ + { + range: { start: { line: 1, character: 0 }, end: { line: 1, character: 0 } }, + newText: " ", + }, + { + range: { start: { line: 2, character: 3 }, end: { line: 2, character: 3 } }, + newText: "$0", + }, + { + range: { start: { line: 3, character: 0 }, end: { line: 3, character: 0 } }, + newText: "\n ", + }, + ] + + assert_equal(expected_edits.to_json, T.must(edits).to_json) + end end