diff options
author | Norbert Preining <norbert@preining.info> | 2021-05-23 03:00:39 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2021-05-23 03:00:39 +0000 |
commit | f1261b349e875b842745b63258c3e338cb1fe3bf (patch) | |
tree | b5d402b3e80818cde2c079a42249f3dcb9732247 /support/texlab/src/syntax/latex | |
parent | 58aa1ac09b1d9e4769d0a0661cf12e2b2db41b14 (diff) |
CTAN sync 202105230300
Diffstat (limited to 'support/texlab/src/syntax/latex')
120 files changed, 5418 insertions, 2290 deletions
diff --git a/support/texlab/src/syntax/latex/analysis.rs b/support/texlab/src/syntax/latex/analysis.rs index af8b756f31..063d8e95f3 100644 --- a/support/texlab/src/syntax/latex/analysis.rs +++ b/support/texlab/src/syntax/latex/analysis.rs @@ -1,913 +1,36 @@ -use crate::{ - protocol::{Options, Position, Range, RangeExt, Uri}, - syntax::{generic_ast::AstNodeIndex, lang_data::*, latex::ast::*, text::SyntaxNode}, - tex::Resolver, +mod command; +mod distro_file; +mod environment; +mod explicit_link; +mod implicit_link; +mod label_name; +mod label_number; +mod theorem; +mod types; + +use crate::syntax::latex; + +pub use self::types::*; +use self::{ + command::analyze_command, + environment::analyze_begin, + explicit_link::{analyze_import, analyze_include}, + implicit_link::analyze_implicit_links, + label_name::analyze_label_name, + label_number::analyze_label_number, + theorem::analyze_theorem_definition, }; -use itertools::{iproduct, Itertools}; -use serde::{Deserialize, Serialize}; -use std::{borrow::Cow, ops::Deref, path::Path}; -#[derive(Debug, Clone)] -pub struct SymbolTableParams<'a> { - pub tree: Tree, - pub uri: &'a Uri, - pub resolver: &'a Resolver, - pub options: &'a Options, - pub current_dir: &'a Path, -} - -#[derive(Debug, Clone)] -pub struct SymbolTable { - pub(crate) tree: Tree, - pub commands: Vec<AstNodeIndex>, - pub environments: Vec<Environment>, - pub is_standalone: bool, - pub includes: Vec<Include>, - pub imports: Vec<Import>, - pub components: Vec<String>, - pub citations: Vec<Citation>, - pub command_definitions: Vec<CommandDefinition>, - pub glossary_entries: Vec<GlossaryEntry>, - pub equations: Vec<Equation>, - pub inlines: Vec<Inline>, - pub math_operators: Vec<MathOperator>, - pub theorem_definitions: Vec<TheoremDefinition>, - pub sections: Vec<Section>, - pub labels: Vec<Label>, - pub label_numberings: Vec<LabelNumbering>, - pub captions: Vec<Caption>, - pub items: Vec<Item>, -} - -impl SymbolTable { - pub fn analyze(params: SymbolTableParams) -> Self { - let SymbolTableParams { - tree, - uri, - resolver, - options, - current_dir, - } = params; - - let commands: Vec<_> = tree.commands().collect(); - let ctx = SymbolContext { - tree: &tree, - commands: &commands, - uri, - resolver, - options, - current_dir, - }; - - let mut environments = None; - let mut includes = None; - let mut imports = None; - let mut citations = None; - let mut command_definitions = None; - let mut glossary_entries = None; - let mut equations = None; - let mut inlines = None; - let mut math_operators = None; - let mut theorem_definitions = None; - let mut sections = None; - let mut labels = None; - let mut label_numberings = None; - let mut captions = None; - let mut items = None; - - rayon::scope(|s| { - s.spawn(|_| environments = Some(Environment::parse(ctx))); - s.spawn(|_| includes = Some(Include::parse(ctx))); - s.spawn(|_| imports = Some(Import::parse(ctx))); - s.spawn(|_| citations = Some(Citation::parse(ctx))); - s.spawn(|_| command_definitions = Some(CommandDefinition::parse(ctx))); - s.spawn(|_| glossary_entries = Some(GlossaryEntry::parse(ctx))); - s.spawn(|_| equations = Some(Equation::parse(ctx))); - s.spawn(|_| inlines = Some(Inline::parse(ctx))); - s.spawn(|_| math_operators = Some(MathOperator::parse(ctx))); - s.spawn(|_| theorem_definitions = Some(TheoremDefinition::parse(ctx))); - s.spawn(|_| sections = Some(Section::parse(ctx))); - s.spawn(|_| labels = Some(Label::parse(ctx))); - s.spawn(|_| label_numberings = Some(LabelNumbering::parse(ctx))); - s.spawn(|_| captions = Some(Caption::parse(ctx))); - s.spawn(|_| items = Some(Item::parse(ctx))); - }); - - let is_standalone = environments - .as_ref() - .unwrap() - .iter() - .any(|env| env.is_root(&tree)); - - let components = includes - .as_ref() - .unwrap() - .iter() - .flat_map(|include| include.components(&tree)) - .collect(); - - Self { - tree, - commands, - environments: environments.unwrap(), - is_standalone, - includes: includes.unwrap(), - imports: imports.unwrap(), - components, - citations: citations.unwrap(), - command_definitions: command_definitions.unwrap(), - glossary_entries: glossary_entries.unwrap(), - equations: equations.unwrap(), - inlines: inlines.unwrap(), - math_operators: math_operators.unwrap(), - theorem_definitions: theorem_definitions.unwrap(), - sections: sections.unwrap(), - labels: labels.unwrap(), - label_numberings: label_numberings.unwrap(), - captions: captions.unwrap(), - items: items.unwrap(), - } - } - - pub fn is_direct_child(&self, env: Environment, pos: Position) -> bool { - env.range(&self.tree).contains(pos) - && !self - .environments - .iter() - .filter(|e| e.left.parent != env.left.parent) - .filter(|e| env.range(&self.tree).contains(e.range(&self.tree).start)) - .any(|e| e.range(&self.tree).contains(pos)) - } - - pub fn is_enum_item(&self, enumeration: Environment, item: Item) -> bool { - let item_range = self.tree[item.parent].range(); - enumeration.range(&self.tree).contains(item_range.start) - && !self - .environments - .iter() - .filter(|env| env.left.parent != enumeration.left.parent) - .filter(|env| env.left.is_enum(&self.tree)) - .filter(|env| { - enumeration - .range(&self.tree) - .contains(env.range(&self.tree).start) - }) - .any(|env| env.range(&self.tree).contains(item_range.start)) - } - - pub fn find_label_by_range(&self, range: Range) -> Option<&Label> { - self.labels - .iter() - .filter(|label| label.kind == LatexLabelKind::Definition) - .filter(|label| label.names(&self).len() == 1) - .find(|label| range.contains(self[label.parent].range().start)) - } - - pub fn find_label_by_environment(&self, env: Environment) -> Option<&Label> { - self.labels - .iter() - .filter(|label| label.kind == LatexLabelKind::Definition) - .filter(|label| label.names(&self.tree).len() == 1) - .find(|label| self.is_direct_child(env, self.tree[label.parent].start())) - } -} - -impl Deref for SymbolTable { - type Target = Tree; - - fn deref(&self) -> &Self::Target { - &self.tree - } -} - -#[derive(Debug, Clone, Copy)] -pub struct SymbolContext<'a> { - tree: &'a Tree, - commands: &'a [AstNodeIndex], - uri: &'a Uri, - resolver: &'a Resolver, - options: &'a Options, - current_dir: &'a Path, -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct EnvironmentDelimiter { - pub parent: AstNodeIndex, -} - -impl EnvironmentDelimiter { - pub fn name(self, tree: &Tree) -> Option<&Token> { - tree.extract_word(self.parent, GroupKind::Group, 0) - } - - pub fn is_math(self, tree: &Tree) -> bool { - self.is_special(tree, LANGUAGE_DATA.math_environments.iter()) - } - - pub fn is_enum(self, tree: &Tree) -> bool { - self.is_special(tree, LANGUAGE_DATA.enum_environments.iter()) - } - - fn is_special<'a, I: Iterator<Item = &'a String>>(self, tree: &Tree, mut values: I) -> bool { - match self.name(tree) { - Some(name) => values.any(|env| env == name.text()), - None => false, - } - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct Environment { - pub left: EnvironmentDelimiter, - pub right: EnvironmentDelimiter, -} - -impl Environment { - pub fn is_root(self, tree: &Tree) -> bool { - self.left - .name(tree) - .iter() - .chain(self.right.name(tree).iter()) - .any(|name| name.text() == "document") - } - - pub fn range(self, tree: &Tree) -> Range { - let start = tree[self.left.parent].start(); - let end = tree[self.right.parent].end(); - Range::new(start, end) - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - let mut stack = Vec::new(); - let mut envs = Vec::new(); - for parent in ctx.commands { - if let Some((delim, delim_cmd)) = Self::parse_delimiter(ctx.tree, *parent) { - if delim_cmd.name.text() == "\\begin" { - stack.push(delim); - } else if let Some(left) = stack.pop() { - envs.push(Self { left, right: delim }); - } - } - } - envs - } - - fn parse_delimiter( - tree: &Tree, - parent: AstNodeIndex, - ) -> Option<(EnvironmentDelimiter, &Command)> { - let cmd = tree.as_command(parent)?; - if cmd.name.text() != "\\begin" && cmd.name.text() != "\\end" { - return None; - } - - let group = tree.extract_group(parent, GroupKind::Group, 0)?; - if tree.extract_word(parent, GroupKind::Group, 0).is_some() - || tree.children(group).next().is_none() - || tree.as_group(group)?.right.is_none() - { - Some((EnvironmentDelimiter { parent }, cmd)) - } else { - None - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Include { - pub parent: AstNodeIndex, - pub arg_index: usize, - pub kind: LatexIncludeKind, - pub all_targets: Vec<Vec<Uri>>, - pub include_extension: bool, -} - -impl Include { - pub fn paths<'a>(&self, tree: &'a Tree) -> Vec<&'a Token> { - tree.extract_comma_separated_words(self.parent, GroupKind::Group, self.arg_index) - .unwrap() - } - - pub fn components<'a>(&self, tree: &'a Tree) -> impl Iterator<Item = String> + 'a { - let kind = self.kind; - self.paths(tree) - .into_iter() - .filter_map(move |path| match kind { - LatexIncludeKind::Package => Some(format!("{}.sty", path.text())), - LatexIncludeKind::Class => Some(format!("{}.cls", path.text())), - LatexIncludeKind::Latex - | LatexIncludeKind::Bibliography - | LatexIncludeKind::Image - | LatexIncludeKind::Svg - | LatexIncludeKind::Pdf - | LatexIncludeKind::Everything => None, - }) - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - iproduct!(ctx.commands, LANGUAGE_DATA.include_commands.iter()) - .filter_map(|(parent, desc)| Self::parse_single(ctx, *parent, desc)) - .collect() - } - - fn parse_single( - ctx: SymbolContext, - parent: AstNodeIndex, - desc: &LatexIncludeCommand, - ) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != desc.name { - return None; - } - - let mut all_targets = Vec::new(); - let paths = ctx - .tree - .extract_comma_separated_words(parent, GroupKind::Group, desc.index)?; - for path in paths { - let mut targets = Vec::new(); - let base_url = base_url(ctx)?; - targets.push(base_url.join(path.text()).ok()?.into()); - - if let Some(extensions) = desc.kind.extensions() { - for extension in extensions { - let path = format!("{}.{}", path.text(), extension); - targets.push(base_url.join(&path).ok()?.into()); - } - } - - if let Some(target) = Self::resolve_distro_file(ctx, desc, path.text()) { - targets.push(target); - } - all_targets.push(targets); - } - - let include = Self { - parent, - arg_index: desc.index, - kind: desc.kind, - all_targets, - include_extension: desc.include_extension, - }; - Some(include) - } - - fn resolve_distro_file( - ctx: SymbolContext, - desc: &LatexIncludeCommand, - name: &str, - ) -> Option<Uri> { - let mut path = ctx.resolver.files_by_name.get(name); - if let Some(extensions) = desc.kind.extensions() { - for extension in extensions { - path = path.or_else(|| { - let full_name = format!("{}.{}", name, extension); - ctx.resolver.files_by_name.get(&full_name) - }); - } - } - path.and_then(|p| Uri::from_file_path(p).ok()) - } -} - -fn base_url(ctx: SymbolContext) -> Option<Uri> { - if let Some(root_directory) = ctx - .options - .latex - .as_ref() - .and_then(|opts| opts.root_directory.as_ref()) - { - let file_name = ctx.uri.path_segments()?.last()?; - let path = ctx.current_dir.join(root_directory).join(file_name); - Uri::from_file_path(path).ok() - } else { - Some(ctx.uri.clone()) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Import { - pub parent: AstNodeIndex, - pub targets: Vec<Uri>, -} - -impl Import { - pub fn dir<'a>(&self, tree: &'a Tree) -> &'a Token { - tree.extract_word(self.parent, GroupKind::Group, 0).unwrap() - } - - pub fn file<'a>(&self, tree: &'a Tree) -> &'a Token { - tree.extract_word(self.parent, GroupKind::Group, 1).unwrap() - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - ctx.commands - .iter() - .filter_map(|parent| Self::parse_single(ctx, *parent)) - .collect() - } - - fn parse_single(ctx: SymbolContext, parent: AstNodeIndex) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != "\\import" && cmd.name.text() != "\\subimport" { - return None; - } - - let dir = ctx.tree.extract_word(parent, GroupKind::Group, 0)?; - let file = ctx.tree.extract_word(parent, GroupKind::Group, 1)?; - - let mut targets = Vec::new(); - let base_url = base_url(ctx)?.join(dir.text()).ok()?; - targets.push(base_url.join(file.text()).ok()?.into()); - targets.push(base_url.join(&format!("{}.tex", file.text())).ok()?.into()); - Some(Self { parent, targets }) - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct Citation { - parent: AstNodeIndex, - arg_index: usize, -} - -impl Citation { - pub fn keys(self, tree: &Tree) -> Vec<&Token> { - tree.extract_comma_separated_words(self.parent, GroupKind::Group, self.arg_index) - .unwrap() - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - iproduct!(ctx.commands, LANGUAGE_DATA.citation_commands.iter()) - .filter_map(|(parent, desc)| Self::parse_single(ctx, *parent, desc)) - .collect() - } - - fn parse_single( - ctx: SymbolContext, - parent: AstNodeIndex, - desc: &LatexCitationCommand, - ) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != desc.name { - return None; - } - - ctx.tree - .extract_comma_separated_words(parent, GroupKind::Group, desc.index)?; - - Some(Self { - parent, - arg_index: desc.index, - }) - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct CommandDefinition { - pub parent: AstNodeIndex, - pub definition: AstNodeIndex, - pub definition_index: usize, - pub implementation: AstNodeIndex, - pub implementation_index: usize, - pub arg_count_index: usize, -} - -impl CommandDefinition { - pub fn definition_name(self, tree: &Tree) -> &str { - tree.as_command(self.definition).unwrap().name.text() - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - let def = LANGUAGE_DATA.command_definition_commands.iter(); - iproduct!(ctx.commands, def) - .filter_map(|(parent, desc)| Self::parse_single(ctx, *parent, desc)) - .collect() - } - - fn parse_single( - ctx: SymbolContext, - parent: AstNodeIndex, - desc: &LatexCommandDefinitionCommand, - ) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != desc.name { - return None; - } - - let group_kind = GroupKind::Group; - let implementation = - ctx.tree - .extract_group(parent, group_kind, desc.implementation_index)?; - - let def_group = ctx - .tree - .extract_group(parent, group_kind, desc.definition_index)?; - - let mut def_children = ctx.tree.children(def_group); - let definition = def_children.next()?; - ctx.tree.as_command(definition)?; - Some(Self { - parent, - definition, - definition_index: desc.definition_index, - implementation, - implementation_index: desc.implementation_index, - arg_count_index: desc.arg_count_index, - }) - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct GlossaryEntry { - pub parent: AstNodeIndex, - pub label_index: usize, - pub kind: LatexGlossaryEntryKind, -} - -impl GlossaryEntry { - pub fn label(self, tree: &Tree) -> &Token { - tree.extract_word(self.parent, GroupKind::Group, self.label_index) - .unwrap() - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - let entry = LANGUAGE_DATA.glossary_entry_definition_commands.iter(); - iproduct!(ctx.commands, entry) - .filter_map(|(parent, desc)| Self::parse_single(ctx, *parent, desc)) - .collect() - } - - fn parse_single( - ctx: SymbolContext, - parent: AstNodeIndex, - desc: &LatexGlossaryEntryDefinitionCommand, - ) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != desc.name { - return None; - } - - ctx.tree - .extract_word(parent, GroupKind::Group, desc.label_index)?; - - Some(Self { - parent, - label_index: desc.label_index, - kind: desc.kind, - }) - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct Equation { - pub left: AstNodeIndex, - pub right: AstNodeIndex, -} - -impl Equation { - pub fn range(self, tree: &Tree) -> Range { - let start = tree[self.left].start(); - let end = tree[self.right].end(); - Range::new(start, end) - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - let mut equations = Vec::new(); - let mut left = None; - for node in ctx.commands { - let cmd = ctx.tree.as_command(*node).unwrap(); - let name = cmd.name.text(); - if name == "\\[" || name == "\\(" { - left = Some(node); - } else if name == "\\]" || name == "\\)" { - if let Some(begin) = left { - equations.push(Self { - left: *begin, - right: *node, - }); - left = None; - } - } - } - equations - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct Inline { - pub left: AstNodeIndex, - pub right: AstNodeIndex, -} - -impl Inline { - pub fn range(self, tree: &Tree) -> Range { - let start = tree[self.left].start(); - let end = tree[self.right].end(); - Range::new(start, end) - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - let mut inlines = Vec::new(); - let mut left = None; - for node in ctx - .tree - .nodes() - .into_iter() - .filter(|node| ctx.tree.as_math(*node).is_some()) - .sorted_by_key(|node| ctx.tree[*node].start()) - { - if let Some(l) = left { - inlines.push(Inline { - left: l, - right: node, - }); - left = None; - } else { - left = Some(node); - } - } - inlines - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct MathOperator { - pub parent: AstNodeIndex, - pub definition: AstNodeIndex, - pub definition_index: usize, - pub implementation: AstNodeIndex, - pub implementation_index: usize, -} - -impl MathOperator { - pub fn definition_name(self, tree: &Tree) -> &str { - tree.as_command(self.definition).unwrap().name.text() - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - iproduct!(ctx.commands, LANGUAGE_DATA.math_operator_commands.iter()) - .filter_map(|(parent, desc)| Self::parse_single(ctx, *parent, desc)) - .collect() - } - - fn parse_single( - ctx: SymbolContext, - parent: AstNodeIndex, - desc: &LatexMathOperatorCommand, - ) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != desc.name { - return None; - } - - let group_kind = GroupKind::Group; - let def_group = ctx - .tree - .extract_group(parent, group_kind, desc.definition_index)?; - let implementation = - ctx.tree - .extract_group(parent, group_kind, desc.implementation_index)?; - - let mut def_children = ctx.tree.children(def_group); - let definition = def_children.next()?; - Some(Self { - parent, - definition, - definition_index: desc.definition_index, - implementation, - implementation_index: desc.implementation_index, - }) - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct TheoremDefinition { - pub parent: AstNodeIndex, - pub arg_index: usize, -} - -impl TheoremDefinition { - pub fn name(self, tree: &Tree) -> &Token { - tree.extract_word(self.parent, GroupKind::Group, self.arg_index) - .unwrap() - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - let thm = LANGUAGE_DATA.theorem_definition_commands.iter(); - iproduct!(ctx.commands, thm) - .filter_map(|(parent, desc)| Self::parse_single(ctx, *parent, desc)) - .collect() - } - - fn parse_single( - ctx: SymbolContext, - parent: AstNodeIndex, - desc: &LatexTheoremDefinitionCommand, - ) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != desc.name { - return None; - } - - let group_kind = GroupKind::Group; - ctx.tree.extract_word(parent, group_kind, desc.index)?; - - Some(Self { - parent, - arg_index: desc.index, - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Section { - pub parent: AstNodeIndex, - pub arg_index: usize, - pub level: i32, - pub prefix: Cow<'static, str>, -} - -impl Section { - pub fn print(&self, tree: &Tree) -> Option<String> { - tree.print_group_content(self.parent, GroupKind::Group, self.arg_index) - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - iproduct!(ctx.commands, LANGUAGE_DATA.section_commands.iter()) - .filter_map(|(parent, desc)| Self::parse_single(ctx, *parent, desc)) - .collect() - } - - fn parse_single( - ctx: SymbolContext, - parent: AstNodeIndex, - desc: &'static LatexSectionCommand, - ) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != desc.name { - return None; - } - - let group_kind = GroupKind::Group; - ctx.tree.extract_group(parent, group_kind, desc.index)?; - - Some(Self { - parent, - arg_index: desc.index, - level: desc.level, - prefix: Cow::from(&desc.prefix), - }) - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct Label { - pub parent: AstNodeIndex, - pub arg_index: usize, - pub kind: LatexLabelKind, -} - -impl Label { - pub fn names(self, tree: &Tree) -> Vec<&Token> { - tree.extract_comma_separated_words(self.parent, GroupKind::Group, self.arg_index) - .unwrap() - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - iproduct!(ctx.commands, LANGUAGE_DATA.label_commands.iter()) - .filter_map(|(parent, desc)| Self::parse_single(ctx, *parent, desc)) - .collect() - } - - fn parse_single( - ctx: SymbolContext, - parent: AstNodeIndex, - desc: &LatexLabelCommand, - ) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != desc.name { - return None; - } - - ctx.tree - .extract_comma_separated_words(parent, GroupKind::Group, desc.index)?; - - Some(Self { - parent, - arg_index: desc.index, - kind: desc.kind, - }) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct LabelNumbering { - pub parent: AstNodeIndex, - pub number: String, -} - -impl LabelNumbering { - pub fn name<'a>(&self, tree: &'a Tree) -> &'a Token { - tree.extract_word(self.parent, GroupKind::Group, 0).unwrap() - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - ctx.commands - .iter() - .filter_map(|parent| Self::parse_single(ctx, *parent)) - .collect() - } - - fn parse_single(ctx: SymbolContext, parent: AstNodeIndex) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != "\\newlabel" { - return None; - } - - ctx.tree.extract_word(parent, GroupKind::Group, 0)?; - - let arg = ctx.tree.extract_group(parent, GroupKind::Group, 1)?; - let mut analyzer = FirstText::default(); - analyzer.visit(ctx.tree, arg); - Some(Self { - parent, - number: analyzer.text?, - }) - } -} - -#[derive(Debug, Default)] -struct FirstText { - text: Option<String>, -} - -impl Visitor for FirstText { - fn visit(&mut self, tree: &Tree, node: AstNodeIndex) { - if let Some(text) = tree.as_text(node) { - self.text = Some(text.words.iter().map(Token::text).join(" ")); - } - - if self.text.is_none() { - tree.walk(self, node); - } - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct Caption { - pub parent: AstNodeIndex, - pub arg_index: usize, -} - -impl Caption { - pub fn print(self, tree: &Tree) -> Option<String> { - tree.print_group_content(self.parent, GroupKind::Group, self.arg_index) - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - ctx.commands - .iter() - .flat_map(|parent| Self::parse_single(ctx, *parent)) - .collect() - } - - fn parse_single(ctx: SymbolContext, parent: AstNodeIndex) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != "\\caption" { - return None; - } - - ctx.tree.extract_group(parent, GroupKind::Group, 0)?; - Some(Self { - parent, - arg_index: 0, - }) - } -} - -#[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct Item { - pub parent: AstNodeIndex, -} - -impl Item { - pub fn name(self, tree: &Tree) -> Option<String> { - tree.print_group_content(self.parent, GroupKind::Options, 0) - } - - fn parse(ctx: SymbolContext) -> Vec<Self> { - ctx.commands - .iter() - .filter_map(|parent| Self::parse_single(ctx, *parent)) - .collect() - } - - fn parse_single(ctx: SymbolContext, parent: AstNodeIndex) -> Option<Self> { - let cmd = ctx.tree.as_command(parent)?; - if cmd.name.text() != "\\item" { - return None; - } - - Some(Self { parent }) - } +pub fn analyze(context: &mut LatexAnalyzerContext, root: &latex::SyntaxNode) { + analyze_implicit_links(context); + for node in root.descendants() { + analyze_command(context, node) + .or_else(|| analyze_begin(context, node)) + .or_else(|| analyze_include(context, node)) + .or_else(|| analyze_import(context, node)) + .or_else(|| analyze_label_name(context, node)) + .or_else(|| analyze_label_number(context, node)) + .or_else(|| analyze_theorem_definition(context, node)); + } + context.extras.has_document_environment = context.extras.environment_names.contains("document"); } diff --git a/support/texlab/src/syntax/latex/analysis/command.rs b/support/texlab/src/syntax/latex/analysis/command.rs new file mode 100644 index 0000000000..9dea4d84ee --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/command.rs @@ -0,0 +1,12 @@ +use crate::syntax::{latex, CstNode}; + +use super::LatexAnalyzerContext; + +pub fn analyze_command(context: &mut LatexAnalyzerContext, node: &latex::SyntaxNode) -> Option<()> { + let command = latex::GenericCommand::cast(node)?; + context + .extras + .command_names + .insert(command.name()?.text().into()); + Some(()) +} diff --git a/support/texlab/src/syntax/latex/analysis/distro_file.rs b/support/texlab/src/syntax/latex/analysis/distro_file.rs new file mode 100644 index 0000000000..4c747ce760 --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/distro_file.rs @@ -0,0 +1,71 @@ +use crate::{distro::Resolver, Uri}; + +pub fn resolve_distro_file(resolver: &Resolver, stem: &str, extensions: &[&str]) -> Option<Uri> { + let mut document = resolver.files_by_name.get(stem); + for extension in extensions { + document = document.or_else(|| { + let full_name = format!("{}.{}", stem, extension); + resolver.files_by_name.get(full_name.as_str()) + }); + } + document.and_then(|path| Uri::from_file_path(path).ok()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(windows)] + fn test() { + let mut resolver = Resolver::default(); + resolver + .files_by_name + .insert("foo.tex".into(), "C:/distro/foo.tex".into()); + resolver + .files_by_name + .insert("foo.sty".into(), "C:/distro/foo.sty".into()); + resolver + .files_by_name + .insert("bar.tex".into(), "C:/distro/bar.tex".into()); + + assert_eq!( + resolve_distro_file(&resolver, "foo", &["tex"]), + Some(Uri::from_file_path("C:/distro/foo.tex").unwrap()) + ); + + assert_eq!( + resolve_distro_file(&resolver, "foo", &["sty"]), + Some(Uri::from_file_path("C:/distro/foo.sty").unwrap()) + ); + + assert_eq!(resolve_distro_file(&resolver, "foo", &["cls"]), None); + } + + #[test] + #[cfg(unix)] + fn test() { + let mut resolver = Resolver::default(); + resolver + .files_by_name + .insert("foo.tex".into(), "/distro/foo.tex".into()); + resolver + .files_by_name + .insert("foo.sty".into(), "/distro/foo.sty".into()); + resolver + .files_by_name + .insert("bar.tex".into(), "/distro/bar.tex".into()); + + assert_eq!( + resolve_distro_file(&resolver, "foo", &["tex"]), + Some(Uri::from_file_path("/distro/foo.tex").unwrap()) + ); + + assert_eq!( + resolve_distro_file(&resolver, "foo", &["sty"]), + Some(Uri::from_file_path("/distro/foo.sty").unwrap()) + ); + + assert_eq!(resolve_distro_file(&resolver, "foo", &["cls"]), None); + } +} diff --git a/support/texlab/src/syntax/latex/analysis/environment.rs b/support/texlab/src/syntax/latex/analysis/environment.rs new file mode 100644 index 0000000000..3b83b40b2f --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/environment.rs @@ -0,0 +1,11 @@ +use crate::syntax::{latex, CstNode}; + +use super::LatexAnalyzerContext; + +pub fn analyze_begin(context: &mut LatexAnalyzerContext, node: &latex::SyntaxNode) -> Option<()> { + let begin = latex::Begin::cast(node)?; + let name = begin.name()?.word()?.text(); + let extras = &mut context.extras; + extras.environment_names.insert(name.into()); + Some(()) +} diff --git a/support/texlab/src/syntax/latex/analysis/explicit_link.rs b/support/texlab/src/syntax/latex/analysis/explicit_link.rs new file mode 100644 index 0000000000..363a576aaa --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/explicit_link.rs @@ -0,0 +1,72 @@ +use std::sync::Arc; + +use crate::syntax::{latex, CstNode}; + +use super::{ + distro_file::resolve_distro_file, ExplicitLink, ExplicitLinkKind, LatexAnalyzerContext, +}; + +pub fn analyze_include(context: &mut LatexAnalyzerContext, node: &latex::SyntaxNode) -> Option<()> { + let include = latex::Include::cast(node)?; + let kind = match include.syntax().kind() { + latex::LATEX_INCLUDE => ExplicitLinkKind::Latex, + latex::BIBLATEX_INCLUDE | latex::BIBTEX_INCLUDE => ExplicitLinkKind::Bibtex, + latex::PACKAGE_INCLUDE => ExplicitLinkKind::Package, + latex::CLASS_INCLUDE => ExplicitLinkKind::Class, + _ => return None, + }; + + let extensions = match kind { + ExplicitLinkKind::Latex => &["tex"], + ExplicitLinkKind::Bibtex => &["bib"], + ExplicitLinkKind::Package => &["sty"], + ExplicitLinkKind::Class => &["cls"], + }; + + for path in include.path_list()?.words() { + let stem = path.text(); + let mut targets = vec![Arc::new(context.base_uri.join(stem).ok()?.into())]; + for extension in extensions { + let path = format!("{}.{}", stem, extension); + targets.push(Arc::new(context.base_uri.join(&path).ok()?.into())); + } + + resolve_distro_file(&context.inner.resolver.lock().unwrap(), stem, extensions) + .into_iter() + .for_each(|target| targets.push(Arc::new(target))); + + context.extras.explicit_links.push(ExplicitLink { + kind, + stem: stem.into(), + stem_range: path.text_range(), + targets, + }); + } + + Some(()) +} + +pub fn analyze_import(context: &mut LatexAnalyzerContext, node: &latex::SyntaxNode) -> Option<()> { + let import = latex::Import::cast(node)?; + + let mut targets = Vec::new(); + let directory = context + .base_uri + .join(import.directory()?.word()?.text()) + .ok()?; + + let file = import.file()?.word()?; + let stem = file.text(); + targets.push(Arc::new(directory.join(stem).ok()?.into())); + targets.push(Arc::new( + directory.join(&format!("{}.tex", stem)).ok()?.into(), + )); + + context.extras.explicit_links.push(ExplicitLink { + stem: stem.into(), + stem_range: file.text_range(), + targets, + kind: ExplicitLinkKind::Latex, + }); + Some(()) +} diff --git a/support/texlab/src/syntax/latex/analysis/implicit_link.rs b/support/texlab/src/syntax/latex/analysis/implicit_link.rs new file mode 100644 index 0000000000..74055b3e31 --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/implicit_link.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; + +use crate::Uri; + +use super::LatexAnalyzerContext; + +pub fn analyze_implicit_links(context: &mut LatexAnalyzerContext) { + context.extras.implicit_links.aux = find_by_extension(context, "aux").unwrap_or_default(); + context.extras.implicit_links.log = find_by_extension(context, "log").unwrap_or_default(); + context.extras.implicit_links.pdf = find_by_extension(context, "pdf").unwrap_or_default(); +} + +fn find_by_extension(context: &LatexAnalyzerContext, extension: &str) -> Option<Vec<Arc<Uri>>> { + let mut targets: Vec<Arc<Uri>> = Vec::new(); + targets.push(Arc::new(context.document_uri.with_extension(extension)?)); + if context.document_uri.scheme() == "file" { + let file_path = context.document_uri.to_file_path().ok()?; + let file_stem = file_path.file_stem()?; + let aux_name = format!("{}.{}", file_stem.to_str()?, extension); + + let options = context.inner.options.read().unwrap(); + if let Some(root_dir) = options.root_directory.as_ref() { + let path = context + .inner + .current_directory + .join(root_dir) + .join(&aux_name); + targets.push(Arc::new(Uri::from_file_path(path).ok()?)); + } + + if let Some(build_dir) = options.aux_directory.as_ref() { + let path = context + .inner + .current_directory + .join(build_dir) + .join(&aux_name); + targets.push(Arc::new(Uri::from_file_path(path).ok()?)); + } + } + Some(targets) +} diff --git a/support/texlab/src/syntax/latex/analysis/label_name.rs b/support/texlab/src/syntax/latex/analysis/label_name.rs new file mode 100644 index 0000000000..d0410b953c --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/label_name.rs @@ -0,0 +1,66 @@ +use latex::LabelReferenceRange; + +use crate::syntax::{latex, CstNode}; + +use super::{LabelName, LatexAnalyzerContext}; + +pub fn analyze_label_name( + context: &mut LatexAnalyzerContext, + node: &latex::SyntaxNode, +) -> Option<()> { + analyze_label_definition_name(context, node) + .or_else(|| analyze_label_reference_name(context, node)) + .or_else(|| analyze_label_reference_range_name(context, node)) +} + +fn analyze_label_definition_name( + context: &mut LatexAnalyzerContext, + node: &latex::SyntaxNode, +) -> Option<()> { + let label = latex::LabelDefinition::cast(node)?; + let name = label.name()?.word()?; + context.extras.label_names.push(LabelName { + text: name.text().into(), + range: name.text_range(), + is_definition: true, + }); + Some(()) +} + +fn analyze_label_reference_name( + context: &mut LatexAnalyzerContext, + node: &latex::SyntaxNode, +) -> Option<()> { + let label = latex::LabelReference::cast(node)?; + for name in label.name_list()?.words() { + context.extras.label_names.push(LabelName { + text: name.text().into(), + range: name.text_range(), + is_definition: false, + }); + } + Some(()) +} + +fn analyze_label_reference_range_name( + context: &mut LatexAnalyzerContext, + node: &latex::SyntaxNode, +) -> Option<()> { + let label = LabelReferenceRange::cast(node)?; + if let Some(name1) = label.from().and_then(|name| name.word()) { + context.extras.label_names.push(LabelName { + text: name1.text().into(), + range: name1.text_range(), + is_definition: false, + }); + } + + if let Some(name2) = label.to().and_then(|name| name.word()) { + context.extras.label_names.push(LabelName { + text: name2.text().into(), + range: name2.text_range(), + is_definition: false, + }); + } + Some(()) +} diff --git a/support/texlab/src/syntax/latex/analysis/label_number.rs b/support/texlab/src/syntax/latex/analysis/label_number.rs new file mode 100644 index 0000000000..de8d0dc1e1 --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/label_number.rs @@ -0,0 +1,22 @@ +use crate::syntax::{latex, CstNode}; + +use super::LatexAnalyzerContext; + +pub fn analyze_label_number( + context: &mut LatexAnalyzerContext, + node: &latex::SyntaxNode, +) -> Option<()> { + let number = latex::LabelNumber::cast(node)?; + let name = number.name()?.word()?.text().into(); + let text = number + .text()? + .syntax() + .descendants_with_tokens() + .filter_map(|element| element.into_node()) + .find(|node| node.kind() == latex::TEXT || node.kind() == latex::MIXED_GROUP)? + .text() + .to_string(); + + context.extras.label_numbers_by_name.insert(name, text); + Some(()) +} diff --git a/support/texlab/src/syntax/latex/analysis/theorem.rs b/support/texlab/src/syntax/latex/analysis/theorem.rs new file mode 100644 index 0000000000..0c365f0ef5 --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/theorem.rs @@ -0,0 +1,23 @@ +use crate::syntax::{ + latex::{self, HasCurly}, + CstNode, +}; + +use super::{LatexAnalyzerContext, TheoremEnvironment}; + +pub fn analyze_theorem_definition( + context: &mut LatexAnalyzerContext, + node: &latex::SyntaxNode, +) -> Option<()> { + let theorem = latex::TheoremDefinition::cast(node)?; + let name = theorem.name()?.word()?.text().into(); + let description = theorem.description()?; + let description = description.content_text()?; + + context + .extras + .theorem_environments + .push(TheoremEnvironment { name, description }); + + Some(()) +} diff --git a/support/texlab/src/syntax/latex/analysis/types.rs b/support/texlab/src/syntax/latex/analysis/types.rs new file mode 100644 index 0000000000..f089721397 --- /dev/null +++ b/support/texlab/src/syntax/latex/analysis/types.rs @@ -0,0 +1,73 @@ +use std::sync::Arc; + +use cstree::TextRange; +use rustc_hash::{FxHashMap, FxHashSet}; +use smol_str::SmolStr; + +use crate::{ServerContext, Uri}; + +#[derive(Debug)] +pub struct LatexAnalyzerContext { + pub inner: Arc<ServerContext>, + pub document_uri: Arc<Uri>, + pub base_uri: Arc<Uri>, + pub extras: Extras, +} + +#[derive(Debug, Clone, Default)] +pub struct Extras { + pub implicit_links: ImplicitLinks, + pub explicit_links: Vec<ExplicitLink>, + pub has_document_environment: bool, + pub command_names: FxHashSet<SmolStr>, + pub environment_names: FxHashSet<SmolStr>, + pub label_names: Vec<LabelName>, + pub label_numbers_by_name: FxHashMap<SmolStr, String>, + pub theorem_environments: Vec<TheoremEnvironment>, +} + +#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)] +pub struct ImplicitLinks { + pub aux: Vec<Arc<Uri>>, + pub log: Vec<Arc<Uri>>, + pub pdf: Vec<Arc<Uri>>, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)] +pub enum ExplicitLinkKind { + Package, + Class, + Latex, + Bibtex, +} + +#[derive(Debug, Clone)] +pub struct ExplicitLink { + pub stem: SmolStr, + pub stem_range: TextRange, + pub targets: Vec<Arc<Uri>>, + pub kind: ExplicitLinkKind, +} + +impl ExplicitLink { + pub fn as_component_name(&self) -> Option<String> { + match self.kind { + ExplicitLinkKind::Package => Some(format!("{}.sty", self.stem)), + ExplicitLinkKind::Class => Some(format!("{}.cls", self.stem)), + ExplicitLinkKind::Latex | ExplicitLinkKind::Bibtex => None, + } + } +} + +#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)] +pub struct TheoremEnvironment { + pub name: SmolStr, + pub description: String, +} + +#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)] +pub struct LabelName { + pub text: SmolStr, + pub range: TextRange, + pub is_definition: bool, +} diff --git a/support/texlab/src/syntax/latex/ast.rs b/support/texlab/src/syntax/latex/ast.rs deleted file mode 100644 index ab7c6863e1..0000000000 --- a/support/texlab/src/syntax/latex/ast.rs +++ /dev/null @@ -1,414 +0,0 @@ -use crate::{ - protocol::{Position, Range, RangeExt}, - syntax::{ - generic_ast::{Ast, AstNodeIndex}, - text::{Span, SyntaxNode}, - }, -}; -use serde::{Deserialize, Serialize}; -use std::ops::Deref; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] -pub enum TokenKind { - Word, - Command, - Math, - Comma, - BeginGroup, - EndGroup, - BeginOptions, - EndOptions, -} - -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct Token { - pub span: Span, - pub kind: TokenKind, -} - -impl Token { - pub fn new(span: Span, kind: TokenKind) -> Self { - Self { span, kind } - } - - pub fn text(&self) -> &str { - &self.span.text - } -} - -impl SyntaxNode for Token { - fn range(&self) -> Range { - self.span.range() - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] -pub struct Root { - pub range: Range, -} - -impl SyntaxNode for Root { - fn range(&self) -> Range { - self.range - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] -pub enum GroupKind { - Group, - Options, -} - -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct Group { - pub range: Range, - pub left: Token, - pub right: Option<Token>, - pub kind: GroupKind, -} - -impl SyntaxNode for Group { - fn range(&self) -> Range { - self.range - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct Command { - pub range: Range, - pub name: Token, -} - -impl Command { - pub fn short_name_range(&self) -> Range { - Range::new_simple( - self.name.start().line, - self.name.start().character + 1, - self.name.end().line, - self.name.end().character, - ) - } -} - -impl SyntaxNode for Command { - fn range(&self) -> Range { - self.range - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct Text { - pub range: Range, - pub words: Vec<Token>, -} - -impl SyntaxNode for Text { - fn range(&self) -> Range { - self.range - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct Comma { - pub range: Range, - pub token: Token, -} - -impl SyntaxNode for Comma { - fn range(&self) -> Range { - self.range - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub struct Math { - pub range: Range, - pub token: Token, -} - -impl SyntaxNode for Math { - fn range(&self) -> Range { - self.range - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] -pub enum Node { - Root(Root), - Group(Group), - Command(Command), - Text(Text), - Comma(Comma), - Math(Math), -} - -impl SyntaxNode for Node { - fn range(&self) -> Range { - match self { - Self::Root(root) => root.range(), - Self::Group(group) => group.range(), - Self::Command(cmd) => cmd.range(), - Self::Text(text) => text.range(), - Self::Comma(comma) => comma.range(), - Self::Math(math) => math.range(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Tree { - pub inner: Ast<Node>, - pub root: AstNodeIndex, -} - -impl Deref for Tree { - type Target = Ast<Node>; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl Tree { - pub fn walk<V: Visitor>(&self, visitor: &mut V, parent: AstNodeIndex) { - for child in self.children(parent) { - visitor.visit(self, child); - } - } - - pub fn find(&self, pos: Position) -> Vec<AstNodeIndex> { - let mut finder = Finder::new(pos); - finder.visit(self, self.root); - finder.results - } - - pub fn find_command_by_short_name_range(&self, pos: Position) -> Option<AstNodeIndex> { - self.find(pos).into_iter().find(|node| { - self.as_command(*node) - .filter(|cmd| { - cmd.name.range().contains(pos) && cmd.name.start().character != pos.character - }) - .is_some() - }) - } - - pub fn print(&self, node: AstNodeIndex) -> String { - let start_position = self[node].start(); - let mut printer = Printer::new(start_position); - printer.visit(self, node); - printer.output - } - - pub fn commands<'a>(&'a self) -> impl Iterator<Item = AstNodeIndex> + 'a { - self.inner - .nodes() - .into_iter() - .filter(move |node| self.as_command(*node).is_some()) - } - - pub fn as_group(&self, node: AstNodeIndex) -> Option<&Group> { - if let Node::Group(group) = &self[node] { - Some(group) - } else { - None - } - } - - pub fn as_command(&self, node: AstNodeIndex) -> Option<&Command> { - if let Node::Command(cmd) = &self[node] { - Some(cmd) - } else { - None - } - } - - pub fn as_text(&self, node: AstNodeIndex) -> Option<&Text> { - if let Node::Text(text) = &self[node] { - Some(text) - } else { - None - } - } - - pub fn as_math(&self, node: AstNodeIndex) -> Option<&Math> { - if let Node::Math(math) = &self[node] { - Some(math) - } else { - None - } - } - - pub fn extract_group( - &self, - parent: AstNodeIndex, - group_kind: GroupKind, - index: usize, - ) -> Option<AstNodeIndex> { - self.children(parent) - .filter(|child| { - self.as_group(*child) - .filter(|group| group.kind == group_kind) - .is_some() - }) - .nth(index) - } - - pub fn extract_text( - &self, - parent: AstNodeIndex, - group_kind: GroupKind, - index: usize, - ) -> Option<&Text> { - let group = self.extract_group(parent, group_kind, index)?; - let mut contents = self.children(group); - let text = self.as_text(contents.next()?); - if contents.next().is_none() { - text - } else { - None - } - } - - pub fn extract_word( - &self, - parent: AstNodeIndex, - group_kind: GroupKind, - index: usize, - ) -> Option<&Token> { - let text = self.extract_text(parent, group_kind, index)?; - if text.words.len() == 1 { - Some(&text.words[0]) - } else { - None - } - } - - pub fn extract_comma_separated_words( - &self, - parent: AstNodeIndex, - group_kind: GroupKind, - index: usize, - ) -> Option<Vec<&Token>> { - let group = self.extract_group(parent, group_kind, index)?; - let mut words = Vec::new(); - for child in self.children(group) { - match &self[child] { - Node::Root(_) | Node::Group(_) | Node::Command(_) | Node::Math(_) => return None, - Node::Text(text) => { - for word in &text.words { - words.push(word); - } - } - Node::Comma(_) => (), - } - } - Some(words) - } - - pub fn print_group_content( - &self, - parent: AstNodeIndex, - group_kind: GroupKind, - index: usize, - ) -> Option<String> { - let arg = self.extract_group(parent, group_kind, index)?; - let text = self.print(arg); - self.as_group(arg)?.right.as_ref()?; - Some(text[1..text.len() - 1].trim().into()) - } -} - -pub trait Visitor { - fn visit(&mut self, tree: &Tree, node: AstNodeIndex); -} - -#[derive(Debug)] -struct Finder { - position: Position, - results: Vec<AstNodeIndex>, -} - -impl Finder { - fn new(position: Position) -> Self { - Self { - position, - results: Vec::new(), - } - } -} - -impl Visitor for Finder { - fn visit(&mut self, tree: &Tree, node: AstNodeIndex) { - if tree[node].range().contains(self.position) { - self.results.push(node); - tree.walk(self, node); - } - } -} - -#[derive(Debug)] -struct Printer { - output: String, - position: Position, -} - -impl Printer { - fn new(start_position: Position) -> Self { - Self { - output: String::new(), - position: start_position, - } - } - - fn synchronize(&mut self, position: Position) { - while self.position.line < position.line { - self.output.push('\n'); - self.position.line += 1; - self.position.character = 0; - } - - while self.position.character < position.character { - self.output.push(' '); - self.position.character += 1; - } - - assert_eq!(self.position, position); - } - - fn print_token(&mut self, token: &Token) { - self.synchronize(token.start()); - self.output.push_str(token.text()); - self.position.character += token.end().character - token.start().character; - self.synchronize(token.end()); - } -} - -impl Visitor for Printer { - fn visit(&mut self, tree: &Tree, node: AstNodeIndex) { - match &tree[node] { - Node::Root(_) => tree.walk(self, node), - Node::Group(group) => { - self.print_token(&group.left); - tree.walk(self, node); - if let Some(right) = &group.right { - self.print_token(right); - } - } - Node::Command(cmd) => { - self.print_token(&cmd.name); - tree.walk(self, node); - } - Node::Text(text) => { - for word in &text.words { - self.print_token(word); - } - } - Node::Comma(comma) => { - self.print_token(&comma.token); - } - Node::Math(math) => { - self.print_token(&math.token); - } - } - } -} 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) + } +} diff --git a/support/texlab/src/syntax/latex/kind.rs b/support/texlab/src/syntax/latex/kind.rs new file mode 100644 index 0000000000..fcab393380 --- /dev/null +++ b/support/texlab/src/syntax/latex/kind.rs @@ -0,0 +1,180 @@ +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)] +#[allow(non_camel_case_types)] +#[repr(u16)] +pub enum SyntaxKind { + ERROR = 0, + MISSING, + + WHITESPACE, + COMMENT, + L_CURLY, + R_CURLY, + L_BRACK, + R_BRACK, + L_PAREN, + R_PAREN, + PARAMETER, + COMMA, + EQUALITY_SIGN, + WORD, + DOLLAR, + GENERIC_COMMAND_NAME, + BEGIN_ENVIRONMENT_NAME, + END_ENVIRONMENT_NAME, + BEGIN_EQUATION_NAME, + END_EQUATION_NAME, + PART_NAME, + CHAPTER_NAME, + SECTION_NAME, + SUBSECTION_NAME, + SUBSUBSECTION_NAME, + PARAGRAPH_NAME, + SUBPARAGRAPH_NAME, + ENUM_ITEM_NAME, + CAPTION_NAME, + CITATION_NAME, + PACKAGE_INCLUDE_NAME, + CLASS_INCLUDE_NAME, + LATEX_INCLUDE_NAME, + BIBLATEX_INCLUDE_NAME, + BIBTEX_INCLUDE_NAME, + GRAPHICS_INCLUDE_NAME, + SVG_INCLUDE_NAME, + INKSCAPE_INCLUDE_NAME, + VERBATIM_INCLUDE_NAME, + IMPORT_NAME, + LABEL_DEFINITION_NAME, + LABEL_REFERENCE_NAME, + LABEL_REFERENCE_RANGE_NAME, + LABEL_NUMBER_NAME, + COMMAND_DEFINITION_NAME, + MATH_OPERATOR_NAME, + GLOSSARY_ENTRY_DEFINITION_NAME, + GLOSSARY_ENTRY_REFERENCE_NAME, + ACRONYM_DEFINITION_NAME, + ACRONYM_DECLARATION_NAME, + ACRONYM_REFERENCE_NAME, + THEOREM_DEFINITION_NAME, + COLOR_REFERENCE_NAME, + COLOR_DEFINITION_NAME, + COLOR_SET_DEFINITION_NAME, + TIKZ_LIBRARY_IMPORT_NAME, + ENVIRONMENT_DEFINIITION_NAME, + + PREAMBLE, + TEXT, + KEY, + VALUE, + KEY_VALUE_PAIR, + KEY_VALUE_BODY, + CURLY_GROUP, + CURLY_GROUP_WORD, + CURLY_GROUP_WORD_LIST, + CURLY_GROUP_COMMAND, + CURLY_GROUP_KEY_VALUE, + BRACK_GROUP, + BRACK_GROUP_WORD, + BRACK_GROUP_KEY_VALUE, + PAREN_GROUP, + MIXED_GROUP, + GENERIC_COMMAND, + ENVIRONMENT, + BEGIN, + END, + EQUATION, + PART, + CHAPTER, + SECTION, + SUBSECTION, + SUBSUBSECTION, + PARAGRAPH, + SUBPARAGRAPH, + ENUM_ITEM, + FORMULA, + CAPTION, + CITATION, + PACKAGE_INCLUDE, + CLASS_INCLUDE, + LATEX_INCLUDE, + BIBLATEX_INCLUDE, + BIBTEX_INCLUDE, + GRAPHICS_INCLUDE, + SVG_INCLUDE, + INKSCAPE_INCLUDE, + VERBATIM_INCLUDE, + IMPORT, + LABEL_DEFINITION, + LABEL_REFERENCE, + LABEL_REFERENCE_RANGE, + LABEL_NUMBER, + COMMAND_DEFINITION, + MATH_OPERATOR, + GLOSSARY_ENTRY_DEFINITION, + GLOSSARY_ENTRY_REFERENCE, + ACRONYM_DEFINITION, + ACRONYM_DECLARATION, + ACRONYM_REFERENCE, + THEOREM_DEFINITION, + COLOR_REFERENCE, + COLOR_DEFINITION, + COLOR_SET_DEFINITION, + TIKZ_LIBRARY_IMPORT, + ENVIRONMENT_DEFINITION, + ROOT, +} + +impl SyntaxKind { + pub fn is_command_name(&self) -> bool { + use SyntaxKind::*; + matches!( + self, + GENERIC_COMMAND_NAME + | BEGIN_ENVIRONMENT_NAME + | END_ENVIRONMENT_NAME + | BEGIN_EQUATION_NAME + | END_EQUATION_NAME + | PART_NAME + | CHAPTER_NAME + | SECTION_NAME + | SUBSECTION_NAME + | SUBSUBSECTION_NAME + | PARAGRAPH_NAME + | SUBPARAGRAPH_NAME + | ENUM_ITEM_NAME + | CAPTION_NAME + | CITATION_NAME + | PACKAGE_INCLUDE_NAME + | CLASS_INCLUDE_NAME + | LATEX_INCLUDE_NAME + | BIBLATEX_INCLUDE_NAME + | BIBTEX_INCLUDE_NAME + | GRAPHICS_INCLUDE_NAME + | SVG_INCLUDE_NAME + | INKSCAPE_INCLUDE_NAME + | VERBATIM_INCLUDE_NAME + | IMPORT_NAME + | LABEL_DEFINITION_NAME + | LABEL_REFERENCE_NAME + | LABEL_REFERENCE_RANGE_NAME + | LABEL_NUMBER_NAME + | COMMAND_DEFINITION_NAME + | MATH_OPERATOR_NAME + | GLOSSARY_ENTRY_DEFINITION_NAME + | GLOSSARY_ENTRY_REFERENCE_NAME + | ACRONYM_DEFINITION_NAME + | ACRONYM_DECLARATION_NAME + | ACRONYM_REFERENCE_NAME + | THEOREM_DEFINITION_NAME + | COLOR_REFERENCE_NAME + | COLOR_DEFINITION_NAME + | COLOR_SET_DEFINITION_NAME + | TIKZ_LIBRARY_IMPORT_NAME + ) + } +} + +impl From<SyntaxKind> for cstree::SyntaxKind { + fn from(kind: SyntaxKind) -> Self { + Self(kind as u16) + } +} diff --git a/support/texlab/src/syntax/latex/lexer.rs b/support/texlab/src/syntax/latex/lexer.rs index e14f1f6d85..7cd94ec897 100644 --- a/support/texlab/src/syntax/latex/lexer.rs +++ b/support/texlab/src/syntax/latex/lexer.rs @@ -1,176 +1,255 @@ -use super::ast::{Token, TokenKind}; -use crate::syntax::text::CharStream; +use logos::Logos; -#[derive(Debug)] +use super::kind::SyntaxKind; + +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord, Logos)] +#[allow(non_camel_case_types)] +#[repr(u16)] +enum Token { + #[regex(r"\s+")] + WHITESPACE = 2, + + #[regex(r"%[^\r\n]*")] + COMMENT, + + #[token("{")] + L_CURLY, + + #[token("}")] + R_CURLY, + + #[token("[")] + L_BRACK, + + #[token("]")] + R_BRACK, + + #[token("(")] + L_PAREN, + + #[token(")")] + R_PAREN, + + #[regex(r"#\d?")] + PARAMETER, + + #[token(",")] + COMMA, + + #[token("=")] + EQUALITY_SIGN, + + #[regex(r"[^\s\\%\{\},\$\[\]\(\)=\#]+")] + #[error] + WORD, + + #[regex(r"\$\$?")] + DOLLAR, + + #[regex(r"\\([^\r\n]|[@a-zA-Z:_]+\*?)?")] + GENERIC_COMMAND_NAME, + + #[regex(r"\\begin")] + BEGIN_ENVIRONMENT_NAME, + + #[regex(r"\\end")] + END_ENVIRONMENT_NAME, + + #[regex(r"\\\[")] + BEGIN_EQUATION_NAME, + + #[regex(r"\\\]")] + END_EQUATION_NAME, + + #[regex(r"\\part\*?")] + PART_NAME, + + #[regex(r"\\chapter\*?")] + CHAPTER_NAME, + + #[regex(r"\\section\*?")] + SECTION_NAME, + + #[regex(r"\\subsection\*?")] + SUBSECTION_NAME, + + #[regex(r"\\subsubsection\*?")] + SUBSUBSECTION_NAME, + + #[regex(r"\\paragraph\*?")] + PARAGRAPH_NAME, + + #[regex(r"\\subparagraph\*?")] + SUBPARAGRAPH_NAME, + + #[regex(r"\\item")] + ENUM_ITEM_NAME, + + #[regex(r"\\caption")] + CAPTION_NAME, + + #[regex(r"\\cite|\\cite\*|\\Cite|\\nocite|\\citet|\\citep|\\citet\*|\\citep\*|\\citeauthor|\\citeauthor\*|\\Citeauthor|\\Citeauthor\*|\\citetitle|\\citetitle\*|\\citeyear|\\citeyear\*|\\citedate|\\citedate\*|\\citeurl|\\fullcite|\\citeyearpar|\\citealt|\\citealp|\\citetext|\\parencite|\\parencite\*|\\Parencite|\\footcite|\\footfullcite|\\footcitetext|\\textcite|\\Textcite|\\smartcite|\\Smartcite|\\supercite|\\autocite|\\Autocite|\\autocite\*|\\Autocite\*|\\volcite|\\Volcite|\\pvolcite|\\Pvolcite|\\fvolcite|\\ftvolcite|\\svolcite|\\Svolcite|\\tvolcite|\\Tvolcite|\\avolcite|\\Avolcite|\\notecite|\\notecite|\\pnotecite|\\Pnotecite|\\fnotecite|\\citeA|\\citeA\*")] + CITATION_NAME, + + #[regex(r"\\usepackage|\\RequirePackage")] + PACKAGE_INCLUDE_NAME, + + #[regex(r"\\documentclass")] + CLASS_INCLUDE_NAME, + + #[regex(r"\\include|\\subfileinclude|\\input|\\subfile")] + LATEX_INCLUDE_NAME, + + #[regex(r"\\addbibresource")] + BIBLATEX_INCLUDE_NAME, + + #[regex(r"\\bibliography")] + BIBTEX_INCLUDE_NAME, + + #[regex(r"\\includegraphics")] + GRAPHICS_INCLUDE_NAME, + + #[regex(r"\\includesvg")] + SVG_INCLUDE_NAME, + + #[regex(r"\\includeinkscape")] + INKSCAPE_INCLUDE_NAME, + + #[regex(r"\\verbatiminput|\\VerbatimInput")] + VERBATIM_INCLUDE_NAME, + + #[regex(r"\\import|\\subimport|\\inputfrom|\\subimportfrom|\\includefrom|\\subincludefrom")] + IMPORT_NAME, + + #[regex(r"\\label")] + LABEL_DEFINITION_NAME, + + #[regex(r"\\ref|\\vref|\\Vref|\\autoref|\\pageref|\\cref|\\Cref|\\cref*|\\Cref*|\\namecref|\\nameCref|\\lcnamecref|\\namecrefs|\\nameCrefs|\\lcnamecrefs|\\labelcref|\\labelcpageref|\\eqref")] + LABEL_REFERENCE_NAME, + + #[regex(r"\\crefrange\*?|\\Crefrange\*?")] + LABEL_REFERENCE_RANGE_NAME, + + #[regex(r"\\newlabel")] + LABEL_NUMBER_NAME, + + #[regex(r"\\newcommand\*?|\\renewcommand|\\DeclareRobustCommand")] + COMMAND_DEFINITION_NAME, + + #[regex(r"\\DeclareMathOperator\*?")] + MATH_OPERATOR_NAME, + + #[regex(r"\\newglossaryentry")] + GLOSSARY_ENTRY_DEFINITION_NAME, + + #[regex(r"\\gls|\\Gls|\\GLS|\\glspl|\\Glspl|\\GLSpl|\\glsdisp|\\glslink|\\glstext|\\Glstext|\\GLStext|\\glsfirst|\\Glsfirst|\\GLSfirst|\\glsplural|\\Glsplural|\\GLSplural|\\glsfirstplural|\\Glsfirstplural|\\GLSfirstplural|\\glsname|\\Glsname|\\GLSname|\\glssymbol|\\Glssymbol|\\glsdesc|\\Glsdesc|\\GLSdesc|\\glsuseri|\\Glsuseri|\\GLSuseri|\\glsuserii|\\Glsuserii|\\GLSuserii|\\glsuseriii|\\Glsuseriii|\\GLSuseriii|\\glsuseriv|\\Glsuseriv|\\GLSuseriv|\\glsuserv|\\Glsuserv|\\GLSuserv|\\glsuservi|\\Glsuservi|\\GLSuservi")] + GLOSSARY_ENTRY_REFERENCE_NAME, + + #[regex(r"\\newacronym")] + ACRONYM_DEFINITION_NAME, + + #[regex(r"\\DeclareAcronym")] + ACRONYM_DECLARATION_NAME, + + #[regex(r"\\acrshort|\\Acrshort|\\ACRshort|\\acrshortpl|\\Acrshortpl|\\ACRshortpl|\\acrlong|\\Acrlong|\\ACRlong|\\acrlongpl|\\Acrlongpl|\\ACRlongpl|\\acrfull|\\Acrfull|\\ACRfull|\\acrfullpl|\\Acrfullpl|\\ACRfullpl|\\acs|\\Acs|\\acsp|\\Acsp|\\acl|\\Acl|\\aclp|\\Aclp|\\acf|\\Acf|\\acfp|\\Acfp|\\ac|\\Ac|\\acp|\\glsentrylong|\\Glsentrylong|\\glsentrylongpl|\\Glsentrylongpl|\\glsentryshort|\\Glsentryshort|\\glsentryshortpl|\\Glsentryshortpl|\\glsentryfullpl|\\Glsentryfullpl")] + ACRONYM_REFERENCE_NAME, + + #[regex(r"\\newtheorem|\\declaretheorem")] + THEOREM_DEFINITION_NAME, + + #[regex(r"\\color|\\colorbox|\\textcolor|\\pagecolor")] + COLOR_REFERENCE_NAME, + + #[regex(r"\\definecolor")] + COLOR_DEFINITION_NAME, + + #[regex(r"\\definecolorset")] + COLOR_SET_DEFINITION_NAME, + + #[regex(r"\\usepgflibrary|\\usetikzlibrary")] + TIKZ_LIBRARY_IMPORT_NAME, + + #[regex(r"\\newenvironment|\\newenvironment*")] + ENVIRONMENT_DEFINITION_NAME, +} + +#[derive(Debug, PartialEq, Eq, Clone)] pub struct Lexer<'a> { - stream: CharStream<'a>, + tokens: Vec<(SyntaxKind, &'a str)>, } impl<'a> Lexer<'a> { pub fn new(text: &'a str) -> Self { - Self { - stream: CharStream::new(text), + let mut tokens = Vec::new(); + let mut lexer = Token::lexer(text); + while let Some(kind) = lexer.next() { + tokens.push(( + unsafe { std::mem::transmute::<Token, SyntaxKind>(kind) }, + lexer.slice(), + )); } + tokens.reverse(); + Self { tokens } } - fn single_char(&mut self, kind: TokenKind) -> Token { - self.stream.start_span(); - self.stream.next(); - let span = self.stream.end_span(); - Token::new(span, kind) + pub fn peek(&self) -> Option<SyntaxKind> { + self.tokens.last().map(|(kind, _)| *kind) } - fn math(&mut self) -> Token { - self.stream.start_span(); - self.stream.next(); - if self.stream.satifies(|c| *c == '$') { - self.stream.next(); - } - let span = self.stream.end_span(); - Token::new(span, TokenKind::Math) + pub fn eat(&mut self) -> Option<(SyntaxKind, &'a str)> { + self.tokens.pop() } +} - fn command(&mut self) -> Token { - let span = self.stream.command(); - Token::new(span, TokenKind::Command) - } +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; - fn word(&mut self) -> Token { - self.stream.start_span(); - self.stream.next(); - while self.stream.satifies(|c| is_word_char(*c)) { - self.stream.next(); - } + use super::*; - let span = self.stream.end_span(); - Token::new(span, TokenKind::Word) + fn verify(text: &str) -> Vec<(SyntaxKind, &str)> { + let mut tokens = Lexer::new(text).tokens; + tokens.reverse(); + tokens } -} -impl<'a> Iterator for Lexer<'a> { - type Item = Token; - - fn next(&mut self) -> Option<Token> { - loop { - match self.stream.peek() { - Some('%') => { - self.stream.skip_rest_of_line(); - } - Some('{') => { - return Some(self.single_char(TokenKind::BeginGroup)); - } - Some('}') => { - return Some(self.single_char(TokenKind::EndGroup)); - } - Some('[') => { - return Some(self.single_char(TokenKind::BeginOptions)); - } - Some(']') => { - return Some(self.single_char(TokenKind::EndOptions)); - } - Some('$') => { - return Some(self.math()); - } - Some(',') => { - return Some(self.single_char(TokenKind::Comma)); - } - Some('\\') => { - return Some(self.command()); - } - Some(c) => { - if c.is_whitespace() { - self.stream.next(); - } else { - return Some(self.word()); - } - } - None => { - return None; - } - } - } + #[test] + fn test_empty() { + assert_debug_snapshot!(verify(r#""#)); } -} - -fn is_word_char(c: char) -> bool { - !c.is_whitespace() - && c != '%' - && c != '{' - && c != '}' - && c != '[' - && c != ']' - && c != '\\' - && c != '$' - && c != ',' -} -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - protocol::{Position, Range}, - syntax::text::Span, - }; - - fn verify<'a>(lexer: &mut Lexer<'a>, line: u64, character: u64, text: &str, kind: TokenKind) { - let start = Position::new(line, character); - let end = Position::new(line, character + text.chars().count() as u64); - let range = Range::new(start, end); - let span = Span::new(range, text.to_owned()); - let token = Token::new(span, kind); - assert_eq!(Some(token), lexer.next()); + #[test] + fn test_delimiters() { + assert_debug_snapshot!(verify(r#"{foo} (bar) [baz, qux = foo-bar]"#)); } #[test] - fn word() { - let mut lexer = Lexer::new("foo bar baz"); - verify(&mut lexer, 0, 0, "foo", TokenKind::Word); - verify(&mut lexer, 0, 4, "bar", TokenKind::Word); - verify(&mut lexer, 0, 8, "baz", TokenKind::Word); - assert_eq!(None, lexer.next()); + fn test_command_with_parameter() { + assert_debug_snapshot!(verify(r#"\newcommand{\id}[1]{#1}"#)); } #[test] - fn command() { - let mut lexer = Lexer::new("\\foo\\bar@baz\n\\foo*"); - verify(&mut lexer, 0, 0, "\\foo", TokenKind::Command); - verify(&mut lexer, 0, 4, "\\bar@baz", TokenKind::Command); - verify(&mut lexer, 1, 0, "\\foo*", TokenKind::Command); - assert_eq!(None, lexer.next()); + fn test_command_with_star() { + assert_debug_snapshot!(verify(r#"\section*{Foo}"#)); } #[test] - fn escape_sequence() { - let mut lexer = Lexer::new("\\%\\**"); - verify(&mut lexer, 0, 0, "\\%", TokenKind::Command); - verify(&mut lexer, 0, 2, "\\*", TokenKind::Command); - verify(&mut lexer, 0, 4, "*", TokenKind::Word); - assert_eq!(None, lexer.next()); + fn test_escape_sequence() { + assert_debug_snapshot!(verify(r#"\% hello"#)); } #[test] - fn group_delimiter() { - let mut lexer = Lexer::new("{}[]"); - verify(&mut lexer, 0, 0, "{", TokenKind::BeginGroup); - verify(&mut lexer, 0, 1, "}", TokenKind::EndGroup); - verify(&mut lexer, 0, 2, "[", TokenKind::BeginOptions); - verify(&mut lexer, 0, 3, "]", TokenKind::EndOptions); - assert_eq!(None, lexer.next()); + fn test_formula() { + assert_debug_snapshot!(verify(r#"$ f(x) = y $$"#)); } #[test] - fn math() { - let mut lexer = Lexer::new("$$ $ $"); - verify(&mut lexer, 0, 0, "$$", TokenKind::Math); - verify(&mut lexer, 0, 3, "$", TokenKind::Math); - verify(&mut lexer, 0, 5, "$", TokenKind::Math); - assert_eq!(None, lexer.next()); + fn test_comment() { + assert_debug_snapshot!(verify("hello %world\r\ntest %test")); } #[test] - fn line_comment() { - let mut lexer = Lexer::new(" %foo \nfoo"); - verify(&mut lexer, 1, 0, "foo", TokenKind::Word); - assert_eq!(None, lexer.next()); + fn test_invalid_parameter() { + assert_debug_snapshot!(verify(r#"#"#)) } } diff --git a/support/texlab/src/syntax/latex/mod.rs b/support/texlab/src/syntax/latex/mod.rs deleted file mode 100644 index cee83ab04e..0000000000 --- a/support/texlab/src/syntax/latex/mod.rs +++ /dev/null @@ -1,686 +0,0 @@ -mod analysis; -mod ast; -mod lexer; -mod parser; - -pub use self::{analysis::*, ast::*}; - -use self::{lexer::Lexer, parser::Parser}; -use crate::{ - protocol::{Options, Uri}, - tex::Resolver, -}; -use std::path::Path; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct OpenParams<'a> { - pub text: &'a str, - pub uri: &'a Uri, - pub resolver: &'a Resolver, - pub options: &'a Options, - pub current_dir: &'a Path, -} - -pub fn open(params: OpenParams) -> SymbolTable { - let OpenParams { - text, - uri, - resolver, - options, - current_dir, - } = params; - - let lexer = Lexer::new(text); - let parser = Parser::new(lexer); - let tree = parser.parse(); - - let params = SymbolTableParams { - tree, - uri, - resolver, - options, - current_dir, - }; - SymbolTable::analyze(params) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - protocol::{Options, Range, RangeExt, Uri}, - syntax::{generic_ast::AstNodeIndex, text::SyntaxNode}, - tex::Resolver, - }; - use indoc::indoc; - use std::env; - - fn open_simple(text: &str) -> SymbolTable { - open(OpenParams { - text: text.trim(), - uri: &Uri::parse("http://www.foo.com/bar.tex").unwrap(), - resolver: &Resolver::default(), - options: &Options::default(), - current_dir: &env::current_dir().unwrap(), - }) - } - - #[derive(Debug, Default)] - struct TreeTraversal { - nodes: Vec<AstNodeIndex>, - } - - impl Visitor for TreeTraversal { - fn visit(&mut self, tree: &Tree, node: AstNodeIndex) { - self.nodes.push(node); - tree.walk(self, node); - } - } - - mod range { - use super::*; - - fn verify(expected_ranges: Vec<Range>, text: &str) { - let table = open_simple(text); - - let mut traversal = TreeTraversal::default(); - traversal.visit(&table.tree, table.tree.root); - let actual_ranges: Vec<_> = traversal - .nodes - .into_iter() - .map(|node| table[node].range()) - .collect(); - assert_eq!(actual_ranges, expected_ranges); - } - - #[test] - fn command() { - verify( - vec![ - Range::new_simple(0, 0, 2, 14), - Range::new_simple(0, 0, 0, 23), - Range::new_simple(0, 14, 0, 23), - Range::new_simple(0, 15, 0, 22), - Range::new_simple(1, 0, 1, 20), - Range::new_simple(1, 11, 1, 20), - Range::new_simple(1, 12, 1, 19), - Range::new_simple(2, 0, 2, 14), - Range::new_simple(2, 4, 2, 9), - Range::new_simple(2, 5, 2, 8), - Range::new_simple(2, 9, 2, 14), - Range::new_simple(2, 10, 2, 13), - ], - indoc!( - r#" - \documentclass{article} - \usepackage{amsmath} - \foo[bar]{baz} - "# - ), - ); - } - - #[test] - fn text() { - verify( - vec![ - Range::new_simple(0, 0, 0, 11), - Range::new_simple(0, 0, 0, 11), - ], - indoc!( - r#" - foo bar baz - "# - ), - ); - } - - #[test] - fn text_bracket() { - verify( - vec![Range::new_simple(0, 0, 0, 5), Range::new_simple(0, 0, 0, 5)], - indoc!( - r#" - ]foo[ - "# - ), - ); - } - - #[test] - fn group() { - verify( - vec![ - Range::new_simple(0, 0, 0, 15), - Range::new_simple(0, 0, 0, 15), - Range::new_simple(0, 2, 0, 5), - Range::new_simple(0, 6, 0, 13), - Range::new_simple(0, 8, 0, 11), - ], - indoc!( - r#" - { foo { bar } } - "# - ), - ); - } - - #[test] - fn group_incomplete() { - verify( - vec![Range::new_simple(0, 1, 0, 2), Range::new_simple(0, 1, 0, 2)], - indoc!( - r#" - }{ - "# - ), - ); - } - - #[test] - fn math() { - verify( - vec![ - Range::new_simple(0, 0, 0, 9), - Range::new_simple(0, 0, 0, 1), - Range::new_simple(0, 2, 0, 7), - Range::new_simple(0, 8, 0, 9), - ], - indoc!( - r#" - $ x = 1 $ - "# - ), - ); - } - - #[test] - fn comma() { - verify( - vec![ - Range::new_simple(0, 0, 0, 8), - Range::new_simple(0, 0, 0, 3), - Range::new_simple(0, 3, 0, 4), - Range::new_simple(0, 5, 0, 8), - ], - indoc!( - r#" - foo, bar - "# - ), - ); - } - } - - mod command { - use super::*; - - fn verify(expected_names: Vec<&str>, text: &str) { - let table = open(OpenParams { - text, - uri: &Uri::parse("http://www.foo.com/bar.tex").unwrap(), - resolver: &Resolver::default(), - options: &Options::default(), - current_dir: &env::current_dir().unwrap(), - }); - - let actual_names: Vec<_> = table - .commands - .iter() - .map(|node| table.tree.as_command(*node).unwrap().name.text()) - .collect(); - - assert_eq!(actual_names, expected_names); - } - - #[test] - fn basic() { - verify( - vec!["\\documentclass", "\\usepackage", "\\begin", "\\end"], - indoc!( - r#" - \documentclass{article} - \usepackage{amsmath} - \begin{document} - Hello World - \end{document} - "# - ), - ); - } - - #[test] - fn star() { - verify( - vec!["\\section*", "\\subsection*"], - indoc!( - r#" - \section*{Foo} - \subsection**{Bar} - "# - ), - ); - } - - #[test] - fn at() { - verify(vec!["\\foo@bar"], indoc!(r#"\foo@bar"#)); - } - - #[test] - fn escape() { - verify(vec!["\\%"], indoc!(r#"\%foo"#)) - } - } - - mod environment { - use super::*; - - fn verify(expected_names: Vec<(&str, &str)>, text: &str) { - let table = open_simple(text); - let actual_names: Vec<_> = table - .environments - .iter() - .map(|env| { - ( - env.left - .name(&table.tree) - .map(Token::text) - .unwrap_or_default(), - env.right - .name(&table.tree) - .map(Token::text) - .unwrap_or_default(), - ) - }) - .collect(); - - assert_eq!(actual_names, expected_names); - } - - #[test] - fn nested() { - verify( - vec![("b", "b"), ("a", "a")], - indoc!( - r#" - \begin{a} - \begin{b} - \end{b} - \end{a} - "# - ), - ); - } - - #[test] - fn empty_name() { - verify( - vec![("a", ""), ("", "b")], - indoc!( - r#" - \begin{a} - \end{} - \begin{} - \end{b} - "# - ), - ); - } - - #[test] - fn incomplete() { - verify( - Vec::new(), - indoc!( - r#" - \end{a} - \begin{a} - "# - ), - ); - } - - #[test] - fn standalone_true() { - let table = open_simple(r#"\begin{document}\end{document}"#); - assert!(table.is_standalone); - } - - #[test] - fn standalone_false() { - let table = open_simple(r#"\begin{doc}\end{doc}"#); - assert!(!table.is_standalone); - } - } - - mod include { - use super::*; - - fn verify(expected_targets: Vec<Vec<&str>>, resolver: Resolver, text: &str) { - let table = open(OpenParams { - text, - uri: &Uri::parse("http://www.foo.com/dir1/dir2/foo.tex").unwrap(), - resolver: &resolver, - options: &Options::default(), - current_dir: &env::current_dir().unwrap(), - }); - - assert_eq!(table.includes.len(), 1); - let include = &table.includes[0]; - let actual_targets: Vec<Vec<&str>> = include - .all_targets - .iter() - .map(|targets| targets.iter().map(|target| target.as_str()).collect()) - .collect(); - - assert_eq!(actual_targets, expected_targets); - } - - #[test] - fn same_directory() { - verify( - vec![vec![ - "http://www.foo.com/dir1/dir2/bar", - "http://www.foo.com/dir1/dir2/bar.tex", - ]], - Resolver::default(), - indoc!(r#"\include{bar}"#), - ); - } - - #[test] - fn two_paths() { - verify( - vec![ - vec![ - "http://www.foo.com/dir1/dir2/bar.tex", - "http://www.foo.com/dir1/dir2/bar.tex.tex", - ], - vec![ - "http://www.foo.com/dir1/dir2/baz.tex", - "http://www.foo.com/dir1/dir2/baz.tex.tex", - ], - ], - Resolver::default(), - indoc!(r#"\input{bar.tex, ./baz.tex}"#), - ); - } - - #[test] - fn sub_directory() { - verify( - vec![vec![ - "http://www.foo.com/dir1/dir2/dir3/bar", - "http://www.foo.com/dir1/dir2/dir3/bar.tex", - ]], - Resolver::default(), - indoc!(r#"\include{dir3/bar}"#), - ); - } - - #[test] - fn parent_directory() { - verify( - vec![vec![ - "http://www.foo.com/dir1/bar", - "http://www.foo.com/dir1/bar.tex", - ]], - Resolver::default(), - indoc!(r#"\include{../bar}"#), - ); - } - - #[test] - fn distro_file() { - let mut resolver = Resolver::default(); - let path = env::current_dir().unwrap().join("biblatex-examples.bib"); - resolver - .files_by_name - .insert("biblatex-examples.bib".into(), path.clone()); - verify( - vec![vec![ - "http://www.foo.com/dir1/dir2/biblatex-examples.bib", - "http://www.foo.com/dir1/dir2/biblatex-examples.bib.bib", - Uri::from_file_path(&path).unwrap().as_str(), - ]], - resolver, - indoc!(r#"\addbibresource{biblatex-examples.bib}"#), - ); - } - - #[test] - fn component() { - let table = open(OpenParams { - text: indoc!( - r#" - \documentclass{article} - \usepackage{amsmath} - \usepackage{geometry, lipsum} - "# - ), - uri: &Uri::parse("http://www.foo.com/bar.tex").unwrap(), - resolver: &Resolver::default(), - options: &Options::default(), - current_dir: &env::current_dir().unwrap(), - }); - assert_eq!( - table.components, - vec!["article.cls", "amsmath.sty", "geometry.sty", "lipsum.sty"] - ); - } - } - - #[test] - fn citation() { - let table = open_simple(indoc!( - r#" - \cite{key1} - \cite{key2, key3} - \nocite{*} - "# - )); - - let expected_keys = vec![vec!["key1"], vec!["key2", "key3"], vec!["*"]]; - - let actual_keys: Vec<Vec<&str>> = table - .citations - .iter() - .map(|cit| cit.keys(&table.tree).into_iter().map(Token::text).collect()) - .collect(); - - assert_eq!(actual_keys, expected_keys); - } - - #[test] - fn command_definition() { - let table = open_simple(indoc!( - r#" - \newcommand{\foo}{Foo} - \newcommand[2]{\bar}{Bar} - \renewcommand{\baz}{Baz} - \qux - "# - )); - - let expected_cmds = vec!["\\foo", "\\bar", "\\baz"]; - - let actual_cmds: Vec<&str> = table - .command_definitions - .iter() - .map(|def| def.definition_name(&table.tree)) - .collect(); - - assert_eq!(actual_cmds, expected_cmds); - } - - #[test] - fn glossary_entry() { - let table = open_simple(indoc!( - r#" - \newglossaryentry{foo}{...} - \newacronym{bar}{...} - "# - )); - - let expected_entries = vec!["foo", "bar"]; - - let actual_entries: Vec<&str> = table - .glossary_entries - .iter() - .map(|entry| entry.label(&table.tree).text()) - .collect(); - - assert_eq!(actual_entries, expected_entries); - } - - #[test] - fn equation() { - let table = open_simple(indoc!( - r#" - \[ - e^{i \pi} + 1 = 0 - \] - \] \[ - "# - )); - - assert_eq!(table.equations.len(), 1); - } - - #[test] - fn inline() { - let table = open_simple(indoc!( - r#" - $ x $ - $ - "# - )); - - assert_eq!(table.inlines.len(), 1); - } - - #[test] - fn math_operator() { - let table = open_simple(indoc!( - r#" - \DeclareMathOperator{\foo}{foo} - "# - )); - - assert_eq!(table.math_operators.len(), 1); - assert_eq!( - table.math_operators[0].definition_name(&table.tree), - "\\foo" - ); - } - - #[test] - fn theorem_definition() { - let table = open_simple(indoc!( - r#" - \newtheorem{lemma}{Lemma} - "# - )); - - assert_eq!(table.theorem_definitions.len(), 1); - assert_eq!( - table.theorem_definitions[0].name(&table.tree).text(), - "lemma" - ); - } - - #[test] - fn section() { - let table = open_simple(indoc!( - r#" - \section{Introduction to \LaTeX} - \subsection*{Foo - "# - )); - assert_eq!(table.sections.len(), 2); - assert_eq!( - table.sections[0].print(&table.tree).unwrap(), - "Introduction to \\LaTeX" - ); - assert_eq!(table.sections[1].print(&table.tree), None); - } - - #[test] - fn label() { - let table = open_simple(indoc!( - r#" - \label{foo} - \ref{bar, baz} - "# - )); - - let expected_names = vec![vec!["foo"], vec!["bar", "baz"]]; - - let actual_names: Vec<Vec<&str>> = table - .labels - .iter() - .map(|label| { - label - .names(&table.tree) - .into_iter() - .map(Token::text) - .collect() - }) - .collect(); - - assert_eq!(actual_names, expected_names); - } - - #[test] - fn label_numbering() { - let table = open_simple(indoc!( - r#" - \newlabel{foo}{{1}{1}} - "# - )); - - assert_eq!(table.label_numberings.len(), 1); - assert_eq!(table.label_numberings[0].name(&table.tree).text(), "foo"); - assert_eq!(table.label_numberings[0].number, "1"); - } - - #[test] - fn caption() { - let table = open_simple(indoc!( - r#" - \caption{Foo \LaTeX Bar} - "# - )); - - assert_eq!(table.captions.len(), 1); - assert_eq!( - table.captions[0].print(&table.tree).unwrap(), - "Foo \\LaTeX Bar" - ); - } - - #[test] - fn item_without_name() { - let table = open_simple(indoc!( - r#" - \item - "# - )); - - assert_eq!(table.items.len(), 1); - assert_eq!(table.items[0].name(&table.tree), None); - } - - #[test] - fn item_with_name() { - let table = open_simple(indoc!( - r#" - \item[foo bar] - "# - )); - - assert_eq!(table.items.len(), 1); - assert_eq!(table.items[0].name(&table.tree).unwrap(), "foo bar"); - } -} diff --git a/support/texlab/src/syntax/latex/parser.rs b/support/texlab/src/syntax/latex/parser.rs index 4ace4fbcd6..4333235ba5 100644 --- a/support/texlab/src/syntax/latex/parser.rs +++ b/support/texlab/src/syntax/latex/parser.rs @@ -1,186 +1,1709 @@ -use super::ast::*; -use crate::{ - protocol::{Range, RangeExt}, - syntax::{ - generic_ast::{Ast, AstNodeIndex}, - text::SyntaxNode, - }, +use cstree::GreenNodeBuilder; + +use super::{ + lexer::Lexer, + SyntaxKind::{self, *}, + SyntaxNode, }; -use std::iter::Peekable; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -enum Scope { - Root, - Group, - Options, +#[derive(Clone)] +pub struct Parse { + pub root: SyntaxNode, +} + +#[derive(Debug, Clone, Copy)] +struct ParserContext { + allow_environment: bool, + allow_comma: bool, +} + +impl Default for ParserContext { + fn default() -> Self { + Self { + allow_environment: true, + allow_comma: true, + } + } } #[derive(Debug)] -pub struct Parser<I: Iterator<Item = Token>> { - tree: Ast<Node>, - tokens: Peekable<I>, +struct Parser<'a> { + lexer: Lexer<'a>, + builder: GreenNodeBuilder<'static, 'static>, } -impl<I: Iterator<Item = Token>> Parser<I> { - pub fn new(tokens: I) -> Self { +impl<'a> Parser<'a> { + pub fn new(text: &'a str) -> Self { Self { - tree: Ast::new(), - tokens: tokens.peekable(), + lexer: Lexer::new(text), + builder: GreenNodeBuilder::new(), } } - pub fn parse(mut self) -> Tree { - let children = self.content(Scope::Root); + fn eat(&mut self) { + let (kind, text) = self.lexer.eat().unwrap(); + self.builder.token(kind.into(), text); + } - let range = if children.is_empty() { - Range::new_simple(0, 0, 0, 0) + fn peek(&self) -> Option<SyntaxKind> { + self.lexer.peek() + } + + fn expect(&mut self, kind: SyntaxKind) { + if self.peek() == Some(kind) { + self.eat(); + self.trivia(); } else { - let start = self.tree[children[0]].start(); - let end = self.tree[children[children.len() - 1]].end(); - Range::new(start, end) - }; + self.builder.token(MISSING.into(), ""); + } + } - let root = self.tree.add_node(Node::Root(Root { range })); - self.connect(root, &children); - Tree { - inner: self.tree, - root, + fn expect2(&mut self, kind1: SyntaxKind, kind2: SyntaxKind) { + if self + .peek() + .filter(|&kind| kind == kind1 || kind == kind2) + .is_some() + { + self.eat(); + self.trivia(); + } else { + self.builder.token(MISSING.into(), ""); } } - fn content(&mut self, scope: Scope) -> Vec<AstNodeIndex> { - let mut children = Vec::new(); - while let Some(ref token) = self.tokens.peek() { - match token.kind { - TokenKind::Word | TokenKind::BeginOptions => { - children.push(self.text(scope)); - } - TokenKind::Command => { - children.push(self.command()); - } - TokenKind::Comma => { - children.push(self.comma()); - } - TokenKind::Math => { - children.push(self.math()); - } - TokenKind::BeginGroup => { - children.push(self.group(GroupKind::Group)); - } - TokenKind::EndGroup => { - if scope == Scope::Root { - self.tokens.next(); - } else { - return children; - } - } - TokenKind::EndOptions => { - if scope == Scope::Options { - return children; + fn trivia(&mut self) { + while self + .peek() + .filter(|&kind| matches!(kind, WHITESPACE | COMMENT)) + .is_some() + { + self.eat(); + } + } + + pub fn parse(mut self) -> Parse { + self.builder.start_node(ROOT.into()); + self.preamble(); + while self.peek().is_some() { + self.content(ParserContext::default()); + } + self.builder.finish_node(); + let (green_node, interner) = self.builder.finish(); + Parse { + root: SyntaxNode::new_root_with_resolver(green_node, interner.unwrap()), + } + } + + fn content(&mut self, context: ParserContext) { + match self.peek().unwrap() { + WHITESPACE | COMMENT => self.eat(), + L_CURLY if context.allow_environment => self.curly_group(), + L_CURLY => self.curly_group_without_environments(), + L_BRACK | L_PAREN => self.mixed_group(), + R_CURLY | R_BRACK | R_PAREN => { + self.builder.start_node(ERROR.into()); + self.eat(); + self.builder.finish_node(); + } + PARAMETER => self.eat(), + WORD | COMMA => self.text(context), + EQUALITY_SIGN => self.eat(), + DOLLAR => self.formula(), + GENERIC_COMMAND_NAME => self.generic_command(), + BEGIN_ENVIRONMENT_NAME if context.allow_environment => self.environment(), + BEGIN_ENVIRONMENT_NAME => self.generic_command(), + END_ENVIRONMENT_NAME => self.generic_command(), + BEGIN_EQUATION_NAME => self.equation(), + END_EQUATION_NAME => self.generic_command(), + MISSING | ERROR => self.eat(), + PART_NAME => self.part(), + CHAPTER_NAME => self.chapter(), + SECTION_NAME => self.section(), + SUBSECTION_NAME => self.subsection(), + SUBSUBSECTION_NAME => self.subsubsection(), + PARAGRAPH_NAME => self.paragraph(), + SUBPARAGRAPH_NAME => self.subparagraph(), + ENUM_ITEM_NAME => self.enum_item(), + CAPTION_NAME => self.caption(), + CITATION_NAME => self.citation(), + PACKAGE_INCLUDE_NAME => self.package_include(), + CLASS_INCLUDE_NAME => self.class_include(), + LATEX_INCLUDE_NAME => self.latex_include(), + BIBLATEX_INCLUDE_NAME => self.biblatex_include(), + BIBTEX_INCLUDE_NAME => self.bibtex_include(), + GRAPHICS_INCLUDE_NAME => self.graphics_include(), + SVG_INCLUDE_NAME => self.svg_include(), + INKSCAPE_INCLUDE_NAME => self.inkscape_include(), + VERBATIM_INCLUDE_NAME => self.verbatim_include(), + IMPORT_NAME => self.import(), + LABEL_DEFINITION_NAME => self.label_definition(), + LABEL_REFERENCE_NAME => self.label_reference(), + LABEL_REFERENCE_RANGE_NAME => self.label_reference_range(), + LABEL_NUMBER_NAME => self.label_number(), + COMMAND_DEFINITION_NAME => self.command_definition(), + MATH_OPERATOR_NAME => self.math_operator(), + GLOSSARY_ENTRY_DEFINITION_NAME => self.glossary_entry_definition(), + GLOSSARY_ENTRY_REFERENCE_NAME => self.glossary_entry_reference(), + ACRONYM_DEFINITION_NAME => self.acronym_definition(), + ACRONYM_DECLARATION_NAME => self.acronym_declaration(), + ACRONYM_REFERENCE_NAME => self.acronym_reference(), + THEOREM_DEFINITION_NAME => self.theorem_definition(), + COLOR_REFERENCE_NAME => self.color_reference(), + COLOR_DEFINITION_NAME => self.color_definition(), + COLOR_SET_DEFINITION_NAME => self.color_set_definition(), + TIKZ_LIBRARY_IMPORT_NAME => self.tikz_library_import(), + ENVIRONMENT_DEFINIITION_NAME => self.environment_definition(), + _ => unreachable!(), + } + } + + fn text(&mut self, context: ParserContext) { + self.builder.start_node(TEXT.into()); + self.eat(); + while self + .peek() + .filter(|&kind| { + matches!(kind, WHITESPACE | COMMENT | WORD | COMMA) + && (context.allow_comma || kind != COMMA) + }) + .is_some() + { + self.eat(); + } + self.builder.finish_node(); + } + + fn group_with_token( + &mut self, + node_kind: SyntaxKind, + content_kind: SyntaxKind, + right_kind: SyntaxKind, + ) { + self.builder.start_node(node_kind.into()); + self.eat(); + self.trivia(); + self.expect(content_kind); + self.expect(right_kind); + self.builder.finish_node(); + } + + fn curly_group(&mut self) { + self.builder.start_node(CURLY_GROUP.into()); + self.eat(); + while self + .peek() + .filter(|&kind| !matches!(kind, R_CURLY | END_ENVIRONMENT_NAME)) + .is_some() + { + self.content(ParserContext::default()); + } + self.expect(R_CURLY); + self.builder.finish_node(); + } + + fn curly_group_without_environments(&mut self) { + self.builder.start_node(CURLY_GROUP.into()); + self.eat(); + while self + .peek() + .filter(|&kind| !matches!(kind, R_CURLY)) + .is_some() + { + self.content(ParserContext { + allow_environment: false, + allow_comma: true, + }); + } + self.expect(R_CURLY); + self.builder.finish_node(); + } + + fn curly_group_word(&mut self) { + self.group_with_token(CURLY_GROUP_WORD, WORD, R_CURLY); + } + + fn curly_group_word_list(&mut self) { + self.builder.start_node(CURLY_GROUP_WORD_LIST.into()); + self.eat(); + + while self + .peek() + .filter(|&kind| matches!(kind, WHITESPACE | COMMENT | WORD | COMMA)) + .is_some() + { + self.eat(); + } + + self.expect(R_CURLY); + self.builder.finish_node(); + } + + fn curly_group_command(&mut self) { + self.group_with_token(CURLY_GROUP_COMMAND, GENERIC_COMMAND_NAME, R_CURLY); + } + + fn brack_group(&mut self) { + self.builder.start_node(BRACK_GROUP.into()); + self.eat(); + while self + .peek() + .filter(|&kind| { + !matches!( + kind, + R_CURLY + | R_BRACK + | PART_NAME + | CHAPTER_NAME + | SECTION_NAME + | SUBSECTION_NAME + | PARAGRAPH_NAME + | SUBPARAGRAPH_NAME + | ENUM_ITEM_NAME + | END_ENVIRONMENT_NAME + ) + }) + .is_some() + { + self.content(ParserContext::default()); + } + self.expect(R_BRACK); + self.builder.finish_node(); + } + + fn brack_group_word(&mut self) { + self.group_with_token(BRACK_GROUP_WORD, WORD, R_BRACK); + } + + // fn paren_group(&mut self) { + // self.builder.start_node(PAREN_GROUP.into()); + // self.eat(); + // while self + // .peek() + // .filter(|&kind| { + // !matches!( + // kind, + // R_CURLY + // | R_BRACK + // | R_PAREN + // | PART_NAME + // | CHAPTER_NAME + // | SECTION_NAME + // | SUBSECTION_NAME + // | PARAGRAPH_NAME + // | SUBPARAGRAPH_NAME + // | ENUM_ITEM_NAME + // | END_ENVIRONMENT_NAME + // ) + // }) + // .is_some() + // { + // self.content(); + // } + // self.expect(R_PAREN); + // self.builder.finish_node(); + // } + + fn mixed_group(&mut self) { + self.builder.start_node(MIXED_GROUP.into()); + self.eat(); + self.trivia(); + while self + .peek() + .filter(|&kind| { + !matches!( + kind, + R_CURLY + | R_BRACK + | R_PAREN + | PART_NAME + | CHAPTER_NAME + | SECTION_NAME + | SUBSECTION_NAME + | PARAGRAPH_NAME + | SUBPARAGRAPH_NAME + | ENUM_ITEM_NAME + | END_ENVIRONMENT_NAME + ) + }) + .is_some() + { + self.content(ParserContext::default()); + } + self.expect2(R_BRACK, R_PAREN); + self.builder.finish_node(); + } + + fn key(&mut self) { + self.builder.start_node(KEY.into()); + self.eat(); + while self + .peek() + .filter(|&kind| matches!(kind, WHITESPACE | COMMENT | WORD)) + .is_some() + { + self.eat(); + } + self.builder.finish_node(); + } + + fn value(&mut self) { + self.builder.start_node(VALUE.into()); + self.content(ParserContext { + allow_environment: true, + allow_comma: false, + }); + self.builder.finish_node(); + } + + fn key_value_pair(&mut self) { + self.builder.start_node(KEY_VALUE_PAIR.into()); + self.key(); + if self.peek() == Some(EQUALITY_SIGN) { + self.eat(); + self.trivia(); + if self + .peek() + .filter(|&kind| { + !matches!( + kind, + END_ENVIRONMENT_NAME | R_CURLY | R_BRACK | R_PAREN | COMMA + ) + }) + .is_some() + { + self.value(); + } else { + self.builder.token(MISSING.into(), ""); + } + } + + self.builder.finish_node(); + } + + fn key_value_body(&mut self) { + self.builder.start_node(KEY_VALUE_BODY.into()); + while let Some(kind) = self.peek() { + match kind { + WHITESPACE | COMMENT => self.eat(), + WORD => { + self.key_value_pair(); + if self.peek() == Some(COMMA) { + self.eat(); } else { - children.push(self.text(scope)); + break; } } + _ => break, } } - children - } - - fn group(&mut self, kind: GroupKind) -> AstNodeIndex { - let left = self.tokens.next().unwrap(); - let scope = match kind { - GroupKind::Group => Scope::Group, - GroupKind::Options => Scope::Options, - }; - - let children = self.content(scope); - let right_kind = match kind { - GroupKind::Group => TokenKind::EndGroup, - GroupKind::Options => TokenKind::EndOptions, - }; - - let right = if self.next_of_kind(right_kind) { - self.tokens.next() - } else { - None - }; - - let end = right - .as_ref() - .map(SyntaxNode::end) - .or_else(|| children.last().map(|child| self.tree[*child].end())) - .unwrap_or_else(|| left.end()); - let range = Range::new(left.start(), end); - - let node = self.tree.add_node(Node::Group(Group { - range, - left, - kind, - right, - })); - self.connect(node, &children); - node - } - - fn command(&mut self) -> AstNodeIndex { - let name = self.tokens.next().unwrap(); - let mut children = Vec::new(); - while let Some(token) = self.tokens.peek() { - match token.kind { - TokenKind::BeginGroup => children.push(self.group(GroupKind::Group)), - TokenKind::BeginOptions => children.push(self.group(GroupKind::Options)), + self.builder.finish_node(); + } + + fn group_key_value(&mut self, node_kind: SyntaxKind, right_kind: SyntaxKind) { + self.builder.start_node(node_kind.into()); + self.eat(); + self.trivia(); + self.key_value_body(); + self.expect(right_kind); + self.builder.finish_node(); + } + + fn curly_group_key_value(&mut self) { + self.group_key_value(CURLY_GROUP_KEY_VALUE, R_CURLY); + } + + fn brack_group_key_value(&mut self) { + self.group_key_value(BRACK_GROUP_KEY_VALUE, R_BRACK); + } + + fn formula(&mut self) { + self.builder.start_node(FORMULA.into()); + self.eat(); + self.trivia(); + while self + .peek() + .filter(|&kind| !matches!(kind, R_CURLY | END_ENVIRONMENT_NAME | DOLLAR)) + .is_some() + { + self.content(ParserContext::default()); + } + self.expect(DOLLAR); + self.builder.finish_node(); + } + + fn generic_command(&mut self) { + self.builder.start_node(GENERIC_COMMAND.into()); + self.eat(); + while let Some(kind) = self.peek() { + match kind { + WHITESPACE | COMMENT => self.eat(), + L_CURLY => self.curly_group(), + L_BRACK | L_PAREN => self.mixed_group(), _ => break, } } + self.builder.finish_node(); + } + + fn equation(&mut self) { + self.builder.start_node(EQUATION.into()); + self.eat(); + while self + .peek() + .filter(|&kind| !matches!(kind, END_ENVIRONMENT_NAME | R_CURLY | END_EQUATION_NAME)) + .is_some() + { + self.content(ParserContext::default()); + } + self.expect(END_EQUATION_NAME); + self.builder.finish_node(); + } - let end = children - .last() - .map(|child| self.tree[*child].end()) - .unwrap_or_else(|| name.end()); - let range = Range::new(name.start(), end); + fn begin(&mut self) { + self.builder.start_node(BEGIN.into()); + self.eat(); + self.trivia(); - let node = self.tree.add_node(Node::Command(Command { range, name })); - self.connect(node, &children); - node + if self.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.peek() == Some(L_BRACK) { + self.brack_group(); + } + self.builder.finish_node(); } - fn text(&mut self, scope: Scope) -> AstNodeIndex { - let mut words = Vec::new(); - while let Some(ref token) = self.tokens.peek() { - let kind = token.kind; - let opts = kind == TokenKind::EndOptions && scope != Scope::Options; - if kind == TokenKind::Word || kind == TokenKind::BeginOptions || opts { - words.push(self.tokens.next().unwrap()); - } else { - break; - } + fn end(&mut self) { + self.builder.start_node(END.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); } - let range = Range::new(words[0].start(), words[words.len() - 1].end()); - self.tree.add_node(Node::Text(Text { range, words })) + + self.builder.finish_node(); } - fn comma(&mut self) -> AstNodeIndex { - let token = self.tokens.next().unwrap(); - let range = token.range(); - self.tree.add_node(Node::Comma(Comma { range, token })) + fn environment(&mut self) { + self.builder.start_node(ENVIRONMENT.into()); + self.begin(); + + while self + .peek() + .filter(|&kind| kind != END_ENVIRONMENT_NAME) + .is_some() + { + self.content(ParserContext::default()); + } + + if self.peek() == Some(END_ENVIRONMENT_NAME) { + self.end(); + } else { + self.builder.token(MISSING.into(), ""); + } + self.builder.finish_node(); } - fn math(&mut self) -> AstNodeIndex { - let token = self.tokens.next().unwrap(); - let range = token.range(); - self.tree.add_node(Node::Math(Math { range, token })) + fn preamble(&mut self) { + self.builder.start_node(PREAMBLE.into()); + while self + .peek() + .filter(|&kind| kind != END_ENVIRONMENT_NAME) + .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); } - fn connect(&mut self, parent: AstNodeIndex, children: &[AstNodeIndex]) { - for child in children { - self.tree.add_edge(parent, *child); + fn part(&mut self) { + self.builder.start_node(PART.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); } + + while self + .peek() + .filter(|&kind| !matches!(kind, END_ENVIRONMENT_NAME | R_CURLY | PART_NAME)) + .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); } - fn next_of_kind(&mut self, kind: TokenKind) -> bool { - self.tokens + fn chapter(&mut self) { + self.builder.start_node(CHAPTER.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + while self .peek() - .filter(|token| token.kind == kind) + .filter(|&kind| { + !matches!( + kind, + END_ENVIRONMENT_NAME | R_CURLY | PART_NAME | CHAPTER_NAME + ) + }) .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); + } + + fn section(&mut self) { + self.builder.start_node(SECTION.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + while self + .peek() + .filter(|&kind| { + !matches!( + kind, + END_ENVIRONMENT_NAME | R_CURLY | PART_NAME | CHAPTER_NAME | SECTION_NAME + ) + }) + .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); + } + + fn subsection(&mut self) { + self.builder.start_node(SUBSECTION.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + while self + .peek() + .filter(|&kind| { + !matches!( + kind, + END_ENVIRONMENT_NAME + | R_CURLY + | PART_NAME + | CHAPTER_NAME + | SECTION_NAME + | SUBSECTION_NAME + ) + }) + .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); + } + + fn subsubsection(&mut self) { + self.builder.start_node(SUBSUBSECTION.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + while self + .peek() + .filter(|&kind| { + !matches!( + kind, + END_ENVIRONMENT_NAME + | R_CURLY + | PART_NAME + | CHAPTER_NAME + | SECTION_NAME + | SUBSECTION_NAME + | SUBSUBSECTION_NAME + ) + }) + .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); + } + + fn paragraph(&mut self) { + self.builder.start_node(PARAGRAPH.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + while self + .peek() + .filter(|&kind| { + !matches!( + kind, + END_ENVIRONMENT_NAME + | R_CURLY + | PART_NAME + | CHAPTER_NAME + | SECTION_NAME + | SUBSECTION_NAME + | SUBSUBSECTION_NAME + | PARAGRAPH_NAME + ) + }) + .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); + } + + fn subparagraph(&mut self) { + self.builder.start_node(SUBPARAGRAPH.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + while self + .peek() + .filter(|&kind| { + !matches!( + kind, + END_ENVIRONMENT_NAME + | R_CURLY + | PART_NAME + | CHAPTER_NAME + | SECTION_NAME + | SUBSECTION_NAME + | SUBSUBSECTION_NAME + | PARAGRAPH_NAME + | SUBPARAGRAPH_NAME + ) + }) + .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); + } + + fn enum_item(&mut self) { + self.builder.start_node(ENUM_ITEM.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_BRACK) { + self.brack_group(); + } + + while self + .peek() + .filter(|&kind| { + !matches!( + kind, + END_ENVIRONMENT_NAME + | R_CURLY + | PART_NAME + | CHAPTER_NAME + | SECTION_NAME + | SUBSECTION_NAME + | SUBSUBSECTION_NAME + | PARAGRAPH_NAME + | SUBPARAGRAPH_NAME + | ENUM_ITEM_NAME + ) + }) + .is_some() + { + self.content(ParserContext::default()); + } + self.builder.finish_node(); + } + + fn caption(&mut self) { + self.builder.start_node(CAPTION.into()); + self.eat(); + self.trivia(); + + if self.peek() == Some(L_BRACK) { + self.brack_group(); + } + + if self.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn citation(&mut self) { + self.builder.start_node(CITATION.into()); + self.eat(); + self.trivia(); + for _ in 0..2 { + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group(); + } + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word_list(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn generic_include(&mut self, kind: SyntaxKind, options: bool) { + self.builder.start_node(kind.into()); + self.eat(); + self.trivia(); + if options && self.lexer.peek() == Some(L_BRACK) { + self.brack_group_key_value(); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word_list(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn package_include(&mut self) { + self.generic_include(PACKAGE_INCLUDE, true); + } + + fn class_include(&mut self) { + self.generic_include(CLASS_INCLUDE, true); + } + + fn latex_include(&mut self) { + self.generic_include(LATEX_INCLUDE, false); + } + + fn biblatex_include(&mut self) { + self.generic_include(BIBLATEX_INCLUDE, true); + } + + fn bibtex_include(&mut self) { + self.generic_include(BIBTEX_INCLUDE, false); + } + + fn graphics_include(&mut self) { + self.generic_include(GRAPHICS_INCLUDE, true); + } + + fn svg_include(&mut self) { + self.generic_include(SVG_INCLUDE, true); + } + + fn inkscape_include(&mut self) { + self.generic_include(INKSCAPE_INCLUDE, true); + } + + fn verbatim_include(&mut self) { + self.generic_include(VERBATIM_INCLUDE, false); + } + + fn import(&mut self) { + self.builder.start_node(IMPORT.into()); + self.eat(); + self.trivia(); + + for _ in 0..2 { + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + } + + self.builder.finish_node(); + } + + fn label_definition(&mut self) { + self.builder.start_node(LABEL_DEFINITION.into()); + self.eat(); + self.trivia(); + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + self.builder.finish_node(); + } + + fn label_reference(&mut self) { + self.builder.start_node(LABEL_REFERENCE.into()); + self.eat(); + self.trivia(); + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word_list(); + } else { + self.builder.token(MISSING.into(), ""); + } + self.builder.finish_node(); + } + + fn label_reference_range(&mut self) { + self.builder.start_node(LABEL_REFERENCE_RANGE.into()); + self.eat(); + self.trivia(); + + for _ in 0..2 { + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + } + + self.builder.finish_node(); + } + + fn label_number(&mut self) { + self.builder.start_node(LABEL_NUMBER.into()); + self.eat(); + self.trivia(); + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group(); + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn command_definition(&mut self) { + self.builder.start_node(COMMAND_DEFINITION.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_command(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group_word(); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn math_operator(&mut self) { + self.builder.start_node(MATH_OPERATOR.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_command(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn glossary_entry_definition(&mut self) { + self.builder.start_node(GLOSSARY_ENTRY_DEFINITION.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_key_value(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn glossary_entry_reference(&mut self) { + self.builder.start_node(GLOSSARY_ENTRY_REFERENCE.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group_key_value(); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn acronym_definition(&mut self) { + self.builder.start_node(ACRONYM_DEFINITION.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group_key_value(); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + for _ in 0..2 { + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + } + + self.builder.finish_node(); + } + + fn acronym_declaration(&mut self) { + self.builder.start_node(ACRONYM_DECLARATION.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_key_value(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn acronym_reference(&mut self) { + self.builder.start_node(ACRONYM_REFERENCE.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group_key_value(); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn theorem_definition(&mut self) { + self.builder.start_node(THEOREM_DEFINITION.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group_word(); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group_word(); + } + + self.builder.finish_node(); + } + + fn color_reference(&mut self) { + self.builder.start_node(COLOR_REFERENCE.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn color_definition(&mut self) { + self.builder.start_node(COLOR_DEFINITION.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn color_set_definition(&mut self) { + self.builder.start_node(COLOR_SET_DEFINITION.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group_word(); + } + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word_list(); + } else { + self.builder.token(MISSING.into(), ""); + } + + for _ in 0..3 { + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + } + + self.builder.finish_node(); + } + + fn tikz_library_import(&mut self) { + self.builder.start_node(TIKZ_LIBRARY_IMPORT.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word_list(); + } else { + self.builder.token(MISSING.into(), ""); + } + + self.builder.finish_node(); + } + + fn environment_definition(&mut self) { + self.builder.start_node(ENVIRONMENT_DEFINITION.into()); + self.eat(); + self.trivia(); + + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_word(); + } else { + self.builder.token(MISSING.into(), ""); + } + + if self.lexer.peek() == Some(L_BRACK) { + self.brack_group_word(); + } + + for _ in 0..2 { + if self.lexer.peek() == Some(L_CURLY) { + self.curly_group_without_environments(); + } else { + self.builder.token(MISSING.into(), ""); + } + } + + self.builder.finish_node(); + } +} + +pub fn parse(text: &str) -> Parse { + Parser::new(text).parse() +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; + + use super::*; + + fn setup(text: &str) -> SyntaxNode { + parse(&text.trim().replace("\r", "")).root + } + + #[test] + fn test_empty() { + assert_debug_snapshot!(setup(r#""#)); + } + + #[test] + fn test_hello_world() { + assert_debug_snapshot!(setup(r#"Hello World!"#)); + } + + #[test] + fn test_generic_command_empty() { + assert_debug_snapshot!(setup(r#"\foo"#)); + } + + #[test] + fn test_generic_command_escape() { + assert_debug_snapshot!(setup(r#"\#"#)); + } + + #[test] + fn test_generic_command_args() { + assert_debug_snapshot!(setup(r#"\foo{bar}[qux]"#)); + } + + #[test] + fn test_inline() { + assert_debug_snapshot!(setup(r#"$x \in [0, \infty)$"#)); + } + + #[test] + fn test_inline_double_dollar() { + assert_debug_snapshot!(setup(r#"$$x \in [0, \infty)$$"#)); + } + + #[test] + fn test_brace_group_simple() { + assert_debug_snapshot!(setup(r#"{hello world}"#)); + } + + #[test] + fn test_brace_group_missing_end() { + assert_debug_snapshot!(setup(r#"{hello world"#)); + } + + #[test] + fn test_unmatched_braces() { + assert_debug_snapshot!(setup(r#"}{"#)); + } + + #[test] + fn test_unmatched_brackets() { + assert_debug_snapshot!(setup(r#"]["#)); + } + + #[test] + fn test_unmatched_brackets_with_group() { + assert_debug_snapshot!(setup(r#"{][}"#)); + } + + #[test] + fn test_escaped_brackets() { + assert_debug_snapshot!(setup(r#"{[}{]}"#)); + } + + #[test] + fn test_parameter() { + assert_debug_snapshot!(setup(r#"#1"#)); + } + + #[test] + fn test_parameter_error() { + assert_debug_snapshot!(setup(r#"#"#)); + } + + #[test] + fn test_environment_simple() { + assert_debug_snapshot!(setup(r#"\begin{foo} Hello World \end{bar}"#)); + } + + #[test] + fn test_environment_nested() { + assert_debug_snapshot!(setup(r#"\begin{foo} \begin{qux} \end{baz} \end{bar}"#)); + } + + #[test] + fn test_environment_nested_missing_braces() { + assert_debug_snapshot!(setup( + r#"\begin{foo \begin{qux Hello World \end{baz} \end{bar"# + )); + } + + #[test] + fn test_structure_siblings() { + assert_debug_snapshot!(setup(r#"\section{Foo} Foo \section{Bar} Bar"#)); + } + + #[test] + fn test_structure_nested() { + assert_debug_snapshot!(setup( + r#"\part{1}\chapter{2}\section{3}\subsection{4}\subsubsection{5}\paragraph{6}\subparagraph{7}"# + )); + } + + #[test] + fn test_structure_enum_item() { + assert_debug_snapshot!(setup( + r#"\begin{enumerate} \item 1 \item[2] 2 \item 3 \end{enumerate}"# + )); + } + + #[test] + fn test_structure_invalid_nesting() { + assert_debug_snapshot!(setup(r#"\section{Foo} \chapter{Bar}"#)); + } + + #[test] + fn test_equation() { + assert_debug_snapshot!(setup(r#"\[ foo bar \]"#)); + } + + #[test] + fn test_equation_missing_end() { + assert_debug_snapshot!(setup(r#"\begin{a} \[ foo bar \end{b}"#)); + } + + #[test] + fn test_equation_missing_begin() { + assert_debug_snapshot!(setup(r#"\begin{a} foo bar \] \end{b}"#)); + } + + #[test] + fn test_caption_minimal() { + assert_debug_snapshot!(setup(r#"\caption{Foo \Bar Baz}"#)); + } + + #[test] + fn test_caption_minimal_error() { + assert_debug_snapshot!(setup(r#"\caption{Foo \Bar Baz"#)); + } + + #[test] + fn test_caption() { + assert_debug_snapshot!(setup(r#"\caption[qux]{Foo \Bar Baz}"#)); + } + + #[test] + fn test_caption_error() { + assert_debug_snapshot!(setup(r#"\caption[qux]{Foo \Bar Baz"#)); + } + + #[test] + fn test_caption_figure() { + assert_debug_snapshot!(setup(r#"\begin{figure}\caption{Foo}\end{figure}"#)); + } + + #[test] + fn test_citation_empty() { + assert_debug_snapshot!(setup(r#"\cite{}"#)); + } + + #[test] + fn test_citation_simple() { + assert_debug_snapshot!(setup(r#"\cite{foo}"#)); + } + + #[test] + fn test_citation_multiple_keys() { + assert_debug_snapshot!(setup(r#"\cite{foo, bar}"#)); + } + + #[test] + fn test_citation_star() { + assert_debug_snapshot!(setup(r#"\nocite{*}"#)); + } + + #[test] + fn test_citation_prenote() { + assert_debug_snapshot!(setup(r#"\cite[foo]{bar}"#)); + } + + #[test] + fn test_citation_prenote_postnote() { + assert_debug_snapshot!(setup(r#"\cite[foo][bar]{baz}"#)); + } + + #[test] + fn test_citation_missing_brace() { + assert_debug_snapshot!(setup(r#"\cite{foo"#)); + } + + #[test] + fn test_citation_redundant_comma() { + assert_debug_snapshot!(setup(r#"\cite{,foo,}"#)); + } + + #[test] + fn test_package_include_empty() { + assert_debug_snapshot!(setup(r#"\usepackage{}"#)); + } + + #[test] + fn test_package_include_simple() { + assert_debug_snapshot!(setup(r#"\usepackage{amsmath}"#)); + } + + #[test] + fn test_package_include_multiple() { + assert_debug_snapshot!(setup(r#"\usepackage{amsmath, lipsum}"#)); + } + + #[test] + fn test_package_include_options() { + assert_debug_snapshot!(setup(r#"\usepackage[foo = bar, baz, qux]{amsmath}"#)); + } + + #[test] + fn test_class_include_empty() { + assert_debug_snapshot!(setup(r#"\documentclass{}"#)); + } + + #[test] + fn test_class_include_simple() { + assert_debug_snapshot!(setup(r#"\documentclass{article}"#)); + } + + #[test] + fn test_class_include_options() { + assert_debug_snapshot!(setup(r#"\documentclass[foo = bar, baz, qux]{article}"#)); + } + + #[test] + fn test_latex_include_simple() { + assert_debug_snapshot!(setup(r#"\include{foo/bar}"#)); + } + + #[test] + fn test_latex_input_simple() { + assert_debug_snapshot!(setup(r#"\input{foo/bar.tex}"#)); + } + + #[test] + fn test_biblatex_include_simple() { + assert_debug_snapshot!(setup(r#"\addbibresource{foo/bar.bib}"#)); + } + + #[test] + fn test_biblatex_include_options() { + assert_debug_snapshot!(setup(r#"\addbibresource[foo=bar, baz]{foo/bar.bib}"#)); + } + + #[test] + fn test_bibtex_include_simple() { + assert_debug_snapshot!(setup(r#"\bibliography{foo/bar}"#)); + } + + #[test] + fn test_graphics_include_simple() { + assert_debug_snapshot!(setup(r#"\includegraphics{foo/bar.pdf}"#)); + } + + #[test] + fn test_graphics_include_options() { + assert_debug_snapshot!(setup(r#"\includegraphics[scale=.5]{foo/bar.pdf}"#)); + } + + #[test] + fn test_svg_include_simple() { + assert_debug_snapshot!(setup(r#"\includesvg{foo/bar.svg}"#)); + } + + #[test] + fn test_svg_include_options() { + assert_debug_snapshot!(setup(r#"\includesvg[scale=.5]{foo/bar.svg}"#)); + } + + #[test] + fn test_inkscape_include_simple() { + assert_debug_snapshot!(setup(r#"\includesvg{foo/bar}"#)); + } + + #[test] + fn test_inkscape_include_options() { + assert_debug_snapshot!(setup(r#"\includesvg[scale=.5]{foo/bar}"#)); + } + + #[test] + fn test_verbatim_include_simple() { + assert_debug_snapshot!(setup(r#"\verbatiminput{foo/bar.txt}"#)); + } + + #[test] + fn test_import_simple() { + assert_debug_snapshot!(setup(r#"\import{foo}{bar}"#)); + } + + #[test] + fn test_import_incomplete() { + assert_debug_snapshot!(setup(r#"\import{foo"#)); + } + + #[test] + fn test_label_definition_simple() { + assert_debug_snapshot!(setup(r#"\label{foo}"#)); + } + + #[test] + fn test_label_reference_simple() { + assert_debug_snapshot!(setup(r#"\ref{foo}"#)); + } + + #[test] + fn test_label_reference_multiple() { + assert_debug_snapshot!(setup(r#"\ref{foo, bar}"#)); + } + + #[test] + fn test_equation_label_reference_simple() { + assert_debug_snapshot!(setup(r#"\eqref{foo}"#)); + } + + #[test] + fn test_label_reference_range_simple() { + assert_debug_snapshot!(setup(r#"\crefrange{foo}{bar}"#)); + } + + #[test] + fn test_label_reference_range_incomplete() { + assert_debug_snapshot!(setup(r#"\crefrange{foo}"#)); + } + + #[test] + fn test_label_reference_range_error() { + assert_debug_snapshot!(setup(r#"\crefrange{foo{bar}"#)); + } + + #[test] + fn test_label_number() { + assert_debug_snapshot!(setup(r#"\newlabel{foo}{{1.1}}"#)); + } + + #[test] + fn test_command_definition_simple() { + assert_debug_snapshot!(setup(r#"\newcommand[1]{\id}{#1}"#)); + } + + #[test] + fn test_command_definition_no_argc() { + assert_debug_snapshot!(setup(r#"\newcommand{\foo}{foo}"#)); + } + + #[test] + fn test_command_definition_no_impl() { + assert_debug_snapshot!(setup(r#"\newcommand{\foo}"#)); + } + + #[test] + fn test_command_definition_no_impl_error() { + assert_debug_snapshot!(setup(r#"\newcommand{\foo"#)); + } + + #[test] + fn test_math_operator_simple() { + assert_debug_snapshot!(setup(r#"\DeclareMathOperator{\foo}{foo}"#)); + } + + #[test] + fn test_math_operator_no_impl() { + assert_debug_snapshot!(setup(r#"\DeclareMathOperator{\foo}"#)); + } + + #[test] + fn test_glossary_entry_definition_simple() { + assert_debug_snapshot!(setup(r#"\newglossaryentry{foo}{bar = baz, qux,}"#)); + } + + #[test] + fn test_glossary_entry_reference_simple() { + assert_debug_snapshot!(setup(r#"\gls{foo}"#)); + } + + #[test] + fn test_glossary_entry_reference_options() { + assert_debug_snapshot!(setup(r#"\gls[foo = bar, qux]{baz}"#)); + } + + #[test] + fn test_acroynm_definition_simple() { + assert_debug_snapshot!(setup(r#"\newacronym{fpsLabel}{FPS}{Frame per Second}"#)); + } + + #[test] + fn test_acroynm_definition_options() { + assert_debug_snapshot!(setup( + r#"\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}"# + )); + } + + #[test] + fn test_acroynm_reference_simple() { + assert_debug_snapshot!(setup(r#"\acrshort{fpsLabel}"#)); + } + + #[test] + fn test_acroynm_reference_options() { + assert_debug_snapshot!(setup(r#"\acrshort[foo=bar,baz]{fpsLabel}"#)); + } + + #[test] + fn test_theorem_definition_only_name() { + assert_debug_snapshot!(setup(r#"\newtheorem{foo}"#)); + } + + #[test] + fn test_theorem_definition_name_with_description() { + assert_debug_snapshot!(setup(r#"\newtheorem{foo}{Foo}"#)); + } + + #[test] + fn test_theorem_definition_name_with_description_and_counter() { + assert_debug_snapshot!(setup(r#"\newtheorem{foo}[bar]{Foo}"#)); + } + + #[test] + fn test_theorem_definition_name_with_counter() { + assert_debug_snapshot!(setup(r#"\newtheorem{foo}[bar]"#)); + } + + #[test] + fn test_theorem_definition_full() { + assert_debug_snapshot!(setup(r#"\newtheorem{foo}[bar]{Foo}[baz]"#)); + } + + #[test] + fn test_color_reference_simple() { + assert_debug_snapshot!(setup(r#"\color{black}"#)); + } + + #[test] + fn test_color_definition_simple() { + assert_debug_snapshot!(setup(r#"\definecolor{foo}{rgb}{255,168,0}"#)); + } + + #[test] + fn test_color_set_definition_simple() { + assert_debug_snapshot!(setup(r#"\definecolorset[ty]{rgb,HTML}{foo}{bar}{baz}"#)); + } + + #[test] + fn test_color_set_definition_error1() { + assert_debug_snapshot!(setup(r#"\definecolorset[ty]{rgb,HTML}{foo}{bar}"#)); + } + + #[test] + fn test_color_set_definition_error2() { + assert_debug_snapshot!(setup(r#"\definecolorset{rgb,HTML}{foo}"#)); + } + + #[test] + fn test_color_set_definition_error3() { + assert_debug_snapshot!(setup(r#"\definecolorset{rgb,HTML}"#)); + } + + #[test] + fn test_color_set_definition_error4() { + assert_debug_snapshot!(setup(r#"\definecolorset"#)); + } + + #[test] + fn test_pgf_library_import_simple() { + assert_debug_snapshot!(setup(r#"\usepgflibrary{foo}"#)); + } + + #[test] + fn test_tikz_library_import_simple() { + assert_debug_snapshot!(setup(r#"\usetikzlibrary{foo}"#)); + } + + #[test] + fn test_environment_definition() { + assert_debug_snapshot!(setup(r#"\newenvironment{bar}[1]{\begin{foo}}{\end{foo}}"#)); + } + + #[test] + fn test_acronym_declaration() { + assert_debug_snapshot!(setup( + r#"\DeclareAcronym{eg}{short = e.g,long = for example,tag = abbrev}"# + )); } } diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_parameter.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_parameter.snap new file mode 100644 index 0000000000..9cff735e99 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_parameter.snap @@ -0,0 +1,47 @@ +--- +source: src/syntax/latex/lexer.rs +expression: "verify(r#\"\\newcommand{\\id}[1]{#1}\"#)" + +--- +[ + ( + COMMAND_DEFINITION_NAME, + "\\newcommand", + ), + ( + L_CURLY, + "{", + ), + ( + GENERIC_COMMAND_NAME, + "\\id", + ), + ( + R_CURLY, + "}", + ), + ( + L_BRACK, + "[", + ), + ( + WORD, + "1", + ), + ( + R_BRACK, + "]", + ), + ( + L_CURLY, + "{", + ), + ( + PARAMETER, + "#1", + ), + ( + R_CURLY, + "}", + ), +] diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_star.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_star.snap new file mode 100644 index 0000000000..41310edaa1 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_star.snap @@ -0,0 +1,23 @@ +--- +source: src/syntax/latex/lexer.rs +expression: "verify(r#\"\\section*{Foo}\"#)" + +--- +[ + ( + SECTION_NAME, + "\\section*", + ), + ( + L_CURLY, + "{", + ), + ( + WORD, + "Foo", + ), + ( + R_CURLY, + "}", + ), +] diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__comment.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__comment.snap new file mode 100644 index 0000000000..2186c957c5 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__comment.snap @@ -0,0 +1,35 @@ +--- +source: src/syntax/latex/lexer.rs +expression: "verify(\"hello %world\\r\\ntest %test\")" + +--- +[ + ( + WORD, + "hello", + ), + ( + WHITESPACE, + " ", + ), + ( + COMMENT, + "%world", + ), + ( + WHITESPACE, + "\r\n", + ), + ( + WORD, + "test", + ), + ( + WHITESPACE, + " ", + ), + ( + COMMENT, + "%test", + ), +] diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__delimiters.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__delimiters.snap new file mode 100644 index 0000000000..36bec0a276 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__delimiters.snap @@ -0,0 +1,79 @@ +--- +source: src/syntax/latex/lexer.rs +expression: "verify(r#\"{foo} (bar) [baz, qux = foo-bar]\"#)" + +--- +[ + ( + L_CURLY, + "{", + ), + ( + WORD, + "foo", + ), + ( + R_CURLY, + "}", + ), + ( + WHITESPACE, + " ", + ), + ( + L_PAREN, + "(", + ), + ( + WORD, + "bar", + ), + ( + R_PAREN, + ")", + ), + ( + WHITESPACE, + " ", + ), + ( + L_BRACK, + "[", + ), + ( + WORD, + "baz", + ), + ( + COMMA, + ",", + ), + ( + WHITESPACE, + " ", + ), + ( + WORD, + "qux", + ), + ( + WHITESPACE, + " ", + ), + ( + EQUALITY_SIGN, + "=", + ), + ( + WHITESPACE, + " ", + ), + ( + WORD, + "foo-bar", + ), + ( + R_BRACK, + "]", + ), +] diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__empty.snap new file mode 100644 index 0000000000..61735b5087 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__empty.snap @@ -0,0 +1,6 @@ +--- +source: src/syntax/latex/lexer.rs +expression: "verify(r#\"\"#)" + +--- +[] diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__escape_sequence.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__escape_sequence.snap new file mode 100644 index 0000000000..4dbc1bb8f5 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__escape_sequence.snap @@ -0,0 +1,19 @@ +--- +source: src/syntax/latex/lexer.rs +expression: "verify(r#\"\\% hello\"#)" + +--- +[ + ( + GENERIC_COMMAND_NAME, + "\\%", + ), + ( + WHITESPACE, + " ", + ), + ( + WORD, + "hello", + ), +] diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__formula.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__formula.snap new file mode 100644 index 0000000000..3fb7079384 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__formula.snap @@ -0,0 +1,55 @@ +--- +source: src/syntax/latex/lexer.rs +expression: "verify(r#\"$ f(x) = y $$\"#)" + +--- +[ + ( + DOLLAR, + "$", + ), + ( + WHITESPACE, + " ", + ), + ( + WORD, + "f", + ), + ( + L_PAREN, + "(", + ), + ( + WORD, + "x", + ), + ( + R_PAREN, + ")", + ), + ( + WHITESPACE, + " ", + ), + ( + EQUALITY_SIGN, + "=", + ), + ( + WHITESPACE, + " ", + ), + ( + WORD, + "y", + ), + ( + WHITESPACE, + " ", + ), + ( + DOLLAR, + "$$", + ), +] diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__invalid_parameter.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__invalid_parameter.snap new file mode 100644 index 0000000000..adadfcf0ef --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__invalid_parameter.snap @@ -0,0 +1,11 @@ +--- +source: src/syntax/latex/lexer.rs +expression: "verify(r#\"#\"#)" + +--- +[ + ( + PARAMETER, + "#", + ), +] diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acronym_declaration.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acronym_declaration.snap new file mode 100644 index 0000000000..dfd05750d3 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acronym_declaration.snap @@ -0,0 +1,49 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\DeclareAcronym{eg}{short = e.g,long = for example,tag = abbrev}\"#)" + +--- +ROOT@0..64 + PREAMBLE@0..64 + ACRONYM_DECLARATION@0..64 + ACRONYM_DECLARATION_NAME@0..15 "\\DeclareAcronym" + CURLY_GROUP_WORD@15..19 + L_CURLY@15..16 "{" + WORD@16..18 "eg" + R_CURLY@18..19 "}" + CURLY_GROUP_KEY_VALUE@19..64 + L_CURLY@19..20 "{" + KEY_VALUE_BODY@20..63 + KEY_VALUE_PAIR@20..31 + KEY@20..26 + WORD@20..25 "short" + WHITESPACE@25..26 " " + EQUALITY_SIGN@26..27 "=" + WHITESPACE@27..28 " " + VALUE@28..31 + TEXT@28..31 + WORD@28..31 "e.g" + COMMA@31..32 "," + KEY_VALUE_PAIR@32..50 + KEY@32..37 + WORD@32..36 "long" + WHITESPACE@36..37 " " + EQUALITY_SIGN@37..38 "=" + WHITESPACE@38..39 " " + VALUE@39..50 + TEXT@39..50 + WORD@39..42 "for" + WHITESPACE@42..43 " " + WORD@43..50 "example" + COMMA@50..51 "," + KEY_VALUE_PAIR@51..63 + KEY@51..55 + WORD@51..54 "tag" + WHITESPACE@54..55 " " + EQUALITY_SIGN@55..56 "=" + WHITESPACE@56..57 " " + VALUE@57..63 + TEXT@57..63 + WORD@57..63 "abbrev" + R_CURLY@63..64 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_options.snap new file mode 100644 index 0000000000..1838e80f9a --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_options.snap @@ -0,0 +1,46 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\"#)" + +--- +ROOT@0..76 + PREAMBLE@0..76 + ACRONYM_DEFINITION@0..76 + ACRONYM_DEFINITION_NAME@0..11 "\\newacronym" + BRACK_GROUP_KEY_VALUE@11..43 + L_BRACK@11..12 "[" + KEY_VALUE_BODY@12..42 + KEY_VALUE_PAIR@12..42 + KEY@12..22 + WORD@12..22 "longplural" + EQUALITY_SIGN@22..23 "=" + VALUE@23..42 + CURLY_GROUP@23..42 + L_CURLY@23..24 "{" + TEXT@24..41 + WORD@24..30 "Frames" + WHITESPACE@30..31 " " + WORD@31..34 "per" + WHITESPACE@34..35 " " + WORD@35..41 "Second" + R_CURLY@41..42 "}" + R_BRACK@42..43 "]" + CURLY_GROUP_WORD@43..53 + L_CURLY@43..44 "{" + WORD@44..52 "fpsLabel" + R_CURLY@52..53 "}" + CURLY_GROUP@53..58 + L_CURLY@53..54 "{" + TEXT@54..57 + WORD@54..57 "FPS" + R_CURLY@57..58 "}" + CURLY_GROUP@58..76 + L_CURLY@58..59 "{" + TEXT@59..75 + WORD@59..64 "Frame" + WHITESPACE@64..65 " " + WORD@65..68 "per" + WHITESPACE@68..69 " " + WORD@69..75 "Second" + R_CURLY@75..76 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_simple.snap new file mode 100644 index 0000000000..1d32bed249 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_simple.snap @@ -0,0 +1,28 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newacronym{fpsLabel}{FPS}{Frame per Second}\"#)" + +--- +ROOT@0..44 + PREAMBLE@0..44 + ACRONYM_DEFINITION@0..44 + ACRONYM_DEFINITION_NAME@0..11 "\\newacronym" + CURLY_GROUP_WORD@11..21 + L_CURLY@11..12 "{" + WORD@12..20 "fpsLabel" + R_CURLY@20..21 "}" + CURLY_GROUP@21..26 + L_CURLY@21..22 "{" + TEXT@22..25 + WORD@22..25 "FPS" + R_CURLY@25..26 "}" + CURLY_GROUP@26..44 + L_CURLY@26..27 "{" + TEXT@27..43 + WORD@27..32 "Frame" + WHITESPACE@32..33 " " + WORD@33..36 "per" + WHITESPACE@36..37 " " + WORD@37..43 "Second" + R_CURLY@43..44 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_options.snap new file mode 100644 index 0000000000..ce5b85c1cf --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_options.snap @@ -0,0 +1,29 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\acrshort[foo=bar,baz]{fpsLabel}\"#)" + +--- +ROOT@0..32 + PREAMBLE@0..32 + ACRONYM_REFERENCE@0..32 + ACRONYM_REFERENCE_NAME@0..9 "\\acrshort" + BRACK_GROUP_KEY_VALUE@9..22 + L_BRACK@9..10 "[" + KEY_VALUE_BODY@10..21 + KEY_VALUE_PAIR@10..17 + KEY@10..13 + WORD@10..13 "foo" + EQUALITY_SIGN@13..14 "=" + VALUE@14..17 + TEXT@14..17 + WORD@14..17 "bar" + COMMA@17..18 "," + KEY_VALUE_PAIR@18..21 + KEY@18..21 + WORD@18..21 "baz" + R_BRACK@21..22 "]" + CURLY_GROUP_WORD@22..32 + L_CURLY@22..23 "{" + WORD@23..31 "fpsLabel" + R_CURLY@31..32 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_simple.snap new file mode 100644 index 0000000000..5df8059f1b --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\acrshort{fpsLabel}\"#)" + +--- +ROOT@0..19 + PREAMBLE@0..19 + ACRONYM_REFERENCE@0..19 + ACRONYM_REFERENCE_NAME@0..9 "\\acrshort" + CURLY_GROUP_WORD@9..19 + L_CURLY@9..10 "{" + WORD@10..18 "fpsLabel" + R_CURLY@18..19 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_options.snap new file mode 100644 index 0000000000..c910699363 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_options.snap @@ -0,0 +1,30 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\addbibresource[foo=bar, baz]{foo/bar.bib}\"#)" + +--- +ROOT@0..42 + PREAMBLE@0..42 + BIBLATEX_INCLUDE@0..42 + BIBLATEX_INCLUDE_NAME@0..15 "\\addbibresource" + BRACK_GROUP_KEY_VALUE@15..29 + L_BRACK@15..16 "[" + KEY_VALUE_BODY@16..28 + KEY_VALUE_PAIR@16..23 + KEY@16..19 + WORD@16..19 "foo" + EQUALITY_SIGN@19..20 "=" + VALUE@20..23 + TEXT@20..23 + WORD@20..23 "bar" + COMMA@23..24 "," + WHITESPACE@24..25 " " + KEY_VALUE_PAIR@25..28 + KEY@25..28 + WORD@25..28 "baz" + R_BRACK@28..29 "]" + CURLY_GROUP_WORD_LIST@29..42 + L_CURLY@29..30 "{" + WORD@30..41 "foo/bar.bib" + R_CURLY@41..42 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_simple.snap new file mode 100644 index 0000000000..3549b985c4 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\addbibresource{foo/bar.bib}\"#)" + +--- +ROOT@0..28 + PREAMBLE@0..28 + BIBLATEX_INCLUDE@0..28 + BIBLATEX_INCLUDE_NAME@0..15 "\\addbibresource" + CURLY_GROUP_WORD_LIST@15..28 + L_CURLY@15..16 "{" + WORD@16..27 "foo/bar.bib" + R_CURLY@27..28 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__bibtex_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__bibtex_include_simple.snap new file mode 100644 index 0000000000..f0d30ebfa3 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__bibtex_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\bibliography{foo/bar}\"#)" + +--- +ROOT@0..22 + PREAMBLE@0..22 + BIBTEX_INCLUDE@0..22 + BIBTEX_INCLUDE_NAME@0..13 "\\bibliography" + CURLY_GROUP_WORD_LIST@13..22 + L_CURLY@13..14 "{" + WORD@14..21 "foo/bar" + R_CURLY@21..22 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_missing_end.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_missing_end.snap new file mode 100644 index 0000000000..c5fc46ec4d --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_missing_end.snap @@ -0,0 +1,15 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"{hello world\"#)" + +--- +ROOT@0..12 + PREAMBLE@0..12 + CURLY_GROUP@0..12 + L_CURLY@0..1 "{" + TEXT@1..12 + WORD@1..6 "hello" + WHITESPACE@6..7 " " + WORD@7..12 "world" + MISSING@12..12 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_simple.snap new file mode 100644 index 0000000000..10ebc4418e --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_simple.snap @@ -0,0 +1,15 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"{hello world}\"#)" + +--- +ROOT@0..13 + PREAMBLE@0..13 + CURLY_GROUP@0..13 + L_CURLY@0..1 "{" + TEXT@1..12 + WORD@1..6 "hello" + WHITESPACE@6..7 " " + WORD@7..12 "world" + R_CURLY@12..13 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption.snap new file mode 100644 index 0000000000..f598a8f7e9 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption.snap @@ -0,0 +1,26 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\caption[qux]{Foo \\Bar Baz}\"#)" + +--- +ROOT@0..27 + PREAMBLE@0..27 + CAPTION@0..27 + CAPTION_NAME@0..8 "\\caption" + BRACK_GROUP@8..13 + L_BRACK@8..9 "[" + TEXT@9..12 + WORD@9..12 "qux" + R_BRACK@12..13 "]" + CURLY_GROUP@13..27 + L_CURLY@13..14 "{" + TEXT@14..18 + WORD@14..17 "Foo" + WHITESPACE@17..18 " " + GENERIC_COMMAND@18..23 + GENERIC_COMMAND_NAME@18..22 "\\Bar" + WHITESPACE@22..23 " " + TEXT@23..26 + WORD@23..26 "Baz" + R_CURLY@26..27 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_error.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_error.snap new file mode 100644 index 0000000000..13697e882b --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_error.snap @@ -0,0 +1,26 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\caption[qux]{Foo \\Bar Baz\"#)" + +--- +ROOT@0..26 + PREAMBLE@0..26 + CAPTION@0..26 + CAPTION_NAME@0..8 "\\caption" + BRACK_GROUP@8..13 + L_BRACK@8..9 "[" + TEXT@9..12 + WORD@9..12 "qux" + R_BRACK@12..13 "]" + CURLY_GROUP@13..26 + L_CURLY@13..14 "{" + TEXT@14..18 + WORD@14..17 "Foo" + WHITESPACE@17..18 " " + GENERIC_COMMAND@18..23 + GENERIC_COMMAND_NAME@18..22 "\\Bar" + WHITESPACE@22..23 " " + TEXT@23..26 + WORD@23..26 "Baz" + MISSING@26..26 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_figure.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_figure.snap new file mode 100644 index 0000000000..4b963caabd --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_figure.snap @@ -0,0 +1,28 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\begin{figure}\\caption{Foo}\\end{figure}\"#)" + +--- +ROOT@0..39 + PREAMBLE@0..39 + ENVIRONMENT@0..39 + BEGIN@0..14 + BEGIN_ENVIRONMENT_NAME@0..6 "\\begin" + CURLY_GROUP_WORD@6..14 + L_CURLY@6..7 "{" + WORD@7..13 "figure" + R_CURLY@13..14 "}" + CAPTION@14..27 + CAPTION_NAME@14..22 "\\caption" + CURLY_GROUP@22..27 + L_CURLY@22..23 "{" + TEXT@23..26 + WORD@23..26 "Foo" + R_CURLY@26..27 "}" + END@27..39 + END_ENVIRONMENT_NAME@27..31 "\\end" + CURLY_GROUP_WORD@31..39 + L_CURLY@31..32 "{" + WORD@32..38 "figure" + R_CURLY@38..39 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal.snap new file mode 100644 index 0000000000..bf9e795e18 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal.snap @@ -0,0 +1,21 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\caption{Foo \\Bar Baz}\"#)" + +--- +ROOT@0..22 + PREAMBLE@0..22 + CAPTION@0..22 + CAPTION_NAME@0..8 "\\caption" + CURLY_GROUP@8..22 + L_CURLY@8..9 "{" + TEXT@9..13 + WORD@9..12 "Foo" + WHITESPACE@12..13 " " + GENERIC_COMMAND@13..18 + GENERIC_COMMAND_NAME@13..17 "\\Bar" + WHITESPACE@17..18 " " + TEXT@18..21 + WORD@18..21 "Baz" + R_CURLY@21..22 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal_error.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal_error.snap new file mode 100644 index 0000000000..6c932ce883 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal_error.snap @@ -0,0 +1,21 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\caption{Foo \\Bar Baz\"#)" + +--- +ROOT@0..21 + PREAMBLE@0..21 + CAPTION@0..21 + CAPTION_NAME@0..8 "\\caption" + CURLY_GROUP@8..21 + L_CURLY@8..9 "{" + TEXT@9..13 + WORD@9..12 "Foo" + WHITESPACE@12..13 " " + GENERIC_COMMAND@13..18 + GENERIC_COMMAND_NAME@13..17 "\\Bar" + WHITESPACE@17..18 " " + TEXT@18..21 + WORD@18..21 "Baz" + MISSING@21..21 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_empty.snap new file mode 100644 index 0000000000..faad4c0039 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_empty.snap @@ -0,0 +1,13 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\cite{}\"#)" + +--- +ROOT@0..7 + PREAMBLE@0..7 + CITATION@0..7 + CITATION_NAME@0..5 "\\cite" + CURLY_GROUP_WORD_LIST@5..7 + L_CURLY@5..6 "{" + R_CURLY@6..7 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_missing_brace.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_missing_brace.snap new file mode 100644 index 0000000000..363f8b0142 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_missing_brace.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\cite{foo\"#)" + +--- +ROOT@0..9 + PREAMBLE@0..9 + CITATION@0..9 + CITATION_NAME@0..5 "\\cite" + CURLY_GROUP_WORD_LIST@5..9 + L_CURLY@5..6 "{" + WORD@6..9 "foo" + MISSING@9..9 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_multiple_keys.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_multiple_keys.snap new file mode 100644 index 0000000000..dafc826a97 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_multiple_keys.snap @@ -0,0 +1,17 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\cite{foo, bar}\"#)" + +--- +ROOT@0..15 + PREAMBLE@0..15 + CITATION@0..15 + CITATION_NAME@0..5 "\\cite" + CURLY_GROUP_WORD_LIST@5..15 + L_CURLY@5..6 "{" + WORD@6..9 "foo" + COMMA@9..10 "," + WHITESPACE@10..11 " " + WORD@11..14 "bar" + R_CURLY@14..15 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote.snap new file mode 100644 index 0000000000..93d83bb448 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote.snap @@ -0,0 +1,19 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\cite[foo]{bar}\"#)" + +--- +ROOT@0..15 + PREAMBLE@0..15 + CITATION@0..15 + CITATION_NAME@0..5 "\\cite" + BRACK_GROUP@5..10 + L_BRACK@5..6 "[" + TEXT@6..9 + WORD@6..9 "foo" + R_BRACK@9..10 "]" + CURLY_GROUP_WORD_LIST@10..15 + L_CURLY@10..11 "{" + WORD@11..14 "bar" + R_CURLY@14..15 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote_postnote.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote_postnote.snap new file mode 100644 index 0000000000..3acaafea3b --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote_postnote.snap @@ -0,0 +1,24 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\cite[foo][bar]{baz}\"#)" + +--- +ROOT@0..20 + PREAMBLE@0..20 + CITATION@0..20 + CITATION_NAME@0..5 "\\cite" + BRACK_GROUP@5..10 + L_BRACK@5..6 "[" + TEXT@6..9 + WORD@6..9 "foo" + R_BRACK@9..10 "]" + BRACK_GROUP@10..15 + L_BRACK@10..11 "[" + TEXT@11..14 + WORD@11..14 "bar" + R_BRACK@14..15 "]" + CURLY_GROUP_WORD_LIST@15..20 + L_CURLY@15..16 "{" + WORD@16..19 "baz" + R_CURLY@19..20 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_redundant_comma.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_redundant_comma.snap new file mode 100644 index 0000000000..12f34f16ae --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_redundant_comma.snap @@ -0,0 +1,16 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\cite{,foo,}\"#)" + +--- +ROOT@0..12 + PREAMBLE@0..12 + CITATION@0..12 + CITATION_NAME@0..5 "\\cite" + CURLY_GROUP_WORD_LIST@5..12 + L_CURLY@5..6 "{" + COMMA@6..7 "," + WORD@7..10 "foo" + COMMA@10..11 "," + R_CURLY@11..12 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_simple.snap new file mode 100644 index 0000000000..a22129f85f --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\cite{foo}\"#)" + +--- +ROOT@0..10 + PREAMBLE@0..10 + CITATION@0..10 + CITATION_NAME@0..5 "\\cite" + CURLY_GROUP_WORD_LIST@5..10 + L_CURLY@5..6 "{" + WORD@6..9 "foo" + R_CURLY@9..10 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_star.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_star.snap new file mode 100644 index 0000000000..4388596dfd --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_star.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\nocite{*}\"#)" + +--- +ROOT@0..10 + PREAMBLE@0..10 + CITATION@0..10 + CITATION_NAME@0..7 "\\nocite" + CURLY_GROUP_WORD_LIST@7..10 + L_CURLY@7..8 "{" + WORD@8..9 "*" + R_CURLY@9..10 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_empty.snap new file mode 100644 index 0000000000..7d84653225 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_empty.snap @@ -0,0 +1,13 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\documentclass{}\"#)" + +--- +ROOT@0..16 + PREAMBLE@0..16 + CLASS_INCLUDE@0..16 + CLASS_INCLUDE_NAME@0..14 "\\documentclass" + CURLY_GROUP_WORD_LIST@14..16 + L_CURLY@14..15 "{" + R_CURLY@15..16 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_options.snap new file mode 100644 index 0000000000..0d0eb1b250 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_options.snap @@ -0,0 +1,37 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\documentclass[foo = bar, baz, qux]{article}\"#)" + +--- +ROOT@0..44 + PREAMBLE@0..44 + CLASS_INCLUDE@0..44 + CLASS_INCLUDE_NAME@0..14 "\\documentclass" + BRACK_GROUP_KEY_VALUE@14..35 + L_BRACK@14..15 "[" + KEY_VALUE_BODY@15..34 + KEY_VALUE_PAIR@15..24 + KEY@15..19 + WORD@15..18 "foo" + WHITESPACE@18..19 " " + EQUALITY_SIGN@19..20 "=" + WHITESPACE@20..21 " " + VALUE@21..24 + TEXT@21..24 + WORD@21..24 "bar" + COMMA@24..25 "," + WHITESPACE@25..26 " " + KEY_VALUE_PAIR@26..29 + KEY@26..29 + WORD@26..29 "baz" + COMMA@29..30 "," + WHITESPACE@30..31 " " + KEY_VALUE_PAIR@31..34 + KEY@31..34 + WORD@31..34 "qux" + R_BRACK@34..35 "]" + CURLY_GROUP_WORD_LIST@35..44 + L_CURLY@35..36 "{" + WORD@36..43 "article" + R_CURLY@43..44 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_simple.snap new file mode 100644 index 0000000000..85e21b47a8 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\documentclass{article}\"#)" + +--- +ROOT@0..23 + PREAMBLE@0..23 + CLASS_INCLUDE@0..23 + CLASS_INCLUDE_NAME@0..14 "\\documentclass" + CURLY_GROUP_WORD_LIST@14..23 + L_CURLY@14..15 "{" + WORD@15..22 "article" + R_CURLY@22..23 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_definition_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_definition_simple.snap new file mode 100644 index 0000000000..e4adfd534c --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_definition_simple.snap @@ -0,0 +1,27 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\definecolor{foo}{rgb}{255,168,0}\"#)" + +--- +ROOT@0..33 + PREAMBLE@0..33 + COLOR_DEFINITION@0..33 + COLOR_DEFINITION_NAME@0..12 "\\definecolor" + CURLY_GROUP_WORD@12..17 + L_CURLY@12..13 "{" + WORD@13..16 "foo" + R_CURLY@16..17 "}" + CURLY_GROUP_WORD@17..22 + L_CURLY@17..18 "{" + WORD@18..21 "rgb" + R_CURLY@21..22 "}" + CURLY_GROUP@22..33 + L_CURLY@22..23 "{" + TEXT@23..32 + WORD@23..26 "255" + COMMA@26..27 "," + WORD@27..30 "168" + COMMA@30..31 "," + WORD@31..32 "0" + R_CURLY@32..33 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_reference_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_reference_simple.snap new file mode 100644 index 0000000000..41a3700122 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_reference_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\color{black}\"#)" + +--- +ROOT@0..13 + PREAMBLE@0..13 + COLOR_REFERENCE@0..13 + COLOR_REFERENCE_NAME@0..6 "\\color" + CURLY_GROUP_WORD@6..13 + L_CURLY@6..7 "{" + WORD@7..12 "black" + R_CURLY@12..13 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error1.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error1.snap new file mode 100644 index 0000000000..42095ff974 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error1.snap @@ -0,0 +1,29 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\definecolorset[ty]{rgb,HTML}{foo}{bar}\"#)" + +--- +ROOT@0..39 + PREAMBLE@0..39 + COLOR_SET_DEFINITION@0..39 + COLOR_SET_DEFINITION_NAME@0..15 "\\definecolorset" + BRACK_GROUP_WORD@15..19 + L_BRACK@15..16 "[" + WORD@16..18 "ty" + R_BRACK@18..19 "]" + CURLY_GROUP_WORD_LIST@19..29 + L_CURLY@19..20 "{" + WORD@20..23 "rgb" + COMMA@23..24 "," + WORD@24..28 "HTML" + R_CURLY@28..29 "}" + CURLY_GROUP_WORD@29..34 + L_CURLY@29..30 "{" + WORD@30..33 "foo" + R_CURLY@33..34 "}" + CURLY_GROUP_WORD@34..39 + L_CURLY@34..35 "{" + WORD@35..38 "bar" + R_CURLY@38..39 "}" + MISSING@39..39 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error2.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error2.snap new file mode 100644 index 0000000000..718d49a3e3 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error2.snap @@ -0,0 +1,22 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\definecolorset{rgb,HTML}{foo}\"#)" + +--- +ROOT@0..30 + PREAMBLE@0..30 + COLOR_SET_DEFINITION@0..30 + COLOR_SET_DEFINITION_NAME@0..15 "\\definecolorset" + CURLY_GROUP_WORD_LIST@15..25 + L_CURLY@15..16 "{" + WORD@16..19 "rgb" + COMMA@19..20 "," + WORD@20..24 "HTML" + R_CURLY@24..25 "}" + CURLY_GROUP_WORD@25..30 + L_CURLY@25..26 "{" + WORD@26..29 "foo" + R_CURLY@29..30 "}" + MISSING@30..30 "" + MISSING@30..30 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error3.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error3.snap new file mode 100644 index 0000000000..f92d813123 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error3.snap @@ -0,0 +1,19 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\definecolorset{rgb,HTML}\"#)" + +--- +ROOT@0..25 + PREAMBLE@0..25 + COLOR_SET_DEFINITION@0..25 + COLOR_SET_DEFINITION_NAME@0..15 "\\definecolorset" + CURLY_GROUP_WORD_LIST@15..25 + L_CURLY@15..16 "{" + WORD@16..19 "rgb" + COMMA@19..20 "," + WORD@20..24 "HTML" + R_CURLY@24..25 "}" + MISSING@25..25 "" + MISSING@25..25 "" + MISSING@25..25 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error4.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error4.snap new file mode 100644 index 0000000000..3cafa81bae --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error4.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\definecolorset\"#)" + +--- +ROOT@0..15 + PREAMBLE@0..15 + COLOR_SET_DEFINITION@0..15 + COLOR_SET_DEFINITION_NAME@0..15 "\\definecolorset" + MISSING@15..15 "" + MISSING@15..15 "" + MISSING@15..15 "" + MISSING@15..15 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_simple.snap new file mode 100644 index 0000000000..f9a736c65f --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_simple.snap @@ -0,0 +1,32 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\definecolorset[ty]{rgb,HTML}{foo}{bar}{baz}\"#)" + +--- +ROOT@0..44 + PREAMBLE@0..44 + COLOR_SET_DEFINITION@0..44 + COLOR_SET_DEFINITION_NAME@0..15 "\\definecolorset" + BRACK_GROUP_WORD@15..19 + L_BRACK@15..16 "[" + WORD@16..18 "ty" + R_BRACK@18..19 "]" + CURLY_GROUP_WORD_LIST@19..29 + L_CURLY@19..20 "{" + WORD@20..23 "rgb" + COMMA@23..24 "," + WORD@24..28 "HTML" + R_CURLY@28..29 "}" + CURLY_GROUP_WORD@29..34 + L_CURLY@29..30 "{" + WORD@30..33 "foo" + R_CURLY@33..34 "}" + CURLY_GROUP_WORD@34..39 + L_CURLY@34..35 "{" + WORD@35..38 "bar" + R_CURLY@38..39 "}" + CURLY_GROUP_WORD@39..44 + L_CURLY@39..40 "{" + WORD@40..43 "baz" + R_CURLY@43..44 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_argc.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_argc.snap new file mode 100644 index 0000000000..2ff3896080 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_argc.snap @@ -0,0 +1,19 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newcommand{\\foo}{foo}\"#)" + +--- +ROOT@0..22 + PREAMBLE@0..22 + COMMAND_DEFINITION@0..22 + COMMAND_DEFINITION_NAME@0..11 "\\newcommand" + CURLY_GROUP_COMMAND@11..17 + L_CURLY@11..12 "{" + GENERIC_COMMAND_NAME@12..16 "\\foo" + R_CURLY@16..17 "}" + CURLY_GROUP@17..22 + L_CURLY@17..18 "{" + TEXT@18..21 + WORD@18..21 "foo" + R_CURLY@21..22 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl.snap new file mode 100644 index 0000000000..4602a7a688 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl.snap @@ -0,0 +1,15 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newcommand{\\foo}\"#)" + +--- +ROOT@0..17 + PREAMBLE@0..17 + COMMAND_DEFINITION@0..17 + COMMAND_DEFINITION_NAME@0..11 "\\newcommand" + CURLY_GROUP_COMMAND@11..17 + L_CURLY@11..12 "{" + GENERIC_COMMAND_NAME@12..16 "\\foo" + R_CURLY@16..17 "}" + MISSING@17..17 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl_error.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl_error.snap new file mode 100644 index 0000000000..4a20be7d7c --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl_error.snap @@ -0,0 +1,15 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newcommand{\\foo\"#)" + +--- +ROOT@0..16 + PREAMBLE@0..16 + COMMAND_DEFINITION@0..16 + COMMAND_DEFINITION_NAME@0..11 "\\newcommand" + CURLY_GROUP_COMMAND@11..16 + L_CURLY@11..12 "{" + GENERIC_COMMAND_NAME@12..16 "\\foo" + MISSING@16..16 "" + MISSING@16..16 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_simple.snap new file mode 100644 index 0000000000..e5f2377fcf --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_simple.snap @@ -0,0 +1,24 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newcommand[1]{\\id}{#1}\"#)" + +--- +ROOT@0..23 + PREAMBLE@0..23 + COMMAND_DEFINITION@0..19 + COMMAND_DEFINITION_NAME@0..11 "\\newcommand" + MISSING@11..11 "" + BRACK_GROUP_WORD@11..14 + L_BRACK@11..12 "[" + WORD@12..13 "1" + R_BRACK@13..14 "]" + CURLY_GROUP@14..19 + L_CURLY@14..15 "{" + GENERIC_COMMAND@15..18 + GENERIC_COMMAND_NAME@15..18 "\\id" + R_CURLY@18..19 "}" + CURLY_GROUP@19..23 + L_CURLY@19..20 "{" + PARAMETER@20..22 "#1" + R_CURLY@22..23 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__empty.snap new file mode 100644 index 0000000000..f01f7f9092 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__empty.snap @@ -0,0 +1,8 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\"#)" + +--- +ROOT@0..0 + PREAMBLE@0..0 + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition.snap new file mode 100644 index 0000000000..df3c0d56fb --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition.snap @@ -0,0 +1,38 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newenvironment{bar}[1]{\\begin{foo}}{\\end{foo}}\"#)" + +--- +ROOT@0..47 + PREAMBLE@0..47 + ENVIRONMENT_DEFINITION@0..47 + ENVIRONMENT_DEFINIITION_NAME@0..15 "\\newenvironment" + CURLY_GROUP_WORD@15..20 + L_CURLY@15..16 "{" + WORD@16..19 "bar" + R_CURLY@19..20 "}" + BRACK_GROUP_WORD@20..23 + L_BRACK@20..21 "[" + WORD@21..22 "1" + R_BRACK@22..23 "]" + CURLY_GROUP@23..36 + L_CURLY@23..24 "{" + GENERIC_COMMAND@24..35 + BEGIN_ENVIRONMENT_NAME@24..30 "\\begin" + CURLY_GROUP@30..35 + L_CURLY@30..31 "{" + TEXT@31..34 + WORD@31..34 "foo" + R_CURLY@34..35 "}" + R_CURLY@35..36 "}" + CURLY_GROUP@36..47 + L_CURLY@36..37 "{" + GENERIC_COMMAND@37..46 + END_ENVIRONMENT_NAME@37..41 "\\end" + CURLY_GROUP@41..46 + L_CURLY@41..42 "{" + TEXT@42..45 + WORD@42..45 "foo" + R_CURLY@45..46 "}" + R_CURLY@46..47 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested.snap new file mode 100644 index 0000000000..a5c566f773 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested.snap @@ -0,0 +1,37 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\begin{foo} \\begin{qux} \\end{baz} \\end{bar}\"#)" + +--- +ROOT@0..43 + PREAMBLE@0..43 + ENVIRONMENT@0..43 + BEGIN@0..12 + BEGIN_ENVIRONMENT_NAME@0..6 "\\begin" + CURLY_GROUP_WORD@6..12 + L_CURLY@6..7 "{" + WORD@7..10 "foo" + R_CURLY@10..11 "}" + WHITESPACE@11..12 " " + ENVIRONMENT@12..34 + BEGIN@12..24 + BEGIN_ENVIRONMENT_NAME@12..18 "\\begin" + CURLY_GROUP_WORD@18..24 + L_CURLY@18..19 "{" + WORD@19..22 "qux" + R_CURLY@22..23 "}" + WHITESPACE@23..24 " " + END@24..34 + END_ENVIRONMENT_NAME@24..28 "\\end" + CURLY_GROUP_WORD@28..34 + L_CURLY@28..29 "{" + WORD@29..32 "baz" + R_CURLY@32..33 "}" + WHITESPACE@33..34 " " + END@34..43 + END_ENVIRONMENT_NAME@34..38 "\\end" + CURLY_GROUP_WORD@38..43 + L_CURLY@38..39 "{" + WORD@39..42 "bar" + R_CURLY@42..43 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested_missing_braces.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested_missing_braces.snap new file mode 100644 index 0000000000..9ff76605d6 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested_missing_braces.snap @@ -0,0 +1,42 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\begin{foo \\begin{qux Hello World \\end{baz} \\end{bar\"#)" + +--- +ROOT@0..52 + PREAMBLE@0..52 + ENVIRONMENT@0..52 + BEGIN@0..11 + BEGIN_ENVIRONMENT_NAME@0..6 "\\begin" + CURLY_GROUP_WORD@6..11 + L_CURLY@6..7 "{" + WORD@7..10 "foo" + WHITESPACE@10..11 " " + MISSING@11..11 "" + ENVIRONMENT@11..44 + BEGIN@11..22 + BEGIN_ENVIRONMENT_NAME@11..17 "\\begin" + CURLY_GROUP_WORD@17..22 + L_CURLY@17..18 "{" + WORD@18..21 "qux" + WHITESPACE@21..22 " " + MISSING@22..22 "" + TEXT@22..34 + WORD@22..27 "Hello" + WHITESPACE@27..28 " " + WORD@28..33 "World" + WHITESPACE@33..34 " " + END@34..44 + END_ENVIRONMENT_NAME@34..38 "\\end" + CURLY_GROUP_WORD@38..44 + L_CURLY@38..39 "{" + WORD@39..42 "baz" + R_CURLY@42..43 "}" + WHITESPACE@43..44 " " + END@44..52 + END_ENVIRONMENT_NAME@44..48 "\\end" + CURLY_GROUP_WORD@48..52 + L_CURLY@48..49 "{" + WORD@49..52 "bar" + MISSING@52..52 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_simple.snap new file mode 100644 index 0000000000..d58f5b26c4 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_simple.snap @@ -0,0 +1,27 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\begin{foo} Hello World \\end{bar}\"#)" + +--- +ROOT@0..33 + PREAMBLE@0..33 + ENVIRONMENT@0..33 + BEGIN@0..12 + BEGIN_ENVIRONMENT_NAME@0..6 "\\begin" + CURLY_GROUP_WORD@6..12 + L_CURLY@6..7 "{" + WORD@7..10 "foo" + R_CURLY@10..11 "}" + WHITESPACE@11..12 " " + TEXT@12..24 + WORD@12..17 "Hello" + WHITESPACE@17..18 " " + WORD@18..23 "World" + WHITESPACE@23..24 " " + END@24..33 + END_ENVIRONMENT_NAME@24..28 "\\end" + CURLY_GROUP_WORD@28..33 + L_CURLY@28..29 "{" + WORD@29..32 "bar" + R_CURLY@32..33 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation.snap new file mode 100644 index 0000000000..e146fcaee6 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation.snap @@ -0,0 +1,17 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\[ foo bar \\]\"#)" + +--- +ROOT@0..13 + PREAMBLE@0..13 + EQUATION@0..13 + BEGIN_EQUATION_NAME@0..2 "\\[" + WHITESPACE@2..3 " " + TEXT@3..11 + WORD@3..6 "foo" + WHITESPACE@6..7 " " + WORD@7..10 "bar" + WHITESPACE@10..11 " " + END_EQUATION_NAME@11..13 "\\]" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_label_reference_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_label_reference_simple.snap new file mode 100644 index 0000000000..7a851233ef --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_label_reference_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\eqref{foo}\"#)" + +--- +ROOT@0..11 + PREAMBLE@0..11 + LABEL_REFERENCE@0..11 + LABEL_REFERENCE_NAME@0..6 "\\eqref" + CURLY_GROUP_WORD_LIST@6..11 + L_CURLY@6..7 "{" + WORD@7..10 "foo" + R_CURLY@10..11 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_begin.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_begin.snap new file mode 100644 index 0000000000..fe065667c3 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_begin.snap @@ -0,0 +1,30 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\begin{a} foo bar \\] \\end{b}\"#)" + +--- +ROOT@0..28 + PREAMBLE@0..28 + ENVIRONMENT@0..28 + BEGIN@0..10 + BEGIN_ENVIRONMENT_NAME@0..6 "\\begin" + CURLY_GROUP_WORD@6..10 + L_CURLY@6..7 "{" + WORD@7..8 "a" + R_CURLY@8..9 "}" + WHITESPACE@9..10 " " + TEXT@10..18 + WORD@10..13 "foo" + WHITESPACE@13..14 " " + WORD@14..17 "bar" + WHITESPACE@17..18 " " + GENERIC_COMMAND@18..21 + END_EQUATION_NAME@18..20 "\\]" + WHITESPACE@20..21 " " + END@21..28 + END_ENVIRONMENT_NAME@21..25 "\\end" + CURLY_GROUP_WORD@25..28 + L_CURLY@25..26 "{" + WORD@26..27 "b" + R_CURLY@27..28 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_end.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_end.snap new file mode 100644 index 0000000000..f7b6205ffb --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_end.snap @@ -0,0 +1,31 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\begin{a} \\[ foo bar \\end{b}\"#)" + +--- +ROOT@0..28 + PREAMBLE@0..28 + ENVIRONMENT@0..28 + BEGIN@0..10 + BEGIN_ENVIRONMENT_NAME@0..6 "\\begin" + CURLY_GROUP_WORD@6..10 + L_CURLY@6..7 "{" + WORD@7..8 "a" + R_CURLY@8..9 "}" + WHITESPACE@9..10 " " + EQUATION@10..21 + BEGIN_EQUATION_NAME@10..12 "\\[" + WHITESPACE@12..13 " " + TEXT@13..21 + WORD@13..16 "foo" + WHITESPACE@16..17 " " + WORD@17..20 "bar" + WHITESPACE@20..21 " " + MISSING@21..21 "" + END@21..28 + END_ENVIRONMENT_NAME@21..25 "\\end" + CURLY_GROUP_WORD@25..28 + L_CURLY@25..26 "{" + WORD@26..27 "b" + R_CURLY@27..28 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__escaped_brackets.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__escaped_brackets.snap new file mode 100644 index 0000000000..c595828583 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__escaped_brackets.snap @@ -0,0 +1,19 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"{[}{]}\"#)" + +--- +ROOT@0..6 + PREAMBLE@0..6 + CURLY_GROUP@0..3 + L_CURLY@0..1 "{" + MIXED_GROUP@1..2 + L_BRACK@1..2 "[" + MISSING@2..2 "" + R_CURLY@2..3 "}" + CURLY_GROUP@3..6 + L_CURLY@3..4 "{" + ERROR@4..5 + R_BRACK@4..5 "]" + R_CURLY@5..6 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_args.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_args.snap new file mode 100644 index 0000000000..b62c8c2559 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_args.snap @@ -0,0 +1,20 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\foo{bar}[qux]\"#)" + +--- +ROOT@0..14 + PREAMBLE@0..14 + GENERIC_COMMAND@0..14 + GENERIC_COMMAND_NAME@0..4 "\\foo" + CURLY_GROUP@4..9 + L_CURLY@4..5 "{" + TEXT@5..8 + WORD@5..8 "bar" + R_CURLY@8..9 "}" + MIXED_GROUP@9..14 + L_BRACK@9..10 "[" + TEXT@10..13 + WORD@10..13 "qux" + R_BRACK@13..14 "]" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_empty.snap new file mode 100644 index 0000000000..84e62ea81d --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_empty.snap @@ -0,0 +1,10 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\foo\"#)" + +--- +ROOT@0..4 + PREAMBLE@0..4 + GENERIC_COMMAND@0..4 + GENERIC_COMMAND_NAME@0..4 "\\foo" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_escape.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_escape.snap new file mode 100644 index 0000000000..a0d5d2e29b --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_escape.snap @@ -0,0 +1,10 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\#\"#)" + +--- +ROOT@0..2 + PREAMBLE@0..2 + GENERIC_COMMAND@0..2 + GENERIC_COMMAND_NAME@0..2 "\\#" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_definition_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_definition_simple.snap new file mode 100644 index 0000000000..d1b31e275a --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_definition_simple.snap @@ -0,0 +1,33 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newglossaryentry{foo}{bar = baz, qux,}\"#)" + +--- +ROOT@0..39 + PREAMBLE@0..39 + GLOSSARY_ENTRY_DEFINITION@0..39 + GLOSSARY_ENTRY_DEFINITION_NAME@0..17 "\\newglossaryentry" + CURLY_GROUP_WORD@17..22 + L_CURLY@17..18 "{" + WORD@18..21 "foo" + R_CURLY@21..22 "}" + CURLY_GROUP_KEY_VALUE@22..39 + L_CURLY@22..23 "{" + KEY_VALUE_BODY@23..38 + KEY_VALUE_PAIR@23..32 + KEY@23..27 + WORD@23..26 "bar" + WHITESPACE@26..27 " " + EQUALITY_SIGN@27..28 "=" + WHITESPACE@28..29 " " + VALUE@29..32 + TEXT@29..32 + WORD@29..32 "baz" + COMMA@32..33 "," + WHITESPACE@33..34 " " + KEY_VALUE_PAIR@34..37 + KEY@34..37 + WORD@34..37 "qux" + COMMA@37..38 "," + R_CURLY@38..39 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_options.snap new file mode 100644 index 0000000000..ad5c44885a --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_options.snap @@ -0,0 +1,32 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\gls[foo = bar, qux]{baz}\"#)" + +--- +ROOT@0..25 + PREAMBLE@0..25 + GLOSSARY_ENTRY_REFERENCE@0..25 + GLOSSARY_ENTRY_REFERENCE_NAME@0..4 "\\gls" + BRACK_GROUP_KEY_VALUE@4..20 + L_BRACK@4..5 "[" + KEY_VALUE_BODY@5..19 + KEY_VALUE_PAIR@5..14 + KEY@5..9 + WORD@5..8 "foo" + WHITESPACE@8..9 " " + EQUALITY_SIGN@9..10 "=" + WHITESPACE@10..11 " " + VALUE@11..14 + TEXT@11..14 + WORD@11..14 "bar" + COMMA@14..15 "," + WHITESPACE@15..16 " " + KEY_VALUE_PAIR@16..19 + KEY@16..19 + WORD@16..19 "qux" + R_BRACK@19..20 "]" + CURLY_GROUP_WORD@20..25 + L_CURLY@20..21 "{" + WORD@21..24 "baz" + R_CURLY@24..25 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_simple.snap new file mode 100644 index 0000000000..2a6b845733 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\gls{foo}\"#)" + +--- +ROOT@0..9 + PREAMBLE@0..9 + GLOSSARY_ENTRY_REFERENCE@0..9 + GLOSSARY_ENTRY_REFERENCE_NAME@0..4 "\\gls" + CURLY_GROUP_WORD@4..9 + L_CURLY@4..5 "{" + WORD@5..8 "foo" + R_CURLY@8..9 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_options.snap new file mode 100644 index 0000000000..910a4848ef --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_options.snap @@ -0,0 +1,25 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\includegraphics[scale=.5]{foo/bar.pdf}\"#)" + +--- +ROOT@0..39 + PREAMBLE@0..39 + GRAPHICS_INCLUDE@0..39 + GRAPHICS_INCLUDE_NAME@0..16 "\\includegraphics" + BRACK_GROUP_KEY_VALUE@16..26 + L_BRACK@16..17 "[" + KEY_VALUE_BODY@17..25 + KEY_VALUE_PAIR@17..25 + KEY@17..22 + WORD@17..22 "scale" + EQUALITY_SIGN@22..23 "=" + VALUE@23..25 + TEXT@23..25 + WORD@23..25 ".5" + R_BRACK@25..26 "]" + CURLY_GROUP_WORD_LIST@26..39 + L_CURLY@26..27 "{" + WORD@27..38 "foo/bar.pdf" + R_CURLY@38..39 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_simple.snap new file mode 100644 index 0000000000..fa6fbf1a14 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\includegraphics{foo/bar.pdf}\"#)" + +--- +ROOT@0..29 + PREAMBLE@0..29 + GRAPHICS_INCLUDE@0..29 + GRAPHICS_INCLUDE_NAME@0..16 "\\includegraphics" + CURLY_GROUP_WORD_LIST@16..29 + L_CURLY@16..17 "{" + WORD@17..28 "foo/bar.pdf" + R_CURLY@28..29 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__hello_world.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__hello_world.snap new file mode 100644 index 0000000000..ee25cb5453 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__hello_world.snap @@ -0,0 +1,12 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"Hello World!\"#)" + +--- +ROOT@0..12 + PREAMBLE@0..12 + TEXT@0..12 + WORD@0..5 "Hello" + WHITESPACE@5..6 " " + WORD@6..12 "World!" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_incomplete.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_incomplete.snap new file mode 100644 index 0000000000..3dae1f433a --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_incomplete.snap @@ -0,0 +1,15 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\import{foo\"#)" + +--- +ROOT@0..11 + PREAMBLE@0..11 + IMPORT@0..11 + IMPORT_NAME@0..7 "\\import" + CURLY_GROUP_WORD@7..11 + L_CURLY@7..8 "{" + WORD@8..11 "foo" + MISSING@11..11 "" + MISSING@11..11 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_simple.snap new file mode 100644 index 0000000000..6e21f65cbf --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_simple.snap @@ -0,0 +1,18 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\import{foo}{bar}\"#)" + +--- +ROOT@0..17 + PREAMBLE@0..17 + IMPORT@0..17 + IMPORT_NAME@0..7 "\\import" + CURLY_GROUP_WORD@7..12 + L_CURLY@7..8 "{" + WORD@8..11 "foo" + R_CURLY@11..12 "}" + CURLY_GROUP_WORD@12..17 + L_CURLY@12..13 "{" + WORD@13..16 "bar" + R_CURLY@16..17 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_options.snap new file mode 100644 index 0000000000..d1fd2df652 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_options.snap @@ -0,0 +1,25 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\includesvg[scale=.5]{foo/bar}\"#)" + +--- +ROOT@0..30 + PREAMBLE@0..30 + SVG_INCLUDE@0..30 + SVG_INCLUDE_NAME@0..11 "\\includesvg" + BRACK_GROUP_KEY_VALUE@11..21 + L_BRACK@11..12 "[" + KEY_VALUE_BODY@12..20 + KEY_VALUE_PAIR@12..20 + KEY@12..17 + WORD@12..17 "scale" + EQUALITY_SIGN@17..18 "=" + VALUE@18..20 + TEXT@18..20 + WORD@18..20 ".5" + R_BRACK@20..21 "]" + CURLY_GROUP_WORD_LIST@21..30 + L_CURLY@21..22 "{" + WORD@22..29 "foo/bar" + R_CURLY@29..30 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_simple.snap new file mode 100644 index 0000000000..59f50c36d3 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\includesvg{foo/bar}\"#)" + +--- +ROOT@0..20 + PREAMBLE@0..20 + SVG_INCLUDE@0..20 + SVG_INCLUDE_NAME@0..11 "\\includesvg" + CURLY_GROUP_WORD_LIST@11..20 + L_CURLY@11..12 "{" + WORD@12..19 "foo/bar" + R_CURLY@19..20 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline.snap new file mode 100644 index 0000000000..b430de766e --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline.snap @@ -0,0 +1,26 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"$x \\in [0, \\infty)$\"#)" + +--- +ROOT@0..19 + PREAMBLE@0..19 + FORMULA@0..19 + DOLLAR@0..1 "$" + TEXT@1..3 + WORD@1..2 "x" + WHITESPACE@2..3 " " + GENERIC_COMMAND@3..18 + GENERIC_COMMAND_NAME@3..6 "\\in" + WHITESPACE@6..7 " " + MIXED_GROUP@7..18 + L_BRACK@7..8 "[" + TEXT@8..11 + WORD@8..9 "0" + COMMA@9..10 "," + WHITESPACE@10..11 " " + GENERIC_COMMAND@11..17 + GENERIC_COMMAND_NAME@11..17 "\\infty" + R_PAREN@17..18 ")" + DOLLAR@18..19 "$" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline_double_dollar.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline_double_dollar.snap new file mode 100644 index 0000000000..8da22f3ecb --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline_double_dollar.snap @@ -0,0 +1,26 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"$$x \\in [0, \\infty)$$\"#)" + +--- +ROOT@0..21 + PREAMBLE@0..21 + FORMULA@0..21 + DOLLAR@0..2 "$$" + TEXT@2..4 + WORD@2..3 "x" + WHITESPACE@3..4 " " + GENERIC_COMMAND@4..19 + GENERIC_COMMAND_NAME@4..7 "\\in" + WHITESPACE@7..8 " " + MIXED_GROUP@8..19 + L_BRACK@8..9 "[" + TEXT@9..12 + WORD@9..10 "0" + COMMA@10..11 "," + WHITESPACE@11..12 " " + GENERIC_COMMAND@12..18 + GENERIC_COMMAND_NAME@12..18 "\\infty" + R_PAREN@18..19 ")" + DOLLAR@19..21 "$$" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_simple.snap new file mode 100644 index 0000000000..7eacd65c59 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\label{foo}\"#)" + +--- +ROOT@0..11 + PREAMBLE@0..11 + LABEL_DEFINITION@0..11 + LABEL_DEFINITION_NAME@0..6 "\\label" + CURLY_GROUP_WORD@6..11 + L_CURLY@6..7 "{" + WORD@7..10 "foo" + R_CURLY@10..11 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_number.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_number.snap new file mode 100644 index 0000000000..46392d7574 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_number.snap @@ -0,0 +1,23 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newlabel{foo}{{1.1}}\"#)" + +--- +ROOT@0..21 + PREAMBLE@0..21 + LABEL_NUMBER@0..21 + LABEL_NUMBER_NAME@0..9 "\\newlabel" + CURLY_GROUP_WORD@9..14 + L_CURLY@9..10 "{" + WORD@10..13 "foo" + R_CURLY@13..14 "}" + CURLY_GROUP@14..21 + L_CURLY@14..15 "{" + CURLY_GROUP@15..20 + L_CURLY@15..16 "{" + TEXT@16..19 + WORD@16..19 "1.1" + R_CURLY@19..20 "}" + R_CURLY@20..21 "}" + MISSING@21..21 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_multiple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_multiple.snap new file mode 100644 index 0000000000..e399397e09 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_multiple.snap @@ -0,0 +1,17 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\ref{foo, bar}\"#)" + +--- +ROOT@0..14 + PREAMBLE@0..14 + LABEL_REFERENCE@0..14 + LABEL_REFERENCE_NAME@0..4 "\\ref" + CURLY_GROUP_WORD_LIST@4..14 + L_CURLY@4..5 "{" + WORD@5..8 "foo" + COMMA@8..9 "," + WHITESPACE@9..10 " " + WORD@10..13 "bar" + R_CURLY@13..14 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_error.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_error.snap new file mode 100644 index 0000000000..2894a9c2ec --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_error.snap @@ -0,0 +1,18 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\crefrange{foo{bar}\"#)" + +--- +ROOT@0..19 + PREAMBLE@0..19 + LABEL_REFERENCE_RANGE@0..19 + LABEL_REFERENCE_RANGE_NAME@0..10 "\\crefrange" + CURLY_GROUP_WORD@10..14 + L_CURLY@10..11 "{" + WORD@11..14 "foo" + MISSING@14..14 "" + CURLY_GROUP_WORD@14..19 + L_CURLY@14..15 "{" + WORD@15..18 "bar" + R_CURLY@18..19 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_incomplete.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_incomplete.snap new file mode 100644 index 0000000000..0a1753867e --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_incomplete.snap @@ -0,0 +1,15 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\crefrange{foo}\"#)" + +--- +ROOT@0..15 + PREAMBLE@0..15 + LABEL_REFERENCE_RANGE@0..15 + LABEL_REFERENCE_RANGE_NAME@0..10 "\\crefrange" + CURLY_GROUP_WORD@10..15 + L_CURLY@10..11 "{" + WORD@11..14 "foo" + R_CURLY@14..15 "}" + MISSING@15..15 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_simple.snap new file mode 100644 index 0000000000..c06c31c1b7 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_simple.snap @@ -0,0 +1,18 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\crefrange{foo}{bar}\"#)" + +--- +ROOT@0..20 + PREAMBLE@0..20 + LABEL_REFERENCE_RANGE@0..20 + LABEL_REFERENCE_RANGE_NAME@0..10 "\\crefrange" + CURLY_GROUP_WORD@10..15 + L_CURLY@10..11 "{" + WORD@11..14 "foo" + R_CURLY@14..15 "}" + CURLY_GROUP_WORD@15..20 + L_CURLY@15..16 "{" + WORD@16..19 "bar" + R_CURLY@19..20 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_simple.snap new file mode 100644 index 0000000000..ed06f5dfc1 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\ref{foo}\"#)" + +--- +ROOT@0..9 + PREAMBLE@0..9 + LABEL_REFERENCE@0..9 + LABEL_REFERENCE_NAME@0..4 "\\ref" + CURLY_GROUP_WORD_LIST@4..9 + L_CURLY@4..5 "{" + WORD@5..8 "foo" + R_CURLY@8..9 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_simple.snap new file mode 100644 index 0000000000..34565aa072 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\include{foo/bar}\"#)" + +--- +ROOT@0..17 + PREAMBLE@0..17 + LATEX_INCLUDE@0..17 + LATEX_INCLUDE_NAME@0..8 "\\include" + CURLY_GROUP_WORD_LIST@8..17 + L_CURLY@8..9 "{" + WORD@9..16 "foo/bar" + R_CURLY@16..17 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_simple.snap new file mode 100644 index 0000000000..208e898407 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\input{foo/bar.tex}\"#)" + +--- +ROOT@0..19 + PREAMBLE@0..19 + LATEX_INCLUDE@0..19 + LATEX_INCLUDE_NAME@0..6 "\\input" + CURLY_GROUP_WORD_LIST@6..19 + L_CURLY@6..7 "{" + WORD@7..18 "foo/bar.tex" + R_CURLY@18..19 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_no_impl.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_no_impl.snap new file mode 100644 index 0000000000..2e39ee899c --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_no_impl.snap @@ -0,0 +1,15 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\DeclareMathOperator{\\foo}\"#)" + +--- +ROOT@0..26 + PREAMBLE@0..26 + MATH_OPERATOR@0..26 + MATH_OPERATOR_NAME@0..20 "\\DeclareMathOperator" + CURLY_GROUP_COMMAND@20..26 + L_CURLY@20..21 "{" + GENERIC_COMMAND_NAME@21..25 "\\foo" + R_CURLY@25..26 "}" + MISSING@26..26 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_simple.snap new file mode 100644 index 0000000000..bb44005153 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_simple.snap @@ -0,0 +1,19 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\DeclareMathOperator{\\foo}{foo}\"#)" + +--- +ROOT@0..31 + PREAMBLE@0..31 + MATH_OPERATOR@0..31 + MATH_OPERATOR_NAME@0..20 "\\DeclareMathOperator" + CURLY_GROUP_COMMAND@20..26 + L_CURLY@20..21 "{" + GENERIC_COMMAND_NAME@21..25 "\\foo" + R_CURLY@25..26 "}" + CURLY_GROUP@26..31 + L_CURLY@26..27 "{" + TEXT@27..30 + WORD@27..30 "foo" + R_CURLY@30..31 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_empty.snap new file mode 100644 index 0000000000..b8851b6e1d --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_empty.snap @@ -0,0 +1,13 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\usepackage{}\"#)" + +--- +ROOT@0..13 + PREAMBLE@0..13 + PACKAGE_INCLUDE@0..13 + PACKAGE_INCLUDE_NAME@0..11 "\\usepackage" + CURLY_GROUP_WORD_LIST@11..13 + L_CURLY@11..12 "{" + R_CURLY@12..13 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_multiple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_multiple.snap new file mode 100644 index 0000000000..e68b98d1b5 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_multiple.snap @@ -0,0 +1,17 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\usepackage{amsmath, lipsum}\"#)" + +--- +ROOT@0..28 + PREAMBLE@0..28 + PACKAGE_INCLUDE@0..28 + PACKAGE_INCLUDE_NAME@0..11 "\\usepackage" + CURLY_GROUP_WORD_LIST@11..28 + L_CURLY@11..12 "{" + WORD@12..19 "amsmath" + COMMA@19..20 "," + WHITESPACE@20..21 " " + WORD@21..27 "lipsum" + R_CURLY@27..28 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_options.snap new file mode 100644 index 0000000000..a33c4e0bd7 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_options.snap @@ -0,0 +1,37 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\usepackage[foo = bar, baz, qux]{amsmath}\"#)" + +--- +ROOT@0..41 + PREAMBLE@0..41 + PACKAGE_INCLUDE@0..41 + PACKAGE_INCLUDE_NAME@0..11 "\\usepackage" + BRACK_GROUP_KEY_VALUE@11..32 + L_BRACK@11..12 "[" + KEY_VALUE_BODY@12..31 + KEY_VALUE_PAIR@12..21 + KEY@12..16 + WORD@12..15 "foo" + WHITESPACE@15..16 " " + EQUALITY_SIGN@16..17 "=" + WHITESPACE@17..18 " " + VALUE@18..21 + TEXT@18..21 + WORD@18..21 "bar" + COMMA@21..22 "," + WHITESPACE@22..23 " " + KEY_VALUE_PAIR@23..26 + KEY@23..26 + WORD@23..26 "baz" + COMMA@26..27 "," + WHITESPACE@27..28 " " + KEY_VALUE_PAIR@28..31 + KEY@28..31 + WORD@28..31 "qux" + R_BRACK@31..32 "]" + CURLY_GROUP_WORD_LIST@32..41 + L_CURLY@32..33 "{" + WORD@33..40 "amsmath" + R_CURLY@40..41 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_simple.snap new file mode 100644 index 0000000000..00c075fdfe --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\usepackage{amsmath}\"#)" + +--- +ROOT@0..20 + PREAMBLE@0..20 + PACKAGE_INCLUDE@0..20 + PACKAGE_INCLUDE_NAME@0..11 "\\usepackage" + CURLY_GROUP_WORD_LIST@11..20 + L_CURLY@11..12 "{" + WORD@12..19 "amsmath" + R_CURLY@19..20 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter.snap new file mode 100644 index 0000000000..8c6bd90cb8 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter.snap @@ -0,0 +1,9 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"#1\"#)" + +--- +ROOT@0..2 + PREAMBLE@0..2 + PARAMETER@0..2 "#1" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter_error.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter_error.snap new file mode 100644 index 0000000000..1a9b68fa2d --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter_error.snap @@ -0,0 +1,9 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"#\"#)" + +--- +ROOT@0..1 + PREAMBLE@0..1 + PARAMETER@0..1 "#" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__pgf_library_import_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__pgf_library_import_simple.snap new file mode 100644 index 0000000000..8f289f97a4 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__pgf_library_import_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\usepgflibrary{foo}\"#)" + +--- +ROOT@0..19 + PREAMBLE@0..19 + TIKZ_LIBRARY_IMPORT@0..19 + TIKZ_LIBRARY_IMPORT_NAME@0..14 "\\usepgflibrary" + CURLY_GROUP_WORD_LIST@14..19 + L_CURLY@14..15 "{" + WORD@15..18 "foo" + R_CURLY@18..19 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_enum_item.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_enum_item.snap new file mode 100644 index 0000000000..43dcae1987 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_enum_item.snap @@ -0,0 +1,45 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\begin{enumerate} \\item 1 \\item[2] 2 \\item 3 \\end{enumerate}\"#)" + +--- +ROOT@0..60 + PREAMBLE@0..60 + ENVIRONMENT@0..60 + BEGIN@0..18 + BEGIN_ENVIRONMENT_NAME@0..6 "\\begin" + CURLY_GROUP_WORD@6..18 + L_CURLY@6..7 "{" + WORD@7..16 "enumerate" + R_CURLY@16..17 "}" + WHITESPACE@17..18 " " + ENUM_ITEM@18..26 + ENUM_ITEM_NAME@18..23 "\\item" + WHITESPACE@23..24 " " + TEXT@24..26 + WORD@24..25 "1" + WHITESPACE@25..26 " " + ENUM_ITEM@26..37 + ENUM_ITEM_NAME@26..31 "\\item" + BRACK_GROUP@31..35 + L_BRACK@31..32 "[" + TEXT@32..33 + WORD@32..33 "2" + R_BRACK@33..34 "]" + WHITESPACE@34..35 " " + TEXT@35..37 + WORD@35..36 "2" + WHITESPACE@36..37 " " + ENUM_ITEM@37..45 + ENUM_ITEM_NAME@37..42 "\\item" + WHITESPACE@42..43 " " + TEXT@43..45 + WORD@43..44 "3" + WHITESPACE@44..45 " " + END@45..60 + END_ENVIRONMENT_NAME@45..49 "\\end" + CURLY_GROUP_WORD@49..60 + L_CURLY@49..50 "{" + WORD@50..59 "enumerate" + R_CURLY@59..60 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_invalid_nesting.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_invalid_nesting.snap new file mode 100644 index 0000000000..f999a50e9a --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_invalid_nesting.snap @@ -0,0 +1,23 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\section{Foo} \\chapter{Bar}\"#)" + +--- +ROOT@0..27 + PREAMBLE@0..27 + SECTION@0..14 + SECTION_NAME@0..8 "\\section" + CURLY_GROUP@8..14 + L_CURLY@8..9 "{" + TEXT@9..12 + WORD@9..12 "Foo" + R_CURLY@12..13 "}" + WHITESPACE@13..14 " " + CHAPTER@14..27 + CHAPTER_NAME@14..22 "\\chapter" + CURLY_GROUP@22..27 + L_CURLY@22..23 "{" + TEXT@23..26 + WORD@23..26 "Bar" + R_CURLY@26..27 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_nested.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_nested.snap new file mode 100644 index 0000000000..db5602e591 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_nested.snap @@ -0,0 +1,57 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\part{1}\\chapter{2}\\section{3}\\subsection{4}\\subsubsection{5}\\paragraph{6}\\subparagraph{7}\"#)" + +--- +ROOT@0..90 + PREAMBLE@0..90 + PART@0..90 + PART_NAME@0..5 "\\part" + CURLY_GROUP@5..8 + L_CURLY@5..6 "{" + TEXT@6..7 + WORD@6..7 "1" + R_CURLY@7..8 "}" + CHAPTER@8..90 + CHAPTER_NAME@8..16 "\\chapter" + CURLY_GROUP@16..19 + L_CURLY@16..17 "{" + TEXT@17..18 + WORD@17..18 "2" + R_CURLY@18..19 "}" + SECTION@19..90 + SECTION_NAME@19..27 "\\section" + CURLY_GROUP@27..30 + L_CURLY@27..28 "{" + TEXT@28..29 + WORD@28..29 "3" + R_CURLY@29..30 "}" + SUBSECTION@30..90 + SUBSECTION_NAME@30..41 "\\subsection" + CURLY_GROUP@41..44 + L_CURLY@41..42 "{" + TEXT@42..43 + WORD@42..43 "4" + R_CURLY@43..44 "}" + SUBSUBSECTION@44..90 + SUBSUBSECTION_NAME@44..58 "\\subsubsection" + CURLY_GROUP@58..61 + L_CURLY@58..59 "{" + TEXT@59..60 + WORD@59..60 "5" + R_CURLY@60..61 "}" + PARAGRAPH@61..90 + PARAGRAPH_NAME@61..71 "\\paragraph" + CURLY_GROUP@71..74 + L_CURLY@71..72 "{" + TEXT@72..73 + WORD@72..73 "6" + R_CURLY@73..74 "}" + SUBPARAGRAPH@74..90 + SUBPARAGRAPH_NAME@74..87 "\\subparagraph" + CURLY_GROUP@87..90 + L_CURLY@87..88 "{" + TEXT@88..89 + WORD@88..89 "7" + R_CURLY@89..90 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_siblings.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_siblings.snap new file mode 100644 index 0000000000..94d2ef40bd --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_siblings.snap @@ -0,0 +1,29 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\section{Foo} Foo \\section{Bar} Bar\"#)" + +--- +ROOT@0..35 + PREAMBLE@0..35 + SECTION@0..18 + SECTION_NAME@0..8 "\\section" + CURLY_GROUP@8..14 + L_CURLY@8..9 "{" + TEXT@9..12 + WORD@9..12 "Foo" + R_CURLY@12..13 "}" + WHITESPACE@13..14 " " + TEXT@14..18 + WORD@14..17 "Foo" + WHITESPACE@17..18 " " + SECTION@18..35 + SECTION_NAME@18..26 "\\section" + CURLY_GROUP@26..32 + L_CURLY@26..27 "{" + TEXT@27..30 + WORD@27..30 "Bar" + R_CURLY@30..31 "}" + WHITESPACE@31..32 " " + TEXT@32..35 + WORD@32..35 "Bar" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_options.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_options.snap new file mode 100644 index 0000000000..863f27cf56 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_options.snap @@ -0,0 +1,25 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\includesvg[scale=.5]{foo/bar.svg}\"#)" + +--- +ROOT@0..34 + PREAMBLE@0..34 + SVG_INCLUDE@0..34 + SVG_INCLUDE_NAME@0..11 "\\includesvg" + BRACK_GROUP_KEY_VALUE@11..21 + L_BRACK@11..12 "[" + KEY_VALUE_BODY@12..20 + KEY_VALUE_PAIR@12..20 + KEY@12..17 + WORD@12..17 "scale" + EQUALITY_SIGN@17..18 "=" + VALUE@18..20 + TEXT@18..20 + WORD@18..20 ".5" + R_BRACK@20..21 "]" + CURLY_GROUP_WORD_LIST@21..34 + L_CURLY@21..22 "{" + WORD@22..33 "foo/bar.svg" + R_CURLY@33..34 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_simple.snap new file mode 100644 index 0000000000..02db942d99 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\includesvg{foo/bar.svg}\"#)" + +--- +ROOT@0..24 + PREAMBLE@0..24 + SVG_INCLUDE@0..24 + SVG_INCLUDE_NAME@0..11 "\\includesvg" + CURLY_GROUP_WORD_LIST@11..24 + L_CURLY@11..12 "{" + WORD@12..23 "foo/bar.svg" + R_CURLY@23..24 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_full.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_full.snap new file mode 100644 index 0000000000..d8fe3816ad --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_full.snap @@ -0,0 +1,27 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newtheorem{foo}[bar]{Foo}[baz]\"#)" + +--- +ROOT@0..31 + PREAMBLE@0..31 + THEOREM_DEFINITION@0..31 + THEOREM_DEFINITION_NAME@0..11 "\\newtheorem" + CURLY_GROUP_WORD@11..16 + L_CURLY@11..12 "{" + WORD@12..15 "foo" + R_CURLY@15..16 "}" + BRACK_GROUP_WORD@16..21 + L_BRACK@16..17 "[" + WORD@17..20 "bar" + R_BRACK@20..21 "]" + CURLY_GROUP@21..26 + L_CURLY@21..22 "{" + TEXT@22..25 + WORD@22..25 "Foo" + R_CURLY@25..26 "}" + BRACK_GROUP_WORD@26..31 + L_BRACK@26..27 "[" + WORD@27..30 "baz" + R_BRACK@30..31 "]" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_counter.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_counter.snap new file mode 100644 index 0000000000..9e550b19a4 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_counter.snap @@ -0,0 +1,19 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newtheorem{foo}[bar]\"#)" + +--- +ROOT@0..21 + PREAMBLE@0..21 + THEOREM_DEFINITION@0..21 + THEOREM_DEFINITION_NAME@0..11 "\\newtheorem" + CURLY_GROUP_WORD@11..16 + L_CURLY@11..12 "{" + WORD@12..15 "foo" + R_CURLY@15..16 "}" + BRACK_GROUP_WORD@16..21 + L_BRACK@16..17 "[" + WORD@17..20 "bar" + R_BRACK@20..21 "]" + MISSING@21..21 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description.snap new file mode 100644 index 0000000000..356dc079f1 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description.snap @@ -0,0 +1,19 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newtheorem{foo}{Foo}\"#)" + +--- +ROOT@0..21 + PREAMBLE@0..21 + THEOREM_DEFINITION@0..21 + THEOREM_DEFINITION_NAME@0..11 "\\newtheorem" + CURLY_GROUP_WORD@11..16 + L_CURLY@11..12 "{" + WORD@12..15 "foo" + R_CURLY@15..16 "}" + CURLY_GROUP@16..21 + L_CURLY@16..17 "{" + TEXT@17..20 + WORD@17..20 "Foo" + R_CURLY@20..21 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description_and_counter.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description_and_counter.snap new file mode 100644 index 0000000000..cc6e34d378 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description_and_counter.snap @@ -0,0 +1,23 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newtheorem{foo}[bar]{Foo}\"#)" + +--- +ROOT@0..26 + PREAMBLE@0..26 + THEOREM_DEFINITION@0..26 + THEOREM_DEFINITION_NAME@0..11 "\\newtheorem" + CURLY_GROUP_WORD@11..16 + L_CURLY@11..12 "{" + WORD@12..15 "foo" + R_CURLY@15..16 "}" + BRACK_GROUP_WORD@16..21 + L_BRACK@16..17 "[" + WORD@17..20 "bar" + R_BRACK@20..21 "]" + CURLY_GROUP@21..26 + L_CURLY@21..22 "{" + TEXT@22..25 + WORD@22..25 "Foo" + R_CURLY@25..26 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_only_name.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_only_name.snap new file mode 100644 index 0000000000..27a040b7ff --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_only_name.snap @@ -0,0 +1,15 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\newtheorem{foo}\"#)" + +--- +ROOT@0..16 + PREAMBLE@0..16 + THEOREM_DEFINITION@0..16 + THEOREM_DEFINITION_NAME@0..11 "\\newtheorem" + CURLY_GROUP_WORD@11..16 + L_CURLY@11..12 "{" + WORD@12..15 "foo" + R_CURLY@15..16 "}" + MISSING@16..16 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__tikz_library_import_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__tikz_library_import_simple.snap new file mode 100644 index 0000000000..4915306c55 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__tikz_library_import_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\usetikzlibrary{foo}\"#)" + +--- +ROOT@0..20 + PREAMBLE@0..20 + TIKZ_LIBRARY_IMPORT@0..20 + TIKZ_LIBRARY_IMPORT_NAME@0..15 "\\usetikzlibrary" + CURLY_GROUP_WORD_LIST@15..20 + L_CURLY@15..16 "{" + WORD@16..19 "foo" + R_CURLY@19..20 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_braces.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_braces.snap new file mode 100644 index 0000000000..df463f501a --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_braces.snap @@ -0,0 +1,13 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"}{\"#)" + +--- +ROOT@0..2 + PREAMBLE@0..2 + ERROR@0..1 + R_CURLY@0..1 "}" + CURLY_GROUP@1..2 + L_CURLY@1..2 "{" + MISSING@2..2 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets.snap new file mode 100644 index 0000000000..578cbf6099 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets.snap @@ -0,0 +1,13 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"][\"#)" + +--- +ROOT@0..2 + PREAMBLE@0..2 + ERROR@0..1 + R_BRACK@0..1 "]" + MIXED_GROUP@1..2 + L_BRACK@1..2 "[" + MISSING@2..2 "" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets_with_group.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets_with_group.snap new file mode 100644 index 0000000000..d929c98c46 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets_with_group.snap @@ -0,0 +1,16 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"{][}\"#)" + +--- +ROOT@0..4 + PREAMBLE@0..4 + CURLY_GROUP@0..4 + L_CURLY@0..1 "{" + ERROR@1..2 + R_BRACK@1..2 "]" + MIXED_GROUP@2..3 + L_BRACK@2..3 "[" + MISSING@3..3 "" + R_CURLY@3..4 "}" + diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__verbatim_include_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__verbatim_include_simple.snap new file mode 100644 index 0000000000..399e16d791 --- /dev/null +++ b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__verbatim_include_simple.snap @@ -0,0 +1,14 @@ +--- +source: src/syntax/latex/parser.rs +expression: "setup(r#\"\\verbatiminput{foo/bar.txt}\"#)" + +--- +ROOT@0..27 + PREAMBLE@0..27 + VERBATIM_INCLUDE@0..27 + VERBATIM_INCLUDE_NAME@0..14 "\\verbatiminput" + CURLY_GROUP_WORD_LIST@14..27 + L_CURLY@14..15 "{" + WORD@15..26 "foo/bar.txt" + R_CURLY@26..27 "}" + |