solargraph 0.18.2 → 0.18.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/solargraph.rb +33 -28
  3. data/lib/solargraph/api_map.rb +997 -1044
  4. data/lib/solargraph/api_map/source_to_yard.rb +4 -3
  5. data/lib/solargraph/diagnostics/rubocop.rb +4 -3
  6. data/lib/solargraph/language_server/host.rb +140 -70
  7. data/lib/solargraph/language_server/message/base.rb +1 -0
  8. data/lib/solargraph/language_server/message/client.rb +6 -2
  9. data/lib/solargraph/language_server/message/text_document/completion.rb +34 -39
  10. data/lib/solargraph/language_server/message/text_document/definition.rb +1 -1
  11. data/lib/solargraph/language_server/message/text_document/did_close.rb +1 -0
  12. data/lib/solargraph/language_server/message/text_document/did_save.rb +1 -3
  13. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +1 -1
  14. data/lib/solargraph/language_server/message/text_document/hover.rb +25 -30
  15. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +1 -1
  16. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +8 -7
  17. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +1 -1
  18. data/lib/solargraph/language_server/transport/socket.rb +15 -17
  19. data/lib/solargraph/library.rb +34 -16
  20. data/lib/solargraph/node_methods.rb +96 -96
  21. data/lib/solargraph/pin.rb +1 -0
  22. data/lib/solargraph/pin/base.rb +2 -1
  23. data/lib/solargraph/pin/base_variable.rb +45 -5
  24. data/lib/solargraph/pin/block_parameter.rb +5 -2
  25. data/lib/solargraph/pin/method.rb +22 -0
  26. data/lib/solargraph/pin/namespace.rb +32 -2
  27. data/lib/solargraph/pin/reference.rb +21 -0
  28. data/lib/solargraph/pin/yard_object.rb +9 -0
  29. data/lib/solargraph/shell.rb +136 -136
  30. data/lib/solargraph/source.rb +134 -188
  31. data/lib/solargraph/source/change.rb +70 -0
  32. data/lib/solargraph/source/fragment.rb +120 -66
  33. data/lib/solargraph/source/position.rb +41 -0
  34. data/lib/solargraph/source/updater.rb +48 -0
  35. data/lib/solargraph/version.rb +3 -3
  36. data/lib/solargraph/workspace/config.rb +4 -9
  37. data/lib/solargraph/yard_map/core_docs.rb +0 -1
  38. metadata +5 -2
@@ -19,5 +19,6 @@ module Solargraph
19
19
  autoload :Parameter, 'solargraph/pin/parameter'
20
20
  autoload :MethodParameter, 'solargraph/pin/method_parameter'
21
21
  autoload :BlockParameter, 'solargraph/pin/block_parameter'
22
+ autoload :Reference, 'solargraph/pin/reference'
22
23
  end
23
24
  end
@@ -99,6 +99,7 @@ module Solargraph
99
99
  def documentation
100
100
  if @documentation.nil? and !docstring.nil?
101
101
  @documentation = ReverseMarkdown.convert(helper.html_markup_rdoc(docstring), github_flavored: true)
102
+ @documentation.strip!
102
103
  end
103
104
  @documentation
104
105
  end
@@ -124,7 +125,7 @@ module Solargraph
124
125
  end
125
126
 
126
127
  def identifier
127
- @identifier ||= "#{path || location}"
128
+ @identifier ||= "#{path}|#{name}"
128
129
  end
129
130
 
130
131
  def variable?
@@ -6,6 +6,7 @@ module Solargraph
6
6
  def initialize source, node, namespace
7
7
  super
8
8
  @tried_to_detect_return_type = false
9
+ @tried_to_resolve_return_type = false
9
10
  end
10
11
 
11
12
  def name
@@ -20,7 +21,7 @@ module Solargraph
20
21
  if @return_type.nil? and !@tried_to_detect_return_type
21
22
  @tried_to_detect_return_type = true
22
23
  if docstring.nil?
23
- @return_type ||= literal_from_assignment
24
+ @return_type ||= infer_literal_node_type(assignment_node)
24
25
  else
25
26
  tag = docstring.tag(:type)
26
27
  @return_type = tag.types[0] unless tag.nil?
@@ -41,11 +42,29 @@ module Solargraph
41
42
  @signature ||= resolve_node_signature(assignment_node)
42
43
  end
43
44
 
45
+ def calculated_signature
46
+ if @calculated_signature.nil?
47
+ if signature.empty?
48
+ type = infer_literal_node_type(assignment_node)
49
+ @calculated_signature = "#{type}.new" unless type.nil?
50
+ end
51
+ @calculated_signature ||= signature
52
+ end
53
+ @calculated_signature
54
+ end
55
+
44
56
  # @param api_map [Solargraph::ApiMap]
45
57
  def resolve api_map
46
- if return_type.nil?
58
+ if return_type.nil? and !@tried_to_resolve_return_type
59
+ @tried_to_detect_return_type = true
47
60
  return nil if signature.nil? or signature.empty? or signature == name or signature.split('.').first.strip == name
48
- @return_type = api_map.infer_signature_type(signature, namespace, call_node: node)
61
+ # @todo This should be able to resolve signatures that start with local variables
62
+ macro_type = nil
63
+ # pin = api_map.tail_pin(signature, namespace, :class, [:public, :private, :protected])
64
+ # unless pin.nil? or !pin.method?
65
+ # macro_type = get_return_type_from_macro(pin, assignment_node)
66
+ # end
67
+ @return_type = macro_type || api_map.infer_type(signature, namespace, scope: :class)
49
68
  end
50
69
  end
51
70
 
@@ -55,8 +74,29 @@ module Solargraph
55
74
 
56
75
  private
57
76
 
58
- def literal_from_assignment
59
- infer_literal_node_type(assignment_node)
77
+ def get_call_arguments node
78
+ return get_call_arguments(node.children[1]) if [:ivasgn, :cvasgn, :lvasgn].include?(node.type)
79
+ return [] unless node.type == :send
80
+ result = []
81
+ node.children[2..-1].each do |c|
82
+ result.push unpack_name(c)
83
+ end
84
+ result
85
+ end
86
+
87
+ def get_return_type_from_macro method_pin, call_node
88
+ return nil if method_pin.docstring.nil?
89
+ type = nil
90
+ all = YARD::Docstring.parser.parse(method_pin.docstring.all).directives
91
+ macro = all.select{|m| m.tag.tag_name == 'macro'}.first
92
+ return nil if macro.nil?
93
+ macstring = YARD::Docstring.parser.parse(macro.tag.text).to_docstring
94
+ rt = macstring.tag(:return)
95
+ unless rt.nil? or rt.types.nil?
96
+ args = get_call_arguments(call_node)
97
+ type = "#{args[rt.types[0][1..-1].to_i-1]}"
98
+ end
99
+ type
60
100
  end
61
101
  end
62
102
  end
@@ -21,12 +21,15 @@ module Solargraph
21
21
  def resolve api_map
22
22
  return unless return_type.nil?
23
23
  signature = resolve_node_signature(@tree[0].children[0])
24
- meth = api_map.infer_signature_pins(signature, namespace, :class, node).first
24
+ # @todo Hardcoding :class scope might not be appropriate
25
+ # meth = api_map.infer_pin(signature, namespace, :class, [:public, :private, :protected], true)
26
+ meth = api_map.tail_pin(signature, namespace, :class, [:public, :private, :protected])
25
27
  return nil if meth.nil?
26
28
  if (Solargraph::CoreFills::METHODS_WITH_YIELDPARAM_SUBTYPES.include?(meth.path))
27
29
  base = signature.split('.')[0..-2].join('.')
28
30
  return nil if base.nil? or base.empty?
29
- bmeth = api_map.infer_signature_pins(base, namespace, :class, node).first
31
+ # @todo Maybe use a fragment so this picks up local variables
32
+ bmeth = api_map.tail_pin(base, namespace, :class, [:public, :private, :protected])
30
33
  return nil if bmeth.nil?
31
34
  subtypes = get_subtypes(bmeth.return_type)
32
35
  @return_type = api_map.find_fully_qualified_namespace(subtypes[0], namespace)
@@ -43,6 +43,28 @@ module Solargraph
43
43
  @parameters ||= get_method_args
44
44
  end
45
45
 
46
+ def documentation
47
+ if @documentation.nil?
48
+ @documentation ||= super || ''
49
+ unless docstring.nil?
50
+ param_tags = docstring.tags(:param)
51
+ unless param_tags.nil? or param_tags.empty?
52
+ @documentation += "\n\n"
53
+ @documentation += "Params:\n"
54
+ lines = []
55
+ param_tags.each do |p|
56
+ l = "* #{p.name}"
57
+ l += " [#{p.types.join(', ')}]" unless p.types.empty?
58
+ l += " #{p.text}"
59
+ lines.push l
60
+ end
61
+ @documentation += lines.join("\n")
62
+ end
63
+ end
64
+ end
65
+ @documentation
66
+ end
67
+
46
68
  # @todo This method was temporarily migrated directly from Suggestion
47
69
  # @return [Array<String>]
48
70
  def params
@@ -5,13 +5,26 @@ module Solargraph
5
5
 
6
6
  attr_reader :visibility
7
7
 
8
- def initialize source, node, namespace, visibility
8
+ def initialize source, node, namespace, visibility, superclass = nil
9
9
  super(source, node, namespace)
10
10
  @visibility = visibility
11
+ @superclass_reference = Reference.new(self, superclass) unless superclass.nil?
12
+ end
13
+
14
+ def reference_include name
15
+ include_references.push Reference.new(self, name)
16
+ end
17
+
18
+ def reference_extend name
19
+ extend_references.push Reference.new(self, name)
20
+ end
21
+
22
+ def reference_superclass name
23
+ @superclass_reference = Reference.new(self, name)
11
24
  end
12
25
 
13
26
  def name
14
- @name ||= pack_name(node.children[0]).last.to_s
27
+ @name ||= (node.type == :source ? '' : pack_name(node.children[0]).last.to_s)
15
28
  end
16
29
 
17
30
  def path
@@ -22,11 +35,28 @@ module Solargraph
22
35
  @kind ||= (node.type == :class ? Solargraph::LanguageServer::CompletionItemKinds::CLASS : Solargraph::LanguageServer::CompletionItemKinds::MODULE)
23
36
  end
24
37
 
38
+ def include_references
39
+ @include_references ||= []
40
+ end
41
+
42
+ def extend_references
43
+ @extend_references ||= []
44
+ end
45
+
46
+ def superclass_reference
47
+ @superclass_reference
48
+ end
49
+
25
50
  # @return [Symbol] :class or :module
26
51
  def type
27
52
  node.type
28
53
  end
29
54
 
55
+ def location
56
+ return "#{source.filename}:0" if name.empty?
57
+ super
58
+ end
59
+
30
60
  def return_type
31
61
  @return_type ||= (node.type == :class ? 'Class' : 'Module') + "<#{path}>"
32
62
  end
@@ -0,0 +1,21 @@
1
+ module Solargraph
2
+ module Pin
3
+ class Reference
4
+ attr_reader :pin
5
+ attr_reader :name
6
+
7
+ def initialize pin, name
8
+ @pin = pin
9
+ @name = name
10
+ @resolved = false
11
+ end
12
+
13
+ def resolve api_map
14
+ unless @resolved
15
+ @resolved = true
16
+ @name = api_map.find_fully_qualified_namespace(@name, pin.namespace)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -81,6 +81,15 @@ module Solargraph
81
81
  completion_item_kind == Solargraph::LanguageServer::CompletionItemKinds::METHOD
82
82
  end
83
83
 
84
+ def visibility
85
+ :public #@todo Resolve this
86
+ end
87
+
88
+ def scope
89
+ return nil unless code_object.is_a?(YARD::CodeObjects::MethodObject)
90
+ code_object.scope
91
+ end
92
+
84
93
  private
85
94
 
86
95
  def get_method_args
@@ -1,136 +1,136 @@
1
- require 'thor'
2
- require 'json'
3
- require 'fileutils'
4
- require 'rubygems/package'
5
- require 'zlib'
6
- require 'eventmachine'
7
-
8
- module Solargraph
9
- class Shell < Thor
10
- include Solargraph::ServerMethods
11
-
12
- map %w[--version -v] => :version
13
-
14
- desc "--version, -v", "Print the version"
15
- def version
16
- puts Solargraph::VERSION
17
- end
18
-
19
- desc 'server', 'Start a Solargraph server'
20
- option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7657
21
- option :views, type: :string, aliases: :v, desc: 'The view template directory', default: nil
22
- option :files, type: :string, aliases: :f, desc: 'The public files directory', default: nil
23
- def server
24
- port = options[:port]
25
- port = available_port if port.zero?
26
- Solargraph::Server.set :port, port
27
- Solargraph::Server.set :views, options[:views] unless options[:views].nil?
28
- Solargraph::Server.set :public_folder, options[:files] unless options[:files].nil?
29
- my_pid = nil
30
- Solargraph::Server.run! do
31
- # This line should not be necessary with WEBrick
32
- #STDERR.puts "Solargraph server pid=#{Process.pid} port=#{port}"
33
- my_pid = Process.pid
34
- Signal.trap("INT") do
35
- Solargraph::Server.stop!
36
- end
37
- Signal.trap("TERM") do
38
- Solargraph::Server.stop!
39
- end
40
- end
41
- end
42
-
43
- desc 'socket', 'Run a Solargraph socket server'
44
- option :host, type: :string, aliases: :h, desc: 'The server host', default: '127.0.0.1'
45
- option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7658
46
- def socket
47
- port = options[:port]
48
- port = available_port if port.zero?
49
- EventMachine.run do
50
- Signal.trap("INT") do
51
- EventMachine.stop
52
- end
53
- Signal.trap("TERM") do
54
- EventMachine.stop
55
- end
56
- EventMachine.start_server options[:host], port, Solargraph::LanguageServer::Transport::Socket
57
- STDERR.puts "Solargraph is listening PORT=#{port} PID=#{Process.pid}"
58
- end
59
- end
60
-
61
- desc 'suggest', 'Get code suggestions for the provided input'
62
- long_desc <<-LONGDESC
63
- Analyze a Ruby file and output a list of code suggestions in JSON format.
64
- LONGDESC
65
- option :line, type: :numeric, aliases: :l, desc: 'Zero-based line number', required: true
66
- option :column, type: :numeric, aliases: [:c, :col], desc: 'Zero-based column number', required: true
67
- option :filename, type: :string, aliases: :f, desc: 'File name', required: false
68
- def suggest(*filenames)
69
- STDERR.puts "WARNING: The `solargraph suggest` command is a candidate for deprecation. It will either change drastically or not exist in a future version."
70
- # HACK: The ARGV array needs to be manipulated for ARGF.read to work
71
- ARGV.clear
72
- ARGV.concat filenames
73
- text = ARGF.read
74
- filename = options[:filename] || filenames[0]
75
- begin
76
- code_map = CodeMap.new(code: text, filename: filename)
77
- offset = code_map.get_offset(options[:line], options[:column])
78
- sugg = code_map.suggest_at(offset, filtered: true)
79
- result = { "status" => "ok", "suggestions" => sugg }.to_json
80
- STDOUT.puts result
81
- rescue Exception => e
82
- STDERR.puts e
83
- STDERR.puts e.backtrace.join("\n")
84
- result = { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
85
- STDOUT.puts result
86
- end
87
- end
88
-
89
- desc 'config [DIRECTORY]', 'Create or overwrite a default configuration file'
90
- option :extensions, type: :boolean, aliases: :e, desc: 'Add installed extensions', default: true
91
- def config(directory = '.')
92
- matches = []
93
- if options[:extensions]
94
- Gem::Specification.each do |g|
95
- puts g.name
96
- if g.name.match(/^solargraph\-[A-Za-z0-9_\-]*?\-ext/)
97
- require g.name
98
- matches.push g.name
99
- end
100
- end
101
- end
102
- conf = Solargraph::Workspace::Config.new.raw_data
103
- unless matches.empty?
104
- matches.each do |m|
105
- conf['extensions'].push m
106
- end
107
- end
108
- File.open(File.join(directory, '.solargraph.yml'), 'w') do |file|
109
- file.puts conf.to_yaml
110
- end
111
- STDOUT.puts "Configuration file initialized."
112
- end
113
-
114
- desc 'download-core [VERSION]', 'Download core documentation'
115
- def download_core version = nil
116
- ver = version || Solargraph::YardMap::CoreDocs.best_download
117
- puts "Downloading docs for #{ver}..."
118
- Solargraph::YardMap::CoreDocs.download ver
119
- end
120
-
121
- desc 'list-cores', 'List the local documentation versions'
122
- def list_cores
123
- puts Solargraph::YardMap::CoreDocs.versions.join("\n")
124
- end
125
-
126
- desc 'available-cores', 'List available documentation versions'
127
- def available_cores
128
- puts Solargraph::YardMap::CoreDocs.available.join("\n")
129
- end
130
-
131
- desc 'clear-cores', 'Clear the cached core documentation'
132
- def clear_cores
133
- Solargraph::YardMap::CoreDocs.clear
134
- end
135
- end
136
- end
1
+ require 'thor'
2
+ require 'json'
3
+ require 'fileutils'
4
+ require 'rubygems/package'
5
+ require 'zlib'
6
+ require 'eventmachine'
7
+
8
+ module Solargraph
9
+ class Shell < Thor
10
+ include Solargraph::ServerMethods
11
+
12
+ map %w[--version -v] => :version
13
+
14
+ desc "--version, -v", "Print the version"
15
+ def version
16
+ puts Solargraph::VERSION
17
+ end
18
+
19
+ desc 'server', 'Start a Solargraph server'
20
+ option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7657
21
+ option :views, type: :string, aliases: :v, desc: 'The view template directory', default: nil
22
+ option :files, type: :string, aliases: :f, desc: 'The public files directory', default: nil
23
+ def server
24
+ port = options[:port]
25
+ port = available_port if port.zero?
26
+ Solargraph::Server.set :port, port
27
+ Solargraph::Server.set :views, options[:views] unless options[:views].nil?
28
+ Solargraph::Server.set :public_folder, options[:files] unless options[:files].nil?
29
+ my_pid = nil
30
+ Solargraph::Server.run! do
31
+ # This line should not be necessary with WEBrick
32
+ #STDERR.puts "Solargraph server pid=#{Process.pid} port=#{port}"
33
+ my_pid = Process.pid
34
+ Signal.trap("INT") do
35
+ Solargraph::Server.stop!
36
+ end
37
+ Signal.trap("TERM") do
38
+ Solargraph::Server.stop!
39
+ end
40
+ end
41
+ end
42
+
43
+ desc 'socket', 'Run a Solargraph socket server'
44
+ option :host, type: :string, aliases: :h, desc: 'The server host', default: '127.0.0.1'
45
+ option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7658
46
+ def socket
47
+ port = options[:port]
48
+ port = available_port if port.zero?
49
+ EventMachine.run do
50
+ Signal.trap("INT") do
51
+ EventMachine.stop
52
+ end
53
+ Signal.trap("TERM") do
54
+ EventMachine.stop
55
+ end
56
+ EventMachine.start_server options[:host], port, Solargraph::LanguageServer::Transport::Socket
57
+ STDERR.puts "Solargraph is listening PORT=#{port} PID=#{Process.pid}"
58
+ end
59
+ end
60
+
61
+ desc 'suggest', 'Get code suggestions for the provided input'
62
+ long_desc <<-LONGDESC
63
+ Analyze a Ruby file and output a list of code suggestions in JSON format.
64
+ LONGDESC
65
+ option :line, type: :numeric, aliases: :l, desc: 'Zero-based line number', required: true
66
+ option :column, type: :numeric, aliases: [:c, :col], desc: 'Zero-based column number', required: true
67
+ option :filename, type: :string, aliases: :f, desc: 'File name', required: false
68
+ def suggest(*filenames)
69
+ STDERR.puts "WARNING: The `solargraph suggest` command is a candidate for deprecation. It will either change drastically or not exist in a future version."
70
+ # HACK: The ARGV array needs to be manipulated for ARGF.read to work
71
+ ARGV.clear
72
+ ARGV.concat filenames
73
+ text = ARGF.read
74
+ filename = options[:filename] || filenames[0]
75
+ begin
76
+ code_map = CodeMap.new(code: text, filename: filename)
77
+ offset = code_map.get_offset(options[:line], options[:column])
78
+ sugg = code_map.suggest_at(offset, filtered: true)
79
+ result = { "status" => "ok", "suggestions" => sugg }.to_json
80
+ STDOUT.puts result
81
+ rescue Exception => e
82
+ STDERR.puts e
83
+ STDERR.puts e.backtrace.join("\n")
84
+ result = { "status" => "err", "message" => e.message + "\n" + e.backtrace.join("\n") }.to_json
85
+ STDOUT.puts result
86
+ end
87
+ end
88
+
89
+ desc 'config [DIRECTORY]', 'Create or overwrite a default configuration file'
90
+ option :extensions, type: :boolean, aliases: :e, desc: 'Add installed extensions', default: true
91
+ def config(directory = '.')
92
+ matches = []
93
+ if options[:extensions]
94
+ Gem::Specification.each do |g|
95
+ puts g.name
96
+ if g.name.match(/^solargraph\-[A-Za-z0-9_\-]*?\-ext/)
97
+ require g.name
98
+ matches.push g.name
99
+ end
100
+ end
101
+ end
102
+ conf = Solargraph::Workspace::Config.new.raw_data
103
+ unless matches.empty?
104
+ matches.each do |m|
105
+ conf['extensions'].push m
106
+ end
107
+ end
108
+ File.open(File.join(directory, '.solargraph.yml'), 'w') do |file|
109
+ file.puts conf.to_yaml
110
+ end
111
+ STDOUT.puts "Configuration file initialized."
112
+ end
113
+
114
+ desc 'download-core [VERSION]', 'Download core documentation'
115
+ def download_core version = nil
116
+ ver = version || Solargraph::YardMap::CoreDocs.best_download
117
+ puts "Downloading docs for #{ver}..."
118
+ Solargraph::YardMap::CoreDocs.download ver
119
+ end
120
+
121
+ desc 'list-cores', 'List the local documentation versions'
122
+ def list_cores
123
+ puts Solargraph::YardMap::CoreDocs.versions.join("\n")
124
+ end
125
+
126
+ desc 'available-cores', 'List available documentation versions'
127
+ def available_cores
128
+ puts Solargraph::YardMap::CoreDocs.available.join("\n")
129
+ end
130
+
131
+ desc 'clear-cores', 'Clear the cached core documentation'
132
+ def clear_cores
133
+ Solargraph::YardMap::CoreDocs.clear
134
+ end
135
+ end
136
+ end