ruby-lsp 0.13.1 → 0.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -0
  3. data/VERSION +1 -1
  4. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -1
  5. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +30 -1
  6. data/lib/ruby_lsp/check_docs.rb +3 -3
  7. data/lib/ruby_lsp/document.rb +15 -7
  8. data/lib/ruby_lsp/executor.rb +85 -226
  9. data/lib/ruby_lsp/listener.rb +1 -50
  10. data/lib/ruby_lsp/listeners/code_lens.rb +233 -0
  11. data/lib/ruby_lsp/listeners/completion.rb +275 -0
  12. data/lib/ruby_lsp/listeners/definition.rb +158 -0
  13. data/lib/ruby_lsp/listeners/document_highlight.rb +556 -0
  14. data/lib/ruby_lsp/listeners/document_link.rb +162 -0
  15. data/lib/ruby_lsp/listeners/document_symbol.rb +223 -0
  16. data/lib/ruby_lsp/listeners/folding_ranges.rb +271 -0
  17. data/lib/ruby_lsp/listeners/hover.rb +152 -0
  18. data/lib/ruby_lsp/listeners/inlay_hints.rb +80 -0
  19. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +430 -0
  20. data/lib/ruby_lsp/listeners/signature_help.rb +74 -0
  21. data/lib/ruby_lsp/requests/code_action_resolve.rb +5 -5
  22. data/lib/ruby_lsp/requests/code_actions.rb +15 -6
  23. data/lib/ruby_lsp/requests/code_lens.rb +21 -221
  24. data/lib/ruby_lsp/requests/completion.rb +64 -246
  25. data/lib/ruby_lsp/requests/definition.rb +34 -147
  26. data/lib/ruby_lsp/requests/diagnostics.rb +17 -5
  27. data/lib/ruby_lsp/requests/document_highlight.rb +12 -536
  28. data/lib/ruby_lsp/requests/document_link.rb +11 -132
  29. data/lib/ruby_lsp/requests/document_symbol.rb +23 -210
  30. data/lib/ruby_lsp/requests/folding_ranges.rb +16 -252
  31. data/lib/ruby_lsp/requests/formatting.rb +4 -4
  32. data/lib/ruby_lsp/requests/hover.rb +48 -92
  33. data/lib/ruby_lsp/requests/inlay_hints.rb +23 -56
  34. data/lib/ruby_lsp/requests/on_type_formatting.rb +18 -6
  35. data/lib/ruby_lsp/requests/request.rb +17 -0
  36. data/lib/ruby_lsp/requests/selection_ranges.rb +4 -3
  37. data/lib/ruby_lsp/requests/semantic_highlighting.rb +21 -408
  38. data/lib/ruby_lsp/requests/show_syntax_tree.rb +5 -5
  39. data/lib/ruby_lsp/requests/signature_help.rb +87 -0
  40. data/lib/ruby_lsp/requests/support/common.rb +3 -2
  41. data/lib/ruby_lsp/requests/support/dependency_detector.rb +2 -0
  42. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -1
  43. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +2 -2
  44. data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
  45. data/lib/ruby_lsp/requests.rb +3 -1
  46. data/lib/ruby_lsp/store.rb +1 -1
  47. data/lib/ruby_lsp/utils.rb +8 -0
  48. metadata +20 -8
  49. data/lib/ruby_lsp/requests/base_request.rb +0 -24
@@ -0,0 +1,158 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Listeners
6
+ class Definition < Listener
7
+ extend T::Sig
8
+ extend T::Generic
9
+
10
+ ResponseType = type_member { { fixed: T.nilable(T.any(T::Array[Interface::Location], Interface::Location)) } }
11
+
12
+ sig { override.returns(ResponseType) }
13
+ attr_reader :_response
14
+
15
+ sig do
16
+ params(
17
+ uri: URI::Generic,
18
+ nesting: T::Array[String],
19
+ index: RubyIndexer::Index,
20
+ dispatcher: Prism::Dispatcher,
21
+ typechecker_enabled: T::Boolean,
22
+ ).void
23
+ end
24
+ def initialize(uri, nesting, index, dispatcher, typechecker_enabled)
25
+ @uri = uri
26
+ @nesting = nesting
27
+ @index = index
28
+ @typechecker_enabled = typechecker_enabled
29
+ @_response = T.let(nil, ResponseType)
30
+
31
+ super(dispatcher)
32
+
33
+ dispatcher.register(
34
+ self,
35
+ :on_call_node_enter,
36
+ :on_constant_read_node_enter,
37
+ :on_constant_path_node_enter,
38
+ )
39
+ end
40
+
41
+ sig { params(node: Prism::CallNode).void }
42
+ def on_call_node_enter(node)
43
+ message = node.name
44
+
45
+ if message == :require || message == :require_relative
46
+ handle_require_definition(node)
47
+ else
48
+ handle_method_definition(node)
49
+ end
50
+ end
51
+
52
+ sig { params(node: Prism::ConstantPathNode).void }
53
+ def on_constant_path_node_enter(node)
54
+ find_in_index(node.slice)
55
+ end
56
+
57
+ sig { params(node: Prism::ConstantReadNode).void }
58
+ def on_constant_read_node_enter(node)
59
+ find_in_index(node.slice)
60
+ end
61
+
62
+ private
63
+
64
+ sig { params(node: Prism::CallNode).void }
65
+ def handle_method_definition(node)
66
+ return unless self_receiver?(node)
67
+
68
+ message = node.message
69
+ return unless message
70
+
71
+ target_method = @index.resolve_method(message, @nesting.join("::"))
72
+ return unless target_method
73
+
74
+ location = target_method.location
75
+ file_path = target_method.file_path
76
+ return if @typechecker_enabled && not_in_dependencies?(file_path)
77
+
78
+ @_response = Interface::Location.new(
79
+ uri: URI::Generic.from_path(path: file_path).to_s,
80
+ range: Interface::Range.new(
81
+ start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
82
+ end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
83
+ ),
84
+ )
85
+ end
86
+
87
+ sig { params(node: Prism::CallNode).void }
88
+ def handle_require_definition(node)
89
+ message = node.name
90
+ arguments = node.arguments
91
+ return unless arguments
92
+
93
+ argument = arguments.arguments.first
94
+ return unless argument.is_a?(Prism::StringNode)
95
+
96
+ case message
97
+ when :require
98
+ entry = @index.search_require_paths(argument.content).find do |indexable_path|
99
+ indexable_path.require_path == argument.content
100
+ end
101
+
102
+ if entry
103
+ candidate = entry.full_path
104
+
105
+ @_response = Interface::Location.new(
106
+ uri: URI::Generic.from_path(path: candidate).to_s,
107
+ range: Interface::Range.new(
108
+ start: Interface::Position.new(line: 0, character: 0),
109
+ end: Interface::Position.new(line: 0, character: 0),
110
+ ),
111
+ )
112
+ end
113
+ when :require_relative
114
+ required_file = "#{argument.content}.rb"
115
+ path = @uri.to_standardized_path
116
+ current_folder = path ? Pathname.new(CGI.unescape(path)).dirname : Dir.pwd
117
+ candidate = File.expand_path(File.join(current_folder, required_file))
118
+
119
+ @_response = Interface::Location.new(
120
+ uri: URI::Generic.from_path(path: candidate).to_s,
121
+ range: Interface::Range.new(
122
+ start: Interface::Position.new(line: 0, character: 0),
123
+ end: Interface::Position.new(line: 0, character: 0),
124
+ ),
125
+ )
126
+ end
127
+ end
128
+
129
+ sig { params(value: String).void }
130
+ def find_in_index(value)
131
+ entries = @index.resolve(value, @nesting)
132
+ return unless entries
133
+
134
+ # We should only allow jumping to the definition of private constants if the constant is defined in the same
135
+ # namespace as the reference
136
+ first_entry = T.must(entries.first)
137
+ return if first_entry.visibility == :private && first_entry.name != "#{@nesting.join("::")}::#{value}"
138
+
139
+ @_response = entries.filter_map do |entry|
140
+ location = entry.location
141
+ # If the project has Sorbet, then we only want to handle go to definition for constants defined in gems, as an
142
+ # additional behavior on top of jumping to RBIs. Sorbet can already handle go to definition for all constants
143
+ # in the project, even if the files are typed false
144
+ file_path = entry.file_path
145
+ next if @typechecker_enabled && not_in_dependencies?(file_path)
146
+
147
+ Interface::Location.new(
148
+ uri: URI::Generic.from_path(path: file_path).to_s,
149
+ range: Interface::Range.new(
150
+ start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
151
+ end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
152
+ ),
153
+ )
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end