]> git.lizzy.rs Git - rust.git/commitdiff
Fold multiline calls
authorAleksey Kladov <aleksey.kladov@gmail.com>
Wed, 1 Jul 2020 16:17:08 +0000 (18:17 +0200)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Wed, 1 Jul 2020 16:27:58 +0000 (18:27 +0200)
crates/ra_ide/src/folding_ranges.rs
crates/rust-analyzer/src/to_proto.rs
crates/test_utils/src/lib.rs

index 8657377dedaace2d1e3a0021123388ee12b648eb..5cec689f8bad11f12a632265f82f079ee7d8e9d3 100644 (file)
@@ -15,6 +15,7 @@ pub enum FoldKind {
     Imports,
     Mods,
     Block,
+    ArgList,
 }
 
 #[derive(Debug)]
@@ -83,6 +84,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
     match kind {
         COMMENT => Some(FoldKind::Comment),
         USE_ITEM => Some(FoldKind::Imports),
+        ARG_LIST => Some(FoldKind::ArgList),
         RECORD_FIELD_DEF_LIST
         | RECORD_FIELD_PAT_LIST
         | ITEM_LIST
@@ -196,89 +198,85 @@ fn contiguous_range_for_comment(
 
 #[cfg(test)]
 mod tests {
+    use test_utils::extract_tags;
+
     use super::*;
-    use test_utils::extract_ranges;
 
-    fn do_check(text: &str, fold_kinds: &[FoldKind]) {
-        let (ranges, text) = extract_ranges(text, "fold");
+    fn check(ra_fixture: &str) {
+        let (ranges, text) = extract_tags(ra_fixture, "fold");
+
         let parse = SourceFile::parse(&text);
         let folds = folding_ranges(&parse.tree());
-
         assert_eq!(
             folds.len(),
             ranges.len(),
             "The amount of folds is different than the expected amount"
         );
-        assert_eq!(
-            folds.len(),
-            fold_kinds.len(),
-            "The amount of fold kinds is different than the expected amount"
-        );
-        for ((fold, range), fold_kind) in
-            folds.iter().zip(ranges.into_iter()).zip(fold_kinds.iter())
-        {
+
+        for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
             assert_eq!(fold.range.start(), range.start());
             assert_eq!(fold.range.end(), range.end());
-            assert_eq!(&fold.kind, fold_kind);
+
+            let kind = match fold.kind {
+                FoldKind::Comment => "comment",
+                FoldKind::Imports => "imports",
+                FoldKind::Mods => "mods",
+                FoldKind::Block => "block",
+                FoldKind::ArgList => "arglist",
+            };
+            assert_eq!(kind, &attr.unwrap());
         }
     }
 
     #[test]
     fn test_fold_comments() {
-        let text = r#"
-<fold>// Hello
+        check(
+            r#"
+<fold comment>// Hello
 // this is a multiline
 // comment
 //</fold>
 
 // But this is not
 
-fn main() <fold>{
-    <fold>// We should
+fn main() <fold block>{
+    <fold comment>// We should
     // also
     // fold
     // this one.</fold>
-    <fold>//! But this one is different
+    <fold comment>//! But this one is different
     //! because it has another flavor</fold>
-    <fold>/* As does this
+    <fold comment>/* As does this
     multiline comment */</fold>
-}</fold>"#;
-
-        let fold_kinds = &[
-            FoldKind::Comment,
-            FoldKind::Block,
-            FoldKind::Comment,
-            FoldKind::Comment,
-            FoldKind::Comment,
-        ];
-        do_check(text, fold_kinds);
+}</fold>"#,
+        );
     }
 
     #[test]
     fn test_fold_imports() {
-        let text = r#"
-<fold>use std::<fold>{
+        check(
+            r#"
+<fold imports>use std::<fold block>{
     str,
     vec,
     io as iop
 }</fold>;</fold>
 
-fn main() <fold>{
-}</fold>"#;
-
-        let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
-        do_check(text, folds);
+fn main() <fold block>{
+}</fold>"#,
+        );
     }
 
     #[test]
     fn test_fold_mods() {
-        let text = r#"
+        check(
+            r#"
 
 pub mod foo;
-<fold>mod after_pub;
+<fold mods>mod after_pub;
 mod after_pub_next;</fold>
 
-<fold>mod before_pub;
+<fold mods>mod before_pub;
 mod before_pub_next;</fold>
 pub mod bar;
 
@@ -286,90 +284,93 @@ fn test_fold_mods() {
 pub mod foobar;
 pub not_folding_single_next;
 
-<fold>#[cfg(test)]
+<fold mods>#[cfg(test)]
 mod with_attribute;
 mod with_attribute_next;</fold>
 
-fn main() <fold>{
-}</fold>"#;
-
-        let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block];
-        do_check(text, folds);
+fn main() <fold block>{
+}</fold>"#,
+        );
     }
 
     #[test]
     fn test_fold_import_groups() {
-        let text = r#"
-<fold>use std::str;
+        check(
+            r#"
+<fold imports>use std::str;
 use std::vec;
 use std::io as iop;</fold>
 
-<fold>use std::mem;
+<fold imports>use std::mem;
 use std::f64;</fold>
 
 use std::collections::HashMap;
 // Some random comment
 use std::collections::VecDeque;
 
-fn main() <fold>{
-}</fold>"#;
-
-        let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
-        do_check(text, folds);
+fn main() <fold block>{
+}</fold>"#,
+        );
     }
 
     #[test]
     fn test_fold_import_and_groups() {
-        let text = r#"
-<fold>use std::str;
+        check(
+            r#"
+<fold imports>use std::str;
 use std::vec;
 use std::io as iop;</fold>
 
-<fold>use std::mem;
+<fold imports>use std::mem;
 use std::f64;</fold>
 
-<fold>use std::collections::<fold>{
+<fold imports>use std::collections::<fold block>{
     HashMap,
     VecDeque,
 }</fold>;</fold>
 // Some random comment
 
-fn main() <fold>{
-}</fold>"#;
-
-        let folds = &[
-            FoldKind::Imports,
-            FoldKind::Imports,
-            FoldKind::Imports,
-            FoldKind::Block,
-            FoldKind::Block,
-        ];
-        do_check(text, folds);
+fn main() <fold block>{
+}</fold>"#,
+        );
     }
 
     #[test]
     fn test_folds_macros() {
-        let text = r#"
-macro_rules! foo <fold>{
+        check(
+            r#"
+macro_rules! foo <fold block>{
     ($($tt:tt)*) => { $($tt)* }
 }</fold>
-"#;
-
-        let folds = &[FoldKind::Block];
-        do_check(text, folds);
+"#,
+        );
     }
 
     #[test]
     fn test_fold_match_arms() {
-        let text = r#"
-fn main() <fold>{
-    match 0 <fold>{
+        check(
+            r#"
+fn main() <fold block>{
+    match 0 <fold block>{
         0 => 0,
         _ => 1,
     }</fold>
-}</fold>"#;
+}</fold>"#,
+        );
+    }
 
-        let folds = &[FoldKind::Block, FoldKind::Block];
-        do_check(text, folds);
+    #[test]
+    fn fold_big_calls() {
+        check(
+            r#"
+fn main() <fold block>{
+    frobnicate<fold arglist>(
+        1,
+        2,
+        3,
+    )</fold>
+}</fold>
+        "#,
+        )
     }
 }
index a0a58f689d5deda4686b677550692ed1094214e3..95dd8e408d0d8ec41eb38a257dffa0f1c1c05f7f 100644 (file)
@@ -352,7 +352,7 @@ pub(crate) fn folding_range(
     let kind = match fold.kind {
         FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
         FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
-        FoldKind::Mods | FoldKind::Block => None,
+        FoldKind::Mods | FoldKind::Block | FoldKind::ArgList => None,
     };
 
     let range = range(line_index, fold.range);
@@ -685,32 +685,27 @@ pub(crate) fn runnable(
 
 #[cfg(test)]
 mod tests {
-    use test_utils::extract_ranges;
+    use ra_ide::Analysis;
 
     use super::*;
 
     #[test]
     fn conv_fold_line_folding_only_fixup() {
-        let text = r#"<fold>mod a;
+        let text = r#"mod a;
 mod b;
-mod c;</fold>
+mod c;
 
-fn main() <fold>{
-    if cond <fold>{
+fn main() {
+    if cond {
         a::do_a();
-    }</fold> else <fold>{
+    } else {
         b::do_b();
-    }</fold>
-}</fold>"#;
-
-        let (ranges, text) = extract_ranges(text, "fold");
-        assert_eq!(ranges.len(), 4);
-        let folds = vec![
-            Fold { range: ranges[0], kind: FoldKind::Mods },
-            Fold { range: ranges[1], kind: FoldKind::Block },
-            Fold { range: ranges[2], kind: FoldKind::Block },
-            Fold { range: ranges[3], kind: FoldKind::Block },
-        ];
+    }
+}"#;
+
+        let (analysis, file_id) = Analysis::from_single_file(text.to_string());
+        let folds = analysis.folding_ranges(file_id).unwrap();
+        assert_eq!(folds.len(), 4);
 
         let line_index = LineIndex::new(&text);
         let converted: Vec<lsp_types::FoldingRange> =
index fba5f42810d6baccb3b8fc835d77419ed0dbbdc6..e4aa894ace3ec49686de0d0c59b78fe5fe265bb9 100644 (file)
@@ -118,8 +118,8 @@ pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) {
 }
 
 /// Extracts ranges, marked with `<tag> </tag>` pairs from the `text`
-pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
-    let open = format!("<{}>", tag);
+pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option<String>)>, String) {
+    let open = format!("<{}", tag);
     let close = format!("</{}>", tag);
     let mut ranges = Vec::new();
     let mut res = String::new();
@@ -134,22 +134,35 @@ pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
                 res.push_str(&text[..i]);
                 text = &text[i..];
                 if text.starts_with(&open) {
-                    text = &text[open.len()..];
+                    let close_open = text.find('>').unwrap();
+                    let attr = text[open.len()..close_open].trim();
+                    let attr = if attr.is_empty() { None } else { Some(attr.to_string()) };
+                    text = &text[close_open + '>'.len_utf8()..];
                     let from = TextSize::of(&res);
-                    stack.push(from);
+                    stack.push((from, attr));
                 } else if text.starts_with(&close) {
                     text = &text[close.len()..];
-                    let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
+                    let (from, attr) =
+                        stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
                     let to = TextSize::of(&res);
-                    ranges.push(TextRange::new(from, to));
+                    ranges.push((TextRange::new(from, to), attr));
+                } else {
+                    res.push('<');
+                    text = &text['<'.len_utf8()..];
                 }
             }
         }
     }
     assert!(stack.is_empty(), "unmatched <{}>", tag);
-    ranges.sort_by_key(|r| (r.start(), r.end()));
+    ranges.sort_by_key(|r| (r.0.start(), r.0.end()));
     (ranges, res)
 }
+#[test]
+fn test_extract_tags() {
+    let (tags, text) = extract_tags(r#"<tag fn>fn <tag>main</tag>() {}</tag>"#, "tag");
+    let actual = tags.into_iter().map(|(range, attr)| (&text[range], attr)).collect::<Vec<_>>();
+    assert_eq!(actual, vec![("fn main() {}", Some("fn".into())), ("main", None),]);
+}
 
 /// Inserts `<|>` marker into the `text` at `offset`.
 pub fn add_cursor(text: &str, offset: TextSize) -> String {