From 745892fbddea56040139108277e728b53fd8fc11 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Thu, 28 May 2020 03:03:21 +0000 Subject: CTAN sync 202005280303 --- support/texlab/src/completion/latex/user.rs | 324 ++++++++++++++++------------ 1 file changed, 186 insertions(+), 138 deletions(-) (limited to 'support/texlab/src/completion/latex/user.rs') 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; - - #[boxed] - async fn execute<'a>(&'a self, request: &'a FeatureRequest) -> 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; - - #[boxed] - async fn execute<'a>(&'a self, request: &'a FeatureRequest) -> 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, + items: &mut Vec>, +) { + 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, + items: &mut Vec>, +) { fn make_item( - request: &FeatureRequest, - delimiter: &LatexEnvironmentDelimiter, + table: &latex::SymbolTable, + delim: latex::EnvironmentDelimiter, name_range: Range, - ) -> Option { - 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 { + 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"]); } } -- cgit v1.2.3