diff --git a/crates/ra_ide/src/display/structure.rs b/crates/ra_ide/src/display/structure.rs index aad5a8e4db..c22a5d17b3 100644 --- a/crates/ra_ide/src/display/structure.rs +++ b/crates/ra_ide/src/display/structure.rs @@ -173,12 +173,19 @@ fn structure_node(node: &SyntaxNode) -> Option { #[cfg(test)] mod tests { + use expect::{expect, Expect}; + use super::*; - use insta::assert_debug_snapshot; + + fn check(ra_fixture: &str, expect: Expect) { + let file = SourceFile::parse(ra_fixture).ok().unwrap(); + let structure = file_structure(&file); + expect.assert_debug_eq(&structure) + } #[test] fn test_file_structure() { - let file = SourceFile::parse( + check( r#" struct Foo { x: i32 @@ -223,216 +230,211 @@ fn obsolete() {} #[deprecated(note = "for awhile")] fn very_obsolete() {} "#, - ) - .ok() - .unwrap(); - let structure = file_structure(&file); - assert_debug_snapshot!(structure, - @r###" - [ - StructureNode { - parent: None, - label: "Foo", - navigation_range: 8..11, - node_range: 1..26, - kind: STRUCT_DEF, - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 0, - ), - label: "x", - navigation_range: 18..19, - node_range: 18..24, - kind: RECORD_FIELD_DEF, - detail: Some( - "i32", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "m", - navigation_range: 32..33, - node_range: 28..158, - kind: MODULE, - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 2, - ), - label: "bar1", - navigation_range: 43..47, - node_range: 40..52, - kind: FN_DEF, - detail: Some( - "fn()", - ), - deprecated: false, - }, - StructureNode { - parent: Some( - 2, - ), - label: "bar2", - navigation_range: 60..64, - node_range: 57..81, - kind: FN_DEF, - detail: Some( - "fn(t: T) -> T", - ), - deprecated: false, - }, - StructureNode { - parent: Some( - 2, - ), - label: "bar3", - navigation_range: 89..93, - node_range: 86..156, - kind: FN_DEF, - detail: Some( - "fn(a: A, b: B) -> Vec< u32 >", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "E", - navigation_range: 165..166, - node_range: 160..180, - kind: ENUM_DEF, - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 6, - ), - label: "X", - navigation_range: 169..170, - node_range: 169..170, - kind: ENUM_VARIANT, - detail: None, - deprecated: false, - }, - StructureNode { - parent: Some( - 6, - ), - label: "Y", - navigation_range: 172..173, - node_range: 172..178, - kind: ENUM_VARIANT, - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "T", - navigation_range: 186..187, - node_range: 181..193, - kind: TYPE_ALIAS_DEF, - detail: Some( - "()", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "S", - navigation_range: 201..202, - node_range: 194..213, - kind: STATIC_DEF, - detail: Some( - "i32", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "C", - navigation_range: 220..221, - node_range: 214..232, - kind: CONST_DEF, - detail: Some( - "i32", - ), - deprecated: false, - }, - StructureNode { - parent: None, - label: "impl E", - navigation_range: 239..240, - node_range: 234..243, - kind: IMPL_DEF, - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "impl fmt::Debug for E", - navigation_range: 265..266, - node_range: 245..269, - kind: IMPL_DEF, - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "mc", - navigation_range: 284..286, - node_range: 271..303, - kind: MACRO_CALL, - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "mcexp", - navigation_range: 334..339, - node_range: 305..356, - kind: MACRO_CALL, - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "mcexp", - navigation_range: 387..392, - node_range: 358..409, - kind: MACRO_CALL, - detail: None, - deprecated: false, - }, - StructureNode { - parent: None, - label: "obsolete", - navigation_range: 428..436, - node_range: 411..441, - kind: FN_DEF, - detail: Some( - "fn()", - ), - deprecated: true, - }, - StructureNode { - parent: None, - label: "very_obsolete", - navigation_range: 481..494, - node_range: 443..499, - kind: FN_DEF, - detail: Some( - "fn()", - ), - deprecated: true, - }, - ] - "### - ); + expect![[r#" + [ + StructureNode { + parent: None, + label: "Foo", + navigation_range: 8..11, + node_range: 1..26, + kind: STRUCT_DEF, + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 0, + ), + label: "x", + navigation_range: 18..19, + node_range: 18..24, + kind: RECORD_FIELD_DEF, + detail: Some( + "i32", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "m", + navigation_range: 32..33, + node_range: 28..158, + kind: MODULE, + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 2, + ), + label: "bar1", + navigation_range: 43..47, + node_range: 40..52, + kind: FN_DEF, + detail: Some( + "fn()", + ), + deprecated: false, + }, + StructureNode { + parent: Some( + 2, + ), + label: "bar2", + navigation_range: 60..64, + node_range: 57..81, + kind: FN_DEF, + detail: Some( + "fn(t: T) -> T", + ), + deprecated: false, + }, + StructureNode { + parent: Some( + 2, + ), + label: "bar3", + navigation_range: 89..93, + node_range: 86..156, + kind: FN_DEF, + detail: Some( + "fn(a: A, b: B) -> Vec< u32 >", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "E", + navigation_range: 165..166, + node_range: 160..180, + kind: ENUM_DEF, + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 6, + ), + label: "X", + navigation_range: 169..170, + node_range: 169..170, + kind: ENUM_VARIANT, + detail: None, + deprecated: false, + }, + StructureNode { + parent: Some( + 6, + ), + label: "Y", + navigation_range: 172..173, + node_range: 172..178, + kind: ENUM_VARIANT, + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "T", + navigation_range: 186..187, + node_range: 181..193, + kind: TYPE_ALIAS_DEF, + detail: Some( + "()", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "S", + navigation_range: 201..202, + node_range: 194..213, + kind: STATIC_DEF, + detail: Some( + "i32", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "C", + navigation_range: 220..221, + node_range: 214..232, + kind: CONST_DEF, + detail: Some( + "i32", + ), + deprecated: false, + }, + StructureNode { + parent: None, + label: "impl E", + navigation_range: 239..240, + node_range: 234..243, + kind: IMPL_DEF, + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "impl fmt::Debug for E", + navigation_range: 265..266, + node_range: 245..269, + kind: IMPL_DEF, + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "mc", + navigation_range: 284..286, + node_range: 271..303, + kind: MACRO_CALL, + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "mcexp", + navigation_range: 334..339, + node_range: 305..356, + kind: MACRO_CALL, + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "mcexp", + navigation_range: 387..392, + node_range: 358..409, + kind: MACRO_CALL, + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, + label: "obsolete", + navigation_range: 428..436, + node_range: 411..441, + kind: FN_DEF, + detail: Some( + "fn()", + ), + deprecated: true, + }, + StructureNode { + parent: None, + label: "very_obsolete", + navigation_range: 481..494, + node_range: 443..499, + kind: FN_DEF, + detail: Some( + "fn()", + ), + deprecated: true, + }, + ] + "#]], + ); } } diff --git a/crates/ra_ide/src/folding_ranges.rs b/crates/ra_ide/src/folding_ranges.rs index 8657377ded..5cec689f8b 100644 --- a/crates/ra_ide/src/folding_ranges.rs +++ b/crates/ra_ide/src/folding_ranges.rs @@ -15,6 +15,7 @@ pub enum FoldKind { Imports, Mods, Block, + ArgList, } #[derive(Debug)] @@ -83,6 +84,7 @@ fn fold_kind(kind: SyntaxKind) -> Option { 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 super::*; - use test_utils::extract_ranges; + use test_utils::extract_tags; + + use super::*; + + fn check(ra_fixture: &str) { + let (ranges, text) = extract_tags(ra_fixture, "fold"); - fn do_check(text: &str, fold_kinds: &[FoldKind]) { - let (ranges, text) = extract_ranges(text, "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#" -// Hello + check( + r#" +// Hello // this is a multiline // comment // // But this is not -fn main() { - // We should +fn main() { + // We should // also // fold // this one. - //! But this one is different + //! But this one is different //! because it has another flavor - /* As does this + /* As does this multiline comment */ -}"#; - - let fold_kinds = &[ - FoldKind::Comment, - FoldKind::Block, - FoldKind::Comment, - FoldKind::Comment, - FoldKind::Comment, - ]; - do_check(text, fold_kinds); +}"#, + ); } #[test] fn test_fold_imports() { - let text = r#" -use std::{ + check( + r#" +use std::{ str, vec, io as iop }; -fn main() { -}"#; - - let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block]; - do_check(text, folds); +fn main() { +}"#, + ); } #[test] fn test_fold_mods() { - let text = r#" + check( + r#" pub mod foo; -mod after_pub; +mod after_pub; mod after_pub_next; -mod before_pub; +mod before_pub; mod before_pub_next; pub mod bar; @@ -286,90 +284,93 @@ mod not_folding_single; pub mod foobar; pub not_folding_single_next; -#[cfg(test)] +#[cfg(test)] mod with_attribute; mod with_attribute_next; -fn main() { -}"#; - - let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block]; - do_check(text, folds); +fn main() { +}"#, + ); } #[test] fn test_fold_import_groups() { - let text = r#" -use std::str; + check( + r#" +use std::str; use std::vec; use std::io as iop; -use std::mem; +use std::mem; use std::f64; use std::collections::HashMap; // Some random comment use std::collections::VecDeque; -fn main() { -}"#; - - let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block]; - do_check(text, folds); +fn main() { +}"#, + ); } #[test] fn test_fold_import_and_groups() { - let text = r#" -use std::str; + check( + r#" +use std::str; use std::vec; use std::io as iop; -use std::mem; +use std::mem; use std::f64; -use std::collections::{ +use std::collections::{ HashMap, VecDeque, }; // Some random comment -fn main() { -}"#; - - let folds = &[ - FoldKind::Imports, - FoldKind::Imports, - FoldKind::Imports, - FoldKind::Block, - FoldKind::Block, - ]; - do_check(text, folds); +fn main() { +}"#, + ); } #[test] fn test_folds_macros() { - let text = r#" -macro_rules! foo { + check( + r#" +macro_rules! foo { ($($tt:tt)*) => { $($tt)* } } -"#; - - let folds = &[FoldKind::Block]; - do_check(text, folds); +"#, + ); } #[test] fn test_fold_match_arms() { - let text = r#" -fn main() { - match 0 { + check( + r#" +fn main() { + match 0 { 0 => 0, _ => 1, } -}"#; +}"#, + ); + } - let folds = &[FoldKind::Block, FoldKind::Block]; - do_check(text, folds); + #[test] + fn fold_big_calls() { + check( + r#" +fn main() { + frobnicate( + 1, + 2, + 3, + ) +} + "#, + ) } } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index a0a58f689d..95dd8e408d 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -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#"mod a; + let text = r#"mod a; mod b; -mod c; +mod c; -fn main() { - if cond { +fn main() { + if cond { a::do_a(); - } else { + } else { b::do_b(); - } -}"#; + } +}"#; - 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 = diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index fba5f42810..e4aa894ace 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -118,8 +118,8 @@ pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) { } /// Extracts ranges, marked with ` ` pairs from the `text` -pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec, String) { - let open = format!("<{}>", tag); +pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option)>, 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, 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#"fn main() {}"#, "tag"); + let actual = tags.into_iter().map(|(range, attr)| (&text[range], attr)).collect::>(); + 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 {