summaryrefslogtreecommitdiff
path: root/support/texlab/src/syntax/latex/cst.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/syntax/latex/cst.rs')
-rw-r--r--support/texlab/src/syntax/latex/cst.rs639
1 files changed, 639 insertions, 0 deletions
diff --git a/support/texlab/src/syntax/latex/cst.rs b/support/texlab/src/syntax/latex/cst.rs
new file mode 100644
index 0000000000..0b839b706d
--- /dev/null
+++ b/support/texlab/src/syntax/latex/cst.rs
@@ -0,0 +1,639 @@
+use cstree::TextRange;
+
+use crate::syntax::CstNode;
+
+use super::{Language, SyntaxKind::*, SyntaxNode, SyntaxToken};
+
+macro_rules! cst_node {
+ ($name:ident, $($kind:pat),+) => {
+ #[derive(Clone)]
+ #[repr(transparent)]
+ pub struct $name<'a>(&'a SyntaxNode);
+
+ impl<'a> CstNode<'a> for $name<'a> {
+ type Lang = Language;
+
+ fn cast(node: &'a cstree::ResolvedNode<Self::Lang>) -> Option<Self>
+ where
+ Self: Sized,
+ {
+ match node.kind() {
+ $($kind => Some(Self(node)),)+
+ _ => None,
+ }
+ }
+
+ fn syntax(&self) -> &'a cstree::ResolvedNode<Self::Lang> {
+ &self.0
+ }
+
+ fn small_range(&self) -> TextRange {
+ let full_range = self.syntax().text_range();
+ let start = full_range.start();
+ let mut token = self.syntax().last_token();
+ while let Some(current) = token {
+ if !matches!(current.kind(), WHITESPACE | COMMENT) {
+ return TextRange::new(start, current.text_range().end());
+ }
+ token = current.prev_token();
+ }
+ TextRange::new(start, start)
+ }
+ }
+ };
+}
+
+cst_node!(Text, TEXT);
+
+pub trait HasCurly<'a>: CstNode<'a, Lang = Language> {
+ fn left_curly(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == L_CURLY)
+ }
+
+ fn right_curly(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == R_CURLY)
+ }
+
+ fn content_text(&self) -> Option<String> {
+ self.left_curly()?;
+ self.right_curly()?;
+ let mut text = String::new();
+ for child in self
+ .syntax()
+ .descendants_with_tokens()
+ .filter_map(|child| child.into_token())
+ .filter(|token| !matches!(token.kind(), COMMENT))
+ {
+ text.push_str(child.text());
+ }
+ let text = text.trim_end();
+ let text = text[1..text.len() - 1].trim().to_string();
+
+ Some(text)
+ }
+}
+
+cst_node!(CurlyGroup, CURLY_GROUP);
+
+impl<'a> HasCurly<'a> for CurlyGroup<'a> {}
+
+impl<'a> CurlyGroup<'a> {}
+
+pub trait HasBrack<'a>: CstNode<'a, Lang = Language> {
+ fn left_brack(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == L_BRACK)
+ }
+
+ fn right_brack(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == R_BRACK)
+ }
+
+ fn content_text(&self) -> Option<String> {
+ self.left_brack()?;
+ self.right_brack()?;
+ let mut text = String::new();
+ for child in self
+ .syntax()
+ .descendants_with_tokens()
+ .filter_map(|child| child.into_token())
+ .filter(|token| !matches!(token.kind(), COMMENT))
+ {
+ text.push_str(child.text());
+ }
+ let text = text.trim_end();
+ let text = text[1..text.len() - 1].trim().to_string();
+
+ Some(text)
+ }
+}
+
+cst_node!(BrackGroup, BRACK_GROUP);
+
+impl<'a> BrackGroup<'a> {}
+
+impl<'a> HasBrack<'a> for BrackGroup<'a> {}
+
+pub trait HasParen<'a>: CstNode<'a, Lang = Language> {
+ fn left_paren(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == L_PAREN)
+ }
+
+ fn right_paren(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == R_PAREN)
+ }
+}
+
+cst_node!(ParenGroup, PAREN_GROUP);
+
+impl<'a> HasParen<'a> for ParenGroup<'a> {}
+
+cst_node!(MixedGroup, MIXED_GROUP);
+
+impl<'a> MixedGroup<'a> {
+ pub fn left_delim(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| matches!(node.kind().into(), L_BRACK | L_PAREN))
+ }
+
+ pub fn right_delim(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| matches!(node.kind().into(), R_BRACK | R_PAREN))
+ }
+}
+
+cst_node!(CurlyGroupWord, CURLY_GROUP_WORD);
+
+impl<'a> HasCurly<'a> for CurlyGroupWord<'a> {}
+
+impl<'a> CurlyGroupWord<'a> {
+ pub fn word(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == WORD)
+ }
+}
+
+cst_node!(BrackGroupWord, BRACK_GROUP_WORD);
+
+impl<'a> HasBrack<'a> for BrackGroupWord<'a> {}
+
+impl<'a> BrackGroupWord<'a> {
+ pub fn word(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == WORD)
+ }
+}
+
+cst_node!(CurlyGroupWordList, CURLY_GROUP_WORD_LIST);
+
+impl<'a> HasCurly<'a> for CurlyGroupWordList<'a> {}
+
+impl<'a> CurlyGroupWordList<'a> {
+ pub fn words(&self) -> impl Iterator<Item = &'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .filter(|node| node.kind() == WORD)
+ }
+}
+
+cst_node!(CurlyGroupCommand, CURLY_GROUP_COMMAND);
+
+impl<'a> HasCurly<'a> for CurlyGroupCommand<'a> {}
+
+impl<'a> CurlyGroupCommand<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == GENERIC_COMMAND_NAME)
+ }
+}
+
+cst_node!(Key, KEY);
+
+impl<'a> Key<'a> {
+ pub fn words(&self) -> impl Iterator<Item = &'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .filter(|node| node.kind() == WORD)
+ }
+}
+
+cst_node!(Value, VALUE);
+
+cst_node!(KeyValuePair, KEY_VALUE_PAIR);
+
+impl<'a> KeyValuePair<'a> {
+ pub fn key(&self) -> Option<Key<'a>> {
+ self.syntax().children().find_map(Key::cast)
+ }
+
+ pub fn value(&self) -> Option<Value<'a>> {
+ self.syntax().children().find_map(Value::cast)
+ }
+}
+
+cst_node!(KeyValueBody, KEY_VALUE_BODY);
+
+impl<'a> KeyValueBody<'a> {
+ pub fn pairs(&self) -> impl Iterator<Item = KeyValuePair<'a>> {
+ self.syntax().children().filter_map(KeyValuePair::cast)
+ }
+}
+
+pub trait HasKeyValueBody<'a>: CstNode<'a, Lang = Language> {
+ fn body(&self) -> Option<KeyValueBody<'a>> {
+ self.syntax().children().find_map(KeyValueBody::cast)
+ }
+}
+
+cst_node!(CurlyGroupKeyValue, CURLY_GROUP_KEY_VALUE);
+
+impl<'a> HasCurly<'a> for CurlyGroupKeyValue<'a> {}
+
+impl<'a> HasKeyValueBody<'a> for CurlyGroupKeyValue<'a> {}
+
+cst_node!(BrackGroupKeyValue, BRACK_GROUP_KEY_VALUE);
+
+impl<'a> HasBrack<'a> for BrackGroupKeyValue<'a> {}
+
+impl<'a> HasKeyValueBody<'a> for BrackGroupKeyValue<'a> {}
+
+cst_node!(Formula, FORMULA);
+
+cst_node!(GenericCommand, GENERIC_COMMAND);
+
+impl<'a> GenericCommand<'a> {
+ pub fn name(&self) -> Option<&'a SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(|node| node.into_token())
+ .find(|node| node.kind() == GENERIC_COMMAND_NAME)
+ }
+}
+
+cst_node!(Equation, EQUATION);
+
+cst_node!(Begin, BEGIN);
+
+impl<'a> Begin<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+
+ pub fn options(&self) -> Option<BrackGroup<'a>> {
+ self.syntax().children().find_map(BrackGroup::cast)
+ }
+}
+
+cst_node!(End, END);
+
+impl<'a> End<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+}
+
+cst_node!(Environment, ENVIRONMENT);
+
+impl<'a> Environment<'a> {
+ pub fn begin(&self) -> Option<Begin<'a>> {
+ self.syntax().children().find_map(Begin::cast)
+ }
+
+ pub fn end(&self) -> Option<End<'a>> {
+ self.syntax().children().find_map(End::cast)
+ }
+}
+
+cst_node!(
+ Section,
+ PART,
+ CHAPTER,
+ SECTION,
+ SUBSECTION,
+ SUBSUBSECTION,
+ PARAGRAPH,
+ SUBPARAGRAPH
+);
+
+impl<'a> Section<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroup<'a>> {
+ self.syntax().children().find_map(CurlyGroup::cast)
+ }
+}
+
+cst_node!(EnumItem, ENUM_ITEM);
+
+impl<'a> EnumItem<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn label(&self) -> Option<BrackGroup<'a>> {
+ self.syntax().children().find_map(BrackGroup::cast)
+ }
+}
+
+cst_node!(Caption, CAPTION);
+
+impl<'a> Caption<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn short(&self) -> Option<BrackGroup<'a>> {
+ self.syntax().children().find_map(BrackGroup::cast)
+ }
+
+ pub fn long(&self) -> Option<CurlyGroup<'a>> {
+ self.syntax().children().find_map(CurlyGroup::cast)
+ }
+}
+
+cst_node!(Citation, CITATION);
+
+impl<'a> Citation<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn prenote(&self) -> Option<BrackGroup<'a>> {
+ self.syntax().children().find_map(BrackGroup::cast)
+ }
+
+ pub fn postnote(&self) -> Option<BrackGroup<'a>> {
+ self.syntax().children().filter_map(BrackGroup::cast).nth(1)
+ }
+
+ pub fn key_list(&self) -> Option<CurlyGroupWordList<'a>> {
+ self.syntax().children().find_map(CurlyGroupWordList::cast)
+ }
+}
+
+cst_node!(
+ Include,
+ PACKAGE_INCLUDE,
+ CLASS_INCLUDE,
+ LATEX_INCLUDE,
+ BIBLATEX_INCLUDE,
+ BIBTEX_INCLUDE,
+ GRAPHICS_INCLUDE,
+ SVG_INCLUDE,
+ INKSCAPE_INCLUDE,
+ VERBATIM_INCLUDE
+);
+
+impl<'a> Include<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn path_list(&self) -> Option<CurlyGroupWordList<'a>> {
+ self.syntax().children().find_map(CurlyGroupWordList::cast)
+ }
+}
+
+cst_node!(Import, IMPORT);
+
+impl<'a> Import<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn directory(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+
+ pub fn file(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax()
+ .children()
+ .filter_map(CurlyGroupWord::cast)
+ .nth(1)
+ }
+}
+
+cst_node!(LabelDefinition, LABEL_DEFINITION);
+
+impl<'a> LabelDefinition<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+}
+
+cst_node!(LabelReference, LABEL_REFERENCE);
+
+impl<'a> LabelReference<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name_list(&self) -> Option<CurlyGroupWordList<'a>> {
+ self.syntax().children().find_map(CurlyGroupWordList::cast)
+ }
+}
+
+cst_node!(LabelReferenceRange, LABEL_REFERENCE_RANGE);
+
+impl<'a> LabelReferenceRange<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn from(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+
+ pub fn to(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax()
+ .children()
+ .filter_map(CurlyGroupWord::cast)
+ .nth(1)
+ }
+}
+
+cst_node!(LabelNumber, LABEL_NUMBER);
+
+impl<'a> LabelNumber<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+
+ pub fn text(&self) -> Option<CurlyGroup<'a>> {
+ self.syntax().children().find_map(CurlyGroup::cast)
+ }
+}
+
+cst_node!(TheoremDefinition, THEOREM_DEFINITION);
+
+impl<'a> TheoremDefinition<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+
+ pub fn description(&self) -> Option<CurlyGroup<'a>> {
+ self.syntax().children().find_map(CurlyGroup::cast)
+ }
+}
+
+cst_node!(CommandDefinition, COMMAND_DEFINITION, MATH_OPERATOR);
+
+impl<'a> CommandDefinition<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupCommand<'a>> {
+ self.syntax().children().find_map(CurlyGroupCommand::cast)
+ }
+
+ pub fn implementation(&self) -> Option<CurlyGroup<'a>> {
+ self.syntax().children().find_map(CurlyGroup::cast)
+ }
+}
+
+cst_node!(AcronymReference, ACRONYM_REFERENCE);
+
+impl<'a> AcronymReference<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+}
+
+cst_node!(AcronymDefinition, ACRONYM_DEFINITION);
+
+impl<'a> AcronymDefinition<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+}
+
+cst_node!(AcronymDeclaration, ACRONYM_DECLARATION);
+
+impl<'a> AcronymDeclaration<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+}
+
+cst_node!(ColorDefinition, COLOR_DEFINITION);
+
+impl<'a> ColorDefinition<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+
+ pub fn model(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax()
+ .children()
+ .filter_map(CurlyGroupWord::cast)
+ .nth(1)
+ }
+
+ pub fn spec(&self) -> Option<CurlyGroup<'a>> {
+ self.syntax().children().find_map(CurlyGroup::cast)
+ }
+}
+
+cst_node!(ColorSetDefinition, COLOR_SET_DEFINITION);
+
+impl<'a> ColorSetDefinition<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn model_list(&self) -> Option<CurlyGroupWordList<'a>> {
+ self.syntax().children().find_map(CurlyGroupWordList::cast)
+ }
+}
+
+cst_node!(ColorReference, COLOR_REFERENCE);
+
+impl<'a> ColorReference<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+}
+
+cst_node!(GlossaryEntryReference, GLOSSARY_ENTRY_REFERENCE);
+
+impl<'a> GlossaryEntryReference<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+}
+
+cst_node!(GlossaryEntryDefinition, GLOSSARY_ENTRY_DEFINITION);
+
+impl<'a> GlossaryEntryDefinition<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name(&self) -> Option<CurlyGroupWord<'a>> {
+ self.syntax().children().find_map(CurlyGroupWord::cast)
+ }
+}
+
+cst_node!(TikzLibraryImport, TIKZ_LIBRARY_IMPORT);
+
+impl<'a> TikzLibraryImport<'a> {
+ pub fn command(&self) -> Option<&'a SyntaxToken> {
+ self.syntax().first_token()
+ }
+
+ pub fn name_list(&self) -> Option<CurlyGroupWordList<'a>> {
+ self.syntax().children().find_map(CurlyGroupWordList::cast)
+ }
+}