Description
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:
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:
- Display a folding arrow in the editor gutter at the start of the chain (e.g., before the
let
statement in the example above). - Allow collapsing the entire chain into a single line, such as:
let a = b.c.d.e();
- 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:
-
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.
- Example:
-
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.
- Example:
-
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.
- Example:
-
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.
- Example:
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.