summaryrefslogtreecommitdiff
path: root/support/texlab/src/completion/latex/user.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/completion/latex/user.rs')
-rw-r--r--support/texlab/src/completion/latex/user.rs324
1 files changed, 186 insertions, 138 deletions
diff --git a/support/texlab/src/completion/latex/user.rs b/support/texlab/src/completion/latex/user.rs
index 890a75882b..0a5706958a 100644
--- a/support/texlab/src/completion/latex/user.rs
+++ b/support/texlab/src/completion/latex/user.rs
@@ -1,156 +1,204 @@
use super::combinators;
-use crate::completion::factory::{self, LatexComponentId};
-use crate::syntax::*;
-use crate::workspace::*;
-use futures_boxed::boxed;
-use itertools::Itertools;
-use lsp_types::*;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub struct LatexUserCommandCompletionProvider;
-
-impl FeatureProvider for LatexUserCommandCompletionProvider {
- type Params = CompletionParams;
- type Output = Vec<CompletionItem>;
-
- #[boxed]
- async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
- combinators::command(request, |current_command| {
- async move {
- let mut items = Vec::new();
- for document in request.related_documents() {
- if let SyntaxTree::Latex(tree) = &document.tree {
- tree.commands
- .iter()
- .filter(|command| command.range() != current_command.range())
- .map(|command| &command.name.text()[1..])
- .unique()
- .map(|command| {
- let text_edit = TextEdit::new(
- current_command.short_name_range(),
- command.to_owned(),
- );
- factory::command(
- request,
- command.to_owned(),
- None,
- None,
- text_edit,
- &LatexComponentId::User,
- )
- })
- .for_each(|item| items.push(item));
- }
- }
- items
- }
- })
- .await
- }
-}
+use crate::{
+ completion::{Item, ItemData},
+ feature::FeatureRequest,
+ protocol::{CompletionParams, Range},
+ syntax::latex,
+ workspace::DocumentContent,
+};
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub struct LatexUserEnvironmentCompletionProvider;
-
-impl FeatureProvider for LatexUserEnvironmentCompletionProvider {
- type Params = CompletionParams;
- type Output = Vec<CompletionItem>;
-
- #[boxed]
- async fn execute<'a>(&'a self, request: &'a FeatureRequest<Self::Params>) -> Self::Output {
- combinators::environment(request, |context| {
- async move {
- let mut items = Vec::new();
- for document in request.related_documents() {
- if let SyntaxTree::Latex(tree) = &document.tree {
- for environment in &tree.env.environments {
- if environment.left.command == context.command
- || environment.right.command == context.command
- {
- continue;
- }
-
- if let Some(item) =
- Self::make_item(request, &environment.left, context.range)
- {
- items.push(item);
- }
-
- if let Some(item) =
- Self::make_item(request, &environment.right, context.range)
- {
- items.push(item);
- }
- }
- }
- }
- items
- }
- })
- .await
- }
+pub async fn complete_latex_user_commands<'a>(
+ req: &'a FeatureRequest<CompletionParams>,
+ items: &mut Vec<Item<'a>>,
+) {
+ combinators::command(req, |current_cmd_node| async move {
+ let current_cmd = req
+ .current()
+ .content
+ .as_latex()
+ .unwrap()
+ .as_command(current_cmd_node)
+ .unwrap();
+
+ for table in req
+ .related()
+ .into_iter()
+ .flat_map(|doc| doc.content.as_latex())
+ {
+ table
+ .commands
+ .iter()
+ .filter(|cmd_node| **cmd_node != current_cmd_node)
+ .map(|cmd_node| {
+ let name = &table.as_command(*cmd_node).unwrap().name.text()[1..];
+ Item::new(
+ current_cmd.short_name_range(),
+ ItemData::UserCommand { name },
+ )
+ })
+ .for_each(|item| items.push(item));
+ }
+ })
+ .await;
}
-impl LatexUserEnvironmentCompletionProvider {
+pub async fn complete_latex_user_environments<'a>(
+ req: &'a FeatureRequest<CompletionParams>,
+ items: &mut Vec<Item<'a>>,
+) {
fn make_item(
- request: &FeatureRequest<CompletionParams>,
- delimiter: &LatexEnvironmentDelimiter,
+ table: &latex::SymbolTable,
+ delim: latex::EnvironmentDelimiter,
name_range: Range,
- ) -> Option<CompletionItem> {
- if let Some(name) = delimiter.name() {
- let text = name.text().to_owned();
- let text_edit = TextEdit::new(name_range, text.clone());
- let item = factory::environment(request, text, text_edit, &LatexComponentId::User);
- return Some(item);
- }
- None
+ ) -> Option<Item> {
+ delim
+ .name(&table)
+ .map(|name| Item::new(name_range, ItemData::UserEnvironment { name: &name.text() }))
}
+
+ combinators::environment(req, |ctx| async move {
+ for doc in req.related() {
+ if let DocumentContent::Latex(table) = &doc.content {
+ for env in &table.environments {
+ if (env.left.parent == ctx.node || env.right.parent == ctx.node)
+ && doc.uri == req.current().uri
+ {
+ continue;
+ }
+
+ if let Some(item) = make_item(&table, env.left, ctx.range) {
+ items.push(item);
+ }
+
+ if let Some(item) = make_item(&table, env.right, ctx.range) {
+ items.push(item);
+ }
+ }
+ }
+ }
+ })
+ .await;
}
#[cfg(test)]
mod tests {
use super::*;
- use lsp_types::Position;
-
- #[test]
- fn test_command() {
- let items = test_feature(
- LatexUserCommandCompletionProvider,
- FeatureSpec {
- files: vec![
- FeatureSpec::file("foo.tex", "\\include{bar.tex}\n\\foo"),
- FeatureSpec::file("bar.tex", "\\bar"),
- FeatureSpec::file("baz.tex", "\\baz"),
- ],
- main_file: "foo.tex",
- position: Position::new(1, 2),
- ..FeatureSpec::default()
- },
- );
- let labels: Vec<&str> = items.iter().map(|item| item.label.as_ref()).collect();
- assert_eq!(labels, vec!["include", "bar"]);
+ use crate::feature::FeatureTester;
+ use indoc::indoc;
+ use itertools::Itertools;
+
+ #[tokio::test]
+ async fn empty_latex_document_command() {
+ 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_user_commands(&req, &mut actual_items).await;
+
+ assert!(actual_items.is_empty());
+ }
+
+ #[tokio::test]
+ async fn empty_bibtex_document_command() {
+ 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_user_commands(&req, &mut actual_items).await;
+
+ assert!(actual_items.is_empty());
}
- #[test]
- fn test_environment() {
- let items = test_feature(
- LatexUserEnvironmentCompletionProvider,
- FeatureSpec {
- files: vec![
- FeatureSpec::file("foo.tex", "\\include{bar.tex}\n\\begin{foo}"),
- FeatureSpec::file("bar.tex", "\\begin{bar}\\end{bar}"),
- FeatureSpec::file("baz.tex", "\\begin{baz}\\end{baz}"),
- ],
- main_file: "foo.tex",
- position: Position::new(1, 9),
- ..FeatureSpec::default()
- },
- );
- let labels: Vec<&str> = items
- .iter()
- .map(|item| item.label.as_ref())
+ #[tokio::test]
+ async fn empty_latex_document_environment() {
+ 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_user_environments(&req, &mut actual_items).await;
+
+ assert!(actual_items.is_empty());
+ }
+
+ #[tokio::test]
+ async fn empty_bibtex_document_environment() {
+ 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_user_environments(&req, &mut actual_items).await;
+
+ assert!(actual_items.is_empty());
+ }
+
+ #[tokio::test]
+ async fn command() {
+ let req = FeatureTester::new()
+ .file(
+ "foo.tex",
+ indoc!(
+ r#"
+ \include{bar}
+ \foo
+ "#
+ ),
+ )
+ .file("bar.tex", r#"\bar"#)
+ .file("baz.tex", r#"\baz"#)
+ .main("foo.tex")
+ .position(1, 2)
+ .test_completion_request()
+ .await;
+ let mut actual_items = Vec::new();
+
+ complete_latex_user_commands(&req, &mut actual_items).await;
+
+ let actual_labels: Vec<_> = actual_items
+ .into_iter()
+ .map(|item| item.data.label().to_owned())
+ .collect();
+ assert_eq!(actual_labels, vec!["include", "bar"]);
+ }
+
+ #[tokio::test]
+ async fn environment() {
+ let req = FeatureTester::new()
+ .file(
+ "foo.tex",
+ indoc!(
+ r#"
+ \include{bar}
+ \begin{foo}
+ "#
+ ),
+ )
+ .file("bar.tex", r#"\begin{bar}\end{bar}"#)
+ .file("baz.tex", r#"\begin{baz}\end{baz}"#)
+ .main("foo.tex")
+ .position(1, 9)
+ .test_completion_request()
+ .await;
+ let mut actual_items = Vec::new();
+
+ complete_latex_user_environments(&req, &mut actual_items).await;
+
+ let actual_labels: Vec<_> = actual_items
+ .into_iter()
+ .map(|item| item.data.label().to_owned())
.unique()
.collect();
- assert_eq!(labels, vec!["bar"]);
+ assert_eq!(actual_labels, vec!["bar"]);
}
}