solargraph 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/solargraph/api_map.rb +72 -58
- data/lib/solargraph/code_map.rb +25 -4
- data/lib/solargraph/server.rb +8 -1
- data/lib/solargraph/shell.rb +1 -1
- data/lib/solargraph/suggestion.rb +38 -18
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/yard_map.rb +30 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3993f33469901ac1b7d51659d9452a48adcd0e3f
|
4
|
+
data.tar.gz: de8f13ed8c39b332b7837fca4bcdfd8516ca8c1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0fdcec41d5a9b6920596d30f16a719948e74b3432b53584a0621b05f7c6d815e5bc5e69748737ef4c415db67061682babefeac0cf28c4cc73e69b8927b86b768
|
7
|
+
data.tar.gz: f6daf69d9d06dba1b7fea6e29ed5a2d8c336cfccbe3c33ab29cbb2fa05c79eca886f1e1474ed92ba5cc11a7eeb71ed6fbdedc5de96fc8ecd52c634fe91417209
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -24,6 +24,7 @@ module Solargraph
|
|
24
24
|
attr_reader :workspace
|
25
25
|
attr_reader :required
|
26
26
|
|
27
|
+
# @param workspace [String]
|
27
28
|
def initialize workspace = nil
|
28
29
|
@workspace = workspace.gsub(/\\/, '/') unless workspace.nil?
|
29
30
|
clear
|
@@ -38,6 +39,7 @@ module Solargraph
|
|
38
39
|
end
|
39
40
|
|
40
41
|
def clear
|
42
|
+
@file_source = {}
|
41
43
|
@file_nodes = {}
|
42
44
|
@file_comments = {}
|
43
45
|
@parent_stack = {}
|
@@ -46,15 +48,20 @@ module Solargraph
|
|
46
48
|
@required = []
|
47
49
|
end
|
48
50
|
|
51
|
+
# @return [Solargraph::YardMap]
|
49
52
|
def yard_map
|
50
53
|
@yard_map ||= YardMap.new(required: required, workspace: workspace)
|
51
54
|
end
|
52
55
|
|
56
|
+
# @param filename [String]
|
53
57
|
def append_file filename
|
54
58
|
append_source File.read(filename), filename
|
55
59
|
end
|
56
60
|
|
61
|
+
# @param text [String]
|
62
|
+
# @param filename [String]
|
57
63
|
def append_source text, filename = nil
|
64
|
+
@file_source[filename] = text
|
58
65
|
begin
|
59
66
|
node, comments = Parser::CurrentRuby.parse_with_comments(text)
|
60
67
|
append_node(node, comments, filename)
|
@@ -107,7 +114,6 @@ module Solargraph
|
|
107
114
|
@file_comments[filename][node.loc]
|
108
115
|
end
|
109
116
|
|
110
|
-
|
111
117
|
def self.get_keywords
|
112
118
|
result = []
|
113
119
|
keywords = KEYWORDS + ['attr_reader', 'attr_writer', 'attr_accessor', 'private', 'public', 'protected']
|
@@ -149,45 +155,6 @@ module Solargraph
|
|
149
155
|
result
|
150
156
|
end
|
151
157
|
|
152
|
-
def inner_namespaces_in name, root, skip
|
153
|
-
result = []
|
154
|
-
fqns = find_fully_qualified_namespace(name, root)
|
155
|
-
unless fqns.nil? or skip.include?(fqns)
|
156
|
-
skip.push fqns
|
157
|
-
nodes = get_namespace_nodes(fqns)
|
158
|
-
nodes.delete_if { |n| yardoc_has_file?(get_filename_for(n))}
|
159
|
-
unless nodes.empty?
|
160
|
-
cursor = @namespace_tree
|
161
|
-
parts = fqns.split('::')
|
162
|
-
parts.each { |p|
|
163
|
-
cursor = cursor[p]
|
164
|
-
}
|
165
|
-
unless cursor.nil?
|
166
|
-
cursor.keys.each { |k|
|
167
|
-
type = get_namespace_type(k, fqns)
|
168
|
-
kind = nil
|
169
|
-
detail = nil
|
170
|
-
if type == :class
|
171
|
-
kind = Suggestion::CLASS
|
172
|
-
detail = 'Class'
|
173
|
-
elsif type == :module
|
174
|
-
kind = Suggestion::MODULE
|
175
|
-
detail = 'Module'
|
176
|
-
end
|
177
|
-
result.push Suggestion.new(k, kind: kind, detail: detail)
|
178
|
-
}
|
179
|
-
nodes = get_namespace_nodes(fqns)
|
180
|
-
nodes.each { |n|
|
181
|
-
get_include_strings_from(n).each { |i|
|
182
|
-
result += inner_namespaces_in(i, fqns, skip)
|
183
|
-
}
|
184
|
-
}
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
result
|
189
|
-
end
|
190
|
-
|
191
158
|
def find_fully_qualified_namespace name, root = '', skip = []
|
192
159
|
return nil if skip.include?(root)
|
193
160
|
skip.push root
|
@@ -269,22 +236,6 @@ module Solargraph
|
|
269
236
|
@yardoc_files.include?(file)
|
270
237
|
end
|
271
238
|
|
272
|
-
def inner_get_instance_variables(node, scope)
|
273
|
-
arr = []
|
274
|
-
if node.kind_of?(AST::Node)
|
275
|
-
node.children.each { |c|
|
276
|
-
if c.kind_of?(AST::Node)
|
277
|
-
is_inst = !find_parent(c, :def).nil?
|
278
|
-
if c.type == :ivasgn and c.children[0] and ( (scope == :instance and is_inst) or (scope != :instance and !is_inst) )
|
279
|
-
arr.push Suggestion.new(c.children[0], kind: Suggestion::VARIABLE, documentation: get_comment_for(c))
|
280
|
-
end
|
281
|
-
arr += inner_get_instance_variables(c, scope) unless [:class, :module].include?(c.type)
|
282
|
-
end
|
283
|
-
}
|
284
|
-
end
|
285
|
-
arr
|
286
|
-
end
|
287
|
-
|
288
239
|
def infer_instance_variable(var, namespace, scope = :instance)
|
289
240
|
result = nil
|
290
241
|
vn = nil
|
@@ -418,11 +369,11 @@ module Solargraph
|
|
418
369
|
if c.type == :arg
|
419
370
|
args.push c.children[0]
|
420
371
|
elsif c.type == :optarg
|
421
|
-
args.push "#{c.children[0]} =
|
372
|
+
args.push "#{c.children[0]} = #{code_for(c.children[1])}"
|
422
373
|
elsif c.type == :kwarg
|
423
374
|
args.push "#{c.children[0]}:"
|
424
375
|
elsif c.type == :kwoptarg
|
425
|
-
args.push "#{c.children[0]}:
|
376
|
+
args.push "#{c.children[0]}: #{code_for(c.children[1])}"
|
426
377
|
end
|
427
378
|
}
|
428
379
|
args
|
@@ -607,6 +558,61 @@ module Solargraph
|
|
607
558
|
meths.uniq
|
608
559
|
end
|
609
560
|
|
561
|
+
def inner_namespaces_in name, root, skip
|
562
|
+
result = []
|
563
|
+
fqns = find_fully_qualified_namespace(name, root)
|
564
|
+
unless fqns.nil? or skip.include?(fqns)
|
565
|
+
skip.push fqns
|
566
|
+
nodes = get_namespace_nodes(fqns)
|
567
|
+
nodes.delete_if { |n| yardoc_has_file?(get_filename_for(n))}
|
568
|
+
unless nodes.empty?
|
569
|
+
cursor = @namespace_tree
|
570
|
+
parts = fqns.split('::')
|
571
|
+
parts.each { |p|
|
572
|
+
cursor = cursor[p]
|
573
|
+
}
|
574
|
+
unless cursor.nil?
|
575
|
+
cursor.keys.each { |k|
|
576
|
+
type = get_namespace_type(k, fqns)
|
577
|
+
kind = nil
|
578
|
+
detail = nil
|
579
|
+
if type == :class
|
580
|
+
kind = Suggestion::CLASS
|
581
|
+
detail = 'Class'
|
582
|
+
elsif type == :module
|
583
|
+
kind = Suggestion::MODULE
|
584
|
+
detail = 'Module'
|
585
|
+
end
|
586
|
+
result.push Suggestion.new(k, kind: kind, detail: detail)
|
587
|
+
}
|
588
|
+
nodes = get_namespace_nodes(fqns)
|
589
|
+
nodes.each { |n|
|
590
|
+
get_include_strings_from(n).each { |i|
|
591
|
+
result += inner_namespaces_in(i, fqns, skip)
|
592
|
+
}
|
593
|
+
}
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
result
|
598
|
+
end
|
599
|
+
|
600
|
+
def inner_get_instance_variables(node, scope)
|
601
|
+
arr = []
|
602
|
+
if node.kind_of?(AST::Node)
|
603
|
+
node.children.each { |c|
|
604
|
+
if c.kind_of?(AST::Node)
|
605
|
+
is_inst = !find_parent(c, :def).nil?
|
606
|
+
if c.type == :ivasgn and c.children[0] and ( (scope == :instance and is_inst) or (scope != :instance and !is_inst) )
|
607
|
+
arr.push Suggestion.new(c.children[0], kind: Suggestion::VARIABLE, documentation: get_comment_for(c))
|
608
|
+
end
|
609
|
+
arr += inner_get_instance_variables(c, scope) unless [:class, :module].include?(c.type)
|
610
|
+
end
|
611
|
+
}
|
612
|
+
end
|
613
|
+
arr
|
614
|
+
end
|
615
|
+
|
610
616
|
def mappable?(node)
|
611
617
|
return true if node.kind_of?(AST::Node) and [:array, :hash, :str, :int, :float].include?(node.type)
|
612
618
|
# TODO Add node.type :casgn (constant assignment)
|
@@ -728,5 +734,13 @@ module Solargraph
|
|
728
734
|
}
|
729
735
|
end
|
730
736
|
end
|
737
|
+
|
738
|
+
def code_for node
|
739
|
+
src = @file_source[get_filename_for(node)]
|
740
|
+
return nil if src.nil?
|
741
|
+
b = node.location.expression.begin.begin_pos
|
742
|
+
e = node.location.expression.end.end_pos
|
743
|
+
src[b..e].strip.gsub(/,$/, '')
|
744
|
+
end
|
731
745
|
end
|
732
746
|
end
|
data/lib/solargraph/code_map.rb
CHANGED
@@ -23,8 +23,8 @@ module Solargraph
|
|
23
23
|
# HACK: The current file is parsed with a trailing underscore to fix
|
24
24
|
# incomplete trees resulting from short scripts (e.g., a lone variable
|
25
25
|
# assignment).
|
26
|
-
node, comments = Parser::CurrentRuby.parse_with_comments(tmp + "\n_")
|
27
|
-
@node = self.api_map.append_node(node, comments, filename)
|
26
|
+
node, @comments = Parser::CurrentRuby.parse_with_comments(tmp + "\n_")
|
27
|
+
@node = self.api_map.append_node(node, @comments, filename)
|
28
28
|
@parsed = tmp
|
29
29
|
@code.freeze
|
30
30
|
@parsed.freeze
|
@@ -99,6 +99,16 @@ module Solargraph
|
|
99
99
|
n.kind_of?(AST::Node) and n.type == :str
|
100
100
|
end
|
101
101
|
|
102
|
+
# Determine if the specified index is inside a comment.
|
103
|
+
#
|
104
|
+
# @return [Boolean]
|
105
|
+
def comment_at?(index)
|
106
|
+
@comments.each do |c|
|
107
|
+
return true if index > c.location.expression.begin_pos and index <= c.location.expression.end_pos
|
108
|
+
end
|
109
|
+
false
|
110
|
+
end
|
111
|
+
|
102
112
|
def parent_node_from(index, *types)
|
103
113
|
arr = tree_at(index)
|
104
114
|
arr.each { |a|
|
@@ -178,7 +188,7 @@ module Solargraph
|
|
178
188
|
#
|
179
189
|
# @return [Array<Suggestions>] The completion suggestions
|
180
190
|
def suggest_at index, filtered: false, with_snippets: false
|
181
|
-
return [] if string_at?(index) or string_at?(index - 1)
|
191
|
+
return [] if string_at?(index) or string_at?(index - 1) or comment_at?(index)
|
182
192
|
result = []
|
183
193
|
phrase = phrase_at(index)
|
184
194
|
signature = get_signature_at(index)
|
@@ -387,6 +397,7 @@ module Solargraph
|
|
387
397
|
# @x.bar @x.bar
|
388
398
|
# y.split(', ').length y.split.length
|
389
399
|
#
|
400
|
+
# @param index [Integer]
|
390
401
|
# @return [String]
|
391
402
|
def get_signature_at index
|
392
403
|
brackets = 0
|
@@ -478,15 +489,25 @@ module Solargraph
|
|
478
489
|
private
|
479
490
|
|
480
491
|
def get_method_arguments_from node
|
492
|
+
param_hash = {}
|
493
|
+
cmnt = api_map.get_comment_for(node)
|
494
|
+
unless cmnt.nil?
|
495
|
+
tags = cmnt.tags(:param)
|
496
|
+
tags.each do |tag|
|
497
|
+
param_hash[tag.name] = tag.types[0]
|
498
|
+
end
|
499
|
+
end
|
481
500
|
result = []
|
482
501
|
args = node.children[1]
|
483
502
|
args.children.each do |arg|
|
484
503
|
name = arg.children[0].to_s
|
485
|
-
result.push Suggestion.new(name, kind: Suggestion::PROPERTY, insert: name)
|
504
|
+
result.push Suggestion.new(name, kind: Suggestion::PROPERTY, insert: name, return_type: param_hash[name])
|
486
505
|
end
|
487
506
|
result
|
488
507
|
end
|
489
508
|
|
509
|
+
# @param suggestions [Array<Solargraph::Suggestion>]
|
510
|
+
# @param word [String]
|
490
511
|
def reduce_starting_with(suggestions, word)
|
491
512
|
suggestions.reject { |s|
|
492
513
|
!s.label.start_with?(word)
|
data/lib/solargraph/server.rb
CHANGED
@@ -132,12 +132,19 @@ module Solargraph
|
|
132
132
|
end
|
133
133
|
|
134
134
|
class Helpers
|
135
|
+
include YARD::Templates::Helpers::HtmlHelper
|
136
|
+
|
135
137
|
attr_accessor :object
|
136
138
|
attr_accessor :serializer
|
137
|
-
|
139
|
+
|
140
|
+
def url_for(object)
|
141
|
+
'.'
|
142
|
+
end
|
143
|
+
|
138
144
|
def options
|
139
145
|
@options ||= YARD::Templates::TemplateOptions.new
|
140
146
|
end
|
147
|
+
|
141
148
|
# HACK: The linkify method just returns the arguments as plain text
|
142
149
|
def linkify *args
|
143
150
|
args.join(', ')
|
data/lib/solargraph/shell.rb
CHANGED
@@ -82,7 +82,7 @@ module Solargraph
|
|
82
82
|
|
83
83
|
desc 'config [DIRECTORY]', 'Create or overwrite a default configuration file'
|
84
84
|
def config(directory = '.')
|
85
|
-
File.open(File.join(directory, '.solargraph'), 'w') do |file|
|
85
|
+
File.open(File.join(directory, '.solargraph.yml'), 'w') do |file|
|
86
86
|
file.puts "include:",
|
87
87
|
" - ./**/*.rb",
|
88
88
|
"exclude:",
|
@@ -14,7 +14,7 @@ module Solargraph
|
|
14
14
|
|
15
15
|
attr_reader :label, :kind, :insert, :detail, :documentation, :code_object, :location, :arguments
|
16
16
|
|
17
|
-
def initialize label, kind: KEYWORD, insert: nil, detail: nil, documentation: nil, code_object: nil, location: nil, arguments: []
|
17
|
+
def initialize label, kind: KEYWORD, insert: nil, detail: nil, documentation: nil, code_object: nil, location: nil, arguments: [], return_type: nil
|
18
18
|
@helper = Server::Helpers.new
|
19
19
|
@label = label.to_s
|
20
20
|
@kind = kind
|
@@ -24,6 +24,7 @@ module Solargraph
|
|
24
24
|
@documentation = documentation
|
25
25
|
@location = location
|
26
26
|
@arguments = arguments
|
27
|
+
@return_type = return_type
|
27
28
|
end
|
28
29
|
|
29
30
|
def path
|
@@ -35,27 +36,28 @@ module Solargraph
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def return_type
|
38
|
-
if
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
if @return_type.nil?
|
40
|
+
if code_object.nil?
|
41
|
+
unless documentation.nil?
|
42
|
+
if documentation.kind_of?(YARD::Docstring)
|
43
|
+
t = documentation.tag(:return)
|
44
|
+
@return_type = t.types[0] unless t.nil? or t.types.nil?
|
45
|
+
else
|
46
|
+
match = documentation.match(/@return \[([a-z0-9:_]*)/i)
|
47
|
+
@return_type = match[1] unless match.nil?
|
48
|
+
end
|
47
49
|
end
|
48
|
-
end
|
49
|
-
else
|
50
|
-
o = code_object.tag(:overload)
|
51
|
-
if o.nil?
|
52
|
-
r = code_object.tag(:return)
|
53
50
|
else
|
54
|
-
|
51
|
+
o = code_object.tag(:overload)
|
52
|
+
if o.nil?
|
53
|
+
r = code_object.tag(:return)
|
54
|
+
else
|
55
|
+
r = o.tag(:return)
|
56
|
+
end
|
57
|
+
@return_type = r.types[0] unless r.nil? or r.types.nil?
|
55
58
|
end
|
56
|
-
return r.types[0] unless r.nil?
|
57
59
|
end
|
58
|
-
|
60
|
+
@return_type
|
59
61
|
end
|
60
62
|
|
61
63
|
def documentation
|
@@ -67,6 +69,23 @@ module Solargraph
|
|
67
69
|
@documentation
|
68
70
|
end
|
69
71
|
|
72
|
+
def params
|
73
|
+
if @params.nil?
|
74
|
+
@params = []
|
75
|
+
return @params if documentation.nil?
|
76
|
+
param_tags = documentation.tags(:param)
|
77
|
+
unless param_tags.empty?
|
78
|
+
param_tags.each do |t|
|
79
|
+
txt = t.name
|
80
|
+
txt += " [#{t.types.join(',')}]" unless t.types.nil? or t.types.empty?
|
81
|
+
txt += " #{t.text}" unless t.text.nil? or t.text.empty?
|
82
|
+
@params.push txt
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
@params
|
87
|
+
end
|
88
|
+
|
70
89
|
def to_json args={}
|
71
90
|
obj = {
|
72
91
|
label: @label,
|
@@ -76,6 +95,7 @@ module Solargraph
|
|
76
95
|
path: path,
|
77
96
|
location: (@location.nil? ? nil : @location.to_s),
|
78
97
|
arguments: @arguments,
|
98
|
+
params: params,
|
79
99
|
return_type: return_type,
|
80
100
|
documentation: @helper.html_markup_rdoc(documentation.to_s)
|
81
101
|
}
|
data/lib/solargraph/version.rb
CHANGED
data/lib/solargraph/yard_map.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'parser/current'
|
3
3
|
require 'yard'
|
4
|
+
require 'bundler'
|
4
5
|
|
5
6
|
module Solargraph
|
6
7
|
|
7
8
|
class YardMap
|
8
9
|
autoload :Cache, 'solargraph/yard_map/cache'
|
9
10
|
|
10
|
-
|
11
|
+
attr_reader :workspace
|
12
|
+
|
13
|
+
def initialize required: [], workspace: nil, with_bundled: false
|
14
|
+
@workspace = workspace
|
11
15
|
unless workspace.nil?
|
12
16
|
wsy = File.join(workspace, '.yardoc')
|
13
17
|
yardocs.push wsy if File.exist?(wsy)
|
@@ -22,16 +26,35 @@ module Solargraph
|
|
22
26
|
if gy.nil?
|
23
27
|
STDERR.puts "Required path not found: #{r}"
|
24
28
|
else
|
25
|
-
|
29
|
+
STDERR.puts "Adding #{gy}"
|
30
|
+
yardocs.unshift gy
|
26
31
|
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
}
|
30
35
|
yardocs.push File.join(Dir.home, '.solargraph', 'cache', '2.0.0', 'yardoc')
|
31
36
|
yardocs.uniq!
|
37
|
+
include_bundled_gems if with_bundled
|
32
38
|
cache_core
|
33
39
|
end
|
34
40
|
|
41
|
+
def include_bundled_gems
|
42
|
+
return if workspace.nil?
|
43
|
+
lockfile = File.join(workspace, 'Gemfile.lock')
|
44
|
+
return unless File.file?(lockfile)
|
45
|
+
parser = Bundler::LockfileParser.new(Bundler.read_file(lockfile))
|
46
|
+
parser.specs.each do |s|
|
47
|
+
STDERR.puts "Specs include #{s.name}"
|
48
|
+
gy = YARD::Registry.yardoc_file_for_gem(s.name)
|
49
|
+
if gy.nil?
|
50
|
+
STDERR.puts "Bundled gem not found: #{s.name}"
|
51
|
+
else
|
52
|
+
yardocs.unshift gy unless yardocs.include?(gy)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Array<String>]
|
35
58
|
def yardocs
|
36
59
|
@yardocs ||= []
|
37
60
|
end
|
@@ -50,6 +73,7 @@ module Solargraph
|
|
50
73
|
end
|
51
74
|
end
|
52
75
|
|
76
|
+
# @param query [String]
|
53
77
|
def search query
|
54
78
|
found = []
|
55
79
|
yardocs.each { |y|
|
@@ -63,6 +87,7 @@ module Solargraph
|
|
63
87
|
found.sort
|
64
88
|
end
|
65
89
|
|
90
|
+
# @param query [String]
|
66
91
|
def document query
|
67
92
|
found = []
|
68
93
|
yardocs.each { |y|
|
@@ -109,6 +134,7 @@ module Solargraph
|
|
109
134
|
result
|
110
135
|
end
|
111
136
|
|
137
|
+
# @param signature [String]
|
112
138
|
def at signature
|
113
139
|
yardocs.each { |y|
|
114
140
|
yard = load_yardoc(y)
|
@@ -120,6 +146,8 @@ module Solargraph
|
|
120
146
|
nil
|
121
147
|
end
|
122
148
|
|
149
|
+
# @param signature [String]
|
150
|
+
# @param scope [String]
|
123
151
|
def resolve signature, scope
|
124
152
|
yardocs.each { |y|
|
125
153
|
yard = load_yardoc(y)
|
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.9.
|
4
|
+
version: 0.9.1
|
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-
|
11
|
+
date: 2017-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|