From 36bd28633baf6015b767e9e70d2d53185271db50 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 9 Aug 2018 16:03:21 +0300 Subject: Extract runnables --- libeditor/src/lib.rs | 34 ++++++++++++++++++++++ libeditor/tests/test.rs | 22 +++++++++++++++ src/ast.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 1 deletion(-) diff --git a/libeditor/src/lib.rs b/libeditor/src/lib.rs index ef31efe35..387859d4a 100644 --- a/libeditor/src/lib.rs +++ b/libeditor/src/lib.rs @@ -26,6 +26,18 @@ pub struct Symbol { pub range: TextRange, } +#[derive(Debug)] +pub struct Runnable { + pub range: TextRange, + pub kind: RunnableKind, +} + +#[derive(Debug)] +pub enum RunnableKind { + Test { name: String }, + Bin, +} + impl File { pub fn new(text: &str) -> File { File { @@ -78,6 +90,28 @@ impl File { let syntax = self.inner.syntax(); extend_selection::extend_selection(syntax.as_ref(), range) } + + pub fn runnables(&self) -> Vec { + self.inner + .functions() + .filter_map(|f| { + let name = f.name()?.text(); + let kind = if name == "main" { + RunnableKind::Bin + } else if f.has_atom_attr("test") { + RunnableKind::Test { + name: name.to_string() + } + } else { + return None; + }; + Some(Runnable { + range: f.syntax().range(), + kind, + }) + }) + .collect() + } } diff --git a/libeditor/tests/test.rs b/libeditor/tests/test.rs index e1c8aee4b..ab8254d16 100644 --- a/libeditor/tests/test.rs +++ b/libeditor/tests/test.rs @@ -37,11 +37,33 @@ fn main() {} ); } +#[test] +fn test_runnables() { + let file = file(r#" +fn main() {} + +#[test] +fn test_foo() {} + +#[test] +#[ignore] +fn test_foo() {} +"#); + let runnables = file.runnables(); + dbg_eq( + &runnables, + r#"[Runnable { range: [1; 13), kind: Bin }, + Runnable { range: [15; 39), kind: Test { name: "test_foo" } }, + Runnable { range: [41; 75), kind: Test { name: "test_foo" } }]"#, + ) +} + fn file(text: &str) -> File { File::new(text) } fn dbg_eq(actual: &impl fmt::Debug, expected: &str) { + let actual = format!("{:?}", actual); let expected = expected.lines().map(|l| l.trim()).join(" "); assert_eq!(actual, expected); } diff --git a/src/ast.rs b/src/ast.rs index caf5fb7ef..a595b9324 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,11 +1,25 @@ use std::sync::Arc; -use {SyntaxNode, SyntaxRoot, TreeRoot}; +use { + SyntaxNode, SyntaxRoot, TreeRoot, + SyntaxKind::*, +}; #[derive(Debug)] pub struct File> { syntax: SyntaxNode, } +#[derive(Debug)] +pub struct Function> { + syntax: SyntaxNode, +} + +#[derive(Debug)] +pub struct Name> { + syntax: SyntaxNode, +} + + impl File> { pub fn parse(text: &str) -> Self { File { @@ -14,6 +28,65 @@ impl File> { } } +impl File { + pub fn functions<'a>(&'a self) -> impl Iterator> + 'a { + self.syntax + .children() + .filter(|node| node.kind() == FN_ITEM) + .map(|node| Function { syntax: node }) + } +} + +impl Function { + pub fn syntax(&self) -> SyntaxNode { + self.syntax.clone() + } + + pub fn name(&self) -> Option> { + self.syntax + .children() + .filter(|node| node.kind() == NAME) + .map(|node| Name { syntax: node }) + .next() + } + + pub fn has_atom_attr(&self, atom: &str) -> bool { + self.syntax + .children() + .filter(|node| node.kind() == ATTR) + .any(|attr| { + let mut metas = attr.children().filter(|node| node.kind() == META_ITEM); + let meta = match metas.next() { + None => return false, + Some(meta) => { + if metas.next().is_some() { + return false; + } + meta + } + }; + let mut children = meta.children(); + match children.next() { + None => false, + Some(child) => { + if children.next().is_some() { + return false; + } + child.kind() == IDENT && child.text() == atom + } + } + }) + } +} + +impl Name { + pub fn text(&self) -> String { + self.syntax.text() + } +} + + + impl File { pub fn syntax(&self) -> SyntaxNode { self.syntax.clone() -- cgit v1.2.3