Skip to content

Commit 93a4e1e

Browse files
committed
Improve target node finding (for require 'path/ completion)
1 parent 35cc655 commit 93a4e1e

1 file changed

Lines changed: 21 additions & 22 deletions

File tree

lib/repl_completion.rb

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ def info
6161

6262
def analyze_code(code, binding = Object::TOPLEVEL_BINDING)
6363
ast = Prism.parse(code, scopes: [binding.local_variables]).value
64-
name = code[/(@@|@|\$)?\w*[!?=]?\z/]
65-
*parents, target_node = find_target ast, code.bytesize - name.bytesize
64+
*parents, target_node = find_target ast, code.bytesize
6665
return unless target_node
6766

6867
calculate_scope = -> { TypeAnalyzer.calculate_target_type_scope(binding, parents, target_node).last }
@@ -74,20 +73,23 @@ def analyze_code(code, binding = Object::TOPLEVEL_BINDING)
7473
return unless call_node.is_a?(Prism::CallNode) && call_node.receiver.nil?
7574
return unless args_node.is_a?(Prism::ArgumentsNode) && args_node.arguments.size == 1
7675

76+
content = code.byteslice(target_node.opening_loc.end_offset..)
7777
case call_node.name
7878
when :require
79-
[:require, name]
79+
[:require, content]
8080
when :require_relative
81-
[:require_relative, name]
81+
[:require_relative, content]
8282
end
8383
when Prism::SymbolNode
84+
name = target_node.value.to_s
8485
if parents.last.is_a? Prism::BlockArgumentNode # method(&:target)
8586
receiver_type, _scope = calculate_type_scope.call target_node
8687
[:call, name, receiver_type, false]
8788
else
8889
[:symbol, name] unless name.empty?
8990
end
9091
when Prism::CallNode
92+
name = target_node.message.to_s
9193
return [:lvar_or_method, name, calculate_scope.call] if target_node.receiver.nil?
9294

9395
self_call = target_node.receiver.is_a? Prism::SelfNode
@@ -96,8 +98,9 @@ def analyze_code(code, binding = Object::TOPLEVEL_BINDING)
9698
receiver_type = receiver_type.nonnillable if op == '&.'
9799
[op == '::' ? :call_or_const : :call, name, receiver_type, self_call]
98100
when Prism::LocalVariableReadNode, Prism::LocalVariableTargetNode
99-
[:lvar_or_method, name, calculate_scope.call]
101+
[:lvar_or_method, target_node.name.to_s, calculate_scope.call]
100102
when Prism::ConstantReadNode, Prism::ConstantTargetNode
103+
name = target_node.name.to_s
101104
if parents.last.is_a? Prism::ConstantPathNode
102105
path_node = parents.last
103106
if path_node.parent # A::B
@@ -111,37 +114,33 @@ def analyze_code(code, binding = Object::TOPLEVEL_BINDING)
111114
[:const, name, nil, calculate_scope.call]
112115
end
113116
when Prism::GlobalVariableReadNode, Prism::GlobalVariableTargetNode
114-
[:gvar, name, calculate_scope.call]
117+
[:gvar, target_node.name.to_s, calculate_scope.call]
115118
when Prism::InstanceVariableReadNode, Prism::InstanceVariableTargetNode
116-
[:ivar, name, calculate_scope.call]
119+
[:ivar, target_node.name.to_s, calculate_scope.call]
117120
when Prism::ClassVariableReadNode, Prism::ClassVariableTargetNode
118-
[:cvar, name, calculate_scope.call]
121+
[:cvar, target_node.name.to_s, calculate_scope.call]
119122
end
120123
end
121124

122125
def find_target(node, position)
123-
location = (
124-
case node
125-
when Prism::CallNode
126-
node.message_loc
127-
when Prism::SymbolNode
128-
node.value_loc
129-
when Prism::StringNode
130-
node.content_loc
131-
when Prism::InterpolatedStringNode
132-
node.closing_loc if node.parts.empty?
133-
end
134-
)
135-
return [node] if location&.start_offset == position
126+
case node
127+
when Prism::StringNode
128+
# Unclosed quoted string has empty content and empty closing
129+
return [node] if node.opening && node.closing&.empty?
130+
when Prism::InterpolatedStringNode
131+
# Unclosed double quoted string is InterpolatedStringNode with empty parts
132+
return [node] if node.parts.empty? && node.opening && node.closing&.empty?
133+
end
136134

137135
node.compact_child_nodes.each do |n|
138136
match = find_target(n, position)
139137
next unless match
138+
140139
match.unshift node
141140
return match
142141
end
143142

144-
[node] if node.location.start_offset == position
143+
[node] if node.location.end_offset == position
145144
end
146145
end
147146
end

0 commit comments

Comments
 (0)