Skip to content

Highlight the method name in method calls#1189

Open
shugo wants to merge 7 commits intoruby:masterfrom
shugo:feature/irb-highlight-method-calls
Open

Highlight the method name in method calls#1189
shugo wants to merge 7 commits intoruby:masterfrom
shugo:feature/irb-highlight-method-calls

Conversation

@shugo
Copy link
Member

@shugo shugo commented Mar 25, 2026

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

shugo added 3 commits March 25, 2026 11:34
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ||= 1

So I think we can also add visitor methods for CallAndWriteNode CallOperatorWriteNode CallOrWriteNode.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed it in 66933a9.


def visit_call_node(node)
if @colorize_call
if node.call_operator_loc.nil? && OPERATORS.include?(node.name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed it in 8643c13.

if node.call_operator_loc.nil? && OPERATORS.include?(node.name)
# Operators should not be highlighted
else
dispatch node.message_loc, :message_name
Copy link
Member

@tompng tompng Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current colorization is:
Image

Array(1) Kernel::Array(1) are definitely a method call, but I think it might be better colored as constant.

In an explicit method call case Kernel.Array(), Kernel&.Array(), it may be better colored as method_name.
What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

I've fixed it in 0b398c3.

shugo added 3 commits March 25, 2026 17:22
Colorize method name `foo` in the following code:

```
a.foo += 1
a.foo &&= 1
a.foo ||= 1
```
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_name token style and colorize method/message names for Prism call nodes in IRB::Color.colorize_code.
  • Add a colorize_call: keyword to enable/disable call highlighting (disabled for IRB::ColorPrinter output).
  • 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
Comment on lines +313 to +316
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)
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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)

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides that, CallOperatorWriteNode seems not to have the name method. I'll fix it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in db9cd4c.

Regexp#match? accepts symbols, so there's no need to call to_s.

Comment on lines +272 to +285
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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Member

st0012 commented Mar 26, 2026

I like having colors to distinguish method calls and local variables, but picking the right color is pretty tricky, especially for tokens as common as method calls.

Ideally, with this change we want to have:

  1. The same color between method name in definition (currently yellow) and method name in call (introduced as blue here)

  2. Different colors between method calls and common adjacent tokens. For example:

    a = 1
    Foo.bar(a)

    Foo, bar, and a should each have a distinctive color. Currently in the PR both Foo and bar are blue

  3. If we combine both 1 and 2, we should color method calls as yellow. Though it kinda hurts my eye with the light yellow my terminals default to:
    Screenshot 2026-03-26 at 12 36 54

    (If we can dim it a bit it would be perfect 😢)

So TL;DR - I think yellow would be a better color for both consistency and visual distinction.

@shugo
Copy link
Member Author

shugo commented Mar 26, 2026

@st0012 Thanks for your feed back.

Ideally, with this change we want to have:

  1. The same color between method name in definition (currently yellow) and method name in call (introduced as blue here)

The current color of method name in definition is blue, isn't it?

method_name: [BLUE, BOLD],

irb_screenshot

(On my terminal, WezTerm, characters with bold attribute are brigter than the ones without bold attr.)

I chose blue because it's used for method name in definition, but I have no strong opinion.

Different colors between method calls and common adjacent tokens. For example:

It might be good if method name name in definition were highlighted with a different color such as magenta.

@st0012
Copy link
Member

st0012 commented Mar 26, 2026

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?

@shugo
Copy link
Member Author

shugo commented Mar 27, 2026

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 ENV is specifically highlighted in cyan.
How about magenta for other constants?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants