solargraph 0.8.3 → 0.8.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e52db6d5b84e35fa182015ad0178c8fde5433534
4
- data.tar.gz: 4cb0dbfa89392f8fb4b9b04b506114d1b975fcb9
3
+ metadata.gz: 9f759172a51025a8b3000009fd8a0495ed8b4e09
4
+ data.tar.gz: 45599c0d4f5f61d08e5f1e9ef58ff383e14500c9
5
5
  SHA512:
6
- metadata.gz: 9f4d6d1f77fb88afb992b1a32eb12e017f74a310e090c0b275d4f5d6546313455c7e5d9230322007d1e15acc9686bc88f744e3cb18512b2ba6be5d356adb147e
7
- data.tar.gz: 74cd777945f475843b629de0613cd10949b9aed887a30f5a1423825bac943df4c4491f9caf98b8d3f231df12f22a4e09cb6c62836cc5047003a4a665a2f5a8fd
6
+ metadata.gz: ac26b06145aa273f6601808a83cfe19ede6cc97eb744514f7435aa0b4780cc8c7e33482662930838a20d3bc13008f976e6caa4460319c4637b72873b615e7f91
7
+ data.tar.gz: e5ae9a35a4ac2fccec2450ab6c96f790bed7173de95395fc7978357b5320abef3c47d95ceb3386d0e33b3178abc07ce39b0b76ae9702c54f72b92f85109c176c
@@ -39,7 +39,7 @@ module Solargraph
39
39
  files -= Dir[File.join @workspace, glob]
40
40
  }
41
41
  files.uniq.each { |f|
42
- append_file f #unless yardoc_has_file?(f)
42
+ append_file f if File.file?(f)
43
43
  }
44
44
  end
45
45
  end
@@ -373,6 +373,10 @@ module Solargraph
373
373
  type
374
374
  end
375
375
 
376
+ # Get an array of singleton methods that are available in the specified
377
+ # namespace.
378
+ #
379
+ # @return [Array<Solargraph::Suggestion>]
376
380
  def get_methods(namespace, root = '', visibility: [:public])
377
381
  meths = []
378
382
  meths += inner_get_methods(namespace, root, []) #unless has_yardoc?
@@ -410,6 +414,10 @@ module Solargraph
410
414
  args
411
415
  end
412
416
 
417
+ # Get an array of instance methods that are available in the specified
418
+ # namespace.
419
+ #
420
+ # @return [Array<Solargraph::Suggestion>]
413
421
  def get_instance_methods(namespace, root = '', visibility: [:public])
414
422
  meths = []
415
423
  meths += inner_get_instance_methods(namespace, root, []) #unless has_yardoc?
@@ -461,6 +469,8 @@ module Solargraph
461
469
  arr
462
470
  end
463
471
 
472
+ # Update the YARD documentation for the current workspace.
473
+ #
464
474
  def update_yardoc
465
475
  if workspace.nil?
466
476
  STDERR.puts "No workspace specified for yardoc update."
@@ -24,7 +24,10 @@ module Solargraph
24
24
  tries = 0
25
25
  tmp = @code
26
26
  begin
27
- node, comments = Parser::CurrentRuby.parse_with_comments(tmp)
27
+ # HACK: The current file is parsed with a trailing underscore to fix
28
+ # incomplete trees resulting from short scripts (e.g., a lone variable
29
+ # assignment).
30
+ node, comments = Parser::CurrentRuby.parse_with_comments(tmp + "\n_")
28
31
  @node = self.api_map.append_node(node, comments, filename)
29
32
  @parsed = tmp
30
33
  @code.freeze
@@ -83,6 +86,12 @@ module Solargraph
83
86
  result
84
87
  end
85
88
 
89
+ # Get the offset of the specified line and column.
90
+ # The offset (also called the "index") is typically used to identify the
91
+ # cursor's location in the code when generating suggestions.
92
+ # The line and column numbers should start at zero.
93
+ #
94
+ # @return [Integer]
86
95
  def get_offset line, col
87
96
  offset = 0
88
97
  if line > 0
@@ -93,10 +102,6 @@ module Solargraph
93
102
  offset + col
94
103
  end
95
104
 
96
- def merge node
97
- api_map.merge node
98
- end
99
-
100
105
  def tree_at(index)
101
106
  arr = []
102
107
  arr.push @node
@@ -126,6 +131,11 @@ module Solargraph
126
131
  @node
127
132
  end
128
133
 
134
+ # Get the namespace at the specified location. For example, given the code
135
+ # `class Foo; def bar; end; end`, index 14 (the center) is in the
136
+ # "Foo" namespace.
137
+ #
138
+ # @return [String]
129
139
  def namespace_at(index)
130
140
  tree = tree_at(index)
131
141
  return nil if tree.length == 0
@@ -140,11 +150,16 @@ module Solargraph
140
150
  parts.join("::")
141
151
  end
142
152
 
153
+ # Get the namespace for the specified node. For example, given the code
154
+ # `class Foo; def bar; end; end`, the node for `def bar` is in the "Foo"
155
+ # namespace.
156
+ #
157
+ # @return [String]
143
158
  def namespace_from(node)
144
159
  if node.respond_to?(:loc)
145
160
  namespace_at(node.loc.expression.begin_pos)
146
161
  else
147
- namespace_at(0)
162
+ ''
148
163
  end
149
164
  end
150
165
 
@@ -180,6 +195,10 @@ module Solargraph
180
195
  api_map.get_instance_variables(ns, (node.type == :def ? :instance : :class))
181
196
  end
182
197
 
198
+ # Get suggestions for code completion at the specified location in the
199
+ # source.
200
+ #
201
+ # @return [Array<Suggestions>] The completion suggestions
183
202
  def suggest_at index, filtered: false, with_snippets: false
184
203
  return [] if string_at?(index) or string_at?(index - 1)
185
204
  result = []
@@ -236,7 +255,7 @@ module Solargraph
236
255
  #end
237
256
  end
238
257
  result = reduce_starting_with(result, word_at(index)) if filtered
239
- result.uniq{|s| s.path}
258
+ result.uniq{|s| s.path}.sort{|a,b| a.label <=> b.label}
240
259
  end
241
260
 
242
261
  def signatures_at index
@@ -307,7 +326,8 @@ module Solargraph
307
326
  var = find_local_variable_node(start, node)
308
327
  if var.nil?
309
328
  if start.start_with?('@')
310
- type = api_map.infer_instance_variable(start, ns_here, (node.type == :def ? :instance : :class))
329
+ scope2 = (node.type == :def ? :instance : :class)
330
+ type = api_map.infer_instance_variable(start, ns_here, scope2)
311
331
  else
312
332
  if node.type == :def or node.type == :defs
313
333
  args = get_method_arguments_from(node).keep_if{|a| a.label == start}
@@ -323,11 +343,15 @@ module Solargraph
323
343
  end
324
344
  else
325
345
  cmnt = api_map.get_comment_for(node)
326
- params = cmnt.tags(:param)
327
- params.each do |p|
328
- if p.name == args[0].label
329
- type = p.types[0]
330
- break
346
+ unless cmnt.nil?
347
+ params = cmnt.tags(:param)
348
+ unless params.nil?
349
+ params.each do |p|
350
+ if p.name == args[0].label
351
+ type = p.types[0]
352
+ break
353
+ end
354
+ end
331
355
  end
332
356
  end
333
357
  end
@@ -375,6 +399,17 @@ module Solargraph
375
399
  obj
376
400
  end
377
401
 
402
+ # Get the signature at the specified index.
403
+ # A signature is a method call that can start with a constant, method, or
404
+ # variable and does not include any method arguments. Examples:
405
+ #
406
+ # Code Signature
407
+ # -----------------------------------------
408
+ # String.new String.new
409
+ # @x.bar @x.bar
410
+ # y.split(', ').length y.split.length
411
+ #
412
+ # @return [String]
378
413
  def get_signature_at index
379
414
  brackets = 0
380
415
  squares = 0
@@ -407,6 +442,10 @@ module Solargraph
407
442
  signature
408
443
  end
409
444
 
445
+ # Build a signature from the specified node. This method returns the node
446
+ # as an array of strings.
447
+ #
448
+ # @return [Array<String>]
410
449
  def build_signature(node, parts)
411
450
  if node.kind_of?(AST::Node)
412
451
  if node.type == :send
@@ -437,6 +476,10 @@ module Solargraph
437
476
  result
438
477
  end
439
478
 
479
+ # Get an array of local variables and methods that can be accessed from
480
+ # the specified location in the code.
481
+ #
482
+ # @return [Array<Solargraph::Suggestion>]
440
483
  def get_local_variables_and_methods_at(index)
441
484
  result = []
442
485
  local = parent_node_from(index, :class, :module, :def, :defs) || @node
@@ -39,27 +39,6 @@ module Solargraph
39
39
  end
40
40
  end
41
41
 
42
- def drill_signature node, signature
43
- return signature unless node.kind_of?(AST::Node)
44
- if node.type == :const or node.type == :cbase
45
- unless node.children[0].nil?
46
- signature += drill_signature(node.children[0], signature)
47
- end
48
- signature += '::' unless signature.empty?
49
- signature += node.children[1].to_s
50
- elsif node.type == :lvar
51
- signature += '.' unless signature.empty?
52
- signature += node.children[0].to_s
53
- elsif node.type == :send
54
- unless node.children[0].nil?
55
- signature += drill_signature(node.children[0], signature)
56
- end
57
- signature += '.' unless signature.empty?
58
- signature += node.children[1].to_s
59
- end
60
- signature
61
- end
62
-
63
42
  def infer node
64
43
  if node.type == :str
65
44
  return 'String'
@@ -127,5 +106,28 @@ module Solargraph
127
106
  end
128
107
  @yard_options
129
108
  end
109
+
110
+ private
111
+
112
+ def drill_signature node, signature
113
+ return signature unless node.kind_of?(AST::Node)
114
+ if node.type == :const or node.type == :cbase
115
+ unless node.children[0].nil?
116
+ signature += drill_signature(node.children[0], signature)
117
+ end
118
+ signature += '::' unless signature.empty?
119
+ signature += node.children[1].to_s
120
+ elsif node.type == :lvar
121
+ signature += '.' unless signature.empty?
122
+ signature += node.children[0].to_s
123
+ elsif node.type == :send
124
+ unless node.children[0].nil?
125
+ signature += drill_signature(node.children[0], signature)
126
+ end
127
+ signature += '.' unless signature.empty?
128
+ signature += node.children[1].to_s
129
+ end
130
+ signature
131
+ end
130
132
  end
131
133
  end
@@ -25,7 +25,7 @@ module Solargraph
25
25
  @@semaphore.synchronize {
26
26
  code_map = CodeMap.new(code: params['text'], filename: params['filename'], api_map: @@api_hash[workspace])
27
27
  offset = code_map.get_offset(params['line'].to_i, params['column'].to_i)
28
- sugg = code_map.suggest_at(offset, with_snippets: params['with_snippets'] == '1' ? true : false)
28
+ sugg = code_map.suggest_at(offset, with_snippets: params['with_snippets'] == '1' ? true : false, filtered: (params['filtered'] || false))
29
29
  }
30
30
  { "status" => "ok", "suggestions" => sugg }.to_json
31
31
  rescue Exception => e
@@ -15,12 +15,13 @@ module Solargraph
15
15
  attr_reader :label, :kind, :insert, :detail, :documentation, :code_object, :location, :arguments
16
16
 
17
17
  def initialize label, kind: KEYWORD, insert: nil, detail: nil, documentation: nil, code_object: nil, location: nil, arguments: []
18
+ @helper = Server::Helpers.new
18
19
  @label = label.to_s
19
20
  @kind = kind
20
21
  @insert = insert || @label
21
22
  @detail = detail
22
23
  @code_object = code_object
23
- @documentation = documentation
24
+ @documentation = @helper.html_markup_rdoc(documentation.to_s) unless documentation.nil?
24
25
  @location = location
25
26
  @arguments = arguments
26
27
  end
@@ -36,7 +37,7 @@ module Solargraph
36
37
  def return_type
37
38
  if code_object.nil?
38
39
  unless documentation.nil?
39
- match = documentation.all.match(/@return \[([a-z0-9:_]*)/i)
40
+ match = documentation.match(/@return \[([a-z0-9:_]*)/i)
40
41
  return match[1] unless match.nil?
41
42
  end
42
43
  else
@@ -51,6 +52,15 @@ module Solargraph
51
52
  nil
52
53
  end
53
54
 
55
+ def documentation
56
+ if @documentation.nil?
57
+ unless @code_object.nil?
58
+ @documentation = @helper.html_markup_rdoc(@code_object.docstring.to_s) unless @code_object.docstring.nil?
59
+ end
60
+ end
61
+ @documentation.to_s
62
+ end
63
+
54
64
  def to_json args={}
55
65
  obj = {
56
66
  label: @label,
@@ -59,13 +69,10 @@ module Solargraph
59
69
  detail: @detail,
60
70
  path: path,
61
71
  location: (@location.nil? ? nil : @location.to_s),
62
- arguments: @arguments
72
+ arguments: @arguments,
73
+ return_type: return_type,
74
+ documentation: documentation
63
75
  }
64
- if @code_object.nil?
65
- obj[:documentation] = @documentation.to_s unless @documentation.nil?
66
- else
67
- obj[:documentation] = @code_object.docstring.to_s unless @code_object.docstring.nil?
68
- end
69
76
  obj.to_json(args)
70
77
  end
71
78
  end
@@ -1,3 +1,3 @@
1
1
  module Solargraph
2
- VERSION = '0.8.3'
2
+ VERSION = '0.8.4'
3
3
  end
@@ -197,10 +197,14 @@ module Solargraph
197
197
  end
198
198
  }
199
199
  if ns.kind_of?(YARD::CodeObjects::ClassObject) and namespace != 'Object'
200
- if ns.superclass.kind_of?(YARD::CodeObjects::Proxy)
200
+ #if ns.superclass.kind_of?(YARD::CodeObjects::Proxy)
201
+ unless ns.nil?
201
202
  meths += get_instance_methods(ns.superclass.to_s)
202
203
  end
203
204
  end
205
+ ns.instance_mixins.each do |m|
206
+ meths += get_instance_methods(m.to_s)
207
+ end
204
208
  end
205
209
  end
206
210
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-08 00:00:00.000000000 Z
11
+ date: 2017-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parser
@@ -137,7 +137,6 @@ files:
137
137
  - lib/solargraph.rb
138
138
  - lib/solargraph/api_map.rb
139
139
  - lib/solargraph/code_map.rb
140
- - lib/solargraph/live_parser.rb
141
140
  - lib/solargraph/mapper.rb
142
141
  - lib/solargraph/node_methods.rb
143
142
  - lib/solargraph/server.rb
@@ -145,7 +144,6 @@ files:
145
144
  - lib/solargraph/snippets.rb
146
145
  - lib/solargraph/suggestion.rb
147
146
  - lib/solargraph/version.rb
148
- - lib/solargraph/views/foo.erb
149
147
  - lib/solargraph/views/layout.erb
150
148
  - lib/solargraph/views/search.erb
151
149
  - lib/solargraph/yard_map.rb
@@ -1,265 +0,0 @@
1
- # Solargraph Ruby Parser
2
- # Copyright (c) 2015 by Fred Snyder for Castwide Technologies LLC
3
- #
4
- # Solargraph::Parser builds a code representation of existing Ruby interfaces
5
- # for use in the Solargraph IDE.
6
- #
7
- # Example use:
8
- #
9
- # parser = Solargraph::Parser.new
10
- # parser.parse #=> String with the entire Ruby interface
11
- # parser.parse("Fixnum") #=> String with the Fixnum interface
12
- #require 'yard'
13
- #require 'yard/registry'
14
-
15
- module Solargraph
16
- class LiveParser
17
- def get_yard_return(path)
18
- objects = []
19
- yardocs = ['yard/2.2.0/.yardoc', 'ruby/yard/2.2.0/.yardoc-stdlib']
20
- yardocs.each { |y|
21
- YARD::Registry.load!(y)
22
- o = YARD::Registry.at(path)
23
- if !o.nil?
24
- objects.push o
25
- end
26
- }
27
- result = nil
28
- objects.each { |x|
29
- meth = x
30
- if !meth.tag(:return) and meth.tag(:overload) and meth.tag(:overload).tag(:return)
31
- meth = meth.tag(:overload)
32
- end
33
- meth.tags(:return).each { |r|
34
- result = "#{r.types[0]}"
35
- break
36
- }
37
- break if !result.nil?
38
- }
39
- result
40
- end
41
- def initialize
42
-
43
- end
44
- def parse namespace = nil
45
- #puts "Namespace: #{namespace}"
46
- @parsed = []
47
- code = ""
48
- fqns = namespace
49
- if fqns.nil?
50
- #code += parse("BasicObject")
51
- #code += parse("Object")
52
- #code += parse("Kernel")
53
- code += parse("Module")
54
- return code
55
- end
56
- mod = eval("#{fqns}")
57
- if !mod.nil?
58
- if mod.instance_of?(Class)
59
- #puts "Parsing class #{mod} to #{fqns}"
60
- code += parse_class mod, fqns
61
- elsif mod.instance_of?(Module)
62
- #puts "Parsing module #{mod} to #{fqns}"
63
- code += parse_module mod, fqns
64
- else
65
- #raise "I don't know what a #{fqns} is."
66
- code += "#{fqns} = nil\n"
67
- end
68
- else
69
- #puts "NIL!"
70
- end
71
- code
72
- end
73
- def self.parse n
74
- LiveParser.new.parse(n)
75
- end
76
- private
77
- def parse_class cls, rel_name
78
- return "" if @parsed.include?(cls)
79
- @parsed.push cls
80
- code = ""
81
- #code += "class #{rel_name}"
82
- code += "class #{cls}"
83
- if !cls.superclass.nil? && cls.superclass != cls
84
- code += " < #{cls.superclass}"
85
- end
86
- code += "\n"
87
- code += parse_class_internals(cls)
88
- code += "end\n"
89
- cls.constants().each { |c|
90
- #obj = cls.class_eval(c.to_s)
91
- begin
92
- obj = cls.const_get(c)
93
- if obj.kind_of?(Class)
94
- code += parse_class(obj, c)
95
- elsif obj.kind_of?(Module)
96
- code += parse_module(obj, c)
97
- else
98
- #code += subparse(obj)
99
- end
100
- #rescue NameError => e
101
- # #puts "NOPE! NOT #{c}"
102
- #end
103
- rescue Exception => e
104
- # TODO: Ignoring all exceptions for now
105
- end
106
- }
107
- code
108
- end
109
- def parse_module mod, rel_name
110
- return "" if @parsed.include?(mod) or mod == Solargraph
111
- @parsed.push mod
112
- code = ""
113
- #if (mod.to_s != "Kernel")
114
- code = "module #{mod}\n"
115
- #end
116
- code += parse_module_internals(mod)
117
- #if (mod.to_s != "Kernel")
118
- code += "end\n"
119
- #end
120
- mod.constants().each { |c|
121
- #obj = mod.class_eval(c.to_s)
122
- begin
123
- obj = mod.const_get(c)
124
- rescue LoadError => e
125
- code += "# @todo Failed to load #{c} from #{mod}\n"
126
- end
127
- if obj.kind_of?(Class)
128
- code += parse_class(obj, c)
129
- elsif obj.kind_of?(Module)
130
- code += parse_module(obj, c)
131
- else
132
- #code += subparse(obj)
133
- end
134
- }
135
- code
136
- end
137
- def parse_class_internals obj
138
- code = ""
139
- obj.included_modules.each { |inc|
140
- #if (inc.to_s != "Kernel")
141
- code += "include #{inc}\n"
142
- #end
143
- }
144
- obj.public_methods(false).each { |m|
145
- if !can_ignore?(obj, m)
146
- args = build_args obj.method(m)
147
- #ret = get_yard_return "#{obj}::#{m}"
148
- #if !ret.nil?
149
- # code += "# @return [#{ret}]\n"
150
- #end
151
- code += "def self.#{m}#{args};end\n"
152
- end
153
- }
154
- alloc = obj
155
- obj.singleton_methods(false).each { |m|
156
- if !can_ignore?(obj, m)
157
- args = build_args obj.method(m)
158
- #ret = get_yard_return "#{obj}::#{m}"
159
- #if !ret.nil?
160
- # code += "# @return [#{ret}]\n"
161
- #end
162
- code += "def self.#{m}#{args};end\n"
163
- end
164
- }
165
- obj.public_instance_methods(false).each { |m|
166
- if !can_ignore?(obj, m)
167
- begin
168
- args = build_args obj.public_instance_method(m)
169
- rescue TypeError => e
170
- args = ""
171
- end
172
- #ret = get_yard_return "#{obj}##{m}"
173
- #if !ret.nil?
174
- # code += "# @return [#{ret}]\n"
175
- #end
176
- code += "def #{m}#{args};end\n"
177
- end
178
- }
179
- code
180
- end
181
- def parse_module_internals obj
182
- code = ""
183
- obj.included_modules.each { |inc|
184
- #if (inc.to_s != "Kernel")
185
- code += "include #{inc}\n"
186
- #end
187
- }
188
- obj.public_methods(false).each { |m|
189
- if obj == Kernel #and obj.singleton_methods.include?(m)
190
- next
191
- end
192
- if !can_ignore?(obj, m)
193
- args = build_args obj.method(m)
194
- #ret = get_yard_return "#{obj}##{m}"
195
- #if !ret.nil?
196
- # code += "# @return [#{ret}]\n"
197
- #end
198
- code += "def #{m}#{args};end\n"
199
- end
200
- }
201
- obj.singleton_methods(false).each { |m|
202
- if !can_ignore?(obj, m)
203
- args = build_args obj.method(m)
204
- #ret = get_yard_return "#{obj}::#{m}"
205
- #if !ret.nil?
206
- # code += "# @return [#{ret}]\n"
207
- #end
208
- code += "def self.#{m}#{args};end\n"
209
- end
210
- }
211
- #obj.public_instance_methods(false).each { |m|
212
- obj.public_instance_methods(false).each { |m|
213
- #if !can_ignore?(obj, m)
214
- args = build_args obj.public_instance_method(m)
215
- #ret = get_yard_return "#{obj}##{m}"
216
- #if !ret.nil?
217
- # code += "# @return [#{ret}]\n"
218
- #end
219
- code += "def #{m}#{args};end\n"
220
- #end
221
- }
222
- code
223
- end
224
- def can_ignore?(obj, sym)
225
- #return false
226
- basics = [Kernel, Module, Object, BasicObject]
227
- return false if basics.include?(obj)
228
- result = false
229
- basics.each { |b|
230
- if b.respond_to?(sym)
231
- result = true
232
- break
233
- end
234
- }
235
- return result
236
- end
237
- def build_args method
238
- args = ""
239
- if (method.arity == -1)
240
- args = "(*args)"
241
- else
242
- arr = []
243
- num = 0
244
- method.parameters.each { |p|
245
- n = p[1]
246
- if n.to_s == ""
247
- n = "arg#{num}"
248
- end
249
- if p[0] == :req
250
- arr.push "#{n}"
251
- elsif p[0] == :opt
252
- arr.push "#{n} = nil"
253
- elsif p[0] == :rest
254
- arr.push "*#{n}"
255
- elsif p[0] == :block
256
- arr.push "&#{n}"
257
- end
258
- num += 1
259
- }
260
- args = "(" + arr.join(", ") + ")"
261
- end
262
- args
263
- end
264
- end
265
- end
@@ -1 +0,0 @@
1
- <p>Foo!</p>