630: Fill in DocumentSymbol::detail r=matklad a=hban

Closes: #516

I just pulled type text from the syntax node and "formatted" is bit. VS Code can't really handle multi-line symbol detail (it's will crop it when rendering), so that formatting will just collapse all white-space to singe space. It isn't pretty, but maybe there's a better way.

Issue also mentions "need to be done for `NavigationTarget` to `SymbolInformation`", but `SymbolInformation` doesn't have detail field on it?

Co-authored-by: Hrvoje Ban <hban@users.noreply.github.com>
This commit is contained in:
bors[bot] 2019-01-25 07:13:16 +00:00
commit 675943712c
5 changed files with 179 additions and 59 deletions

View file

@ -1,5 +1,5 @@
---
created: "2019-01-22T14:45:01.959724300+00:00"
created: "2019-01-24T18:04:00.090162+00:00"
creator: insta@0.4.0
expression: structure
source: "crates\\ra_ide_api_light\\src\\structure.rs"
@ -10,7 +10,8 @@ source: "crates\\ra_ide_api_light\\src\\structure.rs"
label: "Foo",
navigation_range: [8; 11),
node_range: [1; 26),
kind: STRUCT_DEF
kind: STRUCT_DEF,
detail: None
},
StructureNode {
parent: Some(
@ -19,64 +20,107 @@ source: "crates\\ra_ide_api_light\\src\\structure.rs"
label: "x",
navigation_range: [18; 19),
node_range: [18; 24),
kind: NAMED_FIELD_DEF
kind: NAMED_FIELD_DEF,
detail: Some(
"i32"
)
},
StructureNode {
parent: None,
label: "m",
navigation_range: [32; 33),
node_range: [28; 53),
kind: MODULE
node_range: [28; 158),
kind: MODULE,
detail: None
},
StructureNode {
parent: Some(
2
),
label: "bar",
navigation_range: [43; 46),
node_range: [40; 51),
kind: FN_DEF
label: "bar1",
navigation_range: [43; 47),
node_range: [40; 52),
kind: FN_DEF,
detail: Some(
"fn()"
)
},
StructureNode {
parent: Some(
2
),
label: "bar2",
navigation_range: [60; 64),
node_range: [57; 81),
kind: FN_DEF,
detail: Some(
"fn<T>(t: T) -> T"
)
},
StructureNode {
parent: Some(
2
),
label: "bar3",
navigation_range: [89; 93),
node_range: [86; 156),
kind: FN_DEF,
detail: Some(
"fn<A, B>(a: A, b: B) -> Vec< u32 >"
)
},
StructureNode {
parent: None,
label: "E",
navigation_range: [60; 61),
node_range: [55; 75),
kind: ENUM_DEF
navigation_range: [165; 166),
node_range: [160; 180),
kind: ENUM_DEF,
detail: None
},
StructureNode {
parent: None,
label: "T",
navigation_range: [81; 82),
node_range: [76; 88),
kind: TYPE_DEF
navigation_range: [186; 187),
node_range: [181; 193),
kind: TYPE_DEF,
detail: Some(
"()"
)
},
StructureNode {
parent: None,
label: "S",
navigation_range: [96; 97),
node_range: [89; 108),
kind: STATIC_DEF
navigation_range: [201; 202),
node_range: [194; 213),
kind: STATIC_DEF,
detail: Some(
"i32"
)
},
StructureNode {
parent: None,
label: "C",
navigation_range: [115; 116),
node_range: [109; 127),
kind: CONST_DEF
navigation_range: [220; 221),
node_range: [214; 232),
kind: CONST_DEF,
detail: Some(
"i32"
)
},
StructureNode {
parent: None,
label: "impl E",
navigation_range: [134; 135),
node_range: [129; 138),
kind: IMPL_BLOCK
navigation_range: [239; 240),
node_range: [234; 243),
kind: IMPL_BLOCK,
detail: None
},
StructureNode {
parent: None,
label: "impl fmt::Debug for E",
navigation_range: [160; 161),
node_range: [140; 164),
kind: IMPL_BLOCK
navigation_range: [265; 266),
node_range: [245; 269),
kind: IMPL_BLOCK,
detail: None
}
]

View file

@ -2,7 +2,7 @@ use crate::TextRange;
use ra_syntax::{
algo::visit::{visitor, Visitor},
ast::{self, NameOwner},
ast::{self, NameOwner, TypeParamsOwner},
AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent,
};
@ -13,6 +13,7 @@ pub struct StructureNode {
pub navigation_range: TextRange,
pub node_range: TextRange,
pub kind: SyntaxKind,
pub detail: Option<String>,
}
pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
@ -40,6 +41,22 @@ pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
fn decl<N: NameOwner>(node: &N) -> Option<StructureNode> {
decl_with_detail(node, None)
}
fn decl_with_type_ref<N: NameOwner>(
node: &N,
type_ref: Option<&ast::TypeRef>,
) -> Option<StructureNode> {
let detail = type_ref.map(|type_ref| {
let mut detail = String::new();
collapse_ws(type_ref.syntax(), &mut detail);
detail
});
decl_with_detail(node, detail)
}
fn decl_with_detail<N: NameOwner>(node: &N, detail: Option<String>) -> Option<StructureNode> {
let name = node.name()?;
Some(StructureNode {
parent: None,
@ -47,19 +64,50 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
navigation_range: name.syntax().range(),
node_range: node.syntax().range(),
kind: node.syntax().kind(),
detail,
})
}
fn collapse_ws(node: &SyntaxNode, output: &mut String) {
let mut can_insert_ws = false;
for line in node.text().chunks().flat_map(|chunk| chunk.lines()) {
let line = line.trim();
if line.is_empty() {
if can_insert_ws {
output.push_str(" ");
can_insert_ws = false;
}
} else {
output.push_str(line);
can_insert_ws = true;
}
}
}
visitor()
.visit(decl::<ast::FnDef>)
.visit(|fn_def: &ast::FnDef| {
let mut detail = String::from("fn");
if let Some(type_param_list) = fn_def.type_param_list() {
collapse_ws(type_param_list.syntax(), &mut detail);
}
if let Some(param_list) = fn_def.param_list() {
collapse_ws(param_list.syntax(), &mut detail);
}
if let Some(ret_type) = fn_def.ret_type() {
detail.push_str(" ");
collapse_ws(ret_type.syntax(), &mut detail);
}
decl_with_detail(fn_def, Some(detail))
})
.visit(decl::<ast::StructDef>)
.visit(decl::<ast::NamedFieldDef>)
.visit(|nfd: &ast::NamedFieldDef| decl_with_type_ref(nfd, nfd.type_ref()))
.visit(decl::<ast::EnumDef>)
.visit(decl::<ast::TraitDef>)
.visit(decl::<ast::Module>)
.visit(decl::<ast::TypeDef>)
.visit(decl::<ast::ConstDef>)
.visit(decl::<ast::StaticDef>)
.visit(|td: &ast::TypeDef| decl_with_type_ref(td, td.type_ref()))
.visit(|cd: &ast::ConstDef| decl_with_type_ref(cd, cd.type_ref()))
.visit(|sd: &ast::StaticDef| decl_with_type_ref(sd, sd.type_ref()))
.visit(|im: &ast::ImplBlock| {
let target_type = im.target_type()?;
let target_trait = im.target_trait();
@ -78,6 +126,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
navigation_range: target_type.syntax().range(),
node_range: im.syntax().range(),
kind: im.syntax().kind(),
detail: None,
};
Some(node)
})
@ -98,7 +147,13 @@ struct Foo {
}
mod m {
fn bar() {}
fn bar1() {}
fn bar2<T>(t: T) -> T {}
fn bar3<A,
B>(a: A,
b: B) -> Vec<
u32
> {}
}
enum E { X, Y(i32) }

View file

@ -136,7 +136,7 @@ pub fn handle_document_symbol(
for symbol in world.analysis().file_structure(file_id) {
let doc_symbol = DocumentSymbol {
name: symbol.label,
detail: Some("".to_string()),
detail: symbol.detail,
kind: symbol.kind.conv(),
deprecated: None,
range: symbol.node_range.conv_with(&line_index),

View file

@ -598,7 +598,11 @@ impl ast::NameOwner for ConstDef {}
impl ast::TypeParamsOwner for ConstDef {}
impl ast::AttrsOwner for ConstDef {}
impl ast::DocCommentsOwner for ConstDef {}
impl ConstDef {}
impl ConstDef {
pub fn type_ref(&self) -> Option<&TypeRef> {
super::child_opt(self)
}
}
// ContinueExpr
#[derive(Debug, PartialEq, Eq, Hash)]
@ -3407,7 +3411,11 @@ impl ast::NameOwner for StaticDef {}
impl ast::TypeParamsOwner for StaticDef {}
impl ast::AttrsOwner for StaticDef {}
impl ast::DocCommentsOwner for StaticDef {}
impl StaticDef {}
impl StaticDef {
pub fn type_ref(&self) -> Option<&TypeRef> {
super::child_opt(self)
}
}
// Stmt
#[derive(Debug, PartialEq, Eq, Hash)]
@ -3948,7 +3956,11 @@ impl ast::NameOwner for TypeDef {}
impl ast::TypeParamsOwner for TypeDef {}
impl ast::AttrsOwner for TypeDef {}
impl ast::DocCommentsOwner for TypeDef {}
impl TypeDef {}
impl TypeDef {
pub fn type_ref(&self) -> Option<&TypeRef> {
super::child_opt(self)
}
}
// TypeParam
#[derive(Debug, PartialEq, Eq, Hash)]

View file

@ -289,27 +289,36 @@ Grammar(
collections: [["impl_items", "ImplItem"]],
traits: [ "FnDefOwner", "ModuleItemOwner" ],
),
"ConstDef": ( traits: [
"VisibilityOwner",
"NameOwner",
"TypeParamsOwner",
"AttrsOwner",
"DocCommentsOwner"
] ),
"StaticDef": ( traits: [
"VisibilityOwner",
"NameOwner",
"TypeParamsOwner",
"AttrsOwner",
"DocCommentsOwner"
] ),
"TypeDef": ( traits: [
"VisibilityOwner",
"NameOwner",
"TypeParamsOwner",
"AttrsOwner",
"DocCommentsOwner"
] ),
"ConstDef": (
traits: [
"VisibilityOwner",
"NameOwner",
"TypeParamsOwner",
"AttrsOwner",
"DocCommentsOwner"
],
options: ["TypeRef"]
),
"StaticDef": (
traits: [
"VisibilityOwner",
"NameOwner",
"TypeParamsOwner",
"AttrsOwner",
"DocCommentsOwner"
],
options: ["TypeRef"]
),
"TypeDef": (
traits: [
"VisibilityOwner",
"NameOwner",
"TypeParamsOwner",
"AttrsOwner",
"DocCommentsOwner"
],
options: ["TypeRef"]
),
"ImplBlock": (options: ["ItemList"]),
"ParenType": (options: ["TypeRef"]),