solargraph 0.58.1 → 0.58.3

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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/plugins.yml +3 -2
  3. data/.gitignore +1 -0
  4. data/CHANGELOG.md +10 -1
  5. data/lib/solargraph/api_map/cache.rb +110 -110
  6. data/lib/solargraph/api_map/constants.rb +279 -279
  7. data/lib/solargraph/api_map/index.rb +193 -193
  8. data/lib/solargraph/api_map/source_to_yard.rb +97 -97
  9. data/lib/solargraph/api_map/store.rb +384 -384
  10. data/lib/solargraph/api_map.rb +945 -945
  11. data/lib/solargraph/bench.rb +45 -45
  12. data/lib/solargraph/complex_type/type_methods.rb +228 -228
  13. data/lib/solargraph/complex_type/unique_type.rb +482 -482
  14. data/lib/solargraph/complex_type.rb +444 -444
  15. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
  16. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -91
  17. data/lib/solargraph/convention/data_definition.rb +105 -105
  18. data/lib/solargraph/convention/gemfile.rb +15 -15
  19. data/lib/solargraph/convention/gemspec.rb +23 -23
  20. data/lib/solargraph/convention/rakefile.rb +17 -17
  21. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -61
  22. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -102
  23. data/lib/solargraph/convention/struct_definition.rb +164 -164
  24. data/lib/solargraph/convention.rb +78 -78
  25. data/lib/solargraph/converters/dd.rb +17 -17
  26. data/lib/solargraph/converters/dl.rb +15 -15
  27. data/lib/solargraph/converters/dt.rb +15 -15
  28. data/lib/solargraph/converters/misc.rb +1 -1
  29. data/lib/solargraph/diagnostics/require_not_found.rb +53 -53
  30. data/lib/solargraph/diagnostics/rubocop.rb +118 -118
  31. data/lib/solargraph/diagnostics/rubocop_helpers.rb +68 -68
  32. data/lib/solargraph/diagnostics/type_check.rb +55 -55
  33. data/lib/solargraph/diagnostics/update_errors.rb +41 -41
  34. data/lib/solargraph/doc_map.rb +439 -439
  35. data/lib/solargraph/equality.rb +34 -34
  36. data/lib/solargraph/gem_pins.rb +98 -98
  37. data/lib/solargraph/language_server/error_codes.rb +20 -20
  38. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  39. data/lib/solargraph/language_server/host/dispatch.rb +130 -130
  40. data/lib/solargraph/language_server/host/message_worker.rb +112 -112
  41. data/lib/solargraph/language_server/host/sources.rb +99 -99
  42. data/lib/solargraph/language_server/host.rb +878 -878
  43. data/lib/solargraph/language_server/message/base.rb +97 -97
  44. data/lib/solargraph/language_server/message/client/register_capability.rb +15 -15
  45. data/lib/solargraph/language_server/message/completion_item/resolve.rb +60 -60
  46. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +114 -114
  47. data/lib/solargraph/language_server/message/extended/document.rb +23 -23
  48. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  49. data/lib/solargraph/language_server/message/extended/download_core.rb +19 -19
  50. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  51. data/lib/solargraph/language_server/message/initialize.rb +191 -191
  52. data/lib/solargraph/language_server/message/text_document/completion.rb +56 -56
  53. data/lib/solargraph/language_server/message/text_document/definition.rb +40 -40
  54. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +16 -16
  55. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +26 -26
  56. data/lib/solargraph/language_server/message/text_document/formatting.rb +148 -148
  57. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  58. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +11 -11
  59. data/lib/solargraph/language_server/message/text_document/references.rb +16 -16
  60. data/lib/solargraph/language_server/message/text_document/rename.rb +19 -19
  61. data/lib/solargraph/language_server/message/text_document/signature_help.rb +24 -24
  62. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -25
  63. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +35 -35
  64. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +40 -40
  65. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +26 -26
  66. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -23
  67. data/lib/solargraph/language_server/message.rb +94 -94
  68. data/lib/solargraph/language_server/request.rb +27 -27
  69. data/lib/solargraph/language_server/transport/data_reader.rb +74 -74
  70. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  71. data/lib/solargraph/library.rb +683 -683
  72. data/lib/solargraph/location.rb +82 -82
  73. data/lib/solargraph/logging.rb +37 -37
  74. data/lib/solargraph/page.rb +92 -92
  75. data/lib/solargraph/parser/comment_ripper.rb +69 -69
  76. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -255
  77. data/lib/solargraph/parser/node_processor/base.rb +92 -92
  78. data/lib/solargraph/parser/node_processor.rb +62 -62
  79. data/lib/solargraph/parser/parser_gem/class_methods.rb +149 -149
  80. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
  81. data/lib/solargraph/parser/parser_gem/node_chainer.rb +166 -166
  82. data/lib/solargraph/parser/parser_gem/node_methods.rb +486 -486
  83. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  84. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +59 -59
  85. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +15 -15
  86. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
  87. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +53 -53
  88. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +37 -37
  89. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -23
  90. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +40 -40
  91. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +29 -29
  92. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +59 -59
  93. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  94. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  95. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +38 -38
  96. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +52 -52
  97. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +291 -291
  98. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
  99. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -29
  100. data/lib/solargraph/parser/parser_gem/node_processors.rb +70 -70
  101. data/lib/solargraph/parser/parser_gem.rb +12 -12
  102. data/lib/solargraph/parser/region.rb +69 -69
  103. data/lib/solargraph/parser/snippet.rb +17 -17
  104. data/lib/solargraph/parser.rb +23 -23
  105. data/lib/solargraph/pin/base.rb +729 -729
  106. data/lib/solargraph/pin/base_variable.rb +126 -126
  107. data/lib/solargraph/pin/block.rb +104 -104
  108. data/lib/solargraph/pin/breakable.rb +9 -9
  109. data/lib/solargraph/pin/callable.rb +231 -231
  110. data/lib/solargraph/pin/closure.rb +72 -72
  111. data/lib/solargraph/pin/common.rb +79 -79
  112. data/lib/solargraph/pin/constant.rb +45 -45
  113. data/lib/solargraph/pin/conversions.rb +123 -123
  114. data/lib/solargraph/pin/delegated_method.rb +120 -120
  115. data/lib/solargraph/pin/documenting.rb +114 -114
  116. data/lib/solargraph/pin/instance_variable.rb +34 -34
  117. data/lib/solargraph/pin/keyword.rb +20 -20
  118. data/lib/solargraph/pin/local_variable.rb +75 -75
  119. data/lib/solargraph/pin/method.rb +672 -672
  120. data/lib/solargraph/pin/method_alias.rb +34 -34
  121. data/lib/solargraph/pin/namespace.rb +115 -115
  122. data/lib/solargraph/pin/parameter.rb +275 -275
  123. data/lib/solargraph/pin/proxy_type.rb +39 -39
  124. data/lib/solargraph/pin/reference/override.rb +47 -47
  125. data/lib/solargraph/pin/reference/superclass.rb +15 -15
  126. data/lib/solargraph/pin/reference.rb +39 -39
  127. data/lib/solargraph/pin/search.rb +61 -61
  128. data/lib/solargraph/pin/signature.rb +61 -61
  129. data/lib/solargraph/pin/symbol.rb +53 -53
  130. data/lib/solargraph/pin/until.rb +18 -18
  131. data/lib/solargraph/pin/while.rb +18 -18
  132. data/lib/solargraph/pin.rb +44 -44
  133. data/lib/solargraph/pin_cache.rb +245 -245
  134. data/lib/solargraph/position.rb +132 -119
  135. data/lib/solargraph/range.rb +112 -112
  136. data/lib/solargraph/rbs_map/conversions.rb +823 -823
  137. data/lib/solargraph/rbs_map/core_fills.rb +84 -84
  138. data/lib/solargraph/rbs_map/core_map.rb +58 -58
  139. data/lib/solargraph/rbs_map/stdlib_map.rb +43 -43
  140. data/lib/solargraph/rbs_map.rb +163 -163
  141. data/lib/solargraph/server_methods.rb +16 -16
  142. data/lib/solargraph/shell.rb +363 -352
  143. data/lib/solargraph/source/chain/array.rb +37 -37
  144. data/lib/solargraph/source/chain/call.rb +337 -337
  145. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  146. data/lib/solargraph/source/chain/constant.rb +26 -26
  147. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  148. data/lib/solargraph/source/chain/hash.rb +34 -34
  149. data/lib/solargraph/source/chain/if.rb +28 -28
  150. data/lib/solargraph/source/chain/instance_variable.rb +13 -13
  151. data/lib/solargraph/source/chain/link.rb +109 -109
  152. data/lib/solargraph/source/chain/literal.rb +48 -48
  153. data/lib/solargraph/source/chain/or.rb +23 -23
  154. data/lib/solargraph/source/chain/q_call.rb +11 -11
  155. data/lib/solargraph/source/chain/variable.rb +13 -13
  156. data/lib/solargraph/source/chain/z_super.rb +30 -30
  157. data/lib/solargraph/source/chain.rb +291 -291
  158. data/lib/solargraph/source/change.rb +82 -82
  159. data/lib/solargraph/source/cursor.rb +166 -166
  160. data/lib/solargraph/source/source_chainer.rb +194 -194
  161. data/lib/solargraph/source/updater.rb +55 -55
  162. data/lib/solargraph/source.rb +498 -498
  163. data/lib/solargraph/source_map/clip.rb +226 -226
  164. data/lib/solargraph/source_map/data.rb +34 -34
  165. data/lib/solargraph/source_map/mapper.rb +259 -259
  166. data/lib/solargraph/source_map.rb +212 -212
  167. data/lib/solargraph/type_checker/checks.rb +124 -124
  168. data/lib/solargraph/type_checker/param_def.rb +37 -37
  169. data/lib/solargraph/type_checker/problem.rb +32 -32
  170. data/lib/solargraph/type_checker/rules.rb +84 -84
  171. data/lib/solargraph/type_checker.rb +814 -814
  172. data/lib/solargraph/version.rb +1 -1
  173. data/lib/solargraph/workspace/config.rb +255 -255
  174. data/lib/solargraph/workspace/require_paths.rb +97 -97
  175. data/lib/solargraph/workspace.rb +220 -220
  176. data/lib/solargraph/yard_map/helpers.rb +44 -44
  177. data/lib/solargraph/yard_map/mapper/to_method.rb +130 -130
  178. data/lib/solargraph/yard_map/mapper/to_namespace.rb +31 -31
  179. data/lib/solargraph/yard_map/mapper.rb +79 -79
  180. data/lib/solargraph/yard_map/to_method.rb +89 -89
  181. data/lib/solargraph/yard_tags.rb +20 -20
  182. data/lib/solargraph/yardoc.rb +87 -87
  183. data/lib/solargraph.rb +105 -105
  184. data/rbs_collection.yaml +1 -1
  185. metadata +12 -12
  186. /data/{sig → rbs}/shims/ast/0/node.rbs +0 -0
  187. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  188. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  189. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  190. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  191. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  192. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  193. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  194. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  195. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,97 +1,97 @@
1
- # frozen_string_literal: true
2
-
3
- require 'open3'
4
-
5
- module Solargraph
6
- # A workspace consists of the files in a project's directory and the
7
- # project's configuration. It provides a Source for each file to be used
8
- # in an associated Library or ApiMap.
9
- #
10
- class Workspace
11
- # Manages determining which gemspecs are available in a workspace
12
- class RequirePaths
13
- attr_reader :directory, :config
14
-
15
- # @param directory [String, nil]
16
- # @param config [Config, nil]
17
- def initialize directory, config
18
- @directory = directory
19
- @config = config
20
- end
21
-
22
- # Generate require paths from gemspecs if they exist or assume the default
23
- # lib directory.
24
- #
25
- # @return [Array<String>]
26
- def generate
27
- result = require_paths_from_gemspec_files
28
- return configured_require_paths if result.empty?
29
- result.concat(config.require_paths.map { |p| File.join(directory, p) }) if config
30
- result
31
- end
32
-
33
- private
34
-
35
- # @return [Array<String>]
36
- def require_paths_from_gemspec_files
37
- results = []
38
- gemspec_file_paths.each do |gemspec_file_path|
39
- results.concat require_path_from_gemspec_file(gemspec_file_path)
40
- end
41
- results
42
- end
43
-
44
- # Get an array of all gemspec files in the workspace.
45
- #
46
- # @return [Array<String>]
47
- def gemspec_file_paths
48
- return [] if directory.nil?
49
- @gemspec_file_paths ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
50
- config.nil? || config.allow?(gs)
51
- end
52
- end
53
-
54
- # Get additional require paths defined in the configuration.
55
- #
56
- # @return [Array<String>]
57
- def configured_require_paths
58
- return ['lib'] unless directory
59
- return [File.join(directory, 'lib')] if !config || config.require_paths.empty?
60
- config.require_paths.map { |p| File.join(directory, p) }
61
- end
62
-
63
- # Generate require paths from gemspecs if they exist or assume the default
64
- # lib directory.
65
- #
66
- # @param gemspec_file_path [String]
67
- # @return [Array<String>]
68
- def require_path_from_gemspec_file gemspec_file_path
69
- base = File.dirname(gemspec_file_path)
70
- # HACK: Evaluating gemspec files violates the goal of not running
71
- # workspace code, but this is how Gem::Specification.load does it
72
- # anyway.
73
- cmd = ['ruby', '-e',
74
- "require 'rubygems'; " \
75
- "require 'json'; " \
76
- "spec = eval(File.read('#{gemspec_file_path}'), TOPLEVEL_BINDING, '#{gemspec_file_path}'); " \
77
- 'return unless Gem::Specification === spec; ' \
78
- 'puts({name: spec.name, paths: spec.require_paths}.to_json)']
79
- o, e, s = Open3.capture3(*cmd)
80
- if s.success?
81
- begin
82
- hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
83
- return [] if hash.empty?
84
- hash['paths'].map { |path| File.join(base, path) }
85
- rescue StandardError => e
86
- Solargraph.logger.warn "Error reading #{gemspec_file_path}: [#{e.class}] #{e.message}"
87
- []
88
- end
89
- else
90
- Solargraph.logger.warn "Error reading #{gemspec_file_path}"
91
- Solargraph.logger.warn e
92
- []
93
- end
94
- end
95
- end
96
- end
97
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ module Solargraph
6
+ # A workspace consists of the files in a project's directory and the
7
+ # project's configuration. It provides a Source for each file to be used
8
+ # in an associated Library or ApiMap.
9
+ #
10
+ class Workspace
11
+ # Manages determining which gemspecs are available in a workspace
12
+ class RequirePaths
13
+ attr_reader :directory, :config
14
+
15
+ # @param directory [String, nil]
16
+ # @param config [Config, nil]
17
+ def initialize directory, config
18
+ @directory = directory
19
+ @config = config
20
+ end
21
+
22
+ # Generate require paths from gemspecs if they exist or assume the default
23
+ # lib directory.
24
+ #
25
+ # @return [Array<String>]
26
+ def generate
27
+ result = require_paths_from_gemspec_files
28
+ return configured_require_paths if result.empty?
29
+ result.concat(config.require_paths.map { |p| File.join(directory, p) }) if config
30
+ result
31
+ end
32
+
33
+ private
34
+
35
+ # @return [Array<String>]
36
+ def require_paths_from_gemspec_files
37
+ results = []
38
+ gemspec_file_paths.each do |gemspec_file_path|
39
+ results.concat require_path_from_gemspec_file(gemspec_file_path)
40
+ end
41
+ results
42
+ end
43
+
44
+ # Get an array of all gemspec files in the workspace.
45
+ #
46
+ # @return [Array<String>]
47
+ def gemspec_file_paths
48
+ return [] if directory.nil?
49
+ @gemspec_file_paths ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
50
+ config.nil? || config.allow?(gs)
51
+ end
52
+ end
53
+
54
+ # Get additional require paths defined in the configuration.
55
+ #
56
+ # @return [Array<String>]
57
+ def configured_require_paths
58
+ return ['lib'] unless directory
59
+ return [File.join(directory, 'lib')] if !config || config.require_paths.empty?
60
+ config.require_paths.map { |p| File.join(directory, p) }
61
+ end
62
+
63
+ # Generate require paths from gemspecs if they exist or assume the default
64
+ # lib directory.
65
+ #
66
+ # @param gemspec_file_path [String]
67
+ # @return [Array<String>]
68
+ def require_path_from_gemspec_file gemspec_file_path
69
+ base = File.dirname(gemspec_file_path)
70
+ # HACK: Evaluating gemspec files violates the goal of not running
71
+ # workspace code, but this is how Gem::Specification.load does it
72
+ # anyway.
73
+ cmd = ['ruby', '-e',
74
+ "require 'rubygems'; " \
75
+ "require 'json'; " \
76
+ "spec = eval(File.read('#{gemspec_file_path}'), TOPLEVEL_BINDING, '#{gemspec_file_path}'); " \
77
+ 'return unless Gem::Specification === spec; ' \
78
+ 'puts({name: spec.name, paths: spec.require_paths}.to_json)']
79
+ o, e, s = Open3.capture3(*cmd)
80
+ if s.success?
81
+ begin
82
+ hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
83
+ return [] if hash.empty?
84
+ hash['paths'].map { |path| File.join(base, path) }
85
+ rescue StandardError => e
86
+ Solargraph.logger.warn "Error reading #{gemspec_file_path}: [#{e.class}] #{e.message}"
87
+ []
88
+ end
89
+ else
90
+ Solargraph.logger.warn "Error reading #{gemspec_file_path}"
91
+ Solargraph.logger.warn e
92
+ []
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -1,220 +1,220 @@
1
- # frozen_string_literal: true
2
-
3
- require 'open3'
4
- require 'json'
5
-
6
- module Solargraph
7
- # A workspace consists of the files in a project's directory and the
8
- # project's configuration. It provides a Source for each file to be used
9
- # in an associated Library or ApiMap.
10
- #
11
- class Workspace
12
- autoload :Config, 'solargraph/workspace/config'
13
- autoload :RequirePaths, 'solargraph/workspace/require_paths'
14
-
15
- # @return [String]
16
- attr_reader :directory
17
-
18
- # @return [Array<String>]
19
- attr_reader :gemnames
20
- alias source_gems gemnames
21
-
22
- # @param directory [String] TODO: Remove '' and '*' special cases
23
- # @param config [Config, nil]
24
- # @param server [Hash]
25
- def initialize directory = '', config = nil, server = {}
26
- raise ArgumentError, 'directory must be a String' unless directory.is_a?(String)
27
-
28
- @directory = if ['*', ''].include?(directory)
29
- directory
30
- else
31
- File.absolute_path(directory)
32
- end
33
- @config = config
34
- @server = server
35
- load_sources
36
- @gemnames = []
37
- require_plugins
38
- end
39
-
40
- # The require paths associated with the workspace.
41
- #
42
- # @return [Array<String>]
43
- def require_paths
44
- # @todo are the semantics of '*' the same as '', meaning 'don't send back any require paths'?
45
- @require_paths ||= RequirePaths.new(directory_or_nil, config).generate
46
- end
47
-
48
- # @return [Solargraph::Workspace::Config]
49
- def config
50
- @config ||= Solargraph::Workspace::Config.new(directory)
51
- end
52
-
53
- # @param level [Symbol]
54
- # @return [TypeChecker::Rules]
55
- def rules(level)
56
- @rules ||= TypeChecker::Rules.new(level, config.type_checker_rules)
57
- end
58
-
59
- # Merge the source. A merge will update the existing source for the file
60
- # or add it to the sources if the workspace is configured to include it.
61
- # The source is ignored if the configuration excludes it.
62
- #
63
- # @param sources [Array<Solargraph::Source>]
64
- # @return [Boolean] True if the source was added to the workspace
65
- def merge *sources
66
- unless directory == '*' || sources.all? { |source| source_hash.key?(source.filename) }
67
- # Reload the config to determine if a new source should be included
68
- @config = Solargraph::Workspace::Config.new(directory)
69
- end
70
-
71
- includes_any = false
72
- sources.each do |source|
73
- if directory == "*" || config.calculated.include?(source.filename)
74
- source_hash[source.filename] = source
75
- includes_any = true
76
- end
77
- end
78
-
79
- includes_any
80
- end
81
-
82
- # Remove a source from the workspace. The source will not be removed if
83
- # its file exists and the workspace is configured to include it.
84
- #
85
- # @param filename [String]
86
- # @return [Boolean] True if the source was removed from the workspace
87
- def remove filename
88
- return false unless source_hash.key?(filename)
89
- source_hash.delete filename
90
- true
91
- end
92
-
93
- # @return [Array<String>]
94
- def filenames
95
- source_hash.keys
96
- end
97
-
98
- # @return [Array<Solargraph::Source>]
99
- def sources
100
- source_hash.values
101
- end
102
-
103
- # @param filename [String]
104
- # @return [Boolean]
105
- def has_file? filename
106
- source_hash.key?(filename)
107
- end
108
-
109
- # Get a source by its filename.
110
- #
111
- # @param filename [String]
112
- # @return [Solargraph::Source]
113
- def source filename
114
- source_hash[filename]
115
- end
116
-
117
- # True if the path resolves to a file in the workspace's require paths.
118
- #
119
- # @param path [String]
120
- # @return [Boolean]
121
- def would_require? path
122
- require_paths.each do |rp|
123
- full = File.join rp, path
124
- return true if File.file?(full) || File.file?(full << ".rb")
125
- end
126
- false
127
- end
128
-
129
- # @return [String, nil]
130
- def rbs_collection_path
131
- @gem_rbs_collection ||= read_rbs_collection_path
132
- end
133
-
134
- # @return [String, nil]
135
- def rbs_collection_config_path
136
- @rbs_collection_config_path ||= begin
137
- unless directory.empty? || directory == '*'
138
- yaml_file = File.join(directory, 'rbs_collection.yaml')
139
- yaml_file if File.file?(yaml_file)
140
- end
141
- end
142
- end
143
-
144
- # Synchronize the workspace from the provided updater.
145
- #
146
- # @param updater [Source::Updater]
147
- # @return [void]
148
- def synchronize! updater
149
- source_hash[updater.filename] = source_hash[updater.filename].synchronize(updater)
150
- end
151
-
152
- # @return [String]
153
- def command_path
154
- server['commandPath'] || 'solargraph'
155
- end
156
-
157
- # @return [String, nil]
158
- def directory_or_nil
159
- return nil if directory.empty? || directory == '*'
160
- directory
161
- end
162
-
163
- # True if the workspace has a root Gemfile.
164
- #
165
- # @todo Handle projects with custom Bundler/Gemfile setups (see DocMap#gemspecs_required_from_bundler)
166
- #
167
- def gemfile?
168
- directory && File.file?(File.join(directory, 'Gemfile'))
169
- end
170
-
171
- private
172
-
173
- # The language server configuration (or an empty hash if the workspace was
174
- # not initialized from a server).
175
- #
176
- # @return [Hash]
177
- attr_reader :server
178
-
179
- # @return [Hash{String => Solargraph::Source}]
180
- def source_hash
181
- @source_hash ||= {}
182
- end
183
-
184
- # @return [void]
185
- def load_sources
186
- source_hash.clear
187
- unless directory.empty? || directory == '*'
188
- size = config.calculated.length
189
- raise WorkspaceTooLargeError, "The workspace is too large to index (#{size} files, #{config.max_files} max)" if config.max_files > 0 and size > config.max_files
190
- config.calculated.each do |filename|
191
- begin
192
- source_hash[filename] = Solargraph::Source.load(filename)
193
- rescue Errno::ENOENT => e
194
- Solargraph.logger.warn("Error loading #{filename}: [#{e.class}] #{e.message}")
195
- end
196
- end
197
- end
198
- end
199
-
200
- # @return [void]
201
- def require_plugins
202
- config.plugins.each do |plugin|
203
- begin
204
- require plugin
205
- rescue LoadError
206
- Solargraph.logger.warn "Failed to load plugin '#{plugin}'"
207
- end
208
- end
209
- end
210
-
211
- # @return [String, nil]
212
- def read_rbs_collection_path
213
- return unless rbs_collection_config_path
214
-
215
- path = YAML.load_file(rbs_collection_config_path)&.fetch('path')
216
- # make fully qualified
217
- File.expand_path(path, directory)
218
- end
219
- end
220
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'json'
5
+
6
+ module Solargraph
7
+ # A workspace consists of the files in a project's directory and the
8
+ # project's configuration. It provides a Source for each file to be used
9
+ # in an associated Library or ApiMap.
10
+ #
11
+ class Workspace
12
+ autoload :Config, 'solargraph/workspace/config'
13
+ autoload :RequirePaths, 'solargraph/workspace/require_paths'
14
+
15
+ # @return [String]
16
+ attr_reader :directory
17
+
18
+ # @return [Array<String>]
19
+ attr_reader :gemnames
20
+ alias source_gems gemnames
21
+
22
+ # @param directory [String] TODO: Remove '' and '*' special cases
23
+ # @param config [Config, nil]
24
+ # @param server [Hash]
25
+ def initialize directory = '', config = nil, server = {}
26
+ raise ArgumentError, 'directory must be a String' unless directory.is_a?(String)
27
+
28
+ @directory = if ['*', ''].include?(directory)
29
+ directory
30
+ else
31
+ File.absolute_path(directory)
32
+ end
33
+ @config = config
34
+ @server = server
35
+ load_sources
36
+ @gemnames = []
37
+ require_plugins
38
+ end
39
+
40
+ # The require paths associated with the workspace.
41
+ #
42
+ # @return [Array<String>]
43
+ def require_paths
44
+ # @todo are the semantics of '*' the same as '', meaning 'don't send back any require paths'?
45
+ @require_paths ||= RequirePaths.new(directory_or_nil, config).generate
46
+ end
47
+
48
+ # @return [Solargraph::Workspace::Config]
49
+ def config
50
+ @config ||= Solargraph::Workspace::Config.new(directory)
51
+ end
52
+
53
+ # @param level [Symbol]
54
+ # @return [TypeChecker::Rules]
55
+ def rules(level)
56
+ @rules ||= TypeChecker::Rules.new(level, config.type_checker_rules)
57
+ end
58
+
59
+ # Merge the source. A merge will update the existing source for the file
60
+ # or add it to the sources if the workspace is configured to include it.
61
+ # The source is ignored if the configuration excludes it.
62
+ #
63
+ # @param sources [Array<Solargraph::Source>]
64
+ # @return [Boolean] True if the source was added to the workspace
65
+ def merge *sources
66
+ unless directory == '*' || sources.all? { |source| source_hash.key?(source.filename) }
67
+ # Reload the config to determine if a new source should be included
68
+ @config = Solargraph::Workspace::Config.new(directory)
69
+ end
70
+
71
+ includes_any = false
72
+ sources.each do |source|
73
+ if directory == "*" || config.calculated.include?(source.filename)
74
+ source_hash[source.filename] = source
75
+ includes_any = true
76
+ end
77
+ end
78
+
79
+ includes_any
80
+ end
81
+
82
+ # Remove a source from the workspace. The source will not be removed if
83
+ # its file exists and the workspace is configured to include it.
84
+ #
85
+ # @param filename [String]
86
+ # @return [Boolean] True if the source was removed from the workspace
87
+ def remove filename
88
+ return false unless source_hash.key?(filename)
89
+ source_hash.delete filename
90
+ true
91
+ end
92
+
93
+ # @return [Array<String>]
94
+ def filenames
95
+ source_hash.keys
96
+ end
97
+
98
+ # @return [Array<Solargraph::Source>]
99
+ def sources
100
+ source_hash.values
101
+ end
102
+
103
+ # @param filename [String]
104
+ # @return [Boolean]
105
+ def has_file? filename
106
+ source_hash.key?(filename)
107
+ end
108
+
109
+ # Get a source by its filename.
110
+ #
111
+ # @param filename [String]
112
+ # @return [Solargraph::Source]
113
+ def source filename
114
+ source_hash[filename]
115
+ end
116
+
117
+ # True if the path resolves to a file in the workspace's require paths.
118
+ #
119
+ # @param path [String]
120
+ # @return [Boolean]
121
+ def would_require? path
122
+ require_paths.each do |rp|
123
+ full = File.join rp, path
124
+ return true if File.file?(full) || File.file?(full << ".rb")
125
+ end
126
+ false
127
+ end
128
+
129
+ # @return [String, nil]
130
+ def rbs_collection_path
131
+ @gem_rbs_collection ||= read_rbs_collection_path
132
+ end
133
+
134
+ # @return [String, nil]
135
+ def rbs_collection_config_path
136
+ @rbs_collection_config_path ||= begin
137
+ unless directory.empty? || directory == '*'
138
+ yaml_file = File.join(directory, 'rbs_collection.yaml')
139
+ yaml_file if File.file?(yaml_file)
140
+ end
141
+ end
142
+ end
143
+
144
+ # Synchronize the workspace from the provided updater.
145
+ #
146
+ # @param updater [Source::Updater]
147
+ # @return [void]
148
+ def synchronize! updater
149
+ source_hash[updater.filename] = source_hash[updater.filename].synchronize(updater)
150
+ end
151
+
152
+ # @return [String]
153
+ def command_path
154
+ server['commandPath'] || 'solargraph'
155
+ end
156
+
157
+ # @return [String, nil]
158
+ def directory_or_nil
159
+ return nil if directory.empty? || directory == '*'
160
+ directory
161
+ end
162
+
163
+ # True if the workspace has a root Gemfile.
164
+ #
165
+ # @todo Handle projects with custom Bundler/Gemfile setups (see DocMap#gemspecs_required_from_bundler)
166
+ #
167
+ def gemfile?
168
+ directory && File.file?(File.join(directory, 'Gemfile'))
169
+ end
170
+
171
+ private
172
+
173
+ # The language server configuration (or an empty hash if the workspace was
174
+ # not initialized from a server).
175
+ #
176
+ # @return [Hash]
177
+ attr_reader :server
178
+
179
+ # @return [Hash{String => Solargraph::Source}]
180
+ def source_hash
181
+ @source_hash ||= {}
182
+ end
183
+
184
+ # @return [void]
185
+ def load_sources
186
+ source_hash.clear
187
+ unless directory.empty? || directory == '*'
188
+ size = config.calculated.length
189
+ raise WorkspaceTooLargeError, "The workspace is too large to index (#{size} files, #{config.max_files} max)" if config.max_files > 0 and size > config.max_files
190
+ config.calculated.each do |filename|
191
+ begin
192
+ source_hash[filename] = Solargraph::Source.load(filename)
193
+ rescue Errno::ENOENT => e
194
+ Solargraph.logger.warn("Error loading #{filename}: [#{e.class}] #{e.message}")
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ # @return [void]
201
+ def require_plugins
202
+ config.plugins.each do |plugin|
203
+ begin
204
+ require plugin
205
+ rescue LoadError
206
+ Solargraph.logger.warn "Failed to load plugin '#{plugin}'"
207
+ end
208
+ end
209
+ end
210
+
211
+ # @return [String, nil]
212
+ def read_rbs_collection_path
213
+ return unless rbs_collection_config_path
214
+
215
+ path = YAML.load_file(rbs_collection_config_path)&.fetch('path')
216
+ # make fully qualified
217
+ File.expand_path(path, directory)
218
+ end
219
+ end
220
+ end