repl_type_completor 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|