solargraph 0.32.1 → 0.32.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +6 -0
  5. data/.travis.yml +25 -0
  6. data/EXAMPLES.md +76 -0
  7. data/Gemfile +3 -0
  8. data/LANGUAGE_SERVER.md +51 -0
  9. data/LICENSE +21 -0
  10. data/OVERVIEW.md +37 -0
  11. data/README.md +106 -0
  12. data/Rakefile +14 -0
  13. data/SERVER.md +95 -0
  14. data/bin/solargraph +0 -0
  15. data/bin/solargraph-runtime +5 -5
  16. data/lib/solargraph.rb +54 -54
  17. data/lib/solargraph/api_map.rb +659 -659
  18. data/lib/solargraph/api_map/cache.rb +49 -49
  19. data/lib/solargraph/api_map/source_to_yard.rb +67 -67
  20. data/lib/solargraph/api_map/store.rb +201 -201
  21. data/lib/solargraph/bundle.rb +24 -24
  22. data/lib/solargraph/complex_type.rb +150 -150
  23. data/lib/solargraph/complex_type/type_methods.rb +124 -124
  24. data/lib/solargraph/complex_type/unique_type.rb +44 -44
  25. data/lib/solargraph/core_fills.rb +37 -37
  26. data/lib/solargraph/diagnostics.rb +52 -52
  27. data/lib/solargraph/diagnostics/base.rb +20 -20
  28. data/lib/solargraph/diagnostics/require_not_found.rb +28 -28
  29. data/lib/solargraph/diagnostics/rubocop.rb +98 -98
  30. data/lib/solargraph/diagnostics/rubocop_helpers.rb +46 -46
  31. data/lib/solargraph/diagnostics/type_not_defined.rb +108 -108
  32. data/lib/solargraph/diagnostics/update_errors.rb +38 -38
  33. data/lib/solargraph/language_server/completion_item_kinds.rb +33 -33
  34. data/lib/solargraph/language_server/error_codes.rb +18 -18
  35. data/lib/solargraph/language_server/host.rb +684 -681
  36. data/lib/solargraph/language_server/host/cataloger.rb +54 -79
  37. data/lib/solargraph/language_server/host/diagnoser.rb +80 -80
  38. data/lib/solargraph/language_server/host/dispatch.rb +112 -113
  39. data/lib/solargraph/language_server/host/sources.rb +138 -138
  40. data/lib/solargraph/language_server/message.rb +90 -90
  41. data/lib/solargraph/language_server/message/base.rb +83 -83
  42. data/lib/solargraph/language_server/message/completion_item/resolve.rb +40 -40
  43. data/lib/solargraph/language_server/message/exit_notification.rb +11 -11
  44. data/lib/solargraph/language_server/message/extended.rb +19 -19
  45. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +86 -86
  46. data/lib/solargraph/language_server/message/extended/document.rb +18 -18
  47. data/lib/solargraph/language_server/message/extended/document_gems.rb +30 -30
  48. data/lib/solargraph/language_server/message/extended/environment.rb +20 -20
  49. data/lib/solargraph/language_server/message/extended/search.rb +18 -18
  50. data/lib/solargraph/language_server/message/initialize.rb +141 -141
  51. data/lib/solargraph/language_server/message/initialized.rb +23 -23
  52. data/lib/solargraph/language_server/message/shutdown.rb +11 -11
  53. data/lib/solargraph/language_server/message/text_document.rb +25 -25
  54. data/lib/solargraph/language_server/message/text_document/completion.rb +51 -51
  55. data/lib/solargraph/language_server/message/text_document/definition.rb +18 -18
  56. data/lib/solargraph/language_server/message/text_document/did_change.rb +13 -13
  57. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +21 -21
  58. data/lib/solargraph/language_server/message/text_document/folding_range.rb +24 -24
  59. data/lib/solargraph/language_server/message/text_document/formatting.rb +50 -50
  60. data/lib/solargraph/language_server/message/text_document/hover.rb +31 -31
  61. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +32 -32
  62. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +9 -9
  63. data/lib/solargraph/language_server/message/text_document/references.rb +14 -14
  64. data/lib/solargraph/language_server/message/text_document/rename.rb +17 -17
  65. data/lib/solargraph/language_server/message/text_document/signature_help.rb +19 -19
  66. data/lib/solargraph/language_server/message/workspace.rb +12 -12
  67. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +29 -29
  68. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +29 -27
  69. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -24
  70. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +21 -21
  71. data/lib/solargraph/language_server/request.rb +22 -22
  72. data/lib/solargraph/language_server/symbol_kinds.rb +34 -34
  73. data/lib/solargraph/language_server/transport.rb +11 -11
  74. data/lib/solargraph/language_server/transport/adapter.rb +60 -60
  75. data/lib/solargraph/language_server/transport/data_reader.rb +66 -66
  76. data/lib/solargraph/language_server/uri_helpers.rb +25 -25
  77. data/lib/solargraph/library.rb +421 -419
  78. data/lib/solargraph/live_map.rb +126 -126
  79. data/lib/solargraph/live_map/cache.rb +38 -38
  80. data/lib/solargraph/location.rb +31 -31
  81. data/lib/solargraph/logging.rb +25 -25
  82. data/lib/solargraph/page.rb +68 -68
  83. data/lib/solargraph/pin.rb +50 -50
  84. data/lib/solargraph/pin/attribute.rb +41 -41
  85. data/lib/solargraph/pin/base.rb +280 -280
  86. data/lib/solargraph/pin/base_method.rb +76 -76
  87. data/lib/solargraph/pin/base_variable.rb +72 -72
  88. data/lib/solargraph/pin/block.rb +32 -32
  89. data/lib/solargraph/pin/block_parameter.rb +103 -103
  90. data/lib/solargraph/pin/class_variable.rb +9 -9
  91. data/lib/solargraph/pin/constant.rb +30 -30
  92. data/lib/solargraph/pin/conversions.rb +79 -79
  93. data/lib/solargraph/pin/documenting.rb +41 -41
  94. data/lib/solargraph/pin/duck_method.rb +14 -14
  95. data/lib/solargraph/pin/global_variable.rb +9 -9
  96. data/lib/solargraph/pin/instance_variable.rb +9 -9
  97. data/lib/solargraph/pin/keyword.rb +17 -17
  98. data/lib/solargraph/pin/local_variable.rb +23 -23
  99. data/lib/solargraph/pin/localized.rb +22 -22
  100. data/lib/solargraph/pin/method.rb +126 -126
  101. data/lib/solargraph/pin/method_alias.rb +30 -30
  102. data/lib/solargraph/pin/method_parameter.rb +40 -40
  103. data/lib/solargraph/pin/namespace.rb +54 -54
  104. data/lib/solargraph/pin/plugin/method.rb +25 -25
  105. data/lib/solargraph/pin/proxy_type.rb +35 -35
  106. data/lib/solargraph/pin/reference.rb +22 -22
  107. data/lib/solargraph/pin/reference/extend.rb +11 -11
  108. data/lib/solargraph/pin/reference/include.rb +11 -11
  109. data/lib/solargraph/pin/reference/require.rb +15 -15
  110. data/lib/solargraph/pin/reference/superclass.rb +11 -11
  111. data/lib/solargraph/pin/symbol.rb +44 -44
  112. data/lib/solargraph/pin/yard_pin.rb +10 -10
  113. data/lib/solargraph/pin/yard_pin/constant.rb +14 -14
  114. data/lib/solargraph/pin/yard_pin/method.rb +35 -35
  115. data/lib/solargraph/pin/yard_pin/namespace.rb +19 -19
  116. data/lib/solargraph/pin/yard_pin/yard_mixin.rb +14 -14
  117. data/lib/solargraph/plugin.rb +8 -8
  118. data/lib/solargraph/plugin/base.rb +41 -41
  119. data/lib/solargraph/plugin/canceler.rb +11 -11
  120. data/lib/solargraph/plugin/process.rb +172 -172
  121. data/lib/solargraph/plugin/runtime.rb +134 -134
  122. data/lib/solargraph/position.rb +110 -110
  123. data/lib/solargraph/range.rb +83 -83
  124. data/lib/solargraph/server_methods.rb +14 -14
  125. data/lib/solargraph/shell.rb +102 -102
  126. data/lib/solargraph/source.rb +521 -521
  127. data/lib/solargraph/source/chain.rb +120 -120
  128. data/lib/solargraph/source/chain/call.rb +107 -107
  129. data/lib/solargraph/source/chain/class_variable.rb +11 -11
  130. data/lib/solargraph/source/chain/constant.rb +30 -30
  131. data/lib/solargraph/source/chain/global_variable.rb +11 -11
  132. data/lib/solargraph/source/chain/head.rb +33 -33
  133. data/lib/solargraph/source/chain/instance_variable.rb +11 -11
  134. data/lib/solargraph/source/chain/link.rb +33 -33
  135. data/lib/solargraph/source/chain/literal.rb +21 -21
  136. data/lib/solargraph/source/chain/variable.rb +11 -11
  137. data/lib/solargraph/source/change.rb +77 -77
  138. data/lib/solargraph/source/cursor.rb +157 -157
  139. data/lib/solargraph/source/node_chainer.rb +96 -96
  140. data/lib/solargraph/source/node_methods.rb +225 -225
  141. data/lib/solargraph/source/source_chainer.rb +183 -183
  142. data/lib/solargraph/source_map.rb +169 -169
  143. data/lib/solargraph/source_map/clip.rb +145 -145
  144. data/lib/solargraph/source_map/completion.rb +21 -21
  145. data/lib/solargraph/source_map/mapper.rb +149 -149
  146. data/lib/solargraph/source_map/node_processor.rb +78 -78
  147. data/lib/solargraph/source_map/node_processor/alias_node.rb +19 -19
  148. data/lib/solargraph/source_map/node_processor/args_node.rb +28 -28
  149. data/lib/solargraph/source_map/node_processor/base.rb +68 -68
  150. data/lib/solargraph/source_map/node_processor/begin_node.rb +11 -11
  151. data/lib/solargraph/source_map/node_processor/block_node.rb +14 -14
  152. data/lib/solargraph/source_map/node_processor/casgn_node.rb +14 -14
  153. data/lib/solargraph/source_map/node_processor/cvasgn_node.rb +14 -14
  154. data/lib/solargraph/source_map/node_processor/def_node.rb +54 -54
  155. data/lib/solargraph/source_map/node_processor/defs_node.rb +21 -21
  156. data/lib/solargraph/source_map/node_processor/gvasgn_node.rb +12 -12
  157. data/lib/solargraph/source_map/node_processor/ivasgn_node.rb +18 -18
  158. data/lib/solargraph/source_map/node_processor/lvasgn_node.rb +16 -16
  159. data/lib/solargraph/source_map/node_processor/namespace_node.rb +26 -26
  160. data/lib/solargraph/source_map/node_processor/orasgn_node.rb +12 -12
  161. data/lib/solargraph/source_map/node_processor/sclass_node.rb +11 -11
  162. data/lib/solargraph/source_map/node_processor/send_node.rb +162 -162
  163. data/lib/solargraph/source_map/node_processor/sym_node.rb +11 -11
  164. data/lib/solargraph/source_map/region.rb +58 -58
  165. data/lib/solargraph/version.rb +3 -3
  166. data/lib/solargraph/views/environment.erb +53 -53
  167. data/lib/solargraph/workspace.rb +183 -183
  168. data/lib/solargraph/workspace/config.rb +170 -170
  169. data/lib/solargraph/yard_map.rb +298 -298
  170. data/lib/solargraph/yard_map/cache.rb +17 -17
  171. data/lib/solargraph/yard_map/core_docs.rb +163 -163
  172. data/lib/solargraph/yard_map/core_gen.rb +76 -76
  173. data/lib/yard-coregen.rb +16 -16
  174. data/lib/yard-solargraph.rb +18 -18
  175. data/solargraph.gemspec +37 -0
  176. data/travis-bundler.rb +10 -0
  177. metadata +19 -6
@@ -1,170 +1,170 @@
1
- require 'yaml'
2
-
3
- module Solargraph
4
- class Workspace
5
- # Configuration data for a workspace.
6
- #
7
- class Config
8
- # The maximum number of files that can be added to a workspace.
9
- # The workspace's .solargraph.yml can override this value.
10
- MAX_FILES = 5000
11
-
12
- # @return [String]
13
- attr_reader :directory
14
-
15
- # @return [Hash]
16
- attr_reader :raw_data
17
-
18
- # @param directory [String]
19
- def initialize directory = ''
20
- @directory = directory
21
- include_globs = ['**/*.rb']
22
- exclude_globs = ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*']
23
- unless @directory.empty?
24
- sfile = File.join(@directory, '.solargraph.yml')
25
- if File.file?(sfile)
26
- @raw_data = YAML.safe_load(File.read(sfile))
27
- include_globs = @raw_data['include'] || include_globs
28
- exclude_globs = @raw_data['exclude'] || []
29
- end
30
- end
31
- @raw_data ||= {}
32
- @raw_data['include'] ||= include_globs
33
- @raw_data['exclude'] ||= exclude_globs
34
- @raw_data['require'] ||= []
35
- @raw_data['domains'] ||= []
36
- @raw_data['reporters'] ||= %w[rubocop require_not_found]
37
- @raw_data['plugins'] ||= []
38
- @raw_data['require_paths'] ||= []
39
- @raw_data['max_files'] ||= MAX_FILES
40
- included
41
- excluded
42
- end
43
-
44
- # An array of files included in the workspace (before calculating excluded files).
45
- #
46
- # @return [Array<String>]
47
- def included
48
- return [] if directory.empty? || directory == '*'
49
- @included ||= process_globs(@raw_data['include'])
50
- end
51
-
52
- # An array of files excluded from the workspace.
53
- #
54
- # @return [Array<String>]
55
- def excluded
56
- return [] if directory.empty? || directory == '*'
57
- @excluded ||= process_exclusions(@raw_data['exclude'])
58
- end
59
-
60
- # The calculated array of (included - excluded) files in the workspace.
61
- #
62
- # @return [Array<String>]
63
- def calculated
64
- Solargraph.logger.info "Indexing workspace files in #{directory}" unless @calculated || directory.empty? || directory == '*'
65
- @calculated ||= included - excluded
66
- end
67
-
68
- # An array of domains configured for the workspace.
69
- # A domain is a namespace that the ApiMap should include in the global
70
- # namespace. It's typically used to identify available DSLs.
71
- #
72
- # @return [Array<String>]
73
- def domains
74
- raw_data['domains']
75
- end
76
-
77
- # An array of required paths to add to the workspace.
78
- #
79
- # @return [Array<String>]
80
- def required
81
- raw_data['require']
82
- end
83
-
84
- # An array of load paths for required paths.
85
- #
86
- # @return [Array<String>]
87
- def require_paths
88
- raw_data['require_paths'] || []
89
- end
90
-
91
- # An array of Solargraph plugins to install.
92
- #
93
- # @return [Array<String>]
94
- def plugins
95
- raw_data['plugins']
96
- end
97
-
98
- # An array of reporters to use for diagnostics.
99
- #
100
- # @return [Array<String>]
101
- def reporters
102
- raw_data['reporters']
103
- end
104
-
105
- # The maximum number of files to parse from the workspace.
106
- #
107
- # @return [Integer]
108
- def max_files
109
- raw_data['max_files']
110
- end
111
-
112
- private
113
-
114
- # Get an array of files from the provided globs.
115
- #
116
- # @param globs [Array<String>]
117
- # @return [Array<String>]
118
- def process_globs globs
119
- result = []
120
- globs.each do |glob|
121
- result.concat Dir[File.join directory, glob].map{ |f| f.gsub(/\\/, '/') }
122
- end
123
- result
124
- end
125
-
126
- # Modify the included files based on excluded directories and get an
127
- # array of additional files to exclude.
128
- #
129
- # @param globs [Array<String>]
130
- # @return [Array<String>]
131
- def process_exclusions globs
132
- remainder = globs.select do |glob|
133
- if glob_is_directory?(glob)
134
- exdir = File.join(directory, glob_to_directory(glob))
135
- included.delete_if { |file| file.start_with?(exdir) }
136
- false
137
- else
138
- true
139
- end
140
- end
141
- process_globs remainder
142
- end
143
-
144
- # True if the glob translates to a whole directory.
145
- #
146
- # @example
147
- # glob_is_directory?('path/to/dir') # => true
148
- # glob_is_directory?('path/to/dir/**/*) # => true
149
- # glob_is_directory?('path/to/file.txt') # => false
150
- # glob_is_directory?('path/to/*.txt') # => false
151
- #
152
- # @param glob [String]
153
- # @return [Boolean]
154
- def glob_is_directory? glob
155
- File.directory?(glob) || File.directory?(glob_to_directory(glob))
156
- end
157
-
158
- # Translate a glob to a base directory if applicable
159
- #
160
- # @example
161
- # glob_to_directory('path/to/dir/**/*') # => 'path/to/dir'
162
- #
163
- # @param glob [String]
164
- # @return [String]
165
- def glob_to_directory glob
166
- glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
167
- end
168
- end
169
- end
170
- end
1
+ require 'yaml'
2
+
3
+ module Solargraph
4
+ class Workspace
5
+ # Configuration data for a workspace.
6
+ #
7
+ class Config
8
+ # The maximum number of files that can be added to a workspace.
9
+ # The workspace's .solargraph.yml can override this value.
10
+ MAX_FILES = 5000
11
+
12
+ # @return [String]
13
+ attr_reader :directory
14
+
15
+ # @return [Hash]
16
+ attr_reader :raw_data
17
+
18
+ # @param directory [String]
19
+ def initialize directory = ''
20
+ @directory = directory
21
+ include_globs = ['**/*.rb']
22
+ exclude_globs = ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*']
23
+ unless @directory.empty?
24
+ sfile = File.join(@directory, '.solargraph.yml')
25
+ if File.file?(sfile)
26
+ @raw_data = YAML.safe_load(File.read(sfile))
27
+ include_globs = @raw_data['include'] || include_globs
28
+ exclude_globs = @raw_data['exclude'] || []
29
+ end
30
+ end
31
+ @raw_data ||= {}
32
+ @raw_data['include'] ||= include_globs
33
+ @raw_data['exclude'] ||= exclude_globs
34
+ @raw_data['require'] ||= []
35
+ @raw_data['domains'] ||= []
36
+ @raw_data['reporters'] ||= %w[rubocop require_not_found]
37
+ @raw_data['plugins'] ||= []
38
+ @raw_data['require_paths'] ||= []
39
+ @raw_data['max_files'] ||= MAX_FILES
40
+ included
41
+ excluded
42
+ end
43
+
44
+ # An array of files included in the workspace (before calculating excluded files).
45
+ #
46
+ # @return [Array<String>]
47
+ def included
48
+ return [] if directory.empty? || directory == '*'
49
+ @included ||= process_globs(@raw_data['include'])
50
+ end
51
+
52
+ # An array of files excluded from the workspace.
53
+ #
54
+ # @return [Array<String>]
55
+ def excluded
56
+ return [] if directory.empty? || directory == '*'
57
+ @excluded ||= process_exclusions(@raw_data['exclude'])
58
+ end
59
+
60
+ # The calculated array of (included - excluded) files in the workspace.
61
+ #
62
+ # @return [Array<String>]
63
+ def calculated
64
+ Solargraph.logger.info "Indexing workspace files in #{directory}" unless @calculated || directory.empty? || directory == '*'
65
+ @calculated ||= included - excluded
66
+ end
67
+
68
+ # An array of domains configured for the workspace.
69
+ # A domain is a namespace that the ApiMap should include in the global
70
+ # namespace. It's typically used to identify available DSLs.
71
+ #
72
+ # @return [Array<String>]
73
+ def domains
74
+ raw_data['domains']
75
+ end
76
+
77
+ # An array of required paths to add to the workspace.
78
+ #
79
+ # @return [Array<String>]
80
+ def required
81
+ raw_data['require']
82
+ end
83
+
84
+ # An array of load paths for required paths.
85
+ #
86
+ # @return [Array<String>]
87
+ def require_paths
88
+ raw_data['require_paths'] || []
89
+ end
90
+
91
+ # An array of Solargraph plugins to install.
92
+ #
93
+ # @return [Array<String>]
94
+ def plugins
95
+ raw_data['plugins']
96
+ end
97
+
98
+ # An array of reporters to use for diagnostics.
99
+ #
100
+ # @return [Array<String>]
101
+ def reporters
102
+ raw_data['reporters']
103
+ end
104
+
105
+ # The maximum number of files to parse from the workspace.
106
+ #
107
+ # @return [Integer]
108
+ def max_files
109
+ raw_data['max_files']
110
+ end
111
+
112
+ private
113
+
114
+ # Get an array of files from the provided globs.
115
+ #
116
+ # @param globs [Array<String>]
117
+ # @return [Array<String>]
118
+ def process_globs globs
119
+ result = []
120
+ globs.each do |glob|
121
+ result.concat Dir[File.join directory, glob].map{ |f| f.gsub(/\\/, '/') }
122
+ end
123
+ result
124
+ end
125
+
126
+ # Modify the included files based on excluded directories and get an
127
+ # array of additional files to exclude.
128
+ #
129
+ # @param globs [Array<String>]
130
+ # @return [Array<String>]
131
+ def process_exclusions globs
132
+ remainder = globs.select do |glob|
133
+ if glob_is_directory?(glob)
134
+ exdir = File.join(directory, glob_to_directory(glob))
135
+ included.delete_if { |file| file.start_with?(exdir) }
136
+ false
137
+ else
138
+ true
139
+ end
140
+ end
141
+ process_globs remainder
142
+ end
143
+
144
+ # True if the glob translates to a whole directory.
145
+ #
146
+ # @example
147
+ # glob_is_directory?('path/to/dir') # => true
148
+ # glob_is_directory?('path/to/dir/**/*) # => true
149
+ # glob_is_directory?('path/to/file.txt') # => false
150
+ # glob_is_directory?('path/to/*.txt') # => false
151
+ #
152
+ # @param glob [String]
153
+ # @return [Boolean]
154
+ def glob_is_directory? glob
155
+ File.directory?(glob) || File.directory?(glob_to_directory(glob))
156
+ end
157
+
158
+ # Translate a glob to a base directory if applicable
159
+ #
160
+ # @example
161
+ # glob_to_directory('path/to/dir/**/*') # => 'path/to/dir'
162
+ #
163
+ # @param glob [String]
164
+ # @return [String]
165
+ def glob_to_directory glob
166
+ glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
167
+ end
168
+ end
169
+ end
170
+ end
@@ -1,298 +1,298 @@
1
- require 'yard'
2
-
3
- module Solargraph
4
- # The YardMap provides access to YARD documentation for the Ruby core, the
5
- # stdlib, and gems.
6
- #
7
- class YardMap
8
- autoload :Cache, 'solargraph/yard_map/cache'
9
- autoload :CoreDocs, 'solargraph/yard_map/core_docs'
10
- autoload :CoreGen, 'solargraph/yard_map/core_gen'
11
-
12
- CoreDocs.require_minimum
13
- @@stdlib_yardoc = CoreDocs.yardoc_stdlib_file
14
- @@stdlib_paths = {}
15
- YARD::Registry.load! @@stdlib_yardoc
16
- YARD::Registry.all(:class, :module).each do |ns|
17
- next if ns.file.nil?
18
- path = ns.file.sub(/^(ext|lib)\//, '').sub(/\.(rb|c)$/, '')
19
- next if path.start_with?('-')
20
- @@stdlib_paths[path] ||= []
21
- @@stdlib_paths[path].push ns
22
- end
23
-
24
- # @return [Array<String>]
25
- attr_reader :required
26
-
27
- attr_writer :with_dependencies
28
-
29
- # @param required [Array<String>]
30
- # @param with_dependencies [Boolean]
31
- def initialize(required: [], with_dependencies: true)
32
- # HACK: YardMap needs its own copy of this array
33
- @required = required.clone
34
- @with_dependencies = with_dependencies
35
- @gem_paths = {}
36
- @stdlib_namespaces = []
37
- process_requires
38
- yardocs.uniq!
39
- end
40
-
41
- # @return [Array<Solargraph::Pin::Base>]
42
- def pins
43
- @pins ||= []
44
- end
45
-
46
- def with_dependencies?
47
- @with_dependencies ||= true unless @with_dependencies == false
48
- @with_dependencies
49
- end
50
-
51
- # @param new_requires [Array<String>]
52
- # @return [Boolean]
53
- def change new_requires
54
- if new_requires.uniq.sort == required.uniq.sort
55
- false
56
- else
57
- required.clear
58
- required.concat new_requires
59
- process_requires
60
- true
61
- end
62
- end
63
-
64
- # @return [Array<String>]
65
- def yardocs
66
- @yardocs ||= []
67
- end
68
-
69
- # @return [Array<String>]
70
- def unresolved_requires
71
- @unresolved_requires ||= []
72
- end
73
-
74
- # @param y [String]
75
- # @return [YARD::Registry]
76
- def load_yardoc y
77
- if y.kind_of?(Array)
78
- YARD::Registry.load y, true
79
- else
80
- YARD::Registry.load! y
81
- end
82
- rescue Exception => e
83
- Solargraph::Logging.logger.warn "Error loading yardoc '#{y}' #{e.class} #{e.message}"
84
- yardocs.delete y
85
- nil
86
- end
87
-
88
- # @return [Array<Solargraph::Pin::Base>]
89
- def core_pins
90
- @@core_pins ||= begin
91
- result = []
92
- load_yardoc CoreDocs.yardoc_file
93
- YARD::Registry.each do |o|
94
- result.concat generate_pins(o)
95
- end
96
- result
97
- end
98
- end
99
-
100
- # @param path [String]
101
- # @return [Pin::Base]
102
- def path_pin path
103
- pins.select{ |p| p.path == path }.first
104
- end
105
-
106
- private
107
-
108
- # @return [YardMap::Cache]
109
- def cache
110
- @cache ||= YardMap::Cache.new
111
- end
112
-
113
- # @param ns [YARD::CodeObjects::Namespace]
114
- # @return [Array<Solargraph::Pin::Base>]
115
- def recurse_namespace_object ns
116
- result = []
117
- ns.children.each do |c|
118
- result.concat generate_pins(c)
119
- result.concat recurse_namespace_object(c) if c.respond_to?(:children)
120
- end
121
- result
122
- end
123
-
124
- # @param code_object [YARD::CodeObjects::Base]
125
- # @return [Solargraph::Pin::Base]
126
- def generate_pins code_object, spec = nil
127
- result = []
128
- location = object_location(code_object, spec)
129
- if code_object.is_a?(YARD::CodeObjects::NamespaceObject)
130
- result.push Solargraph::Pin::YardPin::Namespace.new(code_object, location)
131
- if code_object.is_a?(YARD::CodeObjects::ClassObject) and !code_object.superclass.nil?
132
- # @todo This method of superclass detection is a bit of a hack. If
133
- # the superclass is a Proxy, it is assumed to be undefined in its
134
- # yardoc and converted to a fully qualified namespace.
135
- if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
136
- superclass = "::#{code_object.superclass}"
137
- else
138
- superclass = code_object.superclass.to_s
139
- end
140
- result.push Solargraph::Pin::Reference::Superclass.new(location, code_object.path, superclass)
141
- end
142
- code_object.class_mixins.each do |m|
143
- result.push Solargraph::Pin::Reference::Extend.new(location, code_object.path, m.path)
144
- end
145
- code_object.instance_mixins.each do |m|
146
- result.push Solargraph::Pin::Reference::Include.new(location, code_object.path, m.path)
147
- end
148
- elsif code_object.is_a?(YARD::CodeObjects::MethodObject)
149
- if code_object.name == :initialize && code_object.scope == :instance
150
- # @todo Check the visibility of <Class>.new
151
- result.push Solargraph::Pin::YardPin::Method.new(code_object, location, 'new', :class, :public)
152
- result.push Solargraph::Pin::YardPin::Method.new(code_object, location, 'initialize', :instance, :private)
153
- else
154
- result.push Solargraph::Pin::YardPin::Method.new(code_object, location)
155
- end
156
- elsif code_object.is_a?(YARD::CodeObjects::ConstantObject)
157
- result.push Solargraph::Pin::YardPin::Constant.new(code_object, location)
158
- end
159
- result
160
- end
161
-
162
- # @return [void]
163
- def process_requires
164
- pins.clear
165
- unresolved_requires.clear
166
- stdnames = {}
167
- done = []
168
- required.each do |r|
169
- next if r.nil? || r.empty? || done.include?(r)
170
- done.push r
171
- cached = cache.get_path_pins(r)
172
- unless cached.nil?
173
- pins.concat cached
174
- next
175
- end
176
- result = []
177
- begin
178
- spec = Gem::Specification.find_by_path(r) || Gem::Specification.find_by_name(r.split('/').first)
179
- ver = spec.version.to_s
180
- ver = ">= 0" if ver.empty?
181
- yd = YARD::Registry.yardoc_file_for_gem(spec.name, ver)
182
- # YARD detects gems for certain libraries that do not have a yardoc
183
- # but exist in the stdlib. `fileutils` is an example. Treat those
184
- # cases as errors and check the stdlib yardoc.
185
- raise Gem::LoadError if yd.nil?
186
- @gem_paths[spec.name] = spec.full_gem_path
187
- unless yardocs.include?(yd)
188
- yardocs.unshift yd
189
- result.concat process_yardoc yd, spec
190
- result.concat add_gem_dependencies(spec) if with_dependencies?
191
- end
192
- rescue Gem::LoadError => e
193
- stdtmp = []
194
- @@stdlib_paths.each_pair do |path, objects|
195
- stdtmp.concat objects if path == r || path.start_with?("#{r}/")
196
- end
197
- if stdtmp.empty?
198
- unresolved_requires.push r
199
- else
200
- stdnames[r] = stdtmp
201
- end
202
- end
203
- result.delete_if(&:nil?)
204
- unless result.empty?
205
- cache.set_path_pins r, result
206
- pins.concat result
207
- end
208
- end
209
- pins.concat process_stdlib(stdnames)
210
- pins.concat core_pins
211
- end
212
-
213
- # @param required_namespaces [Array<YARD::CodeObjects::Namespace>]
214
- # @return [Array<Solargraph::Pin::Base>]
215
- def process_stdlib required_namespaces
216
- pins = []
217
- unless required_namespaces.empty?
218
- yard = load_yardoc @@stdlib_yardoc
219
- done = []
220
- required_namespaces.each_pair do |r, objects|
221
- result = []
222
- objects.each do |ns|
223
- next if done.include?(ns.path)
224
- done.push ns.path
225
- result.concat generate_pins(ns)
226
- result.concat recurse_namespace_object(ns)
227
- end
228
- result.delete_if(&:nil?)
229
- cache.set_path_pins(r, result) unless result.empty?
230
- pins.concat result
231
- end
232
- end
233
- pins
234
- end
235
-
236
- # @param spec [Gem::Specification]
237
- # @return [void]
238
- def add_gem_dependencies spec
239
- result = []
240
- (spec.dependencies - spec.development_dependencies).each do |dep|
241
- begin
242
- depspec = Gem::Specification.find_by_name(dep.name)
243
- next if depspec.nil? || @gem_paths.key?(depspec.name)
244
- @gem_paths[depspec.name] = depspec.full_gem_path
245
- gy = YARD::Registry.yardoc_file_for_gem(dep.name)
246
- if gy.nil?
247
- unresolved_requires.push dep.name
248
- else
249
- next if yardocs.include?(gy)
250
- yardocs.unshift gy
251
- result.concat process_yardoc gy, depspec
252
- result.concat add_gem_dependencies(depspec)
253
- end
254
- rescue Gem::LoadError
255
- # This error probably indicates a bug in an installed gem
256
- Solargraph::Logging.logger.warn "Failed to resolve #{dep.name} gem dependency for #{spec.name}"
257
- end
258
- end
259
- result
260
- end
261
-
262
- # @param y [String, nil]
263
- # @return [Array<Pin::Base>]
264
- def process_yardoc y, spec = nil
265
- return [] if y.nil?
266
- size = Dir.glob(File.join(y, '**', '*'))
267
- .map{ |f| File.size(f) }
268
- .inject(:+)
269
- if !size.nil? && size > 20_000_000
270
- Solargraph::Logging.logger.warn "Yardoc at #{y} is too large to process (#{size} bytes)"
271
- return []
272
- end
273
- result = []
274
- load_yardoc y
275
- YARD::Registry.each do |o|
276
- result.concat generate_pins(o, spec)
277
- end
278
- result
279
- end
280
-
281
- # @param obj [YARD::CodeObjects::Base]
282
- # @return [Solargraph::Location]
283
- def object_location obj, spec = nil
284
- @object_file_cache ||= {}
285
- return nil if spec.nil? || obj.file.nil? || obj.line.nil?
286
- file = nil
287
- if @object_file_cache.key?(obj.file)
288
- file = @object_file_cache[obj.file]
289
- else
290
- tmp = File.join(spec.full_gem_path, obj.file)
291
- file = tmp if File.exist?(tmp)
292
- @object_file_cache[obj.file] = file
293
- end
294
- return nil if file.nil?
295
- Solargraph::Location.new(file, Solargraph::Range.from_to(obj.line - 1, 0, obj.line - 1, 0))
296
- end
297
- end
298
- end
1
+ require 'yard'
2
+
3
+ module Solargraph
4
+ # The YardMap provides access to YARD documentation for the Ruby core, the
5
+ # stdlib, and gems.
6
+ #
7
+ class YardMap
8
+ autoload :Cache, 'solargraph/yard_map/cache'
9
+ autoload :CoreDocs, 'solargraph/yard_map/core_docs'
10
+ autoload :CoreGen, 'solargraph/yard_map/core_gen'
11
+
12
+ CoreDocs.require_minimum
13
+ @@stdlib_yardoc = CoreDocs.yardoc_stdlib_file
14
+ @@stdlib_paths = {}
15
+ YARD::Registry.load! @@stdlib_yardoc
16
+ YARD::Registry.all(:class, :module).each do |ns|
17
+ next if ns.file.nil?
18
+ path = ns.file.sub(/^(ext|lib)\//, '').sub(/\.(rb|c)$/, '')
19
+ next if path.start_with?('-')
20
+ @@stdlib_paths[path] ||= []
21
+ @@stdlib_paths[path].push ns
22
+ end
23
+
24
+ # @return [Array<String>]
25
+ attr_reader :required
26
+
27
+ attr_writer :with_dependencies
28
+
29
+ # @param required [Array<String>]
30
+ # @param with_dependencies [Boolean]
31
+ def initialize(required: [], with_dependencies: true)
32
+ # HACK: YardMap needs its own copy of this array
33
+ @required = required.clone
34
+ @with_dependencies = with_dependencies
35
+ @gem_paths = {}
36
+ @stdlib_namespaces = []
37
+ process_requires
38
+ yardocs.uniq!
39
+ end
40
+
41
+ # @return [Array<Solargraph::Pin::Base>]
42
+ def pins
43
+ @pins ||= []
44
+ end
45
+
46
+ def with_dependencies?
47
+ @with_dependencies ||= true unless @with_dependencies == false
48
+ @with_dependencies
49
+ end
50
+
51
+ # @param new_requires [Array<String>]
52
+ # @return [Boolean]
53
+ def change new_requires
54
+ if new_requires.uniq.sort == required.uniq.sort
55
+ false
56
+ else
57
+ required.clear
58
+ required.concat new_requires
59
+ process_requires
60
+ true
61
+ end
62
+ end
63
+
64
+ # @return [Array<String>]
65
+ def yardocs
66
+ @yardocs ||= []
67
+ end
68
+
69
+ # @return [Array<String>]
70
+ def unresolved_requires
71
+ @unresolved_requires ||= []
72
+ end
73
+
74
+ # @param y [String]
75
+ # @return [YARD::Registry]
76
+ def load_yardoc y
77
+ if y.kind_of?(Array)
78
+ YARD::Registry.load y, true
79
+ else
80
+ YARD::Registry.load! y
81
+ end
82
+ rescue Exception => e
83
+ Solargraph::Logging.logger.warn "Error loading yardoc '#{y}' #{e.class} #{e.message}"
84
+ yardocs.delete y
85
+ nil
86
+ end
87
+
88
+ # @return [Array<Solargraph::Pin::Base>]
89
+ def core_pins
90
+ @@core_pins ||= begin
91
+ result = []
92
+ load_yardoc CoreDocs.yardoc_file
93
+ YARD::Registry.each do |o|
94
+ result.concat generate_pins(o)
95
+ end
96
+ result
97
+ end
98
+ end
99
+
100
+ # @param path [String]
101
+ # @return [Pin::Base]
102
+ def path_pin path
103
+ pins.select{ |p| p.path == path }.first
104
+ end
105
+
106
+ private
107
+
108
+ # @return [YardMap::Cache]
109
+ def cache
110
+ @cache ||= YardMap::Cache.new
111
+ end
112
+
113
+ # @param ns [YARD::CodeObjects::Namespace]
114
+ # @return [Array<Solargraph::Pin::Base>]
115
+ def recurse_namespace_object ns
116
+ result = []
117
+ ns.children.each do |c|
118
+ result.concat generate_pins(c)
119
+ result.concat recurse_namespace_object(c) if c.respond_to?(:children)
120
+ end
121
+ result
122
+ end
123
+
124
+ # @param code_object [YARD::CodeObjects::Base]
125
+ # @return [Solargraph::Pin::Base]
126
+ def generate_pins code_object, spec = nil
127
+ result = []
128
+ location = object_location(code_object, spec)
129
+ if code_object.is_a?(YARD::CodeObjects::NamespaceObject)
130
+ result.push Solargraph::Pin::YardPin::Namespace.new(code_object, location)
131
+ if code_object.is_a?(YARD::CodeObjects::ClassObject) and !code_object.superclass.nil?
132
+ # @todo This method of superclass detection is a bit of a hack. If
133
+ # the superclass is a Proxy, it is assumed to be undefined in its
134
+ # yardoc and converted to a fully qualified namespace.
135
+ if code_object.superclass.is_a?(YARD::CodeObjects::Proxy)
136
+ superclass = "::#{code_object.superclass}"
137
+ else
138
+ superclass = code_object.superclass.to_s
139
+ end
140
+ result.push Solargraph::Pin::Reference::Superclass.new(location, code_object.path, superclass)
141
+ end
142
+ code_object.class_mixins.each do |m|
143
+ result.push Solargraph::Pin::Reference::Extend.new(location, code_object.path, m.path)
144
+ end
145
+ code_object.instance_mixins.each do |m|
146
+ result.push Solargraph::Pin::Reference::Include.new(location, code_object.path, m.path)
147
+ end
148
+ elsif code_object.is_a?(YARD::CodeObjects::MethodObject)
149
+ if code_object.name == :initialize && code_object.scope == :instance
150
+ # @todo Check the visibility of <Class>.new
151
+ result.push Solargraph::Pin::YardPin::Method.new(code_object, location, 'new', :class, :public)
152
+ result.push Solargraph::Pin::YardPin::Method.new(code_object, location, 'initialize', :instance, :private)
153
+ else
154
+ result.push Solargraph::Pin::YardPin::Method.new(code_object, location)
155
+ end
156
+ elsif code_object.is_a?(YARD::CodeObjects::ConstantObject)
157
+ result.push Solargraph::Pin::YardPin::Constant.new(code_object, location)
158
+ end
159
+ result
160
+ end
161
+
162
+ # @return [void]
163
+ def process_requires
164
+ pins.clear
165
+ unresolved_requires.clear
166
+ stdnames = {}
167
+ done = []
168
+ required.each do |r|
169
+ next if r.nil? || r.empty? || done.include?(r)
170
+ done.push r
171
+ cached = cache.get_path_pins(r)
172
+ unless cached.nil?
173
+ pins.concat cached
174
+ next
175
+ end
176
+ result = []
177
+ begin
178
+ spec = Gem::Specification.find_by_path(r) || Gem::Specification.find_by_name(r.split('/').first)
179
+ ver = spec.version.to_s
180
+ ver = ">= 0" if ver.empty?
181
+ yd = YARD::Registry.yardoc_file_for_gem(spec.name, ver)
182
+ # YARD detects gems for certain libraries that do not have a yardoc
183
+ # but exist in the stdlib. `fileutils` is an example. Treat those
184
+ # cases as errors and check the stdlib yardoc.
185
+ raise Gem::LoadError if yd.nil?
186
+ @gem_paths[spec.name] = spec.full_gem_path
187
+ unless yardocs.include?(yd)
188
+ yardocs.unshift yd
189
+ result.concat process_yardoc yd, spec
190
+ result.concat add_gem_dependencies(spec) if with_dependencies?
191
+ end
192
+ rescue Gem::LoadError => e
193
+ stdtmp = []
194
+ @@stdlib_paths.each_pair do |path, objects|
195
+ stdtmp.concat objects if path == r || path.start_with?("#{r}/")
196
+ end
197
+ if stdtmp.empty?
198
+ unresolved_requires.push r
199
+ else
200
+ stdnames[r] = stdtmp
201
+ end
202
+ end
203
+ result.delete_if(&:nil?)
204
+ unless result.empty?
205
+ cache.set_path_pins r, result
206
+ pins.concat result
207
+ end
208
+ end
209
+ pins.concat process_stdlib(stdnames)
210
+ pins.concat core_pins
211
+ end
212
+
213
+ # @param required_namespaces [Array<YARD::CodeObjects::Namespace>]
214
+ # @return [Array<Solargraph::Pin::Base>]
215
+ def process_stdlib required_namespaces
216
+ pins = []
217
+ unless required_namespaces.empty?
218
+ yard = load_yardoc @@stdlib_yardoc
219
+ done = []
220
+ required_namespaces.each_pair do |r, objects|
221
+ result = []
222
+ objects.each do |ns|
223
+ next if done.include?(ns.path)
224
+ done.push ns.path
225
+ result.concat generate_pins(ns)
226
+ result.concat recurse_namespace_object(ns)
227
+ end
228
+ result.delete_if(&:nil?)
229
+ cache.set_path_pins(r, result) unless result.empty?
230
+ pins.concat result
231
+ end
232
+ end
233
+ pins
234
+ end
235
+
236
+ # @param spec [Gem::Specification]
237
+ # @return [void]
238
+ def add_gem_dependencies spec
239
+ result = []
240
+ (spec.dependencies - spec.development_dependencies).each do |dep|
241
+ begin
242
+ depspec = Gem::Specification.find_by_name(dep.name)
243
+ next if depspec.nil? || @gem_paths.key?(depspec.name)
244
+ @gem_paths[depspec.name] = depspec.full_gem_path
245
+ gy = YARD::Registry.yardoc_file_for_gem(dep.name)
246
+ if gy.nil?
247
+ unresolved_requires.push dep.name
248
+ else
249
+ next if yardocs.include?(gy)
250
+ yardocs.unshift gy
251
+ result.concat process_yardoc gy, depspec
252
+ result.concat add_gem_dependencies(depspec)
253
+ end
254
+ rescue Gem::LoadError
255
+ # This error probably indicates a bug in an installed gem
256
+ Solargraph::Logging.logger.warn "Failed to resolve #{dep.name} gem dependency for #{spec.name}"
257
+ end
258
+ end
259
+ result
260
+ end
261
+
262
+ # @param y [String, nil]
263
+ # @return [Array<Pin::Base>]
264
+ def process_yardoc y, spec = nil
265
+ return [] if y.nil?
266
+ size = Dir.glob(File.join(y, '**', '*'))
267
+ .map{ |f| File.size(f) }
268
+ .inject(:+)
269
+ if !size.nil? && size > 20_000_000
270
+ Solargraph::Logging.logger.warn "Yardoc at #{y} is too large to process (#{size} bytes)"
271
+ return []
272
+ end
273
+ result = []
274
+ load_yardoc y
275
+ YARD::Registry.each do |o|
276
+ result.concat generate_pins(o, spec)
277
+ end
278
+ result
279
+ end
280
+
281
+ # @param obj [YARD::CodeObjects::Base]
282
+ # @return [Solargraph::Location]
283
+ def object_location obj, spec = nil
284
+ @object_file_cache ||= {}
285
+ return nil if spec.nil? || obj.file.nil? || obj.line.nil?
286
+ file = nil
287
+ if @object_file_cache.key?(obj.file)
288
+ file = @object_file_cache[obj.file]
289
+ else
290
+ tmp = File.join(spec.full_gem_path, obj.file)
291
+ file = tmp if File.exist?(tmp)
292
+ @object_file_cache[obj.file] = file
293
+ end
294
+ return nil if file.nil?
295
+ Solargraph::Location.new(file, Solargraph::Range.from_to(obj.line - 1, 0, obj.line - 1, 0))
296
+ end
297
+ end
298
+ end