use anyhow::Result; use insta::assert_json_snapshot; use lsp_types::{ request::{Completion, ResolveCompletionItem}, ClientCapabilities, CompletionItem, CompletionList, CompletionParams, CompletionResponse, CompletionTextEdit, Range, }; use crate::lsp::{client::Client, fixture}; fn complete(fixture: &str) -> Result, anyhow::Error> { let mut client = Client::spawn()?; client.initialize(ClientCapabilities::default(), None)?; let fixture = fixture::parse(fixture); for file in fixture.files { client.open(file.name, file.lang, file.text)?; } let range = fixture .ranges .values() .next() .and_then(|map| map.values().next()) .map_or_else( || { let position = fixture.cursor.unwrap().position; Range::new(position, position) }, |file_range| file_range.range, ); let actual_list = client .request::(CompletionParams { text_document_position: fixture.cursor.unwrap().into_params(&client)?, partial_result_params: Default::default(), work_done_progress_params: Default::default(), context: None, })? .map_or(CompletionList::default(), |actual| match actual { CompletionResponse::List(list) => list, CompletionResponse::Array(_) => unreachable!(), }); for item in &actual_list.items { if let Some(CompletionTextEdit::Edit(edit)) = item.text_edit.as_ref() { assert_eq!(edit.range, range); } } let actual_items = actual_list .items .into_iter() .take(5) .map(|item| client.request::(item)) .collect::>>()?; client.shutdown()?; Ok(actual_items) } macro_rules! assert_items { ($items:expr) => { assert_json_snapshot!($items, { "[].data" => "[data]", "[].sortText" => "[sortText]", "[].documentation" => "[documentation]", "[].textEdit.range" => "[range]", "[]" => insta::sorted_redaction() }); }; } #[test] fn acronym_ref_simple() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second} %SRC \acrshort{f} %CUR ^ %1.1 ^"# )?); Ok(()) } #[test] fn acronym_ref_empty() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second} %SRC \acrshort{} %CUR ^"# )?); Ok(()) } #[test] fn acronym_ref_after_group() -> Result<()> { let actual_items = complete( r#" %TEX main.tex %SRC \newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second} %SRC \acrshort{} %CUR ^ %1.1 ^"#, )?; assert_eq!(actual_items, Vec::new()); Ok(()) } #[test] fn acronym_ref_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second} %SRC \acrshort{f %CUR ^ %1.1 ^"# )?); Ok(()) } #[test] fn acronym_package_ref() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \acrodef{fpsLabel}[FPS]{Frames per Second} %SRC \ac{f %CUR ^ %1.1 ^"# )?); Ok(()) } #[test] fn glossary_ref_simple() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second} %SRC \gls{f} %CUR ^ %1.1 ^"# )?); Ok(()) } #[test] fn glossary_ref_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second} %SRC \gls{f %CUR ^ %1.1 ^"# )?); Ok(()) } #[test] fn argument_empty() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \usepackage{amsfonts} %SRC \mathbb{} %CUR ^"# )?); Ok(()) } #[test] fn argument_word() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \usepackage{amsfonts} %SRC \mathbb{A} %CUR ^ %1.1 ^"# )?); Ok(()) } #[test] fn argument_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \usepackage{amsfonts} %SRC \mathbb{ %CUR ^ %SRC Test"# )?); Ok(()) } #[test] fn argument_open_brace_unrelated() -> Result<()> { let actual_items = complete( r#" %TEX main.tex %SRC \usepackage{amsfonts} %SRC \mathbb{}{ %CUR ^ %SRC Test"#, )?; assert_eq!(actual_items, Vec::new()); Ok(()) } #[test] fn begin_environment_without_snippet_support() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \beg %CUR ^ %1.1 ^^^"# )?); Ok(()) } #[test] fn citation() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \documentclass{article} %SRC \bibliography{main} %SRC \begin{document} %SRC \cite{ %CUR ^ %SRC \end{document} %BIB main.bib %SRC @article{foo:2019, %SRC author = {Foo Bar}, %SRC title = {Baz Qux}, %SRC year = {2019}, %SRC } %SRC %SRC @article{bar:2005,}"# )?); Ok(()) } #[test] fn citation_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \addbibresource{main.bib} %SRC \cite{ %CUR ^ %BIB main.bib %SRC @article{foo,}"# )?); Ok(()) } #[test] fn citation_open_brace_multiple() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \addbibresource{main.bib} %SRC \cite{foo,a %CUR ^ %1.1 ^ %BIB main.bib %SRC @article{foo,}"# )?); Ok(()) } #[test] fn citation_acronym() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \addbibresource{main.bib} %SRC \DeclareAcronym{foo}{cite={}} %CUR ^ %BIB main.bib %SRC @article{foo,}"# )?); Ok(()) } #[test] fn citation_after_brace() -> Result<()> { let actual_items = complete( r#" %TEX main.tex %SRC \documentclass{article} %SRC \bibliography{main} %SRC \begin{document} %SRC \cite{} %CUR ^ %SRC \end{document} %BIB main.bib %SRC @article{foo,}"#, )?; assert_eq!(actual_items, Vec::new()); Ok(()) } #[test] fn color_model_definition_simple() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \definecolor{foo}{} %CUR ^"# )?); Ok(()) } #[test] fn color_model_definition_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \definecolor{foo}{ %CUR ^"# )?); Ok(()) } #[test] fn color_model_definition_set_simple() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \definecolorset{} %CUR ^"# )?); Ok(()) } #[test] fn color_model_definition_set_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \definecolorset{ %CUR ^"# )?); Ok(()) } #[test] fn color_simple() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \color{} %CUR ^"# )?); Ok(()) } #[test] fn color_word() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \color{re} %CUR ^ %1.1 ^^"# )?); Ok(()) } #[test] fn color_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \color{ %CUR ^"# )?); Ok(()) } #[test] fn component_command_simple() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \ %CUR ^"# )?); Ok(()) } #[test] fn component_command_simple_before() -> Result<()> { let actual_items = complete( r#" %TEX main.tex %SRC \ %CUR ^"#, )?; assert_eq!(actual_items, Vec::new()); Ok(()) } #[test] fn component_command_simple_package() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \usepackage{lipsum} %SRC \lips %CUR ^ %1.1 ^^^^"# )?); Ok(()) } #[test] fn component_command_bibtex() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @article{b, %SRC c = {\LaT } %CUR ^ %1.1 ^^^ %SRC }"# )?); Ok(()) } #[test] fn component_environment_simple() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \begin{doc %CUR ^ %1.1 ^^^"# )?); Ok(()) } #[test] fn component_environment_simple_end() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \begin{document} %SRC \end{ %CUR ^"# )?); Ok(()) } #[test] fn component_environment_class() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \documentclass{article} %SRC \begin{thein} %CUR ^ %1.1 ^^^^^"# )?); Ok(()) } #[test] fn component_environment_command_definition() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \newcommand{\foo}{\begin{doc} %CUR ^ %1.1 ^^^"# )?); Ok(()) } #[test] fn entry_type_at_empty() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @ %CUR ^"# )?); Ok(()) } #[test] fn entry_type_before_preamble() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @preamble %CUR ^ %1.1 ^^^^^^^^"# )?); Ok(()) } #[test] fn entry_type_before_string() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @string %CUR ^ %1.1 ^^^^^^"# )?); Ok(()) } #[test] fn entry_type_before_article() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @article %CUR ^ %1.1 ^^^^^^^"# )?); Ok(()) } #[test] fn entry_type_after_preamble() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @preamble{ %CUR ^ %1.1 ^^^^^^^^"# )?); Ok(()) } #[test] fn entry_type_after_string() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @string{ %CUR ^ %1.1 ^^^^^^"# )?); Ok(()) } #[test] fn entry_type_complete_entry() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @article{foo, author = {foo}} %CUR ^ %1.1 ^^^^^^^"# )?); Ok(()) } #[test] fn field_empty_entry_open() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @article{foo, %CUR ^"# )?); Ok(()) } #[test] fn field_empty_entry_closed() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @article{foo,} %CUR ^"# )?); Ok(()) } #[test] fn field_entry_field_name() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @article{foo, a %CUR ^ %1.1 ^"# )?); Ok(()) } #[test] fn field_entry_two_fields_name_open() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @article{foo, author = bar, edit %CUR ^ %1.1 ^^^^"# )?); Ok(()) } #[test] fn field_entry_two_fields_name_closed() -> Result<()> { assert_items!(complete( r#" %BIB main.bib %SRC @article{foo, author = bar, edit} %CUR ^ %1.1 ^^^^"# )?); Ok(()) } #[test] fn import_package_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \usepackage{lips %CUR ^ %1.1 ^^^^"# )?); Ok(()) } #[test] fn import_package_closed_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \usepackage{lips} %CUR ^ %1.1 ^^^^"# )?); Ok(()) } #[test] fn import_class_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \documentclass{art \foo %CUR ^ %1.1 ^^^"# )?); Ok(()) } #[test] fn import_class_closed_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \documentclass{art} %CUR ^ %1.1 ^^^"# )?); Ok(()) } #[test] fn label() -> Result<()> { assert_items!(complete( r#" %TEX foo.tex %SRC \documentclass{article} %SRC %SRC \usepackage{amsmath} %SRC \usepackage{caption} %SRC \usepackage{amsthm} %SRC \newtheorem{lemma}{Lemma} %SRC %SRC \begin{document} %SRC %SRC \section{Foo}% %SRC \label{sec:foo} %SRC %SRC \begin{equation}% %SRC \label{eq:foo} %SRC 1 + 1 = 2 %SRC \end{equation} %SRC %SRC \begin{equation}% %SRC \label{eq:bar} %SRC 1 + 1 = 2 %SRC \end{equation} %SRC %SRC \begin{figure}% %SRC \LaTeX{} %SRC \caption{Baz}% %SRC \label{fig:baz} %SRC \end{figure} %SRC %SRC \begin{lemma}% %SRC \label{thm:foo} %SRC 1 + 1 = 2 %SRC \end{lemma} %SRC %SRC \include{bar} %SRC %SRC \end{document} %TEX bar.tex %SRC \section{Bar}% %SRC \label{sec:bar} %SRC %SRC Lorem ipsum dolor sit amet. %SRC \ref{} %CUR ^ %TEX foo.aux %SRC \relax %SRC \@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Baz\relax }}{1}\protected@file@percent } %SRC \providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}} %SRC \newlabel{fig:baz}{{1}{1}} %SRC \@writefile{toc}{\contentsline {section}{\numberline {1}Foo}{1}\protected@file@percent } %SRC \newlabel{sec:foo}{{1}{1}} %SRC \newlabel{eq:foo}{{1}{1}} %SRC \newlabel{eq:bar}{{2}{1}} %SRC \newlabel{thm:foo}{{1}{1}} %SRC \@input{bar.aux}"# )?); Ok(()) } #[test] fn theorem_begin() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \newtheorem{lemma}{Lemma} %SRC \begin{lem %CUR ^ %1.1 ^^^"# )?); Ok(()) } #[test] fn theorem_end() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \newtheorem{lemma}{Lemma} %SRC \begin{} %SRC \end{lem %CUR ^ %1.1 ^^^"# )?); Ok(()) } #[test] fn tikz_library_open_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \usepgflibrary{ %CUR ^"# )?); Ok(()) } #[test] fn tikz_library_closed_brace() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \usepgflibrary{} %CUR ^"# )?); Ok(()) } #[test] fn test_user_command() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \foobar %SRC \fooba %CUR ^ %1.1 ^^^^^ %SRC \begin{foo} %SRC \end{foo} %SRC \begin{fo} "# )?); Ok(()) } #[test] fn test_user_environment() -> Result<()> { assert_items!(complete( r#" %TEX main.tex %SRC \foobar %SRC \fooba %SRC \begin{foo} %SRC \end{foo} %SRC \begin{fo} %CUR ^ %1.1 ^^ "# )?); Ok(()) }