summaryrefslogtreecommitdiff
path: root/support/texlab/tests/lsp/text_document/snapshots
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/tests/lsp/text_document/snapshots')
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_package_ref.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_empty.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_open_brace.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_simple.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_empty.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_open_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_word.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__begin_environment_without_snippet_support.snap31
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap16
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_open_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_open_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_simple.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_simple.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_open_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_simple.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_word.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_bibtex.snap31
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple.snap31
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple_package.snap31
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_class.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_command_definition.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple_end.snap31
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_preamble.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_string.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_at_empty.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_article.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_preamble.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_string.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_complete_entry.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_empty_entry_closed.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_empty_entry_open.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_field_name.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_closed.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_open.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__glossary_ref_open_brace.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__glossary_ref_simple.snap10
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_closed_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_open_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_package_closed_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_package_open_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__label.snap36
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_import.snap31
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_texlabroot.snap31
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_begin.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_end.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_closed_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_open_brace.snap26
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_command.snap11
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_environment.snap16
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_import.snap19
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_include.snap19
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_flat.snap96
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_nested.snap140
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_flat.snap60
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_nested.snap86
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_flat.snap60
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_nested.snap86
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__ignored_patterns.snap24
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_flat.snap60
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_nested.snap87
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_flat.snap78
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_nested.snap113
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__bibtex.snap27
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__latex.snap41
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_command.snap7
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_insert_braces.snap7
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_join_strings.snap7
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_multiple_entries.snap15
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_parens.snap6
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_preamble.snap5
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_string.snap5
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_trailing_comma.snap7
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_wrap_long_lines.snap9
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__citation_inside_cite.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__citation_inside_entry.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__component_known_package.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__entry_type_known_type.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__field_known.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__label_theorem_child_file.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__label_theorem_child_file_mumber.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__section.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__string_inside_reference.snap8
-rw-r--r--support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__inlay_hint__label_definition.snap38
87 files changed, 2234 insertions, 0 deletions
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_package_ref.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_package_ref.snap
new file mode 100644
index 0000000000..19c84e95fc
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_package_ref.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\acrodef{fpsLabel}[FPS]{Frames per Second}\n\\ac{f\n |\n ^\"#)"
+---
+[
+ {
+ "label": "fpsLabel",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_empty.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_empty.snap
new file mode 100644
index 0000000000..23e5b695ef
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_empty.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\acrshort{}\n |\"#)"
+---
+[
+ {
+ "label": "fpsLabel",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_open_brace.snap
new file mode 100644
index 0000000000..25171b679c
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_open_brace.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\acrshort{f\n |\n ^\"#)"
+---
+[
+ {
+ "label": "fpsLabel",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_simple.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_simple.snap
new file mode 100644
index 0000000000..1d3f3329c1
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__acronym_ref_simple.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\acrshort{f}\n |\n ^\"#)"
+---
+[
+ {
+ "label": "fpsLabel",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_empty.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_empty.snap
new file mode 100644
index 0000000000..ecc48b5a7f
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_empty.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\usepackage{amsfonts}\n\\mathbb{}\n |\"#)"
+---
+[
+ {
+ "label": "A",
+ "preselect": false
+ },
+ {
+ "label": "B",
+ "preselect": false
+ },
+ {
+ "label": "C",
+ "preselect": false
+ },
+ {
+ "label": "D",
+ "preselect": false
+ },
+ {
+ "label": "E",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_open_brace.snap
new file mode 100644
index 0000000000..530527a384
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_open_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\usepackage{amsfonts}\n\\mathbb{\n |\nTest\"#)"
+---
+[
+ {
+ "label": "A",
+ "preselect": false
+ },
+ {
+ "label": "B",
+ "preselect": false
+ },
+ {
+ "label": "C",
+ "preselect": false
+ },
+ {
+ "label": "D",
+ "preselect": false
+ },
+ {
+ "label": "E",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_word.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_word.snap
new file mode 100644
index 0000000000..c98249c781
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__argument_word.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\usepackage{amsfonts}\n\\mathbb{A}\n |\n ^\"#)"
+---
+[
+ {
+ "label": "A",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__begin_environment_without_snippet_support.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__begin_environment_without_snippet_support.snap
new file mode 100644
index 0000000000..bb9e30ae55
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__begin_environment_without_snippet_support.snap
@@ -0,0 +1,31 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\beg\n |\n ^^^\"#)"
+---
+[
+ {
+ "label": "AtBeginDocument",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "AtBeginDvi",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "begin",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "begingroup",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "bigwedge",
+ "detail": "â‹€, built-in",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap
new file mode 100644
index 0000000000..b8755fdef0
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation.snap
@@ -0,0 +1,16 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\documentclass{article}\n\\bibliography{main}\n\\begin{document}\n\\cite{\n |\n\\end{document}\n\n%! main.bib\n@article{foo:2019,\n author = {Foo Bar},\n title = {Baz Qux},\n year = {2019},\n}\n\n@article{bar:2005,}\"#)"
+---
+[
+ {
+ "label": "bar:2005",
+ "preselect": false,
+ "filterText": "bar:2005 @article bar:2005"
+ },
+ {
+ "label": "foo:2019",
+ "preselect": false,
+ "filterText": "foo:2019 @article foo:2019 author Foo Bar title Baz Qux year 2019"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap
new file mode 100644
index 0000000000..36478c45c8
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_acronym.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\addbibresource{main.bib}\n\\DeclareAcronym{foo}{cite={}}\n |\n\n%! main.bib\n@article{foo,}\"#)"
+---
+[
+ {
+ "label": "foo",
+ "preselect": false,
+ "filterText": "foo @article foo"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap
new file mode 100644
index 0000000000..41a1d9ced3
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\addbibresource{main.bib}\n\\cite{\n |\n\n%! main.bib\n@article{foo,}\"#)"
+---
+[
+ {
+ "label": "foo",
+ "preselect": false,
+ "filterText": "foo @article foo"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap
new file mode 100644
index 0000000000..8ef509b463
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__citation_open_brace_multiple.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\addbibresource{main.bib}\n\\cite{foo,a\n |\n ^\n\n%! main.bib\n@article{foo,}\"#)"
+---
+[
+ {
+ "label": "foo",
+ "preselect": false,
+ "filterText": "foo @article foo"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_open_brace.snap
new file mode 100644
index 0000000000..421335a4a5
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_open_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\definecolor{foo}{\n |\"#)"
+---
+[
+ {
+ "label": "HTML",
+ "preselect": false
+ },
+ {
+ "label": "RGB",
+ "preselect": false
+ },
+ {
+ "label": "cmyk",
+ "preselect": false
+ },
+ {
+ "label": "gray",
+ "preselect": false
+ },
+ {
+ "label": "rgb",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_open_brace.snap
new file mode 100644
index 0000000000..5d7338e48e
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_open_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\definecolorset{\n |\"#)"
+---
+[
+ {
+ "label": "HTML",
+ "preselect": false
+ },
+ {
+ "label": "RGB",
+ "preselect": false
+ },
+ {
+ "label": "cmyk",
+ "preselect": false
+ },
+ {
+ "label": "gray",
+ "preselect": false
+ },
+ {
+ "label": "rgb",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_simple.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_simple.snap
new file mode 100644
index 0000000000..811b47c9ee
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_set_simple.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\definecolorset{}\n |\"#)"
+---
+[
+ {
+ "label": "HTML",
+ "preselect": false
+ },
+ {
+ "label": "RGB",
+ "preselect": false
+ },
+ {
+ "label": "cmyk",
+ "preselect": false
+ },
+ {
+ "label": "gray",
+ "preselect": false
+ },
+ {
+ "label": "rgb",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_simple.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_simple.snap
new file mode 100644
index 0000000000..dbb34f08d9
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_model_definition_simple.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\definecolor{foo}{}\n |\"#)"
+---
+[
+ {
+ "label": "HTML",
+ "preselect": false
+ },
+ {
+ "label": "RGB",
+ "preselect": false
+ },
+ {
+ "label": "cmyk",
+ "preselect": false
+ },
+ {
+ "label": "gray",
+ "preselect": false
+ },
+ {
+ "label": "rgb",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_open_brace.snap
new file mode 100644
index 0000000000..e30fc4c1b0
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_open_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\color{\n |\"#)"
+---
+[
+ {
+ "label": "Apricot",
+ "preselect": false
+ },
+ {
+ "label": "Aquamarine",
+ "preselect": false
+ },
+ {
+ "label": "Bittersweet",
+ "preselect": false
+ },
+ {
+ "label": "Black",
+ "preselect": false
+ },
+ {
+ "label": "Blue",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_simple.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_simple.snap
new file mode 100644
index 0000000000..5aab0d8e3b
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_simple.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\color{}\n |\"#)"
+---
+[
+ {
+ "label": "Apricot",
+ "preselect": false
+ },
+ {
+ "label": "Aquamarine",
+ "preselect": false
+ },
+ {
+ "label": "Bittersweet",
+ "preselect": false
+ },
+ {
+ "label": "Black",
+ "preselect": false
+ },
+ {
+ "label": "Blue",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_word.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_word.snap
new file mode 100644
index 0000000000..fe803dc6cc
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__color_word.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\color{re}\n |\n ^^\"#)"
+---
+[
+ {
+ "label": "BrickRed",
+ "preselect": false
+ },
+ {
+ "label": "Red",
+ "preselect": false
+ },
+ {
+ "label": "RedOrange",
+ "preselect": false
+ },
+ {
+ "label": "RedViolet",
+ "preselect": false
+ },
+ {
+ "label": "red",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_bibtex.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_bibtex.snap
new file mode 100644
index 0000000000..616fb22a6b
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_bibtex.snap
@@ -0,0 +1,31 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@article{b,\n c = {\\LaT }\n |\n ^^^\n}\"#)"
+---
+[
+ {
+ "label": "LaTeX",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "LaTeXe",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "LastDeclaredEncoding",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "last",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "latexreleaseversion",
+ "detail": "built-in",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple.snap
new file mode 100644
index 0000000000..0e40056a6e
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple.snap
@@ -0,0 +1,31 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\\n |\"#)"
+---
+[
+ {
+ "label": "!",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "\"",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "#",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "$",
+ "detail": "$, built-in",
+ "preselect": false
+ },
+ {
+ "label": "%",
+ "detail": "built-in",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple_package.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple_package.snap
new file mode 100644
index 0000000000..360229fa7a
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_command_simple_package.snap
@@ -0,0 +1,31 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\usepackage{lipsum}\n\\lips\n |\n ^^^^\"#)"
+---
+[
+ {
+ "label": "LipsumPar",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "LipsumProtect",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "LipsumRestoreAll",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "lipsum",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "lipsumexp",
+ "detail": "lipsum.sty",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_class.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_class.snap
new file mode 100644
index 0000000000..a2e5e17ac4
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_class.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\documentclass{article}\n\\begin{thein}\n |\n ^^^^^\"#)"
+---
+[
+ {
+ "label": "theindex",
+ "detail": "article.cls",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_command_definition.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_command_definition.snap
new file mode 100644
index 0000000000..28d9c6e82c
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_command_definition.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\newcommand{\\foo}{\\begin{doc}\n |\n ^^^\"#)"
+---
+[
+ {
+ "label": "document",
+ "detail": "built-in",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple.snap
new file mode 100644
index 0000000000..f892dba5a7
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\begin{doc\n |\n ^^^\"#)"
+---
+[
+ {
+ "label": "document",
+ "detail": "built-in",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple_end.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple_end.snap
new file mode 100644
index 0000000000..95a2e1db04
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__component_environment_simple_end.snap
@@ -0,0 +1,31 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\begin{document}\n\\end{\n |\"#)"
+---
+[
+ {
+ "label": "abstract",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "array",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "center",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "csname",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "document",
+ "detail": "built-in",
+ "preselect": true
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_preamble.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_preamble.snap
new file mode 100644
index 0000000000..0fd8b00254
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_preamble.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@preamble{\n |\n ^^^^^^^^\"#)"
+---
+[
+ {
+ "label": "preamble",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_string.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_string.snap
new file mode 100644
index 0000000000..6844fc1862
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_after_string.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@string{\n |\n ^^^^^^\"#)"
+---
+[
+ {
+ "label": "string",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_at_empty.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_at_empty.snap
new file mode 100644
index 0000000000..e74f5fed37
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_at_empty.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@\n |\"#)"
+---
+[
+ {
+ "label": "article",
+ "preselect": false
+ },
+ {
+ "label": "artwork",
+ "preselect": false
+ },
+ {
+ "label": "audio",
+ "preselect": false
+ },
+ {
+ "label": "bibnote",
+ "preselect": false
+ },
+ {
+ "label": "book",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_article.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_article.snap
new file mode 100644
index 0000000000..f9defdee01
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_article.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@article\n |\n ^^^^^^^\"#)"
+---
+[
+ {
+ "label": "article",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_preamble.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_preamble.snap
new file mode 100644
index 0000000000..aad03a392b
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_preamble.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@preamble\n |\n ^^^^^^^^\"#)"
+---
+[
+ {
+ "label": "preamble",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_string.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_string.snap
new file mode 100644
index 0000000000..e30c60a45c
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_before_string.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@string\n |\n ^^^^^^\"#)"
+---
+[
+ {
+ "label": "string",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_complete_entry.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_complete_entry.snap
new file mode 100644
index 0000000000..2724026a26
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__entry_type_complete_entry.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@article{foo, author = {foo}}\n |\n ^^^^^^^\"#)"
+---
+[
+ {
+ "label": "article",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_empty_entry_closed.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_empty_entry_closed.snap
new file mode 100644
index 0000000000..a5a1d7838e
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_empty_entry_closed.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@article{foo,}\n |\"#)"
+---
+[
+ {
+ "label": "abstract",
+ "preselect": false
+ },
+ {
+ "label": "addendum",
+ "preselect": false
+ },
+ {
+ "label": "address",
+ "preselect": false
+ },
+ {
+ "label": "afterword",
+ "preselect": false
+ },
+ {
+ "label": "annotation",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_empty_entry_open.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_empty_entry_open.snap
new file mode 100644
index 0000000000..693d4ed141
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_empty_entry_open.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@article{foo,\n |\"#)"
+---
+[
+ {
+ "label": "abstract",
+ "preselect": false
+ },
+ {
+ "label": "addendum",
+ "preselect": false
+ },
+ {
+ "label": "address",
+ "preselect": false
+ },
+ {
+ "label": "afterword",
+ "preselect": false
+ },
+ {
+ "label": "annotation",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_field_name.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_field_name.snap
new file mode 100644
index 0000000000..cb0d41ed5d
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_field_name.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@article{foo, a\n |\n ^\"#)"
+---
+[
+ {
+ "label": "abstract",
+ "preselect": false
+ },
+ {
+ "label": "addendum",
+ "preselect": false
+ },
+ {
+ "label": "address",
+ "preselect": false
+ },
+ {
+ "label": "afterword",
+ "preselect": false
+ },
+ {
+ "label": "annotation",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_closed.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_closed.snap
new file mode 100644
index 0000000000..66dbf62785
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_closed.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@article{foo, author = bar, edit}\n |\n ^^^^\"#)"
+---
+[
+ {
+ "label": "edition",
+ "preselect": false
+ },
+ {
+ "label": "editor",
+ "preselect": false
+ },
+ {
+ "label": "editora",
+ "preselect": false
+ },
+ {
+ "label": "editoratype",
+ "preselect": false
+ },
+ {
+ "label": "editorb",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_open.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_open.snap
new file mode 100644
index 0000000000..221f78f335
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__field_entry_two_fields_name_open.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.bib\n@article{foo, author = bar, edit\n |\n ^^^^\"#)"
+---
+[
+ {
+ "label": "edition",
+ "preselect": false
+ },
+ {
+ "label": "editor",
+ "preselect": false
+ },
+ {
+ "label": "editora",
+ "preselect": false
+ },
+ {
+ "label": "editoratype",
+ "preselect": false
+ },
+ {
+ "label": "editorb",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__glossary_ref_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__glossary_ref_open_brace.snap
new file mode 100644
index 0000000000..1be95d5d99
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__glossary_ref_open_brace.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\gls{f\n |\n ^\"#)"
+---
+[
+ {
+ "label": "fpsLabel",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__glossary_ref_simple.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__glossary_ref_simple.snap
new file mode 100644
index 0000000000..81e9299d69
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__glossary_ref_simple.snap
@@ -0,0 +1,10 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n\\gls{f}\n |\n ^\"#)"
+---
+[
+ {
+ "label": "fpsLabel",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_closed_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_closed_brace.snap
new file mode 100644
index 0000000000..9ed7978612
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_closed_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\documentclass{art}\n |\n ^^^\"#)"
+---
+[
+ {
+ "label": "article",
+ "preselect": false
+ },
+ {
+ "label": "articleingud",
+ "preselect": false
+ },
+ {
+ "label": "articoletteracdp",
+ "preselect": false
+ },
+ {
+ "label": "artikel1",
+ "preselect": false
+ },
+ {
+ "label": "artikel2",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_open_brace.snap
new file mode 100644
index 0000000000..b650b621c6
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_class_open_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\documentclass{art \\foo\n |\n ^^^\"#)"
+---
+[
+ {
+ "label": "article",
+ "preselect": false
+ },
+ {
+ "label": "articleingud",
+ "preselect": false
+ },
+ {
+ "label": "articoletteracdp",
+ "preselect": false
+ },
+ {
+ "label": "artikel1",
+ "preselect": false
+ },
+ {
+ "label": "artikel2",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_package_closed_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_package_closed_brace.snap
new file mode 100644
index 0000000000..f8cad5526c
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_package_closed_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\usepackage{lips}\n |\n ^^^^\"#)"
+---
+[
+ {
+ "label": "lips",
+ "preselect": false
+ },
+ {
+ "label": "lipsum",
+ "preselect": false
+ },
+ {
+ "label": "lisp-simple-alloc",
+ "preselect": false
+ },
+ {
+ "label": "lisp-string",
+ "preselect": false
+ },
+ {
+ "label": "lwarp-lips",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_package_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_package_open_brace.snap
new file mode 100644
index 0000000000..d234241e24
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__import_package_open_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\usepackage{lips\n |\n ^^^^\"#)"
+---
+[
+ {
+ "label": "lips",
+ "preselect": false
+ },
+ {
+ "label": "lipsum",
+ "preselect": false
+ },
+ {
+ "label": "lisp-simple-alloc",
+ "preselect": false
+ },
+ {
+ "label": "lisp-string",
+ "preselect": false
+ },
+ {
+ "label": "lwarp-lips",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__label.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__label.snap
new file mode 100644
index 0000000000..a186c56920
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__label.snap
@@ -0,0 +1,36 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! foo.tex\n\\documentclass{article}\n\n\\usepackage{amsmath}\n\\usepackage{caption}\n\\usepackage{amsthm}\n\\newtheorem{lemma}{Lemma}\n\n\\begin{document}\n\n\\section{Foo}%\n\\label{sec:foo}\n\n\\begin{equation}%\n\\label{eq:foo}\n 1 + 1 = 2\n\\end{equation}\n\n\\begin{equation}%\n\\label{eq:bar}\n 1 + 1 = 2\n\\end{equation}\n\n\\begin{figure}%\n\\LaTeX{}\n\\caption{Baz}%\n\\label{fig:baz}\n\\end{figure}\n\n\\begin{lemma}%\n\\label{thm:foo}\n 1 + 1 = 2\n\\end{lemma}\n\n\\include{bar}\n\n\\end{document}\n\n%! bar.tex\n\\section{Bar}%\n\\label{sec:bar}\n\nLorem ipsum dolor sit amet.\n\\ref{}\n |\n\n%! foo.aux\n\\relax\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Baz\\relax }}{1}\\protected@file@percent }\n\\providecommand*\\caption@xref[2]{\\@setref\\relax\\@undefined{#1}}\n\\newlabel{fig:baz}{{1}{1}}\n\\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}\\protected@file@percent }\n\\newlabel{sec:foo}{{1}{1}}\n\\newlabel{eq:foo}{{1}{1}}\n\\newlabel{eq:bar}{{2}{1}}\n\\newlabel{thm:foo}{{1}{1}}\n\\@input{bar.aux}\"#)"
+---
+[
+ {
+ "label": "eq:bar",
+ "detail": "Equation (2)",
+ "preselect": false,
+ "filterText": "eq:bar Equation (2)"
+ },
+ {
+ "label": "eq:foo",
+ "detail": "Equation (1)",
+ "preselect": false,
+ "filterText": "eq:foo Equation (1)"
+ },
+ {
+ "label": "fig:baz",
+ "detail": "Figure 1",
+ "preselect": false,
+ "filterText": "fig:baz Figure 1: Baz"
+ },
+ {
+ "label": "sec:bar",
+ "detail": "Section (Bar)",
+ "preselect": false,
+ "filterText": "sec:bar Section (Bar)"
+ },
+ {
+ "label": "sec:foo",
+ "detail": "Section 1 (Foo)",
+ "preselect": false,
+ "filterText": "sec:foo Section 1 (Foo)"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_import.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_import.snap
new file mode 100644
index 0000000000..351dc96deb
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_import.snap
@@ -0,0 +1,31 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\documentclass{article}\n\\import{sub}{sub/sub.tex}\n\\lipsu\n |\n ^^^^^\n\n%! sub/sub.tex\n\\input{child.tex}\n\n%! sub/child.tex\n\\usepackage{lipsum}\"#)"
+---
+[
+ {
+ "label": "LipsumPar",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "LipsumProtect",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "LipsumRestoreAll",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "lipsum",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "lipsumexp",
+ "detail": "lipsum.sty",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_texlabroot.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_texlabroot.snap
new file mode 100644
index 0000000000..8ddefbc6ad
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__project_resolution_texlabroot.snap
@@ -0,0 +1,31 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! src/main.tex\n\\documentclass{article}\n\\include{src/foo}\n\\lipsu\n |\n ^^^^^\n\n%! src/foo.tex\n\\include{src/bar}\n\n%! src/bar.tex\n\\usepackage{lipsum}\n\n%! .texlabroot\"#)"
+---
+[
+ {
+ "label": "LipsumPar",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "LipsumProtect",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "LipsumRestoreAll",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "lipsum",
+ "detail": "lipsum.sty",
+ "preselect": false
+ },
+ {
+ "label": "lipsumexp",
+ "detail": "lipsum.sty",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_begin.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_begin.snap
new file mode 100644
index 0000000000..f60725667f
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_begin.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\newtheorem{lemma}{Lemma}\n\\begin{lem\n |\n ^^^\"#)"
+---
+[
+ {
+ "label": "lemma",
+ "detail": "user-defined",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_end.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_end.snap
new file mode 100644
index 0000000000..0ec951db1d
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__theorem_end.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\newtheorem{lemma}{Lemma}\n\\begin{}\n\\end{lem\n |\n ^^^\"#)"
+---
+[
+ {
+ "label": "lemma",
+ "detail": "user-defined",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_closed_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_closed_brace.snap
new file mode 100644
index 0000000000..e727fbbc1d
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_closed_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\usepgflibrary{}\n |\"#)"
+---
+[
+ {
+ "label": "arrows",
+ "preselect": false
+ },
+ {
+ "label": "arrows.meta",
+ "preselect": false
+ },
+ {
+ "label": "arrows.spaced",
+ "preselect": false
+ },
+ {
+ "label": "curvilinear",
+ "preselect": false
+ },
+ {
+ "label": "datavisualization.barcharts",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_open_brace.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_open_brace.snap
new file mode 100644
index 0000000000..668b445c91
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__tikz_library_open_brace.snap
@@ -0,0 +1,26 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\usepgflibrary{\n |\"#)"
+---
+[
+ {
+ "label": "arrows",
+ "preselect": false
+ },
+ {
+ "label": "arrows.meta",
+ "preselect": false
+ },
+ {
+ "label": "arrows.spaced",
+ "preselect": false
+ },
+ {
+ "label": "curvilinear",
+ "preselect": false
+ },
+ {
+ "label": "datavisualization.barcharts",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_command.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_command.snap
new file mode 100644
index 0000000000..83e2e701ea
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_command.snap
@@ -0,0 +1,11 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\foobar\n\\fooba\n |\n ^^^^^\n\\begin{foo}\n\\end{foo}\n\\begin{fo}\"#)"
+---
+[
+ {
+ "label": "foobar",
+ "detail": "user-defined",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_environment.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_environment.snap
new file mode 100644
index 0000000000..c46a9beb26
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__user_environment.snap
@@ -0,0 +1,16 @@
+---
+source: tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! main.tex\n\\foobar\n\\fooba\n\\begin{foo}\n\\end{foo}\n\\begin{fo}\n |\n ^^\"#)"
+---
+[
+ {
+ "label": "filecontents",
+ "detail": "built-in",
+ "preselect": false
+ },
+ {
+ "label": "foo",
+ "detail": "user-defined",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_import.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_import.snap
new file mode 100644
index 0000000000..b27d0f7a32
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_import.snap
@@ -0,0 +1,19 @@
+---
+source: tests/lsp/text_document/document_link.rs
+expression: "find_links(r#\"\n%! foo.tex\n\\import{.}{bar/baz}\n|\n\n%! bar/baz.tex\"#)"
+---
+[
+ {
+ "range": {
+ "start": {
+ "line": 0,
+ "character": 11
+ },
+ "end": {
+ "line": 0,
+ "character": 18
+ }
+ },
+ "target": "file:///bar/baz.tex"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_include.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_include.snap
new file mode 100644
index 0000000000..fd88cb4a8c
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_link__document_include.snap
@@ -0,0 +1,19 @@
+---
+source: tests/lsp/text_document/document_link.rs
+expression: "find_links(r#\"\n%! foo.tex\n\\input{bar.tex}\n|\n\n%! bar.tex\"#)"
+---
+[
+ {
+ "range": {
+ "start": {
+ "line": 0,
+ "character": 7
+ },
+ "end": {
+ "line": 0,
+ "character": 14
+ }
+ },
+ "target": "file:///bar.tex"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_flat.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_flat.snap
new file mode 100644
index 0000000000..cd18c3f06e
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_flat.snap
@@ -0,0 +1,96 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{enumerate}\n \\item\\label{it:foo} Foo\n \\item\\label{it:bar} Bar\n \\item[Baz] Baz\n \\item[Qux]\\label{it:qux} Qux\n\\end{enumerate}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{it:foo}{{1}{1}}\n\\newlabel{it:qux}{{2}{1}}\"#,\n serde_json::json!({}), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Enumerate",
+ "kind": 10,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 9,
+ "character": 15
+ }
+ }
+ }
+ },
+ {
+ "name": "1",
+ "kind": 22,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 5,
+ "character": 4
+ },
+ "end": {
+ "line": 5,
+ "character": 27
+ }
+ }
+ }
+ },
+ {
+ "name": "Item",
+ "kind": 22,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 6,
+ "character": 4
+ },
+ "end": {
+ "line": 6,
+ "character": 27
+ }
+ }
+ }
+ },
+ {
+ "name": "Baz",
+ "kind": 22,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 7,
+ "character": 4
+ },
+ "end": {
+ "line": 7,
+ "character": 18
+ }
+ }
+ }
+ },
+ {
+ "name": "2",
+ "kind": 22,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 8,
+ "character": 4
+ },
+ "end": {
+ "line": 8,
+ "character": 32
+ }
+ }
+ }
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_nested.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_nested.snap
new file mode 100644
index 0000000000..8f777b6d8f
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_nested.snap
@@ -0,0 +1,140 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{enumerate}\n \\item\\label{it:foo} Foo\n \\item\\label{it:bar} Bar\n \\item[Baz] Baz\n \\item[Qux]\\label{it:qux} Qux\n\\end{enumerate}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{it:foo}{{1}{1}}\n\\newlabel{it:qux}{{2}{1}}\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Enumerate",
+ "kind": 10,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 9,
+ "character": 15
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 9,
+ "character": 15
+ }
+ },
+ "children": [
+ {
+ "name": "1",
+ "detail": "it:foo",
+ "kind": 22,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 5,
+ "character": 4
+ },
+ "end": {
+ "line": 5,
+ "character": 27
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 5,
+ "character": 9
+ },
+ "end": {
+ "line": 5,
+ "character": 23
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Item",
+ "detail": "it:bar",
+ "kind": 22,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 6,
+ "character": 4
+ },
+ "end": {
+ "line": 6,
+ "character": 27
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 6,
+ "character": 9
+ },
+ "end": {
+ "line": 6,
+ "character": 23
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Baz",
+ "kind": 22,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 7,
+ "character": 4
+ },
+ "end": {
+ "line": 7,
+ "character": 18
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 7,
+ "character": 4
+ },
+ "end": {
+ "line": 7,
+ "character": 18
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "2",
+ "detail": "it:qux",
+ "kind": 22,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 8,
+ "character": 4
+ },
+ "end": {
+ "line": 8,
+ "character": 32
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 8,
+ "character": 14
+ },
+ "end": {
+ "line": 8,
+ "character": 28
+ }
+ },
+ "children": []
+ }
+ ]
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_flat.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_flat.snap
new file mode 100644
index 0000000000..d37fe4cbbf
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_flat.snap
@@ -0,0 +1,60 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{equation}\\label{eq:foo}\n Foo\n\\end{equation}\n\n\\begin{equation}\\label{eq:bar}\n Bar\n\\end{equation}\n\n\\begin{equation}\n Baz\n\\end{equation}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{eq:foo}{{1}{1}}\"#,\n serde_json::json!({}), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Equation (1)",
+ "kind": 14,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 6,
+ "character": 14
+ }
+ }
+ }
+ },
+ {
+ "name": "Equation",
+ "kind": 14,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 8,
+ "character": 0
+ },
+ "end": {
+ "line": 10,
+ "character": 14
+ }
+ }
+ }
+ },
+ {
+ "name": "Equation",
+ "kind": 14,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 12,
+ "character": 0
+ },
+ "end": {
+ "line": 14,
+ "character": 14
+ }
+ }
+ }
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_nested.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_nested.snap
new file mode 100644
index 0000000000..5965400814
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_nested.snap
@@ -0,0 +1,86 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{equation}\\label{eq:foo}\n Foo\n\\end{equation}\n\n\\begin{equation}\\label{eq:bar}\n Bar\n\\end{equation}\n\n\\begin{equation}\n Baz\n\\end{equation}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{eq:foo}{{1}{1}}\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Equation (1)",
+ "detail": "eq:foo",
+ "kind": 14,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 6,
+ "character": 14
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 4,
+ "character": 16
+ },
+ "end": {
+ "line": 4,
+ "character": 30
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Equation",
+ "detail": "eq:bar",
+ "kind": 14,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 8,
+ "character": 0
+ },
+ "end": {
+ "line": 10,
+ "character": 14
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 8,
+ "character": 16
+ },
+ "end": {
+ "line": 8,
+ "character": 30
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Equation",
+ "kind": 14,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 12,
+ "character": 0
+ },
+ "end": {
+ "line": 14,
+ "character": 14
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 12,
+ "character": 0
+ },
+ "end": {
+ "line": 14,
+ "character": 14
+ }
+ },
+ "children": []
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_flat.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_flat.snap
new file mode 100644
index 0000000000..e93be78925
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_flat.snap
@@ -0,0 +1,60 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{figure}\n Foo\n \\caption{Foo}\\label{fig:foo}\n\\end{figure}\n\n\\begin{figure}\n Bar\n \\caption{Bar}\\label{fig:bar}\n\\end{figure}\n\n\\begin{figure}\n Baz\n \\caption{Baz}\n\\end{figure}\n\n\\begin{figure}\n Qux\n\\end{figure}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Foo}}{1}\\protected@file@percent }\n\\newlabel{fig:foo}{{1}{1}}\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {2}{\\ignorespaces Bar}}{1}\\protected@file@percent }\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {3}{\\ignorespaces Baz}}{1}\\protected@file@percent }\"#,\n serde_json::json!({}), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Figure 1: Foo",
+ "kind": 6,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 7,
+ "character": 12
+ }
+ }
+ }
+ },
+ {
+ "name": "Figure: Bar",
+ "kind": 6,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 9,
+ "character": 0
+ },
+ "end": {
+ "line": 12,
+ "character": 12
+ }
+ }
+ }
+ },
+ {
+ "name": "Figure: Baz",
+ "kind": 6,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 14,
+ "character": 0
+ },
+ "end": {
+ "line": 17,
+ "character": 12
+ }
+ }
+ }
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_nested.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_nested.snap
new file mode 100644
index 0000000000..a625beb1fb
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_nested.snap
@@ -0,0 +1,86 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{figure}\n Foo\n \\caption{Foo}\\label{fig:foo}\n\\end{figure}\n\n\\begin{figure}\n Bar\n \\caption{Bar}\\label{fig:bar}\n\\end{figure}\n\n\\begin{figure}\n Baz\n \\caption{Baz}\n\\end{figure}\n\n\\begin{figure}\n Qux\n\\end{figure}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Foo}}{1}\\protected@file@percent }\n\\newlabel{fig:foo}{{1}{1}}\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {2}{\\ignorespaces Bar}}{1}\\protected@file@percent }\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {3}{\\ignorespaces Baz}}{1}\\protected@file@percent }\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Figure 1: Foo",
+ "detail": "fig:foo",
+ "kind": 6,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 7,
+ "character": 12
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 6,
+ "character": 17
+ },
+ "end": {
+ "line": 6,
+ "character": 32
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Figure: Bar",
+ "detail": "fig:bar",
+ "kind": 6,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 9,
+ "character": 0
+ },
+ "end": {
+ "line": 12,
+ "character": 12
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 11,
+ "character": 17
+ },
+ "end": {
+ "line": 11,
+ "character": 32
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Figure: Baz",
+ "kind": 6,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 14,
+ "character": 0
+ },
+ "end": {
+ "line": 17,
+ "character": 12
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 14,
+ "character": 0
+ },
+ "end": {
+ "line": 17,
+ "character": 12
+ }
+ },
+ "children": []
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__ignored_patterns.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__ignored_patterns.snap
new file mode 100644
index 0000000000..90c445fc01
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__ignored_patterns.snap
@@ -0,0 +1,24 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{equation}\\label{eq:foo}\n Foo\n\\end{equation}\n \n\\begin{enumerate}\n \\item Foo\n \\item Bar\n\\end{enumerate}\n\n\\end{document}\n|\"#,\n serde_json::json!({}),\n serde_json::json!({\n \"symbols\" : { \"ignoredPatterns\" : [\"Item\", \"Enumerate\"] }\n }))"
+---
+[
+ {
+ "name": "Equation",
+ "kind": 14,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 6,
+ "character": 14
+ }
+ }
+ }
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_flat.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_flat.snap
new file mode 100644
index 0000000000..85d9cef9e8
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_flat.snap
@@ -0,0 +1,60 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\section{Foo}\n\n\\section{Bar}\\label{sec:bar}\n\n\\subsection{Baz}\\label{sec:baz}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}\\protected@file@percent }\n\\@writefile{toc}{\\contentsline {section}{\\numberline {2}Bar}{1}\\protected@file@percent }\n\\newlabel{sec:bar}{{2}{1}}\"#,\n serde_json::json!({}), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Foo",
+ "kind": 2,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 4,
+ "character": 13
+ }
+ }
+ }
+ },
+ {
+ "name": "2 Bar",
+ "kind": 2,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 6,
+ "character": 0
+ },
+ "end": {
+ "line": 8,
+ "character": 31
+ }
+ }
+ }
+ },
+ {
+ "name": "Baz",
+ "kind": 2,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 8,
+ "character": 0
+ },
+ "end": {
+ "line": 8,
+ "character": 31
+ }
+ }
+ }
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_nested.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_nested.snap
new file mode 100644
index 0000000000..bac292bf01
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_nested.snap
@@ -0,0 +1,87 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\section{Foo}\n\n\\section{Bar}\\label{sec:bar}\n\n\\subsection{Baz}\\label{sec:baz}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}\\protected@file@percent }\n\\@writefile{toc}{\\contentsline {section}{\\numberline {2}Bar}{1}\\protected@file@percent }\n\\newlabel{sec:bar}{{2}{1}}\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Foo",
+ "kind": 2,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 4,
+ "character": 13
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 4,
+ "character": 0
+ },
+ "end": {
+ "line": 4,
+ "character": 13
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "2 Bar",
+ "detail": "sec:bar",
+ "kind": 2,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 6,
+ "character": 0
+ },
+ "end": {
+ "line": 8,
+ "character": 31
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 6,
+ "character": 13
+ },
+ "end": {
+ "line": 6,
+ "character": 28
+ }
+ },
+ "children": [
+ {
+ "name": "Baz",
+ "detail": "sec:baz",
+ "kind": 2,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 8,
+ "character": 0
+ },
+ "end": {
+ "line": 8,
+ "character": 31
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 8,
+ "character": 16
+ },
+ "end": {
+ "line": 8,
+ "character": 31
+ }
+ },
+ "children": []
+ }
+ ]
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_flat.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_flat.snap
new file mode 100644
index 0000000000..55ab44980c
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_flat.snap
@@ -0,0 +1,78 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\\usepackage{amsthm}\n\\newtheorem{lemma}{Lemma}\n\n\\begin{document}\n\n\\begin{lemma}[Foo]\\label{thm:foo}\n Foo\n\\end{lemma}\n\n\\begin{lemma}\\label{thm:bar}\n Bar\n\\end{lemma}\n\n\\begin{lemma}\\label{thm:baz}\n Baz\n\\end{lemma}\n\n\\begin{lemma}[Qux]\n Qux\n\\end{lemma}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{thm:foo}{{1}{1}}\n\\newlabel{thm:bar}{{2}{1}}\"#,\n serde_json::json!({}), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Lemma 1 (Foo)",
+ "kind": 13,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 6,
+ "character": 0
+ },
+ "end": {
+ "line": 8,
+ "character": 11
+ }
+ }
+ }
+ },
+ {
+ "name": "Lemma 2",
+ "kind": 13,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 10,
+ "character": 0
+ },
+ "end": {
+ "line": 12,
+ "character": 11
+ }
+ }
+ }
+ },
+ {
+ "name": "Lemma",
+ "kind": 13,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 14,
+ "character": 0
+ },
+ "end": {
+ "line": 16,
+ "character": 11
+ }
+ }
+ }
+ },
+ {
+ "name": "Lemma (Qux)",
+ "kind": 13,
+ "deprecated": false,
+ "location": {
+ "uri": "file:///main.tex",
+ "range": {
+ "start": {
+ "line": 18,
+ "character": 0
+ },
+ "end": {
+ "line": 20,
+ "character": 11
+ }
+ }
+ }
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_nested.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_nested.snap
new file mode 100644
index 0000000000..82bdd6d1d9
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_nested.snap
@@ -0,0 +1,113 @@
+---
+source: tests/lsp/text_document/document_symbol.rs
+expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\\usepackage{amsthm}\n\\newtheorem{lemma}{Lemma}\n\n\\begin{document}\n\n\\begin{lemma}[Foo]\\label{thm:foo}\n Foo\n\\end{lemma}\n\n\\begin{lemma}\\label{thm:bar}\n Bar\n\\end{lemma}\n\n\\begin{lemma}\\label{thm:baz}\n Baz\n\\end{lemma}\n\n\\begin{lemma}[Qux]\n Qux\n\\end{lemma}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{thm:foo}{{1}{1}}\n\\newlabel{thm:bar}{{2}{1}}\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
+---
+[
+ {
+ "name": "Lemma 1 (Foo)",
+ "detail": "thm:foo",
+ "kind": 13,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 6,
+ "character": 0
+ },
+ "end": {
+ "line": 8,
+ "character": 11
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 6,
+ "character": 18
+ },
+ "end": {
+ "line": 6,
+ "character": 33
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Lemma 2",
+ "detail": "thm:bar",
+ "kind": 13,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 10,
+ "character": 0
+ },
+ "end": {
+ "line": 12,
+ "character": 11
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 10,
+ "character": 13
+ },
+ "end": {
+ "line": 10,
+ "character": 28
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Lemma",
+ "detail": "thm:baz",
+ "kind": 13,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 14,
+ "character": 0
+ },
+ "end": {
+ "line": 16,
+ "character": 11
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 14,
+ "character": 13
+ },
+ "end": {
+ "line": 14,
+ "character": 28
+ }
+ },
+ "children": []
+ },
+ {
+ "name": "Lemma (Qux)",
+ "kind": 13,
+ "deprecated": false,
+ "range": {
+ "start": {
+ "line": 18,
+ "character": 0
+ },
+ "end": {
+ "line": 20,
+ "character": 11
+ }
+ },
+ "selectionRange": {
+ "start": {
+ "line": 18,
+ "character": 0
+ },
+ "end": {
+ "line": 20,
+ "character": 11
+ }
+ },
+ "children": []
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__bibtex.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__bibtex.snap
new file mode 100644
index 0000000000..2063cc39e5
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__bibtex.snap
@@ -0,0 +1,27 @@
+---
+source: tests/lsp/text_document/folding_range.rs
+expression: "find_foldings(r#\"\n%! main.bib\nsome junk\nhere\n\n@article{foo,\n author = {bar},\n title = {baz}\n}\n\n@string{foo = \"bar\"}\n\n@comment{foo,\n author = {bar},\n title = {baz}\n}\n\n@preamble{\"foo\"}\n|\"#)"
+---
+[
+ {
+ "startLine": 3,
+ "startCharacter": 0,
+ "endLine": 6,
+ "endCharacter": 1,
+ "kind": "region"
+ },
+ {
+ "startLine": 8,
+ "startCharacter": 0,
+ "endLine": 8,
+ "endCharacter": 20,
+ "kind": "region"
+ },
+ {
+ "startLine": 15,
+ "startCharacter": 0,
+ "endLine": 15,
+ "endCharacter": 16,
+ "kind": "region"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__latex.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__latex.snap
new file mode 100644
index 0000000000..74632eda56
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__folding_range__latex.snap
@@ -0,0 +1,41 @@
+---
+source: tests/lsp/text_document/folding_range.rs
+expression: "find_foldings(r#\"\n%! main.tex\n\\begin{document}\n \\section{Foo}\n foo\n \\subsection{Bar}\n bar\n \\section{Baz}\n baz\n \\section{Qux}\n\\end{document}\n|\"#)"
+---
+[
+ {
+ "startLine": 0,
+ "startCharacter": 0,
+ "endLine": 8,
+ "endCharacter": 14,
+ "kind": "region"
+ },
+ {
+ "startLine": 1,
+ "startCharacter": 4,
+ "endLine": 4,
+ "endCharacter": 7,
+ "kind": "region"
+ },
+ {
+ "startLine": 3,
+ "startCharacter": 4,
+ "endLine": 4,
+ "endCharacter": 7,
+ "kind": "region"
+ },
+ {
+ "startLine": 5,
+ "startCharacter": 4,
+ "endLine": 6,
+ "endCharacter": 7,
+ "kind": "region"
+ },
+ {
+ "startLine": 7,
+ "startCharacter": 4,
+ "endLine": 7,
+ "endCharacter": 17,
+ "kind": "region"
+ }
+]
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_command.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_command.snap
new file mode 100644
index 0000000000..b98dd68758
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_command.snap
@@ -0,0 +1,7 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@article{foo, bar = \"\\baz\",}\n|\"#)"
+---
+@article{foo,
+ bar = "\baz",
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_insert_braces.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_insert_braces.snap
new file mode 100644
index 0000000000..a95f5d3006
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_insert_braces.snap
@@ -0,0 +1,7 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@article{foo, bar = baz,\n|\"#)"
+---
+@article{foo,
+ bar = baz,
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_join_strings.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_join_strings.snap
new file mode 100644
index 0000000000..3ea6bf18ad
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_join_strings.snap
@@ -0,0 +1,7 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@article{foo, bar = \"baz\" # \"qux\"}\n|\"#)"
+---
+@article{foo,
+ bar = "baz" # "qux",
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_multiple_entries.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_multiple_entries.snap
new file mode 100644
index 0000000000..966f133a76
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_multiple_entries.snap
@@ -0,0 +1,15 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}\n\n@article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}\"\n|\"#)"
+---
+@article{foo,
+ bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum
+ dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit
+ amet, consectetur adipiscing elit.},
+}
+
+@article{foo,
+ bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum
+ dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit
+ amet, consectetur adipiscing elit.},
+}"
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_parens.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_parens.snap
new file mode 100644
index 0000000000..ca317db108
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_parens.snap
@@ -0,0 +1,6 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@article(foo,)\n|\"#)"
+---
+@article{foo,
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_preamble.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_preamble.snap
new file mode 100644
index 0000000000..6448e3a791
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_preamble.snap
@@ -0,0 +1,5 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@preamble{\n \"foo bar baz\" }\n|\"#)"
+---
+@preamble{"foo bar baz"}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_string.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_string.snap
new file mode 100644
index 0000000000..a1739290fd
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_string.snap
@@ -0,0 +1,5 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@string{foo=\"bar\"}\n|\"#)"
+---
+@string{foo = "bar"}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_trailing_comma.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_trailing_comma.snap
new file mode 100644
index 0000000000..dd5c7b49f0
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_trailing_comma.snap
@@ -0,0 +1,7 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@article{foo, bar = baz}\n|\"#)"
+---
+@article{foo,
+ bar = baz,
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_wrap_long_lines.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_wrap_long_lines.snap
new file mode 100644
index 0000000000..c52b8a9317
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__formatting__bibtex_internal_wrap_long_lines.snap
@@ -0,0 +1,9 @@
+---
+source: tests/lsp/text_document/formatting.rs
+expression: "format(r#\"\n%! main.bib\n@article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nLorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}\n|\"#)"
+---
+@article{foo,
+ bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum
+ dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit
+ amet, consectetur adipiscing elit.},
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__citation_inside_cite.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__citation_inside_cite.snap
new file mode 100644
index 0000000000..6e6c6b264c
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__citation_inside_cite.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.bib\n@article{foo, author = {Foo Bar}, title = {Baz Qux}, year = 1337}\n\n%! main.tex\n\\addbibresource{main.bib}\n\\cite{foo}\n |\n ^^^\"#)"
+---
+{
+ "kind": "markdown",
+ "value": "F. Bar: \"Baz Qux\". (1337)."
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__citation_inside_entry.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__citation_inside_entry.snap
new file mode 100644
index 0000000000..c13c16051d
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__citation_inside_entry.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.bib\n@article{foo, author = {Foo Bar}, title = {Baz Qux}, year = 1337}\n |\n ^^^\n\n%! main.tex\n\\addbibresource{main.bib}\n\\cite{foo}\"#)"
+---
+{
+ "kind": "markdown",
+ "value": "F. Bar: \"Baz Qux\". (1337)."
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__component_known_package.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__component_known_package.snap
new file mode 100644
index 0000000000..ea1801d4ed
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__component_known_package.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.tex\n\\usepackage{amsmath}\n |\n ^^^^^^^\"#)"
+---
+{
+ "kind": "plaintext",
+ "value": "The package provides the principal packages in the AMS-LaTeX distribution. It adapts for use in LaTeX most of the mathematical features found in AMS-TeX; it is highly recommended as an adjunct to serious mathematical typesetting in LaTeX. When amsmath is loaded, AMS-LaTeX packages amsbsy (for bold symbols), amsopn (for operator names) and amstext (for text embedded in mathematics) are also loaded. amsmath is part of the LaTeX required distribution; however, several contributed packages add still further to its appeal; examples are empheq, which provides functions for decorating and highlighting mathematics, and ntheorem, for specifying theorem (and similar) definitions."
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__entry_type_known_type.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__entry_type_known_type.snap
new file mode 100644
index 0000000000..f3b146fb21
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__entry_type_known_type.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.bib\n@article{foo,}\n |\n^^^^^^^^\"#)"
+---
+{
+ "kind": "markdown",
+ "value": "An article in a journal, magazine, newspaper, or other periodical which forms a \n self-contained unit with its own title. The title of the periodical is given in the \n journaltitle field. If the issue has its own title in addition to the main title of \n the periodical, it goes in the issuetitle field. Note that editor and related \n fields refer to the journal while translator and related fields refer to the article.\n\nRequired fields: `author`, `title`, `journaltitle`, `year/date`"
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__field_known.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__field_known.snap
new file mode 100644
index 0000000000..42d630c287
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__field_known.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.bib\n@article{foo, author = bar}\n |\n ^^^^^^\"#)"
+---
+{
+ "kind": "markdown",
+ "value": "The author(s) of the `title`."
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__label_theorem_child_file.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__label_theorem_child_file.snap
new file mode 100644
index 0000000000..19b36c4ebb
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__label_theorem_child_file.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.tex\n\\documentclass{article}\n\\newtheorem{lemma}{Lemma}\n\\include{child}\n\\ref{thm:foo}\n |\n ^^^^^^^\n\n%! child.tex\n\\begin{lemma}\\label{thm:foo}\n 1 + 1 = 2\n\\end{lemma}\"#)"
+---
+{
+ "kind": "plaintext",
+ "value": "Lemma"
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__label_theorem_child_file_mumber.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__label_theorem_child_file_mumber.snap
new file mode 100644
index 0000000000..78ccef8e46
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__label_theorem_child_file_mumber.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.tex\n\\documentclass{article}\n\\newtheorem{lemma}{Lemma}\n\\include{child}\n\\ref{thm:foo}\n |\n ^^^^^^^\n\n%! child.tex\n\\begin{lemma}[Foo]\\label{thm:foo}\n 1 + 1 = 2\n\\end{lemma}\n\n%! child.aux\n\\newlabel{thm:foo}{{1}{1}{Foo}{lemma.1}{}}\"#)"
+---
+{
+ "kind": "plaintext",
+ "value": "Lemma 1 (Foo)"
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__section.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__section.snap
new file mode 100644
index 0000000000..c8aa265330
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__section.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.tex\n\\section{Foo}\n\\label{sec:foo}\n |\n ^^^^^^^\"#)"
+---
+{
+ "kind": "plaintext",
+ "value": "Section (Foo)"
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__string_inside_reference.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__string_inside_reference.snap
new file mode 100644
index 0000000000..cfcc196e26
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__hover__string_inside_reference.snap
@@ -0,0 +1,8 @@
+---
+source: tests/lsp/text_document/hover.rs
+expression: "find_hover(r#\"\n%! main.bib\n@string{foo = \"Foo\"}\n@string{bar = \"Bar\"}\n@article{baz, author = bar}\n |\n ^^^\"#)"
+---
+{
+ "kind": "plaintext",
+ "value": "Bar"
+}
diff --git a/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__inlay_hint__label_definition.snap b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__inlay_hint__label_definition.snap
new file mode 100644
index 0000000000..accf4a875c
--- /dev/null
+++ b/support/texlab/tests/lsp/text_document/snapshots/lsp__text_document__inlay_hint__label_definition.snap
@@ -0,0 +1,38 @@
+---
+source: tests/lsp/text_document/inlay_hint.rs
+expression: "find_hints(r#\"\n%! main.tex\n\\documentclass{article}\n\\usepackage{caption}\n\\begin{document}\n\\section{Foo}\\label{sec:foo}\n\\section{Bar}\\label{sec:bar}\n\\subsection{Baz}\\label{sec:baz}\n\\begin{figure}\n Test\n \\label{fig:qux}\n \\caption{Qux}\n\\end{figure}\n\\end{document}\n |\n\n%! main.aux\n\\relax \n\\providecommand*\\caption@xref[2]{\\@setref\\relax\\@undefined{#1}}\n\\newlabel{fig:qux}{{\\caption@xref {fig:qux}{ on input line 15}}{1}}\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Qux\\relax }}{1}{}\\protected@file@percent }\n\\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}{}\\protected@file@percent }\n\\newlabel{sec:foo}{{1}{1}}\n\\@writefile{toc}{\\contentsline {section}{\\numberline {2}Bar}{1}{}\\protected@file@percent }\n\\newlabel{sec:bar}{{2}{1}}\n\\@writefile{toc}{\\contentsline {subsection}{\\numberline {2.1}Baz}{1}{}\\protected@file@percent }\n\\newlabel{sec:baz}{{2.1}{1}}\n\\gdef \\@abspage@last{1}\"#)"
+---
+[
+ {
+ "position": {
+ "line": 3,
+ "character": 27
+ },
+ "label": "Section 1 (Foo)",
+ "paddingLeft": true
+ },
+ {
+ "position": {
+ "line": 4,
+ "character": 27
+ },
+ "label": "Section 2 (Bar)",
+ "paddingLeft": true
+ },
+ {
+ "position": {
+ "line": 5,
+ "character": 30
+ },
+ "label": "Subsection 2.1 (Baz)",
+ "paddingLeft": true
+ },
+ {
+ "position": {
+ "line": 8,
+ "character": 18
+ },
+ "label": "Figure fig:qux: Qux",
+ "paddingLeft": true
+ }
+]