solargraph 0.53.0 → 0.54.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/lib/solargraph/api_map/cache.rb +2 -12
  4. data/lib/solargraph/api_map/source_to_yard.rb +17 -10
  5. data/lib/solargraph/api_map/store.rb +11 -6
  6. data/lib/solargraph/api_map.rb +80 -38
  7. data/lib/solargraph/bench.rb +1 -0
  8. data/lib/solargraph/complex_type/type_methods.rb +62 -30
  9. data/lib/solargraph/complex_type/unique_type.rb +149 -75
  10. data/lib/solargraph/complex_type.rb +41 -25
  11. data/lib/solargraph/doc_map.rb +65 -24
  12. data/lib/solargraph/gem_pins.rb +10 -2
  13. data/lib/solargraph/language_server/host/dispatch.rb +13 -2
  14. data/lib/solargraph/language_server/host/sources.rb +1 -61
  15. data/lib/solargraph/language_server/host.rb +41 -69
  16. data/lib/solargraph/language_server/message/base.rb +1 -1
  17. data/lib/solargraph/language_server/message/initialize.rb +14 -0
  18. data/lib/solargraph/language_server/message/text_document/formatting.rb +1 -0
  19. data/lib/solargraph/language_server/progress.rb +118 -0
  20. data/lib/solargraph/language_server.rb +1 -0
  21. data/lib/solargraph/library.rb +149 -97
  22. data/lib/solargraph/page.rb +6 -0
  23. data/lib/solargraph/parser/node_processor/base.rb +3 -2
  24. data/lib/solargraph/parser/node_processor.rb +1 -0
  25. data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -7
  26. data/lib/solargraph/parser/parser_gem/node_methods.rb +0 -4
  27. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -19
  28. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +47 -0
  29. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +5 -3
  30. data/lib/solargraph/parser/parser_gem/node_processors.rb +2 -0
  31. data/lib/solargraph/pin/base_variable.rb +35 -6
  32. data/lib/solargraph/pin/block.rb +70 -32
  33. data/lib/solargraph/pin/delegated_method.rb +5 -1
  34. data/lib/solargraph/pin/documenting.rb +2 -0
  35. data/lib/solargraph/pin/method.rb +4 -2
  36. data/lib/solargraph/pin/parameter.rb +5 -28
  37. data/lib/solargraph/rbs_map/conversions.rb +16 -47
  38. data/lib/solargraph/rbs_map/core_fills.rb +12 -6
  39. data/lib/solargraph/rbs_map/core_map.rb +2 -13
  40. data/lib/solargraph/rbs_map.rb +17 -7
  41. data/lib/solargraph/shell.rb +18 -13
  42. data/lib/solargraph/source/chain.rb +20 -0
  43. data/lib/solargraph/source/updater.rb +1 -0
  44. data/lib/solargraph/source.rb +0 -44
  45. data/lib/solargraph/source_map/clip.rb +3 -2
  46. data/lib/solargraph/source_map/mapper.rb +3 -2
  47. data/lib/solargraph/source_map.rb +8 -6
  48. data/lib/solargraph/type_checker.rb +58 -13
  49. data/lib/solargraph/version.rb +1 -1
  50. data/lib/solargraph/workspace/config.rb +2 -1
  51. data/lib/solargraph/workspace.rb +27 -1
  52. data/lib/solargraph/yard_map/mapper/to_method.rb +5 -2
  53. metadata +4 -4
  54. data/lib/solargraph/language_server/host/cataloger.rb +0 -57
  55. data/lib/solargraph/rbs_map/core_signs.rb +0 -35
@@ -11,54 +11,10 @@ module Solargraph
11
11
  include Observable
12
12
  include UriHelpers
13
13
 
14
- def initialize
15
- @mutex = Mutex.new
16
- @stopped = true
17
- @has_uri = ConditionVariable.new
18
- end
19
-
20
- def stopped?
21
- @stopped
22
- end
23
-
24
- # @return [void]
25
- def start
26
- return unless @stopped
27
- @stopped = false
28
- Thread.new do
29
- tick until stopped?
30
- end
31
- end
32
-
33
- # @return [void]
34
- def tick
35
- uri = mutex.synchronize { next_uri }
36
-
37
- return if queue.include?(uri)
38
- mutex.synchronize do
39
- nxt = open_source_hash[uri].finish_synchronize
40
- open_source_hash[uri] = nxt
41
- changed
42
- notify_observers uri
43
- end
44
- end
45
-
46
14
  # @param uri [String]
47
15
  # @return [void]
48
16
  def add_uri(uri)
49
17
  queue.push(uri)
50
- @has_uri.signal
51
- end
52
-
53
- # @return [String]
54
- def next_uri
55
- @has_uri.wait(mutex) if queue.empty?
56
- queue.shift
57
- end
58
-
59
- # @return [void]
60
- def stop
61
- @stopped = true
62
18
  end
63
19
 
64
20
  # Open a source.
@@ -89,20 +45,7 @@ module Solargraph
89
45
  # @return [void]
90
46
  def update uri, updater
91
47
  src = find(uri)
92
- mutex.synchronize { open_source_hash[uri] = src.synchronize(updater) }
93
- changed
94
- notify_observers uri
95
- end
96
-
97
- # @param uri [String]
98
- # @param updater [Source::Updater]
99
- # @return [void]
100
- def async_update uri, updater
101
- src = find(uri)
102
- mutex.synchronize do
103
- open_source_hash[uri] = src.start_synchronize(updater)
104
- add_uri(uri)
105
- end
48
+ open_source_hash[uri] = src.synchronize(updater)
106
49
  changed
107
50
  notify_observers uri
108
51
  end
@@ -144,9 +87,6 @@ module Solargraph
144
87
  @open_source_hash ||= {}
145
88
  end
146
89
 
147
- # @return [Mutex]
148
- attr_reader :mutex
149
-
150
90
  # An array of source URIs that are waiting to finish synchronizing.
151
91
  #
152
92
  # @return [::Array<String>]
@@ -12,7 +12,6 @@ module Solargraph
12
12
  #
13
13
  class Host
14
14
  autoload :Diagnoser, 'solargraph/language_server/host/diagnoser'
15
- autoload :Cataloger, 'solargraph/language_server/host/cataloger'
16
15
  autoload :Sources, 'solargraph/language_server/host/sources'
17
16
  autoload :Dispatch, 'solargraph/language_server/host/dispatch'
18
17
  autoload :MessageWorker, 'solargraph/language_server/host/message_worker'
@@ -43,8 +42,6 @@ module Solargraph
43
42
  return unless stopped?
44
43
  @stopped = false
45
44
  diagnoser.start
46
- cataloger.start
47
- sources.start
48
45
  message_worker.start
49
46
  end
50
47
 
@@ -155,6 +152,7 @@ module Solargraph
155
152
  def delete *uris
156
153
  filenames = uris.map { |uri| uri_to_file(uri) }
157
154
  libraries.each do |lib|
155
+ lib.delete_observer self
158
156
  lib.delete(*filenames)
159
157
  end
160
158
  uris.each do |uri|
@@ -253,7 +251,7 @@ module Solargraph
253
251
  # @return [void]
254
252
  def change params
255
253
  updater = generate_updater(params)
256
- sources.async_update params['textDocument']['uri'], updater
254
+ sources.update params['textDocument']['uri'], updater
257
255
  diagnoser.schedule params['textDocument']['uri']
258
256
  end
259
257
 
@@ -292,9 +290,11 @@ module Solargraph
292
290
  path = ''
293
291
  path = normalize_separators(directory) unless directory.nil?
294
292
  begin
295
- lib = Solargraph::Library.load(path, name)
293
+ workspace = Solargraph::Workspace.new(path, nil, options)
294
+ lib = Solargraph::Library.new(workspace, name)
295
+ lib.add_observer self
296
296
  libraries.push lib
297
- async_library_map lib
297
+ library_map lib
298
298
  rescue WorkspaceTooLargeError => e
299
299
  send_notification 'window/showMessage', {
300
300
  'type' => Solargraph::LanguageServer::MessageTypes::WARNING,
@@ -323,6 +323,7 @@ module Solargraph
323
323
  # @param lib [Library]
324
324
  libraries.delete_if do |lib|
325
325
  next false if lib.workspace.directory != directory
326
+ lib.delete_observer self
326
327
  true
327
328
  end
328
329
  end
@@ -457,9 +458,7 @@ module Solargraph
457
458
  return if @stopped
458
459
  @stopped = true
459
460
  message_worker.stop
460
- cataloger.stop
461
461
  diagnoser.stop
462
- sources.stop
463
462
  changed
464
463
  notify_observers
465
464
  end
@@ -492,6 +491,24 @@ module Solargraph
492
491
  end
493
492
  if params['data']['path']
494
493
  result.concat library.path_pins(params['data']['path'])
494
+ # @todo This exception is necessary because `Library#path_pins` does
495
+ # not perform a namespace method query, so the implicit `.new` pin
496
+ # might not exist.
497
+ if result.empty? && params['data']['path'] =~ /\.new$/
498
+ result.concat(library.path_pins(params['data']['path'].sub(/\.new$/, '#initialize')).map do |pin|
499
+ next pin unless pin.name == 'initialize'
500
+
501
+ Pin::Method.new(
502
+ name: 'new',
503
+ scope: :class,
504
+ location: pin.location,
505
+ parameters: pin.parameters,
506
+ return_type: ComplexType.try_parse(params['data']['path']),
507
+ comments: pin.comments,
508
+ closure: pin.closure
509
+ )
510
+ end)
511
+ end
495
512
  end
496
513
  # Selecting by both location and path can result in duplicate pins
497
514
  result.uniq { |p| [p.path, p.location] }
@@ -665,11 +682,15 @@ module Solargraph
665
682
  libraries.each(&:catalog)
666
683
  end
667
684
 
668
- # @return [Hash{String => BasicObject}]
685
+ # @return [Hash{String => Hash{String => Boolean}}]
669
686
  def client_capabilities
670
687
  @client_capabilities ||= {}
671
688
  end
672
689
 
690
+ def client_supports_progress?
691
+ client_capabilities['window'] && client_capabilities['window']['workDoneProgress']
692
+ end
693
+
673
694
  private
674
695
 
675
696
  # @return [MessageWorker]
@@ -682,11 +703,6 @@ module Solargraph
682
703
  @diagnoser ||= Diagnoser.new(self)
683
704
  end
684
705
 
685
- # @return [Cataloger]
686
- def cataloger
687
- @cataloger ||= Cataloger.new(self)
688
- end
689
-
690
706
  # A hash of client requests by ID. The host uses this to keep track of
691
707
  # pending responses.
692
708
  #
@@ -816,72 +832,28 @@ module Solargraph
816
832
  client_capabilities['rename'] && client_capabilities['rename']['prepareSupport']
817
833
  end
818
834
 
819
- def client_supports_progress?
820
- client_capabilities['window'] && client_capabilities['window']['workDoneProgress']
821
- end
822
-
823
835
  # @param library [Library]
824
836
  # @return [void]
825
- def async_library_map library
837
+ def library_map library
826
838
  return if library.mapped?
827
- Thread.new do
828
- if client_supports_progress?
829
- uuid = SecureRandom.uuid
830
- send_request 'window/workDoneProgress/create', {
831
- token: uuid
832
- } do |response|
833
- do_async_library_map library, response.nil? ? uuid : nil
834
- end
835
- else
836
- do_async_library_map library
837
- end
838
- end
839
+ Thread.new { sync_library_map library }
839
840
  end
840
841
 
841
842
  # @param library [Library]
842
843
  # @param uuid [String, nil]
843
844
  # @return [void]
844
- def do_async_library_map library, uuid = nil
845
+ def sync_library_map library
845
846
  total = library.workspace.sources.length
846
- if uuid
847
- send_notification '$/progress', {
848
- token: uuid,
849
- value: {
850
- kind: 'begin',
851
- title: "Mapping workspace",
852
- message: "0/#{total} files",
853
- cancellable: false,
854
- percentage: 0
855
- }
856
- }
857
- end
858
- pct = 0
859
- mod = 10
847
+ progress = Progress.new('Mapping workspace')
848
+ progress.begin "0/#{total} files", 0
849
+ progress.send self
860
850
  while library.next_map
861
- next unless uuid
862
- cur = ((library.source_map_hash.keys.length.to_f / total.to_f) * 100).to_i
863
- if cur > pct && cur % mod == 0
864
- pct = cur
865
- send_notification '$/progress', {
866
- token: uuid,
867
- value: {
868
- kind: 'report',
869
- cancellable: false,
870
- message: "#{library.source_map_hash.keys.length}/#{total} files",
871
- percentage: pct
872
- }
873
- }
874
- end
875
- end
876
- if uuid
877
- send_notification '$/progress', {
878
- token: uuid,
879
- value: {
880
- kind: 'end',
881
- message: 'Mapping complete'
882
- }
883
- }
851
+ pct = ((library.source_map_hash.keys.length.to_f / total) * 100).to_i
852
+ progress.report "#{library.source_map_hash.keys.length}/#{total} files", pct
853
+ progress.send self
884
854
  end
855
+ progress.finish 'done'
856
+ progress.send self
885
857
  end
886
858
  end
887
859
  end
@@ -16,7 +16,7 @@ module Solargraph
16
16
  # @return [String]
17
17
  attr_reader :method
18
18
 
19
- # @return [Hash]
19
+ # @return [Hash{String => Array, Hash, String, Integer}]
20
20
  attr_reader :params
21
21
 
22
22
  # @return [Hash, Array, nil]
@@ -47,6 +47,8 @@ module Solargraph
47
47
 
48
48
  private
49
49
 
50
+ # @todo '?' methods should type like RBS 'boolish' rather than a strict true or false
51
+ # @sg-ignore
50
52
  def support_workspace_folders?
51
53
  params['capabilities'] &&
52
54
  params['capabilities']['workspace'] &&
@@ -82,6 +84,7 @@ module Solargraph
82
84
  }
83
85
  end
84
86
 
87
+ # @return [Hash{Symbol => Hash{Symbol => String, Array<String>}}]
85
88
  def static_on_type_formatting
86
89
  {
87
90
  documentOnTypeFormattingProvider: {
@@ -91,6 +94,7 @@ module Solargraph
91
94
  }
92
95
  end
93
96
 
97
+ # @return [Hash{Symbol => Boolean}]
94
98
  def static_hover
95
99
  return {} unless host.options['hover']
96
100
  {
@@ -98,6 +102,7 @@ module Solargraph
98
102
  }
99
103
  end
100
104
 
105
+ # @return [Hash{Symbol => Boolean}]
101
106
  def static_document_formatting
102
107
  return {} unless host.options['formatting']
103
108
  {
@@ -105,6 +110,7 @@ module Solargraph
105
110
  }
106
111
  end
107
112
 
113
+ # @return [Hash{Symbol => Boolean}]
108
114
  def static_document_symbols
109
115
  return {} unless host.options['symbols']
110
116
  {
@@ -112,12 +118,14 @@ module Solargraph
112
118
  }
113
119
  end
114
120
 
121
+ # @return [Hash{Symbol => Boolean}]
115
122
  def static_workspace_symbols
116
123
  {
117
124
  workspaceSymbolProvider: true
118
125
  }
119
126
  end
120
127
 
128
+ # @return [Hash{Symbol => Boolean}]
121
129
  def static_definitions
122
130
  return {} unless host.options['definitions']
123
131
  {
@@ -125,6 +133,7 @@ module Solargraph
125
133
  }
126
134
  end
127
135
 
136
+ # @return [Hash{Symbol => Boolean}]
128
137
  def static_type_definitions
129
138
  return {} unless host.options['typeDefinitions']
130
139
  {
@@ -132,12 +141,15 @@ module Solargraph
132
141
  }
133
142
  end
134
143
 
144
+ # @return [Hash{Symbol => Hash{Symbol => Boolean}}]
135
145
  def static_rename
136
146
  {
137
147
  renameProvider: {prepareProvider: true}
138
148
  }
139
149
  end
140
150
 
151
+
152
+ # @return [Hash{Symbol => Boolean}]
141
153
  def static_references
142
154
  return {} unless host.options['references']
143
155
  {
@@ -145,6 +157,7 @@ module Solargraph
145
157
  }
146
158
  end
147
159
 
160
+ # @return [Hash{Symbol => Boolean}]
148
161
  def static_folding_range
149
162
  return {} unless host.options['folding']
150
163
  {
@@ -152,6 +165,7 @@ module Solargraph
152
165
  }
153
166
  end
154
167
 
168
+ # @return [Hash{Symbol => Boolean}]
155
169
  def static_highlights
156
170
  {
157
171
  documentHighlightProvider: true
@@ -70,6 +70,7 @@ module Solargraph
70
70
 
71
71
  def formatter_class(config)
72
72
  if self.class.const_defined?('BlankRubocopFormatter')
73
+ # @sg-ignore
73
74
  BlankRubocopFormatter
74
75
  else
75
76
  require_rubocop(config['version'])
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Solargraph
6
+ module LanguageServer
7
+ # Progress notification handling for language server hosts.
8
+ #
9
+ class Progress
10
+ WAITING = :waiting
11
+ CREATED = :created
12
+ FINISHED = :finished
13
+
14
+ # @return [String]
15
+ attr_reader :uuid
16
+
17
+ # @return [String]
18
+ attr_reader :title
19
+
20
+ # @return [String, nil]
21
+ attr_reader :kind
22
+
23
+ # @return [String, nil]
24
+ attr_reader :message
25
+
26
+ # @return [Integer]
27
+ attr_reader :percentage
28
+
29
+ # @return [Symbol]
30
+ attr_reader :status
31
+
32
+ # @param title [String]
33
+ def initialize title
34
+ @title = title
35
+ @uuid = SecureRandom.uuid
36
+ @percentage = 0
37
+ @status = WAITING
38
+ end
39
+
40
+ # @param message [String]
41
+ # @param percentage [Integer]
42
+ def begin message, percentage
43
+ @kind = 'begin'
44
+ @message = message
45
+ @percentage = percentage
46
+ end
47
+
48
+ # @param message [String]
49
+ # @param percentage [Integer]
50
+ def report message, percentage
51
+ @kind = 'report'
52
+ @message = message
53
+ @percentage = percentage
54
+ end
55
+
56
+ # @param message [String]
57
+ def finish message
58
+ @kind = 'end'
59
+ @message = message
60
+ @percentage = 100
61
+ true
62
+ end
63
+
64
+ # @param host [Solargraph::LanguageServer::Host]
65
+ def send host
66
+ return unless host.client_supports_progress? && !finished?
67
+
68
+ message = build
69
+
70
+ create(host) unless created?
71
+ host.send_notification '$/progress', message
72
+ @status = FINISHED if kind == 'end'
73
+ end
74
+
75
+ def created?
76
+ [CREATED, FINISHED].include?(status)
77
+ end
78
+
79
+ def finished?
80
+ status == FINISHED
81
+ end
82
+
83
+ private
84
+
85
+ # @param host [Solargraph::LanguageServer::Host]
86
+ # @return [void]
87
+ def create host
88
+ return if created?
89
+
90
+ host.send_request 'window/workDoneProgress/create', { token: uuid }
91
+ @status = CREATED
92
+ end
93
+
94
+ def build
95
+ {
96
+ token: uuid,
97
+ value: {
98
+ kind: kind,
99
+ cancellable: false
100
+ }.merge(build_value)
101
+ }
102
+ end
103
+
104
+ def build_value
105
+ case kind
106
+ when 'begin'
107
+ { title: title, message: message, percentage: percentage }
108
+ when 'report'
109
+ { message: message, percentage: percentage }
110
+ when 'end'
111
+ { message: message }
112
+ else
113
+ raise "Invalid progress kind #{kind}"
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -15,5 +15,6 @@ module Solargraph
15
15
  autoload :MessageTypes, 'solargraph/language_server/message_types'
16
16
  autoload :Request, 'solargraph/language_server/request'
17
17
  autoload :Transport, 'solargraph/language_server/transport'
18
+ autoload :Progress, 'solargraph/language_server/progress'
18
19
  end
19
20
  end