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,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ class UpdateErrors < Base
6
+ def diagnose source, api_map
7
+ result = []
8
+ combine_ranges(source.code, source.error_ranges).each do |range|
9
+ result.push(
10
+ range: range.to_hash,
11
+ severity: Diagnostics::Severities::ERROR,
12
+ source: 'Solargraph',
13
+ message: 'Syntax error'
14
+ )
15
+ end
16
+ result
17
+ end
18
+
19
+ private
20
+
21
+ # Combine an array of ranges by their starting lines.
22
+ #
23
+ # @param code [String]
24
+ # @param ranges [Array<Range>]
25
+ # @return [Array<Range>]
26
+ def combine_ranges code, ranges
27
+ result = []
28
+ lines = []
29
+ ranges.sort{|a, b| a.start.line <=> b.start.line}.each do |rng|
30
+ next if rng.nil? || lines.include?(rng.start.line)
31
+ lines.push rng.start.line
32
+ next if rng.start.line >= code.lines.length
33
+ scol = code.lines[rng.start.line].index(/[^\s]/) || 0
34
+ ecol = code.lines[rng.start.line].length
35
+ result.push Range.from_to(rng.start.line, scol, rng.start.line, ecol)
36
+ end
37
+ result
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler'
4
+ require 'json'
5
+ require 'open3'
6
+ require 'shellwords'
7
+ require 'yard'
8
+ require 'fileutils'
9
+
10
+ module Solargraph
11
+ class Documentor
12
+ RDOC_GEMS = %w[
13
+ actioncable actionmailbox actionmailer actionpack actiontext actionview
14
+ activejob activemodel activerecord activestorage activesupport railties
15
+ ]
16
+
17
+ def initialize directory, rebuild: false, out: File.new(File::NULL, 'w')
18
+ @directory = directory
19
+ @rebuild = rebuild
20
+ @out = out
21
+ end
22
+
23
+ # @return [Boolean] True if all specs were found and documented.
24
+ def document
25
+ failures = 0
26
+ Documentor.specs_from_bundle(@directory).each_pair do |name, version|
27
+ yd = YARD::Registry.yardoc_file_for_gem(name, "= #{version}")
28
+ if !yd || @rebuild
29
+ FileUtils.safe_unlink File.join(YardMap::CoreDocs.cache_dir, 'gems', "#{name}-#{version}.ser")
30
+ @out.puts "Documenting #{name} #{version}"
31
+ `yard gems #{name} #{version} #{@rebuild ? '--rebuild' : ''}`
32
+ yd = YARD::Registry.yardoc_file_for_gem(name, "= #{version}")
33
+ # HACK: Ignore errors documenting bundler
34
+ if !yd && name != 'bundler'
35
+ @out.puts "#{name} #{version} YARD documentation failed"
36
+ failures += 1
37
+ end
38
+ end
39
+ if yd && RDOC_GEMS.include?(name)
40
+ cache = File.join(Solargraph::YardMap::CoreDocs.cache_dir, 'gems', "#{name}-#{version}", 'yardoc')
41
+ if !File.exist?(cache) || @rebuild
42
+ @out.puts "Caching custom documentation for #{name} #{version}"
43
+ spec = Gem::Specification.find_by_name(name, "= #{version}")
44
+ Solargraph::YardMap::RdocToYard.run(spec)
45
+ end
46
+ end
47
+ end
48
+ if failures > 0
49
+ @out.puts "#{failures} gem#{failures == 1 ? '' : 's'} could not be documented. You might need to run `bundle install`."
50
+ end
51
+ failures == 0
52
+ rescue Solargraph::BundleNotFoundError => e
53
+ @out.puts "[#{e.class}] #{e.message}"
54
+ @out.puts "No bundled gems are available in #{@directory}"
55
+ false
56
+ end
57
+
58
+ # @param directory [String]
59
+ # @return [Hash]
60
+ def self.specs_from_bundle directory
61
+ Solargraph.with_clean_env do
62
+ Dir.chdir directory do
63
+ cmd = [
64
+ 'bundle', 'exec', 'ruby', '-e',
65
+ "require 'bundler'; require 'json'; puts Bundler.definition.specs_for([:default]).map { |spec| [spec.name, spec.version] }.to_h.to_json"
66
+ ]
67
+ o, e, s = Open3.capture3(*cmd)
68
+ if s.success?
69
+ o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
70
+ else
71
+ Solargraph.logger.warn e
72
+ raise BundleNotFoundError, "Failed to load gems from bundle at #{directory}"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ # A collection of additional data, such as map pins and required paths, that
5
+ # can be added to an ApiMap.
6
+ #
7
+ # Conventions are used to add Environs.
8
+ #
9
+ class Environ
10
+ # @return [Array<String>]
11
+ attr_reader :requires
12
+
13
+ # @return [Array<String>]
14
+ attr_reader :domains
15
+
16
+ # @return [Array<Pin::Reference::Override>]
17
+ attr_reader :pins
18
+
19
+ # @param requires [Array<String>]
20
+ # @param domains [Array<String>]
21
+ # @param pins [Array<Pin::Base>]
22
+ def initialize requires: [], domains: [], pins: []
23
+ @requires = requires
24
+ @domains = domains
25
+ @pins = pins
26
+ end
27
+
28
+ # @return [self]
29
+ def clear
30
+ domains.clear
31
+ requires.clear
32
+ pins.clear
33
+ self
34
+ end
35
+
36
+ # @param other [Environ]
37
+ # @return [self]
38
+ def merge other
39
+ domains.concat other.domains
40
+ requires.concat other.requires
41
+ pins.concat other.pins
42
+ self
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solargraph/language_server/error_codes'
4
+ require 'solargraph/language_server/completion_item_kinds'
5
+ require 'solargraph/language_server/symbol_kinds'
6
+
7
+ module Solargraph
8
+ # The LanguageServer namespace contains the classes and modules that compose
9
+ # concrete implementations of language servers.
10
+ #
11
+ module LanguageServer
12
+ autoload :Host, 'solargraph/language_server/host'
13
+ autoload :Message, 'solargraph/language_server/message'
14
+ autoload :UriHelpers, 'solargraph/language_server/uri_helpers'
15
+ autoload :MessageTypes, 'solargraph/language_server/message_types'
16
+ autoload :Request, 'solargraph/language_server/request'
17
+ autoload :Transport, 'solargraph/language_server/transport'
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ # The CompletionItemKind constants for the language server protocol.
6
+ #
7
+ module CompletionItemKinds
8
+ TEXT = 1
9
+ METHOD = 2
10
+ FUNCTION = 3
11
+ CONSTRUCTOR = 4
12
+ FIELD = 5
13
+ VARIABLE = 6
14
+ CLASS = 7
15
+ INTERFACE = 8
16
+ MODULE = 9
17
+ PROPERTY = 10
18
+ UNIT = 11
19
+ VALUE = 12
20
+ ENUM = 13
21
+ KEYWORD = 14
22
+ SNIPPET = 15
23
+ COLOR = 16
24
+ FILE = 17
25
+ REFERENCE = 18
26
+ FOLDER = 19
27
+ ENUM_MEMBER = 20
28
+ CONSTANT = 21
29
+ STRUCT = 22
30
+ EVENT = 23
31
+ OPERATOR = 24
32
+ TYPE_PARAMETER = 25
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module LanguageServer
5
+ # The ErrorCode constants for the language server protocol.
6
+ #
7
+ module ErrorCodes
8
+ PARSE_ERROR = -32700
9
+ INVALID_REQUEST = -32600
10
+ METHOD_NOT_FOUND = -32601
11
+ INVALID_PARAMS = -32602
12
+ INTERNAL_ERROR = -32603
13
+ SERVER_ERROR_START = -32099
14
+ SERVER_ERROR_END = -32000
15
+ SERVER_NOT_INITIALIZED = -32002
16
+ UNKNOWN_ERROR_CODE = -32001
17
+ REQUEST_CANCELLED = -32800
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,746 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'observer'
4
+ require 'set'
5
+
6
+ module Solargraph
7
+ module LanguageServer
8
+ # The language server protocol's data provider. Hosts are responsible for
9
+ # querying the library and processing messages. They also provide thread
10
+ # safety for multi-threaded transports.
11
+ #
12
+ class Host
13
+ autoload :Diagnoser, 'solargraph/language_server/host/diagnoser'
14
+ autoload :Cataloger, 'solargraph/language_server/host/cataloger'
15
+ autoload :Sources, 'solargraph/language_server/host/sources'
16
+ autoload :Dispatch, 'solargraph/language_server/host/dispatch'
17
+
18
+ include UriHelpers
19
+ include Logging
20
+ include Dispatch
21
+ include Observable
22
+
23
+ attr_writer :client_capabilities
24
+
25
+ def initialize
26
+ @cancel_semaphore = Mutex.new
27
+ @buffer_semaphore = Mutex.new
28
+ @register_semaphore = Mutex.new
29
+ @cancel = []
30
+ @buffer = String.new
31
+ @stopped = true
32
+ @next_request_id = 0
33
+ @dynamic_capabilities = Set.new
34
+ @registered_capabilities = Set.new
35
+ end
36
+
37
+ # Start asynchronous process handling.
38
+ #
39
+ # @return [void]
40
+ def start
41
+ return unless stopped?
42
+ @stopped = false
43
+ diagnoser.start
44
+ cataloger.start
45
+ sources.start
46
+ end
47
+
48
+ # Update the configuration options with the provided hash.
49
+ #
50
+ # @param update [Hash]
51
+ # @return [void]
52
+ def configure update
53
+ return if update.nil?
54
+ options.merge! update
55
+ logger.level = LOG_LEVELS[options['logLevel']] || DEFAULT_LOG_LEVEL
56
+ end
57
+
58
+ # @return [Hash]
59
+ def options
60
+ @options ||= default_configuration
61
+ end
62
+
63
+ # Cancel the method with the specified ID.
64
+ #
65
+ # @param id [Integer]
66
+ # @return [void]
67
+ def cancel id
68
+ @cancel_semaphore.synchronize { @cancel.push id }
69
+ end
70
+
71
+ # True if the host received a request to cancel the method with the
72
+ # specified ID.
73
+ #
74
+ # @param id [Integer]
75
+ # @return [Boolean]
76
+ def cancel? id
77
+ result = false
78
+ @cancel_semaphore.synchronize { result = @cancel.include? id }
79
+ result
80
+ end
81
+
82
+ # Delete the specified ID from the list of cancelled IDs if it exists.
83
+ #
84
+ # @param id [Integer]
85
+ # @return [void]
86
+ def clear id
87
+ @cancel_semaphore.synchronize { @cancel.delete id }
88
+ end
89
+
90
+ # Start processing a request from the client. After the message is
91
+ # processed, the transport is responsible for sending the response.
92
+ #
93
+ # @param request [Hash] The contents of the message.
94
+ # @return [Solargraph::LanguageServer::Message::Base] The message handler.
95
+ def receive request
96
+ if request['method']
97
+ logger.info "Server received #{request['method']}"
98
+ logger.debug request
99
+ message = Message.select(request['method']).new(self, request)
100
+ begin
101
+ message.process
102
+ rescue StandardError => e
103
+ logger.warn "Error processing request: [#{e.class}] #{e.message}"
104
+ logger.warn e.backtrace.join("\n")
105
+ message.set_error Solargraph::LanguageServer::ErrorCodes::INTERNAL_ERROR, "[#{e.class}] #{e.message}"
106
+ end
107
+ message
108
+ elsif request['id']
109
+ # @todo What if the id is invalid?
110
+ requests[request['id']].process(request['result'])
111
+ requests.delete request['id']
112
+ else
113
+ logger.warn "Invalid message received."
114
+ logger.debug request
115
+ end
116
+ end
117
+
118
+ # Respond to a notification that a file was created in the workspace.
119
+ # The libraries will determine whether the file should be merged; see
120
+ # Solargraph::Library#create_from_disk.
121
+ #
122
+ # @param uri [String] The file uri.
123
+ # @return [Boolean] True if a library accepted the file.
124
+ def create uri
125
+ filename = uri_to_file(uri)
126
+ result = false
127
+ libraries.each do |lib|
128
+ result = true if lib.create_from_disk(filename)
129
+ end
130
+ diagnoser.schedule uri if open?(uri)
131
+ result
132
+ end
133
+
134
+ # Delete the specified file from the library.
135
+ #
136
+ # @param uri [String] The file uri.
137
+ # @return [void]
138
+ def delete uri
139
+ filename = uri_to_file(uri)
140
+ libraries.each do |lib|
141
+ lib.delete(filename)
142
+ end
143
+ send_notification "textDocument/publishDiagnostics", {
144
+ uri: uri,
145
+ diagnostics: []
146
+ }
147
+ end
148
+
149
+ # Open the specified file in the library.
150
+ #
151
+ # @param uri [String] The file uri.
152
+ # @param text [String] The contents of the file.
153
+ # @param version [Integer] A version number.
154
+ # @return [void]
155
+ def open uri, text, version
156
+ src = sources.open(uri, text, version)
157
+ libraries.each do |lib|
158
+ lib.merge src
159
+ end
160
+ diagnoser.schedule uri
161
+ end
162
+
163
+ # @param uri [String]
164
+ # @return [void]
165
+ def open_from_disk uri
166
+ sources.open_from_disk(uri)
167
+ library = library_for(uri)
168
+ # library.open_from_disk uri_to_file(uri)
169
+ diagnoser.schedule uri
170
+ end
171
+
172
+ # True if the specified file is currently open in the library.
173
+ #
174
+ # @param uri [String]
175
+ # @return [Boolean]
176
+ def open? uri
177
+ sources.include? uri
178
+ end
179
+
180
+ # Close the file specified by the URI.
181
+ #
182
+ # @param uri [String]
183
+ # @return [void]
184
+ def close uri
185
+ logger.info "Closing #{uri}"
186
+ sources.close uri
187
+ diagnoser.schedule uri
188
+ end
189
+
190
+ # @param uri [String]
191
+ # @return [void]
192
+ def diagnose uri
193
+ if sources.include?(uri)
194
+ library = library_for(uri)
195
+ if library.synchronized?
196
+ logger.info "Diagnosing #{uri}"
197
+ begin
198
+ results = library.diagnose uri_to_file(uri)
199
+ send_notification "textDocument/publishDiagnostics", {
200
+ uri: uri,
201
+ diagnostics: results
202
+ }
203
+ rescue DiagnosticsError => e
204
+ logger.warn "Error in diagnostics: #{e.message}"
205
+ options['diagnostics'] = false
206
+ send_notification 'window/showMessage', {
207
+ type: LanguageServer::MessageTypes::ERROR,
208
+ message: "Error in diagnostics: #{e.message}"
209
+ }
210
+ rescue FileNotFoundError => e
211
+ # @todo This appears to happen when an external file is open and
212
+ # scheduled for diagnosis, but the file was closed (i.e., the
213
+ # editor moved to a different file) before diagnosis started
214
+ logger.warn "Unable to diagnose #{uri} : #{e.message}"
215
+ send_notification 'textDocument/publishDiagnostics', {
216
+ uri: uri,
217
+ diagnostics: []
218
+ }
219
+ end
220
+ else
221
+ logger.info "Deferring diagnosis of #{uri}"
222
+ diagnoser.schedule uri
223
+ end
224
+ else
225
+ send_notification 'textDocument/publishDiagnostics', {
226
+ uri: uri,
227
+ diagnostics: []
228
+ }
229
+ end
230
+ end
231
+
232
+ # Update a document from the parameters of a textDocument/didChange
233
+ # method.
234
+ #
235
+ # @param params [Hash]
236
+ # @return [void]
237
+ def change params
238
+ updater = generate_updater(params)
239
+ sources.async_update params['textDocument']['uri'], updater
240
+ diagnoser.schedule params['textDocument']['uri']
241
+ end
242
+
243
+ # Queue a message to be sent to the client.
244
+ #
245
+ # @param message [String] The message to send.
246
+ # @return [void]
247
+ def queue message
248
+ @buffer_semaphore.synchronize { @buffer += message }
249
+ changed
250
+ notify_observers
251
+ end
252
+
253
+ # Clear the message buffer and return the most recent data.
254
+ #
255
+ # @return [String] The most recent data or an empty string.
256
+ def flush
257
+ tmp = ''
258
+ @buffer_semaphore.synchronize do
259
+ tmp = @buffer.clone
260
+ @buffer.clear
261
+ end
262
+ tmp
263
+ end
264
+
265
+ # Prepare a library for the specified directory.
266
+ #
267
+ # @param directory [String]
268
+ # @param name [String, nil]
269
+ # @return [void]
270
+ def prepare directory, name = nil
271
+ # No need to create a library without a directory. The generic library
272
+ # will handle it.
273
+ return if directory.nil?
274
+ logger.info "Preparing library for #{directory}"
275
+ path = ''
276
+ path = normalize_separators(directory) unless directory.nil?
277
+ begin
278
+ lib = Solargraph::Library.load(path, name)
279
+ libraries.push lib
280
+ rescue WorkspaceTooLargeError => e
281
+ send_notification 'window/showMessage', {
282
+ 'type' => Solargraph::LanguageServer::MessageTypes::WARNING,
283
+ 'message' => e.message
284
+ }
285
+ end
286
+ end
287
+
288
+ # Prepare multiple folders.
289
+ #
290
+ # @param array [Array<Hash{String => String}>]
291
+ # @return [void]
292
+ def prepare_folders array
293
+ return if array.nil?
294
+ array.each do |folder|
295
+ prepare uri_to_file(folder['uri']), folder['name']
296
+ end
297
+ end
298
+
299
+ # Remove a directory.
300
+ #
301
+ # @param directory [String]
302
+ # @return [void]
303
+ def remove directory
304
+ logger.info "Removing library for #{directory}"
305
+ # @param lib [Library]
306
+ libraries.delete_if do |lib|
307
+ next false if lib.workspace.directory != directory
308
+ true
309
+ end
310
+ end
311
+
312
+ # @param array [Array<Hash>]
313
+ # @return [void]
314
+ def remove_folders array
315
+ array.each do |folder|
316
+ remove uri_to_file(folder['uri'])
317
+ end
318
+ end
319
+
320
+ # @return [Array<String>]
321
+ def folders
322
+ libraries.map { |lib| lib.workspace.directory }
323
+ end
324
+
325
+ # Send a notification to the client.
326
+ #
327
+ # @param method [String] The message method
328
+ # @param params [Hash] The method parameters
329
+ # @return [void]
330
+ def send_notification method, params
331
+ response = {
332
+ jsonrpc: "2.0",
333
+ method: method,
334
+ params: params
335
+ }
336
+ json = response.to_json
337
+ envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
338
+ queue envelope
339
+ logger.info "Server sent #{method}"
340
+ logger.debug params
341
+ end
342
+
343
+ # Send a request to the client and execute the provided block to process
344
+ # the response. If an ID is not provided, the host will use an auto-
345
+ # incrementing integer.
346
+ #
347
+ # @param method [String] The message method
348
+ # @param params [Hash] The method parameters
349
+ # @param block [Proc] The block that processes the response
350
+ # @yieldparam [Hash] The result sent by the client
351
+ # @return [void]
352
+ def send_request method, params, &block
353
+ message = {
354
+ jsonrpc: "2.0",
355
+ method: method,
356
+ params: params,
357
+ id: @next_request_id
358
+ }
359
+ json = message.to_json
360
+ requests[@next_request_id] = Request.new(@next_request_id, &block)
361
+ envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
362
+ queue envelope
363
+ @next_request_id += 1
364
+ logger.info "Server sent #{method}"
365
+ logger.debug params
366
+ end
367
+
368
+ # Register the methods as capabilities with the client.
369
+ # This method will avoid duplicating registrations and ignore methods
370
+ # that were not flagged for dynamic registration by the client.
371
+ #
372
+ # @param methods [Array<String>] The methods to register
373
+ # @return [void]
374
+ def register_capabilities methods
375
+ logger.debug "Registering capabilities: #{methods}"
376
+ registrations = methods.select{|m| can_register?(m) and !registered?(m)}.map { |m|
377
+ @registered_capabilities.add m
378
+ {
379
+ id: m,
380
+ method: m,
381
+ registerOptions: dynamic_capability_options[m]
382
+ }
383
+ }
384
+ return if registrations.empty?
385
+ @register_semaphore.synchronize do
386
+ send_request 'client/registerCapability', {
387
+ registrations: registrations
388
+ }
389
+ end
390
+ end
391
+
392
+ # Unregister the methods with the client.
393
+ # This method will avoid duplicating unregistrations and ignore methods
394
+ # that were not flagged for dynamic registration by the client.
395
+ #
396
+ # @param methods [Array<String>] The methods to unregister
397
+ # @return [void]
398
+ def unregister_capabilities methods
399
+ logger.debug "Unregistering capabilities: #{methods}"
400
+ unregisterations = methods.select{|m| registered?(m)}.map{ |m|
401
+ @registered_capabilities.delete m
402
+ {
403
+ id: m,
404
+ method: m
405
+ }
406
+ }
407
+ return if unregisterations.empty?
408
+ @register_semaphore.synchronize do
409
+ send_request 'client/unregisterCapability', {
410
+ unregisterations: unregisterations
411
+ }
412
+ end
413
+ end
414
+
415
+ # Flag a method as available for dynamic registration.
416
+ #
417
+ # @param method [String] The method name, e.g., 'textDocument/completion'
418
+ # @return [void]
419
+ def allow_registration method
420
+ @register_semaphore.synchronize do
421
+ @dynamic_capabilities.add method
422
+ end
423
+ end
424
+
425
+ # True if the specified LSP method can be dynamically registered.
426
+ #
427
+ # @param method [String]
428
+ # @return [Boolean]
429
+ def can_register? method
430
+ @dynamic_capabilities.include?(method)
431
+ end
432
+
433
+ # True if the specified method has been registered.
434
+ #
435
+ # @param method [String] The method name, e.g., 'textDocument/completion'
436
+ # @return [Boolean]
437
+ def registered? method
438
+ @registered_capabilities.include?(method)
439
+ end
440
+
441
+ def synchronizing?
442
+ !libraries.all?(&:synchronized?)
443
+ end
444
+
445
+ # @return [void]
446
+ def stop
447
+ return if @stopped
448
+ @stopped = true
449
+ cataloger.stop
450
+ diagnoser.stop
451
+ sources.stop
452
+ changed
453
+ notify_observers
454
+ end
455
+
456
+ def stopped?
457
+ @stopped
458
+ end
459
+
460
+ # Locate multiple pins that match a completion item. The first match is
461
+ # based on the corresponding location in a library source if available.
462
+ # Subsequent matches are based on path.
463
+ #
464
+ # @param params [Hash] A hash representation of a completion item
465
+ # @return [Array<Pin::Base>]
466
+ def locate_pins params
467
+ return [] unless params['data'] && params['data']['uri']
468
+ library = library_for(params['data']['uri'])
469
+ result = []
470
+ if params['data']['location']
471
+ location = Location.new(
472
+ params['data']['location']['filename'],
473
+ Range.from_to(
474
+ params['data']['location']['range']['start']['line'],
475
+ params['data']['location']['range']['start']['character'],
476
+ params['data']['location']['range']['end']['line'],
477
+ params['data']['location']['range']['end']['character']
478
+ )
479
+ )
480
+ result.concat library.locate_pins(location).select{ |pin| pin.name == params['label'] }
481
+ end
482
+ if params['data']['path']
483
+ result.concat library.path_pins(params['data']['path'])
484
+ end
485
+ # Selecting by both location and path can result in duplicate pins
486
+ result.uniq { |p| [p.path, p.location] }
487
+ end
488
+
489
+ # @param uri [String]
490
+ # @return [String]
491
+ def read_text uri
492
+ library = library_for(uri)
493
+ filename = uri_to_file(uri)
494
+ library.read_text(filename)
495
+ end
496
+
497
+ def formatter_config uri
498
+ library = library_for(uri)
499
+ library.workspace.config.formatter
500
+ end
501
+
502
+ # @param uri [String]
503
+ # @param line [Integer]
504
+ # @param column [Integer]
505
+ # @return [Solargraph::SourceMap::Completion]
506
+ def completions_at uri, line, column
507
+ library = library_for(uri)
508
+ library.completions_at uri_to_file(uri), line, column
509
+ end
510
+
511
+ # @param uri [String]
512
+ # @param line [Integer]
513
+ # @param column [Integer]
514
+ # @return [Array<Solargraph::Pin::Base>]
515
+ def definitions_at uri, line, column
516
+ library = library_for(uri)
517
+ library.definitions_at(uri_to_file(uri), line, column)
518
+ end
519
+
520
+ # @param uri [String]
521
+ # @param line [Integer]
522
+ # @param column [Integer]
523
+ # @return [Array<Solargraph::Pin::Base>]
524
+ def signatures_at uri, line, column
525
+ library = library_for(uri)
526
+ library.signatures_at(uri_to_file(uri), line, column)
527
+ end
528
+
529
+ # @param uri [String]
530
+ # @param line [Integer]
531
+ # @param column [Integer]
532
+ # @param strip [Boolean] Strip special characters from variable names
533
+ # @return [Array<Solargraph::Range>]
534
+ def references_from uri, line, column, strip: true
535
+ library = library_for(uri)
536
+ library.references_from(uri_to_file(uri), line, column, strip: strip)
537
+ end
538
+
539
+ # @param query [String]
540
+ # @return [Array<Solargraph::Pin::Base>]
541
+ def query_symbols query
542
+ result = []
543
+ (libraries + [generic_library]).each { |lib| result.concat lib.query_symbols(query) }
544
+ result.uniq
545
+ end
546
+
547
+ # @param query [String]
548
+ # @return [Array<String>]
549
+ def search query
550
+ result = []
551
+ libraries.each { |lib| result.concat lib.search(query) }
552
+ result
553
+ end
554
+
555
+ # @param query [String]
556
+ # @return [Array]
557
+ def document query
558
+ result = []
559
+ libraries.each { |lib| result.concat lib.document(query) }
560
+ result
561
+ end
562
+
563
+ # @param uri [String]
564
+ # @return [Array<Solargraph::Pin::Base>]
565
+ def document_symbols uri
566
+ library = library_for(uri)
567
+ # At this level, document symbols should be unique; e.g., a
568
+ # module_function method should return the location for Module.method
569
+ # or Module#method, but not both.
570
+ library.document_symbols(uri_to_file(uri)).uniq(&:location)
571
+ end
572
+
573
+ # Send a notification to the client.
574
+ #
575
+ # @param text [String]
576
+ # @param type [Integer] A MessageType constant
577
+ # @return [void]
578
+ def show_message text, type = LanguageServer::MessageTypes::INFO
579
+ send_notification 'window/showMessage', {
580
+ type: type,
581
+ message: text
582
+ }
583
+ end
584
+
585
+ # Send a notification with optional responses.
586
+ #
587
+ # @param text [String]
588
+ # @param type [Integer] A MessageType constant
589
+ # @param actions [Array<String>] Response options for the client
590
+ # @param block The block that processes the response
591
+ # @yieldparam [String] The action received from the client
592
+ # @return [void]
593
+ def show_message_request text, type, actions, &block
594
+ send_request 'window/showMessageRequest', {
595
+ type: type,
596
+ message: text,
597
+ actions: actions
598
+ }, &block
599
+ end
600
+
601
+ # Get a list of IDs for server requests that are waiting for responses
602
+ # from the client.
603
+ #
604
+ # @return [Array<Integer>]
605
+ def pending_requests
606
+ requests.keys
607
+ end
608
+
609
+ # @return [Hash{String => Object}]
610
+ def default_configuration
611
+ {
612
+ 'completion' => true,
613
+ 'hover' => true,
614
+ 'symbols' => true,
615
+ 'definitions' => true,
616
+ 'rename' => true,
617
+ 'references' => true,
618
+ 'autoformat' => false,
619
+ 'diagnostics' => false,
620
+ 'formatting' => false,
621
+ 'folding' => true,
622
+ 'logLevel' => 'warn'
623
+ }
624
+ end
625
+
626
+ # @param uri [String]
627
+ # @return [Array<Range>]
628
+ def folding_ranges uri
629
+ sources.find(uri).folding_ranges
630
+ end
631
+
632
+ # @return [void]
633
+ def catalog
634
+ libraries.each(&:catalog)
635
+ end
636
+
637
+ def client_capabilities
638
+ @client_capabilities ||= {}
639
+ end
640
+
641
+ private
642
+
643
+ # @return [Diagnoser]
644
+ def diagnoser
645
+ @diagnoser ||= Diagnoser.new(self)
646
+ end
647
+
648
+ # @return [Cataloger]
649
+ def cataloger
650
+ @cataloger ||= Cataloger.new(self)
651
+ end
652
+
653
+ # A hash of client requests by ID. The host uses this to keep track of
654
+ # pending responses.
655
+ #
656
+ # @return [Hash{Integer => Hash}]
657
+ def requests
658
+ @requests ||= {}
659
+ end
660
+
661
+ # @param path [String]
662
+ # @return [String]
663
+ def normalize_separators path
664
+ return path if File::ALT_SEPARATOR.nil?
665
+ path.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
666
+ end
667
+
668
+ # @param params [Hash]
669
+ # @return [Source::Updater]
670
+ def generate_updater params
671
+ changes = []
672
+ params['contentChanges'].each do |chng|
673
+ changes.push Solargraph::Source::Change.new(
674
+ (chng['range'].nil? ?
675
+ nil :
676
+ Solargraph::Range.from_to(chng['range']['start']['line'], chng['range']['start']['character'], chng['range']['end']['line'], chng['range']['end']['character'])
677
+ ),
678
+ chng['text']
679
+ )
680
+ end
681
+ Solargraph::Source::Updater.new(
682
+ uri_to_file(params['textDocument']['uri']),
683
+ params['textDocument']['version'],
684
+ changes
685
+ )
686
+ end
687
+
688
+ # @return [Hash]
689
+ def dynamic_capability_options
690
+ @dynamic_capability_options ||= {
691
+ # textDocumentSync: 2, # @todo What should this be?
692
+ 'textDocument/completion' => {
693
+ resolveProvider: true,
694
+ triggerCharacters: ['.', ':', '@']
695
+ },
696
+ # hoverProvider: true,
697
+ # definitionProvider: true,
698
+ 'textDocument/signatureHelp' => {
699
+ triggerCharacters: ['(', ',', ' ']
700
+ },
701
+ # documentFormattingProvider: true,
702
+ 'textDocument/onTypeFormatting' => {
703
+ firstTriggerCharacter: '{',
704
+ moreTriggerCharacter: ['(']
705
+ },
706
+ # documentSymbolProvider: true,
707
+ # workspaceSymbolProvider: true,
708
+ # workspace: {
709
+ # workspaceFolders: {
710
+ # supported: true,
711
+ # changeNotifications: true
712
+ # }
713
+ # }
714
+ 'textDocument/definition' => {
715
+ definitionProvider: true
716
+ },
717
+ 'textDocument/references' => {
718
+ referencesProvider: true
719
+ },
720
+ 'textDocument/rename' => {
721
+ renameProvider: prepare_rename? ? { prepareProvider: true } : true
722
+ },
723
+ 'textDocument/documentSymbol' => {
724
+ documentSymbolProvider: true
725
+ },
726
+ 'workspace/symbol' => {
727
+ workspaceSymbolProvider: true
728
+ },
729
+ 'textDocument/formatting' => {
730
+ formattingProvider: true
731
+ },
732
+ 'textDocument/foldingRange' => {
733
+ foldingRangeProvider: true
734
+ },
735
+ 'textDocument/codeAction' => {
736
+ codeActionProvider: true
737
+ }
738
+ }
739
+ end
740
+
741
+ def prepare_rename?
742
+ client_capabilities['rename'] && client_capabilities['rename']['prepareSupport']
743
+ end
744
+ end
745
+ end
746
+ end