solargraph 0.54.1 → 0.54.5
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/CHANGELOG.md +26 -0
- data/lib/solargraph/api_map/cache.rb +10 -1
- data/lib/solargraph/api_map/index.rb +167 -0
- data/lib/solargraph/api_map/store.rb +68 -121
- data/lib/solargraph/api_map.rb +79 -28
- data/lib/solargraph/bench.rb +17 -1
- data/lib/solargraph/complex_type/type_methods.rb +7 -0
- data/lib/solargraph/complex_type/unique_type.rb +21 -1
- data/lib/solargraph/complex_type.rb +13 -12
- data/lib/solargraph/convention.rb +1 -0
- data/lib/solargraph/doc_map.rb +1 -0
- data/lib/solargraph/equality.rb +33 -0
- data/lib/solargraph/language_server/host/message_worker.rb +23 -6
- data/lib/solargraph/language_server/host.rb +12 -11
- data/lib/solargraph/language_server/message/base.rb +19 -12
- data/lib/solargraph/language_server/message/initialize.rb +3 -1
- data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
- data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -0
- data/lib/solargraph/library.rb +7 -8
- data/lib/solargraph/location.rb +7 -0
- data/lib/solargraph/parser/node_methods.rb +1 -1
- data/lib/solargraph/parser/node_processor.rb +1 -0
- data/lib/solargraph/parser/parser_gem/class_methods.rb +2 -6
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +7 -13
- data/lib/solargraph/parser/parser_gem/node_methods.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -2
- data/lib/solargraph/pin/base.rb +28 -18
- data/lib/solargraph/pin/base_variable.rb +3 -2
- data/lib/solargraph/pin/block.rb +1 -3
- data/lib/solargraph/pin/callable.rb +3 -3
- data/lib/solargraph/pin/method.rb +6 -0
- data/lib/solargraph/pin/namespace.rb +1 -1
- data/lib/solargraph/pin/parameter.rb +2 -1
- data/lib/solargraph/position.rb +7 -0
- data/lib/solargraph/range.rb +7 -0
- data/lib/solargraph/rbs_map/conversions.rb +8 -2
- data/lib/solargraph/rbs_map.rb +1 -0
- data/lib/solargraph/shell.rb +2 -0
- data/lib/solargraph/source/chain/array.rb +1 -1
- data/lib/solargraph/source/chain/call.rb +15 -8
- data/lib/solargraph/source/chain/hash.rb +5 -0
- data/lib/solargraph/source/chain/if.rb +5 -0
- data/lib/solargraph/source/chain/link.rb +17 -5
- data/lib/solargraph/source/chain/literal.rb +5 -0
- data/lib/solargraph/source/chain.rb +33 -19
- data/lib/solargraph/source/cursor.rb +1 -11
- data/lib/solargraph/source.rb +2 -1
- data/lib/solargraph/source_map/clip.rb +1 -1
- data/lib/solargraph/type_checker.rb +8 -8
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/workspace/config.rb +7 -3
- data/lib/solargraph/workspace.rb +1 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +1 -0
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +1 -0
- data/lib/solargraph/yard_map/mapper.rb +1 -0
- data/lib/solargraph/yardoc.rb +1 -1
- data/lib/solargraph.rb +1 -0
- data/solargraph.gemspec +5 -5
- metadata +27 -25
data/lib/solargraph/api_map.rb
CHANGED
|
@@ -12,6 +12,7 @@ module Solargraph
|
|
|
12
12
|
autoload :Cache, 'solargraph/api_map/cache'
|
|
13
13
|
autoload :SourceToYard, 'solargraph/api_map/source_to_yard'
|
|
14
14
|
autoload :Store, 'solargraph/api_map/store'
|
|
15
|
+
autoload :Index, 'solargraph/api_map/index'
|
|
15
16
|
|
|
16
17
|
# @return [Array<String>]
|
|
17
18
|
attr_reader :unresolved_requires
|
|
@@ -48,6 +49,15 @@ module Solargraph
|
|
|
48
49
|
equality_fields.hash
|
|
49
50
|
end
|
|
50
51
|
|
|
52
|
+
def to_s
|
|
53
|
+
self.class.to_s
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# avoid enormous dump
|
|
57
|
+
def inspect
|
|
58
|
+
to_s
|
|
59
|
+
end
|
|
60
|
+
|
|
51
61
|
# @param pins [Array<Pin::Base>]
|
|
52
62
|
# @return [self]
|
|
53
63
|
def index pins
|
|
@@ -56,7 +66,7 @@ module Solargraph
|
|
|
56
66
|
@source_map_hash = {}
|
|
57
67
|
implicit.clear
|
|
58
68
|
cache.clear
|
|
59
|
-
|
|
69
|
+
store.update @@core_map.pins, pins
|
|
60
70
|
self
|
|
61
71
|
end
|
|
62
72
|
|
|
@@ -75,10 +85,9 @@ module Solargraph
|
|
|
75
85
|
# @param bench [Bench]
|
|
76
86
|
# @return [self]
|
|
77
87
|
def catalog bench
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
pins = bench.source_maps.flat_map(&:pins).flatten
|
|
88
|
+
@source_map_hash = bench.source_map_hash
|
|
89
|
+
iced_pins = bench.icebox.flat_map(&:pins)
|
|
90
|
+
live_pins = bench.live_map&.pins || []
|
|
82
91
|
implicit.clear
|
|
83
92
|
source_map_hash.each_value do |map|
|
|
84
93
|
implicit.merge map.environ
|
|
@@ -87,17 +96,17 @@ module Solargraph
|
|
|
87
96
|
if @unresolved_requires != unresolved_requires || @doc_map&.uncached_gemspecs&.any?
|
|
88
97
|
@doc_map = DocMap.new(unresolved_requires, [], bench.workspace.rbs_collection_path) # @todo Implement gem preferences
|
|
89
98
|
@unresolved_requires = unresolved_requires
|
|
90
|
-
need_to_uncache = true
|
|
91
99
|
end
|
|
92
|
-
@
|
|
93
|
-
@cache.clear if need_to_uncache
|
|
94
|
-
|
|
100
|
+
@cache.clear if store.update(@@core_map.pins, @doc_map.pins, implicit.pins, iced_pins, live_pins)
|
|
95
101
|
@missing_docs = [] # @todo Implement missing docs
|
|
96
102
|
self
|
|
97
103
|
end
|
|
98
104
|
|
|
105
|
+
# @todo need to model type def statement in chains as a symbol so
|
|
106
|
+
# that this overload of 'protected' will typecheck @sg-ignore
|
|
107
|
+
# @sg-ignore
|
|
99
108
|
protected def equality_fields
|
|
100
|
-
[self.class, @source_map_hash, implicit, @doc_map, @unresolved_requires
|
|
109
|
+
[self.class, @source_map_hash, implicit, @doc_map, @unresolved_requires]
|
|
101
110
|
end
|
|
102
111
|
|
|
103
112
|
# @return [::Array<Gem::Specification>]
|
|
@@ -183,7 +192,7 @@ module Solargraph
|
|
|
183
192
|
|
|
184
193
|
# @return [Array<Solargraph::Pin::Base>]
|
|
185
194
|
def pins
|
|
186
|
-
store.pins
|
|
195
|
+
store.pins.clone.freeze
|
|
187
196
|
end
|
|
188
197
|
|
|
189
198
|
# An array of pins based on Ruby keywords (`if`, `end`, etc.).
|
|
@@ -341,8 +350,12 @@ module Solargraph
|
|
|
341
350
|
# @param deep [Boolean] True to include superclasses, mixins, etc.
|
|
342
351
|
# @return [Array<Solargraph::Pin::Method>]
|
|
343
352
|
def get_methods rooted_tag, scope: :instance, visibility: [:public], deep: true
|
|
353
|
+
rooted_type = ComplexType.try_parse(rooted_tag)
|
|
354
|
+
fqns = rooted_type.namespace
|
|
355
|
+
namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
|
|
344
356
|
cached = cache.get_methods(rooted_tag, scope, visibility, deep)
|
|
345
357
|
return cached.clone unless cached.nil?
|
|
358
|
+
# @type [Array<Solargraph::Pin::Method>]
|
|
346
359
|
result = []
|
|
347
360
|
skip = Set.new
|
|
348
361
|
if rooted_tag == ''
|
|
@@ -380,9 +393,12 @@ module Solargraph
|
|
|
380
393
|
result.concat inner_get_methods('Kernel', :instance, [:public], deep, skip) if visibility.include?(:private)
|
|
381
394
|
result.concat inner_get_methods('Module', scope, visibility, deep, skip) if scope == :module
|
|
382
395
|
end
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
396
|
+
result = resolve_method_aliases(result, visibility)
|
|
397
|
+
if namespace_pin && rooted_tag != rooted_type.name
|
|
398
|
+
result = result.map { |method_pin| method_pin.resolve_generics(namespace_pin, rooted_type) }
|
|
399
|
+
end
|
|
400
|
+
cache.set_methods(rooted_tag, scope, visibility, deep, result)
|
|
401
|
+
result
|
|
386
402
|
end
|
|
387
403
|
|
|
388
404
|
# Get an array of method pins for a complex type.
|
|
@@ -438,8 +454,13 @@ module Solargraph
|
|
|
438
454
|
# @param name [String] Method name to look up
|
|
439
455
|
# @param scope [Symbol] :instance or :class
|
|
440
456
|
# @return [Array<Solargraph::Pin::Method>]
|
|
441
|
-
def get_method_stack rooted_tag, name, scope: :instance
|
|
442
|
-
|
|
457
|
+
def get_method_stack rooted_tag, name, scope: :instance, visibility: [:private, :protected, :public], preserve_generics: false
|
|
458
|
+
rooted_type = ComplexType.parse(rooted_tag)
|
|
459
|
+
fqns = rooted_type.namespace
|
|
460
|
+
namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
|
|
461
|
+
methods = get_methods(rooted_tag, scope: scope, visibility: visibility).select { |p| p.name == name }
|
|
462
|
+
methods = erase_generics(namespace_pin, rooted_type, methods) unless preserve_generics
|
|
463
|
+
methods
|
|
443
464
|
end
|
|
444
465
|
|
|
445
466
|
# Get an array of all suggestions that match the specified path.
|
|
@@ -601,6 +622,7 @@ module Solargraph
|
|
|
601
622
|
rooted_type = ComplexType.parse(rooted_tag).force_rooted
|
|
602
623
|
fqns = rooted_type.namespace
|
|
603
624
|
fqns_generic_params = rooted_type.all_params
|
|
625
|
+
namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
|
|
604
626
|
return [] if no_core && fqns =~ /^(Object|BasicObject|Class|Module)$/
|
|
605
627
|
reqstr = "#{fqns}|#{scope}|#{visibility.sort}|#{deep}"
|
|
606
628
|
return [] if skip.include?(reqstr)
|
|
@@ -615,15 +637,7 @@ module Solargraph
|
|
|
615
637
|
# Store#get_methods doesn't know about full tags, just
|
|
616
638
|
# namespaces; resolving the generics in the method pins is this
|
|
617
639
|
# class' responsibility
|
|
618
|
-
|
|
619
|
-
namespace_pin = store.get_path_pins(fqns).select { |p| p.is_a?(Pin::Namespace) }.first
|
|
620
|
-
methods = if namespace_pin && rooted_tag != fqns
|
|
621
|
-
methods = raw_methods.map do |method_pin|
|
|
622
|
-
method_pin.resolve_generics(namespace_pin, rooted_type)
|
|
623
|
-
end
|
|
624
|
-
else
|
|
625
|
-
raw_methods
|
|
626
|
-
end
|
|
640
|
+
methods = store.get_methods(fqns, scope: scope, visibility: visibility).sort{ |a, b| a.name <=> b.name }
|
|
627
641
|
result.concat methods
|
|
628
642
|
if deep
|
|
629
643
|
if scope == :instance
|
|
@@ -768,8 +782,8 @@ module Solargraph
|
|
|
768
782
|
|
|
769
783
|
# Sort an array of pins to put nil or undefined variables last.
|
|
770
784
|
#
|
|
771
|
-
# @param pins [Enumerable<
|
|
772
|
-
# @return [Enumerable<
|
|
785
|
+
# @param pins [Enumerable<Pin::BaseVariable>]
|
|
786
|
+
# @return [Enumerable<Pin::BaseVariable>]
|
|
773
787
|
def prefer_non_nil_variables pins
|
|
774
788
|
result = []
|
|
775
789
|
nil_pins = []
|
|
@@ -809,11 +823,48 @@ module Solargraph
|
|
|
809
823
|
name: pin.name,
|
|
810
824
|
comments: origin.comments,
|
|
811
825
|
scope: origin.scope,
|
|
826
|
+
# context: pin.context,
|
|
812
827
|
visibility: origin.visibility,
|
|
813
828
|
signatures: origin.signatures,
|
|
814
|
-
attribute: origin.attribute
|
|
829
|
+
attribute: origin.attribute?,
|
|
830
|
+
generics: origin.generics,
|
|
831
|
+
return_type: origin.return_type,
|
|
815
832
|
}
|
|
816
833
|
Pin::Method.new **args
|
|
817
834
|
end
|
|
835
|
+
|
|
836
|
+
include Logging
|
|
837
|
+
|
|
838
|
+
private
|
|
839
|
+
|
|
840
|
+
# @param namespace_pin [Pin::Namespace]
|
|
841
|
+
# @param rooted_type [ComplexType]
|
|
842
|
+
# @param pins [Enumerable<Pin::Base>]
|
|
843
|
+
# @return [Array<Pin::Base>]
|
|
844
|
+
def erase_generics(namespace_pin, rooted_type, pins)
|
|
845
|
+
return pins unless should_erase_generics_when_done?(namespace_pin, rooted_type)
|
|
846
|
+
|
|
847
|
+
logger.debug("Erasing generics on namespace_pin=#{namespace_pin} / rooted_type=#{rooted_type}")
|
|
848
|
+
pins.map do |method_pin|
|
|
849
|
+
method_pin.erase_generics(namespace_pin.generics)
|
|
850
|
+
end
|
|
851
|
+
end
|
|
852
|
+
|
|
853
|
+
# @param namespace_pin [Pin::Namespace]
|
|
854
|
+
# @param rooted_type [ComplexType]
|
|
855
|
+
def should_erase_generics_when_done?(namespace_pin, rooted_type)
|
|
856
|
+
has_generics?(namespace_pin) && !can_resolve_generics?(namespace_pin, rooted_type)
|
|
857
|
+
end
|
|
858
|
+
|
|
859
|
+
# @param namespace_pin [Pin::Namespace]
|
|
860
|
+
def has_generics?(namespace_pin)
|
|
861
|
+
namespace_pin && !namespace_pin.generics.empty?
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
# @param namespace_pin [Pin::Namespace]
|
|
865
|
+
# @param rooted_type [ComplexType]
|
|
866
|
+
def can_resolve_generics?(namespace_pin, rooted_type)
|
|
867
|
+
has_generics?(namespace_pin) && !rooted_type.all_params.empty?
|
|
868
|
+
end
|
|
818
869
|
end
|
|
819
870
|
end
|
data/lib/solargraph/bench.rb
CHANGED
|
@@ -11,18 +11,34 @@ module Solargraph
|
|
|
11
11
|
# @return [Workspace]
|
|
12
12
|
attr_reader :workspace
|
|
13
13
|
|
|
14
|
+
# @return [SourceMap]
|
|
15
|
+
attr_reader :live_map
|
|
16
|
+
|
|
14
17
|
# @return [Set<String>]
|
|
15
18
|
attr_reader :external_requires
|
|
16
19
|
|
|
17
20
|
# @param source_maps [Array<SourceMap>, Set<SourceMap>]
|
|
18
21
|
# @param workspace [Workspace]
|
|
22
|
+
# @param live_map [SourceMap, nil]
|
|
19
23
|
# @param external_requires [Array<String>, Set<String>]
|
|
20
|
-
def initialize source_maps: [], workspace: Workspace.new, external_requires: []
|
|
24
|
+
def initialize source_maps: [], workspace: Workspace.new, live_map: nil, external_requires: []
|
|
21
25
|
@source_maps = source_maps.to_set
|
|
22
26
|
@workspace = workspace
|
|
27
|
+
@live_map = live_map
|
|
23
28
|
@external_requires = external_requires.reject { |path| workspace.would_require?(path) }
|
|
24
29
|
.compact
|
|
25
30
|
.to_set
|
|
26
31
|
end
|
|
32
|
+
|
|
33
|
+
# @return [Hash{String => SourceMap}]
|
|
34
|
+
def source_map_hash
|
|
35
|
+
# @todo Work around #to_h bug in current Ruby head (3.5) with #map#to_h
|
|
36
|
+
@source_map_hash ||= source_maps.map { |s| [s.filename, s] }
|
|
37
|
+
.to_h
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def icebox
|
|
41
|
+
@icebox ||= (source_maps - [live_map])
|
|
42
|
+
end
|
|
27
43
|
end
|
|
28
44
|
end
|
|
@@ -129,6 +129,13 @@ module Solargraph
|
|
|
129
129
|
end.call
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
+
def namespace_type
|
|
133
|
+
return ComplexType.parse('::Object') if duck_type?
|
|
134
|
+
return ComplexType.parse('::NilClass') if nil_type?
|
|
135
|
+
return subtypes.first if (name == 'Class' || name == 'Module') && !subtypes.empty?
|
|
136
|
+
self
|
|
137
|
+
end
|
|
138
|
+
|
|
132
139
|
# @return [String]
|
|
133
140
|
def rooted_namespace
|
|
134
141
|
return namespace unless rooted? && can_root_name?(namespace)
|
|
@@ -7,9 +7,15 @@ module Solargraph
|
|
|
7
7
|
#
|
|
8
8
|
class UniqueType
|
|
9
9
|
include TypeMethods
|
|
10
|
+
include Equality
|
|
10
11
|
|
|
11
12
|
attr_reader :all_params, :subtypes, :key_types
|
|
12
13
|
|
|
14
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
15
|
+
protected def equality_fields
|
|
16
|
+
[@name, @all_params, @subtypes, @key_types]
|
|
17
|
+
end
|
|
18
|
+
|
|
13
19
|
# Create a UniqueType with the specified name and an optional substring.
|
|
14
20
|
# The substring is the parameter section of a parametrized type, e.g.,
|
|
15
21
|
# for the type `Array<String>`, the name is `Array` and the substring is
|
|
@@ -112,6 +118,10 @@ module Solargraph
|
|
|
112
118
|
end
|
|
113
119
|
end
|
|
114
120
|
|
|
121
|
+
def desc
|
|
122
|
+
rooted_tags
|
|
123
|
+
end
|
|
124
|
+
|
|
115
125
|
# @return [String]
|
|
116
126
|
def to_rbs
|
|
117
127
|
if duck_type?
|
|
@@ -235,7 +245,17 @@ module Solargraph
|
|
|
235
245
|
if t.name == GENERIC_TAG_NAME
|
|
236
246
|
idx = definitions.generics.index(t.subtypes.first&.name)
|
|
237
247
|
next t if idx.nil?
|
|
238
|
-
context_type.
|
|
248
|
+
if context_type.parameters_type == :hash
|
|
249
|
+
if idx == 0
|
|
250
|
+
next ComplexType.new(context_type.key_types)
|
|
251
|
+
elsif idx == 1
|
|
252
|
+
next ComplexType.new(context_type.subtypes)
|
|
253
|
+
else
|
|
254
|
+
next ComplexType::UNDEFINED
|
|
255
|
+
end
|
|
256
|
+
else
|
|
257
|
+
context_type.all_params[idx] || ComplexType::UNDEFINED
|
|
258
|
+
end
|
|
239
259
|
else
|
|
240
260
|
t
|
|
241
261
|
end
|
|
@@ -7,6 +7,7 @@ module Solargraph
|
|
|
7
7
|
GENERIC_TAG_NAME = 'generic'.freeze
|
|
8
8
|
# @!parse
|
|
9
9
|
# include TypeMethods
|
|
10
|
+
include Equality
|
|
10
11
|
|
|
11
12
|
autoload :TypeMethods, 'solargraph/complex_type/type_methods'
|
|
12
13
|
autoload :UniqueType, 'solargraph/complex_type/unique_type'
|
|
@@ -18,17 +19,9 @@ module Solargraph
|
|
|
18
19
|
@items = types.flat_map(&:items).uniq(&:to_s)
|
|
19
20
|
end
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def ==(other)
|
|
27
|
-
self.eql?(other)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def hash
|
|
31
|
-
[self.class, @items].hash
|
|
22
|
+
# @sg-ignore Fix "Not enough arguments to Module#protected"
|
|
23
|
+
protected def equality_fields
|
|
24
|
+
[self.class, items]
|
|
32
25
|
end
|
|
33
26
|
|
|
34
27
|
# @param api_map [ApiMap]
|
|
@@ -154,14 +147,22 @@ module Solargraph
|
|
|
154
147
|
map(&:tag).join(', ')
|
|
155
148
|
end
|
|
156
149
|
|
|
150
|
+
def desc
|
|
151
|
+
rooted_tags
|
|
152
|
+
end
|
|
153
|
+
|
|
157
154
|
def rooted_tags
|
|
158
155
|
map(&:rooted_tag).join(', ')
|
|
159
156
|
end
|
|
160
157
|
|
|
158
|
+
# @yieldparam [UniqueType]
|
|
161
159
|
def all? &block
|
|
162
160
|
@items.all? &block
|
|
163
161
|
end
|
|
164
162
|
|
|
163
|
+
# @yieldparam [UniqueType]
|
|
164
|
+
# @yieldreturn [Boolean]
|
|
165
|
+
# @return [Boolean]
|
|
165
166
|
def any? &block
|
|
166
167
|
@items.compact.any? &block
|
|
167
168
|
end
|
|
@@ -263,7 +264,7 @@ module Solargraph
|
|
|
263
264
|
# Consumers should not need to use this parameter; it should only be
|
|
264
265
|
# used internally.
|
|
265
266
|
#
|
|
266
|
-
# @param
|
|
267
|
+
# @param strings [Array<String>] The type definitions to parse
|
|
267
268
|
# @return [ComplexType]
|
|
268
269
|
# # @overload parse(*strings, partial: false)
|
|
269
270
|
# # @todo Need ability to use a literal true as a type below
|
data/lib/solargraph/doc_map.rb
CHANGED
|
@@ -112,6 +112,7 @@ module Solargraph
|
|
|
112
112
|
true
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
+
# @param gemspec [Gem::Specification]
|
|
115
116
|
def update_from_collection gemspec, gempins
|
|
116
117
|
return gempins unless @rbs_path && File.directory?(@rbs_path)
|
|
117
118
|
return gempins if RbsMap.new(gemspec.name, gemspec.version).resolved?
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
# @abstract This mixin relies on these -
|
|
5
|
+
# methods:
|
|
6
|
+
# equality_fields()
|
|
7
|
+
module Equality
|
|
8
|
+
# @!method equality_fields
|
|
9
|
+
# @return [Array]
|
|
10
|
+
|
|
11
|
+
# @param other [Object]
|
|
12
|
+
# @return [Boolean]
|
|
13
|
+
def eql?(other)
|
|
14
|
+
self.class.eql?(other.class) &&
|
|
15
|
+
equality_fields.eql?(other.equality_fields)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param other [Object]
|
|
19
|
+
# @return [Boolean]
|
|
20
|
+
def ==(other)
|
|
21
|
+
self.eql?(other)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def hash
|
|
25
|
+
equality_fields.hash
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def freeze
|
|
29
|
+
equality_fields.each(&:freeze)
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
module Solargraph
|
|
4
4
|
module LanguageServer
|
|
5
5
|
class Host
|
|
6
|
-
# A serial worker Thread to handle
|
|
7
|
-
#
|
|
8
|
-
# this make check pending message possible, and maybe cancelled to speedup process
|
|
6
|
+
# A serial worker Thread to handle incoming messages.
|
|
9
7
|
#
|
|
10
8
|
class MessageWorker
|
|
11
|
-
UPDATE_METHODS = [
|
|
9
|
+
UPDATE_METHODS = [
|
|
10
|
+
'textDocument/didOpen',
|
|
11
|
+
'textDocument/didChange',
|
|
12
|
+
'workspace/didChangeWatchedFiles'
|
|
13
|
+
].freeze
|
|
12
14
|
|
|
13
15
|
# @param host [Host]
|
|
14
16
|
def initialize(host)
|
|
@@ -64,12 +66,24 @@ module Solargraph
|
|
|
64
66
|
private
|
|
65
67
|
|
|
66
68
|
def next_message
|
|
69
|
+
cancel_message || next_priority
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def cancel_message
|
|
73
|
+
# Handle cancellations first
|
|
74
|
+
idx = messages.find_index { |msg| msg['method'] == '$/cancelRequest' }
|
|
75
|
+
return unless idx
|
|
76
|
+
|
|
77
|
+
msg = messages[idx]
|
|
78
|
+
messages.delete_at idx
|
|
79
|
+
msg
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def next_priority
|
|
67
83
|
# Prioritize updates and version-dependent messages for performance
|
|
68
84
|
idx = messages.find_index do |msg|
|
|
69
85
|
UPDATE_METHODS.include?(msg['method']) || version_dependent?(msg)
|
|
70
86
|
end
|
|
71
|
-
# @todo We might want to clear duplicate instances of this message
|
|
72
|
-
# that occur before the next update
|
|
73
87
|
return messages.shift unless idx
|
|
74
88
|
|
|
75
89
|
msg = messages[idx]
|
|
@@ -80,6 +94,9 @@ module Solargraph
|
|
|
80
94
|
# True if the message requires a previous update to have executed in
|
|
81
95
|
# order to work correctly.
|
|
82
96
|
#
|
|
97
|
+
# @param msg [Hash{String => Object}]
|
|
98
|
+
# @todo need boolish type from RBS
|
|
99
|
+
# @return [Object]
|
|
83
100
|
def version_dependent? msg
|
|
84
101
|
msg['textDocument'] && msg['position']
|
|
85
102
|
end
|
|
@@ -24,10 +24,8 @@ module Solargraph
|
|
|
24
24
|
attr_writer :client_capabilities
|
|
25
25
|
|
|
26
26
|
def initialize
|
|
27
|
-
@cancel_semaphore = Mutex.new
|
|
28
27
|
@buffer_semaphore = Mutex.new
|
|
29
28
|
@request_mutex = Mutex.new
|
|
30
|
-
@cancel = []
|
|
31
29
|
@buffer = String.new
|
|
32
30
|
@stopped = true
|
|
33
31
|
@next_request_id = 1
|
|
@@ -65,7 +63,7 @@ module Solargraph
|
|
|
65
63
|
# @param id [Integer]
|
|
66
64
|
# @return [void]
|
|
67
65
|
def cancel id
|
|
68
|
-
|
|
66
|
+
cancelled.push id
|
|
69
67
|
end
|
|
70
68
|
|
|
71
69
|
# True if the host received a request to cancel the method with the
|
|
@@ -74,9 +72,7 @@ module Solargraph
|
|
|
74
72
|
# @param id [Integer]
|
|
75
73
|
# @return [Boolean]
|
|
76
74
|
def cancel? id
|
|
77
|
-
|
|
78
|
-
@cancel_semaphore.synchronize { result = @cancel.include? id }
|
|
79
|
-
result
|
|
75
|
+
cancelled.include? id
|
|
80
76
|
end
|
|
81
77
|
|
|
82
78
|
# Delete the specified ID from the list of cancelled IDs if it exists.
|
|
@@ -84,7 +80,7 @@ module Solargraph
|
|
|
84
80
|
# @param id [Integer]
|
|
85
81
|
# @return [void]
|
|
86
82
|
def clear id
|
|
87
|
-
|
|
83
|
+
cancelled.delete id
|
|
88
84
|
end
|
|
89
85
|
|
|
90
86
|
# Called by adapter, to handle the request
|
|
@@ -101,11 +97,11 @@ module Solargraph
|
|
|
101
97
|
# @return [Solargraph::LanguageServer::Message::Base, nil] The message handler.
|
|
102
98
|
def receive request
|
|
103
99
|
if request['method']
|
|
104
|
-
logger.info "
|
|
100
|
+
logger.info "Host received ##{request['id']} #{request['method']}"
|
|
105
101
|
logger.debug request
|
|
106
102
|
message = Message.select(request['method']).new(self, request)
|
|
107
103
|
begin
|
|
108
|
-
message.process
|
|
104
|
+
message.process unless cancel?(request['id'])
|
|
109
105
|
rescue StandardError => e
|
|
110
106
|
logger.warn "Error processing request: [#{e.class}] #{e.message}"
|
|
111
107
|
logger.warn e.backtrace.join("\n")
|
|
@@ -381,7 +377,6 @@ module Solargraph
|
|
|
381
377
|
envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
|
|
382
378
|
queue envelope
|
|
383
379
|
@next_request_id += 1
|
|
384
|
-
logger.info "Server sent #{method}"
|
|
385
380
|
logger.debug params
|
|
386
381
|
end
|
|
387
382
|
end
|
|
@@ -476,6 +471,7 @@ module Solargraph
|
|
|
476
471
|
def locate_pins params
|
|
477
472
|
return [] unless params['data'] && params['data']['uri']
|
|
478
473
|
library = library_for(params['data']['uri'])
|
|
474
|
+
# @type [Array<Pin::Base>]
|
|
479
475
|
result = []
|
|
480
476
|
if params['data']['location']
|
|
481
477
|
location = Location.new(
|
|
@@ -575,7 +571,7 @@ module Solargraph
|
|
|
575
571
|
# @param column [Integer]
|
|
576
572
|
# @param strip [Boolean] Strip special characters from variable names
|
|
577
573
|
# @param only [Boolean] If true, search current file only
|
|
578
|
-
# @return [Array<Solargraph::
|
|
574
|
+
# @return [Array<Solargraph::Location>]
|
|
579
575
|
def references_from uri, line, column, strip: true, only: false
|
|
580
576
|
library = library_for(uri)
|
|
581
577
|
library.references_from(uri_to_file(uri), line, column, strip: strip, only: only)
|
|
@@ -693,6 +689,11 @@ module Solargraph
|
|
|
693
689
|
|
|
694
690
|
private
|
|
695
691
|
|
|
692
|
+
# @return [Array<Integer>]
|
|
693
|
+
def cancelled
|
|
694
|
+
@cancelled ||= []
|
|
695
|
+
end
|
|
696
|
+
|
|
696
697
|
# @return [MessageWorker]
|
|
697
698
|
def message_worker
|
|
698
699
|
@message_worker ||= MessageWorker.new(self)
|
|
@@ -16,7 +16,7 @@ module Solargraph
|
|
|
16
16
|
# @return [String]
|
|
17
17
|
attr_reader :method
|
|
18
18
|
|
|
19
|
-
# @return [Hash{String => Array
|
|
19
|
+
# @return [Hash{String => Array<undefined>, Hash{String => undefined}, String, Integer}]
|
|
20
20
|
attr_reader :params
|
|
21
21
|
|
|
22
22
|
# @return [Hash, Array, nil]
|
|
@@ -61,18 +61,11 @@ module Solargraph
|
|
|
61
61
|
# @return [void]
|
|
62
62
|
def send_response
|
|
63
63
|
return if id.nil?
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# cancel should send response RequestCancelled
|
|
67
|
-
Solargraph::Logging.logger.info "Cancelled response to #{method}"
|
|
68
|
-
set_result nil
|
|
69
|
-
set_error ErrorCodes::REQUEST_CANCELLED, "cancelled by client"
|
|
70
|
-
else
|
|
71
|
-
Solargraph::Logging.logger.info "Sending response to #{method}"
|
|
72
|
-
end
|
|
64
|
+
|
|
65
|
+
accept_or_cancel
|
|
73
66
|
response = {
|
|
74
|
-
jsonrpc:
|
|
75
|
-
id: id
|
|
67
|
+
jsonrpc: '2.0',
|
|
68
|
+
id: id
|
|
76
69
|
}
|
|
77
70
|
response[:result] = result unless result.nil?
|
|
78
71
|
response[:error] = error unless error.nil?
|
|
@@ -83,6 +76,20 @@ module Solargraph
|
|
|
83
76
|
host.queue envelope
|
|
84
77
|
host.clear id
|
|
85
78
|
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def accept_or_cancel
|
|
83
|
+
if host.cancel?(id)
|
|
84
|
+
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest
|
|
85
|
+
# cancel should send response RequestCancelled
|
|
86
|
+
Solargraph::Logging.logger.info "Cancelled response to ##{id} #{method}"
|
|
87
|
+
set_result nil
|
|
88
|
+
set_error ErrorCodes::REQUEST_CANCELLED, 'Cancelled by client'
|
|
89
|
+
else
|
|
90
|
+
Solargraph::Logging.logger.info "Sending response to ##{id} #{method}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
86
93
|
end
|
|
87
94
|
end
|
|
88
95
|
end
|
|
@@ -174,7 +174,9 @@ module Solargraph
|
|
|
174
174
|
|
|
175
175
|
# @param section [String]
|
|
176
176
|
# @param capability [String]
|
|
177
|
-
# @
|
|
177
|
+
# @todo Need support for RBS' boolish "type", which doesn't
|
|
178
|
+
# enforce strict true/false-ness
|
|
179
|
+
# @sg-ignore
|
|
178
180
|
def dynamic_registration_for? section, capability
|
|
179
181
|
result = (params['capabilities'] &&
|
|
180
182
|
params['capabilities'][section] &&
|
|
@@ -12,9 +12,6 @@ module Solargraph
|
|
|
12
12
|
col = params['position']['character']
|
|
13
13
|
begin
|
|
14
14
|
completion = host.completions_at(params['textDocument']['uri'], line, col)
|
|
15
|
-
if host.cancel?(id)
|
|
16
|
-
return set_result(empty_result) if host.cancel?(id)
|
|
17
|
-
end
|
|
18
15
|
items = []
|
|
19
16
|
last_context = nil
|
|
20
17
|
idx = -1
|
|
@@ -33,6 +33,7 @@ module Solargraph
|
|
|
33
33
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
|
+
# @param corrections [String]
|
|
36
37
|
def log_corrections(corrections)
|
|
37
38
|
corrections = corrections&.strip
|
|
38
39
|
return if corrections&.empty?
|
|
@@ -51,6 +52,7 @@ module Solargraph
|
|
|
51
52
|
conf['rubocop'] || {}
|
|
52
53
|
end
|
|
53
54
|
|
|
55
|
+
# @param config [Hash{String => String}]
|
|
54
56
|
def cli_args file_uri, config
|
|
55
57
|
file = UriHelpers.uri_to_file(file_uri)
|
|
56
58
|
args = [
|
|
@@ -68,6 +70,7 @@ module Solargraph
|
|
|
68
70
|
args + [file]
|
|
69
71
|
end
|
|
70
72
|
|
|
73
|
+
# @param config [Hash{String => String}]
|
|
71
74
|
def formatter_class(config)
|
|
72
75
|
if self.class.const_defined?('BlankRubocopFormatter')
|
|
73
76
|
# @sg-ignore
|
|
@@ -79,6 +82,7 @@ module Solargraph
|
|
|
79
82
|
end
|
|
80
83
|
end
|
|
81
84
|
|
|
85
|
+
# @param value [Array, String]
|
|
82
86
|
def cop_list(value)
|
|
83
87
|
value = value.join(',') if value.respond_to?(:join)
|
|
84
88
|
return nil if value == '' || !value.is_a?(String)
|