mt-lang 0.3.8 → 0.3.10

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/lib/milk_tea/base.rb +1 -2
  3. data/lib/milk_tea/bindings/bindgen/ast_parser.rb +0 -2
  4. data/lib/milk_tea/bindings/bindgen/declaration.rb +0 -2
  5. data/lib/milk_tea/bindings/bindgen/emitter.rb +0 -2
  6. data/lib/milk_tea/bindings/bindgen/overrides.rb +0 -2
  7. data/lib/milk_tea/bindings/bindgen/type_mapper.rb +51 -53
  8. data/lib/milk_tea/bindings/imported_bindings/generator.rb +7 -9
  9. data/lib/milk_tea/bindings/imported_bindings/method_source.rb +0 -2
  10. data/lib/milk_tea/bindings/imported_bindings/naming.rb +6 -8
  11. data/lib/milk_tea/bindings/imported_bindings.rb +0 -2
  12. data/lib/milk_tea/bindings/opengl_registry.rb +3 -7
  13. data/lib/milk_tea/bindings/steamworks.rb +12 -16
  14. data/lib/milk_tea/bindings/upstream_sources.rb +10 -14
  15. data/lib/milk_tea/bindings/vendored_box2d.rb +10 -12
  16. data/lib/milk_tea/bindings/vendored_cjson.rb +6 -8
  17. data/lib/milk_tea/bindings/vendored_flecs.rb +10 -12
  18. data/lib/milk_tea/bindings/vendored_glfw.rb +11 -13
  19. data/lib/milk_tea/bindings/vendored_libuv.rb +11 -13
  20. data/lib/milk_tea/bindings/vendored_pcre2.rb +11 -13
  21. data/lib/milk_tea/bindings/vendored_raylib.rb +6 -10
  22. data/lib/milk_tea/bindings/vendored_sdl3.rb +11 -13
  23. data/lib/milk_tea/bindings/vendored_steamworks.rb +1 -5
  24. data/lib/milk_tea/core/ast.rb +103 -45
  25. data/lib/milk_tea/core/async_runtime_installer.rb +0 -2
  26. data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -3
  27. data/lib/milk_tea/core/c_backend/aggregate_utils.rb +147 -84
  28. data/lib/milk_tea/core/c_backend/control_flow_emission.rb +394 -396
  29. data/lib/milk_tea/core/c_backend/expressions.rb +489 -476
  30. data/lib/milk_tea/core/c_backend/feature_detection.rb +446 -437
  31. data/lib/milk_tea/core/c_backend/format_helpers.rb +0 -2
  32. data/lib/milk_tea/core/c_backend/reachability.rb +339 -341
  33. data/lib/milk_tea/core/c_backend/reinterpret.rb +231 -217
  34. data/lib/milk_tea/core/c_backend/runtime_helpers.rb +531 -526
  35. data/lib/milk_tea/core/c_backend/statements.rb +528 -530
  36. data/lib/milk_tea/core/c_backend/type_collectors.rb +1344 -1346
  37. data/lib/milk_tea/core/c_backend/type_declaration.rb +215 -213
  38. data/lib/milk_tea/core/c_backend/type_system.rb +347 -349
  39. data/lib/milk_tea/core/c_backend.rb +17 -9
  40. data/lib/milk_tea/core/compatibility_helpers.rb +0 -2
  41. data/lib/milk_tea/core/compile_time/const_eval.rb +7 -12
  42. data/lib/milk_tea/core/compile_time.rb +32 -38
  43. data/lib/milk_tea/core/control_flow/builder.rb +3 -5
  44. data/lib/milk_tea/core/control_flow/constant_propagation.rb +14 -17
  45. data/lib/milk_tea/core/control_flow/definite_assignment.rb +0 -1
  46. data/lib/milk_tea/core/ir.rb +10 -10
  47. data/lib/milk_tea/core/lexer/character_classes.rb +5 -7
  48. data/lib/milk_tea/core/lexer/format_strings.rb +7 -9
  49. data/lib/milk_tea/core/lexer/heredocs.rb +22 -22
  50. data/lib/milk_tea/core/lexer/indentation.rb +0 -2
  51. data/lib/milk_tea/core/lexer/numbers.rb +0 -2
  52. data/lib/milk_tea/core/lexer/recovery.rb +0 -2
  53. data/lib/milk_tea/core/lexer/strings.rb +0 -2
  54. data/lib/milk_tea/core/lexer/symbols.rb +0 -2
  55. data/lib/milk_tea/core/lexer/trivia.rb +0 -2
  56. data/lib/milk_tea/core/lexer.rb +0 -2
  57. data/lib/milk_tea/core/lowering/async/analysis.rb +0 -2
  58. data/lib/milk_tea/core/lowering/async/lowering.rb +1264 -1265
  59. data/lib/milk_tea/core/lowering/async/normalization.rb +0 -2
  60. data/lib/milk_tea/core/lowering/async.rb +627 -630
  61. data/lib/milk_tea/core/lowering/block.rb +413 -416
  62. data/lib/milk_tea/core/lowering/calls.rb +1381 -1384
  63. data/lib/milk_tea/core/lowering/declarations.rb +180 -183
  64. data/lib/milk_tea/core/lowering/dyn.rb +48 -50
  65. data/lib/milk_tea/core/lowering/events.rb +983 -985
  66. data/lib/milk_tea/core/lowering/expressions.rb +1513 -1518
  67. data/lib/milk_tea/core/lowering/foreign_cstr.rb +181 -184
  68. data/lib/milk_tea/core/lowering/functions.rb +185 -188
  69. data/lib/milk_tea/core/lowering/loops.rb +1028 -1031
  70. data/lib/milk_tea/core/lowering/proc.rb +363 -366
  71. data/lib/milk_tea/core/lowering/resolve.rb +2133 -2135
  72. data/lib/milk_tea/core/lowering/scans.rb +179 -181
  73. data/lib/milk_tea/core/lowering/str_buffer.rb +102 -105
  74. data/lib/milk_tea/core/lowering/utils.rb +1040 -1044
  75. data/lib/milk_tea/core/lowering.rb +5 -7
  76. data/lib/milk_tea/core/module_binder.rb +0 -2
  77. data/lib/milk_tea/core/module_loader/errors.rb +4 -2
  78. data/lib/milk_tea/core/module_loader.rb +113 -20
  79. data/lib/milk_tea/core/module_path_resolver.rb +0 -2
  80. data/lib/milk_tea/core/module_roots.rb +6 -8
  81. data/lib/milk_tea/core/parser/attributes.rb +0 -2
  82. data/lib/milk_tea/core/parser/blocks.rb +0 -2
  83. data/lib/milk_tea/core/parser/declarations.rb +0 -2
  84. data/lib/milk_tea/core/parser/expressions.rb +31 -14
  85. data/lib/milk_tea/core/parser/recovery.rb +0 -2
  86. data/lib/milk_tea/core/parser/statements.rb +0 -2
  87. data/lib/milk_tea/core/parser/types.rb +8 -10
  88. data/lib/milk_tea/core/parser.rb +1 -3
  89. data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +31 -33
  90. data/lib/milk_tea/core/pretty_printer/base_formatter.rb +0 -2
  91. data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +0 -2
  92. data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +0 -2
  93. data/lib/milk_tea/core/semantic_analyzer/attributes.rb +14 -16
  94. data/lib/milk_tea/core/semantic_analyzer/calls.rb +0 -2
  95. data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -14
  96. data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +18 -21
  97. data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +0 -3
  98. data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +12 -15
  99. data/lib/milk_tea/core/semantic_analyzer/generics.rb +57 -59
  100. data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +0 -2
  101. data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +5 -9
  102. data/lib/milk_tea/core/semantic_analyzer/nullability.rb +0 -3
  103. data/lib/milk_tea/core/semantic_analyzer/statements.rb +35 -40
  104. data/lib/milk_tea/core/semantic_analyzer/top_level.rb +10 -12
  105. data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -6
  106. data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +102 -105
  107. data/lib/milk_tea/core/semantic_analyzer.rb +17 -8
  108. data/lib/milk_tea/core/types/layout.rb +21 -22
  109. data/lib/milk_tea/core/types/predicates.rb +0 -2
  110. data/lib/milk_tea/core/types/registry.rb +16 -18
  111. data/lib/milk_tea/core/types/visitor.rb +0 -4
  112. data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -2
  113. data/lib/milk_tea/dap/protocol.rb +1 -1
  114. data/lib/milk_tea/dap/server/breakpoints.rb +0 -2
  115. data/lib/milk_tea/dap/server/debug_map.rb +0 -2
  116. data/lib/milk_tea/dap/server/handlers.rb +0 -2
  117. data/lib/milk_tea/dap/server/launch.rb +0 -2
  118. data/lib/milk_tea/dap/server/lldb_backend.rb +8 -10
  119. data/lib/milk_tea/dap/server/pause_diagnostics.rb +14 -16
  120. data/lib/milk_tea/dap/server/utilities.rb +0 -2
  121. data/lib/milk_tea/dap/server/wire.rb +0 -2
  122. data/lib/milk_tea/dap/server.rb +0 -2
  123. data/lib/milk_tea/lsp/diagnostics.rb +16 -16
  124. data/lib/milk_tea/lsp/server/call_hierarchy.rb +11 -12
  125. data/lib/milk_tea/lsp/server/code_actions.rb +355 -357
  126. data/lib/milk_tea/lsp/server/code_lens.rb +23 -25
  127. data/lib/milk_tea/lsp/server/completion.rb +873 -875
  128. data/lib/milk_tea/lsp/server/configuration.rb +129 -131
  129. data/lib/milk_tea/lsp/server/debug_info.rb +0 -2
  130. data/lib/milk_tea/lsp/server/definition.rb +564 -565
  131. data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +191 -193
  132. data/lib/milk_tea/lsp/server/execute_command.rb +0 -2
  133. data/lib/milk_tea/lsp/server/folding_range.rb +0 -4
  134. data/lib/milk_tea/lsp/server/formatting.rb +478 -480
  135. data/lib/milk_tea/lsp/server/hover.rb +1282 -1284
  136. data/lib/milk_tea/lsp/server/inlay_hints.rb +179 -181
  137. data/lib/milk_tea/lsp/server/lifecycle.rb +192 -194
  138. data/lib/milk_tea/lsp/server/linked_editing_range.rb +0 -2
  139. data/lib/milk_tea/lsp/server/on_type_formatting.rb +0 -2
  140. data/lib/milk_tea/lsp/server/progress.rb +0 -2
  141. data/lib/milk_tea/lsp/server/references.rb +316 -318
  142. data/lib/milk_tea/lsp/server/rename.rb +445 -447
  143. data/lib/milk_tea/lsp/server/selection_range.rb +0 -4
  144. data/lib/milk_tea/lsp/server/semantic_tokens.rb +1318 -1320
  145. data/lib/milk_tea/lsp/server/signature_help.rb +146 -148
  146. data/lib/milk_tea/lsp/server/text_documents.rb +99 -101
  147. data/lib/milk_tea/lsp/server/type_hierarchy.rb +2 -4
  148. data/lib/milk_tea/lsp/server/utilities.rb +397 -399
  149. data/lib/milk_tea/lsp/server.rb +0 -3
  150. data/lib/milk_tea/lsp/workspace/analysis.rb +40 -42
  151. data/lib/milk_tea/lsp/workspace/dependency_graph.rb +4 -10
  152. data/lib/milk_tea/lsp/workspace/utilities.rb +19 -19
  153. data/lib/milk_tea/packages/atomic_write.rb +4 -5
  154. data/lib/milk_tea/packages/dependency_solver.rb +15 -15
  155. data/lib/milk_tea/packages/lock.rb +4 -4
  156. data/lib/milk_tea/packages/manager_cli.rb +1 -1
  157. data/lib/milk_tea/packages/manifest.rb +3 -3
  158. data/lib/milk_tea/packages/registry_store.rb +4 -6
  159. data/lib/milk_tea/packages/services.rb +16 -16
  160. data/lib/milk_tea/packages/source_cache.rb +4 -6
  161. data/lib/milk_tea/packages/source_resolver.rb +44 -44
  162. data/lib/milk_tea/packages/version.rb +8 -8
  163. data/lib/milk_tea/tooling/build.rb +3 -7
  164. data/lib/milk_tea/tooling/build_cache.rb +0 -2
  165. data/lib/milk_tea/tooling/debug_info_formatter.rb +31 -33
  166. data/lib/milk_tea/tooling/debug_map.rb +8 -10
  167. data/lib/milk_tea/tooling/docs_app.rb +0 -2
  168. data/lib/milk_tea/tooling/linter/doc_tags.rb +25 -27
  169. data/lib/milk_tea/tooling/linter/fix_engine.rb +87 -24
  170. data/lib/milk_tea/tooling/linter/flow_rules.rb +44 -46
  171. data/lib/milk_tea/tooling/linter/imports_platform.rb +14 -16
  172. data/lib/milk_tea/tooling/linter/release_rules.rb +3 -5
  173. data/lib/milk_tea/tooling/linter/reserved_names.rb +23 -25
  174. data/lib/milk_tea/tooling/linter/rules.rb +87 -89
  175. data/lib/milk_tea/tooling/linter/source_helpers.rb +40 -42
  176. data/lib/milk_tea/tooling/linter/trailing_comma.rb +17 -19
  177. data/lib/milk_tea/tooling/linter/visitors.rb +162 -50
  178. data/lib/milk_tea/tooling/linter.rb +0 -2
  179. data/lib/milk_tea/tooling/project_scaffold.rb +0 -2
  180. data/lib/milk_tea/tooling/run.rb +0 -2
  181. data/lib/milk_tea/tooling/toolchain_cli.rb +0 -2
  182. data/std/cli.mt +13 -32
  183. data/std/color.mt +28 -28
  184. data/std/encoding.mt +4 -4
  185. data/std/graph.mt +1 -2
  186. data/std/hash.mt +14 -14
  187. data/std/http/server.mt +3 -3
  188. data/std/input.mt +1 -1
  189. data/std/json.mt +1 -1
  190. data/std/linear_algebra.mt +6 -6
  191. data/std/net/mux.mt +1 -1
  192. data/std/noise.mt +23 -23
  193. data/std/parse.mt +2 -2
  194. data/std/process.mt +3 -4
  195. data/std/sparse_set.mt +1 -1
  196. data/std/steering.mt +5 -5
  197. data/std/str.mt +1 -1
  198. data/std/tween.mt +4 -4
  199. data/std/utility.mt +3 -3
  200. metadata +2 -2
@@ -4,8 +4,6 @@ module MilkTea
4
4
  module LSP
5
5
  class Server
6
6
  module ServerHover
7
- private
8
-
9
7
  KEYWORD_HOVER_INFO = {
10
8
  'size_of' => {
11
9
  signature: 'size_of(Type) -> ptr_uint',
@@ -302,1627 +300,1627 @@ module MilkTea
302
300
  },
303
301
  }.freeze
304
302
 
305
- def handle_hover(params)
306
- stages = new_perf_stages
307
- total_start = stages ? monotonic_time : nil
308
- uri = params['textDocument']['uri']
309
- lsp_line = params['position']['line']
310
- lsp_char = params['position']['character']
311
- token_kind = 'none'
312
- result_state = 'miss'
313
-
314
- context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
315
- token = context&.fetch(:token, nil)
316
- token_kind = token&.type || :none
317
- unless token&.type == :identifier
318
- return nil if token.nil?
319
- unless member_access_token?(context)
320
- info = builtin_keyword_hover_info(token) ||
321
- BUILTIN_CALL_HOVER_INFO[token.lexeme]&.slice(:signature, :docs)
322
- if info
323
- result_state = 'hit'
324
- return {
325
- contents: {
326
- kind: 'markdown',
327
- value: render_hover_markdown(info)
328
- },
329
- range: token_to_range(token)
330
- }
331
- end
332
-
333
- result_state = 'not-identifier'
334
- return nil
335
- end
336
- end
337
-
338
- info = resolve_hover_info(uri, lsp_line, lsp_char, token: token, tokens: context[:tokens], token_index: context[:token_index], stages: stages)
339
- return nil unless info
303
+ def handle_hover(params)
304
+ stages = new_perf_stages
305
+ total_start = stages ? monotonic_time : nil
306
+ uri = params['textDocument']['uri']
307
+ lsp_line = params['position']['line']
308
+ lsp_char = params['position']['character']
309
+ token_kind = 'none'
310
+ result_state = 'miss'
340
311
 
341
- result = measure_perf_stage(stages, 'render') do
342
- {
343
- contents: {
344
- kind: 'markdown',
345
- value: render_hover_markdown(info)
346
- },
347
- range: token_to_range(token)
348
- }
349
- end
350
- result_state = 'hit'
351
- result
352
- rescue StandardError => e
353
- result_state = 'error'
354
- warn "Error in hover handler: #{e.message}"
355
- nil
356
- ensure
357
- log_request_stage_breakdown('textDocument/hover', total_start, uri: uri, stages: stages, summary: "token=#{token_kind} result=#{result_state}")
358
- end
359
-
360
- def resolve_hover_info(uri, lsp_line, lsp_char, token: nil, tokens: nil, token_index: nil, stages: nil)
361
- if token.nil?
362
312
  context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
363
- return nil unless context
313
+ token = context&.fetch(:token, nil)
314
+ token_kind = token&.type || :none
315
+ unless token&.type == :identifier
316
+ return nil if token.nil?
317
+ unless member_access_token?(context)
318
+ info = builtin_keyword_hover_info(token) ||
319
+ BUILTIN_CALL_HOVER_INFO[token.lexeme]&.slice(:signature, :docs)
320
+ if info
321
+ result_state = 'hit'
322
+ return {
323
+ contents: {
324
+ kind: 'markdown',
325
+ value: render_hover_markdown(info)
326
+ },
327
+ range: token_to_range(token)
328
+ }
329
+ end
364
330
 
365
- token = context[:token]
366
- tokens = context[:tokens]
367
- token_index = context[:token_index]
368
- end
331
+ result_state = 'not-identifier'
332
+ return nil
333
+ end
334
+ end
369
335
 
370
- tokens ||= @workspace.get_tokens(uri) || []
371
- token_index = tokens.index(token) if token_index.nil?
372
- member_access_kw = token_index && keyword_member_access_token?(tokens, token_index)
373
- return nil unless token&.type == :identifier || member_access_kw
336
+ info = resolve_hover_info(uri, lsp_line, lsp_char, token: token, tokens: context[:tokens], token_index: context[:token_index], stages: stages)
337
+ return nil unless info
374
338
 
375
- if token_index
376
- module_info = module_declaration_info_at(tokens, token_index)
377
- if module_info
378
- location = module_definition_location(uri, module_info[:module_name])
379
- return {
380
- signature: "module #{module_info[:module_name]}",
381
- docs: nil,
382
- source: hover_source_label_from_location(location),
383
- source_uri: hover_source_uri_from_location(location),
384
- source_line: hover_source_line_from_location(location),
339
+ result = measure_perf_stage(stages, 'render') do
340
+ {
341
+ contents: {
342
+ kind: 'markdown',
343
+ value: render_hover_markdown(info)
344
+ },
345
+ range: token_to_range(token)
385
346
  }
386
347
  end
348
+ result_state = 'hit'
349
+ result
350
+ rescue StandardError => e
351
+ result_state = 'error'
352
+ warn "Error in hover handler: #{e.message}"
353
+ nil
354
+ ensure
355
+ log_request_stage_breakdown('textDocument/hover', total_start, uri: uri, stages: stages, summary: "token=#{token_kind} result=#{result_state}")
387
356
  end
388
357
 
389
- if token_index
390
- import_info = import_path_info_at(tokens, token_index)
391
- if import_info
392
- location = module_definition_location(uri, import_info[:module_name])
393
- return {
394
- signature: "module #{import_info[:module_name]}",
395
- docs: nil,
396
- source: hover_source_label_from_location(location),
397
- source_uri: hover_source_uri_from_location(location),
398
- source_line: hover_source_line_from_location(location),
399
- }
400
- end
401
- end
358
+ def resolve_hover_info(uri, lsp_line, lsp_char, token: nil, tokens: nil, token_index: nil, stages: nil)
359
+ if token.nil?
360
+ context = measure_perf_stage(stages, 'context') { token_context_at(uri, lsp_line, lsp_char) }
361
+ return nil unless context
402
362
 
403
- facts = measure_perf_stage(stages, 'facts') do
404
- @workspace.get_facts(uri, allow_last_good_fallback: allow_hover_last_good_fallback?(uri))
405
- end
406
- return nil unless facts
363
+ token = context[:token]
364
+ tokens = context[:tokens]
365
+ token_index = context[:token_index]
366
+ end
407
367
 
408
- if token_index && field_declaration_token?(tokens, token_index)
409
- return resolve_field_declaration_hover_info(uri, facts, tokens, token_index)
410
- end
368
+ tokens ||= @workspace.get_tokens(uri) || []
369
+ token_index = tokens.index(token) if token_index.nil?
370
+ member_access_kw = token_index && keyword_member_access_token?(tokens, token_index)
371
+ return nil unless token&.type == :identifier || member_access_kw
411
372
 
412
- if token_index && named_argument_label_token?(tokens, token_index)
413
- return resolve_named_argument_label_hover_info(uri, facts, tokens, token_index)
414
- end
373
+ if token_index
374
+ module_info = module_declaration_info_at(tokens, token_index)
375
+ if module_info
376
+ location = module_definition_location(uri, module_info[:module_name])
377
+ return {
378
+ signature: "module #{module_info[:module_name]}",
379
+ docs: nil,
380
+ source: hover_source_label_from_location(location),
381
+ source_uri: hover_source_uri_from_location(location),
382
+ source_line: hover_source_line_from_location(location),
383
+ }
384
+ end
385
+ end
415
386
 
416
- if token_index && (member_hover = resolve_member_access_hover_info(uri, facts, tokens, token_index))
417
- return member_hover
418
- end
387
+ if token_index
388
+ import_info = import_path_info_at(tokens, token_index)
389
+ if import_info
390
+ location = module_definition_location(uri, import_info[:module_name])
391
+ return {
392
+ signature: "module #{import_info[:module_name]}",
393
+ docs: nil,
394
+ source: hover_source_label_from_location(location),
395
+ source_uri: hover_source_uri_from_location(location),
396
+ source_line: hover_source_line_from_location(location),
397
+ }
398
+ end
399
+ end
419
400
 
420
- if token_index && (enum_member_hover = resolve_enum_member_hover_info(uri, facts, tokens, token_index))
421
- return enum_member_hover
422
- end
401
+ facts = measure_perf_stage(stages, 'facts') do
402
+ @workspace.get_facts(uri, allow_last_good_fallback: allow_hover_last_good_fallback?(uri))
403
+ end
404
+ return nil unless facts
423
405
 
424
- name = token.lexeme
425
- signature = nil
426
- docs = nil
427
- source_location = nil
428
- resolved_via_type_member = false
406
+ if token_index && field_declaration_token?(tokens, token_index)
407
+ return resolve_field_declaration_hover_info(uri, facts, tokens, token_index)
408
+ end
429
409
 
430
- if (binding = method_binding_at_token(facts, token))
431
- signature = method_signature(binding)
432
- source_location = module_member_binding_location(uri, facts.module_name, name, binding)
433
- end
410
+ if token_index && named_argument_label_token?(tokens, token_index)
411
+ return resolve_named_argument_label_hover_info(uri, facts, tokens, token_index)
412
+ end
434
413
 
435
- unless signature
436
- if token_index && (for_binding_info = resolve_for_binding_hover_info(tokens, token_index))
437
- signature = for_binding_info[:signature]
414
+ if token_index && (member_hover = resolve_member_access_hover_info(uri, facts, tokens, token_index))
415
+ return member_hover
438
416
  end
439
- end
440
417
 
441
- unless signature
442
- if token_index && match_arm_binding_token?(tokens, token_index)
443
- if (local_binding = resolve_as_binding_declaration_hover_binding(facts, name, lsp_line + 1, lsp_char + 1))
444
- signature = value_hover_signature(local_binding)
445
- end
418
+ if token_index && (enum_member_hover = resolve_enum_member_hover_info(uri, facts, tokens, token_index))
419
+ return enum_member_hover
446
420
  end
447
- end
448
421
 
449
- unless signature
450
- if (local_binding = resolve_local_hover_binding(facts, name, lsp_line + 1, lsp_char + 1))
451
- signature = value_hover_signature(local_binding)
422
+ name = token.lexeme
423
+ signature = nil
424
+ docs = nil
425
+ source_location = nil
426
+ resolved_via_type_member = false
427
+
428
+ if (binding = method_binding_at_token(facts, token))
429
+ signature = method_signature(binding)
430
+ source_location = module_member_binding_location(uri, facts.module_name, name, binding)
452
431
  end
453
- end
454
432
 
455
- unless signature
456
- if (binding = facts.functions[name])
457
- params_str = format_params(binding.type.params)
458
- signature = "function #{name}(#{params_str}) -> #{binding.type.return_type}"
459
- elsif (binding = facts.interfaces[name])
460
- signature = interface_signature(binding)
461
- source_location = module_member_definition_location(uri, binding.module_name, name)
462
- elsif facts.types.key?(name)
463
- type = facts.types[name]
464
- signature = type_hover_signature(name, type)
465
- docs ||= BUILTIN_TYPE_DOCS[name]
466
- elsif !name.include?(".") && (nested = find_nested_type_by_short_name(facts, name))
467
- signature = type_hover_signature(name, nested)
468
- docs ||= BUILTIN_TYPE_DOCS[name]
469
- elsif (binding = facts.values[name])
470
- signature = value_hover_signature(binding)
471
- elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (member_info = find_member_in_types(facts, name))
472
- type, member, value = member_info
473
- signature = value ? "#{type.name}.#{member} = #{value}" : "#{type.name}.#{member}"
474
- resolved_via_type_member = true
475
- elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (arm_sig = find_variant_arm_in_types(facts, name))
476
- signature = arm_sig
477
- resolved_via_type_member = true
478
- elsif (import_binding = facts.imports[name])
479
- signature = "module #{import_binding.name}"
480
- source_location = module_definition_location(uri, import_binding.name)
481
- elsif (attr_binding = facts.attributes[name])
482
- targets = attr_binding.targets.map(&:to_s).join(", ")
483
- params_str = attr_binding.params.map { |p| "#{p.name}: #{p.type}" }.join(", ")
484
- signature = "attribute [#{targets}] #{name}(#{params_str})"
485
- source_location ||= module_definition_location(uri, facts.module_name)
486
- else
487
- dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
488
- dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
489
- if dot_receiver && (module_binding = facts.imports[dot_receiver])
490
- if (fn = module_binding.functions[name])
491
- params_str = format_params(fn.type.params)
492
- signature = "function #{name}(#{params_str}) -> #{fn.type.return_type}"
493
- source_location = module_member_binding_location(uri, module_binding.name, name, fn)
494
- elsif (val = module_binding.values[name])
495
- signature = value_hover_signature(val)
496
- elsif module_binding.types.key?(name)
497
- signature = "type #{name}"
498
- docs ||= BUILTIN_TYPE_DOCS[name]
499
- elsif (binding = module_binding.interfaces[name])
500
- signature = interface_signature(binding)
501
- source_location = module_member_definition_location(uri, module_binding.name, name)
433
+ unless signature
434
+ if token_index && (for_binding_info = resolve_for_binding_hover_info(tokens, token_index))
435
+ signature = for_binding_info[:signature]
502
436
  end
437
+ end
503
438
 
504
- if signature
505
- source_location ||= module_member_definition_location(uri, module_binding.name, name)
506
- source_location ||= module_definition_location(uri, module_binding.name)
439
+ unless signature
440
+ if token_index && match_arm_binding_token?(tokens, token_index)
441
+ if (local_binding = resolve_as_binding_declaration_hover_binding(facts, name, lsp_line + 1, lsp_char + 1))
442
+ signature = value_hover_signature(local_binding)
443
+ end
507
444
  end
508
445
  end
509
446
 
510
447
  unless signature
511
- if (type_method = resolve_static_type_receiver_method(facts, dot_receiver, dot_receiver_path, name))
512
- signature = method_signature(type_method[:binding])
513
- source_location = module_member_binding_location(uri, type_method[:module_name], name, type_method[:binding])
514
- source_location ||= module_member_definition_location(uri, type_method[:module_name], name)
515
- source_location ||= module_definition_location(uri, type_method[:module_name])
448
+ if (local_binding = resolve_local_hover_binding(facts, name, lsp_line + 1, lsp_char + 1))
449
+ signature = value_hover_signature(local_binding)
516
450
  end
517
451
  end
518
452
 
519
453
  unless signature
520
- if dot_receiver
521
- receiver_name = dot_receiver
522
- receiver_binding = resolve_local_hover_binding(facts, receiver_name, lsp_line + 1, lsp_char + 1) ||
523
- facts.values[receiver_name] ||
524
- facts.functions[receiver_name]
525
- if receiver_binding && receiver_binding.type
526
- receiver_type = receiver_binding.respond_to?(:storage_type) ? receiver_binding.storage_type : receiver_binding.type
527
- methods = methods_for_receiver_type(facts, receiver_type)
528
- if (method_binding = methods[name])
529
- signature = method_signature(method_binding)
530
- else
531
- type_base = receiver_type.to_s[/^([A-Za-z_]+)/, 1]
532
- if type_base && (method_sigs = BUILTIN_TYPE_METHOD_SIGNATURES[type_base])
533
- signature = method_sigs[name]
454
+ if (binding = facts.functions[name])
455
+ params_str = format_params(binding.type.params)
456
+ signature = "function #{name}(#{params_str}) -> #{binding.type.return_type}"
457
+ elsif (binding = facts.interfaces[name])
458
+ signature = interface_signature(binding)
459
+ source_location = module_member_definition_location(uri, binding.module_name, name)
460
+ elsif facts.types.key?(name)
461
+ type = facts.types[name]
462
+ signature = type_hover_signature(name, type)
463
+ docs ||= BUILTIN_TYPE_DOCS[name]
464
+ elsif !name.include?(".") && (nested = find_nested_type_by_short_name(facts, name))
465
+ signature = type_hover_signature(name, nested)
466
+ docs ||= BUILTIN_TYPE_DOCS[name]
467
+ elsif (binding = facts.values[name])
468
+ signature = value_hover_signature(binding)
469
+ elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (member_info = find_member_in_types(facts, name))
470
+ type, member, value = member_info
471
+ signature = value ? "#{type.name}.#{member} = #{value}" : "#{type.name}.#{member}"
472
+ resolved_via_type_member = true
473
+ elsif !BUILTIN_CALL_HOVER_INFO.key?(name) && (arm_sig = find_variant_arm_in_types(facts, name))
474
+ signature = arm_sig
475
+ resolved_via_type_member = true
476
+ elsif (import_binding = facts.imports[name])
477
+ signature = "module #{import_binding.name}"
478
+ source_location = module_definition_location(uri, import_binding.name)
479
+ elsif (attr_binding = facts.attributes[name])
480
+ targets = attr_binding.targets.map(&:to_s).join(", ")
481
+ params_str = attr_binding.params.map { |p| "#{p.name}: #{p.type}" }.join(", ")
482
+ signature = "attribute [#{targets}] #{name}(#{params_str})"
483
+ source_location ||= module_definition_location(uri, facts.module_name)
484
+ else
485
+ dot_receiver = @workspace.find_dot_receiver(uri, lsp_line, lsp_char)
486
+ dot_receiver_path = @workspace.find_dot_receiver_path(uri, lsp_line, lsp_char)
487
+ if dot_receiver && (module_binding = facts.imports[dot_receiver])
488
+ if (fn = module_binding.functions[name])
489
+ params_str = format_params(fn.type.params)
490
+ signature = "function #{name}(#{params_str}) -> #{fn.type.return_type}"
491
+ source_location = module_member_binding_location(uri, module_binding.name, name, fn)
492
+ elsif (val = module_binding.values[name])
493
+ signature = value_hover_signature(val)
494
+ elsif module_binding.types.key?(name)
495
+ signature = "type #{name}"
496
+ docs ||= BUILTIN_TYPE_DOCS[name]
497
+ elsif (binding = module_binding.interfaces[name])
498
+ signature = interface_signature(binding)
499
+ source_location = module_member_definition_location(uri, module_binding.name, name)
500
+ end
501
+
502
+ if signature
503
+ source_location ||= module_member_definition_location(uri, module_binding.name, name)
504
+ source_location ||= module_definition_location(uri, module_binding.name)
505
+ end
506
+ end
507
+
508
+ unless signature
509
+ if (type_method = resolve_static_type_receiver_method(facts, dot_receiver, dot_receiver_path, name))
510
+ signature = method_signature(type_method[:binding])
511
+ source_location = module_member_binding_location(uri, type_method[:module_name], name, type_method[:binding])
512
+ source_location ||= module_member_definition_location(uri, type_method[:module_name], name)
513
+ source_location ||= module_definition_location(uri, type_method[:module_name])
514
+ end
515
+ end
516
+
517
+ unless signature
518
+ if dot_receiver
519
+ receiver_name = dot_receiver
520
+ receiver_binding = resolve_local_hover_binding(facts, receiver_name, lsp_line + 1, lsp_char + 1) ||
521
+ facts.values[receiver_name] ||
522
+ facts.functions[receiver_name]
523
+ if receiver_binding && receiver_binding.type
524
+ receiver_type = receiver_binding.respond_to?(:storage_type) ? receiver_binding.storage_type : receiver_binding.type
525
+ methods = methods_for_receiver_type(facts, receiver_type)
526
+ if (method_binding = methods[name])
527
+ signature = method_signature(method_binding)
528
+ else
529
+ type_base = receiver_type.to_s[/^([A-Za-z_]+)/, 1]
530
+ if type_base && (method_sigs = BUILTIN_TYPE_METHOD_SIGNATURES[type_base])
531
+ signature = method_sigs[name]
532
+ end
534
533
  end
535
534
  end
536
535
  end
537
536
  end
538
- end
539
537
 
540
- unless signature
541
- if token_index && (builtin_info = builtin_hover_info(name, tokens, token_index))
542
- signature = builtin_info[:signature]
543
- docs = builtin_info[:docs]
538
+ unless signature
539
+ if token_index && (builtin_info = builtin_hover_info(name, tokens, token_index))
540
+ signature = builtin_info[:signature]
541
+ docs = builtin_info[:docs]
542
+ end
544
543
  end
545
- end
546
544
 
547
- unless signature
548
- if token_index && tokens && parameter_declaration_token?(tokens, token_index)
549
- signature = resolve_lexical_local_hover_signature(uri, name, tokens[token_index])
545
+ unless signature
546
+ if token_index && tokens && parameter_declaration_token?(tokens, token_index)
547
+ signature = resolve_lexical_local_hover_signature(uri, name, tokens[token_index])
548
+ end
549
+ end
550
+
551
+ unless signature
552
+ if token_index && tokens && attribute_target_token?(tokens, token_index)
553
+ signature = "attribute target #{name}"
554
+ end
550
555
  end
551
- end
552
556
 
553
- unless signature
554
- if token_index && tokens && attribute_target_token?(tokens, token_index)
555
- signature = "attribute target #{name}"
556
557
  end
558
+
559
+ return nil unless signature
557
560
  end
558
561
 
562
+ definition_entry = if source_location
563
+ measure_perf_stage(stages, 'definition_entry') { hover_definition_entry_from_location(source_location) }
564
+ elsif resolved_via_type_member
565
+ nil
566
+ else
567
+ measure_perf_stage(stages, 'global_definition') do
568
+ @workspace.find_definition_token_global(
569
+ name,
570
+ preferred_uri: uri,
571
+ before_line: lsp_line + 1,
572
+ before_char: lsp_char + 1,
573
+ )
574
+ end
559
575
  end
560
576
 
561
- return nil unless signature
577
+ source_uri = hover_source_uri_for_definition(definition_entry) || hover_source_uri_from_location(source_location)
578
+ source_line = hover_source_line_for_definition(definition_entry) || hover_source_line_from_location(source_location)
579
+
580
+ {
581
+ signature: signature,
582
+ docs: docs || hover_doc_comment_for_definition(definition_entry),
583
+ doc_comment: hover_doc_comment_data_for_definition(definition_entry),
584
+ source: hover_source_label_for_definition(definition_entry) || hover_source_label_from_location(source_location),
585
+ source_uri: source_uri,
586
+ source_line: source_line,
587
+ }
562
588
  end
563
589
 
564
- definition_entry = if source_location
565
- measure_perf_stage(stages, 'definition_entry') { hover_definition_entry_from_location(source_location) }
566
- elsif resolved_via_type_member
567
- nil
568
- else
569
- measure_perf_stage(stages, 'global_definition') do
570
- @workspace.find_definition_token_global(
571
- name,
572
- preferred_uri: uri,
573
- before_line: lsp_line + 1,
574
- before_char: lsp_char + 1,
575
- )
576
- end
577
- end
590
+ def token_context_at(uri, lsp_line, lsp_char)
591
+ tokens = @workspace.get_tokens(uri) || []
592
+ interpolation_context = fstring_interpolation_token_context(tokens, lsp_line, lsp_char)
593
+ return interpolation_context if interpolation_context
578
594
 
579
- source_uri = hover_source_uri_for_definition(definition_entry) || hover_source_uri_from_location(source_location)
580
- source_line = hover_source_line_for_definition(definition_entry) || hover_source_line_from_location(source_location)
595
+ token = @workspace.find_token_at(uri, lsp_line, lsp_char)
596
+ return nil unless token
581
597
 
582
- {
583
- signature: signature,
584
- docs: docs || hover_doc_comment_for_definition(definition_entry),
585
- doc_comment: hover_doc_comment_data_for_definition(definition_entry),
586
- source: hover_source_label_for_definition(definition_entry) || hover_source_label_from_location(source_location),
587
- source_uri: source_uri,
588
- source_line: source_line,
589
- }
590
- end
598
+ return nil if embedded_heredoc_or_format_heredoc_token?(token)
591
599
 
592
- def token_context_at(uri, lsp_line, lsp_char)
593
- tokens = @workspace.get_tokens(uri) || []
594
- interpolation_context = fstring_interpolation_token_context(tokens, lsp_line, lsp_char)
595
- return interpolation_context if interpolation_context
596
-
597
- token = @workspace.find_token_at(uri, lsp_line, lsp_char)
598
- return nil unless token
600
+ {
601
+ token: token,
602
+ tokens: tokens,
603
+ token_index: tokens.index(token),
604
+ }
605
+ end
599
606
 
600
- return nil if embedded_heredoc_or_format_heredoc_token?(token)
607
+ def embedded_heredoc_or_format_heredoc_token?(token)
608
+ return false unless [:string, :cstring, :fstring].include?(token.type)
601
609
 
602
- {
603
- token: token,
604
- tokens: tokens,
605
- token_index: tokens.index(token),
606
- }
607
- end
610
+ tag = token.lexeme[/\A(?:f|c)?<<-([A-Za-z_][A-Za-z0-9_]*)[ \t]*\n/, 1]
611
+ return false if tag.nil?
608
612
 
609
- def embedded_heredoc_or_format_heredoc_token?(token)
610
- return false unless [:string, :cstring, :fstring].include?(token.type)
613
+ %w[GLSL VERT FRAG COMP JSON JSONC SQL HTML].include?(tag)
614
+ end
611
615
 
612
- tag = token.lexeme[/\A(?:f|c)?<<-([A-Za-z_][A-Za-z0-9_]*)[ \t]*\n/, 1]
613
- return false if tag.nil?
616
+ def fstring_interpolation_token_context(tokens, lsp_line, lsp_char)
617
+ target_line = lsp_line + 1
618
+ target_char = lsp_char + 1
614
619
 
615
- %w[GLSL VERT FRAG COMP JSON JSONC SQL HTML].include?(tag)
616
- end
620
+ fstring_token = tokens.find do |token|
621
+ next false unless token.type == :fstring
617
622
 
618
- def fstring_interpolation_token_context(tokens, lsp_line, lsp_char)
619
- target_line = lsp_line + 1
620
- target_char = lsp_char + 1
623
+ token_contains_position?(token, target_line, target_char)
624
+ end
625
+ return nil unless fstring_token
621
626
 
622
- fstring_token = tokens.find do |token|
623
- next false unless token.type == :fstring
627
+ Array(fstring_token.literal).each do |part|
628
+ next unless part[:kind] == :expr
629
+ next unless part[:line] == target_line
624
630
 
625
- token_contains_position?(token, target_line, target_char)
626
- end
627
- return nil unless fstring_token
631
+ expression_tokens = interpolation_expression_tokens(part)
632
+ token = expression_tokens.find { |candidate| token_contains_position?(candidate, target_line, target_char) }
633
+ next unless token
628
634
 
629
- Array(fstring_token.literal).each do |part|
630
- next unless part[:kind] == :expr
631
- next unless part[:line] == target_line
635
+ return {
636
+ token: token,
637
+ tokens: expression_tokens,
638
+ token_index: expression_tokens.index(token),
639
+ }
640
+ end
632
641
 
633
- expression_tokens = interpolation_expression_tokens(part)
634
- token = expression_tokens.find { |candidate| token_contains_position?(candidate, target_line, target_char) }
635
- next unless token
642
+ nil
643
+ end
636
644
 
637
- return {
638
- token: token,
639
- tokens: expression_tokens,
640
- token_index: expression_tokens.index(token),
641
- }
645
+ def interpolation_expression_tokens(part)
646
+ source = part[:source]
647
+ return [] if source.nil? || source.strip.empty?
648
+
649
+ MilkTea::Lexer.new(source).lex
650
+ .reject { |token| [:newline, :indent, :dedent, :eof].include?(token.type) }
651
+ .map do |token|
652
+ adjusted_line = part[:line] + token.line - 1
653
+ adjusted_column = token.line == 1 ? (part[:column] + token.column - 1) : token.column
654
+
655
+ token.with(
656
+ line: adjusted_line,
657
+ column: adjusted_column,
658
+ start_offset: nil,
659
+ end_offset: nil,
660
+ leading_trivia: [].freeze,
661
+ trailing_trivia: [].freeze,
662
+ )
663
+ end
664
+ rescue MilkTea::LexError
665
+ []
642
666
  end
643
667
 
644
- nil
645
- end
668
+ def token_contains_position?(token, target_line, target_char)
669
+ segments = token.lexeme.split("\n", -1)
670
+ end_line = token.line + segments.length - 1
671
+ return false if target_line < token.line || target_line > end_line
646
672
 
647
- def interpolation_expression_tokens(part)
648
- source = part[:source]
649
- return [] if source.nil? || source.strip.empty?
650
-
651
- MilkTea::Lexer.new(source).lex
652
- .reject { |token| [:newline, :indent, :dedent, :eof].include?(token.type) }
653
- .map do |token|
654
- adjusted_line = part[:line] + token.line - 1
655
- adjusted_column = token.line == 1 ? (part[:column] + token.column - 1) : token.column
656
-
657
- token.with(
658
- line: adjusted_line,
659
- column: adjusted_column,
660
- start_offset: nil,
661
- end_offset: nil,
662
- leading_trivia: [].freeze,
663
- trailing_trivia: [].freeze,
664
- )
665
- end
666
- rescue MilkTea::LexError
667
- []
668
- end
673
+ if segments.length == 1
674
+ return token.column <= target_char && target_char < (token.column + segments.first.length)
675
+ end
669
676
 
670
- def token_contains_position?(token, target_line, target_char)
671
- segments = token.lexeme.split("\n", -1)
672
- end_line = token.line + segments.length - 1
673
- return false if target_line < token.line || target_line > end_line
677
+ if target_line == token.line
678
+ return token.column <= target_char && target_char <= (token.column + segments.first.length - 1)
679
+ end
674
680
 
675
- if segments.length == 1
676
- return token.column <= target_char && target_char < (token.column + segments.first.length)
681
+ target_char <= segments.fetch(target_line - token.line).length
677
682
  end
678
683
 
679
- if target_line == token.line
680
- return token.column <= target_char && target_char <= (token.column + segments.first.length - 1)
681
- end
684
+ def render_hover_markdown(info)
685
+ lines = []
682
686
 
683
- target_char <= segments.fetch(target_line - token.line).length
684
- end
687
+ signature = info[:signature].to_s
688
+ shortened, modules = shorten_qualified_types(signature)
685
689
 
686
- def render_hover_markdown(info)
687
- lines = []
690
+ lines << "```milk-tea"
691
+ lines << shortened
692
+ lines << "```"
688
693
 
689
- signature = info[:signature].to_s
690
- shortened, modules = shorten_qualified_types(signature)
694
+ unless modules.empty?
695
+ prefix = 'From'
696
+ lines << "*#{prefix} #{modules.join(', ')}*"
697
+ end
691
698
 
692
- lines << "```milk-tea"
693
- lines << shortened
694
- lines << "```"
699
+ rendered_doc_comment = false
700
+ if info[:doc_comment].is_a?(Hash)
701
+ rendered_doc_comment = append_structured_doc_comment_markdown(lines, info[:doc_comment])
702
+ end
695
703
 
696
- unless modules.empty?
697
- prefix = 'From'
698
- lines << "*#{prefix} #{modules.join(', ')}*"
699
- end
704
+ docs = info[:docs].to_s.strip
705
+ unless rendered_doc_comment || docs.empty?
706
+ lines << ""
707
+ lines << docs
708
+ end
700
709
 
701
- rendered_doc_comment = false
702
- if info[:doc_comment].is_a?(Hash)
703
- rendered_doc_comment = append_structured_doc_comment_markdown(lines, info[:doc_comment])
704
- end
710
+ source_uri = info[:source_uri]
711
+ source_line = info[:source_line]
712
+ source_label = info[:source].to_s.strip
713
+ unless source_label.empty?
714
+ lines << ""
715
+ if source_uri && source_line
716
+ link_uri = "#{source_uri}#L#{source_line}"
717
+ lines << "Defined at: [#{source_label}](#{link_uri})"
718
+ else
719
+ lines << "Defined at: #{source_label}"
720
+ end
721
+ end
705
722
 
706
- docs = info[:docs].to_s.strip
707
- unless rendered_doc_comment || docs.empty?
708
- lines << ""
709
- lines << docs
723
+ lines.join("\n")
710
724
  end
711
725
 
712
- source_uri = info[:source_uri]
713
- source_line = info[:source_line]
714
- source_label = info[:source].to_s.strip
715
- unless source_label.empty?
716
- lines << ""
717
- if source_uri && source_line
718
- link_uri = "#{source_uri}#L#{source_line}"
719
- lines << "Defined at: [#{source_label}](#{link_uri})"
720
- else
721
- lines << "Defined at: #{source_label}"
726
+ def shorten_qualified_types(signature)
727
+ modules = []
728
+ shortened = signature.gsub(/\b([a-z_][\w]*(?:\.[a-z_][\w]*)*\.)([A-Z]\w*(?:\[[^\]]*\])?(?:\s*\|\s*(?:[a-z_][\w]*(?:\.[a-z_][\w]*)*\.)?[A-Z]\w*(?:\[[^\]]*\])?)*)\b/) do
729
+ prefix = $1
730
+ mod_name = prefix.delete_suffix('.')
731
+ modules << mod_name unless modules.include?(mod_name)
732
+ $2
722
733
  end
734
+ [shortened, modules]
723
735
  end
724
736
 
725
- lines.join("\n")
726
- end
737
+ def append_structured_doc_comment_markdown(lines, doc_comment)
738
+ body = doc_comment[:body_markdown].to_s.strip
739
+ tags = doc_comment.fetch(:tags, {})
740
+ params = Array(tags[:params]).reject { |entry| entry[:name].to_s.strip.empty? }
741
+ returns = tags[:returns]
742
+ throws = Array(tags[:throws]).reject { |entry| entry[:text].to_s.strip.empty? }
743
+ see_also = Array(tags[:see]).reject { |entry| entry[:text].to_s.strip.empty? }
727
744
 
728
- def shorten_qualified_types(signature)
729
- modules = []
730
- shortened = signature.gsub(/\b([a-z_][\w]*(?:\.[a-z_][\w]*)*\.)([A-Z]\w*(?:\[[^\]]*\])?(?:\s*\|\s*(?:[a-z_][\w]*(?:\.[a-z_][\w]*)*\.)?[A-Z]\w*(?:\[[^\]]*\])?)*)\b/) do
731
- prefix = $1
732
- mod_name = prefix.delete_suffix('.')
733
- modules << mod_name unless modules.include?(mod_name)
734
- $2
735
- end
736
- [shortened, modules]
737
- end
745
+ wrote = false
746
+ unless body.empty?
747
+ lines << ""
748
+ lines << body
749
+ wrote = true
750
+ end
738
751
 
739
- def append_structured_doc_comment_markdown(lines, doc_comment)
740
- body = doc_comment[:body_markdown].to_s.strip
741
- tags = doc_comment.fetch(:tags, {})
742
- params = Array(tags[:params]).reject { |entry| entry[:name].to_s.strip.empty? }
743
- returns = tags[:returns]
744
- throws = Array(tags[:throws]).reject { |entry| entry[:text].to_s.strip.empty? }
745
- see_also = Array(tags[:see]).reject { |entry| entry[:text].to_s.strip.empty? }
746
-
747
- wrote = false
748
- unless body.empty?
749
- lines << ""
750
- lines << body
751
- wrote = true
752
- end
753
-
754
- unless params.empty?
755
- lines << ""
756
- lines << "**Parameters**"
757
- params.each do |entry|
758
- description = entry[:text].to_s.strip
759
- if description.empty?
760
- lines << "- `#{entry[:name]}`"
761
- else
762
- lines << "- `#{entry[:name]}`: #{description}"
752
+ unless params.empty?
753
+ lines << ""
754
+ lines << "**Parameters**"
755
+ params.each do |entry|
756
+ description = entry[:text].to_s.strip
757
+ if description.empty?
758
+ lines << "- `#{entry[:name]}`"
759
+ else
760
+ lines << "- `#{entry[:name]}`: #{description}"
761
+ end
762
+ end
763
+ wrote = true
764
+ end
765
+
766
+ if returns
767
+ description = returns[:text].to_s.strip
768
+ unless description.empty?
769
+ lines << ""
770
+ lines << "**Returns**"
771
+ lines << description
772
+ wrote = true
763
773
  end
764
774
  end
765
- wrote = true
766
- end
767
775
 
768
- if returns
769
- description = returns[:text].to_s.strip
770
- unless description.empty?
776
+ unless throws.empty?
771
777
  lines << ""
772
- lines << "**Returns**"
773
- lines << description
778
+ lines << "**Throws**"
779
+ throws.each do |entry|
780
+ lines << "- #{entry[:text]}"
781
+ end
774
782
  wrote = true
775
783
  end
776
- end
777
784
 
778
- unless throws.empty?
779
- lines << ""
780
- lines << "**Throws**"
781
- throws.each do |entry|
782
- lines << "- #{entry[:text]}"
785
+ unless see_also.empty?
786
+ lines << ""
787
+ lines << "**See Also**"
788
+ see_also.each do |entry|
789
+ lines << "- #{entry[:text]}"
790
+ end
791
+ wrote = true
783
792
  end
784
- wrote = true
785
- end
786
793
 
787
- unless see_also.empty?
788
- lines << ""
789
- lines << "**See Also**"
790
- see_also.each do |entry|
791
- lines << "- #{entry[:text]}"
792
- end
793
- wrote = true
794
+ wrote
794
795
  end
795
796
 
796
- wrote
797
- end
797
+ def hover_doc_comment_for_definition(definition_entry)
798
+ return nil unless definition_entry
798
799
 
799
- def hover_doc_comment_for_definition(definition_entry)
800
- return nil unless definition_entry
800
+ @workspace.doc_comment_for_definition(definition_entry[:uri], definition_entry[:token])
801
+ end
801
802
 
802
- @workspace.doc_comment_for_definition(definition_entry[:uri], definition_entry[:token])
803
- end
803
+ def hover_doc_comment_data_for_definition(definition_entry)
804
+ return nil unless definition_entry
804
805
 
805
- def hover_doc_comment_data_for_definition(definition_entry)
806
- return nil unless definition_entry
806
+ @workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
807
+ end
807
808
 
808
- @workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
809
- end
809
+ def signature_help_doc_comment_for_call(uri, name, lsp_line, lsp_char)
810
+ definition_entry = @workspace.find_definition_token_global(
811
+ name,
812
+ preferred_uri: uri,
813
+ before_line: lsp_line + 1,
814
+ before_char: lsp_char + 1,
815
+ )
816
+ return nil unless definition_entry
810
817
 
811
- def signature_help_doc_comment_for_call(uri, name, lsp_line, lsp_char)
812
- definition_entry = @workspace.find_definition_token_global(
813
- name,
814
- preferred_uri: uri,
815
- before_line: lsp_line + 1,
816
- before_char: lsp_char + 1,
817
- )
818
- return nil unless definition_entry
818
+ @workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
819
+ end
819
820
 
820
- @workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
821
- end
821
+ def signature_help_markdown_for_doc_comment(doc_comment)
822
+ return '' unless doc_comment.is_a?(Hash)
822
823
 
823
- def signature_help_markdown_for_doc_comment(doc_comment)
824
- return '' unless doc_comment.is_a?(Hash)
824
+ lines = []
825
+ body = doc_comment[:body_markdown].to_s.strip
826
+ lines << body unless body.empty?
825
827
 
826
- lines = []
827
- body = doc_comment[:body_markdown].to_s.strip
828
- lines << body unless body.empty?
828
+ returns = doc_tag_return_description(doc_comment)
829
+ unless returns.empty?
830
+ lines << '' unless lines.empty?
831
+ lines << "**Returns**"
832
+ lines << returns
833
+ end
829
834
 
830
- returns = doc_tag_return_description(doc_comment)
831
- unless returns.empty?
832
- lines << '' unless lines.empty?
833
- lines << "**Returns**"
834
- lines << returns
835
+ lines.join("\n")
835
836
  end
836
837
 
837
- lines.join("\n")
838
- end
839
-
840
- def doc_tag_param_descriptions(doc_comment)
841
- return {} unless doc_comment.is_a?(Hash)
838
+ def doc_tag_param_descriptions(doc_comment)
839
+ return {} unless doc_comment.is_a?(Hash)
842
840
 
843
- Array(doc_comment.dig(:tags, :params)).each_with_object({}) do |entry, docs|
844
- name = entry[:name].to_s
845
- next if name.empty?
841
+ Array(doc_comment.dig(:tags, :params)).each_with_object({}) do |entry, docs|
842
+ name = entry[:name].to_s
843
+ next if name.empty?
846
844
 
847
- text = entry[:text].to_s.strip
848
- next if text.empty?
845
+ text = entry[:text].to_s.strip
846
+ next if text.empty?
849
847
 
850
- docs[name] = text
848
+ docs[name] = text
849
+ end
851
850
  end
852
- end
853
851
 
854
- def doc_tag_return_description(doc_comment)
855
- return '' unless doc_comment.is_a?(Hash)
852
+ def doc_tag_return_description(doc_comment)
853
+ return '' unless doc_comment.is_a?(Hash)
856
854
 
857
- doc_comment.dig(:tags, :returns, :text).to_s.strip
858
- end
855
+ doc_comment.dig(:tags, :returns, :text).to_s.strip
856
+ end
859
857
 
860
- def completion_function_documentation(uri, name, cache:)
861
- key = [uri, name]
862
- return cache[key] if cache.key?(key)
858
+ def completion_function_documentation(uri, name, cache:)
859
+ key = [uri, name]
860
+ return cache[key] if cache.key?(key)
863
861
 
864
- definition_entry = @workspace.find_definition_token_global(name, preferred_uri: uri)
865
- unless definition_entry
866
- cache[key] = ''
867
- return ''
868
- end
862
+ definition_entry = @workspace.find_definition_token_global(name, preferred_uri: uri)
863
+ unless definition_entry
864
+ cache[key] = ''
865
+ return ''
866
+ end
869
867
 
870
- doc_comment = @workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
871
- cache[key] = signature_help_markdown_for_doc_comment(doc_comment)
872
- end
868
+ doc_comment = @workspace.doc_comment_data_for_definition(definition_entry[:uri], definition_entry[:token])
869
+ cache[key] = signature_help_markdown_for_doc_comment(doc_comment)
870
+ end
873
871
 
874
- def hover_source_label_for_definition(definition_entry)
875
- return nil unless definition_entry
872
+ def hover_source_label_for_definition(definition_entry)
873
+ return nil unless definition_entry
876
874
 
877
- hover_source_label(definition_entry[:uri], definition_entry[:token].line)
878
- end
875
+ hover_source_label(definition_entry[:uri], definition_entry[:token].line)
876
+ end
879
877
 
880
- def hover_source_uri_for_definition(definition_entry)
881
- return nil unless definition_entry
878
+ def hover_source_uri_for_definition(definition_entry)
879
+ return nil unless definition_entry
882
880
 
883
- definition_entry[:uri]
884
- end
881
+ definition_entry[:uri]
882
+ end
885
883
 
886
- def hover_source_line_for_definition(definition_entry)
887
- return nil unless definition_entry
884
+ def hover_source_line_for_definition(definition_entry)
885
+ return nil unless definition_entry
888
886
 
889
- definition_entry[:token].line
890
- end
887
+ definition_entry[:token].line
888
+ end
891
889
 
892
- def hover_source_label_from_location(location)
893
- return nil unless location
890
+ def hover_source_label_from_location(location)
891
+ return nil unless location
894
892
 
895
- line = location.dig(:range, :start, :line)
896
- hover_source_label(location[:uri], (line || 0) + 1)
897
- end
893
+ line = location.dig(:range, :start, :line)
894
+ hover_source_label(location[:uri], (line || 0) + 1)
895
+ end
898
896
 
899
- def hover_source_uri_from_location(location)
900
- return nil unless location
897
+ def hover_source_uri_from_location(location)
898
+ return nil unless location
901
899
 
902
- location[:uri]
903
- end
900
+ location[:uri]
901
+ end
904
902
 
905
- def hover_source_line_from_location(location)
906
- return nil unless location
903
+ def hover_source_line_from_location(location)
904
+ return nil unless location
907
905
 
908
- line = location.dig(:range, :start, :line)
909
- (line || 0) + 1
910
- end
906
+ line = location.dig(:range, :start, :line)
907
+ (line || 0) + 1
908
+ end
911
909
 
912
- def hover_source_label(uri, line)
913
- path = uri_to_path(uri)
914
- return nil unless path
915
-
916
- display = path
917
- if @root_uri
918
- root_path = uri_to_path(@root_uri)
919
- if root_path
920
- begin
921
- relative = Pathname.new(path).relative_path_from(Pathname.new(root_path)).to_s
922
- display = relative unless relative.start_with?('..')
923
- rescue StandardError
924
- display = path
910
+ def hover_source_label(uri, line)
911
+ path = uri_to_path(uri)
912
+ return nil unless path
913
+
914
+ display = path
915
+ if @root_uri
916
+ root_path = uri_to_path(@root_uri)
917
+ if root_path
918
+ begin
919
+ relative = Pathname.new(path).relative_path_from(Pathname.new(root_path)).to_s
920
+ display = relative unless relative.start_with?('..')
921
+ rescue StandardError
922
+ display = path
923
+ end
925
924
  end
926
925
  end
927
- end
928
-
929
- "#{display}:#{line}"
930
- end
931
-
932
- def hover_definition_entry_from_location(location)
933
- return nil unless location
934
926
 
935
- start = location.dig(:range, :start)
936
- return nil unless start
927
+ "#{display}:#{line}"
928
+ end
937
929
 
938
- token = @workspace.find_token_at(location[:uri], start[:line], start[:character])
939
- return nil unless token
930
+ def hover_definition_entry_from_location(location)
931
+ return nil unless location
940
932
 
941
- { uri: location[:uri], token: token }
942
- end
933
+ start = location.dig(:range, :start)
934
+ return nil unless start
943
935
 
944
- def format_params(params)
945
- params.map { |p| "#{p.name}: #{p.type}" }.join(', ')
946
- end
936
+ token = @workspace.find_token_at(location[:uri], start[:line], start[:character])
937
+ return nil unless token
947
938
 
948
- def interface_signature(binding)
949
- method_lines = binding.methods.values.map do |method|
950
- " #{interface_method_signature(method)}"
939
+ { uri: location[:uri], token: token }
951
940
  end
952
941
 
953
- (["interface #{binding.name}"] + method_lines).join("\n")
954
- end
955
-
956
- def interface_method_signature(binding)
957
- keyword = binding.kind == :editable ? 'editable function' : 'function'
958
- keyword = "async #{keyword}" if binding.async
959
- "#{keyword} #{binding.name}(#{format_params(binding.params)}) -> #{binding.return_type}"
960
- end
942
+ def format_params(params)
943
+ params.map { |p| "#{p.name}: #{p.type}" }.join(', ')
944
+ end
961
945
 
962
- def resolve_dot_receiver_value_type(facts, receiver_name, line, char)
963
- local_type = resolve_local_hover_type(facts, receiver_name, line, char)
964
- return local_type if local_type
946
+ def interface_signature(binding)
947
+ method_lines = binding.methods.values.map do |method|
948
+ " #{interface_method_signature(method)}"
949
+ end
965
950
 
966
- facts.values[receiver_name]&.type
967
- end
951
+ (["interface #{binding.name}"] + method_lines).join("\n")
952
+ end
968
953
 
969
- def resolve_member_access_hover_info(current_uri, facts, tokens, token_index)
970
- chain = member_access_chain_at(tokens, token_index)
971
- return nil unless chain
954
+ def interface_method_signature(binding)
955
+ keyword = binding.kind == :editable ? 'editable function' : 'function'
956
+ keyword = "async #{keyword}" if binding.async
957
+ "#{keyword} #{binding.name}(#{format_params(binding.params)}) -> #{binding.return_type}"
958
+ end
972
959
 
973
- hovered_segment = chain[:segments].find { |segment| segment[:token_index] == token_index }
974
- return nil unless hovered_segment && hovered_segment[:position].positive?
960
+ def resolve_dot_receiver_value_type(facts, receiver_name, line, char)
961
+ local_type = resolve_local_hover_type(facts, receiver_name, line, char)
962
+ return local_type if local_type
975
963
 
976
- current_type = resolve_dot_receiver_value_type(
977
- facts,
978
- chain[:segments].first[:name],
979
- chain[:line],
980
- chain[:char],
981
- )
982
- unless current_type
983
- first_name = chain[:segments].first[:name]
984
- current_type = facts.types[first_name]
964
+ facts.values[receiver_name]&.type
985
965
  end
986
- return nil unless current_type
987
966
 
988
- chain[:segments][1..hovered_segment[:position]].each do |segment|
989
- field_receiver_type = project_field_receiver_type_for_completion(current_type, facts)
990
- if field_receiver_type.respond_to?(:field) && (field_type = field_receiver_type.field(segment[:name]))
991
- source_location = field_definition_location(current_uri, field_receiver_type, segment[:name])
967
+ def resolve_member_access_hover_info(current_uri, facts, tokens, token_index)
968
+ chain = member_access_chain_at(tokens, token_index)
969
+ return nil unless chain
970
+
971
+ hovered_segment = chain[:segments].find { |segment| segment[:token_index] == token_index }
972
+ return nil unless hovered_segment && hovered_segment[:position].positive?
973
+
974
+ current_type = resolve_dot_receiver_value_type(
975
+ facts,
976
+ chain[:segments].first[:name],
977
+ chain[:line],
978
+ chain[:char],
979
+ )
980
+ unless current_type
981
+ first_name = chain[:segments].first[:name]
982
+ current_type = facts.types[first_name]
983
+ end
984
+ return nil unless current_type
985
+
986
+ chain[:segments][1..hovered_segment[:position]].each do |segment|
987
+ field_receiver_type = project_field_receiver_type_for_completion(current_type, facts)
988
+ if field_receiver_type.respond_to?(:field) && (field_type = field_receiver_type.field(segment[:name]))
989
+ source_location = field_definition_location(current_uri, field_receiver_type, segment[:name])
990
+
991
+ if segment[:token_index] == token_index
992
+ definition_entry = hover_definition_entry_from_location(source_location)
993
+ return {
994
+ signature: field_hover_signature(segment[:name], field_type),
995
+ docs: hover_doc_comment_for_definition(definition_entry),
996
+ source: hover_source_label_from_location(source_location),
997
+ source_uri: hover_source_uri_from_location(source_location),
998
+ source_line: hover_source_line_from_location(source_location),
999
+ }
1000
+ end
992
1001
 
993
- if segment[:token_index] == token_index
994
- definition_entry = hover_definition_entry_from_location(source_location)
995
- return {
996
- signature: field_hover_signature(segment[:name], field_type),
997
- docs: hover_doc_comment_for_definition(definition_entry),
998
- source: hover_source_label_from_location(source_location),
999
- source_uri: hover_source_uri_from_location(source_location),
1000
- source_line: hover_source_line_from_location(source_location),
1001
- }
1002
+ current_type = field_type
1003
+ next
1002
1004
  end
1003
1005
 
1004
- current_type = field_type
1005
- next
1006
- end
1007
-
1008
- if current_type.respond_to?(:nested_types) && (nested = current_type.nested_types[segment[:name]])
1009
- if segment[:token_index] == token_index
1010
- return {
1011
- signature: type_hover_signature(segment[:name], nested),
1012
- docs: BUILTIN_TYPE_DOCS[segment[:name]],
1013
- }
1006
+ if current_type.respond_to?(:nested_types) && (nested = current_type.nested_types[segment[:name]])
1007
+ if segment[:token_index] == token_index
1008
+ return {
1009
+ signature: type_hover_signature(segment[:name], nested),
1010
+ docs: BUILTIN_TYPE_DOCS[segment[:name]],
1011
+ }
1012
+ end
1013
+ current_type = nested
1014
+ next
1014
1015
  end
1015
- current_type = nested
1016
- next
1017
- end
1018
1016
 
1019
- next unless segment[:token_index] == token_index
1017
+ next unless segment[:token_index] == token_index
1020
1018
 
1021
- method_receiver_type = project_method_receiver_type_for_completion(current_type)
1022
- method_info = member_method_info_for_receiver_type(facts, method_receiver_type, segment[:name])
1023
- return nil unless method_info
1019
+ method_receiver_type = project_method_receiver_type_for_completion(current_type)
1020
+ method_info = member_method_info_for_receiver_type(facts, method_receiver_type, segment[:name])
1021
+ return nil unless method_info
1024
1022
 
1025
- source_location = module_member_binding_location(current_uri, method_info[:module_name], segment[:name], method_info[:binding])
1026
- source_location ||= module_member_definition_location(current_uri, method_info[:module_name], segment[:name])
1027
- definition_entry = hover_definition_entry_from_location(source_location)
1023
+ source_location = module_member_binding_location(current_uri, method_info[:module_name], segment[:name], method_info[:binding])
1024
+ source_location ||= module_member_definition_location(current_uri, method_info[:module_name], segment[:name])
1025
+ definition_entry = hover_definition_entry_from_location(source_location)
1028
1026
 
1029
- return {
1030
- signature: method_signature(method_info[:binding]),
1031
- docs: hover_doc_comment_for_definition(definition_entry),
1032
- source: hover_source_label_from_location(source_location),
1033
- source_uri: hover_source_uri_from_location(source_location),
1034
- source_line: hover_source_line_from_location(source_location),
1035
- }
1027
+ return {
1028
+ signature: method_signature(method_info[:binding]),
1029
+ docs: hover_doc_comment_for_definition(definition_entry),
1030
+ source: hover_source_label_from_location(source_location),
1031
+ source_uri: hover_source_uri_from_location(source_location),
1032
+ source_line: hover_source_line_from_location(source_location),
1033
+ }
1034
+ end
1035
+
1036
+ nil
1036
1037
  end
1037
1038
 
1038
- nil
1039
- end
1039
+ def member_method_info_for_receiver_type(facts, receiver_type, method_name)
1040
+ return nil unless receiver_type
1040
1041
 
1041
- def member_method_info_for_receiver_type(facts, receiver_type, method_name)
1042
- return nil unless receiver_type
1042
+ dispatch_receiver_type = method_dispatch_receiver_type_for_completion(receiver_type)
1043
1043
 
1044
- dispatch_receiver_type = method_dispatch_receiver_type_for_completion(receiver_type)
1044
+ if (binding = find_method_entry(facts.methods, receiver_type, method_name))
1045
+ return {
1046
+ binding: binding,
1047
+ module_name: facts.module_name,
1048
+ }
1049
+ end
1045
1050
 
1046
- if (binding = find_method_entry(facts.methods, receiver_type, method_name))
1047
- return {
1048
- binding: binding,
1049
- module_name: facts.module_name,
1050
- }
1051
- end
1051
+ if dispatch_receiver_type != receiver_type && (binding = find_method_entry(facts.methods, dispatch_receiver_type, method_name))
1052
+ return {
1053
+ binding: binding,
1054
+ module_name: facts.module_name,
1055
+ }
1056
+ end
1052
1057
 
1053
- if dispatch_receiver_type != receiver_type && (binding = find_method_entry(facts.methods, dispatch_receiver_type, method_name))
1054
- return {
1055
- binding: binding,
1056
- module_name: facts.module_name,
1057
- }
1058
- end
1058
+ facts.imports.each_value do |module_binding|
1059
+ binding = find_method_entry(module_binding.methods, receiver_type, method_name)
1060
+ if binding.nil? && dispatch_receiver_type != receiver_type
1061
+ binding = find_method_entry(module_binding.methods, dispatch_receiver_type, method_name)
1062
+ end
1063
+ next unless binding
1059
1064
 
1060
- facts.imports.each_value do |module_binding|
1061
- binding = find_method_entry(module_binding.methods, receiver_type, method_name)
1062
- if binding.nil? && dispatch_receiver_type != receiver_type
1063
- binding = find_method_entry(module_binding.methods, dispatch_receiver_type, method_name)
1065
+ return {
1066
+ binding: binding,
1067
+ module_name: module_binding.name,
1068
+ }
1064
1069
  end
1065
- next unless binding
1066
1070
 
1067
- return {
1068
- binding: binding,
1069
- module_name: module_binding.name,
1070
- }
1071
+ nil
1071
1072
  end
1072
1073
 
1073
- nil
1074
- end
1075
-
1076
- def find_method_entry(methods_table, receiver_type, method_name)
1077
- methods_table.fetch(receiver_type, {})[method_name] || methods_table.fetch(receiver_type, {})["static:#{method_name}"]
1078
- end
1074
+ def find_method_entry(methods_table, receiver_type, method_name)
1075
+ methods_table.fetch(receiver_type, {})[method_name] || methods_table.fetch(receiver_type, {})["static:#{method_name}"]
1076
+ end
1079
1077
 
1080
- def resolve_enum_member_hover_info(current_uri, facts, tokens, token_index)
1081
- member_info = resolve_enum_member_access_info(current_uri, facts, tokens, token_index)
1082
- return nil unless member_info
1078
+ def resolve_enum_member_hover_info(current_uri, facts, tokens, token_index)
1079
+ member_info = resolve_enum_member_access_info(current_uri, facts, tokens, token_index)
1080
+ return nil unless member_info
1083
1081
 
1084
- signature = "#{member_info[:member_name]}: #{member_info[:receiver_label]}"
1085
- signature += " = #{member_info[:value_text]}" if member_info[:value_text]
1082
+ signature = "#{member_info[:member_name]}: #{member_info[:receiver_label]}"
1083
+ signature += " = #{member_info[:value_text]}" if member_info[:value_text]
1086
1084
 
1087
- {
1088
- signature: signature,
1089
- docs: nil,
1090
- source: hover_source_label_from_location(member_info[:location]),
1091
- source_uri: hover_source_uri_from_location(member_info[:location]),
1092
- source_line: hover_source_line_from_location(member_info[:location]),
1093
- }
1094
- end
1085
+ {
1086
+ signature: signature,
1087
+ docs: nil,
1088
+ source: hover_source_label_from_location(member_info[:location]),
1089
+ source_uri: hover_source_uri_from_location(member_info[:location]),
1090
+ source_line: hover_source_line_from_location(member_info[:location]),
1091
+ }
1092
+ end
1095
1093
 
1096
- def resolve_enum_member_definition_location(current_uri, facts, tokens, token_index)
1097
- resolve_enum_member_access_info(current_uri, facts, tokens, token_index)&.fetch(:location, nil)
1098
- end
1094
+ def resolve_enum_member_definition_location(current_uri, facts, tokens, token_index)
1095
+ resolve_enum_member_access_info(current_uri, facts, tokens, token_index)&.fetch(:location, nil)
1096
+ end
1099
1097
 
1100
- def resolve_enum_member_access_info(current_uri, facts, tokens, token_index)
1101
- return nil unless type_name_member_access?(tokens, token_index, facts)
1098
+ def resolve_enum_member_access_info(current_uri, facts, tokens, token_index)
1099
+ return nil unless type_name_member_access?(tokens, token_index, facts)
1102
1100
 
1103
- token = tokens[token_index]
1104
- token_end_char = token.column - 1 + token.lexeme.length
1105
- receiver_name = @workspace.find_dot_receiver(current_uri, token.line - 1, token_end_char)
1106
- receiver_path = @workspace.find_dot_receiver_path(current_uri, token.line - 1, token_end_char)
1107
- receiver_info = resolve_type_receiver_info(facts, receiver_name, receiver_path)
1108
- return nil unless receiver_info
1101
+ token = tokens[token_index]
1102
+ token_end_char = token.column - 1 + token.lexeme.length
1103
+ receiver_name = @workspace.find_dot_receiver(current_uri, token.line - 1, token_end_char)
1104
+ receiver_path = @workspace.find_dot_receiver_path(current_uri, token.line - 1, token_end_char)
1105
+ receiver_info = resolve_type_receiver_info(facts, receiver_name, receiver_path)
1106
+ return nil unless receiver_info
1109
1107
 
1110
- receiver_type = receiver_info[:type]
1111
- return nil unless receiver_type.is_a?(Types::EnumBase)
1112
- return nil unless receiver_type.member(token.lexeme)
1108
+ receiver_type = receiver_info[:type]
1109
+ return nil unless receiver_type.is_a?(Types::EnumBase)
1110
+ return nil unless receiver_type.member(token.lexeme)
1113
1111
 
1114
- owner_module_name = receiver_type.respond_to?(:module_name) ? receiver_type.module_name : receiver_info[:module_name]
1112
+ owner_module_name = receiver_type.respond_to?(:module_name) ? receiver_type.module_name : receiver_info[:module_name]
1115
1113
 
1116
- {
1117
- receiver_label: receiver_info[:label],
1118
- member_name: token.lexeme,
1119
- value_text: enum_member_value_text(current_uri, owner_module_name, receiver_type.name, token.lexeme),
1120
- location: enum_member_definition_location(current_uri, owner_module_name, receiver_type.name, token.lexeme),
1121
- }
1122
- end
1114
+ {
1115
+ receiver_label: receiver_info[:label],
1116
+ member_name: token.lexeme,
1117
+ value_text: enum_member_value_text(current_uri, owner_module_name, receiver_type.name, token.lexeme),
1118
+ location: enum_member_definition_location(current_uri, owner_module_name, receiver_type.name, token.lexeme),
1119
+ }
1120
+ end
1123
1121
 
1124
- def resolve_field_declaration_hover_info(current_uri, facts, tokens, token_index)
1125
- receiver_info = field_declaration_receiver_info(facts, tokens, token_index)
1126
- return nil unless receiver_info
1122
+ def resolve_field_declaration_hover_info(current_uri, facts, tokens, token_index)
1123
+ receiver_info = field_declaration_receiver_info(facts, tokens, token_index)
1124
+ return nil unless receiver_info
1127
1125
 
1128
- field_name = tokens[token_index].lexeme
1129
- receiver_type = project_field_receiver_type_for_completion(receiver_info[:type], facts)
1130
- return nil unless receiver_type.respond_to?(:field)
1126
+ field_name = tokens[token_index].lexeme
1127
+ receiver_type = project_field_receiver_type_for_completion(receiver_info[:type], facts)
1128
+ return nil unless receiver_type.respond_to?(:field)
1131
1129
 
1132
- field_type = receiver_type.field(field_name)
1133
- return nil unless field_type
1130
+ field_type = receiver_type.field(field_name)
1131
+ return nil unless field_type
1134
1132
 
1135
- source_location = field_definition_location(current_uri, receiver_type, field_name)
1133
+ source_location = field_definition_location(current_uri, receiver_type, field_name)
1136
1134
 
1137
- {
1138
- signature: field_hover_signature(field_name, field_type),
1139
- docs: nil,
1140
- source: hover_source_label_from_location(source_location),
1141
- source_uri: hover_source_uri_from_location(source_location),
1142
- source_line: hover_source_line_from_location(source_location),
1143
- }
1144
- end
1135
+ {
1136
+ signature: field_hover_signature(field_name, field_type),
1137
+ docs: nil,
1138
+ source: hover_source_label_from_location(source_location),
1139
+ source_uri: hover_source_uri_from_location(source_location),
1140
+ source_line: hover_source_line_from_location(source_location),
1141
+ }
1142
+ end
1145
1143
 
1146
- def resolve_named_argument_label_hover_info(current_uri, facts, tokens, token_index)
1147
- receiver_info = named_argument_label_receiver_info(facts, tokens, token_index)
1144
+ def resolve_named_argument_label_hover_info(current_uri, facts, tokens, token_index)
1145
+ receiver_info = named_argument_label_receiver_info(facts, tokens, token_index)
1148
1146
 
1149
- field_name = tokens[token_index].lexeme
1150
- if receiver_info
1151
- receiver_type = project_field_receiver_type_for_completion(receiver_info[:type], facts)
1152
- if receiver_type.respond_to?(:field)
1153
- field_type = receiver_type.field(field_name)
1154
- if field_type
1155
- source_location = field_definition_location(current_uri, receiver_type, field_name)
1156
- return {
1157
- signature: field_hover_signature(field_name, field_type),
1158
- docs: nil,
1159
- source: hover_source_label_from_location(source_location),
1160
- source_uri: hover_source_uri_from_location(source_location),
1161
- source_line: hover_source_line_from_location(source_location),
1162
- }
1147
+ field_name = tokens[token_index].lexeme
1148
+ if receiver_info
1149
+ receiver_type = project_field_receiver_type_for_completion(receiver_info[:type], facts)
1150
+ if receiver_type.respond_to?(:field)
1151
+ field_type = receiver_type.field(field_name)
1152
+ if field_type
1153
+ source_location = field_definition_location(current_uri, receiver_type, field_name)
1154
+ return {
1155
+ signature: field_hover_signature(field_name, field_type),
1156
+ docs: nil,
1157
+ source: hover_source_label_from_location(source_location),
1158
+ source_uri: hover_source_uri_from_location(source_location),
1159
+ source_line: hover_source_line_from_location(source_location),
1160
+ }
1161
+ end
1163
1162
  end
1164
1163
  end
1165
- end
1166
1164
 
1167
- param_info = named_argument_parameter_info(facts, tokens, token_index)
1168
- return nil unless param_info
1165
+ param_info = named_argument_parameter_info(facts, tokens, token_index)
1166
+ return nil unless param_info
1169
1167
 
1170
- {
1171
- signature: param_info[:signature],
1172
- docs: param_info[:docs],
1173
- source: param_info[:source],
1174
- source_uri: param_info[:source_uri],
1175
- source_line: param_info[:source_line],
1176
- }
1177
- end
1168
+ {
1169
+ signature: param_info[:signature],
1170
+ docs: param_info[:docs],
1171
+ source: param_info[:source],
1172
+ source_uri: param_info[:source_uri],
1173
+ source_line: param_info[:source_line],
1174
+ }
1175
+ end
1178
1176
 
1179
- def named_argument_parameter_info(facts, tokens, token_index)
1180
- receiver_name = named_argument_callee_name(tokens, token_index)
1181
- return nil unless receiver_name
1177
+ def named_argument_parameter_info(facts, tokens, token_index)
1178
+ receiver_name = named_argument_callee_name(tokens, token_index)
1179
+ return nil unless receiver_name
1182
1180
 
1183
- field_name = tokens[token_index].lexeme
1181
+ field_name = tokens[token_index].lexeme
1184
1182
 
1185
- if facts.functions.key?(receiver_name)
1186
- func = facts.functions[receiver_name]
1187
- func.type.params.each do |param|
1188
- next unless param.name == field_name
1189
- return named_argument_param_result(field_name, param, func.ast)
1183
+ if facts.functions.key?(receiver_name)
1184
+ func = facts.functions[receiver_name]
1185
+ func.type.params.each do |param|
1186
+ next unless param.name == field_name
1187
+ return named_argument_param_result(field_name, param, func.ast)
1188
+ end
1190
1189
  end
1191
- end
1192
1190
 
1193
- facts.methods.each_value do |methods|
1194
- method = methods[receiver_name]
1195
- next unless method
1196
- method.type.params.each do |param|
1197
- next unless param.name == field_name
1198
- return named_argument_param_result(field_name, param, method.ast)
1191
+ facts.methods.each_value do |methods|
1192
+ method = methods[receiver_name]
1193
+ next unless method
1194
+ method.type.params.each do |param|
1195
+ next unless param.name == field_name
1196
+ return named_argument_param_result(field_name, param, method.ast)
1197
+ end
1199
1198
  end
1199
+
1200
+ nil
1200
1201
  end
1201
1202
 
1202
- nil
1203
- end
1203
+ def named_argument_param_result(field_name, param, callable_ast)
1204
+ param_ast = callable_ast.params.find { |p| p.name == field_name }
1205
+ source_location = param_ast ? ast_name_range(field_name, param_ast.line, param_ast.column) : nil
1206
+ doc_tags = callable_ast.respond_to?(:doc_comment) ? param_doc_for_name(callable_ast, field_name) : nil
1204
1207
 
1205
- def named_argument_param_result(field_name, param, callable_ast)
1206
- param_ast = callable_ast.params.find { |p| p.name == field_name }
1207
- source_location = param_ast ? ast_name_range(field_name, param_ast.line, param_ast.column) : nil
1208
- doc_tags = callable_ast.respond_to?(:doc_comment) ? param_doc_for_name(callable_ast, field_name) : nil
1209
-
1210
- {
1211
- signature: "#{field_name}: #{param.type}",
1212
- docs: doc_tags,
1213
- source: hover_source_label_from_location(source_location),
1214
- source_uri: hover_source_uri_from_location(source_location),
1215
- source_line: hover_source_line_from_location(source_location),
1216
- }
1217
- end
1208
+ {
1209
+ signature: "#{field_name}: #{param.type}",
1210
+ docs: doc_tags,
1211
+ source: hover_source_label_from_location(source_location),
1212
+ source_uri: hover_source_uri_from_location(source_location),
1213
+ source_line: hover_source_line_from_location(source_location),
1214
+ }
1215
+ end
1218
1216
 
1219
- def param_doc_for_name(callable_ast, param_name)
1220
- return nil unless callable_ast.respond_to?(:doc_comment)
1221
- return nil unless callable_ast.doc_comment
1222
-
1223
- lines = callable_ast.doc_comment.lines
1224
- param_lines = []
1225
- in_param = false
1226
- lines.each do |line|
1227
- if line =~ /@param\s+#{Regexp.escape(param_name)}\b/
1228
- in_param = true
1229
- param_lines << line.sub(/^\s*##\s*@param\s+#{Regexp.escape(param_name)}\s*/, "")
1230
- next
1231
- end
1232
- if in_param
1233
- if line =~ /@param\b/
1234
- break
1217
+ def param_doc_for_name(callable_ast, param_name)
1218
+ return nil unless callable_ast.respond_to?(:doc_comment)
1219
+ return nil unless callable_ast.doc_comment
1220
+
1221
+ lines = callable_ast.doc_comment.lines
1222
+ param_lines = []
1223
+ in_param = false
1224
+ lines.each do |line|
1225
+ if line =~ /@param\s+#{Regexp.escape(param_name)}\b/
1226
+ in_param = true
1227
+ param_lines << line.sub(/^\s*##\s*@param\s+#{Regexp.escape(param_name)}\s*/, "")
1228
+ next
1229
+ end
1230
+ if in_param
1231
+ if line =~ /@param\b/
1232
+ break
1233
+ end
1234
+ param_lines << line.sub(/^\s*##\s*/, "")
1235
1235
  end
1236
- param_lines << line.sub(/^\s*##\s*/, "")
1237
1236
  end
1237
+ param_lines.join(" ").strip.empty? ? nil : param_lines.join(" ").strip
1238
1238
  end
1239
- param_lines.join(" ").strip.empty? ? nil : param_lines.join(" ").strip
1240
- end
1241
1239
 
1242
- def named_argument_callee_name(tokens, token_index)
1243
- opener_index = parameter_list_opener_index(tokens, token_index)
1244
- return nil unless opener_index
1240
+ def named_argument_callee_name(tokens, token_index)
1241
+ opener_index = parameter_list_opener_index(tokens, token_index)
1242
+ return nil unless opener_index
1245
1243
 
1246
- head_index = previous_non_trivia_token_index(tokens, opener_index)
1247
- return nil unless head_index
1248
- return nil unless tokens[head_index].type == :identifier
1249
-
1250
- tokens[head_index].lexeme
1251
- end
1244
+ head_index = previous_non_trivia_token_index(tokens, opener_index)
1245
+ return nil unless head_index
1246
+ return nil unless tokens[head_index].type == :identifier
1252
1247
 
1253
- def field_declaration_receiver_info(facts, tokens, token_index)
1254
- token = tokens[token_index]
1255
- return nil unless token
1248
+ tokens[head_index].lexeme
1249
+ end
1256
1250
 
1257
- i = token_index - 1
1258
- while i >= 0
1259
- current = tokens[i]
1260
- i -= 1
1251
+ def field_declaration_receiver_info(facts, tokens, token_index)
1252
+ token = tokens[token_index]
1253
+ return nil unless token
1254
+
1255
+ i = token_index - 1
1256
+ while i >= 0
1257
+ current = tokens[i]
1258
+ i -= 1
1259
+
1260
+ next if [:newline, :indent, :dedent, :eof].include?(current.type)
1261
+ next if current.line == token.line
1262
+ next if current.column >= token.column
1263
+
1264
+ header_line_tokens = non_trivia_tokens_on_line(tokens, current.line)
1265
+ header = header_line_tokens.first
1266
+ type_index = 1
1267
+ if header&.type == :public
1268
+ header = header_line_tokens[1]
1269
+ type_index = 2
1270
+ end
1271
+ return nil unless [:struct, :union].include?(header&.type)
1261
1272
 
1262
- next if [:newline, :indent, :dedent, :eof].include?(current.type)
1263
- next if current.line == token.line
1264
- next if current.column >= token.column
1273
+ type_token = header_line_tokens[type_index]
1274
+ return nil unless type_token&.type == :identifier
1265
1275
 
1266
- header_line_tokens = non_trivia_tokens_on_line(tokens, current.line)
1267
- header = header_line_tokens.first
1268
- type_index = 1
1269
- if header&.type == :public
1270
- header = header_line_tokens[1]
1271
- type_index = 2
1276
+ return resolve_type_receiver_info(facts, type_token.lexeme, type_token.lexeme)
1272
1277
  end
1273
- return nil unless [:struct, :union].include?(header&.type)
1274
-
1275
- type_token = header_line_tokens[type_index]
1276
- return nil unless type_token&.type == :identifier
1277
1278
 
1278
- return resolve_type_receiver_info(facts, type_token.lexeme, type_token.lexeme)
1279
+ nil
1279
1280
  end
1280
1281
 
1281
- nil
1282
- end
1282
+ def named_argument_label_receiver_info(facts, tokens, token_index)
1283
+ opener_index = parameter_list_opener_index(tokens, token_index)
1284
+ return nil unless opener_index
1283
1285
 
1284
- def named_argument_label_receiver_info(facts, tokens, token_index)
1285
- opener_index = parameter_list_opener_index(tokens, token_index)
1286
- return nil unless opener_index
1286
+ head_index = previous_non_trivia_token_index(tokens, opener_index)
1287
+ return nil unless head_index
1287
1288
 
1288
- head_index = previous_non_trivia_token_index(tokens, opener_index)
1289
- return nil unless head_index
1289
+ if tokens[head_index].type == :rbracket
1290
+ lbracket_index = matching_opener_index(tokens, head_index)
1291
+ return nil unless lbracket_index
1290
1292
 
1291
- if tokens[head_index].type == :rbracket
1292
- lbracket_index = matching_opener_index(tokens, head_index)
1293
- return nil unless lbracket_index
1293
+ head_index = previous_non_trivia_token_index(tokens, lbracket_index)
1294
+ return nil unless head_index
1295
+ end
1294
1296
 
1295
- head_index = previous_non_trivia_token_index(tokens, lbracket_index)
1296
- return nil unless head_index
1297
- end
1297
+ head = tokens[head_index]
1298
+ return nil unless head.type == :identifier
1298
1299
 
1299
- head = tokens[head_index]
1300
- return nil unless head.type == :identifier
1300
+ receiver_name = head.lexeme
1301
+ receiver_path = receiver_name
1301
1302
 
1302
- receiver_name = head.lexeme
1303
- receiver_path = receiver_name
1303
+ dot_index = previous_non_trivia_token_index(tokens, head_index)
1304
+ if dot_index && tokens[dot_index].type == :dot
1305
+ module_index = previous_non_trivia_token_index(tokens, dot_index)
1306
+ return nil unless module_index && tokens[module_index].type == :identifier
1304
1307
 
1305
- dot_index = previous_non_trivia_token_index(tokens, head_index)
1306
- if dot_index && tokens[dot_index].type == :dot
1307
- module_index = previous_non_trivia_token_index(tokens, dot_index)
1308
- return nil unless module_index && tokens[module_index].type == :identifier
1308
+ receiver_path = "#{tokens[module_index].lexeme}.#{receiver_name}"
1309
+ end
1309
1310
 
1310
- receiver_path = "#{tokens[module_index].lexeme}.#{receiver_name}"
1311
+ resolve_type_receiver_info(facts, receiver_name, receiver_path)
1311
1312
  end
1312
1313
 
1313
- resolve_type_receiver_info(facts, receiver_name, receiver_path)
1314
- end
1314
+ def member_access_chain_at(tokens, token_index)
1315
+ token = tokens[token_index]
1316
+ return nil unless token&.type == :identifier
1315
1317
 
1316
- def member_access_chain_at(tokens, token_index)
1317
- token = tokens[token_index]
1318
- return nil unless token&.type == :identifier
1318
+ indices = [token_index]
1319
+ current_index = token_index
1319
1320
 
1320
- indices = [token_index]
1321
- current_index = token_index
1321
+ loop do
1322
+ dot_index = previous_non_trivia_token_index(tokens, current_index)
1323
+ break unless dot_index && tokens[dot_index].type == :dot && tokens[dot_index].line == token.line
1322
1324
 
1323
- loop do
1324
- dot_index = previous_non_trivia_token_index(tokens, current_index)
1325
- break unless dot_index && tokens[dot_index].type == :dot && tokens[dot_index].line == token.line
1325
+ receiver_index = previous_non_trivia_token_index(tokens, dot_index)
1326
+ break unless receiver_index && tokens[receiver_index].type == :identifier && tokens[receiver_index].line == token.line
1326
1327
 
1327
- receiver_index = previous_non_trivia_token_index(tokens, dot_index)
1328
- break unless receiver_index && tokens[receiver_index].type == :identifier && tokens[receiver_index].line == token.line
1328
+ indices.unshift(receiver_index)
1329
+ current_index = receiver_index
1330
+ end
1329
1331
 
1330
- indices.unshift(receiver_index)
1331
- current_index = receiver_index
1332
- end
1332
+ current_index = token_index
1333
+ loop do
1334
+ dot_index = next_non_trivia_token_index(tokens, current_index + 1)
1335
+ break unless dot_index && tokens[dot_index].type == :dot && tokens[dot_index].line == token.line
1333
1336
 
1334
- current_index = token_index
1335
- loop do
1336
- dot_index = next_non_trivia_token_index(tokens, current_index + 1)
1337
- break unless dot_index && tokens[dot_index].type == :dot && tokens[dot_index].line == token.line
1337
+ member_index = next_non_trivia_token_index(tokens, dot_index + 1)
1338
+ break unless member_index && tokens[member_index].type == :identifier && tokens[member_index].line == token.line
1339
+
1340
+ indices << member_index
1341
+ current_index = member_index
1342
+ end
1338
1343
 
1339
- member_index = next_non_trivia_token_index(tokens, dot_index + 1)
1340
- break unless member_index && tokens[member_index].type == :identifier && tokens[member_index].line == token.line
1344
+ return nil if indices.length < 2
1341
1345
 
1342
- indices << member_index
1343
- current_index = member_index
1346
+ {
1347
+ line: token.line,
1348
+ char: token.column + token.lexeme.length,
1349
+ segments: indices.each_with_index.map do |index, position|
1350
+ {
1351
+ name: tokens[index].lexeme,
1352
+ token_index: index,
1353
+ position: position,
1354
+ }
1355
+ end,
1356
+ }
1344
1357
  end
1345
1358
 
1346
- return nil if indices.length < 2
1359
+ def method_binding_at_token(facts, token)
1360
+ facts.methods.each_value do |methods|
1361
+ methods.each_value do |binding|
1362
+ next unless binding.name == token.lexeme
1363
+ next unless binding.ast.is_a?(AST::MethodDef)
1364
+ next unless binding.ast.line == token.line
1365
+ next unless binding.ast.column == token.column
1347
1366
 
1348
- {
1349
- line: token.line,
1350
- char: token.column + token.lexeme.length,
1351
- segments: indices.each_with_index.map do |index, position|
1352
- {
1353
- name: tokens[index].lexeme,
1354
- token_index: index,
1355
- position: position,
1356
- }
1357
- end,
1358
- }
1359
- end
1367
+ return binding
1368
+ end
1369
+ end
1360
1370
 
1361
- def method_binding_at_token(facts, token)
1362
- facts.methods.each_value do |methods|
1363
- methods.each_value do |binding|
1364
- next unless binding.name == token.lexeme
1365
- next unless binding.ast.is_a?(AST::MethodDef)
1366
- next unless binding.ast.line == token.line
1367
- next unless binding.ast.respond_to?(:column) && binding.ast.column == token.column
1371
+ facts.interfaces.each_value do |interface_binding|
1372
+ interface_binding.methods.each_value do |method_binding|
1373
+ next unless method_binding.name == token.lexeme
1374
+ next unless method_binding.ast.line == token.line
1375
+ next unless method_binding.ast.column == token.column
1368
1376
 
1369
- return binding
1377
+ return method_binding
1378
+ end
1370
1379
  end
1380
+
1381
+ nil
1371
1382
  end
1372
1383
 
1373
- facts.interfaces.each_value do |interface_binding|
1374
- interface_binding.methods.each_value do |method_binding|
1375
- next unless method_binding.name == token.lexeme
1376
- next unless method_binding.ast.respond_to?(:line) && method_binding.ast.line == token.line
1377
- next unless method_binding.ast.respond_to?(:column) && method_binding.ast.column == token.column
1384
+ def method_signature(binding)
1385
+ async_prefix = (binding.respond_to?(:async) && binding.async) || (binding.ast.respond_to?(:async) && binding.ast.async) ? 'async ' : ''
1386
+ if binding.respond_to?(:type) && binding.type
1387
+ params_str = format_params(binding.type.params)
1388
+ keyword = case binding.ast.kind
1389
+ when :editable
1390
+ "editable function"
1391
+ when :static
1392
+ "static function"
1393
+ else
1394
+ "function"
1395
+ end
1396
+
1397
+ "#{async_prefix}#{keyword} #{binding.name}(#{params_str}) -> #{binding.type.return_type}"
1398
+ else
1399
+ params_str = binding.params.map { |p| "#{p.name}: #{p.type}" }.join(', ')
1400
+ keyword = case binding.kind
1401
+ when :editable
1402
+ "editable function"
1403
+ when :static
1404
+ "static function"
1405
+ else
1406
+ "function"
1407
+ end
1378
1408
 
1379
- return method_binding
1409
+ "#{async_prefix}#{keyword} #{binding.name}(#{params_str}) -> #{binding.return_type}"
1380
1410
  end
1381
1411
  end
1382
1412
 
1383
- nil
1384
- end
1413
+ def type_hover_signature(name, type)
1414
+ rendered_type = type.to_s
1415
+ return "type #{name}" if rendered_type == name
1385
1416
 
1386
- def method_signature(binding)
1387
- async_prefix = (binding.respond_to?(:async) && binding.async) || (binding.ast.respond_to?(:async) && binding.ast.async) ? 'async ' : ''
1388
- if binding.respond_to?(:type) && binding.type
1389
- params_str = format_params(binding.type.params)
1390
- keyword = case binding.ast.kind
1391
- when :editable
1392
- "editable function"
1393
- when :static
1394
- "static function"
1395
- else
1396
- "function"
1397
- end
1417
+ "type #{name} = #{rendered_type}"
1418
+ end
1398
1419
 
1399
- "#{async_prefix}#{keyword} #{binding.name}(#{params_str}) -> #{binding.type.return_type}"
1400
- else
1401
- params_str = binding.params.map { |p| "#{p.name}: #{p.type}" }.join(', ')
1402
- keyword = case binding.kind
1403
- when :editable
1404
- "editable function"
1405
- when :static
1406
- "static function"
1407
- else
1408
- "function"
1409
- end
1420
+ def field_hover_signature(name, type)
1421
+ "field #{name}: #{type}"
1422
+ end
1423
+
1424
+ def find_nested_type_by_short_name(facts, short_name)
1425
+ matches = facts.types.keys.select { |k| k.to_s.end_with?(".#{short_name}") }
1426
+ return nil unless matches.length == 1
1410
1427
 
1411
- "#{async_prefix}#{keyword} #{binding.name}(#{params_str}) -> #{binding.return_type}"
1428
+ facts.types[matches.first]
1412
1429
  end
1413
- end
1414
1430
 
1415
- def type_hover_signature(name, type)
1416
- rendered_type = type.to_s
1417
- return "type #{name}" if rendered_type == name
1431
+ def find_member_in_types(facts, name)
1432
+ facts.types.reverse_each do |_key, type|
1433
+ next unless type.respond_to?(:members)
1418
1434
 
1419
- "type #{name} = #{rendered_type}"
1420
- end
1435
+ member = type.members.find { |m| m == name }
1436
+ if member
1437
+ value = type.respond_to?(:member_value) ? type.member_value(name) : nil
1438
+ return [type, member, value]
1439
+ end
1440
+ end
1441
+ nil
1442
+ end
1421
1443
 
1422
- def field_hover_signature(name, type)
1423
- "field #{name}: #{type}"
1424
- end
1444
+ def find_variant_arm_in_types(facts, name)
1445
+ facts.types.reverse_each do |_key, type|
1446
+ arm = nil
1447
+ if type.respond_to?(:arms)
1448
+ arm = type.arms[name]
1449
+ elsif type.respond_to?(:arm_names) && type.arm_names.include?(name)
1450
+ arm = type.arm(name)
1451
+ end
1452
+ next unless arm
1425
1453
 
1426
- def find_nested_type_by_short_name(facts, short_name)
1427
- matches = facts.types.keys.select { |k| k.to_s.end_with?(".#{short_name}") }
1428
- return nil unless matches.length == 1
1454
+ fields = arm.map { |fname, ftype| "#{fname}: #{ftype}" }.join(", ")
1455
+ field_str = fields.empty? ? "" : "(#{fields})"
1456
+ return "#{type.name}.#{name}#{field_str}"
1457
+ end
1458
+ nil
1459
+ end
1429
1460
 
1430
- facts.types[matches.first]
1431
- end
1461
+ def builtin_hover_info(name, tokens, token_index)
1462
+ specialization_info = builtin_value_specialization_info(name, tokens, token_index)
1463
+ return specialization_info if specialization_info
1432
1464
 
1433
- def find_member_in_types(facts, name)
1434
- facts.types.reverse_each do |_key, type|
1435
- next unless type.respond_to?(:members)
1465
+ specialized_call_info = builtin_specialized_call_hover_info(name, tokens, token_index)
1466
+ return specialized_call_info if specialized_call_info
1436
1467
 
1437
- member = type.members.find { |m| m == name }
1438
- if member
1439
- value = type.respond_to?(:member_value) ? type.member_value(name) : nil
1440
- return [type, member, value]
1441
- end
1468
+ type_constructor_info = builtin_type_constructor_hover_info(name, tokens, token_index)
1469
+ return type_constructor_info if type_constructor_info
1470
+
1471
+ builtin_call_hover_info(name, tokens, token_index)
1442
1472
  end
1443
- nil
1444
- end
1445
1473
 
1446
- def find_variant_arm_in_types(facts, name)
1447
- facts.types.reverse_each do |_key, type|
1448
- arm = nil
1449
- if type.respond_to?(:arms)
1450
- arm = type.arms[name]
1451
- elsif type.respond_to?(:arm_names) && type.arm_names.include?(name)
1452
- arm = type.arm(name)
1453
- end
1454
- next unless arm
1474
+ def parameter_declaration_token?(tokens, index)
1475
+ return false unless index && tokens[index]&.type == :identifier
1455
1476
 
1456
- fields = arm.map { |fname, ftype| "#{fname}: #{ftype}" }.join(", ")
1457
- field_str = fields.empty? ? "" : "(#{fields})"
1458
- return "#{type.name}.#{name}#{field_str}"
1477
+ prev = previous_non_trivia_token_index(tokens, index)
1478
+ return false unless prev
1479
+ return false unless [:lparen, :comma].include?(tokens[prev].type)
1480
+
1481
+ nxt = next_non_trivia_token_index(tokens, index + 1)
1482
+ nxt && tokens[nxt].type == :colon
1459
1483
  end
1460
- nil
1461
- end
1462
1484
 
1463
- def builtin_hover_info(name, tokens, token_index)
1464
- specialization_info = builtin_value_specialization_info(name, tokens, token_index)
1465
- return specialization_info if specialization_info
1485
+ def attribute_target_token?(tokens, index)
1486
+ return false unless index && tokens[index]&.type == :identifier
1466
1487
 
1467
- specialized_call_info = builtin_specialized_call_hover_info(name, tokens, token_index)
1468
- return specialized_call_info if specialized_call_info
1488
+ prev = previous_non_trivia_token_index(tokens, index)
1489
+ return false unless prev && [:lbracket, :comma].include?(tokens[prev].type)
1469
1490
 
1470
- type_constructor_info = builtin_type_constructor_hover_info(name, tokens, token_index)
1471
- return type_constructor_info if type_constructor_info
1491
+ after = next_non_trivia_token_index(tokens, index + 1)
1492
+ return false unless after && [:rbracket, :comma].include?(tokens[after].type)
1472
1493
 
1473
- builtin_call_hover_info(name, tokens, token_index)
1474
- end
1494
+ true
1495
+ end
1475
1496
 
1476
- def parameter_declaration_token?(tokens, index)
1477
- return false unless index && tokens[index]&.type == :identifier
1497
+ def call_argument_token?(tokens, index)
1498
+ return false unless index && tokens[index]&.type == :identifier
1478
1499
 
1479
- prev = previous_non_trivia_token_index(tokens, index)
1480
- return false unless prev
1481
- return false unless [:lparen, :comma].include?(tokens[prev].type)
1500
+ prev = previous_non_trivia_token_index(tokens, index)
1501
+ return false unless prev && [:lparen, :comma].include?(tokens[prev].type)
1482
1502
 
1483
- nxt = next_non_trivia_token_index(tokens, index + 1)
1484
- nxt && tokens[nxt].type == :colon
1485
- end
1503
+ nxt = next_non_trivia_token_index(tokens, index + 1)
1504
+ !nxt || ![:colon, :rbracket, :comma].include?(tokens[nxt].type)
1505
+ end
1486
1506
 
1487
- def attribute_target_token?(tokens, index)
1488
- return false unless index && tokens[index]&.type == :identifier
1507
+ def builtin_in_member_access_context?(tokens, token_index)
1508
+ prev_index = previous_non_trivia_token_index(tokens, token_index)
1509
+ prev_index && tokens[prev_index].type == :dot
1510
+ end
1489
1511
 
1490
- prev = previous_non_trivia_token_index(tokens, index)
1491
- return false unless prev && [:lbracket, :comma].include?(tokens[prev].type)
1512
+ def member_access_token?(context)
1513
+ tokens = context[:tokens]
1514
+ token_index = context[:token_index]
1515
+ return false unless tokens && token_index
1516
+ prev = previous_non_trivia_token_index(tokens, token_index)
1517
+ prev && tokens[prev].type == :dot
1518
+ end
1492
1519
 
1493
- after = next_non_trivia_token_index(tokens, index + 1)
1494
- return false unless after && [:rbracket, :comma].include?(tokens[after].type)
1520
+ def keyword_member_access_token?(tokens, token_index)
1521
+ return false unless tokens && token_index
1522
+ tok = tokens[token_index]
1523
+ return false unless tok && tok.type != :identifier
1524
+ prev = previous_non_trivia_token_index(tokens, token_index)
1525
+ prev && tokens[prev].type == :dot
1526
+ end
1495
1527
 
1496
- true
1497
- end
1528
+ def builtin_value_specialization_info(name, tokens, token_index)
1529
+ return nil unless %w[zero default reinterpret].include?(name)
1498
1530
 
1499
- def call_argument_token?(tokens, index)
1500
- return false unless index && tokens[index]&.type == :identifier
1531
+ return nil if builtin_in_member_access_context?(tokens, token_index)
1501
1532
 
1502
- prev = previous_non_trivia_token_index(tokens, index)
1503
- return false unless prev && [:lparen, :comma].include?(tokens[prev].type)
1533
+ lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
1534
+ return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
1504
1535
 
1505
- nxt = next_non_trivia_token_index(tokens, index + 1)
1506
- !nxt || ![:colon, :rbracket, :comma].include?(tokens[nxt].type)
1507
- end
1536
+ rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
1537
+ return nil unless rbracket_index
1508
1538
 
1509
- def builtin_in_member_access_context?(tokens, token_index)
1510
- prev_index = previous_non_trivia_token_index(tokens, token_index)
1511
- prev_index && tokens[prev_index].type == :dot
1512
- end
1539
+ specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
1540
+ target_type = render_builtin_specialization(tokens[(lbracket_index + 1)...rbracket_index])
1541
+ return nil if target_type.empty?
1513
1542
 
1514
- def member_access_token?(context)
1515
- tokens = context[:tokens]
1516
- token_index = context[:token_index]
1517
- return false unless tokens && token_index
1518
- prev = previous_non_trivia_token_index(tokens, token_index)
1519
- prev && tokens[prev].type == :dot
1520
- end
1543
+ docs = case name
1544
+ when 'zero'
1545
+ '`zero[T]` returns the raw zero-initialized value for `T`. It is a value form, not a callable.'
1546
+ when 'default'
1547
+ '`default[T]` returns the semantic default value for `T` and requires an accessible zero-argument associated function `T.default()` that returns `T`. It is a value form, not a callable.'
1548
+ when 'reinterpret'
1549
+ '`reinterpret[T](value)` bit-casts a value to `T`; it requires `unsafe` and compatible concrete sized types.'
1550
+ end
1521
1551
 
1522
- def keyword_member_access_token?(tokens, token_index)
1523
- return false unless tokens && token_index
1524
- tok = tokens[token_index]
1525
- return false unless tok && tok.type != :identifier
1526
- prev = previous_non_trivia_token_index(tokens, token_index)
1527
- prev && tokens[prev].type == :dot
1528
- end
1552
+ {
1553
+ signature: if name == 'reinterpret'
1554
+ "builtin #{specialization}(value) -> #{target_type}"
1555
+ else
1556
+ "builtin #{specialization} -> #{target_type}"
1557
+ end,
1558
+ docs: docs,
1559
+ }
1560
+ end
1529
1561
 
1530
- def builtin_value_specialization_info(name, tokens, token_index)
1531
- return nil unless %w[zero default reinterpret].include?(name)
1532
-
1533
- return nil if builtin_in_member_access_context?(tokens, token_index)
1534
-
1535
- lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
1536
- return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
1537
-
1538
- rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
1539
- return nil unless rbracket_index
1540
-
1541
- specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
1542
- target_type = render_builtin_specialization(tokens[(lbracket_index + 1)...rbracket_index])
1543
- return nil if target_type.empty?
1544
-
1545
- docs = case name
1546
- when 'zero'
1547
- '`zero[T]` returns the raw zero-initialized value for `T`. It is a value form, not a callable.'
1548
- when 'default'
1549
- '`default[T]` returns the semantic default value for `T` and requires an accessible zero-argument associated function `T.default()` that returns `T`. It is a value form, not a callable.'
1550
- when 'reinterpret'
1551
- '`reinterpret[T](value)` bit-casts a value to `T`; it requires `unsafe` and compatible concrete sized types.'
1552
- end
1553
-
1554
- {
1555
- signature: if name == 'reinterpret'
1556
- "builtin #{specialization}(value) -> #{target_type}"
1557
- else
1558
- "builtin #{specialization} -> #{target_type}"
1559
- end,
1560
- docs: docs,
1561
- }
1562
- end
1562
+ def builtin_type_constructor_hover_info(name, tokens, token_index)
1563
+ return nil unless %w[array span Option Result SoA str_buffer ref ptr const_ptr own Task atomic simd].include?(name)
1564
+
1565
+ lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
1566
+ return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
1567
+
1568
+ rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
1569
+ return nil unless rbracket_index
1570
+
1571
+ specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
1572
+ after_bracket_index = next_non_trivia_token_index(tokens, rbracket_index + 1)
1573
+
1574
+ if after_bracket_index && tokens[after_bracket_index].type == :lparen
1575
+ docs = case name
1576
+ when 'array'
1577
+ '`array[T, N](...)` constructs a fixed-length array value of type `array[T, N]`.'
1578
+ when 'span'
1579
+ '`span[T](data = ..., len = ...)` constructs a span view over contiguous `T` storage.'
1580
+ when 'SoA'
1581
+ '`SoA[T, N](...)` constructs a Struct-of-Arrays value with `N` elements of type `T`. Fields are stored in separate contiguous arrays.'
1582
+ when 'simd'
1583
+ '`simd[T, N](...)` constructs a SIMD vector value with `N` lanes of type `T`. Lanes are stored in a single vector register.'
1584
+ when 'Option'
1585
+ '`Option[T]` is a built-in optional type with arms `some(value: T)` and `none`.'
1586
+ when 'Result'
1587
+ '`Result[T, E]` is a built-in result type with arms `success(value: T)` and `failure(error: E)`.'
1588
+ end
1563
1589
 
1564
- def builtin_type_constructor_hover_info(name, tokens, token_index)
1565
- return nil unless %w[array span Option Result SoA str_buffer ref ptr const_ptr own Task atomic simd].include?(name)
1566
-
1567
- lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
1568
- return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
1569
-
1570
- rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
1571
- return nil unless rbracket_index
1572
-
1573
- specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
1574
- after_bracket_index = next_non_trivia_token_index(tokens, rbracket_index + 1)
1575
-
1576
- if after_bracket_index && tokens[after_bracket_index].type == :lparen
1577
- docs = case name
1578
- when 'array'
1579
- '`array[T, N](...)` constructs a fixed-length array value of type `array[T, N]`.'
1580
- when 'span'
1581
- '`span[T](data = ..., len = ...)` constructs a span view over contiguous `T` storage.'
1582
- when 'SoA'
1583
- '`SoA[T, N](...)` constructs a Struct-of-Arrays value with `N` elements of type `T`. Fields are stored in separate contiguous arrays.'
1584
- when 'simd'
1585
- '`simd[T, N](...)` constructs a SIMD vector value with `N` lanes of type `T`. Lanes are stored in a single vector register.'
1586
- when 'Option'
1587
- '`Option[T]` is a built-in optional type with arms `some(value: T)` and `none`.'
1588
- when 'Result'
1589
- '`Result[T, E]` is a built-in result type with arms `success(value: T)` and `failure(error: E)`.'
1590
- end
1591
-
1592
- return {
1593
- signature: case name
1594
- when 'array'
1595
- "builtin #{specialization}(...) -> #{specialization}"
1596
- when 'span'
1597
- "builtin #{specialization}(data = ..., len = ...) -> #{specialization}"
1598
- when 'SoA'
1599
- "builtin #{specialization}(...) -> #{specialization}"
1600
- when 'simd'
1601
- "builtin #{specialization}(...) -> #{specialization}"
1602
- when 'Option'
1603
- "builtin #{specialization}(some: value = ...) / #{specialization}(none:)"
1604
- when 'Result'
1605
- "builtin #{specialization}(success: value = ...) / #{specialization}(failure: error = ...)"
1606
- end,
1590
+ return {
1591
+ signature: case name
1592
+ when 'array'
1593
+ "builtin #{specialization}(...) -> #{specialization}"
1594
+ when 'span'
1595
+ "builtin #{specialization}(data = ..., len = ...) -> #{specialization}"
1596
+ when 'SoA'
1597
+ "builtin #{specialization}(...) -> #{specialization}"
1598
+ when 'simd'
1599
+ "builtin #{specialization}(...) -> #{specialization}"
1600
+ when 'Option'
1601
+ "builtin #{specialization}(some: value = ...) / #{specialization}(none:)"
1602
+ when 'Result'
1603
+ "builtin #{specialization}(success: value = ...) / #{specialization}(failure: error = ...)"
1604
+ end,
1605
+ docs: docs,
1606
+ }
1607
+ end
1608
+
1609
+ docs = case name
1610
+ when 'array'
1611
+ '`array[T, N]` is the built-in fixed-length array type.'
1612
+ when 'span'
1613
+ '`span[T]` is the built-in non-owning contiguous view type.'
1614
+ when 'SoA'
1615
+ '`SoA[T, N]` is the built-in Struct-of-Arrays type. Each struct field is stored in a separate contiguous array of `N` elements, improving SIMD/cache behavior for parallel field access.'
1616
+ when 'simd'
1617
+ '`simd[T, N]` is the built-in SIMD vector type. Fixed-width vector of `N` numeric lanes. Supports component-wise arithmetic, lane access via `[i]`, and explicit aligned/unaligned load/store.'
1618
+ when 'Option'
1619
+ '`Option[T]` is the built-in optional value type with `some(value = ...)` and `none` arms.'
1620
+ when 'Result'
1621
+ '`Result[T, E]` is the built-in success/failure type with `success(value = ...)` and `failure(error = ...)` arms.'
1622
+ when 'str_buffer'
1623
+ '`str_buffer[N]` is a fixed-capacity mutable UTF-8 text buffer. Methods: `assign`, `append`, `assign_format`, `append_format`, `clear`, `len`, `as_str`, `as_cstr`.'
1624
+ when 'ref'
1625
+ '`ref[T]` is a non-null borrow reference. Auto-dereferences for member access and method calls. Cannot be stored in module-level variables, constants, or nested containers.'
1626
+ when 'ptr'
1627
+ '`ptr[T]` is a raw mutable pointer. Indexing, dereference, and arithmetic require `unsafe`. Nullable via `ptr[T]?`.'
1628
+ when 'const_ptr'
1629
+ '`const_ptr[T]` is a read-only pointer. Does not require `unsafe` for dereference.'
1630
+ when 'own'
1631
+ '`own[T]` is an owning heap pointer. Auto-dereferences like `ref`. Storable, returnable, and nullable. Allocated via `heap.must_alloc[T](count)`.'
1632
+ when 'Task'
1633
+ '`Task[T]` is an async task future. Returned by `async function`. Use `await` to unwrap, or `aio.wait`/`aio.run` to drive.'
1634
+ when 'atomic'
1635
+ '`atomic[T]` is an atomic value for lock-free concurrent access. `T` must be a primitive integer or `bool`. Methods: `load`, `store`, `add`, `sub`, `exchange`.'
1636
+ end
1637
+
1638
+ {
1639
+ signature: "builtin type #{specialization}",
1607
1640
  docs: docs,
1608
1641
  }
1609
1642
  end
1610
1643
 
1611
- docs = case name
1612
- when 'array'
1613
- '`array[T, N]` is the built-in fixed-length array type.'
1614
- when 'span'
1615
- '`span[T]` is the built-in non-owning contiguous view type.'
1616
- when 'SoA'
1617
- '`SoA[T, N]` is the built-in Struct-of-Arrays type. Each struct field is stored in a separate contiguous array of `N` elements, improving SIMD/cache behavior for parallel field access.'
1618
- when 'simd'
1619
- '`simd[T, N]` is the built-in SIMD vector type. Fixed-width vector of `N` numeric lanes. Supports component-wise arithmetic, lane access via `[i]`, and explicit aligned/unaligned load/store.'
1620
- when 'Option'
1621
- '`Option[T]` is the built-in optional value type with `some(value = ...)` and `none` arms.'
1622
- when 'Result'
1623
- '`Result[T, E]` is the built-in success/failure type with `success(value = ...)` and `failure(error = ...)` arms.'
1624
- when 'str_buffer'
1625
- '`str_buffer[N]` is a fixed-capacity mutable UTF-8 text buffer. Methods: `assign`, `append`, `assign_format`, `append_format`, `clear`, `len`, `as_str`, `as_cstr`.'
1626
- when 'ref'
1627
- '`ref[T]` is a non-null borrow reference. Auto-dereferences for member access and method calls. Cannot be stored in module-level variables, constants, or nested containers.'
1628
- when 'ptr'
1629
- '`ptr[T]` is a raw mutable pointer. Indexing, dereference, and arithmetic require `unsafe`. Nullable via `ptr[T]?`.'
1630
- when 'const_ptr'
1631
- '`const_ptr[T]` is a read-only pointer. Does not require `unsafe` for dereference.'
1632
- when 'own'
1633
- '`own[T]` is an owning heap pointer. Auto-dereferences like `ref`. Storable, returnable, and nullable. Allocated via `heap.must_alloc[T](count)`.'
1634
- when 'Task'
1635
- '`Task[T]` is an async task future. Returned by `async function`. Use `await` to unwrap, or `aio.wait`/`aio.run` to drive.'
1636
- when 'atomic'
1637
- '`atomic[T]` is an atomic value for lock-free concurrent access. `T` must be a primitive integer or `bool`. Methods: `load`, `store`, `add`, `sub`, `exchange`.'
1638
- end
1644
+ def builtin_specialized_call_hover_info(name, tokens, token_index)
1645
+ return nil unless BUILTIN_ASSOCIATED_HOOK_NAMES.include?(name) || name == 'attribute_arg'
1639
1646
 
1640
- {
1641
- signature: "builtin type #{specialization}",
1642
- docs: docs,
1643
- }
1644
- end
1647
+ return nil if builtin_in_member_access_context?(tokens, token_index)
1645
1648
 
1646
- def builtin_specialized_call_hover_info(name, tokens, token_index)
1647
- return nil unless BUILTIN_ASSOCIATED_HOOK_NAMES.include?(name) || name == 'attribute_arg'
1649
+ lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
1650
+ return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
1648
1651
 
1649
- return nil if builtin_in_member_access_context?(tokens, token_index)
1652
+ rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
1653
+ return nil unless rbracket_index
1650
1654
 
1651
- lbracket_index = next_non_trivia_token_index(tokens, token_index + 1)
1652
- return nil unless lbracket_index && tokens[lbracket_index].type == :lbracket
1655
+ after_bracket_index = next_non_trivia_token_index(tokens, rbracket_index + 1)
1656
+ return nil unless after_bracket_index && tokens[after_bracket_index].type == :lparen
1653
1657
 
1654
- rbracket_index = matching_closer_index(tokens, lbracket_index, :lbracket, :rbracket)
1655
- return nil unless rbracket_index
1658
+ specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
1659
+ if name == 'attribute_arg'
1660
+ target_type = render_builtin_specialization(tokens[(lbracket_index + 1)...rbracket_index])
1661
+ return nil if target_type.empty?
1656
1662
 
1657
- after_bracket_index = next_non_trivia_token_index(tokens, rbracket_index + 1)
1658
- return nil unless after_bracket_index && tokens[after_bracket_index].type == :lparen
1663
+ return {
1664
+ signature: "builtin #{specialization}(attribute, param_name) -> #{target_type}",
1665
+ docs: '`attribute_arg[T](attribute, param_name)` returns the compile-time argument value for the named attribute parameter; `T` must exactly match the declared parameter type.'
1666
+ }
1667
+ end
1659
1668
 
1660
- specialization = render_builtin_specialization(tokens[token_index..rbracket_index])
1661
- if name == 'attribute_arg'
1662
- target_type = render_builtin_specialization(tokens[(lbracket_index + 1)...rbracket_index])
1663
- return nil if target_type.empty?
1669
+ docs = case name
1670
+ when 'hash'
1671
+ '`hash[T](value)` lowers to `T.hash(value: const_ptr[T]) -> uint` after borrowing safe lvalues or forwarding existing refs and pointers.'
1672
+ when 'equal'
1673
+ '`equal[T](left, right)` lowers to `T.equal(left: const_ptr[T], right: const_ptr[T]) -> bool` after borrowing safe lvalues or forwarding existing refs and pointers.'
1674
+ when 'order'
1675
+ '`order[T](left, right)` lowers to `T.order(left: const_ptr[T], right: const_ptr[T]) -> int` after borrowing safe lvalues or forwarding existing refs and pointers.'
1676
+ end
1664
1677
 
1665
- return {
1666
- signature: "builtin #{specialization}(attribute, param_name) -> #{target_type}",
1667
- docs: '`attribute_arg[T](attribute, param_name)` returns the compile-time argument value for the named attribute parameter; `T` must exactly match the declared parameter type.'
1678
+ signature = case name
1679
+ when 'hash'
1680
+ "builtin #{specialization}(value) -> uint"
1681
+ when 'equal'
1682
+ "builtin #{specialization}(left, right) -> bool"
1683
+ when 'order'
1684
+ "builtin #{specialization}(left, right) -> int"
1685
+ end
1686
+
1687
+ {
1688
+ signature: signature,
1689
+ docs: docs,
1668
1690
  }
1669
1691
  end
1670
1692
 
1671
- docs = case name
1672
- when 'hash'
1673
- '`hash[T](value)` lowers to `T.hash(value: const_ptr[T]) -> uint` after borrowing safe lvalues or forwarding existing refs and pointers.'
1674
- when 'equal'
1675
- '`equal[T](left, right)` lowers to `T.equal(left: const_ptr[T], right: const_ptr[T]) -> bool` after borrowing safe lvalues or forwarding existing refs and pointers.'
1676
- when 'order'
1677
- '`order[T](left, right)` lowers to `T.order(left: const_ptr[T], right: const_ptr[T]) -> int` after borrowing safe lvalues or forwarding existing refs and pointers.'
1678
- end
1679
-
1680
- signature = case name
1681
- when 'hash'
1682
- "builtin #{specialization}(value) -> uint"
1683
- when 'equal'
1684
- "builtin #{specialization}(left, right) -> bool"
1685
- when 'order'
1686
- "builtin #{specialization}(left, right) -> int"
1687
- end
1688
-
1689
- {
1690
- signature: signature,
1691
- docs: docs,
1692
- }
1693
- end
1694
-
1695
- def builtin_call_hover_info(name, tokens, token_index)
1696
- info = BUILTIN_CALL_HOVER_INFO[name]
1697
- return nil unless info
1693
+ def builtin_call_hover_info(name, tokens, token_index)
1694
+ info = BUILTIN_CALL_HOVER_INFO[name]
1695
+ return nil unless info
1698
1696
 
1699
- return nil if builtin_in_member_access_context?(tokens, token_index)
1697
+ return nil if builtin_in_member_access_context?(tokens, token_index)
1700
1698
 
1701
- next_index = next_non_trivia_token_index(tokens, token_index + 1)
1702
- return nil unless next_index
1703
- next_type = tokens[next_index].type
1704
- return nil unless next_type == :lparen || next_type == :lbracket
1699
+ next_index = next_non_trivia_token_index(tokens, token_index + 1)
1700
+ return nil unless next_index
1701
+ next_type = tokens[next_index].type
1702
+ return nil unless next_type == :lparen || next_type == :lbracket
1705
1703
 
1706
- info
1707
- end
1704
+ info
1705
+ end
1708
1706
 
1709
- def builtin_keyword_hover_info(token)
1710
- return nil unless token
1707
+ def builtin_keyword_hover_info(token)
1708
+ return nil unless token
1711
1709
 
1712
- info = KEYWORD_HOVER_INFO[token.lexeme]
1713
- return info if info && [:size_of, :align_of, :offset_of].include?(token.type)
1710
+ info = KEYWORD_HOVER_INFO[token.lexeme]
1711
+ return info if info && [:size_of, :align_of, :offset_of].include?(token.type)
1714
1712
 
1715
- LANGUAGE_KEYWORD_HOVER_INFO[token.lexeme]
1716
- end
1713
+ LANGUAGE_KEYWORD_HOVER_INFO[token.lexeme]
1714
+ end
1717
1715
 
1718
- def render_builtin_specialization(tokens)
1719
- Array(tokens).map(&:lexeme).join.gsub(',', ', ')
1720
- end
1716
+ def render_builtin_specialization(tokens)
1717
+ Array(tokens).map(&:lexeme).join.gsub(',', ', ')
1718
+ end
1721
1719
 
1722
- def value_hover_signature(binding)
1723
- case binding.kind
1724
- when :const
1725
- "const #{binding.name}: #{binding.type} (immutable)"
1726
- when :var
1727
- "var #{binding.name}: #{binding.type} (mutable)"
1728
- when :let
1729
- "let #{binding.name}: #{binding.type} (immutable)"
1730
- when :param
1731
- "parameter #{binding.name}: #{binding.type} (immutable)"
1732
- when :local
1733
- suffix = binding.mutable ? 'mutable' : 'immutable'
1734
- "local #{binding.name}: #{binding.type} (#{suffix})"
1735
- else
1736
- "#{binding.name}: #{binding.type}"
1720
+ def value_hover_signature(binding)
1721
+ case binding.kind
1722
+ when :const
1723
+ "const #{binding.name}: #{binding.type} (immutable)"
1724
+ when :var
1725
+ "var #{binding.name}: #{binding.type} (mutable)"
1726
+ when :let
1727
+ "let #{binding.name}: #{binding.type} (immutable)"
1728
+ when :param
1729
+ "parameter #{binding.name}: #{binding.type} (immutable)"
1730
+ when :local
1731
+ suffix = binding.mutable ? 'mutable' : 'immutable'
1732
+ "local #{binding.name}: #{binding.type} (#{suffix})"
1733
+ else
1734
+ "#{binding.name}: #{binding.type}"
1735
+ end
1737
1736
  end
1738
- end
1739
1737
 
1740
- def resolve_local_hover_binding(facts, name, line, char)
1741
- declared_binding = declared_generic_local_hover_binding(facts, name, line)
1742
- return declared_binding if declared_binding
1738
+ def resolve_local_hover_binding(facts, name, line, char)
1739
+ declared_binding = declared_generic_local_hover_binding(facts, name, line)
1740
+ return declared_binding if declared_binding
1743
1741
 
1744
- frame = enclosing_completion_frame(facts, line)
1745
- return nil unless frame
1742
+ frame = enclosing_completion_frame(facts, line)
1743
+ return nil unless frame
1746
1744
 
1747
- snapshot = latest_completion_snapshot(frame, line, char)
1748
- binding = snapshot&.bindings&.dig(name)
1749
- return binding if binding
1745
+ snapshot = latest_completion_snapshot(frame, line, char)
1746
+ binding = snapshot&.bindings&.dig(name)
1747
+ return binding if binding
1750
1748
 
1751
- future_snapshot = same_line_future_completion_snapshot(frame, line, char)
1752
- future_snapshot&.bindings&.dig(name)
1753
- end
1749
+ future_snapshot = same_line_future_completion_snapshot(frame, line, char)
1750
+ future_snapshot&.bindings&.dig(name)
1751
+ end
1754
1752
 
1755
- def resolve_as_binding_declaration_hover_binding(facts, name, line, char)
1756
- frame = enclosing_completion_frame(facts, line)
1757
- return nil unless frame
1753
+ def resolve_as_binding_declaration_hover_binding(facts, name, line, char)
1754
+ frame = enclosing_completion_frame(facts, line)
1755
+ return nil unless frame
1758
1756
 
1759
- Array(frame.snapshots).each do |snapshot|
1760
- next if snapshot.line < line
1761
- next if snapshot.line == line && snapshot.column <= char
1757
+ Array(frame.snapshots).each do |snapshot|
1758
+ next if snapshot.line < line
1759
+ next if snapshot.line == line && snapshot.column <= char
1762
1760
 
1763
- binding = snapshot.bindings[name]
1764
- return binding if binding
1765
- end
1761
+ binding = snapshot.bindings[name]
1762
+ return binding if binding
1763
+ end
1766
1764
 
1767
- nil
1768
- end
1765
+ nil
1766
+ end
1769
1767
 
1770
- def resolve_local_hover_type(facts, name, line, char)
1771
- resolve_local_hover_binding(facts, name, line, char)&.type
1772
- end
1768
+ def resolve_local_hover_type(facts, name, line, char)
1769
+ resolve_local_hover_binding(facts, name, line, char)&.type
1770
+ end
1773
1771
 
1774
- def declared_generic_local_hover_binding(facts, name, line)
1775
- binding = generic_function_binding_for_line(facts, line)
1776
- return nil unless binding
1772
+ def declared_generic_local_hover_binding(facts, name, line)
1773
+ binding = generic_function_binding_for_line(facts, line)
1774
+ return nil unless binding
1777
1775
 
1778
- binding.body_params.find { |param| param.name == name }
1779
- end
1776
+ binding.body_params.find { |param| param.name == name }
1777
+ end
1780
1778
 
1781
- def enclosing_completion_frame(facts, line)
1782
- frames = Array(facts.local_completion_frames)
1783
- containing = frames.select { |frame| frame.start_line && frame.end_line && frame.start_line <= line && line <= frame.end_line }
1784
- containing.min_by { |frame| frame.end_line - frame.start_line }
1785
- end
1779
+ def enclosing_completion_frame(facts, line)
1780
+ frames = Array(facts.local_completion_frames)
1781
+ containing = frames.select { |frame| frame.start_line && frame.end_line && frame.start_line <= line && line <= frame.end_line }
1782
+ containing.min_by { |frame| frame.end_line - frame.start_line }
1783
+ end
1786
1784
 
1787
- def latest_completion_snapshot(frame, line, char)
1788
- snapshots = Array(frame.snapshots)
1789
- snapshots.reverse_each do |snapshot|
1790
- next if snapshot.line > line
1791
- next if snapshot.line == line && snapshot.column > char
1785
+ def latest_completion_snapshot(frame, line, char)
1786
+ snapshots = Array(frame.snapshots)
1787
+ snapshots.reverse_each do |snapshot|
1788
+ next if snapshot.line > line
1789
+ next if snapshot.line == line && snapshot.column > char
1792
1790
 
1793
- return snapshot
1791
+ return snapshot
1792
+ end
1793
+ nil
1794
1794
  end
1795
- nil
1796
- end
1797
1795
 
1798
- def same_line_future_completion_snapshot(frame, line, char)
1799
- snapshots = Array(frame.snapshots)
1800
- snapshots.each do |snapshot|
1801
- next unless snapshot.line == line
1802
- next if snapshot.column <= char
1796
+ def same_line_future_completion_snapshot(frame, line, char)
1797
+ snapshots = Array(frame.snapshots)
1798
+ snapshots.each do |snapshot|
1799
+ next unless snapshot.line == line
1800
+ next if snapshot.column <= char
1803
1801
 
1804
- return snapshot
1802
+ return snapshot
1803
+ end
1804
+ nil
1805
1805
  end
1806
- nil
1807
- end
1808
1806
 
1809
- def resolve_for_binding_hover_info(tokens, token_index)
1810
- tok = tokens[token_index]
1811
- return nil unless tok&.type == :identifier
1807
+ def resolve_for_binding_hover_info(tokens, token_index)
1808
+ tok = tokens[token_index]
1809
+ return nil unless tok&.type == :identifier
1812
1810
 
1813
- binding_info = for_binding_context_at(tokens, token_index)
1814
- return nil unless binding_info
1811
+ binding_info = for_binding_context_at(tokens, token_index)
1812
+ return nil unless binding_info
1815
1813
 
1816
- binding_name = binding_info[:name]
1817
- iterable_text = binding_info[:iterable_text] || "collection"
1814
+ binding_name = binding_info[:name]
1815
+ iterable_text = binding_info[:iterable_text] || "collection"
1818
1816
 
1819
- {
1820
- signature: "for binding #{binding_name} (iterating over #{iterable_text})",
1821
- docs: nil,
1822
- }
1823
- end
1817
+ {
1818
+ signature: "for binding #{binding_name} (iterating over #{iterable_text})",
1819
+ docs: nil,
1820
+ }
1821
+ end
1824
1822
 
1825
- def for_binding_context_at(tokens, token_index)
1826
- return nil unless token_index
1823
+ def for_binding_context_at(tokens, token_index)
1824
+ return nil unless token_index
1827
1825
 
1828
- i = token_index - 1
1829
- passed_in = false
1826
+ i = token_index - 1
1827
+ passed_in = false
1830
1828
 
1831
- while i >= 0
1832
- current = tokens[i]
1833
- break if current.type == :newline && current.line != tokens[token_index].line
1829
+ while i >= 0
1830
+ current = tokens[i]
1831
+ break if current.type == :newline && current.line != tokens[token_index].line
1834
1832
 
1835
- if current.type == :identifier
1836
- case current.lexeme
1837
- when "in"
1838
- passed_in = true
1839
- when "for"
1840
- if passed_in
1841
- ie = token_index + 1
1842
- while ie < tokens.length
1843
- nt = tokens[ie]
1844
- break if nt.type == :newline || nt.type == :colon
1833
+ if current.type == :identifier
1834
+ case current.lexeme
1835
+ when "in"
1836
+ passed_in = true
1837
+ when "for"
1838
+ if passed_in
1839
+ ie = token_index + 1
1840
+ while ie < tokens.length
1841
+ nt = tokens[ie]
1842
+ break if nt.type == :newline || nt.type == :colon
1845
1843
 
1846
- ie += 1
1844
+ ie += 1
1845
+ end
1846
+ iterable_text = tokens[(token_index + 1)...ie].map(&:lexeme).join(" ")
1847
+ iterable_text = iterable_text.gsub(/\s+/, " ").strip
1848
+ return {
1849
+ name: tokens[token_index].lexeme,
1850
+ iterable_text: iterable_text.empty? ? nil : iterable_text,
1851
+ }
1847
1852
  end
1848
- iterable_text = tokens[(token_index + 1)...ie].map(&:lexeme).join(" ")
1849
- iterable_text = iterable_text.gsub(/\s+/, " ").strip
1850
- return {
1851
- name: tokens[token_index].lexeme,
1852
- iterable_text: iterable_text.empty? ? nil : iterable_text,
1853
- }
1854
1853
  end
1855
1854
  end
1855
+
1856
+ i -= 1
1856
1857
  end
1857
1858
 
1858
- i -= 1
1859
+ nil
1859
1860
  end
1860
1861
 
1861
- nil
1862
- end
1863
-
1864
- def resolve_lexical_local_hover_signature(definition_uri, name, definition_token)
1865
- kind = nil
1866
- type_str = nil
1867
-
1868
- tokens = @workspace.get_tokens(definition_uri)
1869
- if tokens
1870
- def_index = tokens.index(definition_token)
1871
- if def_index
1872
- prev = previous_non_trivia_token_index(tokens, def_index)
1873
- if prev
1874
- case tokens[prev].lexeme
1875
- when "let" then kind = :let
1876
- when "var" then kind = :var
1877
- when "const" then kind = :const
1878
- when "struct" then kind = :struct_type
1879
- when "function", "async", "external", "foreign" then kind = :function
1880
- when "enum" then kind = :enum_type
1881
- when "flags" then kind = :flags_type
1882
- when "union" then kind = :union_type
1883
- when "variant" then kind = :variant_type
1884
- when "(" then kind = :param
1885
- when "," then kind = :param
1862
+ def resolve_lexical_local_hover_signature(definition_uri, name, definition_token)
1863
+ kind = nil
1864
+ type_str = nil
1865
+
1866
+ tokens = @workspace.get_tokens(definition_uri)
1867
+ if tokens
1868
+ def_index = tokens.index(definition_token)
1869
+ if def_index
1870
+ prev = previous_non_trivia_token_index(tokens, def_index)
1871
+ if prev
1872
+ case tokens[prev].lexeme
1873
+ when "let" then kind = :let
1874
+ when "var" then kind = :var
1875
+ when "const" then kind = :const
1876
+ when "struct" then kind = :struct_type
1877
+ when "function", "async", "external", "foreign" then kind = :function
1878
+ when "enum" then kind = :enum_type
1879
+ when "flags" then kind = :flags_type
1880
+ when "union" then kind = :union_type
1881
+ when "variant" then kind = :variant_type
1882
+ when "(" then kind = :param
1883
+ when "," then kind = :param
1884
+ end
1886
1885
  end
1887
- end
1888
1886
 
1889
- if kind
1890
- next_idx = next_non_trivia_token_index(tokens, def_index + 1)
1891
- if next_idx && tokens[next_idx].type == :colon
1892
- type_start = next_non_trivia_token_index(tokens, next_idx + 1)
1893
- if type_start && tokens[type_start].type == :identifier
1894
- type_str = tokens[type_start].lexeme
1895
- type_end = type_start
1896
- loop do
1897
- next_tok_idx = next_non_trivia_token_index(tokens, type_end + 1)
1898
- break unless next_tok_idx && %i[identifier lbracket rbracket integer comma].include?(tokens[next_tok_idx].type)
1899
-
1900
- type_str += tokens[next_tok_idx].lexeme
1901
- type_end = next_tok_idx
1902
- break if tokens[type_end].type == :equal
1887
+ if kind
1888
+ next_idx = next_non_trivia_token_index(tokens, def_index + 1)
1889
+ if next_idx && tokens[next_idx].type == :colon
1890
+ type_start = next_non_trivia_token_index(tokens, next_idx + 1)
1891
+ if type_start && tokens[type_start].type == :identifier
1892
+ type_str = tokens[type_start].lexeme
1893
+ type_end = type_start
1894
+ loop do
1895
+ next_tok_idx = next_non_trivia_token_index(tokens, type_end + 1)
1896
+ break unless next_tok_idx && %i[identifier lbracket rbracket integer comma].include?(tokens[next_tok_idx].type)
1897
+
1898
+ type_str += tokens[next_tok_idx].lexeme
1899
+ type_end = next_tok_idx
1900
+ break if tokens[type_end].type == :equal
1901
+ end
1902
+ type_str = type_str.sub(/\s*=.*/, "").strip
1903
1903
  end
1904
- type_str = type_str.sub(/\s*=.*/, "").strip
1905
1904
  end
1906
1905
  end
1907
1906
  end
1908
1907
  end
1909
- end
1910
1908
 
1911
- kind ||= :let
1912
- unless %i[let var const param].include?(kind)
1913
- kind = kind.to_s.sub(/_type$/, "")
1914
- return "#{kind} #{name}"
1915
- end
1909
+ kind ||= :let
1910
+ unless %i[let var const param].include?(kind)
1911
+ kind = kind.to_s.sub(/_type$/, "")
1912
+ return "#{kind} #{name}"
1913
+ end
1916
1914
 
1917
- display_kind = kind == :param ? "parameter" : kind.to_s
1918
- mutability = kind == :var ? "mutable" : "immutable"
1919
- if type_str && !type_str.empty?
1920
- "#{display_kind} #{name}: #{type_str} (#{mutability})"
1921
- else
1922
- "#{kind} #{name} (#{mutability})"
1915
+ display_kind = kind == :param ? "parameter" : kind.to_s
1916
+ mutability = kind == :var ? "mutable" : "immutable"
1917
+ if type_str && !type_str.empty?
1918
+ "#{display_kind} #{name}: #{type_str} (#{mutability})"
1919
+ else
1920
+ "#{kind} #{name} (#{mutability})"
1921
+ end
1923
1922
  end
1924
1923
  end
1925
- end
1926
1924
  end
1927
1925
  end
1928
1926
  end