solargraph 0.17.4 → 0.18.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +16 -12
  3. data/lib/solargraph/api_map.rb +516 -588
  4. data/lib/solargraph/api_map/completion.rb +16 -0
  5. data/lib/solargraph/api_map/source_to_yard.rb +2 -2
  6. data/lib/solargraph/language_server.rb +12 -0
  7. data/lib/solargraph/language_server/completion_item_kinds.rb +31 -0
  8. data/lib/solargraph/language_server/error_codes.rb +16 -0
  9. data/lib/solargraph/language_server/host.rb +305 -0
  10. data/lib/solargraph/language_server/message.rb +70 -0
  11. data/lib/solargraph/language_server/message/base.rb +64 -0
  12. data/lib/solargraph/language_server/message/cancel_request.rb +11 -0
  13. data/lib/solargraph/language_server/message/client.rb +5 -0
  14. data/lib/solargraph/language_server/message/client/register_capability.rb +13 -0
  15. data/lib/solargraph/language_server/message/completion_item.rb +9 -0
  16. data/lib/solargraph/language_server/message/completion_item/resolve.rb +23 -0
  17. data/lib/solargraph/language_server/message/exit_notification.rb +12 -0
  18. data/lib/solargraph/language_server/message/extended.rb +15 -0
  19. data/lib/solargraph/language_server/message/extended/document.rb +18 -0
  20. data/lib/solargraph/language_server/message/extended/search.rb +18 -0
  21. data/lib/solargraph/language_server/message/initialize.rb +39 -0
  22. data/lib/solargraph/language_server/message/initialized.rb +10 -0
  23. data/lib/solargraph/language_server/message/method_not_found.rb +14 -0
  24. data/lib/solargraph/language_server/message/method_not_implemented.rb +12 -0
  25. data/lib/solargraph/language_server/message/shutdown.rb +11 -0
  26. data/lib/solargraph/language_server/message/text_document.rb +21 -0
  27. data/lib/solargraph/language_server/message/text_document/base.rb +17 -0
  28. data/lib/solargraph/language_server/message/text_document/completion.rb +69 -0
  29. data/lib/solargraph/language_server/message/text_document/definition.rb +38 -0
  30. data/lib/solargraph/language_server/message/text_document/did_change.rb +15 -0
  31. data/lib/solargraph/language_server/message/text_document/did_close.rb +12 -0
  32. data/lib/solargraph/language_server/message/text_document/did_open.rb +13 -0
  33. data/lib/solargraph/language_server/message/text_document/did_save.rb +15 -0
  34. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +31 -0
  35. data/lib/solargraph/language_server/message/text_document/formatting.rb +36 -0
  36. data/lib/solargraph/language_server/message/text_document/hover.rb +19 -0
  37. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +29 -0
  38. data/lib/solargraph/language_server/message/text_document/signature_help.rb +23 -0
  39. data/lib/solargraph/language_server/message/workspace.rb +11 -0
  40. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +9 -0
  41. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +30 -0
  42. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +31 -0
  43. data/lib/solargraph/language_server/symbol_kinds.rb +32 -0
  44. data/lib/solargraph/language_server/transport.rb +7 -0
  45. data/lib/solargraph/language_server/transport/socket.rb +66 -0
  46. data/lib/solargraph/language_server/uri_helpers.rb +21 -0
  47. data/lib/solargraph/library.rb +225 -0
  48. data/lib/solargraph/live_map.rb +1 -1
  49. data/lib/solargraph/page.rb +61 -0
  50. data/lib/solargraph/pin.rb +7 -0
  51. data/lib/solargraph/pin/attribute.rb +9 -0
  52. data/lib/solargraph/pin/base.rb +76 -6
  53. data/lib/solargraph/pin/base_variable.rb +29 -7
  54. data/lib/solargraph/pin/block_parameter.rb +53 -0
  55. data/lib/solargraph/pin/constant.rb +6 -2
  56. data/lib/solargraph/pin/conversions.rb +65 -0
  57. data/lib/solargraph/pin/directed/attribute.rb +4 -0
  58. data/lib/solargraph/pin/directed/method.rb +6 -1
  59. data/lib/solargraph/pin/helper.rb +35 -0
  60. data/lib/solargraph/pin/keyword.rb +22 -0
  61. data/lib/solargraph/pin/local_variable.rb +0 -1
  62. data/lib/solargraph/pin/method.rb +55 -2
  63. data/lib/solargraph/pin/method_parameter.rb +19 -0
  64. data/lib/solargraph/pin/namespace.rb +7 -2
  65. data/lib/solargraph/pin/parameter.rb +23 -0
  66. data/lib/solargraph/pin/plugin/method.rb +3 -2
  67. data/lib/solargraph/pin/yard_object.rb +101 -0
  68. data/lib/solargraph/server.rb +82 -135
  69. data/lib/solargraph/shell.rb +20 -1
  70. data/lib/solargraph/source.rb +709 -0
  71. data/lib/solargraph/source/flawed_builder.rb +10 -0
  72. data/lib/solargraph/source/fragment.rb +319 -0
  73. data/lib/solargraph/source/position.rb +26 -0
  74. data/lib/solargraph/source/range.rb +39 -0
  75. data/lib/solargraph/suggestion.rb +29 -4
  76. data/lib/solargraph/version.rb +1 -1
  77. data/lib/solargraph/workspace.rb +105 -0
  78. data/lib/solargraph/{api_map → workspace}/config.rb +1 -1
  79. data/lib/solargraph/yard_map.rb +59 -37
  80. metadata +168 -5
  81. data/lib/solargraph/api_map/source.rb +0 -470
  82. data/lib/solargraph/code_map.rb +0 -868
@@ -0,0 +1,16 @@
1
+ module Solargraph
2
+ class ApiMap
3
+ class Completion
4
+ # @return [Array<Solargraph::Pin::Base>]
5
+ attr_reader :pins
6
+
7
+ # @return [Solargraph::Source::Range]
8
+ attr_reader :range
9
+
10
+ def initialize pins, range
11
+ @pins = pins
12
+ @range = range
13
+ end
14
+ end
15
+ end
16
+ end
@@ -13,7 +13,7 @@ module Solargraph
13
13
  code_object_map.keys
14
14
  end
15
15
 
16
- # @param sources [Array<Solargraph::ApiMap::Source>] Sources for code objects
16
+ # @param sources [Array<Solargraph::Source>] Sources for code objects
17
17
  def rake_yard sources
18
18
  code_object_map.clear
19
19
  sources.each do |s|
@@ -28,7 +28,7 @@ module Solargraph
28
28
  end
29
29
  s.namespace_includes.each_pair do |n, i|
30
30
  i.each do |inc|
31
- code_object_map[n].instance_mixins.push code_object_map[inc] unless code_object_map[inc].nil?
31
+ code_object_map[n].instance_mixins.push code_object_map[inc] unless code_object_map[inc].nil? or code_object_map[n].nil?
32
32
  end
33
33
  end
34
34
  s.attribute_pins.each do |pin|
@@ -0,0 +1,12 @@
1
+ require 'solargraph/language_server/error_codes'
2
+ require 'solargraph/language_server/completion_item_kinds'
3
+ require 'solargraph/language_server/symbol_kinds'
4
+
5
+ module Solargraph
6
+ module LanguageServer
7
+ autoload :Host, 'solargraph/language_server/host'
8
+ autoload :Message, 'solargraph/language_server/message'
9
+ autoload :Transport, 'solargraph/language_server/transport'
10
+ autoload :UriHelpers, 'solargraph/language_server/uri_helpers'
11
+ end
12
+ end
@@ -0,0 +1,31 @@
1
+ module Solargraph
2
+ module LanguageServer
3
+ module CompletionItemKinds
4
+ TEXT = 1
5
+ METHOD = 2
6
+ FUNCTION = 3
7
+ CONSTRUCTOR = 4
8
+ FIELD = 5
9
+ VARIABLE = 6
10
+ CLASS = 7
11
+ INTERFACE = 8
12
+ MODULE = 9
13
+ PROPERTY = 10
14
+ UNIT = 11
15
+ VALUE = 12
16
+ ENUM = 13
17
+ KEYWORD = 14
18
+ SNIPPET = 15
19
+ COLOR = 16
20
+ FILE = 17
21
+ REFERENCE = 18
22
+ FOLDER = 19
23
+ ENUM_MEMBER = 20
24
+ CONSTANT = 21
25
+ STRUCT = 22
26
+ EVENT = 23
27
+ OPERATOR = 24
28
+ TYPE_PARAMETER = 25
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,16 @@
1
+ module Solargraph
2
+ module LanguageServer
3
+ module ErrorCodes
4
+ PARSE_ERROR = -32700
5
+ INVALID_REQUEST = -32600
6
+ METHOD_NOT_FOUND = -32601
7
+ INVALID_PARAMS = -32602
8
+ INTERNAL_ERROR = -32603
9
+ SERVER_ERROR_START = -32099
10
+ SERVER_ERROR_END = -32000
11
+ SERVER_NOT_INITIALIZED = -32002
12
+ UNKNOWN_ERROR_CODE = -32001
13
+ REQUEST_CANCELLED = -32800
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,305 @@
1
+ require 'open3'
2
+ require 'shellwords'
3
+ # require 'rubocop'
4
+ require 'thread'
5
+ require 'set'
6
+
7
+ module Solargraph
8
+ module LanguageServer
9
+ # The language server protocol's data provider. Hosts are responsible for
10
+ # querying the library and processing messages.
11
+ #
12
+ class Host
13
+ include Solargraph::LanguageServer::UriHelpers
14
+
15
+ # @return [Solargraph::Library]
16
+ attr_reader :library
17
+
18
+ def initialize
19
+ @change_semaphore = Mutex.new
20
+ @buffer_semaphore = Mutex.new
21
+ @change_queue = []
22
+ @diagnostics_queue = []
23
+ @cancel = []
24
+ @buffer = ''
25
+ @stopped = false
26
+ @library = nil # @todo How to initialize the library
27
+ start_change_thread
28
+ start_diagnostics_thread
29
+ end
30
+
31
+ # @param update [Hash]
32
+ def configure update
33
+ options.merge! update
34
+ end
35
+
36
+ # @return [Hash]
37
+ def options
38
+ @options ||= {}
39
+ end
40
+
41
+ def cancel id
42
+ @cancel.push id
43
+ end
44
+
45
+ def cancel? id
46
+ @cancel.include? id
47
+ end
48
+
49
+ def clear id
50
+ @cancel.delete id
51
+ end
52
+
53
+ def start request
54
+ message = Message.select(request['method']).new(self, request)
55
+ begin
56
+ message.process
57
+ rescue Exception => e
58
+ STDERR.puts e.message
59
+ STDERR.puts e.backtrace
60
+ message.set_error Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, e.message
61
+ end
62
+ message
63
+ end
64
+
65
+ def create uri
66
+ filename = uri_to_file(uri)
67
+ library.create filename, File.read(filename)
68
+ end
69
+
70
+ def delete uri
71
+ filename = uri_to_file(uri)
72
+ library.delete filename
73
+ end
74
+
75
+ def open uri, text, version
76
+ library.open uri_to_file(uri), text, version
77
+ @change_semaphore.synchronize { @diagnostics_queue.push uri }
78
+ end
79
+
80
+ def change params
81
+ @change_semaphore.synchronize do
82
+ if changing? params['textDocument']['uri']
83
+ @change_queue.push params
84
+ else
85
+ source = library.checkout(uri_to_file(params['textDocument']['uri']))
86
+ @change_queue.push params
87
+ if params['textDocument']['version'] == source.version + params['contentChanges'].length
88
+ source.synchronize(params['contentChanges'], params['textDocument']['version'])
89
+ library.refresh
90
+ @change_queue.pop
91
+ @diagnostics_queue.push params['textDocument']['uri']
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ def queue message
98
+ @buffer_semaphore.synchronize do
99
+ @buffer += message
100
+ end
101
+ end
102
+
103
+ def flush
104
+ tmp = nil
105
+ @buffer_semaphore.synchronize do
106
+ tmp = @buffer.clone
107
+ @buffer.clear
108
+ end
109
+ tmp
110
+ end
111
+
112
+ # @param directory [String]
113
+ def prepare directory
114
+ path = nil
115
+ path = normalize_separators(directory) unless directory.nil?
116
+ @change_semaphore.synchronize do
117
+ @library = Solargraph::Library.load(path)
118
+ end
119
+ end
120
+
121
+ def send_notification method, params
122
+ response = {
123
+ jsonrpc: "2.0",
124
+ method: method,
125
+ params: params
126
+ }
127
+ json = response.to_json
128
+ envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
129
+ queue envelope
130
+ end
131
+
132
+ def changing? file_uri
133
+ @change_queue.any?{|change| change['textDocument']['uri'] == file_uri}
134
+ end
135
+
136
+ def stop
137
+ @stopped = true
138
+ end
139
+
140
+ def stopped?
141
+ @stopped
142
+ end
143
+
144
+ def synchronize &block
145
+ @change_semaphore.synchronize do
146
+ block.call
147
+ end
148
+ end
149
+
150
+ def locate_pin params
151
+ pin = nil
152
+ @change_semaphore.synchronize do
153
+ pin = library.locate_pin(params['data']['location']) unless params['data']['location'].nil?
154
+ # @todo Improve pin location
155
+ if pin.nil? or pin.path != params['data']['path']
156
+ pin = library.path_pins(params['data']['path']).first
157
+ end
158
+ end
159
+ pin
160
+ end
161
+
162
+ def read_text uri
163
+ filename = uri_to_file(uri)
164
+ library.read_text(filename)
165
+ end
166
+
167
+ private
168
+
169
+ def start_change_thread
170
+ Thread.new do
171
+ until stopped?
172
+ @change_semaphore.synchronize do
173
+ begin
174
+ changed = false
175
+ @change_queue.delete_if do |change|
176
+ filename = uri_to_file(change['textDocument']['uri'])
177
+ source = library.checkout(filename)
178
+ if change['textDocument']['version'] == source.version + change['contentChanges'].length
179
+ source.synchronize(change['contentChanges'], change['textDocument']['version'])
180
+ @diagnostics_queue.push change['textDocument']['uri']
181
+ changed = true
182
+ true
183
+ elsif change['textDocument']['version'] == source.version + 1 #and change['contentChanges'].length == 0
184
+ # HACK: This condition fixes the fact that formatting
185
+ # increments the version by one regardless of the number
186
+ # of changes
187
+ source.synchronize(change['contentChanges'], change['textDocument']['version'])
188
+ @diagnostics_queue.push change['textDocument']['uri']
189
+ true
190
+ elsif change['textDocument']['version'] <= source.version
191
+ # @todo Is deleting outdated changes correct behavior?
192
+ STDERR.puts "Deleting stale change"
193
+ @diagnostics_queue.push change['textDocument']['uri']
194
+ changed = true
195
+ true
196
+ else
197
+ # @todo Change is out of order. Save it for later
198
+ STDERR.puts "Kept in queue: #{change['textDocument']['uri']} from #{source.version} to #{change['textDocument']['version']}"
199
+ false
200
+ end
201
+ end
202
+ STDERR.puts "#{@change_queue.length} pending" unless @change_queue.empty?
203
+ library.refresh if changed
204
+ rescue Exception => e
205
+ STDERR.puts e.message
206
+ end
207
+ end
208
+ sleep 0.1
209
+ end
210
+ end
211
+ end
212
+
213
+ def start_diagnostics_thread
214
+ Thread.new do
215
+ until stopped?
216
+ if options['diagnostics'] != 'rubocop'
217
+ @change_semaphore.synchronize { @diagnostics_queue.clear }
218
+ sleep 1
219
+ next
220
+ end
221
+ unless @change_semaphore.locked?
222
+ begin
223
+ current = nil
224
+ @change_semaphore.synchronize do
225
+ current = @diagnostics_queue.shift
226
+ end
227
+ unless current.nil?
228
+ already_changing = false
229
+ @change_semaphore.synchronize { already_changing = (changing?(current) or @diagnostics_queue.include?(current)) }
230
+ unless already_changing
231
+ resp = read_diagnostics(current)
232
+ @change_semaphore.synchronize { already_changing = (changing?(current) or @diagnostics_queue.include?(current)) }
233
+ publish_diagnostics current, resp unless already_changing
234
+ end
235
+ end
236
+ rescue Exception => e
237
+ STDERR.puts e.message
238
+ end
239
+ end
240
+ sleep 0.1
241
+ end
242
+ end
243
+ end
244
+
245
+ def normalize_separators path
246
+ return path if File::ALT_SEPARATOR.nil?
247
+ path.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
248
+ end
249
+
250
+ def read_diagnostics uri
251
+ begin
252
+ filename = nil
253
+ text = nil
254
+ @change_semaphore.synchronize do
255
+ filename = uri_to_file(uri)
256
+ text = library.read_text(filename)
257
+ end
258
+ cmd = "rubocop -f j -s #{Shellwords.escape(filename)}"
259
+ o, e, s = Open3.capture3(cmd, stdin_data: text)
260
+ JSON.parse(o)
261
+ rescue Exception => e
262
+ STDERR.puts "#{e}"
263
+ STDERR.puts "#{e.backtrace}"
264
+ nil
265
+ end
266
+ end
267
+
268
+ def publish_diagnostics uri, resp
269
+ severities = {
270
+ 'refactor' => 4,
271
+ 'convention' => 3,
272
+ 'warning' => 2,
273
+ 'error' => 1,
274
+ 'fatal' => 1
275
+ }
276
+ diagnostics = []
277
+ resp['files'].each do |file|
278
+ file['offenses'].each do |off|
279
+ diag = {
280
+ range: {
281
+ start: {
282
+ line: off['location']['start_line'] - 1,
283
+ character: off['location']['start_column'] - 1
284
+ },
285
+ end: {
286
+ line: off['location']['last_line'] - 1,
287
+ character: off['location']['last_column']
288
+ }
289
+ },
290
+ # 1 = Error, 2 = Warning, 3 = Information, 4 = Hint
291
+ severity: severities[off['severity']],
292
+ source: off['cop_name'],
293
+ message: off['message'].gsub(/^#{off['cop_name']}\:/, '')
294
+ }
295
+ diagnostics.push diag
296
+ end
297
+ end
298
+ send_notification "textDocument/publishDiagnostics", {
299
+ uri: uri,
300
+ diagnostics: diagnostics
301
+ }
302
+ end
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,70 @@
1
+ require 'solargraph'
2
+ require 'uri'
3
+ require 'thread'
4
+
5
+ module Solargraph
6
+ module LanguageServer
7
+ module Message
8
+ autoload :Base, 'solargraph/language_server/message/base'
9
+ autoload :Initialize, 'solargraph/language_server/message/initialize'
10
+ autoload :Initialized, 'solargraph/language_server/message/initialized'
11
+ autoload :TextDocument, 'solargraph/language_server/message/text_document'
12
+ autoload :CompletionItem, 'solargraph/language_server/message/completion_item'
13
+ autoload :CancelRequest, 'solargraph/language_server/message/cancel_request'
14
+ autoload :MethodNotFound, 'solargraph/language_server/message/method_not_found'
15
+ autoload :MethodNotImplemented, 'solargraph/language_server/message/method_not_implemented'
16
+ autoload :Extended, 'solargraph/language_server/message/extended'
17
+ autoload :Shutdown, 'solargraph/language_server/message/shutdown'
18
+ autoload :ExitNotification, 'solargraph/language_server/message/exit_notification'
19
+ autoload :Workspace, 'solargraph/language_server/message/workspace'
20
+
21
+ class << self
22
+ def register path, message_class
23
+ method_map[path] = message_class
24
+ end
25
+
26
+ # @param path [String]
27
+ # @return [Solargraph::LanguageServer::Message::Base]
28
+ def select path
29
+ if method_map.has_key?(path)
30
+ method_map[path]
31
+ elsif path.start_with?('$/')
32
+ MethodNotImplemented
33
+ else
34
+ STDERR.puts "Method not found: #{path}"
35
+ MethodNotFound
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def method_map
42
+ @method_map ||= {}
43
+ end
44
+ end
45
+
46
+ register 'initialize', Initialize
47
+ register 'initialized', Initialized
48
+ register 'textDocument/completion', TextDocument::Completion
49
+ register 'completionItem/resolve', CompletionItem::Resolve
50
+ register 'textDocument/signatureHelp', TextDocument::SignatureHelp
51
+ register 'textDocument/didOpen', TextDocument::DidOpen
52
+ register 'textDocument/didChange', TextDocument::DidChange
53
+ register 'textDocument/didSave', TextDocument::DidSave
54
+ register 'textDocument/didClose', TextDocument::DidClose
55
+ register 'textDocument/hover', TextDocument::Hover
56
+ register 'textDocument/definition', TextDocument::Definition
57
+ register 'textDocument/formatting', TextDocument::Formatting
58
+ register 'textDocument/onTypeFormatting', TextDocument::OnTypeFormatting
59
+ register 'textDocument/documentSymbol', TextDocument::DocumentSymbol
60
+ register 'workspace/didChangeWatchedFiles', Workspace::DidChangeWatchedFiles
61
+ register 'workspace/didChangeConfiguration', Workspace::DidChangeConfiguration
62
+ register 'workspace/symbol', Workspace::WorkspaceSymbol
63
+ register '$/cancelRequest', CancelRequest
64
+ register '$/solargraph/document', Extended::Document
65
+ register '$/solargraph/search', Extended::Search
66
+ register 'shutdown', Shutdown
67
+ register 'exit', ExitNotification
68
+ end
69
+ end
70
+ end