steep-activesupport-4 1.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.gitmodules +0 -0
  4. data/CHANGELOG.md +1032 -0
  5. data/LICENSE +21 -0
  6. data/README.md +260 -0
  7. data/Rakefile +227 -0
  8. data/Steepfile +68 -0
  9. data/bin/console +14 -0
  10. data/bin/generate-diagnostics-docs.rb +112 -0
  11. data/bin/mem_graph.rb +67 -0
  12. data/bin/mem_prof.rb +102 -0
  13. data/bin/output_rebaseline.rb +34 -0
  14. data/bin/output_test.rb +60 -0
  15. data/bin/rbs +20 -0
  16. data/bin/rbs-inline +19 -0
  17. data/bin/setup +9 -0
  18. data/bin/stackprof_test.rb +19 -0
  19. data/bin/steep +19 -0
  20. data/bin/steep-check.rb +251 -0
  21. data/bin/steep-prof +16 -0
  22. data/doc/narrowing.md +195 -0
  23. data/doc/shape.md +194 -0
  24. data/exe/steep +18 -0
  25. data/guides/README.md +5 -0
  26. data/guides/src/gem-rbs-collection/gem-rbs-collection.md +126 -0
  27. data/guides/src/getting-started/getting-started.md +163 -0
  28. data/guides/src/nil-optional/nil-optional.md +195 -0
  29. data/lib/steep/annotation_parser.rb +199 -0
  30. data/lib/steep/ast/annotation/collection.rb +172 -0
  31. data/lib/steep/ast/annotation.rb +137 -0
  32. data/lib/steep/ast/builtin.rb +104 -0
  33. data/lib/steep/ast/ignore.rb +148 -0
  34. data/lib/steep/ast/node/type_application.rb +88 -0
  35. data/lib/steep/ast/node/type_assertion.rb +81 -0
  36. data/lib/steep/ast/types/any.rb +35 -0
  37. data/lib/steep/ast/types/boolean.rb +45 -0
  38. data/lib/steep/ast/types/bot.rb +35 -0
  39. data/lib/steep/ast/types/class.rb +43 -0
  40. data/lib/steep/ast/types/factory.rb +557 -0
  41. data/lib/steep/ast/types/helper.rb +40 -0
  42. data/lib/steep/ast/types/instance.rb +42 -0
  43. data/lib/steep/ast/types/intersection.rb +93 -0
  44. data/lib/steep/ast/types/literal.rb +59 -0
  45. data/lib/steep/ast/types/logic.rb +84 -0
  46. data/lib/steep/ast/types/name.rb +128 -0
  47. data/lib/steep/ast/types/nil.rb +41 -0
  48. data/lib/steep/ast/types/proc.rb +117 -0
  49. data/lib/steep/ast/types/record.rb +79 -0
  50. data/lib/steep/ast/types/self.rb +43 -0
  51. data/lib/steep/ast/types/shared_instance.rb +11 -0
  52. data/lib/steep/ast/types/top.rb +35 -0
  53. data/lib/steep/ast/types/tuple.rb +60 -0
  54. data/lib/steep/ast/types/union.rb +97 -0
  55. data/lib/steep/ast/types/var.rb +65 -0
  56. data/lib/steep/ast/types/void.rb +35 -0
  57. data/lib/steep/cli.rb +401 -0
  58. data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
  59. data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
  60. data/lib/steep/diagnostic/helper.rb +18 -0
  61. data/lib/steep/diagnostic/lsp_formatter.rb +78 -0
  62. data/lib/steep/diagnostic/result_printer2.rb +48 -0
  63. data/lib/steep/diagnostic/ruby.rb +1221 -0
  64. data/lib/steep/diagnostic/signature.rb +570 -0
  65. data/lib/steep/drivers/annotations.rb +52 -0
  66. data/lib/steep/drivers/check.rb +339 -0
  67. data/lib/steep/drivers/checkfile.rb +210 -0
  68. data/lib/steep/drivers/diagnostic_printer.rb +105 -0
  69. data/lib/steep/drivers/init.rb +66 -0
  70. data/lib/steep/drivers/langserver.rb +56 -0
  71. data/lib/steep/drivers/print_project.rb +113 -0
  72. data/lib/steep/drivers/stats.rb +203 -0
  73. data/lib/steep/drivers/utils/driver_helper.rb +143 -0
  74. data/lib/steep/drivers/utils/jobs_option.rb +26 -0
  75. data/lib/steep/drivers/vendor.rb +27 -0
  76. data/lib/steep/drivers/watch.rb +194 -0
  77. data/lib/steep/drivers/worker.rb +58 -0
  78. data/lib/steep/equatable.rb +23 -0
  79. data/lib/steep/expectations.rb +228 -0
  80. data/lib/steep/index/rbs_index.rb +350 -0
  81. data/lib/steep/index/signature_symbol_provider.rb +185 -0
  82. data/lib/steep/index/source_index.rb +167 -0
  83. data/lib/steep/interface/block.rb +103 -0
  84. data/lib/steep/interface/builder.rb +843 -0
  85. data/lib/steep/interface/function.rb +1090 -0
  86. data/lib/steep/interface/method_type.rb +330 -0
  87. data/lib/steep/interface/shape.rb +239 -0
  88. data/lib/steep/interface/substitution.rb +159 -0
  89. data/lib/steep/interface/type_param.rb +115 -0
  90. data/lib/steep/located_value.rb +20 -0
  91. data/lib/steep/method_name.rb +42 -0
  92. data/lib/steep/module_helper.rb +24 -0
  93. data/lib/steep/node_helper.rb +273 -0
  94. data/lib/steep/path_helper.rb +30 -0
  95. data/lib/steep/project/dsl.rb +268 -0
  96. data/lib/steep/project/group.rb +31 -0
  97. data/lib/steep/project/options.rb +63 -0
  98. data/lib/steep/project/pattern.rb +59 -0
  99. data/lib/steep/project/target.rb +92 -0
  100. data/lib/steep/project.rb +78 -0
  101. data/lib/steep/rake_task.rb +132 -0
  102. data/lib/steep/range_extension.rb +29 -0
  103. data/lib/steep/server/base_worker.rb +97 -0
  104. data/lib/steep/server/change_buffer.rb +73 -0
  105. data/lib/steep/server/custom_methods.rb +77 -0
  106. data/lib/steep/server/delay_queue.rb +45 -0
  107. data/lib/steep/server/interaction_worker.rb +492 -0
  108. data/lib/steep/server/lsp_formatter.rb +455 -0
  109. data/lib/steep/server/master.rb +912 -0
  110. data/lib/steep/server/target_group_files.rb +205 -0
  111. data/lib/steep/server/type_check_controller.rb +366 -0
  112. data/lib/steep/server/type_check_worker.rb +303 -0
  113. data/lib/steep/server/work_done_progress.rb +64 -0
  114. data/lib/steep/server/worker_process.rb +176 -0
  115. data/lib/steep/services/completion_provider.rb +802 -0
  116. data/lib/steep/services/content_change.rb +61 -0
  117. data/lib/steep/services/file_loader.rb +74 -0
  118. data/lib/steep/services/goto_service.rb +441 -0
  119. data/lib/steep/services/hover_provider/rbs.rb +88 -0
  120. data/lib/steep/services/hover_provider/ruby.rb +221 -0
  121. data/lib/steep/services/hover_provider/singleton_methods.rb +20 -0
  122. data/lib/steep/services/path_assignment.rb +46 -0
  123. data/lib/steep/services/signature_help_provider.rb +202 -0
  124. data/lib/steep/services/signature_service.rb +428 -0
  125. data/lib/steep/services/stats_calculator.rb +68 -0
  126. data/lib/steep/services/type_check_service.rb +394 -0
  127. data/lib/steep/services/type_name_completion.rb +236 -0
  128. data/lib/steep/signature/validator.rb +651 -0
  129. data/lib/steep/source/ignore_ranges.rb +69 -0
  130. data/lib/steep/source.rb +691 -0
  131. data/lib/steep/subtyping/cache.rb +30 -0
  132. data/lib/steep/subtyping/check.rb +1113 -0
  133. data/lib/steep/subtyping/constraints.rb +341 -0
  134. data/lib/steep/subtyping/relation.rb +101 -0
  135. data/lib/steep/subtyping/result.rb +324 -0
  136. data/lib/steep/subtyping/variable_variance.rb +89 -0
  137. data/lib/steep/test.rb +9 -0
  138. data/lib/steep/thread_waiter.rb +43 -0
  139. data/lib/steep/type_construction.rb +5183 -0
  140. data/lib/steep/type_inference/block_params.rb +416 -0
  141. data/lib/steep/type_inference/case_when.rb +303 -0
  142. data/lib/steep/type_inference/constant_env.rb +56 -0
  143. data/lib/steep/type_inference/context.rb +195 -0
  144. data/lib/steep/type_inference/logic_type_interpreter.rb +613 -0
  145. data/lib/steep/type_inference/method_call.rb +193 -0
  146. data/lib/steep/type_inference/method_params.rb +531 -0
  147. data/lib/steep/type_inference/multiple_assignment.rb +194 -0
  148. data/lib/steep/type_inference/send_args.rb +712 -0
  149. data/lib/steep/type_inference/type_env.rb +341 -0
  150. data/lib/steep/type_inference/type_env_builder.rb +138 -0
  151. data/lib/steep/typing.rb +321 -0
  152. data/lib/steep/version.rb +3 -0
  153. data/lib/steep.rb +369 -0
  154. data/manual/annotations.md +181 -0
  155. data/manual/ignore.md +20 -0
  156. data/manual/ruby-diagnostics.md +1879 -0
  157. data/sample/Steepfile +22 -0
  158. data/sample/lib/conference.rb +49 -0
  159. data/sample/lib/length.rb +35 -0
  160. data/sample/sig/conference.rbs +42 -0
  161. data/sample/sig/generics.rbs +15 -0
  162. data/sample/sig/length.rbs +34 -0
  163. data/steep-activesupport-4.gemspec +55 -0
  164. metadata +437 -0
@@ -0,0 +1,492 @@
1
+ module Steep
2
+ module Server
3
+ class InteractionWorker < BaseWorker
4
+ include ChangeBuffer
5
+
6
+ HoverJob = _ = Struct.new(:id, :path, :line, :column, keyword_init: true)
7
+ CompletionJob = _ = Struct.new(:id, :path, :line, :column, :trigger, keyword_init: true)
8
+ SignatureHelpJob = _ = Struct.new(:id, :path, :line, :column, keyword_init: true)
9
+
10
+ LSP = LanguageServer::Protocol
11
+
12
+ attr_reader :service, :mutex
13
+
14
+ def initialize(project:, reader:, writer:, queue: Queue.new)
15
+ super(project: project, reader: reader, writer: writer)
16
+ @queue = queue
17
+ @mutex = Mutex.new
18
+ @service = Services::TypeCheckService.new(project: project)
19
+ @buffered_changes = {}
20
+ @last_job_mutex = Mutex.new
21
+ end
22
+
23
+ def handle_job(job)
24
+ Steep.logger.tagged "#handle_job" do
25
+ changes = pop_buffer()
26
+
27
+ unless changes.empty?
28
+ Steep.logger.debug { "Applying changes for #{changes.size} files..." }
29
+ service.update(changes: changes)
30
+ end
31
+
32
+ case job
33
+ when HoverJob
34
+ writer.write(
35
+ {
36
+ id: job.id,
37
+ result: process_latest_job(job) { process_hover(job) }
38
+ }
39
+ )
40
+ when CompletionJob
41
+ writer.write(
42
+ {
43
+ id: job.id,
44
+ result: process_latest_job(job) { process_completion(job) }
45
+ }
46
+ )
47
+ when SignatureHelpJob
48
+ writer.write(
49
+ {
50
+ id: job.id,
51
+ result: process_latest_job(job) { process_signature_help(job) }
52
+ }
53
+ )
54
+ end
55
+ end
56
+ end
57
+
58
+ def process_latest_job(job)
59
+ @last_job_mutex.synchronize do
60
+ unless job.equal?(@last_job)
61
+ Steep.logger.debug { "Skipping interaction job: latest_job=#{@last_job.class}, skipped_job#{job.class}" }
62
+ return
63
+ end
64
+ @last_job = nil
65
+ end
66
+
67
+ yield
68
+ end
69
+
70
+ def queue_job(job)
71
+ @last_job_mutex.synchronize do
72
+ @last_job = job
73
+ end
74
+ queue << job
75
+ end
76
+
77
+ def handle_request(request)
78
+ case request[:method]
79
+ when "initialize"
80
+ writer.write({ id: request[:id], result: nil })
81
+
82
+ when "textDocument/didChange"
83
+ collect_changes(request)
84
+
85
+ when CustomMethods::FileLoad::METHOD
86
+ params = request[:params] #: CustomMethods::FileLoad::params
87
+ input = params[:content]
88
+ load_files(input)
89
+
90
+ when CustomMethods::FileReset::METHOD
91
+ params = request[:params] #: CustomMethods::FileReset::params
92
+ uri = params[:uri]
93
+ text = params[:content]
94
+ reset_change(uri: uri, text: text)
95
+
96
+ when "textDocument/hover"
97
+ id = request[:id]
98
+
99
+ path = project.relative_path(PathHelper.to_pathname!(request[:params][:textDocument][:uri]))
100
+ line = request[:params][:position][:line]+1
101
+ column = request[:params][:position][:character]
102
+
103
+ queue_job HoverJob.new(id: id, path: path, line: line, column: column)
104
+
105
+ when "textDocument/completion"
106
+ id = request[:id]
107
+
108
+ params = request[:params]
109
+
110
+ path = project.relative_path(PathHelper.to_pathname!(params[:textDocument][:uri]))
111
+ line, column = params[:position].yield_self {|hash| [hash[:line]+1, hash[:character]] }
112
+ trigger = params.dig(:context, :triggerCharacter)
113
+
114
+ queue_job CompletionJob.new(id: id, path: path, line: line, column: column, trigger: trigger)
115
+ when "textDocument/signatureHelp"
116
+ id = request[:id]
117
+ params = request[:params]
118
+ path = project.relative_path(PathHelper.to_pathname!(params[:textDocument][:uri]))
119
+ line, column = params[:position].yield_self {|hash| [hash[:line]+1, hash[:character]] }
120
+
121
+ queue_job SignatureHelpJob.new(id: id, path: path, line: line, column: column)
122
+ end
123
+ end
124
+
125
+ def process_hover(job)
126
+ Steep.logger.tagged "#process_hover" do
127
+ Steep.measure "Generating hover response" do
128
+ Steep.logger.info { "path=#{job.path}, line=#{job.line}, column=#{job.column}" }
129
+
130
+ content = Services::HoverProvider.content_for(service: service, path: job.path, line: job.line, column: job.column)
131
+ if content
132
+ range = content.location.yield_self do |location|
133
+ lsp_range = location.as_lsp_range
134
+ start_position = LSP::Interface::Position.new(line: lsp_range[:start][:line], character: lsp_range[:start][:character])
135
+ end_position = LSP::Interface::Position.new(line: lsp_range[:end][:line], character: lsp_range[:end][:character])
136
+ LSP::Interface::Range.new(start: start_position, end: end_position)
137
+ end
138
+
139
+ LSP::Interface::Hover.new(
140
+ contents: LSP::Interface::MarkupContent.new(kind: "markdown", value: LSPFormatter.format_hover_content(content).to_s),
141
+ range: range
142
+ )
143
+ end
144
+ rescue Typing::UnknownNodeError => exn
145
+ Steep.log_error exn, message: "Failed to compute hover: #{exn.inspect}"
146
+ nil
147
+ end
148
+ end
149
+ end
150
+
151
+ def process_completion(job)
152
+ Steep.logger.tagged("#response_to_completion") do
153
+ Steep.measure "Generating response" do
154
+ Steep.logger.info "path: #{job.path}, line: #{job.line}, column: #{job.column}, trigger: #{job.trigger}"
155
+
156
+ case
157
+ when target = project.target_for_source_path(job.path)
158
+ file = service.source_files[job.path] or return
159
+ subtyping = service.signature_services.fetch(target.name).current_subtyping or return
160
+
161
+ provider = Services::CompletionProvider.new(source_text: file.content, path: job.path, subtyping: subtyping)
162
+ items = begin
163
+ provider.run(line: job.line, column: job.column)
164
+ rescue Parser::SyntaxError
165
+ [] #: Array[Services::CompletionProvider::item]
166
+ end
167
+
168
+ completion_items = items.map do |item|
169
+ format_completion_item(item)
170
+ end
171
+
172
+ Steep.logger.debug "items = #{completion_items.inspect}"
173
+
174
+ LSP::Interface::CompletionList.new(
175
+ is_incomplete: false,
176
+ items: completion_items
177
+ )
178
+ when target = project.target_for_signature_path(job.path)
179
+ sig_service = service.signature_services[target.name] or raise
180
+ relative_path = job.path
181
+
182
+ context = nil #: RBS::Resolver::context
183
+
184
+ case sig_service.status
185
+ when Services::SignatureService::SyntaxErrorStatus, Services::SignatureService::AncestorErrorStatus
186
+ if buffer = sig_service.latest_env.buffers.find {|buf| Pathname(buf.name) == Pathname(relative_path) }
187
+ dirs = sig_service.latest_env.signatures.fetch(buffer)[0]
188
+ else
189
+ dirs = [] #: Array[RBS::AST::Directives::t]
190
+ end
191
+ else
192
+ signature = sig_service.files.fetch(relative_path).signature
193
+ signature.is_a?(Array) or raise
194
+ buffer, dirs, decls = signature
195
+
196
+ locator = RBS::Locator.new(buffer: buffer, dirs: dirs, decls: decls)
197
+
198
+ _hd, tail = locator.find2(line: job.line, column: job.column)
199
+ tail ||= [] #: Array[RBS::Locator::component]
200
+
201
+ tail.reverse_each do |t|
202
+ case t
203
+ when RBS::AST::Declarations::Module, RBS::AST::Declarations::Class
204
+ if (last_type_name = context&.[](1)).is_a?(RBS::TypeName)
205
+ context = [context, last_type_name + t.name]
206
+ else
207
+ context = [context, t.name.absolute!]
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ buffer = RBS::Buffer.new(name: relative_path, content: sig_service.files.fetch(relative_path).content)
214
+ prefix = Services::TypeNameCompletion::Prefix.parse(buffer, line: job.line, column: job.column)
215
+
216
+ completion = Services::TypeNameCompletion.new(env: sig_service.latest_env, context: context, dirs: dirs)
217
+ type_names = completion.find_type_names(prefix)
218
+ prefix_size = prefix ? prefix.size : 0
219
+
220
+ completion_items = type_names.map do |type_name|
221
+ absolute_name, relative_name = completion.resolve_name_in_context(type_name)
222
+ format_completion_item_for_rbs(sig_service, absolute_name, job, relative_name.to_s, prefix_size)
223
+ end
224
+
225
+ ["untyped", "void", "bool", "class", "module", "instance", "nil"].each do |name|
226
+ completion_items << LSP::Interface::CompletionItem.new(
227
+ label: name,
228
+ detail: "(builtin type)",
229
+ text_edit: LSP::Interface::TextEdit.new(
230
+ range: LSP::Interface::Range.new(
231
+ start: LSP::Interface::Position.new(
232
+ line: job.line - 1,
233
+ character: job.column - prefix_size
234
+ ),
235
+ end: LSP::Interface::Position.new(
236
+ line: job.line - 1,
237
+ character: job.column
238
+ )
239
+ ),
240
+ new_text: name
241
+ ),
242
+ kind: LSP::Constant::CompletionItemKind::KEYWORD,
243
+ filter_text: name,
244
+ sort_text: "zz__#{name}"
245
+ )
246
+ end
247
+
248
+ LSP::Interface::CompletionList.new(
249
+ is_incomplete: !sig_service.status.is_a?(Services::SignatureService::LoadedStatus),
250
+ items: completion_items
251
+ )
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+ def format_completion_item_for_rbs(sig_service, type_name, job, complete_text, prefix_size)
258
+ range = LSP::Interface::Range.new(
259
+ start: LSP::Interface::Position.new(
260
+ line: job.line - 1,
261
+ character: job.column - prefix_size
262
+ ),
263
+ end: LSP::Interface::Position.new(
264
+ line: job.line - 1,
265
+ character: job.column
266
+ )
267
+ )
268
+
269
+ type_name = sig_service.latest_env.normalize_type_name(type_name)
270
+
271
+ case type_name.kind
272
+ when :class
273
+ env = sig_service.latest_env
274
+ class_entry = env.module_class_entry(type_name) or raise
275
+
276
+ case class_entry
277
+ when RBS::Environment::ClassEntry, RBS::Environment::ModuleEntry
278
+ comments = class_entry.decls.map {|decl| decl.decl.comment }.compact
279
+ decl = class_entry.primary.decl
280
+ when RBS::Environment::ClassAliasEntry, RBS::Environment::ModuleAliasEntry
281
+ comments = [class_entry.decl.comment].compact
282
+ decl = class_entry.decl
283
+ end
284
+
285
+ LSP::Interface::CompletionItem.new(
286
+ label: complete_text,
287
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: LSPFormatter.declaration_summary(decl)),
288
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_rbs_completion_docs(type_name, decl, comments) },
289
+ text_edit: LSP::Interface::TextEdit.new(
290
+ range: range,
291
+ new_text: complete_text
292
+ ),
293
+ kind: LSP::Constant::CompletionItemKind::CLASS
294
+ )
295
+ when :alias
296
+ alias_decl = sig_service.latest_env.type_alias_decls[type_name]&.decl or raise
297
+
298
+ LSP::Interface::CompletionItem.new(
299
+ label: complete_text,
300
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: LSPFormatter.declaration_summary(alias_decl)),
301
+ text_edit: LSP::Interface::TextEdit.new(
302
+ range: range,
303
+ new_text: complete_text
304
+ ),
305
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_rbs_completion_docs(type_name, alias_decl, [alias_decl.comment].compact) },
306
+ kind: LSP::Constant::CompletionItemKind::FIELD
307
+ )
308
+ when :interface
309
+ interface_decl = sig_service.latest_env.interface_decls[type_name]&.decl or raise
310
+
311
+ LSP::Interface::CompletionItem.new(
312
+ label: complete_text,
313
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: LSPFormatter.declaration_summary(interface_decl)),
314
+ text_edit: LSP::Interface::TextEdit.new(
315
+ range: range,
316
+ new_text: complete_text
317
+ ),
318
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_rbs_completion_docs(type_name, interface_decl, [interface_decl.comment].compact) },
319
+ kind: LSP::Constant::CompletionItemKind::INTERFACE
320
+ )
321
+ else
322
+ raise
323
+ end
324
+ end
325
+
326
+ def format_completion_item(item)
327
+ range = LSP::Interface::Range.new(
328
+ start: LSP::Interface::Position.new(
329
+ line: item.range.start.line-1,
330
+ character: item.range.start.column
331
+ ),
332
+ end: LSP::Interface::Position.new(
333
+ line: item.range.end.line-1,
334
+ character: item.range.end.column
335
+ )
336
+ )
337
+
338
+ case item
339
+ when Services::CompletionProvider::LocalVariableItem
340
+ LSP::Interface::CompletionItem.new(
341
+ label: item.identifier.to_s,
342
+ kind: LSP::Constant::CompletionItemKind::VARIABLE,
343
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: item.type.to_s),
344
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) },
345
+ insert_text: item.identifier.to_s,
346
+ sort_text: item.identifier.to_s
347
+ )
348
+ when Services::CompletionProvider::ConstantItem
349
+ case
350
+ when item.class? || item.module?
351
+ kind = LSP::Constant::CompletionItemKind::CLASS
352
+ else
353
+ kind = LSP::Constant::CompletionItemKind::CONSTANT
354
+ end
355
+
356
+ detail = LSPFormatter.declaration_summary(item.decl)
357
+
358
+ LSP::Interface::CompletionItem.new(
359
+ label: item.identifier.to_s,
360
+ kind: kind,
361
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: detail),
362
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) },
363
+ text_edit: LSP::Interface::TextEdit.new(
364
+ range: range,
365
+ new_text: item.identifier.to_s
366
+ )
367
+ )
368
+ when Services::CompletionProvider::SimpleMethodNameItem
369
+ LSP::Interface::CompletionItem.new(
370
+ label: item.identifier.to_s,
371
+ kind: LSP::Constant::CompletionItemKind::FUNCTION,
372
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: item.method_name.relative.to_s),
373
+ insert_text: item.identifier.to_s,
374
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) }
375
+ )
376
+ when Services::CompletionProvider::ComplexMethodNameItem
377
+ method_names = item.method_names.map(&:relative).uniq
378
+
379
+ LSP::Interface::CompletionItem.new(
380
+ label: item.identifier.to_s,
381
+ kind: LSP::Constant::CompletionItemKind::FUNCTION,
382
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: method_names.join(", ")),
383
+ insert_text: item.identifier.to_s,
384
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) }
385
+ )
386
+ when Services::CompletionProvider::GeneratedMethodNameItem
387
+ LSP::Interface::CompletionItem.new(
388
+ label: item.identifier.to_s,
389
+ kind: LSP::Constant::CompletionItemKind::FUNCTION,
390
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: "(Generated)"),
391
+ insert_text: item.identifier.to_s,
392
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) }
393
+ )
394
+ when Services::CompletionProvider::InstanceVariableItem
395
+ LSP::Interface::CompletionItem.new(
396
+ label: item.identifier.to_s,
397
+ kind: LSP::Constant::CompletionItemKind::FIELD,
398
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: item.type.to_s),
399
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) },
400
+ text_edit: LSP::Interface::TextEdit.new(
401
+ range: range,
402
+ new_text: item.identifier.to_s
403
+ )
404
+ )
405
+ when Services::CompletionProvider::KeywordArgumentItem
406
+ LSP::Interface::CompletionItem.new(
407
+ label: item.identifier.to_s,
408
+ kind: LSP::Constant::CompletionItemKind::FIELD,
409
+ label_details: LSP::Interface::CompletionItemLabelDetails.new(description: 'Keyword argument'),
410
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) },
411
+ text_edit: LSP::Interface::TextEdit.new(
412
+ range: range,
413
+ new_text: item.identifier.to_s
414
+ )
415
+ )
416
+ when Services::CompletionProvider::TypeNameItem
417
+ kind =
418
+ case
419
+ when item.absolute_type_name.class?
420
+ LSP::Constant::CompletionItemKind::CLASS
421
+ when item.absolute_type_name.interface?
422
+ LSP::Constant::CompletionItemKind::INTERFACE
423
+ when item.absolute_type_name.alias?
424
+ LSP::Constant::CompletionItemKind::FIELD
425
+ end
426
+ LSP::Interface::CompletionItem.new(
427
+ label: item.relative_type_name.to_s,
428
+ kind: kind,
429
+ label_details: nil,
430
+ documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) },
431
+ text_edit: LSP::Interface::TextEdit.new(
432
+ range: range,
433
+ new_text: item.relative_type_name.to_s
434
+ )
435
+ )
436
+ when Services::CompletionProvider::TextItem
437
+ LSP::Interface::CompletionItem.new(
438
+ label: item.label,
439
+ label_details: item.help_text && LSP::Interface::CompletionItemLabelDetails.new(description: item.help_text),
440
+ kind: LSP::Constant::CompletionItemKind::SNIPPET,
441
+ insert_text_format: LSP::Constant::InsertTextFormat::SNIPPET,
442
+ text_edit: LSP::Interface::TextEdit.new(
443
+ range: range,
444
+ new_text: item.text
445
+ )
446
+ )
447
+ end
448
+ end
449
+
450
+ def process_signature_help(job)
451
+ Steep.logger.tagged("##{__method__}") do
452
+ if target = project.target_for_source_path(job.path)
453
+ file = service.source_files[job.path] or return
454
+ subtyping = service.signature_services.fetch(target.name).current_subtyping or return
455
+ source =
456
+ Source.parse(file.content, path: file.path, factory: subtyping.factory)
457
+ .without_unrelated_defs(line: job.line, column: job.column)
458
+
459
+ provider = Services::SignatureHelpProvider.new(source: source, subtyping: subtyping)
460
+
461
+ if (items, index = provider.run(line: job.line, column: job.column))
462
+ signatures = items.map do |item|
463
+ params = item.parameters or raise
464
+
465
+ LSP::Interface::SignatureInformation.new(
466
+ label: item.method_type.to_s,
467
+ parameters: params.map { |param| LSP::Interface::ParameterInformation.new(label: param)},
468
+ active_parameter: item.active_parameter,
469
+ documentation: item.comment&.yield_self do |comment|
470
+ LSP::Interface::MarkupContent.new(
471
+ kind: LSP::Constant::MarkupKind::MARKDOWN,
472
+ value: comment.string.gsub(/<!--(?~-->)-->/, "")
473
+ )
474
+ end
475
+ )
476
+ end
477
+
478
+ @last_signature_help_line = job.line
479
+ @last_signature_help_result = LSP::Interface::SignatureHelp.new(
480
+ signatures: signatures,
481
+ active_signature: index
482
+ )
483
+ end
484
+ end
485
+ end
486
+ rescue Parser::SyntaxError
487
+ # Reuse the latest result to keep SignatureHelp opened while typing
488
+ @last_signature_help_result if @last_signature_help_line == job.line
489
+ end
490
+ end
491
+ end
492
+ end