solargraph 0.32.1 → 0.32.2
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 +4 -4
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +25 -0
- data/EXAMPLES.md +76 -0
- data/Gemfile +3 -0
- data/LANGUAGE_SERVER.md +51 -0
- data/LICENSE +21 -0
- data/OVERVIEW.md +37 -0
- data/README.md +106 -0
- data/Rakefile +14 -0
- data/SERVER.md +95 -0
- data/bin/solargraph +0 -0
- data/bin/solargraph-runtime +5 -5
- data/lib/solargraph.rb +54 -54
- data/lib/solargraph/api_map.rb +659 -659
- data/lib/solargraph/api_map/cache.rb +49 -49
- data/lib/solargraph/api_map/source_to_yard.rb +67 -67
- data/lib/solargraph/api_map/store.rb +201 -201
- data/lib/solargraph/bundle.rb +24 -24
- data/lib/solargraph/complex_type.rb +150 -150
- data/lib/solargraph/complex_type/type_methods.rb +124 -124
- data/lib/solargraph/complex_type/unique_type.rb +44 -44
- data/lib/solargraph/core_fills.rb +37 -37
- data/lib/solargraph/diagnostics.rb +52 -52
- data/lib/solargraph/diagnostics/base.rb +20 -20
- data/lib/solargraph/diagnostics/require_not_found.rb +28 -28
- data/lib/solargraph/diagnostics/rubocop.rb +98 -98
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +46 -46
- data/lib/solargraph/diagnostics/type_not_defined.rb +108 -108
- data/lib/solargraph/diagnostics/update_errors.rb +38 -38
- data/lib/solargraph/language_server/completion_item_kinds.rb +33 -33
- data/lib/solargraph/language_server/error_codes.rb +18 -18
- data/lib/solargraph/language_server/host.rb +684 -681
- data/lib/solargraph/language_server/host/cataloger.rb +54 -79
- data/lib/solargraph/language_server/host/diagnoser.rb +80 -80
- data/lib/solargraph/language_server/host/dispatch.rb +112 -113
- data/lib/solargraph/language_server/host/sources.rb +138 -138
- data/lib/solargraph/language_server/message.rb +90 -90
- data/lib/solargraph/language_server/message/base.rb +83 -83
- data/lib/solargraph/language_server/message/completion_item/resolve.rb +40 -40
- data/lib/solargraph/language_server/message/exit_notification.rb +11 -11
- data/lib/solargraph/language_server/message/extended.rb +19 -19
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +86 -86
- data/lib/solargraph/language_server/message/extended/document.rb +18 -18
- data/lib/solargraph/language_server/message/extended/document_gems.rb +30 -30
- data/lib/solargraph/language_server/message/extended/environment.rb +20 -20
- data/lib/solargraph/language_server/message/extended/search.rb +18 -18
- data/lib/solargraph/language_server/message/initialize.rb +141 -141
- data/lib/solargraph/language_server/message/initialized.rb +23 -23
- data/lib/solargraph/language_server/message/shutdown.rb +11 -11
- data/lib/solargraph/language_server/message/text_document.rb +25 -25
- data/lib/solargraph/language_server/message/text_document/completion.rb +51 -51
- data/lib/solargraph/language_server/message/text_document/definition.rb +18 -18
- data/lib/solargraph/language_server/message/text_document/did_change.rb +13 -13
- data/lib/solargraph/language_server/message/text_document/document_symbol.rb +21 -21
- data/lib/solargraph/language_server/message/text_document/folding_range.rb +24 -24
- data/lib/solargraph/language_server/message/text_document/formatting.rb +50 -50
- data/lib/solargraph/language_server/message/text_document/hover.rb +31 -31
- data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +32 -32
- data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +9 -9
- data/lib/solargraph/language_server/message/text_document/references.rb +14 -14
- data/lib/solargraph/language_server/message/text_document/rename.rb +17 -17
- data/lib/solargraph/language_server/message/text_document/signature_help.rb +19 -19
- data/lib/solargraph/language_server/message/workspace.rb +12 -12
- data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +29 -29
- data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +29 -27
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -24
- data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +21 -21
- data/lib/solargraph/language_server/request.rb +22 -22
- data/lib/solargraph/language_server/symbol_kinds.rb +34 -34
- data/lib/solargraph/language_server/transport.rb +11 -11
- data/lib/solargraph/language_server/transport/adapter.rb +60 -60
- data/lib/solargraph/language_server/transport/data_reader.rb +66 -66
- data/lib/solargraph/language_server/uri_helpers.rb +25 -25
- data/lib/solargraph/library.rb +421 -419
- data/lib/solargraph/live_map.rb +126 -126
- data/lib/solargraph/live_map/cache.rb +38 -38
- data/lib/solargraph/location.rb +31 -31
- data/lib/solargraph/logging.rb +25 -25
- data/lib/solargraph/page.rb +68 -68
- data/lib/solargraph/pin.rb +50 -50
- data/lib/solargraph/pin/attribute.rb +41 -41
- data/lib/solargraph/pin/base.rb +280 -280
- data/lib/solargraph/pin/base_method.rb +76 -76
- data/lib/solargraph/pin/base_variable.rb +72 -72
- data/lib/solargraph/pin/block.rb +32 -32
- data/lib/solargraph/pin/block_parameter.rb +103 -103
- data/lib/solargraph/pin/class_variable.rb +9 -9
- data/lib/solargraph/pin/constant.rb +30 -30
- data/lib/solargraph/pin/conversions.rb +79 -79
- data/lib/solargraph/pin/documenting.rb +41 -41
- data/lib/solargraph/pin/duck_method.rb +14 -14
- data/lib/solargraph/pin/global_variable.rb +9 -9
- data/lib/solargraph/pin/instance_variable.rb +9 -9
- data/lib/solargraph/pin/keyword.rb +17 -17
- data/lib/solargraph/pin/local_variable.rb +23 -23
- data/lib/solargraph/pin/localized.rb +22 -22
- data/lib/solargraph/pin/method.rb +126 -126
- data/lib/solargraph/pin/method_alias.rb +30 -30
- data/lib/solargraph/pin/method_parameter.rb +40 -40
- data/lib/solargraph/pin/namespace.rb +54 -54
- data/lib/solargraph/pin/plugin/method.rb +25 -25
- data/lib/solargraph/pin/proxy_type.rb +35 -35
- data/lib/solargraph/pin/reference.rb +22 -22
- data/lib/solargraph/pin/reference/extend.rb +11 -11
- data/lib/solargraph/pin/reference/include.rb +11 -11
- data/lib/solargraph/pin/reference/require.rb +15 -15
- data/lib/solargraph/pin/reference/superclass.rb +11 -11
- data/lib/solargraph/pin/symbol.rb +44 -44
- data/lib/solargraph/pin/yard_pin.rb +10 -10
- data/lib/solargraph/pin/yard_pin/constant.rb +14 -14
- data/lib/solargraph/pin/yard_pin/method.rb +35 -35
- data/lib/solargraph/pin/yard_pin/namespace.rb +19 -19
- data/lib/solargraph/pin/yard_pin/yard_mixin.rb +14 -14
- data/lib/solargraph/plugin.rb +8 -8
- data/lib/solargraph/plugin/base.rb +41 -41
- data/lib/solargraph/plugin/canceler.rb +11 -11
- data/lib/solargraph/plugin/process.rb +172 -172
- data/lib/solargraph/plugin/runtime.rb +134 -134
- data/lib/solargraph/position.rb +110 -110
- data/lib/solargraph/range.rb +83 -83
- data/lib/solargraph/server_methods.rb +14 -14
- data/lib/solargraph/shell.rb +102 -102
- data/lib/solargraph/source.rb +521 -521
- data/lib/solargraph/source/chain.rb +120 -120
- data/lib/solargraph/source/chain/call.rb +107 -107
- data/lib/solargraph/source/chain/class_variable.rb +11 -11
- data/lib/solargraph/source/chain/constant.rb +30 -30
- data/lib/solargraph/source/chain/global_variable.rb +11 -11
- data/lib/solargraph/source/chain/head.rb +33 -33
- data/lib/solargraph/source/chain/instance_variable.rb +11 -11
- data/lib/solargraph/source/chain/link.rb +33 -33
- data/lib/solargraph/source/chain/literal.rb +21 -21
- data/lib/solargraph/source/chain/variable.rb +11 -11
- data/lib/solargraph/source/change.rb +77 -77
- data/lib/solargraph/source/cursor.rb +157 -157
- data/lib/solargraph/source/node_chainer.rb +96 -96
- data/lib/solargraph/source/node_methods.rb +225 -225
- data/lib/solargraph/source/source_chainer.rb +183 -183
- data/lib/solargraph/source_map.rb +169 -169
- data/lib/solargraph/source_map/clip.rb +145 -145
- data/lib/solargraph/source_map/completion.rb +21 -21
- data/lib/solargraph/source_map/mapper.rb +149 -149
- data/lib/solargraph/source_map/node_processor.rb +78 -78
- data/lib/solargraph/source_map/node_processor/alias_node.rb +19 -19
- data/lib/solargraph/source_map/node_processor/args_node.rb +28 -28
- data/lib/solargraph/source_map/node_processor/base.rb +68 -68
- data/lib/solargraph/source_map/node_processor/begin_node.rb +11 -11
- data/lib/solargraph/source_map/node_processor/block_node.rb +14 -14
- data/lib/solargraph/source_map/node_processor/casgn_node.rb +14 -14
- data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +14 -14
- data/lib/solargraph/source_map/node_processor/def_node.rb +54 -54
- data/lib/solargraph/source_map/node_processor/defs_node.rb +21 -21
- data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +12 -12
- data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +18 -18
- data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +16 -16
- data/lib/solargraph/source_map/node_processor/namespace_node.rb +26 -26
- data/lib/solargraph/source_map/node_processor/orasgn_node.rb +12 -12
- data/lib/solargraph/source_map/node_processor/sclass_node.rb +11 -11
- data/lib/solargraph/source_map/node_processor/send_node.rb +162 -162
- data/lib/solargraph/source_map/node_processor/sym_node.rb +11 -11
- data/lib/solargraph/source_map/region.rb +58 -58
- data/lib/solargraph/version.rb +3 -3
- data/lib/solargraph/views/environment.erb +53 -53
- data/lib/solargraph/workspace.rb +183 -183
- data/lib/solargraph/workspace/config.rb +170 -170
- data/lib/solargraph/yard_map.rb +298 -298
- data/lib/solargraph/yard_map/cache.rb +17 -17
- data/lib/solargraph/yard_map/core_docs.rb +163 -163
- data/lib/solargraph/yard_map/core_gen.rb +76 -76
- data/lib/yard-coregen.rb +16 -16
- data/lib/yard-solargraph.rb +18 -18
- data/solargraph.gemspec +37 -0
- data/travis-bundler.rb +10 -0
- metadata +19 -6
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
require 'jaro_winkler'
|
|
2
|
-
|
|
3
|
-
module Solargraph
|
|
4
|
-
# An index of pins and other ApiMap-related data for a Source.
|
|
5
|
-
#
|
|
6
|
-
class SourceMap
|
|
7
|
-
autoload :NodeProcessor, 'solargraph/source_map/node_processor'
|
|
8
|
-
autoload :Mapper, 'solargraph/source_map/mapper'
|
|
9
|
-
autoload :Clip, 'solargraph/source_map/clip'
|
|
10
|
-
autoload :Completion, 'solargraph/source_map/completion'
|
|
11
|
-
autoload :Region, 'solargraph/source_map/region'
|
|
12
|
-
|
|
13
|
-
# @return [Source]
|
|
14
|
-
attr_reader :source
|
|
15
|
-
|
|
16
|
-
# @return [Array<Pin::Base>]
|
|
17
|
-
attr_reader :pins
|
|
18
|
-
|
|
19
|
-
# @return [Array<Pin::Base>]
|
|
20
|
-
attr_reader :locals
|
|
21
|
-
|
|
22
|
-
# @param source [Source]
|
|
23
|
-
# @param pins [Array<Pin::Base>]
|
|
24
|
-
# @param locals [Array<Pin::Base>]
|
|
25
|
-
def initialize source, pins, locals
|
|
26
|
-
# HACK: Keep the library from changing this
|
|
27
|
-
@source = source.dup
|
|
28
|
-
@pins = pins
|
|
29
|
-
@locals = locals
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# @return [String]
|
|
33
|
-
def filename
|
|
34
|
-
source.filename
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# @return [String]
|
|
38
|
-
def code
|
|
39
|
-
source.code
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# @return [Array<Pin::Reference::Require>]
|
|
43
|
-
def requires
|
|
44
|
-
@requires ||= pins.select{|p| p.kind == Pin::REQUIRE_REFERENCE}
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# @param position [Position, Array(Integer, Integer)]
|
|
48
|
-
# @return [Boolean]
|
|
49
|
-
def string_at? position
|
|
50
|
-
position = Position.normalize(position)
|
|
51
|
-
@source.string_at?(position)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# @param position [Position, Array(Integer, Integer)]
|
|
55
|
-
# @return [Boolean]
|
|
56
|
-
def comment_at? position
|
|
57
|
-
position = Position.normalize(position)
|
|
58
|
-
@source.comment_at?(position)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# @return [Array<Pin::Base>]
|
|
62
|
-
def document_symbols
|
|
63
|
-
@document_symbols ||= pins.select { |pin|
|
|
64
|
-
[Pin::ATTRIBUTE, Pin::CONSTANT, Pin::METHOD, Pin::NAMESPACE].include?(pin.kind) and !pin.path.empty?
|
|
65
|
-
}
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# @param query [String]
|
|
69
|
-
# @return [Array<Pin::Base>]
|
|
70
|
-
def query_symbols query
|
|
71
|
-
document_symbols.select{ |pin| fuzzy_string_match(pin.path, query) || fuzzy_string_match(pin.name, query) }
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# @param position [Position]
|
|
75
|
-
# @return [Solargraph::SourceMap::Fragment]
|
|
76
|
-
def cursor_at position
|
|
77
|
-
Source::Cursor.new(source, position)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# @param path [String]
|
|
81
|
-
# @return [Pin::Base]
|
|
82
|
-
def first_pin path
|
|
83
|
-
pins.select { |p| p.path == path }.first
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# @param location [Solargraph::Location]
|
|
87
|
-
# @return [Array<Solargraph::Pin::Base>]
|
|
88
|
-
def locate_pins location
|
|
89
|
-
# return nil unless location.start_with?("#{filename}:")
|
|
90
|
-
pins.select { |pin| pin.location == location }
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def locate_named_path_pin line, character
|
|
94
|
-
_locate_pin line, character, Pin::NAMESPACE, Pin::METHOD
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def locate_block_pin line, character
|
|
98
|
-
_locate_pin line, character, Pin::NAMESPACE, Pin::METHOD, Pin::BLOCK
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# @param other_map [SourceMap]
|
|
102
|
-
# @return [Boolean]
|
|
103
|
-
def try_merge! other_map
|
|
104
|
-
return false if pins.length != other_map.pins.length || locals.length != other_map.locals.length || requires.map(&:name).uniq.sort != other_map.requires.map(&:name).uniq.sort
|
|
105
|
-
pins.each_index do |i|
|
|
106
|
-
return false unless pins[i].try_merge!(other_map.pins[i])
|
|
107
|
-
end
|
|
108
|
-
locals.each_index do |i|
|
|
109
|
-
return false unless locals[i].try_merge!(other_map.locals[i])
|
|
110
|
-
end
|
|
111
|
-
@source = other_map.source
|
|
112
|
-
true
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# @param name [String]
|
|
116
|
-
# @return [Array<Location>]
|
|
117
|
-
def references name
|
|
118
|
-
source.references name
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
class << self
|
|
122
|
-
# @param filename [String]
|
|
123
|
-
# @return [SourceMap]
|
|
124
|
-
def load filename
|
|
125
|
-
source = Solargraph::Source.load(filename)
|
|
126
|
-
SourceMap.map(source)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# @param code [String]
|
|
130
|
-
# @param filename [String, nil]
|
|
131
|
-
# @return [SourceMap]
|
|
132
|
-
def load_string code, filename = nil
|
|
133
|
-
source = Solargraph::Source.load_string(code, filename)
|
|
134
|
-
SourceMap.map(source)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# @param source [Source]
|
|
138
|
-
# @return [SourceMap]
|
|
139
|
-
def map source
|
|
140
|
-
result = SourceMap::Mapper.map(source)
|
|
141
|
-
new(source, *result)
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
private
|
|
146
|
-
|
|
147
|
-
# @param line [Integer]
|
|
148
|
-
# @param character [Integer]
|
|
149
|
-
# @param *kinds [Array<Symbol>]
|
|
150
|
-
# @return [Pin::Base]
|
|
151
|
-
def _locate_pin line, character, *kinds
|
|
152
|
-
position = Position.new(line, character)
|
|
153
|
-
found = nil
|
|
154
|
-
pins.each do |pin|
|
|
155
|
-
found = pin if (kinds.empty? || kinds.include?(pin.kind)) && pin.location.range.contain?(position)
|
|
156
|
-
break if pin.location.range.start.line > line
|
|
157
|
-
end
|
|
158
|
-
# @todo Assuming the root pin is always valid
|
|
159
|
-
found || pins.first
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
# @param str1 [String]
|
|
163
|
-
# @param str2 [String]
|
|
164
|
-
# @return [Boolean]
|
|
165
|
-
def fuzzy_string_match str1, str2
|
|
166
|
-
JaroWinkler.distance(str1, str2) > 0.6
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
end
|
|
1
|
+
require 'jaro_winkler'
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
# An index of pins and other ApiMap-related data for a Source.
|
|
5
|
+
#
|
|
6
|
+
class SourceMap
|
|
7
|
+
autoload :NodeProcessor, 'solargraph/source_map/node_processor'
|
|
8
|
+
autoload :Mapper, 'solargraph/source_map/mapper'
|
|
9
|
+
autoload :Clip, 'solargraph/source_map/clip'
|
|
10
|
+
autoload :Completion, 'solargraph/source_map/completion'
|
|
11
|
+
autoload :Region, 'solargraph/source_map/region'
|
|
12
|
+
|
|
13
|
+
# @return [Source]
|
|
14
|
+
attr_reader :source
|
|
15
|
+
|
|
16
|
+
# @return [Array<Pin::Base>]
|
|
17
|
+
attr_reader :pins
|
|
18
|
+
|
|
19
|
+
# @return [Array<Pin::Base>]
|
|
20
|
+
attr_reader :locals
|
|
21
|
+
|
|
22
|
+
# @param source [Source]
|
|
23
|
+
# @param pins [Array<Pin::Base>]
|
|
24
|
+
# @param locals [Array<Pin::Base>]
|
|
25
|
+
def initialize source, pins, locals
|
|
26
|
+
# HACK: Keep the library from changing this
|
|
27
|
+
@source = source.dup
|
|
28
|
+
@pins = pins
|
|
29
|
+
@locals = locals
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @return [String]
|
|
33
|
+
def filename
|
|
34
|
+
source.filename
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @return [String]
|
|
38
|
+
def code
|
|
39
|
+
source.code
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [Array<Pin::Reference::Require>]
|
|
43
|
+
def requires
|
|
44
|
+
@requires ||= pins.select{|p| p.kind == Pin::REQUIRE_REFERENCE}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @param position [Position, Array(Integer, Integer)]
|
|
48
|
+
# @return [Boolean]
|
|
49
|
+
def string_at? position
|
|
50
|
+
position = Position.normalize(position)
|
|
51
|
+
@source.string_at?(position)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @param position [Position, Array(Integer, Integer)]
|
|
55
|
+
# @return [Boolean]
|
|
56
|
+
def comment_at? position
|
|
57
|
+
position = Position.normalize(position)
|
|
58
|
+
@source.comment_at?(position)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [Array<Pin::Base>]
|
|
62
|
+
def document_symbols
|
|
63
|
+
@document_symbols ||= pins.select { |pin|
|
|
64
|
+
[Pin::ATTRIBUTE, Pin::CONSTANT, Pin::METHOD, Pin::NAMESPACE].include?(pin.kind) and !pin.path.empty?
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @param query [String]
|
|
69
|
+
# @return [Array<Pin::Base>]
|
|
70
|
+
def query_symbols query
|
|
71
|
+
document_symbols.select{ |pin| fuzzy_string_match(pin.path, query) || fuzzy_string_match(pin.name, query) }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @param position [Position]
|
|
75
|
+
# @return [Solargraph::SourceMap::Fragment]
|
|
76
|
+
def cursor_at position
|
|
77
|
+
Source::Cursor.new(source, position)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @param path [String]
|
|
81
|
+
# @return [Pin::Base]
|
|
82
|
+
def first_pin path
|
|
83
|
+
pins.select { |p| p.path == path }.first
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @param location [Solargraph::Location]
|
|
87
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
88
|
+
def locate_pins location
|
|
89
|
+
# return nil unless location.start_with?("#{filename}:")
|
|
90
|
+
pins.select { |pin| pin.location == location }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def locate_named_path_pin line, character
|
|
94
|
+
_locate_pin line, character, Pin::NAMESPACE, Pin::METHOD
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def locate_block_pin line, character
|
|
98
|
+
_locate_pin line, character, Pin::NAMESPACE, Pin::METHOD, Pin::BLOCK
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @param other_map [SourceMap]
|
|
102
|
+
# @return [Boolean]
|
|
103
|
+
def try_merge! other_map
|
|
104
|
+
return false if pins.length != other_map.pins.length || locals.length != other_map.locals.length || requires.map(&:name).uniq.sort != other_map.requires.map(&:name).uniq.sort
|
|
105
|
+
pins.each_index do |i|
|
|
106
|
+
return false unless pins[i].try_merge!(other_map.pins[i])
|
|
107
|
+
end
|
|
108
|
+
locals.each_index do |i|
|
|
109
|
+
return false unless locals[i].try_merge!(other_map.locals[i])
|
|
110
|
+
end
|
|
111
|
+
@source = other_map.source
|
|
112
|
+
true
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @param name [String]
|
|
116
|
+
# @return [Array<Location>]
|
|
117
|
+
def references name
|
|
118
|
+
source.references name
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class << self
|
|
122
|
+
# @param filename [String]
|
|
123
|
+
# @return [SourceMap]
|
|
124
|
+
def load filename
|
|
125
|
+
source = Solargraph::Source.load(filename)
|
|
126
|
+
SourceMap.map(source)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @param code [String]
|
|
130
|
+
# @param filename [String, nil]
|
|
131
|
+
# @return [SourceMap]
|
|
132
|
+
def load_string code, filename = nil
|
|
133
|
+
source = Solargraph::Source.load_string(code, filename)
|
|
134
|
+
SourceMap.map(source)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# @param source [Source]
|
|
138
|
+
# @return [SourceMap]
|
|
139
|
+
def map source
|
|
140
|
+
result = SourceMap::Mapper.map(source)
|
|
141
|
+
new(source, *result)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private
|
|
146
|
+
|
|
147
|
+
# @param line [Integer]
|
|
148
|
+
# @param character [Integer]
|
|
149
|
+
# @param *kinds [Array<Symbol>]
|
|
150
|
+
# @return [Pin::Base]
|
|
151
|
+
def _locate_pin line, character, *kinds
|
|
152
|
+
position = Position.new(line, character)
|
|
153
|
+
found = nil
|
|
154
|
+
pins.each do |pin|
|
|
155
|
+
found = pin if (kinds.empty? || kinds.include?(pin.kind)) && pin.location.range.contain?(position)
|
|
156
|
+
break if pin.location.range.start.line > line
|
|
157
|
+
end
|
|
158
|
+
# @todo Assuming the root pin is always valid
|
|
159
|
+
found || pins.first
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# @param str1 [String]
|
|
163
|
+
# @param str2 [String]
|
|
164
|
+
# @return [Boolean]
|
|
165
|
+
def fuzzy_string_match str1, str2
|
|
166
|
+
JaroWinkler.distance(str1, str2) > 0.6
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -1,145 +1,145 @@
|
|
|
1
|
-
module Solargraph
|
|
2
|
-
class SourceMap
|
|
3
|
-
# A static analysis tool for obtaining definitions, completions,
|
|
4
|
-
# signatures, and type inferences from a cursor.
|
|
5
|
-
#
|
|
6
|
-
class Clip
|
|
7
|
-
# @param api_map [ApiMap]
|
|
8
|
-
# @param cursor [Source::Cursor]
|
|
9
|
-
def initialize api_map, cursor
|
|
10
|
-
@api_map = api_map
|
|
11
|
-
@cursor = cursor
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# @return [Array<Pin::Base>]
|
|
15
|
-
def define
|
|
16
|
-
return [] if cursor.comment? || cursor.chain.literal?
|
|
17
|
-
result = cursor.chain.define(api_map, context_pin, locals)
|
|
18
|
-
result.concat((source_map.pins + source_map.locals).select{ |p| p.name == cursor.word && p.location.range.contain?(cursor.position) }) if result.empty?
|
|
19
|
-
result
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# @return [Completion]
|
|
23
|
-
def complete
|
|
24
|
-
return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
|
|
25
|
-
return Completion.new([], cursor.range) if cursor.chain.literal? || cursor.comment?
|
|
26
|
-
result = []
|
|
27
|
-
if cursor.chain.constant? || cursor.start_of_constant?
|
|
28
|
-
if cursor.chain.undefined?
|
|
29
|
-
type = cursor.chain.base.infer(api_map, context_pin, locals)
|
|
30
|
-
else
|
|
31
|
-
full = cursor.chain.links.first.word
|
|
32
|
-
if full.include?('::') && cursor.chain.links.length == 1
|
|
33
|
-
type = ComplexType.try_parse(full.split('::')[0..-2].join('::'))
|
|
34
|
-
elsif cursor.chain.links.length > 1
|
|
35
|
-
type = ComplexType.try_parse(full)
|
|
36
|
-
else
|
|
37
|
-
type = ComplexType::UNDEFINED
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
result.concat api_map.get_constants(type.undefined? ? '' : type.namespace, cursor.start_of_constant? ? '' : context_pin.context.namespace)
|
|
41
|
-
else
|
|
42
|
-
type = cursor.chain.base.infer(api_map, context_pin, locals)
|
|
43
|
-
result.concat api_map.get_complex_type_methods(type, context_pin.context.namespace, cursor.chain.links.length == 1)
|
|
44
|
-
if cursor.chain.links.length == 1
|
|
45
|
-
if cursor.word.start_with?('@@')
|
|
46
|
-
return package_completions(api_map.get_class_variable_pins(context_pin.context.namespace))
|
|
47
|
-
elsif cursor.word.start_with?('@')
|
|
48
|
-
return package_completions(api_map.get_instance_variable_pins(context_pin.context.namespace, context_pin.context.scope))
|
|
49
|
-
elsif cursor.word.start_with?('$')
|
|
50
|
-
return package_completions(api_map.get_global_variable_pins)
|
|
51
|
-
end
|
|
52
|
-
result.concat locals
|
|
53
|
-
result.concat api_map.get_constants('', context_pin.context.namespace)
|
|
54
|
-
result.concat api_map.get_methods(context_pin.context.namespace, scope: context_pin.context.scope, visibility: [:public, :private, :protected])
|
|
55
|
-
result.concat api_map.get_methods('Kernel')
|
|
56
|
-
result.concat ApiMap.keywords
|
|
57
|
-
result.concat yielded_self_pins
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
package_completions(result)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# @return [Array<Pin::Base>]
|
|
64
|
-
def signify
|
|
65
|
-
return [] unless cursor.argument?
|
|
66
|
-
clip = Clip.new(api_map, cursor.recipient)
|
|
67
|
-
clip.define.select{|pin| pin.kind == Pin::METHOD}
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# @return [ComplexType]
|
|
71
|
-
def infer
|
|
72
|
-
cursor.chain.infer(api_map, context_pin, locals)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Get an array of all the locals that are visible from the cursors's
|
|
76
|
-
# position. Locals can be local variables, method parameters, or block
|
|
77
|
-
# parameters. The array starts with the nearest local pin.
|
|
78
|
-
#
|
|
79
|
-
# @return [Array<Solargraph::Pin::Base>]
|
|
80
|
-
def locals
|
|
81
|
-
loc_pos = context_pin.location.range.contain?(cursor.position) ? cursor.position : context_pin.location.range.ending
|
|
82
|
-
adj_pos = Position.new(loc_pos.line, (loc_pos.column.zero? ? 0 : loc_pos.column - 1))
|
|
83
|
-
@locals ||= source_map.locals.select { |pin|
|
|
84
|
-
pin.visible_from?(block, adj_pos)
|
|
85
|
-
}.reverse
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
private
|
|
89
|
-
|
|
90
|
-
# @return [ApiMap]
|
|
91
|
-
attr_reader :api_map
|
|
92
|
-
|
|
93
|
-
# @return [Source::Cursor]
|
|
94
|
-
attr_reader :cursor
|
|
95
|
-
|
|
96
|
-
# @return [SourceMap]
|
|
97
|
-
def source_map
|
|
98
|
-
@source_map ||= api_map.source_map(cursor.filename)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
# @return [Solargraph::Pin::Base]
|
|
102
|
-
def block
|
|
103
|
-
@block ||= source_map.locate_block_pin(cursor.node_position.line, cursor.node_position.character)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# The context at the current position.
|
|
107
|
-
#
|
|
108
|
-
# @return [Pin::Base]
|
|
109
|
-
def context_pin
|
|
110
|
-
@context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# @return [Array<Pin::Base>]
|
|
114
|
-
def yielded_self_pins
|
|
115
|
-
return [] unless block.is_a?(Pin::Block) && block.receiver
|
|
116
|
-
chain = Solargraph::Source::NodeChainer.chain(block.receiver, source_map.source.filename)
|
|
117
|
-
receiver_pin = chain.define(api_map, context_pin, locals).first
|
|
118
|
-
return [] if receiver_pin.nil?
|
|
119
|
-
result = []
|
|
120
|
-
ys = receiver_pin.docstring.tag(:yieldself)
|
|
121
|
-
unless ys.nil? || ys.types.empty?
|
|
122
|
-
ysct = ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
|
|
123
|
-
result.concat api_map.get_complex_type_methods(ysct, ysct.namespace, true)
|
|
124
|
-
end
|
|
125
|
-
ys = receiver_pin.docstring.tag(:yieldpublic)
|
|
126
|
-
unless ys.nil? || ys.types.empty?
|
|
127
|
-
ysct = ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
|
|
128
|
-
result.concat api_map.get_complex_type_methods(ysct, '', false)
|
|
129
|
-
end
|
|
130
|
-
result
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# @param result [Array<Pin::Base>]
|
|
134
|
-
# @return [Completion]
|
|
135
|
-
def package_completions result
|
|
136
|
-
frag_start = cursor.start_of_word.to_s.downcase
|
|
137
|
-
filtered = result.uniq(&:name).select { |s|
|
|
138
|
-
s.name.downcase.start_with?(frag_start) &&
|
|
139
|
-
(s.kind != Pin::METHOD || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
|
|
140
|
-
}
|
|
141
|
-
Completion.new(filtered, cursor.range)
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
end
|
|
1
|
+
module Solargraph
|
|
2
|
+
class SourceMap
|
|
3
|
+
# A static analysis tool for obtaining definitions, completions,
|
|
4
|
+
# signatures, and type inferences from a cursor.
|
|
5
|
+
#
|
|
6
|
+
class Clip
|
|
7
|
+
# @param api_map [ApiMap]
|
|
8
|
+
# @param cursor [Source::Cursor]
|
|
9
|
+
def initialize api_map, cursor
|
|
10
|
+
@api_map = api_map
|
|
11
|
+
@cursor = cursor
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return [Array<Pin::Base>]
|
|
15
|
+
def define
|
|
16
|
+
return [] if cursor.comment? || cursor.chain.literal?
|
|
17
|
+
result = cursor.chain.define(api_map, context_pin, locals)
|
|
18
|
+
result.concat((source_map.pins + source_map.locals).select{ |p| p.name == cursor.word && p.location.range.contain?(cursor.position) }) if result.empty?
|
|
19
|
+
result
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Completion]
|
|
23
|
+
def complete
|
|
24
|
+
return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
|
|
25
|
+
return Completion.new([], cursor.range) if cursor.chain.literal? || cursor.comment?
|
|
26
|
+
result = []
|
|
27
|
+
if cursor.chain.constant? || cursor.start_of_constant?
|
|
28
|
+
if cursor.chain.undefined?
|
|
29
|
+
type = cursor.chain.base.infer(api_map, context_pin, locals)
|
|
30
|
+
else
|
|
31
|
+
full = cursor.chain.links.first.word
|
|
32
|
+
if full.include?('::') && cursor.chain.links.length == 1
|
|
33
|
+
type = ComplexType.try_parse(full.split('::')[0..-2].join('::'))
|
|
34
|
+
elsif cursor.chain.links.length > 1
|
|
35
|
+
type = ComplexType.try_parse(full)
|
|
36
|
+
else
|
|
37
|
+
type = ComplexType::UNDEFINED
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
result.concat api_map.get_constants(type.undefined? ? '' : type.namespace, cursor.start_of_constant? ? '' : context_pin.context.namespace)
|
|
41
|
+
else
|
|
42
|
+
type = cursor.chain.base.infer(api_map, context_pin, locals)
|
|
43
|
+
result.concat api_map.get_complex_type_methods(type, context_pin.context.namespace, cursor.chain.links.length == 1)
|
|
44
|
+
if cursor.chain.links.length == 1
|
|
45
|
+
if cursor.word.start_with?('@@')
|
|
46
|
+
return package_completions(api_map.get_class_variable_pins(context_pin.context.namespace))
|
|
47
|
+
elsif cursor.word.start_with?('@')
|
|
48
|
+
return package_completions(api_map.get_instance_variable_pins(context_pin.context.namespace, context_pin.context.scope))
|
|
49
|
+
elsif cursor.word.start_with?('$')
|
|
50
|
+
return package_completions(api_map.get_global_variable_pins)
|
|
51
|
+
end
|
|
52
|
+
result.concat locals
|
|
53
|
+
result.concat api_map.get_constants('', context_pin.context.namespace)
|
|
54
|
+
result.concat api_map.get_methods(context_pin.context.namespace, scope: context_pin.context.scope, visibility: [:public, :private, :protected])
|
|
55
|
+
result.concat api_map.get_methods('Kernel')
|
|
56
|
+
result.concat ApiMap.keywords
|
|
57
|
+
result.concat yielded_self_pins
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
package_completions(result)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [Array<Pin::Base>]
|
|
64
|
+
def signify
|
|
65
|
+
return [] unless cursor.argument?
|
|
66
|
+
clip = Clip.new(api_map, cursor.recipient)
|
|
67
|
+
clip.define.select{|pin| pin.kind == Pin::METHOD}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @return [ComplexType]
|
|
71
|
+
def infer
|
|
72
|
+
cursor.chain.infer(api_map, context_pin, locals)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Get an array of all the locals that are visible from the cursors's
|
|
76
|
+
# position. Locals can be local variables, method parameters, or block
|
|
77
|
+
# parameters. The array starts with the nearest local pin.
|
|
78
|
+
#
|
|
79
|
+
# @return [Array<Solargraph::Pin::Base>]
|
|
80
|
+
def locals
|
|
81
|
+
loc_pos = context_pin.location.range.contain?(cursor.position) ? cursor.position : context_pin.location.range.ending
|
|
82
|
+
adj_pos = Position.new(loc_pos.line, (loc_pos.column.zero? ? 0 : loc_pos.column - 1))
|
|
83
|
+
@locals ||= source_map.locals.select { |pin|
|
|
84
|
+
pin.visible_from?(block, adj_pos)
|
|
85
|
+
}.reverse
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
# @return [ApiMap]
|
|
91
|
+
attr_reader :api_map
|
|
92
|
+
|
|
93
|
+
# @return [Source::Cursor]
|
|
94
|
+
attr_reader :cursor
|
|
95
|
+
|
|
96
|
+
# @return [SourceMap]
|
|
97
|
+
def source_map
|
|
98
|
+
@source_map ||= api_map.source_map(cursor.filename)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @return [Solargraph::Pin::Base]
|
|
102
|
+
def block
|
|
103
|
+
@block ||= source_map.locate_block_pin(cursor.node_position.line, cursor.node_position.character)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# The context at the current position.
|
|
107
|
+
#
|
|
108
|
+
# @return [Pin::Base]
|
|
109
|
+
def context_pin
|
|
110
|
+
@context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @return [Array<Pin::Base>]
|
|
114
|
+
def yielded_self_pins
|
|
115
|
+
return [] unless block.is_a?(Pin::Block) && block.receiver
|
|
116
|
+
chain = Solargraph::Source::NodeChainer.chain(block.receiver, source_map.source.filename)
|
|
117
|
+
receiver_pin = chain.define(api_map, context_pin, locals).first
|
|
118
|
+
return [] if receiver_pin.nil?
|
|
119
|
+
result = []
|
|
120
|
+
ys = receiver_pin.docstring.tag(:yieldself)
|
|
121
|
+
unless ys.nil? || ys.types.empty?
|
|
122
|
+
ysct = ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
|
|
123
|
+
result.concat api_map.get_complex_type_methods(ysct, ysct.namespace, true)
|
|
124
|
+
end
|
|
125
|
+
ys = receiver_pin.docstring.tag(:yieldpublic)
|
|
126
|
+
unless ys.nil? || ys.types.empty?
|
|
127
|
+
ysct = ComplexType.try_parse(*ys.types).qualify(api_map, receiver_pin.context.namespace)
|
|
128
|
+
result.concat api_map.get_complex_type_methods(ysct, '', false)
|
|
129
|
+
end
|
|
130
|
+
result
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# @param result [Array<Pin::Base>]
|
|
134
|
+
# @return [Completion]
|
|
135
|
+
def package_completions result
|
|
136
|
+
frag_start = cursor.start_of_word.to_s.downcase
|
|
137
|
+
filtered = result.uniq(&:name).select { |s|
|
|
138
|
+
s.name.downcase.start_with?(frag_start) &&
|
|
139
|
+
(s.kind != Pin::METHOD || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
|
|
140
|
+
}
|
|
141
|
+
Completion.new(filtered, cursor.range)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|