Highlight the method name in method calls#1189
Conversation
It's useful to differentiate method calls from local variable references.
Method calls in `binding.irb` may be colorized.
This fix prevents struct members from being colorized.
| super | ||
| end | ||
|
|
||
| def visit_call_node(node) |
There was a problem hiding this comment.
Writer methods are also colored blue, but Writer methods with operators are not colored.
# "foo" is colored
a.foo = 1
# "foo" is not colored
a.foo += 1
a.foo &&= 1
a.foo ||= 1So I think we can also add visitor methods for CallAndWriteNode CallOperatorWriteNode CallOrWriteNode.
|
|
||
| def visit_call_node(node) | ||
| if @colorize_call | ||
| if node.call_operator_loc.nil? && OPERATORS.include?(node.name) |
There was a problem hiding this comment.
For a[:key] a[:key] = 2, message_loc contains index part and wrongly colored blue, so we need to exclude :[] and :[]= when call_operator_loc is nil.
When call_operator_loc is present(a.[]=(1, 2)) message_loc is already colored correctly.
| if node.call_operator_loc.nil? && OPERATORS.include?(node.name) | ||
| # Operators should not be highlighted | ||
| else | ||
| dispatch node.message_loc, :message_name |
Colorize method name `foo` in the following code: ``` a.foo += 1 a.foo &&= 1 a.foo ||= 1 ```
There was a problem hiding this comment.
Pull request overview
This PR updates IRB’s syntax colorization to visually distinguish method calls by applying a dedicated style to method/message names during AST traversal.
Changes:
- Add a new
message_nametoken style and colorize method/message names forPrismcall nodes inIRB::Color.colorize_code. - Add a
colorize_call:keyword to enable/disable call highlighting (disabled forIRB::ColorPrinteroutput). - Update IRB colorization tests and adjust an integration-test regex to tolerate ANSI color sequences around
binding.irb.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
lib/irb/color.rb |
Introduces message_name styling and Prism visitor logic to highlight method/message names; adds colorize_call: option. |
lib/irb/color_printer.rb |
Disables call highlighting when pretty-printing fragments to avoid coloring method-like strings in printer output. |
test/irb/test_color.rb |
Updates/expands expectations to reflect method-name highlighting behavior. |
test/irb/helper.rb |
Updates breakpoint detection regex to match binding.irb even when colored. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
lib/irb/color.rb
Outdated
| if node.call_operator_loc.nil? && OPERATORS.include?(node.name) | ||
| # Operators should not be colored as method call | ||
| elsif (node.call_operator_loc.nil? || node.call_operator_loc.slice == "::") && | ||
| /\A\p{Upper}/.match?(node.name) |
There was a problem hiding this comment.
colorize_call calls Regexp#match? with node.name. In Prism, CallNode#name is commonly a Symbol (e.g., :[]=, :+), and passing a Symbol to match? raises TypeError. Consider normalizing once (e.g., name_str = node.name.to_s and name_sym = node.name.is_a?(Symbol) ? node.name : node.name.to_sym) and using name_sym for OPERATORS.include? and name_str for the uppercase check.
| if node.call_operator_loc.nil? && OPERATORS.include?(node.name) | |
| # Operators should not be colored as method call | |
| elsif (node.call_operator_loc.nil? || node.call_operator_loc.slice == "::") && | |
| /\A\p{Upper}/.match?(node.name) | |
| name = node.name | |
| name_sym = name.is_a?(Symbol) ? name : name.to_sym | |
| name_str = name.to_s | |
| if node.call_operator_loc.nil? && OPERATORS.include?(name_sym) | |
| # Operators should not be colored as method call | |
| elsif (node.call_operator_loc.nil? || node.call_operator_loc.slice == "::") && | |
| /\A\p{Upper}/.match?(name_str) |
There was a problem hiding this comment.
Besides that, CallOperatorWriteNode seems not to have the name method. I'll fix it.
There was a problem hiding this comment.
Fixed in db9cd4c.
Regexp#match? accepts symbols, so there's no need to call to_s.
lib/irb/color.rb
Outdated
| def visit_call_operator_write_node(node) | ||
| dispatch node.message_loc, :message_name if @colorize_call | ||
| super | ||
| end | ||
|
|
||
| def visit_call_and_write_node(node) | ||
| dispatch node.message_loc, :message_name if @colorize_call | ||
| super | ||
| end | ||
|
|
||
| def visit_call_or_write_node(node) | ||
| dispatch node.message_loc, :message_name if @colorize_call | ||
| super | ||
| end |
There was a problem hiding this comment.
I didn't use alias to keep super dispatching to the right visit_ method.
However, it seems that NestingParser uses alias, relying on the fact that the current implementation of all visit_* in Prism::Visitor is the same.
|
@st0012 Thanks for your feed back.
The current color of method name in definition is blue, isn't it? Line 105 in 8a1129d
(On my terminal, WezTerm, characters with bold attribute are brighter than the ones without bold attr.) I chose blue because it's used for method name in definition, but I have no strong opinion.
It might be good if method name name in definition were highlighted with a different color such as magenta. |
|
Oh wait I changed the color different times for testing and forgot to change back, sorry 🤦♂️ So now 1 is satisfied. I think it'd be great if we can make 2 happen too. WDYT changing constants to another color? |
It sounds good to me. I noticed that |
Not a fan of green + magenta when defining a class, but yellow is too bright and cyan is too close to blue. So yeah I'd go with magenta for now and we can later implement theme feature to support more color combinations. @tompng Any preference? |
|
IMO Cyan looks good, it's close to blue but easily differentiable still. |
Agree. |
|
In the Cyan screenshot, Magenta looks OK to me too, and might be better to differentiate keywords & constants.
👍 |
|
I'm also fine with cyan if that's what people choose 👍 |
|
Thanks for your comments. Green + magenta looks fine on my terminal, but seem not look good on Stan's, so I'd like to choose cyan for method names and highlight |
It was not used to keep `super` dispatch to the right `visit_` method. However, it seems that `NestingParser` uses `alias`, relying on the fact that the current implementation of all `visit_*` in `Prism::Visitor` is the same.
I've addressed these issues and have supported |
| super(@colorize ? Color.colorize(str, [:GREEN]) : str, width) | ||
| else | ||
| super(@colorize ? Color.colorize_code(str, ignore_error: true) : str, width) | ||
| super(@colorize ? Color.colorize_code(str, ignore_error: true, colorize_call: false) : str, width) |
There was a problem hiding this comment.
Why do we not want to colorize call in this case?
There was a problem hiding this comment.
The above code was introduced to fix the following failure of the debug compatibility test:
https://github.com/ruby/irb/actions/runs/23522320220/job/68468010147
There was a problem hiding this comment.
Hmm. I don't like that we update IRB lib code to workaround a test.
I'd prefer:
- Ship without this workaround
- Propose test changes to debug
- Let CI fail for a few days until 2 is merged
An alternative could be to disable this test until 2 is merged.
@tompng WDYT?
There was a problem hiding this comment.
I'm not sure if it's correct to highlight member names as method names in the Struct inspect output.
Furthermore, the results might differ in environments where variables with the same names as the members are defined.
There was a problem hiding this comment.
Furthermore, the results might differ in environments where variables with the same names as the members are defined.
This might be an overthought, as no local variables are specified here.






It's useful to differentiate method calls from local variable references.