Class: RubyLsp::Listeners::SemanticHighlighting
- Inherits:
-
Object
- Object
- RubyLsp::Listeners::SemanticHighlighting
- Includes:
- Requests::Support::Common
- Defined in:
- lib/ruby_lsp/listeners/semantic_highlighting.rb
Constant Summary collapse
- SPECIAL_RUBY_METHODS =
[ Module.instance_methods(false), Kernel.instance_methods(false), Kernel.methods(false), Bundler::Dsl.instance_methods(false), Module.private_instance_methods(false), ].flatten.map(&:to_s).freeze
Instance Method Summary collapse
-
#initialize(dispatcher, response_builder) ⇒ SemanticHighlighting
constructor
: (Prism::Dispatcher dispatcher, ResponseBuilders::SemanticHighlighting response_builder) -> void.
-
#on_block_local_variable_node_enter(node) ⇒ Object
: (Prism::BlockLocalVariableNode node) -> void.
-
#on_block_node_enter(node) ⇒ Object
: (Prism::BlockNode node) -> void.
-
#on_block_node_leave(node) ⇒ Object
: (Prism::BlockNode node) -> void.
-
#on_block_parameter_node_enter(node) ⇒ Object
: (Prism::BlockParameterNode node) -> void.
-
#on_call_node_enter(node) ⇒ Object
: (Prism::CallNode node) -> void.
-
#on_class_node_enter(node) ⇒ Object
: (Prism::ClassNode node) -> void.
-
#on_def_node_enter(node) ⇒ Object
: (Prism::DefNode node) -> void.
-
#on_def_node_leave(node) ⇒ Object
: (Prism::DefNode node) -> void.
-
#on_implicit_node_enter(node) ⇒ Object
: (Prism::ImplicitNode node) -> void.
-
#on_implicit_node_leave(node) ⇒ Object
: (Prism::ImplicitNode node) -> void.
-
#on_keyword_rest_parameter_node_enter(node) ⇒ Object
: (Prism::KeywordRestParameterNode node) -> void.
-
#on_local_variable_and_write_node_enter(node) ⇒ Object
: (Prism::LocalVariableAndWriteNode node) -> void.
-
#on_local_variable_operator_write_node_enter(node) ⇒ Object
: (Prism::LocalVariableOperatorWriteNode node) -> void.
-
#on_local_variable_or_write_node_enter(node) ⇒ Object
: (Prism::LocalVariableOrWriteNode node) -> void.
-
#on_local_variable_read_node_enter(node) ⇒ Object
: (Prism::LocalVariableReadNode node) -> void.
-
#on_local_variable_target_node_enter(node) ⇒ Object
: (Prism::LocalVariableTargetNode node) -> void.
-
#on_local_variable_write_node_enter(node) ⇒ Object
: (Prism::LocalVariableWriteNode node) -> void.
-
#on_match_write_node_enter(node) ⇒ Object
: (Prism::MatchWriteNode node) -> void.
-
#on_match_write_node_leave(node) ⇒ Object
: (Prism::MatchWriteNode node) -> void.
-
#on_module_node_enter(node) ⇒ Object
: (Prism::ModuleNode node) -> void.
-
#on_optional_keyword_parameter_node_enter(node) ⇒ Object
: (Prism::OptionalKeywordParameterNode node) -> void.
-
#on_optional_parameter_node_enter(node) ⇒ Object
: (Prism::OptionalParameterNode node) -> void.
-
#on_required_keyword_parameter_node_enter(node) ⇒ Object
: (Prism::RequiredKeywordParameterNode node) -> void.
-
#on_required_parameter_node_enter(node) ⇒ Object
: (Prism::RequiredParameterNode node) -> void.
-
#on_rest_parameter_node_enter(node) ⇒ Object
: (Prism::RestParameterNode node) -> void.
-
#on_self_node_enter(node) ⇒ Object
: (Prism::SelfNode node) -> void.
Methods included from Requests::Support::Common
#categorized_markdown_from_index_entries, #constant_name, #create_code_lens, #each_constant_path_part, #kind_for_entry, #markdown_from_index_entries, #namespace_constant_name, #not_in_dependencies?, #range_from_location, #range_from_node, #self_receiver?
Constructor Details
#initialize(dispatcher, response_builder) ⇒ SemanticHighlighting
: (Prism::Dispatcher dispatcher, ResponseBuilders::SemanticHighlighting response_builder) -> void
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 18 def initialize(dispatcher, response_builder) @response_builder = response_builder @special_methods = nil #: Array[String]? @current_scope = Scope.new #: Scope @inside_regex_capture = false #: bool @inside_implicit_node = false #: bool dispatcher.register( self, :on_call_node_enter, :on_class_node_enter, :on_def_node_enter, :on_def_node_leave, :on_block_node_enter, :on_block_node_leave, :on_self_node_enter, :on_module_node_enter, :on_local_variable_write_node_enter, :on_local_variable_read_node_enter, :on_block_parameter_node_enter, :on_required_keyword_parameter_node_enter, :on_optional_keyword_parameter_node_enter, :on_keyword_rest_parameter_node_enter, :on_optional_parameter_node_enter, :on_required_parameter_node_enter, :on_rest_parameter_node_enter, :on_local_variable_and_write_node_enter, :on_local_variable_operator_write_node_enter, :on_local_variable_or_write_node_enter, :on_local_variable_target_node_enter, :on_block_local_variable_node_enter, :on_match_write_node_enter, :on_match_write_node_leave, :on_implicit_node_enter, :on_implicit_node_leave, ) end |
Instance Method Details
#on_block_local_variable_node_enter(node) ⇒ Object
: (Prism::BlockLocalVariableNode node) -> void
121 122 123 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 121 def on_block_local_variable_node_enter(node) @response_builder.add_token(node.location, :variable) end |
#on_block_node_enter(node) ⇒ Object
: (Prism::BlockNode node) -> void
111 112 113 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 111 def on_block_node_enter(node) @current_scope = Scope.new(@current_scope) end |
#on_block_node_leave(node) ⇒ Object
: (Prism::BlockNode node) -> void
116 117 118 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 116 def on_block_node_leave(node) @current_scope = @current_scope.parent #: as !nil end |
#on_block_parameter_node_enter(node) ⇒ Object
: (Prism::BlockParameterNode node) -> void
126 127 128 129 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 126 def on_block_parameter_node_enter(node) name = node.name @current_scope.add(name.to_sym, :parameter) if name end |
#on_call_node_enter(node) ⇒ Object
: (Prism::CallNode node) -> void
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 57 def on_call_node_enter(node) return if @inside_implicit_node = node. return unless # We can't push a semantic token for [] and []= because the argument inside the brackets is a part of # the message_loc return if .start_with?("[") && (.end_with?("]") || .end_with?("]=")) return if == "=~" return if special_method?() if Requests::Support::Sorbet.annotation?(node) @response_builder.add_token( node., #: as !nil :type, ) elsif !node.receiver && !node.opening_loc # If the node has a receiver, then the syntax is not ambiguous and semantic highlighting is not necessary to # determine that the token is a method call. The only ambiguous case is method calls with implicit self # receiver and no parenthesis, which may be confused with local variables @response_builder.add_token( node., #: as !nil :method, ) end end |
#on_class_node_enter(node) ⇒ Object
: (Prism::ClassNode node) -> void
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 219 def on_class_node_enter(node) constant_path = node.constant_path if constant_path.is_a?(Prism::ConstantReadNode) @response_builder.add_token(constant_path.location, :class, [:declaration]) else each_constant_path_part(constant_path) do |part| loc = case part when Prism::ConstantPathNode part.name_loc when Prism::ConstantReadNode part.location end next unless loc @response_builder.add_token(loc, :class, [:declaration]) end end superclass = node.superclass if superclass.is_a?(Prism::ConstantReadNode) @response_builder.add_token(superclass.location, :class) elsif superclass each_constant_path_part(superclass) do |part| loc = case part when Prism::ConstantPathNode part.name_loc when Prism::ConstantReadNode part.location end next unless loc @response_builder.add_token(loc, :class) end end end |
#on_def_node_enter(node) ⇒ Object
: (Prism::DefNode node) -> void
101 102 103 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 101 def on_def_node_enter(node) @current_scope = Scope.new(@current_scope) end |
#on_def_node_leave(node) ⇒ Object
: (Prism::DefNode node) -> void
106 107 108 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 106 def on_def_node_leave(node) @current_scope = @current_scope.parent #: as !nil end |
#on_implicit_node_enter(node) ⇒ Object
: (Prism::ImplicitNode node) -> void
279 280 281 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 279 def on_implicit_node_enter(node) @inside_implicit_node = true end |
#on_implicit_node_leave(node) ⇒ Object
: (Prism::ImplicitNode node) -> void
284 285 286 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 284 def on_implicit_node_leave(node) @inside_implicit_node = false end |
#on_keyword_rest_parameter_node_enter(node) ⇒ Object
: (Prism::KeywordRestParameterNode node) -> void
142 143 144 145 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 142 def on_keyword_rest_parameter_node_enter(node) name = node.name @current_scope.add(name.to_sym, :parameter) if name end |
#on_local_variable_and_write_node_enter(node) ⇒ Object
: (Prism::LocalVariableAndWriteNode node) -> void
189 190 191 192 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 189 def on_local_variable_and_write_node_enter(node) local = @current_scope.lookup(node.name) @response_builder.add_token(node.name_loc, :parameter) if local&.type == :parameter end |
#on_local_variable_operator_write_node_enter(node) ⇒ Object
: (Prism::LocalVariableOperatorWriteNode node) -> void
195 196 197 198 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 195 def on_local_variable_operator_write_node_enter(node) local = @current_scope.lookup(node.name) @response_builder.add_token(node.name_loc, :parameter) if local&.type == :parameter end |
#on_local_variable_or_write_node_enter(node) ⇒ Object
: (Prism::LocalVariableOrWriteNode node) -> void
201 202 203 204 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 201 def on_local_variable_or_write_node_enter(node) local = @current_scope.lookup(node.name) @response_builder.add_token(node.name_loc, :parameter) if local&.type == :parameter end |
#on_local_variable_read_node_enter(node) ⇒ Object
: (Prism::LocalVariableReadNode node) -> void
175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 175 def on_local_variable_read_node_enter(node) return if @inside_implicit_node # Numbered parameters if /_\d+/.match?(node.name) @response_builder.add_token(node.location, :parameter) return end local = @current_scope.lookup(node.name) @response_builder.add_token(node.location, local&.type || :variable) end |
#on_local_variable_target_node_enter(node) ⇒ Object
: (Prism::LocalVariableTargetNode node) -> void
207 208 209 210 211 212 213 214 215 216 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 207 def on_local_variable_target_node_enter(node) # If we're inside a regex capture, Prism will add LocalVariableTarget nodes for each captured variable. # Unfortunately, if the regex contains a backslash, the location will be incorrect and we'll end up highlighting # the entire regex as a local variable. We process these captures in process_regexp_locals instead and then # prevent pushing local variable target tokens. See https://github.com/ruby/prism/issues/1912 return if @inside_regex_capture local = @current_scope.lookup(node.name) @response_builder.add_token(node.location, local&.type || :variable) end |
#on_local_variable_write_node_enter(node) ⇒ Object
: (Prism::LocalVariableWriteNode node) -> void
169 170 171 172 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 169 def on_local_variable_write_node_enter(node) local = @current_scope.lookup(node.name) @response_builder.add_token(node.name_loc, :parameter) if local&.type == :parameter end |
#on_match_write_node_enter(node) ⇒ Object
: (Prism::MatchWriteNode node) -> void
86 87 88 89 90 91 92 93 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 86 def on_match_write_node_enter(node) call = node.call if call. == "=~" @inside_regex_capture = true process_regexp_locals(call) end end |
#on_match_write_node_leave(node) ⇒ Object
: (Prism::MatchWriteNode node) -> void
96 97 98 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 96 def on_match_write_node_leave(node) @inside_regex_capture = true if node.call. == "=~" end |
#on_module_node_enter(node) ⇒ Object
: (Prism::ModuleNode node) -> void
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 258 def on_module_node_enter(node) constant_path = node.constant_path if constant_path.is_a?(Prism::ConstantReadNode) @response_builder.add_token(constant_path.location, :namespace, [:declaration]) else each_constant_path_part(constant_path) do |part| loc = case part when Prism::ConstantPathNode part.name_loc when Prism::ConstantReadNode part.location end next unless loc @response_builder.add_token(loc, :namespace, [:declaration]) end end end |
#on_optional_keyword_parameter_node_enter(node) ⇒ Object
: (Prism::OptionalKeywordParameterNode node) -> void
137 138 139 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 137 def on_optional_keyword_parameter_node_enter(node) @current_scope.add(node.name, :parameter) end |
#on_optional_parameter_node_enter(node) ⇒ Object
: (Prism::OptionalParameterNode node) -> void
148 149 150 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 148 def on_optional_parameter_node_enter(node) @current_scope.add(node.name, :parameter) end |
#on_required_keyword_parameter_node_enter(node) ⇒ Object
: (Prism::RequiredKeywordParameterNode node) -> void
132 133 134 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 132 def on_required_keyword_parameter_node_enter(node) @current_scope.add(node.name, :parameter) end |
#on_required_parameter_node_enter(node) ⇒ Object
: (Prism::RequiredParameterNode node) -> void
153 154 155 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 153 def on_required_parameter_node_enter(node) @current_scope.add(node.name, :parameter) end |
#on_rest_parameter_node_enter(node) ⇒ Object
: (Prism::RestParameterNode node) -> void
158 159 160 161 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 158 def on_rest_parameter_node_enter(node) name = node.name @current_scope.add(name.to_sym, :parameter) if name end |
#on_self_node_enter(node) ⇒ Object
: (Prism::SelfNode node) -> void
164 165 166 |
# File 'lib/ruby_lsp/listeners/semantic_highlighting.rb', line 164 def on_self_node_enter(node) @response_builder.add_token(node.location, :variable, [:default_library]) end |