diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a259eef633e..ac89a48d3b6 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -7,5 +7,5 @@ publish = false [dependencies] clap = "2.32.0" failure = "0.1.1" -libsyntax2 = { path = "../" } +libeditor = { path = "../libeditor" } tools = { path = "../tools" } diff --git a/cli/src/main.rs b/cli/src/main.rs index 0044841ed34..a3a317c697a 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,13 +1,16 @@ extern crate clap; #[macro_use] extern crate failure; -extern crate libsyntax2; +extern crate libeditor; extern crate tools; +use std::{ + fs, io::Read, path::Path, + time::Instant +}; use clap::{App, Arg, SubCommand}; -use std::time::Instant; -use std::{fs, io::Read, path::Path}; use tools::collect_tests; +use libeditor::File; type Result = ::std::result::Result; @@ -30,11 +33,21 @@ fn main() -> Result<()> { ), ) .subcommand(SubCommand::with_name("parse")) + .subcommand(SubCommand::with_name("symbols")) .get_matches(); match matches.subcommand() { ("parse", _) => { - let tree = parse()?; - println!("{}", tree); + let start = Instant::now(); + let file = file()?; + let elapsed = start.elapsed(); + println!("{}", file.syntax_tree()); + eprintln!("parsing: {:?}", elapsed); + } + ("symbols", _) => { + let file = file()?; + for s in file.symbols() { + println!("{:?}", s); + } } ("render-test", Some(matches)) => { let file = matches.value_of("file").unwrap(); @@ -49,13 +62,9 @@ fn main() -> Result<()> { Ok(()) } -fn parse() -> Result { +fn file() -> Result { let text = read_stdin()?; - let start = Instant::now(); - let file = libsyntax2::parse(&text); - eprintln!("elapsed {:?}", start.elapsed()); - let tree = libsyntax2::utils::dump_tree(&file); - Ok(tree) + Ok(File::new(&text)) } fn read_stdin() -> Result { @@ -74,7 +83,7 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> { None => bail!("No test found at line {} at {}", line, file.display()), Some((_start_line, test)) => test, }; - let file = libsyntax2::parse(&test.text); - let tree = libsyntax2::utils::dump_tree(&file); + let file = File::new(&test.text); + let tree = file.syntax_tree(); Ok((test.text, tree)) } diff --git a/libeditor/src/lib.rs b/libeditor/src/lib.rs index 119bdb2d6fb..091aed1256b 100644 --- a/libeditor/src/lib.rs +++ b/libeditor/src/lib.rs @@ -2,6 +2,7 @@ extern crate libsyntax2; extern crate text_unit; use libsyntax2::{ + SyntaxNodeRef, algo::walk, SyntaxKind::*, }; @@ -16,6 +17,13 @@ pub struct HighlightedRange { pub tag: &'static str, } +#[derive(Debug)] +pub struct Symbol { + // pub parent: ???, + pub name: String, + pub range: TextRange, +} + impl File { pub fn new(text: &str) -> File { File { @@ -41,7 +49,7 @@ impl File { }; res.push(HighlightedRange { range: node.range(), - tag + tag, }) } res @@ -50,4 +58,41 @@ impl File { pub fn syntax_tree(&self) -> String { ::libsyntax2::utils::dump_tree(&self.inner.syntax()) } + + pub fn symbols(&self) -> Vec { + let syntax = self.inner.syntax(); + let res: Vec = walk::preorder(syntax.as_ref()) + .filter_map(Declaration::cast) + .filter_map(|decl| { + let name = decl.name()?; + let range = decl.range(); + Some(Symbol { name, range }) + }) + .collect(); + res // NLL :-( + } +} + + +struct Declaration<'f>(SyntaxNodeRef<'f>); + +impl<'f> Declaration<'f> { + fn cast(node: SyntaxNodeRef<'f>) -> Option> { + match node.kind() { + | STRUCT_ITEM | ENUM_ITEM | FN_ITEM | TRAIT_ITEM + | CONST_ITEM | STATIC_ITEM | MOD_ITEM | NAMED_FIELD + | TYPE_ITEM => Some(Declaration(node)), + _ => None + } + } + + fn name(&self) -> Option { + let name = self.0.children() + .find(|child| child.kind() == NAME)?; + Some(name.text()) + } + + fn range(&self) -> TextRange { + self.0.range() + } }