solargraph 0.51.2 → 0.54.2

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.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +40 -0
  3. data/.github/workflows/rspec.yml +1 -3
  4. data/.github/workflows/typecheck.yml +34 -0
  5. data/.yardopts +2 -2
  6. data/CHANGELOG.md +127 -5
  7. data/README.md +13 -16
  8. data/SPONSORS.md +1 -7
  9. data/lib/solargraph/api_map/cache.rb +50 -20
  10. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  11. data/lib/solargraph/api_map/store.rb +60 -15
  12. data/lib/solargraph/api_map.rb +282 -123
  13. data/lib/solargraph/bench.rb +3 -2
  14. data/lib/solargraph/cache.rb +29 -5
  15. data/lib/solargraph/complex_type/type_methods.rb +122 -39
  16. data/lib/solargraph/complex_type/unique_type.rb +310 -76
  17. data/lib/solargraph/complex_type.rb +166 -44
  18. data/lib/solargraph/convention.rb +0 -1
  19. data/lib/solargraph/converters/dd.rb +5 -0
  20. data/lib/solargraph/converters/dl.rb +3 -0
  21. data/lib/solargraph/converters/dt.rb +3 -0
  22. data/lib/solargraph/diagnostics/rubocop.rb +8 -7
  23. data/lib/solargraph/diagnostics/rubocop_helpers.rb +1 -0
  24. data/lib/solargraph/diagnostics/type_check.rb +1 -0
  25. data/lib/solargraph/diagnostics.rb +2 -2
  26. data/lib/solargraph/doc_map.rb +187 -0
  27. data/lib/solargraph/gem_pins.rb +72 -0
  28. data/lib/solargraph/language_server/host/diagnoser.rb +2 -2
  29. data/lib/solargraph/language_server/host/dispatch.rb +22 -5
  30. data/lib/solargraph/language_server/host/message_worker.rb +49 -5
  31. data/lib/solargraph/language_server/host/sources.rb +8 -65
  32. data/lib/solargraph/language_server/host.rb +65 -84
  33. data/lib/solargraph/language_server/message/base.rb +19 -12
  34. data/lib/solargraph/language_server/message/completion_item/resolve.rb +3 -1
  35. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +13 -1
  36. data/lib/solargraph/language_server/message/initialize.rb +19 -2
  37. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  38. data/lib/solargraph/language_server/message/text_document/definition.rb +3 -3
  39. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  40. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  41. data/lib/solargraph/language_server/message/text_document/hover.rb +3 -1
  42. data/lib/solargraph/language_server/message/text_document/type_definition.rb +3 -3
  43. data/lib/solargraph/language_server/message/text_document.rb +0 -1
  44. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +5 -0
  45. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  46. data/lib/solargraph/language_server/progress.rb +135 -0
  47. data/lib/solargraph/language_server/transport/adapter.rb +16 -1
  48. data/lib/solargraph/language_server/transport/data_reader.rb +2 -0
  49. data/lib/solargraph/language_server.rb +1 -0
  50. data/lib/solargraph/library.rb +207 -111
  51. data/lib/solargraph/location.rb +15 -1
  52. data/lib/solargraph/page.rb +6 -0
  53. data/lib/solargraph/parser/comment_ripper.rb +4 -0
  54. data/lib/solargraph/parser/node_methods.rb +47 -7
  55. data/lib/solargraph/parser/node_processor/base.rb +11 -1
  56. data/lib/solargraph/parser/node_processor.rb +1 -0
  57. data/lib/solargraph/parser/{legacy → parser_gem}/class_methods.rb +31 -9
  58. data/lib/solargraph/parser/{legacy → parser_gem}/flawed_builder.rb +3 -1
  59. data/lib/solargraph/parser/{legacy → parser_gem}/node_chainer.rb +62 -43
  60. data/lib/solargraph/parser/parser_gem/node_methods.rb +495 -0
  61. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/alias_node.rb +1 -1
  62. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +57 -0
  63. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/begin_node.rb +1 -1
  64. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/block_node.rb +3 -2
  65. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/casgn_node.rb +2 -2
  66. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/cvasgn_node.rb +1 -1
  67. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/def_node.rb +7 -20
  68. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/defs_node.rb +2 -2
  69. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/gvasgn_node.rb +1 -1
  70. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/ivasgn_node.rb +2 -2
  71. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/lvasgn_node.rb +4 -4
  72. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +53 -0
  73. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/namespace_node.rb +2 -2
  74. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/orasgn_node.rb +1 -1
  75. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/resbody_node.rb +3 -3
  76. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/sclass_node.rb +1 -1
  77. data/lib/solargraph/parser/{legacy → parser_gem}/node_processors/send_node.rb +8 -6
  78. data/lib/solargraph/parser/{rubyvm → parser_gem}/node_processors/sym_node.rb +1 -1
  79. data/lib/solargraph/parser/parser_gem/node_processors.rb +56 -0
  80. data/lib/solargraph/parser/parser_gem.rb +12 -0
  81. data/lib/solargraph/parser/region.rb +1 -1
  82. data/lib/solargraph/parser/snippet.rb +2 -0
  83. data/lib/solargraph/parser.rb +8 -12
  84. data/lib/solargraph/pin/base.rb +78 -10
  85. data/lib/solargraph/pin/base_variable.rb +40 -7
  86. data/lib/solargraph/pin/block.rb +69 -46
  87. data/lib/solargraph/pin/callable.rb +147 -0
  88. data/lib/solargraph/pin/closure.rb +23 -3
  89. data/lib/solargraph/pin/common.rb +6 -6
  90. data/lib/solargraph/pin/conversions.rb +36 -5
  91. data/lib/solargraph/pin/delegated_method.rb +6 -2
  92. data/lib/solargraph/pin/documenting.rb +25 -32
  93. data/lib/solargraph/pin/instance_variable.rb +6 -2
  94. data/lib/solargraph/pin/local_variable.rb +13 -1
  95. data/lib/solargraph/pin/method.rb +205 -32
  96. data/lib/solargraph/pin/namespace.rb +20 -7
  97. data/lib/solargraph/pin/parameter.rb +41 -36
  98. data/lib/solargraph/pin/proxy_type.rb +1 -1
  99. data/lib/solargraph/pin/reference/override.rb +2 -2
  100. data/lib/solargraph/pin/reference.rb +8 -0
  101. data/lib/solargraph/pin/search.rb +3 -3
  102. data/lib/solargraph/pin/signature.rb +8 -14
  103. data/lib/solargraph/pin.rb +4 -2
  104. data/lib/solargraph/range.rb +4 -6
  105. data/lib/solargraph/rbs_map/conversions.rb +326 -76
  106. data/lib/solargraph/rbs_map/core_fills.rb +16 -33
  107. data/lib/solargraph/rbs_map/core_map.rb +3 -13
  108. data/lib/solargraph/rbs_map/stdlib_map.rb +2 -8
  109. data/lib/solargraph/rbs_map.rb +32 -13
  110. data/lib/solargraph/shell.rb +95 -72
  111. data/lib/solargraph/source/chain/array.rb +33 -0
  112. data/lib/solargraph/source/chain/block_symbol.rb +13 -0
  113. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  114. data/lib/solargraph/source/chain/call.rb +152 -69
  115. data/lib/solargraph/source/chain/constant.rb +15 -1
  116. data/lib/solargraph/source/chain/if.rb +23 -0
  117. data/lib/solargraph/source/chain/link.rb +17 -2
  118. data/lib/solargraph/source/chain/or.rb +2 -2
  119. data/lib/solargraph/source/chain/z_super.rb +3 -3
  120. data/lib/solargraph/source/chain.rb +85 -26
  121. data/lib/solargraph/source/change.rb +3 -0
  122. data/lib/solargraph/source/cursor.rb +16 -2
  123. data/lib/solargraph/source/source_chainer.rb +8 -5
  124. data/lib/solargraph/source/updater.rb +1 -0
  125. data/lib/solargraph/source.rb +120 -148
  126. data/lib/solargraph/source_map/clip.rb +16 -27
  127. data/lib/solargraph/source_map/data.rb +30 -0
  128. data/lib/solargraph/source_map/mapper.rb +15 -3
  129. data/lib/solargraph/source_map.rb +48 -24
  130. data/lib/solargraph/type_checker/checks.rb +10 -2
  131. data/lib/solargraph/type_checker/rules.rb +6 -1
  132. data/lib/solargraph/type_checker.rb +150 -39
  133. data/lib/solargraph/version.rb +1 -1
  134. data/lib/solargraph/views/environment.erb +3 -5
  135. data/lib/solargraph/workspace/config.rb +9 -6
  136. data/lib/solargraph/workspace.rb +30 -3
  137. data/lib/solargraph/yard_map/cache.rb +6 -0
  138. data/lib/solargraph/yard_map/helpers.rb +1 -1
  139. data/lib/solargraph/yard_map/mapper/to_method.rb +16 -3
  140. data/lib/solargraph/yard_map/mapper.rb +1 -1
  141. data/lib/solargraph/yard_map/to_method.rb +11 -4
  142. data/lib/solargraph/yard_map.rb +1 -292
  143. data/lib/solargraph/yard_tags.rb +20 -0
  144. data/lib/solargraph/yardoc.rb +52 -0
  145. data/lib/solargraph.rb +6 -4
  146. data/solargraph.gemspec +7 -6
  147. metadata +71 -82
  148. data/lib/solargraph/api_map/bundler_methods.rb +0 -22
  149. data/lib/solargraph/documentor.rb +0 -76
  150. data/lib/solargraph/language_server/host/cataloger.rb +0 -56
  151. data/lib/solargraph/parser/legacy/node_methods.rb +0 -325
  152. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +0 -23
  153. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +0 -50
  154. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +0 -15
  155. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +0 -18
  156. data/lib/solargraph/parser/legacy/node_processors.rb +0 -55
  157. data/lib/solargraph/parser/legacy.rb +0 -12
  158. data/lib/solargraph/parser/rubyvm/class_methods.rb +0 -153
  159. data/lib/solargraph/parser/rubyvm/node_chainer.rb +0 -160
  160. data/lib/solargraph/parser/rubyvm/node_methods.rb +0 -317
  161. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +0 -85
  162. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +0 -42
  163. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +0 -33
  164. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +0 -23
  165. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +0 -75
  166. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +0 -68
  167. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +0 -23
  168. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +0 -38
  169. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +0 -39
  170. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +0 -20
  171. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +0 -27
  172. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +0 -39
  173. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +0 -26
  174. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +0 -15
  175. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +0 -51
  176. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +0 -32
  177. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +0 -15
  178. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +0 -279
  179. data/lib/solargraph/parser/rubyvm/node_processors.rb +0 -64
  180. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +0 -47
  181. data/lib/solargraph/parser/rubyvm.rb +0 -40
  182. data/lib/solargraph/rbs_map/core_signs.rb +0 -33
  183. data/lib/yard-solargraph.rb +0 -33
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+
5
+ module Solargraph
6
+ # A utility for building gem pins from a combination of YARD and RBS
7
+ # documentation.
8
+ #
9
+ module GemPins
10
+ # Build an array of pins from a gem specification. The process starts with
11
+ # YARD, enhances the resulting pins with RBS definitions, and appends RBS
12
+ # pins that don't exist in the YARD mapping.
13
+ #
14
+ # @param gemspec [Gem::Specification]
15
+ # @return [Array<Pin::Base>]
16
+ def self.build(gemspec)
17
+ yard_pins = build_yard_pins(gemspec)
18
+ rbs_map = RbsMap.from_gemspec(gemspec)
19
+ combine yard_pins, rbs_map
20
+ end
21
+
22
+ # @param yard_pins [Array<Pin::Base>]
23
+ # @param rbs_map [RbsMap]
24
+ # @return [Array<Pin::Base>]
25
+ def self.combine(yard_pins, rbs_map)
26
+ in_yard = Set.new
27
+ combined = yard_pins.map do |yard|
28
+ in_yard.add yard.path
29
+ next yard unless yard.is_a?(Pin::Method)
30
+
31
+ rbs = rbs_map.path_pin(yard.path, Pin::Method)
32
+ next yard unless rbs
33
+
34
+ # @sg-ignore
35
+ yard.class.new(
36
+ location: yard.location,
37
+ closure: yard.closure,
38
+ name: yard.name,
39
+ comments: yard.comments,
40
+ scope: yard.scope,
41
+ parameters: rbs.parameters,
42
+ generics: rbs.generics,
43
+ node: yard.node,
44
+ signatures: yard.signatures,
45
+ return_type: best_return_type(rbs.return_type, yard.return_type)
46
+ )
47
+ end
48
+ in_rbs = rbs_map.pins.reject { |pin| in_yard.include?(pin.path) }
49
+ combined + in_rbs
50
+ end
51
+
52
+ class << self
53
+ private
54
+
55
+ # @param gemspec [Gem::Specification]
56
+ # @return [Array<Pin::Base>]
57
+ def build_yard_pins(gemspec)
58
+ Yardoc.cache(gemspec) unless Yardoc.cached?(gemspec)
59
+ yardoc = Yardoc.load!(gemspec)
60
+ YardMap::Mapper.new(yardoc, gemspec).map
61
+ end
62
+
63
+ # Select the first defined type.
64
+ #
65
+ # @param choices [Array<ComplexType>]
66
+ # @return [ComplexType]
67
+ def best_return_type *choices
68
+ choices.find { |pin| pin.defined? } || choices.first || ComplexType::UNDEFINED
69
+ end
70
+ end
71
+ end
72
+ end
@@ -38,7 +38,7 @@ module Solargraph
38
38
 
39
39
  # Start the diagnosis thread.
40
40
  #
41
- # @return [self]
41
+ # @return [self, nil]
42
42
  def start
43
43
  return unless @stopped
44
44
  @stopped = false
@@ -81,7 +81,7 @@ module Solargraph
81
81
  # @return [Mutex]
82
82
  attr_reader :mutex
83
83
 
84
- # @return [Array]
84
+ # @return [::Array]
85
85
  attr_reader :queue
86
86
  end
87
87
  end
@@ -6,6 +6,12 @@ module Solargraph
6
6
  # Methods for associating sources with libraries via URIs.
7
7
  #
8
8
  module Dispatch
9
+ # @abstract
10
+ # @return [Host::Diagnoser]
11
+ def diagnoser
12
+ raise NotImplementedError, 'Host::Dispatch requires a diagnoser method'
13
+ end
14
+
9
15
  # @return [Sources]
10
16
  def sources
11
17
  @sources ||= begin
@@ -15,7 +21,7 @@ module Solargraph
15
21
  end
16
22
  end
17
23
 
18
- # @return [Array<Library>]
24
+ # @return [::Array<Library>]
19
25
  def libraries
20
26
  @libraries ||= []
21
27
  end
@@ -27,9 +33,9 @@ module Solargraph
27
33
  # @return [void]
28
34
  def update_libraries uri
29
35
  src = sources.find(uri)
30
- libraries.each do |lib|
31
- lib.merge src if lib.contain?(src.filename)
32
- end
36
+ using = libraries.select { |lib| lib.contain?(src.filename) }
37
+ using.push library_for(uri) if using.empty?
38
+ using.each { |lib| lib.merge src }
33
39
  diagnoser.schedule uri
34
40
  end
35
41
 
@@ -89,6 +95,10 @@ module Solargraph
89
95
  nil
90
96
  end
91
97
 
98
+ def options
99
+ @options ||= {}.freeze
100
+ end
101
+
92
102
  # Get a generic library for the given URI and attach the corresponding
93
103
  # source.
94
104
  #
@@ -103,7 +113,14 @@ module Solargraph
103
113
 
104
114
  # @return [Library]
105
115
  def generic_library
106
- @generic_library ||= Solargraph::Library.new
116
+ @generic_library ||= Solargraph::Library.new(Solargraph::Workspace.new('', nil, options), nil)
117
+ .tap { |lib| lib.add_observer self }
118
+ end
119
+
120
+ # @param library [Solargraph::Library]
121
+ # @return [void]
122
+ def update progress
123
+ progress&.send(self)
107
124
  end
108
125
  end
109
126
  end
@@ -3,10 +3,15 @@
3
3
  module Solargraph
4
4
  module LanguageServer
5
5
  class Host
6
- # A serial worker Thread to handle message.
6
+ # A serial worker Thread to handle incoming messages.
7
7
  #
8
- # this make check pending message possible, and maybe cancelled to speedup process
9
8
  class MessageWorker
9
+ UPDATE_METHODS = [
10
+ 'textDocument/didOpen',
11
+ 'textDocument/didChange',
12
+ 'workspace/didChangeWatchedFiles'
13
+ ].freeze
14
+
10
15
  # @param host [Host]
11
16
  def initialize(host)
12
17
  @host = host
@@ -16,6 +21,7 @@ module Solargraph
16
21
  end
17
22
 
18
23
  # pending handle messages
24
+ # @return [Array<Hash>]
19
25
  def messages
20
26
  @messages ||= []
21
27
  end
@@ -24,11 +30,12 @@ module Solargraph
24
30
  @stopped
25
31
  end
26
32
 
33
+ # @return [void]
27
34
  def stop
28
35
  @stopped = true
29
36
  end
30
37
 
31
- # @param message [Hash] The message should be handle. will pass back to Host#receive
38
+ # @param message [Hash] The message to handle. Will be forwarded to Host#receive
32
39
  # @return [void]
33
40
  def queue(message)
34
41
  @mutex.synchronize do
@@ -37,6 +44,7 @@ module Solargraph
37
44
  end
38
45
  end
39
46
 
47
+ # @return [void]
40
48
  def start
41
49
  return unless @stopped
42
50
  @stopped = false
@@ -45,13 +53,49 @@ module Solargraph
45
53
  end
46
54
  end
47
55
 
56
+ # @return [void]
48
57
  def tick
49
58
  message = @mutex.synchronize do
50
59
  @resource.wait(@mutex) if messages.empty?
51
- messages.shift
60
+ next_message
52
61
  end
53
62
  handler = @host.receive(message)
54
- handler && handler.send_response
63
+ handler&.send_response
64
+ end
65
+
66
+ private
67
+
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
83
+ # Prioritize updates and version-dependent messages for performance
84
+ idx = messages.find_index do |msg|
85
+ UPDATE_METHODS.include?(msg['method']) || version_dependent?(msg)
86
+ end
87
+ return messages.shift unless idx
88
+
89
+ msg = messages[idx]
90
+ messages.delete_at idx
91
+ msg
92
+ end
93
+
94
+ # True if the message requires a previous update to have executed in
95
+ # order to work correctly.
96
+ #
97
+ def version_dependent? msg
98
+ msg['textDocument'] && msg['position']
55
99
  end
56
100
  end
57
101
  end
@@ -11,53 +11,10 @@ module Solargraph
11
11
  include Observable
12
12
  include UriHelpers
13
13
 
14
- def initialize
15
- @mutex = Mutex.new
16
- @stopped = true
17
- @has_uri = ConditionVariable.new
18
- end
19
-
20
- def stopped?
21
- @stopped
22
- end
23
-
24
- # @return [void]
25
- def start
26
- return unless @stopped
27
- @stopped = false
28
- Thread.new do
29
- tick until stopped?
30
- end
31
- end
32
-
33
- # @return [void]
34
- def tick
35
- uri = mutex.synchronize { next_uri }
36
-
37
- return if queue.include?(uri)
38
- mutex.synchronize do
39
- nxt = open_source_hash[uri].finish_synchronize
40
- open_source_hash[uri] = nxt
41
- changed
42
- notify_observers uri
43
- end
44
- end
45
-
14
+ # @param uri [String]
46
15
  # @return [void]
47
16
  def add_uri(uri)
48
17
  queue.push(uri)
49
- @has_uri.signal
50
- end
51
-
52
- # @return [String]
53
- def next_uri
54
- @has_uri.wait(mutex) if queue.empty?
55
- queue.shift
56
- end
57
-
58
- # @return [void]
59
- def stop
60
- @stopped = true
61
18
  end
62
19
 
63
20
  # Open a source.
@@ -72,6 +29,8 @@ module Solargraph
72
29
  open_source_hash[uri] = source
73
30
  end
74
31
 
32
+ # @param uri [String]
33
+ # @return [void]
75
34
  def open_from_disk uri
76
35
  source = Solargraph::Source.load(UriHelpers.uri_to_file(uri))
77
36
  open_source_hash[uri] = source
@@ -81,25 +40,12 @@ module Solargraph
81
40
  #
82
41
  # @raise [FileNotFoundError] if the URI does not match an open source.
83
42
  #
84
- # @param uri [String]
85
- # @param updater [Source::Updater]
86
- # @return [Source]
87
- def update uri, updater
88
- src = find(uri)
89
- mutex.synchronize { open_source_hash[uri] = src.synchronize(updater) }
90
- changed
91
- notify_observers uri
92
- end
93
-
94
43
  # @param uri [String]
95
44
  # @param updater [Source::Updater]
96
45
  # @return [void]
97
- def async_update uri, updater
46
+ def update uri, updater
98
47
  src = find(uri)
99
- mutex.synchronize do
100
- open_source_hash[uri] = src.start_synchronize(updater)
101
- add_uri(uri)
102
- end
48
+ open_source_hash[uri] = src.synchronize(updater)
103
49
  changed
104
50
  notify_observers uri
105
51
  end
@@ -109,7 +55,7 @@ module Solargraph
109
55
  # @raise [FileNotFoundError] if the URI does not match an open source.
110
56
  #
111
57
  # @param uri [String]
112
- # @return [Source]
58
+ # @return [Solargraph::Source]
113
59
  def find uri
114
60
  open_source_hash[uri] || raise(Solargraph::FileNotFoundError, "Host could not find #{uri}")
115
61
  end
@@ -136,17 +82,14 @@ module Solargraph
136
82
 
137
83
  private
138
84
 
139
- # @return [Hash]
85
+ # @return [Hash{String => Solargraph::Source}]
140
86
  def open_source_hash
141
87
  @open_source_hash ||= {}
142
88
  end
143
89
 
144
- # @return [Mutex]
145
- attr_reader :mutex
146
-
147
90
  # An array of source URIs that are waiting to finish synchronizing.
148
91
  #
149
- # @return [Array<String>]
92
+ # @return [::Array<String>]
150
93
  def queue
151
94
  @queue ||= []
152
95
  end
@@ -3,7 +3,6 @@
3
3
  require 'diff/lcs'
4
4
  require 'observer'
5
5
  require 'securerandom'
6
- require 'set'
7
6
 
8
7
  module Solargraph
9
8
  module LanguageServer
@@ -13,7 +12,6 @@ module Solargraph
13
12
  #
14
13
  class Host
15
14
  autoload :Diagnoser, 'solargraph/language_server/host/diagnoser'
16
- autoload :Cataloger, 'solargraph/language_server/host/cataloger'
17
15
  autoload :Sources, 'solargraph/language_server/host/sources'
18
16
  autoload :Dispatch, 'solargraph/language_server/host/dispatch'
19
17
  autoload :MessageWorker, 'solargraph/language_server/host/message_worker'
@@ -26,10 +24,8 @@ module Solargraph
26
24
  attr_writer :client_capabilities
27
25
 
28
26
  def initialize
29
- @cancel_semaphore = Mutex.new
30
27
  @buffer_semaphore = Mutex.new
31
28
  @request_mutex = Mutex.new
32
- @cancel = []
33
29
  @buffer = String.new
34
30
  @stopped = true
35
31
  @next_request_id = 1
@@ -44,8 +40,6 @@ module Solargraph
44
40
  return unless stopped?
45
41
  @stopped = false
46
42
  diagnoser.start
47
- cataloger.start
48
- sources.start
49
43
  message_worker.start
50
44
  end
51
45
 
@@ -59,7 +53,7 @@ module Solargraph
59
53
  logger.level = LOG_LEVELS[options['logLevel']] || DEFAULT_LOG_LEVEL
60
54
  end
61
55
 
62
- # @return [Hash]
56
+ # @return [Hash{String => [Boolean, String]}]
63
57
  def options
64
58
  @options ||= default_configuration
65
59
  end
@@ -69,7 +63,7 @@ module Solargraph
69
63
  # @param id [Integer]
70
64
  # @return [void]
71
65
  def cancel id
72
- @cancel_semaphore.synchronize { @cancel.push id }
66
+ cancelled.push id
73
67
  end
74
68
 
75
69
  # True if the host received a request to cancel the method with the
@@ -78,9 +72,7 @@ module Solargraph
78
72
  # @param id [Integer]
79
73
  # @return [Boolean]
80
74
  def cancel? id
81
- result = false
82
- @cancel_semaphore.synchronize { result = @cancel.include? id }
83
- result
75
+ cancelled.include? id
84
76
  end
85
77
 
86
78
  # Delete the specified ID from the list of cancelled IDs if it exists.
@@ -88,7 +80,7 @@ module Solargraph
88
80
  # @param id [Integer]
89
81
  # @return [void]
90
82
  def clear id
91
- @cancel_semaphore.synchronize { @cancel.delete id }
83
+ cancelled.delete id
92
84
  end
93
85
 
94
86
  # Called by adapter, to handle the request
@@ -101,15 +93,15 @@ module Solargraph
101
93
  # Start processing a request from the client. After the message is
102
94
  # processed, caller is responsible for sending the response.
103
95
  #
104
- # @param request [Hash] The contents of the message.
105
- # @return [Solargraph::LanguageServer::Message::Base] The message handler.
96
+ # @param request [Hash{String => unspecified}] The contents of the message.
97
+ # @return [Solargraph::LanguageServer::Message::Base, nil] The message handler.
106
98
  def receive request
107
99
  if request['method']
108
- logger.info "Server received #{request['method']}"
100
+ logger.info "Host received ##{request['id']} #{request['method']}"
109
101
  logger.debug request
110
102
  message = Message.select(request['method']).new(self, request)
111
103
  begin
112
- message.process
104
+ message.process unless cancel?(request['id'])
113
105
  rescue StandardError => e
114
106
  logger.warn "Error processing request: [#{e.class}] #{e.message}"
115
107
  logger.warn e.backtrace.join("\n")
@@ -127,6 +119,7 @@ module Solargraph
127
119
  else
128
120
  logger.warn "Invalid message received."
129
121
  logger.debug request
122
+ nil
130
123
  end
131
124
  end
132
125
 
@@ -155,6 +148,7 @@ module Solargraph
155
148
  def delete *uris
156
149
  filenames = uris.map { |uri| uri_to_file(uri) }
157
150
  libraries.each do |lib|
151
+ lib.delete_observer self
158
152
  lib.delete(*filenames)
159
153
  end
160
154
  uris.each do |uri|
@@ -253,7 +247,7 @@ module Solargraph
253
247
  # @return [void]
254
248
  def change params
255
249
  updater = generate_updater(params)
256
- sources.async_update params['textDocument']['uri'], updater
250
+ sources.update params['textDocument']['uri'], updater
257
251
  diagnoser.schedule params['textDocument']['uri']
258
252
  end
259
253
 
@@ -292,9 +286,11 @@ module Solargraph
292
286
  path = ''
293
287
  path = normalize_separators(directory) unless directory.nil?
294
288
  begin
295
- lib = Solargraph::Library.load(path, name)
289
+ workspace = Solargraph::Workspace.new(path, nil, options)
290
+ lib = Solargraph::Library.new(workspace, name)
291
+ lib.add_observer self
296
292
  libraries.push lib
297
- async_library_map lib
293
+ library_map lib
298
294
  rescue WorkspaceTooLargeError => e
299
295
  send_notification 'window/showMessage', {
300
296
  'type' => Solargraph::LanguageServer::MessageTypes::WARNING,
@@ -323,6 +319,7 @@ module Solargraph
323
319
  # @param lib [Library]
324
320
  libraries.delete_if do |lib|
325
321
  next false if lib.workspace.directory != directory
322
+ lib.delete_observer self
326
323
  true
327
324
  end
328
325
  end
@@ -380,7 +377,6 @@ module Solargraph
380
377
  envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
381
378
  queue envelope
382
379
  @next_request_id += 1
383
- logger.info "Server sent #{method}"
384
380
  logger.debug params
385
381
  end
386
382
  end
@@ -457,9 +453,7 @@ module Solargraph
457
453
  return if @stopped
458
454
  @stopped = true
459
455
  message_worker.stop
460
- cataloger.stop
461
456
  diagnoser.stop
462
- sources.stop
463
457
  changed
464
458
  notify_observers
465
459
  end
@@ -492,6 +486,24 @@ module Solargraph
492
486
  end
493
487
  if params['data']['path']
494
488
  result.concat library.path_pins(params['data']['path'])
489
+ # @todo This exception is necessary because `Library#path_pins` does
490
+ # not perform a namespace method query, so the implicit `.new` pin
491
+ # might not exist.
492
+ if result.empty? && params['data']['path'] =~ /\.new$/
493
+ result.concat(library.path_pins(params['data']['path'].sub(/\.new$/, '#initialize')).map do |pin|
494
+ next pin unless pin.name == 'initialize'
495
+
496
+ Pin::Method.new(
497
+ name: 'new',
498
+ scope: :class,
499
+ location: pin.location,
500
+ parameters: pin.parameters,
501
+ return_type: ComplexType.try_parse(params['data']['path']),
502
+ comments: pin.comments,
503
+ closure: pin.closure
504
+ )
505
+ end)
506
+ end
495
507
  end
496
508
  # Selecting by both location and path can result in duplicate pins
497
509
  result.uniq { |p| [p.path, p.location] }
@@ -505,6 +517,8 @@ module Solargraph
505
517
  library.read_text(filename)
506
518
  end
507
519
 
520
+ # @param uri [String]
521
+ # @return [Hash]
508
522
  def formatter_config uri
509
523
  library = library_for(uri)
510
524
  library.workspace.config.formatter
@@ -632,7 +646,7 @@ module Solargraph
632
646
  requests.keys
633
647
  end
634
648
 
635
- # @return [Hash{String => Object}]
649
+ # @return [Hash{String => [Boolean,String]}]
636
650
  def default_configuration
637
651
  {
638
652
  'completion' => true,
@@ -663,12 +677,22 @@ module Solargraph
663
677
  libraries.each(&:catalog)
664
678
  end
665
679
 
680
+ # @return [Hash{String => Hash{String => Boolean}}]
666
681
  def client_capabilities
667
682
  @client_capabilities ||= {}
668
683
  end
669
684
 
685
+ def client_supports_progress?
686
+ client_capabilities['window'] && client_capabilities['window']['workDoneProgress']
687
+ end
688
+
670
689
  private
671
690
 
691
+ # @return [Array<Integer>]
692
+ def cancelled
693
+ @cancelled ||= []
694
+ end
695
+
672
696
  # @return [MessageWorker]
673
697
  def message_worker
674
698
  @message_worker ||= MessageWorker.new(self)
@@ -679,15 +703,10 @@ module Solargraph
679
703
  @diagnoser ||= Diagnoser.new(self)
680
704
  end
681
705
 
682
- # @return [Cataloger]
683
- def cataloger
684
- @cataloger ||= Cataloger.new(self)
685
- end
686
-
687
706
  # A hash of client requests by ID. The host uses this to keep track of
688
707
  # pending responses.
689
708
  #
690
- # @return [Hash{Integer => Hash}]
709
+ # @return [Hash{Integer => Solargraph::LanguageServer::Host}]
691
710
  def requests
692
711
  @requests ||= {}
693
712
  end
@@ -779,6 +798,9 @@ module Solargraph
779
798
  'textDocument/definition' => {
780
799
  definitionProvider: true
781
800
  },
801
+ 'textDocument/typeDefinition' => {
802
+ typeDefinitionProvider: true
803
+ },
782
804
  'textDocument/references' => {
783
805
  referencesProvider: true
784
806
  },
@@ -810,69 +832,28 @@ module Solargraph
810
832
  client_capabilities['rename'] && client_capabilities['rename']['prepareSupport']
811
833
  end
812
834
 
813
- def client_supports_progress?
814
- client_capabilities['window'] && client_capabilities['window']['workDoneProgress']
815
- end
816
-
817
835
  # @param library [Library]
818
836
  # @return [void]
819
- def async_library_map library
837
+ def library_map library
820
838
  return if library.mapped?
821
- Thread.new do
822
- if client_supports_progress?
823
- uuid = SecureRandom.uuid
824
- send_request 'window/workDoneProgress/create', {
825
- token: uuid
826
- } do |response|
827
- do_async_library_map library, response.nil? ? uuid : nil
828
- end
829
- else
830
- do_async_library_map library
831
- end
832
- end
839
+ Thread.new { sync_library_map library }
833
840
  end
834
841
 
835
- def do_async_library_map library, uuid = nil
842
+ # @param library [Library]
843
+ # @param uuid [String, nil]
844
+ # @return [void]
845
+ def sync_library_map library
836
846
  total = library.workspace.sources.length
837
- if uuid
838
- send_notification '$/progress', {
839
- token: uuid,
840
- value: {
841
- kind: 'begin',
842
- title: "Mapping workspace",
843
- message: "0/#{total} files",
844
- cancellable: false,
845
- percentage: 0
846
- }
847
- }
848
- end
849
- pct = 0
850
- mod = 10
847
+ progress = Progress.new('Mapping workspace')
848
+ progress.begin "0/#{total} files", 0
849
+ progress.send self
851
850
  while library.next_map
852
- next unless uuid
853
- cur = ((library.source_map_hash.keys.length.to_f / total.to_f) * 100).to_i
854
- if cur > pct && cur % mod == 0
855
- pct = cur
856
- send_notification '$/progress', {
857
- token: uuid,
858
- value: {
859
- kind: 'report',
860
- cancellable: false,
861
- message: "#{library.source_map_hash.keys.length}/#{total} files",
862
- percentage: pct
863
- }
864
- }
865
- end
866
- end
867
- if uuid
868
- send_notification '$/progress', {
869
- token: uuid,
870
- value: {
871
- kind: 'end',
872
- message: 'Mapping complete'
873
- }
874
- }
851
+ pct = ((library.source_map_hash.keys.length.to_f / total) * 100).to_i
852
+ progress.report "#{library.source_map_hash.keys.length}/#{total} files", pct
853
+ progress.send self
875
854
  end
855
+ progress.finish 'done'
856
+ progress.send self
876
857
  end
877
858
  end
878
859
  end