diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 6e7c718953cc..af9a7ce7881a 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -48,7 +48,6 @@ mod ssr; mod static_index; mod status; mod syntax_highlighting; -mod syntax_tree; mod test_explorer; mod typing; mod view_crate_graph; @@ -56,6 +55,7 @@ mod view_hir; mod view_item_tree; mod view_memory_layout; mod view_mir; +mod view_syntax_tree; use std::{iter, panic::UnwindSafe}; @@ -329,14 +329,8 @@ impl Analysis { }) } - /// Returns a syntax tree represented as `String`, for debug purposes. - // FIXME: use a better name here. - pub fn syntax_tree( - &self, - file_id: FileId, - text_range: Option, - ) -> Cancellable { - self.with_db(|db| syntax_tree::syntax_tree(db, file_id, text_range)) + pub fn view_syntax_tree(&self, file_id: FileId) -> Cancellable { + self.with_db(|db| view_syntax_tree::view_syntax_tree(db, file_id)) } pub fn view_hir(&self, position: FilePosition) -> Cancellable { diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs deleted file mode 100644 index e241cb82bd5b..000000000000 --- a/crates/ide/src/syntax_tree.rs +++ /dev/null @@ -1,338 +0,0 @@ -use hir::Semantics; -use ide_db::{FileId, RootDatabase}; -use syntax::{ - AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize, -}; - -// Feature: Show Syntax Tree -// -// Shows the parse tree of the current file. It exists mostly for debugging -// rust-analyzer itself. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **rust-analyzer: Show Syntax Tree** -// |=== -// image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[] -pub(crate) fn syntax_tree( - db: &RootDatabase, - file_id: FileId, - text_range: Option, -) -> String { - let sema = Semantics::new(db); - let parse = sema.parse_guess_edition(file_id); - if let Some(text_range) = text_range { - let node = match parse.syntax().covering_element(text_range) { - NodeOrToken::Node(node) => node, - NodeOrToken::Token(token) => { - if let Some(tree) = syntax_tree_for_string(&token, text_range) { - return tree; - } - token.parent().unwrap() - } - }; - - format!("{node:#?}") - } else { - format!("{:#?}", parse.syntax()) - } -} - -/// Attempts parsing the selected contents of a string literal -/// as rust syntax and returns its syntax tree -fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option { - // When the range is inside a string - // we'll attempt parsing it as rust syntax - // to provide the syntax tree of the contents of the string - match token.kind() { - STRING => syntax_tree_for_token(token, text_range), - _ => None, - } -} - -fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option { - // Range of the full node - let node_range = node.text_range(); - let text = node.text().to_owned(); - - // We start at some point inside the node - // Either we have selected the whole string - // or our selection is inside it - let start = text_range.start() - node_range.start(); - - // how many characters we have selected - let len = text_range.len(); - - let node_len = node_range.len(); - - // We want to cap our length - let len = len.min(node_len); - - // Ensure our slice is inside the actual string - let end = - if start + len < TextSize::of(&text) { start + len } else { TextSize::of(&text) - start }; - - let text = &text[TextRange::new(start, end)]; - - // Remove possible extra string quotes from the start - // and the end of the string - let text = text - .trim_start_matches('r') - .trim_start_matches('#') - .trim_start_matches('"') - .trim_end_matches('#') - .trim_end_matches('"') - .trim() - // Remove custom markers - .replace("$0", ""); - - let parsed = SourceFile::parse(&text, span::Edition::CURRENT_FIXME); - - // If the "file" parsed without errors, - // return its syntax - if parsed.errors().is_empty() { - return Some(format!("{:#?}", parsed.tree().syntax())); - } - - None -} - -#[cfg(test)] -mod tests { - use expect_test::expect; - - use crate::fixture; - - fn check(ra_fixture: &str, expect: expect_test::Expect) { - let (analysis, file_id) = fixture::file(ra_fixture); - let syn = analysis.syntax_tree(file_id, None).unwrap(); - expect.assert_eq(&syn) - } - fn check_range(ra_fixture: &str, expect: expect_test::Expect) { - let (analysis, frange) = fixture::range(ra_fixture); - let syn = analysis.syntax_tree(frange.file_id, Some(frange.range)).unwrap(); - expect.assert_eq(&syn) - } - - #[test] - fn test_syntax_tree_without_range() { - // Basic syntax - check( - r#"fn foo() {}"#, - expect![[r#" - SOURCE_FILE@0..11 - FN@0..11 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..11 - STMT_LIST@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" - "#]], - ); - - check( - r#" -fn test() { - assert!(" - fn foo() { - } - ", ""); -}"#, - expect![[r#" - SOURCE_FILE@0..60 - FN@0..60 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..7 - IDENT@3..7 "test" - PARAM_LIST@7..9 - L_PAREN@7..8 "(" - R_PAREN@8..9 ")" - WHITESPACE@9..10 " " - BLOCK_EXPR@10..60 - STMT_LIST@10..60 - L_CURLY@10..11 "{" - WHITESPACE@11..16 "\n " - EXPR_STMT@16..58 - MACRO_EXPR@16..57 - MACRO_CALL@16..57 - PATH@16..22 - PATH_SEGMENT@16..22 - NAME_REF@16..22 - IDENT@16..22 "assert" - BANG@22..23 "!" - TOKEN_TREE@23..57 - L_PAREN@23..24 "(" - STRING@24..52 "\"\n fn foo() {\n ..." - COMMA@52..53 "," - WHITESPACE@53..54 " " - STRING@54..56 "\"\"" - R_PAREN@56..57 ")" - SEMICOLON@57..58 ";" - WHITESPACE@58..59 "\n" - R_CURLY@59..60 "}" - "#]], - ) - } - - #[test] - fn test_syntax_tree_with_range() { - check_range( - r#"$0fn foo() {}$0"#, - expect![[r#" - FN@0..11 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..11 - STMT_LIST@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" - "#]], - ); - - check_range( - r#" -fn test() { - $0assert!(" - fn foo() { - } - ", "");$0 -}"#, - expect![[r#" - EXPR_STMT@16..58 - MACRO_EXPR@16..57 - MACRO_CALL@16..57 - PATH@16..22 - PATH_SEGMENT@16..22 - NAME_REF@16..22 - IDENT@16..22 "assert" - BANG@22..23 "!" - TOKEN_TREE@23..57 - L_PAREN@23..24 "(" - STRING@24..52 "\"\n fn foo() {\n ..." - COMMA@52..53 "," - WHITESPACE@53..54 " " - STRING@54..56 "\"\"" - R_PAREN@56..57 ")" - SEMICOLON@57..58 ";" - "#]], - ); - } - - #[test] - fn test_syntax_tree_inside_string() { - check_range( - r#"fn test() { - assert!(" -$0fn foo() { -}$0 -fn bar() { -} - ", ""); -}"#, - expect![[r#" - SOURCE_FILE@0..12 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - "#]], - ); - - // With a raw string - check_range( - r###"fn test() { - assert!(r#" -$0fn foo() { -}$0 -fn bar() { -} - "#, ""); -}"###, - expect![[r#" - SOURCE_FILE@0..12 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - "#]], - ); - - // With a raw string - check_range( - r###"fn test() { - assert!(r$0#" -fn foo() { -} -fn bar() { -}"$0#, ""); -}"###, - expect![[r#" - SOURCE_FILE@0..25 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - WHITESPACE@12..13 "\n" - FN@13..25 - FN_KW@13..15 "fn" - WHITESPACE@15..16 " " - NAME@16..19 - IDENT@16..19 "bar" - PARAM_LIST@19..21 - L_PAREN@19..20 "(" - R_PAREN@20..21 ")" - WHITESPACE@21..22 " " - BLOCK_EXPR@22..25 - STMT_LIST@22..25 - L_CURLY@22..23 "{" - WHITESPACE@23..24 "\n" - R_CURLY@24..25 "}" - "#]], - ); - } -} diff --git a/crates/ide/src/view_syntax_tree.rs b/crates/ide/src/view_syntax_tree.rs new file mode 100644 index 000000000000..b2adff0f36ab --- /dev/null +++ b/crates/ide/src/view_syntax_tree.rs @@ -0,0 +1,226 @@ +use hir::Semantics; +use ide_db::{FileId, RootDatabase}; +use span::TextRange; +use stdx::format_to; +use syntax::{ + ast::{self, IsString}, + AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, WalkEvent, +}; + +// Feature: Show Syntax Tree +// +// Shows a tree view with the syntax tree of the current file +// +// |=== +// | Editor | Panel Name +// +// | VS Code | **Rust Syntax Tree** +// |=== +pub(crate) fn view_syntax_tree(db: &RootDatabase, file_id: FileId) -> String { + let sema = Semantics::new(db); + let parse = sema.parse_guess_edition(file_id); + syntax_node_to_json(parse.syntax(), None) +} + +fn syntax_node_to_json(node: &SyntaxNode, ctx: Option) -> String { + let mut result = String::new(); + for event in node.preorder_with_tokens() { + match event { + WalkEvent::Enter(it) => { + let kind = it.kind(); + let (text_range, inner_range_str) = match &ctx { + Some(ctx) => { + let inner_start: u32 = it.text_range().start().into(); + let inner_end: u32 = it.text_range().end().into(); + + let mut true_start = inner_start + ctx.offset; + let mut true_end = inner_end + ctx.offset; + for pos in &ctx.marker_positions { + if *pos >= inner_end { + break; + } + + // We conditionally add to true_start in case + // the marker is between the start and end. + true_start += 2 * (*pos < inner_start) as u32; + true_end += 2; + } + + let true_range = TextRange::new(true_start.into(), true_end.into()); + + ( + true_range, + format!( + r#","istart":{:?},"iend":{:?}"#, + it.text_range().start(), + it.text_range().end() + ), + ) + } + None => (it.text_range(), "".to_owned()), + }; + let start = text_range.start(); + let end = text_range.end(); + + match it { + NodeOrToken::Node(_) => { + format_to!( + result, + r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":["# + ); + } + NodeOrToken::Token(token) => { + let comma = if token.next_sibling_or_token().is_some() { "," } else { "" }; + match parse_rust_string(token) { + Some(parsed) => { + format_to!( + result, + r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":[{parsed}]}}{comma}"# + ); + } + None => format_to!( + result, + r#"{{"type":"Token","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str}}}{comma}"# + ), + } + } + } + } + WalkEvent::Leave(it) => match it { + NodeOrToken::Node(node) => { + let comma = if node.next_sibling_or_token().is_some() { "," } else { "" }; + format_to!(result, "]}}{comma}") + } + NodeOrToken::Token(_) => (), + }, + } + } + + result +} + +fn parse_rust_string(token: SyntaxToken) -> Option { + let string_node = ast::String::cast(token)?; + let text = string_node.value().ok()?; + + let mut trim_result = String::new(); + let mut marker_positions = Vec::new(); + let mut skipped = 0; + let mut last_end = 0; + for (start, part) in text.match_indices("$0") { + marker_positions.push((start - skipped) as u32); + trim_result.push_str(&text[last_end..start]); + skipped += part.len(); + last_end = start + part.len(); + } + trim_result.push_str(&text[last_end..text.len()]); + + let parsed = SourceFile::parse(&trim_result, span::Edition::CURRENT); + + if !parsed.errors().is_empty() { + return None; + } + + let node: &SyntaxNode = &parsed.syntax_node(); + + if node.children().count() == 0 { + // C'mon, you should have at least one node other than SOURCE_FILE + return None; + } + + Some(syntax_node_to_json( + node, + Some(InStringCtx { + offset: string_node.text_range_between_quotes()?.start().into(), + marker_positions, + }), + )) +} + +struct InStringCtx { + offset: u32, + marker_positions: Vec, +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + + use crate::fixture; + + fn check(ra_fixture: &str, expect: expect_test::Expect) { + let (analysis, file_id) = fixture::file(ra_fixture); + let syn = analysis.view_syntax_tree(file_id).unwrap(); + expect.assert_eq(&syn) + } + + #[test] + fn view_syntax_tree() { + // Basic syntax + check( + r#"fn foo() {}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":11,"children":[{"type":"Node","kind":"FN","start":0,"end":11,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":6,"children":[{"type":"Token","kind":"IDENT","start":3,"end":6}]},{"type":"Node","kind":"PARAM_LIST","start":6,"end":8,"children":[{"type":"Token","kind":"L_PAREN","start":6,"end":7},{"type":"Token","kind":"R_PAREN","start":7,"end":8}]},{"type":"Token","kind":"WHITESPACE","start":8,"end":9},{"type":"Node","kind":"BLOCK_EXPR","start":9,"end":11,"children":[{"type":"Node","kind":"STMT_LIST","start":9,"end":11,"children":[{"type":"Token","kind":"L_CURLY","start":9,"end":10},{"type":"Token","kind":"R_CURLY","start":10,"end":11}]}]}]}]}"# + ]], + ); + + check( + r#" +fn test() { + assert!(" + fn foo() { + } + ", ""); +}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":60,"children":[{"type":"Node","kind":"FN","start":0,"end":60,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":60,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":60,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":58,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":57,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":57,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":57,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":52,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":51,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":30,"istart":0,"iend":5},{"type":"Node","kind":"FN","start":30,"end":46,"istart":5,"iend":21,"children":[{"type":"Token","kind":"FN_KW","start":30,"end":32,"istart":5,"iend":7},{"type":"Token","kind":"WHITESPACE","start":32,"end":33,"istart":7,"iend":8},{"type":"Node","kind":"NAME","start":33,"end":36,"istart":8,"iend":11,"children":[{"type":"Token","kind":"IDENT","start":33,"end":36,"istart":8,"iend":11}]},{"type":"Node","kind":"PARAM_LIST","start":36,"end":38,"istart":11,"iend":13,"children":[{"type":"Token","kind":"L_PAREN","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_PAREN","start":37,"end":38,"istart":12,"iend":13}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"BLOCK_EXPR","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Node","kind":"STMT_LIST","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Token","kind":"L_CURLY","start":39,"end":40,"istart":14,"iend":15},{"type":"Token","kind":"WHITESPACE","start":40,"end":45,"istart":15,"iend":20},{"type":"Token","kind":"R_CURLY","start":45,"end":46,"istart":20,"iend":21}]}]}]},{"type":"Token","kind":"WHITESPACE","start":46,"end":51,"istart":21,"iend":26}]}]},{"type":"Token","kind":"COMMA","start":52,"end":53},{"type":"Token","kind":"WHITESPACE","start":53,"end":54},{"type":"Token","kind":"STRING","start":54,"end":56},{"type":"Token","kind":"R_PAREN","start":56,"end":57}]}]}]},{"type":"Token","kind":"SEMICOLON","start":57,"end":58}]},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"R_CURLY","start":59,"end":60}]}]}]}]}"# + ]], + ) + } + + #[test] + fn view_syntax_tree_inside_string() { + check( + r#"fn test() { + assert!(" +$0fn foo() { +}$0 +fn bar() { +} + ", ""); +}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":65,"children":[{"type":"Node","kind":"FN","start":0,"end":65,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":65,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":65,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":63,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":62,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":62,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":62,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":57,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":56,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":26,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":26,"end":38,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":26,"end":28,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":28,"end":29,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":29,"end":32,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":29,"end":32,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":32,"end":34,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":32,"end":33,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":33,"end":34,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":34,"end":35,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":35,"end":36,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":37,"end":38,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":39,"end":51,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":39,"end":41,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":41,"end":42,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":42,"end":45,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":42,"end":45,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":45,"end":47,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":45,"end":46,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":46,"end":47,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":47,"end":48,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":48,"end":49,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":50,"end":51,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":51,"end":56,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":57,"end":58},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"STRING","start":59,"end":61},{"type":"Token","kind":"R_PAREN","start":61,"end":62}]}]}]},{"type":"Token","kind":"SEMICOLON","start":62,"end":63}]},{"type":"Token","kind":"WHITESPACE","start":63,"end":64},{"type":"Token","kind":"R_CURLY","start":64,"end":65}]}]}]}]}"# + ]], + ); + + // With a raw string + check( + r###"fn test() { + assert!(r#" +$0fn foo() { +}$0 +fn bar() { +} + "#, ""); +}"###, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":68,"children":[{"type":"Node","kind":"FN","start":0,"end":68,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":68,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":68,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":66,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":65,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":65,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":65,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":60,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":58,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":53,"end":58,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":60,"end":61},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"STRING","start":62,"end":64},{"type":"Token","kind":"R_PAREN","start":64,"end":65}]}]}]},{"type":"Token","kind":"SEMICOLON","start":65,"end":66}]},{"type":"Token","kind":"WHITESPACE","start":66,"end":67},{"type":"Token","kind":"R_CURLY","start":67,"end":68}]}]}]}]}"# + ]], + ); + + // With a raw string + check( + r###"fn test() { + assert!(r$0#" +fn foo() { +} +fn bar() { +}"$0#, ""); +}"###, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":63,"children":[{"type":"Node","kind":"FN","start":0,"end":63,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":63,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":63,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":61,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":60,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":60,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":60,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":55,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":53,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]}]}]},{"type":"Token","kind":"COMMA","start":55,"end":56},{"type":"Token","kind":"WHITESPACE","start":56,"end":57},{"type":"Token","kind":"STRING","start":57,"end":59},{"type":"Token","kind":"R_PAREN","start":59,"end":60}]}]}]},{"type":"Token","kind":"SEMICOLON","start":60,"end":61}]},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"R_CURLY","start":62,"end":63}]}]}]}]}"# + ]], + ); + } +} diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 7ac70efe2d6e..d01dc5fba1f7 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -136,15 +136,13 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Res Ok(out) } -pub(crate) fn handle_syntax_tree( +pub(crate) fn handle_view_syntax_tree( snap: GlobalStateSnapshot, - params: lsp_ext::SyntaxTreeParams, + params: lsp_ext::ViewSyntaxTreeParams, ) -> anyhow::Result { - let _p = tracing::info_span!("handle_syntax_tree").entered(); + let _p = tracing::info_span!("handle_view_syntax_tree").entered(); let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(id)?; - let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok()); - let res = snap.analysis.syntax_tree(id, text_range)?; + let res = snap.analysis.view_syntax_tree(id)?; Ok(res) } diff --git a/crates/rust-analyzer/src/lsp/ext.rs b/crates/rust-analyzer/src/lsp/ext.rs index f50cbba7acfe..134de92feab3 100644 --- a/crates/rust-analyzer/src/lsp/ext.rs +++ b/crates/rust-analyzer/src/lsp/ext.rs @@ -108,19 +108,18 @@ impl Request for RebuildProcMacros { const METHOD: &'static str = "rust-analyzer/rebuildProcMacros"; } -pub enum SyntaxTree {} +pub enum ViewSyntaxTree {} -impl Request for SyntaxTree { - type Params = SyntaxTreeParams; +impl Request for ViewSyntaxTree { + type Params = ViewSyntaxTreeParams; type Result = String; - const METHOD: &'static str = "rust-analyzer/syntaxTree"; + const METHOD: &'static str = "rust-analyzer/viewSyntaxTree"; } #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct SyntaxTreeParams { +pub struct ViewSyntaxTreeParams { pub text_document: TextDocumentIdentifier, - pub range: Option, } pub enum ViewHir {} diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 97657b926583..d6dc8b521fd6 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -1145,7 +1145,7 @@ impl GlobalState { .on::(handlers::handle_workspace_symbol) .on::(handlers::handle_ssr) .on::(handlers::handle_view_recursive_memory_layout) - .on::(handlers::handle_syntax_tree) + .on::(handlers::handle_view_syntax_tree) .on::(handlers::handle_view_hir) .on::(handlers::handle_view_mir) .on::(handlers::handle_interpret_function) diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 21ac3a5a2693..a632fc6f5fb8 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@