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/component.rs | 557 +++++++++++++---------- 1 file changed, 315 insertions(+), 242 deletions(-) (limited to 'support/texlab/src/completion/latex/component.rs') diff --git a/support/texlab/src/completion/latex/component.rs b/support/texlab/src/completion/latex/component.rs index 3699a4959e..8cf9f494a4 100644 --- a/support/texlab/src/completion/latex/component.rs +++ b/support/texlab/src/completion/latex/component.rs @@ -1,278 +1,351 @@ use super::combinators; -use crate::completion::factory::{self, LatexComponentId}; -use crate::completion::DATABASE; -use crate::workspace::*; -use futures_boxed::boxed; -use lsp_types::*; - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct LatexComponentCommandCompletionProvider; - -impl FeatureProvider for LatexComponentCommandCompletionProvider { - type Params = CompletionParams; - type Output = Vec; - - #[boxed] - async fn execute<'a>(&'a self, request: &'a FeatureRequest) -> Self::Output { - combinators::command(request, |command| { - async move { - let range = command.short_name_range(); - let mut items = Vec::new(); - for component in DATABASE.related_components(request.related_documents()) { - let file_names = component.file_names.iter().map(AsRef::as_ref).collect(); - let id = LatexComponentId::Component(file_names); - for command in &component.commands { - let text_edit = TextEdit::new(range, (&command.name).into()); - let item = factory::command( - request, - (&command.name).into(), - command.image.as_ref().map(AsRef::as_ref), - command.glyph.as_ref().map(AsRef::as_ref), - text_edit, - &id, - ); - items.push(item); - } - } - items +use crate::{ + completion::types::{Item, ItemData}, + feature::FeatureRequest, + protocol::CompletionParams, +}; + +pub async fn complete_latex_component_commands<'a>( + req: &'a FeatureRequest, + items: &mut Vec>, +) { + combinators::command(req, |cmd_node| async move { + let table = req.current().content.as_latex().unwrap(); + let cmd = table.as_command(cmd_node).unwrap(); + let range = cmd.short_name_range(); + + for comp in req.view.components() { + for cmd in &comp.commands { + items.push(Item::new( + range, + ItemData::ComponentCommand { + name: &cmd.name, + image: cmd.image.as_deref(), + glyph: cmd.glyph.as_deref(), + file_names: &comp.file_names, + }, + )); } - }) - .await - } + } + }) + .await; } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct LatexComponentEnvironmentCompletionProvider; - -impl FeatureProvider for LatexComponentEnvironmentCompletionProvider { - 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 component in DATABASE.related_components(request.related_documents()) { - let file_names = component.file_names.iter().map(AsRef::as_ref).collect(); - let id = LatexComponentId::Component(file_names); - for environment in &component.environments { - let text_edit = TextEdit::new(context.range, environment.into()); - let item = - factory::environment(request, environment.into(), text_edit, &id); - items.push(item); - } - } - items +pub async fn complete_latex_component_environments<'a>( + req: &'a FeatureRequest, + items: &mut Vec>, +) { + combinators::environment(req, |ctx| async move { + for comp in req.view.components() { + for env in &comp.environments { + items.push(Item::new( + ctx.range, + ItemData::ComponentEnvironment { + name: env, + file_names: &comp.file_names, + }, + )); } - }) - .await - } + } + }) + .await; } #[cfg(test)] mod tests { use super::*; - use crate::range::RangeExt; - use lsp_types::{Position, Range}; - - #[test] - fn test_command_start() { - let items = test_feature( - LatexComponentCommandCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\use")], - main_file: "foo.tex", - position: Position::new(0, 0), - ..FeatureSpec::default() - }, - ); - assert!(items.is_empty()); + use crate::{ + feature::FeatureTester, + protocol::{Range, RangeExt}, + }; + use indoc::indoc; + + #[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_component_commands(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); } - #[test] - fn test_command_end() { - let items = test_feature( - LatexComponentCommandCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\use")], - main_file: "foo.tex", - position: Position::new(0, 4), - ..FeatureSpec::default() - }, - ); - assert!(!items.is_empty()); - assert_eq!( - items[0].text_edit.as_ref().map(|edit| edit.range), - Some(Range::new_simple(0, 1, 0, 4)) - ); + #[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_component_commands(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); } - #[test] - fn test_command_word() { - let items = test_feature( - LatexComponentCommandCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "use")], - main_file: "foo.tex", - position: Position::new(0, 2), - ..FeatureSpec::default() - }, - ); - assert!(items.is_empty()); + #[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_component_environments(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); } - #[test] - fn test_command_package() { - let items = test_feature( - LatexComponentCommandCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\usepackage{lipsum}\n\\lips")], - main_file: "foo.tex", - position: Position::new(1, 2), - ..FeatureSpec::default() - }, - ); - assert!(items.iter().any(|item| item.label == "lipsum")); + #[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_component_environments(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); } - #[test] - fn test_command_package_comma_separated() { - let items = test_feature( - LatexComponentCommandCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file( - "foo.tex", - "\\usepackage{geometry, lipsum}\n\\lips", - )], - main_file: "foo.tex", - position: Position::new(1, 2), - ..FeatureSpec::default() - }, - ); - assert!(items.iter().any(|item| item.label == "lipsum")); + #[tokio::test] + async fn command_start() { + let req = FeatureTester::new() + .file("main.tex", r#"\use"#) + .main("main.tex") + .position(0, 0) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_commands(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); } - #[test] - fn test_command_class() { - let items = test_feature( - LatexComponentCommandCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file( - "foo.tex", - "\\documentclass{book}\n\\chap", - )], - main_file: "foo.tex", - position: Position::new(1, 2), - ..FeatureSpec::default() - }, - ); - assert!(items.iter().any(|item| item.label == "chapter")); + #[tokio::test] + async fn command_end() { + let req = FeatureTester::new() + .file("main.tex", r#"\use"#) + .main("main.tex") + .position(0, 4) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_commands(&req, &mut actual_items).await; + + assert!(!actual_items.is_empty()); + assert_eq!(actual_items[0].range, Range::new_simple(0, 1, 0, 4)); } - #[test] - fn test_environment_inside_of_empty_begin() { - let items = test_feature( - LatexComponentEnvironmentCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\begin{}")], - main_file: "foo.tex", - position: Position::new(0, 7), - ..FeatureSpec::default() - }, - ); - assert!(!items.is_empty()); - assert_eq!( - items[0].text_edit.as_ref().map(|edit| edit.range), - Some(Range::new_simple(0, 7, 0, 7)) - ); + #[tokio::test] + async fn command_word() { + let req = FeatureTester::new() + .file("main.tex", r#"use"#) + .main("main.tex") + .position(0, 2) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_commands(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); } - #[test] - fn test_environment_inside_of_non_empty_end() { - let items = test_feature( - LatexComponentEnvironmentCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\end{foo}")], - main_file: "foo.tex", - position: Position::new(0, 6), - ..FeatureSpec::default() - }, - ); - assert!(!items.is_empty()); - assert_eq!( - items[0].text_edit.as_ref().map(|edit| edit.range), - Some(Range::new_simple(0, 5, 0, 8)) - ); + #[tokio::test] + async fn command_package() { + let req = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \usepackage{lipsum} + \lips + "# + ), + ) + .main("main.tex") + .position(1, 2) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_commands(&req, &mut actual_items).await; + + assert!(actual_items + .iter() + .any(|item| item.data.label() == "lipsum")); } - #[test] - fn test_environment_outside_of_empty_begin() { - let items = test_feature( - LatexComponentEnvironmentCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\begin{}")], - main_file: "foo.tex", - position: Position::new(0, 6), - ..FeatureSpec::default() - }, - ); - assert!(items.is_empty()); + #[tokio::test] + async fn command_package_comma_separated() { + let req = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \usepackage{geometry, lipsum} + \lips + "# + ), + ) + .main("main.tex") + .position(1, 2) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_commands(&req, &mut actual_items).await; + + assert!(actual_items + .iter() + .any(|item| item.data.label() == "lipsum")); } - #[test] - fn test_environment_outside_of_empty_end() { - let items = test_feature( - LatexComponentEnvironmentCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\end{}")], - main_file: "foo.tex", - position: Position::new(0, 6), - ..FeatureSpec::default() - }, - ); - assert!(items.is_empty()); + #[tokio::test] + async fn command_class() { + let req = FeatureTester::new() + .file( + "main.tex", + indoc!( + r#" + \documentclass{book} + \chap + "# + ), + ) + .main("main.tex") + .position(1, 2) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_commands(&req, &mut actual_items).await; + + assert!(actual_items + .iter() + .any(|item| item.data.label() == "chapter")); + } + + #[tokio::test] + async fn environment_inside_of_empty_begin() { + let req = FeatureTester::new() + .file("main.tex", r#"\begin{}"#) + .main("main.tex") + .position(0, 7) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_environments(&req, &mut actual_items).await; + + assert!(!actual_items.is_empty()); + assert_eq!(actual_items[0].range, Range::new_simple(0, 7, 0, 7)); } - #[test] - fn test_environment_inside_of_other_command() { - let items = test_feature( - LatexComponentEnvironmentCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\foo{bar}")], - main_file: "foo.tex", - position: Position::new(0, 6), - ..FeatureSpec::default() - }, - ); - assert!(items.is_empty()); + #[tokio::test] + async fn environment_inside_of_non_empty_end() { + let req = FeatureTester::new() + .file("main.tex", r#"\end{foo}"#) + .main("main.tex") + .position(0, 6) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_environments(&req, &mut actual_items).await; + + assert!(!actual_items.is_empty()); + assert_eq!(actual_items[0].range, Range::new_simple(0, 5, 0, 8)); } - #[test] - fn test_environment_inside_second_argument() { - let items = test_feature( - LatexComponentEnvironmentCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\begin{foo}{bar}")], - main_file: "foo.tex", - position: Position::new(0, 14), - ..FeatureSpec::default() - }, - ); - assert!(items.is_empty()); + #[tokio::test] + async fn environment_outside_of_empty_begin() { + let req = FeatureTester::new() + .file("main.tex", r#"\begin{}"#) + .main("main.tex") + .position(0, 6) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_environments(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); } - #[test] - fn test_environment_unterminated() { - let items = test_feature( - LatexComponentEnvironmentCompletionProvider, - FeatureSpec { - files: vec![FeatureSpec::file("foo.tex", "\\begin{ foo")], - main_file: "foo.tex", - position: Position::new(0, 7), - ..FeatureSpec::default() - }, - ); - assert!(!items.is_empty()); + #[tokio::test] + async fn environment_outside_of_empty_end() { + let req = FeatureTester::new() + .file("main.tex", r#"\end{}"#) + .main("main.tex") + .position(0, 6) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_environments(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); + } + + #[tokio::test] + async fn environment_inside_of_other_command() { + let req = FeatureTester::new() + .file("main.tex", r#"\foo{bar}"#) + .main("main.tex") + .position(0, 6) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_environments(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); + } + + #[tokio::test] + async fn environment_inside_second_argument() { + let req = FeatureTester::new() + .file("main.tex", r#"\begin{foo}{bar}"#) + .main("main.tex") + .position(0, 14) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_environments(&req, &mut actual_items).await; + + assert!(actual_items.is_empty()); + } + + #[tokio::test] + async fn environment_unterminated() { + let req = FeatureTester::new() + .file("main.tex", r#"\begin{foo"#) + .main("main.tex") + .position(0, 7) + .test_completion_request() + .await; + let mut actual_items = Vec::new(); + + complete_latex_component_environments(&req, &mut actual_items).await; + + assert!(!actual_items.is_empty()); + assert_eq!(actual_items[0].range, Range::new_simple(0, 7, 0, 10)); } } -- cgit v1.2.3