Skip to content

Commit 8295dc4

Browse files
committed
Fold multiline calls
1 parent 53e3a7a commit 8295dc4

File tree

3 files changed

+114
-105
lines changed

3 files changed

+114
-105
lines changed

crates/ra_ide/src/folding_ranges.rs

Lines changed: 81 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub enum FoldKind {
1515
Imports,
1616
Mods,
1717
Block,
18+
ArgList,
1819
}
1920

2021
#[derive(Debug)]
@@ -83,6 +84,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
8384
match kind {
8485
COMMENT => Some(FoldKind::Comment),
8586
USE_ITEM => Some(FoldKind::Imports),
87+
ARG_LIST => Some(FoldKind::ArgList),
8688
RECORD_FIELD_DEF_LIST
8789
| RECORD_FIELD_PAT_LIST
8890
| ITEM_LIST
@@ -196,180 +198,179 @@ fn contiguous_range_for_comment(
196198

197199
#[cfg(test)]
198200
mod tests {
201+
use test_utils::extract_tags;
202+
199203
use super::*;
200-
use test_utils::extract_ranges;
201204

202-
fn do_check(text: &str, fold_kinds: &[FoldKind]) {
203-
let (ranges, text) = extract_ranges(text, "fold");
205+
fn check(ra_fixture: &str) {
206+
let (ranges, text) = extract_tags(ra_fixture, "fold");
207+
204208
let parse = SourceFile::parse(&text);
205209
let folds = folding_ranges(&parse.tree());
206-
207210
assert_eq!(
208211
folds.len(),
209212
ranges.len(),
210213
"The amount of folds is different than the expected amount"
211214
);
212-
assert_eq!(
213-
folds.len(),
214-
fold_kinds.len(),
215-
"The amount of fold kinds is different than the expected amount"
216-
);
217-
for ((fold, range), fold_kind) in
218-
folds.iter().zip(ranges.into_iter()).zip(fold_kinds.iter())
219-
{
215+
216+
for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
220217
assert_eq!(fold.range.start(), range.start());
221218
assert_eq!(fold.range.end(), range.end());
222-
assert_eq!(&fold.kind, fold_kind);
219+
220+
let kind = match fold.kind {
221+
FoldKind::Comment => "comment",
222+
FoldKind::Imports => "imports",
223+
FoldKind::Mods => "mods",
224+
FoldKind::Block => "block",
225+
FoldKind::ArgList => "arglist",
226+
};
227+
assert_eq!(kind, &attr.unwrap());
223228
}
224229
}
225230

226231
#[test]
227232
fn test_fold_comments() {
228-
let text = r#"
229-
<fold>// Hello
233+
check(
234+
r#"
235+
<fold comment>// Hello
230236
// this is a multiline
231237
// comment
232238
//</fold>
233239
234240
// But this is not
235241
236-
fn main() <fold>{
237-
<fold>// We should
242+
fn main() <fold block>{
243+
<fold comment>// We should
238244
// also
239245
// fold
240246
// this one.</fold>
241-
<fold>//! But this one is different
247+
<fold comment>//! But this one is different
242248
//! because it has another flavor</fold>
243-
<fold>/* As does this
249+
<fold comment>/* As does this
244250
multiline comment */</fold>
245-
}</fold>"#;
246-
247-
let fold_kinds = &[
248-
FoldKind::Comment,
249-
FoldKind::Block,
250-
FoldKind::Comment,
251-
FoldKind::Comment,
252-
FoldKind::Comment,
253-
];
254-
do_check(text, fold_kinds);
251+
}</fold>"#,
252+
);
255253
}
256254

257255
#[test]
258256
fn test_fold_imports() {
259-
let text = r#"
260-
<fold>use std::<fold>{
257+
check(
258+
r#"
259+
<fold imports>use std::<fold block>{
261260
str,
262261
vec,
263262
io as iop
264263
}</fold>;</fold>
265264
266-
fn main() <fold>{
267-
}</fold>"#;
268-
269-
let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
270-
do_check(text, folds);
265+
fn main() <fold block>{
266+
}</fold>"#,
267+
);
271268
}
272269

273270
#[test]
274271
fn test_fold_mods() {
275-
let text = r#"
272+
check(
273+
r#"
276274
277275
pub mod foo;
278-
<fold>mod after_pub;
276+
<fold mods>mod after_pub;
279277
mod after_pub_next;</fold>
280278
281-
<fold>mod before_pub;
279+
<fold mods>mod before_pub;
282280
mod before_pub_next;</fold>
283281
pub mod bar;
284282
285283
mod not_folding_single;
286284
pub mod foobar;
287285
pub not_folding_single_next;
288286
289-
<fold>#[cfg(test)]
287+
<fold mods>#[cfg(test)]
290288
mod with_attribute;
291289
mod with_attribute_next;</fold>
292290
293-
fn main() <fold>{
294-
}</fold>"#;
295-
296-
let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block];
297-
do_check(text, folds);
291+
fn main() <fold block>{
292+
}</fold>"#,
293+
);
298294
}
299295

300296
#[test]
301297
fn test_fold_import_groups() {
302-
let text = r#"
303-
<fold>use std::str;
298+
check(
299+
r#"
300+
<fold imports>use std::str;
304301
use std::vec;
305302
use std::io as iop;</fold>
306303
307-
<fold>use std::mem;
304+
<fold imports>use std::mem;
308305
use std::f64;</fold>
309306
310307
use std::collections::HashMap;
311308
// Some random comment
312309
use std::collections::VecDeque;
313310
314-
fn main() <fold>{
315-
}</fold>"#;
316-
317-
let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
318-
do_check(text, folds);
311+
fn main() <fold block>{
312+
}</fold>"#,
313+
);
319314
}
320315

321316
#[test]
322317
fn test_fold_import_and_groups() {
323-
let text = r#"
324-
<fold>use std::str;
318+
check(
319+
r#"
320+
<fold imports>use std::str;
325321
use std::vec;
326322
use std::io as iop;</fold>
327323
328-
<fold>use std::mem;
324+
<fold imports>use std::mem;
329325
use std::f64;</fold>
330326
331-
<fold>use std::collections::<fold>{
327+
<fold imports>use std::collections::<fold block>{
332328
HashMap,
333329
VecDeque,
334330
}</fold>;</fold>
335331
// Some random comment
336332
337-
fn main() <fold>{
338-
}</fold>"#;
339-
340-
let folds = &[
341-
FoldKind::Imports,
342-
FoldKind::Imports,
343-
FoldKind::Imports,
344-
FoldKind::Block,
345-
FoldKind::Block,
346-
];
347-
do_check(text, folds);
333+
fn main() <fold block>{
334+
}</fold>"#,
335+
);
348336
}
349337

350338
#[test]
351339
fn test_folds_macros() {
352-
let text = r#"
353-
macro_rules! foo <fold>{
340+
check(
341+
r#"
342+
macro_rules! foo <fold block>{
354343
($($tt:tt)*) => { $($tt)* }
355344
}</fold>
356-
"#;
357-
358-
let folds = &[FoldKind::Block];
359-
do_check(text, folds);
345+
"#,
346+
);
360347
}
361348

362349
#[test]
363350
fn test_fold_match_arms() {
364-
let text = r#"
365-
fn main() <fold>{
366-
match 0 <fold>{
351+
check(
352+
r#"
353+
fn main() <fold block>{
354+
match 0 <fold block>{
367355
0 => 0,
368356
_ => 1,
369357
}</fold>
370-
}</fold>"#;
358+
}</fold>"#,
359+
);
360+
}
371361

372-
let folds = &[FoldKind::Block, FoldKind::Block];
373-
do_check(text, folds);
362+
#[test]
363+
fn fold_big_calls() {
364+
check(
365+
r#"
366+
fn main() <fold block>{
367+
frobnicate<fold arglist>(
368+
1,
369+
2,
370+
3,
371+
)</fold>
372+
}</fold>
373+
"#,
374+
)
374375
}
375376
}

crates/rust-analyzer/src/to_proto.rs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ pub(crate) fn folding_range(
352352
let kind = match fold.kind {
353353
FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
354354
FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
355-
FoldKind::Mods | FoldKind::Block => None,
355+
FoldKind::Mods | FoldKind::Block | FoldKind::ArgList => None,
356356
};
357357

358358
let range = range(line_index, fold.range);
@@ -685,32 +685,27 @@ pub(crate) fn runnable(
685685

686686
#[cfg(test)]
687687
mod tests {
688-
use test_utils::extract_ranges;
688+
use ra_ide::Analysis;
689689

690690
use super::*;
691691

692692
#[test]
693693
fn conv_fold_line_folding_only_fixup() {
694-
let text = r#"<fold>mod a;
694+
let text = r#"mod a;
695695
mod b;
696-
mod c;</fold>
696+
mod c;
697697
698-
fn main() <fold>{
699-
if cond <fold>{
698+
fn main() {
699+
if cond {
700700
a::do_a();
701-
}</fold> else <fold>{
701+
} else {
702702
b::do_b();
703-
}</fold>
704-
}</fold>"#;
705-
706-
let (ranges, text) = extract_ranges(text, "fold");
707-
assert_eq!(ranges.len(), 4);
708-
let folds = vec![
709-
Fold { range: ranges[0], kind: FoldKind::Mods },
710-
Fold { range: ranges[1], kind: FoldKind::Block },
711-
Fold { range: ranges[2], kind: FoldKind::Block },
712-
Fold { range: ranges[3], kind: FoldKind::Block },
713-
];
703+
}
704+
}"#;
705+
706+
let (analysis, file_id) = Analysis::from_single_file(text.to_string());
707+
let folds = analysis.folding_ranges(file_id).unwrap();
708+
assert_eq!(folds.len(), 4);
714709

715710
let line_index = LineIndex::new(&text);
716711
let converted: Vec<lsp_types::FoldingRange> =

crates/test_utils/src/lib.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) {
118118
}
119119

120120
/// Extracts ranges, marked with `<tag> </tag>` pairs from the `text`
121-
pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
122-
let open = format!("<{}>", tag);
121+
pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option<String>)>, String) {
122+
let open = format!("<{}", tag);
123123
let close = format!("</{}>", tag);
124124
let mut ranges = Vec::new();
125125
let mut res = String::new();
@@ -134,22 +134,35 @@ pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
134134
res.push_str(&text[..i]);
135135
text = &text[i..];
136136
if text.starts_with(&open) {
137-
text = &text[open.len()..];
137+
let close_open = text.find('>').unwrap();
138+
let attr = text[open.len()..close_open].trim();
139+
let attr = if attr.is_empty() { None } else { Some(attr.to_string()) };
140+
text = &text[close_open + '>'.len_utf8()..];
138141
let from = TextSize::of(&res);
139-
stack.push(from);
142+
stack.push((from, attr));
140143
} else if text.starts_with(&close) {
141144
text = &text[close.len()..];
142-
let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
145+
let (from, attr) =
146+
stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
143147
let to = TextSize::of(&res);
144-
ranges.push(TextRange::new(from, to));
148+
ranges.push((TextRange::new(from, to), attr));
149+
} else {
150+
res.push('<');
151+
text = &text['<'.len_utf8()..];
145152
}
146153
}
147154
}
148155
}
149156
assert!(stack.is_empty(), "unmatched <{}>", tag);
150-
ranges.sort_by_key(|r| (r.start(), r.end()));
157+
ranges.sort_by_key(|r| (r.0.start(), r.0.end()));
151158
(ranges, res)
152159
}
160+
#[test]
161+
fn test_extract_tags() {
162+
let (tags, text) = extract_tags(r#"<tag fn>fn <tag>main</tag>() {}</tag>"#, "tag");
163+
let actual = tags.into_iter().map(|(range, attr)| (&text[range], attr)).collect::<Vec<_>>();
164+
assert_eq!(actual, vec![("fn main() {}", Some("fn".into())), ("main", None),]);
165+
}
153166

154167
/// Inserts `<|>` marker into the `text` at `offset`.
155168
pub fn add_cursor(text: &str, offset: TextSize) -> String {

0 commit comments

Comments
 (0)