Skip to content

Collapsible chained expressions (Method and Field Chains) #19620

Open
@PRO-2684

Description

@PRO-2684

Summary

Add support for collapsing/folding chained expressions in rust-analyzer to improve code readability and navigation in editors.

Problem

Currently, rust-analyzer does not provide a folding option for chained expressions, which are sequences of method calls or field accesses connected by the dot operator (.). For example:

Image

In the editor, there is no folding arrow (or equivalent UI element) before the let statement to collapse this method chain into a single line, unlike other foldable constructs such as blocks or match expressions. This limitation makes it harder to navigate and read code with long chained expressions, especially in complex expressions.

Proposal

Introduce support for collapsing chained expressions in rust-analyzer. When a method chain spans multiple lines, rust-analyzer should:

  1. Display a folding arrow in the editor gutter at the start of the chain (e.g., before the let statement in the example above).
  2. Allow collapsing the entire chain into a single line, such as:
    let a = b.c.d.e();
  3. Preserve the original formatting when expanding the chain back to its multi-line form.

This feature would align with existing folding capabilities for other Rust constructs and improve the editing experience for codebases with frequent method chaining, such as those using iterator patterns.

Use Case

Consider the following code:

let result = collection
    .iter()
    .filter(|x| x > 0)
    .map(|x| x * 2)
    .collect::<Vec<_>>();

With the proposed feature, users could collapse this chain to:

let result = collection.iter().filter(...).map(...).collect::<Vec<_>>();

This would reduce visual clutter and make it easier to focus on surrounding code, especially in larger functions or modules.

Alternatives

To simplify implementation, rust-analyzer could support alternative collapsing formats that are less complex than fully inlining the chain. These include:

  1. Truncated Prefix with Ellipsis: Collapse the chain to the base expression followed by an ellipsis (...).

    • Example: let result = collection...;
    • Benefit: Minimizes visual clutter and is easy to implement by identifying the base expression.
  2. Base Expression with Chain Indicator: Collapse the chain to the base expression with a placeholder like <chain> to indicate a chain exists.

    • Example: let result = collection.<chain>;
    • Benefit: Signals the presence of a chain without parsing its contents.
  3. First Method/Field with Ellipsis: Collapse the chain to the base expression plus the first method call or field access, followed by an ellipsis.

    • Example: let result = collection.iter()...;
    • Benefit: Preserves context about the chain's starting point while remaining simple.
  4. Type-Informed Collapse: Collapse the chain to the base expression and the resulting type (if available), indicating the chain's outcome.

    • Example: let result = collection -> Vec<_>;
    • Benefit: Provides meaningful context about the chain's purpose, leveraging rust-analyzer's type inference.
    • Note: This alternative may not be so useful if type hints are enabled.

These alternatives reduce the complexity of handling complex method arguments (e.g., closures or generics) and provide flexible options for users to customize folding behavior.

Metadata

Metadata

Assignees

Labels

A-idegeneral IDE featuresC-featureCategory: feature request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions