solargraph 0.29.5 → 0.30.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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +1 -0
  3. data/lib/solargraph/api_map.rb +22 -13
  4. data/lib/solargraph/language_server/host.rb +121 -33
  5. data/lib/solargraph/language_server/host/cataloger.rb +5 -4
  6. data/lib/solargraph/language_server/message.rb +3 -0
  7. data/lib/solargraph/language_server/message/extended.rb +5 -4
  8. data/lib/solargraph/language_server/message/extended/document.rb +1 -1
  9. data/lib/solargraph/language_server/message/extended/environment.rb +20 -0
  10. data/lib/solargraph/language_server/message/extended/search.rb +1 -1
  11. data/lib/solargraph/language_server/message/initialize.rb +28 -4
  12. data/lib/solargraph/language_server/message/initialized.rb +1 -0
  13. data/lib/solargraph/language_server/message/text_document.rb +1 -0
  14. data/lib/solargraph/language_server/message/text_document/folding_range.rb +24 -0
  15. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  16. data/lib/solargraph/language_server/message/workspace.rb +4 -3
  17. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +1 -0
  18. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +3 -6
  19. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -0
  20. data/lib/solargraph/language_server/transport.rb +1 -2
  21. data/lib/solargraph/language_server/transport/{socket.rb → adapter.rb} +8 -10
  22. data/lib/solargraph/library.rb +29 -3
  23. data/lib/solargraph/logging.rb +25 -0
  24. data/lib/solargraph/page.rb +14 -4
  25. data/lib/solargraph/pin/documenting.rb +1 -1
  26. data/lib/solargraph/shell.rb +9 -10
  27. data/lib/solargraph/source.rb +59 -5
  28. data/lib/solargraph/source/encoding_fixes.rb +1 -1
  29. data/lib/solargraph/source_map/mapper.rb +14 -8
  30. data/lib/solargraph/version.rb +1 -1
  31. data/lib/solargraph/views/_method.erb +3 -0
  32. data/lib/solargraph/views/environment.erb +50 -0
  33. data/lib/solargraph/views/layout.erb +6 -0
  34. data/lib/solargraph/yard_map.rb +8 -8
  35. metadata +11 -13
  36. data/lib/solargraph/language_server/transport/stdio.rb +0 -63
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef270f7fed3e6a6b8cae0214c0bcdd41e239bfe151951875895a5b6fa76b46f7
4
- data.tar.gz: 5be38dd7aaee4533e5c60abe980176f30225e63393fb1858913c8fb4d9938802
3
+ metadata.gz: 82f40642bcf02b95ca838da6a0ed6ff66ac9d0e8ef42ee8bf8643866342ffb39
4
+ data.tar.gz: e1e30bd1a35dfdfd1b17d74d70ab8afef82c701fdbffb4d4f08455511df95673
5
5
  SHA512:
6
- metadata.gz: 67036eaaafe01c834b8ce7ca20b7ec00cf302653b4dcc45221d15e64121477c938f36027990d2eed1e206f1d037a69aa835c84882753b55fec43dab402ead4e5
7
- data.tar.gz: d30834378eab843bee9b637dcfe0809189100bedce3c9c71f575da5a9a361153eedb9a1b15b48b4907d4b3776b67e3da12b12c9777ff75ac0ee46a7d147dd3d2
6
+ metadata.gz: 67ace010ea2017c9d35c2d8aa8229187ff39c27f926c388eba9105e067088c31ed46a7dadaef787c5845eb838b9c347744cfc48e47dea480558a8d5f05c15ee7
7
+ data.tar.gz: eef1f9e7c56e8623fe44227fedd16b89a0d277ac29ac3005ade6b98387596daff15c0743deb8de8b99ff4950c72b504c4f31e0e44faf075de14fc662efa14449
data/lib/solargraph.rb CHANGED
@@ -34,6 +34,7 @@ module Solargraph
34
34
  autoload :Diagnostics, 'solargraph/diagnostics'
35
35
  autoload :ComplexType, 'solargraph/complex_type'
36
36
  autoload :Bundle, 'solargraph/bundle'
37
+ autoload :Logging, 'solargraph/logging'
37
38
 
38
39
  dir = File.dirname(__FILE__)
39
40
  YARDOC_PATH = File.realpath(File.join(dir, '..', 'yardoc'))
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'set'
3
+ require 'pathname'
3
4
 
4
5
  module Solargraph
5
6
  # An aggregate provider for information about workspaces, sources, gems, and
@@ -96,7 +97,8 @@ module Solargraph
96
97
  reqs.delete_if do |r|
97
98
  result = false
98
99
  bundle.workspace.require_paths.each do |l|
99
- if new_map_hash.keys.include?(File.join(l, "#{r}.rb"))
100
+ pn = Pathname.new(bundle.workspace.directory).join(l, "#{r}.rb")
101
+ if new_map_hash.keys.include?(pn.to_s)
100
102
  result = true
101
103
  break
102
104
  end
@@ -298,13 +300,27 @@ module Solargraph
298
300
  result
299
301
  end
300
302
 
301
- # Get an array of public methods for a complex type.
303
+ # Get an array of method pins for a complex type.
302
304
  #
303
- # @param type [Solargraph::ComplexType]
304
- # @param context [String]
305
+ # The type's namespace and the context should be fully qualified. If the
306
+ # context matches the namespace type or is a subclass of the type,
307
+ # protected methods are included in the results. If protected methods are
308
+ # included and internal is true, private methods are also included.
309
+ #
310
+ # @example
311
+ # api_map = Solargraph::ApiMap.new
312
+ # type = Solargraph::ComplexType.parse('String')
313
+ # api_map.get_complex_type_methods(type)
314
+ #
315
+ # @param type [Solargraph::ComplexType] The complex type of the namespace
316
+ # @param context [String] The context from which the type is referenced
305
317
  # @param internal [Boolean] True to include private methods
306
318
  # @return [Array<Solargraph::Pin::Base>]
307
319
  def get_complex_type_methods type, context = '', internal = false
320
+ # This method does not qualify the complex type's namespace because
321
+ # it can cause conflicts between similar names, e.g., `Foo` vs.
322
+ # `Other::Foo`. It still takes a context argument to determine whether
323
+ # protected and private methods are visible.
308
324
  return [] if type.undefined? || type.void?
309
325
  result = []
310
326
  if type.duck_type?
@@ -314,19 +330,12 @@ module Solargraph
314
330
  result.concat get_methods('Object')
315
331
  else
316
332
  unless type.nil? || type.name == 'void'
317
- # @todo This method does not qualify the complex type's namespace
318
- # because it can cause namespace conflicts, e.g., `Foo` vs.
319
- # `Other::Foo`. It still takes a context argument because it
320
- # uses context to determine whether protected and private methods
321
- # are visible.
322
- # namespace = qualify(type.namespace, context)
323
- namespace = type.namespace
324
333
  visibility = [:public]
325
- if namespace == context || super_and_sub?(namespace, context)
334
+ if type.namespace == context || super_and_sub?(type.namespace, context)
326
335
  visibility.push :protected
327
336
  visibility.push :private if internal
328
337
  end
329
- result.concat get_methods(namespace, scope: type.scope, visibility: visibility)
338
+ result.concat get_methods(type.namespace, scope: type.scope, visibility: visibility)
330
339
  end
331
340
  end
332
341
  result
@@ -12,6 +12,7 @@ module Solargraph
12
12
  autoload :Cataloger, 'solargraph/language_server/host/cataloger'
13
13
 
14
14
  include Solargraph::LanguageServer::UriHelpers
15
+ include Logging
15
16
 
16
17
  def initialize
17
18
  @cancel_semaphore = Mutex.new
@@ -31,6 +32,7 @@ module Solargraph
31
32
  def configure update
32
33
  return if update.nil?
33
34
  options.merge! update
35
+ logger.level = LOG_LEVELS[options['logLevel']] || DEFAULT_LOG_LEVEL
34
36
  end
35
37
 
36
38
  # @return [Hash]
@@ -70,6 +72,8 @@ module Solargraph
70
72
  # @return [Solargraph::LanguageServer::Message::Base] The message handler.
71
73
  def start request
72
74
  if request['method']
75
+ logger.info "Server received #{request['method']}"
76
+ logger.debug request
73
77
  message = Message.select(request['method']).new(self, request)
74
78
  begin
75
79
  message.process
@@ -94,14 +98,18 @@ module Solargraph
94
98
  #
95
99
  # @param uri [String] The file uri.
96
100
  def create uri
101
+ library = library_for(uri)
97
102
  filename = uri_to_file(uri)
98
- library.create_from_disk filename
103
+ result = library.create_from_disk(filename)
104
+ diagnoser.schedule uri if open?(uri)
105
+ result
99
106
  end
100
107
 
101
108
  # Delete the specified file from the library.
102
109
  #
103
110
  # @param uri [String] The file uri.
104
111
  def delete uri
112
+ library = library_for(uri)
105
113
  filename = uri_to_file(uri)
106
114
  library.delete filename
107
115
  send_notification "textDocument/publishDiagnostics", {
@@ -116,10 +124,17 @@ module Solargraph
116
124
  # @param text [String] The contents of the file.
117
125
  # @param version [Integer] A version number.
118
126
  def open uri, text, version
127
+ library = library_for(uri)
119
128
  library.open uri_to_file(uri), text, version
120
129
  diagnoser.schedule uri
121
130
  end
122
131
 
132
+ def open_from_disk uri
133
+ library = library_for(uri)
134
+ library.open_from_disk uri_to_file(uri)
135
+ diagnoser.schedule uri
136
+ end
137
+
123
138
  # True if the specified file is currently open in the library.
124
139
  #
125
140
  # @param uri [String]
@@ -132,12 +147,15 @@ module Solargraph
132
147
  #
133
148
  # @param uri [String]
134
149
  def close uri
150
+ library = library_for(uri)
135
151
  library.close uri_to_file(uri)
136
152
  diagnoser.schedule uri
137
153
  end
138
154
 
139
155
  # @param uri [String]
140
156
  def diagnose uri
157
+ logger.info "Diagnosing #{uri}"
158
+ library = library_for(uri)
141
159
  begin
142
160
  results = library.diagnose uri_to_file(uri)
143
161
  send_notification "textDocument/publishDiagnostics", {
@@ -155,9 +173,10 @@ module Solargraph
155
173
  end
156
174
 
157
175
  def change params
176
+ library = library_for(params['textDocument']['uri'])
158
177
  updater = generate_updater(params)
159
178
  library.update updater
160
- cataloger.ping unless library.synchronized?
179
+ cataloger.ping(library) unless library.synchronized?
161
180
  diagnoser.schedule params['textDocument']['uri']
162
181
  end
163
182
 
@@ -185,22 +204,53 @@ module Solargraph
185
204
  # Prepare a library for the specified directory.
186
205
  #
187
206
  # @param directory [String]
188
- def prepare directory
207
+ # @param name [String]
208
+ def prepare directory, name = nil
209
+ logger.info "Preparing library for #{directory}"
189
210
  path = ''
190
211
  path = normalize_separators(directory) unless directory.nil?
191
212
  begin
192
- @library = Solargraph::Library.load(path)
213
+ lib = Solargraph::Library.load(path, name)
193
214
  rescue WorkspaceTooLargeError => e
194
215
  send_notification 'window/showMessage', {
195
216
  'type' => Solargraph::LanguageServer::MessageTypes::WARNING,
196
217
  'message' => e.message
197
218
  }
198
- @library = Solargraph::Library.load
219
+ lib = Solargraph::Library.new('', name)
199
220
  end
221
+ libraries.push lib
200
222
  diagnoser.start
201
223
  cataloger.start
202
224
  end
203
225
 
226
+ def prepare_folders array
227
+ array.each do |folder|
228
+ prepare uri_to_file(folder['uri']), folder['name']
229
+ end
230
+ end
231
+
232
+ def remove directory
233
+ logger.info "Removing library for #{directory}"
234
+ # @param lib [Library]
235
+ libraries.delete_if do |lib|
236
+ next false if lib.workspace.directory != directory
237
+ lib.open_sources.each do |src|
238
+ orphan_library.open(src.filename, src.code, src.version)
239
+ end
240
+ true
241
+ end
242
+ end
243
+
244
+ def remove_folders array
245
+ array.each do |folder|
246
+ remove uri_to_file(folder['uri'])
247
+ end
248
+ end
249
+
250
+ def folders
251
+ libraries.map { |lib| lib.workspace.directory }
252
+ end
253
+
204
254
  # Send a notification to the client.
205
255
  #
206
256
  # @param method [String] The message method
@@ -214,6 +264,8 @@ module Solargraph
214
264
  json = response.to_json
215
265
  envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
216
266
  queue envelope
267
+ logger.info "Server sent #{method}"
268
+ logger.debug params
217
269
  end
218
270
 
219
271
  # Send a request to the client and execute the provided block to process
@@ -236,6 +288,8 @@ module Solargraph
236
288
  envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
237
289
  queue envelope
238
290
  @next_request_id += 1
291
+ logger.info "Server sent #{method}"
292
+ logger.debug params
239
293
  end
240
294
 
241
295
  # Register the methods as capabilities with the client.
@@ -244,6 +298,7 @@ module Solargraph
244
298
  #
245
299
  # @param methods [Array<String>] The methods to register
246
300
  def register_capabilities methods
301
+ logger.debug "Registering capabilities: #{methods}"
247
302
  @register_semaphore.synchronize do
248
303
  send_request 'client/registerCapability', {
249
304
  registrations: methods.select{|m| can_register?(m) and !registered?(m)}.map { |m|
@@ -264,6 +319,7 @@ module Solargraph
264
319
  #
265
320
  # @param methods [Array<String>] The methods to unregister
266
321
  def unregister_capabilities methods
322
+ logger.debug "Unregistering capabilities: #{methods}"
267
323
  @register_semaphore.synchronize do
268
324
  send_request 'client/unregisterCapability', {
269
325
  unregisterations: methods.select{|m| registered?(m)}.map{ |m|
@@ -300,13 +356,6 @@ module Solargraph
300
356
  @registered_capabilities.include?(method)
301
357
  end
302
358
 
303
- # True if the specified file is in the process of changing.
304
- #
305
- # @return [Boolean]
306
- def changing? file_uri
307
- unsafe_changing?(file_uri)
308
- end
309
-
310
359
  def synchronizing?
311
360
  cataloger.synchronizing?
312
361
  end
@@ -324,6 +373,7 @@ module Solargraph
324
373
  def locate_pin params
325
374
  pin = nil
326
375
  unless params['data']['location'].nil?
376
+ library = library_for(file_to_uri(params['data']['location']['filename']))
327
377
  location = Location.new(
328
378
  params['data']['location']['filename'],
329
379
  Range.from_to(
@@ -336,15 +386,16 @@ module Solargraph
336
386
  pin = library.locate_pin(location)
337
387
  end
338
388
  # @todo Improve pin location
339
- if pin.nil? or pin.path != params['data']['path']
340
- pin = library.path_pins(params['data']['path']).first
341
- end
389
+ # if pin.nil? or pin.path != params['data']['path']
390
+ # pin = library.path_pins(params['data']['path']).first
391
+ # end
342
392
  pin
343
393
  end
344
394
 
345
395
  # @param uri [String]
346
396
  # @return [String]
347
397
  def read_text uri
398
+ library = library_for(uri)
348
399
  filename = uri_to_file(uri)
349
400
  library.read_text(filename)
350
401
  end
@@ -354,9 +405,8 @@ module Solargraph
354
405
  # @param column [Integer]
355
406
  # @return [Solargraph::ApiMap::Completion]
356
407
  def completions_at filename, line, column
357
- result = nil
358
- result = library.completions_at filename, line, column
359
- result
408
+ library = library_for(file_to_uri(filename))
409
+ library.completions_at filename, line, column
360
410
  end
361
411
 
362
412
  # @param filename [String]
@@ -364,6 +414,7 @@ module Solargraph
364
414
  # @param column [Integer]
365
415
  # @return [Array<Solargraph::Pin::Base>]
366
416
  def definitions_at filename, line, column
417
+ library = library_for(file_to_uri(filename))
367
418
  library.definitions_at(filename, line, column)
368
419
  end
369
420
 
@@ -372,6 +423,7 @@ module Solargraph
372
423
  # @param column [Integer]
373
424
  # @return [Array<Solargraph::Pin::Base>]
374
425
  def signatures_at filename, line, column
426
+ library = library_for(file_to_uri(filename))
375
427
  library.signatures_at(filename, line, column)
376
428
  end
377
429
 
@@ -381,30 +433,38 @@ module Solargraph
381
433
  # @param strip [Boolean] Strip special characters from variable names
382
434
  # @return [Array<Solargraph::Range>]
383
435
  def references_from filename, line, column, strip: true
436
+ library = library_for(file_to_uri(filename))
384
437
  result = library.references_from(filename, line, column, strip: strip)
385
438
  end
386
439
 
387
440
  # @param query [String]
388
441
  # @return [Array<Solargraph::Pin::Base>]
389
442
  def query_symbols query
390
- library.query_symbols(query)
443
+ result = []
444
+ libraries.each { |lib| result.concat lib.query_symbols(query) }
445
+ result
391
446
  end
392
447
 
393
448
  # @param query [String]
394
449
  # @return [Array<String>]
395
450
  def search query
396
- library.search(query)
451
+ result = []
452
+ libraries.each { |lib| result.concat lib.search(query) }
453
+ result
397
454
  end
398
455
 
399
456
  # @param query [String]
400
457
  # @return [String]
401
458
  def document query
402
- library.document(query)
459
+ result = []
460
+ libraries.each { |lib| result.concat lib.document(query) }
461
+ result
403
462
  end
404
463
 
405
464
  # @param uri [String]
406
465
  # @return [Array<Solargraph::Pin::Base>]
407
466
  def document_symbols uri
467
+ library = library_for(uri)
408
468
  library.document_symbols(uri_to_file(uri))
409
469
  end
410
470
 
@@ -453,22 +513,52 @@ module Solargraph
453
513
  'references' => true,
454
514
  'autoformat' => false,
455
515
  'diagnostics' => false,
456
- 'formatting' => false
516
+ 'formatting' => false,
517
+ 'folding' => true,
518
+ 'logLevel' => 'warn'
457
519
  }
458
520
  end
459
521
 
460
522
  # Catalog the library.
461
523
  #
462
524
  # @return [void]
463
- def catalog
464
- library.catalog
525
+ def catalog lib
526
+ lib.catalog
527
+ end
528
+
529
+ def folding_ranges uri
530
+ library = library_for(uri)
531
+ file = uri_to_file(uri)
532
+ library.folding_ranges(file)
465
533
  end
466
534
 
467
535
  private
468
536
 
469
- # @return [Solargraph::Library]
470
- def library
471
- @library ||= Solargraph::Library.new
537
+ # @return [Array<Library>]
538
+ def libraries
539
+ @libraries ||= []
540
+ end
541
+
542
+ # @param uri [String]
543
+ # @return [Library]
544
+ def library_for uri
545
+ return libraries.first if libraries.length == 1
546
+ filename = uri_to_file(uri)
547
+ # Find a library with an explicit reference to the file
548
+ libraries.each do |lib|
549
+ return lib if lib.contain?(filename) || lib.open?(filename)
550
+ end
551
+ # Find a library with a workspace that contains the file
552
+ libraries.each do |lib|
553
+ return lib if filename.start_with?(lib.workspace.directory)
554
+ end
555
+ return orphan_library if orphan_library.open?(filename)
556
+ raise "No library for #{uri}"
557
+ end
558
+
559
+ # @return [Library]
560
+ def orphan_library
561
+ @orphan_library ||= Solargraph::Library.new
472
562
  end
473
563
 
474
564
  # @return [Diagnoser]
@@ -481,13 +571,8 @@ module Solargraph
481
571
  @cataloger ||= Cataloger.new(self)
482
572
  end
483
573
 
484
- # @param file_uri [String]
485
- # @return [Boolean]
486
- def unsafe_changing? file_uri
487
- file = uri_to_file(file_uri)
488
- end
489
-
490
574
  def unsafe_open? uri
575
+ library = library_for(uri)
491
576
  library.open?(uri_to_file(uri))
492
577
  end
493
578
 
@@ -560,6 +645,9 @@ module Solargraph
560
645
  },
561
646
  'textDocument/formatting' => {
562
647
  formattingProvider: true
648
+ },
649
+ 'textDocument/foldingRange' => {
650
+ foldingRangeProvider: true
563
651
  }
564
652
  }
565
653
  end