solargraph 0.21.0 → 0.22.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 (50) hide show
  1. checksums.yaml +5 -5
  2. data/lib/solargraph/api_map/completion.rb +3 -0
  3. data/lib/solargraph/api_map/probe.rb +21 -45
  4. data/lib/solargraph/api_map/store.rb +6 -2
  5. data/lib/solargraph/api_map/type_methods.rb +40 -0
  6. data/lib/solargraph/api_map.rb +45 -35
  7. data/lib/solargraph/diagnostics/require_not_found.rb +5 -0
  8. data/lib/solargraph/diagnostics/rubocop.rb +9 -0
  9. data/lib/solargraph/diagnostics.rb +5 -0
  10. data/lib/solargraph/language_server/host.rb +9 -1
  11. data/lib/solargraph/language_server/message/base.rb +1 -8
  12. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +5 -1
  13. data/lib/solargraph/language_server/message/extended/download_core.rb +25 -0
  14. data/lib/solargraph/language_server/message/extended.rb +1 -0
  15. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  16. data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
  17. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  18. data/lib/solargraph/language_server/message/text_document/references.rb +14 -0
  19. data/lib/solargraph/language_server/message/text_document/rename.rb +17 -0
  20. data/lib/solargraph/language_server/message/text_document.rb +13 -11
  21. data/lib/solargraph/language_server/message.rb +3 -0
  22. data/lib/solargraph/language_server/request.rb +4 -0
  23. data/lib/solargraph/language_server/transport/socket.rb +4 -4
  24. data/lib/solargraph/language_server/uri_helpers.rb +2 -0
  25. data/lib/solargraph/library.rb +37 -0
  26. data/lib/solargraph/live_map/cache.rb +7 -0
  27. data/lib/solargraph/live_map.rb +8 -2
  28. data/lib/solargraph/pin/attribute.rb +5 -1
  29. data/lib/solargraph/pin/namespace.rb +0 -2
  30. data/lib/solargraph/pin/proxy_method.rb +31 -0
  31. data/lib/solargraph/pin.rb +1 -0
  32. data/lib/solargraph/plugin/process.rb +1 -1
  33. data/lib/solargraph/plugin/runtime.rb +6 -3
  34. data/lib/solargraph/shell.rb +0 -1
  35. data/lib/solargraph/source/flawed_builder.rb +3 -0
  36. data/lib/solargraph/source/fragment.rb +12 -15
  37. data/lib/solargraph/source/location.rb +3 -0
  38. data/lib/solargraph/source/mapper.rb +60 -18
  39. data/lib/solargraph/source/node_methods.rb +111 -0
  40. data/lib/solargraph/source/position.rb +18 -0
  41. data/lib/solargraph/source/range.rb +5 -1
  42. data/lib/solargraph/source.rb +31 -1
  43. data/lib/solargraph/version.rb +1 -1
  44. data/lib/solargraph/workspace/config.rb +6 -2
  45. data/lib/solargraph/workspace.rb +7 -1
  46. data/lib/solargraph/yard_map/core_docs.rb +1 -1
  47. data/lib/solargraph/yard_map.rb +43 -5
  48. data/lib/solargraph.rb +0 -1
  49. metadata +27 -8
  50. data/lib/solargraph/node_methods.rb +0 -101
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 04dd49e264774d545fbdf1a7f52d0b7227ff3f11
4
- data.tar.gz: cb617a8800b2eec8688c46fc89cf4ee79445dd50
2
+ SHA256:
3
+ metadata.gz: c647321bb57cb5ba859e1762032855324aa967e78a562c0e259508e5c24c22ee
4
+ data.tar.gz: 057c1a4298f9c4574c0773425cce496216ab60e22165871487d6d77e13733745
5
5
  SHA512:
6
- metadata.gz: db20a5e3053060171bf9077c1ce572de8428193b4d562c7d939c9a7003074de64f41ffe879100b7f7a31bb42f625a32e69ad7755afc68b8c31d2cc64d15be353
7
- data.tar.gz: bb9a311819e91501145c05fc2045178a791933fb6f9598e6265f68efe301664cbb6bfa50170928989d1fd8543a726cd36e0079b2f650c2ded36f9ad3a66c92c6
6
+ metadata.gz: ae8cb69f92e2f3ad78959bd8767b78dda5a7d4baa861fa59680be191b7c92944f0df15ff12ccad2ed4a93231afcc55db53bd40cf9b42473387491f4d168f1cef
7
+ data.tar.gz: 8d02f2a10b1a71579a0b48e9dae4268689cc0ec642c137b1adedf6fc99749ae5a1b04f46b4d9b30448d3316a71b65dfdf79b5066c0af499e2181fcc5a107201f
@@ -1,5 +1,8 @@
1
1
  module Solargraph
2
2
  class ApiMap
3
+ # The result of a completion request containing the pins that describe
4
+ # completion options and the range to be replaced.
5
+ #
3
6
  class Completion
4
7
  # @return [Array<Solargraph::Pin::Base>]
5
8
  attr_reader :pins
@@ -1,12 +1,7 @@
1
1
  module Solargraph
2
2
  class ApiMap
3
3
  class Probe
4
- class VirtualPin
5
- attr_reader :return_type
6
- def initialize return_type
7
- @return_type = return_type
8
- end
9
- end
4
+ include TypeMethods
10
5
 
11
6
  # @return [Solargraph::ApiMap]
12
7
  attr_reader :api_map
@@ -24,8 +19,8 @@ module Solargraph
24
19
  return infer_word_pins(base, context_pin, locals) if rest.nil?
25
20
  pins = infer_word_pins(base, context_pin, locals).map do |pin|
26
21
  next pin unless pin.return_type.nil?
27
- type = resolve_pin_type(pin)
28
- VirtualPin.new(type)
22
+ type = resolve_pin_type(pin, locals - [pin])
23
+ Pin::ProxyMethod.new(type)
29
24
  end
30
25
  return [] if pins.empty?
31
26
  rest = rest.split('.')
@@ -53,7 +48,7 @@ module Solargraph
53
48
  def infer_signature_type signature, context_pin, locals
54
49
  pins = infer_signature_pins(signature, context_pin, locals)
55
50
  pins.each do |pin|
56
- type = resolve_pin_type(pin)
51
+ type = resolve_pin_type(pin, locals - [pin])
57
52
  return qualify(type, pin.named_context) unless type.nil?
58
53
  end
59
54
  nil
@@ -70,15 +65,25 @@ module Solargraph
70
65
  namespace, scope = extract_namespace_and_scope_from_pin(context_pin)
71
66
  return api_map.pins.select{|pin| word_matches_context?(word, namespace, scope, pin)} if variable_name?(word)
72
67
  result = []
73
- result.concat api_map.get_path_suggestions(word)
68
+ cparts = namespace.split('::')
69
+ until cparts.empty?
70
+ break unless result.empty?
71
+ cur = cparts.join('::')
72
+ result.concat api_map.get_path_suggestions("#{cur}::#{word}")
73
+ cparts.pop
74
+ end
75
+ result.concat api_map.get_path_suggestions(word) if result.empty?
74
76
  result.concat api_map.get_methods(namespace, scope: scope, visibility: [:public, :private, :protected]).select{|pin| pin.name == word} unless word.include?('::')
75
- result.concat api_map.get_constants('', namespace).select{|pin| pin.name == word}
77
+ result.concat api_map.get_constants('', namespace).select{|pin| pin.name == word} if result.empty?
76
78
  result
77
79
  end
78
80
 
79
81
  # Method name search is external by default
82
+ # @param method_name [String]
83
+ # @param context_pin [Solargraph::Pin::Base]
80
84
  def infer_method_name_pins method_name, context_pin, internal = false
81
- namespace, scope = extract_namespace_and_scope(context_pin.return_type)
85
+ relname, scope = extract_namespace_and_scope(context_pin.return_type)
86
+ namespace = api_map.qualify(relname, context_pin.namespace)
82
87
  visibility = [:public]
83
88
  visibility.push :protected, :private if internal
84
89
  result = api_map.get_methods(namespace, scope: scope, visibility: visibility).select{|pin| pin.name == method_name}
@@ -110,35 +115,6 @@ module Solargraph
110
115
  type.sub(/<#{rns}>/, "<#{res}>")
111
116
  end
112
117
 
113
- # Extract a namespace from a type.
114
- #
115
- # @example
116
- # extract_namespace('String') => 'String'
117
- # extract_namespace('Class<String>') => 'String'
118
- #
119
- # @return [String]
120
- def extract_namespace type
121
- extract_namespace_and_scope(type)[0]
122
- end
123
-
124
- # Extract a namespace and a scope (:instance or :class) from a type.
125
- #
126
- # @example
127
- # extract_namespace('String') #=> ['String', :instance]
128
- # extract_namespace('Class<String>') #=> ['String', :class]
129
- # extract_namespace('Module<Enumerable') #=> ['Enumberable', :class]
130
- #
131
- # @return [Array] The namespace (String) and scope (Symbol).
132
- def extract_namespace_and_scope type
133
- scope = :instance
134
- result = type.to_s.gsub(/<.*$/, '')
135
- if (result == 'Class' or result == 'Module') and type.include?('<')
136
- result = type.match(/<([a-z0-9:_]*)/i)[1]
137
- scope = :class
138
- end
139
- [result, scope]
140
- end
141
-
142
118
  # Extract a namespace and a scope from a pin. For now, the pin must
143
119
  # be either a namespace, a method, or a block.
144
120
  #
@@ -172,11 +148,11 @@ module Solargraph
172
148
  pin
173
149
  end
174
150
 
175
- def resolve_pin_type pin
151
+ def resolve_pin_type pin, locals
176
152
  pin.return_type
177
153
  return pin.return_type unless pin.return_type.nil?
178
154
  return resolve_block_parameter(pin) if pin.kind == Pin::BLOCK_PARAMETER
179
- return resolve_variable(pin) if pin.variable?
155
+ return resolve_variable(pin, locals) if pin.variable?
180
156
  nil
181
157
  end
182
158
 
@@ -205,10 +181,10 @@ module Solargraph
205
181
  nil
206
182
  end
207
183
 
208
- def resolve_variable(pin)
184
+ def resolve_variable(pin, locals)
209
185
  return nil if pin.nil_assignment?
210
186
  # @todo Do we need the locals here?
211
- return infer_signature_type(pin.signature, pin.context, [])
187
+ return infer_signature_type(pin.signature, pin.context, locals)
212
188
  end
213
189
 
214
190
  def get_subtypes type
@@ -43,8 +43,8 @@ module Solargraph
43
43
  }
44
44
  end
45
45
 
46
- def get_attrs fqns
47
- namespace_pins(fqns).select{ |pin| pin.kind == Pin::ATTRIBUTE }
46
+ def get_attrs fqns, scope
47
+ namespace_pins(fqns).select{ |pin| pin.kind == Pin::ATTRIBUTE and pin.scope == scope }
48
48
  end
49
49
 
50
50
  def get_superclass fqns
@@ -80,6 +80,10 @@ module Solargraph
80
80
  namespace_pins(fqns).select{|pin| pin.kind == Pin::INSTANCE_VARIABLE and pin.scope == scope}
81
81
  end
82
82
 
83
+ def get_class_variables(fqns)
84
+ namespace_pins(fqns).select{|pin| pin.kind == Pin::CLASS_VARIABLE}
85
+ end
86
+
83
87
  def get_symbols
84
88
  symbols.uniq(&:name)
85
89
  end
@@ -0,0 +1,40 @@
1
+ module Solargraph
2
+ class ApiMap
3
+ # Module functions for processing YARD types.
4
+ #
5
+ module TypeMethods
6
+ module_function
7
+
8
+ # Extract a namespace from a type.
9
+ #
10
+ # @example
11
+ # extract_namespace('String') => 'String'
12
+ # extract_namespace('Class<String>') => 'String'
13
+ #
14
+ # @param type [String]
15
+ # @return [String]
16
+ def extract_namespace type
17
+ extract_namespace_and_scope(type)[0]
18
+ end
19
+
20
+ # Extract a namespace and a scope (:instance or :class) from a type.
21
+ #
22
+ # @example
23
+ # extract_namespace('String') #=> ['String', :instance]
24
+ # extract_namespace('Class<String>') #=> ['String', :class]
25
+ # extract_namespace('Module<Enumerable') #=> ['Enumberable', :class]
26
+ #
27
+ # @param type [String]
28
+ # @return [Array] The namespace (String) and scope (Symbol).
29
+ def extract_namespace_and_scope type
30
+ scope = :instance
31
+ result = type.to_s.gsub(/<.*$/, '')
32
+ if (result == 'Class' or result == 'Module') and type.include?('<')
33
+ result = type.match(/<([a-z0-9:_]*)/i)[1]
34
+ scope = :class
35
+ end
36
+ [result, scope]
37
+ end
38
+ end
39
+ end
40
+ end
@@ -9,15 +9,25 @@ module Solargraph
9
9
  autoload :Completion, 'solargraph/api_map/completion'
10
10
  autoload :Probe, 'solargraph/api_map/probe'
11
11
  autoload :Store, 'solargraph/api_map/store'
12
+ autoload :TypeMethods, 'solargraph/api_map/type_methods'
12
13
 
13
14
  include Solargraph::ApiMap::SourceToYard
14
15
  include CoreFills
16
+ include TypeMethods
15
17
 
16
18
  # The workspace to analyze and process.
17
19
  #
18
20
  # @return [Solargraph::Workspace]
19
21
  attr_reader :workspace
20
22
 
23
+ # @return [ApiMap::Store]
24
+ attr_reader :store
25
+
26
+ # Get a LiveMap associated with the current workspace.
27
+ #
28
+ # @return [Solargraph::LiveMap]
29
+ attr_reader :live_map
30
+
21
31
  # @param workspace [Solargraph::Workspace]
22
32
  def initialize workspace = Solargraph::Workspace.new(nil)
23
33
  @workspace = workspace
@@ -26,7 +36,7 @@ module Solargraph
26
36
  @yard_stale = true
27
37
  # process_maps
28
38
  @sources = workspace.sources
29
- yard_map
39
+ refresh_store_and_maps
30
40
  end
31
41
 
32
42
  # Create an ApiMap with a workspace in the specified directory.
@@ -36,11 +46,6 @@ module Solargraph
36
46
  self.new(Solargraph::Workspace.new(directory))
37
47
  end
38
48
 
39
- # @return [ApiMap::Store]
40
- def store
41
- @store ||= ApiMap::Store.new(@sources)
42
- end
43
-
44
49
  def pins
45
50
  store.pins
46
51
  end
@@ -66,19 +71,12 @@ module Solargraph
66
71
  # @return [Solargraph::YardMap]
67
72
  def yard_map
68
73
  # refresh
69
- if @yard_map.nil? || @yard_map.required.to_set != required.to_set
74
+ if @yard_map.required.to_set != required.to_set
70
75
  @yard_map = Solargraph::YardMap.new(required: required, workspace: workspace)
71
76
  end
72
77
  @yard_map
73
78
  end
74
79
 
75
- # Get a LiveMap associated with the current workspace.
76
- #
77
- # @return [Solargraph::LiveMap]
78
- def live_map
79
- @live_map ||= Solargraph::LiveMap.new(self)
80
- end
81
-
82
80
  # Declare a virtual source that will be included in the map regardless of
83
81
  # whether it's in the workspace.
84
82
  #
@@ -229,7 +227,7 @@ module Solargraph
229
227
  # @param namespace [String] A fully qualified namespace
230
228
  # @return [Array<Solargraph::Pin::ClassVariable>]
231
229
  def get_class_variable_pins(namespace)
232
- prefer_non_nil_variables(@cvar_pins[namespace] || [])
230
+ prefer_non_nil_variables(store.get_class_variables(namespace))
233
231
  end
234
232
 
235
233
  # @return [Array<Solargraph::Pin::Base>]
@@ -260,6 +258,11 @@ module Solargraph
260
258
  else
261
259
  result.concat inner_get_methods(fqns, scope, visibility, deep, skip)
262
260
  end
261
+ live = live_map.get_methods(fqns, '', scope.to_s, visibility.include?(:private))
262
+ unless live.empty?
263
+ exist = result.map(&:name)
264
+ result.concat live.reject{|p| exist.include?(p.name)}
265
+ end
263
266
  result
264
267
  end
265
268
 
@@ -293,7 +296,7 @@ module Solargraph
293
296
  if fragment.base.empty?
294
297
  result.concat get_methods(pin.path)
295
298
  else
296
- type = probe.infer_signature_type(fragment.base, pin, fragment.locals)
299
+ type = probe.infer_signature_type("#{pin.path}.new.#{fragment.base}", pin, fragment.locals)
297
300
  unless type.nil?
298
301
  namespace, scope = extract_namespace_and_scope(type)
299
302
  result.concat get_methods(namespace, scope: scope)
@@ -310,7 +313,8 @@ module Solargraph
310
313
  end
311
314
  end
312
315
  end
313
- filtered = result.uniq(&:identifier).select{|s| s.kind != Pin::METHOD or s.name.match(/^[a-z0-9_]*(\!|\?|=)?$/i)}.sort_by.with_index{ |x, idx| [x.name, idx] }
316
+ frag_start = fragment.word.to_s.downcase
317
+ filtered = result.uniq(&:identifier).select{|s| s.name.downcase.start_with?(frag_start) and (s.kind != Pin::METHOD or s.name.match(/^[a-z0-9_]*(\!|\?|=)?$/i))}.sort_by.with_index{ |x, idx| [x.name, idx] }
314
318
  Completion.new(filtered, fragment.whole_word_range)
315
319
  end
316
320
 
@@ -318,7 +322,11 @@ module Solargraph
318
322
  # @return [Array<Solargraph::Pin::Base>]
319
323
  def define fragment
320
324
  return [] if fragment.string? or fragment.comment?
321
- probe.infer_signature_pins fragment.whole_signature, fragment.named_path, fragment.locals
325
+ if fragment.base_literal?
326
+ probe.infer_signature_pins fragment.whole_signature, Pin::ProxyMethod.new(fragment.base_literal), fragment.locals
327
+ else
328
+ probe.infer_signature_pins fragment.whole_signature, fragment.named_path, fragment.locals
329
+ end
322
330
  end
323
331
 
324
332
  # Infer a return type from a fragment. This method will attempt to resolve
@@ -342,9 +350,13 @@ module Solargraph
342
350
  def signify fragment
343
351
  return [] unless fragment.argument?
344
352
  return [] if fragment.recipient.whole_signature.nil? or fragment.recipient.whole_signature.empty?
345
- probe.infer_signature_pins(
346
- fragment.recipient.whole_signature, fragment.named_path, fragment.locals
347
- ).select{ |pin| pin.kind == Pin::METHOD }
353
+ result = []
354
+ if fragment.recipient.base_literal?
355
+ result.concat probe.infer_signature_pins(fragment.recipient.whole_signature, Pin::ProxyMethod.new(fragment.recipient.base_literal), fragment.locals)
356
+ else
357
+ result.concat probe.infer_signature_pins(fragment.recipient.whole_signature, fragment.named_path, fragment.locals)
358
+ end
359
+ result.select{ |pin| pin.kind == Pin::METHOD }
348
360
  end
349
361
 
350
362
  # Get an array of all suggestions that match the specified path.
@@ -356,6 +368,10 @@ module Solargraph
356
368
  result = []
357
369
  result.concat store.get_path_pins(path)
358
370
  result.concat yard_map.objects(path)
371
+ if result.empty?
372
+ lp = live_map.get_path_pin(path)
373
+ result.push lp unless lp.nil?
374
+ end
359
375
  result
360
376
  end
361
377
 
@@ -423,6 +439,12 @@ module Solargraph
423
439
 
424
440
  private
425
441
 
442
+ def refresh_store_and_maps
443
+ @store = ApiMap::Store.new(@sources)
444
+ @live_map = Solargraph::LiveMap.new(self)
445
+ @yard_map = Solargraph::YardMap.new(required: required, workspace: workspace)
446
+ end
447
+
426
448
  def process_virtual
427
449
  unless @virtual_source.nil?
428
450
  map_source @virtual_source
@@ -448,9 +470,7 @@ module Solargraph
448
470
  return [] if skip.include?(reqstr)
449
471
  skip.push reqstr
450
472
  result = []
451
- if scope == :instance
452
- result.concat store.get_attrs(fqns)
453
- end
473
+ result.concat store.get_attrs(fqns, scope)
454
474
  result.concat store.get_methods(fqns, scope: scope, visibility: visibility)
455
475
  if deep
456
476
  sc = store.get_superclass(fqns)
@@ -475,7 +495,7 @@ module Solargraph
475
495
  result.concat yard_map.get_methods(fqns, '', visibility: visibility)
476
496
  type = get_namespace_type(fqns)
477
497
  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)
498
+ result.concat inner_get_methods('Module', :instance, fqns == '' ? [:public] : visibility, deep, skip) if type == :module
479
499
  end
480
500
  end
481
501
  result
@@ -568,15 +588,5 @@ module Solargraph
568
588
  return yard_map.get_namespace_type(fqns) if pin.nil?
569
589
  pin.type
570
590
  end
571
-
572
- def extract_namespace_and_scope type
573
- scope = :instance
574
- result = type.to_s.gsub(/<.*$/, '')
575
- if (result == 'Class' or result == 'Module') and type.include?('<')
576
- result = type.match(/<([a-z0-9:_]*)/i)[1]
577
- scope = :class
578
- end
579
- [result, scope]
580
- end
581
591
  end
582
592
  end
@@ -1,5 +1,10 @@
1
1
  module Solargraph
2
2
  module Diagnostics
3
+ # RequireNotFound reports required paths that could not be resolved to
4
+ # either a file in the workspace or a gem.
5
+ #
6
+ # @todo Some stdlib paths can result in false positives.
7
+ #
3
8
  class RequireNotFound < Base
4
9
  def diagnose source, api_map
5
10
  result = []
@@ -3,6 +3,8 @@ require 'shellwords'
3
3
 
4
4
  module Solargraph
5
5
  module Diagnostics
6
+ # This reporter provides linting through RuboCop.
7
+ #
6
8
  class Rubocop < Base
7
9
  # The rubocop command
8
10
  #
@@ -13,6 +15,8 @@ module Solargraph
13
15
  @command = command
14
16
  end
15
17
 
18
+ # @param source [Solargraph::Source]
19
+ # @param api_map [Solargraph::ApiMap]
16
20
  # @return [Array<Hash>]
17
21
  def diagnose source, api_map
18
22
  begin
@@ -20,7 +24,12 @@ module Solargraph
20
24
  filename = source.filename
21
25
  raise DiagnosticsError, 'No command specified' if command.nil? or command.empty?
22
26
  cmd = "#{Shellwords.escape(command)} -f j -s #{Shellwords.escape(filename)}"
27
+ unless api_map.workspace.nil? or api_map.workspace.directory.nil?
28
+ rc = File.join(api_map.workspace.directory, '.rubocop.yml')
29
+ cmd += " -c #{Shellwords.escape(rc)}" if File.file?(rc)
30
+ end
23
31
  o, e, s = Open3.capture3(cmd, stdin_data: text)
32
+ STDERR.puts e unless e.empty?
24
33
  raise DiagnosticsError, "Command '#{command}' is not available (gem exception)" if e.include?('Gem::Exception')
25
34
  raise DiagnosticsError, "RuboCop returned empty data" if o.empty?
26
35
  make_array JSON.parse(o)
@@ -1,10 +1,15 @@
1
1
  module Solargraph
2
+ # The Diagnostics library provides reporters for analyzing problems in code
3
+ # and providing the results to language server clients.
4
+ #
2
5
  module Diagnostics
3
6
  autoload :Base, 'solargraph/diagnostics/base'
4
7
  autoload :Severities, 'solargraph/diagnostics/severities'
5
8
  autoload :Rubocop, 'solargraph/diagnostics/rubocop'
6
9
  autoload :RequireNotFound, 'solargraph/diagnostics/require_not_found'
7
10
 
11
+ # Reporters identified by name for activation in .solargraph.yml files.
12
+ #
8
13
  REPORTERS = {
9
14
  'rubocop' => Rubocop,
10
15
  'require_not_found' => RequireNotFound
@@ -323,6 +323,14 @@ module Solargraph
323
323
  result
324
324
  end
325
325
 
326
+ def references_from filename, line, column
327
+ result = nil
328
+ @change_semaphore.synchronize do
329
+ result = library.references_from(filename, line, column)
330
+ end
331
+ result
332
+ end
333
+
326
334
  def query_symbols query
327
335
  result = nil
328
336
  @change_semaphore.synchronize { result = library.query_symbols(query) }
@@ -446,7 +454,7 @@ module Solargraph
446
454
  Thread.new do
447
455
  diagnoser = Diagnostics::Rubocop.new
448
456
  until stopped?
449
- sleep 1
457
+ sleep 0.1
450
458
  if !options['diagnostics']
451
459
  @change_semaphore.synchronize { @diagnostics_queue.clear }
452
460
  next
@@ -37,14 +37,7 @@ module Solargraph
37
37
  }
38
38
  end
39
39
 
40
- def response
41
- response = {}
42
- response[:result] = result
43
- response[:error] = error unless error.nil?
44
- response
45
- end
46
-
47
- def send
40
+ def send_response
48
41
  unless id.nil? or host.cancel?(id)
49
42
  response = {
50
43
  jsonrpc: "2.0",
@@ -11,7 +11,7 @@ module Solargraph
11
11
  class CheckGemVersion < Base
12
12
  def process
13
13
  o, s = Open3.capture2("gem search solargraph")
14
- match = o.match(/solargraph \([0-9\.]*?\)/)
14
+ match = o.match(/solargraph \(([\d]*\.[\d]*\.[\d]*)\)/)
15
15
  # @todo Error if no match or status code != 0
16
16
  available = Gem::Version.new(match[1])
17
17
  current = Gem::Version.new(Solargraph::VERSION)
@@ -30,6 +30,10 @@ module Solargraph
30
30
  elsif params['verbose']
31
31
  host.show_message "The Solargraph gem is up to date (version #{Solargraph::VERSION})."
32
32
  end
33
+ set_result({
34
+ installed: current,
35
+ available: available
36
+ })
33
37
  end
34
38
  end
35
39
  end
@@ -0,0 +1,25 @@
1
+ require 'open3'
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ module Message
6
+ module Extended
7
+ # Update core Ruby documentation.
8
+ #
9
+ class DownloadCore < Base
10
+ def process
11
+ cmd = "solargraph download-core"
12
+ o, s = Open3.capture2(cmd)
13
+ if s != 0
14
+ host.show_message "An error occurred while downloading documentation.", LanguageServer::MessageTypes::ERROR
15
+ else
16
+ ver = o.match(/[\d]*\.[\d]*\.[\d]*/)[0]
17
+ host.show_message "Downloaded documentation for Ruby #{ver}.", LanguageServer::MessageTypes::INFO
18
+ # @todo YardMap should be refreshed
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -11,6 +11,7 @@ module Solargraph
11
11
  autoload :Search, 'solargraph/language_server/message/extended/search'
12
12
  autoload :CheckGemVersion, 'solargraph/language_server/message/extended/check_gem_version'
13
13
  autoload :DocumentGems, 'solargraph/language_server/message/extended/document_gems'
14
+ autoload :DownloadCore, 'solargraph/language_server/message/extended/download_core'
14
15
  end
15
16
  end
16
17
  end
@@ -11,12 +11,14 @@ module Solargraph
11
11
  definitionProvider: true,
12
12
  documentSymbolProvider: true,
13
13
  workspaceSymbolProvider: true,
14
+ renameProvider: true,
14
15
  workspace: {
15
16
  workspaceFolders: {
16
17
  supported: true,
17
18
  changeNotifications: true
18
19
  }
19
- }
20
+ },
21
+ referencesProvider: true
20
22
  }
21
23
  }
22
24
  result[:capabilities].merge! static_completion unless dynamic_completion?
@@ -11,7 +11,7 @@ module Solargraph::LanguageServer::Message::TextDocument
11
11
  line = params['position']['line']
12
12
  col = params['position']['character']
13
13
  suggestions = host.definitions_at(filename, line, col)
14
- locations = suggestions.map do |pin|
14
+ locations = suggestions.reject{|pin| pin.location.nil?}.map do |pin|
15
15
  unless pin.location.nil?
16
16
  {
17
17
  uri: file_to_uri(pin.location.filename),
@@ -38,6 +38,6 @@ module Solargraph::LanguageServer::Message::TextDocument
38
38
  def link_documentation path
39
39
  uri = "solargraph:/document?query=" + URI.encode(path)
40
40
  "[#{path}](#{uri})"
41
- end
41
+ end
42
42
  end
43
43
  end
@@ -0,0 +1,14 @@
1
+ module Solargraph::LanguageServer::Message::TextDocument
2
+ class References < Base
3
+ def process
4
+ locs = host.references_from(uri_to_file(params['textDocument']['uri']), params['position']['line'], params['position']['character'])
5
+ result = locs.map do |loc|
6
+ {
7
+ uri: file_to_uri(loc.filename),
8
+ range: loc.range.to_hash
9
+ }
10
+ end
11
+ set_result result
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ module Solargraph::LanguageServer::Message::TextDocument
2
+ class Rename < Base
3
+ def process
4
+ locs = host.references_from(uri_to_file(params['textDocument']['uri']), params['position']['line'], params['position']['character'])
5
+ changes = {}
6
+ locs.each do |loc|
7
+ uri = file_to_uri(loc.filename)
8
+ changes[uri] ||= []
9
+ changes[uri].push({
10
+ range: loc.range.to_hash,
11
+ newText: params['newName']
12
+ })
13
+ end
14
+ set_result changes: changes
15
+ end
16
+ end
17
+ end
@@ -2,19 +2,21 @@ module Solargraph
2
2
  module LanguageServer
3
3
  module Message
4
4
  module TextDocument
5
- autoload :Base, 'solargraph/language_server/message/text_document/base'
6
- autoload :Completion, 'solargraph/language_server/message/text_document/completion'
7
- autoload :DidOpen, 'solargraph/language_server/message/text_document/did_open'
8
- autoload :DidChange, 'solargraph/language_server/message/text_document/did_change'
9
- autoload :DidClose, 'solargraph/language_server/message/text_document/did_close'
10
- autoload :DidSave, 'solargraph/language_server/message/text_document/did_save'
11
- autoload :Hover, 'solargraph/language_server/message/text_document/hover'
12
- autoload :SignatureHelp, 'solargraph/language_server/message/text_document/signature_help'
5
+ autoload :Base, 'solargraph/language_server/message/text_document/base'
6
+ autoload :Completion, 'solargraph/language_server/message/text_document/completion'
7
+ autoload :DidOpen, 'solargraph/language_server/message/text_document/did_open'
8
+ autoload :DidChange, 'solargraph/language_server/message/text_document/did_change'
9
+ autoload :DidClose, 'solargraph/language_server/message/text_document/did_close'
10
+ autoload :DidSave, 'solargraph/language_server/message/text_document/did_save'
11
+ autoload :Hover, 'solargraph/language_server/message/text_document/hover'
12
+ autoload :SignatureHelp, 'solargraph/language_server/message/text_document/signature_help'
13
13
  autoload :DiagnosticsQueue, 'solargraph/language_server/message/text_document/diagnostics_queue'
14
14
  autoload :OnTypeFormatting, 'solargraph/language_server/message/text_document/on_type_formatting'
15
- autoload :Definition, 'solargraph/language_server/message/text_document/definition'
16
- autoload :DocumentSymbol, 'solargraph/language_server/message/text_document/document_symbol'
17
- autoload :Formatting, 'solargraph/language_server/message/text_document/formatting'
15
+ autoload :Definition, 'solargraph/language_server/message/text_document/definition'
16
+ autoload :DocumentSymbol, 'solargraph/language_server/message/text_document/document_symbol'
17
+ autoload :Formatting, 'solargraph/language_server/message/text_document/formatting'
18
+ autoload :References, 'solargraph/language_server/message/text_document/references'
19
+ autoload :Rename, 'solargraph/language_server/message/text_document/rename'
18
20
  end
19
21
  end
20
22
  end