repl_type_completor 0.1.6 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/repl_type_completor/result.rb +20 -1
- data/lib/repl_type_completor/type_analyzer.rb +37 -32
- data/lib/repl_type_completor/types.rb +29 -5
- data/lib/repl_type_completor/version.rb +1 -1
- data/lib/repl_type_completor.rb +5 -15
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96985b2dccd9d5437190f365bb6b367a4dd830cbf35c9542825b340f4d833f70
|
4
|
+
data.tar.gz: 53d2a4f5ef5d01b2f1626d978a385bc74d44472ff69f04fc9975b2669226a775
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61535de8984acd5d7bc82b0c93e41dac60b5e43dcf4606666f0c7df491e685c39a983cf5dfac80e368ce20e77e2211242db9e172596dfa1111f67fb9a17bdb47
|
7
|
+
data.tar.gz: 54c7e6900a693254db6e2d462a9b14f0cef5e514581227c2c39b1d13841fea88591f4504037b02edfe6aa1971d3ebdb9e678d735a277d98cebb6df7d372f00fb
|
@@ -64,7 +64,7 @@ module ReplTypeCompletor
|
|
64
64
|
in [:gvar, name, scope]
|
65
65
|
scope.global_variables
|
66
66
|
in [:symbol, name]
|
67
|
-
Symbol.all_symbols
|
67
|
+
filter_symbol_candidates(Symbol.all_symbols, name, limit: 100)
|
68
68
|
in [:call, name, type, self_call]
|
69
69
|
(self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS
|
70
70
|
in [:lvar_or_method, name, scope]
|
@@ -116,6 +116,25 @@ module ReplTypeCompletor
|
|
116
116
|
|
117
117
|
private
|
118
118
|
|
119
|
+
def filter_symbol_candidates(symbols, prefix, limit:)
|
120
|
+
sym_prefix = ":#{prefix}"
|
121
|
+
candidates = symbols.filter_map do |s|
|
122
|
+
next unless s.start_with?(prefix) # Fast and inaccurate check before calling inspect
|
123
|
+
|
124
|
+
inspect = s.inspect
|
125
|
+
inspect[1..] if inspect.start_with?(sym_prefix) # Reject `:"a b"` when completing `:a`
|
126
|
+
rescue EncodingError
|
127
|
+
# ignore
|
128
|
+
end
|
129
|
+
|
130
|
+
if candidates.size > limit
|
131
|
+
# min(n) + max(n) is faster than sort and slice
|
132
|
+
candidates.min(limit - limit / 2) + candidates.max(limit / 2).reverse
|
133
|
+
else
|
134
|
+
candidates.sort
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
119
138
|
def method_doc(type, name)
|
120
139
|
type = type.types.find { _1.all_methods.include? name.to_sym }
|
121
140
|
case type
|
@@ -229,6 +229,11 @@ module ReplTypeCompletor
|
|
229
229
|
alias evaluate_class_variable_read_node evaluate_reference_read
|
230
230
|
alias evaluate_instance_variable_read_node evaluate_reference_read
|
231
231
|
|
232
|
+
def evaluate_it_local_variable_read_node(_node, scope)
|
233
|
+
# `it` is not a normal local variable. It can be overridden like `tap{p it; it=1}`.
|
234
|
+
# Use the name `_1` instead of `it` to avoid conflict.
|
235
|
+
scope['_1'] || Types::NIL
|
236
|
+
end
|
232
237
|
|
233
238
|
def evaluate_call_node(node, scope)
|
234
239
|
receiver_type = node.receiver ? evaluate(node.receiver, scope) : scope.self_type
|
@@ -262,6 +267,8 @@ module ReplTypeCompletor
|
|
262
267
|
assign_numbered_parameters node.block.parameters.maximum, block_scope, block_args, {}
|
263
268
|
when Prism::BlockParametersNode
|
264
269
|
assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
|
270
|
+
when Prism::ItParametersNode
|
271
|
+
scope['_1'] = block_args.first || Types::NIL
|
265
272
|
end
|
266
273
|
result = node.block.body ? evaluate(node.block.body, block_scope) : Types::NIL
|
267
274
|
block_scope.merge_jumps
|
@@ -342,14 +349,14 @@ module ReplTypeCompletor
|
|
342
349
|
Types::UnionType[left, right]
|
343
350
|
else
|
344
351
|
right = evaluate node.value, scope
|
345
|
-
method_call left, node.
|
352
|
+
method_call left, node.binary_operator, [right], nil, nil, scope, name_match: false
|
346
353
|
end
|
347
354
|
end
|
348
355
|
|
349
356
|
def evaluate_variable_operator_write(node, scope)
|
350
357
|
left = scope[node.name.to_s] || Types::OBJECT
|
351
358
|
right = evaluate node.value, scope
|
352
|
-
scope[node.name.to_s] = method_call left, node.
|
359
|
+
scope[node.name.to_s] = method_call left, node.binary_operator, [right], nil, nil, scope, name_match: false
|
353
360
|
end
|
354
361
|
alias evaluate_global_variable_operator_write_node evaluate_variable_operator_write
|
355
362
|
alias evaluate_local_variable_operator_write_node evaluate_variable_operator_write
|
@@ -378,7 +385,7 @@ module ReplTypeCompletor
|
|
378
385
|
def evaluate_constant_operator_write_node(node, scope)
|
379
386
|
left = scope[node.name.to_s] || Types::OBJECT
|
380
387
|
right = evaluate node.value, scope
|
381
|
-
scope[node.name.to_s] = method_call left, node.
|
388
|
+
scope[node.name.to_s] = method_call left, node.binary_operator, [right], nil, nil, scope, name_match: false
|
382
389
|
end
|
383
390
|
|
384
391
|
def evaluate_constant_and_write_node(node, scope)
|
@@ -395,7 +402,7 @@ module ReplTypeCompletor
|
|
395
402
|
def evaluate_constant_path_operator_write_node(node, scope)
|
396
403
|
left, receiver, _parent_module, name = evaluate_constant_node_info node.target, scope
|
397
404
|
right = evaluate node.value, scope
|
398
|
-
value = method_call left, node.
|
405
|
+
value = method_call left, node.binary_operator, [right], nil, nil, scope, name_match: false
|
399
406
|
const_path_write receiver, name, value, scope
|
400
407
|
value
|
401
408
|
end
|
@@ -419,16 +426,20 @@ module ReplTypeCompletor
|
|
419
426
|
def evaluate_constant_path_write_node(node, scope)
|
420
427
|
receiver = evaluate node.target.parent, scope if node.target.parent
|
421
428
|
value = evaluate node.value, scope
|
422
|
-
|
423
|
-
const_path_write receiver, name, value, scope
|
429
|
+
const_path_write receiver, node.target.name.to_s, value, scope
|
424
430
|
value
|
425
431
|
end
|
426
432
|
|
427
433
|
def evaluate_lambda_node(node, scope)
|
428
434
|
local_table = node.locals.to_h { [_1.to_s, Types::OBJECT] }
|
435
|
+
|
436
|
+
# `it` is not added to local_table because it is not a normal local variable.
|
437
|
+
# We need to explicitly add it to the scope.
|
438
|
+
local_table['_1'] = Types::OBJECT if node.parameters.is_a?(Prism::ItParametersNode)
|
439
|
+
|
429
440
|
block_scope = Scope.new scope, { **local_table, Scope::BREAK_RESULT => nil, Scope::NEXT_RESULT => nil, Scope::RETURN_RESULT => nil }
|
430
441
|
block_scope.conditional do |s|
|
431
|
-
assign_parameters node.parameters.parameters, s, [], {} if node.parameters
|
442
|
+
assign_parameters node.parameters.parameters, s, [], {} if node.parameters.is_a?(Prism::ParametersNode) && node.parameters.parameters
|
432
443
|
evaluate node.body, s if node.body
|
433
444
|
end
|
434
445
|
block_scope.merge_jumps
|
@@ -467,13 +478,19 @@ module ReplTypeCompletor
|
|
467
478
|
value.is_a?(Array) ? Types.array_of(*value) : value
|
468
479
|
end
|
469
480
|
|
470
|
-
def evaluate_if_node(node, scope)
|
471
|
-
|
472
|
-
|
481
|
+
def evaluate_if_node(node, scope)
|
482
|
+
evaluate node.predicate, scope
|
483
|
+
Types::UnionType[*scope.run_branches(
|
484
|
+
-> { node.statements ? evaluate(node.statements, _1) : Types::NIL },
|
485
|
+
-> { node.subsequent ? evaluate(node.subsequent, _1) : Types::NIL }
|
486
|
+
)]
|
487
|
+
end
|
488
|
+
|
489
|
+
def evaluate_unless_node(node, scope)
|
473
490
|
evaluate node.predicate, scope
|
474
491
|
Types::UnionType[*scope.run_branches(
|
475
492
|
-> { node.statements ? evaluate(node.statements, _1) : Types::NIL },
|
476
|
-
-> { node.
|
493
|
+
-> { node.else_clause ? evaluate(node.else_clause, _1) : Types::NIL }
|
477
494
|
)]
|
478
495
|
end
|
479
496
|
|
@@ -583,10 +600,10 @@ module ReplTypeCompletor
|
|
583
600
|
end
|
584
601
|
node.statements ? evaluate(node.statements, s) : Types::NIL
|
585
602
|
end
|
586
|
-
if node.
|
603
|
+
if node.subsequent # begin; rescue A; rescue B; end
|
587
604
|
types = scope.run_branches(
|
588
605
|
run_rescue,
|
589
|
-
-> { evaluate node.
|
606
|
+
-> { evaluate node.subsequent, _1 }
|
590
607
|
)
|
591
608
|
Types::UnionType[*types]
|
592
609
|
else
|
@@ -701,8 +718,8 @@ module ReplTypeCompletor
|
|
701
718
|
branches = node.conditions.map do |condition|
|
702
719
|
->(s) { evaluate_case_when_condition condition, s }
|
703
720
|
end
|
704
|
-
if node.
|
705
|
-
branches << ->(s) { evaluate node.
|
721
|
+
if node.else_clause
|
722
|
+
branches << ->(s) { evaluate node.else_clause, s }
|
706
723
|
else
|
707
724
|
branches << ->(_s) { Types::NIL }
|
708
725
|
end
|
@@ -715,8 +732,8 @@ module ReplTypeCompletor
|
|
715
732
|
branches = node.conditions.map do |condition|
|
716
733
|
->(s) { evaluate_case_in_condition target, condition, s }
|
717
734
|
end
|
718
|
-
if node.
|
719
|
-
branches << ->(s) { evaluate node.
|
735
|
+
if node.else_clause
|
736
|
+
branches << ->(s) { evaluate node.else_clause, s }
|
720
737
|
end
|
721
738
|
Types::UnionType[*scope.run_branches(*branches)]
|
722
739
|
end
|
@@ -839,16 +856,6 @@ module ReplTypeCompletor
|
|
839
856
|
[args_types, kwargs_types, block_sym_node, !!block_arg]
|
840
857
|
end
|
841
858
|
|
842
|
-
def const_path_name(node)
|
843
|
-
if node.respond_to?(:name)
|
844
|
-
# ConstantPathNode#name ConstantPathTargetNode#name is added in Prism 0.28.0
|
845
|
-
node.name.to_s
|
846
|
-
else
|
847
|
-
# ConstantPathNode#child ConstantPathTargetNode#child is deprecated in Prism 0.28.0
|
848
|
-
node.child.name.to_s
|
849
|
-
end
|
850
|
-
end
|
851
|
-
|
852
859
|
def const_path_write(receiver, name, value, scope)
|
853
860
|
if receiver # receiver::A = value
|
854
861
|
singleton_type = receiver.types.find { _1.is_a? Types::SingletonType }
|
@@ -875,9 +882,9 @@ module ReplTypeCompletor
|
|
875
882
|
end
|
876
883
|
|
877
884
|
def evaluate_constant_node_info(node, scope)
|
885
|
+
name = node.name.to_s
|
878
886
|
case node
|
879
887
|
when Prism::ConstantPathNode
|
880
|
-
name = const_path_name(node)
|
881
888
|
if node.parent
|
882
889
|
receiver = evaluate node.parent, scope
|
883
890
|
if receiver.is_a? Types::SingletonType
|
@@ -893,7 +900,6 @@ module ReplTypeCompletor
|
|
893
900
|
type = Types::NIL
|
894
901
|
end
|
895
902
|
when Prism::ConstantReadNode
|
896
|
-
name = node.name.to_s
|
897
903
|
type = scope[name]
|
898
904
|
end
|
899
905
|
@dig_targets.resolve type, scope if @dig_targets.target? node
|
@@ -1048,8 +1054,7 @@ module ReplTypeCompletor
|
|
1048
1054
|
scope[node.name.to_s] = value
|
1049
1055
|
when Prism::ConstantPathTargetNode
|
1050
1056
|
receiver = evaluated_receivers&.[](node.parent) || evaluate(node.parent, scope) if node.parent
|
1051
|
-
name
|
1052
|
-
const_path_write receiver, name, value, scope
|
1057
|
+
const_path_write receiver, node.name.to_s, value, scope
|
1053
1058
|
end
|
1054
1059
|
end
|
1055
1060
|
|
@@ -1140,7 +1145,7 @@ module ReplTypeCompletor
|
|
1140
1145
|
receiver_vars = receiver.is_a?(Types::InstanceType) ? receiver.params : {}
|
1141
1146
|
free_vars = method.type.free_variables - receiver_vars.keys.to_set
|
1142
1147
|
vars = receiver_vars.merge Types.match_free_variables(free_vars, method_params, given_params)
|
1143
|
-
if block && method.block
|
1148
|
+
if block && method.block && method.block.type.respond_to?(:required_positionals)
|
1144
1149
|
params_type = method.block.type.required_positionals.map do |func_param|
|
1145
1150
|
Types.from_rbs_type func_param.type, receiver, vars
|
1146
1151
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'rbs'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rbs/cli'
|
3
6
|
require_relative 'methods'
|
4
7
|
|
5
8
|
module ReplTypeCompletor
|
@@ -22,11 +25,28 @@ module ReplTypeCompletor
|
|
22
25
|
|
23
26
|
def self.load_rbs_builder
|
24
27
|
@load_started = true
|
25
|
-
require 'rbs'
|
26
|
-
require 'rbs/cli'
|
27
28
|
loader = RBS::CLI::LibraryOptions.new.loader
|
28
|
-
|
29
|
-
|
29
|
+
sig_path = Pathname('sig')
|
30
|
+
loader.add path: sig_path
|
31
|
+
expanded_sig_path = sig_path.expand_path.to_s
|
32
|
+
|
33
|
+
unless File.exist?('rbs_collection.yaml')
|
34
|
+
# Load rbs signature from gems. This is a fallback when rbs_collection.yaml is not available.
|
35
|
+
Gem.loaded_specs.values.each do |spec|
|
36
|
+
gem_sig_path = File.expand_path("#{spec.gem_dir}/sig")
|
37
|
+
loader.add(library: spec.name, version: spec.version) if Dir.exist?(gem_sig_path) && expanded_sig_path != gem_sig_path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Hack to make this thread priority lower, not to block the main thread.
|
42
|
+
thread_pass_counter = 0
|
43
|
+
tracepoint = TracePoint.new(:call) do
|
44
|
+
Thread.pass if ((thread_pass_counter += 1) % 10).zero?
|
45
|
+
end
|
46
|
+
tracepoint.enable do
|
47
|
+
env = RBS::Environment.from_loader(loader)
|
48
|
+
@rbs_builder = RBS::DefinitionBuilder.new env: env.resolve_type_names
|
49
|
+
end
|
30
50
|
rescue LoadError, StandardError => e
|
31
51
|
@rbs_load_error = e
|
32
52
|
nil
|
@@ -83,7 +103,9 @@ module ReplTypeCompletor
|
|
83
103
|
methods_with_score = receivers.flat_map do |receiver_type, klass, singleton|
|
84
104
|
method = rbs_search_method klass, method_name, singleton
|
85
105
|
next [] unless method
|
86
|
-
method.method_types.
|
106
|
+
method.method_types.filter_map do |method_type|
|
107
|
+
next unless method_type.type.respond_to?(:required_positionals)
|
108
|
+
|
87
109
|
score = 0
|
88
110
|
score += 2 if !!method_type.block == has_block
|
89
111
|
reqs = method_type.type.required_positionals
|
@@ -317,6 +339,8 @@ module ReplTypeCompletor
|
|
317
339
|
self_type.transform do |type|
|
318
340
|
if type.is_a?(SingletonType) && type.module_or_class.is_a?(Class)
|
319
341
|
InstanceType.new type.module_or_class
|
342
|
+
elsif type.is_a?(InstanceType)
|
343
|
+
InstanceType.new type.klass
|
320
344
|
else
|
321
345
|
OBJECT
|
322
346
|
end
|
data/lib/repl_type_completor.rb
CHANGED
@@ -101,6 +101,8 @@ module ReplTypeCompletor
|
|
101
101
|
[op == '::' ? :call_or_const : :call, name, receiver_type, self_call]
|
102
102
|
when Prism::LocalVariableReadNode, Prism::LocalVariableTargetNode
|
103
103
|
[:lvar_or_method, target_node.name.to_s, calculate_scope.call]
|
104
|
+
when Prism::ItLocalVariableReadNode
|
105
|
+
[:lvar_or_method, 'it', calculate_scope.call]
|
104
106
|
when Prism::ConstantPathNode, Prism::ConstantPathTargetNode
|
105
107
|
name = target_node.name.to_s
|
106
108
|
if target_node.parent # A::B
|
@@ -111,19 +113,7 @@ module ReplTypeCompletor
|
|
111
113
|
[:const, name, Types::SingletonType.new(Object), scope]
|
112
114
|
end
|
113
115
|
when Prism::ConstantReadNode, Prism::ConstantTargetNode
|
114
|
-
|
115
|
-
if parents.last.is_a? Prism::ConstantPathNode
|
116
|
-
path_node = parents.last
|
117
|
-
if path_node.parent # A::B
|
118
|
-
receiver, scope = calculate_type_scope.call(path_node.parent)
|
119
|
-
[:const, name, receiver, scope]
|
120
|
-
else # ::A
|
121
|
-
scope = calculate_scope.call
|
122
|
-
[:const, name, Types::SingletonType.new(Object), scope]
|
123
|
-
end
|
124
|
-
else
|
125
|
-
[:const, name, nil, calculate_scope.call]
|
126
|
-
end
|
116
|
+
[:const, target_node.name.to_s, nil, calculate_scope.call]
|
127
117
|
when Prism::GlobalVariableReadNode, Prism::GlobalVariableTargetNode
|
128
118
|
[:gvar, target_node.name.to_s, calculate_scope.call]
|
129
119
|
when Prism::InstanceVariableReadNode, Prism::InstanceVariableTargetNode
|
@@ -134,8 +124,8 @@ module ReplTypeCompletor
|
|
134
124
|
end
|
135
125
|
|
136
126
|
def find_target(node, position)
|
137
|
-
# Skip because
|
138
|
-
return if node.is_a? Prism::
|
127
|
+
# Skip because location of these nodes gives location of whole block
|
128
|
+
return if node.is_a?(Prism::NumberedParametersNode) || node.is_a?(Prism::ItParametersNode)
|
139
129
|
|
140
130
|
node.compact_child_nodes.each do |n|
|
141
131
|
match = find_target(n, position)
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: repl_type_completor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tompng
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prism
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '1.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rbs
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|