mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
structure moved to ra_ide_api
ra_ide_api_light removed completely
This commit is contained in:
parent
afe96b75ea
commit
36cb58f76d
10 changed files with 7 additions and 79 deletions
|
@ -6,9 +6,6 @@
|
|||
//! database, and the `ra_hir` crate, where majority of the analysis happens.
|
||||
//! However, IDE specific bits of the analysis (most notably completion) happen
|
||||
//! in this crate.
|
||||
//!
|
||||
//! The sibling `ra_ide_api_light` handles those bits of IDE functionality
|
||||
//! which are restricted to a single file and need only syntax.
|
||||
|
||||
// For proving that RootDatabase is RefUnwindSafe.
|
||||
#![recursion_limit = "128"]
|
||||
|
@ -33,10 +30,11 @@ mod impls;
|
|||
mod assists;
|
||||
mod diagnostics;
|
||||
mod syntax_tree;
|
||||
mod line_index;
|
||||
mod folding_ranges;
|
||||
mod line_index;
|
||||
mod line_index_utils;
|
||||
mod join_lines;
|
||||
mod structure;
|
||||
mod typing;
|
||||
mod matching_brace;
|
||||
|
||||
|
@ -72,9 +70,10 @@ pub use crate::{
|
|||
line_index_utils::translate_offset_with_edit,
|
||||
folding_ranges::{Fold, FoldKind},
|
||||
syntax_highlighting::HighlightedRange,
|
||||
structure::{StructureNode, file_structure},
|
||||
diagnostics::Severity,
|
||||
};
|
||||
pub use ra_ide_api_light::StructureNode;
|
||||
|
||||
pub use ra_db::{
|
||||
Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId,
|
||||
Edition
|
||||
|
@ -388,7 +387,7 @@ impl Analysis {
|
|||
/// file outline.
|
||||
pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
|
||||
let file = self.db.parse(file_id);
|
||||
ra_ide_api_light::file_structure(&file)
|
||||
structure::file_structure(&file)
|
||||
}
|
||||
|
||||
/// Returns the set of folding ranges.
|
||||
|
|
182
crates/ra_ide_api/src/snapshots/tests__file_structure.snap
Normal file
182
crates/ra_ide_api/src/snapshots/tests__file_structure.snap
Normal file
|
@ -0,0 +1,182 @@
|
|||
---
|
||||
created: "2019-02-05T22:03:50.763530100Z"
|
||||
creator: insta@0.6.1
|
||||
source: crates/ra_ide_api/src/structure.rs
|
||||
expression: structure
|
||||
---
|
||||
[
|
||||
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: NAMED_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) -> T"
|
||||
),
|
||||
deprecated: false
|
||||
},
|
||||
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 >"
|
||||
),
|
||||
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_BLOCK,
|
||||
detail: None,
|
||||
deprecated: false
|
||||
},
|
||||
StructureNode {
|
||||
parent: None,
|
||||
label: "impl fmt::Debug for E",
|
||||
navigation_range: [265; 266),
|
||||
node_range: [245; 269),
|
||||
kind: IMPL_BLOCK,
|
||||
detail: None,
|
||||
deprecated: false
|
||||
},
|
||||
StructureNode {
|
||||
parent: None,
|
||||
label: "obsolete",
|
||||
navigation_range: [288; 296),
|
||||
node_range: [271; 301),
|
||||
kind: FN_DEF,
|
||||
detail: Some(
|
||||
"fn()"
|
||||
),
|
||||
deprecated: true
|
||||
},
|
||||
StructureNode {
|
||||
parent: None,
|
||||
label: "very_obsolete",
|
||||
navigation_range: [341; 354),
|
||||
node_range: [303; 359),
|
||||
kind: FN_DEF,
|
||||
detail: Some(
|
||||
"fn()"
|
||||
),
|
||||
deprecated: true
|
||||
}
|
||||
]
|
190
crates/ra_ide_api/src/structure.rs
Normal file
190
crates/ra_ide_api/src/structure.rs
Normal file
|
@ -0,0 +1,190 @@
|
|||
use crate::TextRange;
|
||||
|
||||
use ra_syntax::{
|
||||
algo::visit::{visitor, Visitor},
|
||||
ast::{self, AttrsOwner, NameOwner, TypeParamsOwner, TypeAscriptionOwner},
|
||||
AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StructureNode {
|
||||
pub parent: Option<usize>,
|
||||
pub label: String,
|
||||
pub navigation_range: TextRange,
|
||||
pub node_range: TextRange,
|
||||
pub kind: SyntaxKind,
|
||||
pub detail: Option<String>,
|
||||
pub deprecated: bool,
|
||||
}
|
||||
|
||||
pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
|
||||
let mut res = Vec::new();
|
||||
let mut stack = Vec::new();
|
||||
|
||||
for event in file.syntax().preorder() {
|
||||
match event {
|
||||
WalkEvent::Enter(node) => {
|
||||
if let Some(mut symbol) = structure_node(node) {
|
||||
symbol.parent = stack.last().map(|&n| n);
|
||||
stack.push(res.len());
|
||||
res.push(symbol);
|
||||
}
|
||||
}
|
||||
WalkEvent::Leave(node) => {
|
||||
if structure_node(node).is_some() {
|
||||
stack.pop().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
|
||||
fn decl<N: NameOwner + AttrsOwner>(node: &N) -> Option<StructureNode> {
|
||||
decl_with_detail(node, None)
|
||||
}
|
||||
|
||||
fn decl_with_ascription<N: NameOwner + AttrsOwner + TypeAscriptionOwner>(
|
||||
node: &N,
|
||||
) -> Option<StructureNode> {
|
||||
decl_with_type_ref(node, node.ascribed_type())
|
||||
}
|
||||
|
||||
fn decl_with_type_ref<N: NameOwner + AttrsOwner>(
|
||||
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 + AttrsOwner>(
|
||||
node: &N,
|
||||
detail: Option<String>,
|
||||
) -> Option<StructureNode> {
|
||||
let name = node.name()?;
|
||||
|
||||
Some(StructureNode {
|
||||
parent: None,
|
||||
label: name.text().to_string(),
|
||||
navigation_range: name.syntax().range(),
|
||||
node_range: node.syntax().range(),
|
||||
kind: node.syntax().kind(),
|
||||
detail,
|
||||
deprecated: node.attrs().filter_map(|x| x.as_named()).any(|x| x == "deprecated"),
|
||||
})
|
||||
}
|
||||
|
||||
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(|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::EnumDef>)
|
||||
.visit(decl::<ast::EnumVariant>)
|
||||
.visit(decl::<ast::TraitDef>)
|
||||
.visit(decl::<ast::Module>)
|
||||
.visit(|td: &ast::TypeAliasDef| decl_with_type_ref(td, td.type_ref()))
|
||||
.visit(decl_with_ascription::<ast::NamedFieldDef>)
|
||||
.visit(decl_with_ascription::<ast::ConstDef>)
|
||||
.visit(decl_with_ascription::<ast::StaticDef>)
|
||||
.visit(|im: &ast::ImplBlock| {
|
||||
let target_type = im.target_type()?;
|
||||
let target_trait = im.target_trait();
|
||||
let label = match target_trait {
|
||||
None => format!("impl {}", target_type.syntax().text()),
|
||||
Some(t) => {
|
||||
format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),)
|
||||
}
|
||||
};
|
||||
|
||||
let node = StructureNode {
|
||||
parent: None,
|
||||
label,
|
||||
navigation_range: target_type.syntax().range(),
|
||||
node_range: im.syntax().range(),
|
||||
kind: im.syntax().kind(),
|
||||
detail: None,
|
||||
deprecated: false,
|
||||
};
|
||||
Some(node)
|
||||
})
|
||||
.accept(node)?
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use insta::assert_debug_snapshot_matches;
|
||||
|
||||
#[test]
|
||||
fn test_file_structure() {
|
||||
let file = SourceFile::parse(
|
||||
r#"
|
||||
struct Foo {
|
||||
x: i32
|
||||
}
|
||||
|
||||
mod m {
|
||||
fn bar1() {}
|
||||
fn bar2<T>(t: T) -> T {}
|
||||
fn bar3<A,
|
||||
B>(a: A,
|
||||
b: B) -> Vec<
|
||||
u32
|
||||
> {}
|
||||
}
|
||||
|
||||
enum E { X, Y(i32) }
|
||||
type T = ();
|
||||
static S: i32 = 92;
|
||||
const C: i32 = 92;
|
||||
|
||||
impl E {}
|
||||
|
||||
impl fmt::Debug for E {}
|
||||
|
||||
#[deprecated]
|
||||
fn obsolete() {}
|
||||
|
||||
#[deprecated(note = "for awhile")]
|
||||
fn very_obsolete() {}
|
||||
"#,
|
||||
);
|
||||
let structure = file_structure(&file);
|
||||
assert_debug_snapshot_matches!("file_structure", structure);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue