solargraph 0.20.0 → 0.21.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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +2 -3
  3. data/lib/solargraph/api_map.rb +6 -6
  4. data/lib/solargraph/api_map/source_to_yard.rb +1 -1
  5. data/lib/solargraph/language_server/host.rb +69 -10
  6. data/lib/solargraph/language_server/message.rb +1 -2
  7. data/lib/solargraph/language_server/message/initialize.rb +83 -15
  8. data/lib/solargraph/language_server/message/initialized.rb +7 -0
  9. data/lib/solargraph/language_server/message/text_document/formatting.rb +4 -1
  10. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +20 -19
  11. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +19 -1
  12. data/lib/solargraph/language_server/request.rb +1 -1
  13. data/lib/solargraph/language_server/transport.rb +1 -0
  14. data/lib/solargraph/language_server/transport/data_reader.rb +66 -0
  15. data/lib/solargraph/language_server/transport/socket.rb +8 -32
  16. data/lib/solargraph/library.rb +11 -6
  17. data/lib/solargraph/page.rb +1 -1
  18. data/lib/solargraph/pin/base.rb +8 -7
  19. data/lib/solargraph/pin/method_parameter.rb +2 -15
  20. data/lib/solargraph/pin/yard_object.rb +1 -1
  21. data/lib/solargraph/plugin/runtime.rb +0 -2
  22. data/lib/solargraph/shell.rb +0 -24
  23. data/lib/solargraph/source.rb +5 -169
  24. data/lib/solargraph/source/mapper.rb +8 -3
  25. data/lib/solargraph/version.rb +1 -1
  26. data/lib/solargraph/workspace.rb +3 -3
  27. data/lib/solargraph/workspace/config.rb +7 -9
  28. data/lib/solargraph/yard_map.rb +9 -48
  29. metadata +17 -74
  30. data/lib/solargraph/server.rb +0 -212
  31. data/lib/solargraph/suggestion.rb +0 -178
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0e1a1a75c9706d5d54ca2359b21bf336b9980bce
4
- data.tar.gz: 618ae6ec9b01ddd2ee7656a34c787cc6b26bfc0b
3
+ metadata.gz: 04dd49e264774d545fbdf1a7f52d0b7227ff3f11
4
+ data.tar.gz: cb617a8800b2eec8688c46fc89cf4ee79445dd50
5
5
  SHA512:
6
- metadata.gz: 7ab817f132710bdb79f93773937cb8280dd764b07e7bd29f4b33064e097690a192afc219f6bbcf69b00d3ca1257cb8a6e90db91c9c8ee3109fa522f6ea054474
7
- data.tar.gz: ccb208a618f8c891c6bfd102e45bd65a31307abc87bb51cd738ed64582eb0e1a45adbc4ba7e7248de64b5cc6760dfa68370eb6f883c63a18c340a2657e38a4b3
6
+ metadata.gz: db20a5e3053060171bf9077c1ce572de8428193b4d562c7d939c9a7003074de64f41ffe879100b7f7a31bb42f625a32e69ad7755afc68b8c31d2cc64d15be353
7
+ data.tar.gz: bb9a311819e91501145c05fc2045178a791933fb6f9598e6265f68efe301664cbb6bfa50170928989d1fd8543a726cd36e0079b2f650c2ded36f9ad3a66c92c6
@@ -1,7 +1,6 @@
1
1
  require 'solargraph/version'
2
2
  require 'rubygems/package'
3
3
  require 'yard-solargraph'
4
- require 'sinatra'
5
4
 
6
5
  module Solargraph
7
6
  class InvalidOffsetError < RangeError; end
@@ -11,6 +10,8 @@ module Solargraph
11
10
 
12
11
  class WorkspaceTooLargeError < RuntimeError
13
12
  attr_reader :size
13
+
14
+ # @param size [Integer] The number of files included in the workspace
14
15
  def initialize size
15
16
  @size = size
16
17
  end
@@ -20,8 +21,6 @@ module Solargraph
20
21
  autoload :Source, 'solargraph/source'
21
22
  autoload :ApiMap, 'solargraph/api_map'
22
23
  autoload :NodeMethods, 'solargraph/node_methods'
23
- autoload :Suggestion, 'solargraph/suggestion'
24
- autoload :Server, 'solargraph/server'
25
24
  autoload :YardMap, 'solargraph/yard_map'
26
25
  autoload :Pin, 'solargraph/pin'
27
26
  autoload :LiveMap, 'solargraph/live_map'
@@ -57,6 +57,7 @@ module Solargraph
57
57
  @sources.each do |s|
58
58
  result.concat s.required.map(&:name)
59
59
  end
60
+ result.concat workspace.config.required
60
61
  result.uniq
61
62
  end
62
63
 
@@ -341,7 +342,9 @@ module Solargraph
341
342
  def signify fragment
342
343
  return [] unless fragment.argument?
343
344
  return [] if fragment.recipient.whole_signature.nil? or fragment.recipient.whole_signature.empty?
344
- probe.infer_signature_pins fragment.recipient.whole_signature, fragment.named_path, fragment.locals
345
+ probe.infer_signature_pins(
346
+ fragment.recipient.whole_signature, fragment.named_path, fragment.locals
347
+ ).select{ |pin| pin.kind == Pin::METHOD }
345
348
  end
346
349
 
347
350
  # Get an array of all suggestions that match the specified path.
@@ -471,11 +474,8 @@ module Solargraph
471
474
  end
472
475
  result.concat yard_map.get_methods(fqns, '', visibility: visibility)
473
476
  type = get_namespace_type(fqns)
474
- if type == :class
475
- result.concat inner_get_methods('Class', :instance, [:public], deep, skip)
476
- else
477
- result.concat inner_get_methods('Module', :instance, [:public], deep, skip)
478
- end
477
+ result.concat inner_get_methods('Class', :instance, fqns == '' ? [:public] : visibility, deep, skip) if type == :class
478
+ result.concat inner_get_methods('Module', :instance, fqns == '' ? [:public] : visibility, deep, skip)
479
479
  end
480
480
  end
481
481
  result
@@ -19,7 +19,7 @@ module Solargraph
19
19
  sources.each do |s|
20
20
  s.namespace_pins.each do |pin|
21
21
  next if pin.path.empty?
22
- if pin.kind == Solargraph::Suggestion::CLASS
22
+ if pin.type == :class
23
23
  code_object_map[pin.path] ||= YARD::CodeObjects::ClassObject.new(root_code_object, pin.path)
24
24
  else
25
25
  code_object_map[pin.path] ||= YARD::CodeObjects::ModuleObject.new(root_code_object, pin.path)
@@ -33,7 +33,7 @@ module Solargraph
33
33
 
34
34
  # @return [Hash]
35
35
  def options
36
- @options ||= {}
36
+ @options ||= default_configuration
37
37
  end
38
38
 
39
39
  def cancel id
@@ -54,7 +54,7 @@ module Solargraph
54
54
  # processed, the transport is responsible for sending the response.
55
55
  #
56
56
  # @param request [Hash] The contents of the message.
57
- # @return [Solargraph::LanguageServer::Message] The message handler.
57
+ # @return [Solargraph::LanguageServer::Message::Base] The message handler.
58
58
  def start request
59
59
  if request['method']
60
60
  message = Message.select(request['method']).new(self, request)
@@ -214,10 +214,12 @@ module Solargraph
214
214
  end
215
215
 
216
216
  # Send a request to the client and execute the provided block to process
217
- # the response.
217
+ # the response. If an ID is not provided, the host will use an auto-
218
+ # incrementing integer.
218
219
  #
219
220
  # @param method [String] The message method
220
221
  # @param params [Hash] The method parameters
222
+ # @param id [String] An optional ID
221
223
  # @yieldparam [Hash] The result sent by the client
222
224
  def send_request method, params, &block
223
225
  message = {
@@ -233,6 +235,29 @@ module Solargraph
233
235
  @next_request_id += 1
234
236
  end
235
237
 
238
+ def register_capabilities methods
239
+ send_request 'client/registerCapability', {
240
+ registrations: methods.map { |m|
241
+ {
242
+ id: m,
243
+ method: m,
244
+ registerOptions: dynamic_capability_options[m]
245
+ }
246
+ }
247
+ }
248
+ end
249
+
250
+ def unregister_capabilities methods
251
+ send_request 'client/unregisterCapability', {
252
+ unregisterations: methods.map { |m|
253
+ {
254
+ id: m,
255
+ method: m
256
+ }
257
+ }
258
+ }
259
+ end
260
+
236
261
  # True if the specified file is in the process of changing.
237
262
  #
238
263
  # @return [Boolean]
@@ -343,6 +368,16 @@ module Solargraph
343
368
  requests.keys
344
369
  end
345
370
 
371
+ def default_configuration
372
+ {
373
+ 'completion' => true,
374
+ 'hover' => true,
375
+ 'autoformat' => false,
376
+ 'diagnostics' => false,
377
+ 'formatting' => false
378
+ }
379
+ end
380
+
346
381
  private
347
382
 
348
383
  # @return [Solargraph::Library]
@@ -412,13 +447,13 @@ module Solargraph
412
447
  diagnoser = Diagnostics::Rubocop.new
413
448
  until stopped?
414
449
  sleep 1
415
- if options['diagnostics'] != 'rubocop'
450
+ if !options['diagnostics']
416
451
  @change_semaphore.synchronize { @diagnostics_queue.clear }
417
452
  next
418
453
  end
419
454
  begin
420
- # Diagnosis is broken into two parts to reduce the amount of times it runs while
421
- # a document is changing
455
+ # Diagnosis is broken into two parts to reduce the number of
456
+ # times it runs while a document is changing
422
457
  current = nil
423
458
  already_changing = nil
424
459
  @change_semaphore.synchronize do
@@ -429,13 +464,9 @@ module Solargraph
429
464
  end
430
465
  next if current.nil? or already_changing
431
466
  filename = uri_to_file(current)
432
- # text = library.read_text(filename)
433
- # results = diagnoser.diagnose text, filename
434
- # results.concat library.diagnose(filename)
435
467
  results = library.diagnose(filename)
436
468
  @change_semaphore.synchronize do
437
469
  already_changing = (unsafe_changing?(current) or @diagnostics_queue.include?(current))
438
- # publish_diagnostics current, resp unless already_changing
439
470
  unless already_changing
440
471
  send_notification "textDocument/publishDiagnostics", {
441
472
  uri: current,
@@ -480,6 +511,34 @@ module Solargraph
480
511
  changes
481
512
  )
482
513
  end
514
+
515
+ def dynamic_capability_options
516
+ @dynamic_capability_options ||= {
517
+ # textDocumentSync: 2, # @todo What should this be?
518
+ 'textDocument/completion' => {
519
+ resolveProvider: true,
520
+ triggerCharacters: ['.', ':', '@']
521
+ },
522
+ # hoverProvider: true,
523
+ # definitionProvider: true,
524
+ 'textDocument/signatureHelp' => {
525
+ triggerCharacters: ['(', ',']
526
+ },
527
+ # documentFormattingProvider: true,
528
+ 'textDocument/onTypeFormatting' => {
529
+ firstTriggerCharacter: '{',
530
+ moreTriggerCharacter: ['(']
531
+ },
532
+ # documentSymbolProvider: true,
533
+ # workspaceSymbolProvider: true,
534
+ # workspace: {
535
+ # workspaceFolders: {
536
+ # supported: true,
537
+ # changeNotifications: true
538
+ # }
539
+ # }
540
+ }
541
+ end
483
542
  end
484
543
  end
485
544
  end
@@ -24,14 +24,13 @@ module Solargraph
24
24
  end
25
25
 
26
26
  # @param path [String]
27
- # @return [Solargraph::LanguageServer::Message::Base]
27
+ # @return [Class<Solargraph::LanguageServer::Message::Base>]
28
28
  def select path
29
29
  if method_map.has_key?(path)
30
30
  method_map[path]
31
31
  elsif path.start_with?('$/')
32
32
  MethodNotImplemented
33
33
  else
34
- STDERR.puts "Method not found: #{path}"
35
34
  MethodNotFound
36
35
  end
37
36
  end
@@ -5,23 +5,10 @@ module Solargraph
5
5
  def process
6
6
  host.configure params['initializationOptions']
7
7
  host.prepare params['rootPath']
8
- set_result(
8
+ result = {
9
9
  capabilities: {
10
10
  textDocumentSync: 2, # @todo What should this be?
11
- completionProvider: {
12
- resolveProvider: true,
13
- triggerCharacters: ['.', ':', '@']
14
- },
15
- hoverProvider: true,
16
11
  definitionProvider: true,
17
- signatureHelpProvider: {
18
- triggerCharacters: ['(', ',']
19
- },
20
- documentFormattingProvider: true,
21
- documentOnTypeFormattingProvider: {
22
- firstTriggerCharacter: '{',
23
- moreTriggerCharacter: ['(']
24
- },
25
12
  documentSymbolProvider: true,
26
13
  workspaceSymbolProvider: true,
27
14
  workspace: {
@@ -31,7 +18,88 @@ module Solargraph
31
18
  }
32
19
  }
33
20
  }
34
- )
21
+ }
22
+ result[:capabilities].merge! static_completion unless dynamic_completion?
23
+ result[:capabilities].merge! static_signature_help unless dynamic_signature_help?
24
+ result[:capabilities].merge! static_on_type_formatting unless dynamic_on_type_formatting?
25
+ result[:capabilities].merge! static_hover unless dynamic_hover?
26
+ result[:capabilities].merge! static_document_formatting unless dynamic_document_formatting?
27
+ set_result result
28
+ end
29
+
30
+ private
31
+
32
+ def static_completion
33
+ {
34
+ completionProvider: {
35
+ resolveProvider: true,
36
+ triggerCharacters: ['.', ':', '@']
37
+ }
38
+ }
39
+ end
40
+
41
+ def dynamic_completion?
42
+ params['capabilities'] and
43
+ params['capabilities']['textDocument'] and
44
+ params['capabilities']['textDocument']['completion'] and
45
+ params['capabilities']['textDocument']['completion']['dynamicRegistration']
46
+ end
47
+
48
+ def static_signature_help
49
+ {
50
+ signatureHelpProvider: {
51
+ triggerCharacters: ['(', ',']
52
+ }
53
+ }
54
+ end
55
+
56
+ def dynamic_signature_help?
57
+ params['capabilities'] and
58
+ params['capabilities']['textDocument'] and
59
+ params['capabilities']['textDocument']['signatureHelp'] and
60
+ params['capabilities']['textDocument']['signatureHelp']['dynamicRegistration']
61
+ end
62
+
63
+ def static_on_type_formatting
64
+ {
65
+ documentOnTypeFormattingProvider: {
66
+ firstTriggerCharacter: '{',
67
+ moreTriggerCharacter: ['(']
68
+ }
69
+ }
70
+ end
71
+
72
+ def dynamic_on_type_formatting?
73
+ params['capabilities'] and
74
+ params['capabilities']['textDocument'] and
75
+ params['capabilities']['textDocument']['onTypeFormatting'] and
76
+ params['capabilities']['textDocument']['onTypeFormatting']['dynamicRegistration']
77
+ end
78
+
79
+ def static_hover
80
+ {
81
+ hoverProvider: true
82
+ }
83
+ end
84
+
85
+ def dynamic_hover?
86
+ params['capabilities'] and
87
+ params['capabilities']['textDocument'] and
88
+ params['capabilities']['textDocument']['hover'] and
89
+ params['capabilities']['textDocument']['hover']['dynamicRegistration']
90
+ end
91
+
92
+ def static_document_formatting
93
+ {
94
+ documentFormattingProvider: true
95
+ }
96
+ end
97
+
98
+ def dynamic_document_formatting?
99
+ params['capabilities'] and
100
+ params['capabilities']['textDocument'] and
101
+ params['capabilities']['textDocument']['hover'] and
102
+ params['capabilities']['textDocument']['hover']['dynamicRegistration']
35
103
  end
36
104
  end
37
105
  end
@@ -3,6 +3,13 @@ module Solargraph
3
3
  module Message
4
4
  class Initialized < Base
5
5
  def process
6
+ meths = []
7
+ meths.push 'textDocument/completion' if host.options['completion']
8
+ meths.push 'textDocument/hover' if host.options['hover']
9
+ meths.push 'textDocument/signatureHelp' if host.options['hover']
10
+ meths.push 'textDocument/onTypeFormatting' if host.options['autoformat']
11
+ meths.push 'textDocument/formatting' if host.options['formatting']
12
+ host.register_capabilities meths unless meths.empty?
6
13
  end
7
14
  end
8
15
  end
@@ -7,10 +7,13 @@ module Solargraph
7
7
  class Formatting < Base
8
8
  def process
9
9
  filename = uri_to_file(params['textDocument']['uri'])
10
+ filename = 'tmp.rb' if filename.nil? or filename.empty?
10
11
  original = host.read_text(params['textDocument']['uri'])
11
12
  cmd = "rubocop -a -f fi -s #{Shellwords.escape(filename)}"
12
13
  o, e, s = Open3.capture3(cmd, stdin_data: original)
13
- formatted = o.lines[2..-1].join
14
+ lines = o.lines
15
+ index = lines.index{|l| l.start_with?('====================')}
16
+ formatted = lines[index+1..-1].join
14
17
  set_result(
15
18
  [
16
19
  {
@@ -4,25 +4,26 @@ module Solargraph
4
4
  module TextDocument
5
5
  class OnTypeFormatting < Base
6
6
  def process
7
- src = host.send(:library).checkout(uri_to_file(params['textDocument']['uri']))
8
- fragment = src.fragment_at(params['position']['line'], params['position']['character'] - 1)
9
- offset = fragment.send(:offset)
10
- if fragment.string? and params['ch'] == '{' and src.code[offset-1,2] == '#{'
11
- set_result(
12
- [
13
- {
14
- range: {
15
- start: params['position'],
16
- end: params['position']
17
- },
18
- newText: '}'
19
- }
20
- ]
21
- )
22
- else
23
- # @todo Is `nil` or `[]` more appropriate here?
24
- set_result nil
25
- end
7
+ # @todo Temporarily disabled due to conflicts with VSCode formatting on type
8
+ # src = host.send(:library).checkout(uri_to_file(params['textDocument']['uri']))
9
+ # fragment = src.fragment_at(params['position']['line'], params['position']['character'] - 1)
10
+ # offset = fragment.send(:offset)
11
+ # if fragment.string? and params['ch'] == '{' and src.code[offset - 1, 2] == '#{'
12
+ # set_result(
13
+ # [
14
+ # {
15
+ # range: {
16
+ # start: params['position'],
17
+ # end: params['position']
18
+ # },
19
+ # newText: '}'
20
+ # }
21
+ # ]
22
+ # )
23
+ # else
24
+ # # @todo Is `nil` or `[]` more appropriate here?
25
+ # set_result nil
26
+ # end
26
27
  end
27
28
  end
28
29
  end
@@ -3,7 +3,25 @@ require 'uri'
3
3
  module Solargraph::LanguageServer::Message::Workspace
4
4
  class DidChangeConfiguration < Solargraph::LanguageServer::Message::Base
5
5
  def process
6
- host.configure params['settings']['solargraph']
6
+ update = params['settings']['solargraph']
7
+
8
+ meths = []
9
+ meths.push 'textDocument/completion' if update.has_key?('completion') and update['completion'] and !host.options['completion']
10
+ meths.push 'textDocument/hover' if update.has_key?('hover') and update['hover'] and !host.options['hover']
11
+ meths.push 'textDocument/signatureHelp' if update.has_key?('hover') and update['hover'] and !host.options['hover']
12
+ meths.push 'textDocument/onTypeFormatting' if update.has_key?('autoformat') and update['autoformat'] and !host.options['autoformat']
13
+ meths.push "textDocument/formatting" if update.has_key?('formatting') and update['formatting'] and !host.options['formatting']
14
+ host.register_capabilities meths unless meths.empty?
15
+
16
+ meths = []
17
+ meths.push 'textDocument/completion' if update.has_key?('completion') and !update['completion'] and host.options['completion']
18
+ meths.push 'textDocument/hover' if update.has_key?('hover') and !update['hover'] and host.options['hover']
19
+ meths.push 'textDocument/signatureHelp' if update.has_key?('hover') and !update['hover'] and host.options['hover']
20
+ meths.push 'textDocument/onTypeFormatting' if update.has_key?('autoformat') and !update['autoformat'] and host.options['autoformat']
21
+ meths.push "textDocument/formatting" if update.has_key?('formatting') and !update['formatting'] and host.options['formatting']
22
+ host.unregister_capabilities meths unless meths.empty?
23
+
24
+ host.configure update
7
25
  end
8
26
  end
9
27
  end