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,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Solargraph::LanguageServer::Message::Workspace::WorkspaceSymbol < Solargraph::LanguageServer::Message::Base
4
+ include Solargraph::LanguageServer::UriHelpers
5
+
6
+ def process
7
+ pins = host.query_symbols(params['query'])
8
+ info = pins.map do |pin|
9
+ uri = file_to_uri(pin.location.filename)
10
+ {
11
+ name: pin.name,
12
+ containerName: pin.namespace,
13
+ kind: pin.symbol_kind,
14
+ location: {
15
+ uri: uri,
16
+ range: pin.location.range.to_hash
17
+ },
18
+ deprecated: pin.deprecated?
19
+ }
20
+ end
21
+ set_result info
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ # The MessageType constants from the language server specification.
6
+ #
7
+ module MessageTypes
8
+ ERROR = 1
9
+ WARNING = 2
10
+ INFO = 3
11
+ LOG = 4
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ class Request
6
+ # @param id [Integer]
7
+ # @param &block The block that processes the client's response
8
+ def initialize id, &block
9
+ @id = id
10
+ @block = block
11
+ end
12
+
13
+ # @param result [Object]
14
+ # @return [void]
15
+ def process result
16
+ @block.call(result) unless @block.nil?
17
+ end
18
+
19
+ def send_response
20
+ # noop
21
+ end
22
+ end
23
+ end
24
+ end
@@ -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,426 @@
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 bench
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
+ if cursor.comment?
175
+ source = read(filename)
176
+ offset = Solargraph::Position.to_offset(source.code, Solargraph::Position.new(line, column))
177
+ lft = source.code[0..offset-1].match(/\[[a-z0-9_:<, ]*?([a-z0-9_:]*)\z/i)
178
+ rgt = source.code[offset..-1].match(/^([a-z0-9_]*)(:[a-z0-9_:]*)?[\]>, ]/i)
179
+ if lft && rgt
180
+ tag = (lft[1] + rgt[1]).sub(/:+$/, '')
181
+ clip = api_map.clip(cursor)
182
+ clip.translate tag
183
+ else
184
+ []
185
+ end
186
+ else
187
+ api_map.clip(cursor).define.map { |pin| pin.realize(api_map) }
188
+ end
189
+ end
190
+
191
+ # Get signature suggestions for the method at the specified file and
192
+ # location.
193
+ #
194
+ # @param filename [String] The file to analyze
195
+ # @param line [Integer] The zero-based line number
196
+ # @param column [Integer] The zero-based column number
197
+ # @return [Array<Solargraph::Pin::Base>]
198
+ # @todo Take filename/position instead of filename/line/column
199
+ def signatures_at filename, line, column
200
+ position = Position.new(line, column)
201
+ cursor = Source::Cursor.new(read(filename), position)
202
+ api_map.clip(cursor).signify
203
+ end
204
+
205
+ # @param filename [String]
206
+ # @param line [Integer]
207
+ # @param column [Integer]
208
+ # @param strip [Boolean] Strip special characters from variable names
209
+ # @return [Array<Solargraph::Range>]
210
+ # @todo Take a Location instead of filename/line/column
211
+ def references_from filename, line, column, strip: false
212
+ cursor = api_map.cursor_at(filename, Position.new(line, column))
213
+ clip = api_map.clip(cursor)
214
+ pins = clip.define
215
+ return [] if pins.empty?
216
+ result = []
217
+ pins.uniq.each do |pin|
218
+ (workspace.sources + (@current ? [@current] : [])).uniq(&:filename).each do |source|
219
+ found = source.references(pin.name)
220
+ found.select! do |loc|
221
+ referenced = definitions_at(loc.filename, loc.range.ending.line, loc.range.ending.character)
222
+ # HACK: The additional location comparison is necessary because
223
+ # Clip#define can return proxies for parameter pins
224
+ referenced.any? { |r| r == pin || r.location == pin.location }
225
+ end
226
+ # HACK: for language clients that exclude special characters from the start of variable names
227
+ if strip && match = cursor.word.match(/^[^a-z0-9_]+/i)
228
+ found.map! do |loc|
229
+ 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))
230
+ end
231
+ end
232
+ result.concat(found.sort do |a, b|
233
+ a.range.start.line <=> b.range.start.line
234
+ end)
235
+ end
236
+ end
237
+ result.uniq
238
+ end
239
+
240
+ # Get the pins at the specified location or nil if the pin does not exist.
241
+ #
242
+ # @param location [Location]
243
+ # @return [Array<Solargraph::Pin::Base>]
244
+ def locate_pins location
245
+ api_map.locate_pins(location).map { |pin| pin.realize(api_map) }
246
+ end
247
+
248
+ def locate_ref location
249
+ api_map.require_reference_at location
250
+ end
251
+
252
+ # Get an array of pins that match a path.
253
+ #
254
+ # @param path [String]
255
+ # @return [Array<Solargraph::Pin::Base>]
256
+ def get_path_pins path
257
+ api_map.get_path_suggestions(path)
258
+ end
259
+
260
+ # @param query [String]
261
+ # @return [Array<YARD::CodeObjects::Base>]
262
+ def document query
263
+ catalog
264
+ api_map.document query
265
+ end
266
+
267
+ # @param query [String]
268
+ # @return [Array<String>]
269
+ def search query
270
+ catalog
271
+ api_map.search query
272
+ end
273
+
274
+ # Get an array of all symbols in the workspace that match the query.
275
+ #
276
+ # @param query [String]
277
+ # @return [Array<Pin::Base>]
278
+ def query_symbols query
279
+ catalog
280
+ api_map.query_symbols query
281
+ end
282
+
283
+ # Get an array of document symbols.
284
+ #
285
+ # Document symbols are composed of namespace, method, and constant pins.
286
+ # The results of this query are appropriate for building the response to a
287
+ # textDocument/documentSymbol message in the language server protocol.
288
+ #
289
+ # @param filename [String]
290
+ # @return [Array<Solargraph::Pin::Base>]
291
+ def document_symbols filename
292
+ api_map.document_symbols(filename)
293
+ end
294
+
295
+ # @param path [String]
296
+ # @return [Array<Solargraph::Pin::Base>]
297
+ def path_pins path
298
+ catalog
299
+ api_map.get_path_suggestions(path)
300
+ end
301
+
302
+ # Get the current text of a file in the library.
303
+ #
304
+ # @param filename [String]
305
+ # @return [String]
306
+ def read_text filename
307
+ source = read(filename)
308
+ source.code
309
+ end
310
+
311
+ # Get diagnostics about a file.
312
+ #
313
+ # @param filename [String]
314
+ # @return [Array<Hash>]
315
+ def diagnose filename
316
+ # @todo Only open files get diagnosed. Determine whether anything or
317
+ # everything in the workspace should get diagnosed, or if there should
318
+ # be an option to do so.
319
+ #
320
+ return [] unless open?(filename)
321
+ catalog
322
+ result = []
323
+ source = read(filename)
324
+ repargs = {}
325
+ workspace.config.reporters.each do |line|
326
+ if line == 'all!'
327
+ Diagnostics.reporters.each do |reporter|
328
+ repargs[reporter] ||= []
329
+ end
330
+ else
331
+ args = line.split(':').map(&:strip)
332
+ name = args.shift
333
+ reporter = Diagnostics.reporter(name)
334
+ raise DiagnosticsError, "Diagnostics reporter #{name} does not exist" if reporter.nil?
335
+ repargs[reporter] ||= []
336
+ repargs[reporter].concat args
337
+ end
338
+ end
339
+ repargs.each_pair do |reporter, args|
340
+ result.concat reporter.new(*args.uniq).diagnose(source, api_map)
341
+ end
342
+ result
343
+ end
344
+
345
+ # Update the ApiMap from the library's workspace and open files.
346
+ #
347
+ # @return [void]
348
+ def catalog
349
+ @catalog_mutex.synchronize do
350
+ break if synchronized?
351
+ logger.info "Cataloging #{workspace.directory.empty? ? 'generic workspace' : workspace.directory}"
352
+ api_map.catalog bench
353
+ @synchronized = true
354
+ logger.info "Catalog complete (#{api_map.source_maps.length} files, #{api_map.pins.length} pins)" if logger.info?
355
+ end
356
+ end
357
+
358
+ # Get an array of foldable ranges for the specified file.
359
+ #
360
+ # @deprecated The library should not need to handle folding ranges. The
361
+ # source itself has all the information it needs.
362
+ #
363
+ # @param filename [String]
364
+ # @return [Array<Range>]
365
+ def folding_ranges filename
366
+ read(filename).folding_ranges
367
+ end
368
+
369
+ # Create a library from a directory.
370
+ #
371
+ # @param directory [String] The path to be used for the workspace
372
+ # @param name [String, nil]
373
+ # @return [Solargraph::Library]
374
+ def self.load directory = '', name = nil
375
+ Solargraph::Library.new(Solargraph::Workspace.new(directory), name)
376
+ end
377
+
378
+ # Try to merge a source into the library's workspace. If the workspace is
379
+ # not configured to include the source, it gets ignored.
380
+ #
381
+ # @param source [Source]
382
+ # @return [Boolean] True if the source was merged into the workspace.
383
+ def merge source
384
+ result = false
385
+ mutex.synchronize do
386
+ result = workspace.merge(source)
387
+ @synchronized = !result if synchronized?
388
+ end
389
+ result
390
+ end
391
+
392
+ private
393
+
394
+ # @return [Mutex]
395
+ def mutex
396
+ @mutex ||= Mutex.new
397
+ end
398
+
399
+ # @return [ApiMap]
400
+ def api_map
401
+ @api_map ||= Solargraph::ApiMap.new
402
+ end
403
+
404
+ # @return [Bench]
405
+ def bench
406
+ Bench.new(
407
+ workspace: workspace,
408
+ opened: @current ? [@current] : []
409
+ )
410
+ end
411
+
412
+ # Get the source for an open file or create a new source if the file
413
+ # exists on disk. Sources created from disk are not added to the open
414
+ # workspace files, i.e., the version on disk remains the authoritative
415
+ # version.
416
+ #
417
+ # @raise [FileNotFoundError] if the file does not exist
418
+ # @param filename [String]
419
+ # @return [Solargraph::Source]
420
+ def read filename
421
+ return @current if @current && @current.filename == filename
422
+ raise FileNotFoundError, "File not found: #{filename}" unless workspace.has_file?(filename)
423
+ workspace.source(filename)
424
+ end
425
+ end
426
+ end