solargraph 0.19.1 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +1 -0
  3. data/lib/solargraph/api_map.rb +29 -4
  4. data/lib/solargraph/api_map/probe.rb +3 -3
  5. data/lib/solargraph/diagnostics.rb +8 -0
  6. data/lib/solargraph/diagnostics/base.rb +12 -0
  7. data/lib/solargraph/diagnostics/require_not_found.rb +23 -0
  8. data/lib/solargraph/diagnostics/rubocop.rb +17 -6
  9. data/lib/solargraph/diagnostics/severities.rb +13 -0
  10. data/lib/solargraph/language_server.rb +5 -4
  11. data/lib/solargraph/language_server/host.rb +113 -19
  12. data/lib/solargraph/language_server/message.rb +2 -0
  13. data/lib/solargraph/language_server/message/base.rb +1 -1
  14. data/lib/solargraph/language_server/message/extended.rb +2 -0
  15. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +38 -0
  16. data/lib/solargraph/language_server/message/extended/document_gems.rb +23 -0
  17. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +6 -7
  18. data/lib/solargraph/language_server/request.rb +14 -0
  19. data/lib/solargraph/library.rb +37 -3
  20. data/lib/solargraph/page.rb +12 -13
  21. data/lib/solargraph/pin/helper.rb +9 -3
  22. data/lib/solargraph/pin/localized.rb +9 -2
  23. data/lib/solargraph/pin/yard_object.rb +2 -3
  24. data/lib/solargraph/shell.rb +6 -0
  25. data/lib/solargraph/source.rb +5 -2
  26. data/lib/solargraph/source/fragment.rb +8 -0
  27. data/lib/solargraph/source/mapper.rb +6 -11
  28. data/lib/solargraph/version.rb +1 -1
  29. data/lib/solargraph/workspace.rb +33 -0
  30. data/lib/solargraph/workspace/config.rb +12 -0
  31. data/lib/solargraph/yard_map.rb +27 -87
  32. data/lib/yard-solargraph.rb +1 -0
  33. metadata +11 -11
@@ -63,6 +63,8 @@ module Solargraph
63
63
  register '$/cancelRequest', CancelRequest
64
64
  register '$/solargraph/document', Extended::Document
65
65
  register '$/solargraph/search', Extended::Search
66
+ register '$/solargraph/checkGemVersion', Extended::CheckGemVersion
67
+ register '$/solargraph/documentGems', Extended::DocumentGems
66
68
  register 'shutdown', Shutdown
67
69
  register 'exit', ExitNotification
68
70
  end
@@ -16,7 +16,7 @@ module Solargraph
16
16
  @id = request['id'].freeze
17
17
  @request = request.freeze
18
18
  @method = request['method'].freeze
19
- @params = request['params'].freeze
19
+ @params = (request['params'] || {}).freeze
20
20
  post_initialize
21
21
  end
22
22
 
@@ -9,6 +9,8 @@ module Solargraph
9
9
  module Extended
10
10
  autoload :Document, 'solargraph/language_server/message/extended/document'
11
11
  autoload :Search, 'solargraph/language_server/message/extended/search'
12
+ autoload :CheckGemVersion, 'solargraph/language_server/message/extended/check_gem_version'
13
+ autoload :DocumentGems, 'solargraph/language_server/message/extended/document_gems'
12
14
  end
13
15
  end
14
16
  end
@@ -0,0 +1,38 @@
1
+ require 'open3'
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ module Message
6
+ module Extended
7
+ # Check if a more recent version of the Solargraph gem is available.
8
+ # Notify the client when an update exists. If the `verbose` parameter
9
+ # is true, notify the client when the gem is up to date.
10
+ #
11
+ class CheckGemVersion < Base
12
+ def process
13
+ o, s = Open3.capture2("gem search solargraph")
14
+ match = o.match(/solargraph \([0-9\.]*?\)/)
15
+ # @todo Error if no match or status code != 0
16
+ available = Gem::Version.new(match[1])
17
+ current = Gem::Version.new(Solargraph::VERSION)
18
+ if available > current
19
+ host.show_message_request "Solagraph gem version #{available} is available.",
20
+ LanguageServer::MessageTypes::INFO,
21
+ ['Update now'] do |result|
22
+ break unless result == 'Update now'
23
+ o, s = Open3.capture2("gem update solargraph")
24
+ if s == 0
25
+ host.show_message 'Successfully updated the Solargraph gem.', LanguageServer::MessageTypes::INFO
26
+ else
27
+ host.show_message 'An error occurred while updating the gem.', LanguageServer::MessageTypes::ERROR
28
+ end
29
+ end
30
+ elsif params['verbose']
31
+ host.show_message "The Solargraph gem is up to date (version #{Solargraph::VERSION})."
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ require 'open3'
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ module Message
6
+ module Extended
7
+ # Update YARD documentation for installed gems. If the `rebuild`
8
+ # parameter is true, rebuild existing yardocs.
9
+ #
10
+ class DocumentGems < Base
11
+ def process
12
+ cmd = "yard gems"
13
+ cmd += " --rebuild" if params['rebuild']
14
+ o, s = Open3.capture2(cmd)
15
+ if s != 0
16
+ host.show_message "An error occurred while building gem documentation.", LanguageServer::MessageTypes::ERROR
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -4,12 +4,10 @@ module Solargraph
4
4
  module TextDocument
5
5
  class OnTypeFormatting < Base
6
6
  def process
7
- # @todo Temporarily disabled
8
- set_result nil
9
- return
10
- src = host.library.checkout(uri_to_file(params['textDocument']['uri']))
11
- offset = src.get_offset(params['position']['line'], params['position']['character'])
12
- if src.string_at?(offset-1) and params['ch'] == '{' and src.code[offset-2,2] == '#{'
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] == '#{'
13
11
  set_result(
14
12
  [
15
13
  {
@@ -22,7 +20,8 @@ module Solargraph
22
20
  ]
23
21
  )
24
22
  else
25
- set_result []
23
+ # @todo Is `nil` or `[]` more appropriate here?
24
+ set_result nil
26
25
  end
27
26
  end
28
27
  end
@@ -0,0 +1,14 @@
1
+ module Solargraph
2
+ module LanguageServer
3
+ class Request
4
+ def initialize id, &block
5
+ @id = id
6
+ @block = block
7
+ end
8
+
9
+ def process result
10
+ @block.call(result)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -31,7 +31,16 @@ module Solargraph
31
31
  source_hash.has_key? filename
32
32
  end
33
33
 
34
- # Create a file source to be added to the workspace. The source is ignored
34
+ # True if the specified file is included in the workspace (but not
35
+ # necessarily open).
36
+ #
37
+ # @param filename [String]
38
+ # @return [Boolean]
39
+ def contain? filename
40
+ workspace.has_file?(filename)
41
+ end
42
+
43
+ # Create a file source to be added to the workspace. The file is ignored
35
44
  # if the workspace is not configured to include the file.
36
45
  #
37
46
  # @param filename [String]
@@ -45,12 +54,18 @@ module Solargraph
45
54
  true
46
55
  end
47
56
 
57
+ # Create a file source from a file on disk. The file is ignored if the
58
+ # workspace is not configured to include the file.
59
+ #
60
+ # @param filename [String]
61
+ # @return [Boolean] True if the file was added to the workspace.
48
62
  def create_from_disk filename
49
- return if File.directory?(filename) or !File.exist?(filename)
50
- return unless workspace.would_merge?(filename)
63
+ return false if File.directory?(filename) or !File.exist?(filename)
64
+ return false unless workspace.would_merge?(filename)
51
65
  source = Solargraph::Source.load_string(File.read(filename), filename)
52
66
  workspace.merge(source)
53
67
  api_map.refresh
68
+ true
54
69
  end
55
70
 
56
71
  # Delete a file from the library. Deleting a file will make it unavailable
@@ -198,6 +213,24 @@ module Solargraph
198
213
  source.code
199
214
  end
200
215
 
216
+ # Get diagnostics about a file.
217
+ #
218
+ # @return [Array<Hash>]
219
+ def diagnose filename
220
+ # @todo Only open files get diagnosed. Determine whether anything or
221
+ # everything in the workspace should get diagnosed, or if there should
222
+ # be an option to do so.
223
+ return [] unless open?(filename)
224
+ result = []
225
+ source = read(filename)
226
+ workspace.config.reporters.each do |name|
227
+ reporter = Diagnostics::REPORTERS[name]
228
+ raise DiagnosticsError, "Diagnostics reporter #{name} does not exist" if reporter.nil?
229
+ result.concat reporter.new.diagnose(source, api_map)
230
+ end
231
+ result
232
+ end
233
+
201
234
  # Create a library from a directory.
202
235
  #
203
236
  # @param directory [String] The path to be used for the workspace
@@ -223,6 +256,7 @@ module Solargraph
223
256
  @workspace
224
257
  end
225
258
 
259
+ # @raise [FileNotFoundError] if the file is not open
226
260
  # @param filename [String]
227
261
  # @return [Solargraph::Source]
228
262
  def read filename
@@ -1,21 +1,11 @@
1
1
  require 'ostruct'
2
2
  require 'tilt'
3
- require 'redcarpet'
3
+ require 'kramdown'
4
4
  require 'htmlentities'
5
5
  require 'coderay'
6
6
 
7
7
  module Solargraph
8
8
  class Page
9
- class SolargraphRenderer < Redcarpet::Render::HTML
10
- def normal_text text
11
- HTMLEntities.new.encode(text, :named)
12
- end
13
- def block_code code, language
14
- CodeRay.scan(code, language || :ruby).div
15
- end
16
- end
17
- private_constant :SolargraphRenderer
18
-
19
9
  class Binder < OpenStruct
20
10
  def initialize locals, render_method
21
11
  super(locals)
@@ -31,8 +21,17 @@ module Solargraph
31
21
  helper = Solargraph::Pin::Helper.new
32
22
  html = helper.html_markup_rdoc(text)
33
23
  conv = ReverseMarkdown.convert(html, github_flavored: true)
34
- markdown = Redcarpet::Markdown.new(SolargraphRenderer.new(prettify: true), fenced_code_blocks: true)
35
- markdown.render(conv)
24
+ Kramdown::Document.new(
25
+ conv,
26
+ input: 'GFM',
27
+ entity_output: :symbolic,
28
+ syntax_highlighter_opts: {
29
+ block: {
30
+ line_numbers: false,
31
+ },
32
+ default_lang: :ruby
33
+ },
34
+ ).to_html
36
35
  end
37
36
 
38
37
  def ruby_to_html code
@@ -1,6 +1,4 @@
1
1
  require 'yard'
2
- require 'yard/templates/helpers/markup_helper'
3
- require 'yard/templates/helpers/html_helper'
4
2
 
5
3
  module Solargraph
6
4
  module Pin
@@ -18,10 +16,18 @@ module Solargraph
18
16
  '.'
19
17
  end
20
18
 
19
+ def html_markup_rdoc(text)
20
+ # @todo The :rdoc markup class might not be immediately available.
21
+ # If not, return nil for now under the assumption that the problem
22
+ # will eventually fix itself.
23
+ return nil if markup_class(:rdoc).nil?
24
+ super
25
+ end
26
+
21
27
  def options
22
28
  if @options.nil?
23
29
  @options = YARD::Templates::TemplateOptions.new
24
- @options.type = :rdoc
30
+ @options[:type] = :rdoc
25
31
  end
26
32
  @options
27
33
  end
@@ -2,10 +2,17 @@ module Solargraph
2
2
  module Pin
3
3
  module Localized
4
4
  attr_reader :block
5
+
6
+ # @return [Source::Range]
5
7
  attr_reader :presence
6
8
 
7
- def visible_from?(block, position)
8
- self.block == block and presence.contain?(position)
9
+ # @param other [Pin::Block] The caller's block
10
+ # @param position [Source::Position] The caller's position
11
+ # @return [Boolean]
12
+ def visible_from?(other, position)
13
+ other.filename == filename and
14
+ (other == block or other.named_context == named_context) and
15
+ presence.contain?(position)
9
16
  end
10
17
  end
11
18
  end
@@ -71,14 +71,13 @@ module Solargraph
71
71
  end
72
72
 
73
73
  def location
74
- # @todo Get the location
75
74
  @location
76
75
  end
77
76
 
78
77
  def path
79
78
  code_object.path
80
79
  end
81
-
80
+
82
81
  def namespace
83
82
  # @todo Is this right?
84
83
  code_object.namespace.to_s
@@ -111,7 +110,7 @@ module Solargraph
111
110
  args.push p
112
111
  }
113
112
  args
114
- end
113
+ end
115
114
  end
116
115
  end
117
116
  end
@@ -54,6 +54,7 @@ module Solargraph
54
54
  EventMachine.stop
55
55
  end
56
56
  EventMachine.start_server options[:host], port, Solargraph::LanguageServer::Transport::Socket
57
+ # Emitted for the benefit of clients that start the process on port 0
57
58
  STDERR.puts "Solargraph is listening PORT=#{port} PID=#{Process.pid}"
58
59
  end
59
60
  end
@@ -132,5 +133,10 @@ module Solargraph
132
133
  def clear_cores
133
134
  Solargraph::YardMap::CoreDocs.clear
134
135
  end
136
+
137
+ desc 'reporters', 'Get a list of diagnostics reporters'
138
+ def reporters
139
+ puts Solargraph::Diagnostics::REPORTERS.keys.sort
140
+ end
135
141
  end
136
142
  end
@@ -44,6 +44,8 @@ module Solargraph
44
44
 
45
45
  attr_reader :requires
46
46
 
47
+ attr_reader :domains
48
+
47
49
  attr_reader :locals
48
50
 
49
51
  include NodeMethods
@@ -282,7 +284,8 @@ module Solargraph
282
284
 
283
285
  def all_symbols
284
286
  result = []
285
- result.concat namespace_pin_map.values.flatten
287
+ # result.concat namespace_pin_map.values.flatten
288
+ result.concat namespace_pins.reject{ |pin| pin.name.empty? }
286
289
  result.concat method_pins
287
290
  result.concat constant_pins
288
291
  result
@@ -339,7 +342,7 @@ module Solargraph
339
342
  end
340
343
 
341
344
  def process_parsed node, comments
342
- @pins, @locals, @requires, @symbols, @path_macros = Mapper.map filename, code, node, comments
345
+ @pins, @locals, @requires, @symbols, @path_macros, @domains = Mapper.map filename, code, node, comments
343
346
  @stime = Time.now
344
347
  end
345
348
 
@@ -9,6 +9,8 @@ module Solargraph
9
9
 
10
10
  attr_reader :column
11
11
 
12
+ attr_reader :source
13
+
12
14
  # @param source [Solargraph::Source]
13
15
  # @param line [Integer]
14
16
  # @param column [Integer]
@@ -216,10 +218,16 @@ module Solargraph
216
218
  @locals ||= @source.locals.select{|pin| pin.visible_from?(block, position)}
217
219
  end
218
220
 
221
+ # True if the fragment is a signature that stems from a literal value.
222
+ #
223
+ # @return [Boolean]
219
224
  def base_literal?
220
225
  !base_literal.nil?
221
226
  end
222
227
 
228
+ # The type of literal value at the root of the signature (or nil).
229
+ #
230
+ # @return [String]
223
231
  def base_literal
224
232
  if @base_literal.nil? and !@calculated_literal
225
233
  @calculated_literal = true
@@ -19,6 +19,7 @@ module Solargraph
19
19
  # @todo Stuff that needs to be resolved
20
20
  @variables = []
21
21
  @path_macros = {}
22
+ @domains = []
22
23
 
23
24
  @pins = []
24
25
  @requires = []
@@ -32,7 +33,7 @@ module Solargraph
32
33
  @pins.push Pin::Namespace.new(get_node_location(nil), '', '', nil, :class, :public, nil)
33
34
  process root
34
35
  process_directives
35
- [@pins, @locals, @requires, @symbols, @path_macros]
36
+ [@pins, @locals, @requires, @symbols, @path_macros, @domains]
36
37
  end
37
38
 
38
39
  class << self
@@ -231,7 +232,8 @@ module Solargraph
231
232
  next
232
233
  elsif c.type == :send and c.children[1] == :require
233
234
  if c.children[2].kind_of?(AST::Node) and c.children[2].type == :str
234
- @requires.push c.children[2].children[0].to_s
235
+ # @requires.push c.children[2].children[0].to_s
236
+ @requires.push Solargraph::Pin::Reference.new(get_node_location(c), fqn, c.children[2].children[0].to_s)
235
237
  end
236
238
  elsif c.type == :args
237
239
  if @node_stack.first.type == :block
@@ -263,15 +265,6 @@ module Solargraph
263
265
  stack.pop
264
266
  end
265
267
 
266
- # def path_for node
267
- # path = namespace_for(node) || ''
268
- # mp = (method_pins + attribute_pins).select{|p| p.node == node}.first
269
- # unless mp.nil?
270
- # path += (mp.scope == :instance ? '#' : '.') + mp.name
271
- # end
272
- # path
273
- # end
274
-
275
268
  def get_last_in_stack_not_begin stack
276
269
  index = stack.length - 1
277
270
  last = stack[index]
@@ -379,6 +372,8 @@ module Solargraph
379
372
  here = get_node_start_position(k.node)
380
373
  pin = @pins.select{|pin| [Pin::NAMESPACE, Pin::METHOD].include?(pin.kind) and pin.location.range.contain?(here)}.first
381
374
  @path_macros[pin.path] = v
375
+ elsif d.tag.tag_name == 'domain'
376
+ @domains.push d.tag.text
382
377
  else
383
378
  # STDERR.puts "Nothing to do for directive: #{d}"
384
379
  end