Skip to content

Commit 896ba66

Browse files
committed
Remove completion suggestions that were added before user began typing column argument key
1 parent 822862a commit 896ba66

File tree

2 files changed

+14
-78
lines changed

2 files changed

+14
-78
lines changed

lib/ruby_lsp/ruby_lsp_rails/completion.rb

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -28,73 +28,49 @@ def initialize(client, response_builder, node_context, dispatcher, uri)
2828

2929
sig { params(node: Prism::CallNode).void }
3030
def on_call_node_enter(node)
31-
if node.name == :where
32-
handle_active_record_where_completions(call_node: node)
33-
elsif @node_context.call_node && @node_context.call_node&.name == :where
34-
handle_active_record_where_completions(call_node: T.must(@node_context.call_node), current_node: node)
31+
if @node_context.call_node && @node_context.call_node&.name == :where
32+
handle_active_record_where_completions(node)
3533
end
3634
end
3735

3836
private
3937

40-
sig { params(call_node: Prism::CallNode, current_node: T.nilable(Prism::CallNode)).void }
41-
def handle_active_record_where_completions(call_node:, current_node: nil)
42-
receiver = call_node.receiver
38+
sig { params(node: Prism::CallNode).void }
39+
def handle_active_record_where_completions(node)
40+
receiver = T.must(@node_context.call_node).receiver
4341
return if receiver.nil?
4442
return unless receiver.is_a?(Prism::ConstantReadNode)
4543

4644
resolved_class = @client.model(receiver.name.to_s)
4745
return if resolved_class.nil?
4846

49-
arguments = call_node.arguments&.arguments
47+
arguments = T.must(@node_context.call_node).arguments&.arguments
5048
existing_args = T.let({}, T::Hash[String, T::Boolean])
5149

5250
if arguments&.is_a?(Array)
53-
return if current_node && current_node_is_argument_value?(current_node: current_node, arguments: arguments)
51+
return if node_is_argument_value?(node: node, arguments: arguments)
5452

5553
existing_args = get_call_node_arguments(arguments: arguments)
5654
end
5755

5856
resolved_class[:columns].each do |column|
59-
next if current_node && !column[0].start_with?(current_node.name.to_s)
57+
next unless column[0].start_with?(node.name.to_s)
6058
next if existing_args[column[0]]
6159

62-
if current_node
63-
location = current_node.location
64-
range = Interface::Range.new(
65-
start: Interface::Position.new(
66-
line: location.start_line - 1,
67-
character: location.start_column,
68-
),
69-
end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
70-
)
71-
else
72-
location = call_node.location
73-
# unclear how to calculate location in this scenario
74-
range = Interface::Range.new(
75-
start: Interface::Position.new(
76-
line: location.start_line - 1,
77-
character: 0,
78-
),
79-
end: Interface::Position.new(line: location.end_line - 1, character: 0),
80-
)
81-
82-
end
83-
8460
@response_builder << Interface::CompletionItem.new(
8561
label: column[0],
8662
filter_text: column[0],
8763
label_details: Interface::CompletionItemLabelDetails.new(
8864
description: "Filter #{receiver.name} records by #{column[0]}",
8965
),
90-
text_edit: Interface::TextEdit.new(range: range, new_text: "#{column[0]}: "),
66+
text_edit: Interface::TextEdit.new(range: range_from_location(node.location), new_text: "#{column[0]}: "),
9167
kind: Constant::CompletionItemKind::FIELD,
9268
)
9369
end
9470
end
9571

96-
sig { params(current_node: Prism::Node, arguments: T::Array[Prism::Node]).returns(T::Boolean) }
97-
def current_node_is_argument_value?(current_node:, arguments:)
72+
sig { params(node: Prism::Node, arguments: T::Array[Prism::Node]).returns(T::Boolean) }
73+
def node_is_argument_value?(node:, arguments:)
9874
arguments.any? do |argument|
9975
next unless argument.is_a?(Prism::KeywordHashNode)
10076

@@ -103,7 +79,7 @@ def current_node_is_argument_value?(current_node:, arguments:)
10379

10480
value = e.value
10581
if value.is_a?(Prism::CallNode)
106-
value == current_node
82+
value == node
10783
end
10884
end
10985
end

test/ruby_lsp_rails/completion_test.rb

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,50 +6,10 @@
66
module RubyLsp
77
module Rails
88
class CompletionTest < ActiveSupport::TestCase
9-
# This test uses node as the call node with name where
10-
test "recognizes Active Record .where call on an Active Record model using (" do
11-
response = generate_completions_for_source(<<~RUBY, { line: 1, character: 11 })
12-
# typed: false
13-
User.where(
14-
RUBY
15-
16-
columns = [
17-
"id",
18-
"first_name",
19-
"last_name",
20-
"age",
21-
"created_at",
22-
"updated_at",
23-
"country_id",
24-
"active",
25-
]
26-
assert_equal(columns.size, response.size)
27-
28-
columns.each_with_index do |column, i|
29-
assert_equal(column, response[i].label)
30-
assert_equal(column, response[i].filter_text)
31-
end
32-
end
33-
349
test "Does not suggest column if it already exists within .where as an arg and parantheses are not closed" do
35-
response = generate_completions_for_source(<<~RUBY, { line: 1, character: 28 })
36-
# typed: false
37-
User.where(id:, first_name:,
38-
RUBY
39-
40-
columns = ["last_name", "age", "created_at", "updated_at", "country_id", "active"]
41-
assert_equal(columns.size, response.size)
42-
43-
columns.each_with_index do |column, i|
44-
assert_equal(column, response[i].label)
45-
assert_equal(column, response[i].filter_text)
46-
end
47-
end
48-
49-
test "Does not provide suggestions when typing argument values" do
50-
response = generate_completions_for_source(<<~RUBY, { line: 1, character: 14 })
10+
response = generate_completions_for_source(<<~RUBY, { line: 1, character: 30 })
5111
# typed: false
52-
User.where(id:
12+
User.where(id:, first_name:, f
5313
RUBY
5414

5515
assert_equal(0, response.size)

0 commit comments

Comments
 (0)