jimeh-solargraph 0.40.4.0

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/.github/workflows/ci.yml +54 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +24 -0
  6. data/.yardopts +2 -0
  7. data/CHANGELOG.md +1003 -0
  8. data/Gemfile +7 -0
  9. data/LICENSE +21 -0
  10. data/README.md +123 -0
  11. data/Rakefile +25 -0
  12. data/SPONSORS.md +15 -0
  13. data/bin/solargraph +5 -0
  14. data/jimeh-solargraph.gemspec +44 -0
  15. data/lib/.rubocop.yml +21 -0
  16. data/lib/solargraph.rb +67 -0
  17. data/lib/solargraph/api_map.rb +752 -0
  18. data/lib/solargraph/api_map/bundler_methods.rb +27 -0
  19. data/lib/solargraph/api_map/cache.rb +70 -0
  20. data/lib/solargraph/api_map/source_to_yard.rb +81 -0
  21. data/lib/solargraph/api_map/store.rb +256 -0
  22. data/lib/solargraph/bench.rb +30 -0
  23. data/lib/solargraph/compat.rb +23 -0
  24. data/lib/solargraph/complex_type.rb +213 -0
  25. data/lib/solargraph/complex_type/type_methods.rb +127 -0
  26. data/lib/solargraph/complex_type/unique_type.rb +75 -0
  27. data/lib/solargraph/convention.rb +47 -0
  28. data/lib/solargraph/convention/base.rb +33 -0
  29. data/lib/solargraph/convention/gemfile.rb +15 -0
  30. data/lib/solargraph/convention/gemspec.rb +22 -0
  31. data/lib/solargraph/convention/rspec.rb +21 -0
  32. data/lib/solargraph/converters/dd.rb +12 -0
  33. data/lib/solargraph/converters/dl.rb +12 -0
  34. data/lib/solargraph/converters/dt.rb +12 -0
  35. data/lib/solargraph/converters/misc.rb +1 -0
  36. data/lib/solargraph/diagnostics.rb +55 -0
  37. data/lib/solargraph/diagnostics/base.rb +29 -0
  38. data/lib/solargraph/diagnostics/require_not_found.rb +37 -0
  39. data/lib/solargraph/diagnostics/rubocop.rb +90 -0
  40. data/lib/solargraph/diagnostics/rubocop_helpers.rb +45 -0
  41. data/lib/solargraph/diagnostics/severities.rb +15 -0
  42. data/lib/solargraph/diagnostics/type_check.rb +54 -0
  43. data/lib/solargraph/diagnostics/update_errors.rb +41 -0
  44. data/lib/solargraph/documentor.rb +78 -0
  45. data/lib/solargraph/environ.rb +45 -0
  46. data/lib/solargraph/language_server.rb +19 -0
  47. data/lib/solargraph/language_server/completion_item_kinds.rb +35 -0
  48. data/lib/solargraph/language_server/error_codes.rb +20 -0
  49. data/lib/solargraph/language_server/host.rb +746 -0
  50. data/lib/solargraph/language_server/host/cataloger.rb +56 -0
  51. data/lib/solargraph/language_server/host/diagnoser.rb +81 -0
  52. data/lib/solargraph/language_server/host/dispatch.rb +112 -0
  53. data/lib/solargraph/language_server/host/sources.rb +156 -0
  54. data/lib/solargraph/language_server/message.rb +92 -0
  55. data/lib/solargraph/language_server/message/base.rb +85 -0
  56. data/lib/solargraph/language_server/message/cancel_request.rb +13 -0
  57. data/lib/solargraph/language_server/message/client.rb +11 -0
  58. data/lib/solargraph/language_server/message/client/register_capability.rb +15 -0
  59. data/lib/solargraph/language_server/message/completion_item.rb +11 -0
  60. data/lib/solargraph/language_server/message/completion_item/resolve.rb +57 -0
  61. data/lib/solargraph/language_server/message/exit_notification.rb +13 -0
  62. data/lib/solargraph/language_server/message/extended.rb +21 -0
  63. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +100 -0
  64. data/lib/solargraph/language_server/message/extended/document.rb +20 -0
  65. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -0
  66. data/lib/solargraph/language_server/message/extended/download_core.rb +23 -0
  67. data/lib/solargraph/language_server/message/extended/environment.rb +25 -0
  68. data/lib/solargraph/language_server/message/extended/search.rb +20 -0
  69. data/lib/solargraph/language_server/message/initialize.rb +153 -0
  70. data/lib/solargraph/language_server/message/initialized.rb +26 -0
  71. data/lib/solargraph/language_server/message/method_not_found.rb +16 -0
  72. data/lib/solargraph/language_server/message/method_not_implemented.rb +14 -0
  73. data/lib/solargraph/language_server/message/shutdown.rb +13 -0
  74. data/lib/solargraph/language_server/message/text_document.rb +28 -0
  75. data/lib/solargraph/language_server/message/text_document/base.rb +19 -0
  76. data/lib/solargraph/language_server/message/text_document/code_action.rb +17 -0
  77. data/lib/solargraph/language_server/message/text_document/completion.rb +57 -0
  78. data/lib/solargraph/language_server/message/text_document/definition.rb +38 -0
  79. data/lib/solargraph/language_server/message/text_document/did_change.rb +15 -0
  80. data/lib/solargraph/language_server/message/text_document/did_close.rb +15 -0
  81. data/lib/solargraph/language_server/message/text_document/did_open.rb +15 -0
  82. data/lib/solargraph/language_server/message/text_document/did_save.rb +17 -0
  83. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +23 -0
  84. data/lib/solargraph/language_server/message/text_document/folding_range.rb +26 -0
  85. data/lib/solargraph/language_server/message/text_document/formatting.rb +105 -0
  86. data/lib/solargraph/language_server/message/text_document/hover.rb +44 -0
  87. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +34 -0
  88. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +11 -0
  89. data/lib/solargraph/language_server/message/text_document/references.rb +16 -0
  90. data/lib/solargraph/language_server/message/text_document/rename.rb +19 -0
  91. data/lib/solargraph/language_server/message/text_document/signature_help.rb +29 -0
  92. data/lib/solargraph/language_server/message/workspace.rb +14 -0
  93. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +29 -0
  94. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +33 -0
  95. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -0
  96. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -0
  97. data/lib/solargraph/language_server/message_types.rb +14 -0
  98. data/lib/solargraph/language_server/request.rb +24 -0
  99. data/lib/solargraph/language_server/symbol_kinds.rb +36 -0
  100. data/lib/solargraph/language_server/transport.rb +13 -0
  101. data/lib/solargraph/language_server/transport/adapter.rb +56 -0
  102. data/lib/solargraph/language_server/transport/data_reader.rb +72 -0
  103. data/lib/solargraph/language_server/uri_helpers.rb +49 -0
  104. data/lib/solargraph/library.rb +426 -0
  105. data/lib/solargraph/location.rb +37 -0
  106. data/lib/solargraph/logging.rb +27 -0
  107. data/lib/solargraph/page.rb +83 -0
  108. data/lib/solargraph/parser.rb +26 -0
  109. data/lib/solargraph/parser/comment_ripper.rb +52 -0
  110. data/lib/solargraph/parser/legacy.rb +12 -0
  111. data/lib/solargraph/parser/legacy/class_methods.rb +109 -0
  112. data/lib/solargraph/parser/legacy/flawed_builder.rb +16 -0
  113. data/lib/solargraph/parser/legacy/node_chainer.rb +118 -0
  114. data/lib/solargraph/parser/legacy/node_methods.rb +311 -0
  115. data/lib/solargraph/parser/legacy/node_processors.rb +54 -0
  116. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +23 -0
  117. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +35 -0
  118. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +15 -0
  119. data/lib/solargraph/parser/legacy/node_processors/block_node.rb +22 -0
  120. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +25 -0
  121. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +23 -0
  122. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +63 -0
  123. data/lib/solargraph/parser/legacy/node_processors/defs_node.rb +36 -0
  124. data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +23 -0
  125. data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +38 -0
  126. data/lib/solargraph/parser/legacy/node_processors/lvasgn_node.rb +28 -0
  127. data/lib/solargraph/parser/legacy/node_processors/namespace_node.rb +39 -0
  128. data/lib/solargraph/parser/legacy/node_processors/orasgn_node.rb +16 -0
  129. data/lib/solargraph/parser/legacy/node_processors/resbody_node.rb +36 -0
  130. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +21 -0
  131. data/lib/solargraph/parser/legacy/node_processors/send_node.rb +257 -0
  132. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +18 -0
  133. data/lib/solargraph/parser/node_methods.rb +43 -0
  134. data/lib/solargraph/parser/node_processor.rb +43 -0
  135. data/lib/solargraph/parser/node_processor/base.rb +80 -0
  136. data/lib/solargraph/parser/region.rb +66 -0
  137. data/lib/solargraph/parser/rubyvm.rb +40 -0
  138. data/lib/solargraph/parser/rubyvm/class_methods.rb +150 -0
  139. data/lib/solargraph/parser/rubyvm/node_chainer.rb +135 -0
  140. data/lib/solargraph/parser/rubyvm/node_methods.rb +301 -0
  141. data/lib/solargraph/parser/rubyvm/node_processors.rb +62 -0
  142. data/lib/solargraph/parser/rubyvm/node_processors/alias_node.rb +23 -0
  143. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +86 -0
  144. data/lib/solargraph/parser/rubyvm/node_processors/begin_node.rb +15 -0
  145. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +22 -0
  146. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +22 -0
  147. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +23 -0
  148. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +64 -0
  149. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +57 -0
  150. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +23 -0
  151. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +38 -0
  152. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +39 -0
  153. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +20 -0
  154. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +27 -0
  155. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +39 -0
  156. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +26 -0
  157. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +15 -0
  158. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +45 -0
  159. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +21 -0
  160. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +15 -0
  161. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +277 -0
  162. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +18 -0
  163. data/lib/solargraph/parser/snippet.rb +13 -0
  164. data/lib/solargraph/pin.rb +36 -0
  165. data/lib/solargraph/pin/base.rb +296 -0
  166. data/lib/solargraph/pin/base_variable.rb +84 -0
  167. data/lib/solargraph/pin/block.rb +62 -0
  168. data/lib/solargraph/pin/class_variable.rb +8 -0
  169. data/lib/solargraph/pin/closure.rb +37 -0
  170. data/lib/solargraph/pin/common.rb +70 -0
  171. data/lib/solargraph/pin/constant.rb +43 -0
  172. data/lib/solargraph/pin/conversions.rb +96 -0
  173. data/lib/solargraph/pin/documenting.rb +105 -0
  174. data/lib/solargraph/pin/duck_method.rb +16 -0
  175. data/lib/solargraph/pin/global_variable.rb +8 -0
  176. data/lib/solargraph/pin/instance_variable.rb +30 -0
  177. data/lib/solargraph/pin/keyword.rb +15 -0
  178. data/lib/solargraph/pin/keyword_param.rb +8 -0
  179. data/lib/solargraph/pin/local_variable.rb +21 -0
  180. data/lib/solargraph/pin/localized.rb +43 -0
  181. data/lib/solargraph/pin/method.rb +245 -0
  182. data/lib/solargraph/pin/method_alias.rb +31 -0
  183. data/lib/solargraph/pin/namespace.rb +85 -0
  184. data/lib/solargraph/pin/parameter.rb +206 -0
  185. data/lib/solargraph/pin/proxy_type.rb +29 -0
  186. data/lib/solargraph/pin/reference.rb +14 -0
  187. data/lib/solargraph/pin/reference/extend.rb +10 -0
  188. data/lib/solargraph/pin/reference/include.rb +10 -0
  189. data/lib/solargraph/pin/reference/override.rb +29 -0
  190. data/lib/solargraph/pin/reference/prepend.rb +10 -0
  191. data/lib/solargraph/pin/reference/require.rb +14 -0
  192. data/lib/solargraph/pin/reference/superclass.rb +10 -0
  193. data/lib/solargraph/pin/singleton.rb +11 -0
  194. data/lib/solargraph/pin/symbol.rb +47 -0
  195. data/lib/solargraph/position.rb +100 -0
  196. data/lib/solargraph/range.rb +95 -0
  197. data/lib/solargraph/server_methods.rb +16 -0
  198. data/lib/solargraph/shell.rb +222 -0
  199. data/lib/solargraph/source.rb +537 -0
  200. data/lib/solargraph/source/chain.rb +154 -0
  201. data/lib/solargraph/source/chain/block_variable.rb +13 -0
  202. data/lib/solargraph/source/chain/call.rb +203 -0
  203. data/lib/solargraph/source/chain/class_variable.rb +13 -0
  204. data/lib/solargraph/source/chain/constant.rb +75 -0
  205. data/lib/solargraph/source/chain/global_variable.rb +13 -0
  206. data/lib/solargraph/source/chain/head.rb +35 -0
  207. data/lib/solargraph/source/chain/instance_variable.rb +13 -0
  208. data/lib/solargraph/source/chain/link.rb +67 -0
  209. data/lib/solargraph/source/chain/literal.rb +23 -0
  210. data/lib/solargraph/source/chain/or.rb +23 -0
  211. data/lib/solargraph/source/chain/variable.rb +13 -0
  212. data/lib/solargraph/source/chain/z_super.rb +30 -0
  213. data/lib/solargraph/source/change.rb +79 -0
  214. data/lib/solargraph/source/cursor.rb +164 -0
  215. data/lib/solargraph/source/encoding_fixes.rb +23 -0
  216. data/lib/solargraph/source/source_chainer.rb +190 -0
  217. data/lib/solargraph/source/updater.rb +54 -0
  218. data/lib/solargraph/source_map.rb +188 -0
  219. data/lib/solargraph/source_map/clip.rb +224 -0
  220. data/lib/solargraph/source_map/completion.rb +23 -0
  221. data/lib/solargraph/source_map/mapper.rb +215 -0
  222. data/lib/solargraph/type_checker.rb +503 -0
  223. data/lib/solargraph/type_checker/checks.rb +99 -0
  224. data/lib/solargraph/type_checker/param_def.rb +35 -0
  225. data/lib/solargraph/type_checker/problem.rb +32 -0
  226. data/lib/solargraph/type_checker/rules.rb +57 -0
  227. data/lib/solargraph/version.rb +5 -0
  228. data/lib/solargraph/views/_method.erb +62 -0
  229. data/lib/solargraph/views/_name_type_tag.erb +10 -0
  230. data/lib/solargraph/views/_namespace.erb +24 -0
  231. data/lib/solargraph/views/document.erb +23 -0
  232. data/lib/solargraph/views/environment.erb +58 -0
  233. data/lib/solargraph/views/layout.erb +44 -0
  234. data/lib/solargraph/views/search.erb +11 -0
  235. data/lib/solargraph/workspace.rb +209 -0
  236. data/lib/solargraph/workspace/config.rb +230 -0
  237. data/lib/solargraph/yard_map.rb +435 -0
  238. data/lib/solargraph/yard_map/cache.rb +19 -0
  239. data/lib/solargraph/yard_map/core_docs.rb +170 -0
  240. data/lib/solargraph/yard_map/core_fills.rb +185 -0
  241. data/lib/solargraph/yard_map/core_gen.rb +76 -0
  242. data/lib/solargraph/yard_map/helpers.rb +16 -0
  243. data/lib/solargraph/yard_map/mapper.rb +77 -0
  244. data/lib/solargraph/yard_map/mapper/to_constant.rb +25 -0
  245. data/lib/solargraph/yard_map/mapper/to_method.rb +78 -0
  246. data/lib/solargraph/yard_map/mapper/to_namespace.rb +27 -0
  247. data/lib/solargraph/yard_map/rdoc_to_yard.rb +140 -0
  248. data/lib/solargraph/yard_map/stdlib_fills.rb +43 -0
  249. data/lib/solargraph/yard_map/to_method.rb +79 -0
  250. data/lib/yard-solargraph.rb +30 -0
  251. data/yardoc/2.2.2.tar.gz +0 -0
  252. metadata +564 -0
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ # A pair of positions that compose a section of text.
5
+ #
6
+ class Range
7
+ # @return [Position]
8
+ attr_reader :start
9
+
10
+ # @return [Position]
11
+ attr_reader :ending
12
+
13
+ # @param start [Position]
14
+ # @param ending [Position]
15
+ def initialize start, ending
16
+ @start = start
17
+ @ending = ending
18
+ end
19
+
20
+ # Get a hash of the range. This representation is suitable for use in
21
+ # the language server protocol.
22
+ #
23
+ # @return [Hash<Symbol, Position>]
24
+ def to_hash
25
+ {
26
+ start: start.to_hash,
27
+ end: ending.to_hash
28
+ }
29
+ end
30
+
31
+ # True if the specified position is inside the range.
32
+ #
33
+ # @param position [Position, Array(Integer, Integer)]
34
+ # @return [Boolean]
35
+ def contain? position
36
+ position = Position.normalize(position)
37
+ return false if position.line < start.line || position.line > ending.line
38
+ return false if position.line == start.line && position.character < start.character
39
+ return false if position.line == ending.line && position.character > ending.character
40
+ true
41
+ end
42
+
43
+ # True if the range contains the specified position and the position does not precede it.
44
+ #
45
+ # @param position [Position, Array(Integer, Integer)]
46
+ # @return [Boolean]
47
+ def include? position
48
+ position = Position.normalize(position)
49
+ contain?(position) && !(position.line == start.line && position.character == start.character)
50
+ end
51
+
52
+ # Create a range from a pair of lines and characters.
53
+ #
54
+ # @param l1 [Integer] Starting line
55
+ # @param c1 [Integer] Starting character
56
+ # @param l2 [Integer] Ending line
57
+ # @param c2 [Integer] Ending character
58
+ # @return [Range]
59
+ def self.from_to l1, c1, l2, c2
60
+ Range.new(Position.new(l1, c1), Position.new(l2, c2))
61
+ end
62
+
63
+ # Get a range from a node.
64
+ #
65
+ # @param node [RubyVM::AbstractSyntaxTree::Node, Parser::AST::Node]
66
+ # @return [Range]
67
+ def self.from_node node
68
+ if defined?(RubyVM::AbstractSyntaxTree::Node)
69
+ if node.is_a?(RubyVM::AbstractSyntaxTree::Node)
70
+ Solargraph::Range.from_to(node.first_lineno - 1, node.first_column, node.last_lineno - 1, node.last_column)
71
+ end
72
+ elsif node.loc && node.loc.expression
73
+ from_expr(node.loc.expression)
74
+ end
75
+ end
76
+
77
+ # Get a range from a Parser range, usually found in
78
+ # Parser::AST::Node#location#expression.
79
+ #
80
+ # @param expr [Parser::Source::Range]
81
+ # @return [Range]
82
+ def self.from_expr expr
83
+ from_to(expr.line, expr.column, expr.last_line, expr.last_column)
84
+ end
85
+
86
+ def == other
87
+ return false unless other.is_a?(Range)
88
+ start == other.start && ending == other.ending
89
+ end
90
+
91
+ def inspect
92
+ "#<#{self.class} #{start.inspect} to #{ending.inspect}>"
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+
5
+ module Solargraph
6
+ module ServerMethods
7
+ # @return [Integer]
8
+ def available_port
9
+ socket = Socket.new(:INET, :STREAM, 0)
10
+ socket.bind(Addrinfo.tcp("127.0.0.1", 0))
11
+ port = socket.local_address.ip_port
12
+ socket.close
13
+ port
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module Solargraph
6
+ class Shell < Thor
7
+ include Solargraph::ServerMethods
8
+
9
+ map %w[--version -v] => :version
10
+
11
+ desc "--version, -v", "Print the version"
12
+ def version
13
+ puts Solargraph::VERSION
14
+ end
15
+
16
+ desc 'socket', 'Run a Solargraph socket server'
17
+ option :host, type: :string, aliases: :h, desc: 'The server host', default: '127.0.0.1'
18
+ option :port, type: :numeric, aliases: :p, desc: 'The server port', default: 7658
19
+ def socket
20
+ require 'backport'
21
+ port = options[:port]
22
+ port = available_port if port.zero?
23
+ Backport.run do
24
+ Signal.trap("INT") do
25
+ Backport.stop
26
+ end
27
+ Signal.trap("TERM") do
28
+ Backport.stop
29
+ end
30
+ Backport.prepare_tcp_server host: options[:host], port: port, adapter: Solargraph::LanguageServer::Transport::Adapter
31
+ STDERR.puts "Solargraph is listening PORT=#{port} PID=#{Process.pid}"
32
+ end
33
+ end
34
+
35
+ desc 'stdio', 'Run a Solargraph stdio server'
36
+ def stdio
37
+ require 'backport'
38
+ Backport.run do
39
+ Signal.trap("INT") do
40
+ Backport.stop
41
+ end
42
+ Signal.trap("TERM") do
43
+ Backport.stop
44
+ end
45
+ Backport.prepare_stdio_server adapter: Solargraph::LanguageServer::Transport::Adapter
46
+ STDERR.puts "Solargraph is listening on stdio PID=#{Process.pid}"
47
+ end
48
+ end
49
+
50
+ desc 'config [DIRECTORY]', 'Create or overwrite a default configuration file'
51
+ option :extensions, type: :boolean, aliases: :e, desc: 'Add installed extensions', default: true
52
+ def config(directory = '.')
53
+ matches = []
54
+ if options[:extensions]
55
+ Gem::Specification.each do |g|
56
+ if g.name.match(/^solargraph\-[A-Za-z0-9_\-]*?\-ext/)
57
+ require g.name
58
+ matches.push g.name
59
+ end
60
+ end
61
+ end
62
+ conf = Solargraph::Workspace::Config.new.raw_data
63
+ unless matches.empty?
64
+ matches.each do |m|
65
+ conf['extensions'].push m
66
+ end
67
+ end
68
+ File.open(File.join(directory, '.solargraph.yml'), 'w') do |file|
69
+ file.puts conf.to_yaml
70
+ end
71
+ STDOUT.puts "Configuration file initialized."
72
+ end
73
+
74
+ desc 'download-core [VERSION]', 'Download core documentation'
75
+ def download_core version = nil
76
+ ver = version || Solargraph::YardMap::CoreDocs.best_download
77
+ puts "Downloading docs for #{ver}..."
78
+ Solargraph::YardMap::CoreDocs.download ver
79
+ # Clear cached documentation if it exists
80
+ FileUtils.rm_rf Dir.glob(File.join(Solargraph::YardMap::CoreDocs.cache_dir, ver, '*.ser'))
81
+ rescue ArgumentError => e
82
+ STDERR.puts "ERROR: #{e.message}"
83
+ STDERR.puts "Run `solargraph available-cores` for a list."
84
+ exit 1
85
+ end
86
+
87
+ desc 'list-cores', 'List the local documentation versions'
88
+ def list_cores
89
+ puts Solargraph::YardMap::CoreDocs.versions.join("\n")
90
+ end
91
+
92
+ desc 'available-cores', 'List available documentation versions'
93
+ def available_cores
94
+ puts Solargraph::YardMap::CoreDocs.available.join("\n")
95
+ end
96
+
97
+ desc 'clear', 'Delete all cached documentation'
98
+ long_desc %(
99
+ This command will delete all core and gem documentation from the cache.
100
+ You can also delete specific gem caches with the `uncache` command or
101
+ update documentation for specific Ruby versions with the `download-core`
102
+ command.
103
+ )
104
+ def clear
105
+ puts "Deleting the cached documentation"
106
+ Solargraph::YardMap::CoreDocs.clear
107
+ end
108
+ map 'clear-cache' => :clear
109
+ map 'clear-cores' => :clear
110
+
111
+ desc 'uncache GEM [...GEM]', "Delete cached gem documentation"
112
+ def uncache *gems
113
+ raise ArgumentError, 'No gems specified.' if gems.empty?
114
+ gems.each do |gem|
115
+ Dir[File.join(Solargraph::YardMap::CoreDocs.cache_dir, 'gems', "#{gem}-*")].each do |dir|
116
+ puts "Deleting cache: #{dir}"
117
+ FileUtils.remove_entry_secure dir
118
+ end
119
+ end
120
+ end
121
+
122
+ desc 'reporters', 'Get a list of diagnostics reporters'
123
+ def reporters
124
+ puts Solargraph::Diagnostics.reporters
125
+ end
126
+
127
+ desc 'typecheck [FILE(s)]', 'Run the type checker'
128
+ long_desc %(
129
+ Perform type checking on one or more files in a workspace. Check the
130
+ entire workspace if no files are specified.
131
+
132
+ Type checking levels are normal, typed, strict, and strong.
133
+ )
134
+ option :level, type: :string, aliases: [:mode, :m, :l], desc: 'Type checking level', default: 'normal'
135
+ option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
136
+ def typecheck *files
137
+ directory = File.realpath(options[:directory])
138
+ api_map = Solargraph::ApiMap.load(directory)
139
+ if files.empty?
140
+ files = api_map.source_maps.map(&:filename)
141
+ else
142
+ files.map! { |file| File.realpath(file) }
143
+ end
144
+ probcount = 0
145
+ filecount = 0
146
+ files.each do |file|
147
+ checker = TypeChecker.new(file, api_map: api_map, level: options[:level].to_sym)
148
+ problems = checker.problems
149
+ next if problems.empty?
150
+ problems.sort! { |a, b| a.location.range.start.line <=> b.location.range.start.line }
151
+ puts problems.map { |prob| "#{prob.location.filename}:#{prob.location.range.start.line + 1} - #{prob.message}" }.join("\n")
152
+ filecount += 1
153
+ probcount += problems.length
154
+ end
155
+ puts "#{probcount} problem#{probcount != 1 ? 's' : ''} found#{files.length != 1 ? " in #{filecount} of #{files.length} files" : ''}."
156
+ exit 1 if probcount > 0
157
+ end
158
+
159
+ desc 'scan', 'Test the workspace for problems'
160
+ long_desc %(
161
+ A scan loads the entire workspace to make sure that the ASTs and
162
+ maps do not raise errors during analysis. It does not perform any type
163
+ checking or validation; it only confirms that the analysis itself is
164
+ error-free.
165
+ )
166
+ option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
167
+ option :verbose, type: :boolean, aliases: :v, desc: 'Verbose output', default: false
168
+ def scan
169
+ require 'benchmark'
170
+ directory = File.realpath(options[:directory])
171
+ api_map = nil
172
+ time = Benchmark.measure {
173
+ api_map = Solargraph::ApiMap.load(directory)
174
+ api_map.pins.each do |pin|
175
+ begin
176
+ puts pin_description(pin) if options[:verbose]
177
+ pin.typify api_map
178
+ pin.probe api_map
179
+ rescue StandardError => e
180
+ STDERR.puts "Error testing #{pin_description(pin)} #{pin.location ? "at #{pin.location.filename}:#{pin.location.range.start.line + 1}" : ''}"
181
+ STDERR.puts "[#{e.class}]: #{e.message}"
182
+ STDERR.puts e.backtrace.join("\n")
183
+ exit 1
184
+ end
185
+ end
186
+ }
187
+ puts "Scanned #{directory} (#{api_map.pins.length} pins) in #{time.real} seconds."
188
+ end
189
+
190
+ desc 'bundle', 'Generate documentation for bundled gems'
191
+ option :directory, type: :string, aliases: :d, desc: 'The workspace directory', default: '.'
192
+ option :rebuild, type: :boolean, aliases: :r, desc: 'Rebuild existing documentation', default: false
193
+ def bundle
194
+ Documentor.new(options[:directory], rebuild: options[:rebuild], out: STDOUT).document
195
+ end
196
+
197
+ desc 'rdoc GEM [VERSION]', 'Use RDoc to cache documentation'
198
+ def rdoc gem, version = '>= 0'
199
+ spec = Gem::Specification.find_by_name(gem, version)
200
+ puts "Caching #{spec.name} #{spec.version} from RDoc"
201
+ Solargraph::YardMap::RdocToYard.run(spec)
202
+ end
203
+
204
+ private
205
+
206
+ # @param pin [Solargraph::Pin::Base]
207
+ # @return [String]
208
+ def pin_description pin
209
+ desc = if pin.path.nil? || pin.path.empty?
210
+ if pin.closure
211
+ "#{pin.closure.path} | #{pin.name}"
212
+ else
213
+ "#{pin.context.namespace} | #{pin.name}"
214
+ end
215
+ else
216
+ pin.path
217
+ end
218
+ desc += " (#{pin.location.filename} #{pin.location.range.start.line})" if pin.location
219
+ desc
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,537 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yard'
4
+
5
+ module Solargraph
6
+ # A Ruby file that has been parsed into an AST.
7
+ #
8
+ class Source
9
+ # autoload :FlawedBuilder, 'solargraph/source/flawed_builder'
10
+ autoload :Updater, 'solargraph/source/updater'
11
+ autoload :Change, 'solargraph/source/change'
12
+ autoload :Mapper, 'solargraph/source/mapper'
13
+ # autoload :NodeMethods, 'solargraph/source/node_methods'
14
+ autoload :EncodingFixes, 'solargraph/source/encoding_fixes'
15
+ autoload :Cursor, 'solargraph/source/cursor'
16
+ autoload :Chain, 'solargraph/source/chain'
17
+ autoload :SourceChainer, 'solargraph/source/source_chainer'
18
+ # autoload :NodeChainer, 'solargraph/source/node_chainer'
19
+
20
+ include EncodingFixes
21
+ # include NodeMethods
22
+
23
+ # @return [String]
24
+ attr_reader :filename
25
+
26
+ # @return [String]
27
+ attr_reader :code
28
+
29
+ # @return [Parser::AST::Node]
30
+ attr_reader :node
31
+
32
+ # @return [Hash{Integer => Array<String>}]
33
+ attr_reader :comments
34
+
35
+ # @todo Deprecate?
36
+ # @return [Integer]
37
+ attr_reader :version
38
+
39
+ # @param code [String]
40
+ # @param filename [String]
41
+ # @param version [Integer]
42
+ def initialize code, filename = nil, version = 0
43
+ @code = normalize(code)
44
+ @repaired = code
45
+ @filename = filename
46
+ @version = version
47
+ @domains = []
48
+ begin
49
+ # @node, @comments = Source.parse_with_comments(@code, filename)
50
+ @node, @comments = Solargraph::Parser.parse_with_comments(@code, filename)
51
+ @parsed = true
52
+ rescue Parser::SyntaxError, EncodingError => e
53
+ # @todo 100% whitespace results in a nil node, so there's no reason to parse it.
54
+ # We still need to determine whether the resulting node should be nil or a dummy
55
+ # node with a location that encompasses the range.
56
+ # @node, @comments = Source.parse_with_comments(@code.gsub(/[^\s]/, ' '), filename)
57
+ @node = nil
58
+ @comments = {}
59
+ @parsed = false
60
+ # rescue Exception => e
61
+ # Solargraph.logger.warn "[#{e.class}] #{e.message}"
62
+ # Solargraph.logger.warn e.backtrace.join("\n")
63
+ # raise "Error parsing #{filename || '(source)'}: [#{e.class}] #{e.message}"
64
+ ensure
65
+ @code.freeze
66
+ end
67
+ end
68
+
69
+ # @param range [Solargraph::Range]
70
+ # @return [String]
71
+ def at range
72
+ from_to range.start.line, range.start.character, range.ending.line, range.ending.character
73
+ end
74
+
75
+ # @param l1 [Integer]
76
+ # @param c1 [Integer]
77
+ # @param l2 [Integer]
78
+ # @param c2 [Integer]
79
+ # @return [String]
80
+ def from_to l1, c1, l2, c2
81
+ b = Solargraph::Position.line_char_to_offset(@code, l1, c1)
82
+ e = Solargraph::Position.line_char_to_offset(@code, l2, c2)
83
+ @code[b..e-1]
84
+ end
85
+
86
+ # Get the nearest node that contains the specified index.
87
+ #
88
+ # @param line [Integer]
89
+ # @param column [Integer]
90
+ # @return [AST::Node]
91
+ def node_at(line, column)
92
+ tree_at(line, column).first
93
+ end
94
+
95
+ # Get an array of nodes containing the specified index, starting with the
96
+ # nearest node and ending with the root.
97
+ #
98
+ # @param line [Integer]
99
+ # @param column [Integer]
100
+ # @return [Array<AST::Node>]
101
+ def tree_at(line, column)
102
+ # offset = Position.line_char_to_offset(@code, line, column)
103
+ position = Position.new(line, column)
104
+ stack = []
105
+ inner_tree_at @node, position, stack
106
+ stack
107
+ end
108
+
109
+ # Start synchronizing the source. This method updates the code without
110
+ # parsing a new AST. The resulting Source object will be marked not
111
+ # synchronized (#synchronized? == false).
112
+ #
113
+ # @param updater [Source::Updater]
114
+ # @return [Source]
115
+ def start_synchronize updater
116
+ raise 'Invalid synchronization' unless updater.filename == filename
117
+ real_code = updater.write(@code)
118
+ src = Source.allocate
119
+ src.filename = filename
120
+ src.code = real_code
121
+ src.version = updater.version
122
+ src.parsed = parsed?
123
+ src.repaired = updater.repair(@repaired)
124
+ src.synchronized = false
125
+ src.node = @node
126
+ src.comments = @comments
127
+ src.error_ranges = error_ranges
128
+ src.last_updater = updater
129
+ return src.finish_synchronize unless real_code.lines.length == @code.lines.length
130
+ src
131
+ end
132
+
133
+ # Finish synchronizing a source that was updated via #start_synchronize.
134
+ # This method returns self if the source is already synchronized. Otherwise
135
+ # it parses the AST and returns a new synchronized Source.
136
+ #
137
+ # @return [Source]
138
+ def finish_synchronize
139
+ return self if synchronized?
140
+ synced = Source.new(@code, filename)
141
+ if synced.parsed?
142
+ synced.version = version
143
+ return synced
144
+ end
145
+ synced = Source.new(@repaired, filename)
146
+ synced.error_ranges.concat (error_ranges + last_updater.changes.map(&:range))
147
+ synced.code = @code
148
+ synced.synchronized = true
149
+ synced.version = version
150
+ synced
151
+ end
152
+
153
+ # Synchronize the Source with an update. This method applies changes to the
154
+ # code, parses the new code's AST, and returns the resulting Source object.
155
+ #
156
+ # @param updater [Source::Updater]
157
+ # @return [Source]
158
+ def synchronize updater
159
+ raise 'Invalid synchronization' unless updater.filename == filename
160
+ real_code = updater.write(@code)
161
+ if real_code == @code
162
+ @version = updater.version
163
+ return self
164
+ end
165
+ synced = Source.new(real_code, filename)
166
+ if synced.parsed?
167
+ synced.version = updater.version
168
+ return synced
169
+ end
170
+ incr_code = updater.repair(@repaired)
171
+ synced = Source.new(incr_code, filename)
172
+ synced.error_ranges.concat (error_ranges + updater.changes.map(&:range))
173
+ synced.code = real_code
174
+ synced.version = updater.version
175
+ synced
176
+ end
177
+
178
+ # @param position [Position, Array(Integer, Integer)]
179
+ # @return [Source::Cursor]
180
+ def cursor_at position
181
+ Cursor.new(self, position)
182
+ end
183
+
184
+ # @return [Boolean]
185
+ def parsed?
186
+ @parsed
187
+ end
188
+
189
+ def repaired?
190
+ @is_repaired ||= (@code != @repaired)
191
+ end
192
+
193
+ # @param position [Position]
194
+ # @return [Boolean]
195
+ def string_at? position
196
+ if Parser.rubyvm?
197
+ string_ranges.each do |range|
198
+ if synchronized?
199
+ return true if range.include?(position) || range.ending == position
200
+ else
201
+ return true if last_updater && last_updater.changes.one? && range.contain?(last_updater.changes.first.range.start)
202
+ end
203
+ end
204
+ false
205
+ else
206
+ return false if Position.to_offset(code, position) >= code.length
207
+ string_nodes.each do |node|
208
+ range = Range.from_node(node)
209
+ next if range.ending.line < position.line
210
+ break if range.ending.line > position.line
211
+ return true if node.type == :str && range.include?(position) && range.start != position
212
+ return true if [:STR, :str].include?(node.type) && range.include?(position) && range.start != position
213
+ if node.type == :dstr
214
+ inner = node_at(position.line, position.column)
215
+ next if inner.nil?
216
+ inner_range = Range.from_node(inner)
217
+ next unless range.include?(inner_range.ending)
218
+ return true if inner.type == :str
219
+ inner_code = at(Solargraph::Range.new(inner_range.start, position))
220
+ return true if (inner.type == :dstr && inner_range.ending.character <= position.character) && !inner_code.end_with?('}') ||
221
+ (inner.type != :dstr && inner_range.ending.line == position.line && position.character <= inner_range.ending.character && inner_code.end_with?('}'))
222
+ end
223
+ break if range.ending.line > position.line
224
+ end
225
+ false
226
+ end
227
+ end
228
+
229
+ def string_ranges
230
+ @string_ranges ||= Parser.string_ranges(node)
231
+ end
232
+
233
+ # @param position [Position]
234
+ # @return [Boolean]
235
+ def comment_at? position
236
+ comment_ranges.each do |range|
237
+ return true if range.include?(position) ||
238
+ (range.ending.line == position.line && range.ending.column < position.column)
239
+ break if range.ending.line > position.line
240
+ end
241
+ false
242
+ end
243
+
244
+ # @param name [String]
245
+ # @return [Array<Location>]
246
+ def references name
247
+ Parser.references self, name
248
+ end
249
+
250
+ # @return [Array<Range>]
251
+ def error_ranges
252
+ @error_ranges ||= []
253
+ end
254
+
255
+ # @param node [Parser::AST::Node]
256
+ # @return [String]
257
+ def code_for(node)
258
+ rng = Range.from_node(node)
259
+ b = Position.line_char_to_offset(@code, rng.start.line, rng.start.column)
260
+ e = Position.line_char_to_offset(@code, rng.ending.line, rng.ending.column)
261
+ frag = code[b..e-1].to_s
262
+ frag.strip.gsub(/,$/, '')
263
+ end
264
+
265
+ # @param node [Parser::AST::Node]
266
+ # @return [String]
267
+ def comments_for node
268
+ rng = Range.from_node(node)
269
+ stringified_comments[rng.start.line] ||= begin
270
+ buff = associated_comments[rng.start.line]
271
+ buff ? stringify_comment_array(buff) : nil
272
+ end
273
+ end
274
+
275
+ # A location representing the file in its entirety.
276
+ #
277
+ # @return [Location]
278
+ def location
279
+ st = Position.new(0, 0)
280
+ en = Position.from_offset(code, code.length)
281
+ range = Range.new(st, en)
282
+ Location.new(filename, range)
283
+ end
284
+
285
+ FOLDING_NODE_TYPES = if Parser.rubyvm?
286
+ %i[
287
+ CLASS SCLASS MODULE DEFN DEFS IF WHILE UNLESS ITER STR HASH ARRAY LIST
288
+ ].freeze
289
+ else
290
+ %i[
291
+ class sclass module def defs if str dstr array while unless kwbegin hash block
292
+ ].freeze
293
+ end
294
+
295
+ # Get an array of ranges that can be folded, e.g., the range of a class
296
+ # definition or an if condition.
297
+ #
298
+ # See FOLDING_NODE_TYPES for the list of node types that can be folded.
299
+ #
300
+ # @return [Array<Range>]
301
+ def folding_ranges
302
+ @folding_ranges ||= begin
303
+ result = []
304
+ inner_folding_ranges node, result
305
+ result.concat foldable_comment_block_ranges
306
+ result
307
+ end
308
+ end
309
+
310
+ def synchronized?
311
+ @synchronized = true if @synchronized.nil?
312
+ @synchronized
313
+ end
314
+
315
+ # Get a hash of comments grouped by the line numbers of the associated code.
316
+ #
317
+ # @return [Hash{Integer => Array<Parser::Source::Comment>}]
318
+ def associated_comments
319
+ @associated_comments ||= begin
320
+ result = {}
321
+ buffer = String.new('')
322
+ last = nil
323
+ @comments.each_pair do |num, snip|
324
+ if !last || num == last + 1
325
+ buffer.concat "#{snip.text}\n"
326
+ else
327
+ result[first_not_empty_from(last + 1)] = buffer.clone
328
+ buffer.replace "#{snip.text}\n"
329
+ end
330
+ last = num
331
+ end
332
+ result[first_not_empty_from(last + 1)] = buffer unless buffer.empty? || last.nil?
333
+ result
334
+ end
335
+ end
336
+
337
+ private
338
+
339
+ def first_not_empty_from line
340
+ cursor = line
341
+ cursor += 1 while cursor < code_lines.length && code_lines[cursor].strip.empty?
342
+ cursor = line if cursor > code_lines.length - 1
343
+ cursor
344
+ end
345
+
346
+ # @param top [Parser::AST::Node]
347
+ # @param result [Array<Range>]
348
+ # @param parent [Symbol]
349
+ # @return [void]
350
+ def inner_folding_ranges top, result = [], parent = nil
351
+ # return unless top.is_a?(::Parser::AST::Node)
352
+ return unless Parser.is_ast_node?(top)
353
+ if FOLDING_NODE_TYPES.include?(top.type)
354
+ # @todo Smelly exception for hash's first-level array in RubyVM
355
+ unless [:ARRAY, :LIST].include?(top.type) && parent == :HASH
356
+ range = Range.from_node(top)
357
+ if result.empty? || range.start.line > result.last.start.line
358
+ result.push range unless range.ending.line - range.start.line < 2
359
+ end
360
+ end
361
+ end
362
+ top.children.each do |child|
363
+ inner_folding_ranges(child, result, top.type)
364
+ end
365
+ end
366
+
367
+ # Get a string representation of an array of comments.
368
+ #
369
+ # @param comments [String]
370
+ # @return [String]
371
+ def stringify_comment_array comments
372
+ ctxt = String.new('')
373
+ started = false
374
+ skip = nil
375
+ comments.lines.each { |l|
376
+ # Trim the comment and minimum leading whitespace
377
+ p = l.gsub(/^#+/, '')
378
+ if p.strip.empty?
379
+ next unless started
380
+ ctxt.concat p
381
+ else
382
+ here = p.index(/[^ \t]/)
383
+ skip = here if skip.nil? || here < skip
384
+ ctxt.concat p[skip..-1]
385
+ end
386
+ started = true
387
+ }
388
+ ctxt
389
+ end
390
+
391
+ # A hash of line numbers and their associated comments.
392
+ #
393
+ # @return [Hash{Integer => Array<String>}]
394
+ def stringified_comments
395
+ @stringified_comments ||= {}
396
+ end
397
+
398
+ # @return [Array<Parser::AST::Node>]
399
+ def string_nodes
400
+ @string_nodes ||= string_nodes_in(@node)
401
+ end
402
+
403
+ # @return [Array<Range>]
404
+ def comment_ranges
405
+ @comment_ranges ||= @comments.values.map(&:range)
406
+ end
407
+
408
+ # Get an array of foldable comment block ranges. Blocks are excluded if
409
+ # they are less than 3 lines long.
410
+ #
411
+ # @return [Array<Range>]
412
+ def foldable_comment_block_ranges
413
+ return [] unless synchronized?
414
+ result = []
415
+ grouped = []
416
+ comments.keys.each do |l|
417
+ if grouped.empty? || l == grouped.last + 1
418
+ grouped.push l
419
+ else
420
+ result.push Range.from_to(grouped.first, 0, grouped.last, 0) unless grouped.length < 3
421
+ grouped = [l]
422
+ end
423
+ end
424
+ result.push Range.from_to(grouped.first, 0, grouped.last, 0) unless grouped.length < 3
425
+ result
426
+ end
427
+
428
+ # @param n [Parser::AST::Node]
429
+ # @return [Array<Parser::AST::Node>]
430
+ def string_nodes_in n
431
+ result = []
432
+ if Parser.is_ast_node?(n)
433
+ if n.type == :str || n.type == :dstr || n.type == :STR || n.type == :DSTR
434
+ result.push n
435
+ else
436
+ n.children.each{ |c| result.concat string_nodes_in(c) }
437
+ end
438
+ end
439
+ result
440
+ end
441
+
442
+ # @param node [Parser::AST::Node]
443
+ # @param position [Position]
444
+ # @param stack [Array<Parser::AST::Node>]
445
+ # @return [void]
446
+ def inner_tree_at node, position, stack
447
+ return if node.nil?
448
+ # here = Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
449
+ here = Range.from_node(node)
450
+ if here.contain?(position) || colonized(here, position, node)
451
+ stack.unshift node
452
+ node.children.each do |c|
453
+ next unless Parser.is_ast_node?(c)
454
+ next if !Parser.rubyvm? && c.loc.expression.nil?
455
+ inner_tree_at(c, position, stack)
456
+ end
457
+ end
458
+ end
459
+
460
+ def colonized range, position, node
461
+ node.type == :COLON2 &&
462
+ range.ending.line == position.line &&
463
+ range.ending.character == position.character - 2 &&
464
+ code[Position.to_offset(code, Position.new(position.line, position.character - 2)), 2] == '::'
465
+ end
466
+
467
+ protected
468
+
469
+ # @return [String]
470
+ attr_writer :filename
471
+
472
+ # @return [Integer]
473
+ attr_writer :version
474
+
475
+ # @param val [String]
476
+ # @return [String]
477
+ def code=(val)
478
+ @code_lines= nil
479
+ @code = val
480
+ end
481
+
482
+ # @return [Parser::AST::Node]
483
+ attr_writer :node
484
+
485
+ # @return [Array<Range>]
486
+ attr_writer :error_ranges
487
+
488
+ # @return [String]
489
+ attr_accessor :repaired
490
+
491
+ # @return [Boolean]
492
+ attr_writer :parsed
493
+
494
+ # @return [Array<Parser::Source::Comment>]
495
+ attr_writer :comments
496
+
497
+ # @return [Boolean]
498
+ attr_writer :synchronized
499
+
500
+ # @return [Source::Updater]
501
+ attr_accessor :last_updater
502
+
503
+ private
504
+
505
+ # @return [Array<String>]
506
+ def code_lines
507
+ @code_lines ||= code.lines
508
+ end
509
+
510
+ class << self
511
+ # @param filename [String]
512
+ # @return [Solargraph::Source]
513
+ def load filename
514
+ file = File.open(filename)
515
+ code = file.read
516
+ file.close
517
+ Source.load_string(code, filename)
518
+ end
519
+
520
+ # @param code [String]
521
+ # @param filename [String]
522
+ # @param version [Integer]
523
+ # @return [Solargraph::Source]
524
+ def load_string code, filename = nil, version = 0
525
+ Source.new code, filename, version
526
+ end
527
+
528
+ # @param comments [String]
529
+ # @return [YARD::DocstringParser]
530
+ def parse_docstring comments
531
+ # HACK: Pass a dummy code object to the parser for plugins that
532
+ # expect it not to be nil
533
+ YARD::Docstring.parser.parse(comments, YARD::CodeObjects::Base.new(:root, 'stub'))
534
+ end
535
+ end
536
+ end
537
+ end