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,533 @@
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]
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
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
+ # @return [void]
349
+ def inner_folding_ranges top, result = []
350
+ # return unless top.is_a?(::Parser::AST::Node)
351
+ return unless Parser.is_ast_node?(top)
352
+ if FOLDING_NODE_TYPES.include?(top.type)
353
+ range = Range.from_node(top)
354
+ if result.empty? || range.start.line > result.last.start.line
355
+ result.push range unless range.ending.line - range.start.line < 2
356
+ end
357
+ end
358
+ top.children.each do |child|
359
+ inner_folding_ranges(child, result)
360
+ end
361
+ end
362
+
363
+ # Get a string representation of an array of comments.
364
+ #
365
+ # @param comments [String]
366
+ # @return [String]
367
+ def stringify_comment_array comments
368
+ ctxt = String.new('')
369
+ started = false
370
+ skip = nil
371
+ comments.lines.each { |l|
372
+ # Trim the comment and minimum leading whitespace
373
+ p = l.gsub(/^#+/, '')
374
+ if p.strip.empty?
375
+ next unless started
376
+ ctxt.concat p
377
+ else
378
+ here = p.index(/[^ \t]/)
379
+ skip = here if skip.nil? || here < skip
380
+ ctxt.concat p[skip..-1]
381
+ end
382
+ started = true
383
+ }
384
+ ctxt
385
+ end
386
+
387
+ # A hash of line numbers and their associated comments.
388
+ #
389
+ # @return [Hash{Integer => Array<String>}]
390
+ def stringified_comments
391
+ @stringified_comments ||= {}
392
+ end
393
+
394
+ # @return [Array<Parser::AST::Node>]
395
+ def string_nodes
396
+ @string_nodes ||= string_nodes_in(@node)
397
+ end
398
+
399
+ # @return [Array<Range>]
400
+ def comment_ranges
401
+ @comment_ranges ||= @comments.values.map(&:range)
402
+ end
403
+
404
+ # Get an array of foldable comment block ranges. Blocks are excluded if
405
+ # they are less than 3 lines long.
406
+ #
407
+ # @return [Array<Range>]
408
+ def foldable_comment_block_ranges
409
+ return [] unless synchronized?
410
+ result = []
411
+ grouped = []
412
+ comments.keys.each do |l|
413
+ if grouped.empty? || l == grouped.last + 1
414
+ grouped.push l
415
+ else
416
+ result.push Range.from_to(grouped.first, 0, grouped.last, 0) unless grouped.length < 3
417
+ grouped = [l]
418
+ end
419
+ end
420
+ result.push Range.from_to(grouped.first, 0, grouped.last, 0) unless grouped.length < 3
421
+ result
422
+ end
423
+
424
+ # @param n [Parser::AST::Node]
425
+ # @return [Array<Parser::AST::Node>]
426
+ def string_nodes_in n
427
+ result = []
428
+ if Parser.is_ast_node?(n)
429
+ if n.type == :str || n.type == :dstr || n.type == :STR || n.type == :DSTR
430
+ result.push n
431
+ else
432
+ n.children.each{ |c| result.concat string_nodes_in(c) }
433
+ end
434
+ end
435
+ result
436
+ end
437
+
438
+ # @param node [Parser::AST::Node]
439
+ # @param position [Position]
440
+ # @param stack [Array<Parser::AST::Node>]
441
+ # @return [void]
442
+ def inner_tree_at node, position, stack
443
+ return if node.nil?
444
+ # here = Range.from_to(node.loc.expression.line, node.loc.expression.column, node.loc.expression.last_line, node.loc.expression.last_column)
445
+ here = Range.from_node(node)
446
+ if here.contain?(position) || colonized(here, position, node)
447
+ stack.unshift node
448
+ node.children.each do |c|
449
+ next unless Parser.is_ast_node?(c)
450
+ next if !Parser.rubyvm? && c.loc.expression.nil?
451
+ inner_tree_at(c, position, stack)
452
+ end
453
+ end
454
+ end
455
+
456
+ def colonized range, position, node
457
+ node.type == :COLON2 &&
458
+ range.ending.line == position.line &&
459
+ range.ending.character == position.character - 2 &&
460
+ code[Position.to_offset(code, Position.new(position.line, position.character - 2)), 2] == '::'
461
+ end
462
+
463
+ protected
464
+
465
+ # @return [String]
466
+ attr_writer :filename
467
+
468
+ # @return [Integer]
469
+ attr_writer :version
470
+
471
+ # @param val [String]
472
+ # @return [String]
473
+ def code=(val)
474
+ @code_lines= nil
475
+ @code = val
476
+ end
477
+
478
+ # @return [Parser::AST::Node]
479
+ attr_writer :node
480
+
481
+ # @return [Array<Range>]
482
+ attr_writer :error_ranges
483
+
484
+ # @return [String]
485
+ attr_accessor :repaired
486
+
487
+ # @return [Boolean]
488
+ attr_writer :parsed
489
+
490
+ # @return [Array<Parser::Source::Comment>]
491
+ attr_writer :comments
492
+
493
+ # @return [Boolean]
494
+ attr_writer :synchronized
495
+
496
+ # @return [Source::Updater]
497
+ attr_accessor :last_updater
498
+
499
+ private
500
+
501
+ # @return [Array<String>]
502
+ def code_lines
503
+ @code_lines ||= code.lines
504
+ end
505
+
506
+ class << self
507
+ # @param filename [String]
508
+ # @return [Solargraph::Source]
509
+ def load filename
510
+ file = File.open(filename)
511
+ code = file.read
512
+ file.close
513
+ Source.load_string(code, filename)
514
+ end
515
+
516
+ # @param code [String]
517
+ # @param filename [String]
518
+ # @param version [Integer]
519
+ # @return [Solargraph::Source]
520
+ def load_string code, filename = nil, version = 0
521
+ Source.new code, filename, version
522
+ end
523
+
524
+ # @param comments [String]
525
+ # @return [YARD::DocstringParser]
526
+ def parse_docstring comments
527
+ # HACK: Pass a dummy code object to the parser for plugins that
528
+ # expect it not to be nil
529
+ YARD::Docstring.parser.parse(comments, YARD::CodeObjects::Base.new(:root, 'stub'))
530
+ end
531
+ end
532
+ end
533
+ end