Add optional range parameter to SyntaxTreeParams

When range is provided, instead of showing the syntax for the whole file, we'll
show the syntax tree for the given range.
This commit is contained in:
Ville Penttinen 2019-03-03 12:02:55 +02:00
parent 17aaece6b3
commit ac52d9a1f1
4 changed files with 148 additions and 5 deletions

View file

@ -38,7 +38,7 @@ mod marks;
use std::sync::Arc;
use ra_syntax::{SourceFile, TreeArc, TextRange, TextUnit, AstNode};
use ra_syntax::{SourceFile, TreeArc, TextRange, TextUnit, AstNode, algo};
use ra_text_edit::TextEdit;
use ra_db::{
SourceDatabase, CheckCanceled,
@ -245,8 +245,14 @@ 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) -> String {
self.db.parse(file_id).syntax().debug_dump()
pub fn syntax_tree(&self, file_id: FileId, text_range: Option<TextRange>) -> String {
if let Some(text_range) = text_range {
let file = self.db.parse(file_id);
let node = algo::find_covering_node(file.syntax(), text_range);
node.debug_dump()
} else {
self.db.parse(file_id).syntax().debug_dump()
}
}
/// Returns an edit to remove all newlines in the range, cleaning up minor

View file

@ -1,6 +1,6 @@
use insta::assert_debug_snapshot_matches;
use ra_ide_api::{
mock_analysis::{single_file, single_file_with_position, MockAnalysis},
mock_analysis::{single_file, single_file_with_position, single_file_with_range, MockAnalysis},
AnalysisChange, CrateGraph, Edition::Edition2018, Query, NavigationTarget,
ReferenceSearchResult,
};
@ -138,3 +138,137 @@ mod foo {
assert_eq!(s.name(), "FooInner");
assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
}
#[test]
fn test_syntax_tree_without_range() {
// Basic syntax
let (analysis, file_id) = single_file(r#"fn foo() {}"#);
let syn = analysis.syntax_tree(file_id, None);
assert_eq!(
syn.trim(),
r#"
SOURCE_FILE@[0; 11)
FN_DEF@[0; 11)
FN_KW@[0; 2)
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@[9; 11)
L_CURLY@[9; 10)
R_CURLY@[10; 11)
"#
.trim()
);
let (analysis, file_id) = single_file(
r#"
fn test() {
assert!("
fn foo() {
}
", "");
}"#
.trim(),
);
let syn = analysis.syntax_tree(file_id, None);
assert_eq!(
syn.trim(),
r#"
SOURCE_FILE@[0; 60)
FN_DEF@[0; 60)
FN_KW@[0; 2)
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@[10; 60)
L_CURLY@[10; 11)
WHITESPACE@[11; 16)
EXPR_STMT@[16; 58)
MACRO_CALL@[16; 57)
PATH@[16; 22)
PATH_SEGMENT@[16; 22)
NAME_REF@[16; 22)
IDENT@[16; 22) "assert"
EXCL@[22; 23)
TOKEN_TREE@[23; 57)
L_PAREN@[23; 24)
STRING@[24; 52)
COMMA@[52; 53)
WHITESPACE@[53; 54)
STRING@[54; 56)
R_PAREN@[56; 57)
SEMI@[57; 58)
WHITESPACE@[58; 59)
R_CURLY@[59; 60)
"#
.trim()
);
}
#[test]
fn test_syntax_tree_with_range() {
let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim());
let syn = analysis.syntax_tree(range.file_id, Some(range.range));
assert_eq!(
syn.trim(),
r#"
FN_DEF@[0; 11)
FN_KW@[0; 2)
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@[9; 11)
L_CURLY@[9; 10)
R_CURLY@[10; 11)
"#
.trim()
);
let (analysis, range) = single_file_with_range(
r#"fn test() {
<|>assert!("
fn foo() {
}
", "");<|>
}"#
.trim(),
);
let syn = analysis.syntax_tree(range.file_id, Some(range.range));
assert_eq!(
syn.trim(),
r#"
EXPR_STMT@[16; 58)
MACRO_CALL@[16; 57)
PATH@[16; 22)
PATH_SEGMENT@[16; 22)
NAME_REF@[16; 22)
IDENT@[16; 22) "assert"
EXCL@[22; 23)
TOKEN_TREE@[23; 57)
L_PAREN@[23; 24)
STRING@[24; 52)
COMMA@[52; 53)
WHITESPACE@[53; 54)
STRING@[54; 56)
R_PAREN@[56; 57)
SEMI@[57; 58)
"#
.trim()
);
}

View file

@ -32,7 +32,9 @@ pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result<String> {
pub fn handle_syntax_tree(world: ServerWorld, params: req::SyntaxTreeParams) -> Result<String> {
let id = params.text_document.try_conv_with(&world)?;
let res = world.analysis().syntax_tree(id);
let line_index = world.analysis().file_line_index(id);
let text_range = params.range.map(|p| p.conv_with(&line_index));
let res = world.analysis().syntax_tree(id, text_range);
Ok(res)
}

View file

@ -39,6 +39,7 @@ impl Request for SyntaxTree {
#[serde(rename_all = "camelCase")]
pub struct SyntaxTreeParams {
pub text_document: TextDocumentIdentifier,
pub range: Option<Range>,
}
pub enum ExtendSelection {}