solargraph 0.54.0 → 0.58.0

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +127 -0
  3. data/.github/workflows/plugins.yml +184 -6
  4. data/.github/workflows/rspec.yml +55 -5
  5. data/.github/workflows/typecheck.yml +8 -3
  6. data/.gitignore +7 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +1279 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +171 -0
  13. data/README.md +20 -6
  14. data/Rakefile +125 -13
  15. data/bin/solargraph +8 -5
  16. data/lib/solargraph/api_map/cache.rb +13 -3
  17. data/lib/solargraph/api_map/constants.rb +279 -0
  18. data/lib/solargraph/api_map/index.rb +193 -0
  19. data/lib/solargraph/api_map/source_to_yard.rb +13 -4
  20. data/lib/solargraph/api_map/store.rb +207 -132
  21. data/lib/solargraph/api_map.rb +394 -261
  22. data/lib/solargraph/bench.rb +18 -1
  23. data/lib/solargraph/complex_type/type_methods.rb +29 -12
  24. data/lib/solargraph/complex_type/unique_type.rb +205 -26
  25. data/lib/solargraph/complex_type.rb +126 -26
  26. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  27. data/lib/solargraph/convention/base.rb +20 -3
  28. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  29. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  30. data/lib/solargraph/convention/data_definition.rb +105 -0
  31. data/lib/solargraph/convention/gemspec.rb +3 -2
  32. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
  33. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  34. data/lib/solargraph/convention/struct_definition.rb +164 -0
  35. data/lib/solargraph/convention.rb +36 -4
  36. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  37. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  38. data/lib/solargraph/doc_map.rb +316 -64
  39. data/lib/solargraph/environ.rb +9 -2
  40. data/lib/solargraph/equality.rb +34 -0
  41. data/lib/solargraph/gem_pins.rb +64 -38
  42. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  43. data/lib/solargraph/language_server/host/message_worker.rb +54 -5
  44. data/lib/solargraph/language_server/host.rb +36 -18
  45. data/lib/solargraph/language_server/message/base.rb +20 -12
  46. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  47. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  48. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  49. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  50. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  51. data/lib/solargraph/language_server/message/text_document/definition.rb +5 -3
  52. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  53. data/lib/solargraph/language_server/message/text_document/formatting.rb +23 -2
  54. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  55. data/lib/solargraph/language_server/message/text_document/type_definition.rb +4 -3
  56. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  57. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  58. data/lib/solargraph/language_server/progress.rb +27 -2
  59. data/lib/solargraph/language_server/request.rb +4 -1
  60. data/lib/solargraph/library.rb +83 -73
  61. data/lib/solargraph/location.rb +45 -1
  62. data/lib/solargraph/logging.rb +12 -2
  63. data/lib/solargraph/page.rb +3 -0
  64. data/lib/solargraph/parser/comment_ripper.rb +20 -7
  65. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  66. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  67. data/lib/solargraph/parser/node_processor.rb +26 -8
  68. data/lib/solargraph/parser/parser_gem/class_methods.rb +10 -18
  69. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  70. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
  71. data/lib/solargraph/parser/parser_gem/node_methods.rb +10 -19
  72. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  73. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -0
  74. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +26 -20
  75. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
  76. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  77. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  78. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  79. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  80. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  81. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  82. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  83. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  84. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +14 -2
  85. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  86. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -0
  87. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  88. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  89. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +16 -6
  90. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +64 -32
  91. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  92. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  93. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  94. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  95. data/lib/solargraph/parser/region.rb +4 -1
  96. data/lib/solargraph/parser/snippet.rb +2 -0
  97. data/lib/solargraph/parser.rb +3 -5
  98. data/lib/solargraph/pin/base.rb +417 -42
  99. data/lib/solargraph/pin/base_variable.rb +21 -12
  100. data/lib/solargraph/pin/block.rb +9 -26
  101. data/lib/solargraph/pin/breakable.rb +9 -0
  102. data/lib/solargraph/pin/callable.rb +231 -0
  103. data/lib/solargraph/pin/closure.rb +30 -10
  104. data/lib/solargraph/pin/common.rb +12 -7
  105. data/lib/solargraph/pin/constant.rb +2 -0
  106. data/lib/solargraph/pin/conversions.rb +3 -2
  107. data/lib/solargraph/pin/delegated_method.rb +20 -1
  108. data/lib/solargraph/pin/documenting.rb +16 -0
  109. data/lib/solargraph/pin/instance_variable.rb +2 -2
  110. data/lib/solargraph/pin/keyword.rb +7 -2
  111. data/lib/solargraph/pin/local_variable.rb +15 -7
  112. data/lib/solargraph/pin/method.rb +241 -70
  113. data/lib/solargraph/pin/method_alias.rb +3 -0
  114. data/lib/solargraph/pin/namespace.rb +21 -13
  115. data/lib/solargraph/pin/parameter.rb +94 -32
  116. data/lib/solargraph/pin/proxy_type.rb +17 -7
  117. data/lib/solargraph/pin/reference/override.rb +24 -6
  118. data/lib/solargraph/pin/reference/require.rb +2 -2
  119. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  120. data/lib/solargraph/pin/reference.rb +17 -0
  121. data/lib/solargraph/pin/search.rb +6 -1
  122. data/lib/solargraph/pin/signature.rb +39 -121
  123. data/lib/solargraph/pin/singleton.rb +1 -1
  124. data/lib/solargraph/pin/symbol.rb +8 -2
  125. data/lib/solargraph/pin/until.rb +18 -0
  126. data/lib/solargraph/pin/while.rb +18 -0
  127. data/lib/solargraph/pin.rb +8 -2
  128. data/lib/solargraph/pin_cache.rb +245 -0
  129. data/lib/solargraph/position.rb +19 -0
  130. data/lib/solargraph/range.rb +23 -4
  131. data/lib/solargraph/rbs_map/conversions.rb +315 -99
  132. data/lib/solargraph/rbs_map/core_fills.rb +50 -16
  133. data/lib/solargraph/rbs_map/core_map.rb +41 -11
  134. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  135. data/lib/solargraph/rbs_map.rb +87 -16
  136. data/lib/solargraph/shell.rb +117 -17
  137. data/lib/solargraph/source/chain/array.rb +13 -8
  138. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  139. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  140. data/lib/solargraph/source/chain/call.rb +135 -66
  141. data/lib/solargraph/source/chain/constant.rb +3 -66
  142. data/lib/solargraph/source/chain/hash.rb +9 -3
  143. data/lib/solargraph/source/chain/head.rb +1 -1
  144. data/lib/solargraph/source/chain/if.rb +7 -2
  145. data/lib/solargraph/source/chain/link.rb +38 -6
  146. data/lib/solargraph/source/chain/literal.rb +27 -2
  147. data/lib/solargraph/source/chain/or.rb +2 -2
  148. data/lib/solargraph/source/chain/z_super.rb +1 -1
  149. data/lib/solargraph/source/chain.rb +140 -63
  150. data/lib/solargraph/source/change.rb +2 -2
  151. data/lib/solargraph/source/cursor.rb +4 -4
  152. data/lib/solargraph/source/source_chainer.rb +3 -3
  153. data/lib/solargraph/source.rb +110 -89
  154. data/lib/solargraph/source_map/clip.rb +22 -28
  155. data/lib/solargraph/source_map/data.rb +34 -0
  156. data/lib/solargraph/source_map/mapper.rb +11 -7
  157. data/lib/solargraph/source_map.rb +50 -43
  158. data/lib/solargraph/type_checker/checks.rb +4 -0
  159. data/lib/solargraph/type_checker/param_def.rb +2 -0
  160. data/lib/solargraph/type_checker/rules.rb +35 -8
  161. data/lib/solargraph/type_checker.rb +331 -189
  162. data/lib/solargraph/version.rb +1 -1
  163. data/lib/solargraph/views/_method.erb +10 -10
  164. data/lib/solargraph/views/_namespace.erb +3 -3
  165. data/lib/solargraph/views/document.erb +10 -10
  166. data/lib/solargraph/views/environment.erb +3 -5
  167. data/lib/solargraph/workspace/config.rb +25 -5
  168. data/lib/solargraph/workspace/require_paths.rb +97 -0
  169. data/lib/solargraph/workspace.rb +53 -72
  170. data/lib/solargraph/yard_map/helpers.rb +29 -1
  171. data/lib/solargraph/yard_map/mapper/to_constant.rb +8 -5
  172. data/lib/solargraph/yard_map/mapper/to_method.rb +55 -19
  173. data/lib/solargraph/yard_map/mapper/to_namespace.rb +11 -7
  174. data/lib/solargraph/yard_map/mapper.rb +5 -3
  175. data/lib/solargraph/yard_map/to_method.rb +6 -3
  176. data/lib/solargraph/yardoc.rb +45 -10
  177. data/lib/solargraph.rb +35 -1
  178. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  179. data/rbs/fills/open3/0/open3.rbs +172 -0
  180. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  181. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  182. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  183. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  184. data/rbs/fills/tuple/tuple.rbs +149 -0
  185. data/rbs_collection.yaml +19 -0
  186. data/sig/shims/ast/0/node.rbs +5 -0
  187. data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
  188. data/sig/shims/ast/2.4/ast.rbs +73 -0
  189. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  190. data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
  191. data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
  192. data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  193. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  194. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  195. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  196. data/solargraph.gemspec +32 -10
  197. metadata +237 -37
  198. data/lib/.rubocop.yml +0 -22
  199. data/lib/solargraph/cache.rb +0 -77
  200. data/lib/solargraph/parser/node_methods.rb +0 -83
@@ -95,6 +95,7 @@ module Solargraph
95
95
  nil
96
96
  end
97
97
 
98
+ # @return [Hash{String => undefined}]
98
99
  def options
99
100
  @options ||= {}.freeze
100
101
  end
@@ -118,6 +119,7 @@ module Solargraph
118
119
  end
119
120
 
120
121
  # @param library [Solargraph::Library]
122
+ # @param progress [Solargraph::LanguageServer::Progress, nil]
121
123
  # @return [void]
122
124
  def update progress
123
125
  progress&.send(self)
@@ -3,10 +3,22 @@
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/didChange',
11
+ 'textDocument/didClose',
12
+ 'textDocument/didOpen',
13
+ 'textDocument/didSave',
14
+ 'workspace/didChangeConfiguration',
15
+ 'workspace/didChangeWatchedFiles',
16
+ 'workspace/didCreateFiles',
17
+ 'workspace/didChangeWorkspaceFolders',
18
+ 'workspace/didDeleteFiles',
19
+ 'workspace/didRenameFiles'
20
+ ].freeze
21
+
10
22
  # @param host [Host]
11
23
  def initialize(host)
12
24
  @host = host
@@ -30,7 +42,7 @@ module Solargraph
30
42
  @stopped = true
31
43
  end
32
44
 
33
- # @param message [Hash] The message should be handle. will pass back to Host#receive
45
+ # @param message [Hash] The message to handle. Will be forwarded to Host#receive
34
46
  # @return [void]
35
47
  def queue(message)
36
48
  @mutex.synchronize do
@@ -52,10 +64,47 @@ module Solargraph
52
64
  def tick
53
65
  message = @mutex.synchronize do
54
66
  @resource.wait(@mutex) if messages.empty?
55
- messages.shift
67
+ next_message
56
68
  end
57
69
  handler = @host.receive(message)
58
- handler && handler.send_response
70
+ handler&.send_response
71
+ end
72
+
73
+ private
74
+
75
+ # @return [Hash, nil]
76
+ def next_message
77
+ cancel_message || next_priority
78
+ end
79
+
80
+ # @return [Hash, nil]
81
+ def cancel_message
82
+ # Handle cancellations first
83
+ idx = messages.find_index { |msg| msg['method'] == '$/cancelRequest' }
84
+ return unless idx
85
+
86
+ msg = messages[idx]
87
+ messages.delete_at idx
88
+ msg
89
+ end
90
+
91
+ # @return [Hash, nil]
92
+ def next_priority
93
+ # Prioritize updates and version-dependent messages for performance
94
+ idx = messages.find_index do |msg|
95
+ UPDATE_METHODS.include?(msg['method']) || version_dependent?(msg)
96
+ end
97
+ idx ? messages.delete_at(idx) : messages.shift
98
+ end
99
+
100
+ # True if the message requires a previous update to have executed in
101
+ # order to work correctly.
102
+ #
103
+ # @param msg [Hash{String => Object}]
104
+ # @todo need boolish type from RBS
105
+ # @return [Object]
106
+ def version_dependent? msg
107
+ msg['textDocument'] && msg['position']
59
108
  end
60
109
  end
61
110
  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
- @cancel_semaphore.synchronize { @cancel.push id }
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
- result = false
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
- @cancel_semaphore.synchronize { @cancel.delete id }
83
+ cancelled.delete id
88
84
  end
89
85
 
90
86
  # Called by adapter, to handle the request
@@ -98,14 +94,15 @@ module Solargraph
98
94
  # processed, caller is responsible for sending the response.
99
95
  #
100
96
  # @param request [Hash{String => unspecified}] The contents of the message.
101
- # @return [Solargraph::LanguageServer::Message::Base, nil] The message handler.
97
+ #
98
+ # @return [Solargraph::LanguageServer::Message::Base, Solargraph::LanguageServer::Request, nil] The message handler.
102
99
  def receive request
103
100
  if request['method']
104
- logger.info "Server received #{request['method']}"
101
+ logger.info "Host received ##{request['id']} #{request['method']}"
105
102
  logger.debug request
106
103
  message = Message.select(request['method']).new(self, request)
107
104
  begin
108
- message.process
105
+ message.process unless cancel?(request['id'])
109
106
  rescue StandardError => e
110
107
  logger.warn "Error processing request: [#{e.class}] #{e.message}"
111
108
  logger.warn e.backtrace.join("\n")
@@ -303,6 +300,11 @@ module Solargraph
303
300
  end
304
301
  end
305
302
 
303
+ # @return [String]
304
+ def command_path
305
+ options['commandPath'] || 'solargraph'
306
+ end
307
+
306
308
  # Prepare multiple folders.
307
309
  #
308
310
  # @param array [Array<Hash{String => String}>]
@@ -381,7 +383,6 @@ module Solargraph
381
383
  envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
382
384
  queue envelope
383
385
  @next_request_id += 1
384
- logger.info "Server sent #{method}"
385
386
  logger.debug params
386
387
  end
387
388
  end
@@ -476,6 +477,7 @@ module Solargraph
476
477
  def locate_pins params
477
478
  return [] unless params['data'] && params['data']['uri']
478
479
  library = library_for(params['data']['uri'])
480
+ # @type [Array<Pin::Base>]
479
481
  result = []
480
482
  if params['data']['location']
481
483
  location = Location.new(
@@ -502,10 +504,12 @@ module Solargraph
502
504
  name: 'new',
503
505
  scope: :class,
504
506
  location: pin.location,
507
+ # @sg-ignore Unresolved call to parameters on Solargraph::Pin::Base
505
508
  parameters: pin.parameters,
506
509
  return_type: ComplexType.try_parse(params['data']['path']),
507
510
  comments: pin.comments,
508
- closure: pin.closure
511
+ closure: pin.closure,
512
+ source: :solargraph
509
513
  )
510
514
  end)
511
515
  end
@@ -532,7 +536,7 @@ module Solargraph
532
536
  # @param uri [String]
533
537
  # @param line [Integer]
534
538
  # @param column [Integer]
535
- # @return [Solargraph::SourceMap::Completion]
539
+ # @return [Solargraph::SourceMap::Completion, nil]
536
540
  def completions_at uri, line, column
537
541
  library = library_for(uri)
538
542
  library.completions_at uri_to_file(uri), line, column
@@ -546,7 +550,7 @@ module Solargraph
546
550
  # @param uri [String]
547
551
  # @param line [Integer]
548
552
  # @param column [Integer]
549
- # @return [Array<Solargraph::Pin::Base>]
553
+ # @return [Array<Solargraph::Pin::Base>, nil]
550
554
  def definitions_at uri, line, column
551
555
  library = library_for(uri)
552
556
  library.definitions_at(uri_to_file(uri), line, column)
@@ -555,7 +559,7 @@ module Solargraph
555
559
  # @param uri [String]
556
560
  # @param line [Integer]
557
561
  # @param column [Integer]
558
- # @return [Array<Solargraph::Pin::Base>]
562
+ # @return [Array<Solargraph::Pin::Base>, nil]
559
563
  def type_definitions_at uri, line, column
560
564
  library = library_for(uri)
561
565
  library.type_definitions_at(uri_to_file(uri), line, column)
@@ -575,10 +579,14 @@ module Solargraph
575
579
  # @param column [Integer]
576
580
  # @param strip [Boolean] Strip special characters from variable names
577
581
  # @param only [Boolean] If true, search current file only
578
- # @return [Array<Solargraph::Range>]
582
+ # @return [Array<Solargraph::Location>]
579
583
  def references_from uri, line, column, strip: true, only: false
580
584
  library = library_for(uri)
581
585
  library.references_from(uri_to_file(uri), line, column, strip: strip, only: only)
586
+ rescue FileNotFoundError, InvalidOffsetError => e
587
+ Solargraph.logger.warn "[#{e.class}] #{e.message}"
588
+ Solargraph.logger.debug e.backtrace
589
+ []
582
590
  end
583
591
 
584
592
  # @param query [String]
@@ -601,7 +609,11 @@ module Solargraph
601
609
  # @return [Array]
602
610
  def document query
603
611
  result = []
604
- libraries.each { |lib| result.concat lib.document(query) }
612
+ if libraries.empty?
613
+ result.concat generic_library.document(query)
614
+ else
615
+ libraries.each { |lib| result.concat lib.document(query) }
616
+ end
605
617
  result
606
618
  end
607
619
 
@@ -693,6 +705,11 @@ module Solargraph
693
705
 
694
706
  private
695
707
 
708
+ # @return [Array<Integer>]
709
+ def cancelled
710
+ @cancelled ||= []
711
+ end
712
+
696
713
  # @return [MessageWorker]
697
714
  def message_worker
698
715
  @message_worker ||= MessageWorker.new(self)
@@ -706,7 +723,7 @@ module Solargraph
706
723
  # A hash of client requests by ID. The host uses this to keep track of
707
724
  # pending responses.
708
725
  #
709
- # @return [Hash{Integer => Solargraph::LanguageServer::Host}]
726
+ # @return [Hash{Integer => Solargraph::LanguageServer::Request}]
710
727
  def requests
711
728
  @requests ||= {}
712
729
  end
@@ -748,6 +765,7 @@ module Solargraph
748
765
  return change if source.code.length + 1 != change['text'].length
749
766
  diffs = Diff::LCS.diff(source.code, change['text'])
750
767
  return change if diffs.length.zero? || diffs.length > 1 || diffs.first.length > 1
768
+ # @sg-ignore push this upstream
751
769
  # @type [Diff::LCS::Change]
752
770
  diff = diffs.first.first
753
771
  return change unless diff.adding? && ['.', ':', '(', ',', ' '].include?(diff.element)
@@ -16,7 +16,7 @@ module Solargraph
16
16
  # @return [String]
17
17
  attr_reader :method
18
18
 
19
- # @return [Hash{String => Array, Hash, String, Integer}]
19
+ # @return [Hash{String => undefined}]
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
- if host.cancel?(id)
65
- # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest
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: "2.0",
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,21 @@ module Solargraph
83
76
  host.queue envelope
84
77
  host.clear id
85
78
  end
79
+
80
+ private
81
+
82
+ # @return [void]
83
+ def accept_or_cancel
84
+ if host.cancel?(id)
85
+ # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#cancelRequest
86
+ # cancel should send response RequestCancelled
87
+ Solargraph::Logging.logger.info "Cancelled response to ##{id} #{method}"
88
+ set_result nil
89
+ set_error ErrorCodes::REQUEST_CANCELLED, 'Cancelled by client'
90
+ else
91
+ Solargraph::Logging.logger.info "Sending response to ##{id} #{method}"
92
+ end
93
+ end
86
94
  end
87
95
  end
88
96
  end
@@ -83,6 +83,8 @@ module Solargraph
83
83
  @fetched = true
84
84
  begin
85
85
  @available ||= begin
86
+ # @sg-ignore Variable type could not be inferred for tuple
87
+ # @type [Gem::Dependency, nil]
86
88
  tuple = CheckGemVersion.fetcher.search_for_dependency(Gem::Dependency.new('solargraph')).flatten.first
87
89
  if tuple.nil?
88
90
  @error = 'An error occurred fetching the gem data'
@@ -6,12 +6,15 @@ module Solargraph
6
6
  module Extended
7
7
  class Document < Base
8
8
  def process
9
- objects = host.document(params['query'])
9
+ api_map, pins = host.document(params['query'])
10
10
  page = Solargraph::Page.new(host.options['viewsPath'])
11
- content = page.render('document', layout: true, locals: {objects: objects})
11
+ content = page.render('document', layout: true, locals: { api_map: api_map, pins: pins })
12
12
  set_result(
13
13
  content: content
14
14
  )
15
+ rescue StandardError => e
16
+ Solargraph.logger.warn "Error processing document: [#{e.class}] #{e.message}"
17
+ Solargraph.logger.debug e.backtrace.join("\n")
15
18
  end
16
19
  end
17
20
  end
@@ -11,9 +11,9 @@ module Solargraph
11
11
  #
12
12
  class DocumentGems < Base
13
13
  def process
14
- cmd = "yard gems"
15
- cmd += " --rebuild" if params['rebuild']
16
- o, s = Open3.capture2(cmd)
14
+ cmd = [host.command_path, 'gems']
15
+ cmd.push '--rebuild' if params['rebuild']
16
+ o, s = Open3.capture2(*cmd)
17
17
  if s != 0
18
18
  host.show_message "An error occurred while building gem documentation.", LanguageServer::MessageTypes::ERROR
19
19
  set_result({
@@ -174,7 +174,9 @@ module Solargraph
174
174
 
175
175
  # @param section [String]
176
176
  # @param capability [String]
177
- # @return [Boolean]
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
@@ -10,17 +10,19 @@ module Solargraph::LanguageServer::Message::TextDocument
10
10
 
11
11
  private
12
12
 
13
+ # @return [Array<Hash>, nil]
13
14
  def code_location
14
15
  suggestions = host.definitions_at(params['textDocument']['uri'], @line, @column)
15
16
  return nil if suggestions.empty?
16
- suggestions.reject { |pin| pin.location.nil? || pin.location.filename.nil? }.map do |pin|
17
+ suggestions.reject { |pin| pin.best_location.nil? || pin.best_location.filename.nil? }.map do |pin|
17
18
  {
18
- uri: file_to_uri(pin.location.filename),
19
- range: pin.location.range.to_hash
19
+ uri: file_to_uri(pin.best_location.filename),
20
+ range: pin.best_location.range.to_hash
20
21
  }
21
22
  end
22
23
  end
23
24
 
25
+ # @return [Array<Hash>, nil]
24
26
  def require_location
25
27
  # @todo Terrible hack
26
28
  lib = host.library_for(params['textDocument']['uri'])
@@ -6,15 +6,15 @@ class Solargraph::LanguageServer::Message::TextDocument::DocumentSymbol < Solarg
6
6
  def process
7
7
  pins = host.document_symbols params['textDocument']['uri']
8
8
  info = pins.map do |pin|
9
- next nil unless pin.location&.filename
9
+ next nil unless pin.best_location&.filename
10
10
 
11
11
  result = {
12
12
  name: pin.name,
13
13
  containerName: pin.namespace,
14
14
  kind: pin.symbol_kind,
15
15
  location: {
16
- uri: file_to_uri(pin.location.filename),
17
- range: pin.location.range.to_hash
16
+ uri: file_to_uri(pin.best_location.filename),
17
+ range: pin.best_location.range.to_hash
18
18
  },
19
19
  deprecated: pin.deprecated?
20
20
  }
@@ -18,10 +18,18 @@ module Solargraph
18
18
 
19
19
  require_rubocop(config['version'])
20
20
  options, paths = ::RuboCop::Options.new.parse(args)
21
+ # @sg-ignore Unresolved call to []=
21
22
  options[:stdin] = original
22
- corrections = redirect_stdout do
23
- ::RuboCop::Runner.new(options, ::RuboCop::ConfigStore.new).run(paths)
23
+
24
+ # Ensure only one instance of RuboCop::Runner is running at
25
+ # a time - it uses 'chdir' to read config files with ERB,
26
+ # which can conflict with other chdirs.
27
+ corrections = Solargraph::CHDIR_MUTEX.synchronize do
28
+ redirect_stdout do
29
+ ::RuboCop::Runner.new(options, ::RuboCop::ConfigStore.new).run(paths)
30
+ end
24
31
  end
32
+ # @sg-ignore Unresolved call to []=
25
33
  result = options[:stdin]
26
34
 
27
35
  log_corrections(corrections)
@@ -33,6 +41,8 @@ module Solargraph
33
41
 
34
42
  private
35
43
 
44
+ # @param corrections [String]
45
+ # @return [void]
36
46
  def log_corrections(corrections)
37
47
  corrections = corrections&.strip
38
48
  return if corrections&.empty?
@@ -44,6 +54,8 @@ module Solargraph
44
54
  end
45
55
  end
46
56
 
57
+ # @param file_uri [String]
58
+ # @return [Hash{String => undefined}]
47
59
  def config_for(file_uri)
48
60
  conf = host.formatter_config(file_uri)
49
61
  return {} unless conf.is_a?(Hash)
@@ -51,6 +63,9 @@ module Solargraph
51
63
  conf['rubocop'] || {}
52
64
  end
53
65
 
66
+ # @param file_uri [String]
67
+ # @param config [Hash{String => String}]
68
+ # @return [Array<String>]
54
69
  def cli_args file_uri, config
55
70
  file = UriHelpers.uri_to_file(file_uri)
56
71
  args = [
@@ -68,6 +83,9 @@ module Solargraph
68
83
  args + [file]
69
84
  end
70
85
 
86
+ # @param config [Hash{String => String}]
87
+ # @sg-ignore
88
+ # @return [Class<RuboCop::Formatter::BaseFormatter>]
71
89
  def formatter_class(config)
72
90
  if self.class.const_defined?('BlankRubocopFormatter')
73
91
  # @sg-ignore
@@ -79,7 +97,10 @@ module Solargraph
79
97
  end
80
98
  end
81
99
 
100
+ # @param value [Array, String]
101
+ # @return [String, nil]
82
102
  def cop_list(value)
103
+ # @type [String]
83
104
  value = value.join(',') if value.respond_to?(:join)
84
105
  return nil if value == '' || !value.is_a?(String)
85
106
  value
@@ -21,7 +21,7 @@ module Solargraph
21
21
  parts.push pin.documentation unless pin.documentation.nil? || pin.documentation.empty?
22
22
  unless parts.empty?
23
23
  data = parts.join("\n\n")
24
- next if contents.last && contents.last.end_with?(data)
24
+ next if contents.last&.end_with?(data)
25
25
  contents.push data
26
26
  end
27
27
  last_link = this_link unless this_link.nil?
@@ -10,13 +10,14 @@ module Solargraph::LanguageServer::Message::TextDocument
10
10
 
11
11
  private
12
12
 
13
+ # @return [Array<Hash>, nil]
13
14
  def code_location
14
15
  suggestions = host.type_definitions_at(params['textDocument']['uri'], @line, @column)
15
16
  return nil if suggestions.empty?
16
- suggestions.reject { |pin| pin.location.nil? || pin.location.filename.nil? }.map do |pin|
17
+ suggestions.reject { |pin| pin.best_location.nil? || pin.best_location.filename.nil? }.map do |pin|
17
18
  {
18
- uri: file_to_uri(pin.location.filename),
19
- range: pin.location.range.to_hash
19
+ uri: file_to_uri(pin.best_location.filename),
20
+ range: pin.best_location.range.to_hash
20
21
  }
21
22
  end
22
23
  end
@@ -9,11 +9,13 @@ module Solargraph::LanguageServer::Message::Workspace
9
9
 
10
10
  private
11
11
 
12
+ # @return [void]
12
13
  def add_folders
13
14
  return unless params['event'] && params['event']['added']
14
15
  host.prepare_folders params['event']['added']
15
16
  end
16
17
 
18
+ # @return [void]
17
19
  def remove_folders
18
20
  return unless params['event'] && params['event']['removed']
19
21
  params['event']['removed'].each do |folder|
@@ -6,14 +6,14 @@ class Solargraph::LanguageServer::Message::Workspace::WorkspaceSymbol < Solargra
6
6
  def process
7
7
  pins = host.query_symbols(params['query'])
8
8
  info = pins.map do |pin|
9
- uri = file_to_uri(pin.location.filename)
9
+ uri = file_to_uri(pin.best_location.filename)
10
10
  {
11
11
  name: pin.path,
12
12
  containerName: pin.namespace,
13
13
  kind: pin.symbol_kind,
14
14
  location: {
15
15
  uri: uri,
16
- range: pin.location.range.to_hash
16
+ range: pin.best_location.range.to_hash
17
17
  },
18
18
  deprecated: pin.deprecated?
19
19
  }
@@ -39,6 +39,7 @@ module Solargraph
39
39
 
40
40
  # @param message [String]
41
41
  # @param percentage [Integer]
42
+ # @return [void]
42
43
  def begin message, percentage
43
44
  @kind = 'begin'
44
45
  @message = message
@@ -47,6 +48,7 @@ module Solargraph
47
48
 
48
49
  # @param message [String]
49
50
  # @param percentage [Integer]
51
+ # @return [void]
50
52
  def report message, percentage
51
53
  @kind = 'report'
52
54
  @message = message
@@ -54,6 +56,7 @@ module Solargraph
54
56
  end
55
57
 
56
58
  # @param message [String]
59
+ # @return [void]
57
60
  def finish message
58
61
  @kind = 'end'
59
62
  @message = message
@@ -62,14 +65,15 @@ module Solargraph
62
65
  end
63
66
 
64
67
  # @param host [Solargraph::LanguageServer::Host]
68
+ # @return [void]
65
69
  def send host
66
70
  return unless host.client_supports_progress? && !finished?
67
71
 
68
72
  message = build
69
-
70
- create(host) unless created?
73
+ create(host)
71
74
  host.send_notification '$/progress', message
72
75
  @status = FINISHED if kind == 'end'
76
+ keep_alive host
73
77
  end
74
78
 
75
79
  def created?
@@ -91,6 +95,7 @@ module Solargraph
91
95
  @status = CREATED
92
96
  end
93
97
 
98
+ # @return [Hash]
94
99
  def build
95
100
  {
96
101
  token: uuid,
@@ -101,6 +106,7 @@ module Solargraph
101
106
  }
102
107
  end
103
108
 
109
+ # @return [Hash]
104
110
  def build_value
105
111
  case kind
106
112
  when 'begin'
@@ -113,6 +119,25 @@ module Solargraph
113
119
  raise "Invalid progress kind #{kind}"
114
120
  end
115
121
  end
122
+
123
+ # @param host [Host]
124
+ # @return [void]
125
+ def keep_alive host
126
+ mutex.synchronize { @last = Time.now }
127
+ @keep_alive ||= Thread.new do
128
+ until finished?
129
+ sleep 10
130
+ break if finished?
131
+ next if mutex.synchronize { Time.now - @last < 10 }
132
+ send host
133
+ end
134
+ end
135
+ end
136
+
137
+ # @return [Thread::Mutex]
138
+ def mutex
139
+ @mutex ||= Mutex.new
140
+ end
116
141
  end
117
142
  end
118
143
  end
@@ -11,11 +11,14 @@ module Solargraph
11
11
  end
12
12
 
13
13
  # @param result [Object]
14
- # @return [void]
14
+ # @generic T
15
+ # @yieldreturn [generic<T>]
16
+ # @return [generic<T>, nil]
15
17
  def process result
16
18
  @block.call(result) unless @block.nil?
17
19
  end
18
20
 
21
+ # @return [void]
19
22
  def send_response
20
23
  # noop
21
24
  end