steep-relaxed 1.9.3.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 (165) 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/STDGEM_DEPENDENCIES.txt +59 -0
  9. data/Steepfile +68 -0
  10. data/bin/console +14 -0
  11. data/bin/generate-diagnostics-docs.rb +112 -0
  12. data/bin/mem_graph.rb +67 -0
  13. data/bin/mem_prof.rb +102 -0
  14. data/bin/output_rebaseline.rb +34 -0
  15. data/bin/output_test.rb +60 -0
  16. data/bin/rbs +20 -0
  17. data/bin/rbs-inline +19 -0
  18. data/bin/setup +9 -0
  19. data/bin/stackprof_test.rb +19 -0
  20. data/bin/steep +19 -0
  21. data/bin/steep-check.rb +251 -0
  22. data/bin/steep-prof +16 -0
  23. data/doc/narrowing.md +195 -0
  24. data/doc/shape.md +194 -0
  25. data/exe/steep +18 -0
  26. data/guides/README.md +5 -0
  27. data/guides/src/gem-rbs-collection/gem-rbs-collection.md +126 -0
  28. data/guides/src/getting-started/getting-started.md +163 -0
  29. data/guides/src/nil-optional/nil-optional.md +195 -0
  30. data/lib/steep/annotation_parser.rb +199 -0
  31. data/lib/steep/ast/annotation/collection.rb +172 -0
  32. data/lib/steep/ast/annotation.rb +137 -0
  33. data/lib/steep/ast/builtin.rb +104 -0
  34. data/lib/steep/ast/ignore.rb +148 -0
  35. data/lib/steep/ast/node/type_application.rb +88 -0
  36. data/lib/steep/ast/node/type_assertion.rb +81 -0
  37. data/lib/steep/ast/types/any.rb +35 -0
  38. data/lib/steep/ast/types/boolean.rb +45 -0
  39. data/lib/steep/ast/types/bot.rb +35 -0
  40. data/lib/steep/ast/types/class.rb +43 -0
  41. data/lib/steep/ast/types/factory.rb +557 -0
  42. data/lib/steep/ast/types/helper.rb +40 -0
  43. data/lib/steep/ast/types/instance.rb +42 -0
  44. data/lib/steep/ast/types/intersection.rb +93 -0
  45. data/lib/steep/ast/types/literal.rb +59 -0
  46. data/lib/steep/ast/types/logic.rb +84 -0
  47. data/lib/steep/ast/types/name.rb +128 -0
  48. data/lib/steep/ast/types/nil.rb +41 -0
  49. data/lib/steep/ast/types/proc.rb +117 -0
  50. data/lib/steep/ast/types/record.rb +79 -0
  51. data/lib/steep/ast/types/self.rb +43 -0
  52. data/lib/steep/ast/types/shared_instance.rb +11 -0
  53. data/lib/steep/ast/types/top.rb +35 -0
  54. data/lib/steep/ast/types/tuple.rb +60 -0
  55. data/lib/steep/ast/types/union.rb +97 -0
  56. data/lib/steep/ast/types/var.rb +65 -0
  57. data/lib/steep/ast/types/void.rb +35 -0
  58. data/lib/steep/cli.rb +401 -0
  59. data/lib/steep/diagnostic/deprecated/else_on_exhaustive_case.rb +20 -0
  60. data/lib/steep/diagnostic/deprecated/unknown_constant_assigned.rb +28 -0
  61. data/lib/steep/diagnostic/helper.rb +18 -0
  62. data/lib/steep/diagnostic/lsp_formatter.rb +78 -0
  63. data/lib/steep/diagnostic/result_printer2.rb +48 -0
  64. data/lib/steep/diagnostic/ruby.rb +1221 -0
  65. data/lib/steep/diagnostic/signature.rb +570 -0
  66. data/lib/steep/drivers/annotations.rb +52 -0
  67. data/lib/steep/drivers/check.rb +339 -0
  68. data/lib/steep/drivers/checkfile.rb +210 -0
  69. data/lib/steep/drivers/diagnostic_printer.rb +105 -0
  70. data/lib/steep/drivers/init.rb +66 -0
  71. data/lib/steep/drivers/langserver.rb +56 -0
  72. data/lib/steep/drivers/print_project.rb +113 -0
  73. data/lib/steep/drivers/stats.rb +203 -0
  74. data/lib/steep/drivers/utils/driver_helper.rb +143 -0
  75. data/lib/steep/drivers/utils/jobs_option.rb +26 -0
  76. data/lib/steep/drivers/vendor.rb +27 -0
  77. data/lib/steep/drivers/watch.rb +194 -0
  78. data/lib/steep/drivers/worker.rb +58 -0
  79. data/lib/steep/equatable.rb +23 -0
  80. data/lib/steep/expectations.rb +228 -0
  81. data/lib/steep/index/rbs_index.rb +350 -0
  82. data/lib/steep/index/signature_symbol_provider.rb +185 -0
  83. data/lib/steep/index/source_index.rb +167 -0
  84. data/lib/steep/interface/block.rb +103 -0
  85. data/lib/steep/interface/builder.rb +843 -0
  86. data/lib/steep/interface/function.rb +1090 -0
  87. data/lib/steep/interface/method_type.rb +330 -0
  88. data/lib/steep/interface/shape.rb +239 -0
  89. data/lib/steep/interface/substitution.rb +159 -0
  90. data/lib/steep/interface/type_param.rb +115 -0
  91. data/lib/steep/located_value.rb +20 -0
  92. data/lib/steep/method_name.rb +42 -0
  93. data/lib/steep/module_helper.rb +24 -0
  94. data/lib/steep/node_helper.rb +273 -0
  95. data/lib/steep/path_helper.rb +30 -0
  96. data/lib/steep/project/dsl.rb +268 -0
  97. data/lib/steep/project/group.rb +31 -0
  98. data/lib/steep/project/options.rb +63 -0
  99. data/lib/steep/project/pattern.rb +59 -0
  100. data/lib/steep/project/target.rb +92 -0
  101. data/lib/steep/project.rb +78 -0
  102. data/lib/steep/rake_task.rb +132 -0
  103. data/lib/steep/range_extension.rb +29 -0
  104. data/lib/steep/server/base_worker.rb +97 -0
  105. data/lib/steep/server/change_buffer.rb +73 -0
  106. data/lib/steep/server/custom_methods.rb +77 -0
  107. data/lib/steep/server/delay_queue.rb +45 -0
  108. data/lib/steep/server/interaction_worker.rb +492 -0
  109. data/lib/steep/server/lsp_formatter.rb +455 -0
  110. data/lib/steep/server/master.rb +922 -0
  111. data/lib/steep/server/target_group_files.rb +205 -0
  112. data/lib/steep/server/type_check_controller.rb +366 -0
  113. data/lib/steep/server/type_check_worker.rb +303 -0
  114. data/lib/steep/server/work_done_progress.rb +64 -0
  115. data/lib/steep/server/worker_process.rb +176 -0
  116. data/lib/steep/services/completion_provider.rb +802 -0
  117. data/lib/steep/services/content_change.rb +61 -0
  118. data/lib/steep/services/file_loader.rb +74 -0
  119. data/lib/steep/services/goto_service.rb +441 -0
  120. data/lib/steep/services/hover_provider/rbs.rb +88 -0
  121. data/lib/steep/services/hover_provider/ruby.rb +221 -0
  122. data/lib/steep/services/hover_provider/singleton_methods.rb +20 -0
  123. data/lib/steep/services/path_assignment.rb +46 -0
  124. data/lib/steep/services/signature_help_provider.rb +202 -0
  125. data/lib/steep/services/signature_service.rb +428 -0
  126. data/lib/steep/services/stats_calculator.rb +68 -0
  127. data/lib/steep/services/type_check_service.rb +394 -0
  128. data/lib/steep/services/type_name_completion.rb +236 -0
  129. data/lib/steep/signature/validator.rb +651 -0
  130. data/lib/steep/source/ignore_ranges.rb +69 -0
  131. data/lib/steep/source.rb +691 -0
  132. data/lib/steep/subtyping/cache.rb +30 -0
  133. data/lib/steep/subtyping/check.rb +1113 -0
  134. data/lib/steep/subtyping/constraints.rb +341 -0
  135. data/lib/steep/subtyping/relation.rb +101 -0
  136. data/lib/steep/subtyping/result.rb +324 -0
  137. data/lib/steep/subtyping/variable_variance.rb +89 -0
  138. data/lib/steep/test.rb +9 -0
  139. data/lib/steep/thread_waiter.rb +43 -0
  140. data/lib/steep/type_construction.rb +5183 -0
  141. data/lib/steep/type_inference/block_params.rb +416 -0
  142. data/lib/steep/type_inference/case_when.rb +303 -0
  143. data/lib/steep/type_inference/constant_env.rb +56 -0
  144. data/lib/steep/type_inference/context.rb +195 -0
  145. data/lib/steep/type_inference/logic_type_interpreter.rb +613 -0
  146. data/lib/steep/type_inference/method_call.rb +193 -0
  147. data/lib/steep/type_inference/method_params.rb +531 -0
  148. data/lib/steep/type_inference/multiple_assignment.rb +194 -0
  149. data/lib/steep/type_inference/send_args.rb +712 -0
  150. data/lib/steep/type_inference/type_env.rb +341 -0
  151. data/lib/steep/type_inference/type_env_builder.rb +138 -0
  152. data/lib/steep/typing.rb +321 -0
  153. data/lib/steep/version.rb +3 -0
  154. data/lib/steep.rb +369 -0
  155. data/manual/annotations.md +181 -0
  156. data/manual/ignore.md +20 -0
  157. data/manual/ruby-diagnostics.md +1879 -0
  158. data/sample/Steepfile +22 -0
  159. data/sample/lib/conference.rb +49 -0
  160. data/sample/lib/length.rb +35 -0
  161. data/sample/sig/conference.rbs +42 -0
  162. data/sample/sig/generics.rbs +15 -0
  163. data/sample/sig/length.rbs +34 -0
  164. data/steep-relaxed.gemspec +56 -0
  165. metadata +340 -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