summaryrefslogtreecommitdiff
path: root/support/texlab/src/completion/latex/import.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/completion/latex/import.rs')
-rw-r--r--support/texlab/src/completion/latex/import.rs244
1 files changed, 161 insertions, 83 deletions
diff --git a/support/texlab/src/completion/latex/import.rs b/support/texlab/src/completion/latex/import.rs
index 7f333f17ae..06c28e189b 100644
--- a/support/texlab/src/completion/latex/import.rs
+++ b/support/texlab/src/completion/latex/import.rs
@@ -1,44 +1,40 @@
use super::combinators::{self, Parameter};
-use crate::completion::factory;
-use crate::completion::DATABASE;
-use crate::syntax::*;
-use crate::workspace::*;
-use futures_boxed::boxed;
-use lsp_types::{CompletionItem, CompletionParams, TextEdit};
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct LatexClassImportProvider;
-
-impl FeatureProvider for LatexClassImportProvider {
- type Params = CompletionParams;
- type Output = Vec<CompletionItem>;
-
- #[boxed]
- async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
- import(request, LatexIncludeKind::Class, factory::class).await
- }
-}
+use crate::{
+ completion::types::{Item, ItemData},
+ components::COMPONENT_DATABASE,
+ feature::FeatureRequest,
+ protocol::CompletionParams,
+ syntax::{LatexIncludeKind, LANGUAGE_DATA},
+};
+use std::{borrow::Cow, collections::HashSet};
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct LatexPackageImportProvider;
-
-impl FeatureProvider for LatexPackageImportProvider {
- type Params = CompletionParams;
- type Output = Vec<CompletionItem>;
+pub async fn complete_latex_classes<'a>(
+ req: &'a FeatureRequest<CompletionParams>,
+ items: &mut Vec<Item<'a>>,
+) {
+ complete_latex_imports(req, items, LatexIncludeKind::Class, |name| {
+ ItemData::Class { name }
+ })
+ .await;
+}
- #[boxed]
- async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
- import(request, LatexIncludeKind::Package, factory::package).await
- }
+pub async fn complete_latex_packages<'a>(
+ req: &'a FeatureRequest<CompletionParams>,
+ items: &mut Vec<Item<'a>>,
+) {
+ complete_latex_imports(req, items, LatexIncludeKind::Package, |name| {
+ ItemData::Package { name }
+ })
+ .await;
}
-async fn import<F>(
- request: &FeatureRequest<CompletionParams>,
+async fn complete_latex_imports<'a, F>(
+ req: &'a FeatureRequest<CompletionParams>,
+ items: &mut Vec<Item<'a>>,
kind: LatexIncludeKind,
- factory: F,
-) -> Vec<CompletionItem>
-where
- F: Fn(&FeatureRequest<CompletionParams>, &'static str, TextEdit) -> CompletionItem,
+ mut factory: F,
+) where
+ F: FnMut(Cow<'a, str>) -> ItemData<'a>,
{
let extension = if kind == LatexIncludeKind::Package {
"sty"
@@ -50,61 +46,143 @@ where
.include_commands
.iter()
.filter(|cmd| cmd.kind == kind)
- .map(|cmd| Parameter::new(&cmd.name, cmd.index));
-
- combinators::argument(request, parameters, |context| {
- async move {
- let mut items = Vec::new();
- for component in &DATABASE.components {
- for file_name in &component.file_names {
- if file_name.ends_with(extension) {
- let stem = &file_name[0..file_name.len() - 4];
- let text_edit = TextEdit::new(context.range, stem.into());
- let item = factory(request, stem, text_edit);
- items.push(item);
- }
- }
- }
- items
- }
+ .map(|cmd| Parameter {
+ name: &cmd.name[1..],
+ index: cmd.index,
+ });
+
+ combinators::argument(req, parameters, |ctx| async move {
+ let resolver = req.distro.resolver().await;
+ let mut file_names = HashSet::new();
+ COMPONENT_DATABASE
+ .components
+ .iter()
+ .flat_map(|comp| comp.file_names.iter())
+ .filter(|file_name| file_name.ends_with(extension))
+ .for_each(|file_name| {
+ file_names.insert(file_name);
+ let stem = &file_name[0..file_name.len() - 4];
+ let data = factory(stem.into());
+ let item = Item::new(ctx.range, data);
+ items.push(item);
+ });
+
+ resolver
+ .files_by_name
+ .keys()
+ .filter(|file_name| file_name.ends_with(extension) && !file_names.contains(file_name))
+ .for_each(|file_name| {
+ let stem = &file_name[0..file_name.len() - 4];
+ let data = factory(stem.to_owned().into());
+ let item = Item::new(ctx.range, data);
+ items.push(item);
+ });
})
- .await
+ .await;
}
#[cfg(test)]
mod tests {
use super::*;
- use lsp_types::Position;
-
- #[test]
- fn test_class() {
- let items = test_feature(
- LatexClassImportProvider,
- FeatureSpec {
- files: vec![FeatureSpec::file("foo.tex", "\\documentclass{}")],
- main_file: "foo.tex",
- position: Position::new(0, 15),
- ..FeatureSpec::default()
- },
- );
-
- assert!(items.iter().any(|item| item.label == "beamer"));
- assert!(items.iter().all(|item| item.label != "amsmath"));
+ use crate::feature::FeatureTester;
+
+ #[tokio::test]
+ async fn empty_latex_document_class() {
+ let req = FeatureTester::new()
+ .file("main.tex", "")
+ .main("main.tex")
+ .position(0, 0)
+ .test_completion_request()
+ .await;
+ let mut actual_items = Vec::new();
+
+ complete_latex_classes(&req, &mut actual_items).await;
+
+ assert!(actual_items.is_empty());
+ }
+
+ #[tokio::test]
+ async fn empty_bibtex_document_class() {
+ let req = FeatureTester::new()
+ .file("main.bib", "")
+ .main("main.bib")
+ .position(0, 0)
+ .test_completion_request()
+ .await;
+ let mut actual_items = Vec::new();
+
+ complete_latex_classes(&req, &mut actual_items).await;
+
+ assert!(actual_items.is_empty());
+ }
+
+ #[tokio::test]
+ async fn empty_latex_document_package() {
+ let req = FeatureTester::new()
+ .file("main.tex", "")
+ .main("main.tex")
+ .position(0, 0)
+ .test_completion_request()
+ .await;
+ let mut actual_items = Vec::new();
+
+ complete_latex_packages(&req, &mut actual_items).await;
+
+ assert!(actual_items.is_empty());
}
- #[test]
- fn test_package() {
- let items = test_feature(
- LatexPackageImportProvider,
- FeatureSpec {
- files: vec![FeatureSpec::file("foo.tex", "\\usepackage{}")],
- main_file: "foo.tex",
- position: Position::new(0, 12),
- ..FeatureSpec::default()
- },
- );
-
- assert!(items.iter().all(|item| item.label != "beamer"));
- assert!(items.iter().any(|item| item.label == "amsmath"));
+ #[tokio::test]
+ async fn empty_bibtex_document_package() {
+ let req = FeatureTester::new()
+ .file("main.bib", "")
+ .main("main.bib")
+ .position(0, 0)
+ .test_completion_request()
+ .await;
+ let mut actual_items = Vec::new();
+
+ complete_latex_packages(&req, &mut actual_items).await;
+
+ assert!(actual_items.is_empty());
+ }
+
+ #[tokio::test]
+ async fn class() {
+ let req = FeatureTester::new()
+ .file("main.tex", r#"\documentclass{}"#)
+ .main("main.tex")
+ .position(0, 15)
+ .test_completion_request()
+ .await;
+ let mut actual_items = Vec::new();
+
+ complete_latex_classes(&req, &mut actual_items).await;
+
+ assert!(actual_items
+ .iter()
+ .any(|item| item.data.label() == "beamer"));
+ assert!(actual_items
+ .iter()
+ .all(|item| item.data.label() != "amsmath"));
+ }
+
+ #[tokio::test]
+ async fn package() {
+ let req = FeatureTester::new()
+ .file("main.tex", r#"\usepackage{}"#)
+ .main("main.tex")
+ .position(0, 12)
+ .test_completion_request()
+ .await;
+ let mut actual_items = Vec::new();
+
+ complete_latex_packages(&req, &mut actual_items).await;
+
+ assert!(actual_items
+ .iter()
+ .all(|item| item.data.label() != "beamer"));
+ assert!(actual_items
+ .iter()
+ .any(|item| item.data.label() == "amsmath"));
}
}