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,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ # The SymbolKind constants for the language server protocol.
6
+ #
7
+ module SymbolKinds
8
+ FILE = 1
9
+ MODULE = 2
10
+ NAMESPACE = 3
11
+ PACKAGE = 4
12
+ CLASS = 5
13
+ METHOD = 6
14
+ PROPERTY = 7
15
+ FIELD = 8
16
+ CONSTRUCTOR = 9
17
+ ENUM = 10
18
+ INTERFACE = 11
19
+ FUNCTION = 12
20
+ VARIABLE = 13
21
+ CONSTANT = 14
22
+ STRING = 15
23
+ NUMBER = 16
24
+ BOOLEAN = 17
25
+ ARRAY = 18
26
+ OBJECT = 19
27
+ KEY = 20
28
+ NULL = 21
29
+ ENUM_MEMBER = 22
30
+ STRUCT = 23
31
+ EVENT = 24
32
+ OPERATOR = 25
33
+ TYPE_PARAMETER = 26
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ # The Transport namespace contains concrete implementations of
6
+ # communication protocols for language servers.
7
+ #
8
+ module Transport
9
+ autoload :Adapter, 'solargraph/language_server/transport/adapter'
10
+ autoload :DataReader, 'solargraph/language_server/transport/data_reader'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'backport'
4
+
5
+ module Solargraph
6
+ module LanguageServer
7
+ module Transport
8
+ # A common module for running language servers in Backport.
9
+ #
10
+ module Adapter
11
+ def opening
12
+ @host = Solargraph::LanguageServer::Host.new
13
+ @host.add_observer self
14
+ @host.start
15
+ @data_reader = Solargraph::LanguageServer::Transport::DataReader.new
16
+ @data_reader.set_message_handler do |message|
17
+ process message
18
+ end
19
+ end
20
+
21
+ def closing
22
+ @host.stop
23
+ end
24
+
25
+ # @param data [String]
26
+ def receiving data
27
+ @data_reader.receive data
28
+ end
29
+
30
+ def update
31
+ if @host.stopped?
32
+ shutdown
33
+ else
34
+ tmp = @host.flush
35
+ write tmp unless tmp.empty?
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # @param request [String]
42
+ # @return [void]
43
+ def process request
44
+ message = @host.receive(request)
45
+ message.send_response
46
+ # tmp = @host.flush
47
+ # write tmp unless tmp.empty?
48
+ end
49
+
50
+ def shutdown
51
+ Backport.stop unless @host.options['transport'] == 'external'
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Solargraph
6
+ module LanguageServer
7
+ module Transport
8
+ class DataReader
9
+ def initialize
10
+ @in_header = true
11
+ @content_length = 0
12
+ @buffer = String.new
13
+ end
14
+
15
+ # Declare a block to be executed for each message received from the
16
+ # client.
17
+ #
18
+ # @yieldparam [Hash] The message received from the client
19
+ def set_message_handler &block
20
+ @message_handler = block
21
+ end
22
+
23
+ # Process raw data received from the client. The data will be parsed
24
+ # into messages based on the JSON-RPC protocol. Each message will be
25
+ # passed to the block declared via set_message_handler. Incomplete data
26
+ # will be buffered and subsequent data will be appended to the buffer.
27
+ #
28
+ # @param data [String]
29
+ def receive data
30
+ data.each_char do |char|
31
+ @buffer.concat char
32
+ if @in_header
33
+ prepare_to_parse_message if @buffer.end_with?("\r\n\r\n")
34
+ else
35
+ parse_message_from_buffer if @buffer.bytesize == @content_length
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ # @return [void]
43
+ def prepare_to_parse_message
44
+ @in_header = false
45
+ @buffer.each_line do |line|
46
+ parts = line.split(':').map(&:strip)
47
+ if parts[0] == 'Content-Length'
48
+ @content_length = parts[1].to_i
49
+ break
50
+ end
51
+ end
52
+ @buffer.clear
53
+ end
54
+
55
+ # @return [void]
56
+ def parse_message_from_buffer
57
+ begin
58
+ msg = JSON.parse(@buffer)
59
+ @message_handler.call msg unless @message_handler.nil?
60
+ rescue JSON::ParserError => e
61
+ Solargraph::Logging.logger.warn "Failed to parse request: #{e.message}"
62
+ Solargraph::Logging.logger.debug "Buffer: #{@buffer}"
63
+ ensure
64
+ @buffer.clear
65
+ @in_header = true
66
+ @content_length = 0
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+
5
+ module Solargraph
6
+ module LanguageServer
7
+ # Methods to handle conversions between file URIs and paths.
8
+ #
9
+ module UriHelpers
10
+ module_function
11
+
12
+ # Convert a file URI to a path.
13
+ #
14
+ # @param uri [String]
15
+ # @return [String]
16
+ def uri_to_file uri
17
+ decode(uri).sub(/^file\:\/\//, '').sub(/^\/([a-z]\:)/i, '\1')
18
+ end
19
+
20
+ # Convert a file path to a URI.
21
+ #
22
+ # @param file [String]
23
+ # @return [String]
24
+ def file_to_uri file
25
+ "file://#{encode(file.gsub(/^([a-z]\:)/i, '/\1'))}"
26
+ end
27
+
28
+ # Encode text to be used as a URI path component in LSP.
29
+ #
30
+ # @param text [String]
31
+ # @return [String]
32
+ def encode text
33
+ CGI.escape(text)
34
+ .gsub('%3A', ':')
35
+ .gsub('%5C', '\\')
36
+ .gsub('%2F', '/')
37
+ .gsub('+', '%20')
38
+ end
39
+
40
+ # Decode text from a URI path component in LSP.
41
+ #
42
+ # @param text [String]
43
+ # @return [String]
44
+ def decode text
45
+ CGI.unescape(text)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,414 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ # A Library handles coordination between a Workspace and an ApiMap.
5
+ #
6
+ class Library
7
+ include Logging
8
+
9
+ # @return [Solargraph::Workspace]
10
+ attr_reader :workspace
11
+
12
+ # @return [String, nil]
13
+ attr_reader :name
14
+
15
+ # @return [Source, nil]
16
+ attr_reader :current
17
+
18
+ # @param workspace [Solargraph::Workspace]
19
+ # @param name [String, nil]
20
+ def initialize workspace = Solargraph::Workspace.new, name = nil
21
+ @workspace = workspace
22
+ @name = name
23
+ api_map.catalog bundle
24
+ @synchronized = true
25
+ @catalog_mutex = Mutex.new
26
+ end
27
+
28
+ def inspect
29
+ # Let's not deal with insane data dumps in spec failures
30
+ to_s
31
+ end
32
+
33
+ # True if the ApiMap is up to date with the library's workspace and open
34
+ # files.
35
+ #
36
+ # @return [Boolean]
37
+ def synchronized?
38
+ @synchronized
39
+ end
40
+
41
+ # Attach a source to the library.
42
+ #
43
+ # The attached source does not need to be a part of the workspace. The
44
+ # library will include it in the ApiMap while it's attached. Only one
45
+ # source can be attached to the library at a time.
46
+ #
47
+ # @param source [Source, nil]
48
+ # @return [void]
49
+ def attach source
50
+ mutex.synchronize do
51
+ @synchronized = (@current == source) if synchronized?
52
+ @current = source
53
+ catalog
54
+ end
55
+ end
56
+
57
+ # True if the specified file is currently attached.
58
+ #
59
+ # @param filename [String]
60
+ # @return [Boolean]
61
+ def attached? filename
62
+ !@current.nil? && @current.filename == filename
63
+ end
64
+ alias open? attached?
65
+
66
+ # Detach the specified file if it is currently attached to the library.
67
+ #
68
+ # @param filename [String]
69
+ # @return [Boolean] True if the specified file was detached
70
+ def detach filename
71
+ return false if @current.nil? || @current.filename != filename
72
+ attach nil
73
+ true
74
+ end
75
+
76
+ # True if the specified file is included in the workspace (but not
77
+ # necessarily open).
78
+ #
79
+ # @param filename [String]
80
+ # @return [Boolean]
81
+ def contain? filename
82
+ workspace.has_file?(filename)
83
+ end
84
+
85
+ # Create a source to be added to the workspace. The file is ignored if it is
86
+ # neither open in the library nor included in the workspace.
87
+ #
88
+ # @param filename [String]
89
+ # @param text [String] The contents of the file
90
+ # @return [Boolean] True if the file was added to the workspace.
91
+ def create filename, text
92
+ result = false
93
+ mutex.synchronize do
94
+ next unless contain?(filename) || open?(filename) || workspace.would_merge?(filename)
95
+ @synchronized = false
96
+ source = Solargraph::Source.load_string(text, filename)
97
+ workspace.merge(source)
98
+ result = true
99
+ end
100
+ result
101
+ end
102
+
103
+ # Create a file source from a file on disk. The file is ignored if it is
104
+ # neither open in the library nor included in the workspace.
105
+ #
106
+ # @param filename [String]
107
+ # @return [Boolean] True if the file was added to the workspace.
108
+ def create_from_disk filename
109
+ result = false
110
+ mutex.synchronize do
111
+ next if File.directory?(filename) || !File.exist?(filename)
112
+ next unless contain?(filename) || open?(filename) || workspace.would_merge?(filename)
113
+ @synchronized = false
114
+ source = Solargraph::Source.load_string(File.read(filename), filename)
115
+ workspace.merge(source)
116
+ result = true
117
+ end
118
+ result
119
+ end
120
+
121
+ # Delete a file from the library. Deleting a file will make it unavailable
122
+ # for checkout and optionally remove it from the workspace unless the
123
+ # workspace configuration determines that it should still exist.
124
+ #
125
+ # @param filename [String]
126
+ # @return [Boolean] True if the file was deleted
127
+ def delete filename
128
+ detach filename
129
+ result = false
130
+ mutex.synchronize do
131
+ result = workspace.remove(filename)
132
+ @synchronized = !result if synchronized?
133
+ end
134
+ result
135
+ end
136
+
137
+ # Close a file in the library. Closing a file will make it unavailable for
138
+ # checkout although it may still exist in the workspace.
139
+ #
140
+ # @param filename [String]
141
+ # @return [void]
142
+ def close filename
143
+ mutex.synchronize do
144
+ @synchronized = false
145
+ @current = nil if @current && @current.filename == filename
146
+ catalog
147
+ end
148
+ end
149
+
150
+ # Get completion suggestions at the specified file and location.
151
+ #
152
+ # @param filename [String] The file to analyze
153
+ # @param line [Integer] The zero-based line number
154
+ # @param column [Integer] The zero-based column number
155
+ # @return [SourceMap::Completion]
156
+ # @todo Take a Location instead of filename/line/column
157
+ def completions_at filename, line, column
158
+ position = Position.new(line, column)
159
+ cursor = Source::Cursor.new(read(filename), position)
160
+ api_map.clip(cursor).complete
161
+ end
162
+
163
+ # Get definition suggestions for the expression at the specified file and
164
+ # location.
165
+ #
166
+ # @param filename [String] The file to analyze
167
+ # @param line [Integer] The zero-based line number
168
+ # @param column [Integer] The zero-based column number
169
+ # @return [Array<Solargraph::Pin::Base>]
170
+ # @todo Take filename/position instead of filename/line/column
171
+ def definitions_at filename, line, column
172
+ position = Position.new(line, column)
173
+ cursor = Source::Cursor.new(read(filename), position)
174
+ api_map.clip(cursor).define.map { |pin| pin.realize(api_map) }
175
+ end
176
+
177
+ # Get signature suggestions for the method at the specified file and
178
+ # location.
179
+ #
180
+ # @param filename [String] The file to analyze
181
+ # @param line [Integer] The zero-based line number
182
+ # @param column [Integer] The zero-based column number
183
+ # @return [Array<Solargraph::Pin::Base>]
184
+ # @todo Take filename/position instead of filename/line/column
185
+ def signatures_at filename, line, column
186
+ position = Position.new(line, column)
187
+ cursor = Source::Cursor.new(read(filename), position)
188
+ api_map.clip(cursor).signify
189
+ end
190
+
191
+ # @param filename [String]
192
+ # @param line [Integer]
193
+ # @param column [Integer]
194
+ # @param strip [Boolean] Strip special characters from variable names
195
+ # @return [Array<Solargraph::Range>]
196
+ # @todo Take a Location instead of filename/line/column
197
+ def references_from filename, line, column, strip: false
198
+ # checkout filename
199
+ cursor = api_map.cursor_at(filename, Position.new(line, column))
200
+ clip = api_map.clip(cursor)
201
+ pins = clip.define
202
+ return [] if pins.empty?
203
+ result = []
204
+ pins.uniq.each do |pin|
205
+ (workspace.sources + (@current ? [@current] : [])).uniq(&:filename).each do |source|
206
+ found = source.references(pin.name)
207
+ found.select! do |loc|
208
+ referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character)
209
+ # HACK: The additional location comparison is necessary because
210
+ # Clip#define can return proxies for parameter pins
211
+ referenced.any?{|r| r == pin || r.location == pin.location}
212
+ end
213
+ # HACK: for language clients that exclude special characters from the start of variable names
214
+ if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
215
+ found.map! do |loc|
216
+ Solargraph::Location.new(loc.filename, Solargraph::Range.from_to(loc.range.start.line, loc.range.start.column + match[0].length, loc.range.ending.line, loc.range.ending.column))
217
+ end
218
+ end
219
+ result.concat(found.sort do |a, b|
220
+ a.range.start.line <=> b.range.start.line
221
+ end)
222
+ end
223
+ end
224
+ result.uniq
225
+ end
226
+
227
+ # Get the pins at the specified location or nil if the pin does not exist.
228
+ #
229
+ # @param location [Location]
230
+ # @return [Array<Solargraph::Pin::Base>]
231
+ def locate_pins location
232
+ api_map.locate_pins(location).map { |pin| pin.realize(api_map) }
233
+ end
234
+
235
+ def locate_ref location
236
+ api_map.require_reference_at location
237
+ end
238
+
239
+ # Get an array of pins that match a path.
240
+ #
241
+ # @param path [String]
242
+ # @return [Array<Solargraph::Pin::Base>]
243
+ def get_path_pins path
244
+ api_map.get_path_suggestions(path)
245
+ end
246
+
247
+ # @param query [String]
248
+ # @return [Array<YARD::CodeObject::Base>]
249
+ def document query
250
+ catalog
251
+ api_map.document query
252
+ end
253
+
254
+ # @param query [String]
255
+ # @return [Array<String>]
256
+ def search query
257
+ catalog
258
+ api_map.search query
259
+ end
260
+
261
+ # Get an array of all symbols in the workspace that match the query.
262
+ #
263
+ # @param query [String]
264
+ # @return [Array<Pin::Base>]
265
+ def query_symbols query
266
+ catalog
267
+ api_map.query_symbols query
268
+ end
269
+
270
+ # Get an array of document symbols.
271
+ #
272
+ # Document symbols are composed of namespace, method, and constant pins.
273
+ # The results of this query are appropriate for building the response to a
274
+ # textDocument/documentSymbol message in the language server protocol.
275
+ #
276
+ # @param filename [String]
277
+ # @return [Array<Solargraph::Pin::Base>]
278
+ def document_symbols filename
279
+ # checkout filename
280
+ api_map.document_symbols(filename)
281
+ end
282
+
283
+ # @param path [String]
284
+ # @return [Array<Solargraph::Pin::Base>]
285
+ def path_pins path
286
+ catalog
287
+ api_map.get_path_suggestions(path)
288
+ end
289
+
290
+ # Get the current text of a file in the library.
291
+ #
292
+ # @param filename [String]
293
+ # @return [String]
294
+ def read_text filename
295
+ source = read(filename)
296
+ source.code
297
+ end
298
+
299
+ # Get diagnostics about a file.
300
+ #
301
+ # @param filename [String]
302
+ # @return [Array<Hash>]
303
+ def diagnose filename
304
+ # @todo Only open files get diagnosed. Determine whether anything or
305
+ # everything in the workspace should get diagnosed, or if there should
306
+ # be an option to do so.
307
+ #
308
+ return [] unless open?(filename)
309
+ catalog
310
+ result = []
311
+ source = read(filename)
312
+ repargs = {}
313
+ workspace.config.reporters.each do |line|
314
+ if line == 'all!'
315
+ Diagnostics.reporters.each do |reporter|
316
+ repargs[reporter] ||= []
317
+ end
318
+ else
319
+ args = line.split(':').map(&:strip)
320
+ name = args.shift
321
+ reporter = Diagnostics.reporter(name)
322
+ raise DiagnosticsError, "Diagnostics reporter #{name} does not exist" if reporter.nil?
323
+ repargs[reporter] ||= []
324
+ repargs[reporter].concat args
325
+ end
326
+ end
327
+ repargs.each_pair do |reporter, args|
328
+ result.concat reporter.new(*args.uniq).diagnose(source, api_map)
329
+ end
330
+ result
331
+ end
332
+
333
+ # Update the ApiMap from the library's workspace and open files.
334
+ #
335
+ # @return [void]
336
+ def catalog
337
+ @catalog_mutex.synchronize do
338
+ break if synchronized?
339
+ logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
340
+ api_map.catalog bundle
341
+ @synchronized = true
342
+ logger.info "Catalog complete (#{api_map.pins.length} pins)"
343
+ end
344
+ end
345
+
346
+ # Get an array of foldable ranges for the specified file.
347
+ #
348
+ # @deprecated The library should not need to handle folding ranges. The
349
+ # source itself has all the information it needs.
350
+ #
351
+ # @param filename [String]
352
+ # @return [Array<Range>]
353
+ def folding_ranges filename
354
+ read(filename).folding_ranges
355
+ end
356
+
357
+ # Create a library from a directory.
358
+ #
359
+ # @param directory [String] The path to be used for the workspace
360
+ # @param name [String, nil]
361
+ # @return [Solargraph::Library]
362
+ def self.load directory = '', name = nil
363
+ Solargraph::Library.new(Solargraph::Workspace.new(directory), name)
364
+ end
365
+
366
+ # Try to merge a source into the library's workspace. If the workspace is
367
+ # not configured to include the source, it gets ignored.
368
+ #
369
+ # @param source [Source]
370
+ # @return [Boolean] True if the source was merged into the workspace.
371
+ def merge source
372
+ result = false
373
+ mutex.synchronize do
374
+ result = workspace.merge(source)
375
+ @synchronized = !result if synchronized?
376
+ end
377
+ result
378
+ end
379
+
380
+ private
381
+
382
+ # @return [Mutex]
383
+ def mutex
384
+ @mutex ||= Mutex.new
385
+ end
386
+
387
+ # @return [ApiMap]
388
+ def api_map
389
+ @api_map ||= Solargraph::ApiMap.new
390
+ end
391
+
392
+ # @return [Bundle]
393
+ def bundle
394
+ Bundle.new(
395
+ workspace: workspace,
396
+ opened: @current ? [@current] : []
397
+ )
398
+ end
399
+
400
+ # Get the source for an open file or create a new source if the file
401
+ # exists on disk. Sources created from disk are not added to the open
402
+ # workspace files, i.e., the version on disk remains the authoritative
403
+ # version.
404
+ #
405
+ # @raise [FileNotFoundError] if the file does not exist
406
+ # @param filename [String]
407
+ # @return [Solargraph::Source]
408
+ def read filename
409
+ return @current if @current && @current.filename == filename
410
+ raise FileNotFoundError, "File not found: #{filename}" unless workspace.has_file?(filename)
411
+ workspace.source(filename)
412
+ end
413
+ end
414
+ end