From bec76726299908f431f06042f1ca6503b221438c Mon Sep 17 00:00:00 2001 From: Thomas Marshall Date: Tue, 29 Aug 2023 17:05:34 +0100 Subject: [PATCH] Fix small issues with end insertion (#940) * Remove extra space after end insertion This commit ensures there is no extra space added after the cursor when on type formatting inserts an `end` keyword. For some reason, if we try to insert the newline character and the `end` keyword via a single edit without the extra space, `applyEdit` [1] strips the indentation and the cursor ends up at the beginning of the middle line. Inserting the newline via a separate edit doesn't seem to have this problem. [1]: https://github.com/Shopify/vscode-ruby-lsp/blob/74e45e754aac281a22d5627c22a1a2a3e73d8b33/src/client.ts#L160 * Fix cusor position when breaking after keyword If the user breaks just after the keyword, this commit ensures the cursor is placed back where the break happened. This is currently broken in that the cursor will end up 1 character into the next line. There was some discussion [1] about whether the cursor should remain where it would normally be if the end insertion didn't happen, but it appears moving it back to where the break happened is the intended behavior. [1]: https://github.com/Shopify/ruby-lsp/pull/462#discussion_r1082642170 * Add newline when breaking after keyword This commit ensures that when breaking after the keyword, the `end` is inserted with a newline, rather than replacing an existing empty line. --- lib/ruby_lsp/requests/on_type_formatting.rb | 7 ++-- test/requests/on_type_formatting_test.rb | 39 +++++++++++++++++++-- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/lib/ruby_lsp/requests/on_type_formatting.rb b/lib/ruby_lsp/requests/on_type_formatting.rb index 3bc5d2a1a..6ce2bcee8 100644 --- a/lib/ruby_lsp/requests/on_type_formatting.rb +++ b/lib/ruby_lsp/requests/on_type_formatting.rb @@ -112,11 +112,12 @@ def handle_statement_end next_line = @lines[@position[:line] + 1] if current_line.nil? || current_line.strip.empty? - add_edit_with_text(" \n#{indents}end") + add_edit_with_text("\n") + add_edit_with_text("#{indents}end") move_cursor_to(@position[:line], @indentation + 2) elsif next_line.nil? || next_line.strip.empty? - add_edit_with_text("#{indents}end", { line: @position[:line] + 1, character: @position[:character] }) - move_cursor_to(@position[:line], @indentation + 3) + add_edit_with_text("#{indents}end\n", { line: @position[:line] + 1, character: @position[:character] }) + move_cursor_to(@position[:line] - 1, @indentation + @previous_line.size + 1) end end diff --git a/test/requests/on_type_formatting_test.rb b/test/requests/on_type_formatting_test.rb index 67fbdc2c6..ea242f7e5 100644 --- a/test/requests/on_type_formatting_test.rb +++ b/test/requests/on_type_formatting_test.rb @@ -20,7 +20,11 @@ def test_adding_missing_ends expected_edits = [ { range: { start: { line: 1, character: 2 }, end: { line: 1, character: 2 } }, - newText: " \nend", + newText: "\n", + }, + { + range: { start: { line: 1, character: 2 }, end: { line: 1, character: 2 } }, + newText: "end", }, { range: { start: { line: 1, character: 2 }, end: { line: 1, character: 2 } }, @@ -302,7 +306,11 @@ def test_breaking_line_between_keyword_and_more_content expected_edits = [ { range: { start: { line: 1, character: 2 }, end: { line: 1, character: 2 } }, - newText: " \nend", + newText: "\n", + }, + { + range: { start: { line: 1, character: 2 }, end: { line: 1, character: 2 } }, + newText: "end", }, { range: { start: { line: 1, character: 2 }, end: { line: 1, character: 2 } }, @@ -328,4 +336,31 @@ def test_breaking_line_between_keyword_when_there_is_content_on_the_next_line edits = RubyLsp::Requests::OnTypeFormatting.new(document, { line: 0, character: 2 }, "\n").run assert_empty(edits) end + + def test_breaking_line_immediately_after_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: " def\nfoo", + }], + version: 2, + ) + document.parse + + edits = RubyLsp::Requests::OnTypeFormatting.new(document, { line: 1, character: 2 }, "\n").run + expected_edits = [ + { + range: { start: { line: 2, character: 2 }, end: { line: 2, character: 2 } }, + newText: " end\n", + }, + { + range: { start: { line: 0, character: 6 }, end: { line: 0, character: 6 } }, + newText: "$0", + }, + ] + + assert_equal(expected_edits.to_json, T.must(edits).to_json) + end end