summaryrefslogtreecommitdiff
path: root/support/texlab/src/syntax/latex/env.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/syntax/latex/env.rs')
-rw-r--r--support/texlab/src/syntax/latex/env.rs123
1 files changed, 123 insertions, 0 deletions
diff --git a/support/texlab/src/syntax/latex/env.rs b/support/texlab/src/syntax/latex/env.rs
new file mode 100644
index 0000000000..163db02ca8
--- /dev/null
+++ b/support/texlab/src/syntax/latex/env.rs
@@ -0,0 +1,123 @@
+use super::ast::*;
+use crate::syntax::language::*;
+use crate::syntax::text::SyntaxNode;
+use lsp_types::Range;
+use std::sync::Arc;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct LatexEnvironmentDelimiter {
+ pub command: Arc<LatexCommand>,
+}
+
+impl LatexEnvironmentDelimiter {
+ pub fn name(&self) -> Option<&LatexToken> {
+ self.command.extract_word(0)
+ }
+
+ pub fn is_math(&self) -> bool {
+ if let Some(name) = self.name() {
+ LANGUAGE_DATA
+ .math_environments
+ .iter()
+ .any(|env| env == name.text())
+ } else {
+ false
+ }
+ }
+
+ pub fn is_enum(&self) -> bool {
+ if let Some(name) = self.name() {
+ LANGUAGE_DATA
+ .enum_environments
+ .iter()
+ .any(|env| env == name.text())
+ } else {
+ false
+ }
+ }
+}
+
+impl SyntaxNode for LatexEnvironmentDelimiter {
+ fn range(&self) -> Range {
+ self.command.range()
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct LatexEnvironment {
+ pub left: LatexEnvironmentDelimiter,
+ pub right: LatexEnvironmentDelimiter,
+}
+
+impl LatexEnvironment {
+ pub fn is_root(&self) -> bool {
+ self.left
+ .name()
+ .iter()
+ .chain(self.right.name().iter())
+ .any(|name| name.text() == "document")
+ }
+
+ fn parse(commands: &[Arc<LatexCommand>]) -> Vec<Self> {
+ let mut stack = Vec::new();
+ let mut environments = Vec::new();
+ for command in commands {
+ if let Some(delimiter) = Self::parse_delimiter(command) {
+ if delimiter.command.name.text() == "\\begin" {
+ stack.push(delimiter);
+ } else if let Some(begin) = stack.pop() {
+ environments.push(Self {
+ left: begin,
+ right: delimiter,
+ });
+ }
+ }
+ }
+ environments
+ }
+
+ fn parse_delimiter(command: &Arc<LatexCommand>) -> Option<LatexEnvironmentDelimiter> {
+ if command.name.text() != "\\begin" && command.name.text() != "\\end" {
+ return None;
+ }
+
+ if command.args.is_empty() {
+ return None;
+ }
+
+ if command.has_word(0)
+ || command.args[0].children.is_empty()
+ || command.args[0].right.is_none()
+ {
+ let delimiter = LatexEnvironmentDelimiter {
+ command: Arc::clone(&command),
+ };
+ Some(delimiter)
+ } else {
+ None
+ }
+ }
+}
+
+impl SyntaxNode for LatexEnvironment {
+ fn range(&self) -> Range {
+ Range::new(self.left.start(), self.right.end())
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct LatexEnvironmentInfo {
+ pub environments: Vec<LatexEnvironment>,
+ pub is_standalone: bool,
+}
+
+impl LatexEnvironmentInfo {
+ pub fn parse(commands: &[Arc<LatexCommand>]) -> Self {
+ let environments = LatexEnvironment::parse(commands);
+ let is_standalone = environments.iter().any(LatexEnvironment::is_root);
+ Self {
+ environments,
+ is_standalone,
+ }
+ }
+}