Skip to content

Commit 2596f87

Browse files
authored
Complete writer methods with self receiver when receiver is self (#3550)
* fix: Complete writer methods with self receiver when appropriate Fixes completion of setter methods to use 'self.method=' syntax when accessed within instance methods. Previously, completion would suggest 'method=' which assigns to a local variable instead of calling the instance writer method. * feat: Add spacing around = in writer method completions Writer method completions now include proper spacing around the equals sign to follow Ruby style conventions (e.g., 'self.attr = ' instead of 'self.attr=').
1 parent 1f3e440 commit 2596f87

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

lib/ruby_lsp/listeners/completion.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,14 @@ def complete_methods(node, name)
516516

517517
entry_name = entry.name
518518
owner_name = entry.owner&.name
519+
new_text = entry_name
520+
521+
if entry_name.end_with?("=")
522+
method_name = entry_name.delete_suffix("=")
523+
524+
# For writer methods, format as assignment and prefix "self." when no receiver is specified
525+
new_text = node.receiver.nil? ? "self.#{method_name} = " : "#{method_name} = "
526+
end
519527

520528
label_details = Interface::CompletionItemLabelDetails.new(
521529
description: entry.file_name,
@@ -525,7 +533,7 @@ def complete_methods(node, name)
525533
label: entry_name,
526534
filter_text: entry_name,
527535
label_details: label_details,
528-
text_edit: Interface::TextEdit.new(range: range, new_text: entry_name),
536+
text_edit: Interface::TextEdit.new(range: range, new_text: new_text),
529537
kind: Constant::CompletionItemKind::METHOD,
530538
data: {
531539
owner_name: owner_name,

test/requests/completion_test.rb

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,12 +687,17 @@ class Foo
687687
688688
def bar
689689
q
690+
self.q
690691
end
691692
end
693+
694+
foo = Foo.new
695+
foo.q
692696
RUBY
693697

694698
with_server(source) do |server, uri|
695699
with_file_structure(server) do
700+
# Test implicit self receiver: "q"
696701
server.process_message(id: 1, method: "textDocument/completion", params: {
697702
textDocument: { uri: uri },
698703
position: { line: 4, character: 5 },
@@ -701,7 +706,29 @@ def bar
701706
result = server.pop_response.response
702707
assert_equal(["qux", "qux="], result.map(&:label))
703708
assert_equal(["qux", "qux="], result.map(&:filter_text))
704-
assert_equal(["qux", "qux="], result.map { |completion| completion.text_edit.new_text })
709+
assert_equal(["qux", "self.qux = "], result.map { |completion| completion.text_edit.new_text })
710+
711+
# Test explicit self receiver: "self.q"
712+
server.process_message(id: 1, method: "textDocument/completion", params: {
713+
textDocument: { uri: uri },
714+
position: { line: 5, character: 10 },
715+
})
716+
717+
result = server.pop_response.response
718+
assert_equal(["qux", "qux="], result.map(&:label))
719+
assert_equal(["qux", "qux="], result.map(&:filter_text))
720+
assert_equal(["qux", "qux = "], result.map { |completion| completion.text_edit.new_text })
721+
722+
# Test external receiver; "foo.q"
723+
server.process_message(id: 1, method: "textDocument/completion", params: {
724+
textDocument: { uri: uri },
725+
position: { line: 10, character: 5 },
726+
})
727+
728+
result = server.pop_response.response
729+
assert_equal(["qux", "qux="], result.map(&:label))
730+
assert_equal(["qux", "qux="], result.map(&:filter_text))
731+
assert_equal(["qux", "qux = "], result.map { |completion| completion.text_edit.new_text })
705732
end
706733
end
707734
end

0 commit comments

Comments
 (0)