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
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'observer'
5
+ require 'open3'
5
6
 
6
7
  module Solargraph
7
8
  # A Library handles coordination between a Workspace and an ApiMap.
@@ -27,11 +28,11 @@ module Solargraph
27
28
  def initialize workspace = Solargraph::Workspace.new, name = nil
28
29
  @workspace = workspace
29
30
  @name = name
30
- @threads = []
31
31
  # @type [Integer, nil]
32
32
  @total = nil
33
33
  # @type [Source, nil]
34
34
  @current = nil
35
+ @sync_count = 0
35
36
  end
36
37
 
37
38
  def inspect
@@ -44,7 +45,7 @@ module Solargraph
44
45
  #
45
46
  # @return [Boolean]
46
47
  def synchronized?
47
- !mutex.locked?
48
+ @sync_count < 2
48
49
  end
49
50
 
50
51
  # Attach a source to the library.
@@ -132,6 +133,7 @@ module Solargraph
132
133
  result = false
133
134
  filenames.each do |filename|
134
135
  detach filename
136
+ source_map_hash.delete(filename)
135
137
  result ||= workspace.remove(filename)
136
138
  end
137
139
  result
@@ -174,9 +176,9 @@ module Solargraph
174
176
  # @return [Array<Solargraph::Pin::Base>, nil]
175
177
  # @todo Take filename/position instead of filename/line/column
176
178
  def definitions_at filename, line, column
179
+ sync_catalog
177
180
  position = Position.new(line, column)
178
181
  cursor = Source::Cursor.new(read(filename), position)
179
- sync_catalog
180
182
  if cursor.comment?
181
183
  source = read(filename)
182
184
  offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
@@ -190,7 +192,10 @@ module Solargraph
190
192
  []
191
193
  end
192
194
  else
193
- mutex.synchronize { api_map.clip(cursor).define.map { |pin| pin.realize(api_map) } }
195
+ mutex.synchronize do
196
+ clip = api_map.clip(cursor)
197
+ clip.define.map { |pin| pin.realize(api_map) }
198
+ end
194
199
  end
195
200
  rescue FileNotFoundError => e
196
201
  handle_file_not_found(filename, e)
@@ -205,9 +210,9 @@ module Solargraph
205
210
  # @return [Array<Solargraph::Pin::Base>, nil]
206
211
  # @todo Take filename/position instead of filename/line/column
207
212
  def type_definitions_at filename, line, column
213
+ sync_catalog
208
214
  position = Position.new(line, column)
209
215
  cursor = Source::Cursor.new(read(filename), position)
210
- sync_catalog
211
216
  mutex.synchronize { api_map.clip(cursor).types }
212
217
  rescue FileNotFoundError => e
213
218
  handle_file_not_found filename, e
@@ -222,9 +227,9 @@ module Solargraph
222
227
  # @return [Array<Solargraph::Pin::Base>]
223
228
  # @todo Take filename/position instead of filename/line/column
224
229
  def signatures_at filename, line, column
230
+ sync_catalog
225
231
  position = Position.new(line, column)
226
232
  cursor = Source::Cursor.new(read(filename), position)
227
- sync_catalog
228
233
  mutex.synchronize { api_map.clip(cursor).signify }
229
234
  end
230
235
 
@@ -233,7 +238,7 @@ module Solargraph
233
238
  # @param column [Integer]
234
239
  # @param strip [Boolean] Strip special characters from variable names
235
240
  # @param only [Boolean] Search for references in the current file only
236
- # @return [Array<Solargraph::Range>]
241
+ # @return [Array<Solargraph::Location>]
237
242
  # @todo Take a Location instead of filename/line/column
238
243
  def references_from filename, line, column, strip: false, only: false
239
244
  sync_catalog
@@ -254,11 +259,11 @@ module Solargraph
254
259
  referenced&.path == pin.path
255
260
  end
256
261
  if pin.path == 'Class#new'
257
- caller = cursor.chain.base.infer(api_map, clip.send(:block), clip.locals).first
262
+ caller = cursor.chain.base.infer(api_map, clip.send(:closure), clip.locals).first
258
263
  if caller.defined?
259
264
  found.select! do |loc|
260
265
  clip = api_map.clip_at(loc.filename, loc.range.start)
261
- other = clip.send(:cursor).chain.base.infer(api_map, clip.send(:block), clip.locals).first
266
+ other = clip.send(:cursor).chain.base.infer(api_map, clip.send(:closure), clip.locals).first
262
267
  caller == other
263
268
  end
264
269
  else
@@ -323,9 +328,10 @@ module Solargraph
323
328
 
324
329
  # @param query [String]
325
330
  # @return [Enumerable<YARD::CodeObjects::Base>]
331
+ # @return [Array(ApiMap, Enumerable<Pin::Base>)]
326
332
  def document query
327
333
  sync_catalog
328
- mutex.synchronize { api_map.document query }
334
+ mutex.synchronize { [api_map, api_map.get_path_pins(query)] }
329
335
  end
330
336
 
331
337
  # @param query [String]
@@ -391,11 +397,13 @@ module Solargraph
391
397
  return [] unless open?(filename)
392
398
  result = []
393
399
  source = read(filename)
400
+
401
+ # @type [Hash{Class<Solargraph::Diagnostics::Base> => Array<String>}]
394
402
  repargs = {}
395
403
  workspace.config.reporters.each do |line|
396
404
  if line == 'all!'
397
- Diagnostics.reporters.each do |reporter|
398
- repargs[reporter] ||= []
405
+ Diagnostics.reporters.each do |reporter_name|
406
+ repargs[Diagnostics.reporter(reporter_name)] ||= []
399
407
  end
400
408
  else
401
409
  args = line.split(':').map(&:strip)
@@ -416,20 +424,7 @@ module Solargraph
416
424
  #
417
425
  # @return [void]
418
426
  def catalog
419
- @threads.delete_if(&:stop?)
420
- @threads.push(Thread.new do
421
- sleep 0.05 if RUBY_PLATFORM =~ /mingw/
422
- next unless @threads.last == Thread.current
423
-
424
- mutex.synchronize do
425
- logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
426
- api_map.catalog bench
427
- logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
428
- logger.info "#{api_map.uncached_gemspecs.length} uncached gemspecs"
429
- cache_next_gemspec
430
- end
431
- end)
432
- @threads.last.run if RUBY_PLATFORM =~ /mingw/
427
+ @sync_count += 1
433
428
  end
434
429
 
435
430
  # @return [Bench]
@@ -437,21 +432,11 @@ module Solargraph
437
432
  Bench.new(
438
433
  source_maps: source_map_hash.values,
439
434
  workspace: workspace,
440
- external_requires: external_requires
435
+ external_requires: external_requires,
436
+ live_map: @current ? source_map_hash[@current.filename] : nil
441
437
  )
442
438
  end
443
439
 
444
- # Get an array of foldable ranges for the specified file.
445
- #
446
- # @deprecated The library should not need to handle folding ranges. The
447
- # source itself has all the information it needs.
448
- #
449
- # @param filename [String]
450
- # @return [Array<Range>]
451
- def folding_ranges filename
452
- read(filename).folding_ranges
453
- end
454
-
455
440
  # Create a library from a directory.
456
441
  #
457
442
  # @param directory [String] The path to be used for the workspace
@@ -467,7 +452,6 @@ module Solargraph
467
452
  # @param source [Source]
468
453
  # @return [Boolean] True if the source was merged into the workspace.
469
454
  def merge source
470
- Logging.logger.debug "Merging source: #{source.filename}"
471
455
  result = workspace.merge(source)
472
456
  maybe_map source
473
457
  result
@@ -489,7 +473,6 @@ module Solargraph
489
473
  if src
490
474
  Logging.logger.debug "Mapping #{src.filename}"
491
475
  source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
492
- find_external_requires(source_map_hash[src.filename])
493
476
  source_map_hash[src.filename]
494
477
  else
495
478
  false
@@ -500,7 +483,7 @@ module Solargraph
500
483
  def map!
501
484
  workspace.sources.each do |src|
502
485
  source_map_hash[src.filename] = Solargraph::SourceMap.map(src)
503
- find_external_requires(source_map_hash[src.filename])
486
+ find_external_requires source_map_hash[src.filename]
504
487
  end
505
488
  self
506
489
  end
@@ -517,7 +500,7 @@ module Solargraph
517
500
 
518
501
  private
519
502
 
520
- # @return [Hash{String => Set<String>}]
503
+ # @return [Hash{String => Array<String>}]
521
504
  def source_map_external_require_hash
522
505
  @source_map_external_require_hash ||= {}
523
506
  end
@@ -525,6 +508,7 @@ module Solargraph
525
508
  # @param source_map [SourceMap]
526
509
  # @return [void]
527
510
  def find_external_requires source_map
511
+ # @type [Set<String>]
528
512
  new_set = source_map.requires.map(&:name).to_set
529
513
  # return if new_set == source_map_external_require_hash[source_map.filename]
530
514
  _filenames = nil
@@ -538,7 +522,7 @@ module Solargraph
538
522
  @external_requires = nil
539
523
  end
540
524
 
541
- # @return [Mutex]
525
+ # @return [Thread::Mutex]
542
526
  def mutex
543
527
  @mutex ||= Mutex.new
544
528
  end
@@ -580,22 +564,10 @@ module Solargraph
580
564
  return unless source
581
565
  return unless @current == source || workspace.has_file?(source.filename)
582
566
  if source_map_hash.key?(source.filename)
583
- return if source_map_hash[source.filename].code == source.code &&
584
- source_map_hash[source.filename].source.synchronized? &&
585
- source.synchronized?
586
- if source.synchronized?
587
- new_map = Solargraph::SourceMap.map(source)
588
- unless source_map_hash[source.filename].try_merge!(new_map)
589
- source_map_hash[source.filename] = new_map
590
- find_external_requires(source_map_hash[source.filename])
591
- end
592
- else
593
- # @todo Smelly instance variable access
594
- source_map_hash[source.filename].instance_variable_set(:@source, source)
595
- end
567
+ new_map = Solargraph::SourceMap.map(source)
568
+ source_map_hash[source.filename] = new_map
596
569
  else
597
570
  source_map_hash[source.filename] = Solargraph::SourceMap.map(source)
598
- find_external_requires(source_map_hash[source.filename])
599
571
  end
600
572
  end
601
573
 
@@ -607,27 +579,54 @@ module Solargraph
607
579
  # @return [void]
608
580
  def cache_next_gemspec
609
581
  return if @cache_progress
610
- spec = api_map.uncached_gemspecs.find { |spec| !cache_errors.include?(spec) }
582
+
583
+ spec = cacheable_specs.first
611
584
  return end_cache_progress unless spec
612
585
 
613
586
  pending = api_map.uncached_gemspecs.length - cache_errors.length - 1
614
- logger.info "Caching #{spec.name} #{spec.version}"
615
- Thread.new do
616
- cache_pid = Process.spawn(workspace.command_path, 'cache', spec.name, spec.version.to_s)
617
- report_cache_progress spec.name, pending
618
- Process.wait(cache_pid)
619
- logger.info "Cached #{spec.name} #{spec.version}"
620
- rescue Errno::EINVAL => _e
621
- logger.info "Cached #{spec.name} #{spec.version} with EINVAL"
622
- rescue StandardError => e
623
- cache_errors.add spec
624
- Solargraph.logger.warn "Error caching gemspec #{spec.name} #{spec.version}: [#{e.class}] #{e.message}"
625
- ensure
626
- end_cache_progress
587
+
588
+ if Yardoc.processing?(spec)
589
+ logger.info "Enqueuing cache of #{spec.name} #{spec.version} (already being processed)"
590
+ queued_gemspec_cache.push(spec)
591
+ return if pending - queued_gemspec_cache.length < 1
592
+
627
593
  catalog
594
+ sync_catalog
595
+ else
596
+ logger.info "Caching #{spec.name} #{spec.version}"
597
+ Thread.new do
598
+ report_cache_progress spec.name, pending
599
+ _o, e, s = Open3.capture3(workspace.command_path, 'cache', spec.name, spec.version.to_s)
600
+ if s.success?
601
+ logger.info "Cached #{spec.name} #{spec.version}"
602
+ else
603
+ cache_errors.add spec
604
+ logger.warn "Error caching gemspec #{spec.name} #{spec.version}"
605
+ logger.warn e
606
+ end
607
+ end_cache_progress
608
+ catalog
609
+ sync_catalog
610
+ end
628
611
  end
629
612
  end
630
613
 
614
+ # @return [Array<Gem::Specification>]
615
+ def cacheable_specs
616
+ cacheable = api_map.uncached_yard_gemspecs +
617
+ api_map.uncached_rbs_collection_gemspecs -
618
+ queued_gemspec_cache -
619
+ cache_errors.to_a
620
+ return cacheable unless cacheable.empty?
621
+
622
+ queued_gemspec_cache
623
+ end
624
+
625
+ # @return [Array<Gem::Specification>]
626
+ def queued_gemspec_cache
627
+ @queued_gemspec_cache ||= []
628
+ end
629
+
631
630
  # @param gem_name [String]
632
631
  # @param pending [Integer]
633
632
  # @return [void]
@@ -665,9 +664,20 @@ module Solargraph
665
664
  @total = nil
666
665
  end
667
666
 
667
+ # @return [void]
668
668
  def sync_catalog
669
- @threads.delete_if(&:stop?)
670
- .last&.join
669
+ return if @sync_count == 0
670
+
671
+ mutex.synchronize do
672
+ logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
673
+ source_map_hash.values.each { |map| find_external_requires(map) }
674
+ api_map.catalog bench
675
+ logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)"
676
+ logger.info "#{api_map.uncached_yard_gemspecs.length} uncached YARD gemspecs"
677
+ logger.info "#{api_map.uncached_rbs_collection_gemspecs.length} uncached RBS collection gemspecs"
678
+ cache_next_gemspec
679
+ @sync_count = 0
680
+ end
671
681
  end
672
682
  end
673
683
  end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- # A section of text identified by its filename and range.
4
+ # A pointer to a section of source text identified by its filename
5
+ # and Range.
5
6
  #
6
7
  class Location
8
+ include Equality
9
+
7
10
  # @return [String]
8
11
  attr_reader :filename
9
12
 
@@ -17,6 +20,38 @@ module Solargraph
17
20
  @range = range
18
21
  end
19
22
 
23
+ # @sg-ignore Fix "Not enough arguments to Module#protected"
24
+ protected def equality_fields
25
+ [filename, range]
26
+ end
27
+
28
+ # @param other [self]
29
+ def <=>(other)
30
+ return nil unless other.is_a?(Location)
31
+ if filename == other.filename
32
+ range <=> other.range
33
+ else
34
+ filename <=> other.filename
35
+ end
36
+ end
37
+
38
+ def rbs?
39
+ filename.end_with?('.rbs')
40
+ end
41
+
42
+ # @param location [self]
43
+ def contain? location
44
+ range.contain?(location.range.start) && range.contain?(location.range.ending) && filename == location.filename
45
+ end
46
+
47
+ def inspect
48
+ "<#{self.class.name}: filename=#{filename}, range=#{range.inspect}>"
49
+ end
50
+
51
+ def to_s
52
+ inspect
53
+ end
54
+
20
55
  # @return [Hash]
21
56
  def to_hash
22
57
  {
@@ -25,9 +60,18 @@ module Solargraph
25
60
  }
26
61
  end
27
62
 
63
+ # @param node [Parser::AST::Node, nil]
64
+ # @return [Location, nil]
65
+ def self.from_node(node)
66
+ return nil if node.nil? || node.loc.nil?
67
+ range = Range.from_node(node)
68
+ self.new(node.loc.expression.source_buffer.name, range)
69
+ end
70
+
28
71
  # @param other [BasicObject]
29
72
  def == other
30
73
  return false unless other.is_a?(Location)
74
+ # @sg-ignore https://github.com/castwide/solargraph/pull/1114
31
75
  filename == other.filename and range == other.range
32
76
  end
33
77
 
@@ -11,8 +11,18 @@ module Solargraph
11
11
  'info' => Logger::INFO,
12
12
  'debug' => Logger::DEBUG
13
13
  }
14
-
15
- @@logger = Logger.new(STDERR, level: DEFAULT_LOG_LEVEL)
14
+ configured_level = ENV.fetch('SOLARGRAPH_LOG', nil)
15
+ level = if LOG_LEVELS.keys.include?(configured_level)
16
+ LOG_LEVELS.fetch(configured_level)
17
+ else
18
+ if configured_level
19
+ warn "Invalid value for SOLARGRAPH_LOG: #{configured_level.inspect} - " \
20
+ "valid values are #{LOG_LEVELS.keys}"
21
+ end
22
+ DEFAULT_LOG_LEVEL
23
+ end
24
+ @@logger = Logger.new(STDERR, level: level)
25
+ # @sg-ignore Fix cvar issue
16
26
  @@logger.formatter = proc do |severity, datetime, progname, msg|
17
27
  "[#{severity}] #{msg}\n"
18
28
  end
@@ -29,6 +29,7 @@ module Solargraph
29
29
  # @param text [String]
30
30
  # @return [String]
31
31
  def htmlify text
32
+ # @type [String]
32
33
  YARD::Templates::Helpers::Markup::RDocMarkup.new(text).to_html
33
34
  end
34
35
 
@@ -70,8 +71,10 @@ module Solargraph
70
71
  # @param template [String]
71
72
  # @param layout [Boolean]
72
73
  # @param locals [Hash]
74
+ # @sg-ignore
73
75
  # @return [String]
74
76
  def render template, layout: true, locals: {}
77
+ # @type [String]
75
78
  @render_method.call(template, layout: layout, locals: locals)
76
79
  end
77
80
 
@@ -3,6 +3,13 @@ require 'ripper'
3
3
  module Solargraph
4
4
  module Parser
5
5
  class CommentRipper < Ripper::SexpBuilderPP
6
+ # @!override Ripper::SexpBuilder#on_embdoc_beg
7
+ # @return [Array(Symbol, String, Array)]
8
+ # @!override Ripper::SexpBuilder#on_embdoc
9
+ # @return [Array(Symbol, String, Array)]
10
+ # @!override Ripper::SexpBuilder#on_embdoc_end
11
+ # @return [Array(Symbol, String, Array)]
12
+
6
13
  # @param src [String]
7
14
  # @param filename [String]
8
15
  # @param lineno [Integer]
@@ -13,6 +20,8 @@ module Solargraph
13
20
  end
14
21
 
15
22
  def on_comment *args
23
+ # @sg-ignore
24
+ # @type [Array(Symbol, String, Array([Integer, nil], [Integer, nil]))]
16
25
  result = super
17
26
  if @buffer_lines[result[2][0]][0..result[2][1]].strip =~ /^#/
18
27
  chomped = result[1].chomp
@@ -24,28 +33,32 @@ module Solargraph
24
33
  result
25
34
  end
26
35
 
36
+ # @param result [Array(Symbol, String, Array([Integer, nil], [Integer, nil]))]
37
+ # @return [void]
38
+ def create_snippet(result)
39
+ chomped = result[1].chomp
40
+ @comments[result[2][0]] = Snippet.new(Range.from_to(result[2][0] || 0, result[2][1] || 0, result[2][0] || 0, (result[2][1] || 0) + chomped.length), chomped)
41
+ end
42
+
27
43
  def on_embdoc_beg *args
28
44
  result = super
29
- chomped = result[1].chomp
30
- @comments[result[2][0]] = Snippet.new(Range.from_to(result[2][0], result[2][1], result[2][0], result[2][1] + chomped.length), chomped)
45
+ create_snippet(result)
31
46
  result
32
47
  end
33
48
 
34
49
  def on_embdoc *args
35
50
  result = super
36
- chomped = result[1].chomp
37
- @comments[result[2][0]] = Snippet.new(Range.from_to(result[2][0], result[2][1], result[2][0], result[2][1] + chomped.length), chomped)
51
+ create_snippet(result)
38
52
  result
39
53
  end
40
54
 
41
55
  def on_embdoc_end *args
42
56
  result = super
43
- chomped = result[1].chomp
44
- @comments[result[2][0]] = Snippet.new(Range.from_to(result[2][0], result[2][1], result[2][0], result[2][1] + chomped.length), chomped)
57
+ create_snippet(result)
45
58
  result
46
59
  end
47
60
 
48
- # @return [Hash{Integer => String}]
61
+ # @return [Hash{Integer => Solargraph::Parser::Snippet}]
49
62
  def parse
50
63
  @comments = {}
51
64
  super