solargraph 0.29.5 → 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
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