solargraph 0.32.1 → 0.32.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +6 -0
  5. data/.travis.yml +25 -0
  6. data/EXAMPLES.md +76 -0
  7. data/Gemfile +3 -0
  8. data/LANGUAGE_SERVER.md +51 -0
  9. data/LICENSE +21 -0
  10. data/OVERVIEW.md +37 -0
  11. data/README.md +106 -0
  12. data/Rakefile +14 -0
  13. data/SERVER.md +95 -0
  14. data/bin/solargraph +0 -0
  15. data/bin/solargraph-runtime +5 -5
  16. data/lib/solargraph.rb +54 -54
  17. data/lib/solargraph/api_map.rb +659 -659
  18. data/lib/solargraph/api_map/cache.rb +49 -49
  19. data/lib/solargraph/api_map/source_to_yard.rb +67 -67
  20. data/lib/solargraph/api_map/store.rb +201 -201
  21. data/lib/solargraph/bundle.rb +24 -24
  22. data/lib/solargraph/complex_type.rb +150 -150
  23. data/lib/solargraph/complex_type/type_methods.rb +124 -124
  24. data/lib/solargraph/complex_type/unique_type.rb +44 -44
  25. data/lib/solargraph/core_fills.rb +37 -37
  26. data/lib/solargraph/diagnostics.rb +52 -52
  27. data/lib/solargraph/diagnostics/base.rb +20 -20
  28. data/lib/solargraph/diagnostics/require_not_found.rb +28 -28
  29. data/lib/solargraph/diagnostics/rubocop.rb +98 -98
  30. data/lib/solargraph/diagnostics/rubocop_helpers.rb +46 -46
  31. data/lib/solargraph/diagnostics/type_not_defined.rb +108 -108
  32. data/lib/solargraph/diagnostics/update_errors.rb +38 -38
  33. data/lib/solargraph/language_server/completion_item_kinds.rb +33 -33
  34. data/lib/solargraph/language_server/error_codes.rb +18 -18
  35. data/lib/solargraph/language_server/host.rb +684 -681
  36. data/lib/solargraph/language_server/host/cataloger.rb +54 -79
  37. data/lib/solargraph/language_server/host/diagnoser.rb +80 -80
  38. data/lib/solargraph/language_server/host/dispatch.rb +112 -113
  39. data/lib/solargraph/language_server/host/sources.rb +138 -138
  40. data/lib/solargraph/language_server/message.rb +90 -90
  41. data/lib/solargraph/language_server/message/base.rb +83 -83
  42. data/lib/solargraph/language_server/message/completion_item/resolve.rb +40 -40
  43. data/lib/solargraph/language_server/message/exit_notification.rb +11 -11
  44. data/lib/solargraph/language_server/message/extended.rb +19 -19
  45. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +86 -86
  46. data/lib/solargraph/language_server/message/extended/document.rb +18 -18
  47. data/lib/solargraph/language_server/message/extended/document_gems.rb +30 -30
  48. data/lib/solargraph/language_server/message/extended/environment.rb +20 -20
  49. data/lib/solargraph/language_server/message/extended/search.rb +18 -18
  50. data/lib/solargraph/language_server/message/initialize.rb +141 -141
  51. data/lib/solargraph/language_server/message/initialized.rb +23 -23
  52. data/lib/solargraph/language_server/message/shutdown.rb +11 -11
  53. data/lib/solargraph/language_server/message/text_document.rb +25 -25
  54. data/lib/solargraph/language_server/message/text_document/completion.rb +51 -51
  55. data/lib/solargraph/language_server/message/text_document/definition.rb +18 -18
  56. data/lib/solargraph/language_server/message/text_document/did_change.rb +13 -13
  57. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +21 -21
  58. data/lib/solargraph/language_server/message/text_document/folding_range.rb +24 -24
  59. data/lib/solargraph/language_server/message/text_document/formatting.rb +50 -50
  60. data/lib/solargraph/language_server/message/text_document/hover.rb +31 -31
  61. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +32 -32
  62. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +9 -9
  63. data/lib/solargraph/language_server/message/text_document/references.rb +14 -14
  64. data/lib/solargraph/language_server/message/text_document/rename.rb +17 -17
  65. data/lib/solargraph/language_server/message/text_document/signature_help.rb +19 -19
  66. data/lib/solargraph/language_server/message/workspace.rb +12 -12
  67. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +29 -29
  68. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +29 -27
  69. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -24
  70. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +21 -21
  71. data/lib/solargraph/language_server/request.rb +22 -22
  72. data/lib/solargraph/language_server/symbol_kinds.rb +34 -34
  73. data/lib/solargraph/language_server/transport.rb +11 -11
  74. data/lib/solargraph/language_server/transport/adapter.rb +60 -60
  75. data/lib/solargraph/language_server/transport/data_reader.rb +66 -66
  76. data/lib/solargraph/language_server/uri_helpers.rb +25 -25
  77. data/lib/solargraph/library.rb +421 -419
  78. data/lib/solargraph/live_map.rb +126 -126
  79. data/lib/solargraph/live_map/cache.rb +38 -38
  80. data/lib/solargraph/location.rb +31 -31
  81. data/lib/solargraph/logging.rb +25 -25
  82. data/lib/solargraph/page.rb +68 -68
  83. data/lib/solargraph/pin.rb +50 -50
  84. data/lib/solargraph/pin/attribute.rb +41 -41
  85. data/lib/solargraph/pin/base.rb +280 -280
  86. data/lib/solargraph/pin/base_method.rb +76 -76
  87. data/lib/solargraph/pin/base_variable.rb +72 -72
  88. data/lib/solargraph/pin/block.rb +32 -32
  89. data/lib/solargraph/pin/block_parameter.rb +103 -103
  90. data/lib/solargraph/pin/class_variable.rb +9 -9
  91. data/lib/solargraph/pin/constant.rb +30 -30
  92. data/lib/solargraph/pin/conversions.rb +79 -79
  93. data/lib/solargraph/pin/documenting.rb +41 -41
  94. data/lib/solargraph/pin/duck_method.rb +14 -14
  95. data/lib/solargraph/pin/global_variable.rb +9 -9
  96. data/lib/solargraph/pin/instance_variable.rb +9 -9
  97. data/lib/solargraph/pin/keyword.rb +17 -17
  98. data/lib/solargraph/pin/local_variable.rb +23 -23
  99. data/lib/solargraph/pin/localized.rb +22 -22
  100. data/lib/solargraph/pin/method.rb +126 -126
  101. data/lib/solargraph/pin/method_alias.rb +30 -30
  102. data/lib/solargraph/pin/method_parameter.rb +40 -40
  103. data/lib/solargraph/pin/namespace.rb +54 -54
  104. data/lib/solargraph/pin/plugin/method.rb +25 -25
  105. data/lib/solargraph/pin/proxy_type.rb +35 -35
  106. data/lib/solargraph/pin/reference.rb +22 -22
  107. data/lib/solargraph/pin/reference/extend.rb +11 -11
  108. data/lib/solargraph/pin/reference/include.rb +11 -11
  109. data/lib/solargraph/pin/reference/require.rb +15 -15
  110. data/lib/solargraph/pin/reference/superclass.rb +11 -11
  111. data/lib/solargraph/pin/symbol.rb +44 -44
  112. data/lib/solargraph/pin/yard_pin.rb +10 -10
  113. data/lib/solargraph/pin/yard_pin/constant.rb +14 -14
  114. data/lib/solargraph/pin/yard_pin/method.rb +35 -35
  115. data/lib/solargraph/pin/yard_pin/namespace.rb +19 -19
  116. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +14 -14
  117. data/lib/solargraph/plugin.rb +8 -8
  118. data/lib/solargraph/plugin/base.rb +41 -41
  119. data/lib/solargraph/plugin/canceler.rb +11 -11
  120. data/lib/solargraph/plugin/process.rb +172 -172
  121. data/lib/solargraph/plugin/runtime.rb +134 -134
  122. data/lib/solargraph/position.rb +110 -110
  123. data/lib/solargraph/range.rb +83 -83
  124. data/lib/solargraph/server_methods.rb +14 -14
  125. data/lib/solargraph/shell.rb +102 -102
  126. data/lib/solargraph/source.rb +521 -521
  127. data/lib/solargraph/source/chain.rb +120 -120
  128. data/lib/solargraph/source/chain/call.rb +107 -107
  129. data/lib/solargraph/source/chain/class_variable.rb +11 -11
  130. data/lib/solargraph/source/chain/constant.rb +30 -30
  131. data/lib/solargraph/source/chain/global_variable.rb +11 -11
  132. data/lib/solargraph/source/chain/head.rb +33 -33
  133. data/lib/solargraph/source/chain/instance_variable.rb +11 -11
  134. data/lib/solargraph/source/chain/link.rb +33 -33
  135. data/lib/solargraph/source/chain/literal.rb +21 -21
  136. data/lib/solargraph/source/chain/variable.rb +11 -11
  137. data/lib/solargraph/source/change.rb +77 -77
  138. data/lib/solargraph/source/cursor.rb +157 -157
  139. data/lib/solargraph/source/node_chainer.rb +96 -96
  140. data/lib/solargraph/source/node_methods.rb +225 -225
  141. data/lib/solargraph/source/source_chainer.rb +183 -183
  142. data/lib/solargraph/source_map.rb +169 -169
  143. data/lib/solargraph/source_map/clip.rb +145 -145
  144. data/lib/solargraph/source_map/completion.rb +21 -21
  145. data/lib/solargraph/source_map/mapper.rb +149 -149
  146. data/lib/solargraph/source_map/node_processor.rb +78 -78
  147. data/lib/solargraph/source_map/node_processor/alias_node.rb +19 -19
  148. data/lib/solargraph/source_map/node_processor/args_node.rb +28 -28
  149. data/lib/solargraph/source_map/node_processor/base.rb +68 -68
  150. data/lib/solargraph/source_map/node_processor/begin_node.rb +11 -11
  151. data/lib/solargraph/source_map/node_processor/block_node.rb +14 -14
  152. data/lib/solargraph/source_map/node_processor/casgn_node.rb +14 -14
  153. data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +14 -14
  154. data/lib/solargraph/source_map/node_processor/def_node.rb +54 -54
  155. data/lib/solargraph/source_map/node_processor/defs_node.rb +21 -21
  156. data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +12 -12
  157. data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +18 -18
  158. data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +16 -16
  159. data/lib/solargraph/source_map/node_processor/namespace_node.rb +26 -26
  160. data/lib/solargraph/source_map/node_processor/orasgn_node.rb +12 -12
  161. data/lib/solargraph/source_map/node_processor/sclass_node.rb +11 -11
  162. data/lib/solargraph/source_map/node_processor/send_node.rb +162 -162
  163. data/lib/solargraph/source_map/node_processor/sym_node.rb +11 -11
  164. data/lib/solargraph/source_map/region.rb +58 -58
  165. data/lib/solargraph/version.rb +3 -3
  166. data/lib/solargraph/views/environment.erb +53 -53
  167. data/lib/solargraph/workspace.rb +183 -183
  168. data/lib/solargraph/workspace/config.rb +170 -170
  169. data/lib/solargraph/yard_map.rb +298 -298
  170. data/lib/solargraph/yard_map/cache.rb +17 -17
  171. data/lib/solargraph/yard_map/core_docs.rb +163 -163
  172. data/lib/solargraph/yard_map/core_gen.rb +76 -76
  173. data/lib/yard-coregen.rb +16 -16
  174. data/lib/yard-solargraph.rb +18 -18
  175. data/solargraph.gemspec +37 -0
  176. data/travis-bundler.rb +10 -0
  177. 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