Skip to content

Commit 789995f

Browse files
kinto0meta-codesync[bot]
authored andcommitted
folding ranges for expressions
Summary: literals + calls Reviewed By: stroxler Differential Revision: D85867049 fbshipit-source-id: e32f6e6fac5606dd9405c2233b61d84e59c8a217
1 parent 7c9d3ba commit 789995f

File tree

2 files changed

+211
-5
lines changed

2 files changed

+211
-5
lines changed

pyrefly/lib/state/state.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,12 @@ use pyrefly_util::uniques::UniqueFactory;
5858
use pyrefly_util::upgrade_lock::UpgradeLock;
5959
use pyrefly_util::upgrade_lock::UpgradeLockExclusiveGuard;
6060
use pyrefly_util::upgrade_lock::UpgradeLockWriteGuard;
61+
use ruff_python_ast::Expr;
6162
use ruff_python_ast::Stmt;
6263
use ruff_python_ast::name::Name;
6364
use ruff_python_ast::visitor::Visitor;
6465
use ruff_python_ast::visitor::walk_body;
66+
use ruff_text_size::Ranged;
6567
use ruff_text_size::TextRange;
6668
use starlark_map::Hashed;
6769
use starlark_map::small_map::SmallMap;
@@ -507,7 +509,8 @@ impl<'a> Transaction<'a> {
507509
handle: &Handle,
508510
) -> Option<Vec<(TextRange, Option<FoldingRangeKind>)>> {
509511
let ast = self.get_ast(handle)?;
510-
let mut ranges = collect_folding_ranges(&ast.body);
512+
let module_info = self.get_module_info(handle)?;
513+
let mut ranges = collect_folding_ranges(&ast.body, &module_info);
511514
ranges.sort_by_key(|(range, _)| range.start());
512515
ranges.dedup();
513516
Some(ranges)
@@ -1629,7 +1632,10 @@ impl<'a> Transaction<'a> {
16291632
}
16301633
}
16311634

1632-
fn collect_folding_ranges(body: &[Stmt]) -> Vec<(TextRange, Option<FoldingRangeKind>)> {
1635+
fn collect_folding_ranges(
1636+
body: &[Stmt],
1637+
module: &Module,
1638+
) -> Vec<(TextRange, Option<FoldingRangeKind>)> {
16331639
use ruff_python_ast::ExceptHandler;
16341640
use ruff_text_size::Ranged;
16351641

@@ -1646,11 +1652,12 @@ fn collect_folding_ranges(body: &[Stmt]) -> Vec<(TextRange, Option<FoldingRangeK
16461652
})
16471653
}
16481654

1649-
struct FoldingRangeCollector {
1655+
struct FoldingRangeCollector<'a> {
16501656
ranges: Vec<(TextRange, Option<FoldingRangeKind>)>,
1657+
module: &'a Module,
16511658
}
16521659

1653-
impl Visitor<'_> for FoldingRangeCollector {
1660+
impl Visitor<'_> for FoldingRangeCollector<'_> {
16541661
fn visit_body(&mut self, body: &[Stmt]) {
16551662
if let Some(range) = Docstring::range_from_stmts(body) {
16561663
self.ranges.push((range, Some(FoldingRangeKind::Comment)));
@@ -1720,9 +1727,31 @@ fn collect_folding_ranges(body: &[Stmt]) -> Vec<(TextRange, Option<FoldingRangeK
17201727
}
17211728
ruff_python_ast::visitor::walk_stmt(self, stmt);
17221729
}
1730+
1731+
fn visit_expr(&mut self, expr: &Expr) {
1732+
let range = match expr {
1733+
Expr::Call(call) => Some(call.arguments.range),
1734+
Expr::Dict(dict) => Some(dict.range),
1735+
Expr::List(list) => Some(list.range),
1736+
Expr::Set(set) => Some(set.range),
1737+
Expr::Tuple(tuple) => Some(tuple.range),
1738+
_ => None,
1739+
};
1740+
1741+
if let Some(range) = range {
1742+
let lsp_range = self.module.lined_buffer().to_lsp_range(range);
1743+
if lsp_range.start.line != lsp_range.end.line {
1744+
self.ranges.push((range, None));
1745+
}
1746+
}
1747+
ruff_python_ast::visitor::walk_expr(self, expr);
1748+
}
17231749
}
17241750

1725-
let mut collector = FoldingRangeCollector { ranges: Vec::new() };
1751+
let mut collector = FoldingRangeCollector {
1752+
ranges: Vec::new(),
1753+
module,
1754+
};
17261755

17271756
if let Some(range) = Docstring::range_from_stmts(body) {
17281757
collector

pyrefly/lib/test/lsp/folding_ranges.rs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,3 +552,180 @@ class MyClass:
552552
report.trim(),
553553
);
554554
}
555+
556+
#[test]
557+
fn folding_ranges_for_calls() {
558+
let code = r#"
559+
def foo(*args):
560+
pass
561+
562+
def short_call(*args):
563+
pass
564+
565+
def multi_line_nested(*args):
566+
pass
567+
568+
def bar(*args):
569+
pass
570+
571+
def very_long_function_name(**kwargs):
572+
pass
573+
574+
nested_arg = 1
575+
another_arg = 2
576+
second_arg = 3
577+
value1 = 1
578+
value2 = 2
579+
value3 = 3
580+
581+
result = foo(
582+
1,
583+
2,
584+
3,
585+
4
586+
)
587+
588+
short_call(1, 2, 3)
589+
590+
multi_line_nested(
591+
bar(
592+
nested_arg,
593+
another_arg
594+
),
595+
second_arg
596+
)
597+
598+
x = very_long_function_name(
599+
param1=value1,
600+
param2=value2,
601+
param3=value3
602+
)
603+
"#;
604+
605+
let report =
606+
get_batched_lsp_operations_report_no_cursor(&[("main", code)], get_folding_ranges_report);
607+
608+
assert_eq!(
609+
r#"# main.py
610+
611+
[
612+
{
613+
"start_line": 1,
614+
"end_line": 2
615+
},
616+
{
617+
"start_line": 4,
618+
"end_line": 5
619+
},
620+
{
621+
"start_line": 7,
622+
"end_line": 8
623+
},
624+
{
625+
"start_line": 10,
626+
"end_line": 11
627+
},
628+
{
629+
"start_line": 13,
630+
"end_line": 14
631+
},
632+
{
633+
"start_line": 23,
634+
"end_line": 28
635+
},
636+
{
637+
"start_line": 32,
638+
"end_line": 38
639+
},
640+
{
641+
"start_line": 33,
642+
"end_line": 36
643+
},
644+
{
645+
"start_line": 40,
646+
"end_line": 44
647+
}
648+
]"#
649+
.trim(),
650+
report.trim(),
651+
);
652+
}
653+
654+
#[test]
655+
fn folding_ranges_for_literals() {
656+
let code = r#"
657+
data = {
658+
"key1": "value1",
659+
"key2": "value2",
660+
"key3": "value3"
661+
}
662+
663+
items = [
664+
1,
665+
2,
666+
3,
667+
4
668+
]
669+
670+
my_set = {
671+
"a",
672+
"b",
673+
"c"
674+
}
675+
676+
coordinates = (
677+
10,
678+
20,
679+
30
680+
)
681+
682+
nested = {
683+
"inner_dict": {
684+
"nested_key": "value"
685+
},
686+
"inner_list": [
687+
1, 2, 3
688+
]
689+
}
690+
"#;
691+
692+
let report =
693+
get_batched_lsp_operations_report_no_cursor(&[("main", code)], get_folding_ranges_report);
694+
695+
assert_eq!(
696+
r#"# main.py
697+
698+
[
699+
{
700+
"start_line": 1,
701+
"end_line": 5
702+
},
703+
{
704+
"start_line": 7,
705+
"end_line": 12
706+
},
707+
{
708+
"start_line": 14,
709+
"end_line": 18
710+
},
711+
{
712+
"start_line": 20,
713+
"end_line": 24
714+
},
715+
{
716+
"start_line": 26,
717+
"end_line": 33
718+
},
719+
{
720+
"start_line": 27,
721+
"end_line": 29
722+
},
723+
{
724+
"start_line": 30,
725+
"end_line": 32
726+
}
727+
]"#
728+
.trim(),
729+
report.trim(),
730+
);
731+
}

0 commit comments

Comments
 (0)