solargraph 0.39.7

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 (252) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +28 -0
  5. data/.yardopts +2 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE +21 -0
  8. data/README.md +104 -0
  9. data/Rakefile +14 -0
  10. data/SPONSORS.md +9 -0
  11. data/bin/solargraph +5 -0
  12. data/lib/.rubocop.yml +21 -0
  13. data/lib/solargraph.rb +66 -0
  14. data/lib/solargraph/api_map.rb +745 -0
  15. data/lib/solargraph/api_map/bundler_methods.rb +27 -0
  16. data/lib/solargraph/api_map/cache.rb +66 -0
  17. data/lib/solargraph/api_map/source_to_yard.rb +81 -0
  18. data/lib/solargraph/api_map/store.rb +267 -0
  19. data/lib/solargraph/bundle.rb +26 -0
  20. data/lib/solargraph/complex_type.rb +213 -0
  21. data/lib/solargraph/complex_type/type_methods.rb +127 -0
  22. data/lib/solargraph/complex_type/unique_type.rb +75 -0
  23. data/lib/solargraph/convention.rb +38 -0
  24. data/lib/solargraph/convention/base.rb +25 -0
  25. data/lib/solargraph/convention/gemfile.rb +18 -0
  26. data/lib/solargraph/convention/gemspec.rb +25 -0
  27. data/lib/solargraph/convention/rspec.rb +24 -0
  28. data/lib/solargraph/converters/dd.rb +12 -0
  29. data/lib/solargraph/converters/dl.rb +12 -0
  30. data/lib/solargraph/converters/dt.rb +12 -0
  31. data/lib/solargraph/converters/misc.rb +1 -0
  32. data/lib/solargraph/core_fills.rb +159 -0
  33. data/lib/solargraph/diagnostics.rb +55 -0
  34. data/lib/solargraph/diagnostics/base.rb +29 -0
  35. data/lib/solargraph/diagnostics/require_not_found.rb +37 -0
  36. data/lib/solargraph/diagnostics/rubocop.rb +90 -0
  37. data/lib/solargraph/diagnostics/rubocop_helpers.rb +64 -0
  38. data/lib/solargraph/diagnostics/severities.rb +15 -0
  39. data/lib/solargraph/diagnostics/type_check.rb +54 -0
  40. data/lib/solargraph/diagnostics/update_errors.rb +41 -0
  41. data/lib/solargraph/documentor.rb +76 -0
  42. data/lib/solargraph/environ.rb +40 -0
  43. data/lib/solargraph/language_server.rb +19 -0
  44. data/lib/solargraph/language_server/completion_item_kinds.rb +35 -0
  45. data/lib/solargraph/language_server/error_codes.rb +20 -0
  46. data/lib/solargraph/language_server/host.rb +741 -0
  47. data/lib/solargraph/language_server/host/cataloger.rb +56 -0
  48. data/lib/solargraph/language_server/host/diagnoser.rb +81 -0
  49. data/lib/solargraph/language_server/host/dispatch.rb +112 -0
  50. data/lib/solargraph/language_server/host/sources.rb +156 -0
  51. data/lib/solargraph/language_server/message.rb +92 -0
  52. data/lib/solargraph/language_server/message/base.rb +85 -0
  53. data/lib/solargraph/language_server/message/cancel_request.rb +13 -0
  54. data/lib/solargraph/language_server/message/client.rb +11 -0
  55. data/lib/solargraph/language_server/message/client/register_capability.rb +15 -0
  56. data/lib/solargraph/language_server/message/completion_item.rb +11 -0
  57. data/lib/solargraph/language_server/message/completion_item/resolve.rb +57 -0
  58. data/lib/solargraph/language_server/message/exit_notification.rb +13 -0
  59. data/lib/solargraph/language_server/message/extended.rb +21 -0
  60. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +95 -0
  61. data/lib/solargraph/language_server/message/extended/document.rb +20 -0
  62. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -0
  63. data/lib/solargraph/language_server/message/extended/download_core.rb +23 -0
  64. data/lib/solargraph/language_server/message/extended/environment.rb +25 -0
  65. data/lib/solargraph/language_server/message/extended/search.rb +20 -0
  66. data/lib/solargraph/language_server/message/initialize.rb +153 -0
  67. data/lib/solargraph/language_server/message/initialized.rb +26 -0
  68. data/lib/solargraph/language_server/message/method_not_found.rb +16 -0
  69. data/lib/solargraph/language_server/message/method_not_implemented.rb +14 -0
  70. data/lib/solargraph/language_server/message/shutdown.rb +13 -0
  71. data/lib/solargraph/language_server/message/text_document.rb +28 -0
  72. data/lib/solargraph/language_server/message/text_document/base.rb +19 -0
  73. data/lib/solargraph/language_server/message/text_document/code_action.rb +17 -0
  74. data/lib/solargraph/language_server/message/text_document/completion.rb +57 -0
  75. data/lib/solargraph/language_server/message/text_document/definition.rb +38 -0
  76. data/lib/solargraph/language_server/message/text_document/did_change.rb +15 -0
  77. data/lib/solargraph/language_server/message/text_document/did_close.rb +15 -0
  78. data/lib/solargraph/language_server/message/text_document/did_open.rb +15 -0
  79. data/lib/solargraph/language_server/message/text_document/did_save.rb +17 -0
  80. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +23 -0
  81. data/lib/solargraph/language_server/message/text_document/folding_range.rb +26 -0
  82. data/lib/solargraph/language_server/message/text_document/formatting.rb +78 -0
  83. data/lib/solargraph/language_server/message/text_document/hover.rb +44 -0
  84. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +34 -0
  85. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +11 -0
  86. data/lib/solargraph/language_server/message/text_document/references.rb +16 -0
  87. data/lib/solargraph/language_server/message/text_document/rename.rb +19 -0
  88. data/lib/solargraph/language_server/message/text_document/signature_help.rb +29 -0
  89. data/lib/solargraph/language_server/message/workspace.rb +14 -0
  90. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +29 -0
  91. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +33 -0
  92. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -0
  93. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -0
  94. data/lib/solargraph/language_server/message_types.rb +14 -0
  95. data/lib/solargraph/language_server/request.rb +24 -0
  96. data/lib/solargraph/language_server/symbol_kinds.rb +36 -0
  97. data/lib/solargraph/language_server/transport.rb +13 -0
  98. data/lib/solargraph/language_server/transport/adapter.rb +56 -0
  99. data/lib/solargraph/language_server/transport/data_reader.rb +72 -0
  100. data/lib/solargraph/language_server/uri_helpers.rb +49 -0
  101. data/lib/solargraph/library.rb +414 -0
  102. data/lib/solargraph/location.rb +37 -0
  103. data/lib/solargraph/logging.rb +27 -0
  104. data/lib/solargraph/page.rb +83 -0
  105. data/lib/solargraph/parser.rb +26 -0
  106. data/lib/solargraph/parser/comment_ripper.rb +52 -0
  107. data/lib/solargraph/parser/legacy.rb +12 -0
  108. data/lib/solargraph/parser/legacy/class_methods.rb +109 -0
  109. data/lib/solargraph/parser/legacy/flawed_builder.rb +16 -0
  110. data/lib/solargraph/parser/legacy/node_chainer.rb +118 -0
  111. data/lib/solargraph/parser/legacy/node_methods.rb +300 -0
  112. data/lib/solargraph/parser/legacy/node_processors.rb +54 -0
  113. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +23 -0
  114. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +35 -0
  115. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +15 -0
  116. data/lib/solargraph/parser/legacy/node_processors/block_node.rb +22 -0
  117. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +25 -0
  118. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +23 -0
  119. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +63 -0
  120. data/lib/solargraph/parser/legacy/node_processors/defs_node.rb +36 -0
  121. data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +23 -0
  122. data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +38 -0
  123. data/lib/solargraph/parser/legacy/node_processors/lvasgn_node.rb +28 -0
  124. data/lib/solargraph/parser/legacy/node_processors/namespace_node.rb +39 -0
  125. data/lib/solargraph/parser/legacy/node_processors/orasgn_node.rb +16 -0
  126. data/lib/solargraph/parser/legacy/node_processors/resbody_node.rb +36 -0
  127. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +21 -0
  128. data/lib/solargraph/parser/legacy/node_processors/send_node.rb +234 -0
  129. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +18 -0
  130. data/lib/solargraph/parser/node_methods.rb +43 -0
  131. data/lib/solargraph/parser/node_processor.rb +43 -0
  132. data/lib/solargraph/parser/node_processor/base.rb +77 -0
  133. data/lib/solargraph/parser/region.rb +66 -0
  134. data/lib/solargraph/parser/rubyvm.rb +40 -0
  135. data/lib/solargraph/parser/rubyvm/class_methods.rb +150 -0
  136. data/lib/solargraph/parser/rubyvm/node_chainer.rb +135 -0
  137. data/lib/solargraph/parser/rubyvm/node_methods.rb +284 -0
  138. data/lib/solargraph/parser/rubyvm/node_processors.rb +61 -0
  139. data/lib/solargraph/parser/rubyvm/node_processors/alias_node.rb +23 -0
  140. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +62 -0
  141. data/lib/solargraph/parser/rubyvm/node_processors/begin_node.rb +15 -0
  142. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +22 -0
  143. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +22 -0
  144. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +23 -0
  145. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +64 -0
  146. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +57 -0
  147. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +23 -0
  148. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +38 -0
  149. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +39 -0
  150. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +20 -0
  151. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +27 -0
  152. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +39 -0
  153. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +31 -0
  154. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +15 -0
  155. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +45 -0
  156. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +21 -0
  157. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +15 -0
  158. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +255 -0
  159. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +18 -0
  160. data/lib/solargraph/parser/snippet.rb +13 -0
  161. data/lib/solargraph/pin.rb +39 -0
  162. data/lib/solargraph/pin/attribute.rb +49 -0
  163. data/lib/solargraph/pin/base.rb +296 -0
  164. data/lib/solargraph/pin/base_method.rb +141 -0
  165. data/lib/solargraph/pin/base_variable.rb +84 -0
  166. data/lib/solargraph/pin/block.rb +48 -0
  167. data/lib/solargraph/pin/class_variable.rb +8 -0
  168. data/lib/solargraph/pin/closure.rb +37 -0
  169. data/lib/solargraph/pin/common.rb +70 -0
  170. data/lib/solargraph/pin/constant.rb +43 -0
  171. data/lib/solargraph/pin/conversions.rb +97 -0
  172. data/lib/solargraph/pin/documenting.rb +110 -0
  173. data/lib/solargraph/pin/duck_method.rb +16 -0
  174. data/lib/solargraph/pin/global_variable.rb +8 -0
  175. data/lib/solargraph/pin/instance_variable.rb +30 -0
  176. data/lib/solargraph/pin/keyword.rb +15 -0
  177. data/lib/solargraph/pin/keyword_param.rb +8 -0
  178. data/lib/solargraph/pin/local_variable.rb +21 -0
  179. data/lib/solargraph/pin/localized.rb +43 -0
  180. data/lib/solargraph/pin/method.rb +111 -0
  181. data/lib/solargraph/pin/method_alias.rb +31 -0
  182. data/lib/solargraph/pin/namespace.rb +85 -0
  183. data/lib/solargraph/pin/parameter.rb +206 -0
  184. data/lib/solargraph/pin/proxy_type.rb +29 -0
  185. data/lib/solargraph/pin/reference.rb +14 -0
  186. data/lib/solargraph/pin/reference/extend.rb +10 -0
  187. data/lib/solargraph/pin/reference/include.rb +10 -0
  188. data/lib/solargraph/pin/reference/override.rb +29 -0
  189. data/lib/solargraph/pin/reference/prepend.rb +10 -0
  190. data/lib/solargraph/pin/reference/require.rb +14 -0
  191. data/lib/solargraph/pin/reference/superclass.rb +10 -0
  192. data/lib/solargraph/pin/singleton.rb +11 -0
  193. data/lib/solargraph/pin/symbol.rb +47 -0
  194. data/lib/solargraph/pin/yard_pin.rb +12 -0
  195. data/lib/solargraph/pin/yard_pin/constant.rb +25 -0
  196. data/lib/solargraph/pin/yard_pin/method.rb +65 -0
  197. data/lib/solargraph/pin/yard_pin/namespace.rb +27 -0
  198. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +26 -0
  199. data/lib/solargraph/position.rb +112 -0
  200. data/lib/solargraph/range.rb +95 -0
  201. data/lib/solargraph/server_methods.rb +16 -0
  202. data/lib/solargraph/shell.rb +221 -0
  203. data/lib/solargraph/source.rb +533 -0
  204. data/lib/solargraph/source/chain.rb +172 -0
  205. data/lib/solargraph/source/chain/block_variable.rb +13 -0
  206. data/lib/solargraph/source/chain/call.rb +203 -0
  207. data/lib/solargraph/source/chain/class_variable.rb +13 -0
  208. data/lib/solargraph/source/chain/constant.rb +75 -0
  209. data/lib/solargraph/source/chain/global_variable.rb +13 -0
  210. data/lib/solargraph/source/chain/head.rb +35 -0
  211. data/lib/solargraph/source/chain/instance_variable.rb +13 -0
  212. data/lib/solargraph/source/chain/link.rb +67 -0
  213. data/lib/solargraph/source/chain/literal.rb +23 -0
  214. data/lib/solargraph/source/chain/or.rb +23 -0
  215. data/lib/solargraph/source/chain/variable.rb +13 -0
  216. data/lib/solargraph/source/chain/z_super.rb +184 -0
  217. data/lib/solargraph/source/change.rb +79 -0
  218. data/lib/solargraph/source/cursor.rb +164 -0
  219. data/lib/solargraph/source/encoding_fixes.rb +23 -0
  220. data/lib/solargraph/source/source_chainer.rb +189 -0
  221. data/lib/solargraph/source/updater.rb +54 -0
  222. data/lib/solargraph/source_map.rb +170 -0
  223. data/lib/solargraph/source_map/clip.rb +190 -0
  224. data/lib/solargraph/source_map/completion.rb +23 -0
  225. data/lib/solargraph/source_map/mapper.rb +199 -0
  226. data/lib/solargraph/stdlib_fills.rb +32 -0
  227. data/lib/solargraph/type_checker.rb +498 -0
  228. data/lib/solargraph/type_checker/checks.rb +95 -0
  229. data/lib/solargraph/type_checker/param_def.rb +35 -0
  230. data/lib/solargraph/type_checker/problem.rb +32 -0
  231. data/lib/solargraph/type_checker/rules.rb +53 -0
  232. data/lib/solargraph/version.rb +5 -0
  233. data/lib/solargraph/views/_method.erb +62 -0
  234. data/lib/solargraph/views/_name_type_tag.erb +10 -0
  235. data/lib/solargraph/views/_namespace.erb +24 -0
  236. data/lib/solargraph/views/document.erb +23 -0
  237. data/lib/solargraph/views/environment.erb +58 -0
  238. data/lib/solargraph/views/layout.erb +44 -0
  239. data/lib/solargraph/views/search.erb +11 -0
  240. data/lib/solargraph/workspace.rb +209 -0
  241. data/lib/solargraph/workspace/config.rb +215 -0
  242. data/lib/solargraph/yard_map.rb +420 -0
  243. data/lib/solargraph/yard_map/cache.rb +19 -0
  244. data/lib/solargraph/yard_map/core_docs.rb +170 -0
  245. data/lib/solargraph/yard_map/core_gen.rb +76 -0
  246. data/lib/solargraph/yard_map/mapper.rb +71 -0
  247. data/lib/solargraph/yard_map/rdoc_to_yard.rb +136 -0
  248. data/lib/yard-solargraph.rb +30 -0
  249. data/solargraph.gemspec +41 -0
  250. data/travis-bundler.rb +11 -0
  251. data/yardoc/2.2.2.tar.gz +0 -0
  252. metadata +575 -0
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ # Information about a position in a source, including the word located
6
+ # there.
7
+ #
8
+ class Cursor
9
+ # @return [Position]
10
+ attr_reader :position
11
+
12
+ # @return [Source]
13
+ attr_reader :source
14
+
15
+ # @param source [Source]
16
+ # @param position [Position, Array(Integer, Integer)]
17
+ def initialize source, position
18
+ @source = source
19
+ @position = Position.normalize(position)
20
+ end
21
+
22
+ # @return [String]
23
+ def filename
24
+ source.filename
25
+ end
26
+
27
+ # The whole word at the current position. Given the text `foo.bar`, the
28
+ # word at position(0,6) is `bar`.
29
+ #
30
+ # @return [String]
31
+ def word
32
+ @word ||= start_of_word + end_of_word
33
+ end
34
+
35
+ # The part of the word before the current position. Given the text
36
+ # `foo.bar`, the start_of_word at position(0, 6) is `ba`.
37
+ #
38
+ # @return [String]
39
+ def start_of_word
40
+ @start_of_word ||= begin
41
+ match = source.code[0..offset-1].to_s.match(start_word_pattern)
42
+ result = (match ? match[0] : '')
43
+ # Including the preceding colon if the word appears to be a symbol
44
+ result = ":#{result}" if source.code[0..offset-result.length-1].end_with?(':') and !source.code[0..offset-result.length-1].end_with?('::')
45
+ result
46
+ end
47
+ end
48
+
49
+ # The part of the word after the current position. Given the text
50
+ # `foo.bar`, the end_of_word at position (0,6) is `r`.
51
+ #
52
+ # @return [String]
53
+ def end_of_word
54
+ @end_of_word ||= begin
55
+ match = source.code[offset..-1].to_s.match(end_word_pattern)
56
+ match ? match[0] : ''
57
+ end
58
+ end
59
+
60
+ # @return [Boolean]
61
+ def start_of_constant?
62
+ source.code[offset-2, 2] == '::'
63
+ end
64
+
65
+ # The range of the word at the current position.
66
+ #
67
+ # @return [Range]
68
+ def range
69
+ @range ||= begin
70
+ s = Position.from_offset(source.code, offset - start_of_word.length)
71
+ e = Position.from_offset(source.code, offset + end_of_word.length)
72
+ Solargraph::Range.new(s, e)
73
+ end
74
+ end
75
+
76
+ # @return [Chain]
77
+ def chain
78
+ @chain ||= SourceChainer.chain(source, position)
79
+ end
80
+
81
+ # True if the statement at the cursor is an argument to a previous
82
+ # method.
83
+ #
84
+ # Given the code `process(foo)`, a cursor pointing at `foo` would
85
+ # identify it as an argument being passed to the `process` method.
86
+ #
87
+ # If #argument? is true, the #recipient method will return a cursor that
88
+ # points to the method receiving the argument.
89
+ #
90
+ # @return [Boolean]
91
+ def argument?
92
+ # @argument ||= !signature_position.nil?
93
+ @argument ||= !recipient.nil?
94
+ end
95
+
96
+ # @return [Boolean]
97
+ def comment?
98
+ @comment ||= source.comment_at?(position)
99
+ end
100
+
101
+ # @return [Boolean]
102
+ def string?
103
+ @string ||= source.string_at?(position)
104
+ end
105
+
106
+ # Get a cursor pointing to the method that receives the current statement
107
+ # as an argument.
108
+ #
109
+ # @return [Cursor, nil]
110
+ def recipient
111
+ @recipient ||= begin
112
+ node = recipient_node
113
+ node ? Cursor.new(source, Range.from_node(node).ending) : nil
114
+ end
115
+ end
116
+ alias receiver recipient
117
+
118
+ def node
119
+ @node ||= source.node_at(position.line, position.column)
120
+ end
121
+
122
+ # @return [Position]
123
+ def node_position
124
+ @node_position ||= begin
125
+ if start_of_word.empty?
126
+ match = source.code[0, offset].match(/[\s]*(\.|:+)[\s]*$/)
127
+ if match
128
+ Position.from_offset(source.code, offset - match[0].length)
129
+ else
130
+ position
131
+ end
132
+ else
133
+ position
134
+ end
135
+ end
136
+ end
137
+
138
+ def recipient_node
139
+ @recipient_node ||= Solargraph::Parser::NodeMethods.find_recipient_node(self)
140
+ end
141
+
142
+ # @return [Integer]
143
+ def offset
144
+ @offset ||= Position.to_offset(source.code, position)
145
+ end
146
+
147
+ private
148
+
149
+ # A regular expression to find the start of a word from an offset.
150
+ #
151
+ # @return [Regexp]
152
+ def start_word_pattern
153
+ /(@{1,2}|\$)?([a-z0-9_]|[^\u0000-\u007F])*\z/i
154
+ end
155
+
156
+ # A regular expression to find the end of a word from an offset.
157
+ #
158
+ # @return [Regexp]
159
+ def end_word_pattern
160
+ /^([a-z0-9_]|[^\u0000-\u007F])*[\?\!]?/i
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ module EncodingFixes
6
+ module_function
7
+
8
+ # Convert strings to normalized UTF-8.
9
+ #
10
+ # @param string [String]
11
+ # @return [String]
12
+ def normalize string
13
+ begin
14
+ string.dup.force_encoding('UTF-8')
15
+ rescue ::Encoding::CompatibilityError, ::Encoding::UndefinedConversionError, ::Encoding::InvalidByteSequenceError => e
16
+ # @todo Improve error handling
17
+ Solargraph::Logging.logger.warn "Normalize error: #{e.message}"
18
+ string
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ # Information about a location in a source, including the location's word
6
+ # and signature, literal values at the base of signatures, and whether the
7
+ # location is inside a string or comment. ApiMaps use Fragments to provide
8
+ # results for completion and definition queries.
9
+ #
10
+ class SourceChainer
11
+ # include Source::NodeMethods
12
+
13
+ private_class_method :new
14
+
15
+ class << self
16
+ # @param source [Source]
17
+ # @param position [Position]
18
+ # @return [Source::Chain]
19
+ def chain source, position
20
+ # raise "Not a source" unless source.is_a?(Source)
21
+ new(source, position).chain
22
+ end
23
+ end
24
+
25
+ # @param source [Source]
26
+ # @param position [Position]
27
+ def initialize source, position
28
+ @source = source
29
+ @position = position
30
+ @calculated_literal = false
31
+ end
32
+
33
+ # @return [Source::Chain]
34
+ def chain
35
+ return Chain.new([Chain::Literal.new('Symbol')]) if phrase.start_with?(':') && !phrase.start_with?('::')
36
+ begin
37
+ return Chain.new([]) if phrase.end_with?('..')
38
+ node = nil
39
+ parent = nil
40
+ if !source.repaired? && source.parsed? && source.synchronized?
41
+ tree = source.tree_at(position.line, position.column)
42
+ # node, parent = source.tree_at(position.line, position.column)[0..2]
43
+ tree.shift while tree.length > 1 && tree.first.type == :SCOPE
44
+ node, parent = tree[0..2]
45
+ elsif source.parsed? && source.repaired? && end_of_phrase == '.'
46
+ node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2]
47
+ node = Parser.parse(fixed_phrase) if node.nil?
48
+ else
49
+ node, parent = source.tree_at(fixed_position.line, fixed_position.column)[0..2] unless source.error_ranges.any?{|r| r.nil? || r.include?(fixed_position)}
50
+ # Exception for positions that chain literal nodes in unsynchronized sources
51
+ node = nil unless source.synchronized? || !Parser.infer_literal_node_type(node).nil?
52
+ node = Parser.parse(fixed_phrase) if node.nil?
53
+ end
54
+ rescue Parser::SyntaxError
55
+ return Chain.new([Chain::UNDEFINED_CALL])
56
+ end
57
+ return Chain.new([Chain::UNDEFINED_CALL]) if node.nil? || (node.type == :sym && !phrase.start_with?(':'))
58
+ # chain = NodeChainer.chain(node, source.filename, parent && parent.type == :block)
59
+ chain = Parser.chain(node, source.filename, parent && [:ITER, :block].include?(parent.type))
60
+ if source.repaired? || !source.parsed? || !source.synchronized?
61
+ if end_of_phrase.strip == '.'
62
+ chain.links.push Chain::UNDEFINED_CALL
63
+ elsif end_of_phrase.strip == '::'
64
+ chain.links.push Chain::UNDEFINED_CONSTANT
65
+ end
66
+ elsif chain.links.last.is_a?(Source::Chain::Constant) && end_of_phrase.strip == '::'
67
+ chain.links.push Source::Chain::UNDEFINED_CONSTANT
68
+ end
69
+ chain
70
+ end
71
+
72
+ private
73
+
74
+ # @return [Position]
75
+ attr_reader :position
76
+
77
+ # @return [Solargraph::Source]
78
+ attr_reader :source
79
+
80
+ # @return [String]
81
+ def phrase
82
+ @phrase ||= source.code[signature_data..offset-1]
83
+ end
84
+
85
+ # @return [String]
86
+ def fixed_phrase
87
+ @fixed_phrase ||= phrase[0..-(end_of_phrase.length+1)]
88
+ end
89
+
90
+ # @return [Position]
91
+ def fixed_position
92
+ @fixed_position ||= Position.from_offset(source.code, offset - end_of_phrase.length)
93
+ end
94
+
95
+ # @return [String]
96
+ def end_of_phrase
97
+ @end_of_phrase ||= begin
98
+ match = phrase.match(/[\s]*(\.{1}|::)[\s]*$/)
99
+ if match
100
+ match[0]
101
+ else
102
+ ''
103
+ end
104
+ end
105
+ end
106
+
107
+ # True if the current offset is inside a string.
108
+ #
109
+ # @return [Boolean]
110
+ def string?
111
+ # @string ||= (node.type == :str or node.type == :dstr)
112
+ @string ||= @source.string_at?(position)
113
+ end
114
+
115
+ # @return [Integer]
116
+ def offset
117
+ @offset ||= get_offset(position.line, position.column)
118
+ end
119
+
120
+ # @param line [Integer]
121
+ # @param column [Integer]
122
+ # @return [Integer]
123
+ def get_offset line, column
124
+ Position.line_char_to_offset(@source.code, line, column)
125
+ end
126
+
127
+ def signature_data
128
+ @signature_data ||= get_signature_data_at(offset)
129
+ end
130
+
131
+ def get_signature_data_at index
132
+ brackets = 0
133
+ squares = 0
134
+ parens = 0
135
+ index -=1
136
+ in_whitespace = false
137
+ while index >= 0
138
+ pos = Position.from_offset(@source.code, index)
139
+ break if index > 0 and @source.comment_at?(pos)
140
+ break if brackets > 0 or parens > 0 or squares > 0
141
+ char = @source.code[index, 1]
142
+ break if char.nil? # @todo Is this the right way to handle this?
143
+ if brackets.zero? and parens.zero? and squares.zero? and [' ', "\r", "\n", "\t"].include?(char)
144
+ in_whitespace = true
145
+ else
146
+ if brackets.zero? and parens.zero? and squares.zero? and in_whitespace
147
+ unless char == '.' or @source.code[index+1..-1].strip.start_with?('.')
148
+ old = @source.code[index+1..-1]
149
+ nxt = @source.code[index+1..-1].lstrip
150
+ index += (@source.code[index+1..-1].length - @source.code[index+1..-1].lstrip.length)
151
+ break
152
+ end
153
+ end
154
+ if char == ')'
155
+ parens -=1
156
+ elsif char == ']'
157
+ squares -=1
158
+ elsif char == '}'
159
+ brackets -= 1
160
+ elsif char == '('
161
+ parens += 1
162
+ elsif char == '{'
163
+ brackets += 1
164
+ elsif char == '['
165
+ squares += 1
166
+ end
167
+ if brackets.zero? and parens.zero? and squares.zero?
168
+ break if ['"', "'", ',', ';', '%'].include?(char)
169
+ break if ['!', '?'].include?(char) && index < offset - 1
170
+ break if char == '$'
171
+ if char == '@'
172
+ index -= 1
173
+ if @source.code[index, 1] == '@'
174
+ index -= 1
175
+ end
176
+ break
177
+ end
178
+ elsif parens == 1 || brackets == 1 || squares == 1
179
+ break
180
+ end
181
+ in_whitespace = false
182
+ end
183
+ index -= 1
184
+ end
185
+ index + 1
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class Source
5
+ # Updaters contain changes to be applied to a source. The source applies
6
+ # the update via the Source#synchronize method.
7
+ #
8
+ class Updater
9
+ # @return [String]
10
+ attr_reader :filename
11
+
12
+ # @return [Integer]
13
+ attr_reader :version
14
+
15
+ # @return [Array<Change>]
16
+ attr_reader :changes
17
+
18
+ # @param filename [String] The file to update.
19
+ # @param version [Integer] A version number associated with this update.
20
+ # @param changes [Array<Solargraph::Source::Change>] The changes.
21
+ def initialize filename, version, changes
22
+ @filename = filename
23
+ @version = version
24
+ @changes = changes
25
+ @input = nil
26
+ @did_nullify = nil
27
+ @output = nil
28
+ end
29
+
30
+ # @param text [String]
31
+ # @param nullable [Boolean]
32
+ # @return [String]
33
+ def write text, nullable = false
34
+ can_nullify = (nullable and changes.length == 1)
35
+ return @output if @input == text and can_nullify == @did_nullify
36
+ @input = text
37
+ @output = text
38
+ @did_nullify = can_nullify
39
+ changes.each do |ch|
40
+ @output = ch.write(@output, can_nullify)
41
+ end
42
+ @output
43
+ end
44
+
45
+ # @return [String]
46
+ def repair text
47
+ changes.each do |ch|
48
+ text = ch.repair(text)
49
+ end
50
+ text
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jaro_winkler'
4
+ require 'yard'
5
+ require 'yard-solargraph'
6
+
7
+ module Solargraph
8
+ # An index of pins and other ApiMap-related data for a Source.
9
+ #
10
+ class SourceMap
11
+ autoload :Mapper, 'solargraph/source_map/mapper'
12
+ autoload :Clip, 'solargraph/source_map/clip'
13
+ autoload :Completion, 'solargraph/source_map/completion'
14
+
15
+ # @return [Source]
16
+ attr_reader :source
17
+
18
+ # @return [Array<Pin::Base>]
19
+ attr_reader :pins
20
+
21
+ # @return [Array<Pin::Base>]
22
+ attr_reader :locals
23
+
24
+ # @param source [Source]
25
+ # @param pins [Array<Pin::Base>]
26
+ # @param locals [Array<Pin::Base>]
27
+ def initialize source, pins, locals
28
+ # HACK: Keep the library from changing this
29
+ @source = source.dup
30
+ @pins = pins
31
+ @locals = locals
32
+ environ.merge Convention.for(source)
33
+ end
34
+
35
+ # @return [String]
36
+ def filename
37
+ source.filename
38
+ end
39
+
40
+ # @return [String]
41
+ def code
42
+ source.code
43
+ end
44
+
45
+ # @return [Array<Pin::Reference::Require>]
46
+ def requires
47
+ @requires ||= pins.select{ |p| p.is_a?(Pin::Reference::Require) }
48
+ end
49
+
50
+ # @return [Environ]
51
+ def environ
52
+ @environ ||= Environ.new
53
+ end
54
+
55
+ # @return [Array<Pin::Base>]
56
+ def document_symbols
57
+ @document_symbols ||= pins.select { |pin|
58
+ pin.path && !pin.path.empty?
59
+ }
60
+ end
61
+
62
+ # @param query [String]
63
+ # @return [Array<Pin::Base>]
64
+ def query_symbols query
65
+ document_symbols.select{ |pin| fuzzy_string_match(pin.path, query) || fuzzy_string_match(pin.name, query) }
66
+ end
67
+
68
+ # @param position [Position]
69
+ # @return [Source::Cursor]
70
+ def cursor_at position
71
+ Source::Cursor.new(source, position)
72
+ end
73
+
74
+ # @param path [String]
75
+ # @return [Pin::Base]
76
+ def first_pin path
77
+ pins.select { |p| p.path == path }.first
78
+ end
79
+
80
+ # @param location [Solargraph::Location]
81
+ # @return [Array<Solargraph::Pin::Base>]
82
+ def locate_pins location
83
+ # return nil unless location.start_with?("#{filename}:")
84
+ (pins + locals).select { |pin| pin.location == location }
85
+ end
86
+
87
+ def locate_named_path_pin line, character
88
+ _locate_pin line, character, Pin::Namespace, Pin::Method
89
+ end
90
+
91
+ def locate_block_pin line, character
92
+ _locate_pin line, character, Pin::Namespace, Pin::Method, Pin::Block
93
+ end
94
+
95
+ # @param other_map [SourceMap]
96
+ # @return [Boolean]
97
+ def try_merge! other_map
98
+ 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
99
+ pins.each_index do |i|
100
+ return false unless pins[i].try_merge!(other_map.pins[i])
101
+ end
102
+ locals.each_index do |i|
103
+ return false unless locals[i].try_merge!(other_map.locals[i])
104
+ end
105
+ @source = other_map.source
106
+ true
107
+ end
108
+
109
+ # @param name [String]
110
+ # @return [Array<Location>]
111
+ def references name
112
+ source.references name
113
+ end
114
+
115
+ # @param location [Location]
116
+ # @return [Array<Pin::LocalVariable>]
117
+ def locals_at(location)
118
+ return [] if location.filename != filename
119
+ locals.select { |pin| pin.visible_at?(location) }
120
+ end
121
+
122
+ class << self
123
+ # @param filename [String]
124
+ # @return [SourceMap]
125
+ def load filename
126
+ source = Solargraph::Source.load(filename)
127
+ SourceMap.map(source)
128
+ end
129
+
130
+ # @param code [String]
131
+ # @param filename [String, nil]
132
+ # @return [SourceMap]
133
+ def load_string code, filename = nil
134
+ source = Solargraph::Source.load_string(code, filename)
135
+ SourceMap.map(source)
136
+ end
137
+
138
+ # @param source [Source]
139
+ # @return [SourceMap]
140
+ def map source
141
+ result = SourceMap::Mapper.map(source)
142
+ new(source, *result)
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ # @param line [Integer]
149
+ # @param character [Integer]
150
+ # @param klasses [Array<Class>]
151
+ # @return [Pin::Base]
152
+ def _locate_pin line, character, *klasses
153
+ position = Position.new(line, character)
154
+ found = nil
155
+ pins.each do |pin|
156
+ found = pin if (klasses.empty? || klasses.any? { |kls| pin.is_a?(kls) } ) && pin.location.range.contain?(position)
157
+ break if pin.location.range.start.line > line
158
+ end
159
+ # Assuming the root pin is always valid
160
+ found || pins.first
161
+ end
162
+
163
+ # @param str1 [String]
164
+ # @param str2 [String]
165
+ # @return [Boolean]
166
+ def fuzzy_string_match str1, str2
167
+ JaroWinkler.distance(str1, str2) > 0.6
168
+ end
169
+ end
170
+ end