summaryrefslogtreecommitdiff
path: root/support/texlab/src/syntax/bibtex/ast.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/syntax/bibtex/ast.rs')
-rw-r--r--support/texlab/src/syntax/bibtex/ast.rs686
1 files changed, 270 insertions, 416 deletions
diff --git a/support/texlab/src/syntax/bibtex/ast.rs b/support/texlab/src/syntax/bibtex/ast.rs
index 09f2ee5b88..77ee98e26d 100644
--- a/support/texlab/src/syntax/bibtex/ast.rs
+++ b/support/texlab/src/syntax/bibtex/ast.rs
@@ -1,9 +1,14 @@
-use crate::range::RangeExt;
-use crate::syntax::text::{Span, SyntaxNode};
-use lsp_types::Range;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum BibtexTokenKind {
+use crate::{
+ protocol::{Position, Range, RangeExt},
+ syntax::{Span, SyntaxNode},
+};
+use itertools::Itertools;
+use petgraph::graph::{Graph, NodeIndex};
+use serde::{Deserialize, Serialize};
+use std::fmt;
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
+pub enum TokenKind {
PreambleKind,
StringKind,
EntryKind,
@@ -19,559 +24,408 @@ pub enum BibtexTokenKind {
EndParen,
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexToken {
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct Token {
pub span: Span,
- pub kind: BibtexTokenKind,
+ pub kind: TokenKind,
}
-impl BibtexToken {
- pub fn new(span: Span, kind: BibtexTokenKind) -> Self {
- BibtexToken { span, kind }
+impl SyntaxNode for Token {
+ fn range(&self) -> Range {
+ self.span.range()
}
+}
- pub fn text(&self) -> &str {
- &self.span.text
+impl Token {
+ pub fn new(span: Span, kind: TokenKind) -> Self {
+ Self { span, kind }
}
-}
-impl SyntaxNode for BibtexToken {
- fn range(&self) -> Range {
- self.span.range
+ pub fn text(&self) -> &str {
+ &self.span.text
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexRoot {
- pub children: Vec<BibtexDeclaration>,
+#[derive(PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
+pub struct Root {
+ pub range: Range,
}
-impl BibtexRoot {
- pub fn new(children: Vec<BibtexDeclaration>) -> Self {
- BibtexRoot { children }
+impl SyntaxNode for Root {
+ fn range(&self) -> Range {
+ self.range
}
}
-impl SyntaxNode for BibtexRoot {
- fn range(&self) -> Range {
- if self.children.is_empty() {
- Range::new_simple(0, 0, 0, 0)
- } else {
- Range::new(
- self.children[0].start(),
- self.children[self.children.len() - 1].end(),
- )
- }
+impl fmt::Debug for Root {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Root")
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub enum BibtexDeclaration {
- Comment(Box<BibtexComment>),
- Preamble(Box<BibtexPreamble>),
- String(Box<BibtexString>),
- Entry(Box<BibtexEntry>),
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct Comment {
+ pub token: Token,
}
-impl BibtexDeclaration {
- pub fn accept<'a, T: BibtexVisitor<'a>>(&'a self, visitor: &mut T) {
- match self {
- BibtexDeclaration::Comment(comment) => visitor.visit_comment(comment),
- BibtexDeclaration::Preamble(preamble) => visitor.visit_preamble(preamble),
- BibtexDeclaration::String(string) => visitor.visit_string(string),
- BibtexDeclaration::Entry(entry) => visitor.visit_entry(entry),
- }
+impl SyntaxNode for Comment {
+ fn range(&self) -> Range {
+ self.token.range()
}
}
-impl SyntaxNode for BibtexDeclaration {
- fn range(&self) -> Range {
- match self {
- BibtexDeclaration::Comment(comment) => comment.range,
- BibtexDeclaration::Preamble(preamble) => preamble.range,
- BibtexDeclaration::String(string) => string.range,
- BibtexDeclaration::Entry(entry) => entry.range,
- }
+impl fmt::Debug for Comment {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Comment({})", self.token.text())
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexComment {
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct Preamble {
pub range: Range,
- pub token: BibtexToken,
+ pub ty: Token,
+ pub left: Option<Token>,
+ pub right: Option<Token>,
}
-impl BibtexComment {
- pub fn new(token: BibtexToken) -> Self {
- BibtexComment {
- range: token.range(),
- token,
- }
+impl SyntaxNode for Preamble {
+ fn range(&self) -> Range {
+ self.range
}
}
-impl SyntaxNode for BibtexComment {
- fn range(&self) -> Range {
- self.range
+impl fmt::Debug for Preamble {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Preamble")
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexPreamble {
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct String {
pub range: Range,
- pub ty: BibtexToken,
- pub left: Option<BibtexToken>,
- pub content: Option<BibtexContent>,
- pub right: Option<BibtexToken>,
-}
-
-impl BibtexPreamble {
- pub fn new(
- ty: BibtexToken,
- left: Option<BibtexToken>,
- content: Option<BibtexContent>,
- right: Option<BibtexToken>,
- ) -> Self {
- let end = if let Some(ref right) = right {
- right.end()
- } else if let Some(ref content) = content {
- content.end()
- } else if let Some(ref left) = left {
- left.end()
- } else {
- ty.end()
- };
- BibtexPreamble {
- range: Range::new(ty.start(), end),
- ty,
- left,
- content,
- right,
- }
- }
+ pub ty: Token,
+ pub left: Option<Token>,
+ pub name: Option<Token>,
+ pub assign: Option<Token>,
+ pub right: Option<Token>,
}
-impl SyntaxNode for BibtexPreamble {
+impl SyntaxNode for String {
fn range(&self) -> Range {
self.range
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexString {
- pub range: Range,
- pub ty: BibtexToken,
- pub left: Option<BibtexToken>,
- pub name: Option<BibtexToken>,
- pub assign: Option<BibtexToken>,
- pub value: Option<BibtexContent>,
- pub right: Option<BibtexToken>,
-}
-
-impl BibtexString {
- pub fn new(
- ty: BibtexToken,
- left: Option<BibtexToken>,
- name: Option<BibtexToken>,
- assign: Option<BibtexToken>,
- value: Option<BibtexContent>,
- right: Option<BibtexToken>,
- ) -> Self {
- let end = if let Some(ref right) = right {
- right.end()
- } else if let Some(ref value) = value {
- value.end()
- } else if let Some(ref assign) = assign {
- assign.end()
- } else if let Some(ref name) = name {
- name.end()
- } else if let Some(ref left) = left {
- left.end()
- } else {
- ty.end()
- };
-
- BibtexString {
- range: Range::new(ty.start(), end),
- ty,
- left,
- name,
- assign,
- value,
- right,
- }
+impl fmt::Debug for String {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "String({:?})", self.name.as_ref().map(Token::text))
}
}
-impl SyntaxNode for BibtexString {
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct Entry {
+ pub range: Range,
+ pub ty: Token,
+ pub left: Option<Token>,
+ pub key: Option<Token>,
+ pub comma: Option<Token>,
+ pub right: Option<Token>,
+}
+
+impl SyntaxNode for Entry {
fn range(&self) -> Range {
self.range
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexEntry {
- pub range: Range,
- pub ty: BibtexToken,
- pub left: Option<BibtexToken>,
- pub key: Option<BibtexToken>,
- pub comma: Option<BibtexToken>,
- pub fields: Vec<BibtexField>,
- pub right: Option<BibtexToken>,
-}
-
-impl BibtexEntry {
- pub fn new(
- ty: BibtexToken,
- left: Option<BibtexToken>,
- key: Option<BibtexToken>,
- comma: Option<BibtexToken>,
- fields: Vec<BibtexField>,
- right: Option<BibtexToken>,
- ) -> Self {
- let end = if let Some(ref right) = right {
- right.end()
- } else if !fields.is_empty() {
- fields[fields.len() - 1].range.end
- } else if let Some(ref comma) = comma {
- comma.end()
- } else if let Some(ref key) = key {
- key.end()
- } else if let Some(ref left) = left {
- left.end()
- } else {
- ty.end()
- };
-
- BibtexEntry {
- range: Range::new(ty.start(), end),
- ty,
- left,
- key,
- comma,
- fields,
- right,
- }
+impl fmt::Debug for Entry {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Entry({:?})", self.key.as_ref().map(Token::text))
}
+}
+impl Entry {
pub fn is_comment(&self) -> bool {
self.ty.text().to_lowercase() == "@comment"
}
+}
- pub fn find_field(&self, name: &str) -> Option<&BibtexField> {
- self.fields
- .iter()
- .find(|field| field.name.text().to_lowercase() == name)
- }
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct Field {
+ pub range: Range,
+ pub name: Token,
+ pub assign: Option<Token>,
+ pub comma: Option<Token>,
}
-impl SyntaxNode for BibtexEntry {
+impl SyntaxNode for Field {
fn range(&self) -> Range {
self.range
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexField {
- pub range: Range,
- pub name: BibtexToken,
- pub assign: Option<BibtexToken>,
- pub content: Option<BibtexContent>,
- pub comma: Option<BibtexToken>,
-}
-
-impl BibtexField {
- pub fn new(
- name: BibtexToken,
- assign: Option<BibtexToken>,
- content: Option<BibtexContent>,
- comma: Option<BibtexToken>,
- ) -> Self {
- let end = if let Some(ref comma) = comma {
- comma.end()
- } else if let Some(ref content) = content {
- content.end()
- } else if let Some(ref assign) = assign {
- assign.end()
- } else {
- name.end()
- };
-
- BibtexField {
- range: Range::new(name.start(), end),
- name,
- assign,
- content,
- comma,
- }
- }
-}
-
-impl SyntaxNode for BibtexField {
- fn range(&self) -> Range {
- self.range
+impl fmt::Debug for Field {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Field({})", self.name.text())
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub enum BibtexContent {
- Word(BibtexWord),
- Command(BibtexCommand),
- QuotedContent(BibtexQuotedContent),
- BracedContent(BibtexBracedContent),
- Concat(Box<BibtexConcat>),
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct Word {
+ pub token: Token,
}
-impl BibtexContent {
- pub fn accept<'a, T: BibtexVisitor<'a>>(&'a self, visitor: &mut T) {
- match self {
- BibtexContent::Word(word) => visitor.visit_word(word),
- BibtexContent::Command(command) => visitor.visit_command(command),
- BibtexContent::QuotedContent(content) => visitor.visit_quoted_content(content),
- BibtexContent::BracedContent(content) => visitor.visit_braced_content(content),
- BibtexContent::Concat(concat) => visitor.visit_concat(concat),
- }
+impl SyntaxNode for Word {
+ fn range(&self) -> Range {
+ self.token.range()
}
}
-impl SyntaxNode for BibtexContent {
- fn range(&self) -> Range {
- match self {
- BibtexContent::Word(word) => word.range(),
- BibtexContent::Command(command) => command.range(),
- BibtexContent::QuotedContent(content) => content.range(),
- BibtexContent::BracedContent(content) => content.range(),
- BibtexContent::Concat(concat) => concat.range(),
- }
+impl fmt::Debug for Word {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Word({})", self.token.text())
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexWord {
- pub range: Range,
- pub token: BibtexToken,
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct Command {
+ pub token: Token,
}
-impl BibtexWord {
- pub fn new(token: BibtexToken) -> Self {
- BibtexWord {
- range: token.range(),
- token,
- }
+impl SyntaxNode for Command {
+ fn range(&self) -> Range {
+ self.token.range()
}
}
-impl SyntaxNode for BibtexWord {
- fn range(&self) -> Range {
- self.range
+impl fmt::Debug for Command {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Command({})", self.token.text())
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexCommand {
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct QuotedContent {
pub range: Range,
- pub token: BibtexToken,
+ pub left: Token,
+ pub right: Option<Token>,
}
-impl BibtexCommand {
- pub fn new(token: BibtexToken) -> Self {
- BibtexCommand {
- range: token.range(),
- token,
- }
+impl SyntaxNode for QuotedContent {
+ fn range(&self) -> Range {
+ self.range
}
}
-impl SyntaxNode for BibtexCommand {
- fn range(&self) -> Range {
- self.range
+impl fmt::Debug for QuotedContent {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "QuotedContent")
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexQuotedContent {
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct BracedContent {
pub range: Range,
- pub left: BibtexToken,
- pub children: Vec<BibtexContent>,
- pub right: Option<BibtexToken>,
-}
-
-impl BibtexQuotedContent {
- pub fn new(
- left: BibtexToken,
- children: Vec<BibtexContent>,
- right: Option<BibtexToken>,
- ) -> Self {
- let end = if let Some(ref right) = right {
- right.end()
- } else if !children.is_empty() {
- children[children.len() - 1].end()
- } else {
- left.end()
- };
-
- BibtexQuotedContent {
- range: Range::new(left.start(), end),
- left,
- children,
- right,
- }
- }
+ pub left: Token,
+ pub right: Option<Token>,
}
-impl SyntaxNode for BibtexQuotedContent {
+impl SyntaxNode for BracedContent {
fn range(&self) -> Range {
self.range
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexBracedContent {
- pub range: Range,
- pub left: BibtexToken,
- pub children: Vec<BibtexContent>,
- pub right: Option<BibtexToken>,
-}
-
-impl BibtexBracedContent {
- pub fn new(
- left: BibtexToken,
- children: Vec<BibtexContent>,
- right: Option<BibtexToken>,
- ) -> Self {
- let end = if let Some(ref right) = right {
- right.end()
- } else if !children.is_empty() {
- children[children.len() - 1].end()
- } else {
- left.end()
- };
-
- BibtexBracedContent {
- range: Range::new(left.start(), end),
- left,
- children,
- right,
- }
+impl fmt::Debug for BracedContent {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "BracedContent")
}
}
-impl SyntaxNode for BibtexBracedContent {
+#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct Concat {
+ pub range: Range,
+ pub operator: Token,
+}
+
+impl SyntaxNode for Concat {
fn range(&self) -> Range {
self.range
}
}
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct BibtexConcat {
- pub range: Range,
- pub left: BibtexContent,
- pub operator: BibtexToken,
- pub right: Option<BibtexContent>,
+impl fmt::Debug for Concat {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Concat")
+ }
}
-impl BibtexConcat {
- pub fn new(left: BibtexContent, operator: BibtexToken, right: Option<BibtexContent>) -> Self {
- let end = if let Some(ref right) = right {
- right.end()
- } else {
- operator.end()
- };
-
- BibtexConcat {
- range: Range::new(left.start(), end),
- left,
- operator,
- right,
- }
- }
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub enum Node {
+ Root(Root),
+ Comment(Comment),
+ Preamble(Box<Preamble>),
+ String(Box<String>),
+ Entry(Box<Entry>),
+ Field(Box<Field>),
+ Word(Word),
+ Command(Command),
+ QuotedContent(QuotedContent),
+ BracedContent(BracedContent),
+ Concat(Concat),
}
-impl SyntaxNode for BibtexConcat {
+impl SyntaxNode for Node {
fn range(&self) -> Range {
- self.range
+ match self {
+ Self::Root(root) => root.range(),
+ Self::Comment(comment) => comment.range(),
+ Self::Preamble(preamble) => preamble.range(),
+ Self::String(string) => string.range(),
+ Self::Entry(entry) => entry.range(),
+ Self::Field(field) => field.range(),
+ Self::Word(word) => word.range(),
+ Self::Command(cmd) => cmd.range(),
+ Self::QuotedContent(content) => content.range(),
+ Self::BracedContent(content) => content.range(),
+ Self::Concat(concat) => concat.range(),
+ }
}
}
-pub trait BibtexVisitor<'a> {
- fn visit_root(&mut self, root: &'a BibtexRoot);
-
- fn visit_comment(&mut self, comment: &'a BibtexComment);
-
- fn visit_preamble(&mut self, preamble: &'a BibtexPreamble);
-
- fn visit_string(&mut self, string: &'a BibtexString);
-
- fn visit_entry(&mut self, entry: &'a BibtexEntry);
-
- fn visit_field(&mut self, field: &'a BibtexField);
-
- fn visit_word(&mut self, word: &'a BibtexWord);
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Tree {
+ pub graph: Graph<Node, ()>,
+ pub root: NodeIndex,
+}
- fn visit_command(&mut self, command: &'a BibtexCommand);
+impl Tree {
+ pub fn children(&self, parent: NodeIndex) -> impl Iterator<Item = NodeIndex> {
+ self.graph
+ .neighbors(parent)
+ .sorted_by_key(|child| self.graph[*child].start())
+ }
- fn visit_quoted_content(&mut self, content: &'a BibtexQuotedContent);
+ pub fn has_children(&self, parent: NodeIndex) -> bool {
+ self.children(parent).next().is_some()
+ }
- fn visit_braced_content(&mut self, content: &'a BibtexBracedContent);
+ pub fn walk<'a, V: Visitor<'a>>(&'a self, visitor: &mut V, parent: NodeIndex) {
+ for child in self.children(parent) {
+ visitor.visit(self, child);
+ }
+ }
- fn visit_concat(&mut self, concat: &'a BibtexConcat);
-}
+ pub fn find(&self, pos: Position) -> Vec<NodeIndex> {
+ let mut finder = Finder::new(pos);
+ finder.visit(self, self.root);
+ finder.results
+ }
-pub struct BibtexWalker;
+ pub fn as_preamble(&self, node: NodeIndex) -> Option<&Preamble> {
+ if let Node::Preamble(preamble) = &self.graph[node] {
+ Some(preamble)
+ } else {
+ None
+ }
+ }
-impl BibtexWalker {
- pub fn walk_root<'a, T: BibtexVisitor<'a>>(visitor: &mut T, root: &'a BibtexRoot) {
- for declaration in &root.children {
- declaration.accept(visitor);
+ pub fn as_string(&self, node: NodeIndex) -> Option<&String> {
+ if let Node::String(string) = &self.graph[node] {
+ Some(string)
+ } else {
+ None
}
}
- pub fn walk_preamble<'a, T: BibtexVisitor<'a>>(visitor: &mut T, preamble: &'a BibtexPreamble) {
- if let Some(ref content) = preamble.content {
- content.accept(visitor);
+ pub fn as_entry(&self, node: NodeIndex) -> Option<&Entry> {
+ if let Node::Entry(entry) = &self.graph[node] {
+ Some(entry)
+ } else {
+ None
}
}
- pub fn walk_string<'a, T: BibtexVisitor<'a>>(visitor: &mut T, string: &'a BibtexString) {
- if let Some(ref value) = string.value {
- value.accept(visitor);
+ pub fn as_field(&self, node: NodeIndex) -> Option<&Field> {
+ if let Node::Field(field) = &self.graph[node] {
+ Some(field)
+ } else {
+ None
}
}
- pub fn walk_entry<'a, T: BibtexVisitor<'a>>(visitor: &mut T, entry: &'a BibtexEntry) {
- for field in &entry.fields {
- visitor.visit_field(field);
+ pub fn as_command(&self, node: NodeIndex) -> Option<&Command> {
+ if let Node::Command(cmd) = &self.graph[node] {
+ Some(cmd)
+ } else {
+ None
}
}
- pub fn walk_field<'a, T: BibtexVisitor<'a>>(visitor: &mut T, field: &'a BibtexField) {
- if let Some(ref content) = field.content {
- content.accept(visitor);
+ pub fn as_word(&self, node: NodeIndex) -> Option<&Word> {
+ if let Node::Word(word) = &self.graph[node] {
+ Some(word)
+ } else {
+ None
}
}
- pub fn walk_quoted_content<'a, T: BibtexVisitor<'a>>(
- visitor: &mut T,
- content: &'a BibtexQuotedContent,
- ) {
- for child in &content.children {
- child.accept(visitor);
+ pub fn entry_by_key(&self, key: &str) -> Option<NodeIndex> {
+ for node in self.children(self.root) {
+ if let Some(entry) = self.as_entry(node) {
+ if entry.key.as_ref().map(Token::text) == Some(key) {
+ return Some(node);
+ }
+ }
+ }
+ None
+ }
+
+ pub fn field_by_name(&self, parent: NodeIndex, name: &str) -> Option<NodeIndex> {
+ let name = name.to_lowercase();
+ self.as_entry(parent)?;
+ for node in self.children(parent) {
+ if let Some(field) = self.as_field(node) {
+ if field.name.text() == name {
+ return Some(node);
+ }
+ }
}
+ None
+ }
+
+ pub fn crossref(&self, entry: NodeIndex) -> Option<NodeIndex> {
+ let field = self.field_by_name(entry, "crossref")?;
+ let content = self.children(field).next()?;
+ let key = self.as_word(self.children(content).next()?)?;
+ self.entry_by_key(key.token.text())
}
+}
+
+pub trait Visitor<'a> {
+ fn visit(&mut self, tree: &'a Tree, node: NodeIndex);
+}
- pub fn walk_braced_content<'a, T: BibtexVisitor<'a>>(
- visitor: &mut T,
- content: &'a BibtexBracedContent,
- ) {
- for child in &content.children {
- child.accept(visitor);
+#[derive(Debug)]
+struct Finder {
+ position: Position,
+ results: Vec<NodeIndex>,
+}
+
+impl Finder {
+ fn new(position: Position) -> Self {
+ Self {
+ position,
+ results: Vec::new(),
}
}
+}
- pub fn walk_concat<'a, T: BibtexVisitor<'a>>(visitor: &mut T, concat: &'a BibtexConcat) {
- concat.left.accept(visitor);
- if let Some(ref right) = concat.right {
- right.accept(visitor);
+impl<'a> Visitor<'a> for Finder {
+ fn visit(&mut self, tree: &'a Tree, node: NodeIndex) {
+ if tree.graph[node].range().contains(self.position) {
+ self.results.push(node);
+ tree.walk(self, node);
}
}
}