summaryrefslogtreecommitdiff
path: root/support/texlab/src/hover
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/hover')
-rw-r--r--support/texlab/src/hover/bibtex/entry_type.rs116
-rw-r--r--support/texlab/src/hover/bibtex/field.rs111
-rw-r--r--support/texlab/src/hover/bibtex/mod.rs3
-rw-r--r--support/texlab/src/hover/bibtex/string_reference.rs165
-rw-r--r--support/texlab/src/hover/latex/citation.rs179
-rw-r--r--support/texlab/src/hover/latex/component.rs95
-rw-r--r--support/texlab/src/hover/latex/label.rs118
-rw-r--r--support/texlab/src/hover/latex/mod.rs6
-rw-r--r--support/texlab/src/hover/latex/preview.rs338
-rw-r--r--support/texlab/src/hover/mod.rs58
10 files changed, 0 insertions, 1189 deletions
diff --git a/support/texlab/src/hover/bibtex/entry_type.rs b/support/texlab/src/hover/bibtex/entry_type.rs
deleted file mode 100644
index 1e009565d7..0000000000
--- a/support/texlab/src/hover/bibtex/entry_type.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-use crate::{
- feature::{FeatureProvider, FeatureRequest},
- protocol::{
- Hover, HoverContents, MarkupContent, MarkupKind, RangeExt, TextDocumentPositionParams,
- },
- syntax::{SyntaxNode, LANGUAGE_DATA},
-};
-use async_trait::async_trait;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
-pub struct BibtexEntryTypeHoverProvider;
-
-#[async_trait]
-impl FeatureProvider for BibtexEntryTypeHoverProvider {
- type Params = TextDocumentPositionParams;
- type Output = Option<Hover>;
-
- async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
- let tree = req.current().content.as_bibtex()?;
- for entry in tree
- .children(tree.root)
- .filter_map(|node| tree.as_entry(node))
- {
- if entry.ty.range().contains(req.params.position) {
- let ty = &entry.ty.text()[1..];
- let docs = LANGUAGE_DATA.entry_type_documentation(ty)?;
- return Some(Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: docs.into(),
- }),
- range: Some(entry.ty.range()),
- });
- }
- }
- None
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{feature::FeatureTester, protocol::Range};
-
- #[tokio::test]
- async fn empty_latex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", "")
- .main("main.tex")
- .position(0, 0)
- .test_position(BibtexEntryTypeHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn empty_bibtex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "")
- .main("main.bib")
- .position(0, 0)
- .test_position(BibtexEntryTypeHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn known_entry_type() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "@article{foo,}")
- .main("main.bib")
- .position(0, 3)
- .test_position(BibtexEntryTypeHoverProvider)
- .await
- .unwrap();
-
- let expected_hover = Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: LANGUAGE_DATA
- .entry_type_documentation("article")
- .unwrap()
- .into(),
- }),
- range: Some(Range::new_simple(0, 0, 0, 8)),
- };
-
- assert_eq!(actual_hover, expected_hover);
- }
-
- #[tokio::test]
- async fn unknown_entry_type() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "@foo{bar,}")
- .main("main.bib")
- .position(0, 3)
- .test_position(BibtexEntryTypeHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn entry_key() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "@article{foo,}")
- .main("main.bib")
- .position(0, 11)
- .test_position(BibtexEntryTypeHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-}
diff --git a/support/texlab/src/hover/bibtex/field.rs b/support/texlab/src/hover/bibtex/field.rs
deleted file mode 100644
index 4b00f3364c..0000000000
--- a/support/texlab/src/hover/bibtex/field.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-use crate::{
- feature::{FeatureProvider, FeatureRequest},
- protocol::{
- Hover, HoverContents, MarkupContent, MarkupKind, RangeExt, TextDocumentPositionParams,
- },
- syntax::{SyntaxNode, LANGUAGE_DATA},
-};
-use async_trait::async_trait;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
-pub struct BibtexFieldHoverProvider;
-
-#[async_trait]
-impl FeatureProvider for BibtexFieldHoverProvider {
- type Params = TextDocumentPositionParams;
- type Output = Option<Hover>;
-
- async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
- let tree = req.current().content.as_bibtex()?;
- let name = tree
- .find(req.params.position)
- .into_iter()
- .filter_map(|node| tree.as_field(node))
- .map(|field| &field.name)
- .find(|name| name.range().contains(req.params.position))?;
-
- let docs = LANGUAGE_DATA.field_documentation(name.text())?;
- Some(Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: docs.into(),
- }),
- range: Some(name.range()),
- })
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{feature::FeatureTester, protocol::Range};
-
- #[tokio::test]
- async fn empty_latex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", "")
- .main("main.tex")
- .position(0, 0)
- .test_position(BibtexFieldHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn empty_bibtex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "")
- .main("main.bib")
- .position(0, 0)
- .test_position(BibtexFieldHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn known_field() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "@article{foo, author = bar}")
- .main("main.bib")
- .position(0, 15)
- .test_position(BibtexFieldHoverProvider)
- .await
- .unwrap();
-
- let expected_hover = Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: LANGUAGE_DATA.field_documentation("author").unwrap().into(),
- }),
- range: Some(Range::new_simple(0, 14, 0, 20)),
- };
-
- assert_eq!(actual_hover, expected_hover);
- }
-
- #[tokio::test]
- async fn unknown_field() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "@article{foo, bar = baz}")
- .main("main.bib")
- .position(0, 15)
- .test_position(BibtexFieldHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn entry_key() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "@article{foo, bar = baz}")
- .main("main.bib")
- .position(0, 11)
- .test_position(BibtexFieldHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-}
diff --git a/support/texlab/src/hover/bibtex/mod.rs b/support/texlab/src/hover/bibtex/mod.rs
deleted file mode 100644
index 59ff356fa0..0000000000
--- a/support/texlab/src/hover/bibtex/mod.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub mod entry_type;
-pub mod field;
-pub mod string_reference;
diff --git a/support/texlab/src/hover/bibtex/string_reference.rs b/support/texlab/src/hover/bibtex/string_reference.rs
deleted file mode 100644
index 46724a4f60..0000000000
--- a/support/texlab/src/hover/bibtex/string_reference.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-use crate::{
- feature::{FeatureProvider, FeatureRequest},
- protocol::{
- BibtexFormattingOptions, Hover, HoverContents, MarkupContent, MarkupKind, Position,
- TextDocumentPositionParams,
- },
- syntax::{bibtex, SyntaxNode},
-};
-use async_trait::async_trait;
-use petgraph::graph::NodeIndex;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
-pub struct BibtexStringReferenceHoverProvider;
-
-#[async_trait]
-impl FeatureProvider for BibtexStringReferenceHoverProvider {
- type Params = TextDocumentPositionParams;
- type Output = Option<Hover>;
-
- async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
- let tree = req.current().content.as_bibtex()?;
- let reference = Self::find_reference(tree, req.params.position)?;
- for string_node in tree.children(tree.root) {
- let hover = Self::find_definition(tree, string_node, reference);
- if hover.is_some() {
- return hover;
- }
- }
- None
- }
-}
-
-impl BibtexStringReferenceHoverProvider {
- fn find_reference(tree: &bibtex::Tree, pos: Position) -> Option<&bibtex::Token> {
- let mut results = tree.find(pos);
- results.reverse();
- match (
- &tree.graph[results[0]],
- results.get(1).map(|node| &tree.graph[*node]),
- ) {
- (bibtex::Node::Word(reference), Some(bibtex::Node::Concat(_))) => {
- Some(&reference.token)
- }
- (bibtex::Node::Word(reference), Some(bibtex::Node::Field(_))) => Some(&reference.token),
- _ => None,
- }
- }
-
- fn find_definition(
- tree: &bibtex::Tree,
- string_node: NodeIndex,
- reference: &bibtex::Token,
- ) -> Option<Hover> {
- let string = tree.as_string(string_node)?;
- if string.name.as_ref()?.text() != reference.text() {
- return None;
- }
-
- let options = BibtexFormattingOptions {
- line_length: None,
- formatter: None,
- };
- let text = bibtex::format(
- tree,
- tree.children(string_node).next()?,
- bibtex::FormattingParams {
- tab_size: 4,
- insert_spaces: true,
- options: &options,
- },
- );
- Some(Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::PlainText,
- value: text,
- }),
- range: Some(reference.range()),
- })
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{
- feature::FeatureTester,
- protocol::{Range, RangeExt},
- };
- use indoc::indoc;
-
- #[tokio::test]
- async fn empty_latex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", "")
- .main("main.tex")
- .position(0, 0)
- .test_position(BibtexStringReferenceHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn empty_bibtex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "")
- .main("main.bib")
- .position(0, 0)
- .test_position(BibtexStringReferenceHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn inside_reference() {
- let actual_hover = FeatureTester::new()
- .file(
- "main.bib",
- indoc!(
- r#"
- @string{foo = "Foo"}
- @string{bar = "Bar"}
- @article{baz, author = bar}
- "#
- ),
- )
- .main("main.bib")
- .position(2, 24)
- .test_position(BibtexStringReferenceHoverProvider)
- .await
- .unwrap();
-
- let expected_hover = Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::PlainText,
- value: "\"Bar\"".into(),
- }),
- range: Some(Range::new_simple(2, 23, 2, 26)),
- };
-
- assert_eq!(actual_hover, expected_hover);
- }
-
- #[tokio::test]
- async fn outside_reference() {
- let actual_hover = FeatureTester::new()
- .file(
- "main.bib",
- indoc!(
- r#"
- @string{foo = "Foo"}
- @string{bar = "Bar"}
- @article{baz, author = bar}
- "#
- ),
- )
- .main("main.bib")
- .position(2, 20)
- .test_position(BibtexStringReferenceHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-}
diff --git a/support/texlab/src/hover/latex/citation.rs b/support/texlab/src/hover/latex/citation.rs
deleted file mode 100644
index 8b5468e52e..0000000000
--- a/support/texlab/src/hover/latex/citation.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-use crate::{
- citeproc::render_citation,
- feature::{FeatureProvider, FeatureRequest},
- protocol::{Hover, HoverContents, RangeExt, TextDocumentPositionParams},
- syntax::{bibtex, Span, SyntaxNode},
- workspace::DocumentContent,
-};
-use async_trait::async_trait;
-use log::warn;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
-pub struct LatexCitationHoverProvider;
-
-#[async_trait]
-impl FeatureProvider for LatexCitationHoverProvider {
- type Params = TextDocumentPositionParams;
- type Output = Option<Hover>;
-
- async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
- let (tree, src_key, entry) = Self::get_entry(req)?;
- if entry.is_comment() {
- None
- } else {
- let key = entry.key.as_ref()?;
- match render_citation(&tree, key.text()) {
- Some(markdown) => Some(Hover {
- contents: HoverContents::Markup(markdown),
- range: Some(src_key.range()),
- }),
- None => {
- warn!("Failed to render entry: {}", key.text());
- None
- }
- }
- }
- }
-}
-
-impl LatexCitationHoverProvider {
- fn get_entry(
- req: &FeatureRequest<TextDocumentPositionParams>,
- ) -> Option<(&bibtex::Tree, &Span, &bibtex::Entry)> {
- let key = Self::get_key(req)?;
- for tree in req
- .related()
- .iter()
- .filter_map(|doc| doc.content.as_bibtex())
- {
- for entry in tree
- .children(tree.root)
- .filter_map(|node| tree.as_entry(node))
- {
- if let Some(current_key) = &entry.key {
- if current_key.text() == key.text {
- return Some((tree, key, entry));
- }
- }
- }
- }
- None
- }
-
- fn get_key(req: &FeatureRequest<TextDocumentPositionParams>) -> Option<&Span> {
- match &req.current().content {
- DocumentContent::Latex(table) => table
- .citations
- .iter()
- .flat_map(|citation| citation.keys(&table))
- .find(|key| key.range().contains(req.params.position))
- .map(|token| &token.span),
- DocumentContent::Bibtex(tree) => tree
- .children(tree.root)
- .filter_map(|node| tree.as_entry(node))
- .filter_map(|entry| entry.key.as_ref())
- .find(|key| key.range().contains(req.params.position))
- .map(|token| &token.span),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{
- feature::FeatureTester,
- protocol::{MarkupContent, MarkupKind, Range, RangeExt},
- };
- use indoc::indoc;
-
- #[tokio::test]
- async fn empty_latex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", "")
- .main("main.tex")
- .position(0, 0)
- .test_position(LatexCitationHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn empty_bibtex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "")
- .main("main.bib")
- .position(0, 0)
- .test_position(LatexCitationHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn inside_label() {
- let actual_hover = FeatureTester::new()
- .file(
- "main.bib",
- "@article{foo, author = {Foo Bar}, title = {Baz Qux}, year = 1337}",
- )
- .file(
- "main.tex",
- indoc!(
- r#"
- \addbibresource{main.bib}
- \cite{foo}
- "#
- ),
- )
- .main("main.tex")
- .position(1, 7)
- .test_position(LatexCitationHoverProvider)
- .await
- .unwrap();
-
- let expected_hover = Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: "Bar, F. (1337). *Baz Qux*.".into(),
- }),
- range: Some(Range::new_simple(1, 6, 1, 9)),
- };
-
- assert_eq!(actual_hover, expected_hover);
- }
-
- #[tokio::test]
- async fn inside_entry() {
- let actual_hover = FeatureTester::new()
- .file(
- "main.bib",
- "@article{foo, author = {Foo Bar}, title = {Baz Qux}, year = 1337}",
- )
- .file(
- "main.tex",
- indoc!(
- r#"
- \addbibresource{main.bib}
- \cite{foo}
- "#
- ),
- )
- .main("main.bib")
- .position(0, 11)
- .test_position(LatexCitationHoverProvider)
- .await
- .unwrap();
-
- let expected_hover = Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: "Bar, F. (1337). *Baz Qux*.".into(),
- }),
- range: Some(Range::new_simple(0, 9, 0, 12)),
- };
-
- assert_eq!(actual_hover, expected_hover);
- }
-}
diff --git a/support/texlab/src/hover/latex/component.rs b/support/texlab/src/hover/latex/component.rs
deleted file mode 100644
index 5285ec795a..0000000000
--- a/support/texlab/src/hover/latex/component.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use crate::{
- components::COMPONENT_DATABASE,
- feature::{FeatureProvider, FeatureRequest},
- protocol::{Hover, HoverContents, RangeExt, TextDocumentPositionParams},
- syntax::{LatexIncludeKind, SyntaxNode},
-};
-use async_trait::async_trait;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
-pub struct LatexComponentHoverProvider;
-
-#[async_trait]
-impl FeatureProvider for LatexComponentHoverProvider {
- type Params = TextDocumentPositionParams;
- type Output = Option<Hover>;
-
- async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
- let table = req.current().content.as_latex()?;
- for include in &table.includes {
- match include.kind {
- LatexIncludeKind::Package | LatexIncludeKind::Class => {
- for path in include.paths(&table) {
- if path.range().contains(req.params.position) {
- let docs = COMPONENT_DATABASE.documentation(path.text())?;
- return Some(Hover {
- contents: HoverContents::Markup(docs),
- range: Some(path.range()),
- });
- }
- }
- }
- _ => {}
- }
- }
- None
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{
- feature::FeatureTester,
- protocol::{Range, RangeExt},
- };
-
- #[tokio::test]
- async fn empty_latex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", "")
- .main("main.tex")
- .position(0, 0)
- .test_position(LatexComponentHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn empty_bibtex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "")
- .main("main.bib")
- .position(0, 0)
- .test_position(LatexComponentHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn known_package() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", r#"\usepackage{amsmath}"#)
- .main("main.tex")
- .position(0, 15)
- .test_position(LatexComponentHoverProvider)
- .await
- .unwrap();
-
- assert_eq!(actual_hover.range.unwrap(), Range::new_simple(0, 12, 0, 19));
- }
-
- #[tokio::test]
- async fn unknown_class() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", r#"\documentclass{abcdefghijklmnop}"#)
- .main("main.tex")
- .position(0, 20)
- .test_position(LatexComponentHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-}
diff --git a/support/texlab/src/hover/latex/label.rs b/support/texlab/src/hover/latex/label.rs
deleted file mode 100644
index 66724d442b..0000000000
--- a/support/texlab/src/hover/latex/label.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-use crate::{
- feature::{DocumentView, FeatureProvider, FeatureRequest},
- outline::{Outline, OutlineContext},
- protocol::{Hover, HoverContents, Position, RangeExt, TextDocumentPositionParams},
- syntax::{latex, LatexLabelKind, SyntaxNode},
- workspace::{Document, DocumentContent},
-};
-use async_trait::async_trait;
-use std::sync::Arc;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
-pub struct LatexLabelHoverProvider;
-
-#[async_trait]
-impl FeatureProvider for LatexLabelHoverProvider {
- type Params = TextDocumentPositionParams;
- type Output = Option<Hover>;
-
- async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
- let table = req.current().content.as_latex()?;
- let reference = Self::find_reference(table, req.params.position)?;
- let (doc, def) = Self::find_definition(&req.view, reference)?;
-
- let snapshot = Arc::clone(&req.view.snapshot);
- let view = DocumentView::analyze(snapshot, doc, &req.options, &req.current_dir);
- let outline = Outline::analyze(&view, &req.options, &req.current_dir);
- let outline_ctx = OutlineContext::parse(&view, &outline, def)?;
- let markup = outline_ctx.documentation();
- Some(Hover {
- contents: HoverContents::Markup(markup),
- range: Some(reference.range()),
- })
- }
-}
-
-impl LatexLabelHoverProvider {
- fn find_reference(table: &latex::SymbolTable, pos: Position) -> Option<&latex::Token> {
- for label in &table.labels {
- let names = label.names(&table);
- if names.len() == 1 && table[label.parent].range().contains(pos) {
- return Some(&label.names(&table)[0]);
- }
-
- for name in &names {
- if name.range().contains(pos) {
- return Some(name);
- }
- }
- }
- None
- }
-
- fn find_definition(
- view: &DocumentView,
- reference: &latex::Token,
- ) -> Option<(Arc<Document>, latex::Label)> {
- for doc in &view.related {
- if let DocumentContent::Latex(table) = &doc.content {
- for label in &table.labels {
- if label.kind == LatexLabelKind::Definition {
- for name in label.names(&table) {
- if name.text() == reference.text() {
- return Some((Arc::clone(&doc), *label));
- }
- }
- }
- }
- }
- }
- None
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{
- feature::FeatureTester,
- protocol::{Range, RangeExt},
- };
-
- #[tokio::test]
- async fn empty_latex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", "")
- .main("main.tex")
- .position(0, 0)
- .test_position(LatexLabelHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn empty_bibtex_document() {
- let actual_hover = FeatureTester::new()
- .file("main.bib", "")
- .main("main.bib")
- .position(0, 0)
- .test_position(LatexLabelHoverProvider)
- .await;
-
- assert_eq!(actual_hover, None);
- }
-
- #[tokio::test]
- async fn section() {
- let actual_hover = FeatureTester::new()
- .file("main.tex", r#"\section{Foo}\label{sec:foo}"#)
- .main("main.tex")
- .position(0, 23)
- .test_position(LatexLabelHoverProvider)
- .await
- .unwrap();
-
- assert_eq!(actual_hover.range.unwrap(), Range::new_simple(0, 20, 0, 27));
- }
-}
diff --git a/support/texlab/src/hover/latex/mod.rs b/support/texlab/src/hover/latex/mod.rs
deleted file mode 100644
index c119bfc832..0000000000
--- a/support/texlab/src/hover/latex/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#[cfg(feature = "citation")]
-pub mod citation;
-
-pub mod component;
-pub mod label;
-pub mod preview;
diff --git a/support/texlab/src/hover/latex/preview.rs b/support/texlab/src/hover/latex/preview.rs
deleted file mode 100644
index 8d2ca00cb5..0000000000
--- a/support/texlab/src/hover/latex/preview.rs
+++ /dev/null
@@ -1,338 +0,0 @@
-use crate::{
- components::COMPONENT_DATABASE,
- feature::{FeatureProvider, FeatureRequest},
- protocol::{
- ClientCapabilitiesExt, Hover, HoverContents, MarkupContent, MarkupKind, Range, RangeExt,
- TextDocumentPositionParams,
- },
- syntax::{latex, CharStream, LatexIncludeKind, SyntaxNode},
- tex::{CompileError, CompileParams, DistributionKind, Format},
- workspace::DocumentContent,
-};
-use async_trait::async_trait;
-use image::{png::PNGEncoder, ColorType, DynamicImage, GenericImageView, ImageBuffer, RgbaImage};
-use io::Cursor;
-use log::warn;
-use std::{io, process::Stdio, time::Duration};
-use tempfile::TempDir;
-use thiserror::Error;
-use tokio::process::Command;
-
-const PREVIEW_ENVIRONMENTS: &[&str] = &[
- "align",
- "alignat",
- "aligned",
- "alignedat",
- "algorithmic",
- "array",
- "Bmatrix",
- "bmatrix",
- "cases",
- "CD",
- "eqnarray",
- "equation",
- "gather",
- "gathered",
- "matrix",
- "multline",
- "pmatrix",
- "smallmatrix",
- "split",
- "subarray",
- "Vmatrix",
- "vmatrix",
-];
-
-const IGNORED_PACKAGES: &[&str] = &["biblatex", "pgf", "tikz"];
-
-#[derive(Debug, Clone, Copy)]
-enum MathElement {
- Environment(latex::Environment),
- Equation(latex::Equation),
- Inline(latex::Inline),
-}
-
-impl MathElement {
- fn range(&self, tree: &latex::Tree) -> Range {
- match self {
- Self::Environment(env) => env.range(tree),
- Self::Equation(eq) => eq.range(tree),
- Self::Inline(inline) => inline.range(tree),
- }
- }
-}
-
-#[derive(Debug, Error)]
-enum RenderError {
- #[error("an I/O error occurred: `{0}`")]
- IO(#[from] io::Error),
- #[error("a compile error occurred: `{0}`")]
- Compile(#[from] CompileError),
- #[error("compilation failed")]
- DviNotFound,
- #[error("dvipng is not installed")]
- DviPngNotInstalled,
- #[error("calling dvipng failed")]
- DviPngFaulty,
- #[error("failed to decode image")]
- DecodeImage,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
-pub struct LatexPreviewHoverProvider;
-
-impl LatexPreviewHoverProvider {
- fn is_preview_environment(
- req: &FeatureRequest<TextDocumentPositionParams>,
- table: &latex::SymbolTable,
- environment: latex::Environment,
- ) -> bool {
- let canonical_name = environment
- .left
- .name(&table)
- .map(latex::Token::text)
- .unwrap_or_default()
- .replace('*', "");
-
- PREVIEW_ENVIRONMENTS.contains(&canonical_name.as_ref())
- || Self::theorem_environments(req).contains(&canonical_name.as_ref())
- }
-
- fn theorem_environments(req: &FeatureRequest<TextDocumentPositionParams>) -> Vec<&str> {
- let mut names = Vec::new();
- for doc in req.related() {
- if let DocumentContent::Latex(table) = &doc.content {
- table
- .theorem_definitions
- .iter()
- .map(|thm| thm.name(&table).text())
- .for_each(|thm| names.push(thm));
- }
- }
- names
- }
-
- async fn render(
- req: &FeatureRequest<TextDocumentPositionParams>,
- range: Range,
- ) -> Result<Hover, RenderError> {
- let code = Self::generate_code(req, range);
- let params = CompileParams {
- file_name: "preview.tex",
- code: &code,
- format: Format::Latex,
- timeout: Duration::from_secs(10),
- };
- let dir = req.distro.compile(params).await?.dir;
- if !dir.path().join("preview.dvi").exists() {
- return Err(RenderError::DviNotFound);
- }
-
- let img = Self::add_margin(Self::dvipng(&dir).await?);
- let base64 = Self::encode_image(img);
- let markdown = format!("![preview](data:image/png;base64,{})", base64);
- dir.close()?;
- Ok(Hover {
- contents: HoverContents::Markup(MarkupContent {
- kind: MarkupKind::Markdown,
- value: markdown,
- }),
- range: Some(range),
- })
- }
-
- fn generate_code(req: &FeatureRequest<TextDocumentPositionParams>, range: Range) -> String {
- let mut code = String::new();
- code.push_str("\\documentclass{article}\n");
- code.push_str("\\thispagestyle{empty}\n");
- Self::generate_includes(req, &mut code);
- Self::generate_command_definitions(req, &mut code);
- Self::generate_math_operators(req, &mut code);
- Self::generate_theorem_definitions(req, &mut code);
- code.push_str("\\begin{document}\n");
- code.push_str(&CharStream::extract(&req.current().text, range));
- code.push('\n');
- code.push_str("\\end{document}\n");
- code
- }
-
- fn generate_includes(req: &FeatureRequest<TextDocumentPositionParams>, code: &mut String) {
- for doc in req.related() {
- if let DocumentContent::Latex(table) = &doc.content {
- let text = &doc.text;
- for include in &table.includes {
- if include.kind == LatexIncludeKind::Package {
- if include
- .paths(&table)
- .iter()
- .all(|path| IGNORED_PACKAGES.contains(&path.text()))
- {
- continue;
- }
-
- if include
- .paths(&table)
- .iter()
- .map(|path| format!("{}.sty", path.text()))
- .any(|name| !COMPONENT_DATABASE.exists(&name))
- {
- continue;
- }
-
- code.push_str(&CharStream::extract(&text, table[include.parent].range()));
- code.push('\n');
- }
- }
- }
- }
- }
-
- fn generate_command_definitions(
- req: &FeatureRequest<TextDocumentPositionParams>,
- code: &mut String,
- ) {
- for doc in req.related() {
- if let DocumentContent::Latex(table) = &doc.content {
- table
- .command_definitions
- .iter()
- .filter(|def| !def.definition_name(&table).contains("@"))
- .map(|def| CharStream::extract(&doc.text, table[def.parent].range()))
- .for_each(|def| {
- code.push_str(&def);
- code.push('\n');
- });
- }
- }
- }
-
- fn generate_math_operators(
- req: &FeatureRequest<TextDocumentPositionParams>,
- code: &mut String,
- ) {
- for doc in req.related() {
- if let DocumentContent::Latex(table) = &doc.content {
- table
- .math_operators
- .iter()
- .filter(|op| !op.definition_name(&table).contains("@"))
- .map(|op| CharStream::extract(&doc.text, table[op.parent].range()))
- .for_each(|op| {
- code.push_str(&op);
- code.push('\n');
- });
- }
- }
- }
-
- fn generate_theorem_definitions(
- req: &FeatureRequest<TextDocumentPositionParams>,
- code: &mut String,
- ) {
- for doc in req.related() {
- if let DocumentContent::Latex(table) = &doc.content {
- table
- .theorem_definitions
- .iter()
- .map(|thm| CharStream::extract(&doc.text, table[thm.parent].range()))
- .for_each(|thm| {
- code.push_str(&thm);
- code.push('\n');
- })
- }
- }
- }
-
- async fn dvipng(dir: &TempDir) -> Result<DynamicImage, RenderError> {
- let process = Command::new("dvipng")
- .args(&["-D", "175", "-T", "tight", "preview.dvi"])
- .current_dir(dir.path())
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .spawn()
- .map_err(|_| RenderError::DviPngNotInstalled)?;
-
- process.await.map_err(|_| RenderError::DviPngFaulty)?;
-
- let png_file = dir.path().join("preview1.png");
- let png = image::open(png_file).map_err(|_| RenderError::DecodeImage)?;
- Ok(png)
- }
-
- fn add_margin(image: DynamicImage) -> RgbaImage {
- let margin = 5;
- let width = image.width() + 2 * margin;
- let height = image.height() + 2 * margin;
- let mut result =
- ImageBuffer::from_pixel(width, height, image::Rgba([0xFF, 0xFF, 0xFF, 0xFF]));
-
- for x in 0..image.width() {
- for y in 0..image.height() {
- let pixel = image.get_pixel(x, y);
- result.put_pixel(x + margin, y + margin, pixel);
- }
- }
- result
- }
-
- fn encode_image(image: RgbaImage) -> String {
- let mut image_buf = Cursor::new(Vec::new());
- let png_encoder = PNGEncoder::new(&mut image_buf);
- let width = image.width();
- let height = image.height();
- png_encoder
- .encode(&image.into_raw(), width, height, ColorType::Rgba8)
- .unwrap();
- base64::encode(&image_buf.into_inner())
- }
-}
-
-#[async_trait]
-impl FeatureProvider for LatexPreviewHoverProvider {
- type Params = TextDocumentPositionParams;
- type Output = Option<Hover>;
-
- async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
- if !req.client_capabilities.has_hover_markdown_support()
- || req.distro.kind() == DistributionKind::Tectonic
- {
- return None;
- }
-
- if let DocumentContent::Latex(table) = &req.current().content {
- let mut elements = Vec::new();
- table
- .inlines
- .iter()
- .map(|inline| MathElement::Inline(*inline))
- .for_each(|inline| elements.push(inline));
-
- table
- .equations
- .iter()
- .map(|eq| MathElement::Equation(*eq))
- .for_each(|eq| elements.push(eq));
-
- table
- .environments
- .iter()
- .filter(|env| Self::is_preview_environment(req, table, **env))
- .map(|env| MathElement::Environment(*env))
- .for_each(|env| elements.push(env));
-
- let range = elements
- .iter()
- .map(|elem| elem.range(&table))
- .find(|range| range.contains(req.params.position))?;
-
- return match Self::render(req, range).await {
- Ok(hover) => Some(hover),
- Err(why) => {
- warn!("Preview failed: {}", why);
- None
- }
- };
- }
- None
- }
-}
diff --git a/support/texlab/src/hover/mod.rs b/support/texlab/src/hover/mod.rs
deleted file mode 100644
index e740657add..0000000000
--- a/support/texlab/src/hover/mod.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-mod bibtex;
-mod latex;
-
-#[cfg(feature = "citation")]
-use self::latex::citation::LatexCitationHoverProvider;
-
-use self::{
- bibtex::{
- entry_type::BibtexEntryTypeHoverProvider, field::BibtexFieldHoverProvider,
- string_reference::BibtexStringReferenceHoverProvider,
- },
- latex::{
- component::LatexComponentHoverProvider, label::LatexLabelHoverProvider,
- preview::LatexPreviewHoverProvider,
- },
-};
-use crate::{
- feature::{ChoiceProvider, FeatureProvider, FeatureRequest},
- protocol::{Hover, TextDocumentPositionParams},
-};
-use async_trait::async_trait;
-
-pub struct HoverProvider {
- provider: ChoiceProvider<TextDocumentPositionParams, Hover>,
-}
-
-impl HoverProvider {
- pub fn new() -> Self {
- Self {
- provider: ChoiceProvider::new(vec![
- Box::new(BibtexEntryTypeHoverProvider),
- Box::new(BibtexStringReferenceHoverProvider),
- Box::new(BibtexFieldHoverProvider),
- #[cfg(feature = "citation")]
- Box::new(LatexCitationHoverProvider),
- Box::new(LatexComponentHoverProvider),
- Box::new(LatexLabelHoverProvider),
- Box::new(LatexPreviewHoverProvider),
- ]),
- }
- }
-}
-
-impl Default for HoverProvider {
- fn default() -> Self {
- Self::new()
- }
-}
-
-#[async_trait]
-impl FeatureProvider for HoverProvider {
- type Params = TextDocumentPositionParams;
- type Output = Option<Hover>;
-
- async fn execute<'a>(&'a self, req: &'a FeatureRequest<Self::Params>) -> Self::Output {
- self.provider.execute(req).await
- }
-}