solargraph 0.56.0 → 0.58.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.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.github/workflows/linting.yml +127 -0
  4. data/.github/workflows/plugins.yml +183 -7
  5. data/.github/workflows/rspec.yml +55 -5
  6. data/.github/workflows/typecheck.yml +6 -3
  7. data/.gitignore +6 -0
  8. data/.overcommit.yml +72 -0
  9. data/.rspec +1 -0
  10. data/.rubocop.yml +66 -0
  11. data/.rubocop_todo.yml +1279 -0
  12. data/.yardopts +1 -0
  13. data/CHANGELOG.md +92 -1
  14. data/README.md +8 -4
  15. data/Rakefile +125 -13
  16. data/bin/solargraph +3 -0
  17. data/lib/solargraph/api_map/cache.rb +110 -109
  18. data/lib/solargraph/api_map/constants.rb +279 -0
  19. data/lib/solargraph/api_map/index.rb +193 -175
  20. data/lib/solargraph/api_map/source_to_yard.rb +97 -88
  21. data/lib/solargraph/api_map/store.rb +384 -266
  22. data/lib/solargraph/api_map.rb +945 -973
  23. data/lib/solargraph/bench.rb +1 -0
  24. data/lib/solargraph/complex_type/type_methods.rb +228 -222
  25. data/lib/solargraph/complex_type/unique_type.rb +482 -475
  26. data/lib/solargraph/complex_type.rb +444 -423
  27. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  28. data/lib/solargraph/convention/base.rb +17 -0
  29. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  30. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  31. data/lib/solargraph/convention/data_definition.rb +105 -0
  32. data/lib/solargraph/convention/gemspec.rb +3 -2
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -60
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -100
  35. data/lib/solargraph/convention/struct_definition.rb +164 -101
  36. data/lib/solargraph/convention.rb +32 -2
  37. data/lib/solargraph/diagnostics/require_not_found.rb +53 -53
  38. data/lib/solargraph/diagnostics/rubocop.rb +118 -113
  39. data/lib/solargraph/diagnostics/rubocop_helpers.rb +68 -66
  40. data/lib/solargraph/diagnostics/type_check.rb +55 -55
  41. data/lib/solargraph/doc_map.rb +439 -405
  42. data/lib/solargraph/environ.rb +9 -2
  43. data/lib/solargraph/equality.rb +34 -33
  44. data/lib/solargraph/gem_pins.rb +98 -88
  45. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  46. data/lib/solargraph/language_server/host/dispatch.rb +130 -128
  47. data/lib/solargraph/language_server/host/message_worker.rb +112 -109
  48. data/lib/solargraph/language_server/host/sources.rb +99 -99
  49. data/lib/solargraph/language_server/host.rb +878 -871
  50. data/lib/solargraph/language_server/message/base.rb +2 -1
  51. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +114 -114
  52. data/lib/solargraph/language_server/message/extended/document.rb +23 -23
  53. data/lib/solargraph/language_server/message/text_document/completion.rb +56 -56
  54. data/lib/solargraph/language_server/message/text_document/definition.rb +40 -38
  55. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +26 -26
  56. data/lib/solargraph/language_server/message/text_document/formatting.rb +148 -131
  57. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  58. data/lib/solargraph/language_server/message/text_document/signature_help.rb +24 -24
  59. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -24
  60. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  61. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -23
  62. data/lib/solargraph/language_server/progress.rb +8 -0
  63. data/lib/solargraph/language_server/request.rb +4 -1
  64. data/lib/solargraph/library.rb +683 -666
  65. data/lib/solargraph/location.rb +82 -79
  66. data/lib/solargraph/logging.rb +37 -28
  67. data/lib/solargraph/page.rb +3 -0
  68. data/lib/solargraph/parser/comment_ripper.rb +69 -62
  69. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -227
  70. data/lib/solargraph/parser/node_processor/base.rb +92 -87
  71. data/lib/solargraph/parser/node_processor.rb +62 -46
  72. data/lib/solargraph/parser/parser_gem/class_methods.rb +149 -159
  73. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  74. data/lib/solargraph/parser/parser_gem/node_chainer.rb +166 -164
  75. data/lib/solargraph/parser/parser_gem/node_methods.rb +486 -497
  76. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -21
  77. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +59 -59
  78. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +15 -15
  79. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -45
  80. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +1 -21
  81. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +53 -53
  82. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -21
  83. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +40 -40
  84. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +29 -29
  85. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +59 -53
  86. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +0 -22
  87. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -41
  88. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -16
  89. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +38 -37
  90. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +52 -43
  91. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +291 -271
  92. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +1 -0
  93. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -29
  94. data/lib/solargraph/parser/parser_gem/node_processors.rb +70 -66
  95. data/lib/solargraph/parser/region.rb +69 -66
  96. data/lib/solargraph/parser/snippet.rb +17 -15
  97. data/lib/solargraph/pin/base.rb +729 -651
  98. data/lib/solargraph/pin/base_variable.rb +126 -125
  99. data/lib/solargraph/pin/block.rb +104 -103
  100. data/lib/solargraph/pin/breakable.rb +9 -9
  101. data/lib/solargraph/pin/callable.rb +231 -218
  102. data/lib/solargraph/pin/closure.rb +72 -74
  103. data/lib/solargraph/pin/common.rb +79 -75
  104. data/lib/solargraph/pin/constant.rb +2 -0
  105. data/lib/solargraph/pin/conversions.rb +123 -123
  106. data/lib/solargraph/pin/delegated_method.rb +120 -120
  107. data/lib/solargraph/pin/documenting.rb +114 -114
  108. data/lib/solargraph/pin/instance_variable.rb +34 -34
  109. data/lib/solargraph/pin/keyword.rb +20 -20
  110. data/lib/solargraph/pin/local_variable.rb +75 -76
  111. data/lib/solargraph/pin/method.rb +672 -651
  112. data/lib/solargraph/pin/method_alias.rb +34 -31
  113. data/lib/solargraph/pin/namespace.rb +115 -115
  114. data/lib/solargraph/pin/parameter.rb +275 -261
  115. data/lib/solargraph/pin/proxy_type.rb +39 -35
  116. data/lib/solargraph/pin/reference/override.rb +47 -33
  117. data/lib/solargraph/pin/reference/superclass.rb +15 -10
  118. data/lib/solargraph/pin/reference.rb +39 -22
  119. data/lib/solargraph/pin/search.rb +61 -56
  120. data/lib/solargraph/pin/signature.rb +61 -59
  121. data/lib/solargraph/pin/symbol.rb +53 -48
  122. data/lib/solargraph/pin/until.rb +18 -18
  123. data/lib/solargraph/pin/while.rb +18 -18
  124. data/lib/solargraph/pin.rb +44 -44
  125. data/lib/solargraph/pin_cache.rb +245 -185
  126. data/lib/solargraph/position.rb +132 -116
  127. data/lib/solargraph/range.rb +112 -107
  128. data/lib/solargraph/rbs_map/conversions.rb +823 -773
  129. data/lib/solargraph/rbs_map/core_fills.rb +18 -0
  130. data/lib/solargraph/rbs_map/core_map.rb +58 -51
  131. data/lib/solargraph/rbs_map/stdlib_map.rb +43 -43
  132. data/lib/solargraph/rbs_map.rb +163 -150
  133. data/lib/solargraph/shell.rb +352 -268
  134. data/lib/solargraph/source/chain/call.rb +337 -333
  135. data/lib/solargraph/source/chain/constant.rb +26 -89
  136. data/lib/solargraph/source/chain/hash.rb +34 -34
  137. data/lib/solargraph/source/chain/if.rb +28 -28
  138. data/lib/solargraph/source/chain/instance_variable.rb +13 -13
  139. data/lib/solargraph/source/chain/link.rb +11 -2
  140. data/lib/solargraph/source/chain/literal.rb +48 -48
  141. data/lib/solargraph/source/chain/or.rb +23 -23
  142. data/lib/solargraph/source/chain.rb +291 -282
  143. data/lib/solargraph/source/change.rb +82 -82
  144. data/lib/solargraph/source/cursor.rb +166 -167
  145. data/lib/solargraph/source/encoding_fixes.rb +23 -23
  146. data/lib/solargraph/source/source_chainer.rb +194 -194
  147. data/lib/solargraph/source/updater.rb +55 -55
  148. data/lib/solargraph/source.rb +498 -495
  149. data/lib/solargraph/source_map/clip.rb +226 -234
  150. data/lib/solargraph/source_map/data.rb +34 -30
  151. data/lib/solargraph/source_map/mapper.rb +259 -259
  152. data/lib/solargraph/source_map.rb +212 -200
  153. data/lib/solargraph/type_checker/checks.rb +124 -124
  154. data/lib/solargraph/type_checker/param_def.rb +37 -35
  155. data/lib/solargraph/type_checker/problem.rb +32 -32
  156. data/lib/solargraph/type_checker/rules.rb +84 -62
  157. data/lib/solargraph/type_checker.rb +814 -699
  158. data/lib/solargraph/version.rb +5 -5
  159. data/lib/solargraph/workspace/config.rb +255 -239
  160. data/lib/solargraph/workspace/require_paths.rb +97 -0
  161. data/lib/solargraph/workspace.rb +220 -249
  162. data/lib/solargraph/yard_map/helpers.rb +44 -16
  163. data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -5
  164. data/lib/solargraph/yard_map/mapper/to_method.rb +130 -134
  165. data/lib/solargraph/yard_map/mapper/to_namespace.rb +31 -30
  166. data/lib/solargraph/yard_map/mapper.rb +79 -79
  167. data/lib/solargraph/yard_map/to_method.rb +89 -88
  168. data/lib/solargraph/yardoc.rb +87 -49
  169. data/lib/solargraph.rb +105 -90
  170. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  171. data/rbs/fills/open3/0/open3.rbs +172 -0
  172. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  173. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  174. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  175. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  176. data/rbs/fills/{tuple.rbs → tuple/tuple.rbs} +2 -3
  177. data/rbs/shims/ast/0/node.rbs +5 -0
  178. data/rbs/shims/ast/2.4/.rbs_meta.yaml +9 -0
  179. data/rbs/shims/ast/2.4/ast.rbs +73 -0
  180. data/rbs/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  181. data/rbs/shims/parser/3.2.0.1/manifest.yaml +7 -0
  182. data/rbs/shims/parser/3.2.0.1/parser.rbs +201 -0
  183. data/rbs/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  184. data/rbs/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  185. data/rbs/shims/thor/1.2.0.1/manifest.yaml +7 -0
  186. data/rbs/shims/thor/1.2.0.1/thor.rbs +17 -0
  187. data/rbs_collection.yaml +4 -4
  188. data/solargraph.gemspec +26 -5
  189. metadata +187 -15
  190. data/lib/.rubocop.yml +0 -22
  191. data/lib/solargraph/parser/node_methods.rb +0 -97
@@ -1,234 +1,226 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class SourceMap
5
- # A static analysis tool for obtaining definitions, Completions,
6
- # signatures, and type inferences from a Cursor.
7
- #
8
- class Clip
9
- # @param api_map [ApiMap]
10
- # @param cursor [Source::Cursor]
11
- def initialize api_map, cursor
12
- @api_map = api_map
13
- @cursor = cursor
14
- block_pin = block
15
- block_pin.rebind(api_map) if block_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(block_pin.receiver).contain?(cursor.range.start)
16
- @in_block = nil
17
- end
18
-
19
- # @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
20
- def define
21
- return [] if cursor.comment? || cursor.chain.literal?
22
- result = cursor.chain.define(api_map, block, locals)
23
- result.concat file_global_methods
24
- result.concat((source_map.pins + source_map.locals).select{ |p| p.name == cursor.word && p.location.range.contain?(cursor.position) }) if result.empty?
25
- result
26
- end
27
-
28
- # @return [Array<Pin::Base>]
29
- def types
30
- infer.namespaces.map { |namespace| api_map.get_path_pins(namespace) }.flatten
31
- end
32
-
33
- # @return [Completion]
34
- def complete
35
- return package_completions([]) if !source_map.source.parsed? || cursor.string?
36
- return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
37
- return Completion.new([], cursor.range) if cursor.chain.literal?
38
- if cursor.comment?
39
- tag_complete
40
- else
41
- code_complete
42
- end
43
- end
44
-
45
- # @return [Array<Pin::Method>]
46
- def signify
47
- return [] unless cursor.argument?
48
- chain = Parser.chain(cursor.recipient_node, cursor.filename)
49
- chain.define(api_map, context_pin, locals).select { |pin| pin.is_a?(Pin::Method) }
50
- end
51
-
52
- # @return [ComplexType]
53
- def infer
54
- result = cursor.chain.infer(api_map, block, locals)
55
- if result.tag == 'Class'
56
- # HACK: Exception to return BasicObject from Class#new
57
- dfn = cursor.chain.define(api_map, block, locals).first
58
- return ComplexType.try_parse('::BasicObject') if dfn && dfn.path == 'Class#new'
59
- end
60
- return result unless result.tag == 'self'
61
- cursor.chain.base.infer(api_map, block, locals)
62
- end
63
-
64
- # Get an array of all the locals that are visible from the cursors's
65
- # position. Locals can be local variables, method parameters, or block
66
- # parameters. The array starts with the nearest local pin.
67
- #
68
- # @return [::Array<Solargraph::Pin::Base>]
69
- def locals
70
- @locals ||= source_map.locals_at(location)
71
- end
72
-
73
- # @return [::Array<String>]
74
- def gates
75
- block.gates
76
- end
77
-
78
- def in_block?
79
- return @in_block unless @in_block.nil?
80
- @in_block = begin
81
- tree = cursor.source.tree_at(cursor.position.line, cursor.position.column)
82
- Parser.is_ast_node?(tree[1]) && [:block, :ITER].include?(tree[1].type)
83
- end
84
- end
85
-
86
- # @param phrase [String]
87
- # @return [Array<Solargraph::Pin::Base>]
88
- def translate phrase
89
- chain = Parser.chain(Parser.parse(phrase))
90
- chain.define(api_map, block, locals)
91
- end
92
-
93
- private
94
-
95
- # @return [ApiMap]
96
- attr_reader :api_map
97
-
98
- # @return [Source::Cursor]
99
- attr_reader :cursor
100
-
101
- # @return [SourceMap]
102
- def source_map
103
- @source_map ||= api_map.source_map(cursor.filename)
104
- end
105
-
106
- # @return [Location]
107
- def location
108
- Location.new(source_map.filename, Solargraph::Range.new(cursor.position, cursor.position))
109
- end
110
-
111
- # @return [Solargraph::Pin::Closure]
112
- def block
113
- @block ||= source_map.locate_block_pin(cursor.node_position.line, cursor.node_position.character)
114
- end
115
-
116
- # The context at the current position.
117
- #
118
- # @return [Pin::Base]
119
- def context_pin
120
- @context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
121
- end
122
-
123
- # @return [Array<Pin::KeywordParam>]
124
- def complete_keyword_parameters
125
- return [] unless cursor.argument? && cursor.chain.links.one? && cursor.word =~ /^[a-z0-9_]*:?$/
126
- pins = signify
127
- result = []
128
- done = []
129
- pins.each do |pin|
130
- pin.parameters.each do |param|
131
- next if done.include?(param.name)
132
- done.push param.name
133
- next unless param.keyword?
134
- result.push Pin::KeywordParam.new(pin.location, "#{param.name}:")
135
- end
136
- if !pin.parameters.empty? && pin.parameters.last.kwrestarg?
137
- pin.docstring.tags(:param).each do |tag|
138
- next if done.include?(tag.name)
139
- done.push tag.name
140
- result.push Pin::KeywordParam.new(pin.location, "#{tag.name}:")
141
- end
142
- end
143
- end
144
- result
145
- end
146
-
147
- # @param result [Enumerable<Pin::Base>]
148
- # @return [Completion]
149
- def package_completions result
150
- frag_start = cursor.start_of_word.to_s.downcase
151
- filtered = result.uniq(&:name).select { |s|
152
- s.name.downcase.start_with?(frag_start) &&
153
- (!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
154
- }
155
- Completion.new(filtered, cursor.range)
156
- end
157
-
158
- # @return [Completion]
159
- def tag_complete
160
- result = []
161
- match = source_map.code[0..cursor.offset-1].match(/[\[<, ]([a-z0-9_:]*)\z/i)
162
- if match
163
- full = match[1]
164
- if full.include?('::')
165
- if full.end_with?('::')
166
- result.concat api_map.get_constants(full[0..-3], *gates)
167
- else
168
- result.concat api_map.get_constants(full.split('::')[0..-2].join('::'), *gates)
169
- end
170
- else
171
- result.concat api_map.get_constants('', full.end_with?('::') ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
172
- end
173
- end
174
- package_completions(result)
175
- end
176
-
177
- # @return [Completion]
178
- def code_complete
179
- result = []
180
- result.concat complete_keyword_parameters
181
- if cursor.chain.constant? || cursor.start_of_constant?
182
- full = cursor.chain.links.first.word
183
- type = if cursor.chain.undefined?
184
- cursor.chain.base.infer(api_map, context_pin, locals)
185
- else
186
- if full.include?('::') && cursor.chain.links.length == 1
187
- ComplexType.try_parse(full.split('::')[0..-2].join('::'))
188
- elsif cursor.chain.links.length > 1
189
- ComplexType.try_parse(full)
190
- else
191
- ComplexType::UNDEFINED
192
- end
193
- end
194
- if type.undefined?
195
- if full.include?('::')
196
- result.concat api_map.get_constants(full, *gates)
197
- else
198
- result.concat api_map.get_constants('', cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
199
- end
200
- else
201
- result.concat api_map.get_constants(type.namespace, cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
202
- end
203
- else
204
- type = cursor.chain.base.infer(api_map, block, locals)
205
- result.concat api_map.get_complex_type_methods(type, block.binder.namespace, cursor.chain.links.length == 1)
206
- if cursor.chain.links.length == 1
207
- if cursor.word.start_with?('@@')
208
- return package_completions(api_map.get_class_variable_pins(context_pin.full_context.namespace))
209
- elsif cursor.word.start_with?('@')
210
- return package_completions(api_map.get_instance_variable_pins(block.binder.namespace, block.binder.scope))
211
- elsif cursor.word.start_with?('$')
212
- return package_completions(api_map.get_global_variable_pins)
213
- end
214
- result.concat locals
215
- result.concat file_global_methods unless block.binder.namespace.empty?
216
- result.concat api_map.get_constants(context_pin.context.namespace, *gates)
217
- result.concat api_map.get_methods(block.binder.namespace, scope: block.binder.scope, visibility: [:public, :private, :protected])
218
- result.concat api_map.get_methods('Kernel')
219
- result.concat api_map.keyword_pins.to_a
220
- end
221
- end
222
- package_completions(result)
223
- end
224
-
225
- # @return [Array<Pin::Base>]
226
- def file_global_methods
227
- return [] if cursor.word.empty?
228
- source_map.pins.select do |pin|
229
- pin.is_a?(Pin::Method) && pin.namespace == '' && pin.name.start_with?(cursor.word)
230
- end
231
- end
232
- end
233
- end
234
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class SourceMap
5
+ # A static analysis tool for obtaining definitions, Completions,
6
+ # signatures, and type inferences from a Cursor.
7
+ #
8
+ class Clip
9
+ # @param api_map [ApiMap]
10
+ # @param cursor [Source::Cursor]
11
+ def initialize api_map, cursor
12
+ @api_map = api_map
13
+ @cursor = cursor
14
+ closure_pin = closure
15
+ closure_pin.rebind(api_map) if closure_pin.is_a?(Pin::Block) && !Solargraph::Range.from_node(closure_pin.receiver).contain?(cursor.range.start)
16
+ end
17
+
18
+ # @return [Array<Pin::Base>] Relevant pins for infering the type of the Cursor's position
19
+ def define
20
+ return [] if cursor.comment? || cursor.chain.literal?
21
+ result = cursor.chain.define(api_map, closure, locals)
22
+ result.concat file_global_methods
23
+ result.concat((source_map.pins + source_map.locals).select{ |p| p.name == cursor.word && p.location.range.contain?(cursor.position) }) if result.empty?
24
+ result
25
+ end
26
+
27
+ # @return [Array<Pin::Base>]
28
+ def types
29
+ infer.namespaces.map { |namespace| api_map.get_path_pins(namespace) }.flatten
30
+ end
31
+
32
+ # @return [Completion]
33
+ def complete
34
+ return package_completions([]) if !source_map.source.parsed? || cursor.string?
35
+ return package_completions(api_map.get_symbols) if cursor.chain.literal? && cursor.chain.links.last.word == '<Symbol>'
36
+ return Completion.new([], cursor.range) if cursor.chain.literal?
37
+ if cursor.comment?
38
+ tag_complete
39
+ else
40
+ code_complete
41
+ end
42
+ end
43
+
44
+ # @return [Array<Pin::Method>]
45
+ def signify
46
+ return [] unless cursor.argument?
47
+ chain = Parser.chain(cursor.recipient_node, cursor.filename)
48
+ chain.define(api_map, context_pin, locals).select { |pin| pin.is_a?(Pin::Method) }
49
+ end
50
+
51
+ # @return [ComplexType]
52
+ def infer
53
+ result = cursor.chain.infer(api_map, closure, locals)
54
+ if result.tag == 'Class'
55
+ # HACK: Exception to return BasicObject from Class#new
56
+ dfn = cursor.chain.define(api_map, closure, locals).first
57
+ return ComplexType.try_parse('::BasicObject') if dfn && dfn.path == 'Class#new'
58
+ end
59
+ # should receive result with selfs resolved from infer()
60
+ Solargraph.assert_or_log(:clip_infer_self, 'Received selfy inference') if result.selfy?
61
+ result
62
+ end
63
+
64
+ # Get an array of all the locals that are visible from the cursors's
65
+ # position. Locals can be local variables, method parameters, or block
66
+ # parameters. The array starts with the nearest local pin.
67
+ #
68
+ # @return [::Array<Solargraph::Pin::LocalVariable>]
69
+ def locals
70
+ @locals ||= source_map.locals_at(location)
71
+ end
72
+
73
+ # @return [::Array<String>]
74
+ def gates
75
+ closure.gates
76
+ end
77
+
78
+ # @param phrase [String]
79
+ # @return [Array<Solargraph::Pin::Base>]
80
+ def translate phrase
81
+ chain = Parser.chain(Parser.parse(phrase))
82
+ chain.define(api_map, closure, locals)
83
+ end
84
+
85
+ private
86
+
87
+ # @return [ApiMap]
88
+ attr_reader :api_map
89
+
90
+ # @return [Source::Cursor]
91
+ attr_reader :cursor
92
+
93
+ # @return [SourceMap]
94
+ def source_map
95
+ @source_map ||= api_map.source_map(cursor.filename)
96
+ end
97
+
98
+ # @return [Location]
99
+ def location
100
+ Location.new(source_map.filename, Solargraph::Range.new(cursor.position, cursor.position))
101
+ end
102
+
103
+ # @return [Solargraph::Pin::Closure]
104
+ def closure
105
+ @closure ||= source_map.locate_closure_pin(cursor.node_position.line, cursor.node_position.character)
106
+ end
107
+
108
+ # The context at the current position.
109
+ #
110
+ # @return [Pin::Base]
111
+ def context_pin
112
+ @context_pin ||= source_map.locate_named_path_pin(cursor.node_position.line, cursor.node_position.character)
113
+ end
114
+
115
+ # @return [Array<Pin::KeywordParam>]
116
+ def complete_keyword_parameters
117
+ return [] unless cursor.argument? && cursor.chain.links.one? && cursor.word =~ /^[a-z0-9_]*:?$/
118
+ pins = signify
119
+ result = []
120
+ done = []
121
+ pins.each do |pin|
122
+ pin.parameters.each do |param|
123
+ next if done.include?(param.name)
124
+ done.push param.name
125
+ next unless param.keyword?
126
+ result.push Pin::KeywordParam.new(pin.location, "#{param.name}:")
127
+ end
128
+ if !pin.parameters.empty? && pin.parameters.last.kwrestarg?
129
+ pin.docstring.tags(:param).each do |tag|
130
+ next if done.include?(tag.name)
131
+ done.push tag.name
132
+ result.push Pin::KeywordParam.new(pin.location, "#{tag.name}:")
133
+ end
134
+ end
135
+ end
136
+ result
137
+ end
138
+
139
+ # @param result [Enumerable<Pin::Base>]
140
+ # @return [Completion]
141
+ def package_completions result
142
+ frag_start = cursor.start_of_word.to_s.downcase
143
+ filtered = result.uniq(&:name).select { |s|
144
+ s.name.downcase.start_with?(frag_start) &&
145
+ (!s.is_a?(Pin::Method) || s.name.match(/^[a-z0-9_]+(\!|\?|=)?$/i))
146
+ }
147
+ Completion.new(filtered, cursor.range)
148
+ end
149
+
150
+ # @return [Completion]
151
+ def tag_complete
152
+ result = []
153
+ match = source_map.code[0..cursor.offset-1].match(/[\[<, ]([a-z0-9_:]*)\z/i)
154
+ if match
155
+ full = match[1]
156
+ if full.include?('::')
157
+ if full.end_with?('::')
158
+ result.concat api_map.get_constants(full[0..-3], *gates)
159
+ else
160
+ result.concat api_map.get_constants(full.split('::')[0..-2].join('::'), *gates)
161
+ end
162
+ else
163
+ result.concat api_map.get_constants('', full.end_with?('::') ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
164
+ end
165
+ end
166
+ package_completions(result)
167
+ end
168
+
169
+ # @return [Completion]
170
+ def code_complete
171
+ result = []
172
+ result.concat complete_keyword_parameters
173
+ if cursor.chain.constant? || cursor.start_of_constant?
174
+ full = cursor.chain.links.first.word
175
+ type = if cursor.chain.undefined?
176
+ cursor.chain.base.infer(api_map, context_pin, locals)
177
+ else
178
+ if full.include?('::') && cursor.chain.links.length == 1
179
+ ComplexType.try_parse(full.split('::')[0..-2].join('::'))
180
+ elsif cursor.chain.links.length > 1
181
+ ComplexType.try_parse(full)
182
+ else
183
+ ComplexType::UNDEFINED
184
+ end
185
+ end
186
+ if type.undefined?
187
+ if full.include?('::')
188
+ result.concat api_map.get_constants(full, *gates)
189
+ else
190
+ result.concat api_map.get_constants('', cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates) #.select { |pin| pin.name.start_with?(full) }
191
+ end
192
+ else
193
+ result.concat api_map.get_constants(type.namespace, cursor.start_of_constant? ? '' : context_pin.full_context.namespace, *gates)
194
+ end
195
+ else
196
+ type = cursor.chain.base.infer(api_map, closure, locals)
197
+ result.concat api_map.get_complex_type_methods(type, closure.binder.namespace, cursor.chain.links.length == 1)
198
+ if cursor.chain.links.length == 1
199
+ if cursor.word.start_with?('@@')
200
+ return package_completions(api_map.get_class_variable_pins(context_pin.full_context.namespace))
201
+ elsif cursor.word.start_with?('@')
202
+ return package_completions(api_map.get_instance_variable_pins(closure.binder.namespace, closure.binder.scope))
203
+ elsif cursor.word.start_with?('$')
204
+ return package_completions(api_map.get_global_variable_pins)
205
+ end
206
+ result.concat locals
207
+ result.concat file_global_methods unless closure.binder.namespace.empty?
208
+ result.concat api_map.get_constants(context_pin.context.namespace, *gates)
209
+ result.concat api_map.get_methods(closure.binder.namespace, scope: closure.binder.scope, visibility: [:public, :private, :protected])
210
+ result.concat api_map.get_methods('Kernel')
211
+ result.concat api_map.keyword_pins.to_a
212
+ end
213
+ end
214
+ package_completions(result)
215
+ end
216
+
217
+ # @return [Array<Pin::Base>]
218
+ def file_global_methods
219
+ return [] if cursor.word.empty?
220
+ source_map.pins.select do |pin|
221
+ pin.is_a?(Pin::Method) && pin.namespace == '' && pin.name.start_with?(cursor.word)
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
@@ -1,30 +1,34 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class SourceMap
5
- class Data
6
- def initialize source
7
- @source = source
8
- end
9
-
10
- def pins
11
- generate
12
- @pins || []
13
- end
14
-
15
- def locals
16
- generate
17
- @locals || []
18
- end
19
-
20
- private
21
-
22
- def generate
23
- return if @generated
24
-
25
- @generated = true
26
- @pins, @locals = Mapper.map(@source)
27
- end
28
- end
29
- end
30
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class SourceMap
5
+ class Data
6
+ # @param source [Solargraph::Source]
7
+ def initialize source
8
+ @source = source
9
+ end
10
+
11
+ # @return [Array<Solargraph::Pin::Base>]
12
+ def pins
13
+ generate
14
+ @pins || []
15
+ end
16
+
17
+ # @return [Array<Solargraph::LocalVariable>]
18
+ def locals
19
+ generate
20
+ @locals || []
21
+ end
22
+
23
+ private
24
+
25
+ # @return [void]
26
+ def generate
27
+ return if @generated
28
+
29
+ @generated = true
30
+ @pins, @locals = Mapper.map(@source)
31
+ end
32
+ end
33
+ end
34
+ end