diff options
Diffstat (limited to 'support/texlab/src/completion/latex/user.rs')
-rw-r--r-- | support/texlab/src/completion/latex/user.rs | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/support/texlab/src/completion/latex/user.rs b/support/texlab/src/completion/latex/user.rs new file mode 100644 index 0000000000..890a75882b --- /dev/null +++ b/support/texlab/src/completion/latex/user.rs @@ -0,0 +1,156 @@ +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 + } +} + +#[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 + } +} + +impl LatexUserEnvironmentCompletionProvider { + fn make_item( + request: &FeatureRequest<CompletionParams>, + delimiter: &LatexEnvironmentDelimiter, + 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 + } +} + +#[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"]); + } + + #[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()) + .unique() + .collect(); + assert_eq!(labels, vec!["bar"]); + } +} |