diff --git a/lib/ruby_lsp/requests/code_action_resolve.rb b/lib/ruby_lsp/requests/code_action_resolve.rb index 2ff6af3d6..47c72d04a 100644 --- a/lib/ruby_lsp/requests/code_action_resolve.rb +++ b/lib/ruby_lsp/requests/code_action_resolve.rb @@ -207,27 +207,43 @@ def refactor_method # Find the closest method declaration node, so that we place the refactor in a valid position node_context = RubyDocument.locate(@document.parse_result.value, start_index, node_types: [Prism::DefNode]) - closest_def = T.cast(node_context.node, Prism::DefNode) - return Error::InvalidTargetRange if closest_def.nil? + closest_node = node_context.node + return Error::InvalidTargetRange unless closest_node - end_keyword_loc = closest_def.end_keyword_loc - return Error::InvalidTargetRange if end_keyword_loc.nil? + target_range = if closest_node.is_a?(Prism::DefNode) + end_keyword_loc = closest_node.end_keyword_loc + return Error::InvalidTargetRange unless end_keyword_loc - end_line = end_keyword_loc.end_line - 1 - character = end_keyword_loc.end_column - indentation = " " * end_keyword_loc.start_column - target_range = { - start: { line: end_line, character: character }, - end: { line: end_line, character: character }, - } + end_line = end_keyword_loc.end_line - 1 + character = end_keyword_loc.end_column + indentation = " " * end_keyword_loc.start_column - new_method_source = <<~RUBY.chomp + new_method_source = <<~RUBY.chomp - #{indentation}def #{NEW_METHOD_NAME} - #{indentation} #{extracted_source} - #{indentation}end - RUBY + #{indentation}def #{NEW_METHOD_NAME} + #{indentation} #{extracted_source} + #{indentation}end + RUBY + + { + start: { line: end_line, character: character }, + end: { line: end_line, character: character }, + } + else + new_method_source = <<~RUBY + #{indentation}def #{NEW_METHOD_NAME} + #{indentation} #{extracted_source.gsub("\n", "\n ")} + #{indentation}end + + RUBY + + line = [0, source_range.dig(:start, :line) - 1].max + { + start: { line: line, character: source_range.dig(:start, :character) }, + end: { line: line, character: source_range.dig(:start, :character) }, + } + end Interface::CodeAction.new( title: CodeActions::EXTRACT_TO_METHOD_TITLE, diff --git a/test/expectations/code_action_resolve/extract_method_script.exp.json b/test/expectations/code_action_resolve/extract_method_script.exp.json new file mode 100644 index 000000000..945cf18e4 --- /dev/null +++ b/test/expectations/code_action_resolve/extract_method_script.exp.json @@ -0,0 +1,60 @@ +{ + "params": { + "kind": "refactor.extract", + "title": "Refactor: Extract Method", + "data": { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 2, + "character": 6 + } + }, + "uri": "file:///fake" + } + }, + "result": { + "title": "Refactor: Extract Method", + "edit": { + "documentChanges": [ + { + "textDocument": { + "uri": "file:///fake", + "version": null + }, + "edits": [ + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "def new_method\n a = 5 + 2\n a * 10\n \nend\n\n" + }, + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 2, + "character": 6 + } + }, + "newText": "new_method" + } + ] + } + ] + } + } +} diff --git a/test/fixtures/extract_method_script.rb b/test/fixtures/extract_method_script.rb new file mode 100644 index 000000000..96b772590 --- /dev/null +++ b/test/fixtures/extract_method_script.rb @@ -0,0 +1,2 @@ +a = 5 + 2 +a * 10