summaryrefslogtreecommitdiff
path: root/support
diff options
context:
space:
mode:
Diffstat (limited to 'support')
-rw-r--r--support/texlab/CHANGELOG.md136
-rw-r--r--support/texlab/Cargo.lock1151
-rw-r--r--support/texlab/Cargo.toml71
-rw-r--r--support/texlab/README.md13
-rw-r--r--support/texlab/benches/bench_main.rs39
-rw-r--r--support/texlab/docs/custom_commands.md21
-rw-r--r--support/texlab/docs/custom_messages.md102
-rw-r--r--support/texlab/docs/lsp_kinds.md31
-rw-r--r--support/texlab/docs/options.md225
-rw-r--r--support/texlab/docs/previewing.md195
-rw-r--r--support/texlab/docs/tectonic.md48
-rw-r--r--support/texlab/images/demo.gif (renamed from support/texlab/docs/demo.gif)bin380190 -> 380190 bytes
-rw-r--r--support/texlab/rust-toolchain1
-rw-r--r--support/texlab/src/citation/driver.rs2
-rw-r--r--support/texlab/src/citation/field/date.rs2
-rw-r--r--support/texlab/src/citation/tests.rs4
-rw-r--r--support/texlab/src/client.rs144
-rw-r--r--support/texlab/src/component_db.rs151
-rw-r--r--support/texlab/src/db.rs14
-rw-r--r--support/texlab/src/db/analysis.rs199
-rw-r--r--support/texlab/src/db/analysis/label.rs122
-rw-r--r--support/texlab/src/db/diagnostics.rs187
-rw-r--r--support/texlab/src/db/diagnostics/bib.rs112
-rw-r--r--support/texlab/src/db/diagnostics/log.rs100
-rw-r--r--support/texlab/src/db/diagnostics/tex.rs125
-rw-r--r--support/texlab/src/db/discovery.rs251
-rw-r--r--support/texlab/src/db/document.rs193
-rw-r--r--support/texlab/src/db/parse.rs71
-rw-r--r--support/texlab/src/db/workspace.rs245
-rw-r--r--support/texlab/src/debouncer.rs55
-rw-r--r--support/texlab/src/diagnostics.rs167
-rw-r--r--support/texlab/src/diagnostics/bibtex.rs139
-rw-r--r--support/texlab/src/diagnostics/build.rs68
-rw-r--r--support/texlab/src/diagnostics/chktex.rs103
-rw-r--r--support/texlab/src/diagnostics/latex.rs126
-rw-r--r--support/texlab/src/distro.rs65
-rw-r--r--support/texlab/src/distro/file_name_db.rs80
-rw-r--r--support/texlab/src/distro/kpsewhich.rs52
-rw-r--r--support/texlab/src/distro/miktex.rs30
-rw-r--r--support/texlab/src/distro/texlive.rs10
-rw-r--r--support/texlab/src/document.rs135
-rw-r--r--support/texlab/src/environment.rs33
-rw-r--r--support/texlab/src/features.rs66
-rw-r--r--support/texlab/src/features/build.rs335
-rw-r--r--support/texlab/src/features/build/progress.rs54
-rw-r--r--support/texlab/src/features/completion.rs599
-rw-r--r--support/texlab/src/features/completion/acronym_ref.rs25
-rw-r--r--support/texlab/src/features/completion/argument.rs27
-rw-r--r--support/texlab/src/features/completion/begin_command.rs18
-rw-r--r--support/texlab/src/features/completion/begin_snippet.rs9
-rw-r--r--support/texlab/src/features/completion/builder.rs784
-rw-r--r--support/texlab/src/features/completion/citation.rs82
-rw-r--r--support/texlab/src/features/completion/color.rs19
-rw-r--r--support/texlab/src/features/completion/color_model.rs20
-rw-r--r--support/texlab/src/features/completion/component_command.rs28
-rw-r--r--support/texlab/src/features/completion/component_environment.rs22
-rw-r--r--support/texlab/src/features/completion/entry_type.rs22
-rw-r--r--support/texlab/src/features/completion/field.rs19
-rw-r--r--support/texlab/src/features/completion/glossary_ref.rs27
-rw-r--r--support/texlab/src/features/completion/import.rs57
-rw-r--r--support/texlab/src/features/completion/include.rs78
-rw-r--r--support/texlab/src/features/completion/label.rs112
-rw-r--r--support/texlab/src/features/completion/theorem.rs26
-rw-r--r--support/texlab/src/features/completion/tikz_library.rs24
-rw-r--r--support/texlab/src/features/completion/types.rs151
-rw-r--r--support/texlab/src/features/completion/user_command.rs34
-rw-r--r--support/texlab/src/features/completion/user_environment.rs26
-rw-r--r--support/texlab/src/features/completion/util.rs64
-rw-r--r--support/texlab/src/features/definition.rs54
-rw-r--r--support/texlab/src/features/definition/command.rs20
-rw-r--r--support/texlab/src/features/definition/document.rs50
-rw-r--r--support/texlab/src/features/definition/entry.rs24
-rw-r--r--support/texlab/src/features/definition/label.rs37
-rw-r--r--support/texlab/src/features/definition/string.rs33
-rw-r--r--support/texlab/src/features/execute_command.rs103
-rw-r--r--support/texlab/src/features/folding.rs59
-rw-r--r--support/texlab/src/features/formatting.rs35
-rw-r--r--support/texlab/src/features/formatting/bibtex_internal.rs56
-rw-r--r--support/texlab/src/features/formatting/latexindent.rs112
-rw-r--r--support/texlab/src/features/forward_search.rs184
-rw-r--r--support/texlab/src/features/highlight.rs14
-rw-r--r--support/texlab/src/features/highlight/label.rs93
-rw-r--r--support/texlab/src/features/hover.rs39
-rw-r--r--support/texlab/src/features/hover/citation.rs25
-rw-r--r--support/texlab/src/features/hover/component.rs39
-rw-r--r--support/texlab/src/features/hover/entry_type.rs11
-rw-r--r--support/texlab/src/features/hover/field.rs11
-rw-r--r--support/texlab/src/features/hover/label.rs24
-rw-r--r--support/texlab/src/features/hover/string_ref.rs15
-rw-r--r--support/texlab/src/features/inlay_hint.rs45
-rw-r--r--support/texlab/src/features/inlay_hint/label.rs31
-rw-r--r--support/texlab/src/features/link.rs54
-rw-r--r--support/texlab/src/features/link/include.rs42
-rw-r--r--support/texlab/src/features/reference.rs45
-rw-r--r--support/texlab/src/features/reference/entry.rs35
-rw-r--r--support/texlab/src/features/reference/label.rs31
-rw-r--r--support/texlab/src/features/reference/string.rs24
-rw-r--r--support/texlab/src/features/rename.rs58
-rw-r--r--support/texlab/src/features/rename/command.rs30
-rw-r--r--support/texlab/src/features/rename/entry.rs40
-rw-r--r--support/texlab/src/features/rename/label.rs34
-rw-r--r--support/texlab/src/features/symbol.rs82
-rw-r--r--support/texlab/src/features/symbol/bibtex.rs137
-rw-r--r--support/texlab/src/features/symbol/latex.rs236
-rw-r--r--support/texlab/src/features/symbol/project_order.rs307
-rw-r--r--support/texlab/src/features/symbol/types.rs15
-rw-r--r--support/texlab/src/features/workspace_command.rs103
-rw-r--r--support/texlab/src/language.rs33
-rw-r--r--support/texlab/src/lib.rs147
-rw-r--r--support/texlab/src/main.rs8
-rw-r--r--support/texlab/src/options.rs103
-rw-r--r--support/texlab/src/parser.rs5
-rw-r--r--support/texlab/src/parser/bibtex.rs (renamed from support/texlab/src/syntax/bibtex/parser.rs)206
-rw-r--r--support/texlab/src/parser/build_log.rs184
-rw-r--r--support/texlab/src/parser/latex.rs (renamed from support/texlab/src/syntax/latex/parser.rs)700
-rw-r--r--support/texlab/src/parser/latex/lexer.rs (renamed from support/texlab/src/syntax/latex/lexer.rs)115
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@comment.txt.snap10
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@issue_809.txt.snap31
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@preamble.txt.snap (renamed from support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__preamble.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__aho_2006.txt.snap132
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__aksin_2006.txt.snap (renamed from support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_002.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__almendro_1998.txt.snap246
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__averroes_1998.txt.snap351
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__betram_1996.txt.snap208
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__blom_2021.txt.snap223
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__combi_2004.txt.snap251
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__erwin_2007.txt.snap239
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__jain_1999.txt.snap267
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__kastenholz_2006.txt.snap302
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__knuth_1984.txt.snap320
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__matuz_1990.txt.snap176
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__nietzsche_1998.txt.snap368
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__rivest_1978.txt.snap232
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@001.txt.snap27
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@002.txt.snap20
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@003.txt.snap23
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@004.txt.snap31
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@005.txt.snap30
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@006.txt.snap69
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@007.txt.snap19
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@block_comments.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__block_comments.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_default.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_default_error.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_error.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_figure.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_figure.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_minimal.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_minimal_error.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal_error.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_empty.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_empty.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_missing_brace.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_missing_brace.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_multiple_keys.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_multiple_keys.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_prenote.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_prenote_postnote.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote_postnote.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_redundant_comma.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_redundant_comma.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_star.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_star.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_definition_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_definition_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_reference_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_reference_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error1.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error1.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error2.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error2.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error3.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error3.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error4.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error4.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_argc.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_argc.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_impl.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_impl_error.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl_error.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_optional.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_optional.snap)7
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_with_begin.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_with_begin.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__math_operator_no_impl.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_no_impl.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__math_operator_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_asymptote.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__asymptote.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_definition.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_definition_optional_arg.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition_optional_arg.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_nested.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_nested_missing_braces.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested_missing_braces.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@equation.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@equation_missing_begin.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_begin.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_args.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_args.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_empty.txt.snap10
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_escape.txt.snap10
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_declaration.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acronym_declaration.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_definition_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_definition_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_package.txt.snap30
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_reference_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_reference_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_definition_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_definition_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_reference_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_reference_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path.txt.snap18
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path_command.txt.snap23
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path_options.txt.snap23
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__curly_group_missing_end.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_missing_end.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__curly_group_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__equation_missing_end.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_end.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__escaped_brackets.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__escaped_brackets.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_braces.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_braces.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_brackets.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_brackets_with_group.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets_with_group.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@hello_world.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__hello_world.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__biblatex_include_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__biblatex_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__bibtex_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__bibtex_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_empty.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_empty.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_command.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_command.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_complicated_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_complicated_options.snap)7
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__import_incomplete.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_incomplete.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__import_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__inkscape_include_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__inkscape_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_include_equality_sign.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_equality_sign.snap)7
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_input_path_brackets.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_path_with_brackets.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_empty.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_empty.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_multiple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_multiple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__pgf_library_import_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__pgf_library_import_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__svg_include_options.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_options.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__svg_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__tikz_library_import_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__tikz_library_import_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__verbatim_include_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__verbatim_include_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@inline.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@inline_double_dollar.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline_double_dollar.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@issue_745.txt.snap120
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@issue_789.txt.snap15
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_definition_line_break.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_line_break.snap)7
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_definition_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_number.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_number.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_equation.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_label_reference_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_incomplete.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_incomplete.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_multiple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_multiple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_error.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_error.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_incomplete.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_incomplete.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_simple.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_simple.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@parameter.txt.snap10
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@parameter_error.txt.snap10
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_enum_item.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_enum_item.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_invalid_nesting.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_invalid_nesting.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_nested.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_nested.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_siblings.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_siblings.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_full.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_full.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_counter.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_counter.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description_and_counter.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description_and_counter.snap)6
-rw-r--r--support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_only_name.txt.snap (renamed from support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_only_name.snap)6
-rw-r--r--support/texlab/src/parser/test_data/bibtex/comment.txt6
-rw-r--r--support/texlab/src/parser/test_data/bibtex/issue_809.txt3
-rw-r--r--support/texlab/src/parser/test_data/bibtex/preamble.txt1
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/aho_2006.txt8
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/aksin_2006.txt16
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/almendro_1998.txt14
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/averroes_1998.txt21
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/betram_1996.txt16
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/blom_2021.txt20
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/combi_2004.txt16
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/erwin_2007.txt14
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/jain_1999.txt18
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/kastenholz_2006.txt20
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/knuth_1984.txt22
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/matuz_1990.txt14
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/nietzsche_1998.txt24
-rw-r--r--support/texlab/src/parser/test_data/bibtex/samples/rivest_1978.txt17
-rw-r--r--support/texlab/src/parser/test_data/build_log/001.txt83
-rw-r--r--support/texlab/src/parser/test_data/build_log/002.txt64
-rw-r--r--support/texlab/src/parser/test_data/build_log/003.txt65
-rw-r--r--support/texlab/src/parser/test_data/build_log/004.txt83
-rw-r--r--support/texlab/src/parser/test_data/build_log/005.txt385
-rw-r--r--support/texlab/src/parser/test_data/build_log/006.txt122
-rw-r--r--support/texlab/src/parser/test_data/build_log/007.txt176
-rw-r--r--support/texlab/src/parser/test_data/latex/block_comments.txt9
-rw-r--r--support/texlab/src/parser/test_data/latex/caption/caption_default.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/caption/caption_default_error.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/caption/caption_figure.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/caption/caption_minimal.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/caption/caption_minimal_error.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/citation/citation_empty.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/citation/citation_missing_brace.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/citation/citation_multiple_keys.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/citation/citation_prenote.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/citation/citation_prenote_postnote.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/citation/citation_redundant_comma.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/citation/citation_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/citation/citation_star.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/color/color_definition_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/color/color_reference_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/color/color_set_definition_error1.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/color/color_set_definition_error2.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/color/color_set_definition_error3.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/color/color_set_definition_error4.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/color/color_set_definition_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_argc.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_impl.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_impl_error.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/command_definition/command_definition_optional.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/command_definition/command_definition_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/command_definition/command_definition_with_begin.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/command_definition/math_operator_no_impl.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/command_definition/math_operator_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/environment/environment_asymptote.txt3
-rw-r--r--support/texlab/src/parser/test_data/latex/environment/environment_definition.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/environment/environment_definition_optional_arg.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/environment/environment_nested.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/environment/environment_nested_missing_braces.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/environment/environment_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/equation.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/equation_missing_begin.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/generic_command_args.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/generic_command_empty.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/generic_command_escape.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/acronym_declaration.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/acronym_definition_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/acronym_definition_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/acronym_package.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/acronym_reference_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/acronym_reference_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/glossary_entry_definition_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/glossary_entry_reference_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/glossary/glossary_entry_reference_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/graphics_path.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/graphics_path_command.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/graphics_path_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/group/curly_group_missing_end.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/group/curly_group_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/group/equation_missing_end.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/group/escaped_brackets.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/group/unmatched_braces.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/group/unmatched_brackets.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/group/unmatched_brackets_with_group.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/hello_world.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/biblatex_include_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/biblatex_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/bibtex_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/class_include_empty.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/class_include_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/class_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/graphics_include_command.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/graphics_include_complicated_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/graphics_include_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/graphics_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/import_incomplete.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/import_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/inkscape_include_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/inkscape_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/latex_include_equality_sign.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/latex_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/latex_input_path_brackets.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/package_include_empty.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/package_include_multiple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/package_include_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/package_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/pgf_library_import_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/svg_include_options.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/svg_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/tikz_library_import_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/include/verbatim_include_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/inline.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/inline_double_dollar.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/issue_745.txt21
-rw-r--r--support/texlab/src/parser/test_data/latex/issue_789.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_definition_line_break.txt2
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_definition_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_number.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_reference_equation.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_reference_incomplete.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_reference_multiple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_reference_range_error.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_reference_range_incomplete.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_reference_range_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/label/label_reference_simple.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/parameter.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/parameter_error.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/structure/structure_enum_item.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/structure/structure_invalid_nesting.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/structure/structure_nested.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/structure/structure_siblings.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_full.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_counter.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description_and_counter.txt1
-rw-r--r--support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_only_name.txt1
-rw-r--r--support/texlab/src/range.rs20
-rw-r--r--support/texlab/src/req_queue.rs10
-rw-r--r--support/texlab/src/server.rs1156
-rw-r--r--support/texlab/src/server/dispatch.rs (renamed from support/texlab/src/dispatch.rs)0
-rw-r--r--support/texlab/src/server/query.rs32
-rw-r--r--support/texlab/src/syntax.rs21
-rw-r--r--support/texlab/src/syntax/bibtex.rs247
-rw-r--r--support/texlab/src/syntax/bibtex/ast.rs244
-rw-r--r--support/texlab/src/syntax/bibtex/lexer.rs180
-rw-r--r--support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_001.snap430
-rw-r--r--support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_003.snap208
-rw-r--r--support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__comment.snap9
-rw-r--r--support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__entry_colon.snap51
-rw-r--r--support/texlab/src/syntax/bibtex/tests.rs126
-rw-r--r--support/texlab/src/syntax/build_log.rs1332
-rw-r--r--support/texlab/src/syntax/latex.rs5
-rw-r--r--support/texlab/src/syntax/latex/analysis.rs40
-rw-r--r--support/texlab/src/syntax/latex/analysis/command.rs26
-rw-r--r--support/texlab/src/syntax/latex/analysis/distro_file.rs73
-rw-r--r--support/texlab/src/syntax/latex/analysis/environment.rs13
-rw-r--r--support/texlab/src/syntax/latex/analysis/explicit_link.rs72
-rw-r--r--support/texlab/src/syntax/latex/analysis/graphics_path.rs21
-rw-r--r--support/texlab/src/syntax/latex/analysis/implicit_link.rs64
-rw-r--r--support/texlab/src/syntax/latex/analysis/label_name.rs67
-rw-r--r--support/texlab/src/syntax/latex/analysis/label_number.rs24
-rw-r--r--support/texlab/src/syntax/latex/analysis/theorem.rs22
-rw-r--r--support/texlab/src/syntax/latex/analysis/types.rs75
-rw-r--r--support/texlab/src/syntax/latex/cst.rs2
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__asymptote.snap43
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__block_comment.snap27
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_parameter.snap47
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_star.snap23
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__comment.snap36
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__delimiters.snap79
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__empty.snap6
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__escape_sequence.snap19
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__formula.snap55
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__invalid_parameter.snap11
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__line_break.snap20
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__empty.snap8
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_empty.snap10
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_escape.snap10
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_path.snap17
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_simple.snap15
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter.snap10
-rw-r--r--support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter_error.snap10
-rw-r--r--support/texlab/src/syntax/snapshots/texlab__syntax__build_log__tests__parse_007.snap15
-rw-r--r--support/texlab/src/tests.rs (renamed from support/texlab/tests/integration/lsp.rs)1
-rw-r--r--support/texlab/src/tests/client.rs (renamed from support/texlab/tests/integration/lsp/client.rs)106
-rw-r--r--support/texlab/src/tests/fixture.rs (renamed from support/texlab/tests/integration/lsp/fixture.rs)11
-rw-r--r--support/texlab/src/tests/issues.rs12
-rw-r--r--support/texlab/src/tests/snapshots/texlab__tests__issues__issue_707.snap45
-rw-r--r--support/texlab/src/tests/text_document.rs (renamed from support/texlab/tests/integration/lsp/text_document.rs)3
-rw-r--r--support/texlab/src/tests/text_document/completion.rs (renamed from support/texlab/tests/integration/lsp/text_document/completion.rs)390
-rw-r--r--support/texlab/src/tests/text_document/definition.rs (renamed from support/texlab/tests/integration/lsp/text_document/definition.rs)34
-rw-r--r--support/texlab/src/tests/text_document/did_change_configuration.rs (renamed from support/texlab/tests/integration/lsp/text_document/did_change_configuration.rs)14
-rw-r--r--support/texlab/src/tests/text_document/document_highlight.rs (renamed from support/texlab/tests/integration/lsp/text_document/document_highlight.rs)22
-rw-r--r--support/texlab/src/tests/text_document/document_link.rs (renamed from support/texlab/tests/integration/lsp/text_document/document_link.rs)30
-rw-r--r--support/texlab/src/tests/text_document/document_symbol.rs (renamed from support/texlab/tests/integration/lsp/text_document/document_symbol.rs)89
-rw-r--r--support/texlab/src/tests/text_document/folding_range.rs (renamed from support/texlab/tests/integration/lsp/text_document/folding_range.rs)23
-rw-r--r--support/texlab/src/tests/text_document/formatting.rs (renamed from support/texlab/tests/integration/lsp/text_document/formatting.rs)78
-rw-r--r--support/texlab/src/tests/text_document/hover.rs (renamed from support/texlab/tests/integration/lsp/text_document/hover.rs)61
-rw-r--r--support/texlab/src/tests/text_document/inlay_hint.rs65
-rw-r--r--support/texlab/src/tests/text_document/references.rs (renamed from support/texlab/tests/integration/lsp/text_document/references.rs)48
-rw-r--r--support/texlab/src/tests/text_document/rename.rs (renamed from support/texlab/tests/integration/lsp/text_document/rename.rs)29
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_package_ref.snap16
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_empty.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_empty.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_open_brace.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_simple.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_simple.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_empty.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_empty.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_open_brace.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_word.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_word.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__begin_environment_without_snippet_support.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__begin_environment_without_snippet_support.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_acronym.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_acronym.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_open_brace.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_open_brace_multiple.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_open_brace_multiple.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_open_brace.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_set_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_set_open_brace.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_set_simple.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_set_simple.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_simple.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_simple.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_open_brace.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_simple.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_simple.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_word.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_word.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_bibtex.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_bibtex.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_simple.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_simple.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_simple_package.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_simple_package.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_class.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_class.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_command_definition.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_command_definition.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_simple.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_simple.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_simple_end.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_simple_end.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_after_preamble.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_after_preamble.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_after_string.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_after_string.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_at_empty.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_at_empty.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_article.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_article.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_preamble.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_preamble.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_string.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_string.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_complete_entry.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_complete_entry.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_empty_entry_closed.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_empty_entry_closed.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_empty_entry_open.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_empty_entry_open.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_field_name.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_field_name.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_two_fields_name_closed.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_two_fields_name_closed.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_two_fields_name_open.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_two_fields_name_open.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__glossary_ref_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__glossary_ref_open_brace.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__glossary_ref_simple.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__glossary_ref_simple.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_class_closed_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_class_closed_brace.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_class_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_class_open_brace.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_package_closed_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_package_closed_brace.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_package_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_package_open_brace.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__label.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__label.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__project_resolution.snap61
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__theorem_begin.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__theorem_begin.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__theorem_end.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__theorem_end.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__tikz_library_closed_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__tikz_library_closed_brace.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__tikz_library_open_brace.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__tikz_library_open_brace.snap)8
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__user_command.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__user_command.snap)4
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__user_environment.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__user_environment.snap)5
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__did_change_configuration__invalid_configuration.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__did_change_configuration__invalid_configuration.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__enumerate_flat.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__enumerate_flat.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__enumerate_nested.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__enumerate_nested.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__equation_flat.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__equation_flat.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__equation_nested.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__equation_nested.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__float_flat.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__float_flat.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__float_nested.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__float_nested.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__section_flat.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__section_flat.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__section_nested.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__section_nested.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__theorem_flat.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__theorem_flat.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__theorem_nested.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__theorem_nested.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_command.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_command.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_insert_braces.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_insert_braces.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_join_strings.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_join_strings.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_multiple_entries.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_multiple_entries.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_parens.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_parens.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_preamble.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_preamble.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_string.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_string.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_trailing_comma.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_trailing_comma.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_wrap_long_lines.snap (renamed from support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_wrap_long_lines.snap)3
-rw-r--r--support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__inlay_hint__label_definition.snap38
-rw-r--r--support/texlab/src/tests/workspace.rs (renamed from support/texlab/tests/integration/lsp/workspace.rs)0
-rw-r--r--support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_bibtex.snap (renamed from support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_bibtex.snap)3
-rw-r--r--support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_figure.snap (renamed from support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_figure.snap)3
-rw-r--r--support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_item.snap (renamed from support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_item.snap)3
-rw-r--r--support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_math.snap (renamed from support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_math.snap)3
-rw-r--r--support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_section.snap (renamed from support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_section.snap)3
-rw-r--r--support/texlab/src/tests/workspace/symbol.rs (renamed from support/texlab/tests/integration/lsp/workspace/symbol.rs)45
-rw-r--r--support/texlab/src/util.rs15
-rw-r--r--support/texlab/src/util/capabilities.rs (renamed from support/texlab/src/capabilities.rs)25
-rw-r--r--support/texlab/src/util/chktex.rs112
-rw-r--r--support/texlab/src/util/components.rs120
-rw-r--r--support/texlab/src/util/cursor.rs (renamed from support/texlab/src/features/cursor.rs)171
-rw-r--r--support/texlab/src/util/label.rs (renamed from support/texlab/src/label.rs)203
-rw-r--r--support/texlab/src/util/lang_data.rs (renamed from support/texlab/src/lang_data.rs)2
-rw-r--r--support/texlab/src/util/line_index.rs (renamed from support/texlab/src/line_index.rs)0
-rw-r--r--support/texlab/src/util/line_index_ext.rs (renamed from support/texlab/src/line_index_ext.rs)2
-rw-r--r--support/texlab/src/util/lsp_enums.rs (renamed from support/texlab/src/features/lsp_kinds.rs)2
-rw-r--r--support/texlab/src/workspace.rs225
-rw-r--r--support/texlab/tests/integration/lsp/text_document/publish_diagnostics.rs264
-rw-r--r--support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_allowed.snap24
-rw-r--r--support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_ignored.snap24
-rw-r--r--support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_none.snap39
-rw-r--r--support/texlab/tests/integration/main.rs1
-rw-r--r--support/texlab/texlab.131
-rw-r--r--support/texlab/texlab.pdfbin82677 -> 26341 bytes
-rw-r--r--support/texshop/README.txt2
-rw-r--r--support/texshop/texshop510.html (renamed from support/texshop/texshop509.html)4
551 files changed, 13457 insertions, 11891 deletions
diff --git a/support/texlab/CHANGELOG.md b/support/texlab/CHANGELOG.md
index 85f8d0bdb3..5b12294b3e 100644
--- a/support/texlab/CHANGELOG.md
+++ b/support/texlab/CHANGELOG.md
@@ -5,7 +5,73 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [4.2.0] - 03.07.2022
+## [5.0.0] - 2022-12-29
+
+### Changed
+
+- _BREAKING_: `texlab.rootDirectory` is now used as the folder path from which the compiler is executed
+ relative to the main document. By default it is equal to `"."`. For more information, please visit the wiki.
+- Improve performance of completion by a huge margin due to a faster filtering method used internally
+- Do not discover project files beyond the provided workspace folders
+- Try to guess the root directory by checking for files such as `.latexmkrc` or `Tectonic.toml` if `texlab.rootDirectory` is not set
+
+### Fixed
+
+- Update positions of reported build diagnostics when editing the affected line
+- Do not treat links to files as bidirectional by default. This prevents issues where `texlab` ends up compiling the wrong file
+ in projects with shared files ([#806](https://github.com/latex-lsp/texlab/issues/806), [#757](https://github.com/latex-lsp/texlab/issues/757), [#679](https://github.com/latex-lsp/texlab/issues/679))
+- Fix coverage of directories which need to be watched for changes ([#502](https://github.com/latex-lsp/texlab/issues/502), [#491](https://github.com/latex-lsp/texlab/issues/491))
+- Resolve links of the `import` package correctly
+- Use `filterText` of completion items when filtering internally ([#829](https://github.com/latex-lsp/texlab/issues/829))
+
+## [4.3.2] - 2022-11-20
+
+### Fixed
+
+- Do not try to run the TeX engine on package files and fail the build instead ([#801](https://github.com/latex-lsp/texlab/issues/801))
+- Handle URIs with URL-encoded drive letters on Windows ([#802](https://github.com/latex-lsp/texlab/issues/802))
+- Parse BibTeX entries with unbalanced quotes correctly ([#809](https://github.com/latex-lsp/texlab/issues/809))
+- Provide completion for more acronym commands ([#813](https://github.com/latex-lsp/texlab/issues/813))
+- Fix parsing acronym definitions ([#813](https://github.com/latex-lsp/texlab/issues/813))
+
+## [4.3.1] - 2022-10-22
+
+### Fixed
+
+- Do not crash with a stack overflow when trying to load packages with many internal dependencies ([#793](https://github.com/latex-lsp/texlab/issues/793))
+- Normalize drive letters of all document URIs
+- Fix parsing commands that take file paths as arguments ([#789](https://github.com/latex-lsp/texlab/issues/789))
+- Use the correct working directory and command line arguments when calling `latexindent` ([#645](https://github.com/latex-lsp/texlab/issues/645))
+- Fix publishing to CTAN
+
+## [4.3.0] - 2022-09-25
+
+### Added
+
+- Add inlay hints for `\label{...}` ([#753](https://github.com/latex-lsp/texlab/issues/753))
+
+### Fixed
+
+- Improve accuracy of the error locations reported by the TeX engine ([#738](https://github.com/latex-lsp/texlab/issues/738))
+- Reduce number of false positive errors reported by `texlab` ([#745](https://github.com/latex-lsp/texlab/issues/745))
+
+## [4.2.2] - 2022-08-28
+
+### Fixed
+
+- Do not watch the same directory multiple times, which can result in a memory leak on Windows ([#737](https://github.com/latex-lsp/texlab/issues/679))
+- Fix detection of root document when sharing files between projects ([#679](https://github.com/latex-lsp/texlab/issues/679))
+- Fix text synchronization problem caused by file watcher ([#724](https://github.com/latex-lsp/texlab/issues/724))
+
+## [4.2.1] - 2022-08-05
+
+### Fixed
+
+- Deserialize server options with missing keys (or not keys at all) correctly ([#707](https://github.com/latex-lsp/texlab/issues/707))
+- Pass `chktexrc` files if they are not in the current directory ([#683](https://github.com/latex-lsp/texlab/issues/683))
+- Revert back to server-side file watching due to lack of client support ([#679](https://github.com/latex-lsp/texlab/issues/679))
+
+## [4.2.0] - 2022-07-03
### Added
@@ -22,7 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Parse incomplete server options correctly ([#651](https://github.com/latex-lsp/texlab/issues/651))
-## [4.1.0] - 12.06.2022
+## [4.1.0] - 2022-06-12
### Added
@@ -38,7 +104,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow brackets in included file paths ([#639](https://github.com/latex-lsp/texlab/issues/639))
- Allow commands in included file paths ([#641](https://github.com/latex-lsp/texlab/issues/641))
-## [4.0.0] - 25.05.2022
+## [4.0.0] - 2022-05-25
### Added
@@ -63,7 +129,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow optional arguments in environment definitions ([#570](https://github.com/latex-lsp/texlab/issues/570))
- Allow `=` in include paths ([#568](https://github.com/latex-lsp/texlab/issues/568))
-## [3.3.2] - 26.02.2022
+## [3.3.2] - 2022-02-26
### Fixed
@@ -78,7 +144,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Make directory path in `\import` optional ([#540](https://github.com/latex-lsp/texlab/issues/540))
- Do not spam workspace/configuration requests ([#533](https://github.com/latex-lsp/texlab/issues/533))
-## [3.3.1] - 10.11.2021
+## [3.3.1] - 2021-11-10
### Fixed
@@ -87,7 +153,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix a bug that sometimes causes the `aux` file to pick up the diagnostics of the `tex` file ([#502](https://github.com/latex-lsp/texlab/issues/502))
- Fix a bug that sometimes prevents `log` files from being reanalyzed ([#502](https://github.com/latex-lsp/texlab/issues/502))
-## [3.3.0] - 10.10.2021
+## [3.3.0] - 2021-10-10
### Added
@@ -103,7 +169,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Prevent `texlab` from hanging because of unanswered configuration requests sent to Emacs ([#456](https://github.com/latex-lsp/texlab/issues/456))
- Re-analyze the workspace if the initial configuration has been received late
-## [3.2.0] - 12.06.2021
+## [3.2.0] - 2021-06-12
### Added
@@ -122,7 +188,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix conditional compilation of the `citation` feature.
-## [3.1.0] - 03.06.2021
+## [3.1.0] - 2021-06-03
### Added
@@ -140,14 +206,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
-## [3.0.1] - 22.05.2021
+## [3.0.1] - 2021-05-22
### Fixed
- Sometimes the log parser does not pick up errors from the log file ([#426](https://github.com/latex-lsp/texlab/issues/426))
- Fix a bug involving characters that are not part of the ASCII charset ([#428](https://github.com/latex-lsp/texlab/issues/428))
-## [3.0.0] - 16.05.2021
+## [3.0.0] - 2021-05-16
### Added
@@ -180,13 +246,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Hopefully fixes the ChkTeX spamming issue ([#186](https://github.com/latex-lsp/texlab/issues/186))
- Reduce CPU-load when idle ([#400](https://github.com/latex-lsp/texlab/issues/400))
-## [2.2.2] - 10.01.2021
+## [2.2.2] - 2021-01-10
### Fixed
- Fix compilation on `arm64-apple-darwin` (Apple Silicon) ([#343](https://github.com/latex-lsp/texlab/issues/343))
-## [2.2.1] - 06.01.2021
+## [2.2.1] - 2021-01-06
### Added
@@ -201,7 +267,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix compilation on `aarch64` and `armv7l` ([#289](https://github.com/latex-lsp/texlab/issues/289))
-## [2.2.0] - 27.05.2020
+## [2.2.0] - 2020-05-27
### Added
@@ -216,7 +282,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix the ordering of completion items when using `lsp-mode` ([#227](https://github.com/latex-lsp/texlab/issues/227))
- Fix preview when using custom class files ([#228](https://github.com/latex-lsp/texlab/issues/228))
-## [2.1.0] - 10.05.2020
+## [2.1.0] - 2020-05-10
### Added
@@ -229,7 +295,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix a parsing error that caused `texlab` to take 100% CPU usage in some cases ([#212](https://github.com/latex-lsp/texlab/issues/212))
- Prevent building the same file multiple times at once
-## [2.0.0] - 20.04.2020
+## [2.0.0] - 2020-04-20
### Added
@@ -253,7 +319,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improve performance of completion (when completing LaTeX commands)
- Improve workspace detection algorithm
-## [1.10.0] - 11.02.2020
+## [1.10.0] - 2020-02-11
### Added
@@ -266,7 +332,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Show all digits of chktex warning number ([#160](https://github.com/latex-lsp/texlab/issues/160))
-## [1.9.0] - 30.12.2019
+## [1.9.0] - 2019-12-30
### Added
@@ -282,7 +348,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Run LaTeX linter when opening a file if enabled
- Handle `\hyphen` when rendering citations
-## [1.8.0] - 01.12.2019
+## [1.8.0] - 2019-12-01
### Added
@@ -294,7 +360,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Change license to GPLv3
- Do not require Node.js when building the server (#[87](https://github.com/latex-lsp/texlab/issues/87))
-## [1.7.0] - 20.11.2019
+## [1.7.0] - 2019-11-20
### Added
@@ -315,7 +381,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#110](https://github.com/latex-lsp/texlab/issues/110))
- Fix potential crash in "Goto Definition"
-## [1.6.0] - 29.09.2019
+## [1.6.0] - 2019-09-29
### Added
@@ -341,7 +407,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix filter text of citations with braces inside a field
- Handle invalid UTF-8 in log files
-## [1.5.0] - 27.08.2019
+## [1.5.0] - 2019-08-27
### Added
@@ -357,7 +423,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Do not run ChkTeX on BibTeX files
- Fix build freezes on Windows ([#63](https://github.com/latex-lsp/texlab/issues/63))
-## [1.4.1] - 22.08.2019
+## [1.4.1] - 2019-08-22
### Added
@@ -369,7 +435,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix rendering of theorem labels
- Handle Windows paths correctly
-## [1.4.0] - 20.08.2019
+## [1.4.0] - 2019-08-20
### Added
@@ -383,7 +449,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Use LocationLink for "peek definition" when possible
- Node.js is no longer a dependency
-## [1.3.0] - 06.08.2019
+## [1.3.0] - 2019-08-06
### Added
@@ -398,7 +464,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Build cancellation has been reimplemented ([#47](https://github.com/latex-lsp/texlab/issues/47), [#63](https://github.com/latex-lsp/texlab/issues/63))
-## [1.2.0] - 23.07.2019
+## [1.2.0] - 2019-07-23
### Added
@@ -409,7 +475,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The index mechanism has been removed. Packages are now indexed with a script beforehand.
-## [1.1.0] - 13.07.2019
+## [1.1.0] - 2019-07-13
### Added
@@ -427,7 +493,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix preselect for environments with missing braces
-## [1.0.0] - 04.07.2019
+## [1.0.0] - 2019-07-04
### Added
@@ -464,14 +530,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Do not depend on the `workspace/configuration` request (#[22](https://github.com/latex-lsp/texlab/issues/22))
- Prevent completion from triggering too often
-## [0.4.2] - 10.04.2019
+## [0.4.2] - 2019-04-10
### Fixed
- Fix completion inside `\( \)`. ([#14](https://github.com/latex-lsp/texlab/issues/14))
- Do not crash on invalid requests.
-## [0.4.1] - 30.03.2019
+## [0.4.1] - 2019-03-30
### Changed
@@ -481,7 +547,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improve MiKTeX support ([#8](https://github.com/latex-lsp/texlab-vscode/issues/8))
-## [0.4.0] - 09.03.2019
+## [0.4.0] - 2019-03-09
### Added
@@ -493,7 +559,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improve completion for includes
- Improve performance of completion
-## [0.3.0] - 05.03.2019
+## [0.3.0] - 2019-03-05
### Added
@@ -510,7 +576,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix crash when hovering over invalid BibTeX entries
- Fix a bug where the completion does not get triggered correctly
-## [0.2.0] - 01.03.2019
+## [0.2.0] - 2019-03-01
### Added
@@ -523,14 +589,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix completion of file includes
- Prevent server crash when opening a locked file
-## [0.1.2] - 16.02.2019
+## [0.1.2] - 2019-02-16
### Fixed
- Do not display an error when PDF viewers return a non-zero
exit code while performing forward search
-## [0.1.1] - 15.02.2019
+## [0.1.1] - 2019-02-15
### Changed
@@ -540,6 +606,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix rendering of completion symbols
-## [0.1.0] - 15.02.2019
+## [0.1.0] - 2019-02-15
- Initial release
diff --git a/support/texlab/Cargo.lock b/support/texlab/Cargo.lock
index cd1348e8c7..7f205d9514 100644
--- a/support/texlab/Cargo.lock
+++ b/support/texlab/Cargo.lock
@@ -9,15 +9,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
+name = "ahash"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
name = "aho-corasick"
-version = "0.7.18"
+version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
+name = "anes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
+
+[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -28,9 +45,15 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.58"
+version = "1.0.67"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7724808837b77f4b4de9d283820f9d98bcf496d5692934b857a2399d31ff22e6"
+
+[[package]]
+name = "arc-swap"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
+checksum = "983cd8b9d4b02a6dc6ffa557262eb5858a27a0038ffffe21a0f133eaa819a164"
[[package]]
name = "assert_unordered"
@@ -47,7 +70,7 @@ version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
"libc",
"winapi",
]
@@ -72,63 +95,39 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
-version = "0.7.3"
+version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
+checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
- "block-padding",
- "byte-tools",
- "byteorder",
"generic-array",
]
[[package]]
-name = "block-padding"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
-dependencies = [
- "byte-tools",
-]
-
-[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
- "lazy_static",
"memchr",
- "regex-automata",
- "serde",
]
[[package]]
name = "bumpalo"
-version = "3.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
-
-[[package]]
-name = "byte-tools"
-version = "0.3.1"
+version = "3.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
-name = "byteorder"
-version = "1.4.3"
+name = "cast"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
-name = "cast"
-version = "0.2.7"
+name = "cc"
+version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
-dependencies = [
- "rustc_version",
-]
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]]
name = "cfg-if"
@@ -138,44 +137,73 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
-version = "0.4.19"
+version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
+name = "ciborium"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
name = "clap"
-version = "2.34.0"
+version = "3.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
+checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
dependencies = [
"bitflags",
- "textwrap 0.11.0",
- "unicode-width",
+ "clap_lex 0.2.4",
+ "indexmap",
+ "textwrap",
]
[[package]]
name = "clap"
-version = "3.2.8"
+version = "4.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
+checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
dependencies = [
"bitflags",
"clap_derive",
- "clap_lex",
- "indexmap",
+ "clap_lex 0.3.0",
+ "is-terminal",
"once_cell",
- "textwrap 0.15.0",
+ "strsim",
+ "termcolor",
]
[[package]]
name = "clap_derive"
-version = "3.2.7"
+version = "4.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902"
+checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
dependencies = [
"heck",
"proc-macro-error",
@@ -194,31 +222,43 @@ dependencies = [
]
[[package]]
+name = "clap_lex"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
name = "console"
-version = "0.15.0"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31"
+checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
dependencies = [
"encode_unicode",
+ "lazy_static",
"libc",
- "once_cell",
"terminal_size",
"winapi",
]
[[package]]
-name = "convert_case"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
-
-[[package]]
name = "countme"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
[[package]]
+name = "cpufeatures"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -229,15 +269,16 @@ dependencies = [
[[package]]
name = "criterion"
-version = "0.3.5"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
+checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb"
dependencies = [
+ "anes",
"atty",
"cast",
- "clap 2.34.0",
+ "ciborium",
+ "clap 3.2.23",
"criterion-plot",
- "csv",
"itertools",
"lazy_static",
"num-traits",
@@ -246,7 +287,6 @@ dependencies = [
"rayon",
"regex",
"serde",
- "serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
@@ -255,19 +295,33 @@ dependencies = [
[[package]]
name = "criterion-plot"
-version = "0.4.4"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
+checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
"itertools",
]
[[package]]
+name = "crossbeam"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c"
+dependencies = [
+ "cfg-if",
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-epoch",
+ "crossbeam-queue",
+ "crossbeam-utils",
+]
+
+[[package]]
name = "crossbeam-channel"
-version = "0.5.5"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
+checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
dependencies = [
"cfg-if",
"crossbeam-utils",
@@ -275,9 +329,9 @@ dependencies = [
[[package]]
name = "crossbeam-deque"
-version = "0.8.1"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
dependencies = [
"cfg-if",
"crossbeam-epoch",
@@ -286,88 +340,94 @@ dependencies = [
[[package]]
name = "crossbeam-epoch"
-version = "0.9.9"
+version = "0.9.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
+checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
- "memoffset",
- "once_cell",
+ "memoffset 0.7.1",
"scopeguard",
]
[[package]]
-name = "crossbeam-utils"
-version = "0.8.10"
+name = "crossbeam-queue"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
+checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
dependencies = [
"cfg-if",
- "once_cell",
+ "crossbeam-utils",
]
[[package]]
-name = "csv"
-version = "1.1.6"
+name = "crossbeam-utils"
+version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
- "bstr",
- "csv-core",
- "itoa 0.4.8",
- "ryu",
- "serde",
+ "cfg-if",
]
[[package]]
-name = "csv-core"
-version = "0.1.10"
+name = "crypto-common"
+version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
- "memchr",
+ "generic-array",
+ "typenum",
]
[[package]]
name = "dashmap"
-version = "5.2.0"
+version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8858831f7781322e539ea39e72449c46b059638250c14344fec8d0aa6e539c"
+checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
dependencies = [
"cfg-if",
- "num_cpus",
- "parking_lot",
+ "hashbrown",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
]
[[package]]
-name = "derive_more"
-version = "0.99.17"
+name = "digest"
+version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
+checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
- "convert_case",
- "proc-macro2",
- "quote",
- "rustc_version",
- "syn",
+ "block-buffer",
+ "crypto-common",
]
[[package]]
-name = "digest"
-version = "0.8.1"
+name = "dirs"
+version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
+checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
- "generic-array",
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
]
[[package]]
name = "either"
-version = "1.7.0"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
+checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "encode_unicode"
@@ -394,16 +454,54 @@ dependencies = [
]
[[package]]
-name = "fake-simd"
+name = "env_logger"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
+dependencies = [
+ "humantime",
+ "is-terminal",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "errno"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "eyre"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
+dependencies = [
+ "indenter",
+ "once_cell",
+]
[[package]]
name = "fastrand"
-version = "1.7.0"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
+checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
dependencies = [
"instant",
]
@@ -418,22 +516,41 @@ dependencies = [
]
[[package]]
-name = "fixedbitset"
-version = "0.4.1"
+name = "filetime"
+version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
+checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "windows-sys",
+]
[[package]]
name = "flate2"
-version = "1.0.24"
+version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
+checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
+name = "flume"
+version = "0.10.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "nanorand",
+ "pin-project",
+ "spin",
+]
+
+[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -441,15 +558,35 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
+checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
dependencies = [
- "matches",
"percent-encoding",
]
[[package]]
+name = "fsevent-sys"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
+
+[[package]]
name = "fuzzy-matcher"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -460,22 +597,38 @@ dependencies = [
[[package]]
name = "generic-array"
-version = "0.12.4"
+version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
+checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
+ "version_check",
]
[[package]]
name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "globset"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "fnv",
+ "log",
+ "regex",
]
[[package]]
@@ -486,9 +639,21 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hashbrown"
-version = "0.12.1"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
+checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa"
+dependencies = [
+ "hashbrown",
+]
[[package]]
name = "heck"
@@ -506,58 +671,102 @@ dependencies = [
]
[[package]]
+name = "hermit-abi"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "human_name"
-version = "1.0.3"
+version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29d4c0030db95c2e6e68fc240def0fc5bcbecab549c1c856a9f14ec309ccb332"
+checksum = "42af7ece82db04720531abb16506781d40a72c8e62ecb0762d39746d2173255e"
dependencies = [
+ "crossbeam-utils",
"libc",
"phf",
+ "phf_codegen",
"serde",
- "serde_derive",
"serde_json",
"smallstr",
"smallvec",
+ "unicode-case-mapping",
"unicode-normalization",
"unicode-segmentation",
"unidecode",
]
[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
name = "idna"
-version = "0.2.3"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
+checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
dependencies = [
- "matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
+name = "indenter"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
+
+[[package]]
name = "indexmap"
-version = "1.9.1"
+version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
+name = "inotify"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
+dependencies = [
+ "bitflags",
+ "inotify-sys",
+ "libc",
+]
+
+[[package]]
+name = "inotify-sys"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "insta"
-version = "1.15.0"
+version = "1.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4126dd76ebfe2561486a1bd6738a33d2029ffb068a99ac446b7f8c77b2e58dbc"
+checksum = "e48b08a091dfe5b09a6a9688c468fdd5b4396e92ce09e2eb932f0884b02788a4"
dependencies = [
"console",
- "once_cell",
+ "globset",
+ "lazy_static",
+ "linked-hash-map",
"pest",
"pest_derive",
"serde",
- "serde_json",
- "serde_yaml",
"similar",
+ "walkdir",
+ "yaml-rust",
]
[[package]]
@@ -570,6 +779,28 @@ dependencies = [
]
[[package]]
+name = "io-lifetimes"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
+dependencies = [
+ "hermit-abi 0.2.6",
+ "io-lifetimes",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
name = "isocountry"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -581,24 +812,18 @@ dependencies = [
[[package]]
name = "itertools"
-version = "0.10.3"
+version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
-version = "0.4.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
-
-[[package]]
-name = "itoa"
-version = "1.0.2"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "jod-thread"
@@ -607,15 +832,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b23360e99b8717f20aaa4598f5a6541efbe30630039fbc7706cf954a87947ae"
[[package]]
+name = "joinery"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5"
+
+[[package]]
name = "js-sys"
-version = "0.3.58"
+version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
dependencies = [
"wasm-bindgen",
]
[[package]]
+name = "kqueue"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c8fc60ba15bf51257aa9807a48a61013db043fcf3a78cb0d916e8e396dcad98"
+dependencies = [
+ "kqueue-sys",
+ "libc",
+]
+
+[[package]]
+name = "kqueue-sys"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8367585489f01bc55dd27404dcf56b95e6da061a256a666ab23be9ba96a2e587"
+dependencies = [
+ "bitflags",
+ "libc",
+]
+
+[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -623,9 +874,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.126"
+version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "linked-hash-map"
@@ -634,10 +885,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
+name = "linux-raw-sys"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
+
+[[package]]
name = "lock_api"
-version = "0.4.7"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
+checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
@@ -689,9 +946,9 @@ dependencies = [
[[package]]
name = "lsp-types"
-version = "0.93.0"
+version = "0.93.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70c74e2173b2b31f8655d33724b4b45ac13f439386f66290f539c22b144c2212"
+checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51"
dependencies = [
"bitflags",
"serde",
@@ -701,18 +958,6 @@ dependencies = [
]
[[package]]
-name = "maplit"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
-
-[[package]]
-name = "matches"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
-
-[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -728,15 +973,63 @@ dependencies = [
]
[[package]]
+name = "memoffset"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "miniz_oxide"
-version = "0.5.3"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
]
[[package]]
+name = "mio"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys",
+]
+
+[[package]]
+name = "nanorand"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "notify"
+version = "5.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2c66da08abae1c024c01d635253e402341b4060a12e99b31c7594063bf490a"
+dependencies = [
+ "bitflags",
+ "crossbeam-channel",
+ "filetime",
+ "fsevent-sys",
+ "inotify",
+ "kqueue",
+ "libc",
+ "mio",
+ "walkdir",
+ "winapi",
+]
+
+[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -757,19 +1050,19 @@ dependencies = [
[[package]]
name = "num_cpus"
-version = "1.13.1"
+version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
+checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
dependencies = [
- "hermit-abi",
+ "hermit-abi 0.1.19",
"libc",
]
[[package]]
name = "once_cell"
-version = "1.12.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "oorandom"
@@ -778,16 +1071,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
-name = "opaque-debug"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
-
-[[package]]
name = "os_str_bytes"
-version = "6.1.0"
+version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
+checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "parking_lot"
@@ -801,9 +1088,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.3"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
+checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
dependencies = [
"cfg-if",
"libc",
@@ -814,24 +1101,25 @@ dependencies = [
[[package]]
name = "percent-encoding"
-version = "2.1.0"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pest"
-version = "2.1.3"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
+checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0"
dependencies = [
+ "thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
-version = "2.1.0"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
+checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344"
dependencies = [
"pest",
"pest_generator",
@@ -839,9 +1127,9 @@ dependencies = [
[[package]]
name = "pest_generator"
-version = "2.1.3"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
+checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c"
dependencies = [
"pest",
"pest_meta",
@@ -852,74 +1140,78 @@ dependencies = [
[[package]]
name = "pest_meta"
-version = "2.1.3"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
+checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20"
dependencies = [
- "maplit",
+ "once_cell",
"pest",
- "sha-1",
+ "sha1",
]
[[package]]
-name = "petgraph"
-version = "0.6.2"
+name = "phf"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
+checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
dependencies = [
- "fixedbitset",
- "indexmap",
+ "phf_shared",
]
[[package]]
-name = "phf"
-version = "0.10.1"
+name = "phf_codegen"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
+checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
dependencies = [
- "phf_macros",
+ "phf_generator",
"phf_shared",
- "proc-macro-hack",
]
[[package]]
name = "phf_generator"
-version = "0.10.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
+checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
-name = "phf_macros"
-version = "0.10.0"
+name = "phf_shared"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
+checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
dependencies = [
- "phf_generator",
- "phf_shared",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn",
+ "siphasher",
]
[[package]]
-name = "phf_shared"
-version = "0.10.0"
+name = "pin-project"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
+checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc"
dependencies = [
- "siphasher",
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
name = "plotters"
-version = "0.3.1"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
+checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
dependencies = [
"num-traits",
"plotters-backend",
@@ -930,26 +1222,20 @@ dependencies = [
[[package]]
name = "plotters-backend"
-version = "0.3.2"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
+checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
[[package]]
name = "plotters-svg"
-version = "0.3.1"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
+checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
dependencies = [
"plotters-backend",
]
[[package]]
-name = "ppv-lite86"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
-
-[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -974,25 +1260,19 @@ dependencies = [
]
[[package]]
-name = "proc-macro-hack"
-version = "0.5.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
-
-[[package]]
name = "proc-macro2"
-version = "1.0.40"
+version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
+checksum = "e9d89e5dba24725ae5678020bf8f1357a9aa7ff10736b551adbcd3f8d17d766f"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.20"
+version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
+checksum = "556d0f47a940e895261e77dc200d5eadfc6ef644c179c6f5edfc105e3a2292c8"
dependencies = [
"proc-macro2",
]
@@ -1003,47 +1283,30 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
-version = "0.6.3"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
-dependencies = [
- "getrandom",
-]
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rayon"
-version = "1.5.3"
+version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
+checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7"
dependencies = [
- "autocfg",
- "crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
-version = "1.9.3"
+version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
+checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
@@ -1053,18 +1316,29 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.2.13"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
+name = "redox_users"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
+dependencies = [
+ "getrandom",
+ "redox_syscall",
+ "thiserror",
+]
+
+[[package]]
name = "regex"
-version = "1.5.6"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
+checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
@@ -1072,16 +1346,10 @@ dependencies = [
]
[[package]]
-name = "regex-automata"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-
-[[package]]
name = "regex-syntax"
-version = "0.6.26"
+version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
@@ -1094,13 +1362,13 @@ dependencies = [
[[package]]
name = "rowan"
-version = "0.15.5"
+version = "0.15.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce1f383129e417a6265b16ed78e6e9307748f0863b2ba75f78ff14717db5b017"
+checksum = "5811547e7ba31e903fe48c8ceab10d40d70a101f3d15523c847cce91aa71f332"
dependencies = [
"countme",
"hashbrown",
- "memoffset",
+ "memoffset 0.6.5",
"rustc-hash",
"text-size",
]
@@ -1112,25 +1380,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
-name = "rustc_version"
-version = "0.4.0"
+name = "rustix"
+version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [
- "semver",
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
]
[[package]]
name = "rustversion"
-version = "1.0.7"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf"
+checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
[[package]]
name = "ryu"
-version = "1.0.10"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
+
+[[package]]
+name = "salsa-2022"
+version = "0.1.0"
+source = "git+https://github.com/salsa-rs/salsa?rev=20c7834ff34fd00a41b59bec61f3d5c85ea3abd4#20c7834ff34fd00a41b59bec61f3d5c85ea3abd4"
+dependencies = [
+ "arc-swap",
+ "crossbeam",
+ "crossbeam-utils",
+ "dashmap",
+ "hashlink",
+ "indexmap",
+ "log",
+ "parking_lot",
+ "rustc-hash",
+ "salsa-2022-macros",
+ "smallvec",
+]
+
+[[package]]
+name = "salsa-2022-macros"
+version = "0.1.0"
+source = "git+https://github.com/salsa-rs/salsa?rev=20c7834ff34fd00a41b59bec61f3d5c85ea3abd4#20c7834ff34fd00a41b59bec61f3d5c85ea3abd4"
+dependencies = [
+ "eyre",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
[[package]]
name = "same-file"
@@ -1148,35 +1451,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
-name = "semver"
-version = "1.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1"
-
-[[package]]
name = "serde"
-version = "1.0.138"
+version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
+checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
dependencies = [
"serde_derive",
]
[[package]]
-name = "serde_cbor"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
-dependencies = [
- "half",
- "serde",
-]
-
-[[package]]
name = "serde_derive"
-version = "1.0.138"
+version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
+checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
dependencies = [
"proc-macro2",
"quote",
@@ -1185,16 +1472,25 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.82"
+version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
+checksum = "8778cc0b528968fe72abec38b5db5a20a70d148116cd9325d2bc5f5180ca3faf"
dependencies = [
- "itoa 1.0.2",
+ "itoa",
"ryu",
"serde",
]
[[package]]
+name = "serde_millis"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e2dc780ca5ee2c369d1d01d100270203c4ff923d2a4264812d723766434d00"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "serde_regex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1206,9 +1502,9 @@ dependencies = [
[[package]]
name = "serde_repr"
-version = "0.1.8"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed"
+checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e"
dependencies = [
"proc-macro2",
"quote",
@@ -1216,34 +1512,21 @@ dependencies = [
]
[[package]]
-name = "serde_yaml"
-version = "0.8.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc"
-dependencies = [
- "indexmap",
- "ryu",
- "serde",
- "yaml-rust",
-]
-
-[[package]]
-name = "sha-1"
-version = "0.8.2"
+name = "sha1"
+version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
+checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
- "block-buffer",
+ "cfg-if",
+ "cpufeatures",
"digest",
- "fake-simd",
- "opaque-debug",
]
[[package]]
name = "similar"
-version = "2.1.0"
+version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3"
+checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
[[package]]
name = "siphasher"
@@ -1253,18 +1536,18 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "smallstr"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e922794d168678729ffc7e07182721a14219c65814e66e91b839a272fe5ae4f"
+checksum = "63b1aefdf380735ff8ded0b15f31aab05daf1f70216c01c02a12926badd1df9d"
dependencies = [
"smallvec",
]
[[package]]
name = "smallvec"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "smol_str"
@@ -1276,6 +1559,21 @@ dependencies = [
]
[[package]]
+name = "spin"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1286,9 +1584,9 @@ dependencies = [
[[package]]
name = "strum_macros"
-version = "0.24.2"
+version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4faebde00e8ff94316c01800f9054fd2ba77d30d9e922541913051d1d978918b"
+checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck",
"proc-macro2",
@@ -1299,9 +1597,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.98"
+version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
+checksum = "09ee3a69cd2c7e06684677e5629b3878b253af05e4714964204279c6bc02cf0b"
dependencies = [
"proc-macro2",
"quote",
@@ -1323,6 +1621,15 @@ dependencies = [
]
[[package]]
+name = "termcolor"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1334,21 +1641,22 @@ dependencies = [
[[package]]
name = "texlab"
-version = "4.2.0"
+version = "5.0.0"
dependencies = [
"anyhow",
"assert_unordered",
- "byteorder",
"chrono",
- "clap 3.2.8",
+ "clap 4.0.29",
"criterion",
"crossbeam-channel",
"dashmap",
- "derive_more",
+ "dirs",
"encoding_rs",
"encoding_rs_io",
+ "env_logger",
"fern",
"flate2",
+ "flume",
"fuzzy-matcher",
"human_name",
"insta",
@@ -1359,23 +1667,24 @@ dependencies = [
"logos",
"lsp-server",
"lsp-types",
+ "notify",
"once_cell",
- "petgraph",
"regex",
"rowan",
"rustc-hash",
+ "salsa-2022",
"serde",
"serde_json",
+ "serde_millis",
"serde_regex",
"serde_repr",
"smol_str",
"strum",
"tempfile",
+ "thiserror",
"threadpool",
"titlecase",
"unicode-normalization",
- "url",
- "uuid",
]
[[package]]
@@ -1386,33 +1695,24 @@ checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a"
[[package]]
name = "textwrap"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-dependencies = [
- "unicode-width",
-]
-
-[[package]]
-name = "textwrap"
-version = "0.15.0"
+version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
+checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
-version = "1.0.31"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.31"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -1464,25 +1764,26 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "titlecase"
-version = "2.0.0"
+version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea7a2f1a76e892e6c07c275e6e851400257304a6e34c0e4e32ebbd3871808802"
+checksum = "38397a8cdb017cfeb48bf6c154d6de975ac69ffeed35980fde199d2ee0842042"
dependencies = [
+ "joinery",
"lazy_static",
"regex",
]
[[package]]
name = "typenum"
-version = "1.15.0"
+version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
+checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ucd-trie"
-version = "0.1.3"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
+checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "unicode-bidi"
@@ -1491,31 +1792,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
[[package]]
+name = "unicode-case-mapping"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "916a391c62ffbc5b6220fdafa353e93b530d21904d82ca1a2e29cdb5cfb4399f"
+
+[[package]]
name = "unicode-ident"
-version = "1.0.1"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unicode-normalization"
-version = "0.1.21"
+version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
-
-[[package]]
-name = "unicode-width"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
[[package]]
name = "unidecode"
@@ -1525,27 +1826,17 @@ checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc"
[[package]]
name = "url"
-version = "2.2.2"
+version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
+checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
dependencies = [
"form_urlencoded",
"idna",
- "matches",
"percent-encoding",
"serde",
]
[[package]]
-name = "uuid"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1570,9 +1861,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.81"
+version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -1580,13 +1871,13 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.81"
+version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
dependencies = [
"bumpalo",
- "lazy_static",
"log",
+ "once_cell",
"proc-macro2",
"quote",
"syn",
@@ -1595,9 +1886,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.81"
+version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1605,9 +1896,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.81"
+version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [
"proc-macro2",
"quote",
@@ -1618,15 +1909,15 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.81"
+version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "web-sys"
-version = "0.3.58"
+version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90"
+checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -1665,46 +1956,60 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
-version = "0.36.1"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
+ "windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
+[[package]]
name = "windows_aarch64_msvc"
-version = "0.36.1"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
-version = "0.36.1"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
-version = "0.36.1"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.36.1"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.36.1"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "yaml-rust"
diff --git a/support/texlab/Cargo.toml b/support/texlab/Cargo.toml
index 803f280e39..62e487b394 100644
--- a/support/texlab/Cargo.toml
+++ b/support/texlab/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "texlab"
description = "LaTeX Language Server"
-version = "4.2.0"
+version = "5.0.0"
license = "GPL-3.0"
readme = "README.md"
authors = [
@@ -9,7 +9,7 @@ authors = [
"Patrick Förster <patrick.foerster@outlook.de>",
]
edition = "2021"
-rust-version = "1.58.1"
+rust-version = "1.60"
homepage = "https://github.com/latex-lsp/texlab"
repository = "https://github.com/latex-lsp/texlab"
documentation = "https://github.com/latex-lsp/texlab"
@@ -33,55 +33,54 @@ test = false
[lib]
doctest = false
-[features]
-default = ["completion"]
-completion = ["fuzzy-matcher"]
-
[dependencies]
-anyhow = "1.0.58"
-byteorder = "1.4.3"
-chrono = { version = "0.4.19", default-features = false, features = ["std"] }
-clap = { version = "3.2.8", features = [
- "std",
- "derive",
-], default-features = false }
-crossbeam-channel = "0.5.5"
-dashmap = "~5.2.0"
-derive_more = "0.99.17"
+anyhow = "1.0.66"
+chrono = { version = "0.4.23", default-features = false, features = ["std"] }
+clap = { version = "4.0.29", features = ["derive"] }
+crossbeam-channel = "0.5.6"
+dashmap = "5.4.0"
+dirs = "4.0.0"
encoding_rs = "0.8.31"
encoding_rs_io = "0.1.7"
-fern = "0.6"
-flate2 = "1.0.24"
-fuzzy-matcher = { version = "0.3.7", optional = true }
-human_name = { version = "1.0.3", default-features = false }
+fern = "0.6.1"
+flate2 = "1.0.25"
+flume = "0.10.14"
+fuzzy-matcher = { version = "0.3.7", features = ["compact"] }
+human_name = { version = "2.0.1", default-features = false }
isocountry = "0.3.2"
-itertools = "0.10.1"
+itertools = "0.10.5"
log = "0.4.17"
logos = "0.12.1"
lsp-server = "0.6.0"
-lsp-types = "0.93.0"
-once_cell = "1.10.0"
-petgraph = "0.6.2"
-regex = "1.5.5"
-rowan = "0.15.5"
+lsp-types = { version = "0.93.2", features = ["proposed"] }
+notify = "5.0.0"
+once_cell = "1.16.0"
+regex = "1.7.0"
+rowan = "0.15.10"
rustc-hash = "1.1.0"
-serde = "1.0.137"
-serde_json = "1.0.82"
+serde = "1.0.151"
+serde_json = "1.0.90"
+serde_millis = "0.1.1"
serde_regex = "1.1.0"
-serde_repr = "0.1.8"
+serde_repr = "0.1.10"
smol_str = { version = "0.1.23", features = ["serde"] }
-strum = { version = "0.24.0", features = ["derive"] }
+strum = { version = "0.24.1", features = ["derive"] }
tempfile = "3.3.0"
+thiserror = "1.0.38"
threadpool = "1.8.1"
-titlecase = "2.0.0"
-unicode-normalization = "0.1.20"
-url = { version = "2.2.2", features = ["serde"] }
-uuid = { version = "1.1.2", features = ["v4"] }
+titlecase = "2.2.1"
+unicode-normalization = "0.1.22"
+
+[dependencies.salsa]
+git = "https://github.com/salsa-rs/salsa"
+rev = "20c7834ff34fd00a41b59bec61f3d5c85ea3abd4"
+package = "salsa-2022"
[dev-dependencies]
assert_unordered = "0.3.5"
-criterion = { version = "0.3.5" }
-insta = { version = "1.15.0", features = ["backtrace", "redactions"] }
+criterion = { version = "0.4.0" }
+env_logger = "0.10.0"
+insta = { version = "1.23.0", features = ["glob", "redactions", "json"] }
jod-thread = "0.1.2"
[profile.release]
diff --git a/support/texlab/README.md b/support/texlab/README.md
index e43082f20f..6e96e40f75 100644
--- a/support/texlab/README.md
+++ b/support/texlab/README.md
@@ -1,6 +1,7 @@
[![CI](https://github.com/latex-lsp/texlab/workflows/CI/badge.svg)](https://github.com/latex-lsp/texlab/actions)
[![Coverage](https://codecov.io/gh/latex-lsp/texlab/branch/master/graph/badge.svg)](https://codecov.io/gh/latex-lsp/texlab)
-[![Rust](https://img.shields.io/badge/rustc-1.58.1%2B-blue)](https://blog.rust-lang.org/2022/01/20/Rust-1.58.1.html)
+![Rust](https://img.shields.io/badge/rustc-1.60%2B-blue)
+[![Wiki](https://img.shields.io/badge/docs-Wiki-success)](https://github.com/latex-lsp/texlab/wiki)
[![GitHub release](https://img.shields.io/github/release/latex-lsp/texlab?label=github)](https://github.com/latex-lsp/texlab/releases)
[![crates.io](https://img.shields.io/crates/v/texlab)](https://crates.io/crates/texlab)
@@ -12,7 +13,7 @@ A cross-platform implementation of the [Language Server Protocol](https://micros
providing rich cross-editing support for the [LaTeX](https://www.latex-project.org/) typesetting system.
The server may be used with [any editor that implements the Language Server Protocol](https://microsoft.github.io/language-server-protocol/implementors/tools/).
-![Demo](docs/demo.gif)
+![Demo](images/demo.gif)
## Getting Started
@@ -30,7 +31,7 @@ For a list of supported package managers, you can take a look at [Repology](http
A [TeX distribution](https://www.latex-project.org/get/#tex-distributions) is _not_ strictly required
to use the server but TexLab cannot compile your documents without one.
TexLab supports compiling using [Tectonic](https://tectonic-typesetting.github.io/).
-For an example configuration, please see [here](docs/tectonic.md).
+For an example configuration, please see [here](https://github.com/latex-lsp/texlab/wiki/Tectonic).
On Windows, you may need to install [Microsoft Visual C++ Redistributable for Visual Studio 2015](https://www.microsoft.com/en-US/download/details.aspx?id=48145).
@@ -59,7 +60,9 @@ There is no need for magic comments like `%!TEX root`
and TexLab should figure out the dependencies of a file on its own.
Note that you may need to set the `texlab.rootDirectory` option for some multi-folder projects.
-TexLab features a variety of [options](docs/options.md) which can be used to configure features like building or [forward search](docs/previewing.md).
+TexLab features a variety of options which can be used to configure features like building or forward search.
+
+See the [Wiki](https://github.com/latex-lsp/texlab/wiki) for more information.
## Development
@@ -75,8 +78,6 @@ cargo test
in the project folder.
-For a list of custom messages, please see [here](docs/custom_messages.md).
-
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
diff --git a/support/texlab/benches/bench_main.rs b/support/texlab/benches/bench_main.rs
index 44364c5d5e..196afb1f43 100644
--- a/support/texlab/benches/bench_main.rs
+++ b/support/texlab/benches/bench_main.rs
@@ -1,39 +1,22 @@
-use std::sync::Arc;
-
use criterion::{black_box, criterion_group, criterion_main, Criterion};
-use lsp_types::{
- CompletionParams, Position, TextDocumentIdentifier, TextDocumentPositionParams, Url,
+use lsp_types::{Position, Url};
+use texlab::{
+ db::{Language, Owner, Workspace},
+ parser::parse_latex,
+ Database,
};
-use texlab::{features::FeatureRequest, syntax::latex, DocumentLanguage, Workspace};
fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("LaTeX/Parser", |b| {
- b.iter(|| latex::parse(black_box(include_str!("../texlab.tex"))));
+ b.iter(|| parse_latex(black_box(include_str!("../texlab.tex"))));
});
c.bench_function("LaTeX/Completion/Command", |b| {
- let uri = Arc::new(Url::parse("http://example.com/texlab.tex").unwrap());
- let text = Arc::new(include_str!("../texlab.tex").to_string());
- let mut workspace = Workspace::default();
- workspace
- .open(Arc::clone(&uri), text, DocumentLanguage::Latex)
- .unwrap();
-
- b.iter(|| {
- texlab::features::complete(FeatureRequest {
- params: CompletionParams {
- context: None,
- partial_result_params: Default::default(),
- work_done_progress_params: Default::default(),
- text_document_position: TextDocumentPositionParams::new(
- TextDocumentIdentifier::new(uri.as_ref().clone()),
- Position::new(0, 1),
- ),
- },
- workspace: workspace.clone(),
- uri: Arc::clone(&uri),
- })
- });
+ let uri = Url::parse("http://example.com/texlab.tex").unwrap();
+ let text = include_str!("../texlab.tex").to_string();
+ let mut db = Database::default();
+ Workspace::get(&db).open(&mut db, uri.clone(), text, Language::Tex, Owner::Client);
+ b.iter(|| texlab::features::completion::complete(&db, &uri, Position::new(0, 1)));
});
}
diff --git a/support/texlab/docs/custom_commands.md b/support/texlab/docs/custom_commands.md
deleted file mode 100644
index 2b85787f35..0000000000
--- a/support/texlab/docs/custom_commands.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Custom Commands
-
-The server provides the following commands through the `workspace/executeCommand` request:
-
-## texlab.cleanAuxiliary
-
-Removes the auxiliary files produced by compiling the specified LaTeX document.
-At the moment, this command simply calls `latexmk -c` with the currently configured output directory.
-
-Parameters:
-
-- `document`: `TextDocumentIdentifier` (_Required_)
-
-## texlab.cleanArtifacts
-
-Removes the auxiliary files and the artifacts produced by compiling the specified LaTeX document.
-At the moment, this command simply calls `latexmk -C` with the currently configured output directory.
-
-Parameters:
-
-- `document`: `TextDocumentIdentifier` (_Required_)
diff --git a/support/texlab/docs/custom_messages.md b/support/texlab/docs/custom_messages.md
deleted file mode 100644
index 0142a76342..0000000000
--- a/support/texlab/docs/custom_messages.md
+++ /dev/null
@@ -1,102 +0,0 @@
-# Custom Messages
-
-We extend the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/specification)
-with custom messages to provide better LaTeX integration.
-These messages are _optional_ and it is up to the client to support them.
-
-## Build Request
-
-The build request is sent from the client to the server to build a given LaTeX document.
-
-_Request_:
-
-- method: 'textDocument/build'
-- params: `BuildTextDocumentParams` defined as follows:
-
-```typescript
-interface BuildTextDocumentParams {
- /**
- * The text document to build.
- */
- textDocument: TextDocumentIdentifier;
-}
-```
-
-_Response_:
-
-- result: `BuildResult` defined as follows:
-
-```typescript
-interface BuildResult {
- /**
- * The status of the build process.
- */
- status: BuildStatus;
-}
-
-enum BuildStatus {
- /**
- * The build process terminated without any errors.
- */
- Success = 0,
-
- /**
- * The build process terminated with errors.
- */
- Error = 1,
-
- /**
- * The build process failed to start or crashed.
- */
- Failure = 2,
-
- /**
- * The build process was cancelled.
- */
- Cancelled = 3,
-}
-```
-
-## Forward Search Request
-
-The forward search request is sent from the client to the server when the user requests a forward search via SyncTeX.
-
-_Request_:
-
-- method: 'textDocument/forwardSearch'
-- params: [`TextDocumentPositionParams`](https://microsoft.github.io/language-server-protocol/specification#textdocumentpositionparams)
-
-_Response_:
-
-- result: `ForwardSearchResult` defined as follows:
-
-```typescript
-interface ForwardSearchResult {
- /**
- * The status of the previewer process.
- */
- status: ForwardSearchStatus;
-}
-
-enum ForwardSearchStatus {
- /**
- * The previewer process executed the command without any errors.
- */
- Success = 0,
-
- /**
- * The previewer process executed the command with errors.
- */
- Error = 1,
-
- /**
- * The previewer process failed to start or crashed.
- */
- Failure = 2,
-
- /**
- * The previewer command is not configured.
- */
- Unconfigured = 3,
-}
-```
diff --git a/support/texlab/docs/lsp_kinds.md b/support/texlab/docs/lsp_kinds.md
deleted file mode 100644
index 8d6ad6efc7..0000000000
--- a/support/texlab/docs/lsp_kinds.md
+++ /dev/null
@@ -1,31 +0,0 @@
-The following table describes the mapping of LaTeX and BibTeX structures
-to their `CompletionItemKind` and `SymbolKind`.
-
-| LaTeX / BibTeX structure | CompletionItemKind | SymbolKind |
-| ------------------------- | -------------------- | -------------------- |
-| Command | `Function` (3) | `Function` (12) |
-| Command Argument | `Value` (12) | `Number` (16) |
-| Snippet | `Snippet` (15) | |
-| Environment | `Enum` (13) | `Enum` (10) |
-| Section | `Module` (9) | `Module` (2) |
-| Float | `Method` (2) | `Method` (6) |
-| Theorem | `Variable` (6) | `Variable` (13) |
-| Equation | `Constant` (21) | `Constant` (14) |
-| Enumeration Item | `EnumMember` (20) | `EnumMember` (22) |
-| Label | `Constructor` (4) | `Constructor` (9) |
-| Folder | `Folder` (19) | `Namespace` (3) |
-| File | `File` (17) | `File` (1) |
-| PGF Library | `Property` (10) | `Property` (7) |
-| TikZ Library | `Property` (10) | `Property` (7) |
-| Color | `Color` (16) | |
-| Color Model | `Color` (16) | |
-| Package | `Class` (7) | `Class` (5) |
-| Class | `Class` (7) | `Class` (5) |
-| BibTeX Entry (Misc) | `Interface` (8) | `Interface` (11) |
-| BibTeX Entry (Article) | `Event` (23) | `Event` (24) |
-| BibTeX Entry (Book) | `Struct` (22) | `Struct` (23) |
-| BibTeX Entry (Collection) | `TypeParameter` (25) | `TypeParameter` (26) |
-| BibTeX Entry (Part) | `Operator` (24) | `Operator` (25) |
-| BibTeX Entry (Thesis) | `Unit` (11) | `Object` (19) |
-| BibTeX String | `Text` (1) | `String` (15) |
-| BibTeX Field | `Field` (5) | `Field` (8) |
diff --git a/support/texlab/docs/options.md b/support/texlab/docs/options.md
deleted file mode 100644
index 9b3599cce1..0000000000
--- a/support/texlab/docs/options.md
+++ /dev/null
@@ -1,225 +0,0 @@
-# Configuration
-
-This document describes the configuration settings
-that the server will query from the LSP client / extension.
-
----
-
-## texlab.rootDirectory
-
-Defines the directory from which the source files get compiled.
-You may need to set this property for multi-folder projects
-where TexLab fails to detect the root document.
-
-**Type:** `string | null`
-
-**Default value**: `null`
-
----
-
-## texlab.build.executable
-
-Defines the executable of the LaTeX build tool.
-
-**Type:** `string`
-
-**Default value:** `latexmk`
-
----
-
-## texlab.build.args
-
-Defines additional arguments that are passed to the configured LaTeX build tool.
-Note that flags and their arguments need to be separate
-elements in this array.
-To pass the arguments `-foo bar` to a build tool,
-`latex.build.args` needs to be `["-foo", "bar"]`.
-The placeholder `%f` will be replaced by the server.
-
-**Placeholders:**
-
-- `%f`: The path of the TeX file to compile.
-
-**Type:** `string[]`
-
-**Default value:** `["-pdf", "-interaction=nonstopmode", "-synctex=1", "%f"]`
-
----
-
-## texlab.build.forwardSearchAfter
-
-Set this property to `true` if you want to execute a forward search after a build.
-
-**Type:** `boolean`
-
-**Default value:** `false`
-
----
-
-## texlab.build.onSave
-
-Set this property to `true` if you want to compile the project after saving a file.
-
-**Type:** `boolean`
-
-**Default value:** `false`
-
----
-
-## texlab.auxDirectory
-
-Defines the directory containing the build artifacts.
-Note that you need to set the output directory in `latex.build.args` too,
-if you want to change the build directory.
-In this case, use the `-outdir` flag for `latexmk`.
-
-**Type:** `string`
-
-**Default value:** `.` (the same directory as the TeX file)
-
----
-
-## texlab.forwardSearch.executable
-
-Defines the executable of the PDF previewer.
-The previewer needs to support [SyncTeX](http://www.tug.org/TUGboat/tb29-3/tb93laurens.pdf).
-
-**Type:** `string | null`
-
-**Default value:** `null`
-
----
-
-## texlab.forwardSearch.args
-
-Defines additional arguments that are passed to the configured previewer to perform the forward search.
-The placeholders `%f, %p, %l` will be replaced by the server.
-
-**Placeholders:**
-
-- `%f`: The path of the current TeX file.
-- `%p`: The path of the current PDF file.
-- `%l`: The current line number.
-
-**Type:** `string[] | null`
-
-**Default value:** `null`
-
----
-
-## texlab.chktex.onOpenAndSave
-
-Lint using [chktex](https://www.nongnu.org/chktex/) after opening and saving a file.
-
-**Type:** `boolean`
-
-**Default value:** `false`
-
----
-
-## texlab.chktex.onEdit
-
-Lint using [chktex](https://www.nongnu.org/chktex/) after editing a file.
-
-**Type:** `boolean`
-
-**Default value:** `false`
-
----
-
-## texlab.diagnosticsDelay
-
-Delay in milliseconds before reporting diagnostics.
-
-**Type:** `integer`
-
-**Default value:** `300`
-
----
-
-## texlab.diagnostics.allowedPatterns
-
-A list of regular expressions used to filter the list of reported diagnostics.
-If specified, only diagnostics that match _at least one_ of the specified patterns
-are sent to the client.
-
-See also [`texlab.diagnostics.ignoredPatterns`](#texlabdiagnosticsignoredpatterns).
-
-_Hint_:
-If both `allowedPatterns` and `ignoredPatterns` are set,
-then allowed patterns are applied first. Afterwards, the results are filtered with the ignored patterns.
-
-**Type:** `RegExp[]`
-
-**Default value:** `[]`
-
----
-
-## texlab.diagnostics.ignoredPatterns
-
-A list of regular expressions used to filter the list of reported diagnostics.
-If specified, only diagnostics that match _none_ of the specified patterns
-are sent to the client.
-
-See also [`texlab.diagnostics.allowedPatterns`](#texlabdiagnosticsallowedpatterns).
-
-**Type:** `RegExp[]`
-
-**Default value:** `[]`
-
----
-
-## texlab.formatterLineLength
-
-Defines the maximum amount of characters per line (0 = disable) when formatting BibTeX files.
-
-**Type:** `integer`
-
-**Default value:** `80`
-
----
-
-## texlab.bibtexFormatter
-
-Defines the formatter to use for BibTeX formatting.
-Possible values are either `texlab` or `latexindent`.
-
-**Type:** `string`
-
-**Default value:** `texlab`
-
----
-
-## texlab.latexFormatter
-
-Defines the formatter to use for LaTeX formatting.
-Possible values are either `texlab` or `latexindent`.
-Note that `texlab` is not implemented yet.
-
-**Type:** `string`
-
-**Default value:** `latexindent`
-
----
-
-## texlab.latexindent.local
-
-Defines the path of a file containing the `latexindent` configuration.
-This corresponds to the `--local=file.yaml` flag of `latexindent`.
-By default the configuration inside the project root directory is used.
-
-**Type:** `string`
-
-**Default value:** `null`
-
----
-
-## texlab.latexindent.modifyLineBreaks
-
-Modifies linebreaks before, during, and at the end of code blocks
-when formatting with `latexindent`.
-This corresponds to the `--modifylinebreaks` flag of `latexindent`.
-
-**Type:** `boolean`
-
-**Default value:** `false`
diff --git a/support/texlab/docs/previewing.md b/support/texlab/docs/previewing.md
deleted file mode 100644
index 3e97390429..0000000000
--- a/support/texlab/docs/previewing.md
+++ /dev/null
@@ -1,195 +0,0 @@
-# Previewing
-
-`texlab` supports compiling LaTeX using a custom request (`textDocument/build`)
-and by building a document after saving if configured to do so.
-To enable building on save, simply set `texlab.build.onSave` to true.
-Previewing can be configured in a variety of ways:
-
-1. If you are using `latexmk`, you can create a `.latexmkrc` file and call your viewer accordingly.
- Afterwards, you can add the `-pv` flag to your `texlab.build.args`.
-
-2. If you want the PDF viewer to stay synchronized with the cursor position in your editor,
- you can instruct `texlab` to execute a forward search after every build (`texlab.build.forwardSearchAfter`).
- To do so, you need to enable [SyncTeX](http://www.tug.org/TUGboat/tb29-3/tb93laurens.pdf)
- and update the `texlab.forwardSearch` configuration.
- If you want to use this feature, we do _not_ recommend the `-pvc` flag
- because `texlab` does not get notified by `latexmk` when a document gets built.
- Instead, you can use `texlab.build.onSave`.
-
-In the following sections, we will give forward search configurations for several popular viewers.
-If your viewer is not listed here, you can send us a pull request or create an issue.
-
-The inverse search configuration depends on the editor.
-In this section, we will give instructions for [Visual Studio Code](https://code.visualstudio.com/).
-However, these settings can easily be adapted to other editors.
-Some plugins can help with setting up inverse search:
-
-- `Neovim`: [`f3fora/nvim-texlabconfig`](https://github.com/f3fora/nvim-texlabconfig)
-- `Emacs`: [`ROCKTAKEY/lsp-latex`](https://github.com/ROCKTAKEY/lsp-latex#inverse-search)
-
----
-
-## SumatraPDF
-
-We highly recommend [SumatraPDF](https://www.sumatrapdfreader.org) on Windows
-because Adobe Reader locks the opened PDF file and will therefore prevent further builds.
-
-### Forward Search
-
-Add the following lines to your editor config:
-
-```json
-{
- "texlab.forwardSearch.executable": "C:/Users/{User}/AppData/Local/SumatraPDF/SumatraPDF.exe",
- "texlab.forwardSearch.args": [
- "-reuse-instance",
- "%p",
- "-forward-search",
- "%f",
- "%l"
- ]
-}
-```
-
-### Inverse Search
-
-Add the following line to your SumatraPDF settings file (Menu -> Settings -> Advanced Options):
-
-```ini
-InverseSearchCmdLine = "C:\Users\{User}\AppData\Local\Programs\Microsoft VS Code\Code.exe" -g "%f":%l
-```
-
-> **Note**: Please make sure to replace `{User}` with your Windows username.
-
-You can execute the search by pressing `Alt+DoubleClick` in the PDF document.
-
----
-
-## Evince
-
-The SyncTeX feature of [Evince](https://wiki.gnome.org/Apps/Evince) requires communication via D-Bus.
-In order to use it from the command line, install the [evince-synctex](https://github.com/latex-lsp/evince-synctex) script.
-
-### Forward Search
-
-Add the following lines to your editor config:
-
-```json
-{
- "texlab.forwardSearch.executable": "evince-synctex",
- "texlab.forwardSearch.args": ["-f", "%l", "%p", "\"code -g %f:%l\""]
-}
-```
-
-### Inverse Search
-
-The inverse search feature is already configured if you use `evince-synctex`.
-You can execute the search by pressing `Ctrl+Click` in the PDF document.
-
----
-
-## Okular
-
-### Forward Search
-
-Add the following lines to your editor config:
-
-```json
-{
- "texlab.forwardSearch.executable": "okular",
- "texlab.forwardSearch.args": ["--editor-cmd": "code -g \"%%f\":%%l", "--unique", "file:%p#src:%l%f"]
-}
-```
-
-### Inverse Search
-
-Change the editor of Okular (Settings -> Configure Okular... -> Editor) to "Custom Text Editor" and set the following command:
-
-```bash
-code -g "%f":%l
-```
-
-You can execute the search by pressing `Shift+Click` in the PDF document.
-
----
-
-## Zathura
-
-### Forward Search
-
-Add the following lines to your editor config:
-
-```json
-{
- "texlab.forwardSearch.executable": "zathura",
- "texlab.forwardSearch.args": ["--synctex-forward", "%l:1:%f", "%p"]
-}
-```
-
-### Inverse Search
-
-Add the following lines to your `~/.config/zathura/zathurarc` file:
-
-```bash
-set synctex true
-set synctex-editor-command "code -g %{input}:%{line}"
-```
-
-You can execute the search by pressing `Ctrl+Click` in the PDF document.
-
----
-
-## qpdfview
-
-### Forward Search
-
-Add the following lines to your editor config:
-
-```json
-{
- "texlab.forwardSearch.executable": "qpdfview",
- "texlab.forwardSearch.args": ["--unique", "%p#src:%f:%l:1"]
-}
-```
-
-### Inverse Search
-
-Change the source editor setting (Edit -> Settings... -> Behavior -> Source editor) to:
-
-```bash
-code -g "%1":%2
-```
-
-and select a mouse button modifier (Edit -> Settings... -> Behavior -> Modifiers -> Mouse button modifiers -> Open in Source Editor)
-of choice.
-You can execute the search by pressing `Modifier+Click` in the PDF document.
-
----
-
-## Skim
-
-We recommend [Skim](https://skim-app.sourceforge.io/) on macOS since it is the only native viewer that supports SyncTeX.
-
-Additionally, enable the "Reload automatically" setting in the Skim preferences (Skim -> Preferences -> Sync -> Check for file changes).
-
-### Forward Search
-
-Add the following lines to your editor config:
-
-```json
-{
- "texlab.forwardSearch.executable": "/Applications/Skim.app/Contents/SharedSupport/displayline",
- "texlab.forwardSearch.args": ["%l", "%p", "%f"]
-}
-```
-
-If you want Skim to stay in the background after
-executing the forward search, you can add the `-g` option
-to `texlab.forwardSearch.args`.
-
-### Inverse Search
-
-Select the Visual Studio Code preset in the Skim preferences (Skim -> Preferences -> Sync -> PDF-TeX Sync support).
-You can execute the search by pressing `Shift+⌘+Click` in the PDF document.
-
----
diff --git a/support/texlab/docs/tectonic.md b/support/texlab/docs/tectonic.md
deleted file mode 100644
index b08e64b946..0000000000
--- a/support/texlab/docs/tectonic.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Usage with `tectonic`
-
-[`tectonic`](https://tectonic-typesetting.github.io/) is a modernized, alternative TeX engine.
-Most features of `texlab` work out of the box when using `tectonic`.
-To compile documents through `texlab`, you need to change the configuration.
-See `tectonic --help` for more information about the flags.
-
----
-
-**Hint:**
-
-Please make sure to set `texlab.auxDirectory` if you change the build directory with the `--outdir` argument.
-
-Also, `--keep-intermediates` is recommended because they allow `texlab`
-to find out the section numbers and show them in the completion.
-Without the `--keep-logs` flag, `texlab` won't be able to report compilation warnings.
-
----
-
-## V2 CLI
-
-```json
-{
- "texlab.build.executable": "tectonic",
- "texlab.build.args": [
- "-X",
- "compile",
- "%f",
- "--synctex",
- "--keep-logs",
- "--keep-intermediates"
- ]
-}
-```
-
-## V1 CLI
-
-```json
-{
- "texlab.build.executable": "tectonic",
- "texlab.build.args": [
- "%f",
- "--synctex",
- "--keep-logs",
- "--keep-intermediates"
- ]
-}
-```
diff --git a/support/texlab/docs/demo.gif b/support/texlab/images/demo.gif
index 6bb0817a59..6bb0817a59 100644
--- a/support/texlab/docs/demo.gif
+++ b/support/texlab/images/demo.gif
Binary files differ
diff --git a/support/texlab/rust-toolchain b/support/texlab/rust-toolchain
deleted file mode 100644
index 870bbe4e50..0000000000
--- a/support/texlab/rust-toolchain
+++ /dev/null
@@ -1 +0,0 @@
-stable \ No newline at end of file
diff --git a/support/texlab/src/citation/driver.rs b/support/texlab/src/citation/driver.rs
index 815474a107..ab3fe6d80f 100644
--- a/support/texlab/src/citation/driver.rs
+++ b/support/texlab/src/citation/driver.rs
@@ -1,7 +1,7 @@
use isocountry::CountryCode;
use itertools::Itertools;
+use lsp_types::Url;
use titlecase::titlecase;
-use url::Url;
use crate::syntax::bibtex;
diff --git a/support/texlab/src/citation/field/date.rs b/support/texlab/src/citation/field/date.rs
index b67972e691..4eba9cdea4 100644
--- a/support/texlab/src/citation/field/date.rs
+++ b/support/texlab/src/citation/field/date.rs
@@ -42,7 +42,7 @@ impl Add for DateFieldData {
| (Self::Other(_), date)
| (date, Self::Other(_)) => date,
(Self::Year(year), Self::Month(month)) | (Self::Month(month), Self::Year(year)) => {
- let new_date = NaiveDate::from_ymd(year, month.number_from_month(), 1);
+ let new_date = NaiveDate::from_ymd_opt(year, month.number_from_month(), 1).unwrap();
Self::Date(new_date)
}
(Self::Year(year), Self::Date(date)) | (Self::Date(date), Self::Year(year)) => {
diff --git a/support/texlab/src/citation/tests.rs b/support/texlab/src/citation/tests.rs
index 16aefea11d..6caff1add0 100644
--- a/support/texlab/src/citation/tests.rs
+++ b/support/texlab/src/citation/tests.rs
@@ -1,10 +1,10 @@
use insta::assert_snapshot;
use rowan::ast::AstNode;
-use crate::syntax::bibtex;
+use crate::{parser::parse_bibtex, syntax::bibtex};
fn render_entry(input: &str) -> String {
- let green = bibtex::parse(input);
+ let green = parse_bibtex(input);
let root = bibtex::Root::cast(bibtex::SyntaxNode::new_root(green)).unwrap();
let entry = root.entries().next().unwrap();
super::render(&entry).unwrap()
diff --git a/support/texlab/src/client.rs b/support/texlab/src/client.rs
index 72f2ac9eba..ab912653b0 100644
--- a/support/texlab/src/client.rs
+++ b/support/texlab/src/client.rs
@@ -1,53 +1,109 @@
-use std::sync::Mutex;
+use std::sync::{
+ atomic::{AtomicI32, Ordering},
+ Arc,
+};
-use anyhow::{anyhow, Result};
-use crossbeam_channel::{Receiver, Sender};
-use lsp_server::{Message, ResponseError};
+use anyhow::{bail, Result};
+use crossbeam_channel::Sender;
+use dashmap::DashMap;
+use lsp_server::{ErrorCode, Message, Request, RequestId, Response};
+use lsp_types::{notification::ShowMessage, MessageType, ShowMessageParams};
use serde::{de::DeserializeOwned, Serialize};
-use crate::req_queue::{OutgoingData, ReqQueue};
+use crate::Options;
-pub fn send_notification<N>(lsp_sender: &Sender<Message>, params: N::Params) -> Result<()>
-where
- N: lsp_types::notification::Notification,
- N::Params: Serialize,
-{
- lsp_sender.send(lsp_server::Notification::new(N::METHOD.to_string(), params).into())?;
- Ok(())
+#[derive(Debug)]
+struct RawClient {
+ sender: Sender<Message>,
+ next_id: AtomicI32,
+ pending: DashMap<RequestId, Sender<Response>>,
}
-pub fn send_request<R>(
- req_queue: &Mutex<ReqQueue>,
- lsp_sender: &Sender<Message>,
- params: R::Params,
-) -> Result<R::Result>
-where
- R: lsp_types::request::Request,
- R::Params: Serialize,
- R::Result: DeserializeOwned,
-{
- let receiver = register_outgoing_request::<R>(req_queue, lsp_sender, params)?;
- let params = receiver.recv()?.map_err(|err| anyhow!(err.message))?;
- let result = serde_json::from_value(params)?;
- Ok(result)
+#[derive(Debug, Clone)]
+pub struct LspClient {
+ raw: Arc<RawClient>,
}
-fn register_outgoing_request<R>(
- req_queue: &Mutex<ReqQueue>,
- lsp_sender: &Sender<Message>,
- params: R::Params,
-) -> Result<Receiver<Result<serde_json::Value, ResponseError>>>
-where
- R: lsp_types::request::Request,
- R::Params: Serialize,
- R::Result: DeserializeOwned,
-{
- let mut req_queue = req_queue.lock().unwrap();
- let (sender, receiver) = crossbeam_channel::bounded(1);
- let method = R::METHOD.to_string();
- let data = OutgoingData { sender };
- let req = req_queue.outgoing.register(method, params, data);
- drop(req_queue);
- lsp_sender.send(req.into())?;
- Ok(receiver)
+impl LspClient {
+ pub fn new(sender: Sender<Message>) -> Self {
+ let raw = Arc::new(RawClient {
+ sender,
+ next_id: AtomicI32::new(1),
+ pending: DashMap::default(),
+ });
+
+ Self { raw }
+ }
+
+ pub fn send_notification<N>(&self, params: N::Params) -> Result<()>
+ where
+ N: lsp_types::notification::Notification,
+ N::Params: Serialize,
+ {
+ self.raw
+ .sender
+ .send(lsp_server::Notification::new(N::METHOD.to_string(), params).into())?;
+ Ok(())
+ }
+
+ pub fn send_request<R>(&self, params: R::Params) -> Result<R::Result>
+ where
+ R: lsp_types::request::Request,
+ R::Params: Serialize,
+ R::Result: DeserializeOwned,
+ {
+ let id = RequestId::from(self.raw.next_id.fetch_add(1, Ordering::SeqCst));
+
+ let (tx, rx) = crossbeam_channel::bounded(1);
+ self.raw.pending.insert(id.clone(), tx);
+
+ self.raw
+ .sender
+ .send(Request::new(id, R::METHOD.to_string(), params).into())?;
+
+ let response = rx.recv()?;
+ let result = match response.error {
+ Some(error) => bail!(error.message),
+ None => response.result.unwrap_or_default(),
+ };
+
+ Ok(serde_json::from_value(result)?)
+ }
+
+ pub fn send_response(&self, response: lsp_server::Response) -> Result<()> {
+ self.raw.sender.send(response.into())?;
+ Ok(())
+ }
+
+ pub fn send_error(&self, id: RequestId, code: ErrorCode, message: String) -> Result<()> {
+ self.send_response(lsp_server::Response::new_err(id, code as i32, message))?;
+ Ok(())
+ }
+
+ pub fn recv_response(&self, response: lsp_server::Response) -> Result<()> {
+ let (_, tx) = self
+ .raw
+ .pending
+ .remove(&response.id)
+ .expect("response with known request id received");
+
+ tx.send(response)?;
+ Ok(())
+ }
+
+ pub fn parse_options(&self, value: serde_json::Value) -> Result<Options> {
+ let options = match serde_json::from_value(value) {
+ Ok(new_options) => new_options,
+ Err(why) => {
+ let message = format!(
+ "The texlab configuration is invalid; using the default settings instead.\nDetails: {why}"
+ );
+ let typ = MessageType::WARNING;
+ self.send_notification::<ShowMessage>(ShowMessageParams { message, typ })?;
+ None
+ }
+ };
+
+ Ok(options.unwrap_or_default())
+ }
}
diff --git a/support/texlab/src/component_db.rs b/support/texlab/src/component_db.rs
deleted file mode 100644
index 8dc547369f..0000000000
--- a/support/texlab/src/component_db.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-use std::io::Read;
-
-use flate2::read::GzDecoder;
-use itertools::Itertools;
-use lsp_types::{MarkupContent, MarkupKind};
-use once_cell::sync::Lazy;
-use serde::{Deserialize, Serialize};
-use smol_str::SmolStr;
-
-use crate::{syntax::latex::ExplicitLink, Workspace};
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct ComponentDatabase {
- pub components: Vec<Component>,
- pub metadata: Vec<ComponentMetadata>,
-}
-
-impl ComponentDatabase {
- #[must_use]
- pub fn find(&self, name: &str) -> Option<&Component> {
- self.components.iter().find(|component| {
- component
- .file_names
- .iter()
- .any(|file_name| file_name == name)
- })
- }
-
- #[must_use]
- pub fn find_no_ext(&self, name: &str) -> Option<&Component> {
- self.components.iter().find(|component| {
- component
- .file_names
- .iter()
- .any(|file_name| &file_name[0..file_name.len() - 4] == name)
- })
- }
-
- #[must_use]
- pub fn linked_components(&self, workspace: &Workspace) -> Vec<&Component> {
- let mut start_components = vec![self.kernel()];
- for document in workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- data.extras
- .explicit_links
- .iter()
- .filter_map(ExplicitLink::as_component_name)
- .filter_map(|name| self.find(&name))
- .for_each(|component| start_components.push(component));
- }
- }
-
- let mut all_components = Vec::new();
- for component in start_components {
- all_components.push(component);
- component
- .references
- .iter()
- .filter_map(|file| self.find(file))
- .for_each(|component| all_components.push(component));
- }
-
- all_components
- .into_iter()
- .unique_by(|component| &component.file_names)
- .collect()
- }
-
- #[must_use]
- pub fn contains(&self, short_name: &str) -> bool {
- let sty = format!("{}.sty", short_name);
- let cls = format!("{}.cls", short_name);
- self.find(&sty).is_some() || self.find(&cls).is_some()
- }
-
- #[must_use]
- pub fn kernel(&self) -> &Component {
- self.components
- .iter()
- .find(|component| component.file_names.is_empty())
- .unwrap()
- }
-
- #[must_use]
- pub fn exists(&self, file_name: &str) -> bool {
- self.components
- .iter()
- .any(|component| component.file_names.iter().any(|f| f == file_name))
- }
-
- #[must_use]
- pub fn documentation(&self, name: &str) -> Option<MarkupContent> {
- let metadata = self
- .metadata
- .iter()
- .find(|metadata| metadata.name == name)?;
-
- let desc = metadata.description.clone()?;
- Some(MarkupContent {
- kind: MarkupKind::PlainText,
- value: desc,
- })
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct Component {
- pub file_names: Vec<SmolStr>,
- pub references: Vec<SmolStr>,
- pub commands: Vec<ComponentCommand>,
- pub environments: Vec<SmolStr>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct ComponentCommand {
- pub name: SmolStr,
- pub image: Option<String>,
- pub glyph: Option<SmolStr>,
- pub parameters: Vec<ComponentParameter>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct ComponentParameter(pub Vec<ComponentArgument>);
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct ComponentArgument {
- pub name: SmolStr,
- pub image: Option<String>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct ComponentMetadata {
- pub name: String,
- pub caption: Option<String>,
- pub description: Option<String>,
-}
-
-const JSON_GZ: &[u8] = include_bytes!("../data/components.json.gz");
-
-pub static COMPONENT_DATABASE: Lazy<ComponentDatabase> = Lazy::new(|| {
- let mut decoder = GzDecoder::new(JSON_GZ);
- let mut buf = String::new();
- decoder.read_to_string(&mut buf).unwrap();
- serde_json::from_str(&buf).unwrap()
-});
diff --git a/support/texlab/src/db.rs b/support/texlab/src/db.rs
new file mode 100644
index 0000000000..64165b76c2
--- /dev/null
+++ b/support/texlab/src/db.rs
@@ -0,0 +1,14 @@
+pub mod analysis;
+pub mod diagnostics;
+mod discovery;
+mod document;
+pub mod parse;
+mod workspace;
+
+pub use {discovery::*, document::*, workspace::*};
+
+#[salsa::interned]
+pub struct Word {
+ #[return_ref]
+ pub text: String,
+}
diff --git a/support/texlab/src/db/analysis.rs b/support/texlab/src/db/analysis.rs
new file mode 100644
index 0000000000..35ee4be2a1
--- /dev/null
+++ b/support/texlab/src/db/analysis.rs
@@ -0,0 +1,199 @@
+pub mod label;
+
+use rowan::{ast::AstNode, TextRange};
+
+use crate::{
+ syntax::latex::{self, HasCurly},
+ Db,
+};
+
+use super::Word;
+
+#[salsa::tracked]
+pub struct TexLink {
+ pub kind: TexLinkKind,
+ pub path: Word,
+ pub range: TextRange,
+ pub base_dir: Option<Word>,
+}
+
+impl TexLink {
+ fn of_include(db: &dyn Db, node: latex::SyntaxNode, results: &mut Vec<Self>) -> Option<()> {
+ let include = latex::Include::cast(node)?;
+ let kind = match include.syntax().kind() {
+ latex::LATEX_INCLUDE => TexLinkKind::Tex,
+ latex::BIBLATEX_INCLUDE | latex::BIBTEX_INCLUDE => TexLinkKind::Bib,
+ latex::PACKAGE_INCLUDE => TexLinkKind::Sty,
+ latex::CLASS_INCLUDE => TexLinkKind::Cls,
+ _ => return None,
+ };
+
+ for path in include.path_list()?.keys() {
+ results.push(Self::new(
+ db,
+ kind,
+ Word::new(db, path.to_string()),
+ latex::small_range(&path),
+ None,
+ ));
+ }
+
+ Some(())
+ }
+
+ fn of_import(db: &dyn Db, node: latex::SyntaxNode, results: &mut Vec<Self>) -> Option<()> {
+ let import = latex::Import::cast(node)?;
+
+ let mut base_dir = import.directory()?.key()?.to_string();
+ if !base_dir.ends_with("/") {
+ base_dir.push('/');
+ }
+
+ let path = import.file()?.key()?;
+ results.push(Self::new(
+ db,
+ TexLinkKind::Tex,
+ Word::new(db, path.to_string()),
+ latex::small_range(&path),
+ Some(Word::new(db, base_dir)),
+ ));
+
+ Some(())
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+pub enum TexLinkKind {
+ Sty,
+ Cls,
+ Tex,
+ Bib,
+}
+
+impl TexLinkKind {
+ pub fn extensions(self) -> &'static [&'static str] {
+ match self {
+ Self::Sty => &["sty"],
+ Self::Cls => &["cls"],
+ Self::Tex => &["tex"],
+ Self::Bib => &["bib"],
+ }
+ }
+}
+
+#[salsa::tracked]
+pub struct TheoremEnvironment {
+ pub name: Word,
+ pub description: Word,
+}
+
+impl TheoremEnvironment {
+ fn of_definition(db: &dyn Db, node: latex::SyntaxNode, results: &mut Vec<Self>) -> Option<()> {
+ let theorem = latex::TheoremDefinition::cast(node)?;
+ let name = theorem.name()?.key()?.to_string();
+ let description = theorem.description()?;
+ let description = description.content_text()?;
+
+ results.push(Self::new(
+ db,
+ Word::new(db, name),
+ Word::new(db, description),
+ ));
+
+ Some(())
+ }
+}
+
+#[salsa::tracked]
+pub struct GraphicsPath {
+ #[return_ref]
+ pub path: String,
+}
+
+impl GraphicsPath {
+ pub fn of_command(db: &dyn Db, node: latex::SyntaxNode, results: &mut Vec<Self>) -> Option<()> {
+ let definition = latex::GraphicsPath::cast(node)?;
+ for path in definition
+ .path_list()
+ .filter_map(|group| group.key())
+ .map(|path| path.to_string())
+ {
+ results.push(GraphicsPath::new(db, path));
+ }
+
+ Some(())
+ }
+}
+
+#[salsa::tracked]
+pub struct TexAnalysis {
+ #[return_ref]
+ pub links: Vec<TexLink>,
+
+ #[return_ref]
+ pub labels: Vec<label::Name>,
+
+ #[return_ref]
+ pub label_numbers: Vec<label::Number>,
+
+ #[return_ref]
+ pub theorem_environments: Vec<TheoremEnvironment>,
+
+ #[return_ref]
+ pub graphics_paths: Vec<GraphicsPath>,
+
+ #[return_ref]
+ pub command_name_ranges: Vec<TextRange>,
+
+ #[return_ref]
+ pub environment_names: Vec<String>,
+}
+
+impl TexAnalysis {
+ pub(super) fn analyze(db: &dyn Db, root: &latex::SyntaxNode) -> Self {
+ let mut links = Vec::new();
+ let mut labels = Vec::new();
+ let mut label_numbers = Vec::new();
+ let mut theorem_environments = Vec::new();
+ let mut graphics_paths = Vec::new();
+ let mut command_name_ranges = Vec::new();
+ let mut environment_names = Vec::new();
+
+ for node in root.descendants() {
+ TexLink::of_include(db, node.clone(), &mut links)
+ .or_else(|| TexLink::of_import(db, node.clone(), &mut links))
+ .or_else(|| label::Name::of_definition(db, node.clone(), &mut labels))
+ .or_else(|| label::Name::of_reference(db, node.clone(), &mut labels))
+ .or_else(|| label::Name::of_reference_range(db, node.clone(), &mut labels))
+ .or_else(|| label::Number::of_number(db, node.clone(), &mut label_numbers))
+ .or_else(|| {
+ TheoremEnvironment::of_definition(db, node.clone(), &mut theorem_environments)
+ })
+ .or_else(|| GraphicsPath::of_command(db, node.clone(), &mut graphics_paths))
+ .or_else(|| {
+ let range = latex::GenericCommand::cast(node.clone())?
+ .name()?
+ .text_range();
+
+ command_name_ranges.push(range);
+ Some(())
+ })
+ .or_else(|| {
+ let begin = latex::Begin::cast(node.clone())?;
+ environment_names.push(begin.name()?.key()?.to_string());
+ Some(())
+ });
+ }
+
+ Self::new(
+ db,
+ links,
+ labels,
+ label_numbers,
+ theorem_environments,
+ graphics_paths,
+ command_name_ranges,
+ environment_names,
+ )
+ }
+}
diff --git a/support/texlab/src/db/analysis/label.rs b/support/texlab/src/db/analysis/label.rs
new file mode 100644
index 0000000000..77ee5268eb
--- /dev/null
+++ b/support/texlab/src/db/analysis/label.rs
@@ -0,0 +1,122 @@
+use rowan::{
+ ast::{AstNode, AstPtr},
+ TextRange,
+};
+
+use crate::{db::Word, syntax::latex, Db};
+
+#[salsa::tracked]
+pub struct Number {
+ pub name: Word,
+ pub text: Word,
+}
+
+impl Number {
+ pub(super) fn of_number(
+ db: &dyn Db,
+ node: latex::SyntaxNode,
+ results: &mut Vec<Self>,
+ ) -> Option<()> {
+ let number = latex::LabelNumber::cast(node)?;
+ let name = number.name()?.key()?.to_string();
+ let text = number
+ .text()?
+ .syntax()
+ .descendants_with_tokens()
+ .filter_map(|element| element.into_node())
+ .find(|node| node.kind() == latex::TEXT || node.kind() == latex::MIXED_GROUP)?
+ .text()
+ .to_string();
+
+ results.push(Self::new(db, Word::new(db, name), Word::new(db, text)));
+
+ Some(())
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+pub enum Origin {
+ Definition(AstPtr<latex::LabelDefinition>),
+ Reference(AstPtr<latex::LabelReference>),
+ ReferenceRange(AstPtr<latex::LabelReferenceRange>),
+}
+
+impl Origin {
+ pub fn as_definition(&self) -> Option<&AstPtr<latex::LabelDefinition>> {
+ match self {
+ Self::Definition(ptr) => Some(ptr),
+ _ => None,
+ }
+ }
+}
+
+#[salsa::tracked]
+pub struct Name {
+ pub origin: Origin,
+ pub name: Word,
+ pub range: TextRange,
+}
+
+impl Name {
+ pub(super) fn of_definition(
+ db: &dyn Db,
+ node: latex::SyntaxNode,
+ results: &mut Vec<Self>,
+ ) -> Option<()> {
+ let label = latex::LabelDefinition::cast(node)?;
+ let name = label.name()?.key()?;
+ results.push(Self::new(
+ db,
+ Origin::Definition(AstPtr::new(&label)),
+ Word::new(db, name.to_string()),
+ latex::small_range(&name),
+ ));
+
+ Some(())
+ }
+
+ pub(super) fn of_reference(
+ db: &dyn Db,
+ node: latex::SyntaxNode,
+ results: &mut Vec<Self>,
+ ) -> Option<()> {
+ let label = latex::LabelReference::cast(node)?;
+ for name in label.name_list()?.keys() {
+ results.push(Self::new(
+ db,
+ Origin::Reference(AstPtr::new(&label)),
+ Word::new(db, name.to_string()),
+ latex::small_range(&name),
+ ));
+ }
+
+ Some(())
+ }
+
+ pub(super) fn of_reference_range(
+ db: &dyn Db,
+ node: latex::SyntaxNode,
+ results: &mut Vec<Self>,
+ ) -> Option<()> {
+ let label = latex::LabelReferenceRange::cast(node)?;
+ if let Some(name) = label.from().and_then(|name| name.key()) {
+ results.push(Self::new(
+ db,
+ Origin::ReferenceRange(AstPtr::new(&label)),
+ Word::new(db, name.to_string()),
+ latex::small_range(&name),
+ ));
+ }
+
+ if let Some(name) = label.to().and_then(|name| name.key()) {
+ results.push(Self::new(
+ db,
+ Origin::ReferenceRange(AstPtr::new(&label)),
+ Word::new(db, name.to_string()),
+ latex::small_range(&name),
+ ));
+ }
+
+ Some(())
+ }
+}
diff --git a/support/texlab/src/db/diagnostics.rs b/support/texlab/src/db/diagnostics.rs
new file mode 100644
index 0000000000..9b6691b873
--- /dev/null
+++ b/support/texlab/src/db/diagnostics.rs
@@ -0,0 +1,187 @@
+pub mod bib;
+pub mod log;
+pub mod tex;
+
+use lsp_types::{DiagnosticSeverity, NumberOrString, Range};
+use rustc_hash::FxHashMap;
+
+use crate::{db::workspace::Workspace, Db};
+
+use super::document::{Document, Language};
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct Diagnostic {
+ pub severity: DiagnosticSeverity,
+ pub range: Range,
+ pub code: DiagnosticCode,
+ pub message: String,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
+pub enum DiagnosticCode {
+ Tex(TexCode),
+ Bib(BibCode),
+ Log(Document),
+ Chktex(String),
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+pub enum TexCode {
+ UnexpectedRCurly,
+ RCurlyInserted,
+ MismatchedEnvironment,
+}
+
+impl From<TexCode> for String {
+ fn from(code: TexCode) -> Self {
+ match code {
+ TexCode::UnexpectedRCurly => "Unexpected \"}\"".to_string(),
+ TexCode::RCurlyInserted => "Missing \"}\" inserted".to_string(),
+ TexCode::MismatchedEnvironment => "Mismatched environment".to_string(),
+ }
+ }
+}
+
+impl From<TexCode> for NumberOrString {
+ fn from(code: TexCode) -> Self {
+ match code {
+ TexCode::UnexpectedRCurly => NumberOrString::Number(1),
+ TexCode::RCurlyInserted => NumberOrString::Number(2),
+ TexCode::MismatchedEnvironment => NumberOrString::Number(3),
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+#[allow(clippy::enum_variant_names)]
+pub enum BibCode {
+ ExpectingLCurly,
+ ExpectingKey,
+ ExpectingRCurly,
+ ExpectingEq,
+ ExpectingFieldValue,
+}
+
+impl From<BibCode> for String {
+ fn from(code: BibCode) -> Self {
+ match code {
+ BibCode::ExpectingLCurly => "Expecting a curly bracket: \"{\"".to_string(),
+ BibCode::ExpectingKey => "Expecting a key".to_string(),
+ BibCode::ExpectingRCurly => "Expecting a curly bracket: \"}\"".to_string(),
+ BibCode::ExpectingEq => "Expecting an equality sign: \"=\"".to_string(),
+ BibCode::ExpectingFieldValue => "Expecting a field value".to_string(),
+ }
+ }
+}
+
+impl From<BibCode> for NumberOrString {
+ fn from(code: BibCode) -> Self {
+ match code {
+ BibCode::ExpectingLCurly => NumberOrString::Number(4),
+ BibCode::ExpectingKey => NumberOrString::Number(5),
+ BibCode::ExpectingRCurly => NumberOrString::Number(6),
+ BibCode::ExpectingEq => NumberOrString::Number(7),
+ BibCode::ExpectingFieldValue => NumberOrString::Number(8),
+ }
+ }
+}
+
+#[salsa::tracked(return_ref)]
+pub fn collect(db: &dyn Db, workspace: Workspace) -> FxHashMap<Document, Vec<Diagnostic>> {
+ let mut results: FxHashMap<Document, Vec<Diagnostic>> = FxHashMap::default();
+
+ for document in workspace.documents(db).iter().copied() {
+ match document.language(db) {
+ Language::Tex => {
+ results.entry(document).or_default().extend(
+ tex::collect(db, document)
+ .iter()
+ .chain(document.linter(db).chktex(db))
+ .cloned(),
+ );
+ }
+ Language::Bib => {
+ results
+ .entry(document)
+ .or_default()
+ .extend(bib::collect(db, document).iter().cloned());
+ }
+ Language::Log => {
+ log::collect(db, workspace, document)
+ .iter()
+ .for_each(|(document, diagnostics)| {
+ results
+ .entry(*document)
+ .or_default()
+ .extend(diagnostics.clone());
+ });
+ }
+ }
+ }
+
+ results
+}
+
+#[salsa::tracked]
+pub fn collect_filtered(
+ db: &dyn Db,
+ workspace: Workspace,
+) -> FxHashMap<Document, Vec<lsp_types::Diagnostic>> {
+ let all_diagnostics = collect(db, workspace);
+ let mut all_filtered: FxHashMap<Document, Vec<lsp_types::Diagnostic>> = FxHashMap::default();
+
+ let options = &workspace.options(db).diagnostics;
+ for document in workspace.documents(db) {
+ let mut filtered = Vec::new();
+ if !matches!(document.language(db), Language::Tex | Language::Bib) {
+ continue;
+ }
+
+ if let Some(diagnostics) = all_diagnostics.get(document) {
+ for diagnostic in diagnostics.iter() {
+ if !options.allowed_patterns.is_empty()
+ && !options
+ .allowed_patterns
+ .iter()
+ .any(|pattern| pattern.0.is_match(&diagnostic.message))
+ {
+ continue;
+ }
+
+ if options
+ .ignored_patterns
+ .iter()
+ .any(|pattern| pattern.0.is_match(&diagnostic.message))
+ {
+ continue;
+ }
+
+ let source = match diagnostic.code {
+ DiagnosticCode::Tex(_) | DiagnosticCode::Bib(_) => "texlab",
+ DiagnosticCode::Log(_) => "latex-build",
+ DiagnosticCode::Chktex(_) => "chktex",
+ };
+
+ let code = match diagnostic.code.clone() {
+ DiagnosticCode::Tex(code) => Some(code.into()),
+ DiagnosticCode::Bib(code) => Some(code.into()),
+ DiagnosticCode::Chktex(code) => Some(NumberOrString::String(code)),
+ DiagnosticCode::Log(_) => None,
+ };
+
+ filtered.push(lsp_types::Diagnostic {
+ range: diagnostic.range,
+ code,
+ severity: Some(diagnostic.severity),
+ message: diagnostic.message.clone(),
+ source: Some(source.to_string()),
+ ..Default::default()
+ });
+ }
+ }
+
+ all_filtered.insert(*document, filtered);
+ }
+
+ all_filtered
+}
diff --git a/support/texlab/src/db/diagnostics/bib.rs b/support/texlab/src/db/diagnostics/bib.rs
new file mode 100644
index 0000000000..6d0f66e960
--- /dev/null
+++ b/support/texlab/src/db/diagnostics/bib.rs
@@ -0,0 +1,112 @@
+use lsp_types::DiagnosticSeverity;
+use rowan::{ast::AstNode, TextRange};
+
+use crate::{
+ db::document::Document,
+ syntax::bibtex::{self, HasDelims, HasEq, HasName, HasType, HasValue},
+ util::line_index_ext::LineIndexExt,
+ Db,
+};
+
+use super::{BibCode, Diagnostic, DiagnosticCode};
+
+#[salsa::tracked(return_ref)]
+pub fn collect(db: &dyn Db, document: Document) -> Vec<Diagnostic> {
+ let mut results = Vec::new();
+ let data = match document.parse(db).as_bib() {
+ Some(data) => data,
+ None => return results,
+ };
+
+ for node in data.root(db).descendants() {
+ analyze_entry(db, document, node.clone(), &mut results)
+ .or_else(|| analyze_field(db, document, node, &mut results));
+ }
+
+ results
+}
+
+fn analyze_entry(
+ db: &dyn Db,
+ document: Document,
+ node: bibtex::SyntaxNode,
+ results: &mut Vec<Diagnostic>,
+) -> Option<()> {
+ let line_index = document.contents(db).line_index(db);
+
+ let entry = bibtex::Entry::cast(node)?;
+ if entry.left_delim_token().is_none() {
+ let code = BibCode::ExpectingLCurly;
+ results.push(Diagnostic {
+ severity: DiagnosticSeverity::ERROR,
+ range: line_index.line_col_lsp_range(entry.type_token()?.text_range()),
+ code: DiagnosticCode::Bib(code),
+ message: String::from(code),
+ });
+
+ return Some(());
+ }
+
+ if entry.name_token().is_none() {
+ let code = BibCode::ExpectingKey;
+ results.push(Diagnostic {
+ severity: DiagnosticSeverity::ERROR,
+ range: line_index.line_col_lsp_range(entry.left_delim_token()?.text_range()),
+ code: DiagnosticCode::Bib(code),
+ message: String::from(code),
+ });
+
+ return Some(());
+ }
+
+ if entry.right_delim_token().is_none() {
+ let code = BibCode::ExpectingRCurly;
+ results.push(Diagnostic {
+ severity: DiagnosticSeverity::ERROR,
+ range: line_index
+ .line_col_lsp_range(TextRange::empty(entry.syntax().text_range().end())),
+ code: DiagnosticCode::Bib(code),
+ message: String::from(code),
+ });
+
+ return Some(());
+ }
+
+ Some(())
+}
+
+fn analyze_field(
+ db: &dyn Db,
+ document: Document,
+ node: bibtex::SyntaxNode,
+ results: &mut Vec<Diagnostic>,
+) -> Option<()> {
+ let line_index = document.contents(db).line_index(db);
+
+ let field = bibtex::Field::cast(node)?;
+ if field.eq_token().is_none() {
+ let code = BibCode::ExpectingEq;
+ results.push(Diagnostic {
+ severity: DiagnosticSeverity::ERROR,
+ range: line_index.line_col_lsp_range(field.name_token()?.text_range()),
+ code: DiagnosticCode::Bib(code),
+ message: String::from(code),
+ });
+
+ return Some(());
+ }
+
+ if field.value().is_none() {
+ let code = BibCode::ExpectingFieldValue;
+ results.push(Diagnostic {
+ severity: DiagnosticSeverity::ERROR,
+ range: line_index.line_col_lsp_range(field.name_token()?.text_range()),
+ code: DiagnosticCode::Bib(code),
+ message: String::from(code),
+ });
+
+ return Some(());
+ }
+
+ Some(())
+}
diff --git a/support/texlab/src/db/diagnostics/log.rs b/support/texlab/src/db/diagnostics/log.rs
new file mode 100644
index 0000000000..436999259b
--- /dev/null
+++ b/support/texlab/src/db/diagnostics/log.rs
@@ -0,0 +1,100 @@
+use lsp_types::{DiagnosticSeverity, Position, Range, Url};
+use rowan::{TextLen, TextRange, TextSize};
+use rustc_hash::FxHashMap;
+
+use crate::{
+ db::{document::Document, workspace::Workspace},
+ syntax::{BuildError, BuildErrorLevel},
+ util::line_index_ext::LineIndexExt,
+ Db,
+};
+
+use super::{Diagnostic, DiagnosticCode};
+
+#[salsa::tracked(return_ref)]
+pub fn collect(
+ db: &dyn Db,
+ workspace: Workspace,
+ log_document: Document,
+) -> FxHashMap<Document, Vec<Diagnostic>> {
+ let mut results = FxHashMap::default();
+
+ let log = match log_document.parse(db).as_log() {
+ Some(data) => data.log(db),
+ None => return results,
+ };
+
+ let root_document = match workspace.parents(db, log_document).iter().next().copied() {
+ Some(document) => document,
+ None => return results,
+ };
+
+ let base_path = match root_document
+ .location(db)
+ .path(db)
+ .as_deref()
+ .and_then(|path| path.parent())
+ {
+ Some(path) => path,
+ None => return results,
+ };
+
+ for error in &log.errors {
+ let full_path = base_path.join(&error.relative_path);
+ let full_path_uri = if let Ok(uri) = Url::from_file_path(&full_path) {
+ uri
+ } else {
+ continue;
+ };
+
+ let severity = match error.level {
+ BuildErrorLevel::Error => DiagnosticSeverity::ERROR,
+ BuildErrorLevel::Warning => DiagnosticSeverity::WARNING,
+ };
+
+ let range = find_range_of_hint(db, workspace, &full_path_uri, error).unwrap_or_else(|| {
+ let line = error.line.unwrap_or(0);
+ Range::new(Position::new(line, 0), Position::new(line, 0))
+ });
+
+ let diagnostic = Diagnostic {
+ severity,
+ range,
+ code: DiagnosticCode::Log(log_document),
+ message: error.message.clone(),
+ };
+
+ let tex_document = workspace
+ .lookup_uri(db, &full_path_uri)
+ .unwrap_or(root_document);
+
+ results.entry(tex_document).or_default().push(diagnostic);
+ }
+
+ results
+}
+
+fn find_range_of_hint(
+ db: &dyn Db,
+ workspace: Workspace,
+ uri: &Url,
+ error: &BuildError,
+) -> Option<Range> {
+ let document = workspace.lookup_uri(db, uri)?;
+ let text = document.contents(db).text(db);
+ let line = error.line? as usize;
+ let hint = error.hint.as_deref()?;
+ let line_index = document.contents(db).line_index(db);
+
+ let line_start = line_index.newlines.get(line).copied()?;
+ let line_end = line_index
+ .newlines
+ .get(line + 1)
+ .copied()
+ .unwrap_or(text.text_len());
+
+ let line_text = &text[line_start.into()..line_end.into()];
+ let hint_start = line_start + TextSize::try_from(line_text.find(hint)?).unwrap();
+ let hint_end = hint_start + hint.text_len();
+ Some(line_index.line_col_lsp_range(TextRange::new(hint_start, hint_end)))
+}
diff --git a/support/texlab/src/db/diagnostics/tex.rs b/support/texlab/src/db/diagnostics/tex.rs
new file mode 100644
index 0000000000..50233f8bd6
--- /dev/null
+++ b/support/texlab/src/db/diagnostics/tex.rs
@@ -0,0 +1,125 @@
+use lsp_types::DiagnosticSeverity;
+use rowan::{ast::AstNode, NodeOrToken, TextRange};
+
+use crate::{db::document::Document, syntax::latex, util::line_index_ext::LineIndexExt, Db};
+
+use super::{Diagnostic, DiagnosticCode, TexCode};
+
+#[salsa::tracked(return_ref)]
+pub fn collect(db: &dyn Db, document: Document) -> Vec<Diagnostic> {
+ let mut results = Vec::new();
+
+ if !document.location(db).uri(db).as_str().ends_with(".tex") {
+ return results;
+ }
+
+ let data = match document.parse(db).as_tex() {
+ Some(data) => data,
+ None => return results,
+ };
+
+ for node in data.root(db).descendants() {
+ analyze_environment(db, document, node.clone(), &mut results)
+ .or_else(|| analyze_curly_group(db, document, node.clone(), &mut results))
+ .or_else(|| analyze_curly_braces(document, db, node, &mut results));
+ }
+
+ results
+}
+
+fn analyze_environment(
+ db: &dyn Db,
+ document: Document,
+ node: latex::SyntaxNode,
+ results: &mut Vec<Diagnostic>,
+) -> Option<()> {
+ let environment = latex::Environment::cast(node)?;
+ let name1 = environment.begin()?.name()?.key()?;
+ let name2 = environment.end()?.name()?.key()?;
+ if name1 != name2 {
+ let code = TexCode::MismatchedEnvironment;
+ results.push(Diagnostic {
+ severity: DiagnosticSeverity::ERROR,
+ range: document
+ .contents(db)
+ .line_index(db)
+ .line_col_lsp_range(latex::small_range(&name1)),
+ code: DiagnosticCode::Tex(code),
+ message: String::from(code),
+ });
+ }
+
+ Some(())
+}
+
+fn analyze_curly_group(
+ db: &dyn Db,
+ document: Document,
+ node: latex::SyntaxNode,
+ results: &mut Vec<Diagnostic>,
+) -> Option<()> {
+ if !matches!(
+ node.kind(),
+ latex::CURLY_GROUP
+ | latex::CURLY_GROUP_COMMAND
+ | latex::CURLY_GROUP_KEY_VALUE
+ | latex::CURLY_GROUP_WORD
+ | latex::CURLY_GROUP_WORD_LIST
+ ) {
+ return None;
+ }
+
+ let is_inside_verbatim_environment = node
+ .ancestors()
+ .filter_map(latex::Environment::cast)
+ .filter_map(|env| env.begin())
+ .filter_map(|begin| begin.name())
+ .filter_map(|name| name.key())
+ .any(|name| {
+ ["asy", "lstlisting", "minted", "verbatim"].contains(&name.to_string().as_str())
+ });
+
+ if !is_inside_verbatim_environment
+ && !node
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .any(|token| token.kind() == latex::R_CURLY)
+ {
+ let code = TexCode::RCurlyInserted;
+ results.push(Diagnostic {
+ severity: DiagnosticSeverity::ERROR,
+ range: document
+ .contents(db)
+ .line_index(db)
+ .line_col_lsp_range(TextRange::empty(node.text_range().end())),
+ code: DiagnosticCode::Tex(code),
+ message: String::from(code),
+ });
+ }
+
+ Some(())
+}
+
+fn analyze_curly_braces(
+ document: Document,
+ db: &dyn Db,
+ node: rowan::SyntaxNode<latex::LatexLanguage>,
+ results: &mut Vec<Diagnostic>,
+) -> Option<()> {
+ if node.kind() == latex::ERROR && node.first_token()?.text() == "}" {
+ let code = TexCode::UnexpectedRCurly;
+ results.push(Diagnostic {
+ severity: DiagnosticSeverity::ERROR,
+ range: document
+ .contents(db)
+ .line_index(db)
+ .line_col_lsp_range(node.text_range()),
+ code: DiagnosticCode::Tex(code),
+ message: String::from(code),
+ });
+
+ Some(())
+ } else {
+ None
+ }
+}
diff --git a/support/texlab/src/db/discovery.rs b/support/texlab/src/db/discovery.rs
new file mode 100644
index 0000000000..0e1ec314f7
--- /dev/null
+++ b/support/texlab/src/db/discovery.rs
@@ -0,0 +1,251 @@
+use std::path::Path;
+
+use itertools::Itertools;
+use lsp_types::Url;
+use rustc_hash::FxHashSet;
+
+use crate::{util::HOME_DIR, Db};
+
+use super::{
+ analysis::TexLink,
+ document::{Document, Language, Location, Owner},
+ workspace::Workspace,
+};
+
+#[salsa::accumulator]
+pub struct MissingDependencies(MissingDependency);
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+pub struct MissingDependency {
+ pub location: Location,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+pub struct Dependency {
+ pub source: Document,
+ pub target: Document,
+ pub origin: Option<DependencyOrigin>,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+pub struct DependencyOrigin {
+ pub link: TexLink,
+ pub old_base_dir: Location,
+ pub new_base_dir: Location,
+}
+
+pub fn hidden_dependencies(
+ db: &dyn Db,
+ document: Document,
+ base_dir: Location,
+ dependencies: &mut Vec<Dependency>,
+) {
+ dependencies.extend(hidden_dependency(db, document, base_dir, "log"));
+ dependencies.extend(hidden_dependency(db, document, base_dir, "aux"));
+}
+
+#[salsa::tracked]
+pub fn hidden_dependency(
+ db: &dyn Db,
+ source: Document,
+ base_dir: Location,
+ extension: &'static str,
+) -> Option<Dependency> {
+ let workspace = Workspace::get(db);
+
+ let stem = source.location(db).stem(db)?;
+ let name = format!("{stem}.{extension}");
+
+ let location = workspace.output_dir(db, base_dir).join(db, &name)?;
+ match workspace.lookup(db, location) {
+ Some(target) => Some(Dependency {
+ source,
+ target,
+ origin: None,
+ }),
+ None => {
+ MissingDependencies::push(db, MissingDependency { location });
+ None
+ }
+ }
+}
+
+pub fn source_dependencies<'db>(
+ db: &'db dyn Db,
+ source: Document,
+ base_dir: Location,
+) -> impl Iterator<Item = Dependency> + 'db {
+ source
+ .parse(db)
+ .as_tex()
+ .into_iter()
+ .flat_map(|data| data.analyze(db).links(db))
+ .filter_map(move |link| source_dependency(db, source, base_dir, *link))
+}
+
+#[salsa::tracked]
+pub fn source_dependency(
+ db: &dyn Db,
+ source: Document,
+ base_dir: Location,
+ link: TexLink,
+) -> Option<Dependency> {
+ let workspace = Workspace::get(db);
+
+ let stem = link.path(db).text(db);
+
+ let mut file_names = vec![stem.clone()];
+ link.kind(db)
+ .extensions()
+ .iter()
+ .map(|ext| format!("{stem}.{ext}"))
+ .for_each(|name| file_names.push(name));
+
+ let file_name_db = workspace.file_name_db(db);
+ let distro_files = file_names
+ .iter()
+ .filter_map(|name| file_name_db.get(name))
+ .filter(|path| {
+ HOME_DIR
+ .as_deref()
+ .map_or(false, |dir| path.starts_with(dir))
+ })
+ .flat_map(|path| Url::from_file_path(path))
+ .map(|uri| Location::new(db, uri));
+
+ for location in file_names
+ .iter()
+ .filter_map(|file_name| base_dir.join(db, &file_name))
+ .chain(distro_files)
+ {
+ match workspace.lookup(db, location) {
+ Some(target) => {
+ let origin = Some(DependencyOrigin {
+ link,
+ old_base_dir: base_dir,
+ new_base_dir: link
+ .base_dir(db)
+ .and_then(|path| base_dir.join(db, path.text(db)))
+ .unwrap_or(base_dir),
+ });
+
+ return Some(Dependency {
+ source,
+ target,
+ origin,
+ });
+ }
+ None => {
+ MissingDependencies::push(db, MissingDependency { location });
+ }
+ };
+ }
+
+ None
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+pub struct DependencyGraph {
+ pub start: Document,
+ pub edges: Vec<Dependency>,
+}
+
+impl DependencyGraph {
+ pub fn preorder(&self) -> impl DoubleEndedIterator<Item = Document> + '_ {
+ std::iter::once(self.start)
+ .chain(self.edges.iter().map(|group| group.target))
+ .unique()
+ }
+}
+
+#[salsa::tracked]
+pub fn dependency_graph(db: &dyn Db, start: Document) -> DependencyGraph {
+ let workspace = Workspace::get(db);
+
+ let base_dir = workspace.working_dir(db, start.directory(db));
+ let mut edges = Vec::new();
+ let mut stack = vec![(start, base_dir)];
+ let mut visited = FxHashSet::default();
+
+ while let Some((source, base_dir)) = stack.pop() {
+ for edge in source_dependencies(db, source, base_dir) {
+ edges.push(edge);
+ if visited.insert(edge.target) {
+ stack.push((edge.target, edge.origin.unwrap().new_base_dir));
+ }
+ }
+
+ hidden_dependencies(db, source, base_dir, &mut edges);
+ }
+
+ DependencyGraph { start, edges }
+}
+
+pub fn discover_dependencies(db: &mut dyn Db) {
+ let workspace = Workspace::get(db);
+ loop {
+ let mut changed = discover_parents(db, workspace);
+
+ let paths: FxHashSet<_> = workspace
+ .documents(db)
+ .iter()
+ .flat_map(|&start| dependency_graph::accumulated::<MissingDependencies>(db, start))
+ .filter_map(|link| link.location.path(db).as_deref())
+ .filter(|path| path.is_file())
+ .map(Path::to_path_buf)
+ .collect();
+
+ for path in paths {
+ if workspace.lookup_path(db, &path).is_none() {
+ let language = Language::from_path(&path).unwrap_or(Language::Tex);
+ changed |= workspace.load(db, &path, language, Owner::Server).is_some();
+ }
+ }
+
+ if !changed {
+ break;
+ }
+ }
+}
+
+fn discover_parents(db: &mut dyn Db, workspace: Workspace) -> bool {
+ let mut changed = false;
+
+ let dirs: FxHashSet<_> = workspace
+ .documents(db)
+ .iter()
+ .flat_map(|document| document.ancestor_dirs(db))
+ .filter(|path| is_part_of_workspace(db, workspace, path))
+ .map(Path::to_path_buf)
+ .collect();
+
+ for path in dirs
+ .iter()
+ .flat_map(std::fs::read_dir)
+ .flatten()
+ .flatten()
+ .filter(|entry| entry.file_type().map_or(false, |ty| ty.is_file()))
+ .map(|entry| entry.path())
+ .filter(|path| Language::from_path(&path) == Some(Language::Tex))
+ {
+ if workspace.lookup_path(db, &path).is_none() {
+ changed |= workspace
+ .load(db, &path, Language::Tex, Owner::Server)
+ .is_some();
+ }
+ }
+
+ changed
+}
+
+fn is_part_of_workspace(db: &dyn Db, workspace: Workspace, path: &Path) -> bool {
+ let root_dirs = workspace.root_dirs(db);
+ if root_dirs.is_empty() {
+ return true;
+ }
+
+ root_dirs
+ .iter()
+ .filter_map(|dir| dir.path(db).as_deref())
+ .any(|dir| path.starts_with(dir))
+}
diff --git a/support/texlab/src/db/document.rs b/support/texlab/src/db/document.rs
new file mode 100644
index 0000000000..186bd06ab3
--- /dev/null
+++ b/support/texlab/src/db/document.rs
@@ -0,0 +1,193 @@
+use std::{
+ ffi::OsStr,
+ path::{Path, PathBuf},
+};
+
+use lsp_types::Url;
+use rowan::{TextRange, TextSize};
+
+use crate::{
+ db::{
+ diagnostics::Diagnostic,
+ parse::{BibDocumentData, LogDocumentData, TexDocumentData},
+ },
+ parser::{parse_bibtex, parse_build_log, parse_latex},
+ util::line_index::LineIndex,
+ Db,
+};
+
+use super::{
+ analysis::TexLinkKind,
+ parse::{self, DocumentData},
+};
+
+#[salsa::interned]
+pub struct Location {
+ #[return_ref]
+ pub uri: Url,
+}
+
+#[salsa::tracked]
+impl Location {
+ #[salsa::tracked(return_ref)]
+ pub fn path(self, db: &dyn Db) -> Option<PathBuf> {
+ let uri = self.uri(db);
+ if uri.scheme() == "file" {
+ uri.to_file_path().ok()
+ } else {
+ None
+ }
+ }
+
+ pub fn stem<'db>(self, db: &'db dyn Db) -> Option<&'db str> {
+ let name = self.uri(db).path_segments()?.last()?;
+ let stem = name.rsplit_once('.').map_or(name, |(stem, _)| stem);
+ Some(stem)
+ }
+
+ pub fn join(self, db: &dyn Db, path: &str) -> Option<Location> {
+ let uri = self.uri(db).join(path).ok()?;
+ Some(Location::new(db, uri))
+ }
+
+ pub fn into_dir(self, db: &dyn Db) -> Location {
+ if self.uri(db).path().ends_with("/") {
+ self.join(db, ".").unwrap()
+ } else {
+ self
+ }
+ }
+}
+
+#[salsa::input]
+pub struct Contents {
+ #[return_ref]
+ pub text: String,
+}
+
+#[salsa::tracked]
+impl Contents {
+ #[salsa::tracked(return_ref)]
+ pub fn line_index(self, db: &dyn Db) -> LineIndex {
+ LineIndex::new(self.text(db))
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+pub enum Owner {
+ Client,
+ Server,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+pub enum Language {
+ Tex,
+ Bib,
+ Log,
+}
+
+impl Language {
+ pub fn from_path(path: &Path) -> Option<Self> {
+ path.extension()
+ .and_then(OsStr::to_str)
+ .and_then(Self::from_extension)
+ }
+
+ pub fn from_extension(extension: &str) -> Option<Self> {
+ match extension.to_lowercase().as_str() {
+ "tex" | "sty" | "cls" | "def" | "lco" | "aux" | "rnw" => Some(Self::Tex),
+ "bib" | "bibtex" => Some(Self::Bib),
+ "log" => Some(Self::Log),
+ _ => None,
+ }
+ }
+
+ pub fn from_id(id: &str) -> Option<Self> {
+ match id {
+ "tex" | "latex" => Some(Self::Tex),
+ "bib" | "bibtex" => Some(Self::Bib),
+ _ => None,
+ }
+ }
+}
+
+#[salsa::input]
+pub struct LinterData {
+ #[return_ref]
+ pub chktex: Vec<Diagnostic>,
+}
+
+#[salsa::input]
+pub struct Document {
+ pub location: Location,
+ pub contents: Contents,
+ pub language: Language,
+ pub owner: Owner,
+ pub cursor: TextSize,
+ pub linter: LinterData,
+}
+
+impl Document {
+ pub fn edit(self, db: &mut dyn Db, range: TextRange, replace_with: &str) {
+ let mut text = self.contents(db).set_text(db).to(String::new());
+ text.replace_range(std::ops::Range::<usize>::from(range), &replace_with);
+ self.contents(db).set_text(db).to(text);
+ self.set_cursor(db).to(range.start());
+ }
+
+ pub fn directory(self, db: &dyn Db) -> Location {
+ self.location(db).into_dir(db)
+ }
+
+ pub fn ancestor_dirs<'db>(self, db: &'db dyn Db) -> impl Iterator<Item = &'db Path> + 'db {
+ self.location(db)
+ .path(db)
+ .as_deref()
+ .into_iter()
+ .flat_map(|path| path.ancestors())
+ .skip(1)
+ }
+}
+
+#[salsa::tracked]
+impl Document {
+ #[salsa::tracked]
+ pub fn parse(self, db: &dyn Db) -> DocumentData {
+ let text = self.contents(db).text(db);
+ match self.language(db) {
+ Language::Tex => {
+ let data = TexDocumentData::new(db, parse_latex(text));
+ parse::DocumentData::Tex(data)
+ }
+ Language::Bib => {
+ let data = BibDocumentData::new(db, parse_bibtex(text));
+ DocumentData::Bib(data)
+ }
+ Language::Log => {
+ let data = LogDocumentData::new(db, parse_build_log(text));
+ DocumentData::Log(data)
+ }
+ }
+ }
+
+ #[salsa::tracked]
+ pub fn can_be_index(self, db: &dyn Db) -> bool {
+ self.parse(db).as_tex().map_or(false, |data| {
+ data.analyze(db)
+ .links(db)
+ .iter()
+ .filter(|link| link.kind(db) == TexLinkKind::Cls)
+ .any(|link| link.path(db).text(db) != "subfiles")
+ })
+ }
+
+ #[salsa::tracked]
+ pub fn can_be_built(self, db: &dyn Db) -> bool {
+ self.parse(db).as_tex().map_or(false, |data| {
+ data.analyze(db)
+ .links(db)
+ .iter()
+ .any(|link| link.kind(db) == TexLinkKind::Cls)
+ })
+ }
+}
diff --git a/support/texlab/src/db/parse.rs b/support/texlab/src/db/parse.rs
new file mode 100644
index 0000000000..d532c536a3
--- /dev/null
+++ b/support/texlab/src/db/parse.rs
@@ -0,0 +1,71 @@
+use crate::{
+ db::analysis::TexAnalysis,
+ syntax::{bibtex, latex, BuildLog},
+ Db,
+};
+
+#[salsa::interned]
+pub struct TexDocumentData {
+ pub green: rowan::GreenNode,
+}
+
+impl TexDocumentData {
+ pub fn root(self, db: &dyn Db) -> latex::SyntaxNode {
+ latex::SyntaxNode::new_root(self.green(db))
+ }
+}
+
+#[salsa::tracked]
+impl TexDocumentData {
+ #[salsa::tracked]
+ pub fn analyze(self, db: &dyn Db) -> TexAnalysis {
+ let root = latex::SyntaxNode::new_root(self.green(db));
+ TexAnalysis::analyze(db, &root)
+ }
+}
+
+#[salsa::interned]
+pub struct BibDocumentData {
+ pub green: rowan::GreenNode,
+}
+
+impl BibDocumentData {
+ pub fn root(self, db: &dyn Db) -> bibtex::SyntaxNode {
+ bibtex::SyntaxNode::new_root(self.green(db))
+ }
+}
+
+#[salsa::interned]
+pub struct LogDocumentData {
+ pub log: BuildLog,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+pub enum DocumentData {
+ Tex(TexDocumentData),
+ Bib(BibDocumentData),
+ Log(LogDocumentData),
+}
+
+impl DocumentData {
+ pub fn as_tex(self) -> Option<TexDocumentData> {
+ match self {
+ Self::Tex(data) => Some(data),
+ _ => None,
+ }
+ }
+
+ pub fn as_bib(self) -> Option<BibDocumentData> {
+ match self {
+ Self::Bib(data) => Some(data),
+ _ => None,
+ }
+ }
+
+ pub fn as_log(self) -> Option<LogDocumentData> {
+ match self {
+ Self::Log(data) => Some(data),
+ _ => None,
+ }
+ }
+}
diff --git a/support/texlab/src/db/workspace.rs b/support/texlab/src/db/workspace.rs
new file mode 100644
index 0000000000..b8bdb27f1f
--- /dev/null
+++ b/support/texlab/src/db/workspace.rs
@@ -0,0 +1,245 @@
+use std::{
+ borrow::Cow,
+ path::{Path, PathBuf},
+};
+
+use itertools::Itertools;
+use lsp_types::{ClientCapabilities, ClientInfo, Url};
+use rowan::TextSize;
+use rustc_hash::FxHashSet;
+
+use crate::{
+ db::document::{Document, Location},
+ distro::FileNameDB,
+ util::HOME_DIR,
+ Db, Options,
+};
+
+use super::{
+ dependency_graph,
+ document::{Contents, Language, LinterData, Owner},
+ Word,
+};
+
+#[salsa::input(singleton)]
+pub struct Workspace {
+ #[return_ref]
+ pub documents: FxHashSet<Document>,
+
+ #[return_ref]
+ pub options: Options,
+
+ #[return_ref]
+ pub client_capabilities: ClientCapabilities,
+
+ #[return_ref]
+ pub client_info: Option<ClientInfo>,
+
+ #[return_ref]
+ pub root_dirs: Vec<Location>,
+
+ #[return_ref]
+ pub file_name_db: FileNameDB,
+}
+
+impl Workspace {
+ pub fn lookup(self, db: &dyn Db, location: Location) -> Option<Document> {
+ self.documents(db)
+ .iter()
+ .find(|document| document.location(db) == location)
+ .copied()
+ }
+
+ pub fn lookup_uri(self, db: &dyn Db, uri: &Url) -> Option<Document> {
+ self.documents(db)
+ .iter()
+ .find(|document| document.location(db).uri(db) == uri)
+ .copied()
+ }
+
+ pub fn lookup_path(self, db: &dyn Db, path: &Path) -> Option<Document> {
+ self.documents(db)
+ .iter()
+ .find(|document| document.location(db).path(db).as_deref() == Some(path))
+ .copied()
+ }
+
+ pub fn index_files<'db>(self, db: &'db dyn Db) -> impl Iterator<Item = Document> + 'db {
+ self.documents(db)
+ .iter()
+ .copied()
+ .filter(|&document| document.can_be_index(db))
+ }
+
+ pub fn open(
+ self,
+ db: &mut dyn Db,
+ uri: Url,
+ text: String,
+ language: Language,
+ owner: Owner,
+ ) -> Document {
+ let location = Location::new(db, uri);
+ let contents = Contents::new(db, text);
+ let cursor = TextSize::from(0);
+ match self.lookup(db, location) {
+ Some(document) => {
+ document.set_contents(db).to(contents);
+ document.set_language(db).to(language);
+ document.set_owner(db).to(owner);
+ document.set_cursor(db).to(cursor);
+ document
+ }
+ None => {
+ let document = Document::new(
+ db,
+ location,
+ contents,
+ language,
+ owner,
+ cursor,
+ LinterData::new(db, Vec::new()),
+ );
+
+ let mut documents = self.set_documents(db).to(FxHashSet::default());
+ documents.insert(document);
+ self.set_documents(db).to(documents);
+ document
+ }
+ }
+ }
+
+ pub fn load(
+ self,
+ db: &mut dyn Db,
+ path: &Path,
+ language: Language,
+ owner: Owner,
+ ) -> Option<Document> {
+ log::debug!("Loading document {} from disk...", path.display());
+
+ let uri = Url::from_file_path(path).ok()?;
+ let data = std::fs::read(path).ok()?;
+ let text = match String::from_utf8_lossy(&data) {
+ Cow::Borrowed(_) => unsafe { String::from_utf8_unchecked(data) },
+ Cow::Owned(text) => text,
+ };
+
+ Some(self.open(db, uri, text, language, owner))
+ }
+
+ pub fn watch(
+ self,
+ db: &dyn Db,
+ watcher: &mut dyn notify::Watcher,
+ watched_dirs: &mut FxHashSet<PathBuf>,
+ ) {
+ let output_dirs = self
+ .documents(db)
+ .iter()
+ .map(|document| self.working_dir(db, document.directory(db)))
+ .map(|base_dir| self.output_dir(db, base_dir))
+ .filter_map(|location| location.path(db).as_deref());
+
+ self.documents(db)
+ .iter()
+ .map(|document| document.location(db))
+ .filter_map(|location| location.path(db).as_deref())
+ .filter_map(|path| path.parent())
+ .chain(output_dirs)
+ .filter(|path| watched_dirs.insert(path.to_path_buf()))
+ .for_each(|path| {
+ let _ = watcher.watch(path, notify::RecursiveMode::NonRecursive);
+ });
+ }
+}
+
+const SPECIAL_ENTRIES: &[&str] = &[
+ ".git",
+ "Tectonic.toml",
+ ".latexmkrc",
+ "latexmkrc",
+ ".chktexrc",
+ "chktexrc",
+];
+
+#[salsa::tracked]
+impl Workspace {
+ #[salsa::tracked]
+ pub fn working_dir(self, db: &dyn Db, base_dir: Location) -> Location {
+ let mut path = self
+ .options(db)
+ .root_directory
+ .as_deref()
+ .and_then(|path| path.to_str())
+ .or_else(|| {
+ for dir in base_dir
+ .path(db)
+ .as_deref()?
+ .ancestors()
+ .skip(1)
+ .filter(|path| Some(*path) != HOME_DIR.as_deref())
+ {
+ for name in SPECIAL_ENTRIES {
+ if dir.join(name).exists() {
+ return Some(dir.to_str()?);
+ }
+ }
+ }
+
+ None
+ })
+ .unwrap_or(".")
+ .to_string();
+
+ if !path.ends_with(".") {
+ path.push('/');
+ }
+
+ base_dir.join(db, &path).unwrap_or(base_dir)
+ }
+
+ #[salsa::tracked]
+ pub fn output_dir(self, db: &dyn Db, base_dir: Location) -> Location {
+ let mut path = self
+ .options(db)
+ .aux_directory
+ .as_deref()
+ .and_then(|path| path.to_str())
+ .unwrap_or(".")
+ .to_string();
+
+ if !path.ends_with("/") {
+ path.push('/');
+ }
+
+ base_dir.join(db, &path).unwrap_or(base_dir)
+ }
+
+ #[salsa::tracked(return_ref)]
+ pub fn parents(self, db: &dyn Db, child: Document) -> Vec<Document> {
+ self.index_files(db)
+ .filter(|&parent| dependency_graph(db, parent).preorder().contains(&child))
+ .collect()
+ }
+
+ #[salsa::tracked(return_ref)]
+ pub fn related(self, db: &dyn Db, child: Document) -> FxHashSet<Document> {
+ self.index_files(db)
+ .chain(self.documents(db).iter().copied())
+ .map(|start| dependency_graph(db, start).preorder().collect_vec())
+ .filter(|project| project.contains(&child))
+ .flatten()
+ .collect()
+ }
+
+ #[salsa::tracked]
+ pub fn number_of_label(self, db: &dyn Db, child: Document, name: Word) -> Option<Word> {
+ self.related(db, child)
+ .iter()
+ .filter_map(|document| document.parse(db).as_tex())
+ .flat_map(|data| data.analyze(db).label_numbers(db))
+ .find(|number| number.name(db) == name)
+ .map(|number| number.text(db))
+ }
+}
diff --git a/support/texlab/src/debouncer.rs b/support/texlab/src/debouncer.rs
deleted file mode 100644
index b123dfc433..0000000000
--- a/support/texlab/src/debouncer.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use std::time::{Duration, Instant};
-
-use anyhow::Result;
-
-pub struct Sender<T> {
- tx: crossbeam_channel::Sender<(T, crossbeam_channel::Receiver<Instant>)>,
-}
-
-impl<T> Clone for Sender<T> {
- fn clone(&self) -> Self {
- Self {
- tx: self.tx.clone(),
- }
- }
-}
-
-impl<T> Sender<T>
-where
- T: Send + Sync + 'static,
-{
- pub fn send(&self, msg: T, delay: Duration) -> Result<()> {
- self.tx.send((msg, crossbeam_channel::after(delay)))?;
- Ok(())
- }
-}
-
-pub struct Receiver<T> {
- rx: crossbeam_channel::Receiver<(T, crossbeam_channel::Receiver<Instant>)>,
-}
-
-impl<T> Clone for Receiver<T> {
- fn clone(&self) -> Self {
- Self {
- rx: self.rx.clone(),
- }
- }
-}
-
-impl<T> Receiver<T> {
- pub fn recv(&self) -> Result<T> {
- let (mut last_msg, delay) = self.rx.recv()?;
- delay.recv()?;
- while let Ok((msg, delay)) = self.rx.try_recv() {
- delay.recv()?;
- last_msg = msg;
- }
-
- Ok(last_msg)
- }
-}
-
-pub fn unbounded<T>() -> (Sender<T>, Receiver<T>) {
- let (tx, rx) = crossbeam_channel::unbounded();
- (Sender { tx }, Receiver { rx })
-}
diff --git a/support/texlab/src/diagnostics.rs b/support/texlab/src/diagnostics.rs
deleted file mode 100644
index bdd8faf106..0000000000
--- a/support/texlab/src/diagnostics.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-mod bibtex;
-mod build;
-mod chktex;
-mod latex;
-
-use std::sync::Arc;
-
-use dashmap::DashMap;
-use lsp_types::{DiagnosticSeverity, NumberOrString, Range, Url};
-use regex::Regex;
-
-use crate::Workspace;
-
-use self::{
- bibtex::collect_bibtex_diagnostics, build::collect_build_diagnostics,
- chktex::collect_chktex_diagnostics, latex::collect_latex_diagnostics,
-};
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct Diagnostic {
- pub severity: DiagnosticSeverity,
- pub range: Range,
- pub code: DiagnosticCode,
- pub message: String,
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
-pub enum DiagnosticCode {
- Latex(LatexCode),
- Bibtex(BibtexCode),
- Chktex(String),
- Build(Arc<Url>),
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
-pub enum LatexCode {
- UnexpectedRCurly,
- RCurlyInserted,
- MismatchedEnvironment,
-}
-
-impl From<LatexCode> for String {
- fn from(code: LatexCode) -> Self {
- match code {
- LatexCode::UnexpectedRCurly => "Unexpected \"}\"".to_string(),
- LatexCode::RCurlyInserted => "Missing \"}\" inserted".to_string(),
- LatexCode::MismatchedEnvironment => "Mismatched environment".to_string(),
- }
- }
-}
-
-impl From<LatexCode> for NumberOrString {
- fn from(code: LatexCode) -> Self {
- match code {
- LatexCode::UnexpectedRCurly => NumberOrString::Number(1),
- LatexCode::RCurlyInserted => NumberOrString::Number(2),
- LatexCode::MismatchedEnvironment => NumberOrString::Number(3),
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
-#[allow(clippy::enum_variant_names)]
-pub enum BibtexCode {
- ExpectingLCurly,
- ExpectingKey,
- ExpectingRCurly,
- ExpectingEq,
- ExpectingFieldValue,
-}
-
-impl From<BibtexCode> for String {
- fn from(code: BibtexCode) -> Self {
- match code {
- BibtexCode::ExpectingLCurly => "Expecting a curly bracket: \"{\"".to_string(),
- BibtexCode::ExpectingKey => "Expecting a key".to_string(),
- BibtexCode::ExpectingRCurly => "Expecting a curly bracket: \"}\"".to_string(),
- BibtexCode::ExpectingEq => "Expecting an equality sign: \"=\"".to_string(),
- BibtexCode::ExpectingFieldValue => "Expecting a field value".to_string(),
- }
- }
-}
-
-impl From<BibtexCode> for NumberOrString {
- fn from(code: BibtexCode) -> Self {
- match code {
- BibtexCode::ExpectingLCurly => NumberOrString::Number(4),
- BibtexCode::ExpectingKey => NumberOrString::Number(5),
- BibtexCode::ExpectingRCurly => NumberOrString::Number(6),
- BibtexCode::ExpectingEq => NumberOrString::Number(7),
- BibtexCode::ExpectingFieldValue => NumberOrString::Number(8),
- }
- }
-}
-
-#[derive(Default, Clone)]
-pub struct DiagnosticManager {
- all_diagnostics: Arc<DashMap<Arc<Url>, Vec<Diagnostic>>>,
-}
-
-impl DiagnosticManager {
- pub fn push_syntax(&self, workspace: &Workspace, uri: &Url) {
- collect_bibtex_diagnostics(&self.all_diagnostics, workspace, uri)
- .or_else(|| collect_latex_diagnostics(&self.all_diagnostics, workspace, uri))
- .or_else(|| collect_build_diagnostics(&self.all_diagnostics, workspace, uri));
- }
-
- pub fn push_chktex(&self, workspace: &Workspace, uri: &Url) {
- collect_chktex_diagnostics(&self.all_diagnostics, workspace, uri);
- }
-
- pub fn publish(&self, workspace: &Workspace, uri: &Url) -> Vec<lsp_types::Diagnostic> {
- let options = &workspace.environment.options.diagnostics;
-
- let mut results = Vec::new();
- if let Some(diagnostics) = self.all_diagnostics.get(uri) {
- for diagnostic in diagnostics.iter() {
- if !options.allowed_patterns.is_empty()
- && !options
- .allowed_patterns
- .iter()
- .any(|pattern| pattern.0.is_match(&diagnostic.message))
- {
- continue;
- }
-
- if options
- .ignored_patterns
- .iter()
- .any(|pattern| pattern.0.is_match(&diagnostic.message))
- {
- continue;
- }
-
- let source = match diagnostic.code {
- DiagnosticCode::Latex(_) | DiagnosticCode::Bibtex(_) => "texlab",
- DiagnosticCode::Chktex(_) => "chktex",
- DiagnosticCode::Build(_) => "latex-build",
- };
-
- let code = match diagnostic.code.clone() {
- DiagnosticCode::Latex(code) => Some(code.into()),
- DiagnosticCode::Bibtex(code) => Some(code.into()),
- DiagnosticCode::Chktex(code) => Some(NumberOrString::String(code)),
- DiagnosticCode::Build(_) => None,
- };
-
- results.push(lsp_types::Diagnostic {
- range: diagnostic.range,
- code,
- severity: Some(diagnostic.severity),
- message: diagnostic.message.clone(),
- source: Some(source.to_string()),
- ..Default::default()
- });
- }
- }
-
- results
- }
-}
-
-#[derive(Debug, Default)]
-pub struct DiagnosticFilter {
- pub allowed_patterns: Vec<Regex>,
- pub ignored_patterns: Vec<Regex>,
-}
diff --git a/support/texlab/src/diagnostics/bibtex.rs b/support/texlab/src/diagnostics/bibtex.rs
deleted file mode 100644
index 42e215a794..0000000000
--- a/support/texlab/src/diagnostics/bibtex.rs
+++ /dev/null
@@ -1,139 +0,0 @@
-use std::sync::Arc;
-
-use dashmap::DashMap;
-use lsp_types::{DiagnosticSeverity, Url};
-use rowan::{ast::AstNode, TextRange};
-
-use crate::{
- syntax::bibtex::{self, HasDelims, HasEq, HasName, HasType, HasValue},
- Document, LineIndexExt, Workspace,
-};
-
-use super::{BibtexCode, Diagnostic, DiagnosticCode};
-
-pub fn collect_bibtex_diagnostics(
- all_diagnostics: &DashMap<Arc<Url>, Vec<Diagnostic>>,
- workspace: &Workspace,
- uri: &Url,
-) -> Option<()> {
- let document = workspace.documents_by_uri.get(uri)?;
- let data = document.data.as_bibtex()?;
-
- all_diagnostics.alter(uri, |_, mut diagnostics| {
- diagnostics.retain(|diag| !matches!(diag.code, DiagnosticCode::Bibtex(_)));
- diagnostics
- });
-
- let root = bibtex::SyntaxNode::new_root(data.green.clone());
- for node in root.descendants() {
- analyze_entry(all_diagnostics, document, node.clone())
- .or_else(|| analyze_field(all_diagnostics, document, node));
- }
-
- Some(())
-}
-
-fn analyze_entry(
- all_diagnostics: &DashMap<Arc<Url>, Vec<Diagnostic>>,
- document: &Document,
- node: bibtex::SyntaxNode,
-) -> Option<()> {
- let entry = bibtex::Entry::cast(node)?;
- if entry.left_delim_token().is_none() {
- let code = BibtexCode::ExpectingLCurly;
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .push(Diagnostic {
- severity: DiagnosticSeverity::ERROR,
- range: document
- .line_index
- .line_col_lsp_range(entry.type_token()?.text_range()),
- code: DiagnosticCode::Bibtex(code),
- message: String::from(code),
- });
-
- return Some(());
- }
-
- if entry.name_token().is_none() {
- let code = BibtexCode::ExpectingKey;
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .push(Diagnostic {
- severity: DiagnosticSeverity::ERROR,
- range: document
- .line_index
- .line_col_lsp_range(entry.left_delim_token()?.text_range()),
- code: DiagnosticCode::Bibtex(code),
- message: String::from(code),
- });
-
- return Some(());
- }
-
- if entry.right_delim_token().is_none() {
- let code = BibtexCode::ExpectingRCurly;
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .push(Diagnostic {
- severity: DiagnosticSeverity::ERROR,
- range: document
- .line_index
- .line_col_lsp_range(TextRange::empty(entry.syntax().text_range().end())),
- code: DiagnosticCode::Bibtex(code),
- message: String::from(code),
- });
-
- return Some(());
- }
-
- Some(())
-}
-
-fn analyze_field(
- all_diagnostics: &DashMap<Arc<Url>, Vec<Diagnostic>>,
- document: &Document,
- node: bibtex::SyntaxNode,
-) -> Option<()> {
- let field = bibtex::Field::cast(node)?;
- if field.eq_token().is_none() {
- let code = BibtexCode::ExpectingEq;
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .push(Diagnostic {
- severity: DiagnosticSeverity::ERROR,
- range: document
- .line_index
- .line_col_lsp_range(field.name_token()?.text_range()),
-
- code: DiagnosticCode::Bibtex(code),
- message: String::from(code),
- });
-
- return Some(());
- }
-
- if field.value().is_none() {
- let code = BibtexCode::ExpectingFieldValue;
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .push(Diagnostic {
- severity: DiagnosticSeverity::ERROR,
- range: document
- .line_index
- .line_col_lsp_range(field.name_token()?.text_range()),
-
- code: DiagnosticCode::Bibtex(code),
- message: String::from(code),
- });
-
- return Some(());
- }
-
- Some(())
-}
diff --git a/support/texlab/src/diagnostics/build.rs b/support/texlab/src/diagnostics/build.rs
deleted file mode 100644
index 4b4ffcc8b4..0000000000
--- a/support/texlab/src/diagnostics/build.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use std::{path::PathBuf, sync::Arc};
-
-use dashmap::DashMap;
-use lsp_types::{DiagnosticSeverity, Position, Range, Url};
-
-use crate::{syntax::build_log::BuildErrorLevel, Workspace};
-
-use super::{Diagnostic, DiagnosticCode};
-
-pub fn collect_build_diagnostics(
- all_diagnostics: &DashMap<Arc<Url>, Vec<Diagnostic>>,
- workspace: &Workspace,
- build_log_uri: &Url,
-) -> Option<()> {
- let build_log_document = workspace.documents_by_uri.get(build_log_uri)?;
- let build_log = build_log_document.data.as_build_log()?;
-
- all_diagnostics.alter_all(|_, mut diagnostics| {
- diagnostics.retain(
- |diag| !matches!(&diag.code, DiagnosticCode::Build(uri) if uri.as_ref() == build_log_uri),
- );
- diagnostics
- });
-
- let root_document = workspace.documents_by_uri.values().find(|document| {
- document.data.as_latex().map_or(false, |data| {
- !document.uri.as_str().ends_with(".aux")
- && data
- .extras
- .implicit_links
- .log
- .iter()
- .any(|u| u.as_ref() == build_log_uri)
- })
- })?;
-
- let base_path = PathBuf::from(root_document.uri.path());
- for error in &build_log.errors {
- let position = Position::new(error.line.unwrap_or(0), 0);
- let severity = match error.level {
- BuildErrorLevel::Error => DiagnosticSeverity::ERROR,
- BuildErrorLevel::Warning => DiagnosticSeverity::WARNING,
- };
- let range = Range::new(position, position);
- let diagnostic = Diagnostic {
- severity,
- range,
- code: DiagnosticCode::Build(Arc::clone(&build_log_document.uri)),
- message: error.message.clone(),
- };
-
- let full_path = base_path.join(&error.relative_path);
-
- let uri = if full_path.starts_with(&base_path) {
- error
- .relative_path
- .to_str()
- .and_then(|path| root_document.uri.join(path).map(Into::into).ok())
- .map_or_else(|| Arc::clone(&root_document.uri), Arc::new)
- } else {
- Arc::clone(&root_document.uri)
- };
-
- all_diagnostics.entry(uri).or_default().push(diagnostic);
- }
-
- Some(())
-}
diff --git a/support/texlab/src/diagnostics/chktex.rs b/support/texlab/src/diagnostics/chktex.rs
deleted file mode 100644
index ad676bd70d..0000000000
--- a/support/texlab/src/diagnostics/chktex.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use std::{
- fs, io,
- path::Path,
- process::{Command, Stdio},
- sync::Arc,
-};
-
-use dashmap::DashMap;
-use lsp_types::{DiagnosticSeverity, Range, Url};
-use once_cell::sync::Lazy;
-use regex::Regex;
-use tempfile::tempdir;
-
-use crate::{RangeExt, Workspace};
-
-use super::{Diagnostic, DiagnosticCode};
-
-pub fn collect_chktex_diagnostics(
- all_diagnostics: &DashMap<Arc<Url>, Vec<Diagnostic>>,
- workspace: &Workspace,
- uri: &Url,
-) -> Option<()> {
- let document = workspace.documents_by_uri.get(uri)?;
- document.data.as_latex()?;
-
- all_diagnostics.alter(uri, |_, mut diagnostics| {
- diagnostics.retain(|diag| !matches!(diag.code, DiagnosticCode::Chktex(_)));
- diagnostics
- });
-
- let current_dir = workspace
- .environment
- .options
- .root_directory
- .as_ref()
- .cloned()
- .or_else(|| {
- if document.uri.scheme() == "file" {
- document
- .uri
- .to_file_path()
- .unwrap()
- .parent()
- .map(ToOwned::to_owned)
- } else {
- None
- }
- })
- .unwrap_or_else(|| ".".into());
-
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .extend(lint(&document.text, &current_dir).unwrap_or_default());
-
- Some(())
-}
-
-static LINE_REGEX: Lazy<Regex> =
- Lazy::new(|| Regex::new("(\\d+):(\\d+):(\\d+):(\\w+):(\\w+):(.*)").unwrap());
-
-fn lint(text: &str, current_dir: &Path) -> io::Result<Vec<Diagnostic>> {
- let directory = tempdir()?;
- fs::write(directory.path().join("file.tex"), text)?;
- drop(fs::copy(
- current_dir.join("chktexrc"),
- directory.path().join("chktexrc"),
- ));
-
- let output = Command::new("chktex")
- .args(&["-I0", "-f%l:%c:%d:%k:%n:%m\n", "file.tex"])
- .stdin(Stdio::null())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .current_dir(directory.path())
- .output()?;
-
- let mut diagnostics = Vec::new();
- for line in String::from_utf8_lossy(&output.stdout).lines() {
- let captures = LINE_REGEX.captures(line).unwrap();
- let line = captures[1].parse::<u32>().unwrap() - 1;
- let character = captures[2].parse::<u32>().unwrap() - 1;
- let digit = captures[3].parse::<u32>().unwrap();
- let kind = &captures[4];
- let code = &captures[5];
- let message = captures[6].into();
- let range = Range::new_simple(line, character, line, character + digit);
- let severity = match kind {
- "Message" => DiagnosticSeverity::INFORMATION,
- "Warning" => DiagnosticSeverity::WARNING,
- _ => DiagnosticSeverity::ERROR,
- };
-
- diagnostics.push(Diagnostic {
- range,
- severity,
- code: DiagnosticCode::Chktex(code.into()),
- message,
- });
- }
-
- Ok(diagnostics)
-}
diff --git a/support/texlab/src/diagnostics/latex.rs b/support/texlab/src/diagnostics/latex.rs
deleted file mode 100644
index a17aab3f77..0000000000
--- a/support/texlab/src/diagnostics/latex.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use std::sync::Arc;
-
-use dashmap::DashMap;
-use lsp_types::{DiagnosticSeverity, Url};
-use rowan::{ast::AstNode, NodeOrToken, TextRange};
-
-use crate::{syntax::latex, Document, LineIndexExt, Workspace};
-
-use super::{Diagnostic, DiagnosticCode, LatexCode};
-
-pub fn collect_latex_diagnostics(
- all_diagnostics: &DashMap<Arc<Url>, Vec<Diagnostic>>,
- workspace: &Workspace,
- uri: &Url,
-) -> Option<()> {
- let document = workspace.documents_by_uri.get(uri)?;
- if !document.uri.as_str().ends_with(".tex") {
- return None;
- }
-
- let data = document.data.as_latex()?;
-
- all_diagnostics.alter(uri, |_, mut diagnostics| {
- diagnostics.retain(|diag| !matches!(diag.code, DiagnosticCode::Latex(_)));
- diagnostics
- });
-
- for node in latex::SyntaxNode::new_root(data.green.clone()).descendants() {
- analyze_environment(all_diagnostics, document, node.clone())
- .or_else(|| analyze_curly_group(all_diagnostics, document, &node))
- .or_else(|| {
- if node.kind() == latex::ERROR && node.first_token()?.text() == "}" {
- let code = LatexCode::UnexpectedRCurly;
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .push(Diagnostic {
- severity: DiagnosticSeverity::ERROR,
- range: document.line_index.line_col_lsp_range(node.text_range()),
- code: DiagnosticCode::Latex(code),
- message: String::from(code),
- });
-
- Some(())
- } else {
- None
- }
- });
- }
-
- Some(())
-}
-
-fn analyze_environment(
- all_diagnostics: &DashMap<Arc<Url>, Vec<Diagnostic>>,
- document: &Document,
- node: latex::SyntaxNode,
-) -> Option<()> {
- let environment = latex::Environment::cast(node)?;
- let name1 = environment.begin()?.name()?.key()?;
- let name2 = environment.end()?.name()?.key()?;
- if name1 != name2 {
- let code = LatexCode::MismatchedEnvironment;
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .push(Diagnostic {
- severity: DiagnosticSeverity::ERROR,
- range: document
- .line_index
- .line_col_lsp_range(latex::small_range(&name1)),
- code: DiagnosticCode::Latex(code),
- message: String::from(code),
- });
- }
- Some(())
-}
-
-fn analyze_curly_group(
- all_diagnostics: &DashMap<Arc<Url>, Vec<Diagnostic>>,
- document: &Document,
- node: &latex::SyntaxNode,
-) -> Option<()> {
- if !matches!(
- node.kind(),
- latex::CURLY_GROUP
- | latex::CURLY_GROUP_COMMAND
- | latex::CURLY_GROUP_KEY_VALUE
- | latex::CURLY_GROUP_WORD
- | latex::CURLY_GROUP_WORD_LIST
- ) {
- return None;
- }
-
- let is_inside_verbatim_environment = node
- .ancestors()
- .filter_map(latex::Environment::cast)
- .filter_map(|env| env.begin())
- .filter_map(|begin| begin.name())
- .filter_map(|name| name.key())
- .any(|name| {
- ["asy", "lstlisting", "minted", "verbatim"].contains(&name.to_string().as_str())
- });
-
- if !is_inside_verbatim_environment
- && !node
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .any(|token| token.kind() == latex::R_CURLY)
- {
- let code = LatexCode::RCurlyInserted;
- all_diagnostics
- .entry(Arc::clone(&document.uri))
- .or_default()
- .push(Diagnostic {
- severity: DiagnosticSeverity::ERROR,
- range: document
- .line_index
- .line_col_lsp_range(TextRange::empty(node.text_range().end())),
- code: DiagnosticCode::Latex(code),
- message: String::from(code),
- });
- }
-
- Some(())
-}
diff --git a/support/texlab/src/distro.rs b/support/texlab/src/distro.rs
index f869392366..759374da81 100644
--- a/support/texlab/src/distro.rs
+++ b/support/texlab/src/distro.rs
@@ -1,3 +1,4 @@
+mod file_name_db;
mod kpsewhich;
mod miktex;
mod texlive;
@@ -5,41 +6,40 @@ mod texlive;
use std::process::{Command, Stdio};
use anyhow::Result;
-use derive_more::Display;
-use log::warn;
-pub use kpsewhich::Resolver;
+pub use file_name_db::FileNameDB;
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Display)]
-pub enum DistributionKind {
- #[display(fmt = "TeXLive")]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum DistroKind {
Texlive,
- #[display(fmt = "MikTeX")]
Miktex,
- #[display(fmt = "Tectonic")]
Tectonic,
- #[display(fmt = "Unknown")]
Unknown,
}
-#[derive(Debug, Clone)]
-pub struct Distribution {
- pub kind: DistributionKind,
- pub resolver: Resolver,
+impl Default for DistroKind {
+ fn default() -> Self {
+ Self::Unknown
+ }
+}
+
+#[derive(Debug, Default)]
+pub struct Distro {
+ pub kind: DistroKind,
+ pub file_name_db: FileNameDB,
}
-impl Distribution {
- #[must_use]
- pub fn detect() -> Self {
+impl Distro {
+ pub fn detect() -> Result<Self> {
let kind = match Command::new("latex").arg("--version").output() {
Ok(output) => {
let stdout = String::from_utf8_lossy(&output.stdout);
if stdout.contains("TeX Live") {
- DistributionKind::Texlive
+ DistroKind::Texlive
} else if stdout.contains("MiKTeX") {
- DistributionKind::Miktex
+ DistroKind::Miktex
} else {
- DistributionKind::Unknown
+ DistroKind::Unknown
}
}
Err(_) => {
@@ -50,26 +50,25 @@ impl Distribution {
.status()
.is_ok()
{
- DistributionKind::Tectonic
+ DistroKind::Tectonic
} else {
- DistributionKind::Unknown
+ DistroKind::Unknown
}
}
};
- let resolver = match kind {
- DistributionKind::Texlive => Self::load_resolver(texlive::load_resolver),
- DistributionKind::Miktex => Self::load_resolver(miktex::load_resolver),
- DistributionKind::Tectonic | DistributionKind::Unknown => Resolver::default(),
+ let file_name_db = match kind {
+ DistroKind::Texlive => {
+ let root_dirs = kpsewhich::root_directories()?;
+ FileNameDB::parse(&root_dirs, &mut texlive::read_database)?
+ }
+ DistroKind::Miktex => {
+ let root_dirs = kpsewhich::root_directories()?;
+ FileNameDB::parse(&root_dirs, &mut miktex::read_database)?
+ }
+ DistroKind::Tectonic | DistroKind::Unknown => FileNameDB::default(),
};
- Self { kind, resolver }
- }
- fn load_resolver(loader: impl FnOnce() -> Result<Resolver>) -> Resolver {
- match loader() {
- Ok(resolver) => return resolver,
- Err(why) => warn!("Failed to load resolver: {}", why),
- };
- Resolver::default()
+ Ok(Self { kind, file_name_db })
}
}
diff --git a/support/texlab/src/distro/file_name_db.rs b/support/texlab/src/distro/file_name_db.rs
new file mode 100644
index 0000000000..9234d0a3f9
--- /dev/null
+++ b/support/texlab/src/distro/file_name_db.rs
@@ -0,0 +1,80 @@
+use std::{
+ borrow::Borrow,
+ path::{Path, PathBuf},
+};
+
+use anyhow::Result;
+use rustc_hash::FxHashSet;
+
+use crate::db::Language;
+
+#[derive(Debug)]
+pub struct DistroFile(PathBuf);
+
+impl DistroFile {
+ pub fn path(&self) -> &Path {
+ &self.0
+ }
+
+ pub fn name(&self) -> &str {
+ self.0.file_name().unwrap().to_str().unwrap()
+ }
+}
+
+impl PartialEq for DistroFile {
+ fn eq(&self, other: &Self) -> bool {
+ self.name() == other.name()
+ }
+}
+
+impl Eq for DistroFile {}
+
+impl std::hash::Hash for DistroFile {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.name().hash(state)
+ }
+}
+
+impl Borrow<str> for DistroFile {
+ fn borrow(&self) -> &str {
+ self.name()
+ }
+}
+
+#[derive(Debug, Default)]
+pub struct FileNameDB {
+ files: FxHashSet<DistroFile>,
+}
+
+impl FileNameDB {
+ pub fn get(&self, name: &str) -> Option<&Path> {
+ self.files.get(name).map(|file| file.path())
+ }
+
+ pub fn iter(&self) -> impl Iterator<Item = (&str, &Path)> + '_ {
+ self.files.iter().map(|file| (file.name(), file.path()))
+ }
+
+ pub fn parse(
+ root_dirs: &[PathBuf],
+ reader: &mut dyn FnMut(&Path) -> Result<Vec<PathBuf>>,
+ ) -> Result<Self> {
+ let files = root_dirs
+ .iter()
+ .flat_map(|dir| reader(dir))
+ .flatten()
+ .filter_map(|rel_path| {
+ Language::from_path(&rel_path)?;
+ rel_path.file_name()?.to_str()?;
+ let abs_path = root_dirs
+ .iter()
+ .rev()
+ .map(|dir| dir.join(&rel_path))
+ .find_map(|path| std::fs::canonicalize(path).ok())?;
+ Some(DistroFile(abs_path))
+ })
+ .collect();
+
+ Ok(Self { files })
+ }
+}
diff --git a/support/texlab/src/distro/kpsewhich.rs b/support/texlab/src/distro/kpsewhich.rs
index b14e64bf56..0a6d1d35ad 100644
--- a/support/texlab/src/distro/kpsewhich.rs
+++ b/support/texlab/src/distro/kpsewhich.rs
@@ -1,56 +1,6 @@
-use std::{
- env,
- ffi::OsStr,
- fs,
- path::{Path, PathBuf},
- process::Command,
-};
+use std::{env, ffi::OsStr, path::PathBuf, process::Command};
use anyhow::Result;
-use rustc_hash::FxHashMap;
-use smol_str::SmolStr;
-
-use crate::DocumentLanguage;
-
-#[derive(Debug, PartialEq, Eq, Clone, Default)]
-pub struct Resolver {
- pub files_by_name: FxHashMap<SmolStr, PathBuf>,
-}
-
-impl Resolver {
- #[must_use]
- pub fn new(files_by_name: FxHashMap<SmolStr, PathBuf>) -> Self {
- Self { files_by_name }
- }
-}
-
-pub fn parse_database(
- root_directories: &[PathBuf],
- mut reader: impl FnMut(&Path) -> Result<Vec<PathBuf>>,
-) -> Result<Resolver> {
- let mut files_by_name = FxHashMap::default();
- for directory in root_directories {
- for path in reader(directory)? {
- if DocumentLanguage::by_path(&path).is_some() {
- if let Some(path) = make_absolute(root_directories, &path) {
- if let Some(name) = path.file_name().and_then(OsStr::to_str).map(Into::into) {
- files_by_name.insert(name, path);
- }
- }
- }
- }
- }
- Ok(Resolver::new(files_by_name))
-}
-
-fn make_absolute(root_directories: &[PathBuf], relative_path: &Path) -> Option<PathBuf> {
- for dir in root_directories.iter().rev() {
- if let Ok(path) = fs::canonicalize(dir.join(&relative_path)) {
- return Some(path);
- }
- }
- None
-}
pub fn root_directories() -> Result<Vec<PathBuf>> {
let texmf = run(&["-var-value", "TEXMF"])?;
diff --git a/support/texlab/src/distro/miktex.rs b/support/texlab/src/distro/miktex.rs
index c7a92d572e..fc778752db 100644
--- a/support/texlab/src/distro/miktex.rs
+++ b/support/texlab/src/distro/miktex.rs
@@ -1,20 +1,11 @@
use std::{
ffi::OsStr,
fs,
- io::{self, Cursor},
+ io::{self, Cursor, Read},
path::{Path, PathBuf},
};
use anyhow::{Context, Result};
-use byteorder::{LittleEndian, ReadBytesExt};
-
-use super::kpsewhich::{self, Resolver};
-
-pub fn load_resolver() -> Result<Resolver> {
- let root_directories = kpsewhich::root_directories()?;
- let resolver = kpsewhich::parse_database(&root_directories, read_database)?;
- Ok(resolver)
-}
const DATABASE_PATH: &str = "miktex/data/le";
const FNDB_SIGNATURE: u32 = 0x42_44_4e_46;
@@ -23,7 +14,7 @@ const FNDB_TABLE_POINTER_OFFSET: u32 = 4 * FNDB_WORD_SIZE;
const FNDB_TABLE_SIZE_OFFSET: u32 = 6 * FNDB_WORD_SIZE;
const FNDB_ENTRY_SIZE: u32 = 4 * FNDB_WORD_SIZE;
-fn read_database(directory: &Path) -> Result<Vec<PathBuf>> {
+pub(super) fn read_database(directory: &Path) -> Result<Vec<PathBuf>> {
let database_directory = directory.join(DATABASE_PATH);
if !database_directory.exists() {
return Ok(Vec::new());
@@ -36,27 +27,28 @@ fn read_database(directory: &Path) -> Result<Vec<PathBuf>> {
database.extend(parse_database(&bytes).context("parsing kpsewhich database")?);
}
}
+
Ok(database)
}
fn parse_database(bytes: &[u8]) -> io::Result<Vec<PathBuf>> {
let mut reader = Cursor::new(bytes);
- if reader.read_u32::<LittleEndian>()? != FNDB_SIGNATURE {
+ if read_u32(&mut reader)? != FNDB_SIGNATURE {
return Err(io::ErrorKind::InvalidData.into());
}
reader.set_position(u64::from(FNDB_TABLE_POINTER_OFFSET));
- let table_address = reader.read_u32::<LittleEndian>()?;
+ let table_address = read_u32(&mut reader)?;
reader.set_position(u64::from(FNDB_TABLE_SIZE_OFFSET));
- let table_size = reader.read_u32::<LittleEndian>()?;
+ let table_size = read_u32(&mut reader)?;
let mut files = Vec::new();
for i in 0..table_size {
let offset = table_address + i * FNDB_ENTRY_SIZE as u32;
reader.set_position(u64::from(offset));
- let file_name_offset = reader.read_u32::<LittleEndian>()? as usize;
- let directory_offset = reader.read_u32::<LittleEndian>()? as usize;
+ let file_name_offset = read_u32(&mut reader)? as usize;
+ let directory_offset = read_u32(&mut reader)? as usize;
let file_name = read_string(bytes, file_name_offset)?;
let directory = read_string(bytes, directory_offset)?;
@@ -78,3 +70,9 @@ fn read_string(bytes: &[u8], offset: usize) -> io::Result<&str> {
std::str::from_utf8(&bytes[offset..offset + length])
.map_err(|_| io::ErrorKind::InvalidData.into())
}
+
+fn read_u32(reader: &mut Cursor<&[u8]>) -> io::Result<u32> {
+ let mut buf = [0u8; std::mem::size_of::<u32>()];
+ reader.read_exact(&mut buf)?;
+ Ok(u32::from_le_bytes(buf))
+}
diff --git a/support/texlab/src/distro/texlive.rs b/support/texlab/src/distro/texlive.rs
index 47159b2efc..8013033e6d 100644
--- a/support/texlab/src/distro/texlive.rs
+++ b/support/texlab/src/distro/texlive.rs
@@ -6,17 +6,9 @@ use std::{
use anyhow::Result;
-use super::kpsewhich::{self, Resolver};
-
-pub fn load_resolver() -> Result<Resolver> {
- let root_directories = kpsewhich::root_directories()?;
- let resolver = kpsewhich::parse_database(&root_directories, read_database)?;
- Ok(resolver)
-}
-
const DATABASE_PATH: &str = "ls-R";
-fn read_database(directory: &Path) -> Result<Vec<PathBuf>> {
+pub(super) fn read_database(directory: &Path) -> Result<Vec<PathBuf>> {
let file = directory.join(DATABASE_PATH);
if !file.is_file() {
return Ok(Vec::new());
diff --git a/support/texlab/src/document.rs b/support/texlab/src/document.rs
deleted file mode 100644
index 60e295b2e4..0000000000
--- a/support/texlab/src/document.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-use std::{fmt, sync::Arc};
-
-use derive_more::From;
-use lsp_types::Url;
-
-use crate::{
- line_index::LineIndex,
- syntax::{
- bibtex, build_log,
- latex::{self, LatexAnalyzerContext},
- },
- DocumentLanguage, Environment,
-};
-
-#[derive(Debug, Clone)]
-pub struct LatexDocumentData {
- pub green: rowan::GreenNode,
- pub extras: Arc<latex::Extras>,
-}
-
-#[derive(Debug, Clone)]
-pub struct BibtexDocumentData {
- pub green: rowan::GreenNode,
-}
-
-#[derive(Debug, Clone, From)]
-pub enum DocumentData {
- Latex(Box<LatexDocumentData>),
- Bibtex(BibtexDocumentData),
- BuildLog(Arc<build_log::Parse>),
-}
-
-impl DocumentData {
- #[must_use]
- pub fn language(&self) -> DocumentLanguage {
- match self {
- Self::Latex(_) => DocumentLanguage::Latex,
- Self::Bibtex(_) => DocumentLanguage::Bibtex,
- Self::BuildLog(_) => DocumentLanguage::BuildLog,
- }
- }
-
- #[must_use]
- pub fn as_latex(&self) -> Option<&LatexDocumentData> {
- if let Self::Latex(data) = self {
- Some(data)
- } else {
- None
- }
- }
-
- #[must_use]
- pub fn as_bibtex(&self) -> Option<&BibtexDocumentData> {
- if let Self::Bibtex(data) = self {
- Some(data)
- } else {
- None
- }
- }
-
- #[must_use]
- pub fn as_build_log(&self) -> Option<&build_log::Parse> {
- if let Self::BuildLog(v) = self {
- Some(v)
- } else {
- None
- }
- }
-}
-
-#[derive(Clone)]
-pub struct Document {
- pub uri: Arc<Url>,
- pub text: Arc<String>,
- pub line_index: Arc<LineIndex>,
- pub data: DocumentData,
-}
-
-impl fmt::Debug for Document {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.uri)
- }
-}
-
-impl Document {
- #[must_use]
- pub fn parse(
- environment: &Environment,
- uri: Arc<Url>,
- text: Arc<String>,
- language: DocumentLanguage,
- ) -> Self {
- let line_index = Arc::new(LineIndex::new(&text));
- let data = match language {
- DocumentLanguage::Latex => {
- let green = latex::parse(&text).green;
- let root = latex::SyntaxNode::new_root(green.clone());
-
- let base_uri = match &environment.options.root_directory {
- Some(root_dir) => {
- let root_dir = environment.current_directory.join(&root_dir);
- Url::from_directory_path(root_dir)
- .map_or_else(|()| Arc::clone(&uri), Arc::new)
- }
- None => Arc::clone(&uri),
- };
-
- let mut context = LatexAnalyzerContext {
- environment,
- extras: latex::Extras::default(),
- document_uri: Arc::clone(&uri),
- base_uri,
- };
- latex::analyze(&mut context, &root);
- let extras = Arc::new(context.extras);
- DocumentData::Latex(Box::new(LatexDocumentData { green, extras }))
- }
- DocumentLanguage::Bibtex => {
- let green = bibtex::parse(&text);
- DocumentData::Bibtex(BibtexDocumentData { green })
- }
- DocumentLanguage::BuildLog => {
- let data = Arc::new(build_log::parse(&text));
- DocumentData::BuildLog(data)
- }
- };
-
- Self {
- uri,
- text,
- line_index,
- data,
- }
- }
-}
diff --git a/support/texlab/src/environment.rs b/support/texlab/src/environment.rs
deleted file mode 100644
index 54b6279f30..0000000000
--- a/support/texlab/src/environment.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-use std::{path::PathBuf, sync::Arc};
-
-use lsp_types::{ClientCapabilities, ClientInfo};
-
-use crate::{distro::Resolver, Options};
-
-#[derive(Debug, Clone)]
-pub struct Environment {
- pub current_directory: Arc<PathBuf>,
- pub client_capabilities: Arc<ClientCapabilities>,
- pub client_info: Option<Arc<ClientInfo>>,
- pub options: Arc<Options>,
- pub resolver: Arc<Resolver>,
-}
-
-impl Environment {
- #[must_use]
- pub fn new(current_directory: Arc<PathBuf>) -> Self {
- Self {
- current_directory,
- client_capabilities: Arc::new(ClientCapabilities::default()),
- client_info: None,
- options: Arc::new(Options::default()),
- resolver: Arc::new(Resolver::default()),
- }
- }
-}
-
-impl Default for Environment {
- fn default() -> Self {
- Self::new(Arc::new(std::env::temp_dir()))
- }
-}
diff --git a/support/texlab/src/features.rs b/support/texlab/src/features.rs
index 9576f266a9..0d82bcb4f4 100644
--- a/support/texlab/src/features.rs
+++ b/support/texlab/src/features.rs
@@ -1,52 +1,14 @@
-mod build;
-#[cfg(feature = "completion")]
-mod completion;
-mod cursor;
-mod definition;
-mod execute_command;
-mod folding;
-mod formatting;
-mod forward_search;
-mod highlight;
-mod hover;
-mod link;
-mod lsp_kinds;
-mod reference;
-mod rename;
-mod symbol;
-
-use std::sync::Arc;
-
-use lsp_types::Url;
-
-use crate::{Document, Workspace};
-
-#[cfg(feature = "completion")]
-pub use self::completion::{complete, CompletionItemData, COMPLETION_LIMIT};
-pub use self::{
- build::{BuildEngine, BuildParams, BuildResult, BuildStatus},
- definition::goto_definition,
- execute_command::execute_command,
- folding::find_foldings,
- formatting::format_source_code,
- forward_search::{execute_forward_search, ForwardSearchResult, ForwardSearchStatus},
- highlight::find_document_highlights,
- hover::find_hover,
- link::find_document_links,
- reference::find_all_references,
- rename::{prepare_rename_all, rename_all},
- symbol::{find_document_symbols, find_workspace_symbols},
-};
-
-#[derive(Clone)]
-pub struct FeatureRequest<P> {
- pub params: P,
- pub workspace: Workspace,
- pub uri: Arc<Url>,
-}
-
-impl<P> FeatureRequest<P> {
- pub fn main_document(&self) -> &Document {
- &self.workspace.documents_by_uri[&self.uri]
- }
-}
+pub mod build;
+pub mod completion;
+pub mod definition;
+pub mod folding;
+pub mod formatting;
+pub mod forward_search;
+pub mod highlight;
+pub mod hover;
+pub mod inlay_hint;
+pub mod link;
+pub mod reference;
+pub mod rename;
+pub mod symbol;
+pub mod workspace_command;
diff --git a/support/texlab/src/features/build.rs b/support/texlab/src/features/build.rs
index d961052061..645f1e8e0e 100644
--- a/support/texlab/src/features/build.rs
+++ b/support/texlab/src/features/build.rs
@@ -1,28 +1,18 @@
+mod progress;
+
use std::{
io::{BufRead, BufReader, Read},
- path::Path,
- process::{Command, Stdio},
- sync::{Arc, Mutex},
+ path::{Path, PathBuf},
+ process::Stdio,
thread::{self, JoinHandle},
};
-use anyhow::Result;
-use crossbeam_channel::{Receiver, Sender};
-use dashmap::DashMap;
use encoding_rs_io::DecodeReaderBytesBuilder;
-use lsp_types::{
- notification::{LogMessage, Progress},
- LogMessageParams, NumberOrString, Position, ProgressParams, ProgressParamsValue,
- TextDocumentIdentifier, TextDocumentPositionParams, Url, WorkDoneProgress,
- WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd,
-};
+use lsp_types::{notification::LogMessage, LogMessageParams, TextDocumentIdentifier, Url};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
-use uuid::Uuid;
-use crate::{client, req_queue::ReqQueue, ClientCapabilitiesExt, DocumentLanguage};
-
-use super::{forward_search, FeatureRequest};
+use crate::{client::LspClient, db::Workspace, util::capabilities::ClientCapabilitiesExt, Db};
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@@ -30,6 +20,12 @@ pub struct BuildParams {
pub text_document: TextDocumentIdentifier,
}
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct BuildResult {
+ pub status: BuildStatus,
+}
+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize_repr, Deserialize_repr)]
#[repr(i32)]
pub enum BuildStatus {
@@ -39,217 +35,132 @@ pub enum BuildStatus {
CANCELLED = 3,
}
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct BuildResult {
- pub status: BuildStatus,
-}
-
-struct ProgressReporter<'a> {
- supports_progress: bool,
- req_queue: &'a Mutex<ReqQueue>,
- lsp_sender: Sender<lsp_server::Message>,
- token: &'a str,
+#[derive(Debug)]
+pub struct Command {
+ uri: Url,
+ progress: bool,
+ executable: String,
+ args: Vec<String>,
+ working_dir: PathBuf,
+ client: LspClient,
}
-impl<'a> ProgressReporter<'a> {
- pub fn start(&self, uri: &Url) -> Result<()> {
- if self.supports_progress {
- client::send_request::<lsp_types::request::WorkDoneProgressCreate>(
- self.req_queue,
- &self.lsp_sender,
- WorkDoneProgressCreateParams {
- token: NumberOrString::String(self.token.to_string()),
- },
- )?;
- client::send_notification::<Progress>(
- &self.lsp_sender,
- ProgressParams {
- token: NumberOrString::String(self.token.to_string()),
- value: ProgressParamsValue::WorkDone(WorkDoneProgress::Begin(
- WorkDoneProgressBegin {
- title: "Building".to_string(),
- message: Some(uri.as_str().to_string()),
- cancellable: Some(false),
- percentage: None,
- },
- )),
- },
- )?;
+impl Command {
+ pub fn new(db: &dyn Db, uri: Url, client: LspClient) -> Option<Self> {
+ let workspace = Workspace::get(db);
+ let document = match workspace.lookup_uri(db, &uri) {
+ Some(child) => workspace
+ .parents(db, child)
+ .iter()
+ .next()
+ .copied()
+ .unwrap_or(child),
+ None => return None,
};
- Ok(())
- }
-}
-impl<'a> Drop for ProgressReporter<'a> {
- fn drop(&mut self) {
- if self.supports_progress {
- drop(client::send_notification::<Progress>(
- &self.lsp_sender,
- ProgressParams {
- token: NumberOrString::String(self.token.to_string()),
- value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(
- WorkDoneProgressEnd { message: None },
- )),
- },
- ));
+ if document.location(db).path(db).is_none() {
+ log::warn!("Document {uri} cannot be compiled; skipping...");
+ return None;
}
- }
-}
-
-#[derive(Default)]
-pub struct BuildEngine {
- lock: Mutex<()>,
- pub positions_by_uri: DashMap<Arc<Url>, Position>,
-}
-
-impl BuildEngine {
- pub fn build(
- &self,
- request: FeatureRequest<BuildParams>,
- req_queue: &Mutex<ReqQueue>,
- lsp_sender: &Sender<lsp_server::Message>,
- ) -> Result<BuildResult> {
- let lock = self.lock.lock().unwrap();
-
- let document = request
- .workspace
- .documents_by_uri
- .values()
- .find(|document| {
- if let Some(data) = document.data.as_latex() {
- data.extras.has_document_environment
- } else {
- false
- }
- })
- .unwrap_or_else(|| request.main_document());
-
- if document.data.language() != DocumentLanguage::Latex {
- return Ok(BuildResult {
- status: BuildStatus::SUCCESS,
- });
- }
-
- if document.uri.scheme() != "file" {
- return Ok(BuildResult {
- status: BuildStatus::FAILURE,
- });
- }
- let path = document.uri.to_file_path().unwrap();
-
- let supports_progress = request
- .workspace
- .environment
- .client_capabilities
- .has_work_done_progress_support();
-
- let token = format!("texlab-build-{}", Uuid::new_v4());
- let progress_reporter = ProgressReporter {
- supports_progress,
- req_queue,
- lsp_sender: lsp_sender.clone(),
- token: &token,
- };
- progress_reporter.start(&document.uri)?;
- let options = &request.workspace.environment.options;
-
- let build_dir = options
- .root_directory
- .as_ref()
- .map(AsRef::as_ref)
- .or_else(|| path.parent())
- .unwrap();
-
- let args: Vec<_> = options
- .build
+ let options = &workspace.options(db).build;
+ let executable = options.executable.0.clone();
+ let path = document.location(db).path(db).as_deref().unwrap();
+ let args = options
.args
+ .0
.iter()
- .map(|arg| replace_placeholder(arg.clone(), &path))
+ .map(|arg| replace_placeholder(arg, path))
.collect();
- let mut process = Command::new(&options.build.executable)
- .args(args)
- .stdin(Stdio::null())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .current_dir(build_dir)
- .spawn()?;
-
- let (exit_sender, exit_receiver) = crossbeam_channel::bounded(1);
- let log_handle = capture_output(&mut process, lsp_sender, exit_receiver);
- let success = process.wait().map(|status| status.success())?;
- exit_sender.send(())?;
- drop(exit_sender);
+ let working_dir = workspace
+ .working_dir(db, document.directory(db))
+ .path(db)
+ .clone()?;
+
+ Some(Self {
+ uri: document.location(db).uri(db).clone(),
+ progress: workspace
+ .client_capabilities(db)
+ .has_work_done_progress_support(),
+ executable,
+ args,
+ working_dir,
+ client,
+ })
+ }
- log_handle.join().unwrap();
- let status = if success {
- BuildStatus::SUCCESS
+ pub fn run(self) -> BuildStatus {
+ let reporter = if self.progress {
+ let inner = progress::Reporter::new(&self.client);
+ inner.start(&self.uri).expect("report progress");
+ Some(inner)
} else {
- BuildStatus::ERROR
+ None
};
- drop(progress_reporter);
- drop(lock);
-
- if options.build.forward_search_after {
- let request = FeatureRequest {
- params: TextDocumentPositionParams {
- position: self
- .positions_by_uri
- .get(&request.main_document().uri)
- .map(|guard| *guard)
- .unwrap_or_default(),
- text_document: TextDocumentIdentifier::new(request.uri.as_ref().clone()),
- },
- uri: request.uri,
- workspace: request.workspace,
- };
- forward_search::execute_forward_search(request);
- }
-
- Ok(BuildResult { status })
- }
-}
-
-fn capture_output(
- process: &mut std::process::Child,
- lsp_sender: &Sender<lsp_server::Message>,
- exit_receiver: Receiver<()>,
-) -> JoinHandle<()> {
- let (log_sender, log_receiver) = crossbeam_channel::unbounded();
- track_output(process.stdout.take().unwrap(), log_sender.clone());
- track_output(process.stderr.take().unwrap(), log_sender);
- let lsp_sender = lsp_sender.clone();
- thread::spawn(move || loop {
- crossbeam_channel::select! {
- recv(&log_receiver) -> message => {
- if let Ok(message) = message {
- client::send_notification::<LogMessage>(
- &lsp_sender,
- LogMessageParams {
- message,
- typ: lsp_types::MessageType::LOG,
- },
- )
- .unwrap();
- }
- },
- recv(&exit_receiver) -> _ => break,
+ let mut process = match std::process::Command::new(&self.executable)
+ .args(self.args)
+ .stdin(Stdio::null())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .current_dir(self.working_dir)
+ .spawn()
+ {
+ Ok(process) => process,
+ Err(_) => {
+ log::error!("Failed to spawn process: {:?}", self.executable);
+ return BuildStatus::FAILURE;
+ }
};
- })
-}
-fn replace_placeholder(arg: String, file: &Path) -> String {
- if arg.starts_with('"') || arg.ends_with('"') {
- arg
- } else {
- arg.replace("%f", &file.to_string_lossy())
+ let (line_sender, line_receiver) = flume::unbounded();
+ let (exit_sender, exit_receiver) = flume::unbounded();
+ track_output(process.stderr.take().unwrap(), line_sender.clone());
+ track_output(process.stdout.take().unwrap(), line_sender);
+ let client = self.client.clone();
+ let handle = std::thread::spawn(move || {
+ let typ = lsp_types::MessageType::LOG;
+
+ loop {
+ let done = flume::Selector::new()
+ .recv(&line_receiver, |line| match line {
+ Ok(message) => {
+ let params = LogMessageParams { message, typ };
+ client.send_notification::<LogMessage>(params).unwrap();
+ false
+ }
+ Err(_) => true,
+ })
+ .recv(&exit_receiver, |_| true)
+ .wait();
+
+ if done {
+ break;
+ }
+ }
+ });
+
+ let status = process.wait().map_or(BuildStatus::FAILURE, |result| {
+ if result.success() {
+ BuildStatus::SUCCESS
+ } else {
+ BuildStatus::ERROR
+ }
+ });
+
+ let _ = exit_sender.send(());
+ handle.join().unwrap();
+
+ drop(reporter);
+ status
}
}
-fn track_output(output: impl Read + Send + 'static, sender: Sender<String>) -> JoinHandle<()> {
+fn track_output(
+ output: impl Read + Send + 'static,
+ sender: flume::Sender<String>,
+) -> JoinHandle<()> {
let reader = BufReader::new(
DecodeReaderBytesBuilder::new()
.encoding(Some(encoding_rs::UTF_8))
@@ -264,3 +175,11 @@ fn track_output(output: impl Read + Send + 'static, sender: Sender<String>) -> J
}
})
}
+
+fn replace_placeholder(arg: &str, file: &Path) -> String {
+ if arg.starts_with('"') || arg.ends_with('"') {
+ arg.to_string()
+ } else {
+ arg.replace("%f", &file.to_string_lossy())
+ }
+}
diff --git a/support/texlab/src/features/build/progress.rs b/support/texlab/src/features/build/progress.rs
new file mode 100644
index 0000000000..6f235bebd6
--- /dev/null
+++ b/support/texlab/src/features/build/progress.rs
@@ -0,0 +1,54 @@
+use std::sync::atomic::{AtomicI32, Ordering};
+
+use anyhow::Result;
+use lsp_types::{
+ notification::Progress, request::WorkDoneProgressCreate, NumberOrString, ProgressParams,
+ ProgressParamsValue, Url, WorkDoneProgress, WorkDoneProgressBegin,
+ WorkDoneProgressCreateParams, WorkDoneProgressEnd,
+};
+
+use crate::client::LspClient;
+
+static NEXT_TOKEN: AtomicI32 = AtomicI32::new(1);
+
+pub struct Reporter<'a> {
+ client: &'a LspClient,
+ token: i32,
+}
+
+impl<'a> Reporter<'a> {
+ pub fn new(client: &'a LspClient) -> Self {
+ let token = NEXT_TOKEN.fetch_add(1, Ordering::SeqCst);
+ Self { client, token }
+ }
+
+ pub fn start(&self, uri: &Url) -> Result<()> {
+ self.client
+ .send_request::<WorkDoneProgressCreate>(WorkDoneProgressCreateParams {
+ token: NumberOrString::Number(self.token),
+ })?;
+
+ self.client.send_notification::<Progress>(ProgressParams {
+ token: NumberOrString::Number(self.token),
+ value: ProgressParamsValue::WorkDone(WorkDoneProgress::Begin(WorkDoneProgressBegin {
+ title: "Building".to_string(),
+ message: Some(uri.as_str().to_string()),
+ cancellable: Some(false),
+ percentage: None,
+ })),
+ })?;
+
+ Ok(())
+ }
+}
+
+impl<'a> Drop for Reporter<'a> {
+ fn drop(&mut self) {
+ let _ = self.client.send_notification::<Progress>(ProgressParams {
+ token: NumberOrString::Number(self.token),
+ value: ProgressParamsValue::WorkDone(WorkDoneProgress::End(WorkDoneProgressEnd {
+ message: None,
+ })),
+ });
+ }
+}
diff --git a/support/texlab/src/features/completion.rs b/support/texlab/src/features/completion.rs
index 3009b437e7..949b5552e5 100644
--- a/support/texlab/src/features/completion.rs
+++ b/support/texlab/src/features/completion.rs
@@ -1,6 +1,7 @@
mod acronym_ref;
mod argument;
-mod begin_command;
+mod begin_snippet;
+pub mod builder;
mod citation;
mod color;
mod color_model;
@@ -14,584 +15,36 @@ mod include;
mod label;
mod theorem;
mod tikz_library;
-mod types;
mod user_command;
mod user_environment;
-mod util;
-use std::borrow::Cow;
+use lsp_types::{CompletionList, Position, Url};
-use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
-use itertools::Itertools;
-use lsp_types::{
- CompletionItem, CompletionList, CompletionParams, CompletionTextEdit, Documentation,
- InsertTextFormat, MarkupContent, MarkupKind, TextEdit,
-};
-use rowan::{ast::AstNode, TextSize};
-use rustc_hash::FxHashSet;
-
-use crate::{
- syntax::{
- bibtex::{self},
- latex,
- },
- LineIndexExt,
-};
-
-use self::{
- acronym_ref::complete_acronyms,
- argument::complete_arguments,
- begin_command::complete_begin_command,
- citation::complete_citations,
- color::complete_colors,
- color_model::complete_color_models,
- component_command::complete_component_commands,
- component_environment::complete_component_environments,
- entry_type::complete_entry_types,
- field::complete_fields,
- glossary_ref::complete_glossary_entries,
- import::complete_imports,
- include::complete_includes,
- label::complete_labels,
- theorem::complete_theorem_environments,
- tikz_library::complete_tikz_libraries,
- types::{InternalCompletionItem, InternalCompletionItemData},
- user_command::complete_user_commands,
- user_environment::complete_user_environments,
- util::{adjust_kind, component_detail, image_documentation},
-};
-
-pub use self::types::CompletionItemData;
-
-use super::{
- cursor::{Cursor, CursorContext},
- lsp_kinds::Structure,
- FeatureRequest,
-};
+use crate::{features::completion::builder::CompletionBuilder, util::cursor::CursorContext, Db};
pub const COMPLETION_LIMIT: usize = 50;
-#[must_use]
-pub fn complete(request: FeatureRequest<CompletionParams>) -> Option<CompletionList> {
- let mut items = Vec::new();
- let context = CursorContext::new(request);
+pub fn complete(db: &dyn Db, uri: &Url, position: Position) -> Option<CompletionList> {
+ let context = CursorContext::new(db, uri, position, ())?;
+ let mut builder = CompletionBuilder::new(&context);
log::debug!("[Completion] Cursor: {:?}", context.cursor);
- complete_entry_types(&context, &mut items);
- complete_fields(&context, &mut items);
- complete_arguments(&context, &mut items);
- complete_citations(&context, &mut items);
- complete_imports(&context, &mut items);
- complete_colors(&context, &mut items);
- complete_color_models(&context, &mut items);
- complete_acronyms(&context, &mut items);
- complete_glossary_entries(&context, &mut items);
- complete_includes(&context, &mut items);
- complete_labels(&context, &mut items);
- complete_tikz_libraries(&context, &mut items);
- complete_component_environments(&context, &mut items);
- complete_theorem_environments(&context, &mut items);
- complete_user_environments(&context, &mut items);
- complete_begin_command(&context, &mut items);
- complete_component_commands(&context, &mut items);
- complete_user_commands(&context, &mut items);
-
- let mut items = dedup(items);
- preselect(&context, &mut items);
- score(&context, &mut items);
-
- items.sort_by(|a, b| {
- a.preselect
- .cmp(&b.preselect)
- .reverse()
- .then_with(|| a.score.cmp(&b.score).reverse())
- .then_with(|| a.data.label().cmp(b.data.label()))
- });
-
- let items: Vec<_> = items
- .into_iter()
- .take(COMPLETION_LIMIT)
- .filter(|item| item.score.is_some())
- .map(|item| convert_internal_items(&context, item))
- .enumerate()
- .map(|(i, item)| append_sort_text(item, i))
- .collect();
-
- let is_incomplete = if context
- .request
- .workspace
- .environment
- .client_info
- .as_ref()
- .as_ref()
- .map_or(false, |info| info.name.as_str() == "Visual Studio Code")
- {
- true
- } else {
- items.len() >= COMPLETION_LIMIT
- };
-
- Some(CompletionList {
- is_incomplete,
- items,
- })
-}
-
-fn dedup(items: Vec<InternalCompletionItem>) -> Vec<InternalCompletionItem> {
- let mut labels = FxHashSet::default();
- let mut insert = vec![false; items.len()];
- for (i, item) in items.iter().enumerate() {
- insert[i] = labels.insert(item.data.label());
- }
- items
- .into_iter()
- .enumerate()
- .filter(|(i, _)| insert[*i])
- .map(|(_, item)| item)
- .collect()
-}
-
-fn score(context: &CursorContext<CompletionParams>, items: &mut Vec<InternalCompletionItem>) {
- let pattern: Cow<str> = match &context.cursor {
- Cursor::Latex(token) if token.kind().is_command_name() => {
- if token.text_range().start() + TextSize::from(1) == context.offset {
- // Handle cases similar to this one correctly:
- // $\|$ % (| is the cursor)
- "\\".into()
- } else {
- token.text().trim_end().into()
- }
- }
- Cursor::Latex(token) if token.kind() == latex::WORD => {
- if let Some(key) = token.parent().and_then(latex::Key::cast) {
- key.words()
- .take_while(|word| word.text_range() != token.text_range())
- .chain(std::iter::once(token.clone()))
- .filter(|word| word.text_range().start() < context.offset)
- .join(" ")
- .into()
- } else {
- token.text().into()
- }
- }
- Cursor::Bibtex(token)
- if matches!(
- token.kind(),
- bibtex::TYPE
- | bibtex::NAME
- | bibtex::WORD
- | bibtex::COMMAND_NAME
- | bibtex::ACCENT_NAME
- ) =>
- {
- token.text().into()
- }
- Cursor::Latex(_) | Cursor::Bibtex(_) | Cursor::Nothing => "".into(),
- };
-
- let file_pattern = pattern.split('/').last().unwrap();
- let matcher = SkimMatcherV2::default().ignore_case();
- for item in items {
- item.score = match &item.data {
- InternalCompletionItemData::EntryType { ty } => {
- matcher.fuzzy_match(&ty.name, &pattern[1..])
- }
- InternalCompletionItemData::Field { field } => {
- matcher.fuzzy_match(&field.name, &pattern)
- }
- InternalCompletionItemData::Argument { name, .. } => {
- matcher.fuzzy_match(name, &pattern)
- }
- InternalCompletionItemData::BeginCommand => matcher.fuzzy_match("begin", &pattern[1..]),
- InternalCompletionItemData::Citation { key, .. } => matcher.fuzzy_match(key, &pattern),
- InternalCompletionItemData::ComponentCommand { name, .. } => {
- matcher.fuzzy_match(name, &pattern[1..])
- }
- InternalCompletionItemData::ComponentEnvironment { name, .. } => {
- matcher.fuzzy_match(name, &pattern)
- }
- InternalCompletionItemData::Class { name } => matcher.fuzzy_match(name, &pattern),
- InternalCompletionItemData::Package { name } => matcher.fuzzy_match(name, &pattern),
- InternalCompletionItemData::Color { name } => matcher.fuzzy_match(name, &pattern),
- InternalCompletionItemData::ColorModel { name } => matcher.fuzzy_match(name, &pattern),
- InternalCompletionItemData::Acronym { name } => matcher.fuzzy_match(name, &pattern),
- InternalCompletionItemData::GlossaryEntry { name } => {
- matcher.fuzzy_match(name, &pattern)
- }
- InternalCompletionItemData::File { name } => matcher.fuzzy_match(name, file_pattern),
- InternalCompletionItemData::Directory { name } => {
- matcher.fuzzy_match(name, file_pattern)
- }
- InternalCompletionItemData::Label { name, .. } => matcher.fuzzy_match(name, &pattern),
- InternalCompletionItemData::UserCommand { name } => matcher.fuzzy_match(name, &pattern),
- InternalCompletionItemData::UserEnvironment { name } => {
- matcher.fuzzy_match(name, &pattern)
- }
- InternalCompletionItemData::PgfLibrary { name } => matcher.fuzzy_match(name, &pattern),
- InternalCompletionItemData::TikzLibrary { name } => matcher.fuzzy_match(name, &pattern),
- };
- }
-}
-
-fn preselect(
- context: &CursorContext<CompletionParams>,
- items: &mut [InternalCompletionItem],
-) -> Option<()> {
- let name = context.cursor.as_latex()?;
- let group = latex::CurlyGroupWord::cast(name.parent()?)?;
- let end = latex::End::cast(group.syntax().parent()?)?;
- let environment = latex::Environment::cast(end.syntax().parent()?)?;
- let name = environment.begin()?.name()?.key()?.to_string();
-
- for item in items {
- if item.data.label() == name {
- item.preselect = true;
- }
- }
- Some(())
-}
-
-fn convert_internal_items(
- context: &CursorContext<CompletionParams>,
- item: InternalCompletionItem,
-) -> CompletionItem {
- let range = context
- .request
- .main_document()
- .line_index
- .line_col_lsp_range(item.range);
-
- let mut new_item = match item.data {
- InternalCompletionItemData::EntryType { ty } => {
- let text_edit = TextEdit::new(range, (&ty.name).into());
- let kind = Structure::Entry(ty.category).completion_kind();
- CompletionItem {
- label: (&ty.name).into(),
- kind: Some(adjust_kind(&context.request, kind)),
- documentation: ty.documentation.as_ref().map(|doc| {
- Documentation::MarkupContent(MarkupContent {
- kind: MarkupKind::Markdown,
- value: doc.into(),
- })
- }),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- data: Some(serde_json::to_value(CompletionItemData::EntryType).unwrap()),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::Field { field } => {
- let text_edit = TextEdit::new(range, (&field.name).into());
- CompletionItem {
- label: (&field.name).into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::Field.completion_kind(),
- )),
- documentation: Some(Documentation::MarkupContent(MarkupContent {
- kind: MarkupKind::Markdown,
- value: (&field.documentation).into(),
- })),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- data: Some(serde_json::to_value(CompletionItemData::FieldName).unwrap()),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::Argument { name, image } => {
- let text_edit = TextEdit::new(range, name.into());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::Argument.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Argument).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- documentation: image
- .and_then(|image| image_documentation(&context.request, name, image)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::BeginCommand => {
- if context
- .request
- .workspace
- .environment
- .client_capabilities
- .text_document
- .as_ref()
- .and_then(|cap| cap.completion.as_ref())
- .and_then(|cap| cap.completion_item.as_ref())
- .and_then(|cap| cap.snippet_support)
- == Some(true)
- {
- let text_edit = TextEdit::new(range, "begin{$1}\n\t$0\n\\end{$1}".into());
- CompletionItem {
- kind: Some(adjust_kind(
- &context.request,
- Structure::Snippet.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::CommandSnippet).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- insert_text_format: Some(InsertTextFormat::SNIPPET),
- ..CompletionItem::new_simple("begin".into(), component_detail(&[]))
- }
- } else {
- let text_edit = TextEdit::new(range, "begin".to_string());
- CompletionItem {
- kind: Some(adjust_kind(
- &context.request,
- Structure::Command.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Command).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::new_simple("begin".to_string(), component_detail(&[]))
- }
- }
- }
- InternalCompletionItemData::Citation { uri, key, text, ty } => {
- let text_edit = TextEdit::new(range, key.to_string());
- CompletionItem {
- label: key.to_string(),
- kind: Some(adjust_kind(&context.request, ty.completion_kind())),
- filter_text: Some(text.clone()),
- sort_text: Some(text),
- data: Some(
- serde_json::to_value(CompletionItemData::Citation {
- uri: uri.as_ref().clone(),
- key: key.into(),
- })
- .unwrap(),
- ),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::ComponentCommand {
- name,
- image,
- glyph,
- file_names,
- } => {
- let detail = glyph.map_or_else(
- || component_detail(file_names),
- |glyph| format!("{}, {}", glyph, component_detail(file_names)),
- );
- let documentation =
- image.and_then(|img| image_documentation(&context.request, name, img));
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- kind: Some(adjust_kind(
- &context.request,
- Structure::Command.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Command).unwrap()),
- documentation,
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::new_simple(name.to_string(), detail)
- }
- }
- InternalCompletionItemData::ComponentEnvironment { name, file_names } => {
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- kind: Some(adjust_kind(
- &context.request,
- Structure::Environment.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Environment).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::new_simple(name.to_string(), component_detail(file_names))
- }
- }
- InternalCompletionItemData::Class { name } => {
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::Class.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Class).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::Package { name } => {
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::Package.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Package).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::Color { name } => {
- let text_edit = TextEdit::new(range, name.into());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::Color.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Color).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::ColorModel { name } => {
- let text_edit = TextEdit::new(range, name.into());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::ColorModel.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::ColorModel).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::Acronym { name } => {
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- label: name,
- kind: Some(adjust_kind(
- &context.request,
- Structure::GlossaryEntry.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Acronym).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::GlossaryEntry { name } => {
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- label: name,
- kind: Some(adjust_kind(
- &context.request,
- Structure::GlossaryEntry.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::GlossaryEntry).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::File { name } => {
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::File.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::File).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::Directory { name } => {
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::Folder.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Folder).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::Label {
- name,
- kind,
- header,
- footer,
- text,
- } => {
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- label: name,
- kind: Some(adjust_kind(&context.request, kind.completion_kind())),
- detail: header,
- documentation: footer.map(Documentation::String),
- sort_text: Some(text.clone()),
- filter_text: Some(text),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- data: Some(serde_json::to_value(CompletionItemData::Label).unwrap()),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::UserCommand { name } => {
- let detail = "user-defined".into();
- let name = &name[1..];
- let text_edit = TextEdit::new(range, name.to_string());
- CompletionItem {
- kind: Some(adjust_kind(
- &context.request,
- Structure::Command.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Command).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::new_simple(name.into(), detail)
- }
- }
- InternalCompletionItemData::UserEnvironment { name } => {
- let detail = "user-defined".into();
- let text_edit = TextEdit::new(range, name.clone());
- CompletionItem {
- kind: Some(adjust_kind(
- &context.request,
- Structure::Environment.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::Environment).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::new_simple(name, detail)
- }
- }
- InternalCompletionItemData::PgfLibrary { name } => {
- let text_edit = TextEdit::new(range, name.into());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::PgfLibrary.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::PgfLibrary).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- InternalCompletionItemData::TikzLibrary { name } => {
- let text_edit = TextEdit::new(range, name.into());
- CompletionItem {
- label: name.into(),
- kind: Some(adjust_kind(
- &context.request,
- Structure::TikzLibrary.completion_kind(),
- )),
- data: Some(serde_json::to_value(CompletionItemData::TikzLibrary).unwrap()),
- text_edit: Some(CompletionTextEdit::Edit(text_edit)),
- ..CompletionItem::default()
- }
- }
- };
- new_item.preselect = Some(item.preselect);
- new_item
-}
-
-fn append_sort_text(mut item: CompletionItem, index: usize) -> CompletionItem {
- let sort_prefix = format!("{:0>2}", index);
- match &item.sort_text {
- Some(sort_text) => {
- item.sort_text = Some(format!("{} {}", sort_prefix, sort_text));
- }
- None => {
- item.sort_text = Some(sort_prefix);
- }
- };
- item
+ entry_type::complete(&context, &mut builder);
+ field::complete(&context, &mut builder);
+ argument::complete(&context, &mut builder);
+ citation::complete(&context, &mut builder);
+ import::complete(&context, &mut builder);
+ color::complete(&context, &mut builder);
+ color_model::complete(&context, &mut builder);
+ acronym_ref::complete(&context, &mut builder);
+ glossary_ref::complete(&context, &mut builder);
+ include::complete(&context, &mut builder);
+ label::complete(&context, &mut builder);
+ tikz_library::complete(&context, &mut builder);
+ component_environment::complete(&context, &mut builder);
+ theorem::complete(&context, &mut builder);
+ user_environment::complete(&context, &mut builder);
+ begin_snippet::complete(&context, &mut builder);
+ component_command::complete(&context, &mut builder);
+ user_command::complete(&context, &mut builder);
+ Some(builder.finish())
}
diff --git a/support/texlab/src/features/completion/acronym_ref.rs b/support/texlab/src/features/completion/acronym_ref.rs
index 84cbd8bc23..be7725fa2f 100644
--- a/support/texlab/src/features/completion/acronym_ref.rs
+++ b/support/texlab/src/features/completion/acronym_ref.rs
@@ -1,32 +1,29 @@
-use lsp_types::CompletionParams;
use rowan::ast::AstNode;
-use crate::{features::cursor::CursorContext, syntax::latex};
+use crate::{syntax::latex, util::cursor::CursorContext};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_acronyms<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (_, range, group) = context.find_curly_group_word()?;
latex::AcronymReference::cast(group.syntax().parent()?)?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- for name in latex::SyntaxNode::new_root(data.green.clone())
+ for document in context.related() {
+ if let Some(data) = document.parse(context.db).as_tex() {
+ for name in data
+ .root(context.db)
.descendants()
.filter_map(latex::AcronymDefinition::cast)
.filter_map(|node| node.name())
.filter_map(|name| name.key())
- .map(|name| name.to_string())
{
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::Acronym { name },
- ));
+ builder.glossary_entry(range, name.to_string());
}
}
}
+
Some(())
}
diff --git a/support/texlab/src/features/completion/argument.rs b/support/texlab/src/features/completion/argument.rs
index 3ba28f9dea..10b377cb0e 100644
--- a/support/texlab/src/features/completion/argument.rs
+++ b/support/texlab/src/features/completion/argument.rs
@@ -1,15 +1,17 @@
-use lsp_types::CompletionParams;
use rowan::{ast::AstNode, TextRange};
-use crate::{component_db::COMPONENT_DATABASE, features::cursor::CursorContext, syntax::latex};
+use crate::{
+ syntax::latex,
+ util::{components::COMPONENT_DATABASE, cursor::CursorContext},
+};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_arguments<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
- let token = context.cursor.as_latex()?;
+ let token = context.cursor.as_tex()?;
let range = if token.kind() == latex::WORD {
token.text_range()
@@ -37,7 +39,7 @@ pub fn complete_arguments<'a>(
let command_name = command.name()?;
let command_name = &command_name.text()[1..];
- for component in COMPONENT_DATABASE.linked_components(&context.request.workspace) {
+ for component in COMPONENT_DATABASE.linked_components(context.db, context.document) {
for component_command in component
.commands
.iter()
@@ -50,14 +52,7 @@ pub fn complete_arguments<'a>(
.filter(|(i, _)| *i == index)
{
for arg in &param.0 {
- let item = InternalCompletionItem::new(
- range,
- InternalCompletionItemData::Argument {
- name: &arg.name,
- image: arg.image.as_deref(),
- },
- );
- items.push(item);
+ builder.generic_argument(range, &arg.name, arg.image.as_deref());
}
}
}
diff --git a/support/texlab/src/features/completion/begin_command.rs b/support/texlab/src/features/completion/begin_command.rs
deleted file mode 100644
index 699b06c067..0000000000
--- a/support/texlab/src/features/completion/begin_command.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use lsp_types::CompletionParams;
-
-use crate::features::cursor::CursorContext;
-
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
-
-pub fn complete_begin_command(
- context: &CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem>,
-) -> Option<()> {
- let range = context.cursor.command_range(context.offset)?;
-
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::BeginCommand,
- ));
- Some(())
-}
diff --git a/support/texlab/src/features/completion/begin_snippet.rs b/support/texlab/src/features/completion/begin_snippet.rs
new file mode 100644
index 0000000000..06be4faf13
--- /dev/null
+++ b/support/texlab/src/features/completion/begin_snippet.rs
@@ -0,0 +1,9 @@
+use crate::util::cursor::CursorContext;
+
+use super::builder::CompletionBuilder;
+
+pub fn complete(context: &CursorContext, builder: &mut CompletionBuilder) -> Option<()> {
+ let range = context.cursor.command_range(context.offset)?;
+ builder.begin_snippet(range);
+ Some(())
+}
diff --git a/support/texlab/src/features/completion/builder.rs b/support/texlab/src/features/completion/builder.rs
new file mode 100644
index 0000000000..f8ea4c5d15
--- /dev/null
+++ b/support/texlab/src/features/completion/builder.rs
@@ -0,0 +1,784 @@
+use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
+use itertools::Itertools;
+use lsp_types::{
+ CompletionItem, CompletionItemKind, CompletionList, CompletionTextEdit, Documentation,
+ InsertTextFormat, MarkupContent, MarkupKind, TextEdit, Url,
+};
+use once_cell::sync::Lazy;
+use regex::Regex;
+use rowan::{ast::AstNode, TextRange, TextSize};
+use serde::{Deserialize, Serialize};
+use smol_str::SmolStr;
+
+use crate::{
+ db::{Document, Workspace},
+ syntax::{
+ bibtex::{self, HasName, HasType},
+ latex,
+ },
+ util::{
+ capabilities::ClientCapabilitiesExt,
+ cursor::{Cursor, CursorContext},
+ lang_data::{BibtexEntryTypeCategory, BibtexEntryTypeDoc, BibtexFieldDoc, LANGUAGE_DATA},
+ line_index_ext::LineIndexExt,
+ lsp_enums::Structure,
+ },
+};
+
+use super::COMPLETION_LIMIT;
+
+pub struct CompletionBuilder<'db> {
+ context: &'db CursorContext<'db>,
+ items: Vec<Item<'db>>,
+ matcher: SkimMatcherV2,
+ text_pattern: String,
+ file_pattern: String,
+ preselect: Option<String>,
+ snippets: bool,
+ markdown: bool,
+ item_kinds: &'db [CompletionItemKind],
+}
+
+impl<'db> CompletionBuilder<'db> {
+ pub fn new(context: &'db CursorContext) -> Self {
+ let items = Vec::new();
+ let matcher = SkimMatcherV2::default().ignore_case();
+ let text_pattern = match &context.cursor {
+ Cursor::Tex(token) if token.kind().is_command_name() => {
+ if token.text_range().start() + TextSize::from(1) == context.offset {
+ // Handle cases similar to this one correctly:
+ // $\|$ % (| is the cursor)
+ String::from("\\")
+ } else {
+ token.text().trim_end().into()
+ }
+ }
+ Cursor::Tex(token) if token.kind() == latex::WORD => {
+ match token.parent().and_then(latex::Key::cast) {
+ Some(key) => key
+ .words()
+ .take_while(|word| word.text_range() != token.text_range())
+ .chain(std::iter::once(token.clone()))
+ .filter(|word| word.text_range().start() < context.offset)
+ .join(" ")
+ .into(),
+ None => token.text().into(),
+ }
+ }
+ Cursor::Bib(token)
+ if matches!(
+ token.kind(),
+ bibtex::TYPE
+ | bibtex::NAME
+ | bibtex::WORD
+ | bibtex::COMMAND_NAME
+ | bibtex::ACCENT_NAME
+ ) =>
+ {
+ token.text().into()
+ }
+ Cursor::Tex(_) | Cursor::Bib(_) | Cursor::Nothing => "".into(),
+ };
+
+ let file_pattern = text_pattern.split('/').last().unwrap().to_string();
+
+ let preselect = context
+ .cursor
+ .as_tex()
+ .and_then(|name| name.parent())
+ .and_then(latex::CurlyGroupWord::cast)
+ .and_then(|group| group.syntax().parent())
+ .and_then(|end| end.parent())
+ .and_then(latex::Environment::cast)
+ .and_then(|env| env.begin())
+ .and_then(|begin| begin.name())
+ .and_then(|name| name.key())
+ .map(|name| name.to_string());
+
+ let client_capabilities = context.workspace.client_capabilities(context.db);
+ let snippets = client_capabilities.has_snippet_support();
+ let markdown = client_capabilities.has_completion_markdown_support();
+ let item_kinds = client_capabilities
+ .text_document
+ .as_ref()
+ .and_then(|cap| cap.completion.as_ref())
+ .and_then(|cap| cap.completion_item_kind.as_ref())
+ .and_then(|cap| cap.value_set.as_deref())
+ .unwrap_or_default();
+
+ Self {
+ context,
+ items,
+ matcher,
+ text_pattern,
+ file_pattern,
+ preselect,
+ snippets,
+ markdown,
+ item_kinds,
+ }
+ }
+
+ pub fn glossary_entry(&mut self, range: TextRange, name: String) -> Option<()> {
+ let score = self.matcher.fuzzy_match(&name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::GlossaryEntry { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn generic_argument(
+ &mut self,
+ range: TextRange,
+ name: &'db str,
+ image: Option<&'db str>,
+ ) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::Argument { name, image },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn begin_snippet(&mut self, range: TextRange) -> Option<()> {
+ let capabilities = Workspace::get(self.context.db).client_capabilities(self.context.db);
+ if capabilities.has_snippet_support() {
+ let score = self.matcher.fuzzy_match("begin", &self.text_pattern[1..])?;
+ self.items.push(Item {
+ range,
+ data: Data::BeginSnippet,
+ preselect: false,
+ score,
+ });
+ }
+
+ Some(())
+ }
+
+ pub fn citation(
+ &mut self,
+ range: TextRange,
+ document: Document,
+ entry: &bibtex::Entry,
+ ) -> Option<()> {
+ let key = entry.name_token()?.to_string();
+
+ let category = LANGUAGE_DATA
+ .find_entry_type(&entry.type_token()?.text()[1..])
+ .map_or(BibtexEntryTypeCategory::Misc, |ty| ty.category);
+
+ let code = entry.syntax().text().to_string();
+ let filter_text = format!(
+ "{} {}",
+ key,
+ WHITESPACE_REGEX
+ .replace_all(
+ &code
+ .replace('{', " ")
+ .replace('}', " ")
+ .replace(',', " ")
+ .replace('=', " "),
+ " "
+ )
+ .trim(),
+ );
+
+ let score = self.matcher.fuzzy_match(&filter_text, &self.text_pattern)?;
+
+ let data = Data::Citation {
+ document,
+ key,
+ filter_text,
+ category,
+ };
+
+ self.items.push(Item {
+ range,
+ data,
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn color_model(&mut self, range: TextRange, name: &'db str) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::ColorModel { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn color(&mut self, range: TextRange, name: &'db str) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::Color { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn component_command(
+ &mut self,
+ range: TextRange,
+ name: &'db str,
+ image: Option<&'db str>,
+ glyph: Option<&'db str>,
+ file_names: &'db [SmolStr],
+ ) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern[1..])?;
+ let data = Data::ComponentCommand {
+ name,
+ image,
+ glyph,
+ file_names,
+ };
+
+ self.items.push(Item {
+ range,
+ data,
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn component_environment(
+ &mut self,
+ range: TextRange,
+ name: &'db str,
+ file_names: &'db [SmolStr],
+ ) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::ComponentEnvironment { name, file_names },
+ preselect: Some(name) == self.preselect.as_deref(),
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn entry_type(
+ &mut self,
+ range: TextRange,
+ entry_type: &'db BibtexEntryTypeDoc,
+ ) -> Option<()> {
+ let score = self
+ .matcher
+ .fuzzy_match(&entry_type.name, &self.text_pattern[1..])?;
+
+ self.items.push(Item {
+ range,
+ data: Data::EntryType { entry_type },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn field(&mut self, range: TextRange, field: &'db BibtexFieldDoc) -> Option<()> {
+ let score = self.matcher.fuzzy_match(&field.name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::Field { field },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn class(&mut self, range: TextRange, name: &'db str) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::Class { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn package(&mut self, range: TextRange, name: &'db str) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::Package { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn file(&mut self, range: TextRange, name: String) -> Option<()> {
+ let score = self.matcher.fuzzy_match(&name, &self.file_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::File { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn directory(&mut self, range: TextRange, name: String) -> Option<()> {
+ let score = self.matcher.fuzzy_match(&name, &self.file_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::Directory { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn label(
+ &mut self,
+ range: TextRange,
+ name: &'db str,
+ kind: Structure,
+ header: Option<String>,
+ footer: Option<String>,
+ text: String,
+ ) -> Option<()> {
+ let score = self.matcher.fuzzy_match(&text, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::Label {
+ name,
+ kind,
+ header,
+ footer,
+ text,
+ },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn tikz_library(&mut self, range: TextRange, name: &'db str) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::TikzLibrary { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn user_command(&mut self, range: TextRange, name: &'db str) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern[1..])?;
+ self.items.push(Item {
+ range,
+ data: Data::UserCommand { name },
+ preselect: false,
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn user_environment(&mut self, range: TextRange, name: &'db str) -> Option<()> {
+ let score = self.matcher.fuzzy_match(name, &self.text_pattern)?;
+ self.items.push(Item {
+ range,
+ data: Data::UserEnvironment { name },
+ preselect: Some(name) == self.preselect.as_deref(),
+ score,
+ });
+
+ Some(())
+ }
+
+ pub fn finish(mut self) -> CompletionList {
+ let mut list = CompletionList::default();
+ list.items = std::mem::take(&mut self.items)
+ .into_iter()
+ .sorted_by(|a, b| {
+ b.preselect
+ .cmp(&a.preselect)
+ .then_with(|| b.score.cmp(&a.score))
+ .then_with(|| a.data.label().cmp(b.data.label()))
+ })
+ .dedup_by(|a, b| a.data.label() == b.data.label())
+ .take(COMPLETION_LIMIT)
+ .enumerate()
+ .map(|(i, item)| self.convert_item(item, i))
+ .collect();
+
+ list.is_incomplete = if self
+ .context
+ .workspace
+ .client_info(self.context.db)
+ .as_ref()
+ .map_or(false, |client| client.name.as_str() == "Visual Studio Code")
+ {
+ true
+ } else {
+ list.items.len() >= COMPLETION_LIMIT
+ };
+
+ list
+ }
+
+ fn convert_item(&self, item: Item, index: usize) -> CompletionItem {
+ let range = self.context.line_index.line_col_lsp_range(item.range);
+ let preselect = item.preselect;
+ let mut item = match item.data {
+ Data::EntryType { entry_type } => CompletionItem {
+ label: entry_type.name.clone(),
+ kind: Some(Structure::Entry(entry_type.category).completion_kind()),
+ documentation: entry_type.documentation.clone().map(|value| {
+ let kind = MarkupKind::Markdown;
+ Documentation::MarkupContent(MarkupContent { kind, value })
+ }),
+ text_edit: Some(TextEdit::new(range, entry_type.name.clone()).into()),
+ ..CompletionItem::default()
+ },
+ Data::Field { field } => CompletionItem {
+ label: field.name.clone(),
+ kind: Some(Structure::Field.completion_kind()),
+ documentation: Some(Documentation::MarkupContent(MarkupContent {
+ kind: MarkupKind::Markdown,
+ value: field.documentation.clone(),
+ })),
+ text_edit: Some(TextEdit::new(range, field.name.clone()).into()),
+ ..CompletionItem::default()
+ },
+ Data::Argument { name, image } => {
+ let text_edit = TextEdit::new(range, String::from(name));
+ CompletionItem {
+ label: name.into(),
+ kind: Some(Structure::Argument.completion_kind()),
+ text_edit: Some(CompletionTextEdit::Edit(text_edit)),
+ documentation: image.and_then(|base64| self.inline_image(name, base64)),
+ ..CompletionItem::default()
+ }
+ }
+ Data::BeginSnippet => {
+ if self.snippets {
+ CompletionItem {
+ kind: Some(Structure::Snippet.completion_kind()),
+ text_edit: Some(
+ TextEdit::new(range, "begin{$1}\n\t\n\\end{$1}".into()).into(),
+ ),
+ insert_text_format: Some(InsertTextFormat::SNIPPET),
+ ..CompletionItem::new_simple("begin".into(), self.component_detail(&[]))
+ }
+ } else {
+ CompletionItem {
+ kind: Some(Structure::Command.completion_kind()),
+ text_edit: Some(TextEdit::new(range, "begin".to_string()).into()),
+ ..CompletionItem::new_simple("begin".into(), self.component_detail(&[]))
+ }
+ }
+ }
+ Data::Citation {
+ document,
+ key,
+ filter_text,
+ category,
+ } => CompletionItem {
+ label: key.clone(),
+ kind: Some(Structure::Entry(category).completion_kind()),
+ filter_text: Some(filter_text.clone()),
+ sort_text: Some(filter_text),
+ data: Some(
+ serde_json::to_value(CompletionItemData::Citation {
+ uri: document
+ .location(self.context.db)
+ .uri(self.context.db)
+ .clone(),
+ key: key.clone(),
+ })
+ .unwrap(),
+ ),
+ text_edit: Some(TextEdit::new(range, key).into()),
+ ..CompletionItem::default()
+ },
+ Data::ComponentCommand {
+ name,
+ image,
+ glyph,
+ file_names,
+ } => CompletionItem {
+ label: name.into(),
+ detail: Some(glyph.map_or_else(
+ || self.component_detail(file_names),
+ |glyph| format!("{}, {}", glyph, self.component_detail(file_names)),
+ )),
+ kind: Some(Structure::Command.completion_kind()),
+ documentation: image.and_then(|base64| self.inline_image(name, base64)),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::default()
+ },
+ Data::ComponentEnvironment { name, file_names } => CompletionItem {
+ kind: Some(Structure::Environment.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::new_simple(name.into(), self.component_detail(file_names))
+ },
+ Data::Class { name } => CompletionItem {
+ label: name.into(),
+ kind: Some(Structure::Class.completion_kind()),
+ data: Some(serde_json::to_value(CompletionItemData::Package).unwrap()),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::default()
+ },
+ Data::Package { name } => CompletionItem {
+ label: name.into(),
+ kind: Some(Structure::Package.completion_kind()),
+ data: Some(serde_json::to_value(CompletionItemData::Class).unwrap()),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::default()
+ },
+ Data::Color { name } => CompletionItem {
+ label: name.into(),
+ kind: Some(Structure::Color.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::default()
+ },
+ Data::ColorModel { name } => CompletionItem {
+ label: name.into(),
+ kind: Some(Structure::ColorModel.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::default()
+ },
+ Data::GlossaryEntry { name } => CompletionItem {
+ label: name.clone(),
+ kind: Some(Structure::GlossaryEntry.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name).into()),
+ ..CompletionItem::default()
+ },
+ Data::File { name } => CompletionItem {
+ label: name.clone(),
+ kind: Some(Structure::File.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name).into()),
+ ..CompletionItem::default()
+ },
+ Data::Directory { name } => CompletionItem {
+ label: name.clone(),
+ kind: Some(Structure::Folder.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name).into()),
+ ..CompletionItem::default()
+ },
+ Data::Label {
+ name,
+ kind,
+ header,
+ footer,
+ text,
+ } => CompletionItem {
+ label: name.into(),
+ kind: Some(kind.completion_kind()),
+ detail: header,
+ documentation: footer.map(Documentation::String),
+ sort_text: Some(text.clone()),
+ filter_text: Some(text),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::default()
+ },
+ Data::UserCommand { name } => {
+ let detail = "user-defined".into();
+ let name = &name[1..];
+ CompletionItem {
+ kind: Some(Structure::Command.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::new_simple(name.into(), detail)
+ }
+ }
+ Data::UserEnvironment { name } => {
+ let detail = "user-defined".into();
+ CompletionItem {
+ kind: Some(Structure::Environment.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::new_simple(name.into(), detail)
+ }
+ }
+ Data::TikzLibrary { name } => CompletionItem {
+ label: name.into(),
+ kind: Some(Structure::TikzLibrary.completion_kind()),
+ text_edit: Some(TextEdit::new(range, name.into()).into()),
+ ..CompletionItem::default()
+ },
+ };
+
+ item.preselect = Some(preselect);
+
+ if !self.item_kinds.contains(&item.kind.unwrap()) {
+ item.kind = Some(CompletionItemKind::TEXT);
+ }
+
+ let sort_prefix = format!("{:0>2}", index);
+ match &item.sort_text {
+ Some(sort_text) => {
+ item.sort_text = Some(format!("{} {}", sort_prefix, sort_text));
+ }
+ None => {
+ item.sort_text = Some(sort_prefix);
+ }
+ };
+
+ item
+ }
+
+ fn inline_image(&self, name: &str, base64: &str) -> Option<Documentation> {
+ if self.markdown {
+ let kind = MarkupKind::Markdown;
+ let value = format!(
+ "![{}](data:image/png;base64,{}|width=48,height=48)",
+ name, base64
+ );
+
+ Some(Documentation::MarkupContent(MarkupContent { kind, value }))
+ } else {
+ None
+ }
+ }
+
+ fn component_detail(&self, file_names: &[SmolStr]) -> String {
+ if file_names.is_empty() {
+ "built-in".into()
+ } else {
+ file_names.join(", ")
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+struct Item<'db> {
+ range: TextRange,
+ data: Data<'db>,
+ preselect: bool,
+ score: i32,
+}
+
+#[derive(Debug, Clone)]
+enum Data<'db> {
+ EntryType {
+ entry_type: &'db BibtexEntryTypeDoc,
+ },
+ Field {
+ field: &'db BibtexFieldDoc,
+ },
+ Argument {
+ name: &'db str,
+ image: Option<&'db str>,
+ },
+ BeginSnippet,
+ Citation {
+ document: Document,
+ key: String,
+ filter_text: String,
+ category: BibtexEntryTypeCategory,
+ },
+ ComponentCommand {
+ name: &'db str,
+ image: Option<&'db str>,
+ glyph: Option<&'db str>,
+ file_names: &'db [SmolStr],
+ },
+ ComponentEnvironment {
+ name: &'db str,
+ file_names: &'db [SmolStr],
+ },
+ Class {
+ name: &'db str,
+ },
+ Package {
+ name: &'db str,
+ },
+ Color {
+ name: &'db str,
+ },
+ ColorModel {
+ name: &'db str,
+ },
+ GlossaryEntry {
+ name: String,
+ },
+ File {
+ name: String,
+ },
+ Directory {
+ name: String,
+ },
+ Label {
+ name: &'db str,
+ kind: Structure,
+ header: Option<String>,
+ footer: Option<String>,
+ text: String,
+ },
+ UserCommand {
+ name: &'db str,
+ },
+ UserEnvironment {
+ name: &'db str,
+ },
+ TikzLibrary {
+ name: &'db str,
+ },
+}
+
+impl<'db> Data<'db> {
+ pub fn label<'this: 'db>(&'this self) -> &'db str {
+ match self {
+ Self::EntryType { entry_type } => &entry_type.name,
+ Self::Field { field } => &field.name,
+ Self::Argument { name, .. } => name,
+ Self::BeginSnippet => "begin",
+ Self::Citation { key, .. } => key,
+ Self::ComponentCommand { name, .. } => name,
+ Self::ComponentEnvironment { name, .. } => name,
+ Self::Class { name } => name,
+ Self::Package { name } => name,
+ Self::Color { name } => name,
+ Self::ColorModel { name } => name,
+ Self::GlossaryEntry { name } => name,
+ Self::File { name } => name,
+ Self::Directory { name } => name,
+ Self::Label { name, .. } => name,
+ Self::UserCommand { name } => name,
+ Self::UserEnvironment { name } => name,
+ Self::TikzLibrary { name } => name,
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub(crate) enum CompletionItemData {
+ Package,
+ Class,
+ Citation { uri: Url, key: String },
+}
+
+static WHITESPACE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("\\s+").unwrap());
diff --git a/support/texlab/src/features/completion/citation.rs b/support/texlab/src/features/completion/citation.rs
index e6436689d7..68d72717a7 100644
--- a/support/texlab/src/features/completion/citation.rs
+++ b/support/texlab/src/features/completion/citation.rs
@@ -1,26 +1,17 @@
-use std::sync::Arc;
-
-use lsp_types::CompletionParams;
-use once_cell::sync::Lazy;
-use regex::Regex;
use rowan::{ast::AstNode, TextRange};
use crate::{
- features::{cursor::CursorContext, lsp_kinds::Structure},
- syntax::{
- bibtex::{self, HasName, HasType},
- latex,
- },
- BibtexEntryTypeCategory, Document, LANGUAGE_DATA,
+ syntax::{bibtex, latex},
+ util::cursor::CursorContext,
};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_citations<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
- let token = context.cursor.as_latex()?;
+ let token = context.cursor.as_tex()?;
let range = if token.kind() == latex::WORD {
latex::Key::cast(token.parent()?)
@@ -36,15 +27,14 @@ pub fn complete_citations<'a>(
};
check_citation(context).or_else(|| check_acronym(context))?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_bibtex() {
- for entry in bibtex::SyntaxNode::new_root(data.green.clone())
+ for document in context.related() {
+ if let Some(data) = document.parse(context.db).as_bib() {
+ for entry in data
+ .root(context.db)
.children()
.filter_map(bibtex::Entry::cast)
{
- if let Some(item) = make_item(document, &entry, range) {
- items.push(item);
- }
+ builder.citation(range, document, &entry);
}
}
}
@@ -52,14 +42,14 @@ pub fn complete_citations<'a>(
Some(())
}
-fn check_citation(context: &CursorContext<CompletionParams>) -> Option<()> {
+fn check_citation(context: &CursorContext) -> Option<()> {
let (_, _, group) = context.find_curly_group_word_list()?;
latex::Citation::cast(group.syntax().parent()?)?;
Some(())
}
-fn check_acronym(context: &CursorContext<CompletionParams>) -> Option<()> {
- let token = context.cursor.as_latex()?;
+fn check_acronym(context: &CursorContext) -> Option<()> {
+ let token = context.cursor.as_tex()?;
let pair = token
.parent_ancestors()
@@ -71,45 +61,3 @@ fn check_acronym(context: &CursorContext<CompletionParams>) -> Option<()> {
latex::AcronymDeclaration::cast(pair.syntax().parent()?.parent()?.parent()?)?;
Some(())
}
-
-fn make_item<'a>(
- document: &'a Document,
- entry: &bibtex::Entry,
- range: TextRange,
-) -> Option<InternalCompletionItem<'a>> {
- let key = entry.name_token()?.to_string();
- let ty = LANGUAGE_DATA
- .find_entry_type(&entry.type_token()?.text()[1..])
- .map_or_else(
- || Structure::Entry(BibtexEntryTypeCategory::Misc),
- |ty| Structure::Entry(ty.category),
- );
-
- let entry_code = entry.syntax().text().to_string();
- let text = format!(
- "{} {}",
- key,
- WHITESPACE_REGEX
- .replace_all(
- &entry_code
- .replace('{', " ")
- .replace('}', " ")
- .replace(',', " ")
- .replace('=', " "),
- " "
- )
- .trim(),
- );
-
- Some(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::Citation {
- uri: Arc::clone(&document.uri),
- key,
- text,
- ty,
- },
- ))
-}
-
-static WHITESPACE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("\\s+").unwrap());
diff --git a/support/texlab/src/features/completion/color.rs b/support/texlab/src/features/completion/color.rs
index a9a385c3c9..cce6517cb4 100644
--- a/support/texlab/src/features/completion/color.rs
+++ b/support/texlab/src/features/completion/color.rs
@@ -1,22 +1,21 @@
-use lsp_types::CompletionParams;
use rowan::ast::AstNode;
-use crate::{features::cursor::CursorContext, syntax::latex, LANGUAGE_DATA};
+use crate::{
+ syntax::latex,
+ util::{cursor::CursorContext, lang_data::LANGUAGE_DATA},
+};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_colors<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (_, range, group) = context.find_curly_group_word()?;
latex::ColorReference::cast(group.syntax().parent()?)?;
for name in &LANGUAGE_DATA.colors {
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::Color { name },
- ));
+ builder.color(range, name);
}
Some(())
diff --git a/support/texlab/src/features/completion/color_model.rs b/support/texlab/src/features/completion/color_model.rs
index cd582d0031..af700a96fb 100644
--- a/support/texlab/src/features/completion/color_model.rs
+++ b/support/texlab/src/features/completion/color_model.rs
@@ -1,29 +1,25 @@
-use lsp_types::CompletionParams;
use rowan::{ast::AstNode, TextRange};
-use crate::{features::cursor::CursorContext, syntax::latex};
+use crate::{syntax::latex, util::cursor::CursorContext};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
const MODEL_NAMES: &[&str] = &["gray", "rgb", "RGB", "HTML", "cmyk"];
-pub fn complete_color_models<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let range = check_color_definition(context).or_else(|| check_color_definition_set(context))?;
for name in MODEL_NAMES {
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::ColorModel { name },
- ));
+ builder.color_model(range, name);
}
Some(())
}
-fn check_color_definition(context: &CursorContext<CompletionParams>) -> Option<TextRange> {
+fn check_color_definition(context: &CursorContext) -> Option<TextRange> {
let (_, range, group) = context.find_curly_group_word()?;
let definition = latex::ColorDefinition::cast(group.syntax().parent()?)?;
@@ -33,7 +29,7 @@ fn check_color_definition(context: &CursorContext<CompletionParams>) -> Option<T
Some(range)
}
-fn check_color_definition_set(context: &CursorContext<CompletionParams>) -> Option<TextRange> {
+fn check_color_definition_set(context: &CursorContext) -> Option<TextRange> {
let (_, range, group) = context.find_curly_group_word_list()?;
let definition = latex::ColorSetDefinition::cast(group.syntax().parent()?)?;
definition
diff --git a/support/texlab/src/features/completion/component_command.rs b/support/texlab/src/features/completion/component_command.rs
index 097b28633f..20cef73848 100644
--- a/support/texlab/src/features/completion/component_command.rs
+++ b/support/texlab/src/features/completion/component_command.rs
@@ -1,26 +1,22 @@
-use lsp_types::CompletionParams;
+use crate::util::{components::COMPONENT_DATABASE, cursor::CursorContext};
-use crate::{component_db::COMPONENT_DATABASE, features::cursor::CursorContext};
+use super::builder::CompletionBuilder;
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
-
-pub fn complete_component_commands<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let range = context.cursor.command_range(context.offset)?;
- for component in COMPONENT_DATABASE.linked_components(&context.request.workspace) {
+ for component in COMPONENT_DATABASE.linked_components(context.db, context.document) {
for command in &component.commands {
- items.push(InternalCompletionItem::new(
+ builder.component_command(
range,
- InternalCompletionItemData::ComponentCommand {
- name: &command.name,
- image: command.image.as_deref(),
- glyph: command.glyph.as_deref(),
- file_names: &component.file_names,
- },
- ));
+ &command.name,
+ command.image.as_deref(),
+ command.glyph.as_deref(),
+ &component.file_names,
+ );
}
}
diff --git a/support/texlab/src/features/completion/component_environment.rs b/support/texlab/src/features/completion/component_environment.rs
index a9478694bb..e58e319a46 100644
--- a/support/texlab/src/features/completion/component_environment.rs
+++ b/support/texlab/src/features/completion/component_environment.rs
@@ -1,24 +1,16 @@
-use lsp_types::CompletionParams;
+use crate::util::{components::COMPONENT_DATABASE, cursor::CursorContext};
-use crate::{component_db::COMPONENT_DATABASE, features::cursor::CursorContext};
+use super::builder::CompletionBuilder;
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
-
-pub fn complete_component_environments<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (_, range) = context.find_environment_name()?;
- for component in COMPONENT_DATABASE.linked_components(&context.request.workspace) {
+ for component in COMPONENT_DATABASE.linked_components(context.db, context.document) {
for name in &component.environments {
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::ComponentEnvironment {
- name,
- file_names: &component.file_names,
- },
- ));
+ builder.component_environment(range, name, &component.file_names);
}
}
diff --git a/support/texlab/src/features/completion/entry_type.rs b/support/texlab/src/features/completion/entry_type.rs
index 519737ed08..38bc0e3f3a 100644
--- a/support/texlab/src/features/completion/entry_type.rs
+++ b/support/texlab/src/features/completion/entry_type.rs
@@ -1,26 +1,26 @@
-use lsp_types::CompletionParams;
use rowan::{TextRange, TextSize};
-use crate::{features::cursor::CursorContext, syntax::bibtex, LANGUAGE_DATA};
+use crate::{
+ syntax::bibtex,
+ util::{cursor::CursorContext, lang_data::LANGUAGE_DATA},
+};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_entry_types<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let range = context
.cursor
- .as_bibtex()
+ .as_bib()
.filter(|token| token.kind() == bibtex::TYPE)
.map(bibtex::SyntaxToken::text_range)
.filter(|range| range.start() != context.offset)
.map(|range| TextRange::new(range.start() + TextSize::from(1), range.end()))?;
- for ty in &LANGUAGE_DATA.entry_types {
- let data = InternalCompletionItemData::EntryType { ty };
- let item = InternalCompletionItem::new(range, data);
- items.push(item);
+ for entry_type in &LANGUAGE_DATA.entry_types {
+ builder.entry_type(range, entry_type);
}
Some(())
diff --git a/support/texlab/src/features/completion/field.rs b/support/texlab/src/features/completion/field.rs
index 4f386ed1b1..ff6e54a562 100644
--- a/support/texlab/src/features/completion/field.rs
+++ b/support/texlab/src/features/completion/field.rs
@@ -1,19 +1,17 @@
-use lsp_types::CompletionParams;
use rowan::{ast::AstNode, TextRange};
use crate::{
- features::cursor::CursorContext,
syntax::bibtex::{self, HasName},
- LANGUAGE_DATA,
+ util::{cursor::CursorContext, lang_data::LANGUAGE_DATA},
};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_fields<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
- let token = context.cursor.as_bibtex()?;
+ let token = context.cursor.as_bib()?;
let range = if token.kind() == bibtex::NAME {
token.text_range()
@@ -31,9 +29,8 @@ pub fn complete_fields<'a>(
}
for field in &LANGUAGE_DATA.fields {
- let data = InternalCompletionItemData::Field { field };
- let item = InternalCompletionItem::new(range, data);
- items.push(item);
+ builder.field(range, field);
}
+
Some(())
}
diff --git a/support/texlab/src/features/completion/glossary_ref.rs b/support/texlab/src/features/completion/glossary_ref.rs
index 6223079fdf..34d53bf24d 100644
--- a/support/texlab/src/features/completion/glossary_ref.rs
+++ b/support/texlab/src/features/completion/glossary_ref.rs
@@ -1,38 +1,31 @@
-use lsp_types::CompletionParams;
use rowan::ast::AstNode;
-use crate::{features::cursor::CursorContext, syntax::latex};
+use crate::{syntax::latex, util::cursor::CursorContext};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_glossary_entries<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (_, range, group) = context.find_curly_group_word()?;
latex::GlossaryEntryReference::cast(group.syntax().parent()?)?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- for node in latex::SyntaxNode::new_root(data.green.clone()).descendants() {
+ for document in context.related() {
+ if let Some(data) = document.parse(context.db).as_tex() {
+ for node in data.root(context.db).descendants() {
if let Some(name) = latex::GlossaryEntryDefinition::cast(node.clone())
.and_then(|entry| entry.name())
.and_then(|name| name.key())
.map(|name| name.to_string())
{
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::GlossaryEntry { name },
- ));
+ builder.glossary_entry(range, name);
} else if let Some(name) = latex::AcronymDefinition::cast(node)
.and_then(|entry| entry.name())
.and_then(|name| name.key())
.map(|name| name.to_string())
{
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::Acronym { name },
- ));
+ builder.glossary_entry(range, name);
}
}
}
diff --git a/support/texlab/src/features/completion/import.rs b/support/texlab/src/features/completion/import.rs
index 9cb35b68a7..bf6da78a43 100644
--- a/support/texlab/src/features/completion/import.rs
+++ b/support/texlab/src/features/completion/import.rs
@@ -1,31 +1,24 @@
-use lsp_types::CompletionParams;
use rowan::ast::AstNode;
use rustc_hash::FxHashSet;
-use smol_str::SmolStr;
-use crate::{component_db::COMPONENT_DATABASE, features::cursor::CursorContext, syntax::latex};
+use crate::{
+ syntax::latex,
+ util::{components::COMPONENT_DATABASE, cursor::CursorContext},
+};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_imports<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (_, range, group) = context.find_curly_group_word_list()?;
- let (extension, mut factory): (
- &str,
- Box<dyn FnMut(SmolStr) -> InternalCompletionItemData<'a>>,
- ) = match group.syntax().parent()?.kind() {
- latex::PACKAGE_INCLUDE => (
- "sty",
- Box::new(|name| InternalCompletionItemData::Package { name }),
- ),
- latex::CLASS_INCLUDE => (
- "cls",
- Box::new(|name| InternalCompletionItemData::Class { name }),
- ),
- _ => return None,
+ let kind = group.syntax().parent()?.kind();
+ let extension = match kind {
+ latex::PACKAGE_INCLUDE => "sty",
+ latex::CLASS_INCLUDE => "cls",
+ _ => return Some(()),
};
let mut file_names = FxHashSet::default();
@@ -35,21 +28,27 @@ pub fn complete_imports<'a>(
.flat_map(|comp| comp.file_names.iter())
.filter(|file_name| file_name.ends_with(extension))
{
- file_names.insert(file_name);
+ file_names.insert(file_name.as_str());
let stem = &file_name[0..file_name.len() - 4];
- let data = factory(stem.into());
- items.push(InternalCompletionItem::new(range, data));
+ if kind == latex::PACKAGE_INCLUDE {
+ builder.package(range, stem);
+ } else {
+ builder.class(range, stem);
+ }
}
- let resolver = &context.request.workspace.environment.resolver;
- for file_name in resolver
- .files_by_name
- .keys()
+ let file_name_db = context.workspace.file_name_db(context.db);
+ for file_name in file_name_db
+ .iter()
+ .map(|(file_name, _)| file_name)
.filter(|file_name| file_name.ends_with(extension) && !file_names.contains(file_name))
{
let stem = &file_name[0..file_name.len() - 4];
- let data = factory(stem.into());
- items.push(InternalCompletionItem::new(range, data));
+ if kind == latex::PACKAGE_INCLUDE {
+ builder.package(range, stem);
+ } else {
+ builder.class(range, stem);
+ }
}
Some(())
diff --git a/support/texlab/src/features/completion/include.rs b/support/texlab/src/features/completion/include.rs
index d851aca820..bde7544570 100644
--- a/support/texlab/src/features/completion/include.rs
+++ b/support/texlab/src/features/completion/include.rs
@@ -4,18 +4,22 @@ use std::{
path::{Path, PathBuf},
};
-use lsp_types::CompletionParams;
use rowan::{ast::AstNode, TextRange, TextSize};
-use crate::{features::cursor::CursorContext, syntax::latex};
+use crate::{syntax::latex, util::cursor::CursorContext};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_includes<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
- if context.request.main_document().uri.scheme() != "file" {
+ if context
+ .document
+ .location(context.db)
+ .path(context.db)
+ .is_none()
+ {
return None;
}
@@ -51,10 +55,15 @@ pub fn complete_includes<'a>(
let mut dirs = vec![current_dir(context, &path_text, None)];
if include.kind() == latex::GRAPHICS_INCLUDE {
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- for graphics_path in &data.extras.graphics_paths {
- dirs.push(current_dir(context, &path_text, Some(graphics_path)));
+ for document in context.related() {
+ if let Some(data) = document.parse(context.db).as_tex() {
+ for path in data
+ .analyze(context.db)
+ .graphics_paths(context.db)
+ .iter()
+ .map(|node| node.path(context.db))
+ {
+ dirs.push(current_dir(context, &path_text, Some(path)));
}
}
}
@@ -74,15 +83,12 @@ pub fn complete_includes<'a>(
if !include_extension {
remove_extension(&mut path);
}
+
let name = path.file_name()?.to_str()?.into();
- let data = InternalCompletionItemData::File { name };
- let item = InternalCompletionItem::new(segment_range, data);
- items.push(item);
+ builder.file(segment_range, name);
} else if file_type.is_dir() {
let name = path.file_name()?.to_str()?.into();
- let data = InternalCompletionItemData::Directory { name };
- let item = InternalCompletionItem::new(segment_range, data);
- items.push(item);
+ builder.directory(segment_range, name);
}
}
@@ -90,34 +96,24 @@ pub fn complete_includes<'a>(
}
fn current_dir(
- context: &CursorContext<CompletionParams>,
+ context: &CursorContext,
path_text: &str,
graphics_path: Option<&str>,
) -> Option<PathBuf> {
- let mut path = context
- .request
+ let parent = context
.workspace
- .environment
- .options
- .root_directory
- .as_ref()
- .map_or_else(
- || {
- let mut path = context.request.main_document().uri.to_file_path().unwrap();
- path.pop();
- path
- },
- |root_directory| {
- context
- .request
- .workspace
- .environment
- .current_directory
- .join(root_directory)
- },
- );
-
- path = PathBuf::from(path.to_str()?.replace('\\', "/"));
+ .parents(context.db, context.document)
+ .iter()
+ .next()
+ .map_or(context.document, Clone::clone);
+
+ let path = context
+ .workspace
+ .working_dir(context.db, parent.directory(context.db))
+ .path(context.db)
+ .as_deref()?;
+
+ let mut path = PathBuf::from(path.to_str()?.replace('\\', "/"));
if !path_text.is_empty() {
if let Some(graphics_path) = graphics_path {
path.push(graphics_path);
diff --git a/support/texlab/src/features/completion/label.rs b/support/texlab/src/features/completion/label.rs
index b662f98c8a..ae3e010b0e 100644
--- a/support/texlab/src/features/completion/label.rs
+++ b/support/texlab/src/features/completion/label.rs
@@ -1,83 +1,61 @@
-use lsp_types::CompletionParams;
use rowan::{ast::AstNode, TextRange};
use crate::{
- features::{cursor::CursorContext, lsp_kinds::Structure},
- render_label,
syntax::latex,
- LabelledObject,
+ util::{self, cursor::CursorContext, label::LabeledObject, lsp_enums::Structure},
};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_labels<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (range, is_math) = find_reference(context).or_else(|| find_reference_range(context))?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- for label in latex::SyntaxNode::new_root(data.green.clone())
- .descendants()
- .filter_map(latex::LabelDefinition::cast)
+ let db = context.db;
+ for document in context.related() {
+ if let Some(data) = document.parse(db).as_tex() {
+ for label in data
+ .analyze(db)
+ .labels(db)
+ .iter()
+ .filter(|label| label.origin(db).as_definition().is_some())
{
- if let Some(name) = label
- .name()
- .and_then(|name| name.key())
- .map(|name| name.to_string())
- {
- match render_label(&context.request.workspace, &name, Some(label)) {
- Some(rendered_label) => {
- let kind = match &rendered_label.object {
- LabelledObject::Section { .. } => Structure::Section,
- LabelledObject::Float { .. } => Structure::Float,
- LabelledObject::Theorem { .. } => Structure::Theorem,
- LabelledObject::Equation => Structure::Equation,
- LabelledObject::EnumItem => Structure::Item,
- };
+ match util::label::render(db, document, *label) {
+ Some(rendered_label) => {
+ let kind = match &rendered_label.object {
+ LabeledObject::Section { .. } => Structure::Section,
+ LabeledObject::Float { .. } => Structure::Float,
+ LabeledObject::Theorem { .. } => Structure::Theorem,
+ LabeledObject::Equation => Structure::Equation,
+ LabeledObject::EnumItem => Structure::Item,
+ };
- if is_math && kind != Structure::Equation {
- continue;
- }
+ if is_math && kind != Structure::Equation {
+ continue;
+ }
- let header = rendered_label.detail();
- let footer = match &rendered_label.object {
- LabelledObject::Float { caption, .. } => Some(caption.clone()),
- _ => None,
- };
+ let header = rendered_label.detail(db);
+ let footer = match &rendered_label.object {
+ LabeledObject::Float { caption, .. } => Some(caption.clone()),
+ _ => None,
+ };
- let text = format!("{} {}", name, rendered_label.reference());
+ let text = format!(
+ "{} {}",
+ label.name(db).text(db),
+ rendered_label.reference(db)
+ );
- let item = InternalCompletionItem::new(
- range,
- InternalCompletionItemData::Label {
- name,
- kind,
- header,
- footer,
- text,
- },
- );
- items.push(item);
- }
- None => {
- let kind = Structure::Label;
- let header = None;
- let footer = None;
- let text = name.to_string();
- let item = InternalCompletionItem::new(
- range,
- InternalCompletionItemData::Label {
- name,
- kind,
- header,
- footer,
- text,
- },
- );
- items.push(item);
- }
+ builder.label(range, label.name(db).text(db), kind, header, footer, text);
+ }
+ None => {
+ let kind = Structure::Label;
+ let header = None;
+ let footer = None;
+ let text = label.name(db).text(db).clone();
+ builder.label(range, label.name(db).text(db), kind, header, footer, text);
}
}
}
@@ -87,14 +65,14 @@ pub fn complete_labels<'a>(
Some(())
}
-fn find_reference(context: &CursorContext<CompletionParams>) -> Option<(TextRange, bool)> {
+fn find_reference(context: &CursorContext) -> Option<(TextRange, bool)> {
let (_, range, group) = context.find_curly_group_word_list()?;
let reference = latex::LabelReference::cast(group.syntax().parent()?)?;
let is_math = reference.command()?.text() == "\\eqref";
Some((range, is_math))
}
-fn find_reference_range(context: &CursorContext<CompletionParams>) -> Option<(TextRange, bool)> {
+fn find_reference_range(context: &CursorContext) -> Option<(TextRange, bool)> {
let (_, range, group) = context.find_curly_group_word()?;
latex::LabelReferenceRange::cast(group.syntax().parent()?)?;
Some((range, false))
diff --git a/support/texlab/src/features/completion/theorem.rs b/support/texlab/src/features/completion/theorem.rs
index 65b511f7ad..cd0dfe3a84 100644
--- a/support/texlab/src/features/completion/theorem.rs
+++ b/support/texlab/src/features/completion/theorem.rs
@@ -1,24 +1,18 @@
-use lsp_types::CompletionParams;
+use crate::util::cursor::CursorContext;
-use crate::features::cursor::CursorContext;
+use super::builder::CompletionBuilder;
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
-
-pub fn complete_theorem_environments<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (_, range) = context.find_environment_name()?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- for environment in &data.extras.theorem_environments {
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::UserEnvironment {
- name: environment.name.clone(),
- },
- ));
+ let db = context.db;
+ for document in context.related() {
+ if let Some(data) = document.parse(db).as_tex() {
+ for environment in data.analyze(db).theorem_environments(db) {
+ builder.user_environment(range, environment.name(db).text(db));
}
}
}
diff --git a/support/texlab/src/features/completion/tikz_library.rs b/support/texlab/src/features/completion/tikz_library.rs
index bf15695722..7ea26d50c2 100644
--- a/support/texlab/src/features/completion/tikz_library.rs
+++ b/support/texlab/src/features/completion/tikz_library.rs
@@ -1,13 +1,15 @@
-use lsp_types::CompletionParams;
use rowan::ast::AstNode;
-use crate::{features::cursor::CursorContext, syntax::latex, LANGUAGE_DATA};
+use crate::{
+ syntax::latex,
+ util::{cursor::CursorContext, lang_data::LANGUAGE_DATA},
+};
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
+use super::builder::CompletionBuilder;
-pub fn complete_tikz_libraries<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (_, range, group) = context.find_curly_group_word_list()?;
@@ -15,17 +17,11 @@ pub fn complete_tikz_libraries<'a>(
if import.command()?.text() == "\\usepgflibrary" {
for name in &LANGUAGE_DATA.pgf_libraries {
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::PgfLibrary { name },
- ));
+ builder.tikz_library(range, name);
}
} else {
for name in &LANGUAGE_DATA.tikz_libraries {
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::TikzLibrary { name },
- ));
+ builder.tikz_library(range, name);
}
}
diff --git a/support/texlab/src/features/completion/types.rs b/support/texlab/src/features/completion/types.rs
deleted file mode 100644
index 3655c6a074..0000000000
--- a/support/texlab/src/features/completion/types.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-use std::sync::Arc;
-
-use lsp_types::Url;
-use rowan::TextRange;
-use serde::{Deserialize, Serialize};
-use smol_str::SmolStr;
-
-use crate::{features::lsp_kinds::Structure, BibtexEntryTypeDoc, BibtexFieldDoc};
-
-#[derive(Debug, Clone)]
-pub struct InternalCompletionItem<'a> {
- pub range: TextRange,
- pub data: InternalCompletionItemData<'a>,
- pub preselect: bool,
- pub score: Option<i64>,
-}
-
-impl<'a> InternalCompletionItem<'a> {
- pub fn new(range: TextRange, data: InternalCompletionItemData<'a>) -> Self {
- Self {
- range,
- data,
- preselect: false,
- score: None,
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub enum InternalCompletionItemData<'a> {
- EntryType {
- ty: &'a BibtexEntryTypeDoc,
- },
- Field {
- field: &'a BibtexFieldDoc,
- },
- Argument {
- name: &'a str,
- image: Option<&'a str>,
- },
- BeginCommand,
- Citation {
- uri: Arc<Url>,
- key: String,
- text: String,
- ty: Structure,
- },
- ComponentCommand {
- name: &'a SmolStr,
- image: Option<&'a str>,
- glyph: Option<&'a str>,
- file_names: &'a [SmolStr],
- },
- ComponentEnvironment {
- name: &'a SmolStr,
- file_names: &'a [SmolStr],
- },
- Class {
- name: SmolStr,
- },
- Package {
- name: SmolStr,
- },
- Color {
- name: &'a str,
- },
- ColorModel {
- name: &'a str,
- },
- Acronym {
- name: String,
- },
- GlossaryEntry {
- name: String,
- },
- File {
- name: SmolStr,
- },
- Directory {
- name: SmolStr,
- },
- Label {
- name: String,
- kind: Structure,
- header: Option<String>,
- footer: Option<String>,
- text: String,
- },
- UserCommand {
- name: SmolStr,
- },
- UserEnvironment {
- name: String,
- },
- PgfLibrary {
- name: &'a str,
- },
- TikzLibrary {
- name: &'a str,
- },
-}
-
-impl<'a> InternalCompletionItemData<'a> {
- pub fn label<'b: 'a>(&'b self) -> &'a str {
- match self {
- Self::EntryType { ty } => &ty.name,
- Self::Field { field } => &field.name,
- Self::Argument { name, .. } => name,
- Self::BeginCommand => "begin",
- Self::Citation { key, .. } => key,
- Self::ComponentCommand { name, .. } => name,
- Self::ComponentEnvironment { name, .. } => name,
- Self::Class { name } => name,
- Self::Package { name } => name,
- Self::Color { name } => name,
- Self::ColorModel { name } => name,
- Self::Acronym { name } => name,
- Self::GlossaryEntry { name } => name,
- Self::File { name } => name,
- Self::Directory { name } => name,
- Self::Label { name, .. } => name,
- Self::UserCommand { name } => name,
- Self::UserEnvironment { name } => name,
- Self::PgfLibrary { name } => name,
- Self::TikzLibrary { name } => name,
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub enum CompletionItemData {
- Command,
- CommandSnippet,
- Environment,
- Label,
- Folder,
- File,
- PgfLibrary,
- TikzLibrary,
- Color,
- ColorModel,
- Package,
- Class,
- EntryType,
- FieldName,
- Citation { uri: Url, key: SmolStr },
- Argument,
- Acronym,
- GlossaryEntry,
-}
diff --git a/support/texlab/src/features/completion/user_command.rs b/support/texlab/src/features/completion/user_command.rs
index 8c4d593bee..99d9883ee9 100644
--- a/support/texlab/src/features/completion/user_command.rs
+++ b/support/texlab/src/features/completion/user_command.rs
@@ -1,29 +1,27 @@
-use lsp_types::CompletionParams;
+use crate::util::cursor::CursorContext;
-use crate::features::cursor::CursorContext;
+use super::builder::CompletionBuilder;
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
-
-pub fn complete_user_commands<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let range = context.cursor.command_range(context.offset)?;
- let token = context.cursor.as_latex()?;
+ let token = context.cursor.as_tex()?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
+ let db = context.db;
+ for document in context.related() {
+ if let Some(data) = document.parse(db).as_tex() {
+ let text = document.contents(db).text(db);
for name in data
- .extras
- .command_names
+ .analyze(db)
+ .command_name_ranges(db)
.iter()
- .filter(|name| name.as_str() != token.text())
- .cloned()
+ .copied()
+ .filter(|range| *range != token.text_range())
+ .map(|range| &text[std::ops::Range::<usize>::from(range)])
{
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::UserCommand { name },
- ));
+ builder.user_command(range, name);
}
}
}
diff --git a/support/texlab/src/features/completion/user_environment.rs b/support/texlab/src/features/completion/user_environment.rs
index 91dd5a9ea2..cf6c2a7c78 100644
--- a/support/texlab/src/features/completion/user_environment.rs
+++ b/support/texlab/src/features/completion/user_environment.rs
@@ -1,28 +1,22 @@
-use lsp_types::CompletionParams;
+use crate::util::cursor::CursorContext;
-use crate::features::cursor::CursorContext;
+use super::builder::CompletionBuilder;
-use super::types::{InternalCompletionItem, InternalCompletionItemData};
-
-pub fn complete_user_environments<'a>(
- context: &'a CursorContext<CompletionParams>,
- items: &mut Vec<InternalCompletionItem<'a>>,
+pub fn complete<'db>(
+ context: &'db CursorContext,
+ builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
let (name, range) = context.find_environment_name()?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
+ for document in context.related() {
+ if let Some(data) = document.parse(context.db).as_tex() {
for name in data
- .extras
- .environment_names
+ .analyze(context.db)
+ .environment_names(context.db)
.iter()
.filter(|n| n.as_str() != name)
- .cloned()
{
- items.push(InternalCompletionItem::new(
- range,
- InternalCompletionItemData::UserEnvironment { name },
- ));
+ builder.user_environment(range, name);
}
}
}
diff --git a/support/texlab/src/features/completion/util.rs b/support/texlab/src/features/completion/util.rs
deleted file mode 100644
index 05827bbf24..0000000000
--- a/support/texlab/src/features/completion/util.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use lsp_types::{CompletionItemKind, CompletionParams, Documentation, MarkupContent, MarkupKind};
-use smol_str::SmolStr;
-
-use crate::features::FeatureRequest;
-
-pub fn component_detail(file_names: &[SmolStr]) -> String {
- if file_names.is_empty() {
- "built-in".to_owned()
- } else {
- file_names.join(", ")
- }
-}
-
-pub fn image_documentation(
- request: &FeatureRequest<CompletionParams>,
- name: &str,
- image: &str,
-) -> Option<Documentation> {
- if supports_images(request) {
- Some(Documentation::MarkupContent(MarkupContent {
- kind: MarkupKind::Markdown,
- value: format!(
- "![{}](data:image/png;base64,{}|width=48,height=48)",
- name, image
- ),
- }))
- } else {
- None
- }
-}
-
-fn supports_images(request: &FeatureRequest<CompletionParams>) -> bool {
- request
- .workspace
- .environment
- .client_capabilities
- .text_document
- .as_ref()
- .and_then(|cap| cap.completion.as_ref())
- .and_then(|cap| cap.completion_item.as_ref())
- .and_then(|cap| cap.documentation_format.as_ref())
- .map_or(true, |formats| formats.contains(&MarkupKind::Markdown))
-}
-
-pub fn adjust_kind(
- request: &FeatureRequest<CompletionParams>,
- kind: CompletionItemKind,
-) -> CompletionItemKind {
- if let Some(value_set) = request
- .workspace
- .environment
- .client_capabilities
- .text_document
- .as_ref()
- .and_then(|cap| cap.completion.as_ref())
- .and_then(|cap| cap.completion_item_kind.as_ref())
- .and_then(|cap| cap.value_set.as_ref())
- {
- if value_set.contains(&kind) {
- return kind;
- }
- }
- CompletionItemKind::TEXT
-}
diff --git a/support/texlab/src/features/definition.rs b/support/texlab/src/features/definition.rs
index 20da72a142..7c9e6d4841 100644
--- a/support/texlab/src/features/definition.rs
+++ b/support/texlab/src/features/definition.rs
@@ -4,48 +4,44 @@ mod entry;
mod label;
mod string;
-use std::sync::Arc;
-
-use lsp_types::{GotoDefinitionParams, GotoDefinitionResponse, LocationLink, Url};
+use lsp_types::{GotoDefinitionResponse, LocationLink, Position, Url};
use rowan::TextRange;
-use crate::LineIndexExt;
-
-use self::{
- command::goto_command_definition, document::goto_document_definition,
- entry::goto_entry_definition, label::goto_label_definition, string::goto_string_definition,
+use crate::{
+ db::Document,
+ util::{cursor::CursorContext, line_index_ext::LineIndexExt},
+ Db,
};
-use super::{cursor::CursorContext, FeatureRequest};
-
pub fn goto_definition(
- request: FeatureRequest<GotoDefinitionParams>,
+ db: &dyn Db,
+ uri: &Url,
+ position: Position,
) -> Option<GotoDefinitionResponse> {
- let context = CursorContext::new(request);
+ let context = CursorContext::new(db, uri, position, ())?;
log::debug!("[Definition] Cursor: {:?}", context.cursor);
- let origin_document = context.request.main_document();
- let links: Vec<_> = goto_command_definition(&context)
- .or_else(|| goto_document_definition(&context))
- .or_else(|| goto_entry_definition(&context))
- .or_else(|| goto_label_definition(&context))
- .or_else(|| goto_string_definition(&context))?
+ let links: Vec<_> = command::goto_definition(&context)
+ .or_else(|| document::goto_definition(&context))
+ .or_else(|| entry::goto_definition(&context))
+ .or_else(|| label::goto_definition(&context))
+ .or_else(|| string::goto_definition(&context))?
.into_iter()
.map(|result| {
let origin_selection_range = Some(
- origin_document
- .line_index
+ context
+ .document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(result.origin_selection_range),
);
- let target_document = &context.request.workspace.documents_by_uri[&result.target_uri];
- let target_uri = result.target_uri.as_ref().clone();
- let target_range = target_document
- .line_index
- .line_col_lsp_range(result.target_range);
- let target_selection_range = target_document
- .line_index
- .line_col_lsp_range(result.target_selection_range);
+ let target_line_index = result.target.contents(db).line_index(db);
+ let target_uri = result.target.location(context.db).uri(context.db).clone();
+ let target_range = target_line_index.line_col_lsp_range(result.target_range);
+
+ let target_selection_range =
+ target_line_index.line_col_lsp_range(result.target_selection_range);
LocationLink {
origin_selection_range,
@@ -62,7 +58,7 @@ pub fn goto_definition(
#[derive(Debug, Clone)]
struct DefinitionResult {
origin_selection_range: TextRange,
- target_uri: Arc<Url>,
+ target: Document,
target_range: TextRange,
target_selection_range: TextRange,
}
diff --git a/support/texlab/src/features/definition/command.rs b/support/texlab/src/features/definition/command.rs
index 599c792dfd..cf9fe1b511 100644
--- a/support/texlab/src/features/definition/command.rs
+++ b/support/texlab/src/features/definition/command.rs
@@ -1,26 +1,20 @@
-use std::sync::Arc;
-
-use lsp_types::GotoDefinitionParams;
use rowan::ast::AstNode;
-use crate::{features::cursor::CursorContext, syntax::latex};
+use crate::{syntax::latex, util::cursor::CursorContext};
use super::DefinitionResult;
-pub(super) fn goto_command_definition(
- context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<DefinitionResult>> {
+pub(super) fn goto_definition(context: &CursorContext) -> Option<Vec<DefinitionResult>> {
let name = context
.cursor
- .as_latex()
+ .as_tex()
.filter(|token| token.kind().is_command_name())?;
let origin_selection_range = name.text_range();
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- let root = latex::SyntaxNode::new_root(data.green.clone());
-
+ for document in context.related() {
+ if let Some(data) = document.parse(context.db).as_tex() {
+ let root = data.root(context.db);
if let Some(result) = root
.descendants()
.filter_map(latex::CommandDefinition::cast)
@@ -32,7 +26,7 @@ pub(super) fn goto_command_definition(
.find_map(|def| {
Some(DefinitionResult {
origin_selection_range,
- target_uri: Arc::clone(&document.uri),
+ target: document,
target_range: latex::small_range(&def),
target_selection_range: def.name()?.command()?.text_range(),
})
diff --git a/support/texlab/src/features/definition/document.rs b/support/texlab/src/features/definition/document.rs
index 1c09bbc88d..58237f7521 100644
--- a/support/texlab/src/features/definition/document.rs
+++ b/support/texlab/src/features/definition/document.rs
@@ -1,40 +1,30 @@
-use std::sync::Arc;
-
-use lsp_types::GotoDefinitionParams;
use rowan::TextRange;
-use crate::features::cursor::CursorContext;
+use crate::{db::dependency_graph, util::cursor::CursorContext};
use super::DefinitionResult;
-pub(super) fn goto_document_definition(
- context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<DefinitionResult>> {
- let data = context.request.main_document().data.as_latex()?;
-
- for include in data
- .extras
- .explicit_links
+pub(super) fn goto_definition(context: &CursorContext) -> Option<Vec<DefinitionResult>> {
+ let db = context.db;
+ context
+ .workspace
+ .parents(db, context.document)
.iter()
- .filter(|link| link.stem_range.contains_inclusive(context.offset))
- {
- for target in &include.targets {
- if context
- .request
- .workspace
- .documents_by_uri
- .values()
- .any(|document| document.uri.as_ref() == target.as_ref())
- {
- return Some(vec![DefinitionResult {
- origin_selection_range: include.stem_range,
- target_uri: Arc::clone(target),
+ .copied()
+ .chain(std::iter::once(context.document))
+ .flat_map(|parent| dependency_graph(db, parent).edges)
+ .filter(|edge| edge.source == context.document)
+ .find_map(|edge| {
+ let range = edge.origin?.link.range(db);
+ if range.contains_inclusive(context.offset) {
+ Some(vec![DefinitionResult {
+ origin_selection_range: range,
+ target: edge.target,
target_range: TextRange::default(),
target_selection_range: TextRange::default(),
- }]);
+ }])
+ } else {
+ None
}
- }
- }
-
- None
+ })
}
diff --git a/support/texlab/src/features/definition/entry.rs b/support/texlab/src/features/definition/entry.rs
index 1dcd983af1..a945b18c41 100644
--- a/support/texlab/src/features/definition/entry.rs
+++ b/support/texlab/src/features/definition/entry.rs
@@ -1,24 +1,21 @@
-use std::sync::Arc;
-
-use lsp_types::GotoDefinitionParams;
use rowan::ast::AstNode;
use crate::{
- features::cursor::CursorContext,
syntax::{
bibtex::{self, HasName},
latex,
},
+ util::cursor::CursorContext,
};
use super::DefinitionResult;
-pub(super) fn goto_entry_definition(
- context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<DefinitionResult>> {
+pub(super) fn goto_definition(context: &CursorContext) -> Option<Vec<DefinitionResult>> {
+ let db = context.db;
+
let word = context
.cursor
- .as_latex()
+ .as_tex()
.filter(|token| token.kind() == latex::WORD)?;
let key = latex::Key::cast(word.parent()?)?;
@@ -27,16 +24,13 @@ pub(super) fn goto_entry_definition(
let origin_selection_range = latex::small_range(&key);
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_bibtex() {
- for entry in bibtex::SyntaxNode::new_root(data.green.clone())
- .children()
- .filter_map(bibtex::Entry::cast)
- {
+ for document in context.related() {
+ if let Some(data) = document.parse(db).as_bib() {
+ for entry in data.root(db).children().filter_map(bibtex::Entry::cast) {
if let Some(key) = entry.name_token().filter(|k| k.text() == word.text()) {
return Some(vec![DefinitionResult {
origin_selection_range,
- target_uri: Arc::clone(&document.uri),
+ target: document,
target_selection_range: key.text_range(),
target_range: entry.syntax().text_range(),
}]);
diff --git a/support/texlab/src/features/definition/label.rs b/support/texlab/src/features/definition/label.rs
index 867e8a1076..a1cc4ed15b 100644
--- a/support/texlab/src/features/definition/label.rs
+++ b/support/texlab/src/features/definition/label.rs
@@ -1,31 +1,32 @@
-use std::sync::Arc;
-
-use lsp_types::GotoDefinitionParams;
-
-use crate::{features::cursor::CursorContext, find_label_definition, render_label, syntax::latex};
+use crate::{
+ db::analysis::label,
+ util::{self, cursor::CursorContext},
+};
use super::DefinitionResult;
-pub(super) fn goto_label_definition(
- context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<DefinitionResult>> {
+pub(super) fn goto_definition(context: &CursorContext) -> Option<Vec<DefinitionResult>> {
+ let db = context.db;
let (name_text, origin_selection_range) = context
.find_label_name_key()
.or_else(|| context.find_label_name_command())?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- let root = latex::SyntaxNode::new_root(data.green.clone());
- if let Some(definition) = find_label_definition(&root, &name_text) {
- let target_selection_range = latex::small_range(&definition.name()?.key()?);
- let target_range =
- render_label(&context.request.workspace, &name_text, Some(definition))
- .map(|label| label.range)
- .unwrap_or(target_selection_range);
+ for document in context.related() {
+ if let Some(data) = document.parse(db).as_tex() {
+ if let Some(label) = data
+ .analyze(db)
+ .labels(db)
+ .iter()
+ .filter(|label| matches!(label.origin(db), label::Origin::Definition(_)))
+ .find(|label| label.name(db).text(db) == name_text.as_str())
+ {
+ let target_selection_range = label.range(db);
+ let target_range = util::label::render(db, document, *label)
+ .map_or(target_selection_range, |label| label.range);
return Some(vec![DefinitionResult {
origin_selection_range,
- target_uri: Arc::clone(&document.uri),
+ target: document,
target_range,
target_selection_range,
}]);
diff --git a/support/texlab/src/features/definition/string.rs b/support/texlab/src/features/definition/string.rs
index c774e24e1d..44ea1e9094 100644
--- a/support/texlab/src/features/definition/string.rs
+++ b/support/texlab/src/features/definition/string.rs
@@ -1,43 +1,34 @@
-use std::sync::Arc;
-
-use lsp_types::GotoDefinitionParams;
use rowan::ast::AstNode;
use crate::{
- features::cursor::CursorContext,
syntax::bibtex::{self, HasName},
+ util::cursor::CursorContext,
};
use super::DefinitionResult;
-pub(super) fn goto_string_definition(
- context: &CursorContext<GotoDefinitionParams>,
-) -> Option<Vec<DefinitionResult>> {
- let main_document = context.request.main_document();
-
- let data = main_document.data.as_bibtex()?;
+pub(super) fn goto_definition(context: &CursorContext) -> Option<Vec<DefinitionResult>> {
+ let db = context.db;
+ let data = context.document.parse(db).as_bib()?;
let key = context
.cursor
- .as_bibtex()
+ .as_bib()
.filter(|token| token.kind() == bibtex::NAME)?;
bibtex::Value::cast(key.parent()?)?;
let origin_selection_range = key.text_range();
- for string in bibtex::SyntaxNode::new_root(data.green.clone())
+ data.root(db)
.children()
.filter_map(bibtex::StringDef::cast)
- {
- if let Some(string_name) = string.name_token().filter(|k| k.text() == key.text()) {
- return Some(vec![DefinitionResult {
+ .find_map(|string| {
+ let string_name = string.name_token().filter(|k| k.text() == key.text())?;
+ Some(vec![DefinitionResult {
origin_selection_range,
- target_uri: Arc::clone(&main_document.uri),
+ target: context.document,
target_selection_range: string_name.text_range(),
target_range: string.syntax().text_range(),
- }]);
- }
- }
-
- None
+ }])
+ })
}
diff --git a/support/texlab/src/features/execute_command.rs b/support/texlab/src/features/execute_command.rs
deleted file mode 100644
index b1b89d4f50..0000000000
--- a/support/texlab/src/features/execute_command.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use std::{path::PathBuf, process::Stdio, sync::Arc};
-
-use anyhow::Result;
-use lsp_types::{TextDocumentIdentifier, Url};
-
-use crate::Workspace;
-
-pub fn execute_command(
- workspace: &Workspace,
- name: &str,
- args: Vec<serde_json::Value>,
-) -> Result<()> {
- match name {
- "texlab.cleanAuxiliary" => {
- let params = args
- .into_iter()
- .next()
- .ok_or_else(|| anyhow::anyhow!("texlab.cleanAuxiliary requires one argument"))?;
-
- clean_output_files(workspace, CleanOptions::Auxiliary, params)?;
- }
- "texlab.cleanArtifacts" => {
- let params = args
- .into_iter()
- .next()
- .ok_or_else(|| anyhow::anyhow!("texlab.cleanArtifacts requires one argument"))?;
-
- clean_output_files(workspace, CleanOptions::Artifacts, params)?;
- }
- _ => anyhow::bail!("Unknown command: {}", name),
- }
-
- Ok(())
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
-enum CleanOptions {
- Auxiliary,
- Artifacts,
-}
-
-fn clean_output_files(
- workspace: &Workspace,
- options: CleanOptions,
- params: serde_json::Value,
-) -> Result<()> {
- let params: TextDocumentIdentifier = serde_json::from_value(params)?;
-
- let uri = workspace
- .find_parent(&params.uri)
- .map(|document| document.uri)
- .unwrap_or_else(|| Arc::new(params.uri));
-
- if let Some(cx) = BuildContext::find(workspace, &uri) {
- let flag = match options {
- CleanOptions::Auxiliary => "-c",
- CleanOptions::Artifacts => "-C",
- };
-
- std::process::Command::new("latexmk")
- .arg(format!("-outdir={}", cx.output_dir.to_string_lossy()))
- .arg(flag)
- .arg(cx.input_file)
- .stdin(Stdio::null())
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .status()?;
- }
-
- Ok(())
-}
-
-struct BuildContext {
- input_file: PathBuf,
- output_dir: PathBuf,
-}
-
-impl BuildContext {
- pub fn find(workspace: &Workspace, uri: &Url) -> Option<Self> {
- if uri.scheme() != "file" {
- return None;
- }
-
- let input_file = uri.to_file_path().ok()?;
- let options = &workspace.environment.options;
- let current_dir = &workspace.environment.current_directory;
- let output_dir = match (
- options.root_directory.as_ref(),
- options.aux_directory.as_ref(),
- ) {
- (_, Some(aux_dir)) => current_dir.join(aux_dir),
- (Some(root_dir), None) => current_dir.join(root_dir),
- (None, None) => input_file.parent()?.to_path_buf(),
- };
-
- log::info!("Output = {:#?}", output_dir);
-
- Some(Self {
- input_file,
- output_dir,
- })
- }
-}
diff --git a/support/texlab/src/features/folding.rs b/support/texlab/src/features/folding.rs
index 71fb0bee6f..ea26121f3f 100644
--- a/support/texlab/src/features/folding.rs
+++ b/support/texlab/src/features/folding.rs
@@ -1,49 +1,52 @@
-use lsp_types::{FoldingRange, FoldingRangeKind, FoldingRangeParams, Range};
+use lsp_types::{FoldingRange, FoldingRangeKind, Range, Url};
use rowan::ast::AstNode;
use crate::{
+ db::{parse::DocumentData, Workspace},
syntax::{bibtex, latex},
- DocumentData, LineIndexExt,
+ util::line_index_ext::LineIndexExt,
+ Db,
};
-use super::FeatureRequest;
-
-pub fn find_foldings(request: FeatureRequest<FoldingRangeParams>) -> Vec<FoldingRange> {
- let mut foldings = Vec::new();
- let main_document = request.main_document();
- match &main_document.data {
- DocumentData::Latex(data) => {
- for node in latex::SyntaxNode::new_root(data.green.clone()).descendants() {
+pub fn find_all(db: &dyn Db, uri: &Url) -> Option<Vec<FoldingRange>> {
+ let document = Workspace::get(db).lookup_uri(db, uri)?;
+ let line_index = document.contents(db).line_index(db);
+ let foldings = match document.parse(db) {
+ DocumentData::Tex(data) => {
+ let mut results = Vec::new();
+ let root = data.root(db);
+ for node in root.descendants() {
if let Some(folding) = latex::Environment::cast(node.clone())
.map(|node| latex::small_range(&node))
.or_else(|| {
latex::Section::cast(node.clone()).map(|node| latex::small_range(&node))
})
.or_else(|| latex::EnumItem::cast(node).map(|node| latex::small_range(&node)))
- .map(|node| main_document.line_index.line_col_lsp_range(node))
+ .map(|node| line_index.line_col_lsp_range(node))
.map(create_range)
{
- foldings.push(folding);
+ results.push(folding);
}
}
+
+ results
}
- DocumentData::Bibtex(data) => {
- for node in bibtex::SyntaxNode::new_root(data.green.clone()).descendants() {
- if matches!(
- node.kind(),
- bibtex::PREAMBLE | bibtex::STRING | bibtex::ENTRY
- ) {
- foldings.push(create_range(
- main_document
- .line_index
- .line_col_lsp_range(node.text_range()),
- ));
- }
- }
+ DocumentData::Bib(data) => {
+ let root = data.root(db);
+ root.descendants()
+ .filter(|node| {
+ matches!(
+ node.kind(),
+ bibtex::PREAMBLE | bibtex::STRING | bibtex::ENTRY
+ )
+ })
+ .map(|node| create_range(line_index.line_col_lsp_range(node.text_range())))
+ .collect()
}
- DocumentData::BuildLog(_) => {}
- }
- foldings
+ DocumentData::Log(_) => return None,
+ };
+
+ Some(foldings)
}
fn create_range(range: Range) -> FoldingRange {
diff --git a/support/texlab/src/features/formatting.rs b/support/texlab/src/features/formatting.rs
index 1107e5fd38..66375bd576 100644
--- a/support/texlab/src/features/formatting.rs
+++ b/support/texlab/src/features/formatting.rs
@@ -1,26 +1,31 @@
mod bibtex_internal;
mod latexindent;
-use lsp_types::{DocumentFormattingParams, TextEdit};
+use lsp_types::{FormattingOptions, TextEdit, Url};
-use crate::{BibtexFormatter, LatexFormatter};
+use crate::{
+ db::{Language, Workspace},
+ BibtexFormatter, Db, LatexFormatter,
+};
use self::{bibtex_internal::format_bibtex_internal, latexindent::format_with_latexindent};
-use super::FeatureRequest;
-
pub fn format_source_code(
- request: FeatureRequest<DocumentFormattingParams>,
+ db: &dyn Db,
+ uri: &Url,
+ options: &FormattingOptions,
) -> Option<Vec<TextEdit>> {
- let mut edits = None;
- if request.workspace.environment.options.bibtex_formatter == BibtexFormatter::Texlab {
- edits = edits.or_else(|| format_bibtex_internal(&request));
- }
-
- if request.workspace.environment.options.latex_formatter == LatexFormatter::Texlab {
- edits = edits.or_else(|| Some(vec![]));
+ let workspace = Workspace::get(db);
+ let document = workspace.lookup_uri(db, uri)?;
+ match document.language(db) {
+ Language::Tex => match workspace.options(db).latex_formatter {
+ LatexFormatter::Texlab => None,
+ LatexFormatter::Latexindent => format_with_latexindent(db, document),
+ },
+ Language::Bib => match workspace.options(db).bibtex_formatter {
+ BibtexFormatter::Texlab => format_bibtex_internal(db, document, options),
+ BibtexFormatter::Latexindent => format_with_latexindent(db, document),
+ },
+ Language::Log => None,
}
-
- edits = edits.or_else(|| format_with_latexindent(&request));
- edits
}
diff --git a/support/texlab/src/features/formatting/bibtex_internal.rs b/support/texlab/src/features/formatting/bibtex_internal.rs
index 2dcc507be9..8447778d90 100644
--- a/support/texlab/src/features/formatting/bibtex_internal.rs
+++ b/support/texlab/src/features/formatting/bibtex_internal.rs
@@ -1,63 +1,57 @@
-use lsp_types::{DocumentFormattingParams, TextEdit};
+use lsp_types::{FormattingOptions, TextEdit};
use rowan::{ast::AstNode, NodeOrToken};
use crate::{
- features::FeatureRequest,
+ db::{Document, Workspace},
syntax::bibtex::{self, HasName, HasType, HasValue},
- LineIndex, LineIndexExt,
+ util::{line_index::LineIndex, line_index_ext::LineIndexExt},
+ Db,
};
pub fn format_bibtex_internal(
- request: &FeatureRequest<DocumentFormattingParams>,
+ db: &dyn Db,
+ document: Document,
+ options: &FormattingOptions,
) -> Option<Vec<TextEdit>> {
let mut indent = String::new();
- if request.params.options.insert_spaces {
- for _ in 0..request.params.options.tab_size {
+
+ if options.insert_spaces {
+ for _ in 0..options.tab_size {
indent.push(' ');
}
} else {
indent.push('\t');
}
- let line_length = request
- .workspace
- .environment
- .options
+ let line_length = Workspace::get(db)
+ .options(db)
.formatter_line_length
- .map(|value| {
+ .map_or(80, |value| {
if value <= 0 {
usize::MAX
} else {
value as usize
}
- })
- .unwrap_or(80);
+ });
- let document = request.main_document();
- let data = document.data.as_bibtex()?;
+ let line_index = document.contents(db).line_index(db);
+ let data = document.parse(db).as_bib()?;
let mut edits = Vec::new();
- for node in bibtex::SyntaxNode::new_root(data.green.clone())
- .children()
- .filter(|node| {
- matches!(
- node.kind(),
- bibtex::PREAMBLE | bibtex::STRING | bibtex::ENTRY
- )
- })
- {
+ for node in data.root(db).children().filter(|node| {
+ matches!(
+ node.kind(),
+ bibtex::PREAMBLE | bibtex::STRING | bibtex::ENTRY
+ )
+ }) {
let range = node.text_range();
- let mut formatter = Formatter::new(
- indent.clone(),
- request.params.options.tab_size,
- line_length,
- &document.line_index,
- );
+ let mut formatter =
+ Formatter::new(indent.clone(), options.tab_size, line_length, line_index);
formatter.visit_node(node);
edits.push(TextEdit {
- range: document.line_index.line_col_lsp_range(range),
+ range: line_index.line_col_lsp_range(range),
new_text: formatter.output,
});
}
diff --git a/support/texlab/src/features/formatting/latexindent.rs b/support/texlab/src/features/formatting/latexindent.rs
index 4898aa4415..3dab10c923 100644
--- a/support/texlab/src/features/formatting/latexindent.rs
+++ b/support/texlab/src/features/formatting/latexindent.rs
@@ -1,94 +1,78 @@
use std::{
- fs,
+ path::Path,
process::{Command, Stdio},
};
-use lsp_types::{DocumentFormattingParams, TextEdit};
+use lsp_types::TextEdit;
use rowan::{TextLen, TextRange};
use tempfile::tempdir;
-use crate::{features::FeatureRequest, DocumentLanguage, LineIndexExt};
-
-pub fn format_with_latexindent(
- request: &FeatureRequest<DocumentFormattingParams>,
-) -> Option<Vec<TextEdit>> {
- let directory = tempdir().ok()?;
- let document = request.main_document();
+use crate::{
+ db::{Document, Language, Workspace},
+ util::line_index_ext::LineIndexExt,
+ Db, LatexindentOptions,
+};
- let options = &request.workspace.environment.options;
- let current_dir = options
- .root_directory
- .as_ref()
- .cloned()
- .or_else(|| {
- if document.uri.scheme() == "file" {
- document
- .uri
- .to_file_path()
- .unwrap()
- .parent()
- .map(ToOwned::to_owned)
- } else {
- None
- }
- })
- .unwrap_or_else(|| ".".into());
+pub fn format_with_latexindent(db: &dyn Db, document: Document) -> Option<Vec<TextEdit>> {
+ let workspace = Workspace::get(db);
+ let options = workspace.options(db);
+ let target_dir = tempdir().ok()?;
+ let source_dir = workspace
+ .working_dir(db, document.directory(db))
+ .path(db)
+ .as_deref()?;
- let local = match &options.latexindent.local {
- Some(local) => format!("--local={}", local),
- None => "-l".to_string(),
- };
+ let target_file = target_dir
+ .path()
+ .join(if document.language(db) == Language::Bib {
+ "file.bib"
+ } else {
+ "file.tex"
+ });
+ std::fs::write(&target_file, document.contents(db).text(db)).ok()?;
- let modify_line_breaks = options.latexindent.modify_line_breaks;
+ let args = build_arguments(&options.latexindent, &target_file);
- let path = directory.path();
- let _ = fs::copy(
- current_dir.join("localSettings.yaml"),
- path.join("localSettings.yaml"),
- );
- let _ = fs::copy(
- current_dir.join(".localSettings.yaml"),
- path.join(".localSettings.yaml"),
- );
- let _ = fs::copy(
- current_dir.join("latexindent.yaml"),
- path.join("latexindent.yaml"),
+ log::debug!(
+ "Running latexindent in folder \"{}\" with args: {:?}",
+ source_dir.display(),
+ args,
);
- let name = if document.data.language() == DocumentLanguage::Bibtex {
- "file.bib"
- } else {
- "file.tex"
- };
-
- fs::write(directory.path().join(name), document.text.as_str()).ok()?;
-
- let mut args = Vec::new();
- if modify_line_breaks {
- args.push("--modifylinebreaks");
- }
- args.push(&local);
- args.push(name);
-
let output = Command::new("latexindent")
.args(&args)
- .current_dir(current_dir)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
- .current_dir(directory.path())
+ .current_dir(source_dir)
.output()
.ok()?;
+ let old_text = document.contents(db).text(db);
let new_text = String::from_utf8_lossy(&output.stdout).into_owned();
if new_text.is_empty() {
None
} else {
+ let line_index = document.contents(db).line_index(db);
Some(vec![TextEdit {
- range: document
- .line_index
- .line_col_lsp_range(TextRange::new(0.into(), document.text.text_len())),
+ range: line_index.line_col_lsp_range(TextRange::new(0.into(), old_text.text_len())),
new_text,
}])
}
}
+
+fn build_arguments(options: &LatexindentOptions, target_file: &Path) -> Vec<String> {
+ let mut args = Vec::new();
+
+ args.push(match &options.local {
+ Some(yaml_file) => format!("--local={yaml_file}"),
+ None => "--local".to_string(),
+ });
+
+ if options.modify_line_breaks {
+ args.push("--modifylinebreaks".to_string());
+ }
+
+ args.push(target_file.display().to_string());
+ args
+}
diff --git a/support/texlab/src/features/forward_search.rs b/support/texlab/src/features/forward_search.rs
index 54629d0dc0..47be702659 100644
--- a/support/texlab/src/features/forward_search.rs
+++ b/support/texlab/src/features/forward_search.rs
@@ -1,94 +1,120 @@
use std::{
io,
- path::Path,
- process::{Command, Stdio},
+ path::{Path, PathBuf},
+ process::Stdio,
};
use log::error;
-use lsp_types::TextDocumentPositionParams;
-use serde::{Deserialize, Serialize};
-use serde_repr::{Deserialize_repr, Serialize_repr};
-
-use super::FeatureRequest;
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize_repr, Deserialize_repr)]
-#[repr(i32)]
-pub enum ForwardSearchStatus {
- SUCCESS = 0,
- ERROR = 1,
- FAILURE = 2,
- UNCONFIGURED = 3,
+use lsp_types::{Position, Url};
+use thiserror::Error;
+
+use crate::{db::Workspace, util::line_index_ext::LineIndexExt, Db};
+
+#[derive(Debug, Error)]
+pub enum Error {
+ #[error("TeX document '{0}' not found")]
+ TexNotFound(Url),
+
+ #[error("PDF document '{0}' not found")]
+ PdfNotFound(PathBuf),
+
+ #[error("TeX document '{0}' is not a local file")]
+ NoLocalFile(Url),
+
+ #[error("PDF viewer is not configured")]
+ Unconfigured,
+
+ #[error("Failed to spawn process: {0}")]
+ Spawn(io::Error),
}
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-pub struct ForwardSearchResult {
- pub status: ForwardSearchStatus,
+pub struct Command {
+ executable: String,
+ args: Vec<String>,
}
-pub fn execute_forward_search(
- request: FeatureRequest<TextDocumentPositionParams>,
-) -> Option<ForwardSearchResult> {
- let options = &request.workspace.environment.options.forward_search;
+impl Command {
+ pub fn configure(db: &dyn Db, uri: &Url, position: Option<Position>) -> Result<Self, Error> {
+ let workspace = Workspace::get(db);
+ let child = workspace
+ .lookup_uri(db, uri)
+ .ok_or_else(|| Error::TexNotFound(uri.clone()))?;
+
+ let parent = workspace
+ .parents(db, child)
+ .iter()
+ .copied()
+ .next()
+ .unwrap_or(child);
+
+ let output_dir = workspace
+ .output_dir(db, workspace.working_dir(db, parent.directory(db)))
+ .path(db)
+ .as_deref()
+ .ok_or_else(|| Error::NoLocalFile(uri.clone()))?;
+
+ let tex_path = child
+ .location(db)
+ .path(db)
+ .as_deref()
+ .ok_or_else(|| Error::NoLocalFile(uri.clone()))?;
+
+ let pdf_name = format!("{}.pdf", parent.location(db).stem(db).unwrap());
+ let pdf_path = output_dir.join(pdf_name);
+ if !pdf_path.exists() {
+ return Err(Error::PdfNotFound(pdf_path));
+ }
- if options.executable.is_none() || options.args.is_none() {
- return Some(ForwardSearchResult {
- status: ForwardSearchStatus::UNCONFIGURED,
+ let position = position.unwrap_or_else(|| {
+ child
+ .contents(db)
+ .line_index(db)
+ .line_col_lsp(child.cursor(db))
});
+
+ let options = &workspace.options(db).forward_search;
+
+ let executable = options
+ .executable
+ .as_deref()
+ .ok_or(Error::Unconfigured)?
+ .to_string();
+
+ let args: Vec<_> = options
+ .args
+ .as_deref()
+ .ok_or(Error::Unconfigured)?
+ .iter()
+ .flat_map(|arg| replace_placeholder(tex_path, &pdf_path, position.line, arg))
+ .collect();
+
+ Ok(Self { executable, args })
}
+}
- let root_document = request
- .workspace
- .documents_by_uri
- .values()
- .find(|document| {
- if let Some(data) = document.data.as_latex() {
- data.extras.has_document_environment
- && !data
- .extras
- .explicit_links
- .iter()
- .filter_map(|link| link.as_component_name())
- .any(|name| name == "subfiles.cls")
- } else {
- false
- }
- })
- .filter(|document| document.uri.scheme() == "file")?;
-
- let data = root_document.data.as_latex()?;
- let pdf_path = data
- .extras
- .implicit_links
- .pdf
- .iter()
- .filter_map(|uri| uri.to_file_path().ok())
- .find(|path| path.exists())?;
-
- let tex_path = request.main_document().uri.to_file_path().ok()?;
-
- let args: Vec<String> = options
- .args
- .as_ref()
- .unwrap()
- .iter()
- .flat_map(|arg| {
- replace_placeholder(&tex_path, &pdf_path, request.params.position.line, arg)
- })
- .collect();
-
- let status = match run_process(options.executable.as_ref().unwrap(), args) {
- Ok(()) => ForwardSearchStatus::SUCCESS,
- Err(why) => {
- error!("Unable to execute forward search: {}", why);
- ForwardSearchStatus::FAILURE
- }
- };
- Some(ForwardSearchResult { status })
+impl Command {
+ pub fn run(self) -> Result<(), Error> {
+ log::debug!(
+ "Executing forward search: {} {:?}",
+ self.executable,
+ self.args
+ );
+
+ std::process::Command::new(self.executable)
+ .args(self.args)
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()
+ .map_err(Error::Spawn)?;
+
+ Ok(())
+ }
}
/// Iterate overs chunks of a string. Either returns a slice of the
/// original string, or the placeholder replacement.
-pub struct PlaceHolderIterator<'a> {
+struct PlaceHolderIterator<'a> {
remainder: &'a str,
tex_file: &'a str,
pdf_file: &'a str,
@@ -168,13 +194,3 @@ fn replace_placeholder(
};
Some(result)
}
-
-fn run_process(executable: &str, args: Vec<String>) -> io::Result<()> {
- Command::new(executable)
- .args(args)
- .stdin(Stdio::null())
- .stdout(Stdio::null())
- .stderr(Stdio::null())
- .status()?;
- Ok(())
-}
diff --git a/support/texlab/src/features/highlight.rs b/support/texlab/src/features/highlight.rs
index b2c5794461..52746a040f 100644
--- a/support/texlab/src/features/highlight.rs
+++ b/support/texlab/src/features/highlight.rs
@@ -1,14 +1,10 @@
mod label;
-use lsp_types::{DocumentHighlight, DocumentHighlightParams};
+use lsp_types::{DocumentHighlight, Position, Url};
-use self::label::find_label_highlights;
+use crate::{util::cursor::CursorContext, Db};
-use super::{cursor::CursorContext, FeatureRequest};
-
-pub fn find_document_highlights(
- request: FeatureRequest<DocumentHighlightParams>,
-) -> Option<Vec<DocumentHighlight>> {
- let context = CursorContext::new(request);
- find_label_highlights(&context)
+pub fn find_all(db: &dyn Db, uri: &Url, position: Position) -> Option<Vec<DocumentHighlight>> {
+ let context = CursorContext::new(db, uri, position, ())?;
+ label::find_highlights(&context)
}
diff --git a/support/texlab/src/features/highlight/label.rs b/support/texlab/src/features/highlight/label.rs
index cb51abdd68..2ae66d5c47 100644
--- a/support/texlab/src/features/highlight/label.rs
+++ b/support/texlab/src/features/highlight/label.rs
@@ -1,78 +1,31 @@
-use lsp_types::{DocumentHighlight, DocumentHighlightKind, DocumentHighlightParams};
-use rowan::ast::AstNode;
+use lsp_types::{DocumentHighlight, DocumentHighlightKind};
-use crate::{features::cursor::CursorContext, syntax::latex, LineIndexExt};
+use crate::{
+ db::analysis::label,
+ util::{cursor::CursorContext, line_index_ext::LineIndexExt},
+};
-pub fn find_label_highlights(
- context: &CursorContext<DocumentHighlightParams>,
-) -> Option<Vec<DocumentHighlight>> {
+pub fn find_highlights(context: &CursorContext) -> Option<Vec<DocumentHighlight>> {
+ let db = context.db;
let (name_text, _) = context.find_label_name_key()?;
-
- let main_document = context.request.main_document();
- let data = main_document.data.as_latex()?;
+ let data = context.document.parse(db).as_tex()?;
let mut highlights = Vec::new();
- for node in latex::SyntaxNode::new_root(data.green.clone()).descendants() {
- if let Some(label_name) = latex::LabelDefinition::cast(node.clone())
- .and_then(|label| label.name())
- .and_then(|label_name| label_name.key())
- .filter(|label_name| label_name.to_string() == name_text)
- {
- let range = main_document
- .line_index
- .line_col_lsp_range(latex::small_range(&label_name));
-
- highlights.push(DocumentHighlight {
- range,
- kind: Some(DocumentHighlightKind::WRITE),
- });
- } else if let Some(label) = latex::LabelReference::cast(node.clone()) {
- for label_name in label
- .name_list()
- .into_iter()
- .flat_map(|name| name.keys())
- .filter(|label_name| label_name.to_string() == name_text)
- {
- let range = main_document
- .line_index
- .line_col_lsp_range(latex::small_range(&label_name));
-
- highlights.push(DocumentHighlight {
- range,
- kind: Some(DocumentHighlightKind::READ),
- });
- }
- } else if let Some(label) = latex::LabelReferenceRange::cast(node.clone()) {
- if let Some(label_name) = label
- .from()
- .and_then(|label_name| label_name.key())
- .filter(|label_name| label_name.to_string() == name_text)
- {
- let range = main_document
- .line_index
- .line_col_lsp_range(latex::small_range(&label_name));
-
- highlights.push(DocumentHighlight {
- range,
- kind: Some(DocumentHighlightKind::READ),
- });
- }
-
- if let Some(label_name) = label
- .to()
- .and_then(|label_name| label_name.key())
- .filter(|label_name| label_name.to_string() == name_text)
- {
- let range = main_document
- .line_index
- .line_col_lsp_range(latex::small_range(&label_name));
-
- highlights.push(DocumentHighlight {
- range,
- kind: Some(DocumentHighlightKind::READ),
- });
- }
- }
+ let line_index = context.document.contents(db).line_index(db);
+ for label in data
+ .analyze(db)
+ .labels(db)
+ .iter()
+ .filter(|label| label.name(db).text(db) == &name_text)
+ {
+ let range = line_index.line_col_lsp_range(label.range(db));
+ let kind = Some(match label.origin(db) {
+ label::Origin::Definition(_) => DocumentHighlightKind::WRITE,
+ label::Origin::Reference(_) => DocumentHighlightKind::READ,
+ label::Origin::ReferenceRange(_) => DocumentHighlightKind::READ,
+ });
+
+ highlights.push(DocumentHighlight { range, kind });
}
Some(highlights)
diff --git a/support/texlab/src/features/hover.rs b/support/texlab/src/features/hover.rs
index 8663f6256d..27d07f74cd 100644
--- a/support/texlab/src/features/hover.rs
+++ b/support/texlab/src/features/hover.rs
@@ -5,43 +5,32 @@ mod field;
mod label;
mod string_ref;
-use lsp_types::{Hover, HoverContents, HoverParams, MarkupContent, MarkupKind};
+use lsp_types::{Hover, HoverContents, MarkupContent, MarkupKind, Position, Url};
use rowan::TextRange;
use crate::{
- features::{cursor::CursorContext, hover::citation::find_citation_hover},
- LineIndexExt,
+ util::{cursor::CursorContext, line_index_ext::LineIndexExt},
+ Db,
};
-use self::{
- component::find_component_hover, entry_type::find_entry_type_hover, field::find_field_hover,
- label::find_label_hover, string_ref::find_string_reference_hover,
-};
-
-use super::FeatureRequest;
-
-pub fn find_hover(request: FeatureRequest<HoverParams>) -> Option<Hover> {
- let context = CursorContext::new(request);
+pub fn find(db: &dyn Db, uri: &Url, position: Position) -> Option<Hover> {
+ let context = CursorContext::new(db, uri, position, ())?;
log::debug!("[Hover] Cursor: {:?}", context.cursor);
- let result = find_label_hover(&context)
- .or_else(|| find_citation_hover(&context))
- .or_else(|| find_component_hover(&context))
- .or_else(|| find_string_reference_hover(&context))
- .or_else(|| find_field_hover(&context))
- .or_else(|| find_entry_type_hover(&context))?;
+ let result = label::find_hover(&context)
+ .or_else(|| citation::find_hover(&context))
+ .or_else(|| component::find_hover(&context))
+ .or_else(|| string_ref::find_hover(&context))
+ .or_else(|| field::find_hover(&context))
+ .or_else(|| entry_type::find_hover(&context))?;
+
+ let line_index = context.document.contents(db).line_index(db);
Some(Hover {
contents: HoverContents::Markup(MarkupContent {
kind: result.value_kind,
value: result.value,
}),
- range: Some(
- context
- .request
- .main_document()
- .line_index
- .line_col_lsp_range(result.range),
- ),
+ range: Some(line_index.line_col_lsp_range(result.range)),
})
}
diff --git a/support/texlab/src/features/hover/citation.rs b/support/texlab/src/features/hover/citation.rs
index 5e86019eee..e0e17176d5 100644
--- a/support/texlab/src/features/hover/citation.rs
+++ b/support/texlab/src/features/hover/citation.rs
@@ -1,28 +1,23 @@
-use lsp_types::{HoverParams, MarkupKind};
+use lsp_types::MarkupKind;
use rowan::ast::AstNode;
-use crate::{citation, features::cursor::CursorContext, syntax::bibtex};
+use crate::{citation, syntax::bibtex, util::cursor::CursorContext};
use super::HoverResult;
-pub(super) fn find_citation_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
+pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
let (key, range) = context
.find_citation_key_word()
.or_else(|| context.find_citation_key_command())
.or_else(|| context.find_entry_key())?;
- let value = context
- .request
- .workspace
- .documents_by_uri
- .values()
- .find_map(|document| {
- let data = document.data.as_bibtex()?;
- let root = bibtex::SyntaxNode::new_root(data.green.clone());
- let root = bibtex::Root::cast(root)?;
- let entry = root.find_entry(&key)?;
- citation::render(&entry)
- })?;
+ let value = context.related().find_map(|document| {
+ let data = document.parse(context.db).as_bib()?;
+ let root = data.root(context.db);
+ let root = bibtex::Root::cast(root)?;
+ let entry = root.find_entry(&key)?;
+ citation::render(&entry)
+ })?;
Some(HoverResult {
range,
diff --git a/support/texlab/src/features/hover/component.rs b/support/texlab/src/features/hover/component.rs
index 737a99d3ea..61a428a9ce 100644
--- a/support/texlab/src/features/hover/component.rs
+++ b/support/texlab/src/features/hover/component.rs
@@ -1,25 +1,28 @@
-use lsp_types::{HoverParams, MarkupKind};
+use lsp_types::MarkupKind;
-use crate::{component_db::COMPONENT_DATABASE, features::cursor::CursorContext, syntax::latex};
+use crate::{
+ db::analysis::TexLinkKind,
+ util::{components::COMPONENT_DATABASE, cursor::CursorContext},
+};
use super::HoverResult;
-pub(super) fn find_component_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
- let data = context.request.main_document().data.as_latex()?;
- for link in &data.extras.explicit_links {
- if matches!(
- link.kind,
- latex::ExplicitLinkKind::Package | latex::ExplicitLinkKind::Class
- ) && link.stem_range.contains_inclusive(context.offset)
- {
- let value = COMPONENT_DATABASE.documentation(&link.stem)?.value;
- return Some(HoverResult {
+pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
+ let db = context.db;
+ let links = context.document.parse(db).as_tex()?.analyze(db).links(db);
+ links
+ .iter()
+ .filter(|link| matches!(link.kind(db), TexLinkKind::Sty | TexLinkKind::Cls))
+ .filter(|link| link.range(db).contains_inclusive(context.offset))
+ .find_map(|link| {
+ let value = COMPONENT_DATABASE
+ .documentation(link.path(db).text(db))?
+ .value;
+
+ Some(HoverResult {
value,
value_kind: MarkupKind::PlainText,
- range: link.stem_range,
- });
- }
- }
-
- None
+ range: link.range(db),
+ })
+ })
}
diff --git a/support/texlab/src/features/hover/entry_type.rs b/support/texlab/src/features/hover/entry_type.rs
index 41a561395c..0f4ccbdb72 100644
--- a/support/texlab/src/features/hover/entry_type.rs
+++ b/support/texlab/src/features/hover/entry_type.rs
@@ -1,13 +1,16 @@
-use lsp_types::{HoverParams, MarkupKind};
+use lsp_types::MarkupKind;
-use crate::{features::cursor::CursorContext, syntax::bibtex, LANGUAGE_DATA};
+use crate::{
+ syntax::bibtex,
+ util::{cursor::CursorContext, lang_data::LANGUAGE_DATA},
+};
use super::HoverResult;
-pub(super) fn find_entry_type_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
+pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
let name = context
.cursor
- .as_bibtex()
+ .as_bib()
.filter(|token| token.kind() == bibtex::TYPE)?;
let docs = LANGUAGE_DATA.entry_type_documentation(&name.text()[1..])?;
diff --git a/support/texlab/src/features/hover/field.rs b/support/texlab/src/features/hover/field.rs
index 6102bd6b68..48193997d6 100644
--- a/support/texlab/src/features/hover/field.rs
+++ b/support/texlab/src/features/hover/field.rs
@@ -1,14 +1,17 @@
-use lsp_types::{HoverParams, MarkupKind};
+use lsp_types::MarkupKind;
use rowan::ast::AstNode;
-use crate::{features::cursor::CursorContext, syntax::bibtex, LANGUAGE_DATA};
+use crate::{
+ syntax::bibtex,
+ util::{cursor::CursorContext, lang_data::LANGUAGE_DATA},
+};
use super::HoverResult;
-pub(super) fn find_field_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
+pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
let name = context
.cursor
- .as_bibtex()
+ .as_bib()
.filter(|token| token.kind() == bibtex::NAME)?;
bibtex::Field::cast(name.parent()?)?;
diff --git a/support/texlab/src/features/hover/label.rs b/support/texlab/src/features/hover/label.rs
index 2f8489d769..eafc104de6 100644
--- a/support/texlab/src/features/hover/label.rs
+++ b/support/texlab/src/features/hover/label.rs
@@ -1,19 +1,23 @@
-use lsp_types::{HoverParams, MarkupKind};
+use lsp_types::MarkupKind;
-use crate::{features::cursor::CursorContext, render_label};
+use crate::{
+ db::Word,
+ util::{self, cursor::CursorContext},
+};
use super::HoverResult;
-pub(super) fn find_label_hover(context: &CursorContext<HoverParams>) -> Option<HoverResult> {
+pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
let (name_text, range) = context
.find_label_name_key()
.or_else(|| context.find_label_name_command())?;
- let label = render_label(&context.request.workspace, &name_text, None)?;
-
- Some(HoverResult {
- range,
- value: label.reference(),
- value_kind: MarkupKind::PlainText,
- })
+ let db = context.db;
+ util::label::find_label_definition(db, context.document, Word::new(db, name_text))
+ .and_then(|(document, label)| util::label::render(db, document, label))
+ .map(|label| HoverResult {
+ range,
+ value: label.reference(db),
+ value_kind: MarkupKind::PlainText,
+ })
}
diff --git a/support/texlab/src/features/hover/string_ref.rs b/support/texlab/src/features/hover/string_ref.rs
index adccdd556c..41c4c5bddb 100644
--- a/support/texlab/src/features/hover/string_ref.rs
+++ b/support/texlab/src/features/hover/string_ref.rs
@@ -1,29 +1,28 @@
-use lsp_types::{HoverParams, MarkupKind};
+use lsp_types::MarkupKind;
use rowan::ast::AstNode;
use crate::{
citation::field::text::TextFieldData,
- features::cursor::CursorContext,
syntax::bibtex::{self, HasName, HasValue},
+ util::cursor::CursorContext,
};
use super::HoverResult;
-pub(super) fn find_string_reference_hover(
- context: &CursorContext<HoverParams>,
-) -> Option<HoverResult> {
- let data = context.request.main_document().data.as_bibtex()?;
+pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
+ let data = context.document.parse(context.db).as_bib()?;
let name = context
.cursor
- .as_bibtex()
+ .as_bib()
.filter(|token| token.kind() == bibtex::NAME)
.filter(|token| {
let parent = token.parent().unwrap();
bibtex::Value::can_cast(parent.kind()) || bibtex::StringDef::can_cast(parent.kind())
})?;
- for string in bibtex::SyntaxNode::new_root(data.green.clone())
+ for string in data
+ .root(context.db)
.children()
.filter_map(bibtex::StringDef::cast)
{
diff --git a/support/texlab/src/features/inlay_hint.rs b/support/texlab/src/features/inlay_hint.rs
new file mode 100644
index 0000000000..6d53259900
--- /dev/null
+++ b/support/texlab/src/features/inlay_hint.rs
@@ -0,0 +1,45 @@
+mod label;
+
+use lsp_types::{InlayHint, InlayHintLabel, Range, Url};
+use rowan::TextSize;
+
+use crate::{
+ db::Workspace,
+ util::{line_index::LineIndex, line_index_ext::LineIndexExt},
+ Db,
+};
+
+pub fn find_all(db: &dyn Db, uri: &Url, range: Range) -> Option<Vec<InlayHint>> {
+ let document = Workspace::get(db).lookup_uri(db, uri)?;
+ let line_index = document.contents(db).line_index(db);
+
+ let mut builder = InlayHintBuilder {
+ line_index,
+ hints: Vec::new(),
+ };
+
+ let range = line_index.offset_lsp_range(range);
+ label::find_hints(db, document, range, &mut builder);
+ Some(builder.hints)
+}
+
+struct InlayHintBuilder<'db> {
+ line_index: &'db LineIndex,
+ hints: Vec<InlayHint>,
+}
+
+impl<'db> InlayHintBuilder<'db> {
+ pub fn push(&mut self, offset: TextSize, text: String) {
+ let position = self.line_index.line_col_lsp(offset);
+ self.hints.push(InlayHint {
+ position,
+ label: InlayHintLabel::String(text),
+ kind: None,
+ text_edits: None,
+ tooltip: None,
+ padding_left: Some(true),
+ padding_right: None,
+ data: None,
+ });
+ }
+}
diff --git a/support/texlab/src/features/inlay_hint/label.rs b/support/texlab/src/features/inlay_hint/label.rs
new file mode 100644
index 0000000000..5654f79bf4
--- /dev/null
+++ b/support/texlab/src/features/inlay_hint/label.rs
@@ -0,0 +1,31 @@
+use rowan::TextRange;
+
+use crate::{
+ db::{analysis::label, Document},
+ util, Db,
+};
+
+use super::InlayHintBuilder;
+
+pub(super) fn find_hints(
+ db: &dyn Db,
+ document: Document,
+ range: TextRange,
+ builder: &mut InlayHintBuilder,
+) -> Option<()> {
+ let data = document.parse(db).as_tex()?;
+ for label in data
+ .analyze(db)
+ .labels(db)
+ .iter()
+ .copied()
+ .filter(|label| matches!(label.origin(db), label::Origin::Definition(_)))
+ .filter(|label| label.range(db).intersect(range).is_some())
+ {
+ if let Some(rendered) = util::label::render(db, document, label) {
+ builder.push(label.range(db).end(), rendered.reference(db));
+ }
+ }
+
+ Some(())
+}
diff --git a/support/texlab/src/features/link.rs b/support/texlab/src/features/link.rs
index c4ce4413f5..71bba58ba7 100644
--- a/support/texlab/src/features/link.rs
+++ b/support/texlab/src/features/link.rs
@@ -1,33 +1,41 @@
mod include;
-use std::sync::Arc;
-
-use lsp_types::{DocumentLink, DocumentLinkParams, Url};
+use lsp_types::{DocumentLink, Url};
use rowan::TextRange;
-use crate::LineIndexExt;
+use crate::{
+ db::{Document, Workspace},
+ util::{line_index::LineIndex, line_index_ext::LineIndexExt},
+ Db,
+};
-use self::include::find_include_links;
+pub fn find_all(db: &dyn Db, uri: &Url) -> Option<Vec<DocumentLink>> {
+ let document = Workspace::get(db).lookup_uri(db, uri)?;
+ let mut builder = LinkBuilder {
+ db,
+ line_index: document.contents(db).line_index(db),
+ links: Vec::new(),
+ };
-use super::FeatureRequest;
+ include::find_links(db, document, &mut builder);
+ Some(builder.links)
+}
-pub fn find_document_links(request: FeatureRequest<DocumentLinkParams>) -> Vec<DocumentLink> {
- let document = request.main_document();
- let mut results = Vec::new();
- find_include_links(&request, &mut results);
- results
- .into_iter()
- .map(|result| DocumentLink {
- range: document.line_index.line_col_lsp_range(result.range),
- target: Some(result.target.as_ref().clone()),
- tooltip: None,
- data: None,
- })
- .collect()
+struct LinkBuilder<'db> {
+ db: &'db dyn Db,
+ line_index: &'db LineIndex,
+ links: Vec<DocumentLink>,
}
-#[derive(Debug, Clone)]
-struct LinkResult {
- range: TextRange,
- target: Arc<Url>,
+impl<'db> LinkBuilder<'db> {
+ pub fn push(&mut self, range: TextRange, target: Document) {
+ let range = self.line_index.line_col_lsp_range(range);
+ let target = Some(target.location(self.db).uri(self.db).clone());
+ self.links.push(DocumentLink {
+ range,
+ target,
+ tooltip: None,
+ data: None,
+ });
+ }
}
diff --git a/support/texlab/src/features/link/include.rs b/support/texlab/src/features/link/include.rs
index b4d1804cce..f0c9d147fb 100644
--- a/support/texlab/src/features/link/include.rs
+++ b/support/texlab/src/features/link/include.rs
@@ -1,31 +1,23 @@
-use std::sync::Arc;
+use crate::{
+ db::{dependency_graph, Document, Workspace},
+ Db,
+};
-use lsp_types::DocumentLinkParams;
+use super::LinkBuilder;
-use crate::features::FeatureRequest;
+pub(super) fn find_links(db: &dyn Db, document: Document, builder: &mut LinkBuilder) -> Option<()> {
+ let workspace = Workspace::get(db);
+ let parent = workspace
+ .parents(db, document)
+ .iter()
+ .next()
+ .copied()
+ .unwrap_or(document);
-use super::LinkResult;
-
-pub(super) fn find_include_links(
- request: &FeatureRequest<DocumentLinkParams>,
- results: &mut Vec<LinkResult>,
-) -> Option<()> {
- let data = request.main_document().data.as_latex()?;
-
- for include in &data.extras.explicit_links {
- for target in &include.targets {
- if request
- .workspace
- .documents_by_uri
- .values()
- .any(|document| document.uri.as_ref() == target.as_ref())
- {
- results.push(LinkResult {
- range: include.stem_range,
- target: Arc::clone(target),
- });
- break;
- }
+ let graph = dependency_graph(db, parent);
+ for edge in graph.edges.iter().filter(|edge| edge.source == document) {
+ if let Some(origin) = edge.origin {
+ builder.push(origin.link.range(db), edge.target);
}
}
diff --git a/support/texlab/src/features/reference.rs b/support/texlab/src/features/reference.rs
index f84a3f67d5..54a5fefb27 100644
--- a/support/texlab/src/features/reference.rs
+++ b/support/texlab/src/features/reference.rs
@@ -2,40 +2,45 @@ mod entry;
mod label;
mod string;
-use std::sync::Arc;
-
-use lsp_types::{Location, ReferenceParams, Url};
+use lsp_types::{Location, Position, ReferenceContext, Url};
use rowan::TextRange;
-use crate::LineIndexExt;
-
-use self::{
- entry::find_entry_references, label::find_label_references, string::find_string_references,
+use crate::{
+ db::Document,
+ util::{cursor::CursorContext, line_index_ext::LineIndexExt},
+ Db,
};
-use super::{cursor::CursorContext, FeatureRequest};
-
-pub fn find_all_references(request: FeatureRequest<ReferenceParams>) -> Vec<Location> {
+pub fn find_all(
+ db: &dyn Db,
+ uri: &Url,
+ position: Position,
+ params: &ReferenceContext,
+) -> Option<Vec<Location>> {
let mut results = Vec::new();
- let context = CursorContext::new(request);
+ let context = CursorContext::new(db, uri, position, params)?;
log::debug!("[References] Cursor: {:?}", context.cursor);
- find_label_references(&context, &mut results);
- find_entry_references(&context, &mut results);
- find_string_references(&context, &mut results);
+ label::find_all_references(&context, &mut results);
+ entry::find_all_references(&context, &mut results);
+ string::find_all_references(&context, &mut results);
- results
+ let locations = results
.into_iter()
.map(|result| Location {
- uri: result.uri.as_ref().clone(),
- range: context.request.workspace.documents_by_uri[&result.uri]
- .line_index
+ uri: result.document.location(db).uri(db).clone(),
+ range: result
+ .document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(result.range),
})
- .collect()
+ .collect();
+
+ Some(locations)
}
#[derive(Debug, Clone)]
struct ReferenceResult {
- uri: Arc<Url>,
+ document: Document,
range: TextRange,
}
diff --git a/support/texlab/src/features/reference/entry.rs b/support/texlab/src/features/reference/entry.rs
index 0144d2d074..3dfa10da5b 100644
--- a/support/texlab/src/features/reference/entry.rs
+++ b/support/texlab/src/features/reference/entry.rs
@@ -1,32 +1,31 @@
-use std::sync::Arc;
-
-use lsp_types::ReferenceParams;
+use lsp_types::ReferenceContext;
use rowan::ast::AstNode;
use crate::{
- features::cursor::CursorContext,
+ db::parse::DocumentData,
syntax::{
bibtex::{self, HasName},
latex,
},
- DocumentData,
+ util::cursor::CursorContext,
};
use super::ReferenceResult;
-pub(super) fn find_entry_references(
- context: &CursorContext<ReferenceParams>,
+pub(super) fn find_all_references(
+ context: &CursorContext<&ReferenceContext>,
results: &mut Vec<ReferenceResult>,
) -> Option<()> {
+ let db = context.db;
let (key_text, _) = context
.find_citation_key_word()
.or_else(|| context.find_citation_key_command())
.or_else(|| context.find_entry_key())?;
- for document in context.request.workspace.documents_by_uri.values() {
- match &document.data {
- DocumentData::Latex(data) => {
- latex::SyntaxNode::new_root(data.green.clone())
+ for document in context.related() {
+ match document.parse(db) {
+ DocumentData::Tex(data) => {
+ data.root(db)
.descendants()
.filter_map(latex::Citation::cast)
.filter_map(|citation| citation.key_list())
@@ -34,24 +33,22 @@ pub(super) fn find_entry_references(
.filter(|key| key.to_string() == key_text)
.map(|key| latex::small_range(&key))
.for_each(|range| {
- let uri = Arc::clone(&document.uri);
- results.push(ReferenceResult { uri, range });
+ results.push(ReferenceResult { document, range });
});
}
- DocumentData::Bibtex(data) if context.request.params.context.include_declaration => {
- bibtex::SyntaxNode::new_root(data.green.clone())
+ DocumentData::Bib(data) if context.params.include_declaration => {
+ data.root(db)
.children()
.filter_map(bibtex::Entry::cast)
.filter_map(|entry| entry.name_token())
.filter(|key| key.text() == key_text)
.map(|key| key.text_range())
.for_each(|range| {
- let uri = Arc::clone(&document.uri);
- results.push(ReferenceResult { uri, range });
+ results.push(ReferenceResult { document, range });
});
}
- DocumentData::Bibtex(_) | DocumentData::BuildLog(_) => {}
- }
+ DocumentData::Bib(_) | DocumentData::Log(_) => {}
+ };
}
Some(())
diff --git a/support/texlab/src/features/reference/label.rs b/support/texlab/src/features/reference/label.rs
index 3dadada08b..394542320c 100644
--- a/support/texlab/src/features/reference/label.rs
+++ b/support/texlab/src/features/reference/label.rs
@@ -1,33 +1,32 @@
-use std::sync::Arc;
+use lsp_types::ReferenceContext;
-use lsp_types::ReferenceParams;
-
-use crate::features::cursor::CursorContext;
+use crate::util::cursor::CursorContext;
use super::ReferenceResult;
-pub(super) fn find_label_references(
- context: &CursorContext<ReferenceParams>,
+pub(super) fn find_all_references(
+ context: &CursorContext<&ReferenceContext>,
results: &mut Vec<ReferenceResult>,
) -> Option<()> {
+ let db = context.db;
let (name_text, _) = context
.find_label_name_key()
.or_else(|| context.find_label_name_command())?;
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- for name in data
- .extras
- .label_names
+ for document in context.related() {
+ if let Some(data) = document.parse(db).as_tex() {
+ for label in data
+ .analyze(db)
+ .labels(db)
.iter()
- .filter(|name| name.text == name_text)
- .filter(|name| {
- !name.is_definition || context.request.params.context.include_declaration
+ .filter(|label| label.name(db).text(db) == &name_text)
+ .filter(|label| {
+ label.origin(db).as_definition().is_none() || context.params.include_declaration
})
{
results.push(ReferenceResult {
- uri: Arc::clone(&document.uri),
- range: name.range,
+ document,
+ range: label.range(db),
});
}
}
diff --git a/support/texlab/src/features/reference/string.rs b/support/texlab/src/features/reference/string.rs
index c00cf93546..c4bc6ded3d 100644
--- a/support/texlab/src/features/reference/string.rs
+++ b/support/texlab/src/features/reference/string.rs
@@ -1,22 +1,21 @@
-use std::sync::Arc;
-
-use lsp_types::ReferenceParams;
+use lsp_types::ReferenceContext;
use rowan::ast::AstNode;
use crate::{
- features::cursor::CursorContext,
syntax::bibtex::{self, HasName},
+ util::cursor::CursorContext,
};
use super::ReferenceResult;
-pub(super) fn find_string_references(
- context: &CursorContext<ReferenceParams>,
+pub(super) fn find_all_references(
+ context: &CursorContext<&ReferenceContext>,
results: &mut Vec<ReferenceResult>,
) -> Option<()> {
+ let db = context.db;
let name_text = context
.cursor
- .as_bibtex()
+ .as_bib()
.filter(|token| token.kind() == bibtex::NAME)
.filter(|token| {
let parent = token.parent().unwrap();
@@ -24,14 +23,11 @@ pub(super) fn find_string_references(
})?
.text();
- let document = context.request.main_document();
- let data = document.data.as_bibtex()?;
- for node in bibtex::SyntaxNode::new_root(data.green.clone()).descendants() {
+ let data = context.document.parse(db).as_bib()?;
+ for node in data.root(db).descendants() {
if let Some(name) = bibtex::StringDef::cast(node.clone())
.and_then(|string| string.name_token())
- .filter(|name| {
- context.request.params.context.include_declaration && name.text() == name_text
- })
+ .filter(|name| context.params.include_declaration && name.text() == name_text)
.or_else(|| {
bibtex::Value::cast(node)
.and_then(|token| token.syntax().first_token())
@@ -39,7 +35,7 @@ pub(super) fn find_string_references(
})
{
results.push(ReferenceResult {
- uri: Arc::clone(&document.uri),
+ document: context.document,
range: name.text_range(),
});
}
diff --git a/support/texlab/src/features/rename.rs b/support/texlab/src/features/rename.rs
index c21faf262e..57e1ef5763 100644
--- a/support/texlab/src/features/rename.rs
+++ b/support/texlab/src/features/rename.rs
@@ -2,57 +2,61 @@ mod command;
mod entry;
mod label;
-use std::sync::Arc;
-
-use lsp_types::{Range, RenameParams, TextDocumentPositionParams, TextEdit, Url, WorkspaceEdit};
+use lsp_types::{Position, Range, TextEdit, Url, WorkspaceEdit};
use rowan::TextRange;
use rustc_hash::FxHashMap;
-use crate::LineIndexExt;
-
-use self::{
- command::{prepare_command_rename, rename_command},
- entry::{prepare_entry_rename, rename_entry},
- label::{prepare_label_rename, rename_label},
+use crate::{
+ db::Document,
+ util::{cursor::CursorContext, line_index_ext::LineIndexExt},
+ Db,
};
-use super::{cursor::CursorContext, FeatureRequest};
-
-pub fn prepare_rename_all(request: FeatureRequest<TextDocumentPositionParams>) -> Option<Range> {
- let context = CursorContext::new(request);
- let range = prepare_entry_rename(&context)
- .or_else(|| prepare_label_rename(&context))
- .or_else(|| prepare_command_rename(&context))?;
+pub fn prepare_rename_all(db: &dyn Db, uri: &Url, position: Position) -> Option<Range> {
+ let context = CursorContext::new(db, uri, position, ())?;
+ let range = entry::prepare_rename(&context)
+ .or_else(|| label::prepare_rename(&context))
+ .or_else(|| command::prepare_rename(&context))?;
- let line_index = &context.request.main_document().line_index;
+ let line_index = context.document.contents(db).line_index(db);
Some(line_index.line_col_lsp_range(range))
}
-pub fn rename_all(request: FeatureRequest<RenameParams>) -> Option<WorkspaceEdit> {
- let context = CursorContext::new(request);
- let result = rename_entry(&context)
- .or_else(|| rename_label(&context))
- .or_else(|| rename_command(&context))?;
+pub fn rename_all(
+ db: &dyn Db,
+ uri: &Url,
+ position: Position,
+ new_name: String,
+) -> Option<WorkspaceEdit> {
+ let context = CursorContext::new(db, uri, position, Params { new_name })?;
+ let result = entry::rename(&context)
+ .or_else(|| label::rename(&context))
+ .or_else(|| command::rename(&context))?;
let changes = result
.changes
.into_iter()
- .map(|(uri, old_edits)| {
- let document = &context.request.workspace.documents_by_uri[&uri];
+ .map(|(document, old_edits)| {
+ let line_index = document.contents(db).line_index(db);
let new_edits = old_edits
.into_iter()
.map(|Indel { delete, insert }| {
- TextEdit::new(document.line_index.line_col_lsp_range(delete), insert)
+ TextEdit::new(line_index.line_col_lsp_range(delete), insert)
})
.collect();
- (uri.as_ref().clone(), new_edits)
+ (document.location(db).uri(db).clone(), new_edits)
})
.collect();
Some(WorkspaceEdit::new(changes))
}
+#[derive(Debug)]
+struct Params {
+ new_name: String,
+}
+
#[derive(Debug, PartialEq, Eq, Clone)]
struct Indel {
delete: TextRange,
@@ -61,5 +65,5 @@ struct Indel {
#[derive(Debug, PartialEq, Eq, Clone)]
struct RenameResult {
- changes: FxHashMap<Arc<Url>, Vec<Indel>>,
+ changes: FxHashMap<Document, Vec<Indel>>,
}
diff --git a/support/texlab/src/features/rename/command.rs b/support/texlab/src/features/rename/command.rs
index aaa08f8cb4..5610b2f7ee 100644
--- a/support/texlab/src/features/rename/command.rs
+++ b/support/texlab/src/features/rename/command.rs
@@ -1,29 +1,21 @@
-use std::sync::Arc;
-
-use lsp_types::RenameParams;
use rowan::{TextRange, TextSize};
use rustc_hash::FxHashMap;
-use crate::{
- features::cursor::{CursorContext, HasPosition},
- syntax::latex,
-};
+use crate::util::cursor::CursorContext;
-use super::{Indel, RenameResult};
+use super::{Indel, Params, RenameResult};
-pub(super) fn prepare_command_rename<P: HasPosition>(
- context: &CursorContext<P>,
-) -> Option<TextRange> {
+pub(super) fn prepare_rename<T>(context: &CursorContext<T>) -> Option<TextRange> {
context.cursor.command_range(context.offset)
}
-pub(super) fn rename_command(context: &CursorContext<RenameParams>) -> Option<RenameResult> {
- prepare_command_rename(context)?;
- let name = context.cursor.as_latex()?.text();
+pub(super) fn rename(context: &CursorContext<Params>) -> Option<RenameResult> {
+ prepare_rename(context)?;
+ let name = context.cursor.as_tex()?.text();
let mut changes = FxHashMap::default();
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- let root = latex::SyntaxNode::new_root(data.green.clone());
+ for document in context.related() {
+ if let Some(data) = document.parse(context.db).as_tex() {
+ let root = data.root(context.db);
let edits = root
.descendants_with_tokens()
.filter_map(|element| element.into_token())
@@ -32,12 +24,12 @@ pub(super) fn rename_command(context: &CursorContext<RenameParams>) -> Option<Re
let range = token.text_range();
Indel {
delete: TextRange::new(range.start() + TextSize::from(1), range.end()),
- insert: context.request.params.new_name.clone(),
+ insert: context.params.new_name.clone(),
}
})
.collect();
- changes.insert(Arc::clone(&document.uri), edits);
+ changes.insert(document, edits);
}
}
diff --git a/support/texlab/src/features/rename/entry.rs b/support/texlab/src/features/rename/entry.rs
index 6eac79030b..79ee25ac71 100644
--- a/support/texlab/src/features/rename/entry.rs
+++ b/support/texlab/src/features/rename/entry.rs
@@ -1,23 +1,18 @@
-use std::sync::Arc;
-
-use lsp_types::RenameParams;
use rowan::{ast::AstNode, TextRange};
use rustc_hash::FxHashMap;
use crate::{
- features::cursor::{CursorContext, HasPosition},
+ db::parse::DocumentData,
syntax::{
bibtex::{self, HasName},
latex,
},
- DocumentData,
+ util::cursor::CursorContext,
};
-use super::{Indel, RenameResult};
+use super::{Indel, Params, RenameResult};
-pub(super) fn prepare_entry_rename<P: HasPosition>(
- context: &CursorContext<P>,
-) -> Option<TextRange> {
+pub(super) fn prepare_rename<T>(context: &CursorContext<T>) -> Option<TextRange> {
let (_, range) = context
.find_citation_key_word()
.or_else(|| context.find_entry_key())?;
@@ -25,18 +20,17 @@ pub(super) fn prepare_entry_rename<P: HasPosition>(
Some(range)
}
-pub(super) fn rename_entry(context: &CursorContext<RenameParams>) -> Option<RenameResult> {
- prepare_entry_rename(context)?;
+pub(super) fn rename(context: &CursorContext<Params>) -> Option<RenameResult> {
+ prepare_rename(context)?;
let (key_text, _) = context
.find_citation_key_word()
.or_else(|| context.find_entry_key())?;
let mut changes = FxHashMap::default();
- for document in context.request.workspace.documents_by_uri.values() {
- let uri = Arc::clone(&document.uri);
- match &document.data {
- DocumentData::Latex(data) => {
- let root = latex::SyntaxNode::new_root(data.green.clone());
+ for document in context.related() {
+ match document.parse(context.db) {
+ DocumentData::Tex(data) => {
+ let root = data.root(context.db);
let edits: Vec<_> = root
.descendants()
.filter_map(latex::Citation::cast)
@@ -45,13 +39,13 @@ pub(super) fn rename_entry(context: &CursorContext<RenameParams>) -> Option<Rena
.filter(|key| key.to_string() == key_text)
.map(|key| Indel {
delete: latex::small_range(&key),
- insert: context.request.params.new_name.clone(),
+ insert: context.params.new_name.clone(),
})
.collect();
- changes.insert(uri, edits);
+ changes.insert(document, edits);
}
- DocumentData::Bibtex(data) => {
- let root = bibtex::SyntaxNode::new_root(data.green.clone());
+ DocumentData::Bib(data) => {
+ let root = data.root(context.db);
let edits: Vec<_> = root
.descendants()
.filter_map(bibtex::Entry::cast)
@@ -59,12 +53,12 @@ pub(super) fn rename_entry(context: &CursorContext<RenameParams>) -> Option<Rena
.filter(|key| key.text() == key_text)
.map(|key| Indel {
delete: key.text_range(),
- insert: context.request.params.new_name.clone(),
+ insert: context.params.new_name.clone(),
})
.collect();
- changes.insert(uri, edits);
+ changes.insert(document, edits);
}
- DocumentData::BuildLog(_) => {}
+ DocumentData::Log(_) => {}
}
}
diff --git a/support/texlab/src/features/rename/label.rs b/support/texlab/src/features/rename/label.rs
index 30a99c3b36..d38d13ae93 100644
--- a/support/texlab/src/features/rename/label.rs
+++ b/support/texlab/src/features/rename/label.rs
@@ -1,32 +1,24 @@
-use std::sync::Arc;
-
-use lsp_types::RenameParams;
use rowan::{ast::AstNode, TextRange};
use rustc_hash::FxHashMap;
-use crate::{
- features::cursor::{CursorContext, HasPosition},
- syntax::latex,
-};
+use crate::{syntax::latex, util::cursor::CursorContext};
-use super::{Indel, RenameResult};
+use super::{Indel, Params, RenameResult};
-pub(super) fn prepare_label_rename<P: HasPosition>(
- context: &CursorContext<P>,
-) -> Option<TextRange> {
+pub(super) fn prepare_rename<T>(context: &CursorContext<T>) -> Option<TextRange> {
let (_, range) = context.find_label_name_key()?;
Some(range)
}
-pub(super) fn rename_label(context: &CursorContext<RenameParams>) -> Option<RenameResult> {
- prepare_label_rename(context)?;
+pub(super) fn rename(context: &CursorContext<Params>) -> Option<RenameResult> {
+ prepare_rename(context)?;
let (name_text, _) = context.find_label_name_key()?;
let mut changes = FxHashMap::default();
- for document in context.request.workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
+ for document in context.related() {
+ if let Some(data) = document.parse(context.db).as_tex() {
let mut edits = Vec::new();
- for node in latex::SyntaxNode::new_root(data.green.clone()).descendants() {
+ for node in data.root(context.db).descendants() {
if let Some(range) = latex::LabelDefinition::cast(node.clone())
.and_then(|label| label.name())
.and_then(|name| name.key())
@@ -35,7 +27,7 @@ pub(super) fn rename_label(context: &CursorContext<RenameParams>) -> Option<Rena
{
edits.push(Indel {
delete: range,
- insert: context.request.params.new_name.clone(),
+ insert: context.params.new_name.clone(),
});
}
@@ -47,7 +39,7 @@ pub(super) fn rename_label(context: &CursorContext<RenameParams>) -> Option<Rena
.for_each(|name| {
edits.push(Indel {
delete: latex::small_range(&name),
- insert: context.request.params.new_name.clone(),
+ insert: context.params.new_name.clone(),
});
});
@@ -59,7 +51,7 @@ pub(super) fn rename_label(context: &CursorContext<RenameParams>) -> Option<Rena
{
edits.push(Indel {
delete: latex::small_range(&name1),
- insert: context.request.params.new_name.clone(),
+ insert: context.params.new_name.clone(),
});
}
@@ -70,13 +62,13 @@ pub(super) fn rename_label(context: &CursorContext<RenameParams>) -> Option<Rena
{
edits.push(Indel {
delete: latex::small_range(&name2),
- insert: context.request.params.new_name.clone(),
+ insert: context.params.new_name.clone(),
});
}
}
}
- changes.insert(Arc::clone(&document.uri), edits);
+ changes.insert(document, edits);
}
}
diff --git a/support/texlab/src/features/symbol.rs b/support/texlab/src/features/symbol.rs
index 24d599c3e1..c16193efcb 100644
--- a/support/texlab/src/features/symbol.rs
+++ b/support/texlab/src/features/symbol.rs
@@ -3,49 +3,44 @@ mod latex;
mod project_order;
mod types;
-use std::{cmp::Reverse, sync::Arc};
+use std::cmp::Reverse;
-use lsp_types::{
- DocumentSymbolParams, DocumentSymbolResponse, PartialResultParams, SymbolInformation,
- TextDocumentIdentifier, WorkDoneProgressParams, WorkspaceSymbolParams,
-};
+use lsp_types::{DocumentSymbolResponse, SymbolInformation, Url, WorkspaceSymbolParams};
-use crate::{ClientCapabilitiesExt, Workspace};
+use crate::{db::Workspace, util::capabilities::ClientCapabilitiesExt, Db};
-use self::{
- bibtex::find_bibtex_symbols, latex::find_latex_symbols, project_order::ProjectOrdering,
- types::InternalSymbol,
-};
+use self::project_order::ProjectOrdering;
-use super::FeatureRequest;
+pub fn find_document_symbols(db: &dyn Db, uri: &Url) -> Option<DocumentSymbolResponse> {
+ let workspace = Workspace::get(db);
+ let document = workspace.lookup_uri(db, uri)?;
-#[must_use]
-pub fn find_document_symbols(req: FeatureRequest<DocumentSymbolParams>) -> DocumentSymbolResponse {
let mut buf = Vec::new();
- find_latex_symbols(&req, &mut buf);
- find_bibtex_symbols(&req, &mut buf);
- if req
- .workspace
- .environment
- .client_capabilities
+ latex::find_symbols(db, document, &mut buf);
+ bibtex::find_symbols(db, document, &mut buf);
+ if workspace
+ .client_capabilities(db)
.has_hierarchical_document_symbol_support()
{
- DocumentSymbolResponse::Nested(
- buf.into_iter()
- .map(InternalSymbol::into_document_symbol)
- .collect(),
- )
+ let symbols = buf
+ .into_iter()
+ .map(|symbol| symbol.into_document_symbol(db))
+ .collect();
+
+ Some(DocumentSymbolResponse::Nested(symbols))
} else {
let mut new_buf = Vec::new();
for symbol in buf {
symbol.flatten(&mut new_buf);
}
+
let mut new_buf: Vec<_> = new_buf
.into_iter()
- .map(|symbol| symbol.into_symbol_info(req.main_document().uri.as_ref().clone()))
+ .map(|symbol| symbol.into_symbol_info(uri.clone()))
.collect();
- sort_symbols(&req.workspace, &mut new_buf);
- DocumentSymbolResponse::Flat(new_buf)
+
+ sort_symbols(db, &mut new_buf);
+ Some(DocumentSymbolResponse::Flat(new_buf))
}
}
@@ -57,25 +52,16 @@ struct WorkspaceSymbol {
#[must_use]
pub fn find_workspace_symbols(
- workspace: &Workspace,
+ db: &dyn Db,
params: &WorkspaceSymbolParams,
) -> Vec<SymbolInformation> {
let mut symbols = Vec::new();
- for document in workspace.documents_by_uri.values() {
- let request = FeatureRequest {
- uri: Arc::clone(&document.uri),
- params: DocumentSymbolParams {
- text_document: TextDocumentIdentifier::new(document.uri.as_ref().clone()),
- partial_result_params: PartialResultParams::default(),
- work_done_progress_params: WorkDoneProgressParams::default(),
- },
- workspace: workspace.slice(&document.uri),
- };
-
+ let workspace = Workspace::get(db);
+ for document in workspace.documents(db).iter().copied() {
let mut buf = Vec::new();
- find_latex_symbols(&request, &mut buf);
- find_bibtex_symbols(&request, &mut buf);
+ latex::find_symbols(db, document, &mut buf);
+ bibtex::find_symbols(db, document, &mut buf);
let mut new_buf = Vec::new();
for symbol in buf {
@@ -85,7 +71,7 @@ pub fn find_workspace_symbols(
for symbol in new_buf {
symbols.push(WorkspaceSymbol {
search_text: symbol.search_text(),
- info: symbol.into_symbol_info(document.uri.as_ref().clone()),
+ info: symbol.into_symbol_info(document.location(db).uri(db).clone()),
});
}
}
@@ -95,6 +81,7 @@ pub fn find_workspace_symbols(
.split_whitespace()
.map(str::to_lowercase)
.collect();
+
let mut filtered = Vec::new();
for symbol in symbols {
let mut included = true;
@@ -109,20 +96,21 @@ pub fn find_workspace_symbols(
filtered.push(symbol.info);
}
}
- sort_symbols(workspace, &mut filtered);
+
+ sort_symbols(db, &mut filtered);
filtered
}
-fn sort_symbols(workspace: &Workspace, symbols: &mut [SymbolInformation]) {
- let ordering = ProjectOrdering::from(workspace);
+fn sort_symbols(db: &dyn Db, symbols: &mut [SymbolInformation]) {
+ let ordering = ProjectOrdering::new(db);
symbols.sort_by(|left, right| {
let left_key = (
- ordering.get(&left.location.uri),
+ ordering.get(db, &left.location.uri),
left.location.range.start,
Reverse(left.location.range.end),
);
let right_key = (
- ordering.get(&right.location.uri),
+ ordering.get(db, &right.location.uri),
right.location.range.start,
Reverse(right.location.range.end),
);
diff --git a/support/texlab/src/features/symbol/bibtex.rs b/support/texlab/src/features/symbol/bibtex.rs
index bbc9026b0b..6a92405f17 100644
--- a/support/texlab/src/features/symbol/bibtex.rs
+++ b/support/texlab/src/features/symbol/bibtex.rs
@@ -1,82 +1,87 @@
-use lsp_types::DocumentSymbolParams;
use rowan::ast::AstNode;
use crate::{
- features::FeatureRequest,
+ db::Document,
syntax::bibtex::{self, HasName, HasType},
- BibtexEntryTypeCategory, LineIndexExt, LANGUAGE_DATA,
+ util::{
+ lang_data::{BibtexEntryTypeCategory, LANGUAGE_DATA},
+ line_index::LineIndex,
+ line_index_ext::LineIndexExt,
+ },
+ Db,
};
use super::types::{InternalSymbol, InternalSymbolKind};
-pub fn find_bibtex_symbols(
- request: &FeatureRequest<DocumentSymbolParams>,
+pub fn find_symbols(db: &dyn Db, document: Document, buf: &mut Vec<InternalSymbol>) -> Option<()> {
+ let data = document.parse(db).as_bib()?;
+ let line_index = document.contents(db).line_index(db);
+ for node in data.root(db).children() {
+ process_string(node.clone(), line_index, buf)
+ .or_else(|| process_entry(node, line_index, buf));
+ }
+
+ Some(())
+}
+
+fn process_string(
+ node: bibtex::SyntaxNode,
+ line_index: &LineIndex,
buf: &mut Vec<InternalSymbol>,
) -> Option<()> {
- let main_document = request.main_document();
- let data = main_document.data.as_bibtex()?;
-
- for node in bibtex::SyntaxNode::new_root(data.green.clone()).children() {
- if let Some(string) = bibtex::StringDef::cast(node.clone()) {
- if let Some(name) = string.name_token() {
- buf.push(InternalSymbol {
- name: name.text().into(),
- label: None,
- kind: InternalSymbolKind::String,
- deprecated: false,
- full_range: main_document
- .line_index
- .line_col_lsp_range(string.syntax().text_range()),
- selection_range: main_document
- .line_index
- .line_col_lsp_range(name.text_range()),
- children: Vec::new(),
- })
- }
- } else if let Some(entry) = bibtex::Entry::cast(node) {
- if let Some(ty) = entry.type_token() {
- if let Some(key) = entry.name_token() {
- let mut children = Vec::new();
- for field in entry.fields() {
- if let Some(name) = field.name_token() {
- let symbol = InternalSymbol {
- name: name.text().to_string(),
- label: None,
- kind: InternalSymbolKind::Field,
- deprecated: false,
- full_range: main_document
- .line_index
- .line_col_lsp_range(field.syntax().text_range()),
- selection_range: main_document
- .line_index
- .line_col_lsp_range(name.text_range()),
- children: Vec::new(),
- };
- children.push(symbol);
- }
- }
+ let string = bibtex::StringDef::cast(node)?;
+ let name = string.name_token()?;
+ buf.push(InternalSymbol {
+ name: name.text().into(),
+ label: None,
+ kind: InternalSymbolKind::String,
+ deprecated: false,
+ full_range: line_index.line_col_lsp_range(string.syntax().text_range()),
+ selection_range: line_index.line_col_lsp_range(name.text_range()),
+ children: Vec::new(),
+ });
- let category = LANGUAGE_DATA
- .find_entry_type(&ty.text()[1..])
- .map(|ty| ty.category)
- .unwrap_or(BibtexEntryTypeCategory::Misc);
+ Some(())
+}
- buf.push(InternalSymbol {
- name: key.to_string(),
- label: None,
- kind: InternalSymbolKind::Entry(category),
- deprecated: false,
- full_range: main_document
- .line_index
- .line_col_lsp_range(entry.syntax().text_range()),
- selection_range: main_document
- .line_index
- .line_col_lsp_range(key.text_range()),
- children,
- });
- }
- }
+fn process_entry(
+ node: bibtex::SyntaxNode,
+ line_index: &LineIndex,
+ buf: &mut Vec<InternalSymbol>,
+) -> Option<()> {
+ let entry = bibtex::Entry::cast(node)?;
+ let ty = entry.type_token()?;
+ let key = entry.name_token()?;
+ let mut children = Vec::new();
+ for field in entry.fields() {
+ if let Some(name) = field.name_token() {
+ let symbol = InternalSymbol {
+ name: name.text().to_string(),
+ label: None,
+ kind: InternalSymbolKind::Field,
+ deprecated: false,
+ full_range: line_index.line_col_lsp_range(field.syntax().text_range()),
+ selection_range: line_index.line_col_lsp_range(name.text_range()),
+ children: Vec::new(),
+ };
+ children.push(symbol);
}
}
+
+ let category = LANGUAGE_DATA
+ .find_entry_type(&ty.text()[1..])
+ .map(|ty| ty.category)
+ .unwrap_or(BibtexEntryTypeCategory::Misc);
+
+ buf.push(InternalSymbol {
+ name: key.to_string(),
+ label: None,
+ kind: InternalSymbolKind::Entry(category),
+ deprecated: false,
+ full_range: line_index.line_col_lsp_range(entry.syntax().text_range()),
+ selection_range: line_index.line_col_lsp_range(key.text_range()),
+ children,
+ });
+
Some(())
}
diff --git a/support/texlab/src/features/symbol/latex.rs b/support/texlab/src/features/symbol/latex.rs
index 8a88ffb0d9..81927ab515 100644
--- a/support/texlab/src/features/symbol/latex.rs
+++ b/support/texlab/src/features/symbol/latex.rs
@@ -1,38 +1,30 @@
use std::str::FromStr;
-use lsp_types::{DocumentSymbolParams, Range};
+use lsp_types::Range;
use rowan::ast::AstNode;
-use smol_str::SmolStr;
use titlecase::titlecase;
use crate::{
- features::FeatureRequest,
- find_caption_by_parent, find_label_number,
+ db::{Document, Word, Workspace},
syntax::latex::{self, HasBrack, HasCurly},
- LabelledFloatKind, LatexDocumentData, LineIndexExt, LANGUAGE_DATA,
+ util::{
+ label::{find_caption_by_parent, LabeledFloatKind},
+ lang_data::LANGUAGE_DATA,
+ line_index_ext::LineIndexExt,
+ },
+ Db,
};
use super::types::{InternalSymbol, InternalSymbolKind};
-pub fn find_latex_symbols(
- request: &FeatureRequest<DocumentSymbolParams>,
- buf: &mut Vec<InternalSymbol>,
-) -> Option<()> {
- let data = request.main_document().data.as_latex()?;
- let mut context = Context { request, data };
-
- let root = context.data.green.clone();
- let mut symbols = visit(&mut context, latex::SyntaxNode::new_root(root));
+pub fn find_symbols(db: &dyn Db, document: Document, buf: &mut Vec<InternalSymbol>) -> Option<()> {
+ let data = document.parse(db).as_tex()?;
+ let mut symbols = visit(db, document, data.root(db));
buf.append(&mut symbols);
Some(())
}
-struct Context<'a> {
- request: &'a FeatureRequest<DocumentSymbolParams>,
- data: &'a LatexDocumentData,
-}
-
-fn visit(context: &mut Context, node: latex::SyntaxNode) -> Vec<InternalSymbol> {
+fn visit(db: &dyn Db, document: Document, node: latex::SyntaxNode) -> Vec<InternalSymbol> {
let symbol = match node.kind() {
latex::PART
| latex::CHAPTER
@@ -40,9 +32,9 @@ fn visit(context: &mut Context, node: latex::SyntaxNode) -> Vec<InternalSymbol>
| latex::SUBSECTION
| latex::SUBSUBSECTION
| latex::PARAGRAPH
- | latex::SUBPARAGRAPH => visit_section(context, node.clone()),
- latex::ENUM_ITEM => visit_enum_item(context, node.clone()),
- latex::EQUATION => visit_equation(context, node.clone()),
+ | latex::SUBPARAGRAPH => visit_section(db, document, node.clone()),
+ latex::ENUM_ITEM => visit_enum_item(db, document, node.clone()),
+ latex::EQUATION => visit_equation(db, document, node.clone()),
latex::ENVIRONMENT => latex::Environment::cast(node.clone())
.and_then(|env| env.begin())
.and_then(|begin| begin.name())
@@ -54,17 +46,17 @@ fn visit(context: &mut Context, node: latex::SyntaxNode) -> Vec<InternalSymbol>
.iter()
.any(|env| env == &name)
{
- visit_equation_environment(context, node.clone())
+ visit_equation_environment(db, document, node.clone())
} else if LANGUAGE_DATA
.enum_environments
.iter()
.any(|env| env == &name)
{
- visit_enumeration(context, node.clone(), &name)
- } else if let Ok(float_kind) = LabelledFloatKind::from_str(&name) {
- visit_float(context, node.clone(), float_kind)
+ visit_enumeration(db, document, node.clone(), &name)
+ } else if let Ok(float_kind) = LabeledFloatKind::from_str(&name) {
+ visit_float(db, document, node.clone(), float_kind)
} else {
- visit_theorem(context, node.clone(), &name)
+ visit_theorem(db, document, node.clone(), &name)
}
}),
_ => None,
@@ -73,39 +65,42 @@ fn visit(context: &mut Context, node: latex::SyntaxNode) -> Vec<InternalSymbol>
match symbol {
Some(mut parent) => {
for child in node.children() {
- parent.children.append(&mut visit(context, child));
+ parent.children.append(&mut visit(db, document, child));
}
vec![parent]
}
None => {
let mut symbols = Vec::new();
for child in node.children() {
- symbols.append(&mut visit(context, child));
+ symbols.append(&mut visit(db, document, child));
}
symbols
}
}
}
-fn visit_section(context: &mut Context, node: latex::SyntaxNode) -> Option<InternalSymbol> {
+fn visit_section(
+ db: &dyn Db,
+ document: Document,
+ node: latex::SyntaxNode,
+) -> Option<InternalSymbol> {
let section = latex::Section::cast(node)?;
- let full_range = context
- .request
- .main_document()
- .line_index
+ let full_range = document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(latex::small_range(&section));
let group = section.name()?;
let group_text = group.content_text()?;
- let symbol = match find_label_by_parent(context, section.syntax()) {
+ let symbol = match find_label_by_parent(db, document, section.syntax()) {
Some(NumberedLabel {
name: label,
range: selection_range,
number,
}) => {
let name = match number {
- Some(number) => format!("{} {}", number, group_text),
+ Some(number) => format!("{} {}", number.text(db), group_text),
None => group_text,
};
@@ -129,10 +124,15 @@ fn visit_section(context: &mut Context, node: latex::SyntaxNode) -> Option<Inter
children: Vec::new(),
},
};
+
Some(symbol)
}
-fn visit_enum_item(context: &mut Context, node: latex::SyntaxNode) -> Option<InternalSymbol> {
+fn visit_enum_item(
+ db: &dyn Db,
+ document: Document,
+ node: latex::SyntaxNode,
+) -> Option<InternalSymbol> {
let enum_item = latex::EnumItem::cast(node.clone())?;
if !enum_item
.syntax()
@@ -151,10 +151,9 @@ fn visit_enum_item(context: &mut Context, node: latex::SyntaxNode) -> Option<Int
return None;
}
- let full_range = context
- .request
- .main_document()
- .line_index
+ let full_range = document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(latex::small_range(&enum_item));
let name = enum_item
@@ -162,13 +161,15 @@ fn visit_enum_item(context: &mut Context, node: latex::SyntaxNode) -> Option<Int
.and_then(|label| label.content_text())
.unwrap_or_else(|| "Item".to_string());
- let symbol = match find_label_by_parent(context, &node) {
+ let symbol = match find_label_by_parent(db, document, &node) {
Some(NumberedLabel {
name: label,
range: selection_range,
number,
}) => InternalSymbol {
- name: number.map(Into::into).unwrap_or_else(|| name.to_string()),
+ name: number
+ .map(|num| num.text(db).clone())
+ .unwrap_or_else(|| name.clone()),
label: Some(label),
kind: InternalSymbolKind::EnumerationItem,
deprecated: false,
@@ -189,46 +190,50 @@ fn visit_enum_item(context: &mut Context, node: latex::SyntaxNode) -> Option<Int
Some(symbol)
}
-fn visit_equation(context: &mut Context, node: latex::SyntaxNode) -> Option<InternalSymbol> {
+fn visit_equation(
+ db: &dyn Db,
+ document: Document,
+ node: latex::SyntaxNode,
+) -> Option<InternalSymbol> {
let equation = latex::Equation::cast(node)?;
- let full_range = context
- .request
- .main_document()
- .line_index
+ let full_range = document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(latex::small_range(&equation));
- make_equation_symbol(context, equation.syntax(), full_range)
+ make_equation_symbol(db, document, equation.syntax(), full_range)
}
fn visit_equation_environment(
- context: &mut Context,
+ db: &dyn Db,
+ document: Document,
node: latex::SyntaxNode,
) -> Option<InternalSymbol> {
let environment = latex::Environment::cast(node)?;
- let full_range = context
- .request
- .main_document()
- .line_index
+ let full_range = document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(latex::small_range(&environment));
- make_equation_symbol(context, environment.syntax(), full_range)
+ make_equation_symbol(db, document, environment.syntax(), full_range)
}
fn make_equation_symbol(
- context: &mut Context,
+ db: &dyn Db,
+ document: Document,
node: &latex::SyntaxNode,
full_range: Range,
) -> Option<InternalSymbol> {
- let symbol = match find_label_by_parent(context, node) {
+ let symbol = match find_label_by_parent(db, document, node) {
Some(NumberedLabel {
name: label,
range: selection_range,
number,
}) => {
let name = match number {
- Some(number) => format!("Equation ({})", number),
+ Some(number) => format!("Equation ({})", number.text(db)),
None => "Equation".to_string(),
};
@@ -256,26 +261,26 @@ fn make_equation_symbol(
}
fn visit_enumeration(
- context: &mut Context,
+ db: &dyn Db,
+ document: Document,
node: latex::SyntaxNode,
env_name: &str,
) -> Option<InternalSymbol> {
let environment = latex::Environment::cast(node)?;
- let full_range = context
- .request
- .main_document()
- .line_index
+ let full_range = document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(latex::small_range(&environment));
let name = titlecase(env_name);
- let symbol = match find_label_by_parent(context, environment.syntax()) {
+ let symbol = match find_label_by_parent(db, document, environment.syntax()) {
Some(NumberedLabel {
name: label,
range: selection_range,
number,
}) => {
let name = match number {
- Some(number) => format!("{} {}", name, number),
+ Some(number) => format!("{} {}", name, number.text(db)),
None => name,
};
@@ -303,33 +308,33 @@ fn visit_enumeration(
}
fn visit_float(
- context: &mut Context,
+ db: &dyn Db,
+ document: Document,
node: latex::SyntaxNode,
- float_kind: LabelledFloatKind,
+ float_kind: LabeledFloatKind,
) -> Option<InternalSymbol> {
let environment = latex::Environment::cast(node)?;
- let full_range = context
- .request
- .main_document()
- .line_index
+ let full_range = document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(latex::small_range(&environment));
let (float_kind, symbol_kind) = match float_kind {
- LabelledFloatKind::Algorithm => ("Algorithm", InternalSymbolKind::Algorithm),
- LabelledFloatKind::Figure => ("Figure", InternalSymbolKind::Figure),
- LabelledFloatKind::Listing => ("Listing", InternalSymbolKind::Listing),
- LabelledFloatKind::Table => ("Table", InternalSymbolKind::Table),
+ LabeledFloatKind::Algorithm => ("Algorithm", InternalSymbolKind::Algorithm),
+ LabeledFloatKind::Figure => ("Figure", InternalSymbolKind::Figure),
+ LabeledFloatKind::Listing => ("Listing", InternalSymbolKind::Listing),
+ LabeledFloatKind::Table => ("Table", InternalSymbolKind::Table),
};
let caption = find_caption_by_parent(environment.syntax())?;
- let symbol = match find_label_by_parent(context, environment.syntax()) {
+ let symbol = match find_label_by_parent(db, document, environment.syntax()) {
Some(NumberedLabel {
name: label,
range: selection_range,
number,
}) => {
let name = match number {
- Some(number) => format!("{} {}: {}", float_kind, number, caption),
+ Some(number) => format!("{} {}: {}", float_kind, number.text(db), caption),
None => format!("{}: {}", float_kind, caption),
};
@@ -358,23 +363,17 @@ fn visit_float(
}
fn visit_theorem(
- context: &mut Context,
+ db: &dyn Db,
+ document: Document,
node: latex::SyntaxNode,
environment_name: &str,
) -> Option<InternalSymbol> {
- let definition = context
- .request
- .workspace
- .documents_by_uri
- .values()
- .filter_map(|document| document.data.as_latex())
- .find_map(|data| {
- data.extras
- .theorem_environments
- .iter()
- .find(|environment| environment.name == environment_name)
- .cloned()
- })?;
+ let definition = Workspace::get(db)
+ .related(db, document)
+ .iter()
+ .filter_map(|document| document.parse(db).as_tex())
+ .flat_map(|data| data.analyze(db).theorem_environments(db))
+ .find(|env| env.name(db).text(db) == environment_name)?;
let node = latex::Environment::cast(node)?;
let theorem_description = node
@@ -382,13 +381,12 @@ fn visit_theorem(
.options()
.and_then(|option| option.content_text());
- let full_range = context
- .request
- .main_document()
- .line_index
+ let full_range = document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(latex::small_range(&node));
- let symbol = match find_label_by_parent(context, node.syntax()) {
+ let symbol = match find_label_by_parent(db, document, node.syntax()) {
Some(NumberedLabel {
name: label,
range: selection_range,
@@ -396,11 +394,20 @@ fn visit_theorem(
}) => {
let name = match (number, theorem_description) {
(Some(number), Some(desc)) => {
- format!("{} {} ({})", definition.description, number, desc)
+ format!(
+ "{} {} ({})",
+ definition.description(db).text(db),
+ number.text(db),
+ desc
+ )
}
- (Some(number), None) => format!("{} {}", definition.description, number),
- (None, Some(desc)) => format!("{} ({})", definition.description, desc),
- (None, None) => definition.description,
+ (Some(number), None) => format!(
+ "{} {}",
+ definition.description(db).text(db),
+ number.text(db)
+ ),
+ (None, Some(desc)) => format!("{} ({})", definition.description(db).text(db), desc),
+ (None, None) => definition.description(db).text(db).clone(),
};
InternalSymbol {
@@ -415,8 +422,8 @@ fn visit_theorem(
}
None => {
let name = match theorem_description {
- Some(desc) => format!("{} ({})", definition.description, desc),
- None => definition.description,
+ Some(desc) => format!("{} ({})", definition.description(db).text(db), desc),
+ None => definition.description(db).text(db).clone(),
};
InternalSymbol {
name,
@@ -434,28 +441,27 @@ fn visit_theorem(
#[derive(Debug, PartialEq, Eq, Clone)]
struct NumberedLabel {
- name: String,
+ name: Word,
range: Range,
- number: Option<SmolStr>,
+ number: Option<Word>,
}
fn find_label_by_parent(
- context: &mut Context,
+ db: &dyn Db,
+ document: Document,
parent: &latex::SyntaxNode,
) -> Option<NumberedLabel> {
let node = parent.children().find_map(latex::LabelDefinition::cast)?;
-
- let name = node.name()?.key()?.to_string();
- let range = context
- .request
- .main_document()
- .line_index
+ let name = Word::new(db, node.name()?.key()?.to_string());
+ let range = document
+ .contents(db)
+ .line_index(db)
.line_col_lsp_range(latex::small_range(&node));
- let number = find_label_number(&context.request.workspace, &name);
+ let number = Workspace::get(db).number_of_label(db, document, name);
Some(NumberedLabel {
- name: name.to_string(),
+ name,
range,
- number: number.map(Into::into),
+ number,
})
}
diff --git a/support/texlab/src/features/symbol/project_order.rs b/support/texlab/src/features/symbol/project_order.rs
index 794447ecf6..f4aeb63bca 100644
--- a/support/texlab/src/features/symbol/project_order.rs
+++ b/support/texlab/src/features/symbol/project_order.rs
@@ -1,209 +1,202 @@
-use std::{sync::Arc, usize};
-
+use itertools::Itertools;
use lsp_types::Url;
-use petgraph::{algo::tarjan_scc, Directed, Graph};
-use rustc_hash::FxHashSet;
-use crate::{Document, Workspace};
+use crate::{
+ db::{dependency_graph, Document, Workspace},
+ Db,
+};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ProjectOrdering {
- ordering: Vec<Arc<Url>>,
+ ordering: Vec<Document>,
}
impl ProjectOrdering {
- pub fn get(&self, uri: &Url) -> usize {
- self.ordering
- .iter()
- .position(|u| u.as_ref() == uri)
- .unwrap_or(usize::MAX)
- }
-}
-
-impl From<&Workspace> for ProjectOrdering {
- fn from(workspace: &Workspace) -> Self {
- let mut ordering = Vec::new();
- let uris: FxHashSet<Arc<Url>> = workspace
- .documents_by_uri
- .values()
- .map(|document| Arc::clone(&document.uri))
+ pub fn new(db: &dyn Db) -> Self {
+ let workspace = Workspace::get(db);
+
+ let ordering: Vec<_> = workspace
+ .index_files(db)
+ .chain(workspace.documents(db).iter().copied())
+ .flat_map(|document| {
+ dependency_graph(db, document)
+ .preorder()
+ .rev()
+ .collect_vec()
+ })
+ .unique()
.collect();
- let comps = connected_components(workspace);
- for comp in comps {
- let (graph, documents) = build_dependency_graph(&comp);
-
- let mut visited = FxHashSet::default();
- let root_index = *graph.node_weight(tarjan_scc(&graph)[0][0]).unwrap();
- let mut stack = vec![Arc::clone(&documents[root_index].uri)];
-
- while let Some(uri) = stack.pop() {
- if !visited.insert(Arc::clone(&uri)) {
- continue;
- }
-
- ordering.push(Arc::clone(&uri));
- if let Some(document) = workspace.documents_by_uri.get(&uri) {
- if let Some(data) = document.data.as_latex() {
- for link in data.extras.explicit_links.iter().rev() {
- for target in &link.targets {
- if uris.contains(target.as_ref()) {
- stack.push(Arc::clone(target));
- }
- }
- }
- }
- }
- }
- }
-
Self { ordering }
}
-}
-
-fn connected_components(workspace: &Workspace) -> Vec<Workspace> {
- let mut components = Vec::new();
- let mut visited = FxHashSet::default();
- for root_document in workspace.documents_by_uri.values() {
- if !visited.insert(Arc::clone(&root_document.uri)) {
- continue;
- }
-
- let slice = workspace.slice(&root_document.uri);
- for uri in slice.documents_by_uri.keys() {
- visited.insert(Arc::clone(uri));
- }
- components.push(slice);
- }
- components
-}
-fn build_dependency_graph(workspace: &Workspace) -> (Graph<usize, (), Directed>, Vec<&Document>) {
- let mut graph = Graph::new();
- let documents: Vec<_> = workspace.documents_by_uri.values().collect();
- let nodes: Vec<_> = (0..documents.len()).map(|i| graph.add_node(i)).collect();
-
- for (i, document) in documents.iter().enumerate() {
- if let Some(data) = document.data.as_latex() {
- for link in &data.extras.explicit_links {
- for target in &link.targets {
- if let Some(j) = documents
- .iter()
- .position(|document| document.uri.as_ref() == target.as_ref())
- {
- graph.add_edge(nodes[j], nodes[i], ());
- break;
- }
- }
- }
- }
+ pub fn get(&self, db: &dyn Db, uri: &Url) -> usize {
+ self.ordering
+ .iter()
+ .position(|doc| doc.location(db).uri(db) == uri)
+ .unwrap_or(std::usize::MAX)
}
-
- (graph, documents)
}
#[cfg(test)]
mod tests {
- use std::sync::Arc;
-
- use anyhow::Result;
-
- use crate::DocumentLanguage;
+ use crate::{
+ db::{Language, Owner},
+ Database,
+ };
use super::*;
#[test]
- fn test_no_cycles() -> Result<()> {
- let mut workspace = Workspace::default();
+ fn test_no_cycles() {
+ let mut db = Database::default();
+ let workspace = Workspace::get(&db);
let a = workspace.open(
- Arc::new(Url::parse("http://example.com/a.tex")?),
- Arc::new(String::new()),
- DocumentLanguage::Latex,
- )?;
+ &mut db,
+ Url::parse("http://example.com/a.tex").unwrap(),
+ String::new(),
+ Language::Tex,
+ Owner::Client,
+ );
let b = workspace.open(
- Arc::new(Url::parse("http://example.com/b.tex")?),
- Arc::new(String::new()),
- DocumentLanguage::Latex,
- )?;
+ &mut db,
+ Url::parse("http://example.com/b.tex").unwrap(),
+ String::new(),
+ Language::Tex,
+ Owner::Client,
+ );
let c = workspace.open(
- Arc::new(Url::parse("http://example.com/c.tex")?),
- Arc::new(r#"\include{b}\include{a}"#.to_string()),
- DocumentLanguage::Latex,
- )?;
-
- let ordering = ProjectOrdering::from(&workspace);
-
- assert_eq!(ordering.get(&a.uri), 2);
- assert_eq!(ordering.get(&b.uri), 1);
- assert_eq!(ordering.get(&c.uri), 0);
- Ok(())
+ &mut db,
+ Url::parse("http://example.com/c.tex").unwrap(),
+ r#"\documentclass{article}\include{b}\include{a}"#.to_string(),
+ Language::Tex,
+ Owner::Client,
+ );
+
+ let ordering = ProjectOrdering::new(&db);
+
+ assert_eq!(ordering.get(&db, a.location(&db).uri(&db)), 0);
+ assert_eq!(ordering.get(&db, b.location(&db).uri(&db)), 1);
+ assert_eq!(ordering.get(&db, c.location(&db).uri(&db)), 2);
}
#[test]
- fn test_cycles() -> Result<()> {
- let mut workspace = Workspace::default();
+ fn test_two_layers() {
+ let mut db = Database::default();
+ let workspace = Workspace::get(&db);
let a = workspace.open(
- Arc::new(Url::parse("http://example.com/a.tex")?),
- Arc::new(r#"\include{b}"#.to_string()),
- DocumentLanguage::Latex,
- )?;
+ &mut db,
+ Url::parse("http://example.com/a.tex").unwrap(),
+ String::new(),
+ Language::Tex,
+ Owner::Client,
+ );
let b = workspace.open(
- Arc::new(Url::parse("http://example.com/b.tex")?),
- Arc::new(r#"\include{a}"#.to_string()),
- DocumentLanguage::Latex,
- )?;
+ &mut db,
+ Url::parse("http://example.com/b.tex").unwrap(),
+ r#"\include{a}"#.to_string(),
+ Language::Tex,
+ Owner::Client,
+ );
let c = workspace.open(
- Arc::new(Url::parse("http://example.com/c.tex")?),
- Arc::new(r#"\include{a}"#.to_string()),
- DocumentLanguage::Latex,
- )?;
+ &mut db,
+ Url::parse("http://example.com/c.tex").unwrap(),
+ r#"\documentclass{article}\include{b}"#.to_string(),
+ Language::Tex,
+ Owner::Client,
+ );
+
+ let ordering = ProjectOrdering::new(&db);
+
+ assert_eq!(ordering.get(&db, a.location(&db).uri(&db)), 0);
+ assert_eq!(ordering.get(&db, b.location(&db).uri(&db)), 1);
+ assert_eq!(ordering.get(&db, c.location(&db).uri(&db)), 2);
+ }
- let ordering = ProjectOrdering::from(&workspace);
+ #[test]
+ fn test_cycles() {
+ let mut db = Database::default();
+ let workspace = Workspace::get(&db);
- assert_eq!(ordering.get(&a.uri), 1);
- assert_eq!(ordering.get(&b.uri), 2);
- assert_eq!(ordering.get(&c.uri), 0);
- Ok(())
+ let a = workspace.open(
+ &mut db,
+ Url::parse("http://example.com/a.tex").unwrap(),
+ r#"\documentclass{article}\include{b}"#.to_string(),
+ Language::Tex,
+ Owner::Client,
+ );
+
+ workspace.open(
+ &mut db,
+ Url::parse("http://example.com/b.tex").unwrap(),
+ r#"\include{a}"#.to_string(),
+ Language::Tex,
+ Owner::Client,
+ );
+
+ workspace.open(
+ &mut db,
+ Url::parse("http://example.com/c.tex").unwrap(),
+ r#"\include{a}"#.to_string(),
+ Language::Tex,
+ Owner::Client,
+ );
+
+ let ordering = ProjectOrdering::new(&db);
+ assert_ne!(ordering.get(&db, a.location(&db).uri(&db)), 0);
}
#[test]
- fn test_multiple_roots() -> Result<()> {
- let mut workspace = Workspace::default();
+ fn test_multiple_roots() {
+ let mut db = Database::default();
+ let workspace = Workspace::get(&db);
let a = workspace.open(
- Arc::new(Url::parse("http://example.com/a.tex")?),
- Arc::new(r#"\include{b}"#.to_string()),
- DocumentLanguage::Latex,
- )?;
+ &mut db,
+ Url::parse("http://example.com/a.tex").unwrap(),
+ r#"\documentclass{article}\include{b}"#.to_string(),
+ Language::Tex,
+ Owner::Client,
+ );
let b = workspace.open(
- Arc::new(Url::parse("http://example.com/b.tex")?),
- Arc::new(r#""#.to_string()),
- DocumentLanguage::Latex,
- )?;
+ &mut db,
+ Url::parse("http://example.com/b.tex").unwrap(),
+ String::new(),
+ Language::Tex,
+ Owner::Client,
+ );
let c = workspace.open(
- Arc::new(Url::parse("http://example.com/c.tex")?),
- Arc::new(r#""#.to_string()),
- DocumentLanguage::Latex,
- )?;
+ &mut db,
+ Url::parse("http://example.com/c.tex").unwrap(),
+ String::new(),
+ Language::Tex,
+ Owner::Client,
+ );
let d = workspace.open(
- Arc::new(Url::parse("http://example.com/d.tex")?),
- Arc::new(r#"\include{c}"#.to_string()),
- DocumentLanguage::Latex,
- )?;
-
- let ordering = ProjectOrdering::from(&workspace);
-
- assert!(ordering.get(&a.uri) < ordering.get(&b.uri));
- assert!(ordering.get(&d.uri) < ordering.get(&c.uri));
- Ok(())
+ &mut db,
+ Url::parse("http://example.com/d.tex").unwrap(),
+ r#"\documentclass{article}\include{c}"#.to_string(),
+ Language::Tex,
+ Owner::Client,
+ );
+
+ let ordering = ProjectOrdering::new(&db);
+ assert!(
+ ordering.get(&db, b.location(&db).uri(&db))
+ < ordering.get(&db, a.location(&db).uri(&db))
+ );
+ assert!(
+ ordering.get(&db, c.location(&db).uri(&db))
+ < ordering.get(&db, d.location(&db).uri(&db))
+ );
}
}
diff --git a/support/texlab/src/features/symbol/types.rs b/support/texlab/src/features/symbol/types.rs
index 88e7ffcb86..be0ffeceda 100644
--- a/support/texlab/src/features/symbol/types.rs
+++ b/support/texlab/src/features/symbol/types.rs
@@ -1,6 +1,10 @@
use lsp_types::{DocumentSymbol, Location, Range, SymbolInformation, SymbolKind, Url};
-use crate::{features::lsp_kinds::Structure, BibtexEntryTypeCategory};
+use crate::{
+ db::Word,
+ util::{lang_data::BibtexEntryTypeCategory, lsp_enums::Structure},
+ Db,
+};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum InternalSymbolKind {
@@ -39,7 +43,7 @@ impl InternalSymbolKind {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct InternalSymbol {
pub name: String,
- pub label: Option<String>,
+ pub label: Option<Word>,
pub kind: InternalSymbolKind,
pub deprecated: bool,
pub full_range: Range,
@@ -76,16 +80,17 @@ impl InternalSymbol {
buffer.push(self);
}
- pub fn into_document_symbol(self) -> DocumentSymbol {
+ pub fn into_document_symbol(self, db: &dyn Db) -> DocumentSymbol {
let children = self
.children
.into_iter()
- .map(|child| child.into_document_symbol())
+ .map(|child| child.into_document_symbol(db))
.collect();
+
#[allow(deprecated)]
DocumentSymbol {
name: self.name,
- detail: self.label,
+ detail: self.label.map(|word| word.text(db).clone()),
kind: self.kind.into_symbol_kind(),
deprecated: Some(self.deprecated),
range: self.full_range,
diff --git a/support/texlab/src/features/workspace_command.rs b/support/texlab/src/features/workspace_command.rs
new file mode 100644
index 0000000000..8d6732cd1c
--- /dev/null
+++ b/support/texlab/src/features/workspace_command.rs
@@ -0,0 +1,103 @@
+use std::process::Stdio;
+
+use anyhow::{bail, Result};
+use lsp_types::{TextDocumentIdentifier, Url};
+use thiserror::Error;
+
+use crate::{db::Workspace, normalize_uri, Db};
+
+pub fn select(db: &dyn Db, name: &str, args: Vec<serde_json::Value>) -> Result<CleanCommand> {
+ Ok(match name {
+ "texlab.cleanAuxiliary" => CleanCommand::new(db, CleanOptions::Auxiliary, args)?,
+ "texlab.cleanArtifacts" => CleanCommand::new(db, CleanOptions::Artifacts, args)?,
+ _ => bail!("Unknown command: {}", name),
+ })
+}
+
+#[derive(Debug, Error)]
+pub enum CleanError {
+ #[error("document '{0}' not found")]
+ DocumentNotFound(Url),
+
+ #[error("document '{0}' is not a local file")]
+ NoLocalFile(Url),
+
+ #[error("document was not provided as an argument")]
+ MissingArg,
+
+ #[error("invalid argument: {0}")]
+ InvalidArg(serde_json::Error),
+
+ #[error("failed to spawn process: {0}")]
+ Spawn(std::io::Error),
+}
+
+#[derive(Debug)]
+pub struct CleanCommand {
+ executable: String,
+ args: Vec<String>,
+}
+
+impl CleanCommand {
+ fn new(db: &dyn Db, options: CleanOptions, args: Vec<serde_json::Value>) -> Result<Self> {
+ let params: TextDocumentIdentifier =
+ serde_json::from_value(args.into_iter().next().ok_or(CleanError::MissingArg)?)
+ .map_err(CleanError::InvalidArg)?;
+
+ let mut uri = params.uri;
+ normalize_uri(&mut uri);
+
+ let workspace = Workspace::get(db);
+
+ let document = workspace
+ .lookup_uri(db, &uri)
+ .ok_or_else(|| CleanError::DocumentNotFound(uri.clone()))?;
+
+ let working_dir = workspace.working_dir(db, document.directory(db));
+
+ let output_dir = workspace
+ .output_dir(db, working_dir)
+ .path(db)
+ .as_deref()
+ .ok_or_else(|| CleanError::NoLocalFile(uri.clone()))?;
+
+ let path = document
+ .location(db)
+ .path(db)
+ .as_deref()
+ .ok_or_else(|| CleanError::NoLocalFile(uri.clone()))?;
+
+ let flag = match options {
+ CleanOptions::Auxiliary => "-c",
+ CleanOptions::Artifacts => "-C",
+ };
+
+ let executable = "latexmk".to_string();
+ let args = vec![
+ format!("-outdir={}", output_dir.display()),
+ flag.to_string(),
+ path.display().to_string(),
+ ];
+
+ Ok(Self { executable, args })
+ }
+
+ pub fn run(self) -> Result<(), CleanError> {
+ log::debug!("Cleaning output files: {} {:?}", self.executable, self.args);
+ std::process::Command::new(self.executable)
+ .args(self.args)
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()
+ .map_err(CleanError::Spawn)?;
+
+ Ok(())
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
+enum CleanOptions {
+ Auxiliary,
+ Artifacts,
+}
diff --git a/support/texlab/src/language.rs b/support/texlab/src/language.rs
deleted file mode 100644
index 45ef22daba..0000000000
--- a/support/texlab/src/language.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-use std::{ffi::OsStr, path::Path};
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
-pub enum DocumentLanguage {
- Latex,
- Bibtex,
- BuildLog,
-}
-
-impl DocumentLanguage {
- pub fn by_path(path: &Path) -> Option<Self> {
- path.extension()
- .and_then(OsStr::to_str)
- .and_then(Self::by_extension)
- }
-
- pub fn by_extension(extension: &str) -> Option<Self> {
- match extension.to_lowercase().as_str() {
- "tex" | "sty" | "cls" | "def" | "lco" | "aux" | "rnw" => Some(Self::Latex),
- "bib" | "bibtex" => Some(Self::Bibtex),
- "log" => Some(Self::BuildLog),
- _ => None,
- }
- }
-
- pub fn by_language_id(language_id: &str) -> Option<Self> {
- match language_id {
- "latex" | "tex" => Some(Self::Latex),
- "bibtex" | "bib" => Some(Self::Bibtex),
- _ => None,
- }
- }
-}
diff --git a/support/texlab/src/lib.rs b/support/texlab/src/lib.rs
index 1f3d22d7aa..9a7b587ab8 100644
--- a/support/texlab/src/lib.rs
+++ b/support/texlab/src/lib.rs
@@ -1,37 +1,120 @@
-mod capabilities;
-pub mod citation;
+#![allow(clippy::needless_lifetimes)]
+
+pub(crate) mod citation;
mod client;
-pub mod component_db;
-mod debouncer;
-mod diagnostics;
-mod dispatch;
-pub mod distro;
-mod document;
-mod environment;
+pub mod db;
+pub(crate) mod distro;
pub mod features;
-mod label;
-mod lang_data;
-mod language;
-mod line_index;
-mod line_index_ext;
mod options;
-mod range;
-mod req_queue;
+pub mod parser;
mod server;
pub mod syntax;
-mod workspace;
-
-pub use self::{
- capabilities::ClientCapabilitiesExt,
- document::*,
- environment::Environment,
- label::*,
- lang_data::*,
- language::DocumentLanguage,
- line_index::{LineCol, LineColUtf16, LineIndex},
- line_index_ext::LineIndexExt,
- options::*,
- range::RangeExt,
- server::Server,
- workspace::{Workspace, WorkspaceEvent},
-};
+pub(crate) mod util;
+
+pub use self::{options::*, server::Server};
+
+#[salsa::jar(db = Db)]
+pub struct Jar(
+ db::Word,
+ db::Location,
+ db::Location_path,
+ db::Contents,
+ db::Contents_line_index,
+ db::LinterData,
+ db::Document,
+ db::Document_parse,
+ db::Document_can_be_index,
+ db::Document_can_be_built,
+ db::parse::TexDocumentData,
+ db::parse::TexDocumentData_analyze,
+ db::parse::BibDocumentData,
+ db::parse::LogDocumentData,
+ db::analysis::TexLink,
+ db::analysis::label::Number,
+ db::analysis::label::Name,
+ db::analysis::TheoremEnvironment,
+ db::analysis::GraphicsPath,
+ db::analysis::TexAnalysis,
+ db::MissingDependencies,
+ db::hidden_dependency,
+ db::source_dependency,
+ db::dependency_graph,
+ db::Workspace,
+ db::Workspace_working_dir,
+ db::Workspace_output_dir,
+ db::Workspace_parents,
+ db::Workspace_related,
+ db::Workspace_number_of_label,
+ db::diagnostics::tex::collect,
+ db::diagnostics::bib::collect,
+ db::diagnostics::log::collect,
+ db::diagnostics::collect,
+ db::diagnostics::collect_filtered,
+);
+
+pub trait Db: salsa::DbWithJar<Jar> {}
+
+impl<DB> Db for DB where DB: ?Sized + salsa::DbWithJar<Jar> {}
+
+#[salsa::db(crate::Jar)]
+pub struct Database {
+ storage: salsa::Storage<Self>,
+}
+
+impl Default for Database {
+ fn default() -> Self {
+ let storage = salsa::Storage::default();
+ let db = Self { storage };
+ db::Workspace::new(
+ &db,
+ Default::default(),
+ Default::default(),
+ Default::default(),
+ Default::default(),
+ Default::default(),
+ Default::default(),
+ );
+
+ db
+ }
+}
+
+impl salsa::Database for Database {}
+
+impl salsa::ParallelDatabase for Database {
+ fn snapshot(&self) -> salsa::Snapshot<Self> {
+ salsa::Snapshot::new(Self {
+ storage: self.storage.snapshot(),
+ })
+ }
+}
+
+pub(crate) fn normalize_uri(uri: &mut lsp_types::Url) {
+ fn fix_drive_letter(text: &str) -> Option<String> {
+ if !text.is_ascii() {
+ return None;
+ }
+
+ match &text[1..] {
+ ":" => Some(text.to_ascii_uppercase()),
+ "%3A" | "%3a" => Some(format!("{}:", text[0..1].to_ascii_uppercase())),
+ _ => None,
+ }
+ }
+
+ if let Some(mut segments) = uri.path_segments() {
+ if let Some(mut path) = segments.next().and_then(fix_drive_letter) {
+ for segment in segments {
+ path.push('/');
+ path.push_str(segment);
+ }
+
+ uri.set_path(&path);
+ }
+ }
+
+ uri.set_fragment(None);
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/support/texlab/src/main.rs b/support/texlab/src/main.rs
index 06cbba3f5d..ed807f8799 100644
--- a/support/texlab/src/main.rs
+++ b/support/texlab/src/main.rs
@@ -1,4 +1,4 @@
-use std::{env, fs::OpenOptions, io, path::PathBuf};
+use std::{fs::OpenOptions, io, path::PathBuf};
use anyhow::Result;
use clap::{ArgAction, Parser};
@@ -21,10 +21,6 @@ struct Opts {
/// Write the logging output to FILE
#[clap(long, name = "FILE", value_parser)]
log_file: Option<PathBuf>,
-
- /// Print version information and exit
- #[clap(short = 'V', long)]
- version: bool,
}
fn main() -> Result<()> {
@@ -32,7 +28,7 @@ fn main() -> Result<()> {
setup_logger(opts);
let (connection, threads) = Connection::stdio();
- Server::with_connection(connection, env::current_dir()?, true).run()?;
+ Server::new(connection).run()?;
threads.join()?;
Ok(())
diff --git a/support/texlab/src/options.rs b/support/texlab/src/options.rs
index 241126d908..cc0058fc68 100644
--- a/support/texlab/src/options.rs
+++ b/support/texlab/src/options.rs
@@ -1,47 +1,32 @@
-use std::path::PathBuf;
+use std::{path::PathBuf, time::Duration};
use regex::Regex;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+#[serde(default)]
pub struct Options {
- #[serde(default)]
pub root_directory: Option<PathBuf>,
-
- #[serde(default)]
pub aux_directory: Option<PathBuf>,
-
- #[serde(default)]
pub bibtex_formatter: BibtexFormatter,
-
- #[serde(default)]
pub latex_formatter: LatexFormatter,
-
- #[serde(default)]
pub formatter_line_length: Option<i32>,
-
- #[serde(default)]
pub diagnostics: DiagnosticsOptions,
-
- #[serde(default = "default_diagnostics_delay")]
- pub diagnostics_delay: u64,
-
- #[serde(default)]
+ pub diagnostics_delay: DiagnosticsDelay,
pub build: BuildOptions,
-
- #[serde(default)]
pub chktex: ChktexOptions,
-
- #[serde(default)]
pub latexindent: LatexindentOptions,
-
- #[serde(default)]
pub forward_search: ForwardSearchOptions,
}
-fn default_diagnostics_delay() -> u64 {
- 300
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
+pub struct DiagnosticsDelay(#[serde(with = "serde_millis")] pub Duration);
+
+impl Default for DiagnosticsDelay {
+ fn default() -> Self {
+ Self(Duration::from_millis(300))
+ }
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
@@ -72,75 +57,77 @@ impl Default for LatexFormatter {
#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+#[serde(default)]
pub struct LatexindentOptions {
- #[serde(default)]
pub local: Option<String>,
-
- #[serde(default)]
pub modify_line_breaks: bool,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+#[serde(default)]
pub struct BuildOptions {
- #[serde(default = "default_build_executable")]
- pub executable: String,
-
- #[serde(default = "default_build_args")]
- pub args: Vec<String>,
-
- #[serde(default)]
- pub is_continuous: bool,
-
- #[serde(default)]
+ pub executable: BuildExecutable,
+ pub args: BuildArgs,
pub on_save: bool,
-
- #[serde(default)]
pub forward_search_after: bool,
}
-fn default_build_executable() -> String {
- "latexmk".to_string()
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
+#[serde(transparent)]
+pub struct BuildExecutable(pub String);
+
+impl Default for BuildExecutable {
+ fn default() -> Self {
+ Self("latexmk".to_string())
+ }
}
-fn default_build_args() -> Vec<String> {
- vec![
- "-pdf".to_string(),
- "-interaction=nonstopmode".to_string(),
- "-synctex=1".to_string(),
- "%f".to_string(),
- ]
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
+#[serde(transparent)]
+pub struct BuildArgs(pub Vec<String>);
+
+impl Default for BuildArgs {
+ fn default() -> Self {
+ Self(vec![
+ "-pdf".to_string(),
+ "-interaction=nonstopmode".to_string(),
+ "-synctex=1".to_string(),
+ "%f".to_string(),
+ ])
+ }
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+#[serde(default)]
pub struct ChktexOptions {
- #[serde(default)]
pub on_open_and_save: bool,
-
- #[serde(default)]
pub on_edit: bool,
}
#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+#[serde(default)]
pub struct ForwardSearchOptions {
- #[serde(default)]
pub executable: Option<String>,
-
- #[serde(default)]
pub args: Option<Vec<String>>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
+#[serde(default)]
pub struct DiagnosticsOptions {
- #[serde(default)]
pub allowed_patterns: Vec<DiagnosticsPattern>,
-
- #[serde(default)]
pub ignored_patterns: Vec<DiagnosticsPattern>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiagnosticsPattern(#[serde(with = "serde_regex")] pub Regex);
+
+#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+#[serde(default)]
+pub struct StartupOptions {
+ pub skip_distro: bool,
+}
diff --git a/support/texlab/src/parser.rs b/support/texlab/src/parser.rs
new file mode 100644
index 0000000000..51d56475cf
--- /dev/null
+++ b/support/texlab/src/parser.rs
@@ -0,0 +1,5 @@
+mod bibtex;
+mod build_log;
+mod latex;
+
+pub use self::{bibtex::parse_bibtex, build_log::parse_build_log, latex::parse_latex};
diff --git a/support/texlab/src/syntax/bibtex/parser.rs b/support/texlab/src/parser/bibtex.rs
index 4a8a429b18..e03a39c9ae 100644
--- a/support/texlab/src/syntax/bibtex/parser.rs
+++ b/support/texlab/src/parser/bibtex.rs
@@ -1,12 +1,9 @@
-use logos::{Lexer, Logos};
+use logos::Logos;
use rowan::{GreenNode, GreenNodeBuilder};
-use super::{
- lexer::*,
- SyntaxKind::{self, *},
-};
+use crate::syntax::bibtex::SyntaxKind::{self, *};
-pub fn parse(input: &str) -> GreenNode {
+pub fn parse_bibtex(input: &str) -> GreenNode {
let mut ptr = TokenPtr {
builder: GreenNodeBuilder::new(),
lexer: RootToken::lexer(input),
@@ -136,9 +133,9 @@ fn curly_group(mut ptr: TokenPtr<ContentToken>) -> TokenPtr<ContentToken> {
| ContentToken::Nbsp
| ContentToken::Comma
| ContentToken::Integer
+ | ContentToken::Quote
| ContentToken::Word => ptr.bump(),
ContentToken::LCurly => ptr = curly_group(ptr),
- ContentToken::Quote => ptr = quote_group(ptr),
ContentToken::AccentName => ptr = accent(ptr),
ContentToken::CommandName => ptr = command(ptr),
};
@@ -205,7 +202,7 @@ fn command(mut ptr: TokenPtr<ContentToken>) -> TokenPtr<ContentToken> {
struct TokenPtr<'a, T: Logos<'a>> {
builder: GreenNodeBuilder<'static>,
- lexer: Lexer<'a, T>,
+ lexer: logos::Lexer<'a, T>,
token: Option<(T, &'a str)>,
}
@@ -262,3 +259,196 @@ where
self.token
}
}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
+enum RootToken {
+ #[token(r"@preamble", ignore(ascii_case))]
+ Preamble,
+
+ #[token(r"@string", ignore(ascii_case))]
+ String,
+
+ #[token(r"@comment", ignore(ascii_case))]
+ Comment,
+
+ #[regex(r"@[a-zA-Z]*")]
+ Entry,
+
+ #[regex(r"[^@]+")]
+ #[error]
+ Junk,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
+enum BodyToken {
+ #[regex(r"\s+")]
+ Whitespace,
+
+ #[token("{")]
+ #[token("(")]
+ LDelim,
+
+ #[token("}")]
+ #[token(")")]
+ RDelim,
+
+ #[token(",")]
+ Comma,
+
+ #[token("=")]
+ Eq,
+
+ #[regex(r"[^\s\(\)\{\}@,=]+")]
+ Name,
+
+ #[error]
+ Error,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
+enum ValueToken {
+ #[regex(r"\s+")]
+ Whitespace,
+
+ #[token("#")]
+ Pound,
+
+ #[token(",")]
+ Comma,
+
+ #[token("{")]
+ LCurly,
+
+ #[token("}")]
+ RCurly,
+
+ #[token("\"")]
+ Quote,
+
+ #[regex(r"\d+", priority = 2)]
+ Integer,
+
+ #[regex(r#"[^\s"\{\},]+"#)]
+ #[error]
+ Name,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
+enum ContentToken {
+ #[regex(r"\s+")]
+ Whitespace,
+
+ #[token(",")]
+ Comma,
+
+ #[token("{")]
+ LCurly,
+
+ #[token("}")]
+ RCurly,
+
+ #[token("\"")]
+ Quote,
+
+ #[regex(r"\d+", priority = 2)]
+ Integer,
+
+ #[token(r#"~"#)]
+ Nbsp,
+
+ #[token(r#"\`"#)]
+ #[token(r#"\'"#)]
+ #[token(r#"\^"#)]
+ #[token(r#"\""#)]
+ #[token(r#"\H"#)]
+ #[token(r#"\~"#)]
+ #[token(r#"\c"#)]
+ #[token(r#"\k"#)]
+ #[token(r#"\="#)]
+ #[token(r#"\b"#)]
+ #[token(r#"\."#)]
+ #[token(r#"\d"#)]
+ #[token(r#"\r"#)]
+ #[token(r#"\u"#)]
+ #[token(r#"\v"#)]
+ #[token(r#"\t"#)]
+ AccentName,
+
+ #[regex(r"\\([^\r\n]|[@a-zA-Z:_]+\*?)?")]
+ CommandName,
+
+ #[regex(r#"[^\s"\{\}\\~,]+"#)]
+ #[error]
+ Word,
+}
+
+impl From<RootToken> for SyntaxKind {
+ fn from(token: RootToken) -> Self {
+ match token {
+ RootToken::Preamble | RootToken::String | RootToken::Comment | RootToken::Entry => TYPE,
+ RootToken::Junk => JUNK,
+ }
+ }
+}
+
+impl From<BodyToken> for SyntaxKind {
+ fn from(token: BodyToken) -> Self {
+ match token {
+ BodyToken::Whitespace => WHITESPACE,
+ BodyToken::LDelim => L_DELIM,
+ BodyToken::RDelim => R_DELIM,
+ BodyToken::Comma => COMMA,
+ BodyToken::Eq => EQ,
+ BodyToken::Name => NAME,
+ BodyToken::Error => unreachable!(),
+ }
+ }
+}
+
+impl From<ValueToken> for SyntaxKind {
+ fn from(token: ValueToken) -> Self {
+ match token {
+ ValueToken::Whitespace => WHITESPACE,
+ ValueToken::Pound => POUND,
+ ValueToken::Comma => COMMA,
+ ValueToken::LCurly => L_CURLY,
+ ValueToken::RCurly => R_CURLY,
+ ValueToken::Quote => QUOTE,
+ ValueToken::Integer => INTEGER,
+ ValueToken::Name => NAME,
+ }
+ }
+}
+
+impl From<ContentToken> for SyntaxKind {
+ fn from(token: ContentToken) -> Self {
+ match token {
+ ContentToken::Whitespace => WHITESPACE,
+ ContentToken::Comma => COMMA,
+ ContentToken::LCurly => L_CURLY,
+ ContentToken::RCurly => R_CURLY,
+ ContentToken::Quote => QUOTE,
+ ContentToken::Integer => INTEGER,
+ ContentToken::Nbsp => NBSP,
+ ContentToken::AccentName => ACCENT_NAME,
+ ContentToken::CommandName => COMMAND_NAME,
+ ContentToken::Word => WORD,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::syntax::bibtex;
+
+ use super::parse_bibtex;
+
+ #[test]
+ fn test_parse() {
+ insta::glob!("test_data/bibtex/{,**/}*.txt", |path| {
+ let text = std::fs::read_to_string(path).unwrap().replace("\r\n", "\n");
+ let root = bibtex::SyntaxNode::new_root(parse_bibtex(&text));
+ insta::assert_debug_snapshot!(root);
+ });
+ }
+}
diff --git a/support/texlab/src/parser/build_log.rs b/support/texlab/src/parser/build_log.rs
new file mode 100644
index 0000000000..5f99129cdb
--- /dev/null
+++ b/support/texlab/src/parser/build_log.rs
@@ -0,0 +1,184 @@
+use std::{cmp::Ordering, path::PathBuf};
+
+use once_cell::sync::Lazy;
+use regex::{Match, Regex};
+
+use crate::syntax::{BuildError, BuildErrorLevel, BuildLog};
+
+const MAX_LINE_LENGTH: usize = 79;
+
+static PACKAGE_MESSAGE_REGEX: Lazy<Regex> =
+ Lazy::new(|| Regex::new("^\\([a-zA-Z_\\-]+\\)\\s*(?P<msg>.*)$").unwrap());
+
+static FILE_REGEX: Lazy<Regex> =
+ Lazy::new(|| Regex::new("\\((?P<file>[^\r\n()]+\\.(tex|sty|cls))").unwrap());
+
+static TEX_ERROR_REGEX: Lazy<Regex> = Lazy::new(|| {
+ Regex::new("(?m)^! ((?P<msg1>(.|\r|\n)*?)\r?\nl\\.(?P<line>\\d+)( (\\.\\.\\.)?(?P<hint>[^\r\n]+))?|(?P<msg2>[^\r\n]*))").unwrap()
+});
+
+static WARNING_REGEX: Lazy<Regex> =
+ Lazy::new(|| Regex::new("(LaTeX|Package [a-zA-Z_\\-]+) Warning: (?P<msg>[^\r\n]*)").unwrap());
+
+static BAD_BOX_REGEX: Lazy<Regex> = Lazy::new(|| {
+ Regex::new("(?P<msg>(Ov|Und)erfull \\\\[hv]box[^\r\n]*lines? (?P<line>\\d+)[^\r\n]*)").unwrap()
+});
+
+pub fn parse_build_log(log: &str) -> BuildLog {
+ let log = prepare_log(log);
+ let mut ranges: Vec<FileRange> = FILE_REGEX
+ .find_iter(&log)
+ .map(|result| FileRange::create(&log, result))
+ .collect();
+ ranges.sort();
+
+ let tex_errors = extract_matches(&log, &ranges, &TEX_ERROR_REGEX, BuildErrorLevel::Error);
+ let warnings = extract_matches(&log, &ranges, &WARNING_REGEX, BuildErrorLevel::Warning);
+ let bad_boxes = extract_matches(&log, &ranges, &BAD_BOX_REGEX, BuildErrorLevel::Warning);
+
+ let errors = vec![tex_errors, warnings, bad_boxes].concat();
+ BuildLog { errors }
+}
+
+fn extract_matches(
+ log: &str,
+ ranges: &[FileRange],
+ regex: &Regex,
+ level: BuildErrorLevel,
+) -> Vec<BuildError> {
+ let mut errors = Vec::new();
+ for result in regex.find_iter(log) {
+ let captures = regex.captures(&log[result.start()..result.end()]).unwrap();
+ let message = captures
+ .name("msg")
+ .or_else(|| captures.name("msg1"))
+ .or_else(|| captures.name("msg2"))
+ .unwrap()
+ .as_str()
+ .lines()
+ .next()
+ .unwrap_or_default()
+ .to_owned();
+
+ if let Some(range) = ranges.iter().find(|range| range.contains(result.start())) {
+ let line = captures
+ .name("line")
+ .map(|result| result.as_str().parse::<u32>().unwrap() - 1);
+
+ let hint: Option<String> = if line.is_some() {
+ captures
+ .name("hint")
+ .map(|r| String::from(r.as_str().trim()))
+ } else {
+ None
+ };
+
+ errors.push(BuildError {
+ relative_path: range.path.clone(),
+ level,
+ message,
+ line,
+ hint,
+ });
+ }
+ }
+ errors
+}
+
+fn prepare_log(log: &str) -> String {
+ let mut old_lines = log.lines();
+ let mut new_lines: Vec<String> = Vec::new();
+ while let Some(line) = old_lines.next() {
+ if PACKAGE_MESSAGE_REGEX.is_match(line) {
+ let captures = PACKAGE_MESSAGE_REGEX.captures(line).unwrap();
+ if let Some(last_line) = new_lines.last_mut() {
+ last_line.push(' ');
+ last_line.push_str(captures.name("msg").unwrap().as_str());
+ }
+ } else if line.ends_with("...") {
+ let mut new_line = line[line.len() - 3..].to_owned();
+ if let Some(old_line) = old_lines.next() {
+ new_line.push_str(old_line);
+ }
+ new_lines.push(new_line);
+ } else if line.chars().count() == MAX_LINE_LENGTH {
+ let mut new_line = String::new();
+ new_line.push_str(line);
+ if let Some(old_line) = old_lines.next() {
+ new_line.push_str(old_line);
+ }
+ new_lines.push(new_line);
+ } else {
+ new_lines.push(line.to_owned());
+ }
+ }
+ new_lines.join("\n")
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+struct FileRange {
+ pub path: PathBuf,
+ pub start: usize,
+ pub end: usize,
+}
+
+impl FileRange {
+ fn create(log: &str, result: Match) -> Self {
+ let mut balance = 1;
+ let mut end = result.start() + 1;
+ let chars = log[result.start() + 1..].chars();
+ for c in chars {
+ if balance <= 0 {
+ break;
+ }
+
+ if c == '(' {
+ balance += 1;
+ } else if c == ')' {
+ balance -= 1;
+ }
+ end += c.len_utf8();
+ }
+
+ let captures = FILE_REGEX.captures(result.as_str()).unwrap();
+ let path = PathBuf::from(captures.name("file").unwrap().as_str());
+ Self {
+ path,
+ start: result.start(),
+ end,
+ }
+ }
+
+ fn len(&self) -> usize {
+ self.end - self.start + 1
+ }
+
+ fn contains(&self, index: usize) -> bool {
+ index >= self.start && index <= self.end
+ }
+}
+
+impl Ord for FileRange {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.len().cmp(&other.len())
+ }
+}
+
+impl PartialOrd for FileRange {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::parse_build_log;
+
+ #[test]
+ fn test_parse() {
+ insta::glob!("test_data/build_log/*.txt", |path| {
+ let text = std::fs::read_to_string(path).unwrap().replace("\r\n", "\n");
+ insta::assert_debug_snapshot!(parse_build_log(&text));
+ });
+ }
+}
diff --git a/support/texlab/src/syntax/latex/parser.rs b/support/texlab/src/parser/latex.rs
index a43a77ebc9..a103561685 100644
--- a/support/texlab/src/syntax/latex/parser.rs
+++ b/support/texlab/src/parser/latex.rs
@@ -1,14 +1,10 @@
+mod lexer;
+
use rowan::{GreenNode, GreenNodeBuilder};
-use super::{
- lexer::Lexer,
- SyntaxKind::{self, *},
-};
+use crate::syntax::latex::SyntaxKind::{self, *};
-#[derive(Clone)]
-pub struct Parse {
- pub green: GreenNode,
-}
+use self::lexer::Lexer;
#[derive(Debug, Clone, Copy)]
struct ParserContext {
@@ -80,15 +76,14 @@ impl<'a> Parser<'a> {
}
}
- pub fn parse(mut self) -> Parse {
+ pub fn parse(mut self) -> GreenNode {
self.builder.start_node(ROOT.into());
self.preamble();
while self.peek().is_some() {
self.content(ParserContext::default());
}
self.builder.finish_node();
- let green = self.builder.finish();
- Parse { green }
+ self.builder.finish()
}
fn content(&mut self, context: ParserContext) {
@@ -177,7 +172,7 @@ impl<'a> Parser<'a> {
self.eat();
while self
.peek()
- .filter(|&kind| !matches!(kind, R_CURLY | END_ENVIRONMENT_NAME))
+ .filter(|&kind| !matches!(kind, R_CURLY))
.is_some()
{
self.content(ParserContext::default());
@@ -518,7 +513,7 @@ impl<'a> Parser<'a> {
while self
.peek()
- .filter(|&kind| kind != END_ENVIRONMENT_NAME)
+ .filter(|&kind| !matches!(kind, R_CURLY | END_ENVIRONMENT_NAME))
.is_some()
{
self.content(ParserContext::default());
@@ -854,11 +849,16 @@ impl<'a> Parser<'a> {
fn curly_group_path(&mut self) {
self.builder.start_node(CURLY_GROUP_WORD.into());
self.eat();
- while matches!(
- self.peek(),
- Some(WORD | L_BRACK | R_BRACK | GENERIC_COMMAND_NAME)
- ) {
- self.path();
+ self.trivia();
+
+ while let Some(kind) = self.lexer.peek() {
+ match kind {
+ COMMENT | WORD | EQUALITY_SIGN | COMMA | L_BRACK | R_BRACK
+ | GENERIC_COMMAND_NAME => self.path(),
+ L_CURLY => self.curly_group_path(),
+ WHITESPACE => self.eat(),
+ _ => break,
+ };
}
self.expect(R_CURLY);
@@ -868,29 +868,17 @@ impl<'a> Parser<'a> {
fn curly_group_path_list(&mut self) {
self.builder.start_node(CURLY_GROUP_WORD_LIST.into());
self.eat();
+ self.trivia();
- while self.peek().map_or(false, |kind| {
- matches!(
- kind,
- LINE_BREAK
- | WHITESPACE
- | COMMENT
- | WORD
- | COMMA
- | EQUALITY_SIGN
- | L_BRACK
- | R_BRACK
- | GENERIC_COMMAND_NAME
- )
- }) {
- if matches!(
- self.peek(),
- Some(WORD | L_BRACK | R_BRACK | GENERIC_COMMAND_NAME)
- ) {
- self.path();
- } else {
- self.eat();
- }
+ while let Some(kind) = self.peek() {
+ match kind {
+ COMMENT | WORD | EQUALITY_SIGN | L_BRACK | R_BRACK | GENERIC_COMMAND_NAME => {
+ self.path()
+ }
+ WHITESPACE | LINE_BREAK | COMMA => self.eat(),
+ L_CURLY => self.curly_group_path(),
+ _ => break,
+ };
}
self.expect(R_CURLY);
@@ -900,22 +888,16 @@ impl<'a> Parser<'a> {
fn path(&mut self) {
self.builder.start_node(KEY.into());
self.eat();
- while self.peek().map_or(false, |kind| {
- matches!(
- kind,
- WHITESPACE
- | COMMENT
- | WORD
- | EQUALITY_SIGN
- | L_BRACK
- | R_BRACK
- | GENERIC_COMMAND_NAME
- )
- }) {
- self.eat();
+
+ while let Some(kind) = self.peek() {
+ match kind {
+ WHITESPACE | COMMENT | WORD | EQUALITY_SIGN | L_BRACK | R_BRACK
+ | GENERIC_COMMAND_NAME => self.eat(),
+ L_CURLY => self.curly_group_path(),
+ _ => break,
+ };
}
- self.trivia();
self.builder.finish_node();
}
@@ -1126,15 +1108,15 @@ impl<'a> Parser<'a> {
if self.lexer.peek() == Some(L_CURLY) {
self.curly_group_word();
- } else {
- self.builder.token(MISSING.into(), "");
+ }
+
+ if self.lexer.peek() == Some(L_BRACK) {
+ self.brack_group();
}
for _ in 0..2 {
if self.lexer.peek() == Some(L_CURLY) {
self.curly_group();
- } else {
- self.builder.token(MISSING.into(), "");
}
}
@@ -1321,603 +1303,49 @@ impl<'a> Parser<'a> {
self.eat();
self.trivia();
+ let checkpoint = self.builder.checkpoint();
if self.lexer.peek() == Some(L_CURLY) {
self.eat();
self.trivia();
- while matches!(self.lexer.peek(), Some(L_CURLY)) {
- self.curly_group_path();
+ if matches!(
+ self.lexer.peek(),
+ Some(WORD | EQUALITY_SIGN | L_BRACK | R_BRACK | GENERIC_COMMAND_NAME)
+ ) {
+ self.builder
+ .start_node_at(checkpoint, CURLY_GROUP_WORD.into());
+ self.path();
+ } else {
+ self.builder.start_node_at(checkpoint, CURLY_GROUP.into());
+ while matches!(self.lexer.peek(), Some(L_CURLY)) {
+ self.curly_group_path();
+ }
}
- } else {
- self.builder.token(MISSING.into(), "");
+
+ self.expect(R_CURLY);
+ self.builder.finish_node();
}
- self.expect(R_CURLY);
self.builder.finish_node();
}
}
-pub fn parse(text: &str) -> Parse {
+pub fn parse_latex(text: &str) -> GreenNode {
Parser::new(text).parse()
}
#[cfg(test)]
mod tests {
- use insta::assert_debug_snapshot;
-
use crate::syntax::latex;
- use super::*;
-
- fn setup(text: &str) -> latex::SyntaxNode {
- latex::SyntaxNode::new_root(parse(&text.trim().replace('\r', "")).green)
- }
-
- #[test]
- fn test_empty() {
- assert_debug_snapshot!(setup(r#""#));
- }
-
- #[test]
- fn test_hello_world() {
- assert_debug_snapshot!(setup(r#"Hello World!"#));
- }
-
- #[test]
- fn test_generic_command_empty() {
- assert_debug_snapshot!(setup(r#"\foo"#));
- }
-
- #[test]
- fn test_generic_command_escape() {
- assert_debug_snapshot!(setup(r#"\#"#));
- }
-
- #[test]
- fn test_generic_command_args() {
- assert_debug_snapshot!(setup(r#"\foo{bar}[qux]"#));
- }
-
- #[test]
- fn test_inline() {
- assert_debug_snapshot!(setup(r#"$x \in [0, \infty)$"#));
- }
-
- #[test]
- fn test_inline_double_dollar() {
- assert_debug_snapshot!(setup(r#"$$x \in [0, \infty)$$"#));
- }
-
- #[test]
- fn test_brace_group_simple() {
- assert_debug_snapshot!(setup(r#"{hello world}"#));
- }
-
- #[test]
- fn test_brace_group_missing_end() {
- assert_debug_snapshot!(setup(r#"{hello world"#));
- }
-
- #[test]
- fn test_unmatched_braces() {
- assert_debug_snapshot!(setup(r#"}{"#));
- }
-
- #[test]
- fn test_unmatched_brackets() {
- assert_debug_snapshot!(setup(r#"]["#));
- }
-
- #[test]
- fn test_unmatched_brackets_with_group() {
- assert_debug_snapshot!(setup(r#"{][}"#));
- }
-
- #[test]
- fn test_escaped_brackets() {
- assert_debug_snapshot!(setup(r#"{[}{]}"#));
- }
-
- #[test]
- fn test_parameter() {
- assert_debug_snapshot!(setup(r#"#1"#));
- }
-
- #[test]
- fn test_parameter_error() {
- assert_debug_snapshot!(setup(r#"#"#));
- }
-
- #[test]
- fn test_environment_simple() {
- assert_debug_snapshot!(setup(r#"\begin{foo} Hello World \end{bar}"#));
- }
-
- #[test]
- fn test_environment_nested() {
- assert_debug_snapshot!(setup(r#"\begin{foo} \begin{qux} \end{baz} \end{bar}"#));
- }
-
- #[test]
- fn test_environment_nested_missing_braces() {
- assert_debug_snapshot!(setup(
- r#"\begin{foo \begin{qux Hello World \end{baz} \end{bar"#
- ));
- }
-
- #[test]
- fn test_structure_siblings() {
- assert_debug_snapshot!(setup(r#"\section{Foo} Foo \section{Bar} Bar"#));
- }
-
- #[test]
- fn test_structure_nested() {
- assert_debug_snapshot!(setup(
- r#"\part{1}\chapter{2}\section{3}\subsection{4}\subsubsection{5}\paragraph{6}\subparagraph{7}"#
- ));
- }
-
- #[test]
- fn test_structure_enum_item() {
- assert_debug_snapshot!(setup(
- r#"\begin{enumerate} \item 1 \item[2] 2 \item 3 \end{enumerate}"#
- ));
- }
-
- #[test]
- fn test_structure_invalid_nesting() {
- assert_debug_snapshot!(setup(r#"\section{Foo} \chapter{Bar}"#));
- }
-
- #[test]
- fn test_equation() {
- assert_debug_snapshot!(setup(r#"\[ foo bar \]"#));
- }
-
- #[test]
- fn test_equation_missing_end() {
- assert_debug_snapshot!(setup(r#"\begin{a} \[ foo bar \end{b}"#));
- }
-
- #[test]
- fn test_equation_missing_begin() {
- assert_debug_snapshot!(setup(r#"\begin{a} foo bar \] \end{b}"#));
- }
-
- #[test]
- fn test_caption_minimal() {
- assert_debug_snapshot!(setup(r#"\caption{Foo \Bar Baz}"#));
- }
-
- #[test]
- fn test_caption_minimal_error() {
- assert_debug_snapshot!(setup(r#"\caption{Foo \Bar Baz"#));
- }
-
- #[test]
- fn test_caption() {
- assert_debug_snapshot!(setup(r#"\caption[qux]{Foo \Bar Baz}"#));
- }
-
- #[test]
- fn test_caption_error() {
- assert_debug_snapshot!(setup(r#"\caption[qux]{Foo \Bar Baz"#));
- }
-
- #[test]
- fn test_caption_figure() {
- assert_debug_snapshot!(setup(r#"\begin{figure}\caption{Foo}\end{figure}"#));
- }
-
- #[test]
- fn test_citation_empty() {
- assert_debug_snapshot!(setup(r#"\cite{}"#));
- }
-
- #[test]
- fn test_citation_simple() {
- assert_debug_snapshot!(setup(r#"\cite{foo}"#));
- }
-
- #[test]
- fn test_citation_multiple_keys() {
- assert_debug_snapshot!(setup(r#"\cite{foo, bar}"#));
- }
-
- #[test]
- fn test_citation_star() {
- assert_debug_snapshot!(setup(r#"\nocite{*}"#));
- }
-
- #[test]
- fn test_citation_prenote() {
- assert_debug_snapshot!(setup(r#"\cite[foo]{bar}"#));
- }
-
- #[test]
- fn test_citation_prenote_postnote() {
- assert_debug_snapshot!(setup(r#"\cite[foo][bar]{baz}"#));
- }
-
- #[test]
- fn test_citation_missing_brace() {
- assert_debug_snapshot!(setup(r#"\cite{foo"#));
- }
-
- #[test]
- fn test_citation_redundant_comma() {
- assert_debug_snapshot!(setup(r#"\cite{,foo,}"#));
- }
-
- #[test]
- fn test_package_include_empty() {
- assert_debug_snapshot!(setup(r#"\usepackage{}"#));
- }
-
- #[test]
- fn test_package_include_simple() {
- assert_debug_snapshot!(setup(r#"\usepackage{amsmath}"#));
- }
-
- #[test]
- fn test_package_include_multiple() {
- assert_debug_snapshot!(setup(r#"\usepackage{amsmath, lipsum}"#));
- }
-
- #[test]
- fn test_package_include_options() {
- assert_debug_snapshot!(setup(r#"\usepackage[foo = bar, baz, qux]{amsmath}"#));
- }
-
- #[test]
- fn test_class_include_empty() {
- assert_debug_snapshot!(setup(r#"\documentclass{}"#));
- }
-
- #[test]
- fn test_class_include_simple() {
- assert_debug_snapshot!(setup(r#"\documentclass{article}"#));
- }
-
- #[test]
- fn test_class_include_options() {
- assert_debug_snapshot!(setup(r#"\documentclass[foo = bar, baz, qux]{article}"#));
- }
-
- #[test]
- fn test_latex_include_simple() {
- assert_debug_snapshot!(setup(r#"\include{foo/bar}"#));
- }
-
- #[test]
- fn test_latex_include_equality_sign() {
- assert_debug_snapshot!(setup(r#"\include{foo=bar}"#));
- }
-
- #[test]
- fn test_latex_input_simple() {
- assert_debug_snapshot!(setup(r#"\input{foo/bar.tex}"#));
- }
-
- #[test]
- fn test_latex_input_path_with_brackets() {
- assert_debug_snapshot!(setup(r#"\input{foo[bar].tex}"#));
- }
-
- #[test]
- fn test_biblatex_include_simple() {
- assert_debug_snapshot!(setup(r#"\addbibresource{foo/bar.bib}"#));
- }
-
- #[test]
- fn test_biblatex_include_options() {
- assert_debug_snapshot!(setup(r#"\addbibresource[foo=bar, baz]{foo/bar.bib}"#));
- }
-
- #[test]
- fn test_bibtex_include_simple() {
- assert_debug_snapshot!(setup(r#"\bibliography{foo/bar}"#));
- }
-
- #[test]
- fn test_graphics_include_simple() {
- assert_debug_snapshot!(setup(r#"\includegraphics{foo/bar.pdf}"#));
- }
-
- #[test]
- fn test_graphics_include_options() {
- assert_debug_snapshot!(setup(r#"\includegraphics[scale=.5]{foo/bar.pdf}"#));
- }
-
- #[test]
- fn test_graphics_include_complicated_options() {
- assert_debug_snapshot!(setup(r#"\includegraphics[width=0.5\textwidth]{}"#));
- }
-
- #[test]
- fn test_graphics_include_command() {
- assert_debug_snapshot!(setup(
- r#"\includegraphics[width=0.5\textwidth]{\foo.\bar.pdf}"#
- ));
- }
-
- #[test]
- fn test_svg_include_simple() {
- assert_debug_snapshot!(setup(r#"\includesvg{foo/bar.svg}"#));
- }
-
- #[test]
- fn test_svg_include_options() {
- assert_debug_snapshot!(setup(r#"\includesvg[scale=.5]{foo/bar.svg}"#));
- }
-
- #[test]
- fn test_inkscape_include_simple() {
- assert_debug_snapshot!(setup(r#"\includesvg{foo/bar}"#));
- }
-
- #[test]
- fn test_inkscape_include_options() {
- assert_debug_snapshot!(setup(r#"\includesvg[scale=.5]{foo/bar}"#));
- }
-
- #[test]
- fn test_verbatim_include_simple() {
- assert_debug_snapshot!(setup(r#"\verbatiminput{foo/bar.txt}"#));
- }
-
- #[test]
- fn test_import_simple() {
- assert_debug_snapshot!(setup(r#"\import{foo}{bar}"#));
- }
-
- #[test]
- fn test_import_incomplete() {
- assert_debug_snapshot!(setup(r#"\import{foo"#));
- }
-
- #[test]
- fn test_label_definition_simple() {
- assert_debug_snapshot!(setup(r#"\label{foo}"#));
- }
-
- #[test]
- fn test_label_reference_simple() {
- assert_debug_snapshot!(setup(r#"\ref{foo}"#));
- }
-
- #[test]
- fn test_label_reference_multiple() {
- assert_debug_snapshot!(setup(r#"\ref{foo, bar}"#));
- }
-
- #[test]
- fn test_label_reference_incomplete() {
- assert_debug_snapshot!(setup(r#"Equation \eqref{eq is a \emph{useful} identity."#));
- }
-
- #[test]
- fn test_equation_label_reference_simple() {
- assert_debug_snapshot!(setup(r#"\eqref{foo}"#));
- }
-
- #[test]
- fn test_label_reference_range_simple() {
- assert_debug_snapshot!(setup(r#"\crefrange{foo}{bar}"#));
- }
-
- #[test]
- fn test_label_reference_range_incomplete() {
- assert_debug_snapshot!(setup(r#"\crefrange{foo}"#));
- }
-
- #[test]
- fn test_label_reference_range_error() {
- assert_debug_snapshot!(setup(r#"\crefrange{foo{bar}"#));
- }
-
- #[test]
- fn test_label_number() {
- assert_debug_snapshot!(setup(r#"\newlabel{foo}{{1.1}}"#));
- }
-
- #[test]
- fn test_command_definition_simple() {
- assert_debug_snapshot!(setup(r#"\newcommand[1]{\id}{#1}"#));
- }
-
- #[test]
- fn test_command_definition_optional() {
- assert_debug_snapshot!(setup(r#"\newcommand{\foo}[1][def]{#1}"#));
- }
-
- #[test]
- fn test_command_definition_no_argc() {
- assert_debug_snapshot!(setup(r#"\newcommand{\foo}{foo}"#));
- }
-
- #[test]
- fn test_command_definition_no_impl() {
- assert_debug_snapshot!(setup(r#"\newcommand{\foo}"#));
- }
-
- #[test]
- fn test_command_definition_no_impl_error() {
- assert_debug_snapshot!(setup(r#"\newcommand{\foo"#));
- }
-
- #[test]
- fn test_command_definition_with_begin() {
- assert_debug_snapshot!(setup(
- r#"\newcommand{\CVSubHeadingListStart}{\begin{itemize}[leftmargin=0.5cm, label={}]}"#
- ));
- }
-
- #[test]
- fn test_math_operator_simple() {
- assert_debug_snapshot!(setup(r#"\DeclareMathOperator{\foo}{foo}"#));
- }
-
- #[test]
- fn test_math_operator_no_impl() {
- assert_debug_snapshot!(setup(r#"\DeclareMathOperator{\foo}"#));
- }
-
- #[test]
- fn test_glossary_entry_definition_simple() {
- assert_debug_snapshot!(setup(r#"\newglossaryentry{foo}{bar = baz, qux,}"#));
- }
-
- #[test]
- fn test_glossary_entry_reference_simple() {
- assert_debug_snapshot!(setup(r#"\gls{foo}"#));
- }
-
- #[test]
- fn test_glossary_entry_reference_options() {
- assert_debug_snapshot!(setup(r#"\gls[foo = bar, qux]{baz}"#));
- }
-
- #[test]
- fn test_acroynm_definition_simple() {
- assert_debug_snapshot!(setup(r#"\newacronym{fpsLabel}{FPS}{Frame per Second}"#));
- }
-
- #[test]
- fn test_acroynm_definition_options() {
- assert_debug_snapshot!(setup(
- r#"\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}"#
- ));
- }
-
- #[test]
- fn test_acroynm_reference_simple() {
- assert_debug_snapshot!(setup(r#"\acrshort{fpsLabel}"#));
- }
-
- #[test]
- fn test_acroynm_reference_options() {
- assert_debug_snapshot!(setup(r#"\acrshort[foo=bar,baz]{fpsLabel}"#));
- }
-
- #[test]
- fn test_theorem_definition_only_name() {
- assert_debug_snapshot!(setup(r#"\newtheorem{foo}"#));
- }
-
- #[test]
- fn test_theorem_definition_name_with_description() {
- assert_debug_snapshot!(setup(r#"\newtheorem{foo}{Foo}"#));
- }
-
- #[test]
- fn test_theorem_definition_name_with_description_and_counter() {
- assert_debug_snapshot!(setup(r#"\newtheorem{foo}[bar]{Foo}"#));
- }
-
- #[test]
- fn test_theorem_definition_name_with_counter() {
- assert_debug_snapshot!(setup(r#"\newtheorem{foo}[bar]"#));
- }
-
- #[test]
- fn test_theorem_definition_full() {
- assert_debug_snapshot!(setup(r#"\newtheorem{foo}[bar]{Foo}[baz]"#));
- }
-
- #[test]
- fn test_color_reference_simple() {
- assert_debug_snapshot!(setup(r#"\color{black}"#));
- }
-
- #[test]
- fn test_color_definition_simple() {
- assert_debug_snapshot!(setup(r#"\definecolor{foo}{rgb}{255,168,0}"#));
- }
-
- #[test]
- fn test_color_set_definition_simple() {
- assert_debug_snapshot!(setup(r#"\definecolorset[ty]{rgb,HTML}{foo}{bar}{baz}"#));
- }
-
- #[test]
- fn test_color_set_definition_error1() {
- assert_debug_snapshot!(setup(r#"\definecolorset[ty]{rgb,HTML}{foo}{bar}"#));
- }
-
- #[test]
- fn test_color_set_definition_error2() {
- assert_debug_snapshot!(setup(r#"\definecolorset{rgb,HTML}{foo}"#));
- }
-
- #[test]
- fn test_color_set_definition_error3() {
- assert_debug_snapshot!(setup(r#"\definecolorset{rgb,HTML}"#));
- }
-
- #[test]
- fn test_color_set_definition_error4() {
- assert_debug_snapshot!(setup(r#"\definecolorset"#));
- }
-
- #[test]
- fn test_pgf_library_import_simple() {
- assert_debug_snapshot!(setup(r#"\usepgflibrary{foo}"#));
- }
-
- #[test]
- fn test_tikz_library_import_simple() {
- assert_debug_snapshot!(setup(r#"\usetikzlibrary{foo}"#));
- }
-
- #[test]
- fn test_environment_definition() {
- assert_debug_snapshot!(setup(r#"\newenvironment{bar}[1]{\begin{foo}}{\end{foo}}"#));
- }
-
- #[test]
- fn test_environment_definition_optional_arg() {
- assert_debug_snapshot!(setup(r#"\newenvironment{foo}[1][default]{begin}{end}"#));
- }
-
- #[test]
- fn test_acronym_declaration() {
- assert_debug_snapshot!(setup(
- r#"\DeclareAcronym{eg}{short = e.g,long = for example,tag = abbrev}"#
- ));
- }
-
- #[test]
- fn test_label_definition_line_break() {
- assert_debug_snapshot!(setup("\\label{hello\nworld}"));
- }
-
- #[test]
- fn test_block_comments() {
- assert_debug_snapshot!(setup(
- r#"Foo
-\iffalse
-Test1
-\fi
-Bar
-\iffalse
-\fii
-\fi
-Baz"#
- ));
- }
-
- #[test]
- fn test_asymptote() {
- assert_debug_snapshot!(setup(
- r#"\begin{asy}
- printf("Hello World\n");
-\end{asy}"#
- ));
- }
+ use super::parse_latex;
#[test]
- fn test_graphics_path() {
- assert_debug_snapshot!(setup(r#"\graphicspath{{../figures/}}"#));
+ fn test_parse() {
+ insta::glob!("test_data/latex/{,**/}*.txt", |path| {
+ let text = std::fs::read_to_string(path).unwrap().replace("\r\n", "\n");
+ let root = latex::SyntaxNode::new_root(parse_latex(&text));
+ insta::assert_debug_snapshot!(root);
+ });
}
}
diff --git a/support/texlab/src/syntax/latex/lexer.rs b/support/texlab/src/parser/latex/lexer.rs
index 39196375b1..9b0a6726eb 100644
--- a/support/texlab/src/syntax/latex/lexer.rs
+++ b/support/texlab/src/parser/latex/lexer.rs
@@ -1,9 +1,8 @@
use logos::Logos;
-use super::kind::SyntaxKind;
+use crate::syntax::latex::SyntaxKind;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord, Logos)]
-#[allow(non_camel_case_types)]
#[repr(u16)]
enum RootToken {
#[regex(r"[\r\n]+", priority = 2)]
@@ -299,6 +298,15 @@ enum CommandNameToken {
GlossaryEntryReference,
#[token("\\newacronym")]
+ #[token("\\newacro")]
+ #[token("\\acrodef")]
+ #[token("\\acro")]
+ #[token("\\newacroindefinite")]
+ #[token("\\acrodefindefinite")]
+ #[token("\\acroindefinite")]
+ #[token("\\acroplural")]
+ #[token("\\newacroplural")]
+ #[token("\\acrodefplural")]
AcronymDefinition,
#[token("\\DeclareAcronym")]
@@ -332,11 +340,42 @@ enum CommandNameToken {
#[token("\\Aclp")]
#[token("\\acf")]
#[token("\\Acf")]
+ #[token("\\acfi")]
+ #[token("\\Acfi")]
#[token("\\acfp")]
#[token("\\Acfp")]
#[token("\\ac")]
#[token("\\Ac")]
#[token("\\acp")]
+ #[token("\\Acp")]
+ #[token("\\acused")]
+ #[token("\\acsu")]
+ #[token("\\Aclu")]
+ #[token("\\iac")]
+ #[token("\\Iac")]
+ #[token("\\acs*")]
+ #[token("\\Acs*")]
+ #[token("\\acsp*")]
+ #[token("\\Acsp*")]
+ #[token("\\acl*")]
+ #[token("\\Acl*")]
+ #[token("\\aclp*")]
+ #[token("\\Aclp*")]
+ #[token("\\acf*")]
+ #[token("\\Acf*")]
+ #[token("\\acfi*")]
+ #[token("\\Acfi*")]
+ #[token("\\acfp*")]
+ #[token("\\Acfp*")]
+ #[token("\\ac*")]
+ #[token("\\Ac*")]
+ #[token("\\acp*")]
+ #[token("\\Acp*")]
+ #[token("\\acused*")]
+ #[token("\\acsu*")]
+ #[token("\\Aclu*")]
+ #[token("\\iac*")]
+ #[token("\\Iac*")]
#[token("\\glsentrylong")]
#[token("\\Glsentrylong")]
#[token("\\glsentrylongpl")]
@@ -600,75 +639,3 @@ fn tokenize_verbatim_environment<'a>(
&input[end..]
}
-
-#[cfg(test)]
-mod tests {
- use insta::assert_debug_snapshot;
-
- use super::*;
-
- fn verify(text: &str) -> Vec<(SyntaxKind, &str)> {
- let mut tokens = Lexer::new(text).tokens;
- tokens.reverse();
- tokens
- }
-
- #[test]
- fn test_empty() {
- assert_debug_snapshot!(verify(r#""#));
- }
-
- #[test]
- fn test_delimiters() {
- assert_debug_snapshot!(verify(r#"{foo} (bar) [baz, qux = foo-bar]"#));
- }
-
- #[test]
- fn test_command_with_parameter() {
- assert_debug_snapshot!(verify(r#"\newcommand{\id}[1]{#1}"#));
- }
-
- #[test]
- fn test_command_with_star() {
- assert_debug_snapshot!(verify(r#"\section*{Foo}"#));
- }
-
- #[test]
- fn test_escape_sequence() {
- assert_debug_snapshot!(verify(r#"\% hello"#));
- }
-
- #[test]
- fn test_formula() {
- assert_debug_snapshot!(verify(r#"$ f(x) = y $$"#));
- }
-
- #[test]
- fn test_comment() {
- assert_debug_snapshot!(verify("hello %world\r\ntest %test"));
- }
-
- #[test]
- fn test_invalid_parameter() {
- assert_debug_snapshot!(verify(r#"#"#))
- }
-
- #[test]
- fn test_line_break() {
- assert_debug_snapshot!(verify("hello\nworld"));
- }
-
- #[test]
- fn test_block_comment() {
- assert_debug_snapshot!(verify("Foo\\iffalse\n\\Bar{Baz}\n\\fi\\Qux"));
- }
-
- #[test]
- fn test_asymptote() {
- assert_debug_snapshot!(verify(
- r#"\begin{asy}
- printf("Hello World\n");
-\end{asy}"#
- ));
- }
-}
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@comment.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@comment.txt.snap
new file mode 100644
index 0000000000..f2e1163eff
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@comment.txt.snap
@@ -0,0 +1,10 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/comment.txt
+---
+ROOT@0..82
+ JUNK@0..16 "Some junk here\n\n"
+ TYPE@16..24 "@comment"
+ JUNK@24..82 "{foo,\n author = {F ..."
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@issue_809.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@issue_809.txt.snap
new file mode 100644
index 0000000000..922e926cef
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@issue_809.txt.snap
@@ -0,0 +1,31 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+---
+ROOT@0..50
+ ENTRY@0..50
+ TYPE@0..8 "@article"
+ L_DELIM@8..9 "{"
+ NAME@9..18 "issue_809"
+ COMMA@18..19 ","
+ WHITESPACE@19..22 "\n "
+ FIELD@22..48
+ NAME@22..27 "title"
+ WHITESPACE@27..28 " "
+ EQ@28..29 "="
+ WHITESPACE@29..30 " "
+ CURLY_GROUP@30..47
+ L_CURLY@30..31 "{"
+ WORD@31..34 "foo"
+ WHITESPACE@34..35 " "
+ WORD@35..36 "("
+ QUOTE@36..37 "\""
+ WHITESPACE@37..38 " "
+ WORD@38..42 "bar)"
+ WHITESPACE@42..43 " "
+ WORD@43..46 "baz"
+ R_CURLY@46..47 "}"
+ COMMA@47..48 ","
+ WHITESPACE@48..49 "\n"
+ R_DELIM@49..50 "}"
+
diff --git a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__preamble.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@preamble.txt.snap
index 596a9d108a..26d8a919ba 100644
--- a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__preamble.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@preamble.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/bibtex/tests.rs
-assertion_line: 11
-expression: "setup(r#\"@preamble{\"Hello World!\"}\"#)"
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/preamble.txt
---
ROOT@0..25
PREAMBLE@0..25
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__aho_2006.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__aho_2006.txt.snap
new file mode 100644
index 0000000000..d1d34942d8
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__aho_2006.txt.snap
@@ -0,0 +1,132 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/aho_2006.txt
+---
+ROOT@0..314
+ ENTRY@0..314
+ TYPE@0..5 "@book"
+ L_DELIM@5..6 "{"
+ NAME@6..21 "10.5555/1177220"
+ COMMA@21..22 ","
+ WHITESPACE@22..27 "\n "
+ FIELD@27..111
+ NAME@27..33 "author"
+ WHITESPACE@33..34 " "
+ EQ@34..35 "="
+ WHITESPACE@35..36 " "
+ CURLY_GROUP@36..110
+ L_CURLY@36..37 "{"
+ WORD@37..40 "Aho"
+ COMMA@40..41 ","
+ WHITESPACE@41..42 " "
+ WORD@42..48 "Alfred"
+ WHITESPACE@48..49 " "
+ WORD@49..51 "V."
+ WHITESPACE@51..52 " "
+ WORD@52..55 "and"
+ WHITESPACE@55..56 " "
+ WORD@56..59 "Lam"
+ COMMA@59..60 ","
+ WHITESPACE@60..61 " "
+ WORD@61..67 "Monica"
+ WHITESPACE@67..68 " "
+ WORD@68..70 "S."
+ WHITESPACE@70..71 " "
+ WORD@71..74 "and"
+ WHITESPACE@74..75 " "
+ WORD@75..80 "Sethi"
+ COMMA@80..81 ","
+ WHITESPACE@81..82 " "
+ WORD@82..86 "Ravi"
+ WHITESPACE@86..87 " "
+ WORD@87..90 "and"
+ WHITESPACE@90..91 " "
+ WORD@91..97 "Ullman"
+ COMMA@97..98 ","
+ WHITESPACE@98..99 " "
+ WORD@99..106 "Jeffrey"
+ WHITESPACE@106..107 " "
+ WORD@107..109 "D."
+ R_CURLY@109..110 "}"
+ COMMA@110..111 ","
+ WHITESPACE@111..116 "\n "
+ FIELD@116..185
+ NAME@116..121 "title"
+ WHITESPACE@121..122 " "
+ EQ@122..123 "="
+ WHITESPACE@123..124 " "
+ CURLY_GROUP@124..184
+ L_CURLY@124..125 "{"
+ WORD@125..135 "Compilers:"
+ WHITESPACE@135..136 " "
+ WORD@136..146 "Principles"
+ COMMA@146..147 ","
+ WHITESPACE@147..148 " "
+ WORD@148..158 "Techniques"
+ COMMA@158..159 ","
+ WHITESPACE@159..160 " "
+ WORD@160..163 "and"
+ WHITESPACE@163..164 " "
+ WORD@164..169 "Tools"
+ WHITESPACE@169..170 " "
+ WORD@170..174 "(2nd"
+ WHITESPACE@174..175 " "
+ WORD@175..183 "Edition)"
+ R_CURLY@183..184 "}"
+ COMMA@184..185 ","
+ WHITESPACE@185..190 "\n "
+ FIELD@190..204
+ NAME@190..194 "year"
+ WHITESPACE@194..195 " "
+ EQ@195..196 "="
+ WHITESPACE@196..197 " "
+ CURLY_GROUP@197..203
+ L_CURLY@197..198 "{"
+ INTEGER@198..202 "2006"
+ R_CURLY@202..203 "}"
+ COMMA@203..204 ","
+ WHITESPACE@204..209 "\n "
+ FIELD@209..229
+ NAME@209..213 "isbn"
+ WHITESPACE@213..214 " "
+ EQ@214..215 "="
+ WHITESPACE@215..216 " "
+ CURLY_GROUP@216..228
+ L_CURLY@216..217 "{"
+ INTEGER@217..227 "0321486811"
+ R_CURLY@227..228 "}"
+ COMMA@228..229 ","
+ WHITESPACE@229..234 "\n "
+ FIELD@234..292
+ NAME@234..243 "publisher"
+ WHITESPACE@243..244 " "
+ EQ@244..245 "="
+ WHITESPACE@245..246 " "
+ CURLY_GROUP@246..291
+ L_CURLY@246..247 "{"
+ WORD@247..261 "Addison-Wesley"
+ WHITESPACE@261..262 " "
+ WORD@262..269 "Longman"
+ WHITESPACE@269..270 " "
+ WORD@270..280 "Publishing"
+ WHITESPACE@280..281 " "
+ WORD@281..284 "Co."
+ COMMA@284..285 ","
+ WHITESPACE@285..286 " "
+ WORD@286..290 "Inc."
+ R_CURLY@290..291 "}"
+ COMMA@291..292 ","
+ WHITESPACE@292..297 "\n "
+ FIELD@297..313
+ NAME@297..304 "address"
+ WHITESPACE@304..305 " "
+ EQ@305..306 "="
+ WHITESPACE@306..307 " "
+ CURLY_GROUP@307..312
+ L_CURLY@307..308 "{"
+ WORD@308..311 "USA"
+ R_CURLY@311..312 "}"
+ WHITESPACE@312..313 "\n"
+ R_DELIM@313..314 "}"
+
diff --git a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_002.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__aksin_2006.txt.snap
index 5607e5a507..72e354e3c0 100644
--- a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_002.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__aksin_2006.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/bibtex/tests.rs
-assertion_line: 87
-expression: "setup(r#\"@string{jomch = {J.~Organomet. Chem.}}\n\n@article{aksin,\n author = {Aks{\\i}n, {\\\"O}zge and T{\\\"u}rkmen, Hayati and Artok, Levent\n and {\\c{C}}etinkaya, Bekir and Ni, Chaoying and\n B{\\\"u}y{\\\"u}kg{\\\"u}ng{\\\"o}r, Orhan and {\\\"O}zkal, Erhan},\n title = {Effect of immobilization on catalytic characteristics of\n saturated {Pd-N}-heterocyclic carbenes in {Mizoroki-Heck}\n reactions},\n journaltitle = jomch,\n date = 2006,\n volume = 691,\n number = 13,\n pages = {3027-3036},\n indextitle = {Effect of immobilization on catalytic characteristics},\n}\"#)"
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/aksin_2006.txt
---
ROOT@0..679
STRING@0..40
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__almendro_1998.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__almendro_1998.txt.snap
new file mode 100644
index 0000000000..cff0323cb4
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__almendro_1998.txt.snap
@@ -0,0 +1,246 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/almendro_1998.txt
+---
+ROOT@0..706
+ ENTRY@0..706
+ TYPE@0..7 "@patent"
+ L_DELIM@7..8 "{"
+ NAME@8..16 "almendro"
+ COMMA@16..17 ","
+ WHITESPACE@17..22 "\n "
+ FIELD@22..150
+ NAME@22..28 "author"
+ WHITESPACE@28..35 " "
+ EQ@35..36 "="
+ WHITESPACE@36..37 " "
+ CURLY_GROUP@37..149
+ L_CURLY@37..38 "{"
+ WORD@38..46 "Almendro"
+ COMMA@46..47 ","
+ WHITESPACE@47..48 " "
+ WORD@48..51 "Jos"
+ CURLY_GROUP@51..56
+ L_CURLY@51..52 "{"
+ ACCENT@52..55
+ ACCENT_NAME@52..54 "\\'"
+ WORD@54..55 "e"
+ R_CURLY@55..56 "}"
+ WHITESPACE@56..57 " "
+ WORD@57..59 "L."
+ WHITESPACE@59..60 " "
+ WORD@60..63 "and"
+ WHITESPACE@63..64 " "
+ WORD@64..68 "Mart"
+ CURLY_GROUP@68..73
+ L_CURLY@68..69 "{"
+ ACCENT@69..72
+ ACCENT_NAME@69..71 "\\'"
+ WORD@71..72 "i"
+ R_CURLY@72..73 "}"
+ WORD@73..74 "n"
+ COMMA@74..75 ","
+ WHITESPACE@75..76 " "
+ WORD@76..83 "Jacinto"
+ WHITESPACE@83..84 " "
+ WORD@84..87 "and"
+ WHITESPACE@87..88 " "
+ WORD@88..89 "S"
+ CURLY_GROUP@89..94
+ L_CURLY@89..90 "{"
+ ACCENT@90..93
+ ACCENT_NAME@90..92 "\\'"
+ WORD@92..93 "a"
+ R_CURLY@93..94 "}"
+ WORD@94..99 "nchez"
+ COMMA@99..100 ","
+ WHITESPACE@100..121 "\n "
+ WORD@121..128 "Alberto"
+ WHITESPACE@128..129 " "
+ WORD@129..132 "and"
+ WHITESPACE@132..133 " "
+ WORD@133..138 "Nozal"
+ COMMA@138..139 ","
+ WHITESPACE@139..140 " "
+ WORD@140..148 "Fernando"
+ R_CURLY@148..149 "}"
+ COMMA@149..150 ","
+ WHITESPACE@150..155 "\n "
+ FIELD@155..203
+ NAME@155..160 "title"
+ WHITESPACE@160..168 " "
+ EQ@168..169 "="
+ WHITESPACE@169..170 " "
+ CURLY_GROUP@170..202
+ L_CURLY@170..171 "{"
+ WORD@171..190 "Elektromagnetisches"
+ WHITESPACE@190..191 " "
+ WORD@191..201 "Signalhorn"
+ R_CURLY@201..202 "}"
+ COMMA@202..203 ","
+ WHITESPACE@203..208 "\n "
+ FIELD@208..238
+ NAME@208..214 "number"
+ WHITESPACE@214..221 " "
+ EQ@221..222 "="
+ WHITESPACE@222..223 " "
+ CURLY_GROUP@223..237
+ L_CURLY@223..224 "{"
+ WORD@224..236 "EU-29702195U"
+ R_CURLY@236..237 "}"
+ COMMA@237..238 ","
+ WHITESPACE@238..243 "\n "
+ FIELD@243..263
+ NAME@243..247 "date"
+ WHITESPACE@247..256 " "
+ EQ@256..257 "="
+ WHITESPACE@257..258 " "
+ LITERAL@258..262
+ INTEGER@258..262 "1998"
+ COMMA@262..263 ","
+ WHITESPACE@263..268 "\n "
+ FIELD@268..323
+ NAME@268..276 "location"
+ WHITESPACE@276..281 " "
+ EQ@281..282 "="
+ WHITESPACE@282..283 " "
+ CURLY_GROUP@283..322
+ L_CURLY@283..284 "{"
+ WORD@284..293 "countryfr"
+ WHITESPACE@293..294 " "
+ WORD@294..297 "and"
+ WHITESPACE@297..298 " "
+ WORD@298..307 "countryuk"
+ WHITESPACE@307..308 " "
+ WORD@308..311 "and"
+ WHITESPACE@311..312 " "
+ WORD@312..321 "countryde"
+ R_CURLY@321..322 "}"
+ COMMA@322..323 ","
+ WHITESPACE@323..328 "\n "
+ FIELD@328..352
+ NAME@328..334 "langid"
+ WHITESPACE@334..341 " "
+ EQ@341..342 "="
+ WHITESPACE@342..343 " "
+ CURLY_GROUP@343..351
+ L_CURLY@343..344 "{"
+ WORD@344..350 "german"
+ R_CURLY@350..351 "}"
+ COMMA@351..352 ","
+ WHITESPACE@352..357 "\n "
+ FIELD@357..704
+ NAME@357..367 "annotation"
+ WHITESPACE@367..370 " "
+ EQ@370..371 "="
+ WHITESPACE@371..372 " "
+ CURLY_GROUP@372..703
+ L_CURLY@372..373 "{"
+ WORD@373..377 "This"
+ WHITESPACE@377..378 " "
+ WORD@378..380 "is"
+ WHITESPACE@380..381 " "
+ WORD@381..382 "a"
+ WHITESPACE@382..383 " "
+ COMMAND@383..390
+ COMMAND_NAME@383..390 "\\texttt"
+ CURLY_GROUP@390..398
+ L_CURLY@390..391 "{"
+ WORD@391..397 "patent"
+ R_CURLY@397..398 "}"
+ WHITESPACE@398..399 " "
+ WORD@399..404 "entry"
+ WHITESPACE@404..405 " "
+ WORD@405..409 "with"
+ WHITESPACE@409..410 " "
+ WORD@410..411 "a"
+ WHITESPACE@411..412 " "
+ COMMAND@412..419
+ COMMAND_NAME@412..419 "\\texttt"
+ CURLY_GROUP@419..429
+ L_CURLY@419..420 "{"
+ WORD@420..428 "location"
+ R_CURLY@428..429 "}"
+ WHITESPACE@429..450 "\n "
+ WORD@450..456 "field."
+ WHITESPACE@456..457 " "
+ WORD@457..460 "The"
+ WHITESPACE@460..461 " "
+ WORD@461..467 "number"
+ WHITESPACE@467..468 " "
+ WORD@468..470 "is"
+ WHITESPACE@470..471 " "
+ WORD@471..476 "given"
+ WHITESPACE@476..477 " "
+ WORD@477..479 "in"
+ WHITESPACE@479..480 " "
+ WORD@480..483 "the"
+ WHITESPACE@483..484 " "
+ COMMAND@484..491
+ COMMAND_NAME@484..491 "\\texttt"
+ CURLY_GROUP@491..499
+ L_CURLY@491..492 "{"
+ WORD@492..498 "number"
+ R_CURLY@498..499 "}"
+ WHITESPACE@499..500 " "
+ WORD@500..506 "field."
+ WHITESPACE@506..507 " "
+ WORD@507..511 "Note"
+ WHITESPACE@511..532 "\n "
+ WORD@532..535 "the"
+ WHITESPACE@535..536 " "
+ WORD@536..542 "format"
+ WHITESPACE@542..543 " "
+ WORD@543..545 "of"
+ WHITESPACE@545..546 " "
+ WORD@546..549 "the"
+ WHITESPACE@549..550 " "
+ COMMAND@550..557
+ COMMAND_NAME@550..557 "\\texttt"
+ CURLY_GROUP@557..567
+ L_CURLY@557..558 "{"
+ WORD@558..566 "location"
+ R_CURLY@566..567 "}"
+ WHITESPACE@567..568 " "
+ WORD@568..573 "field"
+ WHITESPACE@573..574 " "
+ WORD@574..576 "in"
+ WHITESPACE@576..577 " "
+ WORD@577..580 "the"
+ WHITESPACE@580..581 " "
+ WORD@581..589 "database"
+ WHITESPACE@589..610 "\n "
+ WORD@610..615 "file."
+ WHITESPACE@615..616 " "
+ WORD@616..623 "Compare"
+ WHITESPACE@623..624 " "
+ COMMAND@624..631
+ COMMAND_NAME@624..631 "\\texttt"
+ CURLY_GROUP@631..643
+ L_CURLY@631..632 "{"
+ WORD@632..642 "laufenberg"
+ R_CURLY@642..643 "}"
+ COMMA@643..644 ","
+ WHITESPACE@644..645 " "
+ COMMAND@645..652
+ COMMAND_NAME@645..652 "\\texttt"
+ CURLY_GROUP@652..660
+ L_CURLY@652..653 "{"
+ WORD@653..659 "sorace"
+ R_CURLY@659..660 "}"
+ COMMA@660..661 ","
+ WHITESPACE@661..662 " "
+ WORD@662..665 "and"
+ WHITESPACE@665..686 "\n "
+ COMMAND@686..693
+ COMMAND_NAME@686..693 "\\texttt"
+ CURLY_GROUP@693..702
+ L_CURLY@693..694 "{"
+ WORD@694..701 "kowalik"
+ R_CURLY@701..702 "}"
+ R_CURLY@702..703 "}"
+ COMMA@703..704 ","
+ WHITESPACE@704..705 "\n"
+ R_DELIM@705..706 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__averroes_1998.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__averroes_1998.txt.snap
new file mode 100644
index 0000000000..c02d61d272
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__averroes_1998.txt.snap
@@ -0,0 +1,351 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/averroes_1998.txt
+---
+ROOT@0..1008
+ ENTRY@0..1008
+ TYPE@0..5 "@book"
+ L_DELIM@5..6 "{"
+ NAME@6..20 "averroes/bland"
+ COMMA@20..21 ","
+ WHITESPACE@21..26 "\n "
+ FIELD@26..52
+ NAME@26..32 "author"
+ WHITESPACE@32..39 " "
+ EQ@39..40 "="
+ WHITESPACE@40..41 " "
+ CURLY_GROUP@41..51
+ L_CURLY@41..42 "{"
+ WORD@42..50 "Averroes"
+ R_CURLY@50..51 "}"
+ COMMA@51..52 ","
+ WHITESPACE@52..57 "\n "
+ FIELD@57..220
+ NAME@57..62 "title"
+ WHITESPACE@62..70 " "
+ EQ@70..71 "="
+ WHITESPACE@71..72 " "
+ CURLY_GROUP@72..219
+ L_CURLY@72..73 "{"
+ WORD@73..76 "The"
+ WHITESPACE@76..77 " "
+ WORD@77..84 "Epistle"
+ WHITESPACE@84..85 " "
+ WORD@85..87 "on"
+ WHITESPACE@87..88 " "
+ WORD@88..91 "the"
+ WHITESPACE@91..92 " "
+ WORD@92..103 "Possibility"
+ WHITESPACE@103..104 " "
+ WORD@104..106 "of"
+ WHITESPACE@106..107 " "
+ WORD@107..118 "Conjunction"
+ WHITESPACE@118..119 " "
+ WORD@119..123 "with"
+ WHITESPACE@123..124 " "
+ WORD@124..127 "the"
+ WHITESPACE@127..128 " "
+ WORD@128..134 "Active"
+ WHITESPACE@134..155 "\n "
+ WORD@155..164 "Intellect"
+ WHITESPACE@164..165 " "
+ WORD@165..167 "by"
+ WHITESPACE@167..168 " "
+ CURLY_GROUP@168..179
+ L_CURLY@168..169 "{"
+ WORD@169..172 "Ibn"
+ WHITESPACE@172..173 " "
+ WORD@173..178 "Rushd"
+ R_CURLY@178..179 "}"
+ WHITESPACE@179..180 " "
+ WORD@180..184 "with"
+ WHITESPACE@184..185 " "
+ WORD@185..188 "the"
+ WHITESPACE@188..189 " "
+ WORD@189..199 "Commentary"
+ WHITESPACE@199..200 " "
+ WORD@200..202 "of"
+ WHITESPACE@202..203 " "
+ CURLY_GROUP@203..218
+ L_CURLY@203..204 "{"
+ WORD@204..209 "Moses"
+ WHITESPACE@209..210 " "
+ WORD@210..217 "Narboni"
+ R_CURLY@217..218 "}"
+ R_CURLY@218..219 "}"
+ COMMA@219..220 ","
+ WHITESPACE@220..225 "\n "
+ FIELD@225..245
+ NAME@225..229 "date"
+ WHITESPACE@229..238 " "
+ EQ@238..239 "="
+ WHITESPACE@239..240 " "
+ LITERAL@240..244
+ INTEGER@240..244 "1982"
+ COMMA@244..245 ","
+ WHITESPACE@245..250 "\n "
+ FIELD@250..284
+ NAME@250..256 "editor"
+ WHITESPACE@256..263 " "
+ EQ@263..264 "="
+ WHITESPACE@264..265 " "
+ CURLY_GROUP@265..283
+ L_CURLY@265..266 "{"
+ WORD@266..271 "Bland"
+ COMMA@271..272 ","
+ WHITESPACE@272..273 " "
+ WORD@273..279 "Kalman"
+ WHITESPACE@279..280 " "
+ WORD@280..282 "P."
+ R_CURLY@282..283 "}"
+ COMMA@283..284 ","
+ WHITESPACE@284..289 "\n "
+ FIELD@289..323
+ NAME@289..299 "translator"
+ WHITESPACE@299..302 " "
+ EQ@302..303 "="
+ WHITESPACE@303..304 " "
+ CURLY_GROUP@304..322
+ L_CURLY@304..305 "{"
+ WORD@305..310 "Bland"
+ COMMA@310..311 ","
+ WHITESPACE@311..312 " "
+ WORD@312..318 "Kalman"
+ WHITESPACE@318..319 " "
+ WORD@319..321 "P."
+ R_CURLY@321..322 "}"
+ COMMA@322..323 ","
+ WHITESPACE@323..328 "\n "
+ FIELD@328..407
+ NAME@328..334 "series"
+ WHITESPACE@334..341 " "
+ EQ@341..342 "="
+ WHITESPACE@342..343 " "
+ CURLY_GROUP@343..406
+ L_CURLY@343..344 "{"
+ WORD@344..353 "Moreshet:"
+ WHITESPACE@353..354 " "
+ WORD@354..361 "Studies"
+ WHITESPACE@361..362 " "
+ WORD@362..364 "in"
+ WHITESPACE@364..365 " "
+ CURLY_GROUP@365..373
+ L_CURLY@365..366 "{"
+ WORD@366..372 "Jewish"
+ R_CURLY@372..373 "}"
+ WHITESPACE@373..374 " "
+ WORD@374..381 "History"
+ COMMA@381..382 ","
+ WHITESPACE@382..383 " "
+ WORD@383..393 "Literature"
+ WHITESPACE@393..394 " "
+ WORD@394..397 "and"
+ WHITESPACE@397..398 " "
+ WORD@398..405 "Thought"
+ R_CURLY@405..406 "}"
+ COMMA@406..407 ","
+ WHITESPACE@407..412 "\n "
+ FIELD@412..429
+ NAME@412..418 "number"
+ WHITESPACE@418..425 " "
+ EQ@425..426 "="
+ WHITESPACE@426..427 " "
+ LITERAL@427..428
+ INTEGER@427..428 "7"
+ COMMA@428..429 ","
+ WHITESPACE@429..434 "\n "
+ FIELD@434..490
+ NAME@434..443 "publisher"
+ WHITESPACE@443..447 " "
+ EQ@447..448 "="
+ WHITESPACE@448..449 " "
+ CURLY_GROUP@449..489
+ L_CURLY@449..450 "{"
+ WORD@450..456 "Jewish"
+ WHITESPACE@456..457 " "
+ WORD@457..468 "Theological"
+ WHITESPACE@468..469 " "
+ WORD@469..477 "Seminary"
+ WHITESPACE@477..478 " "
+ WORD@478..480 "of"
+ WHITESPACE@480..481 " "
+ WORD@481..488 "America"
+ R_CURLY@488..489 "}"
+ COMMA@489..490 ","
+ WHITESPACE@490..495 "\n "
+ FIELD@495..521
+ NAME@495..503 "location"
+ WHITESPACE@503..508 " "
+ EQ@508..509 "="
+ WHITESPACE@509..510 " "
+ CURLY_GROUP@510..520
+ L_CURLY@510..511 "{"
+ WORD@511..514 "New"
+ WHITESPACE@514..515 " "
+ WORD@515..519 "York"
+ R_CURLY@519..520 "}"
+ COMMA@520..521 ","
+ WHITESPACE@521..526 "\n "
+ FIELD@526..551
+ NAME@526..534 "keywords"
+ WHITESPACE@534..539 " "
+ EQ@539..540 "="
+ WHITESPACE@540..541 " "
+ CURLY_GROUP@541..550
+ L_CURLY@541..542 "{"
+ WORD@542..549 "primary"
+ R_CURLY@549..550 "}"
+ COMMA@550..551 ","
+ WHITESPACE@551..556 "\n "
+ FIELD@556..581
+ NAME@556..562 "langid"
+ WHITESPACE@562..569 " "
+ EQ@569..570 "="
+ WHITESPACE@570..571 " "
+ CURLY_GROUP@571..580
+ L_CURLY@571..572 "{"
+ WORD@572..579 "english"
+ R_CURLY@579..580 "}"
+ COMMA@580..581 ","
+ WHITESPACE@581..586 "\n "
+ FIELD@586..620
+ NAME@586..596 "langidopts"
+ WHITESPACE@596..599 " "
+ EQ@599..600 "="
+ WHITESPACE@600..601 " "
+ CURLY_GROUP@601..619
+ L_CURLY@601..602 "{"
+ WORD@602..618 "variant=american"
+ R_CURLY@618..619 "}"
+ COMMA@619..620 ","
+ WHITESPACE@620..625 "\n "
+ FIELD@625..689
+ NAME@625..635 "indextitle"
+ WHITESPACE@635..638 " "
+ EQ@638..639 "="
+ WHITESPACE@639..640 " "
+ CURLY_GROUP@640..688
+ L_CURLY@640..641 "{"
+ WORD@641..648 "Epistle"
+ WHITESPACE@648..649 " "
+ WORD@649..651 "on"
+ WHITESPACE@651..652 " "
+ WORD@652..655 "the"
+ WHITESPACE@655..656 " "
+ WORD@656..667 "Possibility"
+ WHITESPACE@667..668 " "
+ WORD@668..670 "of"
+ WHITESPACE@670..671 " "
+ WORD@671..682 "Conjunction"
+ COMMA@682..683 ","
+ WHITESPACE@683..684 " "
+ WORD@684..687 "The"
+ R_CURLY@687..688 "}"
+ COMMA@688..689 ","
+ WHITESPACE@689..694 "\n "
+ FIELD@694..738
+ NAME@694..704 "shorttitle"
+ WHITESPACE@704..707 " "
+ EQ@707..708 "="
+ WHITESPACE@708..709 " "
+ CURLY_GROUP@709..737
+ L_CURLY@709..710 "{"
+ WORD@710..721 "Possibility"
+ WHITESPACE@721..722 " "
+ WORD@722..724 "of"
+ WHITESPACE@724..725 " "
+ WORD@725..736 "Conjunction"
+ R_CURLY@736..737 "}"
+ COMMA@737..738 ","
+ WHITESPACE@738..743 "\n "
+ FIELD@743..1006
+ NAME@743..753 "annotation"
+ WHITESPACE@753..756 " "
+ EQ@756..757 "="
+ WHITESPACE@757..758 " "
+ CURLY_GROUP@758..1005
+ L_CURLY@758..759 "{"
+ WORD@759..760 "A"
+ WHITESPACE@760..761 " "
+ COMMAND@761..768
+ COMMAND_NAME@761..768 "\\texttt"
+ CURLY_GROUP@768..774
+ L_CURLY@768..769 "{"
+ WORD@769..773 "book"
+ R_CURLY@773..774 "}"
+ WHITESPACE@774..775 " "
+ WORD@775..780 "entry"
+ WHITESPACE@780..781 " "
+ WORD@781..785 "with"
+ WHITESPACE@785..786 " "
+ WORD@786..787 "a"
+ WHITESPACE@787..788 " "
+ COMMAND@788..795
+ COMMAND_NAME@788..795 "\\texttt"
+ CURLY_GROUP@795..803
+ L_CURLY@795..796 "{"
+ WORD@796..802 "series"
+ R_CURLY@802..803 "}"
+ WHITESPACE@803..804 " "
+ WORD@804..807 "and"
+ WHITESPACE@807..808 " "
+ WORD@808..809 "a"
+ WHITESPACE@809..830 "\n "
+ COMMAND@830..837
+ COMMAND_NAME@830..837 "\\texttt"
+ CURLY_GROUP@837..845
+ L_CURLY@837..838 "{"
+ WORD@838..844 "number"
+ R_CURLY@844..845 "}"
+ WORD@845..846 "."
+ WHITESPACE@846..847 " "
+ WORD@847..851 "Note"
+ WHITESPACE@851..852 " "
+ WORD@852..855 "the"
+ WHITESPACE@855..856 " "
+ WORD@856..869 "concatenation"
+ WHITESPACE@869..870 " "
+ WORD@870..872 "of"
+ WHITESPACE@872..873 " "
+ WORD@873..876 "the"
+ WHITESPACE@876..877 " "
+ COMMAND@877..884
+ COMMAND_NAME@877..884 "\\texttt"
+ CURLY_GROUP@884..892
+ L_CURLY@884..885 "{"
+ WORD@885..891 "editor"
+ R_CURLY@891..892 "}"
+ WHITESPACE@892..913 "\n "
+ WORD@913..916 "and"
+ WHITESPACE@916..917 " "
+ COMMAND@917..924
+ COMMAND_NAME@917..924 "\\texttt"
+ CURLY_GROUP@924..936
+ L_CURLY@924..925 "{"
+ WORD@925..935 "translator"
+ R_CURLY@935..936 "}"
+ WHITESPACE@936..937 " "
+ WORD@937..943 "fields"
+ WHITESPACE@943..944 " "
+ WORD@944..946 "as"
+ WHITESPACE@946..947 " "
+ WORD@947..951 "well"
+ WHITESPACE@951..952 " "
+ WORD@952..954 "as"
+ WHITESPACE@954..955 " "
+ WORD@955..958 "the"
+ WHITESPACE@958..979 "\n "
+ COMMAND@979..986
+ COMMAND_NAME@979..986 "\\texttt"
+ CURLY_GROUP@986..998
+ L_CURLY@986..987 "{"
+ WORD@987..997 "indextitle"
+ R_CURLY@997..998 "}"
+ WHITESPACE@998..999 " "
+ WORD@999..1004 "field"
+ R_CURLY@1004..1005 "}"
+ COMMA@1005..1006 ","
+ WHITESPACE@1006..1007 "\n"
+ R_DELIM@1007..1008 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__betram_1996.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__betram_1996.txt.snap
new file mode 100644
index 0000000000..c2748c1661
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__betram_1996.txt.snap
@@ -0,0 +1,208 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/betram_1996.txt
+---
+ROOT@0..556
+ STRING@0..40
+ TYPE@0..7 "@string"
+ L_DELIM@7..8 "{"
+ NAME@8..12 "jams"
+ WHITESPACE@12..16 " "
+ EQ@16..17 "="
+ WHITESPACE@17..18 " "
+ CURLY_GROUP@18..39
+ L_CURLY@18..19 "{"
+ WORD@19..21 "J."
+ NBSP@21..22 "~"
+ WORD@22..27 "Amer."
+ WHITESPACE@27..28 " "
+ WORD@28..33 "Math."
+ WHITESPACE@33..34 " "
+ WORD@34..38 "Soc."
+ R_CURLY@38..39 "}"
+ R_DELIM@39..40 "}"
+ JUNK@40..42 "\n\n"
+ ENTRY@42..556
+ TYPE@42..50 "@article"
+ L_DELIM@50..51 "{"
+ NAME@51..58 "bertram"
+ COMMA@58..59 ","
+ WHITESPACE@59..64 "\n "
+ FIELD@64..119
+ NAME@64..70 "author"
+ WHITESPACE@70..77 " "
+ EQ@77..78 "="
+ WHITESPACE@78..79 " "
+ CURLY_GROUP@79..118
+ L_CURLY@79..80 "{"
+ WORD@80..87 "Bertram"
+ COMMA@87..88 ","
+ WHITESPACE@88..89 " "
+ WORD@89..94 "Aaron"
+ WHITESPACE@94..95 " "
+ WORD@95..98 "and"
+ WHITESPACE@98..99 " "
+ WORD@99..108 "Wentworth"
+ COMMA@108..109 ","
+ WHITESPACE@109..110 " "
+ WORD@110..117 "Richard"
+ R_CURLY@117..118 "}"
+ COMMA@118..119 ","
+ WHITESPACE@119..124 "\n "
+ FIELD@124..202
+ NAME@124..129 "title"
+ WHITESPACE@129..137 " "
+ EQ@137..138 "="
+ WHITESPACE@138..139 " "
+ CURLY_GROUP@139..201
+ L_CURLY@139..140 "{"
+ WORD@140..146 "Gromov"
+ WHITESPACE@146..147 " "
+ WORD@147..157 "invariants"
+ WHITESPACE@157..158 " "
+ WORD@158..161 "for"
+ WHITESPACE@161..162 " "
+ WORD@162..173 "holomorphic"
+ WHITESPACE@173..174 " "
+ WORD@174..178 "maps"
+ WHITESPACE@178..179 " "
+ WORD@179..181 "on"
+ WHITESPACE@181..182 " "
+ CURLY_GROUP@182..191
+ L_CURLY@182..183 "{"
+ WORD@183..190 "Riemann"
+ R_CURLY@190..191 "}"
+ WHITESPACE@191..192 " "
+ WORD@192..200 "surfaces"
+ R_CURLY@200..201 "}"
+ COMMA@201..202 ","
+ WHITESPACE@202..207 "\n "
+ FIELD@207..227
+ NAME@207..219 "journaltitle"
+ WHITESPACE@219..220 " "
+ EQ@220..221 "="
+ WHITESPACE@221..222 " "
+ LITERAL@222..226
+ NAME@222..226 "jams"
+ COMMA@226..227 ","
+ WHITESPACE@227..232 "\n "
+ FIELD@232..252
+ NAME@232..236 "date"
+ WHITESPACE@236..245 " "
+ EQ@245..246 "="
+ WHITESPACE@246..247 " "
+ LITERAL@247..251
+ INTEGER@247..251 "1996"
+ COMMA@251..252 ","
+ WHITESPACE@252..257 "\n "
+ FIELD@257..274
+ NAME@257..263 "volume"
+ WHITESPACE@263..270 " "
+ EQ@270..271 "="
+ WHITESPACE@271..272 " "
+ LITERAL@272..273
+ INTEGER@272..273 "9"
+ COMMA@273..274 ","
+ WHITESPACE@274..279 "\n "
+ FIELD@279..296
+ NAME@279..285 "number"
+ WHITESPACE@285..292 " "
+ EQ@292..293 "="
+ WHITESPACE@293..294 " "
+ LITERAL@294..295
+ INTEGER@294..295 "2"
+ COMMA@295..296 ","
+ WHITESPACE@296..301 "\n "
+ FIELD@301..326
+ NAME@301..306 "pages"
+ WHITESPACE@306..314 " "
+ EQ@314..315 "="
+ WHITESPACE@315..316 " "
+ CURLY_GROUP@316..325
+ L_CURLY@316..317 "{"
+ WORD@317..324 "529-571"
+ R_CURLY@324..325 "}"
+ COMMA@325..326 ","
+ WHITESPACE@326..331 "\n "
+ FIELD@331..356
+ NAME@331..337 "langid"
+ WHITESPACE@337..344 " "
+ EQ@344..345 "="
+ WHITESPACE@345..346 " "
+ CURLY_GROUP@346..355
+ L_CURLY@346..347 "{"
+ WORD@347..354 "english"
+ R_CURLY@354..355 "}"
+ COMMA@355..356 ","
+ WHITESPACE@356..361 "\n "
+ FIELD@361..395
+ NAME@361..371 "langidopts"
+ WHITESPACE@371..374 " "
+ EQ@374..375 "="
+ WHITESPACE@375..376 " "
+ CURLY_GROUP@376..394
+ L_CURLY@376..377 "{"
+ WORD@377..393 "variant=american"
+ R_CURLY@393..394 "}"
+ COMMA@394..395 ","
+ WHITESPACE@395..400 "\n "
+ FIELD@400..435
+ NAME@400..410 "shorttitle"
+ WHITESPACE@410..413 " "
+ EQ@413..414 "="
+ WHITESPACE@414..415 " "
+ CURLY_GROUP@415..434
+ L_CURLY@415..416 "{"
+ WORD@416..422 "Gromov"
+ WHITESPACE@422..423 " "
+ WORD@423..433 "invariants"
+ R_CURLY@433..434 "}"
+ COMMA@434..435 ","
+ WHITESPACE@435..440 "\n "
+ FIELD@440..554
+ NAME@440..450 "annotation"
+ WHITESPACE@450..453 " "
+ EQ@453..454 "="
+ WHITESPACE@454..455 " "
+ CURLY_GROUP@455..553
+ L_CURLY@455..456 "{"
+ WORD@456..458 "An"
+ WHITESPACE@458..459 " "
+ COMMAND@459..466
+ COMMAND_NAME@459..466 "\\texttt"
+ CURLY_GROUP@466..475
+ L_CURLY@466..467 "{"
+ WORD@467..474 "article"
+ R_CURLY@474..475 "}"
+ WHITESPACE@475..476 " "
+ WORD@476..481 "entry"
+ WHITESPACE@481..482 " "
+ WORD@482..486 "with"
+ WHITESPACE@486..487 " "
+ WORD@487..488 "a"
+ WHITESPACE@488..489 " "
+ COMMAND@489..496
+ COMMAND_NAME@489..496 "\\texttt"
+ CURLY_GROUP@496..504
+ L_CURLY@496..497 "{"
+ WORD@497..503 "volume"
+ R_CURLY@503..504 "}"
+ WHITESPACE@504..505 " "
+ WORD@505..508 "and"
+ WHITESPACE@508..509 " "
+ WORD@509..510 "a"
+ WHITESPACE@510..531 "\n "
+ COMMAND@531..538
+ COMMAND_NAME@531..538 "\\texttt"
+ CURLY_GROUP@538..546
+ L_CURLY@538..539 "{"
+ WORD@539..545 "number"
+ R_CURLY@545..546 "}"
+ WHITESPACE@546..547 " "
+ WORD@547..552 "field"
+ R_CURLY@552..553 "}"
+ COMMA@553..554 ","
+ WHITESPACE@554..555 "\n"
+ R_DELIM@555..556 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__blom_2021.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__blom_2021.txt.snap
new file mode 100644
index 0000000000..417bda4ec9
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__blom_2021.txt.snap
@@ -0,0 +1,223 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/blom_2021.txt
+---
+ROOT@0..860
+ ENTRY@0..860
+ TYPE@0..8 "@article"
+ L_DELIM@8..9 "{"
+ NAME@9..42 "DBLP:journals/corr/ab ..."
+ COMMA@42..43 ","
+ WHITESPACE@43..48 "\n "
+ FIELD@48..322
+ NAME@48..54 "author"
+ WHITESPACE@54..58 " "
+ EQ@58..59 "="
+ WHITESPACE@59..60 " "
+ CURLY_GROUP@60..321
+ L_CURLY@60..61 "{"
+ WORD@61..69 "Michelle"
+ WHITESPACE@69..70 " "
+ WORD@70..72 "L."
+ WHITESPACE@72..73 " "
+ WORD@73..77 "Blom"
+ WHITESPACE@77..78 " "
+ WORD@78..81 "and"
+ WHITESPACE@81..102 "\n "
+ WORD@102..109 "Jurlind"
+ WHITESPACE@109..110 " "
+ WORD@110..119 "Budurushi"
+ WHITESPACE@119..120 " "
+ WORD@120..123 "and"
+ WHITESPACE@123..144 "\n "
+ WORD@144..150 "Ronald"
+ WHITESPACE@150..151 " "
+ WORD@151..153 "L."
+ WHITESPACE@153..154 " "
+ WORD@154..160 "Rivest"
+ WHITESPACE@160..161 " "
+ WORD@161..164 "and"
+ WHITESPACE@164..185 "\n "
+ WORD@185..191 "Philip"
+ WHITESPACE@191..192 " "
+ WORD@192..194 "B."
+ WHITESPACE@194..195 " "
+ WORD@195..200 "Stark"
+ WHITESPACE@200..201 " "
+ WORD@201..204 "and"
+ WHITESPACE@204..225 "\n "
+ WORD@225..230 "Peter"
+ WHITESPACE@230..231 " "
+ WORD@231..233 "J."
+ WHITESPACE@233..234 " "
+ WORD@234..241 "Stuckey"
+ WHITESPACE@241..242 " "
+ WORD@242..245 "and"
+ WHITESPACE@245..266 "\n "
+ WORD@266..273 "Vanessa"
+ WHITESPACE@273..274 " "
+ WORD@274..280 "Teague"
+ WHITESPACE@280..281 " "
+ WORD@281..284 "and"
+ WHITESPACE@284..305 "\n "
+ WORD@305..311 "Damjan"
+ WHITESPACE@311..312 " "
+ WORD@312..320 "Vukcevic"
+ R_CURLY@320..321 "}"
+ COMMA@321..322 ","
+ WHITESPACE@322..327 "\n "
+ FIELD@327..473
+ NAME@327..332 "title"
+ WHITESPACE@332..337 " "
+ EQ@337..338 "="
+ WHITESPACE@338..339 " "
+ CURLY_GROUP@339..472
+ L_CURLY@339..340 "{"
+ WORD@340..355 "Assertion-based"
+ WHITESPACE@355..356 " "
+ WORD@356..366 "Approaches"
+ WHITESPACE@366..367 " "
+ WORD@367..369 "to"
+ WHITESPACE@369..370 " "
+ WORD@370..378 "Auditing"
+ WHITESPACE@378..379 " "
+ WORD@379..386 "Complex"
+ WHITESPACE@386..387 " "
+ WORD@387..396 "Elections"
+ COMMA@396..397 ","
+ WHITESPACE@397..398 " "
+ WORD@398..402 "with"
+ WHITESPACE@402..403 " "
+ WORD@403..414 "application"
+ WHITESPACE@414..435 "\n "
+ WORD@435..437 "to"
+ WHITESPACE@437..438 " "
+ WORD@438..448 "party-list"
+ WHITESPACE@448..449 " "
+ WORD@449..461 "proportional"
+ WHITESPACE@461..462 " "
+ WORD@462..471 "elections"
+ R_CURLY@471..472 "}"
+ COMMA@472..473 ","
+ WHITESPACE@473..478 "\n "
+ FIELD@478..497
+ NAME@478..485 "journal"
+ WHITESPACE@485..488 " "
+ EQ@488..489 "="
+ WHITESPACE@489..490 " "
+ CURLY_GROUP@490..496
+ L_CURLY@490..491 "{"
+ WORD@491..495 "CoRR"
+ R_CURLY@495..496 "}"
+ COMMA@496..497 ","
+ WHITESPACE@497..502 "\n "
+ FIELD@502..531
+ NAME@502..508 "volume"
+ WHITESPACE@508..512 " "
+ EQ@512..513 "="
+ WHITESPACE@513..514 " "
+ CURLY_GROUP@514..530
+ L_CURLY@514..515 "{"
+ WORD@515..529 "abs/2107.11903"
+ R_CURLY@529..530 "}"
+ COMMA@530..531 ","
+ WHITESPACE@531..536 "\n "
+ FIELD@536..555
+ NAME@536..540 "year"
+ WHITESPACE@540..546 " "
+ EQ@546..547 "="
+ WHITESPACE@547..548 " "
+ CURLY_GROUP@548..554
+ L_CURLY@548..549 "{"
+ INTEGER@549..553 "2021"
+ R_CURLY@553..554 "}"
+ COMMA@554..555 ","
+ WHITESPACE@555..560 "\n "
+ FIELD@560..607
+ NAME@560..563 "url"
+ WHITESPACE@563..570 " "
+ EQ@570..571 "="
+ WHITESPACE@571..572 " "
+ CURLY_GROUP@572..606
+ L_CURLY@572..573 "{"
+ WORD@573..605 "https://arxiv.org/abs ..."
+ R_CURLY@605..606 "}"
+ COMMA@606..607 ","
+ WHITESPACE@607..612 "\n "
+ FIELD@612..633
+ NAME@612..622 "eprinttype"
+ WHITESPACE@622..623 " "
+ EQ@623..624 "="
+ WHITESPACE@624..625 " "
+ CURLY_GROUP@625..632
+ L_CURLY@625..626 "{"
+ WORD@626..631 "arXiv"
+ R_CURLY@631..632 "}"
+ COMMA@632..633 ","
+ WHITESPACE@633..638 "\n "
+ FIELD@638..663
+ NAME@638..644 "eprint"
+ WHITESPACE@644..648 " "
+ EQ@648..649 "="
+ WHITESPACE@649..650 " "
+ CURLY_GROUP@650..662
+ L_CURLY@650..651 "{"
+ WORD@651..661 "2107.11903"
+ R_CURLY@661..662 "}"
+ COMMA@662..663 ","
+ WHITESPACE@663..668 "\n "
+ FIELD@668..714
+ NAME@668..677 "timestamp"
+ WHITESPACE@677..678 " "
+ EQ@678..679 "="
+ WHITESPACE@679..680 " "
+ CURLY_GROUP@680..713
+ L_CURLY@680..681 "{"
+ WORD@681..684 "Thu"
+ COMMA@684..685 ","
+ WHITESPACE@685..686 " "
+ INTEGER@686..688 "29"
+ WHITESPACE@688..689 " "
+ WORD@689..692 "Jul"
+ WHITESPACE@692..693 " "
+ INTEGER@693..697 "2021"
+ WHITESPACE@697..698 " "
+ WORD@698..706 "16:14:15"
+ WHITESPACE@706..707 " "
+ WORD@707..712 "+0200"
+ R_CURLY@712..713 "}"
+ COMMA@713..714 ","
+ WHITESPACE@714..719 "\n "
+ FIELD@719..787
+ NAME@719..725 "biburl"
+ WHITESPACE@725..729 " "
+ EQ@729..730 "="
+ WHITESPACE@730..731 " "
+ CURLY_GROUP@731..786
+ L_CURLY@731..732 "{"
+ WORD@732..785 "https://dblp.org/rec/ ..."
+ R_CURLY@785..786 "}"
+ COMMA@786..787 ","
+ WHITESPACE@787..792 "\n "
+ FIELD@792..859
+ NAME@792..801 "bibsource"
+ WHITESPACE@801..802 " "
+ EQ@802..803 "="
+ WHITESPACE@803..804 " "
+ CURLY_GROUP@804..858
+ L_CURLY@804..805 "{"
+ WORD@805..809 "dblp"
+ WHITESPACE@809..810 " "
+ WORD@810..818 "computer"
+ WHITESPACE@818..819 " "
+ WORD@819..826 "science"
+ WHITESPACE@826..827 " "
+ WORD@827..839 "bibliography"
+ COMMA@839..840 ","
+ WHITESPACE@840..841 " "
+ WORD@841..857 "https://dblp.org"
+ R_CURLY@857..858 "}"
+ WHITESPACE@858..859 "\n"
+ R_DELIM@859..860 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__combi_2004.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__combi_2004.txt.snap
new file mode 100644
index 0000000000..82f58a700f
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__combi_2004.txt.snap
@@ -0,0 +1,251 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/combi_2004.txt
+---
+ROOT@0..674
+ ENTRY@0..674
+ TYPE@0..14 "@inproceedings"
+ L_DELIM@14..15 "{"
+ NAME@15..36 "10.1145/967900.968040"
+ COMMA@36..37 ","
+ WHITESPACE@37..42 "\n "
+ FIELD@42..86
+ NAME@42..48 "author"
+ WHITESPACE@48..49 " "
+ EQ@49..50 "="
+ WHITESPACE@50..51 " "
+ CURLY_GROUP@51..85
+ L_CURLY@51..52 "{"
+ WORD@52..57 "Combi"
+ COMMA@57..58 ","
+ WHITESPACE@58..59 " "
+ WORD@59..64 "Carlo"
+ WHITESPACE@64..65 " "
+ WORD@65..68 "and"
+ WHITESPACE@68..69 " "
+ WORD@69..74 "Pozzi"
+ COMMA@74..75 ","
+ WHITESPACE@75..76 " "
+ WORD@76..84 "Giuseppe"
+ R_CURLY@84..85 "}"
+ COMMA@85..86 ","
+ WHITESPACE@86..91 "\n "
+ FIELD@91..157
+ NAME@91..96 "title"
+ WHITESPACE@96..97 " "
+ EQ@97..98 "="
+ WHITESPACE@98..99 " "
+ CURLY_GROUP@99..156
+ L_CURLY@99..100 "{"
+ WORD@100..113 "Architectures"
+ WHITESPACE@113..114 " "
+ WORD@114..117 "for"
+ WHITESPACE@117..118 " "
+ WORD@118..119 "a"
+ WHITESPACE@119..120 " "
+ WORD@120..128 "Temporal"
+ WHITESPACE@128..129 " "
+ WORD@129..137 "Workflow"
+ WHITESPACE@137..138 " "
+ WORD@138..148 "Management"
+ WHITESPACE@148..149 " "
+ WORD@149..155 "System"
+ R_CURLY@155..156 "}"
+ COMMA@156..157 ","
+ WHITESPACE@157..162 "\n "
+ FIELD@162..176
+ NAME@162..166 "year"
+ WHITESPACE@166..167 " "
+ EQ@167..168 "="
+ WHITESPACE@168..169 " "
+ CURLY_GROUP@169..175
+ L_CURLY@169..170 "{"
+ INTEGER@170..174 "2004"
+ R_CURLY@174..175 "}"
+ COMMA@175..176 ","
+ WHITESPACE@176..181 "\n "
+ FIELD@181..201
+ NAME@181..185 "isbn"
+ WHITESPACE@185..186 " "
+ EQ@186..187 "="
+ WHITESPACE@187..188 " "
+ CURLY_GROUP@188..200
+ L_CURLY@188..189 "{"
+ INTEGER@189..199 "1581138121"
+ R_CURLY@199..200 "}"
+ COMMA@200..201 ","
+ WHITESPACE@201..206 "\n "
+ FIELD@206..256
+ NAME@206..215 "publisher"
+ WHITESPACE@215..216 " "
+ EQ@216..217 "="
+ WHITESPACE@217..218 " "
+ CURLY_GROUP@218..255
+ L_CURLY@218..219 "{"
+ WORD@219..230 "Association"
+ WHITESPACE@230..231 " "
+ WORD@231..234 "for"
+ WHITESPACE@234..235 " "
+ WORD@235..244 "Computing"
+ WHITESPACE@244..245 " "
+ WORD@245..254 "Machinery"
+ R_CURLY@254..255 "}"
+ COMMA@255..256 ","
+ WHITESPACE@256..261 "\n "
+ FIELD@261..291
+ NAME@261..268 "address"
+ WHITESPACE@268..269 " "
+ EQ@269..270 "="
+ WHITESPACE@270..271 " "
+ CURLY_GROUP@271..290
+ L_CURLY@271..272 "{"
+ WORD@272..275 "New"
+ WHITESPACE@275..276 " "
+ WORD@276..280 "York"
+ COMMA@280..281 ","
+ WHITESPACE@281..282 " "
+ WORD@282..284 "NY"
+ COMMA@284..285 ","
+ WHITESPACE@285..286 " "
+ WORD@286..289 "USA"
+ R_CURLY@289..290 "}"
+ COMMA@290..291 ","
+ WHITESPACE@291..296 "\n "
+ FIELD@296..342
+ NAME@296..299 "url"
+ WHITESPACE@299..300 " "
+ EQ@300..301 "="
+ WHITESPACE@301..302 " "
+ CURLY_GROUP@302..341
+ L_CURLY@302..303 "{"
+ WORD@303..340 "https://doi.org/10.11 ..."
+ R_CURLY@340..341 "}"
+ COMMA@341..342 ","
+ WHITESPACE@342..347 "\n "
+ FIELD@347..377
+ NAME@347..350 "doi"
+ WHITESPACE@350..351 " "
+ EQ@351..352 "="
+ WHITESPACE@352..353 " "
+ CURLY_GROUP@353..376
+ L_CURLY@353..354 "{"
+ WORD@354..375 "10.1145/967900.968040"
+ R_CURLY@375..376 "}"
+ COMMA@376..377 ","
+ WHITESPACE@377..382 "\n "
+ FIELD@382..455
+ NAME@382..391 "booktitle"
+ WHITESPACE@391..392 " "
+ EQ@392..393 "="
+ WHITESPACE@393..394 " "
+ CURLY_GROUP@394..454
+ L_CURLY@394..395 "{"
+ WORD@395..406 "Proceedings"
+ WHITESPACE@406..407 " "
+ WORD@407..409 "of"
+ WHITESPACE@409..410 " "
+ WORD@410..413 "the"
+ WHITESPACE@413..414 " "
+ INTEGER@414..418 "2004"
+ WHITESPACE@418..419 " "
+ WORD@419..422 "ACM"
+ WHITESPACE@422..423 " "
+ WORD@423..432 "Symposium"
+ WHITESPACE@432..433 " "
+ WORD@433..435 "on"
+ WHITESPACE@435..436 " "
+ WORD@436..443 "Applied"
+ WHITESPACE@443..444 " "
+ WORD@444..453 "Computing"
+ R_CURLY@453..454 "}"
+ COMMA@454..455 ","
+ WHITESPACE@455..460 "\n "
+ FIELD@460..478
+ NAME@460..465 "pages"
+ WHITESPACE@465..466 " "
+ EQ@466..467 "="
+ WHITESPACE@467..468 " "
+ CURLY_GROUP@468..477
+ L_CURLY@468..469 "{"
+ WORD@469..476 "659-666"
+ R_CURLY@476..477 "}"
+ COMMA@477..478 ","
+ WHITESPACE@478..483 "\n "
+ FIELD@483..498
+ NAME@483..491 "numpages"
+ WHITESPACE@491..492 " "
+ EQ@492..493 "="
+ WHITESPACE@493..494 " "
+ CURLY_GROUP@494..497
+ L_CURLY@494..495 "{"
+ INTEGER@495..496 "8"
+ R_CURLY@496..497 "}"
+ COMMA@497..498 ","
+ WHITESPACE@498..503 "\n "
+ FIELD@503..615
+ NAME@503..511 "keywords"
+ WHITESPACE@511..512 " "
+ EQ@512..513 "="
+ WHITESPACE@513..514 " "
+ CURLY_GROUP@514..614
+ L_CURLY@514..515 "{"
+ WORD@515..521 "active"
+ WHITESPACE@521..522 " "
+ WORD@522..526 "DBMS"
+ COMMA@526..527 ","
+ WHITESPACE@527..528 " "
+ WORD@528..536 "temporal"
+ WHITESPACE@536..537 " "
+ WORD@537..541 "DBMS"
+ COMMA@541..542 ","
+ WHITESPACE@542..543 " "
+ WORD@543..551 "workflow"
+ WHITESPACE@551..552 " "
+ WORD@552..562 "management"
+ WHITESPACE@562..563 " "
+ WORD@563..569 "system"
+ WHITESPACE@569..570 " "
+ WORD@570..571 "-"
+ WHITESPACE@571..572 " "
+ WORD@572..576 "WfMS"
+ COMMA@576..577 ","
+ WHITESPACE@577..578 " "
+ WORD@578..586 "temporal"
+ WHITESPACE@586..587 " "
+ WORD@587..595 "workflow"
+ WHITESPACE@595..596 " "
+ WORD@596..606 "management"
+ WHITESPACE@606..607 " "
+ WORD@607..613 "system"
+ R_CURLY@613..614 "}"
+ COMMA@614..615 ","
+ WHITESPACE@615..620 "\n "
+ FIELD@620..649
+ NAME@620..628 "location"
+ WHITESPACE@628..629 " "
+ EQ@629..630 "="
+ WHITESPACE@630..631 " "
+ CURLY_GROUP@631..648
+ L_CURLY@631..632 "{"
+ WORD@632..639 "Nicosia"
+ COMMA@639..640 ","
+ WHITESPACE@640..641 " "
+ WORD@641..647 "Cyprus"
+ R_CURLY@647..648 "}"
+ COMMA@648..649 ","
+ WHITESPACE@649..654 "\n "
+ FIELD@654..673
+ NAME@654..660 "series"
+ WHITESPACE@660..661 " "
+ EQ@661..662 "="
+ WHITESPACE@662..663 " "
+ CURLY_GROUP@663..672
+ L_CURLY@663..664 "{"
+ WORD@664..667 "SAC"
+ WHITESPACE@667..668 " "
+ WORD@668..671 "'04"
+ R_CURLY@671..672 "}"
+ WHITESPACE@672..673 "\n"
+ R_DELIM@673..674 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__erwin_2007.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__erwin_2007.txt.snap
new file mode 100644
index 0000000000..58094d2f42
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__erwin_2007.txt.snap
@@ -0,0 +1,239 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/erwin_2007.txt
+---
+ROOT@0..615
+ ENTRY@0..615
+ TYPE@0..14 "@inproceedings"
+ L_DELIM@14..15 "{"
+ NAME@15..38 "10.5555/1386993.1386994"
+ COMMA@38..39 ","
+ WHITESPACE@39..44 "\n "
+ FIELD@44..107
+ NAME@44..50 "author"
+ WHITESPACE@50..51 " "
+ EQ@51..52 "="
+ WHITESPACE@52..53 " "
+ CURLY_GROUP@53..106
+ L_CURLY@53..54 "{"
+ WORD@54..59 "Erwin"
+ COMMA@59..60 ","
+ WHITESPACE@60..61 " "
+ WORD@61..65 "Alva"
+ WHITESPACE@65..66 " "
+ WORD@66..69 "and"
+ WHITESPACE@69..70 " "
+ WORD@70..77 "Gopalan"
+ COMMA@77..78 ","
+ WHITESPACE@78..79 " "
+ WORD@79..82 "Raj"
+ WHITESPACE@82..83 " "
+ WORD@83..85 "P."
+ WHITESPACE@85..86 " "
+ WORD@86..89 "and"
+ WHITESPACE@89..90 " "
+ WORD@90..98 "Achuthan"
+ COMMA@98..99 ","
+ WHITESPACE@99..100 " "
+ WORD@100..102 "N."
+ WHITESPACE@102..103 " "
+ WORD@103..105 "R."
+ R_CURLY@105..106 "}"
+ COMMA@106..107 ","
+ WHITESPACE@107..112 "\n "
+ FIELD@112..194
+ NAME@112..117 "title"
+ WHITESPACE@117..118 " "
+ EQ@118..119 "="
+ WHITESPACE@119..120 " "
+ CURLY_GROUP@120..193
+ L_CURLY@120..121 "{"
+ WORD@121..122 "A"
+ WHITESPACE@122..123 " "
+ WORD@123..132 "Bottom-up"
+ WHITESPACE@132..133 " "
+ WORD@133..143 "Projection"
+ WHITESPACE@143..144 " "
+ WORD@144..149 "Based"
+ WHITESPACE@149..150 " "
+ WORD@150..159 "Algorithm"
+ WHITESPACE@159..160 " "
+ WORD@160..163 "for"
+ WHITESPACE@163..164 " "
+ WORD@164..170 "Mining"
+ WHITESPACE@170..171 " "
+ WORD@171..175 "High"
+ WHITESPACE@175..176 " "
+ WORD@176..183 "Utility"
+ WHITESPACE@183..184 " "
+ WORD@184..192 "Itemsets"
+ R_CURLY@192..193 "}"
+ COMMA@193..194 ","
+ WHITESPACE@194..199 "\n "
+ FIELD@199..213
+ NAME@199..203 "year"
+ WHITESPACE@203..204 " "
+ EQ@204..205 "="
+ WHITESPACE@205..206 " "
+ CURLY_GROUP@206..212
+ L_CURLY@206..207 "{"
+ INTEGER@207..211 "2007"
+ R_CURLY@211..212 "}"
+ COMMA@212..213 ","
+ WHITESPACE@213..218 "\n "
+ FIELD@218..241
+ NAME@218..222 "isbn"
+ WHITESPACE@222..223 " "
+ EQ@223..224 "="
+ WHITESPACE@224..225 " "
+ CURLY_GROUP@225..240
+ L_CURLY@225..226 "{"
+ INTEGER@226..239 "9781920682651"
+ R_CURLY@239..240 "}"
+ COMMA@240..241 ","
+ WHITESPACE@241..246 "\n "
+ FIELD@246..294
+ NAME@246..255 "publisher"
+ WHITESPACE@255..256 " "
+ EQ@256..257 "="
+ WHITESPACE@257..258 " "
+ CURLY_GROUP@258..293
+ L_CURLY@258..259 "{"
+ WORD@259..269 "Australian"
+ WHITESPACE@269..270 " "
+ WORD@270..278 "Computer"
+ WHITESPACE@278..279 " "
+ WORD@279..286 "Society"
+ COMMA@286..287 ","
+ WHITESPACE@287..288 " "
+ WORD@288..292 "Inc."
+ R_CURLY@292..293 "}"
+ COMMA@293..294 ","
+ WHITESPACE@294..299 "\n "
+ FIELD@299..315
+ NAME@299..306 "address"
+ WHITESPACE@306..307 " "
+ EQ@307..308 "="
+ WHITESPACE@308..309 " "
+ CURLY_GROUP@309..314
+ L_CURLY@309..310 "{"
+ WORD@310..313 "AUS"
+ R_CURLY@313..314 "}"
+ COMMA@314..315 ","
+ WHITESPACE@315..320 "\n "
+ FIELD@320..447
+ NAME@320..329 "booktitle"
+ WHITESPACE@329..330 " "
+ EQ@330..331 "="
+ WHITESPACE@331..332 " "
+ CURLY_GROUP@332..446
+ L_CURLY@332..333 "{"
+ WORD@333..344 "Proceedings"
+ WHITESPACE@344..345 " "
+ WORD@345..347 "of"
+ WHITESPACE@347..348 " "
+ WORD@348..351 "the"
+ WHITESPACE@351..352 " "
+ WORD@352..355 "2nd"
+ WHITESPACE@355..356 " "
+ WORD@356..369 "International"
+ WHITESPACE@369..370 " "
+ WORD@370..378 "Workshop"
+ WHITESPACE@378..379 " "
+ WORD@379..381 "on"
+ WHITESPACE@381..382 " "
+ WORD@382..393 "Integrating"
+ WHITESPACE@393..394 " "
+ WORD@394..404 "Artificial"
+ WHITESPACE@404..405 " "
+ WORD@405..417 "Intelligence"
+ WHITESPACE@417..418 " "
+ WORD@418..421 "and"
+ WHITESPACE@421..422 " "
+ WORD@422..426 "Data"
+ WHITESPACE@426..427 " "
+ WORD@427..433 "Mining"
+ WHITESPACE@433..434 " "
+ WORD@434..435 "-"
+ WHITESPACE@435..436 " "
+ WORD@436..442 "Volume"
+ WHITESPACE@442..443 " "
+ INTEGER@443..445 "84"
+ R_CURLY@445..446 "}"
+ COMMA@446..447 ","
+ WHITESPACE@447..452 "\n "
+ FIELD@452..467
+ NAME@452..457 "pages"
+ WHITESPACE@457..458 " "
+ EQ@458..459 "="
+ WHITESPACE@459..460 " "
+ CURLY_GROUP@460..466
+ L_CURLY@460..461 "{"
+ WORD@461..465 "3-11"
+ R_CURLY@465..466 "}"
+ COMMA@466..467 ","
+ WHITESPACE@467..472 "\n "
+ FIELD@472..487
+ NAME@472..480 "numpages"
+ WHITESPACE@480..481 " "
+ EQ@481..482 "="
+ WHITESPACE@482..483 " "
+ CURLY_GROUP@483..486
+ L_CURLY@483..484 "{"
+ INTEGER@484..485 "9"
+ R_CURLY@485..486 "}"
+ COMMA@486..487 ","
+ WHITESPACE@487..492 "\n "
+ FIELD@492..549
+ NAME@492..500 "keywords"
+ WHITESPACE@500..501 " "
+ EQ@501..502 "="
+ WHITESPACE@502..503 " "
+ CURLY_GROUP@503..548
+ L_CURLY@503..504 "{"
+ WORD@504..511 "pattern"
+ WHITESPACE@511..512 " "
+ WORD@512..518 "growth"
+ COMMA@518..519 ","
+ WHITESPACE@519..520 " "
+ WORD@520..524 "high"
+ WHITESPACE@524..525 " "
+ WORD@525..532 "utility"
+ WHITESPACE@532..533 " "
+ WORD@533..540 "itemset"
+ WHITESPACE@540..541 " "
+ WORD@541..547 "mining"
+ R_CURLY@547..548 "}"
+ COMMA@548..549 ","
+ WHITESPACE@549..554 "\n "
+ FIELD@554..589
+ NAME@554..562 "location"
+ WHITESPACE@562..563 " "
+ EQ@563..564 "="
+ WHITESPACE@564..565 " "
+ CURLY_GROUP@565..588
+ L_CURLY@565..566 "{"
+ WORD@566..570 "Gold"
+ WHITESPACE@570..571 " "
+ WORD@571..576 "Coast"
+ COMMA@576..577 ","
+ WHITESPACE@577..578 " "
+ WORD@578..587 "Australia"
+ R_CURLY@587..588 "}"
+ COMMA@588..589 ","
+ WHITESPACE@589..594 "\n "
+ FIELD@594..614
+ NAME@594..600 "series"
+ WHITESPACE@600..601 " "
+ EQ@601..602 "="
+ WHITESPACE@602..603 " "
+ CURLY_GROUP@603..613
+ L_CURLY@603..604 "{"
+ WORD@604..608 "AIDM"
+ WHITESPACE@608..609 " "
+ WORD@609..612 "'07"
+ R_CURLY@612..613 "}"
+ WHITESPACE@613..614 "\n"
+ R_DELIM@614..615 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__jain_1999.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__jain_1999.txt.snap
new file mode 100644
index 0000000000..d9f83b339a
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__jain_1999.txt.snap
@@ -0,0 +1,267 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/jain_1999.txt
+---
+ROOT@0..674
+ ENTRY@0..674
+ TYPE@0..8 "@article"
+ L_DELIM@8..9 "{"
+ NAME@9..30 "10.1145/331499.331504"
+ COMMA@30..31 ","
+ WHITESPACE@31..36 "\n "
+ FIELD@36..93
+ NAME@36..42 "author"
+ WHITESPACE@42..43 " "
+ EQ@43..44 "="
+ WHITESPACE@44..45 " "
+ CURLY_GROUP@45..92
+ L_CURLY@45..46 "{"
+ WORD@46..50 "Jain"
+ COMMA@50..51 ","
+ WHITESPACE@51..52 " "
+ WORD@52..54 "A."
+ WHITESPACE@54..55 " "
+ WORD@55..57 "K."
+ WHITESPACE@57..58 " "
+ WORD@58..61 "and"
+ WHITESPACE@61..62 " "
+ WORD@62..67 "Murty"
+ COMMA@67..68 ","
+ WHITESPACE@68..69 " "
+ WORD@69..71 "M."
+ WHITESPACE@71..72 " "
+ WORD@72..74 "N."
+ WHITESPACE@74..75 " "
+ WORD@75..78 "and"
+ WHITESPACE@78..79 " "
+ WORD@79..84 "Flynn"
+ COMMA@84..85 ","
+ WHITESPACE@85..86 " "
+ WORD@86..88 "P."
+ WHITESPACE@88..89 " "
+ WORD@89..91 "J."
+ R_CURLY@91..92 "}"
+ COMMA@92..93 ","
+ WHITESPACE@93..98 "\n "
+ FIELD@98..134
+ NAME@98..103 "title"
+ WHITESPACE@103..104 " "
+ EQ@104..105 "="
+ WHITESPACE@105..106 " "
+ CURLY_GROUP@106..133
+ L_CURLY@106..107 "{"
+ WORD@107..111 "Data"
+ WHITESPACE@111..112 " "
+ WORD@112..123 "Clustering:"
+ WHITESPACE@123..124 " "
+ WORD@124..125 "A"
+ WHITESPACE@125..126 " "
+ WORD@126..132 "Review"
+ R_CURLY@132..133 "}"
+ COMMA@133..134 ","
+ WHITESPACE@134..139 "\n "
+ FIELD@139..153
+ NAME@139..143 "year"
+ WHITESPACE@143..144 " "
+ EQ@144..145 "="
+ WHITESPACE@145..146 " "
+ CURLY_GROUP@146..152
+ L_CURLY@146..147 "{"
+ INTEGER@147..151 "1999"
+ R_CURLY@151..152 "}"
+ COMMA@152..153 ","
+ WHITESPACE@153..158 "\n "
+ FIELD@158..184
+ NAME@158..168 "issue_date"
+ WHITESPACE@168..169 " "
+ EQ@169..170 "="
+ WHITESPACE@170..171 " "
+ CURLY_GROUP@171..183
+ L_CURLY@171..172 "{"
+ WORD@172..177 "Sept."
+ WHITESPACE@177..178 " "
+ INTEGER@178..182 "1999"
+ R_CURLY@182..183 "}"
+ COMMA@183..184 ","
+ WHITESPACE@184..189 "\n "
+ FIELD@189..239
+ NAME@189..198 "publisher"
+ WHITESPACE@198..199 " "
+ EQ@199..200 "="
+ WHITESPACE@200..201 " "
+ CURLY_GROUP@201..238
+ L_CURLY@201..202 "{"
+ WORD@202..213 "Association"
+ WHITESPACE@213..214 " "
+ WORD@214..217 "for"
+ WHITESPACE@217..218 " "
+ WORD@218..227 "Computing"
+ WHITESPACE@227..228 " "
+ WORD@228..237 "Machinery"
+ R_CURLY@237..238 "}"
+ COMMA@238..239 ","
+ WHITESPACE@239..244 "\n "
+ FIELD@244..274
+ NAME@244..251 "address"
+ WHITESPACE@251..252 " "
+ EQ@252..253 "="
+ WHITESPACE@253..254 " "
+ CURLY_GROUP@254..273
+ L_CURLY@254..255 "{"
+ WORD@255..258 "New"
+ WHITESPACE@258..259 " "
+ WORD@259..263 "York"
+ COMMA@263..264 ","
+ WHITESPACE@264..265 " "
+ WORD@265..267 "NY"
+ COMMA@267..268 ","
+ WHITESPACE@268..269 " "
+ WORD@269..272 "USA"
+ R_CURLY@272..273 "}"
+ COMMA@273..274 ","
+ WHITESPACE@274..279 "\n "
+ FIELD@279..293
+ NAME@279..285 "volume"
+ WHITESPACE@285..286 " "
+ EQ@286..287 "="
+ WHITESPACE@287..288 " "
+ CURLY_GROUP@288..292
+ L_CURLY@288..289 "{"
+ INTEGER@289..291 "31"
+ R_CURLY@291..292 "}"
+ COMMA@292..293 ","
+ WHITESPACE@293..298 "\n "
+ FIELD@298..311
+ NAME@298..304 "number"
+ WHITESPACE@304..305 " "
+ EQ@305..306 "="
+ WHITESPACE@306..307 " "
+ CURLY_GROUP@307..310
+ L_CURLY@307..308 "{"
+ INTEGER@308..309 "3"
+ R_CURLY@309..310 "}"
+ COMMA@310..311 ","
+ WHITESPACE@311..316 "\n "
+ FIELD@316..335
+ NAME@316..320 "issn"
+ WHITESPACE@320..321 " "
+ EQ@321..322 "="
+ WHITESPACE@322..323 " "
+ CURLY_GROUP@323..334
+ L_CURLY@323..324 "{"
+ WORD@324..333 "0360-0300"
+ R_CURLY@333..334 "}"
+ COMMA@334..335 ","
+ WHITESPACE@335..340 "\n "
+ FIELD@340..386
+ NAME@340..343 "url"
+ WHITESPACE@343..344 " "
+ EQ@344..345 "="
+ WHITESPACE@345..346 " "
+ CURLY_GROUP@346..385
+ L_CURLY@346..347 "{"
+ WORD@347..384 "https://doi.org/10.11 ..."
+ R_CURLY@384..385 "}"
+ COMMA@385..386 ","
+ WHITESPACE@386..391 "\n "
+ FIELD@391..421
+ NAME@391..394 "doi"
+ WHITESPACE@394..395 " "
+ EQ@395..396 "="
+ WHITESPACE@396..397 " "
+ CURLY_GROUP@397..420
+ L_CURLY@397..398 "{"
+ WORD@398..419 "10.1145/331499.331504"
+ R_CURLY@419..420 "}"
+ COMMA@420..421 ","
+ WHITESPACE@421..426 "\n "
+ FIELD@426..456
+ NAME@426..433 "journal"
+ WHITESPACE@433..434 " "
+ EQ@434..435 "="
+ WHITESPACE@435..436 " "
+ CURLY_GROUP@436..455
+ L_CURLY@436..437 "{"
+ WORD@437..440 "ACM"
+ WHITESPACE@440..441 " "
+ WORD@441..448 "Comput."
+ WHITESPACE@448..449 " "
+ WORD@449..454 "Surv."
+ R_CURLY@454..455 "}"
+ COMMA@455..456 ","
+ WHITESPACE@456..461 "\n "
+ FIELD@461..475
+ NAME@461..466 "month"
+ WHITESPACE@466..467 " "
+ EQ@467..468 "="
+ WHITESPACE@468..469 " "
+ CURLY_GROUP@469..474
+ L_CURLY@469..470 "{"
+ WORD@470..473 "sep"
+ R_CURLY@473..474 "}"
+ COMMA@474..475 ","
+ WHITESPACE@475..480 "\n "
+ FIELD@480..498
+ NAME@480..485 "pages"
+ WHITESPACE@485..486 " "
+ EQ@486..487 "="
+ WHITESPACE@487..488 " "
+ CURLY_GROUP@488..497
+ L_CURLY@488..489 "{"
+ WORD@489..496 "264-323"
+ R_CURLY@496..497 "}"
+ COMMA@497..498 ","
+ WHITESPACE@498..503 "\n "
+ FIELD@503..519
+ NAME@503..511 "numpages"
+ WHITESPACE@511..512 " "
+ EQ@512..513 "="
+ WHITESPACE@513..514 " "
+ CURLY_GROUP@514..518
+ L_CURLY@514..515 "{"
+ INTEGER@515..517 "60"
+ R_CURLY@517..518 "}"
+ COMMA@518..519 ","
+ WHITESPACE@519..524 "\n "
+ FIELD@524..673
+ NAME@524..532 "keywords"
+ WHITESPACE@532..533 " "
+ EQ@533..534 "="
+ WHITESPACE@534..535 " "
+ CURLY_GROUP@535..672
+ L_CURLY@535..536 "{"
+ WORD@536..547 "incremental"
+ WHITESPACE@547..548 " "
+ WORD@548..558 "clustering"
+ COMMA@558..559 ","
+ WHITESPACE@559..560 " "
+ WORD@560..570 "clustering"
+ WHITESPACE@570..571 " "
+ WORD@571..583 "applications"
+ COMMA@583..584 ","
+ WHITESPACE@584..585 " "
+ WORD@585..596 "exploratory"
+ WHITESPACE@596..597 " "
+ WORD@597..601 "data"
+ WHITESPACE@601..602 " "
+ WORD@602..610 "analysis"
+ COMMA@610..611 ","
+ WHITESPACE@611..612 " "
+ WORD@612..619 "cluster"
+ WHITESPACE@619..620 " "
+ WORD@620..628 "analysis"
+ COMMA@628..629 ","
+ WHITESPACE@629..630 " "
+ WORD@630..640 "similarity"
+ WHITESPACE@640..641 " "
+ WORD@641..648 "indices"
+ COMMA@648..649 ","
+ WHITESPACE@649..650 " "
+ WORD@650..662 "unsupervised"
+ WHITESPACE@662..663 " "
+ WORD@663..671 "learning"
+ R_CURLY@671..672 "}"
+ WHITESPACE@672..673 "\n"
+ R_DELIM@673..674 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__kastenholz_2006.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__kastenholz_2006.txt.snap
new file mode 100644
index 0000000000..8d67f95096
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__kastenholz_2006.txt.snap
@@ -0,0 +1,302 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/kastenholz_2006.txt
+---
+ROOT@0..898
+ STRING@0..35
+ TYPE@0..7 "@string"
+ L_DELIM@7..8 "{"
+ NAME@8..13 "jchph"
+ WHITESPACE@13..16 " "
+ EQ@16..17 "="
+ WHITESPACE@17..18 " "
+ CURLY_GROUP@18..34
+ L_CURLY@18..19 "{"
+ WORD@19..21 "J."
+ NBSP@21..22 "~"
+ WORD@22..27 "Chem."
+ WHITESPACE@27..28 " "
+ WORD@28..33 "Phys."
+ R_CURLY@33..34 "}"
+ R_DELIM@34..35 "}"
+ JUNK@35..37 "\n\n"
+ ENTRY@37..898
+ TYPE@37..45 "@article"
+ L_DELIM@45..46 "{"
+ NAME@46..56 "kastenholz"
+ COMMA@56..57 ","
+ WHITESPACE@57..62 "\n "
+ FIELD@62..130
+ NAME@62..68 "author"
+ WHITESPACE@68..75 " "
+ EQ@75..76 "="
+ WHITESPACE@76..77 " "
+ CURLY_GROUP@77..129
+ L_CURLY@77..78 "{"
+ WORD@78..88 "Kastenholz"
+ COMMA@88..89 ","
+ WHITESPACE@89..90 " "
+ WORD@90..92 "M."
+ WHITESPACE@92..93 " "
+ WORD@93..95 "A."
+ WHITESPACE@95..96 " "
+ WORD@96..99 "and"
+ WHITESPACE@99..100 " "
+ WORD@100..101 "H"
+ CURLY_GROUP@101..106
+ L_CURLY@101..102 "{"
+ ACCENT@102..105
+ ACCENT_NAME@102..104 "\\\""
+ WORD@104..105 "u"
+ R_CURLY@105..106 "}"
+ WORD@106..115 "nenberger"
+ COMMA@115..116 ","
+ WHITESPACE@116..117 " "
+ WORD@117..125 "Philippe"
+ WHITESPACE@125..126 " "
+ WORD@126..128 "H."
+ R_CURLY@128..129 "}"
+ COMMA@129..130 ","
+ WHITESPACE@130..135 "\n "
+ FIELD@135..275
+ NAME@135..140 "title"
+ WHITESPACE@140..148 " "
+ EQ@148..149 "="
+ WHITESPACE@149..150 " "
+ CURLY_GROUP@150..274
+ L_CURLY@150..151 "{"
+ WORD@151..162 "Computation"
+ WHITESPACE@162..163 " "
+ WORD@163..165 "of"
+ WHITESPACE@165..166 " "
+ WORD@166..177 "methodology"
+ COMMAND@177..184
+ COMMAND_NAME@177..184 "\\hyphen"
+ WHITESPACE@184..185 " "
+ WORD@185..196 "independent"
+ WHITESPACE@196..197 " "
+ WORD@197..202 "ionic"
+ WHITESPACE@202..203 " "
+ WORD@203..212 "solvation"
+ WHITESPACE@212..233 "\n "
+ WORD@233..237 "free"
+ WHITESPACE@237..238 " "
+ WORD@238..246 "energies"
+ WHITESPACE@246..247 " "
+ WORD@247..251 "from"
+ WHITESPACE@251..252 " "
+ WORD@252..261 "molecular"
+ WHITESPACE@261..262 " "
+ WORD@262..273 "simulations"
+ R_CURLY@273..274 "}"
+ COMMA@274..275 ","
+ WHITESPACE@275..280 "\n "
+ FIELD@280..301
+ NAME@280..292 "journaltitle"
+ WHITESPACE@292..293 " "
+ EQ@293..294 "="
+ WHITESPACE@294..295 " "
+ LITERAL@295..300
+ NAME@295..300 "jchph"
+ COMMA@300..301 ","
+ WHITESPACE@301..306 "\n "
+ FIELD@306..326
+ NAME@306..310 "date"
+ WHITESPACE@310..319 " "
+ EQ@319..320 "="
+ WHITESPACE@320..321 " "
+ LITERAL@321..325
+ INTEGER@321..325 "2006"
+ COMMA@325..326 ","
+ WHITESPACE@326..331 "\n "
+ FIELD@331..404
+ NAME@331..339 "subtitle"
+ WHITESPACE@339..344 " "
+ EQ@344..345 "="
+ WHITESPACE@345..346 " "
+ CURLY_GROUP@346..403
+ L_CURLY@346..347 "{"
+ CURLY_GROUP@347..350
+ L_CURLY@347..348 "{"
+ WORD@348..349 "I"
+ R_CURLY@349..350 "}"
+ WORD@350..351 "."
+ WHITESPACE@351..352 " "
+ CURLY_GROUP@352..357
+ L_CURLY@352..353 "{"
+ WORD@353..356 "The"
+ R_CURLY@356..357 "}"
+ WHITESPACE@357..358 " "
+ WORD@358..371 "electrostatic"
+ WHITESPACE@371..372 " "
+ WORD@372..381 "potential"
+ WHITESPACE@381..382 " "
+ WORD@382..384 "in"
+ WHITESPACE@384..385 " "
+ WORD@385..394 "molecular"
+ WHITESPACE@394..395 " "
+ WORD@395..402 "liquids"
+ R_CURLY@402..403 "}"
+ COMMA@403..404 ","
+ WHITESPACE@404..409 "\n "
+ FIELD@409..428
+ NAME@409..415 "volume"
+ WHITESPACE@415..422 " "
+ EQ@422..423 "="
+ WHITESPACE@423..424 " "
+ LITERAL@424..427
+ INTEGER@424..427 "124"
+ COMMA@427..428 ","
+ WHITESPACE@428..433 "\n "
+ FIELD@433..455
+ NAME@433..436 "eid"
+ WHITESPACE@436..446 " "
+ EQ@446..447 "="
+ WHITESPACE@447..448 " "
+ LITERAL@448..454
+ INTEGER@448..454 "124106"
+ COMMA@454..455 ","
+ WHITESPACE@455..460 "\n "
+ FIELD@460..495
+ NAME@460..463 "doi"
+ WHITESPACE@463..473 " "
+ EQ@473..474 "="
+ WHITESPACE@474..475 " "
+ CURLY_GROUP@475..494
+ L_CURLY@475..476 "{"
+ WORD@476..493 "10.1063/1.2172593"
+ R_CURLY@493..494 "}"
+ COMMA@494..495 ","
+ WHITESPACE@495..500 "\n "
+ FIELD@500..525
+ NAME@500..506 "langid"
+ WHITESPACE@506..513 " "
+ EQ@513..514 "="
+ WHITESPACE@514..515 " "
+ CURLY_GROUP@515..524
+ L_CURLY@515..516 "{"
+ WORD@516..523 "english"
+ R_CURLY@523..524 "}"
+ COMMA@524..525 ","
+ WHITESPACE@525..530 "\n "
+ FIELD@530..564
+ NAME@530..540 "langidopts"
+ WHITESPACE@540..543 " "
+ EQ@543..544 "="
+ WHITESPACE@544..545 " "
+ CURLY_GROUP@545..563
+ L_CURLY@545..546 "{"
+ WORD@546..562 "variant=american"
+ R_CURLY@562..563 "}"
+ COMMA@563..564 ","
+ WHITESPACE@564..569 "\n "
+ FIELD@569..631
+ NAME@569..579 "indextitle"
+ WHITESPACE@579..582 " "
+ EQ@582..583 "="
+ WHITESPACE@583..584 " "
+ CURLY_GROUP@584..630
+ L_CURLY@584..585 "{"
+ WORD@585..596 "Computation"
+ WHITESPACE@596..597 " "
+ WORD@597..599 "of"
+ WHITESPACE@599..600 " "
+ WORD@600..605 "ionic"
+ WHITESPACE@605..606 " "
+ WORD@606..615 "solvation"
+ WHITESPACE@615..616 " "
+ WORD@616..620 "free"
+ WHITESPACE@620..621 " "
+ WORD@621..629 "energies"
+ R_CURLY@629..630 "}"
+ COMMA@630..631 ","
+ WHITESPACE@631..636 "\n "
+ FIELD@636..896
+ NAME@636..646 "annotation"
+ WHITESPACE@646..649 " "
+ EQ@649..650 "="
+ WHITESPACE@650..651 " "
+ CURLY_GROUP@651..895
+ L_CURLY@651..652 "{"
+ WORD@652..654 "An"
+ WHITESPACE@654..655 " "
+ COMMAND@655..662
+ COMMAND_NAME@655..662 "\\texttt"
+ CURLY_GROUP@662..671
+ L_CURLY@662..663 "{"
+ WORD@663..670 "article"
+ R_CURLY@670..671 "}"
+ WHITESPACE@671..672 " "
+ WORD@672..677 "entry"
+ WHITESPACE@677..678 " "
+ WORD@678..682 "with"
+ WHITESPACE@682..683 " "
+ WORD@683..685 "an"
+ WHITESPACE@685..686 " "
+ COMMAND@686..693
+ COMMAND_NAME@686..693 "\\texttt"
+ CURLY_GROUP@693..698
+ L_CURLY@693..694 "{"
+ WORD@694..697 "eid"
+ R_CURLY@697..698 "}"
+ WHITESPACE@698..699 " "
+ WORD@699..702 "and"
+ WHITESPACE@702..703 " "
+ WORD@703..704 "a"
+ WHITESPACE@704..725 "\n "
+ COMMAND@725..732
+ COMMAND_NAME@725..732 "\\texttt"
+ CURLY_GROUP@732..737
+ L_CURLY@732..733 "{"
+ WORD@733..736 "doi"
+ R_CURLY@736..737 "}"
+ WHITESPACE@737..738 " "
+ WORD@738..744 "field."
+ WHITESPACE@744..745 " "
+ WORD@745..749 "Note"
+ WHITESPACE@749..750 " "
+ WORD@750..754 "that"
+ WHITESPACE@754..755 " "
+ WORD@755..758 "the"
+ WHITESPACE@758..759 " "
+ COMMAND@759..766
+ COMMAND_NAME@759..766 "\\textsc"
+ CURLY_GROUP@766..771
+ L_CURLY@766..767 "{"
+ WORD@767..770 "doi"
+ R_CURLY@770..771 "}"
+ WHITESPACE@771..772 " "
+ WORD@772..774 "is"
+ WHITESPACE@774..775 " "
+ WORD@775..786 "transformed"
+ WHITESPACE@786..807 "\n "
+ WORD@807..811 "into"
+ WHITESPACE@811..812 " "
+ WORD@812..813 "a"
+ WHITESPACE@813..814 " "
+ WORD@814..823 "clickable"
+ WHITESPACE@823..824 " "
+ WORD@824..828 "link"
+ WHITESPACE@828..829 " "
+ WORD@829..831 "if"
+ WHITESPACE@831..832 " "
+ COMMAND@832..839
+ COMMAND_NAME@832..839 "\\texttt"
+ CURLY_GROUP@839..849
+ L_CURLY@839..840 "{"
+ WORD@840..848 "hyperref"
+ R_CURLY@848..849 "}"
+ WHITESPACE@849..850 " "
+ WORD@850..857 "support"
+ WHITESPACE@857..858 " "
+ WORD@858..861 "has"
+ WHITESPACE@861..862 " "
+ WORD@862..866 "been"
+ WHITESPACE@866..887 "\n "
+ WORD@887..894 "enabled"
+ R_CURLY@894..895 "}"
+ COMMA@895..896 ","
+ WHITESPACE@896..897 "\n"
+ R_DELIM@897..898 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__knuth_1984.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__knuth_1984.txt.snap
new file mode 100644
index 0000000000..2be9233f95
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__knuth_1984.txt.snap
@@ -0,0 +1,320 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/knuth_1984.txt
+---
+ROOT@0..993
+ ENTRY@0..993
+ TYPE@0..5 "@book"
+ L_DELIM@5..6 "{"
+ NAME@6..16 "knuth:ct:a"
+ COMMA@16..17 ","
+ WHITESPACE@17..22 "\n "
+ FIELD@22..56
+ NAME@22..28 "author"
+ WHITESPACE@28..35 " "
+ EQ@35..36 "="
+ WHITESPACE@36..37 " "
+ CURLY_GROUP@37..55
+ L_CURLY@37..38 "{"
+ WORD@38..43 "Knuth"
+ COMMA@43..44 ","
+ WHITESPACE@44..45 " "
+ WORD@45..51 "Donald"
+ WHITESPACE@51..52 " "
+ WORD@52..54 "E."
+ R_CURLY@54..55 "}"
+ COMMA@55..56 ","
+ WHITESPACE@56..61 "\n "
+ FIELD@61..94
+ NAME@61..66 "title"
+ WHITESPACE@66..74 " "
+ EQ@74..75 "="
+ WHITESPACE@75..76 " "
+ CURLY_GROUP@76..93
+ L_CURLY@76..77 "{"
+ WORD@77..80 "The"
+ WHITESPACE@80..81 " "
+ CURLY_GROUP@81..92
+ L_CURLY@81..82 "{"
+ COMMAND@82..86
+ COMMAND_NAME@82..86 "\\TeX"
+ WHITESPACE@86..87 " "
+ WORD@87..91 "book"
+ R_CURLY@91..92 "}"
+ R_CURLY@92..93 "}"
+ COMMA@93..94 ","
+ WHITESPACE@94..99 "\n "
+ FIELD@99..119
+ NAME@99..103 "date"
+ WHITESPACE@103..112 " "
+ EQ@112..113 "="
+ WHITESPACE@113..114 " "
+ LITERAL@114..118
+ INTEGER@114..118 "1984"
+ COMMA@118..119 ","
+ WHITESPACE@119..124 "\n "
+ FIELD@124..166
+ NAME@124..133 "maintitle"
+ WHITESPACE@133..137 " "
+ EQ@137..138 "="
+ WHITESPACE@138..139 " "
+ CURLY_GROUP@139..165
+ L_CURLY@139..140 "{"
+ WORD@140..149 "Computers"
+ WHITESPACE@149..150 " "
+ COMMAND@150..152
+ COMMAND_NAME@150..152 "\\&"
+ WHITESPACE@152..153 " "
+ WORD@153..164 "Typesetting"
+ R_CURLY@164..165 "}"
+ COMMA@165..166 ","
+ WHITESPACE@166..171 "\n "
+ FIELD@171..190
+ NAME@171..177 "volume"
+ WHITESPACE@177..184 " "
+ EQ@184..185 "="
+ WHITESPACE@185..186 " "
+ CURLY_GROUP@186..189
+ L_CURLY@186..187 "{"
+ WORD@187..188 "A"
+ R_CURLY@188..189 "}"
+ COMMA@189..190 ","
+ WHITESPACE@190..195 "\n "
+ FIELD@195..227
+ NAME@195..204 "publisher"
+ WHITESPACE@204..208 " "
+ EQ@208..209 "="
+ WHITESPACE@209..210 " "
+ CURLY_GROUP@210..226
+ L_CURLY@210..211 "{"
+ WORD@211..225 "Addison-Wesley"
+ R_CURLY@225..226 "}"
+ COMMA@226..227 ","
+ WHITESPACE@227..232 "\n "
+ FIELD@232..264
+ NAME@232..240 "location"
+ WHITESPACE@240..245 " "
+ EQ@245..246 "="
+ WHITESPACE@246..247 " "
+ CURLY_GROUP@247..263
+ L_CURLY@247..248 "{"
+ WORD@248..255 "Reading"
+ COMMA@255..256 ","
+ WHITESPACE@256..257 " "
+ WORD@257..262 "Mass."
+ R_CURLY@262..263 "}"
+ COMMA@263..264 ","
+ WHITESPACE@264..269 "\n "
+ FIELD@269..294
+ NAME@269..275 "langid"
+ WHITESPACE@275..282 " "
+ EQ@282..283 "="
+ WHITESPACE@283..284 " "
+ CURLY_GROUP@284..293
+ L_CURLY@284..285 "{"
+ WORD@285..292 "english"
+ R_CURLY@292..293 "}"
+ COMMA@293..294 ","
+ WHITESPACE@294..299 "\n "
+ FIELD@299..333
+ NAME@299..309 "langidopts"
+ WHITESPACE@309..312 " "
+ EQ@312..313 "="
+ WHITESPACE@313..314 " "
+ CURLY_GROUP@314..332
+ L_CURLY@314..315 "{"
+ WORD@315..331 "variant=american"
+ R_CURLY@331..332 "}"
+ COMMA@332..333 ","
+ WHITESPACE@333..338 "\n "
+ FIELD@338..381
+ NAME@338..347 "sorttitle"
+ WHITESPACE@347..351 " "
+ EQ@351..352 "="
+ WHITESPACE@352..353 " "
+ CURLY_GROUP@353..380
+ L_CURLY@353..354 "{"
+ WORD@354..363 "Computers"
+ WHITESPACE@363..364 " "
+ WORD@364..365 "&"
+ WHITESPACE@365..366 " "
+ WORD@366..377 "Typesetting"
+ WHITESPACE@377..378 " "
+ WORD@378..379 "A"
+ R_CURLY@379..380 "}"
+ COMMA@380..381 ","
+ WHITESPACE@381..386 "\n "
+ FIELD@386..416
+ NAME@386..400 "indexsorttitle"
+ EQ@400..401 "="
+ WHITESPACE@401..402 " "
+ CURLY_GROUP@402..415
+ L_CURLY@402..403 "{"
+ WORD@403..406 "The"
+ WHITESPACE@406..407 " "
+ WORD@407..414 "TeXbook"
+ R_CURLY@414..415 "}"
+ COMMA@415..416 ","
+ WHITESPACE@416..421 "\n "
+ FIELD@421..461
+ NAME@421..431 "indextitle"
+ WHITESPACE@431..434 " "
+ EQ@434..435 "="
+ WHITESPACE@435..436 " "
+ CURLY_GROUP@436..460
+ L_CURLY@436..437 "{"
+ COMMAND@437..445
+ COMMAND_NAME@437..445 "\\protect"
+ COMMAND@445..449
+ COMMAND_NAME@445..449 "\\TeX"
+ WHITESPACE@449..450 " "
+ WORD@450..454 "book"
+ COMMA@454..455 ","
+ WHITESPACE@455..456 " "
+ WORD@456..459 "The"
+ R_CURLY@459..460 "}"
+ COMMA@460..461 ","
+ WHITESPACE@461..466 "\n "
+ FIELD@466..493
+ NAME@466..476 "shorttitle"
+ WHITESPACE@476..479 " "
+ EQ@479..480 "="
+ WHITESPACE@480..481 " "
+ CURLY_GROUP@481..492
+ L_CURLY@481..482 "{"
+ COMMAND@482..486
+ COMMAND_NAME@482..486 "\\TeX"
+ WHITESPACE@486..487 " "
+ WORD@487..491 "book"
+ R_CURLY@491..492 "}"
+ COMMA@492..493 ","
+ WHITESPACE@493..498 "\n "
+ FIELD@498..991
+ NAME@498..508 "annotation"
+ WHITESPACE@508..511 " "
+ EQ@511..512 "="
+ WHITESPACE@512..513 " "
+ CURLY_GROUP@513..990
+ L_CURLY@513..514 "{"
+ WORD@514..517 "The"
+ WHITESPACE@517..518 " "
+ WORD@518..523 "first"
+ WHITESPACE@523..524 " "
+ WORD@524..530 "volume"
+ WHITESPACE@530..531 " "
+ WORD@531..533 "of"
+ WHITESPACE@533..534 " "
+ WORD@534..535 "a"
+ WHITESPACE@535..536 " "
+ WORD@536..547 "five-volume"
+ WHITESPACE@547..548 " "
+ WORD@548..553 "book."
+ WHITESPACE@553..554 " "
+ WORD@554..558 "Note"
+ WHITESPACE@558..559 " "
+ WORD@559..562 "the"
+ WHITESPACE@562..583 "\n "
+ COMMAND@583..590
+ COMMAND_NAME@583..590 "\\texttt"
+ CURLY_GROUP@590..601
+ L_CURLY@590..591 "{"
+ WORD@591..600 "sorttitle"
+ R_CURLY@600..601 "}"
+ WHITESPACE@601..602 " "
+ WORD@602..608 "field."
+ WHITESPACE@608..609 " "
+ WORD@609..611 "We"
+ WHITESPACE@611..612 " "
+ WORD@612..616 "want"
+ WHITESPACE@616..617 " "
+ WORD@617..621 "this"
+ WHITESPACE@621..642 "\n "
+ WORD@642..648 "volume"
+ WHITESPACE@648..649 " "
+ WORD@649..651 "to"
+ WHITESPACE@651..652 " "
+ WORD@652..654 "be"
+ WHITESPACE@654..655 " "
+ WORD@655..661 "listed"
+ WHITESPACE@661..662 " "
+ WORD@662..667 "after"
+ WHITESPACE@667..668 " "
+ WORD@668..671 "the"
+ WHITESPACE@671..672 " "
+ WORD@672..677 "entry"
+ WHITESPACE@677..678 " "
+ WORD@678..687 "referring"
+ WHITESPACE@687..688 " "
+ WORD@688..690 "to"
+ WHITESPACE@690..691 " "
+ WORD@691..694 "the"
+ WHITESPACE@694..695 " "
+ WORD@695..701 "entire"
+ WHITESPACE@701..722 "\n "
+ WORD@722..733 "five-volume"
+ WHITESPACE@733..734 " "
+ WORD@734..738 "set."
+ WHITESPACE@738..739 " "
+ WORD@739..743 "Also"
+ WHITESPACE@743..744 " "
+ WORD@744..748 "note"
+ WHITESPACE@748..749 " "
+ WORD@749..752 "the"
+ WHITESPACE@752..753 " "
+ COMMAND@753..760
+ COMMAND_NAME@753..760 "\\texttt"
+ CURLY_GROUP@760..772
+ L_CURLY@760..761 "{"
+ WORD@761..771 "indextitle"
+ R_CURLY@771..772 "}"
+ WHITESPACE@772..773 " "
+ WORD@773..776 "and"
+ WHITESPACE@776..797 "\n "
+ COMMAND@797..804
+ COMMAND_NAME@797..804 "\\texttt"
+ CURLY_GROUP@804..820
+ L_CURLY@804..805 "{"
+ WORD@805..819 "indexsorttitle"
+ R_CURLY@819..820 "}"
+ WHITESPACE@820..821 " "
+ WORD@821..828 "fields."
+ WHITESPACE@828..829 " "
+ WORD@829..837 "Indexing"
+ WHITESPACE@837..838 " "
+ WORD@838..846 "packages"
+ WHITESPACE@846..847 " "
+ WORD@847..851 "that"
+ WHITESPACE@851..852 " "
+ WORD@852..857 "don't"
+ WHITESPACE@857..878 "\n "
+ WORD@878..886 "generate"
+ WHITESPACE@886..887 " "
+ WORD@887..893 "robust"
+ WHITESPACE@893..894 " "
+ WORD@894..899 "index"
+ WHITESPACE@899..900 " "
+ WORD@900..907 "entries"
+ WHITESPACE@907..908 " "
+ WORD@908..915 "require"
+ WHITESPACE@915..916 " "
+ WORD@916..920 "some"
+ WHITESPACE@920..921 " "
+ WORD@921..928 "control"
+ WHITESPACE@928..929 " "
+ WORD@929..938 "sequences"
+ WHITESPACE@938..959 "\n "
+ WORD@959..961 "to"
+ WHITESPACE@961..962 " "
+ WORD@962..964 "be"
+ WHITESPACE@964..965 " "
+ WORD@965..974 "protected"
+ WHITESPACE@974..975 " "
+ WORD@975..979 "from"
+ WHITESPACE@979..980 " "
+ WORD@980..989 "expansion"
+ R_CURLY@989..990 "}"
+ COMMA@990..991 ","
+ WHITESPACE@991..992 "\n"
+ R_DELIM@992..993 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__matuz_1990.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__matuz_1990.txt.snap
new file mode 100644
index 0000000000..1e2b67f36c
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__matuz_1990.txt.snap
@@ -0,0 +1,176 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/matuz_1990.txt
+---
+ROOT@0..517
+ ENTRY@0..517
+ TYPE@0..11 "@collection"
+ L_DELIM@11..12 "{"
+ NAME@12..23 "matuz:doody"
+ COMMA@23..24 ","
+ WHITESPACE@24..29 "\n "
+ FIELD@29..59
+ NAME@29..35 "editor"
+ WHITESPACE@35..42 " "
+ EQ@42..43 "="
+ WHITESPACE@43..44 " "
+ CURLY_GROUP@44..58
+ L_CURLY@44..45 "{"
+ WORD@45..50 "Matuz"
+ COMMA@50..51 ","
+ WHITESPACE@51..52 " "
+ WORD@52..57 "Roger"
+ R_CURLY@57..58 "}"
+ COMMA@58..59 ","
+ WHITESPACE@59..64 "\n "
+ FIELD@64..113
+ NAME@64..69 "title"
+ WHITESPACE@69..77 " "
+ EQ@77..78 "="
+ WHITESPACE@78..79 " "
+ CURLY_GROUP@79..112
+ L_CURLY@79..80 "{"
+ WORD@80..92 "Contemporary"
+ WHITESPACE@92..93 " "
+ WORD@93..101 "Literary"
+ WHITESPACE@101..102 " "
+ WORD@102..111 "Criticism"
+ R_CURLY@111..112 "}"
+ COMMA@112..113 ","
+ WHITESPACE@113..118 "\n "
+ FIELD@118..138
+ NAME@118..122 "year"
+ WHITESPACE@122..131 " "
+ EQ@131..132 "="
+ WHITESPACE@132..133 " "
+ LITERAL@133..137
+ INTEGER@133..137 "1990"
+ COMMA@137..138 ","
+ WHITESPACE@138..143 "\n "
+ FIELD@143..161
+ NAME@143..149 "volume"
+ WHITESPACE@149..156 " "
+ EQ@156..157 "="
+ WHITESPACE@157..158 " "
+ LITERAL@158..160
+ INTEGER@158..160 "61"
+ COMMA@160..161 ","
+ WHITESPACE@161..166 "\n "
+ FIELD@166..188
+ NAME@166..175 "publisher"
+ WHITESPACE@175..179 " "
+ EQ@179..180 "="
+ WHITESPACE@180..181 " "
+ CURLY_GROUP@181..187
+ L_CURLY@181..182 "{"
+ WORD@182..186 "Gale"
+ R_CURLY@186..187 "}"
+ COMMA@187..188 ","
+ WHITESPACE@188..193 "\n "
+ FIELD@193..218
+ NAME@193..201 "location"
+ WHITESPACE@201..206 " "
+ EQ@206..207 "="
+ WHITESPACE@207..208 " "
+ CURLY_GROUP@208..217
+ L_CURLY@208..209 "{"
+ WORD@209..216 "Detroit"
+ R_CURLY@216..217 "}"
+ COMMA@217..218 ","
+ WHITESPACE@218..223 "\n "
+ FIELD@223..248
+ NAME@223..228 "pages"
+ WHITESPACE@228..236 " "
+ EQ@236..237 "="
+ WHITESPACE@237..238 " "
+ CURLY_GROUP@238..247
+ L_CURLY@238..239 "{"
+ WORD@239..246 "204-208"
+ R_CURLY@246..247 "}"
+ COMMA@247..248 ","
+ WHITESPACE@248..253 "\n "
+ FIELD@253..278
+ NAME@253..259 "langid"
+ WHITESPACE@259..266 " "
+ EQ@266..267 "="
+ WHITESPACE@267..268 " "
+ CURLY_GROUP@268..277
+ L_CURLY@268..269 "{"
+ WORD@269..276 "english"
+ R_CURLY@276..277 "}"
+ COMMA@277..278 ","
+ WHITESPACE@278..283 "\n "
+ FIELD@283..317
+ NAME@283..293 "langidopts"
+ WHITESPACE@293..296 " "
+ EQ@296..297 "="
+ WHITESPACE@297..298 " "
+ CURLY_GROUP@298..316
+ L_CURLY@298..299 "{"
+ WORD@299..315 "variant=american"
+ R_CURLY@315..316 "}"
+ COMMA@316..317 ","
+ WHITESPACE@317..322 "\n "
+ FIELD@322..515
+ NAME@322..332 "annotation"
+ WHITESPACE@332..335 " "
+ EQ@335..336 "="
+ WHITESPACE@336..337 " "
+ CURLY_GROUP@337..514
+ L_CURLY@337..338 "{"
+ WORD@338..339 "A"
+ WHITESPACE@339..340 " "
+ COMMAND@340..347
+ COMMAND_NAME@340..347 "\\texttt"
+ CURLY_GROUP@347..359
+ L_CURLY@347..348 "{"
+ WORD@348..358 "collection"
+ R_CURLY@358..359 "}"
+ WHITESPACE@359..360 " "
+ WORD@360..365 "entry"
+ WHITESPACE@365..366 " "
+ WORD@366..375 "providing"
+ WHITESPACE@375..376 " "
+ WORD@376..379 "the"
+ WHITESPACE@379..380 " "
+ WORD@380..387 "excerpt"
+ WHITESPACE@387..388 " "
+ WORD@388..399 "information"
+ WHITESPACE@399..420 "\n "
+ WORD@420..423 "for"
+ WHITESPACE@423..424 " "
+ WORD@424..427 "the"
+ WHITESPACE@427..428 " "
+ COMMAND@428..435
+ COMMAND_NAME@428..435 "\\texttt"
+ CURLY_GROUP@435..442
+ L_CURLY@435..436 "{"
+ WORD@436..441 "doody"
+ R_CURLY@441..442 "}"
+ WHITESPACE@442..443 " "
+ WORD@443..449 "entry."
+ WHITESPACE@449..450 " "
+ WORD@450..454 "Note"
+ WHITESPACE@454..455 " "
+ WORD@455..458 "the"
+ WHITESPACE@458..459 " "
+ WORD@459..465 "format"
+ WHITESPACE@465..466 " "
+ WORD@466..468 "of"
+ WHITESPACE@468..469 " "
+ WORD@469..472 "the"
+ WHITESPACE@472..493 "\n "
+ COMMAND@493..500
+ COMMAND_NAME@493..500 "\\texttt"
+ CURLY_GROUP@500..507
+ L_CURLY@500..501 "{"
+ WORD@501..506 "pages"
+ R_CURLY@506..507 "}"
+ WHITESPACE@507..508 " "
+ WORD@508..513 "field"
+ R_CURLY@513..514 "}"
+ COMMA@514..515 ","
+ WHITESPACE@515..516 "\n"
+ R_DELIM@516..517 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__nietzsche_1998.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__nietzsche_1998.txt.snap
new file mode 100644
index 0000000000..40d1f230af
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__nietzsche_1998.txt.snap
@@ -0,0 +1,368 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/nietzsche_1998.txt
+---
+ROOT@0..1112
+ STRING@0..49
+ TYPE@0..7 "@string"
+ L_DELIM@7..8 "{"
+ NAME@8..11 "dtv"
+ WHITESPACE@11..16 " "
+ EQ@16..17 "="
+ WHITESPACE@17..18 " "
+ CURLY_GROUP@18..48
+ L_CURLY@18..19 "{"
+ WORD@19..28 "Deutscher"
+ WHITESPACE@28..29 " "
+ WORD@29..47 "Taschenbuch-Verlag"
+ R_CURLY@47..48 "}"
+ R_DELIM@48..49 "}"
+ JUNK@49..51 "\n\n"
+ ENTRY@51..1112
+ TYPE@51..58 "@mvbook"
+ L_DELIM@58..59 "{"
+ NAME@59..72 "nietzsche:ksa"
+ COMMA@72..73 ","
+ WHITESPACE@73..78 "\n "
+ FIELD@78..116
+ NAME@78..84 "author"
+ WHITESPACE@84..91 " "
+ EQ@91..92 "="
+ WHITESPACE@92..93 " "
+ CURLY_GROUP@93..115
+ L_CURLY@93..94 "{"
+ WORD@94..103 "Nietzsche"
+ COMMA@103..104 ","
+ WHITESPACE@104..105 " "
+ WORD@105..114 "Friedrich"
+ R_CURLY@114..115 "}"
+ COMMA@115..116 ","
+ WHITESPACE@116..121 "\n "
+ FIELD@121..158
+ NAME@121..126 "title"
+ WHITESPACE@126..134 " "
+ EQ@134..135 "="
+ WHITESPACE@135..136 " "
+ CURLY_GROUP@136..157
+ L_CURLY@136..137 "{"
+ WORD@137..138 "S"
+ CURLY_GROUP@138..143
+ L_CURLY@138..139 "{"
+ ACCENT@139..142
+ ACCENT_NAME@139..141 "\\\""
+ WORD@141..142 "a"
+ R_CURLY@142..143 "}"
+ WORD@143..150 "mtliche"
+ WHITESPACE@150..151 " "
+ WORD@151..156 "Werke"
+ R_CURLY@156..157 "}"
+ COMMA@157..158 ","
+ WHITESPACE@158..163 "\n "
+ FIELD@163..183
+ NAME@163..167 "date"
+ WHITESPACE@167..176 " "
+ EQ@176..177 "="
+ WHITESPACE@177..178 " "
+ LITERAL@178..182
+ INTEGER@178..182 "1988"
+ COMMA@182..183 ","
+ WHITESPACE@183..188 "\n "
+ FIELD@188..243
+ NAME@188..194 "editor"
+ WHITESPACE@194..201 " "
+ EQ@201..202 "="
+ WHITESPACE@202..203 " "
+ CURLY_GROUP@203..242
+ L_CURLY@203..204 "{"
+ WORD@204..209 "Colli"
+ COMMA@209..210 ","
+ WHITESPACE@210..211 " "
+ WORD@211..218 "Giorgio"
+ WHITESPACE@218..219 " "
+ WORD@219..222 "and"
+ WHITESPACE@222..223 " "
+ WORD@223..232 "Montinari"
+ COMMA@232..233 ","
+ WHITESPACE@233..234 " "
+ WORD@234..241 "Mazzino"
+ R_CURLY@241..242 "}"
+ COMMA@242..243 ","
+ WHITESPACE@243..248 "\n "
+ FIELD@248..265
+ NAME@248..255 "edition"
+ WHITESPACE@255..261 " "
+ EQ@261..262 "="
+ WHITESPACE@262..263 " "
+ LITERAL@263..264
+ INTEGER@263..264 "2"
+ COMMA@264..265 ","
+ WHITESPACE@265..270 "\n "
+ FIELD@270..288
+ NAME@270..277 "volumes"
+ WHITESPACE@277..283 " "
+ EQ@283..284 "="
+ WHITESPACE@284..285 " "
+ LITERAL@285..287
+ INTEGER@285..287 "15"
+ COMMA@287..288 ","
+ WHITESPACE@288..293 "\n "
+ FIELD@293..339
+ NAME@293..302 "publisher"
+ WHITESPACE@302..306 " "
+ EQ@306..307 "="
+ WHITESPACE@307..308 " "
+ JOIN@308..338
+ LITERAL@308..311
+ NAME@308..311 "dtv"
+ WHITESPACE@311..312 " "
+ POUND@312..313 "#"
+ WHITESPACE@313..314 " "
+ CURLY_GROUP@314..338
+ L_CURLY@314..315 "{"
+ WHITESPACE@315..316 " "
+ WORD@316..319 "and"
+ WHITESPACE@319..320 " "
+ WORD@320..326 "Walter"
+ WHITESPACE@326..327 " "
+ WORD@327..329 "de"
+ WHITESPACE@329..330 " "
+ WORD@330..337 "Gruyter"
+ R_CURLY@337..338 "}"
+ COMMA@338..339 ","
+ WHITESPACE@339..344 "\n "
+ FIELD@344..397
+ NAME@344..352 "location"
+ WHITESPACE@352..357 " "
+ EQ@357..358 "="
+ WHITESPACE@358..359 " "
+ CURLY_GROUP@359..396
+ L_CURLY@359..360 "{"
+ WORD@360..361 "M"
+ CURLY_GROUP@361..366
+ L_CURLY@361..362 "{"
+ ACCENT@362..365
+ ACCENT_NAME@362..364 "\\\""
+ WORD@364..365 "u"
+ R_CURLY@365..366 "}"
+ WORD@366..371 "nchen"
+ WHITESPACE@371..372 " "
+ WORD@372..375 "and"
+ WHITESPACE@375..376 " "
+ WORD@376..382 "Berlin"
+ WHITESPACE@382..383 " "
+ WORD@383..386 "and"
+ WHITESPACE@386..387 " "
+ WORD@387..390 "New"
+ WHITESPACE@390..391 " "
+ WORD@391..395 "York"
+ R_CURLY@395..396 "}"
+ COMMA@396..397 ","
+ WHITESPACE@397..402 "\n "
+ FIELD@402..426
+ NAME@402..408 "langid"
+ WHITESPACE@408..415 " "
+ EQ@415..416 "="
+ WHITESPACE@416..417 " "
+ CURLY_GROUP@417..425
+ L_CURLY@417..418 "{"
+ WORD@418..424 "german"
+ R_CURLY@424..425 "}"
+ COMMA@425..426 ","
+ WHITESPACE@426..431 "\n "
+ FIELD@431..461
+ NAME@431..440 "sorttitle"
+ WHITESPACE@440..444 " "
+ EQ@444..445 "="
+ WHITESPACE@445..446 " "
+ CURLY_GROUP@446..460
+ L_CURLY@446..447 "{"
+ WORD@447..459 "Werke-00-000"
+ R_CURLY@459..460 "}"
+ COMMA@460..461 ","
+ WHITESPACE@461..466 "\n "
+ FIELD@466..500
+ NAME@466..480 "indexsorttitle"
+ EQ@480..481 "="
+ WHITESPACE@481..482 " "
+ CURLY_GROUP@482..499
+ L_CURLY@482..483 "{"
+ WORD@483..492 "Samtliche"
+ WHITESPACE@492..493 " "
+ WORD@493..498 "Werke"
+ R_CURLY@498..499 "}"
+ COMMA@499..500 ","
+ WHITESPACE@500..505 "\n "
+ FIELD@505..547
+ NAME@505..513 "subtitle"
+ WHITESPACE@513..518 " "
+ EQ@518..519 "="
+ WHITESPACE@519..520 " "
+ CURLY_GROUP@520..546
+ L_CURLY@520..521 "{"
+ WORD@521..530 "Kritische"
+ WHITESPACE@530..531 " "
+ WORD@531..545 "Studienausgabe"
+ R_CURLY@545..546 "}"
+ COMMA@546..547 ","
+ WHITESPACE@547..552 "\n "
+ FIELD@552..1110
+ NAME@552..562 "annotation"
+ WHITESPACE@562..565 " "
+ EQ@565..566 "="
+ WHITESPACE@566..567 " "
+ CURLY_GROUP@567..1109
+ L_CURLY@567..568 "{"
+ WORD@568..571 "The"
+ WHITESPACE@571..572 " "
+ WORD@572..580 "critical"
+ WHITESPACE@580..581 " "
+ WORD@581..588 "edition"
+ WHITESPACE@588..589 " "
+ WORD@589..591 "of"
+ WHITESPACE@591..592 " "
+ WORD@592..603 "Nietzsche's"
+ WHITESPACE@603..604 " "
+ WORD@604..610 "works."
+ WHITESPACE@610..611 " "
+ WORD@611..615 "This"
+ WHITESPACE@615..616 " "
+ WORD@616..618 "is"
+ WHITESPACE@618..619 " "
+ WORD@619..620 "a"
+ WHITESPACE@620..641 "\n "
+ COMMAND@641..648
+ COMMAND_NAME@641..648 "\\texttt"
+ CURLY_GROUP@648..656
+ L_CURLY@648..649 "{"
+ WORD@649..655 "mvbook"
+ R_CURLY@655..656 "}"
+ WHITESPACE@656..657 " "
+ WORD@657..662 "entry"
+ WHITESPACE@662..663 " "
+ WORD@663..672 "referring"
+ WHITESPACE@672..673 " "
+ WORD@673..675 "to"
+ WHITESPACE@675..676 " "
+ WORD@676..677 "a"
+ WHITESPACE@677..678 " "
+ WORD@678..687 "15-volume"
+ WHITESPACE@687..688 " "
+ WORD@688..692 "work"
+ WHITESPACE@692..693 " "
+ WORD@693..695 "as"
+ WHITESPACE@695..696 " "
+ WORD@696..697 "a"
+ WHITESPACE@697..718 "\n "
+ WORD@718..724 "whole."
+ WHITESPACE@724..725 " "
+ WORD@725..729 "Note"
+ WHITESPACE@729..730 " "
+ WORD@730..733 "the"
+ WHITESPACE@733..734 " "
+ COMMAND@734..741
+ COMMAND_NAME@734..741 "\\texttt"
+ CURLY_GROUP@741..750
+ L_CURLY@741..742 "{"
+ WORD@742..749 "volumes"
+ R_CURLY@749..750 "}"
+ WHITESPACE@750..751 " "
+ WORD@751..756 "field"
+ WHITESPACE@756..757 " "
+ WORD@757..760 "and"
+ WHITESPACE@760..761 " "
+ WORD@761..764 "the"
+ WHITESPACE@764..765 " "
+ WORD@765..771 "format"
+ WHITESPACE@771..772 " "
+ WORD@772..774 "of"
+ WHITESPACE@774..775 " "
+ WORD@775..778 "the"
+ WHITESPACE@778..799 "\n "
+ COMMAND@799..806
+ COMMAND_NAME@799..806 "\\texttt"
+ CURLY_GROUP@806..817
+ L_CURLY@806..807 "{"
+ WORD@807..816 "publisher"
+ R_CURLY@816..817 "}"
+ WHITESPACE@817..818 " "
+ WORD@818..821 "and"
+ WHITESPACE@821..822 " "
+ COMMAND@822..829
+ COMMAND_NAME@822..829 "\\texttt"
+ CURLY_GROUP@829..839
+ L_CURLY@829..830 "{"
+ WORD@830..838 "location"
+ R_CURLY@838..839 "}"
+ WHITESPACE@839..840 " "
+ WORD@840..846 "fields"
+ WHITESPACE@846..847 " "
+ WORD@847..849 "in"
+ WHITESPACE@849..850 " "
+ WORD@850..853 "the"
+ WHITESPACE@853..874 "\n "
+ WORD@874..882 "database"
+ WHITESPACE@882..883 " "
+ WORD@883..888 "file."
+ WHITESPACE@888..889 " "
+ WORD@889..893 "Also"
+ WHITESPACE@893..894 " "
+ WORD@894..898 "note"
+ WHITESPACE@898..899 " "
+ WORD@899..902 "the"
+ WHITESPACE@902..903 " "
+ COMMAND@903..910
+ COMMAND_NAME@903..910 "\\texttt"
+ CURLY_GROUP@910..921
+ L_CURLY@910..911 "{"
+ WORD@911..920 "sorttitle"
+ R_CURLY@920..921 "}"
+ WHITESPACE@921..922 " "
+ WORD@922..925 "and"
+ WHITESPACE@925..946 "\n "
+ WORD@946..951 "field"
+ WHITESPACE@951..952 " "
+ WORD@952..957 "which"
+ WHITESPACE@957..958 " "
+ WORD@958..960 "is"
+ WHITESPACE@960..961 " "
+ WORD@961..965 "used"
+ WHITESPACE@965..966 " "
+ WORD@966..968 "to"
+ WHITESPACE@968..969 " "
+ WORD@969..978 "fine-tune"
+ WHITESPACE@978..979 " "
+ WORD@979..982 "the"
+ WHITESPACE@982..1003 "\n "
+ WORD@1003..1010 "sorting"
+ WHITESPACE@1010..1011 " "
+ WORD@1011..1016 "order"
+ WHITESPACE@1016..1017 " "
+ WORD@1017..1019 "of"
+ WHITESPACE@1019..1020 " "
+ WORD@1020..1023 "the"
+ WHITESPACE@1023..1024 " "
+ WORD@1024..1037 "bibliography."
+ WHITESPACE@1037..1038 " "
+ WORD@1038..1040 "We"
+ WHITESPACE@1040..1041 " "
+ WORD@1041..1045 "want"
+ WHITESPACE@1045..1046 " "
+ WORD@1046..1050 "this"
+ WHITESPACE@1050..1051 " "
+ WORD@1051..1055 "item"
+ WHITESPACE@1055..1056 " "
+ WORD@1056..1062 "listed"
+ WHITESPACE@1062..1083 "\n "
+ WORD@1083..1088 "first"
+ WHITESPACE@1088..1089 " "
+ WORD@1089..1091 "in"
+ WHITESPACE@1091..1092 " "
+ WORD@1092..1095 "the"
+ WHITESPACE@1095..1096 " "
+ WORD@1096..1108 "bibliography"
+ R_CURLY@1108..1109 "}"
+ COMMA@1109..1110 ","
+ WHITESPACE@1110..1111 "\n"
+ R_DELIM@1111..1112 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__rivest_1978.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__rivest_1978.txt.snap
new file mode 100644
index 0000000000..b296d9cd4b
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__bibtex__tests__parse@samples__rivest_1978.txt.snap
@@ -0,0 +1,232 @@
+---
+source: src/parser/bibtex.rs
+expression: root
+input_file: src/parser/test_data/bibtex/samples/rivest_1978.txt
+---
+ROOT@0..557
+ ENTRY@0..557
+ TYPE@0..8 "@article"
+ L_DELIM@8..9 "{"
+ NAME@9..30 "10.1145/359340.359342"
+ COMMA@30..31 ","
+ WHITESPACE@31..36 "\n "
+ FIELD@36..92
+ NAME@36..42 "author"
+ WHITESPACE@42..43 " "
+ EQ@43..44 "="
+ WHITESPACE@44..45 " "
+ CURLY_GROUP@45..91
+ L_CURLY@45..46 "{"
+ WORD@46..52 "Rivest"
+ COMMA@52..53 ","
+ WHITESPACE@53..54 " "
+ WORD@54..56 "R."
+ WHITESPACE@56..57 " "
+ WORD@57..59 "L."
+ WHITESPACE@59..60 " "
+ WORD@60..63 "and"
+ WHITESPACE@63..64 " "
+ WORD@64..70 "Shamir"
+ COMMA@70..71 ","
+ WHITESPACE@71..72 " "
+ WORD@72..74 "A."
+ WHITESPACE@74..75 " "
+ WORD@75..78 "and"
+ WHITESPACE@78..79 " "
+ WORD@79..86 "Adleman"
+ COMMA@86..87 ","
+ WHITESPACE@87..88 " "
+ WORD@88..90 "L."
+ R_CURLY@90..91 "}"
+ COMMA@91..92 ","
+ WHITESPACE@92..97 "\n "
+ FIELD@97..178
+ NAME@97..102 "title"
+ WHITESPACE@102..103 " "
+ EQ@103..104 "="
+ WHITESPACE@104..105 " "
+ CURLY_GROUP@105..177
+ L_CURLY@105..106 "{"
+ WORD@106..107 "A"
+ WHITESPACE@107..108 " "
+ WORD@108..114 "Method"
+ WHITESPACE@114..115 " "
+ WORD@115..118 "for"
+ WHITESPACE@118..119 " "
+ WORD@119..128 "Obtaining"
+ WHITESPACE@128..129 " "
+ WORD@129..136 "Digital"
+ WHITESPACE@136..137 " "
+ WORD@137..147 "Signatures"
+ WHITESPACE@147..148 " "
+ WORD@148..151 "and"
+ WHITESPACE@151..152 " "
+ WORD@152..162 "Public-Key"
+ WHITESPACE@162..163 " "
+ WORD@163..176 "Cryptosystems"
+ R_CURLY@176..177 "}"
+ COMMA@177..178 ","
+ WHITESPACE@178..183 "\n "
+ FIELD@183..197
+ NAME@183..187 "year"
+ WHITESPACE@187..188 " "
+ EQ@188..189 "="
+ WHITESPACE@189..190 " "
+ CURLY_GROUP@190..196
+ L_CURLY@190..191 "{"
+ INTEGER@191..195 "1978"
+ R_CURLY@195..196 "}"
+ COMMA@196..197 ","
+ WHITESPACE@197..202 "\n "
+ FIELD@202..227
+ NAME@202..212 "issue_date"
+ WHITESPACE@212..213 " "
+ EQ@213..214 "="
+ WHITESPACE@214..215 " "
+ CURLY_GROUP@215..226
+ L_CURLY@215..216 "{"
+ WORD@216..220 "Feb."
+ WHITESPACE@220..221 " "
+ INTEGER@221..225 "1978"
+ R_CURLY@225..226 "}"
+ COMMA@226..227 ","
+ WHITESPACE@227..232 "\n "
+ FIELD@232..282
+ NAME@232..241 "publisher"
+ WHITESPACE@241..242 " "
+ EQ@242..243 "="
+ WHITESPACE@243..244 " "
+ CURLY_GROUP@244..281
+ L_CURLY@244..245 "{"
+ WORD@245..256 "Association"
+ WHITESPACE@256..257 " "
+ WORD@257..260 "for"
+ WHITESPACE@260..261 " "
+ WORD@261..270 "Computing"
+ WHITESPACE@270..271 " "
+ WORD@271..280 "Machinery"
+ R_CURLY@280..281 "}"
+ COMMA@281..282 ","
+ WHITESPACE@282..287 "\n "
+ FIELD@287..317
+ NAME@287..294 "address"
+ WHITESPACE@294..295 " "
+ EQ@295..296 "="
+ WHITESPACE@296..297 " "
+ CURLY_GROUP@297..316
+ L_CURLY@297..298 "{"
+ WORD@298..301 "New"
+ WHITESPACE@301..302 " "
+ WORD@302..306 "York"
+ COMMA@306..307 ","
+ WHITESPACE@307..308 " "
+ WORD@308..310 "NY"
+ COMMA@310..311 ","
+ WHITESPACE@311..312 " "
+ WORD@312..315 "USA"
+ R_CURLY@315..316 "}"
+ COMMA@316..317 ","
+ WHITESPACE@317..322 "\n "
+ FIELD@322..336
+ NAME@322..328 "volume"
+ WHITESPACE@328..329 " "
+ EQ@329..330 "="
+ WHITESPACE@330..331 " "
+ CURLY_GROUP@331..335
+ L_CURLY@331..332 "{"
+ INTEGER@332..334 "21"
+ R_CURLY@334..335 "}"
+ COMMA@335..336 ","
+ WHITESPACE@336..341 "\n "
+ FIELD@341..354
+ NAME@341..347 "number"
+ WHITESPACE@347..348 " "
+ EQ@348..349 "="
+ WHITESPACE@349..350 " "
+ CURLY_GROUP@350..353
+ L_CURLY@350..351 "{"
+ INTEGER@351..352 "2"
+ R_CURLY@352..353 "}"
+ COMMA@353..354 ","
+ WHITESPACE@354..359 "\n "
+ FIELD@359..378
+ NAME@359..363 "issn"
+ WHITESPACE@363..364 " "
+ EQ@364..365 "="
+ WHITESPACE@365..366 " "
+ CURLY_GROUP@366..377
+ L_CURLY@366..367 "{"
+ WORD@367..376 "0001-0782"
+ R_CURLY@376..377 "}"
+ COMMA@377..378 ","
+ WHITESPACE@378..383 "\n "
+ FIELD@383..429
+ NAME@383..386 "url"
+ WHITESPACE@386..387 " "
+ EQ@387..388 "="
+ WHITESPACE@388..389 " "
+ CURLY_GROUP@389..428
+ L_CURLY@389..390 "{"
+ WORD@390..427 "https://doi.org/10.11 ..."
+ R_CURLY@427..428 "}"
+ COMMA@428..429 ","
+ WHITESPACE@429..434 "\n "
+ FIELD@434..464
+ NAME@434..437 "doi"
+ WHITESPACE@437..438 " "
+ EQ@438..439 "="
+ WHITESPACE@439..440 " "
+ CURLY_GROUP@440..463
+ L_CURLY@440..441 "{"
+ WORD@441..462 "10.1145/359340.359342"
+ R_CURLY@462..463 "}"
+ COMMA@463..464 ","
+ WHITESPACE@464..469 "\n "
+ FIELD@469..493
+ NAME@469..476 "journal"
+ WHITESPACE@476..477 " "
+ EQ@477..478 "="
+ WHITESPACE@478..479 " "
+ CURLY_GROUP@479..492
+ L_CURLY@479..480 "{"
+ WORD@480..487 "Commun."
+ WHITESPACE@487..488 " "
+ WORD@488..491 "ACM"
+ R_CURLY@491..492 "}"
+ COMMA@492..493 ","
+ WHITESPACE@493..498 "\n "
+ FIELD@498..512
+ NAME@498..503 "month"
+ WHITESPACE@503..504 " "
+ EQ@504..505 "="
+ WHITESPACE@505..506 " "
+ CURLY_GROUP@506..511
+ L_CURLY@506..507 "{"
+ WORD@507..510 "feb"
+ R_CURLY@510..511 "}"
+ COMMA@511..512 ","
+ WHITESPACE@512..517 "\n "
+ FIELD@517..535
+ NAME@517..522 "pages"
+ WHITESPACE@522..523 " "
+ EQ@523..524 "="
+ WHITESPACE@524..525 " "
+ CURLY_GROUP@525..534
+ L_CURLY@525..526 "{"
+ WORD@526..533 "120-126"
+ R_CURLY@533..534 "}"
+ COMMA@534..535 ","
+ WHITESPACE@535..540 "\n "
+ FIELD@540..555
+ NAME@540..548 "numpages"
+ WHITESPACE@548..549 " "
+ EQ@549..550 "="
+ WHITESPACE@550..551 " "
+ CURLY_GROUP@551..554
+ L_CURLY@551..552 "{"
+ INTEGER@552..553 "7"
+ R_CURLY@553..554 "}"
+ COMMA@554..555 ","
+ WHITESPACE@555..556 "\n"
+ R_DELIM@556..557 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@001.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@001.txt.snap
new file mode 100644
index 0000000000..1d91ff7fff
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@001.txt.snap
@@ -0,0 +1,27 @@
+---
+source: src/parser/build_log.rs
+expression: parse_build_log(&text)
+input_file: src/parser/test_data/build_log/001.txt
+---
+BuildLog {
+ errors: [
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Warning,
+ message: "Overfull \\hbox (200.00162pt too wide) in paragraph at lines 8--9",
+ hint: None,
+ line: Some(
+ 7,
+ ),
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Warning,
+ message: "Overfull \\vbox (3.19998pt too high) detected at line 23",
+ hint: None,
+ line: Some(
+ 22,
+ ),
+ },
+ ],
+}
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@002.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@002.txt.snap
new file mode 100644
index 0000000000..91fa71d636
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@002.txt.snap
@@ -0,0 +1,20 @@
+---
+source: src/parser/build_log.rs
+expression: parse_build_log(&text)
+input_file: src/parser/test_data/build_log/002.txt
+---
+BuildLog {
+ errors: [
+ BuildError {
+ relative_path: "./child.tex",
+ level: Error,
+ message: "Undefined control sequence.",
+ hint: Some(
+ "\\foo",
+ ),
+ line: Some(
+ 0,
+ ),
+ },
+ ],
+}
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@003.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@003.txt.snap
new file mode 100644
index 0000000000..d2024a8cd3
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@003.txt.snap
@@ -0,0 +1,23 @@
+---
+source: src/parser/build_log.rs
+expression: parse_build_log(&text)
+input_file: src/parser/test_data/build_log/003.txt
+---
+BuildLog {
+ errors: [
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Warning,
+ message: "Citation `foo' on page 1 undefined on input line 6.",
+ hint: None,
+ line: None,
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Warning,
+ message: "There were undefined references.",
+ hint: None,
+ line: None,
+ },
+ ],
+}
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@004.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@004.txt.snap
new file mode 100644
index 0000000000..83219b5fff
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@004.txt.snap
@@ -0,0 +1,31 @@
+---
+source: src/parser/build_log.rs
+expression: parse_build_log(&text)
+input_file: src/parser/test_data/build_log/004.txt
+---
+BuildLog {
+ errors: [
+ BuildError {
+ relative_path: "/TexLive/texmf-dist/tex/generic/babel/babel.sty",
+ level: Error,
+ message: "Package babel Error: Unknown option `foo'. Either you misspelled it or the language definition file foo.ldf was not found.",
+ hint: Some(
+ "\\ProcessOptions*",
+ ),
+ line: Some(
+ 392,
+ ),
+ },
+ BuildError {
+ relative_path: "/TexLive/texmf-dist/tex/generic/babel/babel.sty",
+ level: Error,
+ message: "Package babel Error: You haven't specified a language option.",
+ hint: Some(
+ "ry to proceed from here, type x to quit.}",
+ ),
+ line: Some(
+ 425,
+ ),
+ },
+ ],
+}
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@005.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@005.txt.snap
new file mode 100644
index 0000000000..e4857d00d8
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@005.txt.snap
@@ -0,0 +1,30 @@
+---
+source: src/parser/build_log.rs
+expression: parse_build_log(&text)
+input_file: src/parser/test_data/build_log/005.txt
+---
+BuildLog {
+ errors: [
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Warning,
+ message: "'babel/polyglossia' detected but 'csquotes' missing. Loading 'csquotes' recommended.",
+ hint: None,
+ line: None,
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Warning,
+ message: "There were undefined references.",
+ hint: None,
+ line: None,
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Warning,
+ message: "Please (re)run Biber on the file: parent and rerun LaTeX afterwards.",
+ hint: None,
+ line: None,
+ },
+ ],
+}
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@006.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@006.txt.snap
new file mode 100644
index 0000000000..837aa9c295
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@006.txt.snap
@@ -0,0 +1,69 @@
+---
+source: src/parser/build_log.rs
+expression: parse_build_log(&text)
+input_file: src/parser/test_data/build_log/006.txt
+---
+BuildLog {
+ errors: [
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Error,
+ message: "Undefined control sequence.",
+ hint: Some(
+ "\\foo",
+ ),
+ line: Some(
+ 6,
+ ),
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Error,
+ message: "Missing $ inserted.",
+ hint: Some(
+ "\\bar",
+ ),
+ line: Some(
+ 7,
+ ),
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Error,
+ message: "Undefined control sequence.",
+ hint: Some(
+ "\\baz",
+ ),
+ line: Some(
+ 8,
+ ),
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Error,
+ message: "Missing { inserted.",
+ hint: None,
+ line: Some(
+ 9,
+ ),
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Error,
+ message: "Missing $ inserted.",
+ hint: None,
+ line: Some(
+ 9,
+ ),
+ },
+ BuildError {
+ relative_path: "./parent.tex",
+ level: Error,
+ message: "Missing } inserted.",
+ hint: None,
+ line: Some(
+ 9,
+ ),
+ },
+ ],
+}
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@007.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@007.txt.snap
new file mode 100644
index 0000000000..d509a01bd4
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__build_log__tests__parse@007.txt.snap
@@ -0,0 +1,19 @@
+---
+source: src/parser/build_log.rs
+expression: parse_build_log(&text)
+---
+BuildLog {
+ errors: [
+ BuildError {
+ relative_path: "/some/folder/a.tex",
+ level: Error,
+ message: "Undefined control sequence.",
+ hint: Some(
+ "\\lsdkfjlskdfj",
+ ),
+ line: Some(
+ 3,
+ ),
+ },
+ ],
+}
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__block_comments.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@block_comments.txt.snap
index 355a93ebad..14c73e7da5 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__block_comments.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@block_comments.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1814
-expression: "setup(r#\"Foo\n\\iffalse\nTest1\n\\fi\nBar\n\\iffalse\n\\fii\n\\fi\nBaz\"#)"
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/block_comments.txt
---
ROOT@0..48
PREAMBLE@0..48
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_default.txt.snap
index f598a8f7e9..33e119c524 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_default.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\caption[qux]{Foo \\Bar Baz}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/caption/caption_default.txt
---
ROOT@0..27
PREAMBLE@0..27
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_error.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_default_error.txt.snap
index 13697e882b..a016dcebed 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_error.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_default_error.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\caption[qux]{Foo \\Bar Baz\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/caption/caption_default_error.txt
---
ROOT@0..26
PREAMBLE@0..26
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_figure.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_figure.txt.snap
index b3bf7589d8..9303bd3ebe 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_figure.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_figure.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\begin{figure}\\caption{Foo}\\end{figure}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/caption/caption_figure.txt
---
ROOT@0..39
PREAMBLE@0..39
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_minimal.txt.snap
index bf9e795e18..6af368cc21 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_minimal.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\caption{Foo \\Bar Baz}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/caption/caption_minimal.txt
---
ROOT@0..22
PREAMBLE@0..22
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal_error.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_minimal_error.txt.snap
index 6c932ce883..68fc629613 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__caption_minimal_error.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@caption__caption_minimal_error.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\caption{Foo \\Bar Baz\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/caption/caption_minimal_error.txt
---
ROOT@0..21
PREAMBLE@0..21
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_empty.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_empty.txt.snap
index faad4c0039..fbf2b5123e 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_empty.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_empty.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\cite{}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/citation/citation_empty.txt
---
ROOT@0..7
PREAMBLE@0..7
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_missing_brace.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_missing_brace.txt.snap
index 61cd6d8f0b..72bd618594 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_missing_brace.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_missing_brace.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\cite{foo\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/citation/citation_missing_brace.txt
---
ROOT@0..9
PREAMBLE@0..9
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_multiple_keys.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_multiple_keys.txt.snap
index 7195e8992e..81716cf8b1 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_multiple_keys.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_multiple_keys.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\cite{foo, bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/citation/citation_multiple_keys.txt
---
ROOT@0..15
PREAMBLE@0..15
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_prenote.txt.snap
index b5d92886aa..f5afdca536 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_prenote.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\cite[foo]{bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/citation/citation_prenote.txt
---
ROOT@0..15
PREAMBLE@0..15
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote_postnote.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_prenote_postnote.txt.snap
index ba99b66e35..feecca0435 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_prenote_postnote.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_prenote_postnote.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\cite[foo][bar]{baz}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/citation/citation_prenote_postnote.txt
---
ROOT@0..20
PREAMBLE@0..20
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_redundant_comma.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_redundant_comma.txt.snap
index 9062479f7a..2a8acd1173 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_redundant_comma.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_redundant_comma.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\cite{,foo,}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/citation/citation_redundant_comma.txt
---
ROOT@0..12
PREAMBLE@0..12
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_simple.txt.snap
index 335b9d461c..faa2e07155 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\cite{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/citation/citation_simple.txt
---
ROOT@0..10
PREAMBLE@0..10
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_star.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_star.txt.snap
index e6d5dad128..3bcd74701c 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__citation_star.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@citation__citation_star.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\nocite{*}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/citation/citation_star.txt
---
ROOT@0..10
PREAMBLE@0..10
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_definition_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_definition_simple.txt.snap
index 64eee4351b..163ea09071 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_definition_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_definition_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\definecolor{foo}{rgb}{255,168,0}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/color/color_definition_simple.txt
---
ROOT@0..33
PREAMBLE@0..33
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_reference_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_reference_simple.txt.snap
index cb0ee151b9..0c68b5eae0 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_reference_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_reference_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\color{black}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/color/color_reference_simple.txt
---
ROOT@0..13
PREAMBLE@0..13
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error1.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error1.txt.snap
index 59688f0902..2e3be43ecb 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error1.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error1.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\definecolorset[ty]{rgb,HTML}{foo}{bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/color/color_set_definition_error1.txt
---
ROOT@0..39
PREAMBLE@0..39
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error2.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error2.txt.snap
index cbbeacb649..ee15174688 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error2.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error2.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\definecolorset{rgb,HTML}{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/color/color_set_definition_error2.txt
---
ROOT@0..30
PREAMBLE@0..30
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error3.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error3.txt.snap
index 826bea28b6..3416786dda 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error3.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error3.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\definecolorset{rgb,HTML}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/color/color_set_definition_error3.txt
---
ROOT@0..25
PREAMBLE@0..25
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error4.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error4.txt.snap
index 3cafa81bae..5c16d9d7a5 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_error4.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_error4.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\definecolorset\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/color/color_set_definition_error4.txt
---
ROOT@0..15
PREAMBLE@0..15
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_simple.txt.snap
index 9d32e127ef..a4cff9c7a1 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__color_set_definition_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@color__color_set_definition_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\definecolorset[ty]{rgb,HTML}{foo}{bar}{baz}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/color/color_set_definition_simple.txt
---
ROOT@0..44
PREAMBLE@0..44
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_argc.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_argc.txt.snap
index 2ff3896080..a10287b262 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_argc.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_argc.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newcommand{\\foo}{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/command_definition/command_definition_no_argc.txt
---
ROOT@0..22
PREAMBLE@0..22
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_impl.txt.snap
index 4602a7a688..ae9b54e0c8 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_impl.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newcommand{\\foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/command_definition/command_definition_no_impl.txt
---
ROOT@0..17
PREAMBLE@0..17
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl_error.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_impl_error.txt.snap
index 4a20be7d7c..2e1f2f2956 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_no_impl_error.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_no_impl_error.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newcommand{\\foo\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/command_definition/command_definition_no_impl_error.txt
---
ROOT@0..16
PREAMBLE@0..16
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_optional.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_optional.txt.snap
index 66c263e49a..fe1a3ad6ec 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_optional.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_optional.txt.snap
@@ -1,8 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1579
-expression: "setup(r#\"\\newcommand{\\foo}[1][def]{#1}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/command_definition/command_definition_optional.txt
---
ROOT@0..29
PREAMBLE@0..29
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_simple.txt.snap
index b6b8380155..422fdd0d5b 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newcommand[1]{\\id}{#1}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/command_definition/command_definition_simple.txt
---
ROOT@0..23
PREAMBLE@0..23
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_with_begin.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_with_begin.txt.snap
index 6b7724c0aa..9ee38a1796 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__command_definition_with_begin.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__command_definition_with_begin.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1723
-expression: "setup(r#\"\\newcommand{\\CVSubHeadingListStart}{\\begin{itemize}[leftmargin=0.5cm, label={}]}\"#)"
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/command_definition/command_definition_with_begin.txt
---
ROOT@0..80
PREAMBLE@0..80
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_no_impl.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__math_operator_no_impl.txt.snap
index 2e39ee899c..371d1272c4 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_no_impl.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__math_operator_no_impl.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\DeclareMathOperator{\\foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/command_definition/math_operator_no_impl.txt
---
ROOT@0..26
PREAMBLE@0..26
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__math_operator_simple.txt.snap
index bb44005153..004e6918e4 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__math_operator_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@command_definition__math_operator_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\DeclareMathOperator{\\foo}{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/command_definition/math_operator_simple.txt
---
ROOT@0..31
PREAMBLE@0..31
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__asymptote.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_asymptote.txt.snap
index a735d71e73..abbc71e6ed 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__asymptote.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_asymptote.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1829
-expression: "setup(r#\"\\begin{asy}\n printf(\"Hello World\\n\");\n\\end{asy}\"#)"
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/environment/environment_asymptote.txt
---
ROOT@0..50
PREAMBLE@0..50
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_definition.txt.snap
index 5d977db814..fb45f5d35b 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_definition.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1792
-expression: "setup(r#\"\\newenvironment{bar}[1]{\\begin{foo}}{\\end{foo}}\"#)"
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/environment/environment_definition.txt
---
ROOT@0..47
PREAMBLE@0..47
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition_optional_arg.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_definition_optional_arg.txt.snap
index 1a064fefe3..10009e851b 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_definition_optional_arg.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_definition_optional_arg.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1797
-expression: "setup(r#\"\\newenvironment{foo}[1][default]{begin}{end}\"#)"
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/environment/environment_definition_optional_arg.txt
---
ROOT@0..44
PREAMBLE@0..44
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_nested.txt.snap
index 3a65af3a2b..e3274ef70e 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_nested.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\begin{foo} \\begin{qux} \\end{baz} \\end{bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/environment/environment_nested.txt
---
ROOT@0..43
PREAMBLE@0..43
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested_missing_braces.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_nested_missing_braces.txt.snap
index 973e6e9a9f..698be0eae7 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_nested_missing_braces.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_nested_missing_braces.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\begin{foo \\begin{qux Hello World \\end{baz} \\end{bar\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/environment/environment_nested_missing_braces.txt
---
ROOT@0..52
PREAMBLE@0..52
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_simple.txt.snap
index b8b85f1348..db57d39580 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__environment_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@environment__environment_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\begin{foo} Hello World \\end{bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/environment/environment_simple.txt
---
ROOT@0..33
PREAMBLE@0..33
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@equation.txt.snap
index e146fcaee6..0974c69449 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@equation.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\[ foo bar \\]\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/equation.txt
---
ROOT@0..13
PREAMBLE@0..13
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_begin.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@equation_missing_begin.txt.snap
index 9a2af78417..c649fc6a6a 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_begin.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@equation_missing_begin.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\begin{a} foo bar \\] \\end{b}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/equation_missing_begin.txt
---
ROOT@0..28
PREAMBLE@0..28
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_args.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_args.txt.snap
index b62c8c2559..9fee38a855 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_args.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_args.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\foo{bar}[qux]\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/generic_command_args.txt
---
ROOT@0..14
PREAMBLE@0..14
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_empty.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_empty.txt.snap
new file mode 100644
index 0000000000..dcd2382d02
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_empty.txt.snap
@@ -0,0 +1,10 @@
+---
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/generic_command_empty.txt
+---
+ROOT@0..4
+ PREAMBLE@0..4
+ GENERIC_COMMAND@0..4
+ GENERIC_COMMAND_NAME@0..4 "\\foo"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_escape.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_escape.txt.snap
new file mode 100644
index 0000000000..d7d88a32ce
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@generic_command_escape.txt.snap
@@ -0,0 +1,10 @@
+---
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/generic_command_escape.txt
+---
+ROOT@0..2
+ PREAMBLE@0..2
+ GENERIC_COMMAND@0..2
+ GENERIC_COMMAND_NAME@0..2 "\\#"
+
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acronym_declaration.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_declaration.txt.snap
index a92180efb3..c1298e50fc 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acronym_declaration.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_declaration.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\DeclareAcronym{eg}{short = e.g,long = for example,tag = abbrev}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/acronym_declaration.txt
---
ROOT@0..64
PREAMBLE@0..64
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_definition_options.txt.snap
index 80043c18e7..eac9b6e3ba 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_definition_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/acronym_definition_options.txt
---
ROOT@0..76
PREAMBLE@0..76
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_definition_simple.txt.snap
index 74ae2219de..e6bfe2a9d5 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_definition_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_definition_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newacronym{fpsLabel}{FPS}{Frame per Second}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/acronym_definition_simple.txt
---
ROOT@0..44
PREAMBLE@0..44
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_package.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_package.txt.snap
new file mode 100644
index 0000000000..9babc04165
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_package.txt.snap
@@ -0,0 +1,30 @@
+---
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/acronym_package.txt
+---
+ROOT@0..35
+ PREAMBLE@0..35
+ ACRONYM_DEFINITION@0..35
+ ACRONYM_DEFINITION_NAME@0..5 "\\acro"
+ CURLY_GROUP_WORD@5..10
+ L_CURLY@5..6 "{"
+ KEY@6..9
+ WORD@6..9 "fps"
+ R_CURLY@9..10 "}"
+ BRACK_GROUP@10..15
+ L_BRACK@10..11 "["
+ TEXT@11..14
+ WORD@11..14 "FPS"
+ R_BRACK@14..15 "]"
+ CURLY_GROUP@15..35
+ L_CURLY@15..16 "{"
+ TEXT@16..33
+ WORD@16..22 "Frames"
+ WHITESPACE@22..23 " "
+ WORD@23..26 "per"
+ WHITESPACE@26..27 " "
+ WORD@27..33 "Second"
+ R_CURLY@33..34 "}"
+ LINE_BREAK@34..35 "\n"
+
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_reference_options.txt.snap
index 6a1c2cdcbe..99a8fbc562 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_reference_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\acrshort[foo=bar,baz]{fpsLabel}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/acronym_reference_options.txt
---
ROOT@0..32
PREAMBLE@0..32
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_reference_simple.txt.snap
index 9924c7175c..08effadf7e 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__acroynm_reference_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__acronym_reference_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\acrshort{fpsLabel}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/acronym_reference_simple.txt
---
ROOT@0..19
PREAMBLE@0..19
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_definition_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_definition_simple.txt.snap
index 519abf75e8..4ab51a0db3 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_definition_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_definition_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newglossaryentry{foo}{bar = baz, qux,}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/glossary_entry_definition_simple.txt
---
ROOT@0..39
PREAMBLE@0..39
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_reference_options.txt.snap
index 494c0be0a0..d97e984b77 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_reference_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\gls[foo = bar, qux]{baz}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/glossary_entry_reference_options.txt
---
ROOT@0..25
PREAMBLE@0..25
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_reference_simple.txt.snap
index 94af3796fc..8c8fb0c1e2 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__glossary_entry_reference_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@glossary__glossary_entry_reference_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\gls{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/glossary/glossary_entry_reference_simple.txt
---
ROOT@0..9
PREAMBLE@0..9
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path.txt.snap
new file mode 100644
index 0000000000..9067d36c7d
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path.txt.snap
@@ -0,0 +1,18 @@
+---
+source: src/parser/latex.rs
+assertion_line: 1361
+expression: root
+---
+ROOT@0..28
+ PREAMBLE@0..28
+ GRAPHICS_PATH@0..28
+ GRAPHICS_PATH_NAME@0..13 "\\graphicspath"
+ CURLY_GROUP@13..28
+ L_CURLY@13..14 "{"
+ CURLY_GROUP_WORD@14..27
+ L_CURLY@14..15 "{"
+ KEY@15..26
+ WORD@15..26 "../figures/"
+ R_CURLY@26..27 "}"
+ R_CURLY@27..28 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path_command.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path_command.txt.snap
new file mode 100644
index 0000000000..4092b2e8e9
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path_command.txt.snap
@@ -0,0 +1,23 @@
+---
+source: src/parser/latex.rs
+assertion_line: 1348
+expression: root
+---
+ROOT@0..32
+ PREAMBLE@0..32
+ GRAPHICS_PATH@0..32
+ GRAPHICS_PATH_NAME@0..13 "\\graphicspath"
+ CURLY_GROUP@13..32
+ L_CURLY@13..14 "{"
+ CURLY_GROUP_WORD@14..31
+ L_CURLY@14..15 "{"
+ KEY@15..30
+ GENERIC_COMMAND_NAME@15..22 "\\subfix"
+ CURLY_GROUP_WORD@22..30
+ L_CURLY@22..23 "{"
+ KEY@23..29
+ WORD@23..29 "./img/"
+ R_CURLY@29..30 "}"
+ R_CURLY@30..31 "}"
+ R_CURLY@31..32 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path_options.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path_options.txt.snap
new file mode 100644
index 0000000000..0eb034bbb3
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@graphics_path_options.txt.snap
@@ -0,0 +1,23 @@
+---
+source: src/parser/latex.rs
+assertion_line: 1348
+expression: root
+---
+ROOT@0..33
+ PREAMBLE@0..33
+ GRAPHICS_PATH@0..13
+ GRAPHICS_PATH_NAME@0..13 "\\graphicspath"
+ MIXED_GROUP@13..18
+ L_BRACK@13..14 "["
+ TEXT@14..17
+ WORD@14..17 "foo"
+ R_BRACK@17..18 "]"
+ CURLY_GROUP@18..33
+ L_CURLY@18..19 "{"
+ CURLY_GROUP@19..32
+ L_CURLY@19..20 "{"
+ TEXT@20..31
+ WORD@20..31 "../figures/"
+ R_CURLY@31..32 "}"
+ R_CURLY@32..33 "}"
+
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_missing_end.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__curly_group_missing_end.txt.snap
index c5fc46ec4d..68969f9c11 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_missing_end.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__curly_group_missing_end.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"{hello world\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/group/curly_group_missing_end.txt
---
ROOT@0..12
PREAMBLE@0..12
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__curly_group_simple.txt.snap
index 10ebc4418e..156ec2e0a2 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__brace_group_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__curly_group_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"{hello world}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/group/curly_group_simple.txt
---
ROOT@0..13
PREAMBLE@0..13
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_end.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__equation_missing_end.txt.snap
index 3085037fac..eae04433d1 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_missing_end.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__equation_missing_end.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\begin{a} \\[ foo bar \\end{b}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/group/equation_missing_end.txt
---
ROOT@0..28
PREAMBLE@0..28
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__escaped_brackets.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__escaped_brackets.txt.snap
index c595828583..a396d2e984 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__escaped_brackets.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__escaped_brackets.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"{[}{]}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/group/escaped_brackets.txt
---
ROOT@0..6
PREAMBLE@0..6
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_braces.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_braces.txt.snap
index df463f501a..82d7e9db45 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_braces.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_braces.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"}{\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/group/unmatched_braces.txt
---
ROOT@0..2
PREAMBLE@0..2
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_brackets.txt.snap
index 578cbf6099..7dd82d48bc 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_brackets.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"][\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/group/unmatched_brackets.txt
---
ROOT@0..2
PREAMBLE@0..2
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets_with_group.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_brackets_with_group.txt.snap
index d929c98c46..3c45c0c14c 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__unmatched_brackets_with_group.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@group__unmatched_brackets_with_group.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"{][}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/group/unmatched_brackets_with_group.txt
---
ROOT@0..4
PREAMBLE@0..4
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__hello_world.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@hello_world.txt.snap
index ee25cb5453..7c1ff02b81 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__hello_world.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@hello_world.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"Hello World!\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/hello_world.txt
---
ROOT@0..12
PREAMBLE@0..12
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__biblatex_include_options.txt.snap
index 3189cabd46..897d693fd0 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__biblatex_include_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\addbibresource[foo=bar, baz]{foo/bar.bib}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/biblatex_include_options.txt
---
ROOT@0..42
PREAMBLE@0..42
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__biblatex_include_simple.txt.snap
index 3166d13aff..a4be9c38cb 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__biblatex_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__biblatex_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\addbibresource{foo/bar.bib}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/biblatex_include_simple.txt
---
ROOT@0..28
PREAMBLE@0..28
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__bibtex_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__bibtex_include_simple.txt.snap
index db58621c75..0a8f9cd3f6 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__bibtex_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__bibtex_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\bibliography{foo/bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/bibtex_include_simple.txt
---
ROOT@0..22
PREAMBLE@0..22
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_empty.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_empty.txt.snap
index 7d84653225..37ea745308 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_empty.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_empty.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\documentclass{}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/class_include_empty.txt
---
ROOT@0..16
PREAMBLE@0..16
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_options.txt.snap
index ac20c4b8ac..ff95f8358f 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\documentclass[foo = bar, baz, qux]{article}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/class_include_options.txt
---
ROOT@0..44
PREAMBLE@0..44
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_simple.txt.snap
index 07c426101e..670fa2b902 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__class_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__class_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\documentclass{article}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/class_include_simple.txt
---
ROOT@0..23
PREAMBLE@0..23
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_command.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_command.txt.snap
index d279eda7f7..0332499c66 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_command.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_command.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1639
-expression: "setup(r#\"\\includegraphics[width=0.5\\textwidth]{\\foo.\\bar.pdf}\"#)"
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/graphics_include_command.txt
---
ROOT@0..52
PREAMBLE@0..52
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_complicated_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_complicated_options.txt.snap
index a79c7f925e..5259eb5072 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_complicated_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_complicated_options.txt.snap
@@ -1,8 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1547
-expression: "setup(r#\"\\includegraphics[width=0.5\\textwidth]{}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/graphics_include_complicated_options.txt
---
ROOT@0..39
PREAMBLE@0..39
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_options.txt.snap
index 14e2413323..5ed7df9cfc 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\includegraphics[scale=.5]{foo/bar.pdf}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/graphics_include_options.txt
---
ROOT@0..39
PREAMBLE@0..39
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_simple.txt.snap
index f4c640bca8..cabb065d24 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__graphics_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\includegraphics{foo/bar.pdf}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/graphics_include_simple.txt
---
ROOT@0..29
PREAMBLE@0..29
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_incomplete.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__import_incomplete.txt.snap
index c8634d6269..dad78222c2 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_incomplete.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__import_incomplete.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\import{foo\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/import_incomplete.txt
---
ROOT@0..11
PREAMBLE@0..11
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__import_simple.txt.snap
index c94f34eb3f..9e4fdeb284 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__import_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__import_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\import{foo}{bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/import_simple.txt
---
ROOT@0..17
PREAMBLE@0..17
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__inkscape_include_options.txt.snap
index 8b95509be6..d0e8321692 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__inkscape_include_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\includesvg[scale=.5]{foo/bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/inkscape_include_options.txt
---
ROOT@0..30
PREAMBLE@0..30
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__inkscape_include_simple.txt.snap
index e3d1f9bdfd..1d1e68f33c 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inkscape_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__inkscape_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\includesvg{foo/bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/inkscape_include_simple.txt
---
ROOT@0..20
PREAMBLE@0..20
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_equality_sign.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_include_equality_sign.txt.snap
index c6cfb5dda3..abf7865a42 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_equality_sign.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_include_equality_sign.txt.snap
@@ -1,8 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1504
-expression: "setup(r#\"\\include{foo=bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/latex_include_equality_sign.txt
---
ROOT@0..17
PREAMBLE@0..17
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_include_simple.txt.snap
index dbdeaad2f7..2315a2ad7c 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\include{foo/bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/latex_include_simple.txt
---
ROOT@0..17
PREAMBLE@0..17
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_path_with_brackets.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_input_path_brackets.txt.snap
index cb99f39728..0ba79f0c41 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_path_with_brackets.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__latex_input_path_brackets.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1591
-expression: "setup(r#\"\\input{foo[bar].tex}\"#)"
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/latex_input_path_brackets.txt
---
ROOT@0..20
PREAMBLE@0..20
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_empty.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_empty.txt.snap
index b8851b6e1d..36e2ab5aeb 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_empty.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_empty.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\usepackage{}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/package_include_empty.txt
---
ROOT@0..13
PREAMBLE@0..13
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_multiple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_multiple.txt.snap
index 2df92fd909..876f7313d7 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_multiple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_multiple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\usepackage{amsmath, lipsum}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/package_include_multiple.txt
---
ROOT@0..28
PREAMBLE@0..28
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_options.txt.snap
index 0f87570023..32a624f769 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\usepackage[foo = bar, baz, qux]{amsmath}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/package_include_options.txt
---
ROOT@0..41
PREAMBLE@0..41
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_simple.txt.snap
index a28dd39a13..014ed983dd 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__package_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__package_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\usepackage{amsmath}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/package_include_simple.txt
---
ROOT@0..20
PREAMBLE@0..20
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__pgf_library_import_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__pgf_library_import_simple.txt.snap
index c36bf857bb..7f5f78415e 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__pgf_library_import_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__pgf_library_import_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\usepgflibrary{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/pgf_library_import_simple.txt
---
ROOT@0..19
PREAMBLE@0..19
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_options.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__svg_include_options.txt.snap
index 3140282630..2410aeaa5a 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_options.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__svg_include_options.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\includesvg[scale=.5]{foo/bar.svg}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/svg_include_options.txt
---
ROOT@0..34
PREAMBLE@0..34
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__svg_include_simple.txt.snap
index 2cf133b4d0..61dd22f045 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__svg_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__svg_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\includesvg{foo/bar.svg}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/svg_include_simple.txt
---
ROOT@0..24
PREAMBLE@0..24
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__tikz_library_import_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__tikz_library_import_simple.txt.snap
index 4cd63e6728..c68ff02964 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__tikz_library_import_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__tikz_library_import_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\usetikzlibrary{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/tikz_library_import_simple.txt
---
ROOT@0..20
PREAMBLE@0..20
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__verbatim_include_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__verbatim_include_simple.txt.snap
index 48d6b816f3..3c35fddf18 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__verbatim_include_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@include__verbatim_include_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\verbatiminput{foo/bar.txt}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/include/verbatim_include_simple.txt
---
ROOT@0..27
PREAMBLE@0..27
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@inline.txt.snap
index b430de766e..c055d183bd 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@inline.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"$x \\in [0, \\infty)$\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/inline.txt
---
ROOT@0..19
PREAMBLE@0..19
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline_double_dollar.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@inline_double_dollar.txt.snap
index 8da22f3ecb..7084156fce 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__inline_double_dollar.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@inline_double_dollar.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"$$x \\in [0, \\infty)$$\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/inline_double_dollar.txt
---
ROOT@0..21
PREAMBLE@0..21
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@issue_745.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@issue_745.txt.snap
new file mode 100644
index 0000000000..8530953285
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@issue_745.txt.snap
@@ -0,0 +1,120 @@
+---
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/issue_745.txt
+---
+ROOT@0..271
+ PREAMBLE@0..271
+ CLASS_INCLUDE@0..24
+ CLASS_INCLUDE_NAME@0..14 "\\documentclass"
+ CURLY_GROUP_WORD_LIST@14..24
+ L_CURLY@14..15 "{"
+ KEY@15..22
+ WORD@15..22 "article"
+ R_CURLY@22..23 "}"
+ LINE_BREAK@23..24 "\n"
+ PACKAGE_INCLUDE@24..50
+ PACKAGE_INCLUDE_NAME@24..35 "\\usepackage"
+ CURLY_GROUP_WORD_LIST@35..50
+ L_CURLY@35..36 "{"
+ KEY@36..46
+ WORD@36..46 "tabularray"
+ R_CURLY@46..47 "}"
+ WHITESPACE@47..50 " \n\n"
+ GENERIC_COMMAND@50..64
+ GENERIC_COMMAND_NAME@50..63 "\\ExplSyntaxOn"
+ LINE_BREAK@63..64 "\n"
+ GENERIC_COMMAND@64..223
+ GENERIC_COMMAND_NAME@64..87 "\\NewDocumentEnvironment"
+ CURLY_GROUP@87..96
+ L_CURLY@87..88 "{"
+ TEXT@88..95
+ WORD@88..95 "exptblr"
+ R_CURLY@95..96 "}"
+ CURLY_GROUP@96..107
+ L_CURLY@96..97 "{"
+ TEXT@97..98
+ WORD@97..98 "O"
+ CURLY_GROUP@98..100
+ L_CURLY@98..99 "{"
+ R_CURLY@99..100 "}"
+ TEXT@100..101
+ WORD@100..101 "m"
+ R_CURLY@101..102 "}"
+ WHITESPACE@102..107 "\n "
+ CURLY_GROUP@107..200
+ L_CURLY@107..108 "{"
+ WHITESPACE@108..113 "\n "
+ GENERIC_COMMAND@113..194
+ GENERIC_COMMAND_NAME@113..119 "\\use:x"
+ WHITESPACE@119..124 "\n "
+ CURLY_GROUP@124..194
+ L_CURLY@124..125 "{"
+ WHITESPACE@125..130 "\n "
+ GENERIC_COMMAND@130..141
+ GENERIC_COMMAND_NAME@130..140 "\\exp_not:N"
+ WHITESPACE@140..141 " "
+ ENVIRONMENT@141..188
+ BEGIN@141..179
+ BEGIN_ENVIRONMENT_NAME@141..147 "\\begin"
+ CURLY_GROUP_WORD@147..158
+ L_CURLY@147..148 "{"
+ KEY@148..152
+ WORD@148..152 "tblr"
+ R_CURLY@152..153 "}"
+ WHITESPACE@153..158 "\n "
+ BRACK_GROUP@158..179
+ L_BRACK@158..159 "["
+ GENERIC_COMMAND@159..173
+ GENERIC_COMMAND_NAME@159..169 "\\exp_not:n"
+ CURLY_GROUP@169..173
+ L_CURLY@169..170 "{"
+ TEXT@170..172
+ WORD@170..172 "#1"
+ R_CURLY@172..173 "}"
+ R_BRACK@173..174 "]"
+ WHITESPACE@174..179 "\n "
+ CURLY_GROUP@179..188
+ L_CURLY@179..180 "{"
+ TEXT@180..182
+ WORD@180..182 "#2"
+ R_CURLY@182..183 "}"
+ WHITESPACE@183..188 "\n "
+ MISSING@188..188 ""
+ R_CURLY@188..189 "}"
+ WHITESPACE@189..194 "\n "
+ R_CURLY@194..195 "}"
+ WHITESPACE@195..200 "\n "
+ CURLY_GROUP@200..223
+ L_CURLY@200..201 "{"
+ WHITESPACE@201..206 "\n "
+ GENERIC_COMMAND@206..221
+ END_ENVIRONMENT_NAME@206..210 "\\end"
+ CURLY_GROUP@210..221
+ L_CURLY@210..211 "{"
+ TEXT@211..215
+ WORD@211..215 "tblr"
+ R_CURLY@215..216 "}"
+ WHITESPACE@216..221 "\n "
+ R_CURLY@221..222 "}"
+ LINE_BREAK@222..223 "\n"
+ GENERIC_COMMAND@223..239
+ GENERIC_COMMAND_NAME@223..237 "\\ExplSyntaxOff"
+ LINE_BREAK@237..239 "\n\n"
+ ENVIRONMENT@239..271
+ BEGIN@239..257
+ BEGIN_ENVIRONMENT_NAME@239..245 "\\begin"
+ CURLY_GROUP_WORD@245..257
+ L_CURLY@245..246 "{"
+ KEY@246..254
+ WORD@246..254 "document"
+ R_CURLY@254..255 "}"
+ LINE_BREAK@255..257 "\n\n"
+ END@257..271
+ END_ENVIRONMENT_NAME@257..261 "\\end"
+ CURLY_GROUP_WORD@261..271
+ L_CURLY@261..262 "{"
+ KEY@262..270
+ WORD@262..270 "document"
+ R_CURLY@270..271 "}"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@issue_789.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@issue_789.txt.snap
new file mode 100644
index 0000000000..ff20c01008
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@issue_789.txt.snap
@@ -0,0 +1,15 @@
+---
+source: src/parser/latex.rs
+assertion_line: 1361
+expression: root
+---
+ROOT@0..19
+ PREAMBLE@0..19
+ GRAPHICS_PATH@0..19
+ GRAPHICS_PATH_NAME@0..13 "\\graphicspath"
+ CURLY_GROUP_WORD@13..19
+ L_CURLY@13..14 "{"
+ KEY@14..18
+ WORD@14..18 "test"
+ R_CURLY@18..19 "}"
+
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_line_break.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_definition_line_break.txt.snap
index 47187fabcd..7f2ff377b8 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_line_break.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_definition_line_break.txt.snap
@@ -1,8 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-assertion_line: 1719
-expression: "setup(\"\\\\label{hello\\nworld}\")"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_definition_line_break.txt
---
ROOT@0..19
PREAMBLE@0..19
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_definition_simple.txt.snap
index 2d15533f87..a2e8b85b55 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_definition_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_definition_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\label{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_definition_simple.txt
---
ROOT@0..11
PREAMBLE@0..11
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_number.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_number.txt.snap
index a63752d80e..9afdf9e88e 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_number.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_number.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newlabel{foo}{{1.1}}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_number.txt
---
ROOT@0..21
PREAMBLE@0..21
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_label_reference_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_equation.txt.snap
index 9123fafcf2..93580e846e 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__equation_label_reference_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_equation.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\eqref{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_reference_equation.txt
---
ROOT@0..11
PREAMBLE@0..11
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_incomplete.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_incomplete.txt.snap
index 047eea657d..64e2d9af44 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_incomplete.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_incomplete.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"Equation \\eqref{eq is a \\emph{useful} identity.\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_reference_incomplete.txt
---
ROOT@0..47
PREAMBLE@0..47
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_multiple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_multiple.txt.snap
index 0176c770e8..27d56c6789 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_multiple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_multiple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\ref{foo, bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_reference_multiple.txt
---
ROOT@0..14
PREAMBLE@0..14
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_error.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_error.txt.snap
index ee65f8a02f..ce5e6a49b5 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_error.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_error.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\crefrange{foo{bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_reference_range_error.txt
---
ROOT@0..19
PREAMBLE@0..19
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_incomplete.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_incomplete.txt.snap
index 3dbe4bbab6..b682f40ebc 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_incomplete.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_incomplete.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\crefrange{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_reference_range_incomplete.txt
---
ROOT@0..15
PREAMBLE@0..15
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_simple.txt.snap
index 094d0e2870..e76708bf43 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_range_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_range_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\crefrange{foo}{bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_reference_range_simple.txt
---
ROOT@0..20
PREAMBLE@0..20
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_simple.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_simple.txt.snap
index 9b6e622ef9..398a6c1682 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__label_reference_simple.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@label__label_reference_simple.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\ref{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/label/label_reference_simple.txt
---
ROOT@0..9
PREAMBLE@0..9
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@parameter.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@parameter.txt.snap
new file mode 100644
index 0000000000..333db9df78
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@parameter.txt.snap
@@ -0,0 +1,10 @@
+---
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/parameter.txt
+---
+ROOT@0..2
+ PREAMBLE@0..2
+ TEXT@0..2
+ WORD@0..2 "#1"
+
diff --git a/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@parameter_error.txt.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@parameter_error.txt.snap
new file mode 100644
index 0000000000..8e3b45ad67
--- /dev/null
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@parameter_error.txt.snap
@@ -0,0 +1,10 @@
+---
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/parameter_error.txt
+---
+ROOT@0..1
+ PREAMBLE@0..1
+ TEXT@0..1
+ WORD@0..1 "#"
+
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_enum_item.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_enum_item.txt.snap
index 0ca7421ac6..4c6222045c 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_enum_item.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_enum_item.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\begin{enumerate} \\item 1 \\item[2] 2 \\item 3 \\end{enumerate}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/structure/structure_enum_item.txt
---
ROOT@0..60
PREAMBLE@0..60
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_invalid_nesting.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_invalid_nesting.txt.snap
index f999a50e9a..c5f7aede51 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_invalid_nesting.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_invalid_nesting.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\section{Foo} \\chapter{Bar}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/structure/structure_invalid_nesting.txt
---
ROOT@0..27
PREAMBLE@0..27
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_nested.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_nested.txt.snap
index db5602e591..1f93b8c11f 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_nested.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_nested.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\part{1}\\chapter{2}\\section{3}\\subsection{4}\\subsubsection{5}\\paragraph{6}\\subparagraph{7}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/structure/structure_nested.txt
---
ROOT@0..90
PREAMBLE@0..90
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_siblings.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_siblings.txt.snap
index 94d2ef40bd..03a29cb4bd 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__structure_siblings.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@structure__structure_siblings.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\section{Foo} Foo \\section{Bar} Bar\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/structure/structure_siblings.txt
---
ROOT@0..35
PREAMBLE@0..35
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_full.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_full.txt.snap
index 7f21c0ef52..81b9c92758 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_full.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_full.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newtheorem{foo}[bar]{Foo}[baz]\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/theorem_definition/theorem_definition_full.txt
---
ROOT@0..31
PREAMBLE@0..31
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_counter.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_counter.txt.snap
index d7bb29bf58..b422a2619f 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_counter.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_counter.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newtheorem{foo}[bar]\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_counter.txt
---
ROOT@0..21
PREAMBLE@0..21
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description.txt.snap
index 7c8b49efa1..0b1a3f3e48 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newtheorem{foo}{Foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description.txt
---
ROOT@0..21
PREAMBLE@0..21
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description_and_counter.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description_and_counter.txt.snap
index 3322a9a116..1f84c653bd 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_name_with_description_and_counter.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_name_with_description_and_counter.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newtheorem{foo}[bar]{Foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description_and_counter.txt
---
ROOT@0..26
PREAMBLE@0..26
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_only_name.snap b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_only_name.txt.snap
index 0ba62df76c..8c85579665 100644
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__theorem_definition_only_name.snap
+++ b/support/texlab/src/parser/snapshots/texlab__parser__latex__tests__parse@theorem_definition__theorem_definition_only_name.txt.snap
@@ -1,7 +1,7 @@
---
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\newtheorem{foo}\"#)"
-
+source: src/parser/latex.rs
+expression: root
+input_file: src/parser/test_data/latex/theorem_definition/theorem_definition_only_name.txt
---
ROOT@0..16
PREAMBLE@0..16
diff --git a/support/texlab/src/parser/test_data/bibtex/comment.txt b/support/texlab/src/parser/test_data/bibtex/comment.txt
new file mode 100644
index 0000000000..f2ff586ab7
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/comment.txt
@@ -0,0 +1,6 @@
+Some junk here
+
+@comment{foo,
+ author = {Foo Bar},
+ title = {Some Title},
+}
diff --git a/support/texlab/src/parser/test_data/bibtex/issue_809.txt b/support/texlab/src/parser/test_data/bibtex/issue_809.txt
new file mode 100644
index 0000000000..c94b808fd5
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/issue_809.txt
@@ -0,0 +1,3 @@
+@article{issue_809,
+ title = {foo (" bar) baz},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/preamble.txt b/support/texlab/src/parser/test_data/bibtex/preamble.txt
new file mode 100644
index 0000000000..266b5ce228
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/preamble.txt
@@ -0,0 +1 @@
+@preamble{"Hello World!"} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/aho_2006.txt b/support/texlab/src/parser/test_data/bibtex/samples/aho_2006.txt
new file mode 100644
index 0000000000..ff829b40d1
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/aho_2006.txt
@@ -0,0 +1,8 @@
+@book{10.5555/1177220,
+ author = {Aho, Alfred V. and Lam, Monica S. and Sethi, Ravi and Ullman, Jeffrey D.},
+ title = {Compilers: Principles, Techniques, and Tools (2nd Edition)},
+ year = {2006},
+ isbn = {0321486811},
+ publisher = {Addison-Wesley Longman Publishing Co., Inc.},
+ address = {USA}
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/aksin_2006.txt b/support/texlab/src/parser/test_data/bibtex/samples/aksin_2006.txt
new file mode 100644
index 0000000000..88ea701c22
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/aksin_2006.txt
@@ -0,0 +1,16 @@
+@string{jomch = {J.~Organomet. Chem.}}
+
+@article{aksin,
+ author = {Aks{\i}n, {\"O}zge and T{\"u}rkmen, Hayati and Artok, Levent
+ and {\c{C}}etinkaya, Bekir and Ni, Chaoying and
+ B{\"u}y{\"u}kg{\"u}ng{\"o}r, Orhan and {\"O}zkal, Erhan},
+ title = {Effect of immobilization on catalytic characteristics of
+ saturated {Pd-N}-heterocyclic carbenes in {Mizoroki-Heck}
+ reactions},
+ journaltitle = jomch,
+ date = 2006,
+ volume = 691,
+ number = 13,
+ pages = {3027-3036},
+ indextitle = {Effect of immobilization on catalytic characteristics},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/almendro_1998.txt b/support/texlab/src/parser/test_data/bibtex/samples/almendro_1998.txt
new file mode 100644
index 0000000000..ed16d33c67
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/almendro_1998.txt
@@ -0,0 +1,14 @@
+@patent{almendro,
+ author = {Almendro, Jos{\'e} L. and Mart{\'i}n, Jacinto and S{\'a}nchez,
+ Alberto and Nozal, Fernando},
+ title = {Elektromagnetisches Signalhorn},
+ number = {EU-29702195U},
+ date = 1998,
+ location = {countryfr and countryuk and countryde},
+ langid = {german},
+ annotation = {This is a \texttt{patent} entry with a \texttt{location}
+ field. The number is given in the \texttt{number} field. Note
+ the format of the \texttt{location} field in the database
+ file. Compare \texttt{laufenberg}, \texttt{sorace}, and
+ \texttt{kowalik}},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/averroes_1998.txt b/support/texlab/src/parser/test_data/bibtex/samples/averroes_1998.txt
new file mode 100644
index 0000000000..9f224353cc
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/averroes_1998.txt
@@ -0,0 +1,21 @@
+@book{averroes/bland,
+ author = {Averroes},
+ title = {The Epistle on the Possibility of Conjunction with the Active
+ Intellect by {Ibn Rushd} with the Commentary of {Moses Narboni}},
+ date = 1982,
+ editor = {Bland, Kalman P.},
+ translator = {Bland, Kalman P.},
+ series = {Moreshet: Studies in {Jewish} History, Literature and Thought},
+ number = 7,
+ publisher = {Jewish Theological Seminary of America},
+ location = {New York},
+ keywords = {primary},
+ langid = {english},
+ langidopts = {variant=american},
+ indextitle = {Epistle on the Possibility of Conjunction, The},
+ shorttitle = {Possibility of Conjunction},
+ annotation = {A \texttt{book} entry with a \texttt{series} and a
+ \texttt{number}. Note the concatenation of the \texttt{editor}
+ and \texttt{translator} fields as well as the
+ \texttt{indextitle} field},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/betram_1996.txt b/support/texlab/src/parser/test_data/bibtex/samples/betram_1996.txt
new file mode 100644
index 0000000000..b2d77e216f
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/betram_1996.txt
@@ -0,0 +1,16 @@
+@string{jams = {J.~Amer. Math. Soc.}}
+
+@article{bertram,
+ author = {Bertram, Aaron and Wentworth, Richard},
+ title = {Gromov invariants for holomorphic maps on {Riemann} surfaces},
+ journaltitle = jams,
+ date = 1996,
+ volume = 9,
+ number = 2,
+ pages = {529-571},
+ langid = {english},
+ langidopts = {variant=american},
+ shorttitle = {Gromov invariants},
+ annotation = {An \texttt{article} entry with a \texttt{volume} and a
+ \texttt{number} field},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/blom_2021.txt b/support/texlab/src/parser/test_data/bibtex/samples/blom_2021.txt
new file mode 100644
index 0000000000..a502e53e03
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/blom_2021.txt
@@ -0,0 +1,20 @@
+@article{DBLP:journals/corr/abs-2107-11903,
+ author = {Michelle L. Blom and
+ Jurlind Budurushi and
+ Ronald L. Rivest and
+ Philip B. Stark and
+ Peter J. Stuckey and
+ Vanessa Teague and
+ Damjan Vukcevic},
+ title = {Assertion-based Approaches to Auditing Complex Elections, with application
+ to party-list proportional elections},
+ journal = {CoRR},
+ volume = {abs/2107.11903},
+ year = {2021},
+ url = {https://arxiv.org/abs/2107.11903},
+ eprinttype = {arXiv},
+ eprint = {2107.11903},
+ timestamp = {Thu, 29 Jul 2021 16:14:15 +0200},
+ biburl = {https://dblp.org/rec/journals/corr/abs-2107-11903.bib},
+ bibsource = {dblp computer science bibliography, https://dblp.org}
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/combi_2004.txt b/support/texlab/src/parser/test_data/bibtex/samples/combi_2004.txt
new file mode 100644
index 0000000000..7d8545577d
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/combi_2004.txt
@@ -0,0 +1,16 @@
+@inproceedings{10.1145/967900.968040,
+ author = {Combi, Carlo and Pozzi, Giuseppe},
+ title = {Architectures for a Temporal Workflow Management System},
+ year = {2004},
+ isbn = {1581138121},
+ publisher = {Association for Computing Machinery},
+ address = {New York, NY, USA},
+ url = {https://doi.org/10.1145/967900.968040},
+ doi = {10.1145/967900.968040},
+ booktitle = {Proceedings of the 2004 ACM Symposium on Applied Computing},
+ pages = {659-666},
+ numpages = {8},
+ keywords = {active DBMS, temporal DBMS, workflow management system - WfMS, temporal workflow management system},
+ location = {Nicosia, Cyprus},
+ series = {SAC '04}
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/erwin_2007.txt b/support/texlab/src/parser/test_data/bibtex/samples/erwin_2007.txt
new file mode 100644
index 0000000000..116f5e7098
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/erwin_2007.txt
@@ -0,0 +1,14 @@
+@inproceedings{10.5555/1386993.1386994,
+ author = {Erwin, Alva and Gopalan, Raj P. and Achuthan, N. R.},
+ title = {A Bottom-up Projection Based Algorithm for Mining High Utility Itemsets},
+ year = {2007},
+ isbn = {9781920682651},
+ publisher = {Australian Computer Society, Inc.},
+ address = {AUS},
+ booktitle = {Proceedings of the 2nd International Workshop on Integrating Artificial Intelligence and Data Mining - Volume 84},
+ pages = {3-11},
+ numpages = {9},
+ keywords = {pattern growth, high utility itemset mining},
+ location = {Gold Coast, Australia},
+ series = {AIDM '07}
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/jain_1999.txt b/support/texlab/src/parser/test_data/bibtex/samples/jain_1999.txt
new file mode 100644
index 0000000000..c367ef12ee
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/jain_1999.txt
@@ -0,0 +1,18 @@
+@article{10.1145/331499.331504,
+ author = {Jain, A. K. and Murty, M. N. and Flynn, P. J.},
+ title = {Data Clustering: A Review},
+ year = {1999},
+ issue_date = {Sept. 1999},
+ publisher = {Association for Computing Machinery},
+ address = {New York, NY, USA},
+ volume = {31},
+ number = {3},
+ issn = {0360-0300},
+ url = {https://doi.org/10.1145/331499.331504},
+ doi = {10.1145/331499.331504},
+ journal = {ACM Comput. Surv.},
+ month = {sep},
+ pages = {264-323},
+ numpages = {60},
+ keywords = {incremental clustering, clustering applications, exploratory data analysis, cluster analysis, similarity indices, unsupervised learning}
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/kastenholz_2006.txt b/support/texlab/src/parser/test_data/bibtex/samples/kastenholz_2006.txt
new file mode 100644
index 0000000000..457f871491
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/kastenholz_2006.txt
@@ -0,0 +1,20 @@
+@string{jchph = {J.~Chem. Phys.}}
+
+@article{kastenholz,
+ author = {Kastenholz, M. A. and H{\"u}nenberger, Philippe H.},
+ title = {Computation of methodology\hyphen independent ionic solvation
+ free energies from molecular simulations},
+ journaltitle = jchph,
+ date = 2006,
+ subtitle = {{I}. {The} electrostatic potential in molecular liquids},
+ volume = 124,
+ eid = 124106,
+ doi = {10.1063/1.2172593},
+ langid = {english},
+ langidopts = {variant=american},
+ indextitle = {Computation of ionic solvation free energies},
+ annotation = {An \texttt{article} entry with an \texttt{eid} and a
+ \texttt{doi} field. Note that the \textsc{doi} is transformed
+ into a clickable link if \texttt{hyperref} support has been
+ enabled},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/knuth_1984.txt b/support/texlab/src/parser/test_data/bibtex/samples/knuth_1984.txt
new file mode 100644
index 0000000000..98c595e35c
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/knuth_1984.txt
@@ -0,0 +1,22 @@
+@book{knuth:ct:a,
+ author = {Knuth, Donald E.},
+ title = {The {\TeX book}},
+ date = 1984,
+ maintitle = {Computers \& Typesetting},
+ volume = {A},
+ publisher = {Addison-Wesley},
+ location = {Reading, Mass.},
+ langid = {english},
+ langidopts = {variant=american},
+ sorttitle = {Computers & Typesetting A},
+ indexsorttitle= {The TeXbook},
+ indextitle = {\protect\TeX book, The},
+ shorttitle = {\TeX book},
+ annotation = {The first volume of a five-volume book. Note the
+ \texttt{sorttitle} field. We want this
+ volume to be listed after the entry referring to the entire
+ five-volume set. Also note the \texttt{indextitle} and
+ \texttt{indexsorttitle} fields. Indexing packages that don't
+ generate robust index entries require some control sequences
+ to be protected from expansion},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/matuz_1990.txt b/support/texlab/src/parser/test_data/bibtex/samples/matuz_1990.txt
new file mode 100644
index 0000000000..cb803aab51
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/matuz_1990.txt
@@ -0,0 +1,14 @@
+@collection{matuz:doody,
+ editor = {Matuz, Roger},
+ title = {Contemporary Literary Criticism},
+ year = 1990,
+ volume = 61,
+ publisher = {Gale},
+ location = {Detroit},
+ pages = {204-208},
+ langid = {english},
+ langidopts = {variant=american},
+ annotation = {A \texttt{collection} entry providing the excerpt information
+ for the \texttt{doody} entry. Note the format of the
+ \texttt{pages} field},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/nietzsche_1998.txt b/support/texlab/src/parser/test_data/bibtex/samples/nietzsche_1998.txt
new file mode 100644
index 0000000000..e245be39bb
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/nietzsche_1998.txt
@@ -0,0 +1,24 @@
+@string{dtv = {Deutscher Taschenbuch-Verlag}}
+
+@mvbook{nietzsche:ksa,
+ author = {Nietzsche, Friedrich},
+ title = {S{\"a}mtliche Werke},
+ date = 1988,
+ editor = {Colli, Giorgio and Montinari, Mazzino},
+ edition = 2,
+ volumes = 15,
+ publisher = dtv # { and Walter de Gruyter},
+ location = {M{\"u}nchen and Berlin and New York},
+ langid = {german},
+ sorttitle = {Werke-00-000},
+ indexsorttitle= {Samtliche Werke},
+ subtitle = {Kritische Studienausgabe},
+ annotation = {The critical edition of Nietzsche's works. This is a
+ \texttt{mvbook} entry referring to a 15-volume work as a
+ whole. Note the \texttt{volumes} field and the format of the
+ \texttt{publisher} and \texttt{location} fields in the
+ database file. Also note the \texttt{sorttitle} and
+ field which is used to fine-tune the
+ sorting order of the bibliography. We want this item listed
+ first in the bibliography},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/bibtex/samples/rivest_1978.txt b/support/texlab/src/parser/test_data/bibtex/samples/rivest_1978.txt
new file mode 100644
index 0000000000..e1076145ea
--- /dev/null
+++ b/support/texlab/src/parser/test_data/bibtex/samples/rivest_1978.txt
@@ -0,0 +1,17 @@
+@article{10.1145/359340.359342,
+ author = {Rivest, R. L. and Shamir, A. and Adleman, L.},
+ title = {A Method for Obtaining Digital Signatures and Public-Key Cryptosystems},
+ year = {1978},
+ issue_date = {Feb. 1978},
+ publisher = {Association for Computing Machinery},
+ address = {New York, NY, USA},
+ volume = {21},
+ number = {2},
+ issn = {0001-0782},
+ url = {https://doi.org/10.1145/359340.359342},
+ doi = {10.1145/359340.359342},
+ journal = {Commun. ACM},
+ month = {feb},
+ pages = {120-126},
+ numpages = {7},
+} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/build_log/001.txt b/support/texlab/src/parser/test_data/build_log/001.txt
new file mode 100644
index 0000000000..fc9968af0f
--- /dev/null
+++ b/support/texlab/src/parser/test_data/build_log/001.txt
@@ -0,0 +1,83 @@
+This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:50
+entering extended mode
+restricted \write18 enabled.
+%&-line parsing enabled.
+**./parent.tex
+(./parent.tex
+LaTeX2e <2017-04-15>
+Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
+(/TexLive/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
+(/TexLive/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
+)
+\c@part=\count79
+\c@section=\count80
+\c@subsection=\count81
+\c@subsubsection=\count82
+\c@paragraph=\count83
+\c@subparagraph=\count84
+\c@figure=\count85
+\c@table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+)
+(/TexLive/texmf-dist/tex/latex/multirow/bigstrut.sty
+Package: bigstrut 2016/11/25 v2.2 Provide larger struts in tabulars
+\bigstrutjot=\dimen103
+)
+(/TexLive/texmf-dist/tex/latex/multirow/multirow.sty
+Package: multirow 2016/11/25 v2.2 Span multiple rows of a table
+\multirow@colwidth=\skip43
+\multirow@cntb=\count87
+\multirow@dima=\skip44
+) (./parent.aux)
+\openout1 = `parent.aux'.
+
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+
+Overfull \hbox (200.00162pt too wide) in paragraph at lines 8--9
+[]\OT1/cmr/m/n/10 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+[]
+
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <7> on input line 11.
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <5> on input line 11.
+
+Overfull \vbox (3.19998pt too high) detected at line 23
+[]
+
+[1
+
+{/TexLive/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./parent.aux) )
+Here is how much of TeX's memory you used:
+265 strings out of 492995
+3121 string characters out of 6138727
+55074 words of memory out of 5000000
+3896 multiletter control sequences out of 15000+600000
+3640 words of font info for 14 fonts, out of 8000000 for 9000
+1141 hyphenation exceptions out of 8191
+23i,20n,20p,124b,282s stack positions out of 5000i,500n,10000p,200000b,80000s
+</
+TexLive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></TexLive/texmf-d
+ist/fonts/type1/public/amsfonts/cm/cmr7.pfb>
+Output written on parent.pdf (1 page, 17505 bytes).
+PDF statistics:
+16 PDF objects out of 1000 (max. 8388607)
+10 compressed objects within 1 object stream
+0 named destinations out of 1000 (max. 500000)
+1 words of extra memory for PDF output out of 10000 (max. 10000000) \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/build_log/002.txt b/support/texlab/src/parser/test_data/build_log/002.txt
new file mode 100644
index 0000000000..8d438d1f12
--- /dev/null
+++ b/support/texlab/src/parser/test_data/build_log/002.txt
@@ -0,0 +1,64 @@
+This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:52
+entering extended mode
+restricted \write18 enabled.
+%&-line parsing enabled.
+**./parent.tex
+(./parent.tex
+LaTeX2e <2017-04-15>
+Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
+(/TexLive/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
+(/TexLive/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
+)
+\c@part=\count79
+\c@section=\count80
+\c@subsection=\count81
+\c@subsubsection=\count82
+\c@paragraph=\count83
+\c@subparagraph=\count84
+\c@figure=\count85
+\c@table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+) (./parent.aux (./child.aux))
+\openout1 = `parent.aux'.
+
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+(./child.tex
+! Undefined control sequence.
+l.1 \foo
+
+The control sequence at the end of the top line
+of your error message was never \def'ed. If you have
+misspelled it (e.g., `\hobx'), type `I' and the correct
+spelling (e.g., `I\hbox'). Otherwise just continue,
+and I'll forget about whatever was undefined.
+
+) (./parent.aux) )
+Here is how much of TeX's memory you used:
+205 strings out of 492995
+2149 string characters out of 6138727
+54074 words of memory out of 5000000
+3841 multiletter control sequences out of 15000+600000
+3640 words of font info for 14 fonts, out of 8000000 for 9000
+1141 hyphenation exceptions out of 8191
+23i,1n,17p,116b,36s stack positions out of 5000i,500n,10000p,200000b,80000s
+
+No pages of output.
+PDF statistics:
+0 PDF objects out of 1000 (max. 8388607)
+0 named destinations out of 1000 (max. 500000)
+1 words of extra memory for PDF output out of 10000 (max. 10000000) \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/build_log/003.txt b/support/texlab/src/parser/test_data/build_log/003.txt
new file mode 100644
index 0000000000..220614b91c
--- /dev/null
+++ b/support/texlab/src/parser/test_data/build_log/003.txt
@@ -0,0 +1,65 @@
+This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:51
+entering extended mode
+restricted \write18 enabled.
+%&-line parsing enabled.
+**./parent.tex
+(./parent.tex
+LaTeX2e <2017-04-15>
+Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
+(/TexLive/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
+(/TexLive/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
+)
+\c@part=\count79
+\c@section=\count80
+\c@subsection=\count81
+\c@subsubsection=\count82
+\c@paragraph=\count83
+\c@subparagraph=\count84
+\c@figure=\count85
+\c@table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+) (./parent.aux)
+\openout1 = `parent.aux'.
+
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 4.
+LaTeX Font Info: ... okay on input line 4.
+
+LaTeX Warning: Citation `foo' on page 1 undefined on input line 6.
+
+[1
+
+{/TexLive/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./parent.aux)
+
+LaTeX Warning: There were undefined references.
+
+)
+Here is how much of TeX's memory you used:
+204 strings out of 492995
+2142 string characters out of 6138727
+54074 words of memory out of 5000000
+3842 multiletter control sequences out of 15000+600000
+3948 words of font info for 15 fonts, out of 8000000 for 9000
+1141 hyphenation exceptions out of 8191
+23i,4n,21p,116b,107s stack positions out of 5000i,500n,10000p,200000b,80000s
+</TexLive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></TexLive/
+texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb>
+Output written on parent.pdf (1 page, 17339 bytes).
+PDF statistics:
+16 PDF objects out of 1000 (max. 8388607)
+10 compressed objects within 1 object stream
+0 named destinations out of 1000 (max. 500000)
+1 words of extra memory for PDF output out of 10000 (max. 10000000) \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/build_log/004.txt b/support/texlab/src/parser/test_data/build_log/004.txt
new file mode 100644
index 0000000000..4ab379cd53
--- /dev/null
+++ b/support/texlab/src/parser/test_data/build_log/004.txt
@@ -0,0 +1,83 @@
+This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:40
+entering extended mode
+restricted \write18 enabled.
+%&-line parsing enabled.
+**./parent.tex
+(./parent.tex
+LaTeX2e <2017-04-15>
+Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
+(/TexLive/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
+(/TexLive/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
+)
+\c@part=\count79
+\c@section=\count80
+\c@subsection=\count81
+\c@subsubsection=\count82
+\c@paragraph=\count83
+\c@subparagraph=\count84
+\c@figure=\count85
+\c@table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+)
+(/TexLive/texmf-dist/tex/generic/babel/babel.sty
+Package: babel 2017/05/19 3.10 The Babel package
+
+! Package babel Error: Unknown option `foo'. Either you misspelled it
+(babel) or the language definition file foo.ldf was not found.
+
+See the babel package documentation for explanation.
+Type H <return> for immediate help.
+...
+
+l.393 \ProcessOptions*
+
+Valid options are: shorthands=, KeepShorthandsActive,
+activeacute, activegrave, noconfigs, safe=, main=, math=
+headfoot=, strings=, config=, hyphenmap=, or a language name.
+
+! Package babel Error: You haven't specified a language option.
+
+See the babel package documentation for explanation.
+Type H <return> for immediate help.
+...
+
+l.426 ...ry to proceed from here, type x to quit.}
+
+You need to specify a language, either as a global option
+or as an optional argument to the \usepackage command;
+You shouldn't try to proceed from here, type x to quit.
+
+) (./parent.aux)
+\openout1 = `parent.aux'.
+
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 5.
+LaTeX Font Info: ... okay on input line 5.
+(./parent.aux) )
+Here is how much of TeX's memory you used:
+304 strings out of 492995
+3421 string characters out of 6138727
+56035 words of memory out of 5000000
+3938 multiletter control sequences out of 15000+600000
+3640 words of font info for 14 fonts, out of 8000000 for 9000
+1141 hyphenation exceptions out of 8191
+23i,1n,17p,116b,36s stack positions out of 5000i,500n,10000p,200000b,80000s
+
+No pages of output.
+PDF statistics:
+0 PDF objects out of 1000 (max. 8388607)
+0 named destinations out of 1000 (max. 500000)
+1 words of extra memory for PDF output out of 10000 (max. 10000000) \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/build_log/005.txt b/support/texlab/src/parser/test_data/build_log/005.txt
new file mode 100644
index 0000000000..07c95bfc6b
--- /dev/null
+++ b/support/texlab/src/parser/test_data/build_log/005.txt
@@ -0,0 +1,385 @@
+This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:45
+entering extended mode
+restricted \write18 enabled.
+%&-line parsing enabled.
+**./parent.tex
+(./parent.tex
+LaTeX2e <2017-04-15>
+Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
+(/TexLive/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
+(/TexLive/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
+)
+\c@part=\count79
+\c@section=\count80
+\c@subsection=\count81
+\c@subsubsection=\count82
+\c@paragraph=\count83
+\c@subparagraph=\count84
+\c@figure=\count85
+\c@table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+)
+(/TexLive/texmf-dist/tex/generic/babel/babel.sty
+Package: babel 2017/05/19 3.10 The Babel package
+
+(/TexLive/texmf-dist/tex/generic/babel-spanish/spanish.ldf
+Language: spanish.ldf 2016/03/03 v5.0p Spanish support from the babel system
+
+(/TexLive/texmf-dist/tex/generic/babel/babel.def
+File: babel.def 2017/05/19 3.10 Babel common definitions
+\babel@savecnt=\count87
+\U@D=\dimen103
+)
+\es@quottoks=\toks14
+\es@quotdepth=\count88
+Package babel Info: Making " an active character on input line 561.
+Package babel Info: Making . an active character on input line 662.
+Package babel Info: Making < an active character on input line 707.
+Package babel Info: Making > an active character on input line 707.
+))
+(/TexLive/texmf-dist/tex/latex/biblatex/biblatex.sty
+Package: biblatex 2016/12/05 v3.7 programmable bibliographies (PK/JW/AB)
+
+(/TexLive/texmf-dist/tex/generic/oberdiek/pdftexcmds.sty
+Package: pdftexcmds 2017/03/19 v0.25 Utility functions of pdfTeX for LuaTeX (HO
+)
+
+(/TexLive/texmf-dist/tex/generic/oberdiek/infwarerr.sty
+Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO)
+)
+(/TexLive/texmf-dist/tex/generic/oberdiek/ifluatex.sty
+Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO)
+Package ifluatex Info: LuaTeX not detected.
+)
+(/TexLive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty
+Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO)
+)
+(/TexLive/texmf-dist/tex/generic/oberdiek/ifpdf.sty
+Package: ifpdf 2017/03/15 v3.2 Provides the ifpdf switch
+)
+Package pdftexcmds Info: LuaTeX not detected.
+Package pdftexcmds Info: \pdf@primitive is available.
+Package pdftexcmds Info: \pdf@ifprimitive is available.
+Package pdftexcmds Info: \pdfdraftmode found.
+)
+(/TexLive/texmf-dist/tex/latex/etoolbox/etoolbox.sty
+Package: etoolbox 2017/01/02 v2.4 e-TeX tools for LaTeX (JAW)
+\etb@tempcnta=\count89
+)
+(/TexLive/texmf-dist/tex/latex/graphics/keyval.sty
+Package: keyval 2014/10/28 v1.15 key=value parser (DPC)
+\KV@toks@=\toks15
+)
+(/TexLive/texmf-dist/tex/latex/oberdiek/kvoptions.sty
+Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO)
+
+(/TexLive/texmf-dist/tex/generic/oberdiek/kvsetkeys.sty
+Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO)
+
+(/TexLive/texmf-dist/tex/generic/oberdiek/etexcmds.sty
+Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO)
+Package etexcmds Info: Could not find \expanded.
+(etexcmds) That can mean that you are not using pdfTeX 1.50 or
+(etexcmds) that some package has redefined \expanded.
+(etexcmds) In the latter case, load this package earlier.
+)))
+(/TexLive/texmf-dist/tex/latex/logreq/logreq.sty
+Package: logreq 2010/08/04 v1.0 xml request logger
+\lrq@indent=\count90
+
+(/TexLive/texmf-dist/tex/latex/logreq/logreq.def
+File: logreq.def 2010/08/04 v1.0 logreq spec v1.0
+))
+(/TexLive/texmf-dist/tex/latex/base/ifthen.sty
+Package: ifthen 2014/09/29 v1.1c Standard LaTeX ifthen package (DPC)
+)
+(/TexLive/texmf-dist/tex/latex/url/url.sty
+\Urlmuskip=\muskip10
+Package: url 2013/09/16 ver 3.4 Verb mode for urls, etc.
+)
+(/TexLive/texmf-dist/tex/generic/xstring/xstring.sty
+(/TexLive/texmf-dist/tex/generic/xstring/xstring.tex
+\@xs@message=\write3
+\integerpart=\count91
+\decimalpart=\count92
+)
+Package: xstring 2013/10/13 v1.7c String manipulations (C Tellechea)
+)
+\c@tabx@nest=\count93
+\c@listtotal=\count94
+\c@listcount=\count95
+\c@liststart=\count96
+\c@liststop=\count97
+\c@citecount=\count98
+\c@citetotal=\count99
+\c@multicitecount=\count100
+\c@multicitetotal=\count101
+\c@instcount=\count102
+\c@maxnames=\count103
+\c@minnames=\count104
+\c@maxitems=\count105
+\c@minitems=\count106
+\c@citecounter=\count107
+\c@savedcitecounter=\count108
+\c@uniquelist=\count109
+\c@uniquename=\count110
+\c@refsection=\count111
+\c@refsegment=\count112
+\c@maxextratitle=\count113
+\c@maxextratitleyear=\count114
+\c@maxextrayear=\count115
+\c@maxextraalpha=\count116
+\c@abbrvpenalty=\count117
+\c@highnamepenalty=\count118
+\c@lownamepenalty=\count119
+\c@maxparens=\count120
+\c@parenlevel=\count121
+\blx@tempcnta=\count122
+\blx@tempcntb=\count123
+\blx@tempcntc=\count124
+\blx@maxsection=\count125
+\blx@maxsegment@0=\count126
+\blx@notetype=\count127
+\blx@parenlevel@text=\count128
+\blx@parenlevel@foot=\count129
+\blx@sectionciteorder@0=\count130
+\labelnumberwidth=\skip43
+\labelalphawidth=\skip44
+\biblabelsep=\skip45
+\bibitemsep=\skip46
+\bibnamesep=\skip47
+\bibinitsep=\skip48
+\bibparsep=\skip49
+\bibhang=\skip50
+\blx@bcfin=\read1
+\blx@bcfout=\write4
+\c@mincomprange=\count131
+\c@maxcomprange=\count132
+\c@mincompwidth=\count133
+Package biblatex Info: Trying to load biblatex default data model...
+Package biblatex Info: ... file 'blx-dm.def' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/blx-dm.def)
+Package biblatex Info: Trying to load biblatex style data model...
+Package biblatex Info: ... file 'ieee.dbx' not found.
+Package biblatex Info: Trying to load biblatex custom data model...
+Package biblatex Info: ... file 'biblatex-dm.cfg' not found.
+\c@afterword=\count134
+\c@savedafterword=\count135
+\c@annotator=\count136
+\c@savedannotator=\count137
+\c@author=\count138
+\c@savedauthor=\count139
+\c@bookauthor=\count140
+\c@savedbookauthor=\count141
+\c@commentator=\count142
+\c@savedcommentator=\count143
+\c@editor=\count144
+\c@savededitor=\count145
+\c@editora=\count146
+\c@savededitora=\count147
+\c@editorb=\count148
+\c@savededitorb=\count149
+\c@editorc=\count150
+\c@savededitorc=\count151
+\c@foreword=\count152
+\c@savedforeword=\count153
+\c@holder=\count154
+\c@savedholder=\count155
+\c@introduction=\count156
+\c@savedintroduction=\count157
+\c@namea=\count158
+\c@savednamea=\count159
+\c@nameb=\count160
+\c@savednameb=\count161
+\c@namec=\count162
+\c@savednamec=\count163
+\c@translator=\count164
+\c@savedtranslator=\count165
+\c@shortauthor=\count166
+\c@savedshortauthor=\count167
+\c@shorteditor=\count168
+\c@savedshorteditor=\count169
+\c@labelname=\count170
+\c@savedlabelname=\count171
+\c@institution=\count172
+\c@savedinstitution=\count173
+\c@lista=\count174
+\c@savedlista=\count175
+\c@listb=\count176
+\c@savedlistb=\count177
+\c@listc=\count178
+\c@savedlistc=\count179
+\c@listd=\count180
+\c@savedlistd=\count181
+\c@liste=\count182
+\c@savedliste=\count183
+\c@listf=\count184
+\c@savedlistf=\count185
+\c@location=\count186
+\c@savedlocation=\count187
+\c@organization=\count188
+\c@savedorganization=\count189
+\c@origlocation=\count190
+\c@savedoriglocation=\count191
+\c@origpublisher=\count192
+\c@savedorigpublisher=\count193
+\c@publisher=\count194
+\c@savedpublisher=\count195
+\c@language=\count196
+\c@savedlanguage=\count197
+\c@pageref=\count198
+\c@savedpageref=\count199
+\shorthandwidth=\skip51
+\shortjournalwidth=\skip52
+\shortserieswidth=\skip53
+\shorttitlewidth=\skip54
+\shortauthorwidth=\skip55
+\shorteditorwidth=\skip56
+Package biblatex Info: Trying to load compatibility code...
+Package biblatex Info: ... file 'blx-compat.def' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/blx-compat.def
+File: blx-compat.def 2016/12/05 v3.7 biblatex compatibility (PK/JW/AB)
+)
+Package biblatex Info: Trying to load generic definitions...
+Package biblatex Info: ... file 'biblatex.def' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/biblatex.def
+File: biblatex.def 2016/12/05 v3.7 biblatex compatibility (PK/JW/AB)
+\c@textcitecount=\count266
+\c@textcitetotal=\count267
+\c@textcitemaxnames=\count268
+\c@biburlnumpenalty=\count269
+\c@biburlucpenalty=\count270
+\c@biburllcpenalty=\count271
+\c@smartand=\count272
+)
+Package biblatex Info: Trying to load bibliography style 'ieee'...
+Package biblatex Info: ... file 'ieee.bbx' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex-ieee/ieee.bbx
+File: ieee.bbx 2017/03/27 v1.2d biblatex bibliography style
+Package biblatex Info: Trying to load bibliography style 'numeric-comp'...
+Package biblatex Info: ... file 'numeric-comp.bbx' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/bbx/numeric-comp.bbx
+File: numeric-comp.bbx 2016/12/05 v3.7 biblatex bibliography style (PK/JW/AB)
+Package biblatex Info: Trying to load bibliography style 'numeric'...
+Package biblatex Info: ... file 'numeric.bbx' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/bbx/numeric.bbx
+File: numeric.bbx 2016/12/05 v3.7 biblatex bibliography style (PK/JW/AB)
+Package biblatex Info: Trying to load bibliography style 'standard'...
+Package biblatex Info: ... file 'standard.bbx' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/bbx/standard.bbx
+File: standard.bbx 2016/12/05 v3.7 biblatex bibliography style (PK/JW/AB)
+\c@bbx:relatedcount=\count273
+\c@bbx:relatedtotal=\count274
+))))
+Package biblatex Info: Trying to load citation style 'ieee'...
+Package biblatex Info: ... file 'ieee.cbx' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex-ieee/ieee.cbx
+File: ieee.cbx 2017/03/27 v1.2d biblatex citation style
+Package biblatex Info: Trying to load citation style 'numeric-comp'...
+Package biblatex Info: ... file 'numeric-comp.cbx' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/cbx/numeric-comp.cbx
+File: numeric-comp.cbx 2016/12/05 v3.7 biblatex citation style (PK/JW/AB)
+\c@cbx@tempcnta=\count275
+\c@cbx@tempcntb=\count276
+Package biblatex Info: Redefining '\cite'.
+Package biblatex Info: Redefining '\parencite'.
+Package biblatex Info: Redefining '\footcite'.
+Package biblatex Info: Redefining '\footcitetext'.
+Package biblatex Info: Redefining '\smartcite'.
+Package biblatex Info: Redefining '\supercite'.
+Package biblatex Info: Redefining '\textcite'.
+Package biblatex Info: Redefining '\textcites'.
+Package biblatex Info: Redefining '\cites'.
+Package biblatex Info: Redefining '\parencites'.
+Package biblatex Info: Redefining '\smartcites'.
+)
+Package biblatex Info: Redefining '\cite'.
+Package biblatex Info: Redefining '\cites'.
+)
+Package biblatex Info: Trying to load configuration file...
+Package biblatex Info: ... file 'biblatex.cfg' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/biblatex.cfg
+File: biblatex.cfg
+))
+Package biblatex Info: Trying to load language 'spanish'...
+Package biblatex Info: ... file 'spanish.lbx' found.
+
+(/TexLive/texmf-dist/tex/latex/biblatex/lbx/spanish.lbx
+File: spanish.lbx 2016/12/05 v3.7 biblatex localization (PK/JW/AB)
+)
+
+Package biblatex Warning: 'babel/polyglossia' detected but 'csquotes' missing.
+(biblatex) Loading 'csquotes' recommended.
+
+\@quotelevel=\count277
+\@quotereset=\count278
+(./parent.aux)
+\openout1 = `parent.aux'.
+
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 6.
+LaTeX Font Info: ... okay on input line 6.
+LaTeX Info: Redefining \sptext on input line 6.
+LaTeX Info: Redefining \. on input line 6.
+LaTeX Info: Redefining \% on input line 6.
+Package biblatex Info: No input encoding detected.
+(biblatex) Assuming 'ascii'.
+Package biblatex Info: Automatic encoding selection.
+(biblatex) Assuming data encoding 'ascii'.
+\openout4 = `parent.bcf'.
+
+Package biblatex Info: Trying to load bibliographic data...
+Package biblatex Info: ... file 'parent.bbl' not found.
+
+No file parent.bbl.
+Package biblatex Info: Reference section=0 on input line 6.
+Package biblatex Info: Reference segment=0 on input line 6.
+(./parent.aux)
+
+LaTeX Warning: There were undefined references.
+
+Package biblatex Warning: Please (re)run Biber on the file:
+(biblatex) parent
+(biblatex) and rerun LaTeX afterwards.
+
+Package logreq Info: Writing requests to 'parent.run.xml'.
+\openout1 = `parent.run.xml'.
+
+)
+Here is how much of TeX's memory you used:
+7717 strings out of 492995
+133301 string characters out of 6138727
+557258 words of memory out of 5000000
+11248 multiletter control sequences out of 15000+600000
+3640 words of font info for 14 fonts, out of 8000000 for 9000
+1141 hyphenation exceptions out of 8191
+35i,1n,30p,856b,700s stack positions out of 5000i,500n,10000p,200000b,80000s
+
+No pages of output.
+PDF statistics:
+0 PDF objects out of 1000 (max. 8388607)
+0 named destinations out of 1000 (max. 500000)
+1 words of extra memory for PDF output out of 10000 (max. 10000000) \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/build_log/006.txt b/support/texlab/src/parser/test_data/build_log/006.txt
new file mode 100644
index 0000000000..3edb18b8c7
--- /dev/null
+++ b/support/texlab/src/parser/test_data/build_log/006.txt
@@ -0,0 +1,122 @@
+This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:33
+entering extended mode
+restricted \write18 enabled.
+%&-line parsing enabled.
+**./parent.tex
+(./parent.tex
+LaTeX2e <2017-04-15>
+Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
+(/TexLive/texmf-dist/tex/latex/base/article.cls
+Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
+(/TexLive/texmf-dist/tex/latex/base/size10.clo
+File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
+)
+\c@part=\count79
+\c@section=\count80
+\c@subsection=\count81
+\c@subsubsection=\count82
+\c@paragraph=\count83
+\c@subparagraph=\count84
+\c@figure=\count85
+\c@table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+) (./parent.aux
+(./child.tex.aux))
+\openout1 = `parent.aux'.
+
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+\openout2 = `child.aux'.
+
+(./child.tex)
+! Undefined control sequence.
+l.7 \foo
+
+The control sequence at the end of the top line
+of your error message was never \def'ed. If you have
+misspelled it (e.g., `\hobx'), type `I' and the correct
+spelling (e.g., `I\hbox'). Otherwise just continue,
+and I'll forget about whatever was undefined.
+
+! Missing $ inserted.
+<inserted text>
+ $
+l.8 \bar
+
+I've inserted a begin-math/end-math symbol since I think
+you left one out. Proceed, with fingers crossed.
+
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <7> on input line 8.
+LaTeX Font Info: External font `cmex10' loaded for size
+(Font) <5> on input line 8.
+! Undefined control sequence.
+l.9 \baz
+
+The control sequence at the end of the top line
+of your error message was never \def'ed. If you have
+misspelled it (e.g., `\hobx'), type `I' and the correct
+spelling (e.g., `I\hbox'). Otherwise just continue,
+and I'll forget about whatever was undefined.
+
+! Missing { inserted.
+<to be read again>
+ \par
+l.10
+
+A left brace was mandatory here, so I've put one in.
+You might want to delete and/or insert some corrections
+so that I will find a matching right brace soon.
+(If you're confused by all this, try typing `I}' now.)
+
+! Missing $ inserted.
+<inserted text>
+ $
+l.10
+
+I've inserted a begin-math/end-math symbol since I think
+you left one out. Proceed, with fingers crossed.
+
+! Missing } inserted.
+<inserted text>
+ }
+l.10
+
+I've inserted something that you may have forgotten.
+(See the <inserted text> above.)
+With luck, this will get me unwedged. But if you
+really didn't forget anything, try typing `2' now; then
+my insertion and my current dilemma will both disappear.
+
+[1
+
+{/TexLive/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./parent.aux
+(./child.aux)) )
+Here is how much of TeX's memory you used:
+212 strings out of 492995
+2238 string characters out of 6138727
+54074 words of memory out of 5000000
+3843 multiletter control sequences out of 15000+600000
+3640 words of font info for 14 fonts, out of 8000000 for 9000
+1141 hyphenation exceptions out of 8191
+23i,4n,17p,116b,107s stack positions out of 5000i,500n,10000p,200000b,80000s
+</TexLive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb
+>
+Output written on parent.pdf (1 page, 8329 bytes).
+PDF statistics:
+12 PDF objects out of 1000 (max. 8388607)
+7 compressed objects within 1 object stream
+0 named destinations out of 1000 (max. 500000)
+1 words of extra memory for PDF output out of 10000 (max. 10000000) \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/build_log/007.txt b/support/texlab/src/parser/test_data/build_log/007.txt
new file mode 100644
index 0000000000..4c86405c0d
--- /dev/null
+++ b/support/texlab/src/parser/test_data/build_log/007.txt
@@ -0,0 +1,176 @@
+This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021/W32TeX) (preloaded format=pdflatex 2021.6.19) 5 NOV 2021 19:10
+entering extended mode
+restricted \write18 enabled.
+%&-line parsing enabled.
+**/some/folder/a.tex
+(/some/folder/a.tex
+LaTeX2e <2021-06-01> patch level 1
+L3 programming layer <2021-06-18>
+(/texlive/2021/texmf-dist/tex/latex/koma-script/scrartcl.cls
+Document Class: scrartcl 2021/03/17 v3.33 KOMA-Script document class (article)
+(/texlive/2021/texmf-dist/tex/latex/koma-script/scrkbase.sty
+Package: scrkbase 2021/03/17 v3.33 KOMA-Script package (KOMA-Script-dependent b
+asics and keyval usage)
+
+(/texlive/2021/texmf-dist/tex/latex/koma-script/scrbase.sty
+Package: scrbase 2021/03/17 v3.33 KOMA-Script package (KOMA-Script-independent
+basics and keyval usage)
+
+(/texlive/2021/texmf-dist/tex/latex/koma-script/scrlfile.sty
+Package: scrlfile 2021/03/17 v3.33 KOMA-Script package (file load hooks)
+
+(/texlive/2021/texmf-dist/tex/latex/koma-script/scrlfile-hook.sty
+Package: scrlfile-hook 2021/03/17 v3.33 KOMA-Script package (using LaTeX hooks)
+
+
+(/texlive/2021/texmf-dist/tex/latex/koma-script/scrlogo.sty
+Package: scrlogo 2021/03/17 v3.33 KOMA-Script package (logo)
+)))
+(/texlive/2021/texmf-dist/tex/latex/graphics/keyval.sty
+Package: keyval 2014/10/28 v1.15 key=value parser (DPC)
+\KV@toks@=\toks16
+)
+Applying: [2021/05/01] Usage of raw option list on input line 252.
+Already applied: [0000/00/00] compatibility for LaTeX before 2021/05/01 on inpu
+t line 337.
+))
+==> First Aid for scrkbase.sty no longer applied!
+(/texlive/2021/texmf-dist/tex/latex/koma-script/tocbasic.sty
+Package: tocbasic 2021/03/17 v3.33 KOMA-Script package (handling toc-files)
+\scr@dte@tocline@numberwidth=\skip47
+\scr@dte@tocline@numbox=\box50
+)
+Package tocbasic Info: babel extension for `toc' omitted
+(tocbasic) because of missing \bbl@set@language on input line 135.
+Class scrartcl Info: File `scrsize11pt.clo' used instead of
+(scrartcl) file `scrsize11.clo' to setup font sizes on input line 223
+9.
+
+(/texlive/2021/texmf-dist/tex/latex/koma-script/scrsize11pt.clo
+File: scrsize11pt.clo 2021/03/17 v3.33 KOMA-Script font size class option (11pt
+)
+)
+(/texlive/2021/texmf-dist/tex/latex/koma-script/typearea.sty
+Package: typearea 2021/03/17 v3.33 KOMA-Script package (type area)
+\ta@bcor=\skip48
+\ta@div=\count182
+\ta@hblk=\skip49
+\ta@vblk=\skip50
+\ta@temp=\skip51
+\footheight=\skip52
+Package typearea Info: These are the values describing the layout:
+(typearea) DIV = 10
+(typearea) BCOR = 0.0pt
+(typearea) \paperwidth = 597.50793pt
+(typearea) \textwidth = 418.25555pt
+(typearea) DIV departure = -6%
+(typearea) \evensidemargin = 17.3562pt
+(typearea) \oddsidemargin = 17.3562pt
+(typearea) \paperheight = 845.04694pt
+(typearea) \textheight = 595.80026pt
+(typearea) \topmargin = -25.16531pt
+(typearea) \headheight = 17.0pt
+(typearea) \headsep = 20.40001pt
+(typearea) \topskip = 11.0pt
+(typearea) \footskip = 47.6pt
+(typearea) \baselineskip = 13.6pt
+(typearea) on input line 1741.
+)
+\c@part=\count183
+\c@section=\count184
+\c@subsection=\count185
+\c@subsubsection=\count186
+\c@paragraph=\count187
+\c@subparagraph=\count188
+\scr@dte@section@maxnumwidth=\skip53
+Class scrartcl Info: using compatibility default `runin=bysign'
+(scrartcl) for `\section on input line 4846.
+Class scrartcl Info: using compatibility default `afterindent=bysign'
+(scrartcl) for `\section on input line 4846.
+\scr@dte@part@maxnumwidth=\skip54
+Class scrartcl Info: using compatibility default `afterindent=false'
+(scrartcl) for `\part on input line 4854.
+\scr@dte@subsection@maxnumwidth=\skip55
+Class scrartcl Info: using compatibility default `runin=bysign'
+(scrartcl) for `\subsection on input line 4864.
+Class scrartcl Info: using compatibility default `afterindent=bysign'
+(scrartcl) for `\subsection on input line 4864.
+\scr@dte@subsubsection@maxnumwidth=\skip56
+Class scrartcl Info: using compatibility default `runin=bysign'
+(scrartcl) for `\subsubsection on input line 4874.
+Class scrartcl Info: using compatibility default `afterindent=bysign'
+(scrartcl) for `\subsubsection on input line 4874.
+\scr@dte@paragraph@maxnumwidth=\skip57
+Class scrartcl Info: using compatibility default `runin=bysign'
+(scrartcl) for `\paragraph on input line 4885.
+Class scrartcl Info: using compatibility default `afterindent=bysign'
+(scrartcl) for `\paragraph on input line 4885.
+\scr@dte@subparagraph@maxnumwidth=\skip58
+Class scrartcl Info: using compatibility default `runin=bysign'
+(scrartcl) for `\subparagraph on input line 4895.
+Class scrartcl Info: using compatibility default `afterindent=bysign'
+(scrartcl) for `\subparagraph on input line 4895.
+\abovecaptionskip=\skip59
+\belowcaptionskip=\skip60
+\c@pti@nb@sid@b@x=\box51
+Package tocbasic Info: babel extension for `lof' omitted
+(tocbasic) because of missing \bbl@set@language on input line 6127.
+
+\scr@dte@figure@maxnumwidth=\skip61
+\c@figure=\count189
+Package tocbasic Info: babel extension for `lot' omitted
+(tocbasic) because of missing \bbl@set@language on input line 6139.
+
+\scr@dte@table@maxnumwidth=\skip62
+\c@table=\count190
+Class scrartcl Info: Redefining `\numberline' on input line 6303.
+\bibindent=\dimen138
+)
+(/texlive/2021/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def
+File: l3backend-pdftex.def 2021-05-07 L3 backend support: PDF output (pdfTeX)
+\l__color_backend_stack_int=\count191
+\l__pdf_internal_box=\box52
+) (./a.aux)
+\openout1 = `a.aux'.
+
+LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 3.
+LaTeX Font Info: ... okay on input line 3.
+Package scrbase Info: activating english \contentsname on input line 3.
+Package scrbase Info: activating english \listfigurename on input line 3.
+Package scrbase Info: activating english \listtablename on input line 3.
+! Undefined control sequence.
+l.4 \lsdkfjlskdfj
+
+The control sequence at the end of the top line
+of your error message was never \def'ed. If you have
+misspelled it (e.g., `\hobx'), type `I' and the correct
+spelling (e.g., `I\hbox'). Otherwise just continue,
+and I'll forget about whatever was undefined.
+
+(./a.aux) )
+Here is how much of TeX's memory you used:
+3199 strings out of 478510
+74549 string characters out of 5853586
+510929 words of memory out of 5000000
+21227 multiletter control sequences out of 15000+600000
+403730 words of font info for 28 fonts, out of 8000000 for 9000
+1141 hyphenation exceptions out of 8191
+108i,1n,108p,10625b,270s stack positions out of 5000i,500n,10000p,200000b,80000s
+
+No pages of output.
+PDF statistics:
+0 PDF objects out of 1000 (max. 8388607)
+0 named destinations out of 1000 (max. 500000)
+1 words of extra memory for PDF output out of 10000 (max. 10000000) \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/block_comments.txt b/support/texlab/src/parser/test_data/latex/block_comments.txt
new file mode 100644
index 0000000000..d4e63ab1c8
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/block_comments.txt
@@ -0,0 +1,9 @@
+Foo
+\iffalse
+Test1
+\fi
+Bar
+\iffalse
+\fii
+\fi
+Baz \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/caption/caption_default.txt b/support/texlab/src/parser/test_data/latex/caption/caption_default.txt
new file mode 100644
index 0000000000..9084f143bf
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/caption/caption_default.txt
@@ -0,0 +1 @@
+\caption[qux]{Foo \Bar Baz} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/caption/caption_default_error.txt b/support/texlab/src/parser/test_data/latex/caption/caption_default_error.txt
new file mode 100644
index 0000000000..62e5962816
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/caption/caption_default_error.txt
@@ -0,0 +1 @@
+\caption[qux]{Foo \Bar Baz \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/caption/caption_figure.txt b/support/texlab/src/parser/test_data/latex/caption/caption_figure.txt
new file mode 100644
index 0000000000..8a1d3067d8
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/caption/caption_figure.txt
@@ -0,0 +1 @@
+\begin{figure}\caption{Foo}\end{figure} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/caption/caption_minimal.txt b/support/texlab/src/parser/test_data/latex/caption/caption_minimal.txt
new file mode 100644
index 0000000000..07af0af8ca
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/caption/caption_minimal.txt
@@ -0,0 +1 @@
+\caption{Foo \Bar Baz} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/caption/caption_minimal_error.txt b/support/texlab/src/parser/test_data/latex/caption/caption_minimal_error.txt
new file mode 100644
index 0000000000..747db731c1
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/caption/caption_minimal_error.txt
@@ -0,0 +1 @@
+\caption{Foo \Bar Baz \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/citation/citation_empty.txt b/support/texlab/src/parser/test_data/latex/citation/citation_empty.txt
new file mode 100644
index 0000000000..06704b89a4
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/citation/citation_empty.txt
@@ -0,0 +1 @@
+\cite{} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/citation/citation_missing_brace.txt b/support/texlab/src/parser/test_data/latex/citation/citation_missing_brace.txt
new file mode 100644
index 0000000000..1f8e4c9310
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/citation/citation_missing_brace.txt
@@ -0,0 +1 @@
+\cite{foo \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/citation/citation_multiple_keys.txt b/support/texlab/src/parser/test_data/latex/citation/citation_multiple_keys.txt
new file mode 100644
index 0000000000..be5da02c62
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/citation/citation_multiple_keys.txt
@@ -0,0 +1 @@
+\cite{foo, bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/citation/citation_prenote.txt b/support/texlab/src/parser/test_data/latex/citation/citation_prenote.txt
new file mode 100644
index 0000000000..5ae28c28ec
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/citation/citation_prenote.txt
@@ -0,0 +1 @@
+\cite[foo]{bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/citation/citation_prenote_postnote.txt b/support/texlab/src/parser/test_data/latex/citation/citation_prenote_postnote.txt
new file mode 100644
index 0000000000..23103b2476
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/citation/citation_prenote_postnote.txt
@@ -0,0 +1 @@
+\cite[foo][bar]{baz} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/citation/citation_redundant_comma.txt b/support/texlab/src/parser/test_data/latex/citation/citation_redundant_comma.txt
new file mode 100644
index 0000000000..68e3c2d36e
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/citation/citation_redundant_comma.txt
@@ -0,0 +1 @@
+\cite{,foo,} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/citation/citation_simple.txt b/support/texlab/src/parser/test_data/latex/citation/citation_simple.txt
new file mode 100644
index 0000000000..cd5809ef25
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/citation/citation_simple.txt
@@ -0,0 +1 @@
+\cite{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/citation/citation_star.txt b/support/texlab/src/parser/test_data/latex/citation/citation_star.txt
new file mode 100644
index 0000000000..d1a2677021
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/citation/citation_star.txt
@@ -0,0 +1 @@
+\nocite{*} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/color/color_definition_simple.txt b/support/texlab/src/parser/test_data/latex/color/color_definition_simple.txt
new file mode 100644
index 0000000000..e8b58c8162
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/color/color_definition_simple.txt
@@ -0,0 +1 @@
+\definecolor{foo}{rgb}{255,168,0} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/color/color_reference_simple.txt b/support/texlab/src/parser/test_data/latex/color/color_reference_simple.txt
new file mode 100644
index 0000000000..4fea2b24ec
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/color/color_reference_simple.txt
@@ -0,0 +1 @@
+\color{black} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/color/color_set_definition_error1.txt b/support/texlab/src/parser/test_data/latex/color/color_set_definition_error1.txt
new file mode 100644
index 0000000000..f377ffcf2f
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/color/color_set_definition_error1.txt
@@ -0,0 +1 @@
+\definecolorset[ty]{rgb,HTML}{foo}{bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/color/color_set_definition_error2.txt b/support/texlab/src/parser/test_data/latex/color/color_set_definition_error2.txt
new file mode 100644
index 0000000000..0b5fa35868
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/color/color_set_definition_error2.txt
@@ -0,0 +1 @@
+\definecolorset{rgb,HTML}{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/color/color_set_definition_error3.txt b/support/texlab/src/parser/test_data/latex/color/color_set_definition_error3.txt
new file mode 100644
index 0000000000..fb695b4530
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/color/color_set_definition_error3.txt
@@ -0,0 +1 @@
+\definecolorset{rgb,HTML} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/color/color_set_definition_error4.txt b/support/texlab/src/parser/test_data/latex/color/color_set_definition_error4.txt
new file mode 100644
index 0000000000..7c494133bf
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/color/color_set_definition_error4.txt
@@ -0,0 +1 @@
+\definecolorset \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/color/color_set_definition_simple.txt b/support/texlab/src/parser/test_data/latex/color/color_set_definition_simple.txt
new file mode 100644
index 0000000000..c812e61041
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/color/color_set_definition_simple.txt
@@ -0,0 +1 @@
+\definecolorset[ty]{rgb,HTML}{foo}{bar}{baz} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_argc.txt b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_argc.txt
new file mode 100644
index 0000000000..ef63ef62cb
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_argc.txt
@@ -0,0 +1 @@
+\newcommand{\foo}{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_impl.txt b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_impl.txt
new file mode 100644
index 0000000000..5ffc7e97c2
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_impl.txt
@@ -0,0 +1 @@
+\newcommand{\foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_impl_error.txt b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_impl_error.txt
new file mode 100644
index 0000000000..9323f5a313
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_no_impl_error.txt
@@ -0,0 +1 @@
+\newcommand{\foo \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/command_definition/command_definition_optional.txt b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_optional.txt
new file mode 100644
index 0000000000..c3fb7225f3
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_optional.txt
@@ -0,0 +1 @@
+\newcommand{\foo}[1][def]{#1} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/command_definition/command_definition_simple.txt b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_simple.txt
new file mode 100644
index 0000000000..ffce86f21c
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_simple.txt
@@ -0,0 +1 @@
+\newcommand[1]{\id}{#1} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/command_definition/command_definition_with_begin.txt b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_with_begin.txt
new file mode 100644
index 0000000000..e7ce7984cb
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/command_definition/command_definition_with_begin.txt
@@ -0,0 +1 @@
+\newcommand{\CVSubHeadingListStart}{\begin{itemize}[leftmargin=0.5cm, label={}]} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/command_definition/math_operator_no_impl.txt b/support/texlab/src/parser/test_data/latex/command_definition/math_operator_no_impl.txt
new file mode 100644
index 0000000000..685be22ce6
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/command_definition/math_operator_no_impl.txt
@@ -0,0 +1 @@
+\DeclareMathOperator{\foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/command_definition/math_operator_simple.txt b/support/texlab/src/parser/test_data/latex/command_definition/math_operator_simple.txt
new file mode 100644
index 0000000000..ffbf671f74
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/command_definition/math_operator_simple.txt
@@ -0,0 +1 @@
+\DeclareMathOperator{\foo}{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/environment/environment_asymptote.txt b/support/texlab/src/parser/test_data/latex/environment/environment_asymptote.txt
new file mode 100644
index 0000000000..76646075ea
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/environment/environment_asymptote.txt
@@ -0,0 +1,3 @@
+\begin{asy}
+ printf("Hello World\n");
+\end{asy} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/environment/environment_definition.txt b/support/texlab/src/parser/test_data/latex/environment/environment_definition.txt
new file mode 100644
index 0000000000..d3a5291dca
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/environment/environment_definition.txt
@@ -0,0 +1 @@
+\newenvironment{bar}[1]{\begin{foo}}{\end{foo}} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/environment/environment_definition_optional_arg.txt b/support/texlab/src/parser/test_data/latex/environment/environment_definition_optional_arg.txt
new file mode 100644
index 0000000000..bead3228a4
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/environment/environment_definition_optional_arg.txt
@@ -0,0 +1 @@
+\newenvironment{foo}[1][default]{begin}{end} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/environment/environment_nested.txt b/support/texlab/src/parser/test_data/latex/environment/environment_nested.txt
new file mode 100644
index 0000000000..8d84019ac7
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/environment/environment_nested.txt
@@ -0,0 +1 @@
+\begin{foo} \begin{qux} \end{baz} \end{bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/environment/environment_nested_missing_braces.txt b/support/texlab/src/parser/test_data/latex/environment/environment_nested_missing_braces.txt
new file mode 100644
index 0000000000..35ce901a83
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/environment/environment_nested_missing_braces.txt
@@ -0,0 +1 @@
+\begin{foo \begin{qux Hello World \end{baz} \end{bar \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/environment/environment_simple.txt b/support/texlab/src/parser/test_data/latex/environment/environment_simple.txt
new file mode 100644
index 0000000000..309b559957
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/environment/environment_simple.txt
@@ -0,0 +1 @@
+\begin{foo} Hello World \end{bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/equation.txt b/support/texlab/src/parser/test_data/latex/equation.txt
new file mode 100644
index 0000000000..7f85196961
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/equation.txt
@@ -0,0 +1 @@
+\[ foo bar \] \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/equation_missing_begin.txt b/support/texlab/src/parser/test_data/latex/equation_missing_begin.txt
new file mode 100644
index 0000000000..9e5707b196
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/equation_missing_begin.txt
@@ -0,0 +1 @@
+\begin{a} foo bar \] \end{b} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/generic_command_args.txt b/support/texlab/src/parser/test_data/latex/generic_command_args.txt
new file mode 100644
index 0000000000..2d62314c5c
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/generic_command_args.txt
@@ -0,0 +1 @@
+\foo{bar}[qux] \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/generic_command_empty.txt b/support/texlab/src/parser/test_data/latex/generic_command_empty.txt
new file mode 100644
index 0000000000..eeb4a48255
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/generic_command_empty.txt
@@ -0,0 +1 @@
+\foo \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/generic_command_escape.txt b/support/texlab/src/parser/test_data/latex/generic_command_escape.txt
new file mode 100644
index 0000000000..133d674d1e
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/generic_command_escape.txt
@@ -0,0 +1 @@
+\# \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/glossary/acronym_declaration.txt b/support/texlab/src/parser/test_data/latex/glossary/acronym_declaration.txt
new file mode 100644
index 0000000000..abf12b6cae
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/acronym_declaration.txt
@@ -0,0 +1 @@
+\DeclareAcronym{eg}{short = e.g,long = for example,tag = abbrev} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/glossary/acronym_definition_options.txt b/support/texlab/src/parser/test_data/latex/glossary/acronym_definition_options.txt
new file mode 100644
index 0000000000..47a69067ca
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/acronym_definition_options.txt
@@ -0,0 +1 @@
+\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/glossary/acronym_definition_simple.txt b/support/texlab/src/parser/test_data/latex/glossary/acronym_definition_simple.txt
new file mode 100644
index 0000000000..4fbf285927
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/acronym_definition_simple.txt
@@ -0,0 +1 @@
+\newacronym{fpsLabel}{FPS}{Frame per Second} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/glossary/acronym_package.txt b/support/texlab/src/parser/test_data/latex/glossary/acronym_package.txt
new file mode 100644
index 0000000000..86e60c4584
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/acronym_package.txt
@@ -0,0 +1 @@
+\acro{fps}[FPS]{Frames per Second}
diff --git a/support/texlab/src/parser/test_data/latex/glossary/acronym_reference_options.txt b/support/texlab/src/parser/test_data/latex/glossary/acronym_reference_options.txt
new file mode 100644
index 0000000000..43fd03f12b
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/acronym_reference_options.txt
@@ -0,0 +1 @@
+\acrshort[foo=bar,baz]{fpsLabel} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/glossary/acronym_reference_simple.txt b/support/texlab/src/parser/test_data/latex/glossary/acronym_reference_simple.txt
new file mode 100644
index 0000000000..d9fb5b9a25
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/acronym_reference_simple.txt
@@ -0,0 +1 @@
+\acrshort{fpsLabel} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_definition_simple.txt b/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_definition_simple.txt
new file mode 100644
index 0000000000..fb1e12899a
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_definition_simple.txt
@@ -0,0 +1 @@
+\newglossaryentry{foo}{bar = baz, qux,} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_reference_options.txt b/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_reference_options.txt
new file mode 100644
index 0000000000..fbae075e1d
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_reference_options.txt
@@ -0,0 +1 @@
+\gls[foo = bar, qux]{baz} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_reference_simple.txt b/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_reference_simple.txt
new file mode 100644
index 0000000000..a603355f0f
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/glossary/glossary_entry_reference_simple.txt
@@ -0,0 +1 @@
+\gls{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/graphics_path.txt b/support/texlab/src/parser/test_data/latex/graphics_path.txt
new file mode 100644
index 0000000000..0e9f431c36
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/graphics_path.txt
@@ -0,0 +1 @@
+\graphicspath{{../figures/}} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/graphics_path_command.txt b/support/texlab/src/parser/test_data/latex/graphics_path_command.txt
new file mode 100644
index 0000000000..729ee51690
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/graphics_path_command.txt
@@ -0,0 +1 @@
+\graphicspath{{\subfix{./img/}}} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/graphics_path_options.txt b/support/texlab/src/parser/test_data/latex/graphics_path_options.txt
new file mode 100644
index 0000000000..ae8aa84d86
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/graphics_path_options.txt
@@ -0,0 +1 @@
+\graphicspath[foo]{{../figures/}} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/group/curly_group_missing_end.txt b/support/texlab/src/parser/test_data/latex/group/curly_group_missing_end.txt
new file mode 100644
index 0000000000..6c7b76c0f8
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/group/curly_group_missing_end.txt
@@ -0,0 +1 @@
+{hello world \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/group/curly_group_simple.txt b/support/texlab/src/parser/test_data/latex/group/curly_group_simple.txt
new file mode 100644
index 0000000000..5084aae70a
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/group/curly_group_simple.txt
@@ -0,0 +1 @@
+{hello world} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/group/equation_missing_end.txt b/support/texlab/src/parser/test_data/latex/group/equation_missing_end.txt
new file mode 100644
index 0000000000..fcb715926a
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/group/equation_missing_end.txt
@@ -0,0 +1 @@
+\begin{a} \[ foo bar \end{b} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/group/escaped_brackets.txt b/support/texlab/src/parser/test_data/latex/group/escaped_brackets.txt
new file mode 100644
index 0000000000..144a5fdd6d
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/group/escaped_brackets.txt
@@ -0,0 +1 @@
+{[}{]} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/group/unmatched_braces.txt b/support/texlab/src/parser/test_data/latex/group/unmatched_braces.txt
new file mode 100644
index 0000000000..8f606b7dbe
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/group/unmatched_braces.txt
@@ -0,0 +1 @@
+}{ \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/group/unmatched_brackets.txt b/support/texlab/src/parser/test_data/latex/group/unmatched_brackets.txt
new file mode 100644
index 0000000000..94ea4d5c96
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/group/unmatched_brackets.txt
@@ -0,0 +1 @@
+][ \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/group/unmatched_brackets_with_group.txt b/support/texlab/src/parser/test_data/latex/group/unmatched_brackets_with_group.txt
new file mode 100644
index 0000000000..ebf6229429
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/group/unmatched_brackets_with_group.txt
@@ -0,0 +1 @@
+{][} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/hello_world.txt b/support/texlab/src/parser/test_data/latex/hello_world.txt
new file mode 100644
index 0000000000..c57eff55eb
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/hello_world.txt
@@ -0,0 +1 @@
+Hello World! \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/biblatex_include_options.txt b/support/texlab/src/parser/test_data/latex/include/biblatex_include_options.txt
new file mode 100644
index 0000000000..216e7ea165
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/biblatex_include_options.txt
@@ -0,0 +1 @@
+\addbibresource[foo=bar, baz]{foo/bar.bib} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/biblatex_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/biblatex_include_simple.txt
new file mode 100644
index 0000000000..fe10ce257d
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/biblatex_include_simple.txt
@@ -0,0 +1 @@
+\addbibresource{foo/bar.bib} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/bibtex_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/bibtex_include_simple.txt
new file mode 100644
index 0000000000..955353f690
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/bibtex_include_simple.txt
@@ -0,0 +1 @@
+\bibliography{foo/bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/class_include_empty.txt b/support/texlab/src/parser/test_data/latex/include/class_include_empty.txt
new file mode 100644
index 0000000000..144b418175
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/class_include_empty.txt
@@ -0,0 +1 @@
+\documentclass{} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/class_include_options.txt b/support/texlab/src/parser/test_data/latex/include/class_include_options.txt
new file mode 100644
index 0000000000..32dc4279d7
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/class_include_options.txt
@@ -0,0 +1 @@
+\documentclass[foo = bar, baz, qux]{article} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/class_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/class_include_simple.txt
new file mode 100644
index 0000000000..15f3d6ea0a
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/class_include_simple.txt
@@ -0,0 +1 @@
+\documentclass{article} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/graphics_include_command.txt b/support/texlab/src/parser/test_data/latex/include/graphics_include_command.txt
new file mode 100644
index 0000000000..14a4a96216
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/graphics_include_command.txt
@@ -0,0 +1 @@
+\includegraphics[width=0.5\textwidth]{\foo.\bar.pdf} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/graphics_include_complicated_options.txt b/support/texlab/src/parser/test_data/latex/include/graphics_include_complicated_options.txt
new file mode 100644
index 0000000000..d6b6910c14
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/graphics_include_complicated_options.txt
@@ -0,0 +1 @@
+\includegraphics[width=0.5\textwidth]{} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/graphics_include_options.txt b/support/texlab/src/parser/test_data/latex/include/graphics_include_options.txt
new file mode 100644
index 0000000000..8d3c45f2a5
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/graphics_include_options.txt
@@ -0,0 +1 @@
+\includegraphics[scale=.5]{foo/bar.pdf} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/graphics_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/graphics_include_simple.txt
new file mode 100644
index 0000000000..629cf3e8a9
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/graphics_include_simple.txt
@@ -0,0 +1 @@
+\includegraphics{foo/bar.pdf} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/import_incomplete.txt b/support/texlab/src/parser/test_data/latex/include/import_incomplete.txt
new file mode 100644
index 0000000000..3d6bc5f043
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/import_incomplete.txt
@@ -0,0 +1 @@
+\import{foo \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/import_simple.txt b/support/texlab/src/parser/test_data/latex/include/import_simple.txt
new file mode 100644
index 0000000000..f38059d6c1
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/import_simple.txt
@@ -0,0 +1 @@
+\import{foo}{bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/inkscape_include_options.txt b/support/texlab/src/parser/test_data/latex/include/inkscape_include_options.txt
new file mode 100644
index 0000000000..e6dd431c7c
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/inkscape_include_options.txt
@@ -0,0 +1 @@
+\includesvg[scale=.5]{foo/bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/inkscape_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/inkscape_include_simple.txt
new file mode 100644
index 0000000000..4e3a4ea9ba
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/inkscape_include_simple.txt
@@ -0,0 +1 @@
+\includesvg{foo/bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/latex_include_equality_sign.txt b/support/texlab/src/parser/test_data/latex/include/latex_include_equality_sign.txt
new file mode 100644
index 0000000000..5a763b4e29
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/latex_include_equality_sign.txt
@@ -0,0 +1 @@
+\include{foo=bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/latex_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/latex_include_simple.txt
new file mode 100644
index 0000000000..c0d3d390df
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/latex_include_simple.txt
@@ -0,0 +1 @@
+\include{foo/bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/latex_input_path_brackets.txt b/support/texlab/src/parser/test_data/latex/include/latex_input_path_brackets.txt
new file mode 100644
index 0000000000..6585f50d52
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/latex_input_path_brackets.txt
@@ -0,0 +1 @@
+\input{foo[bar].tex} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/package_include_empty.txt b/support/texlab/src/parser/test_data/latex/include/package_include_empty.txt
new file mode 100644
index 0000000000..09e02cc1cc
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/package_include_empty.txt
@@ -0,0 +1 @@
+\usepackage{} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/package_include_multiple.txt b/support/texlab/src/parser/test_data/latex/include/package_include_multiple.txt
new file mode 100644
index 0000000000..c1080aaf66
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/package_include_multiple.txt
@@ -0,0 +1 @@
+\usepackage{amsmath, lipsum} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/package_include_options.txt b/support/texlab/src/parser/test_data/latex/include/package_include_options.txt
new file mode 100644
index 0000000000..83a50c12cf
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/package_include_options.txt
@@ -0,0 +1 @@
+\usepackage[foo = bar, baz, qux]{amsmath} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/package_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/package_include_simple.txt
new file mode 100644
index 0000000000..3cf1b4edc0
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/package_include_simple.txt
@@ -0,0 +1 @@
+\usepackage{amsmath} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/pgf_library_import_simple.txt b/support/texlab/src/parser/test_data/latex/include/pgf_library_import_simple.txt
new file mode 100644
index 0000000000..25a2b24720
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/pgf_library_import_simple.txt
@@ -0,0 +1 @@
+\usepgflibrary{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/svg_include_options.txt b/support/texlab/src/parser/test_data/latex/include/svg_include_options.txt
new file mode 100644
index 0000000000..3eb90568ab
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/svg_include_options.txt
@@ -0,0 +1 @@
+\includesvg[scale=.5]{foo/bar.svg} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/svg_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/svg_include_simple.txt
new file mode 100644
index 0000000000..964a3adcd6
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/svg_include_simple.txt
@@ -0,0 +1 @@
+\includesvg{foo/bar.svg} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/tikz_library_import_simple.txt b/support/texlab/src/parser/test_data/latex/include/tikz_library_import_simple.txt
new file mode 100644
index 0000000000..ff616ebd11
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/tikz_library_import_simple.txt
@@ -0,0 +1 @@
+\usetikzlibrary{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/include/verbatim_include_simple.txt b/support/texlab/src/parser/test_data/latex/include/verbatim_include_simple.txt
new file mode 100644
index 0000000000..a0b3fec843
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/include/verbatim_include_simple.txt
@@ -0,0 +1 @@
+\verbatiminput{foo/bar.txt} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/inline.txt b/support/texlab/src/parser/test_data/latex/inline.txt
new file mode 100644
index 0000000000..81a429dc26
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/inline.txt
@@ -0,0 +1 @@
+$x \in [0, \infty)$ \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/inline_double_dollar.txt b/support/texlab/src/parser/test_data/latex/inline_double_dollar.txt
new file mode 100644
index 0000000000..c3a7fee9f6
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/inline_double_dollar.txt
@@ -0,0 +1 @@
+$$x \in [0, \infty)$$ \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/issue_745.txt b/support/texlab/src/parser/test_data/latex/issue_745.txt
new file mode 100644
index 0000000000..4cbebeb2d8
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/issue_745.txt
@@ -0,0 +1,21 @@
+\documentclass{article}
+\usepackage{tabularray}
+
+\ExplSyntaxOn
+\NewDocumentEnvironment{exptblr}{O{}m}
+ {
+ \use:x
+ {
+ \exp_not:N \begin{tblr}
+ [\exp_not:n{#1}]
+ {#2}
+ }
+ }
+ {
+ \end{tblr}
+ }
+\ExplSyntaxOff
+
+\begin{document}
+
+\end{document} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/issue_789.txt b/support/texlab/src/parser/test_data/latex/issue_789.txt
new file mode 100644
index 0000000000..612c6de786
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/issue_789.txt
@@ -0,0 +1 @@
+\graphicspath{test} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_definition_line_break.txt b/support/texlab/src/parser/test_data/latex/label/label_definition_line_break.txt
new file mode 100644
index 0000000000..d567c6d25a
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_definition_line_break.txt
@@ -0,0 +1,2 @@
+\label{hello
+world} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_definition_simple.txt b/support/texlab/src/parser/test_data/latex/label/label_definition_simple.txt
new file mode 100644
index 0000000000..43ebaf1cec
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_definition_simple.txt
@@ -0,0 +1 @@
+\label{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_number.txt b/support/texlab/src/parser/test_data/latex/label/label_number.txt
new file mode 100644
index 0000000000..6e994af500
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_number.txt
@@ -0,0 +1 @@
+\newlabel{foo}{{1.1}} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_reference_equation.txt b/support/texlab/src/parser/test_data/latex/label/label_reference_equation.txt
new file mode 100644
index 0000000000..ab386645df
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_reference_equation.txt
@@ -0,0 +1 @@
+\eqref{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_reference_incomplete.txt b/support/texlab/src/parser/test_data/latex/label/label_reference_incomplete.txt
new file mode 100644
index 0000000000..1d0f79ec8e
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_reference_incomplete.txt
@@ -0,0 +1 @@
+Equation \eqref{eq is a \emph{useful} identity. \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_reference_multiple.txt b/support/texlab/src/parser/test_data/latex/label/label_reference_multiple.txt
new file mode 100644
index 0000000000..e8bb38ee9e
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_reference_multiple.txt
@@ -0,0 +1 @@
+\ref{foo, bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_reference_range_error.txt b/support/texlab/src/parser/test_data/latex/label/label_reference_range_error.txt
new file mode 100644
index 0000000000..9213da0460
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_reference_range_error.txt
@@ -0,0 +1 @@
+\crefrange{foo{bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_reference_range_incomplete.txt b/support/texlab/src/parser/test_data/latex/label/label_reference_range_incomplete.txt
new file mode 100644
index 0000000000..841133d73a
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_reference_range_incomplete.txt
@@ -0,0 +1 @@
+\crefrange{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_reference_range_simple.txt b/support/texlab/src/parser/test_data/latex/label/label_reference_range_simple.txt
new file mode 100644
index 0000000000..a0e985ea88
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_reference_range_simple.txt
@@ -0,0 +1 @@
+\crefrange{foo}{bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/label/label_reference_simple.txt b/support/texlab/src/parser/test_data/latex/label/label_reference_simple.txt
new file mode 100644
index 0000000000..dde4f444f4
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/label/label_reference_simple.txt
@@ -0,0 +1 @@
+\ref{foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/parameter.txt b/support/texlab/src/parser/test_data/latex/parameter.txt
new file mode 100644
index 0000000000..d44ac7b947
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/parameter.txt
@@ -0,0 +1 @@
+#1 \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/parameter_error.txt b/support/texlab/src/parser/test_data/latex/parameter_error.txt
new file mode 100644
index 0000000000..4287ca8617
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/parameter_error.txt
@@ -0,0 +1 @@
+# \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/structure/structure_enum_item.txt b/support/texlab/src/parser/test_data/latex/structure/structure_enum_item.txt
new file mode 100644
index 0000000000..3288ec259b
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/structure/structure_enum_item.txt
@@ -0,0 +1 @@
+\begin{enumerate} \item 1 \item[2] 2 \item 3 \end{enumerate} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/structure/structure_invalid_nesting.txt b/support/texlab/src/parser/test_data/latex/structure/structure_invalid_nesting.txt
new file mode 100644
index 0000000000..7203dd2d24
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/structure/structure_invalid_nesting.txt
@@ -0,0 +1 @@
+\section{Foo} \chapter{Bar} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/structure/structure_nested.txt b/support/texlab/src/parser/test_data/latex/structure/structure_nested.txt
new file mode 100644
index 0000000000..082f10765b
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/structure/structure_nested.txt
@@ -0,0 +1 @@
+\part{1}\chapter{2}\section{3}\subsection{4}\subsubsection{5}\paragraph{6}\subparagraph{7} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/structure/structure_siblings.txt b/support/texlab/src/parser/test_data/latex/structure/structure_siblings.txt
new file mode 100644
index 0000000000..d8e347c429
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/structure/structure_siblings.txt
@@ -0,0 +1 @@
+\section{Foo} Foo \section{Bar} Bar \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_full.txt b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_full.txt
new file mode 100644
index 0000000000..286d111ad1
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_full.txt
@@ -0,0 +1 @@
+\newtheorem{foo}[bar]{Foo}[baz] \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_counter.txt b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_counter.txt
new file mode 100644
index 0000000000..af1b6903a5
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_counter.txt
@@ -0,0 +1 @@
+\newtheorem{foo}[bar] \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description.txt b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description.txt
new file mode 100644
index 0000000000..e5d6551666
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description.txt
@@ -0,0 +1 @@
+\newtheorem{foo}{Foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description_and_counter.txt b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description_and_counter.txt
new file mode 100644
index 0000000000..89c37d9497
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_name_with_description_and_counter.txt
@@ -0,0 +1 @@
+\newtheorem{foo}[bar]{Foo} \ No newline at end of file
diff --git a/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_only_name.txt b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_only_name.txt
new file mode 100644
index 0000000000..62adb2c4b9
--- /dev/null
+++ b/support/texlab/src/parser/test_data/latex/theorem_definition/theorem_definition_only_name.txt
@@ -0,0 +1 @@
+\newtheorem{foo} \ No newline at end of file
diff --git a/support/texlab/src/range.rs b/support/texlab/src/range.rs
deleted file mode 100644
index c70a573f39..0000000000
--- a/support/texlab/src/range.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use lsp_types::{Position, Range};
-
-pub trait RangeExt {
- fn new_simple(start_line: u32, start_character: u32, end_line: u32, end_character: u32)
- -> Self;
-}
-
-impl RangeExt for Range {
- fn new_simple(
- start_line: u32,
- start_character: u32,
- end_line: u32,
- end_character: u32,
- ) -> Self {
- Self {
- start: Position::new(start_line, start_character),
- end: Position::new(end_line, end_character),
- }
- }
-}
diff --git a/support/texlab/src/req_queue.rs b/support/texlab/src/req_queue.rs
deleted file mode 100644
index c1eb7b9594..0000000000
--- a/support/texlab/src/req_queue.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use crossbeam_channel::Sender;
-use lsp_server::ResponseError;
-
-pub struct IncomingData;
-
-pub struct OutgoingData {
- pub(crate) sender: Sender<Result<serde_json::Value, ResponseError>>,
-}
-
-pub type ReqQueue = lsp_server::ReqQueue<IncomingData, OutgoingData>;
diff --git a/support/texlab/src/server.rs b/support/texlab/src/server.rs
index 0d5d1f8fe1..93b35c69c6 100644
--- a/support/texlab/src/server.rs
+++ b/support/texlab/src/server.rs
@@ -1,83 +1,89 @@
+mod dispatch;
+mod query;
+
use std::{
path::PathBuf,
sync::{Arc, Mutex},
- time::Duration,
};
use anyhow::Result;
use crossbeam_channel::{Receiver, Sender};
-use log::{error, info, warn};
-use lsp_server::{Connection, Message, RequestId};
+use log::{error, info};
+use lsp_server::{Connection, ErrorCode, Message, RequestId};
use lsp_types::{notification::*, request::*, *};
-use serde::Serialize;
+use once_cell::sync::Lazy;
+use rowan::{ast::AstNode, TextSize};
+use rustc_hash::FxHashSet;
+use serde::{Deserialize, Serialize};
+use serde_repr::{Deserialize_repr, Serialize_repr};
use threadpool::ThreadPool;
use crate::{
- client::{send_notification, send_request},
- debouncer,
- diagnostics::DiagnosticManager,
- dispatch::{NotificationDispatcher, RequestDispatcher},
- distro::Distribution,
+ citation,
+ client::LspClient,
+ db::{self, discover_dependencies, Document, Language, Owner, Workspace},
+ distro::Distro,
features::{
- execute_command, find_all_references, find_document_highlights, find_document_links,
- find_document_symbols, find_foldings, find_hover, find_workspace_symbols,
- format_source_code, goto_definition, prepare_rename_all, rename_all, BuildEngine,
- BuildParams, BuildResult, BuildStatus, FeatureRequest, ForwardSearchResult,
- ForwardSearchStatus,
+ build::{self, BuildParams, BuildResult, BuildStatus},
+ completion::{self, builder::CompletionItemData},
+ definition, folding, formatting, forward_search, highlight, hover, inlay_hint, link,
+ reference, rename, symbol, workspace_command,
+ },
+ normalize_uri,
+ syntax::bibtex,
+ util::{
+ self, capabilities::ClientCapabilitiesExt, components::COMPONENT_DATABASE,
+ line_index_ext::LineIndexExt,
},
- req_queue::{IncomingData, ReqQueue},
- ClientCapabilitiesExt, Document, DocumentData, DocumentLanguage, Environment, LineIndex,
- LineIndexExt, Options, Workspace, WorkspaceEvent,
+ Db, Options, StartupOptions,
};
#[derive(Debug)]
enum InternalMessage {
- SetDistro(Distribution),
- SetOptions(Arc<Options>),
+ SetDistro(Distro),
+ SetOptions(Options),
+ FileEvent(notify::Event),
+ ForwardSearch(Url),
+ Diagnostics,
+ ChktexResult(Url, Vec<db::diagnostics::Diagnostic>),
}
-#[derive(Clone)]
pub struct Server {
connection: Arc<Connection>,
internal_tx: Sender<InternalMessage>,
internal_rx: Receiver<InternalMessage>,
- req_queue: Arc<Mutex<ReqQueue>>,
- workspace: Workspace,
- diagnostic_tx: debouncer::Sender<Workspace>,
- diagnostic_manager: DiagnosticManager,
- pool: Arc<Mutex<ThreadPool>>,
- load_resolver: bool,
- build_engine: Arc<BuildEngine>,
+ client: LspClient,
+ engine: query::Engine,
+ watcher: FileWatcher,
+ pool: ThreadPool,
}
impl Server {
- pub fn with_connection(
- connection: Connection,
- current_dir: PathBuf,
- load_resolver: bool,
- ) -> Self {
- let req_queue = Arc::default();
- let workspace = Workspace::new(Environment::new(Arc::new(current_dir)));
+ pub fn new(connection: Connection) -> Self {
+ let client = LspClient::new(connection.sender.clone());
let (internal_tx, internal_rx) = crossbeam_channel::unbounded();
- let diagnostic_manager = DiagnosticManager::default();
- let diagnostic_tx = create_debouncer(connection.sender.clone(), diagnostic_manager.clone());
+ let watcher = FileWatcher::new(internal_tx.clone()).expect("init file watcher");
Self {
connection: Arc::new(connection),
internal_tx,
internal_rx,
- req_queue,
- workspace,
- diagnostic_tx,
- diagnostic_manager,
- pool: Arc::new(Mutex::new(threadpool::Builder::new().build())),
- load_resolver,
- build_engine: Arc::default(),
+ client,
+ engine: query::Engine::default(),
+ watcher,
+ pool: threadpool::Builder::new().build(),
}
}
- fn spawn(&self, job: impl FnOnce(Self) + Send + 'static) {
- let server = self.clone();
- self.pool.lock().unwrap().execute(move || job(server));
+ fn run_with_db<R, Q>(&self, id: RequestId, query: Q)
+ where
+ R: Serialize,
+ Q: FnOnce(&dyn Db) -> R + Send + 'static,
+ {
+ let client = self.client.clone();
+ self.engine.fork(move |db| {
+ let response = lsp_server::Response::new_ok(id, query(db));
+ client.send_response(response).unwrap();
+ });
}
fn capabilities(&self) -> ServerCapabilities {
@@ -101,7 +107,6 @@ impl Server {
definition_provider: Some(OneOf::Left(true)),
references_provider: Some(OneOf::Left(true)),
hover_provider: Some(HoverProviderCapability::Simple(true)),
- #[cfg(feature = "completion")]
completion_provider: Some(CompletionOptions {
resolve_provider: Some(true),
trigger_characters: Some(vec![
@@ -129,6 +134,7 @@ impl Server {
],
..Default::default()
}),
+ inlay_hint_provider: Some(OneOf::Left(true)),
..ServerCapabilities::default()
}
}
@@ -137,8 +143,29 @@ impl Server {
let (id, params) = self.connection.initialize_start()?;
let params: InitializeParams = serde_json::from_value(params)?;
- self.workspace.environment.client_capabilities = Arc::new(params.capabilities);
- self.workspace.environment.client_info = params.client_info.map(Arc::new);
+ let db = self.engine.write();
+ let workspace = Workspace::get(db);
+ workspace
+ .set_client_capabilities(db)
+ .with_durability(salsa::Durability::HIGH)
+ .to(params.capabilities);
+
+ workspace
+ .set_client_info(db)
+ .with_durability(salsa::Durability::HIGH)
+ .to(params.client_info);
+
+ let root_dirs = params
+ .workspace_folders
+ .unwrap_or_default()
+ .into_iter()
+ .map(|folder| db::Location::new(db, folder.uri))
+ .collect();
+
+ workspace
+ .set_root_dirs(db)
+ .with_durability(salsa::Durability::HIGH)
+ .to(root_dirs);
let result = InitializeResult {
capabilities: self.capabilities(),
@@ -146,132 +173,109 @@ impl Server {
name: "TexLab".to_owned(),
version: Some(env!("CARGO_PKG_VERSION").to_owned()),
}),
+ offset_encoding: None,
};
self.connection
.initialize_finish(id, serde_json::to_value(result)?)?;
- if self.load_resolver {
- self.spawn(move |server| {
- let distro = Distribution::detect();
- info!("Detected distribution: {}", distro.kind);
+ let StartupOptions { skip_distro } =
+ serde_json::from_value(params.initialization_options.unwrap_or_default())
+ .unwrap_or_default();
- server
- .internal_tx
- .send(InternalMessage::SetDistro(distro))
- .unwrap();
+ if !skip_distro {
+ let sender = self.internal_tx.clone();
+ self.pool.execute(move || {
+ let distro = Distro::detect().unwrap_or_else(|why| {
+ log::warn!("Unable to load distro files: {}", why);
+ Distro::default()
+ });
+
+ info!("Detected distribution: {:?}", distro.kind);
+ sender.send(InternalMessage::SetDistro(distro)).unwrap();
});
}
- self.register_diagnostics_handler();
-
- self.spawn(move |server| {
- server.register_config_capability();
- server.register_file_watching();
- let _ = server.pull_config();
- });
-
+ self.register_configuration();
+ self.pull_options();
Ok(())
}
- fn register_file_watching(&self) {
- if self
- .workspace
- .environment
- .client_capabilities
- .has_file_watching_support()
- {
- let options = DidChangeWatchedFilesRegistrationOptions {
- watchers: vec![FileSystemWatcher {
- glob_pattern: "**/*.{aux,log}".into(),
- kind: Some(WatchKind::Create | WatchKind::Change | WatchKind::Delete),
- }],
- };
-
- let reg = Registration {
- id: "build-watch".to_string(),
- method: DidChangeWatchedFiles::METHOD.to_string(),
- register_options: Some(serde_json::to_value(options).unwrap()),
- };
-
- let params = RegistrationParams {
- registrations: vec![reg],
- };
-
- if let Err(why) =
- send_request::<RegisterCapability>(&self.req_queue, &self.connection.sender, params)
- {
- error!(
- "Failed to register \"{}\" notification: {}",
- DidChangeWatchedFiles::METHOD,
- why
- );
- }
- }
- }
+ fn register_configuration(&mut self) {
+ let db = self.engine.read();
- fn register_config_capability(&self) {
- if self
- .workspace
- .environment
- .client_capabilities
+ if Workspace::get(db)
+ .client_capabilities(db)
.has_push_configuration_support()
{
- let reg = Registration {
+ let registration = Registration {
id: "pull-config".to_string(),
method: DidChangeConfiguration::METHOD.to_string(),
register_options: None,
};
let params = RegistrationParams {
- registrations: vec![reg],
+ registrations: vec![registration],
};
- if let Err(why) =
- send_request::<RegisterCapability>(&self.req_queue, &self.connection.sender, params)
- {
- error!(
- "Failed to register \"{}\" notification: {}",
- DidChangeConfiguration::METHOD,
- why
- );
- }
+ let client = self.client.clone();
+ self.pool.execute(move || {
+ if let Err(why) = client.send_request::<RegisterCapability>(params) {
+ log::error!(
+ "Failed to register \"{}\" notification: {}",
+ DidChangeConfiguration::METHOD,
+ why
+ );
+ }
+ });
}
}
- fn register_diagnostics_handler(&mut self) {
- let (event_sender, event_receiver) = crossbeam_channel::unbounded();
- let diagnostic_tx = self.diagnostic_tx.clone();
- let diagnostic_manager = self.diagnostic_manager.clone();
- std::thread::spawn(move || {
- for event in event_receiver {
- match event {
- WorkspaceEvent::Changed(workspace, document) => {
- diagnostic_manager.push_syntax(&workspace, &document.uri);
- let delay = workspace.environment.options.diagnostics_delay;
- diagnostic_tx
- .send(workspace, Duration::from_millis(delay))
- .unwrap();
- }
- };
- }
- });
+ fn update_workspace(&mut self) {
+ let db = self.engine.write();
+ discover_dependencies(db);
+ self.watcher.watch(db);
+ self.publish_diagnostics_with_delay();
+ }
+
+ fn publish_diagnostics(&mut self) -> Result<()> {
+ let db = self.engine.read();
+
+ let all_diagnostics = db::diagnostics::collect_filtered(db, Workspace::get(db));
+
+ for (document, diagnostics) in all_diagnostics {
+ let uri = document.location(db).uri(db).clone();
+ let version = None;
+ let params = PublishDiagnosticsParams {
+ uri,
+ diagnostics,
+ version,
+ };
+
+ self.client
+ .send_notification::<PublishDiagnostics>(params)?;
+ }
- self.workspace.listeners.push(event_sender);
+ Ok(())
}
- fn register_incoming_request(&self, id: RequestId) {
- let mut req_queue = self.req_queue.lock().unwrap();
- req_queue.incoming.register(id, IncomingData);
+ fn publish_diagnostics_with_delay(&mut self) {
+ let db = self.engine.read();
+ let sender = self.internal_tx.clone();
+ let delay = Workspace::get(db).options(db).diagnostics_delay.0;
+ self.pool.execute(move || {
+ std::thread::sleep(delay);
+ sender.send(InternalMessage::Diagnostics).unwrap();
+ });
}
- fn pull_config(&self) -> Result<()> {
- if !self
- .workspace
- .environment
- .client_capabilities
+ fn pull_options(&mut self) {
+ let db = self.engine.read();
+ let workspace = Workspace::get(db);
+ if !workspace
+ .client_capabilities(db)
.has_pull_configuration_support()
{
- return Ok(());
+ return;
}
let params = ConfigurationParams {
@@ -281,108 +285,81 @@ impl Server {
}],
};
- match send_request::<WorkspaceConfiguration>(
- &self.req_queue,
- &self.connection.sender,
- params,
- ) {
- Ok(mut json) => {
- let value = json.pop().expect("invalid configuration request");
- let options = self.parse_options(value)?;
- self.internal_tx
- .send(InternalMessage::SetOptions(Arc::new(options)))
- .unwrap();
- }
- Err(why) => {
- error!("Retrieving configuration failed: {}", why);
- }
- };
+ let client = self.client.clone();
+ let sender = self.internal_tx.clone();
+ self.pool.execute(move || {
+ match client.send_request::<WorkspaceConfiguration>(params) {
+ Ok(mut json) => {
+ let options = client
+ .parse_options(json.pop().expect("invalid configuration request"))
+ .unwrap();
- Ok(())
+ sender.send(InternalMessage::SetOptions(options)).unwrap();
+ }
+ Err(why) => {
+ error!("Retrieving configuration failed: {}", why);
+ }
+ };
+ });
}
- fn parse_options(&self, value: serde_json::Value) -> Result<Options> {
- let options = match serde_json::from_value(value) {
- Ok(new_options) => new_options,
- Err(why) => {
- send_notification::<ShowMessage>(
- &self.connection.sender,
- ShowMessageParams {
- message: format!(
- "The texlab configuration is invalid; using the default settings instead.\nDetails: {why}"
- ),
- typ: MessageType::WARNING,
- },
- )?;
-
- Options::default()
- }
- };
+ fn update_options(&mut self, options: Options) {
+ let db = self.engine.write();
+ let workspace = Workspace::get(db);
+ workspace
+ .set_options(db)
+ .with_durability(salsa::Durability::MEDIUM)
+ .to(options);
- Ok(options)
+ self.watcher.watch(db);
}
- fn cancel(&self, params: CancelParams) -> Result<()> {
- let id = match params.id {
- NumberOrString::Number(id) => RequestId::from(id),
- NumberOrString::String(id) => RequestId::from(id),
- };
-
- let mut req_queue = self.req_queue.lock().unwrap();
- req_queue.incoming.complete(id);
-
+ fn cancel(&self, _params: CancelParams) -> Result<()> {
Ok(())
}
- fn did_change_watched_files(&mut self, params: DidChangeWatchedFilesParams) -> Result<()> {
- for change in params.changes {
- if let Ok(path) = change.uri.to_file_path() {
- match change.typ {
- FileChangeType::CREATED | FileChangeType::CHANGED => {
- self.workspace.reload(path)?;
- }
- FileChangeType::DELETED => {
- self.workspace.documents_by_uri.remove(&change.uri);
- }
- _ => {}
- }
- }
- }
-
+ fn did_change_watched_files(&mut self, _params: DidChangeWatchedFilesParams) -> Result<()> {
Ok(())
}
fn did_change_configuration(&mut self, params: DidChangeConfigurationParams) -> Result<()> {
- if self
- .workspace
- .environment
- .client_capabilities
+ let db = self.engine.read();
+ let workspace = Workspace::get(db);
+ if workspace
+ .client_capabilities(db)
.has_pull_configuration_support()
{
- self.spawn(move |server| {
- let _ = server.pull_config();
- });
+ self.pull_options();
} else {
- let options = self.parse_options(params.settings)?;
- self.workspace.environment.options = Arc::new(options);
- self.reparse_all()?;
+ let options = self.client.parse_options(params.settings)?;
+ self.update_options(options);
}
Ok(())
}
- fn did_open(&mut self, params: DidOpenTextDocumentParams) -> Result<()> {
+ fn did_open(&mut self, mut params: DidOpenTextDocumentParams) -> Result<()> {
+ normalize_uri(&mut params.text_document.uri);
+
+ let db = self.engine.write();
+ let workspace = Workspace::get(db);
let language_id = &params.text_document.language_id;
- let language = DocumentLanguage::by_language_id(language_id);
- let document = self.workspace.open(
- Arc::new(params.text_document.uri),
- Arc::new(params.text_document.text),
- language.unwrap_or(DocumentLanguage::Latex),
- )?;
+ let language = Language::from_id(language_id).unwrap_or(Language::Tex);
+ let document = workspace.open(
+ db,
+ params.text_document.uri,
+ params.text_document.text,
+ language,
+ Owner::Client,
+ );
- self.workspace.viewport.insert(Arc::clone(&document.uri));
+ self.update_workspace();
- if self.workspace.environment.options.chktex.on_open_and_save {
+ if workspace
+ .options(self.engine.read())
+ .chktex
+ .on_open_and_save
+ {
self.run_chktex(document);
}
@@ -390,315 +367,299 @@ impl Server {
}
fn did_change(&mut self, params: DidChangeTextDocumentParams) -> Result<()> {
- let uri = Arc::new(params.text_document.uri);
- match self.workspace.documents_by_uri.get(&uri).cloned() {
- Some(old_document) => {
- let mut text = old_document.text.to_string();
- apply_document_edit(&mut text, params.content_changes);
- let language = old_document.data.language();
- let new_document =
- self.workspace
- .open(Arc::clone(&uri), Arc::new(text), language)?;
- self.workspace
- .viewport
- .insert(Arc::clone(&new_document.uri));
-
- self.build_engine.positions_by_uri.insert(
- Arc::clone(&uri),
- Position::new(
- old_document
- .text
- .lines()
- .zip(new_document.text.lines())
- .position(|(a, b)| a != b)
- .unwrap_or_default() as u32,
- 0,
- ),
- );
-
- if self.workspace.environment.options.chktex.on_edit {
- self.run_chktex(new_document);
- };
- }
- None => match uri.to_file_path() {
- Ok(path) => {
- self.workspace.load(path)?;
- }
- Err(_) => return Ok(()),
- },
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+
+ let db = self.engine.write();
+ let workspace = Workspace::get(db);
+ let document = match workspace.lookup_uri(db, &uri) {
+ Some(document) => document,
+ None => return Ok(()),
};
+ for change in params.content_changes {
+ match change.range {
+ Some(range) => {
+ let range = document.contents(db).line_index(db).offset_lsp_range(range);
+ document.edit(db, range, &change.text);
+ }
+ None => {
+ document
+ .contents(db)
+ .set_text(db)
+ .with_durability(salsa::Durability::LOW)
+ .to(change.text);
+
+ document
+ .set_cursor(db)
+ .with_durability(salsa::Durability::LOW)
+ .to(TextSize::from(0));
+ }
+ };
+ }
+
+ self.update_workspace();
+
+ if workspace.options(self.engine.read()).chktex.on_edit {
+ self.run_chktex(document);
+ }
+
Ok(())
}
fn did_save(&mut self, params: DidSaveTextDocumentParams) -> Result<()> {
- let uri = params.text_document.uri;
-
- if let Some(request) = self
- .workspace
- .documents_by_uri
- .get(&uri)
- .filter(|_| self.workspace.environment.options.build.on_save)
- .map(|document| {
- self.feature_request(
- Arc::clone(&document.uri),
- BuildParams {
- text_document: TextDocumentIdentifier::new(uri.clone()),
- },
- )
- })
- {
- self.spawn(move |server| {
- server
- .build_engine
- .build(request, &server.req_queue, &server.connection.sender)
- .unwrap_or_else(|why| {
- error!("Build failed: {}", why);
- BuildResult {
- status: BuildStatus::FAILURE,
- }
- });
- });
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+
+ let db = self.engine.read();
+ let workspace = Workspace::get(db);
+ if workspace.options(db).build.on_save {
+ self.build_internal(uri.clone(), |_| ())?;
}
- if let Some(document) = self
- .workspace
- .documents_by_uri
- .get(&uri)
- .filter(|_| self.workspace.environment.options.chktex.on_open_and_save)
- .cloned()
- {
- self.run_chktex(document);
+ self.publish_diagnostics_with_delay();
+
+ let db = self.engine.read();
+ if let Some(document) = workspace.lookup_uri(db, &uri) {
+ if workspace.options(db).chktex.on_open_and_save {
+ self.run_chktex(document);
+ }
}
Ok(())
}
fn did_close(&mut self, params: DidCloseTextDocumentParams) -> Result<()> {
- self.workspace.close(&params.text_document.uri);
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+
+ let db = self.engine.write();
+ if let Some(document) = Workspace::get(db).lookup_uri(db, &uri) {
+ document
+ .set_owner(db)
+ .with_durability(salsa::Durability::LOW)
+ .to(Owner::Server);
+ }
+
+ self.publish_diagnostics_with_delay();
Ok(())
}
fn run_chktex(&mut self, document: Document) {
- self.spawn(move |server| {
- server
- .diagnostic_manager
- .push_chktex(&server.workspace, &document.uri);
-
- let delay = server.workspace.environment.options.diagnostics_delay;
- server
- .diagnostic_tx
- .send(server.workspace.clone(), Duration::from_millis(delay))
- .unwrap();
- });
- }
-
- fn feature_request<P>(&self, uri: Arc<Url>, params: P) -> FeatureRequest<P> {
- FeatureRequest {
- params,
- workspace: self.workspace.slice(&uri),
- uri,
- }
- }
-
- fn handle_feature_request<P, R, H>(
- &self,
- id: RequestId,
- params: P,
- uri: Arc<Url>,
- handler: H,
- ) -> Result<()>
- where
- P: Send + 'static,
- R: Serialize,
- H: FnOnce(FeatureRequest<P>) -> R + Send + 'static,
- {
- self.spawn(move |server| {
- let request = server.feature_request(uri, params);
- if request.workspace.documents_by_uri.is_empty() {
- let code = lsp_server::ErrorCode::InvalidRequest as i32;
- let message = "unknown document".to_string();
- let response = lsp_server::Response::new_err(id, code, message);
- server.connection.sender.send(response.into()).unwrap();
- } else {
- let result = handler(request);
- server
- .connection
- .sender
- .send(lsp_server::Response::new_ok(id, result).into())
+ let db = self.engine.read();
+ if let Some(command) = util::chktex::Command::new(db, document) {
+ let sender = self.internal_tx.clone();
+ let uri = document.location(db).uri(db).clone();
+ self.pool.execute(move || {
+ let diagnostics = command.run().unwrap_or_default();
+ sender
+ .send(InternalMessage::ChktexResult(uri, diagnostics))
.unwrap();
- }
- });
-
- Ok(())
+ });
+ }
}
fn document_link(&self, id: RequestId, params: DocumentLinkParams) -> Result<()> {
- let uri = Arc::new(params.text_document.uri.clone());
- self.handle_feature_request(id, params, uri, find_document_links)?;
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+ self.run_with_db(id, move |db| link::find_all(db, &uri).unwrap_or_default());
Ok(())
}
fn document_symbols(&self, id: RequestId, params: DocumentSymbolParams) -> Result<()> {
- let uri = Arc::new(params.text_document.uri.clone());
- self.handle_feature_request(id, params, uri, find_document_symbols)?;
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+ self.run_with_db(id, move |db| symbol::find_document_symbols(db, &uri));
Ok(())
}
fn workspace_symbols(&self, id: RequestId, params: WorkspaceSymbolParams) -> Result<()> {
- self.spawn(move |server| {
- let result = find_workspace_symbols(&server.workspace, &params);
- server
- .connection
- .sender
- .send(lsp_server::Response::new_ok(id, result).into())
- .unwrap();
- });
+ self.run_with_db(id, move |db| symbol::find_workspace_symbols(db, &params));
Ok(())
}
- #[cfg(feature = "completion")]
- fn completion(&self, id: RequestId, params: CompletionParams) -> Result<()> {
- let uri = Arc::new(params.text_document_position.text_document.uri.clone());
-
- self.build_engine
- .positions_by_uri
- .insert(Arc::clone(&uri), params.text_document_position.position);
-
- self.handle_feature_request(id, params, uri, crate::features::complete)?;
+ fn completion(&mut self, id: RequestId, params: CompletionParams) -> Result<()> {
+ let mut uri = params.text_document_position.text_document.uri;
+ normalize_uri(&mut uri);
+ let position = params.text_document_position.position;
+ self.run_with_db(id, move |db| completion::complete(db, &uri, position));
Ok(())
}
- #[cfg(feature = "completion")]
fn completion_resolve(&self, id: RequestId, mut item: CompletionItem) -> Result<()> {
- use rowan::ast::AstNode;
-
- use crate::{
- citation, component_db::COMPONENT_DATABASE, features::CompletionItemData,
- syntax::bibtex,
- };
-
- self.spawn(move |server| {
- match serde_json::from_value(item.data.clone().unwrap()).unwrap() {
- CompletionItemData::Package | CompletionItemData::Class => {
+ self.run_with_db(id, move |db| {
+ match item
+ .data
+ .clone()
+ .map(|data| serde_json::from_value(data).unwrap())
+ {
+ Some(CompletionItemData::Package | CompletionItemData::Class) => {
item.documentation = COMPONENT_DATABASE
.documentation(&item.label)
.map(Documentation::MarkupContent);
}
- CompletionItemData::Citation { uri, key } => {
- if let Some(document) = server.workspace.documents_by_uri.get(&uri) {
- if let Some(data) = document.data.as_bibtex() {
- let root = bibtex::SyntaxNode::new_root(data.green.clone());
- item.documentation = bibtex::Root::cast(root)
- .and_then(|root| root.find_entry(&key))
- .and_then(|entry| citation::render(&entry))
- .map(|value| {
- Documentation::MarkupContent(MarkupContent {
- kind: MarkupKind::Markdown,
- value,
- })
- });
- }
+ Some(CompletionItemData::Citation { uri, key }) => {
+ if let Some(root) = Workspace::get(db)
+ .lookup_uri(db, &uri)
+ .and_then(|document| document.parse(db).as_bib().map(|data| data.root(db)))
+ {
+ item.documentation = bibtex::Root::cast(root)
+ .and_then(|root| root.find_entry(&key))
+ .and_then(|entry| citation::render(&entry))
+ .map(|value| {
+ Documentation::MarkupContent(MarkupContent {
+ kind: MarkupKind::Markdown,
+ value,
+ })
+ });
}
}
- _ => {}
+ None => {}
};
- server
- .connection
- .sender
- .send(lsp_server::Response::new_ok(id, item).into())
- .unwrap();
+ item
});
+
Ok(())
}
fn folding_range(&self, id: RequestId, params: FoldingRangeParams) -> Result<()> {
- let uri = Arc::new(params.text_document.uri.clone());
- self.handle_feature_request(id, params, uri, find_foldings)?;
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+ self.run_with_db(id, move |db| {
+ folding::find_all(db, &uri).unwrap_or_default()
+ });
Ok(())
}
fn references(&self, id: RequestId, params: ReferenceParams) -> Result<()> {
- let uri = Arc::new(params.text_document_position.text_document.uri.clone());
- self.handle_feature_request(id, params, uri, find_all_references)?;
+ let mut uri = params.text_document_position.text_document.uri;
+ normalize_uri(&mut uri);
+ let position = params.text_document_position.position;
+ self.run_with_db(id, move |db| {
+ reference::find_all(db, &uri, position, &params.context).unwrap_or_default()
+ });
+
Ok(())
}
- fn hover(&self, id: RequestId, params: HoverParams) -> Result<()> {
- let uri = Arc::new(
- params
- .text_document_position_params
- .text_document
- .uri
- .clone(),
- );
- self.build_engine.positions_by_uri.insert(
- Arc::clone(&uri),
- params.text_document_position_params.position,
- );
+ fn hover(&mut self, id: RequestId, params: HoverParams) -> Result<()> {
+ let mut uri = params.text_document_position_params.text_document.uri;
+ normalize_uri(&mut uri);
- self.handle_feature_request(id, params, uri, find_hover)?;
+ let db = self.engine.write();
+ let workspace = Workspace::get(db);
+ if let Some(document) = workspace.lookup_uri(db, &uri) {
+ let position = document
+ .contents(db)
+ .line_index(db)
+ .offset_lsp(params.text_document_position_params.position);
+
+ document
+ .set_cursor(db)
+ .with_durability(salsa::Durability::LOW)
+ .to(position);
+ }
+
+ let position = params.text_document_position_params.position;
+ self.run_with_db(id, move |db| hover::find(db, &uri, position));
Ok(())
}
fn goto_definition(&self, id: RequestId, params: GotoDefinitionParams) -> Result<()> {
- let uri = Arc::new(
- params
- .text_document_position_params
- .text_document
- .uri
- .clone(),
- );
- self.handle_feature_request(id, params, uri, goto_definition)?;
+ let mut uri = params.text_document_position_params.text_document.uri;
+ normalize_uri(&mut uri);
+ let position = params.text_document_position_params.position;
+ self.run_with_db(id, move |db| {
+ definition::goto_definition(db, &uri, position)
+ });
+
Ok(())
}
fn prepare_rename(&self, id: RequestId, params: TextDocumentPositionParams) -> Result<()> {
- let uri = Arc::new(params.text_document.uri.clone());
- self.handle_feature_request(id, params, uri, prepare_rename_all)?;
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+ self.run_with_db(id, move |db| {
+ rename::prepare_rename_all(db, &uri, params.position)
+ });
+
Ok(())
}
fn rename(&self, id: RequestId, params: RenameParams) -> Result<()> {
- let uri = Arc::new(params.text_document_position.text_document.uri.clone());
- self.handle_feature_request(id, params, uri, rename_all)?;
+ let mut uri = params.text_document_position.text_document.uri;
+ normalize_uri(&mut uri);
+ let position = params.text_document_position.position;
+ self.run_with_db(id, move |db| {
+ rename::rename_all(db, &uri, position, params.new_name)
+ });
+
Ok(())
}
fn document_highlight(&self, id: RequestId, params: DocumentHighlightParams) -> Result<()> {
- let uri = Arc::new(
- params
- .text_document_position_params
- .text_document
- .uri
- .clone(),
- );
- self.handle_feature_request(id, params, uri, find_document_highlights)?;
+ let mut uri = params.text_document_position_params.text_document.uri;
+ normalize_uri(&mut uri);
+ let position = params.text_document_position_params.position;
+ self.run_with_db(id, move |db| {
+ highlight::find_all(db, &uri, position).unwrap_or_default()
+ });
Ok(())
}
fn formatting(&self, id: RequestId, params: DocumentFormattingParams) -> Result<()> {
- let uri = Arc::new(params.text_document.uri.clone());
- self.handle_feature_request(id, params, uri, format_source_code)?;
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+ self.run_with_db(id, move |db| {
+ formatting::format_source_code(db, &uri, &params.options)
+ });
+
Ok(())
}
- fn execute_command(&self, id: RequestId, params: ExecuteCommandParams) -> Result<()> {
- self.spawn(move |server| {
- let result = execute_command(&server.workspace, &params.command, params.arguments);
- let response = match result {
- Ok(()) => lsp_server::Response::new_ok(id, ()),
- Err(why) => lsp_server::Response::new_err(
- id,
- lsp_server::ErrorCode::InternalError as i32,
- why.to_string(),
- ),
- };
+ fn execute_command(&mut self, id: RequestId, params: ExecuteCommandParams) -> Result<()> {
+ let db = self.engine.read();
+ match workspace_command::select(db, &params.command, params.arguments) {
+ Ok(command) => {
+ let client = self.client.clone();
+ self.pool.execute(move || {
+ match command.run() {
+ Ok(()) => {
+ client
+ .send_response(lsp_server::Response::new_ok(id, ()))
+ .unwrap();
+ }
+ Err(why) => {
+ client
+ .send_error(id, ErrorCode::InternalError, why.to_string())
+ .unwrap();
+ }
+ };
+ });
+ }
+ Err(why) => {
+ self.client
+ .send_error(id, ErrorCode::InvalidParams, why.to_string())
+ .unwrap();
+ }
+ };
+
+ Ok(())
+ }
- server.connection.sender.send(response.into()).unwrap();
+ fn inlay_hints(&self, id: RequestId, params: InlayHintParams) -> Result<()> {
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+ self.run_with_db(id, move |db| {
+ inlay_hint::find_all(db, &uri, params.range).unwrap_or_default()
});
+ Ok(())
+ }
+ fn inlay_hint_resolve(&self, id: RequestId, hint: InlayHint) -> Result<()> {
+ let response = lsp_server::Response::new_ok(id, hint);
+ self.connection.sender.send(response.into()).unwrap();
Ok(())
}
@@ -710,52 +671,144 @@ impl Server {
Ok(())
}
- fn build(&self, id: RequestId, params: BuildParams) -> Result<()> {
- let uri = Arc::new(params.text_document.uri.clone());
- let lsp_sender = self.connection.sender.clone();
- let req_queue = Arc::clone(&self.req_queue);
- let build_engine = Arc::clone(&self.build_engine);
- self.handle_feature_request(id, params, uri, move |request| {
- build_engine
- .build(request, &req_queue, &lsp_sender)
- .unwrap_or_else(|why| {
- error!("Build failed: {}", why);
- BuildResult {
- status: BuildStatus::FAILURE,
- }
- })
+ fn build(&mut self, id: RequestId, params: BuildParams) -> Result<()> {
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+
+ let client = self.client.clone();
+ self.build_internal(uri, move |status| {
+ let result = BuildResult { status };
+ client
+ .send_response(lsp_server::Response::new_ok(id, result))
+ .unwrap();
})?;
+
+ Ok(())
+ }
+
+ fn build_internal(
+ &mut self,
+ uri: Url,
+ callback: impl FnOnce(BuildStatus) + Send + 'static,
+ ) -> Result<()> {
+ static LOCK: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
+
+ let db = self.engine.read();
+ let compiler = match build::Command::new(db, uri.clone(), self.client.clone()) {
+ Some(compiler) => compiler,
+ None => {
+ callback(BuildStatus::FAILURE);
+ return Ok(());
+ }
+ };
+
+ let forward_search_after = Workspace::get(db).options(db).build.forward_search_after;
+
+ let sender = self.internal_tx.clone();
+ self.pool.execute(move || {
+ let guard = LOCK.lock().unwrap();
+
+ let status = compiler.run();
+ if forward_search_after {
+ sender.send(InternalMessage::ForwardSearch(uri)).unwrap();
+ }
+
+ drop(guard);
+ callback(status);
+ });
+
Ok(())
}
- fn forward_search(&self, id: RequestId, params: TextDocumentPositionParams) -> Result<()> {
- let uri = Arc::new(params.text_document.uri.clone());
- self.handle_feature_request(id, params, uri, |req| {
- crate::features::execute_forward_search(req).unwrap_or(ForwardSearchResult {
- status: ForwardSearchStatus::ERROR,
- })
+ fn forward_search(&mut self, id: RequestId, params: TextDocumentPositionParams) -> Result<()> {
+ let mut uri = params.text_document.uri;
+ normalize_uri(&mut uri);
+
+ let client = self.client.clone();
+ self.forward_search_internal(uri, Some(params.position), move |status| {
+ let result = ForwardSearchResult { status };
+ client
+ .send_response(lsp_server::Response::new_ok(id, result))
+ .unwrap();
})?;
+
Ok(())
}
- fn reparse_all(&mut self) -> Result<()> {
- for document in self
- .workspace
- .documents_by_uri
- .values()
- .cloned()
- .collect::<Vec<_>>()
- {
- self.workspace.open(
- Arc::clone(&document.uri),
- document.text.clone(),
- document.data.language(),
- )?;
- }
+ fn forward_search_internal(
+ &mut self,
+ uri: Url,
+ position: Option<Position>,
+ callback: impl FnOnce(ForwardSearchStatus) + Send + 'static,
+ ) -> Result<()> {
+ let db = self.engine.read();
+ let command = match forward_search::Command::configure(db, &uri, position) {
+ Ok(command) => command,
+ Err(why) => {
+ log::error!("Forward search failed: {}", why);
+ callback(why.into());
+ return Ok(());
+ }
+ };
+
+ self.pool.execute(move || {
+ let status = command
+ .run()
+ .map_or_else(ForwardSearchStatus::from, |()| ForwardSearchStatus::SUCCESS);
+
+ callback(status);
+ });
Ok(())
}
+ fn handle_file_event(&mut self, event: notify::Event) {
+ let mut changed = false;
+
+ let db = self.engine.write();
+ let workspace = Workspace::get(db);
+ match event.kind {
+ notify::EventKind::Create(_) | notify::EventKind::Modify(_) => {
+ for path in event.paths {
+ if workspace
+ .lookup_path(db, &path)
+ .map_or(true, |document| document.owner(db) == Owner::Server)
+ {
+ if let Some(language) = Language::from_path(&path) {
+ workspace.load(db, &path, language, Owner::Server);
+ changed = true;
+ }
+ }
+ }
+ }
+ notify::EventKind::Remove(_) => {
+ for path in event.paths {
+ if let Some(document) = workspace.lookup_path(db, &path) {
+ if document.owner(db) == Owner::Server {
+ let mut documents = workspace
+ .set_documents(db)
+ .with_durability(salsa::Durability::LOW)
+ .to(FxHashSet::default());
+
+ documents.remove(&document);
+ workspace
+ .set_documents(db)
+ .with_durability(salsa::Durability::MEDIUM)
+ .to(documents);
+
+ changed = true;
+ }
+ }
+ }
+ }
+ notify::EventKind::Any | notify::EventKind::Access(_) | notify::EventKind::Other => {}
+ };
+
+ if changed {
+ self.publish_diagnostics_with_delay();
+ }
+ }
+
fn process_messages(&mut self) -> Result<()> {
loop {
crossbeam_channel::select! {
@@ -766,8 +819,7 @@ impl Server {
return Ok(());
}
- self.register_incoming_request(request.id.clone());
- if let Some(response) = RequestDispatcher::new(request)
+ if let Some(response) = dispatch::RequestDispatcher::new(request)
.on::<DocumentLinkRequest, _>(|id, params| self.document_link(id, params))?
.on::<FoldingRangeRequest, _>(|id, params| self.folding_range(id, params))?
.on::<References, _>(|id, params| self.references(id, params))?
@@ -777,12 +829,10 @@ impl Server {
})?
.on::<WorkspaceSymbol, _>(|id, params| self.workspace_symbols(id, params))?
.on::<Completion, _>(|id, params| {
- #[cfg(feature = "completion")]
self.completion(id, params)?;
Ok(())
})?
.on::<ResolveCompletionItem, _>(|id, params| {
- #[cfg(feature = "completion")]
self.completion_resolve(id, params)?;
Ok(())
})?
@@ -803,13 +853,19 @@ impl Server {
.on::<SemanticTokensRangeRequest, _>(|id, params| {
self.semantic_tokens_range(id, params)
})?
+ .on::<InlayHintRequest, _>(|id,params| {
+ self.inlay_hints(id, params)
+ })?
+ .on::<InlayHintResolveRequest,_>(|id, params| {
+ self.inlay_hint_resolve(id, params)
+ })?
.default()
{
self.connection.sender.send(response.into())?;
}
}
Message::Notification(notification) => {
- NotificationDispatcher::new(notification)
+ dispatch::NotificationDispatcher::new(notification)
.on::<Cancel, _>(|params| self.cancel(params))?
.on::<DidChangeConfiguration, _>(|params| {
self.did_change_configuration(params)
@@ -824,26 +880,39 @@ impl Server {
.default();
}
Message::Response(response) => {
- let mut req_queue = self.req_queue.lock().unwrap();
- if let Some(data) = req_queue.outgoing.complete(response.id) {
- let result = match response.error {
- Some(error) => Err(error),
- None => Ok(response.result.unwrap_or_default()),
- };
- data.sender.send(result)?;
- }
+ self.client.recv_response(response)?;
}
};
},
recv(&self.internal_rx) -> msg => {
match msg? {
InternalMessage::SetDistro(distro) => {
- self.workspace.environment.resolver = Arc::new(distro.resolver);
- self.reparse_all()?;
+ let db = self.engine.write();
+ Workspace::get(db)
+ .set_file_name_db(db)
+ .with_durability(salsa::Durability::HIGH)
+ .to(distro.file_name_db);
}
InternalMessage::SetOptions(options) => {
- self.workspace.environment.options = options;
- self.reparse_all()?;
+ self.update_options(options);
+ }
+ InternalMessage::FileEvent(event) => {
+ self.handle_file_event(event);
+ }
+ InternalMessage::ForwardSearch(uri) => {
+ self.forward_search_internal(uri, None, |_| ())?;
+ }
+ InternalMessage::Diagnostics => {
+ self.publish_diagnostics()?;
+ }
+ InternalMessage::ChktexResult(uri, diagnostics) => {
+ let db = self.engine.write();
+ let workspace = Workspace::get(db);
+ if let Some(document) = workspace.lookup_uri(db, &uri) {
+ document.linter(db).set_chktex(db).to(diagnostics);
+ }
+
+ self.publish_diagnostics()?;
}
};
}
@@ -854,63 +923,34 @@ impl Server {
pub fn run(mut self) -> Result<()> {
self.initialize()?;
self.process_messages()?;
- self.pool.lock().unwrap().join();
+ self.pool.join();
+ self.engine.finish();
Ok(())
}
}
-fn create_debouncer(
- lsp_sender: Sender<Message>,
- diagnostic_manager: DiagnosticManager,
-) -> debouncer::Sender<Workspace> {
- let (tx, rx) = debouncer::unbounded();
- std::thread::spawn(move || {
- while let Ok(workspace) = rx.recv() {
- if let Err(why) = publish_diagnostics(&lsp_sender, &diagnostic_manager, &workspace) {
- warn!("Failed to publish diagnostics: {}", why);
- }
- }
- });
-
- tx
+struct FileWatcher {
+ watcher: notify::RecommendedWatcher,
+ watched_dirs: FxHashSet<PathBuf>,
}
-fn publish_diagnostics(
- lsp_sender: &Sender<lsp_server::Message>,
- diagnostic_manager: &DiagnosticManager,
- workspace: &Workspace,
-) -> Result<()> {
- for document in workspace.documents_by_uri.values() {
- if matches!(document.data, DocumentData::BuildLog(_)) {
- continue;
- }
+impl FileWatcher {
+ pub fn new(sender: Sender<InternalMessage>) -> Result<Self> {
+ let handle = move |event| {
+ if let Ok(event) = event {
+ sender.send(InternalMessage::FileEvent(event)).unwrap();
+ }
+ };
- let diagnostics = diagnostic_manager.publish(workspace, &document.uri);
- send_notification::<PublishDiagnostics>(
- lsp_sender,
- PublishDiagnosticsParams {
- uri: document.uri.as_ref().clone(),
- version: None,
- diagnostics,
- },
- )?;
+ Ok(Self {
+ watcher: notify::recommended_watcher(handle)?,
+ watched_dirs: FxHashSet::default(),
+ })
}
- Ok(())
-}
-
-fn apply_document_edit(old_text: &mut String, changes: Vec<TextDocumentContentChangeEvent>) {
- for change in changes {
- let line_index = LineIndex::new(old_text);
- match change.range {
- Some(range) => {
- let range = std::ops::Range::<usize>::from(line_index.offset_lsp_range(range));
- old_text.replace_range(range, &change.text);
- }
- None => {
- *old_text = change.text;
- }
- };
+ pub fn watch(&mut self, db: &dyn Db) {
+ let workspace = Workspace::get(db);
+ workspace.watch(db, &mut self.watcher, &mut self.watched_dirs);
}
}
@@ -933,3 +973,29 @@ impl lsp_types::request::Request for ForwardSearchRequest {
const METHOD: &'static str = "textDocument/forwardSearch";
}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize_repr, Deserialize_repr)]
+#[repr(i32)]
+pub enum ForwardSearchStatus {
+ SUCCESS = 0,
+ ERROR = 1,
+ FAILURE = 2,
+ UNCONFIGURED = 3,
+}
+
+impl From<forward_search::Error> for ForwardSearchStatus {
+ fn from(err: forward_search::Error) -> Self {
+ match err {
+ forward_search::Error::TexNotFound(_) => ForwardSearchStatus::FAILURE,
+ forward_search::Error::PdfNotFound(_) => ForwardSearchStatus::ERROR,
+ forward_search::Error::NoLocalFile(_) => ForwardSearchStatus::FAILURE,
+ forward_search::Error::Unconfigured => ForwardSearchStatus::UNCONFIGURED,
+ forward_search::Error::Spawn(_) => ForwardSearchStatus::ERROR,
+ }
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
+pub struct ForwardSearchResult {
+ pub status: ForwardSearchStatus,
+}
diff --git a/support/texlab/src/dispatch.rs b/support/texlab/src/server/dispatch.rs
index f5659ee3b4..f5659ee3b4 100644
--- a/support/texlab/src/dispatch.rs
+++ b/support/texlab/src/server/dispatch.rs
diff --git a/support/texlab/src/server/query.rs b/support/texlab/src/server/query.rs
new file mode 100644
index 0000000000..f19d15f85b
--- /dev/null
+++ b/support/texlab/src/server/query.rs
@@ -0,0 +1,32 @@
+use salsa::{DbWithJar, ParallelDatabase};
+use threadpool::ThreadPool;
+
+use crate::{Database, Db};
+
+#[derive(Default)]
+pub struct Engine {
+ db: Database,
+ pool: ThreadPool,
+}
+
+impl Engine {
+ pub fn read(&self) -> &dyn Db {
+ &self.db
+ }
+
+ pub fn write(&mut self) -> &mut dyn Db {
+ self.pool.join();
+ &mut self.db
+ }
+
+ pub fn fork<F: FnOnce(&dyn Db) + Send + 'static>(&self, action: F) {
+ let snapshot = self.db.snapshot();
+ self.pool.execute(move || {
+ action(snapshot.as_jar_db());
+ });
+ }
+
+ pub fn finish(self) {
+ self.pool.join();
+ }
+}
diff --git a/support/texlab/src/syntax.rs b/support/texlab/src/syntax.rs
index a0ae96089c..dc8761b73d 100644
--- a/support/texlab/src/syntax.rs
+++ b/support/texlab/src/syntax.rs
@@ -1,3 +1,22 @@
pub mod bibtex;
-pub mod build_log;
pub mod latex;
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
+pub enum BuildErrorLevel {
+ Error,
+ Warning,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+pub struct BuildError {
+ pub relative_path: std::path::PathBuf,
+ pub level: BuildErrorLevel,
+ pub message: String,
+ pub hint: Option<String>,
+ pub line: Option<u32>,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+pub struct BuildLog {
+ pub errors: Vec<BuildError>,
+}
diff --git a/support/texlab/src/syntax/bibtex.rs b/support/texlab/src/syntax/bibtex.rs
index a35399419a..9b4b1ab77e 100644
--- a/support/texlab/src/syntax/bibtex.rs
+++ b/support/texlab/src/syntax/bibtex.rs
@@ -1,10 +1,4 @@
-mod ast;
-mod lexer;
-mod parser;
-#[cfg(test)]
-mod tests;
-
-pub use self::{ast::*, parser::parse, SyntaxKind::*};
+use rowan::{ast::AstNode, NodeOrToken};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
#[allow(non_camel_case_types)]
@@ -42,6 +36,8 @@ pub enum SyntaxKind {
ROOT,
}
+pub use SyntaxKind::*;
+
impl From<SyntaxKind> for rowan::SyntaxKind {
fn from(kind: SyntaxKind) -> Self {
Self(kind as u16)
@@ -69,3 +65,240 @@ pub type SyntaxNode = rowan::SyntaxNode<Lang>;
pub type SyntaxToken = rowan::SyntaxToken<Lang>;
pub type SyntaxElement = rowan::SyntaxElement<Lang>;
+
+macro_rules! ast_node {
+ (name: $name:ident, kinds: [$($kind:pat),+], traits: [$($trait: ident),*]) => {
+ #[derive(Clone)]
+ pub struct $name {
+ node: SyntaxNode,
+ }
+
+ impl AstNode for $name {
+ type Language = Lang;
+
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ $($kind => true,)+
+ _ => false,
+ }
+ }
+
+ fn cast(node: SyntaxNode) -> Option<Self>
+ where
+ Self: Sized,
+ {
+ match node.kind() {
+ $($kind => Some(Self { node}),)+
+ _ => None,
+ }
+ }
+
+ fn syntax(&self) -> &SyntaxNode {
+ &self.node
+ }
+ }
+
+ $(
+ impl $trait for $name { }
+ )*
+ };
+}
+
+macro_rules! ast_node_enum {
+ (name: $name:ident, variants: [$($variant:ident),+]) => {
+ #[derive(Clone)]
+ pub enum $name {
+ $($variant($variant),)*
+ }
+
+ impl AstNode for $name {
+ type Language = Lang;
+
+ fn can_cast(kind: SyntaxKind) -> bool {
+ false $(|| $variant::can_cast(kind))+
+ }
+
+ fn cast(node: SyntaxNode) -> Option<Self>
+ where
+ Self: Sized,
+ {
+ None $(.or_else(|| $variant::cast(node.clone()).map(Self::$variant)))*
+ }
+
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ $(Self::$variant(node) => node.syntax(),)*
+ }
+ }
+ }
+
+ $(
+ impl From<$variant> for $name {
+ fn from(node: $variant) -> Self {
+ Self::$variant(node)
+ }
+ }
+ )*
+ };
+}
+
+pub trait HasType: AstNode<Language = Lang> {
+ fn type_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == TYPE)
+ }
+}
+
+pub trait HasDelims: AstNode<Language = Lang> {
+ fn left_delim_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == L_DELIM)
+ }
+
+ fn right_delim_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == R_DELIM)
+ }
+}
+
+pub trait HasName: AstNode<Language = Lang> {
+ fn name_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == NAME)
+ }
+}
+
+pub trait HasEq: AstNode<Language = Lang> {
+ fn eq_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == NAME)
+ }
+}
+
+pub trait HasComma: AstNode<Language = Lang> {
+ fn comma_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == COMMA)
+ }
+}
+
+pub trait HasPound: AstNode<Language = Lang> {
+ fn pound_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == POUND)
+ }
+}
+
+pub trait HasInteger: AstNode<Language = Lang> {
+ fn integer_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == INTEGER)
+ }
+}
+
+pub trait HasCommandName: AstNode<Language = Lang> {
+ fn command_name_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == COMMAND_NAME)
+ }
+}
+
+pub trait HasAccentName: AstNode<Language = Lang> {
+ fn accent_name_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == ACCENT_NAME)
+ }
+}
+
+pub trait HasWord: AstNode<Language = Lang> {
+ fn word_token(&self) -> Option<SyntaxToken> {
+ self.syntax()
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|token| token.kind() == WORD)
+ }
+}
+
+pub trait HasValue: AstNode<Language = Lang> {
+ fn value(&self) -> Option<Value> {
+ self.syntax().children().find_map(Value::cast)
+ }
+}
+
+ast_node!(name: Root, kinds: [ROOT], traits: []);
+
+impl Root {
+ pub fn strings(&self) -> impl Iterator<Item = StringDef> {
+ self.syntax().children().filter_map(StringDef::cast)
+ }
+
+ pub fn entries(&self) -> impl Iterator<Item = Entry> {
+ self.syntax().children().filter_map(Entry::cast)
+ }
+
+ pub fn find_entry(&self, name: &str) -> Option<Entry> {
+ self.entries().find(|entry| {
+ entry
+ .name_token()
+ .map_or(false, |token| token.text() == name)
+ })
+ }
+}
+
+ast_node!(name: Preamble, kinds: [PREAMBLE], traits: [HasType, HasDelims, HasValue]);
+
+ast_node!(name: StringDef, kinds: [STRING], traits: [HasType, HasDelims, HasName, HasEq, HasValue]);
+
+ast_node!(name: Entry, kinds: [ENTRY], traits: [HasType, HasDelims, HasName, HasComma]);
+
+impl Entry {
+ pub fn fields(&self) -> impl Iterator<Item = Field> {
+ self.syntax().children().filter_map(Field::cast)
+ }
+}
+
+ast_node!(name: Field, kinds: [FIELD], traits: [HasName, HasEq, HasValue, HasComma]);
+
+ast_node_enum!(name: Value, variants: [Literal, CurlyGroup, QuoteGroup, Join, Accent, Command]);
+
+ast_node!(name: Literal, kinds: [LITERAL], traits: [HasName, HasInteger]);
+
+ast_node!(name: CurlyGroup, kinds: [CURLY_GROUP], traits: []);
+
+ast_node!(name: QuoteGroup, kinds: [QUOTE_GROUP], traits: []);
+
+ast_node!(name: Join, kinds: [JOIN], traits: [HasPound]);
+
+impl Join {
+ pub fn left_value(&self) -> Option<Value> {
+ self.syntax().children().find_map(Value::cast)
+ }
+
+ pub fn right_value(&self) -> Option<Value> {
+ self.syntax().children().filter_map(Value::cast).nth(1)
+ }
+}
+
+ast_node!(name: Accent, kinds: [ACCENT], traits: [HasAccentName, HasWord]);
+
+ast_node!(name: Command, kinds: [COMMAND], traits: [HasCommandName]);
diff --git a/support/texlab/src/syntax/bibtex/ast.rs b/support/texlab/src/syntax/bibtex/ast.rs
deleted file mode 100644
index 10ac571dd2..0000000000
--- a/support/texlab/src/syntax/bibtex/ast.rs
+++ /dev/null
@@ -1,244 +0,0 @@
-use rowan::{ast::AstNode, NodeOrToken};
-
-use super::{
- Lang,
- SyntaxKind::{self, *},
- SyntaxNode, SyntaxToken,
-};
-
-macro_rules! ast_node {
- (name: $name:ident, kinds: [$($kind:pat),+], traits: [$($trait: ident),*]) => {
- #[derive(Clone)]
- pub struct $name {
- node: SyntaxNode,
- }
-
- impl AstNode for $name {
- type Language = Lang;
-
- fn can_cast(kind: SyntaxKind) -> bool {
- match kind {
- $($kind => true,)+
- _ => false,
- }
- }
-
- fn cast(node: SyntaxNode) -> Option<Self>
- where
- Self: Sized,
- {
- match node.kind() {
- $($kind => Some(Self { node}),)+
- _ => None,
- }
- }
-
- fn syntax(&self) -> &SyntaxNode {
- &self.node
- }
- }
-
- $(
- impl $trait for $name { }
- )*
- };
-}
-
-macro_rules! ast_node_enum {
- (name: $name:ident, variants: [$($variant:ident),+]) => {
- #[derive(Clone)]
- pub enum $name {
- $($variant($variant),)*
- }
-
- impl AstNode for $name {
- type Language = Lang;
-
- fn can_cast(kind: SyntaxKind) -> bool {
- false $(|| $variant::can_cast(kind))+
- }
-
- fn cast(node: SyntaxNode) -> Option<Self>
- where
- Self: Sized,
- {
- None $(.or_else(|| $variant::cast(node.clone()).map(Self::$variant)))*
- }
-
- fn syntax(&self) -> &SyntaxNode {
- match self {
- $(Self::$variant(node) => node.syntax(),)*
- }
- }
- }
-
- $(
- impl From<$variant> for $name {
- fn from(node: $variant) -> Self {
- Self::$variant(node)
- }
- }
- )*
- };
-}
-
-pub trait HasType: AstNode<Language = Lang> {
- fn type_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == TYPE)
- }
-}
-
-pub trait HasDelims: AstNode<Language = Lang> {
- fn left_delim_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == L_DELIM)
- }
-
- fn right_delim_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == R_DELIM)
- }
-}
-
-pub trait HasName: AstNode<Language = Lang> {
- fn name_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == NAME)
- }
-}
-
-pub trait HasEq: AstNode<Language = Lang> {
- fn eq_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == NAME)
- }
-}
-
-pub trait HasComma: AstNode<Language = Lang> {
- fn comma_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == COMMA)
- }
-}
-
-pub trait HasPound: AstNode<Language = Lang> {
- fn pound_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == POUND)
- }
-}
-
-pub trait HasInteger: AstNode<Language = Lang> {
- fn integer_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == INTEGER)
- }
-}
-
-pub trait HasCommandName: AstNode<Language = Lang> {
- fn command_name_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == COMMAND_NAME)
- }
-}
-
-pub trait HasAccentName: AstNode<Language = Lang> {
- fn accent_name_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == ACCENT_NAME)
- }
-}
-
-pub trait HasWord: AstNode<Language = Lang> {
- fn word_token(&self) -> Option<SyntaxToken> {
- self.syntax()
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|token| token.kind() == WORD)
- }
-}
-
-pub trait HasValue: AstNode<Language = Lang> {
- fn value(&self) -> Option<Value> {
- self.syntax().children().find_map(Value::cast)
- }
-}
-
-ast_node!(name: Root, kinds: [ROOT], traits: []);
-
-impl Root {
- pub fn strings(&self) -> impl Iterator<Item = StringDef> {
- self.syntax().children().filter_map(StringDef::cast)
- }
-
- pub fn entries(&self) -> impl Iterator<Item = Entry> {
- self.syntax().children().filter_map(Entry::cast)
- }
-
- pub fn find_entry(&self, name: &str) -> Option<Entry> {
- self.entries().find(|entry| {
- entry
- .name_token()
- .map_or(false, |token| token.text() == name)
- })
- }
-}
-
-ast_node!(name: Preamble, kinds: [PREAMBLE], traits: [HasType, HasDelims, HasValue]);
-
-ast_node!(name: StringDef, kinds: [STRING], traits: [HasType, HasDelims, HasName, HasEq, HasValue]);
-
-ast_node!(name: Entry, kinds: [ENTRY], traits: [HasType, HasDelims, HasName, HasComma]);
-
-impl Entry {
- pub fn fields(&self) -> impl Iterator<Item = Field> {
- self.syntax().children().filter_map(Field::cast)
- }
-}
-
-ast_node!(name: Field, kinds: [FIELD], traits: [HasName, HasEq, HasValue, HasComma]);
-
-ast_node_enum!(name: Value, variants: [Literal, CurlyGroup, QuoteGroup, Join, Accent, Command]);
-
-ast_node!(name: Literal, kinds: [LITERAL], traits: [HasName, HasInteger]);
-
-ast_node!(name: CurlyGroup, kinds: [CURLY_GROUP], traits: []);
-
-ast_node!(name: QuoteGroup, kinds: [QUOTE_GROUP], traits: []);
-
-ast_node!(name: Join, kinds: [JOIN], traits: [HasPound]);
-
-impl Join {
- pub fn left_value(&self) -> Option<Value> {
- self.syntax().children().find_map(Value::cast)
- }
-
- pub fn right_value(&self) -> Option<Value> {
- self.syntax().children().filter_map(Value::cast).nth(1)
- }
-}
-
-ast_node!(name: Accent, kinds: [ACCENT], traits: [HasAccentName, HasWord]);
-
-ast_node!(name: Command, kinds: [COMMAND], traits: [HasCommandName]);
diff --git a/support/texlab/src/syntax/bibtex/lexer.rs b/support/texlab/src/syntax/bibtex/lexer.rs
deleted file mode 100644
index 3ea8e9f8d2..0000000000
--- a/support/texlab/src/syntax/bibtex/lexer.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-use logos::Logos;
-
-use super::SyntaxKind::{self, *};
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
-pub enum RootToken {
- #[token(r"@preamble", ignore(ascii_case))]
- Preamble,
-
- #[token(r"@string", ignore(ascii_case))]
- String,
-
- #[token(r"@comment", ignore(ascii_case))]
- Comment,
-
- #[regex(r"@[a-zA-Z]*")]
- Entry,
-
- #[regex(r"[^@]+")]
- #[error]
- Junk,
-}
-
-impl From<RootToken> for SyntaxKind {
- fn from(token: RootToken) -> Self {
- match token {
- RootToken::Preamble | RootToken::String | RootToken::Comment | RootToken::Entry => TYPE,
- RootToken::Junk => JUNK,
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
-pub enum BodyToken {
- #[regex(r"\s+")]
- Whitespace,
-
- #[token("{")]
- #[token("(")]
- LDelim,
-
- #[token("}")]
- #[token(")")]
- RDelim,
-
- #[token(",")]
- Comma,
-
- #[token("=")]
- Eq,
-
- #[regex(r"[^\s\(\)\{\}@,=]+")]
- Name,
-
- #[error]
- Error,
-}
-
-impl From<BodyToken> for SyntaxKind {
- fn from(token: BodyToken) -> Self {
- match token {
- BodyToken::Whitespace => WHITESPACE,
- BodyToken::LDelim => L_DELIM,
- BodyToken::RDelim => R_DELIM,
- BodyToken::Comma => COMMA,
- BodyToken::Eq => EQ,
- BodyToken::Name => NAME,
- BodyToken::Error => unreachable!(),
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
-pub enum ValueToken {
- #[regex(r"\s+")]
- Whitespace,
-
- #[token("#")]
- Pound,
-
- #[token(",")]
- Comma,
-
- #[token("{")]
- LCurly,
-
- #[token("}")]
- RCurly,
-
- #[token("\"")]
- Quote,
-
- #[regex(r"\d+", priority = 2)]
- Integer,
-
- #[regex(r#"[^\s"\{\},]+"#)]
- #[error]
- Name,
-}
-
-impl From<ValueToken> for SyntaxKind {
- fn from(token: ValueToken) -> Self {
- match token {
- ValueToken::Whitespace => WHITESPACE,
- ValueToken::Pound => POUND,
- ValueToken::Comma => COMMA,
- ValueToken::LCurly => L_CURLY,
- ValueToken::RCurly => R_CURLY,
- ValueToken::Quote => QUOTE,
- ValueToken::Integer => INTEGER,
- ValueToken::Name => NAME,
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash, Logos)]
-pub enum ContentToken {
- #[regex(r"\s+")]
- Whitespace,
-
- #[token(",")]
- Comma,
-
- #[token("{")]
- LCurly,
-
- #[token("}")]
- RCurly,
-
- #[token("\"")]
- Quote,
-
- #[regex(r"\d+", priority = 2)]
- Integer,
-
- #[token(r#"~"#)]
- Nbsp,
-
- #[token(r#"\`"#)]
- #[token(r#"\'"#)]
- #[token(r#"\^"#)]
- #[token(r#"\""#)]
- #[token(r#"\H"#)]
- #[token(r#"\~"#)]
- #[token(r#"\c"#)]
- #[token(r#"\k"#)]
- #[token(r#"\="#)]
- #[token(r#"\b"#)]
- #[token(r#"\."#)]
- #[token(r#"\d"#)]
- #[token(r#"\r"#)]
- #[token(r#"\u"#)]
- #[token(r#"\v"#)]
- #[token(r#"\t"#)]
- AccentName,
-
- #[regex(r"\\([^\r\n]|[@a-zA-Z:_]+\*?)?")]
- CommandName,
-
- #[regex(r#"[^\s"\{\}\\~,]+"#)]
- #[error]
- Word,
-}
-
-impl From<ContentToken> for SyntaxKind {
- fn from(token: ContentToken) -> Self {
- match token {
- ContentToken::Whitespace => WHITESPACE,
- ContentToken::Comma => COMMA,
- ContentToken::LCurly => L_CURLY,
- ContentToken::RCurly => R_CURLY,
- ContentToken::Quote => QUOTE,
- ContentToken::Integer => INTEGER,
- ContentToken::Nbsp => NBSP,
- ContentToken::AccentName => ACCENT_NAME,
- ContentToken::CommandName => COMMAND_NAME,
- ContentToken::Word => WORD,
- }
- }
-}
diff --git a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_001.snap b/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_001.snap
deleted file mode 100644
index 4fbec161d2..0000000000
--- a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_001.snap
+++ /dev/null
@@ -1,430 +0,0 @@
----
-source: src/syntax/bibtex/tests.rs
-assertion_line: 47
-expression: "setup(r#\"@incollection{westfahl:space,\n author = {Westfahl, Gary},\n title = {The True Frontier},\n subtitle = {Confronting and Avoiding the Realities of Space in {American}\n Science Fiction Films},\n pages = {55-65},\n crossref = {westfahl:frontier},\n langid = {english},\n langidopts = {variant=american},\n indextitle = {True Frontier, The},\n annotation = {A cross-referenced article from a \\texttt{collection}. This is\n an \\texttt{incollection} entry with a \\texttt{crossref}\n field. Note the \\texttt{subtitle} and \\texttt{indextitle}\n fields},\n}\n\n% booktitle and booksubtitle are only needed for BibTeX's less sophisticated\n% inheritance set-up to make sure westfahl:space shows correctly.\n% With Biber they are not needed.\n@collection{westfahl:frontier,\n editor = {Westfahl, Gary},\n title = {Space and Beyond},\n date = 2000,\n subtitle = {The Frontier Theme in Science Fiction},\n publisher = {Greenwood},\n location = {Westport, Conn. and London},\n langid = {english},\n langidopts = {variant=american},\n booktitle = {Space and Beyond},\n booksubtitle = {The Frontier Theme in Science Fiction},\n annotation = {This is a \\texttt{collection} entry. Note the format of the\n \\texttt{location} field as well as the \\texttt{subtitle}\n field},\n}\"#)"
----
-ROOT@0..1484
- ENTRY@0..678
- TYPE@0..13 "@incollection"
- L_DELIM@13..14 "{"
- NAME@14..28 "westfahl:space"
- COMMA@28..29 ","
- WHITESPACE@29..34 "\n "
- FIELD@34..66
- NAME@34..40 "author"
- WHITESPACE@40..47 " "
- EQ@47..48 "="
- WHITESPACE@48..49 " "
- CURLY_GROUP@49..65
- L_CURLY@49..50 "{"
- WORD@50..58 "Westfahl"
- COMMA@58..59 ","
- WHITESPACE@59..60 " "
- WORD@60..64 "Gary"
- R_CURLY@64..65 "}"
- COMMA@65..66 ","
- WHITESPACE@66..71 "\n "
- FIELD@71..106
- NAME@71..76 "title"
- WHITESPACE@76..84 " "
- EQ@84..85 "="
- WHITESPACE@85..86 " "
- CURLY_GROUP@86..105
- L_CURLY@86..87 "{"
- WORD@87..90 "The"
- WHITESPACE@90..91 " "
- WORD@91..95 "True"
- WHITESPACE@95..96 " "
- WORD@96..104 "Frontier"
- R_CURLY@104..105 "}"
- COMMA@105..106 ","
- WHITESPACE@106..111 "\n "
- FIELD@111..232
- NAME@111..119 "subtitle"
- WHITESPACE@119..124 " "
- EQ@124..125 "="
- WHITESPACE@125..126 " "
- CURLY_GROUP@126..231
- L_CURLY@126..127 "{"
- WORD@127..138 "Confronting"
- WHITESPACE@138..139 " "
- WORD@139..142 "and"
- WHITESPACE@142..143 " "
- WORD@143..151 "Avoiding"
- WHITESPACE@151..152 " "
- WORD@152..155 "the"
- WHITESPACE@155..156 " "
- WORD@156..165 "Realities"
- WHITESPACE@165..166 " "
- WORD@166..168 "of"
- WHITESPACE@168..169 " "
- WORD@169..174 "Space"
- WHITESPACE@174..175 " "
- WORD@175..177 "in"
- WHITESPACE@177..178 " "
- CURLY_GROUP@178..188
- L_CURLY@178..179 "{"
- WORD@179..187 "American"
- R_CURLY@187..188 "}"
- WHITESPACE@188..209 "\n "
- WORD@209..216 "Science"
- WHITESPACE@216..217 " "
- WORD@217..224 "Fiction"
- WHITESPACE@224..225 " "
- WORD@225..230 "Films"
- R_CURLY@230..231 "}"
- COMMA@231..232 ","
- WHITESPACE@232..237 "\n "
- FIELD@237..260
- NAME@237..242 "pages"
- WHITESPACE@242..250 " "
- EQ@250..251 "="
- WHITESPACE@251..252 " "
- CURLY_GROUP@252..259
- L_CURLY@252..253 "{"
- WORD@253..258 "55-65"
- R_CURLY@258..259 "}"
- COMMA@259..260 ","
- WHITESPACE@260..265 "\n "
- FIELD@265..300
- NAME@265..273 "crossref"
- WHITESPACE@273..278 " "
- EQ@278..279 "="
- WHITESPACE@279..280 " "
- CURLY_GROUP@280..299
- L_CURLY@280..281 "{"
- WORD@281..298 "westfahl:frontier"
- R_CURLY@298..299 "}"
- COMMA@299..300 ","
- WHITESPACE@300..305 "\n "
- FIELD@305..330
- NAME@305..311 "langid"
- WHITESPACE@311..318 " "
- EQ@318..319 "="
- WHITESPACE@319..320 " "
- CURLY_GROUP@320..329
- L_CURLY@320..321 "{"
- WORD@321..328 "english"
- R_CURLY@328..329 "}"
- COMMA@329..330 ","
- WHITESPACE@330..335 "\n "
- FIELD@335..369
- NAME@335..345 "langidopts"
- WHITESPACE@345..348 " "
- EQ@348..349 "="
- WHITESPACE@349..350 " "
- CURLY_GROUP@350..368
- L_CURLY@350..351 "{"
- WORD@351..367 "variant=american"
- R_CURLY@367..368 "}"
- COMMA@368..369 ","
- WHITESPACE@369..374 "\n "
- FIELD@374..410
- NAME@374..384 "indextitle"
- WHITESPACE@384..387 " "
- EQ@387..388 "="
- WHITESPACE@388..389 " "
- CURLY_GROUP@389..409
- L_CURLY@389..390 "{"
- WORD@390..394 "True"
- WHITESPACE@394..395 " "
- WORD@395..403 "Frontier"
- COMMA@403..404 ","
- WHITESPACE@404..405 " "
- WORD@405..408 "The"
- R_CURLY@408..409 "}"
- COMMA@409..410 ","
- WHITESPACE@410..415 "\n "
- FIELD@415..676
- NAME@415..425 "annotation"
- WHITESPACE@425..428 " "
- EQ@428..429 "="
- WHITESPACE@429..430 " "
- CURLY_GROUP@430..675
- L_CURLY@430..431 "{"
- WORD@431..432 "A"
- WHITESPACE@432..433 " "
- WORD@433..449 "cross-referenced"
- WHITESPACE@449..450 " "
- WORD@450..457 "article"
- WHITESPACE@457..458 " "
- WORD@458..462 "from"
- WHITESPACE@462..463 " "
- WORD@463..464 "a"
- WHITESPACE@464..465 " "
- COMMAND@465..472
- COMMAND_NAME@465..472 "\\texttt"
- CURLY_GROUP@472..484
- L_CURLY@472..473 "{"
- WORD@473..483 "collection"
- R_CURLY@483..484 "}"
- WORD@484..485 "."
- WHITESPACE@485..486 " "
- WORD@486..490 "This"
- WHITESPACE@490..491 " "
- WORD@491..493 "is"
- WHITESPACE@493..514 "\n "
- WORD@514..516 "an"
- WHITESPACE@516..517 " "
- COMMAND@517..524
- COMMAND_NAME@517..524 "\\texttt"
- CURLY_GROUP@524..538
- L_CURLY@524..525 "{"
- WORD@525..537 "incollection"
- R_CURLY@537..538 "}"
- WHITESPACE@538..539 " "
- WORD@539..544 "entry"
- WHITESPACE@544..545 " "
- WORD@545..549 "with"
- WHITESPACE@549..550 " "
- WORD@550..551 "a"
- WHITESPACE@551..552 " "
- COMMAND@552..559
- COMMAND_NAME@552..559 "\\texttt"
- CURLY_GROUP@559..569
- L_CURLY@559..560 "{"
- WORD@560..568 "crossref"
- R_CURLY@568..569 "}"
- WHITESPACE@569..590 "\n "
- WORD@590..596 "field."
- WHITESPACE@596..597 " "
- WORD@597..601 "Note"
- WHITESPACE@601..602 " "
- WORD@602..605 "the"
- WHITESPACE@605..606 " "
- COMMAND@606..613
- COMMAND_NAME@606..613 "\\texttt"
- CURLY_GROUP@613..623
- L_CURLY@613..614 "{"
- WORD@614..622 "subtitle"
- R_CURLY@622..623 "}"
- WHITESPACE@623..624 " "
- WORD@624..627 "and"
- WHITESPACE@627..628 " "
- COMMAND@628..635
- COMMAND_NAME@628..635 "\\texttt"
- CURLY_GROUP@635..647
- L_CURLY@635..636 "{"
- WORD@636..646 "indextitle"
- R_CURLY@646..647 "}"
- WHITESPACE@647..668 "\n "
- WORD@668..674 "fields"
- R_CURLY@674..675 "}"
- COMMA@675..676 ","
- WHITESPACE@676..677 "\n"
- R_DELIM@677..678 "}"
- JUNK@678..857 "\n\n% booktitle and boo ..."
- ENTRY@857..1484
- TYPE@857..868 "@collection"
- L_DELIM@868..869 "{"
- NAME@869..886 "westfahl:frontier"
- COMMA@886..887 ","
- WHITESPACE@887..892 "\n "
- FIELD@892..924
- NAME@892..898 "editor"
- WHITESPACE@898..905 " "
- EQ@905..906 "="
- WHITESPACE@906..907 " "
- CURLY_GROUP@907..923
- L_CURLY@907..908 "{"
- WORD@908..916 "Westfahl"
- COMMA@916..917 ","
- WHITESPACE@917..918 " "
- WORD@918..922 "Gary"
- R_CURLY@922..923 "}"
- COMMA@923..924 ","
- WHITESPACE@924..929 "\n "
- FIELD@929..963
- NAME@929..934 "title"
- WHITESPACE@934..942 " "
- EQ@942..943 "="
- WHITESPACE@943..944 " "
- CURLY_GROUP@944..962
- L_CURLY@944..945 "{"
- WORD@945..950 "Space"
- WHITESPACE@950..951 " "
- WORD@951..954 "and"
- WHITESPACE@954..955 " "
- WORD@955..961 "Beyond"
- R_CURLY@961..962 "}"
- COMMA@962..963 ","
- WHITESPACE@963..968 "\n "
- FIELD@968..988
- NAME@968..972 "date"
- WHITESPACE@972..981 " "
- EQ@981..982 "="
- WHITESPACE@982..983 " "
- LITERAL@983..987
- INTEGER@983..987 "2000"
- COMMA@987..988 ","
- WHITESPACE@988..993 "\n "
- FIELD@993..1048
- NAME@993..1001 "subtitle"
- WHITESPACE@1001..1006 " "
- EQ@1006..1007 "="
- WHITESPACE@1007..1008 " "
- CURLY_GROUP@1008..1047
- L_CURLY@1008..1009 "{"
- WORD@1009..1012 "The"
- WHITESPACE@1012..1013 " "
- WORD@1013..1021 "Frontier"
- WHITESPACE@1021..1022 " "
- WORD@1022..1027 "Theme"
- WHITESPACE@1027..1028 " "
- WORD@1028..1030 "in"
- WHITESPACE@1030..1031 " "
- WORD@1031..1038 "Science"
- WHITESPACE@1038..1039 " "
- WORD@1039..1046 "Fiction"
- R_CURLY@1046..1047 "}"
- COMMA@1047..1048 ","
- WHITESPACE@1048..1053 "\n "
- FIELD@1053..1080
- NAME@1053..1062 "publisher"
- WHITESPACE@1062..1066 " "
- EQ@1066..1067 "="
- WHITESPACE@1067..1068 " "
- CURLY_GROUP@1068..1079
- L_CURLY@1068..1069 "{"
- WORD@1069..1078 "Greenwood"
- R_CURLY@1078..1079 "}"
- COMMA@1079..1080 ","
- WHITESPACE@1080..1085 "\n "
- FIELD@1085..1129
- NAME@1085..1093 "location"
- WHITESPACE@1093..1098 " "
- EQ@1098..1099 "="
- WHITESPACE@1099..1100 " "
- CURLY_GROUP@1100..1128
- L_CURLY@1100..1101 "{"
- WORD@1101..1109 "Westport"
- COMMA@1109..1110 ","
- WHITESPACE@1110..1111 " "
- WORD@1111..1116 "Conn."
- WHITESPACE@1116..1117 " "
- WORD@1117..1120 "and"
- WHITESPACE@1120..1121 " "
- WORD@1121..1127 "London"
- R_CURLY@1127..1128 "}"
- COMMA@1128..1129 ","
- WHITESPACE@1129..1134 "\n "
- FIELD@1134..1159
- NAME@1134..1140 "langid"
- WHITESPACE@1140..1147 " "
- EQ@1147..1148 "="
- WHITESPACE@1148..1149 " "
- CURLY_GROUP@1149..1158
- L_CURLY@1149..1150 "{"
- WORD@1150..1157 "english"
- R_CURLY@1157..1158 "}"
- COMMA@1158..1159 ","
- WHITESPACE@1159..1164 "\n "
- FIELD@1164..1198
- NAME@1164..1174 "langidopts"
- WHITESPACE@1174..1177 " "
- EQ@1177..1178 "="
- WHITESPACE@1178..1179 " "
- CURLY_GROUP@1179..1197
- L_CURLY@1179..1180 "{"
- WORD@1180..1196 "variant=american"
- R_CURLY@1196..1197 "}"
- COMMA@1197..1198 ","
- WHITESPACE@1198..1203 "\n "
- FIELD@1203..1237
- NAME@1203..1212 "booktitle"
- WHITESPACE@1212..1216 " "
- EQ@1216..1217 "="
- WHITESPACE@1217..1218 " "
- CURLY_GROUP@1218..1236
- L_CURLY@1218..1219 "{"
- WORD@1219..1224 "Space"
- WHITESPACE@1224..1225 " "
- WORD@1225..1228 "and"
- WHITESPACE@1228..1229 " "
- WORD@1229..1235 "Beyond"
- R_CURLY@1235..1236 "}"
- COMMA@1236..1237 ","
- WHITESPACE@1237..1242 "\n "
- FIELD@1242..1297
- NAME@1242..1254 "booksubtitle"
- WHITESPACE@1254..1255 " "
- EQ@1255..1256 "="
- WHITESPACE@1256..1257 " "
- CURLY_GROUP@1257..1296
- L_CURLY@1257..1258 "{"
- WORD@1258..1261 "The"
- WHITESPACE@1261..1262 " "
- WORD@1262..1270 "Frontier"
- WHITESPACE@1270..1271 " "
- WORD@1271..1276 "Theme"
- WHITESPACE@1276..1277 " "
- WORD@1277..1279 "in"
- WHITESPACE@1279..1280 " "
- WORD@1280..1287 "Science"
- WHITESPACE@1287..1288 " "
- WORD@1288..1295 "Fiction"
- R_CURLY@1295..1296 "}"
- COMMA@1296..1297 ","
- WHITESPACE@1297..1302 "\n "
- FIELD@1302..1482
- NAME@1302..1312 "annotation"
- WHITESPACE@1312..1315 " "
- EQ@1315..1316 "="
- WHITESPACE@1316..1317 " "
- CURLY_GROUP@1317..1481
- L_CURLY@1317..1318 "{"
- WORD@1318..1322 "This"
- WHITESPACE@1322..1323 " "
- WORD@1323..1325 "is"
- WHITESPACE@1325..1326 " "
- WORD@1326..1327 "a"
- WHITESPACE@1327..1328 " "
- COMMAND@1328..1335
- COMMAND_NAME@1328..1335 "\\texttt"
- CURLY_GROUP@1335..1347
- L_CURLY@1335..1336 "{"
- WORD@1336..1346 "collection"
- R_CURLY@1346..1347 "}"
- WHITESPACE@1347..1348 " "
- WORD@1348..1354 "entry."
- WHITESPACE@1354..1355 " "
- WORD@1355..1359 "Note"
- WHITESPACE@1359..1360 " "
- WORD@1360..1363 "the"
- WHITESPACE@1363..1364 " "
- WORD@1364..1370 "format"
- WHITESPACE@1370..1371 " "
- WORD@1371..1373 "of"
- WHITESPACE@1373..1374 " "
- WORD@1374..1377 "the"
- WHITESPACE@1377..1398 "\n "
- COMMAND@1398..1405
- COMMAND_NAME@1398..1405 "\\texttt"
- CURLY_GROUP@1405..1415
- L_CURLY@1405..1406 "{"
- WORD@1406..1414 "location"
- R_CURLY@1414..1415 "}"
- WHITESPACE@1415..1416 " "
- WORD@1416..1421 "field"
- WHITESPACE@1421..1422 " "
- WORD@1422..1424 "as"
- WHITESPACE@1424..1425 " "
- WORD@1425..1429 "well"
- WHITESPACE@1429..1430 " "
- WORD@1430..1432 "as"
- WHITESPACE@1432..1433 " "
- WORD@1433..1436 "the"
- WHITESPACE@1436..1437 " "
- COMMAND@1437..1444
- COMMAND_NAME@1437..1444 "\\texttt"
- CURLY_GROUP@1444..1454
- L_CURLY@1444..1445 "{"
- WORD@1445..1453 "subtitle"
- R_CURLY@1453..1454 "}"
- WHITESPACE@1454..1475 "\n "
- WORD@1475..1480 "field"
- R_CURLY@1480..1481 "}"
- COMMA@1481..1482 ","
- WHITESPACE@1482..1483 "\n"
- R_DELIM@1483..1484 "}"
-
diff --git a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_003.snap b/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_003.snap
deleted file mode 100644
index 360b133a8e..0000000000
--- a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__biblatex_examples_003.snap
+++ /dev/null
@@ -1,208 +0,0 @@
----
-source: src/syntax/bibtex/tests.rs
-assertion_line: 109
-expression: "setup(r#\"@article{angenendt,\n author = {Angenendt, Arnold},\n title = {In Honore Salvatoris~-- Vom Sinn und Unsinn der\n Patrozinienkunde},\n journaltitle = {Revue d'Histoire Eccl{\\'e}siastique},\n date = 2002,\n volume = 97,\n pages = {431--456, 791--823},\n langid = {german},\n indextitle = {In Honore Salvatoris},\n shorttitle = {In Honore Salvatoris},\n annotation = {A German article in a French journal. Apart from that, a\n typical \\texttt{article} entry. Note the \\texttt{indextitle}\n field},\n}\"#)"
----
-ROOT@0..616
- ENTRY@0..616
- TYPE@0..8 "@article"
- L_DELIM@8..9 "{"
- NAME@9..18 "angenendt"
- COMMA@18..19 ","
- WHITESPACE@19..24 "\n "
- FIELD@24..59
- NAME@24..30 "author"
- WHITESPACE@30..37 " "
- EQ@37..38 "="
- WHITESPACE@38..39 " "
- CURLY_GROUP@39..58
- L_CURLY@39..40 "{"
- WORD@40..49 "Angenendt"
- COMMA@49..50 ","
- WHITESPACE@50..51 " "
- WORD@51..57 "Arnold"
- R_CURLY@57..58 "}"
- COMMA@58..59 ","
- WHITESPACE@59..64 "\n "
- FIELD@64..166
- NAME@64..69 "title"
- WHITESPACE@69..77 " "
- EQ@77..78 "="
- WHITESPACE@78..79 " "
- CURLY_GROUP@79..165
- L_CURLY@79..80 "{"
- WORD@80..82 "In"
- WHITESPACE@82..83 " "
- WORD@83..89 "Honore"
- WHITESPACE@89..90 " "
- WORD@90..100 "Salvatoris"
- NBSP@100..101 "~"
- WORD@101..103 "--"
- WHITESPACE@103..104 " "
- WORD@104..107 "Vom"
- WHITESPACE@107..108 " "
- WORD@108..112 "Sinn"
- WHITESPACE@112..113 " "
- WORD@113..116 "und"
- WHITESPACE@116..117 " "
- WORD@117..123 "Unsinn"
- WHITESPACE@123..124 " "
- WORD@124..127 "der"
- WHITESPACE@127..148 "\n "
- WORD@148..164 "Patrozinienkunde"
- R_CURLY@164..165 "}"
- COMMA@165..166 ","
- WHITESPACE@166..171 "\n "
- FIELD@171..224
- NAME@171..183 "journaltitle"
- WHITESPACE@183..184 " "
- EQ@184..185 "="
- WHITESPACE@185..186 " "
- CURLY_GROUP@186..223
- L_CURLY@186..187 "{"
- WORD@187..192 "Revue"
- WHITESPACE@192..193 " "
- WORD@193..203 "d'Histoire"
- WHITESPACE@203..204 " "
- WORD@204..208 "Eccl"
- CURLY_GROUP@208..213
- L_CURLY@208..209 "{"
- ACCENT@209..212
- ACCENT_NAME@209..211 "\\'"
- WORD@211..212 "e"
- R_CURLY@212..213 "}"
- WORD@213..222 "siastique"
- R_CURLY@222..223 "}"
- COMMA@223..224 ","
- WHITESPACE@224..229 "\n "
- FIELD@229..249
- NAME@229..233 "date"
- WHITESPACE@233..242 " "
- EQ@242..243 "="
- WHITESPACE@243..244 " "
- LITERAL@244..248
- INTEGER@244..248 "2002"
- COMMA@248..249 ","
- WHITESPACE@249..254 "\n "
- FIELD@254..272
- NAME@254..260 "volume"
- WHITESPACE@260..267 " "
- EQ@267..268 "="
- WHITESPACE@268..269 " "
- LITERAL@269..271
- INTEGER@269..271 "97"
- COMMA@271..272 ","
- WHITESPACE@272..277 "\n "
- FIELD@277..313
- NAME@277..282 "pages"
- WHITESPACE@282..290 " "
- EQ@290..291 "="
- WHITESPACE@291..292 " "
- CURLY_GROUP@292..312
- L_CURLY@292..293 "{"
- WORD@293..301 "431--456"
- COMMA@301..302 ","
- WHITESPACE@302..303 " "
- WORD@303..311 "791--823"
- R_CURLY@311..312 "}"
- COMMA@312..313 ","
- WHITESPACE@313..318 "\n "
- FIELD@318..342
- NAME@318..324 "langid"
- WHITESPACE@324..331 " "
- EQ@331..332 "="
- WHITESPACE@332..333 " "
- CURLY_GROUP@333..341
- L_CURLY@333..334 "{"
- WORD@334..340 "german"
- R_CURLY@340..341 "}"
- COMMA@341..342 ","
- WHITESPACE@342..347 "\n "
- FIELD@347..385
- NAME@347..357 "indextitle"
- WHITESPACE@357..360 " "
- EQ@360..361 "="
- WHITESPACE@361..362 " "
- CURLY_GROUP@362..384
- L_CURLY@362..363 "{"
- WORD@363..365 "In"
- WHITESPACE@365..366 " "
- WORD@366..372 "Honore"
- WHITESPACE@372..373 " "
- WORD@373..383 "Salvatoris"
- R_CURLY@383..384 "}"
- COMMA@384..385 ","
- WHITESPACE@385..390 "\n "
- FIELD@390..428
- NAME@390..400 "shorttitle"
- WHITESPACE@400..403 " "
- EQ@403..404 "="
- WHITESPACE@404..405 " "
- CURLY_GROUP@405..427
- L_CURLY@405..406 "{"
- WORD@406..408 "In"
- WHITESPACE@408..409 " "
- WORD@409..415 "Honore"
- WHITESPACE@415..416 " "
- WORD@416..426 "Salvatoris"
- R_CURLY@426..427 "}"
- COMMA@427..428 ","
- WHITESPACE@428..433 "\n "
- FIELD@433..614
- NAME@433..443 "annotation"
- WHITESPACE@443..446 " "
- EQ@446..447 "="
- WHITESPACE@447..448 " "
- CURLY_GROUP@448..613
- L_CURLY@448..449 "{"
- WORD@449..450 "A"
- WHITESPACE@450..451 " "
- WORD@451..457 "German"
- WHITESPACE@457..458 " "
- WORD@458..465 "article"
- WHITESPACE@465..466 " "
- WORD@466..468 "in"
- WHITESPACE@468..469 " "
- WORD@469..470 "a"
- WHITESPACE@470..471 " "
- WORD@471..477 "French"
- WHITESPACE@477..478 " "
- WORD@478..486 "journal."
- WHITESPACE@486..487 " "
- WORD@487..492 "Apart"
- WHITESPACE@492..493 " "
- WORD@493..497 "from"
- WHITESPACE@497..498 " "
- WORD@498..502 "that"
- COMMA@502..503 ","
- WHITESPACE@503..504 " "
- WORD@504..505 "a"
- WHITESPACE@505..526 "\n "
- WORD@526..533 "typical"
- WHITESPACE@533..534 " "
- COMMAND@534..541
- COMMAND_NAME@534..541 "\\texttt"
- CURLY_GROUP@541..550
- L_CURLY@541..542 "{"
- WORD@542..549 "article"
- R_CURLY@549..550 "}"
- WHITESPACE@550..551 " "
- WORD@551..557 "entry."
- WHITESPACE@557..558 " "
- WORD@558..562 "Note"
- WHITESPACE@562..563 " "
- WORD@563..566 "the"
- WHITESPACE@566..567 " "
- COMMAND@567..574
- COMMAND_NAME@567..574 "\\texttt"
- CURLY_GROUP@574..586
- L_CURLY@574..575 "{"
- WORD@575..585 "indextitle"
- R_CURLY@585..586 "}"
- WHITESPACE@586..607 "\n "
- WORD@607..612 "field"
- R_CURLY@612..613 "}"
- COMMA@613..614 ","
- WHITESPACE@614..615 "\n"
- R_DELIM@615..616 "}"
-
diff --git a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__comment.snap b/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__comment.snap
deleted file mode 100644
index 3267517c49..0000000000
--- a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__comment.snap
+++ /dev/null
@@ -1,9 +0,0 @@
----
-source: src/syntax/bibtex/tests.rs
-assertion_line: 16
-expression: "setup(r#\"@comment{aksin,\n author = {Aks{\\i}n, {\\\"O}zge and T{\\\"u}rkmen, Hayati and Artok, Levent\n and {\\c{C}}etinkaya, Bekir and Ni, Chaoying and\n B{\\\"u}y{\\\"u}kg{\\\"u}ng{\\\"o}r, Orhan and {\\\"O}zkal, Erhan},\n title = {Effect of immobilization on catalytic characteristics of\n saturated {Pd-N}-heterocyclic carbenes in {Mizoroki-Heck}\n reactions},\n journaltitle = jomch,\n date = 2006,\n volume = 691,\n number = 13,\n pages = {3027-3036},\n indextitle = {Effect of immobilization on catalytic characteristics},\n}\"#)"
----
-ROOT@0..637
- TYPE@0..8 "@comment"
- JUNK@8..637 "{aksin,\n author ..."
-
diff --git a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__entry_colon.snap b/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__entry_colon.snap
deleted file mode 100644
index bff11a8d5a..0000000000
--- a/support/texlab/src/syntax/bibtex/snapshots/texlab__syntax__bibtex__tests__entry_colon.snap
+++ /dev/null
@@ -1,51 +0,0 @@
----
-source: src/syntax/bibtex/tests.rs
-assertion_line: 36
-expression: "setup(r#\"@article{foo:2019,\n author = {Foo Bar},\n title = {Baz Qux},\n year = {2019},\n}\"#)"
----
-ROOT@0..86
- ENTRY@0..86
- TYPE@0..8 "@article"
- L_DELIM@8..9 "{"
- NAME@9..17 "foo:2019"
- COMMA@17..18 ","
- WHITESPACE@18..23 "\n "
- FIELD@23..42
- NAME@23..29 "author"
- WHITESPACE@29..30 " "
- EQ@30..31 "="
- WHITESPACE@31..32 " "
- CURLY_GROUP@32..41
- L_CURLY@32..33 "{"
- WORD@33..36 "Foo"
- WHITESPACE@36..37 " "
- WORD@37..40 "Bar"
- R_CURLY@40..41 "}"
- COMMA@41..42 ","
- WHITESPACE@42..47 "\n "
- FIELD@47..65
- NAME@47..52 "title"
- WHITESPACE@52..53 " "
- EQ@53..54 "="
- WHITESPACE@54..55 " "
- CURLY_GROUP@55..64
- L_CURLY@55..56 "{"
- WORD@56..59 "Baz"
- WHITESPACE@59..60 " "
- WORD@60..63 "Qux"
- R_CURLY@63..64 "}"
- COMMA@64..65 ","
- WHITESPACE@65..70 "\n "
- FIELD@70..84
- NAME@70..74 "year"
- WHITESPACE@74..75 " "
- EQ@75..76 "="
- WHITESPACE@76..77 " "
- CURLY_GROUP@77..83
- L_CURLY@77..78 "{"
- INTEGER@78..82 "2019"
- R_CURLY@82..83 "}"
- COMMA@83..84 ","
- WHITESPACE@84..85 "\n"
- R_DELIM@85..86 "}"
-
diff --git a/support/texlab/src/syntax/bibtex/tests.rs b/support/texlab/src/syntax/bibtex/tests.rs
deleted file mode 100644
index 8dce0e2df9..0000000000
--- a/support/texlab/src/syntax/bibtex/tests.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use insta::assert_debug_snapshot;
-
-use super::{parse, SyntaxNode};
-
-fn setup(input: &str) -> SyntaxNode {
- SyntaxNode::new_root(parse(input))
-}
-
-#[test]
-fn test_preamble() {
- assert_debug_snapshot!(setup(r#"@preamble{"Hello World!"}"#));
-}
-
-#[test]
-fn test_comment() {
- assert_debug_snapshot!(setup(
- r#"@comment{aksin,
- author = {Aks{\i}n, {\"O}zge and T{\"u}rkmen, Hayati and Artok, Levent
- and {\c{C}}etinkaya, Bekir and Ni, Chaoying and
- B{\"u}y{\"u}kg{\"u}ng{\"o}r, Orhan and {\"O}zkal, Erhan},
- title = {Effect of immobilization on catalytic characteristics of
- saturated {Pd-N}-heterocyclic carbenes in {Mizoroki-Heck}
- reactions},
- journaltitle = jomch,
- date = 2006,
- volume = 691,
- number = 13,
- pages = {3027-3036},
- indextitle = {Effect of immobilization on catalytic characteristics},
-}"#
- ));
-}
-
-#[test]
-fn test_entry_colon() {
- assert_debug_snapshot!(setup(
- r#"@article{foo:2019,
- author = {Foo Bar},
- title = {Baz Qux},
- year = {2019},
-}"#
- ));
-}
-
-#[test]
-fn test_biblatex_examples_001() {
- assert_debug_snapshot!(setup(
- r#"@incollection{westfahl:space,
- author = {Westfahl, Gary},
- title = {The True Frontier},
- subtitle = {Confronting and Avoiding the Realities of Space in {American}
- Science Fiction Films},
- pages = {55-65},
- crossref = {westfahl:frontier},
- langid = {english},
- langidopts = {variant=american},
- indextitle = {True Frontier, The},
- annotation = {A cross-referenced article from a \texttt{collection}. This is
- an \texttt{incollection} entry with a \texttt{crossref}
- field. Note the \texttt{subtitle} and \texttt{indextitle}
- fields},
-}
-
-% booktitle and booksubtitle are only needed for BibTeX's less sophisticated
-% inheritance set-up to make sure westfahl:space shows correctly.
-% With Biber they are not needed.
-@collection{westfahl:frontier,
- editor = {Westfahl, Gary},
- title = {Space and Beyond},
- date = 2000,
- subtitle = {The Frontier Theme in Science Fiction},
- publisher = {Greenwood},
- location = {Westport, Conn. and London},
- langid = {english},
- langidopts = {variant=american},
- booktitle = {Space and Beyond},
- booksubtitle = {The Frontier Theme in Science Fiction},
- annotation = {This is a \texttt{collection} entry. Note the format of the
- \texttt{location} field as well as the \texttt{subtitle}
- field},
-}"#
- ));
-}
-
-#[test]
-fn test_biblatex_examples_002() {
- assert_debug_snapshot!(setup(
- r#"@string{jomch = {J.~Organomet. Chem.}}
-
-@article{aksin,
- author = {Aks{\i}n, {\"O}zge and T{\"u}rkmen, Hayati and Artok, Levent
- and {\c{C}}etinkaya, Bekir and Ni, Chaoying and
- B{\"u}y{\"u}kg{\"u}ng{\"o}r, Orhan and {\"O}zkal, Erhan},
- title = {Effect of immobilization on catalytic characteristics of
- saturated {Pd-N}-heterocyclic carbenes in {Mizoroki-Heck}
- reactions},
- journaltitle = jomch,
- date = 2006,
- volume = 691,
- number = 13,
- pages = {3027-3036},
- indextitle = {Effect of immobilization on catalytic characteristics},
-}"#
- ));
-}
-
-#[test]
-fn test_biblatex_examples_003() {
- assert_debug_snapshot!(setup(
- r#"@article{angenendt,
- author = {Angenendt, Arnold},
- title = {In Honore Salvatoris~-- Vom Sinn und Unsinn der
- Patrozinienkunde},
- journaltitle = {Revue d'Histoire Eccl{\'e}siastique},
- date = 2002,
- volume = 97,
- pages = {431--456, 791--823},
- langid = {german},
- indextitle = {In Honore Salvatoris},
- shorttitle = {In Honore Salvatoris},
- annotation = {A German article in a French journal. Apart from that, a
- typical \texttt{article} entry. Note the \texttt{indextitle}
- field},
-}"#
- ));
-}
diff --git a/support/texlab/src/syntax/build_log.rs b/support/texlab/src/syntax/build_log.rs
deleted file mode 100644
index af03e51d11..0000000000
--- a/support/texlab/src/syntax/build_log.rs
+++ /dev/null
@@ -1,1332 +0,0 @@
-use std::{cmp::Ordering, path::PathBuf};
-
-use once_cell::sync::Lazy;
-use regex::{Match, Regex};
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
-pub enum BuildErrorLevel {
- Error,
- Warning,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Hash)]
-pub struct BuildError {
- pub relative_path: PathBuf,
- pub level: BuildErrorLevel,
- pub message: String,
- pub line: Option<u32>,
-}
-
-const MAX_LINE_LENGTH: usize = 79;
-
-pub static PACKAGE_MESSAGE_REGEX: Lazy<Regex> =
- Lazy::new(|| Regex::new("^\\([a-zA-Z_\\-]+\\)\\s*(?P<msg>.*)$").unwrap());
-
-pub static FILE_REGEX: Lazy<Regex> =
- Lazy::new(|| Regex::new("\\((?P<file>[^\r\n()]+\\.(tex|sty|cls))").unwrap());
-
-pub static TEX_ERROR_REGEX: Lazy<Regex> = Lazy::new(|| {
- Regex::new("(?m)^! ((?P<msg1>(.|\r|\n)*?)\r?\nl\\.(?P<line>\\d+)|(?P<msg2>[^\r\n]*))").unwrap()
-});
-
-pub static WARNING_REGEX: Lazy<Regex> =
- Lazy::new(|| Regex::new("(LaTeX|Package [a-zA-Z_\\-]+) Warning: (?P<msg>[^\r\n]*)").unwrap());
-
-pub static BAD_BOX_REGEX: Lazy<Regex> = Lazy::new(|| {
- Regex::new("(?P<msg>(Ov|Und)erfull \\\\[hv]box[^\r\n]*lines? (?P<line>\\d+)[^\r\n]*)").unwrap()
-});
-
-#[derive(Debug, PartialEq, Eq, Clone, Hash)]
-pub struct Parse {
- pub errors: Vec<BuildError>,
-}
-
-pub fn parse(log: &str) -> Parse {
- let log = prepare_log(log);
- let mut ranges: Vec<FileRange> = FILE_REGEX
- .find_iter(&log)
- .map(|result| FileRange::create(&log, result))
- .collect();
- ranges.sort();
-
- let tex_errors = extract_matches(&log, &ranges, &TEX_ERROR_REGEX, BuildErrorLevel::Error);
- let warnings = extract_matches(&log, &ranges, &WARNING_REGEX, BuildErrorLevel::Warning);
- let bad_boxes = extract_matches(&log, &ranges, &BAD_BOX_REGEX, BuildErrorLevel::Warning);
-
- Parse {
- errors: vec![tex_errors, warnings, bad_boxes].concat(),
- }
-}
-
-fn extract_matches(
- log: &str,
- ranges: &[FileRange],
- regex: &Regex,
- level: BuildErrorLevel,
-) -> Vec<BuildError> {
- let mut errors = Vec::new();
- for result in regex.find_iter(log) {
- let captures = regex.captures(&log[result.start()..result.end()]).unwrap();
- let message = captures
- .name("msg")
- .or_else(|| captures.name("msg1"))
- .or_else(|| captures.name("msg2"))
- .unwrap()
- .as_str()
- .lines()
- .next()
- .unwrap_or_default()
- .to_owned();
-
- if let Some(range) = ranges.iter().find(|range| range.contains(result.start())) {
- let line = captures
- .name("line")
- .map(|result| result.as_str().parse::<u32>().unwrap() - 1);
-
- errors.push(BuildError {
- relative_path: range.path.clone(),
- level,
- message,
- line,
- });
- }
- }
- errors
-}
-
-fn prepare_log(log: &str) -> String {
- let mut old_lines = log.lines();
- let mut new_lines: Vec<String> = Vec::new();
- while let Some(line) = old_lines.next() {
- if PACKAGE_MESSAGE_REGEX.is_match(line) {
- let captures = PACKAGE_MESSAGE_REGEX.captures(line).unwrap();
- if let Some(last_line) = new_lines.last_mut() {
- last_line.push(' ');
- last_line.push_str(captures.name("msg").unwrap().as_str());
- }
- } else if line.ends_with("...") {
- let mut new_line = line[line.len() - 3..].to_owned();
- if let Some(old_line) = old_lines.next() {
- new_line.push_str(old_line);
- }
- new_lines.push(new_line);
- } else if line.chars().count() == MAX_LINE_LENGTH {
- let mut new_line = String::new();
- new_line.push_str(line);
- if let Some(old_line) = old_lines.next() {
- new_line.push_str(old_line);
- }
- new_lines.push(new_line);
- } else {
- new_lines.push(line.to_owned());
- }
- }
- new_lines.join("\n")
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-struct FileRange {
- pub path: PathBuf,
- pub start: usize,
- pub end: usize,
-}
-
-impl FileRange {
- fn create(log: &str, result: Match) -> Self {
- let mut balance = 1;
- let mut end = result.start() + 1;
- let chars = (&log[result.start() + 1..]).chars();
- for c in chars {
- if balance <= 0 {
- break;
- }
-
- if c == '(' {
- balance += 1;
- } else if c == ')' {
- balance -= 1;
- }
- end += c.len_utf8();
- }
-
- let captures = FILE_REGEX.captures(result.as_str()).unwrap();
- let path = PathBuf::from(captures.name("file").unwrap().as_str());
- Self {
- path,
- start: result.start(),
- end,
- }
- }
-
- fn len(&self) -> usize {
- self.end - self.start + 1
- }
-
- fn contains(&self, index: usize) -> bool {
- index >= self.start && index <= self.end
- }
-}
-
-impl Ord for FileRange {
- fn cmp(&self, other: &Self) -> Ordering {
- self.len().cmp(&other.len())
- }
-}
-
-impl PartialOrd for FileRange {
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(self.cmp(other))
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use insta::assert_debug_snapshot;
-
- #[test]
- fn parse_001() {
- let log = r#"
-This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:50
-entering extended mode
-restricted \write18 enabled.
-%&-line parsing enabled.
-**./parent.tex
-(./parent.tex
-LaTeX2e <2017-04-15>
-Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
-(/TexLive/texmf-dist/tex/latex/base/article.cls
-Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
-(/TexLive/texmf-dist/tex/latex/base/size10.clo
-File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
-)
-\c@part=\count79
-\c@section=\count80
-\c@subsection=\count81
-\c@subsubsection=\count82
-\c@paragraph=\count83
-\c@subparagraph=\count84
-\c@figure=\count85
-\c@table=\count86
-\abovecaptionskip=\skip41
-\belowcaptionskip=\skip42
-\bibindent=\dimen102
-)
-(/TexLive/texmf-dist/tex/latex/multirow/bigstrut.sty
-Package: bigstrut 2016/11/25 v2.2 Provide larger struts in tabulars
-\bigstrutjot=\dimen103
-)
-(/TexLive/texmf-dist/tex/latex/multirow/multirow.sty
-Package: multirow 2016/11/25 v2.2 Span multiple rows of a table
-\multirow@colwidth=\skip43
-\multirow@cntb=\count87
-\multirow@dima=\skip44
-) (./parent.aux)
-\openout1 = `parent.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-
-Overfull \hbox (200.00162pt too wide) in paragraph at lines 8--9
-[]\OT1/cmr/m/n/10 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-[]
-
-LaTeX Font Info: External font `cmex10' loaded for size
-(Font) <7> on input line 11.
-LaTeX Font Info: External font `cmex10' loaded for size
-(Font) <5> on input line 11.
-
-Overfull \vbox (3.19998pt too high) detected at line 23
-[]
-
-[1
-
-{/TexLive/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./parent.aux) )
-Here is how much of TeX's memory you used:
-265 strings out of 492995
-3121 string characters out of 6138727
-55074 words of memory out of 5000000
-3896 multiletter control sequences out of 15000+600000
-3640 words of font info for 14 fonts, out of 8000000 for 9000
-1141 hyphenation exceptions out of 8191
-23i,20n,20p,124b,282s stack positions out of 5000i,500n,10000p,200000b,80000s
-</
-TexLive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></TexLive/texmf-d
-ist/fonts/type1/public/amsfonts/cm/cmr7.pfb>
-Output written on parent.pdf (1 page, 17505 bytes).
-PDF statistics:
-16 PDF objects out of 1000 (max. 8388607)
-10 compressed objects within 1 object stream
-0 named destinations out of 1000 (max. 500000)
-1 words of extra memory for PDF output out of 10000 (max. 10000000)"#;
-
- assert_eq!(
- parse(log).errors,
- vec![
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Warning,
- message: "Overfull \\hbox (200.00162pt too wide) in paragraph at lines 8--9"
- .into(),
- line: Some(7),
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Warning,
- message: "Overfull \\vbox (3.19998pt too high) detected at line 23".into(),
- line: Some(22),
- }
- ]
- );
- }
-
- #[test]
- fn parse_002() {
- let log = r#"
-This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:52
-entering extended mode
-restricted \write18 enabled.
-%&-line parsing enabled.
-**./parent.tex
-(./parent.tex
-LaTeX2e <2017-04-15>
-Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
-(/TexLive/texmf-dist/tex/latex/base/article.cls
-Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
-(/TexLive/texmf-dist/tex/latex/base/size10.clo
-File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
-)
-\c@part=\count79
-\c@section=\count80
-\c@subsection=\count81
-\c@subsubsection=\count82
-\c@paragraph=\count83
-\c@subparagraph=\count84
-\c@figure=\count85
-\c@table=\count86
-\abovecaptionskip=\skip41
-\belowcaptionskip=\skip42
-\bibindent=\dimen102
-) (./parent.aux (./child.aux))
-\openout1 = `parent.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-(./child.tex
-! Undefined control sequence.
-l.1 \foo
-
-The control sequence at the end of the top line
-of your error message was never \def'ed. If you have
-misspelled it (e.g., `\hobx'), type `I' and the correct
-spelling (e.g., `I\hbox'). Otherwise just continue,
-and I'll forget about whatever was undefined.
-
-) (./parent.aux) )
-Here is how much of TeX's memory you used:
-205 strings out of 492995
-2149 string characters out of 6138727
-54074 words of memory out of 5000000
-3841 multiletter control sequences out of 15000+600000
-3640 words of font info for 14 fonts, out of 8000000 for 9000
-1141 hyphenation exceptions out of 8191
-23i,1n,17p,116b,36s stack positions out of 5000i,500n,10000p,200000b,80000s
-
-No pages of output.
-PDF statistics:
-0 PDF objects out of 1000 (max. 8388607)
-0 named destinations out of 1000 (max. 500000)
-1 words of extra memory for PDF output out of 10000 (max. 10000000)"#;
-
- assert_eq!(
- parse(log).errors,
- vec![BuildError {
- relative_path: "./child.tex".into(),
- level: BuildErrorLevel::Error,
- message: "Undefined control sequence.".into(),
- line: Some(0)
- }]
- );
- }
-
- #[test]
- fn parse_003() {
- let log = r#"
-This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:51
-entering extended mode
-restricted \write18 enabled.
-%&-line parsing enabled.
-**./parent.tex
-(./parent.tex
-LaTeX2e <2017-04-15>
-Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
-(/TexLive/texmf-dist/tex/latex/base/article.cls
-Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
-(/TexLive/texmf-dist/tex/latex/base/size10.clo
-File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
-)
-\c@part=\count79
-\c@section=\count80
-\c@subsection=\count81
-\c@subsubsection=\count82
-\c@paragraph=\count83
-\c@subparagraph=\count84
-\c@figure=\count85
-\c@table=\count86
-\abovecaptionskip=\skip41
-\belowcaptionskip=\skip42
-\bibindent=\dimen102
-) (./parent.aux)
-\openout1 = `parent.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 4.
-LaTeX Font Info: ... okay on input line 4.
-
-LaTeX Warning: Citation `foo' on page 1 undefined on input line 6.
-
-[1
-
-{/TexLive/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./parent.aux)
-
-LaTeX Warning: There were undefined references.
-
-)
-Here is how much of TeX's memory you used:
-204 strings out of 492995
-2142 string characters out of 6138727
-54074 words of memory out of 5000000
-3842 multiletter control sequences out of 15000+600000
-3948 words of font info for 15 fonts, out of 8000000 for 9000
-1141 hyphenation exceptions out of 8191
-23i,4n,21p,116b,107s stack positions out of 5000i,500n,10000p,200000b,80000s
-</TexLive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></TexLive/
-texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb>
-Output written on parent.pdf (1 page, 17339 bytes).
-PDF statistics:
-16 PDF objects out of 1000 (max. 8388607)
-10 compressed objects within 1 object stream
-0 named destinations out of 1000 (max. 500000)
-1 words of extra memory for PDF output out of 10000 (max. 10000000)"#;
-
- assert_eq!(
- parse(log).errors,
- vec![
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Warning,
- message: "Citation `foo' on page 1 undefined on input line 6.".into(),
- line: None
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Warning,
- message: "There were undefined references.".into(),
- line: None,
- }
- ]
- );
- }
-
- #[test]
- fn parse_004() {
- let log = r#"
-This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:40
-entering extended mode
-restricted \write18 enabled.
-%&-line parsing enabled.
-**./parent.tex
-(./parent.tex
-LaTeX2e <2017-04-15>
-Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
-(/TexLive/texmf-dist/tex/latex/base/article.cls
-Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
-(/TexLive/texmf-dist/tex/latex/base/size10.clo
-File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
-)
-\c@part=\count79
-\c@section=\count80
-\c@subsection=\count81
-\c@subsubsection=\count82
-\c@paragraph=\count83
-\c@subparagraph=\count84
-\c@figure=\count85
-\c@table=\count86
-\abovecaptionskip=\skip41
-\belowcaptionskip=\skip42
-\bibindent=\dimen102
-)
-(/TexLive/texmf-dist/tex/generic/babel/babel.sty
-Package: babel 2017/05/19 3.10 The Babel package
-
-! Package babel Error: Unknown option `foo'. Either you misspelled it
-(babel) or the language definition file foo.ldf was not found.
-
-See the babel package documentation for explanation.
-Type H <return> for immediate help.
-...
-
-l.393 \ProcessOptions*
-
-Valid options are: shorthands=, KeepShorthandsActive,
-activeacute, activegrave, noconfigs, safe=, main=, math=
-headfoot=, strings=, config=, hyphenmap=, or a language name.
-
-! Package babel Error: You haven't specified a language option.
-
-See the babel package documentation for explanation.
-Type H <return> for immediate help.
-...
-
-l.426 ...ry to proceed from here, type x to quit.}
-
-You need to specify a language, either as a global option
-or as an optional argument to the \usepackage command;
-You shouldn't try to proceed from here, type x to quit.
-
-) (./parent.aux)
-\openout1 = `parent.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 5.
-LaTeX Font Info: ... okay on input line 5.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 5.
-LaTeX Font Info: ... okay on input line 5.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 5.
-LaTeX Font Info: ... okay on input line 5.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 5.
-LaTeX Font Info: ... okay on input line 5.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 5.
-LaTeX Font Info: ... okay on input line 5.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 5.
-LaTeX Font Info: ... okay on input line 5.
-(./parent.aux) )
-Here is how much of TeX's memory you used:
-304 strings out of 492995
-3421 string characters out of 6138727
-56035 words of memory out of 5000000
-3938 multiletter control sequences out of 15000+600000
-3640 words of font info for 14 fonts, out of 8000000 for 9000
-1141 hyphenation exceptions out of 8191
-23i,1n,17p,116b,36s stack positions out of 5000i,500n,10000p,200000b,80000s
-
-No pages of output.
-PDF statistics:
-0 PDF objects out of 1000 (max. 8388607)
-0 named destinations out of 1000 (max. 500000)
-1 words of extra memory for PDF output out of 10000 (max. 10000000)"#;
-
- assert_eq!(
- parse(log).errors,
- vec![
- BuildError {
- relative_path: "/TexLive/texmf-dist/tex/generic/babel/babel.sty".into(),
- level: BuildErrorLevel::Error,
- message: "Package babel Error: Unknown option `foo'. Either you misspelled it or the language definition file foo.ldf was not found.".into(),
- line: Some(392)
- },
- BuildError {
- relative_path: "/TexLive/texmf-dist/tex/generic/babel/babel.sty".into(),
- level: BuildErrorLevel::Error,
- message: "Package babel Error: You haven't specified a language option.".into(),
- line: Some(425)
- }
- ]
- );
- }
-
- #[test]
- fn parse_005() {
- let log = r#"
-This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:45
-entering extended mode
-restricted \write18 enabled.
-%&-line parsing enabled.
-**./parent.tex
-(./parent.tex
-LaTeX2e <2017-04-15>
-Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
-(/TexLive/texmf-dist/tex/latex/base/article.cls
-Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
-(/TexLive/texmf-dist/tex/latex/base/size10.clo
-File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
-)
-\c@part=\count79
-\c@section=\count80
-\c@subsection=\count81
-\c@subsubsection=\count82
-\c@paragraph=\count83
-\c@subparagraph=\count84
-\c@figure=\count85
-\c@table=\count86
-\abovecaptionskip=\skip41
-\belowcaptionskip=\skip42
-\bibindent=\dimen102
-)
-(/TexLive/texmf-dist/tex/generic/babel/babel.sty
-Package: babel 2017/05/19 3.10 The Babel package
-
-(/TexLive/texmf-dist/tex/generic/babel-spanish/spanish.ldf
-Language: spanish.ldf 2016/03/03 v5.0p Spanish support from the babel system
-
-(/TexLive/texmf-dist/tex/generic/babel/babel.def
-File: babel.def 2017/05/19 3.10 Babel common definitions
-\babel@savecnt=\count87
-\U@D=\dimen103
-)
-\es@quottoks=\toks14
-\es@quotdepth=\count88
-Package babel Info: Making " an active character on input line 561.
-Package babel Info: Making . an active character on input line 662.
-Package babel Info: Making < an active character on input line 707.
-Package babel Info: Making > an active character on input line 707.
-))
-(/TexLive/texmf-dist/tex/latex/biblatex/biblatex.sty
-Package: biblatex 2016/12/05 v3.7 programmable bibliographies (PK/JW/AB)
-
-(/TexLive/texmf-dist/tex/generic/oberdiek/pdftexcmds.sty
-Package: pdftexcmds 2017/03/19 v0.25 Utility functions of pdfTeX for LuaTeX (HO
-)
-
-(/TexLive/texmf-dist/tex/generic/oberdiek/infwarerr.sty
-Package: infwarerr 2016/05/16 v1.4 Providing info/warning/error messages (HO)
-)
-(/TexLive/texmf-dist/tex/generic/oberdiek/ifluatex.sty
-Package: ifluatex 2016/05/16 v1.4 Provides the ifluatex switch (HO)
-Package ifluatex Info: LuaTeX not detected.
-)
-(/TexLive/texmf-dist/tex/generic/oberdiek/ltxcmds.sty
-Package: ltxcmds 2016/05/16 v1.23 LaTeX kernel commands for general use (HO)
-)
-(/TexLive/texmf-dist/tex/generic/oberdiek/ifpdf.sty
-Package: ifpdf 2017/03/15 v3.2 Provides the ifpdf switch
-)
-Package pdftexcmds Info: LuaTeX not detected.
-Package pdftexcmds Info: \pdf@primitive is available.
-Package pdftexcmds Info: \pdf@ifprimitive is available.
-Package pdftexcmds Info: \pdfdraftmode found.
-)
-(/TexLive/texmf-dist/tex/latex/etoolbox/etoolbox.sty
-Package: etoolbox 2017/01/02 v2.4 e-TeX tools for LaTeX (JAW)
-\etb@tempcnta=\count89
-)
-(/TexLive/texmf-dist/tex/latex/graphics/keyval.sty
-Package: keyval 2014/10/28 v1.15 key=value parser (DPC)
-\KV@toks@=\toks15
-)
-(/TexLive/texmf-dist/tex/latex/oberdiek/kvoptions.sty
-Package: kvoptions 2016/05/16 v3.12 Key value format for package options (HO)
-
-(/TexLive/texmf-dist/tex/generic/oberdiek/kvsetkeys.sty
-Package: kvsetkeys 2016/05/16 v1.17 Key value parser (HO)
-
-(/TexLive/texmf-dist/tex/generic/oberdiek/etexcmds.sty
-Package: etexcmds 2016/05/16 v1.6 Avoid name clashes with e-TeX commands (HO)
-Package etexcmds Info: Could not find \expanded.
-(etexcmds) That can mean that you are not using pdfTeX 1.50 or
-(etexcmds) that some package has redefined \expanded.
-(etexcmds) In the latter case, load this package earlier.
-)))
-(/TexLive/texmf-dist/tex/latex/logreq/logreq.sty
-Package: logreq 2010/08/04 v1.0 xml request logger
-\lrq@indent=\count90
-
-(/TexLive/texmf-dist/tex/latex/logreq/logreq.def
-File: logreq.def 2010/08/04 v1.0 logreq spec v1.0
-))
-(/TexLive/texmf-dist/tex/latex/base/ifthen.sty
-Package: ifthen 2014/09/29 v1.1c Standard LaTeX ifthen package (DPC)
-)
-(/TexLive/texmf-dist/tex/latex/url/url.sty
-\Urlmuskip=\muskip10
-Package: url 2013/09/16 ver 3.4 Verb mode for urls, etc.
-)
-(/TexLive/texmf-dist/tex/generic/xstring/xstring.sty
-(/TexLive/texmf-dist/tex/generic/xstring/xstring.tex
-\@xs@message=\write3
-\integerpart=\count91
-\decimalpart=\count92
-)
-Package: xstring 2013/10/13 v1.7c String manipulations (C Tellechea)
-)
-\c@tabx@nest=\count93
-\c@listtotal=\count94
-\c@listcount=\count95
-\c@liststart=\count96
-\c@liststop=\count97
-\c@citecount=\count98
-\c@citetotal=\count99
-\c@multicitecount=\count100
-\c@multicitetotal=\count101
-\c@instcount=\count102
-\c@maxnames=\count103
-\c@minnames=\count104
-\c@maxitems=\count105
-\c@minitems=\count106
-\c@citecounter=\count107
-\c@savedcitecounter=\count108
-\c@uniquelist=\count109
-\c@uniquename=\count110
-\c@refsection=\count111
-\c@refsegment=\count112
-\c@maxextratitle=\count113
-\c@maxextratitleyear=\count114
-\c@maxextrayear=\count115
-\c@maxextraalpha=\count116
-\c@abbrvpenalty=\count117
-\c@highnamepenalty=\count118
-\c@lownamepenalty=\count119
-\c@maxparens=\count120
-\c@parenlevel=\count121
-\blx@tempcnta=\count122
-\blx@tempcntb=\count123
-\blx@tempcntc=\count124
-\blx@maxsection=\count125
-\blx@maxsegment@0=\count126
-\blx@notetype=\count127
-\blx@parenlevel@text=\count128
-\blx@parenlevel@foot=\count129
-\blx@sectionciteorder@0=\count130
-\labelnumberwidth=\skip43
-\labelalphawidth=\skip44
-\biblabelsep=\skip45
-\bibitemsep=\skip46
-\bibnamesep=\skip47
-\bibinitsep=\skip48
-\bibparsep=\skip49
-\bibhang=\skip50
-\blx@bcfin=\read1
-\blx@bcfout=\write4
-\c@mincomprange=\count131
-\c@maxcomprange=\count132
-\c@mincompwidth=\count133
-Package biblatex Info: Trying to load biblatex default data model...
-Package biblatex Info: ... file 'blx-dm.def' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/blx-dm.def)
-Package biblatex Info: Trying to load biblatex style data model...
-Package biblatex Info: ... file 'ieee.dbx' not found.
-Package biblatex Info: Trying to load biblatex custom data model...
-Package biblatex Info: ... file 'biblatex-dm.cfg' not found.
-\c@afterword=\count134
-\c@savedafterword=\count135
-\c@annotator=\count136
-\c@savedannotator=\count137
-\c@author=\count138
-\c@savedauthor=\count139
-\c@bookauthor=\count140
-\c@savedbookauthor=\count141
-\c@commentator=\count142
-\c@savedcommentator=\count143
-\c@editor=\count144
-\c@savededitor=\count145
-\c@editora=\count146
-\c@savededitora=\count147
-\c@editorb=\count148
-\c@savededitorb=\count149
-\c@editorc=\count150
-\c@savededitorc=\count151
-\c@foreword=\count152
-\c@savedforeword=\count153
-\c@holder=\count154
-\c@savedholder=\count155
-\c@introduction=\count156
-\c@savedintroduction=\count157
-\c@namea=\count158
-\c@savednamea=\count159
-\c@nameb=\count160
-\c@savednameb=\count161
-\c@namec=\count162
-\c@savednamec=\count163
-\c@translator=\count164
-\c@savedtranslator=\count165
-\c@shortauthor=\count166
-\c@savedshortauthor=\count167
-\c@shorteditor=\count168
-\c@savedshorteditor=\count169
-\c@labelname=\count170
-\c@savedlabelname=\count171
-\c@institution=\count172
-\c@savedinstitution=\count173
-\c@lista=\count174
-\c@savedlista=\count175
-\c@listb=\count176
-\c@savedlistb=\count177
-\c@listc=\count178
-\c@savedlistc=\count179
-\c@listd=\count180
-\c@savedlistd=\count181
-\c@liste=\count182
-\c@savedliste=\count183
-\c@listf=\count184
-\c@savedlistf=\count185
-\c@location=\count186
-\c@savedlocation=\count187
-\c@organization=\count188
-\c@savedorganization=\count189
-\c@origlocation=\count190
-\c@savedoriglocation=\count191
-\c@origpublisher=\count192
-\c@savedorigpublisher=\count193
-\c@publisher=\count194
-\c@savedpublisher=\count195
-\c@language=\count196
-\c@savedlanguage=\count197
-\c@pageref=\count198
-\c@savedpageref=\count199
-\shorthandwidth=\skip51
-\shortjournalwidth=\skip52
-\shortserieswidth=\skip53
-\shorttitlewidth=\skip54
-\shortauthorwidth=\skip55
-\shorteditorwidth=\skip56
-Package biblatex Info: Trying to load compatibility code...
-Package biblatex Info: ... file 'blx-compat.def' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/blx-compat.def
-File: blx-compat.def 2016/12/05 v3.7 biblatex compatibility (PK/JW/AB)
-)
-Package biblatex Info: Trying to load generic definitions...
-Package biblatex Info: ... file 'biblatex.def' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/biblatex.def
-File: biblatex.def 2016/12/05 v3.7 biblatex compatibility (PK/JW/AB)
-\c@textcitecount=\count266
-\c@textcitetotal=\count267
-\c@textcitemaxnames=\count268
-\c@biburlnumpenalty=\count269
-\c@biburlucpenalty=\count270
-\c@biburllcpenalty=\count271
-\c@smartand=\count272
-)
-Package biblatex Info: Trying to load bibliography style 'ieee'...
-Package biblatex Info: ... file 'ieee.bbx' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex-ieee/ieee.bbx
-File: ieee.bbx 2017/03/27 v1.2d biblatex bibliography style
-Package biblatex Info: Trying to load bibliography style 'numeric-comp'...
-Package biblatex Info: ... file 'numeric-comp.bbx' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/bbx/numeric-comp.bbx
-File: numeric-comp.bbx 2016/12/05 v3.7 biblatex bibliography style (PK/JW/AB)
-Package biblatex Info: Trying to load bibliography style 'numeric'...
-Package biblatex Info: ... file 'numeric.bbx' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/bbx/numeric.bbx
-File: numeric.bbx 2016/12/05 v3.7 biblatex bibliography style (PK/JW/AB)
-Package biblatex Info: Trying to load bibliography style 'standard'...
-Package biblatex Info: ... file 'standard.bbx' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/bbx/standard.bbx
-File: standard.bbx 2016/12/05 v3.7 biblatex bibliography style (PK/JW/AB)
-\c@bbx:relatedcount=\count273
-\c@bbx:relatedtotal=\count274
-))))
-Package biblatex Info: Trying to load citation style 'ieee'...
-Package biblatex Info: ... file 'ieee.cbx' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex-ieee/ieee.cbx
-File: ieee.cbx 2017/03/27 v1.2d biblatex citation style
-Package biblatex Info: Trying to load citation style 'numeric-comp'...
-Package biblatex Info: ... file 'numeric-comp.cbx' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/cbx/numeric-comp.cbx
-File: numeric-comp.cbx 2016/12/05 v3.7 biblatex citation style (PK/JW/AB)
-\c@cbx@tempcnta=\count275
-\c@cbx@tempcntb=\count276
-Package biblatex Info: Redefining '\cite'.
-Package biblatex Info: Redefining '\parencite'.
-Package biblatex Info: Redefining '\footcite'.
-Package biblatex Info: Redefining '\footcitetext'.
-Package biblatex Info: Redefining '\smartcite'.
-Package biblatex Info: Redefining '\supercite'.
-Package biblatex Info: Redefining '\textcite'.
-Package biblatex Info: Redefining '\textcites'.
-Package biblatex Info: Redefining '\cites'.
-Package biblatex Info: Redefining '\parencites'.
-Package biblatex Info: Redefining '\smartcites'.
-)
-Package biblatex Info: Redefining '\cite'.
-Package biblatex Info: Redefining '\cites'.
-)
-Package biblatex Info: Trying to load configuration file...
-Package biblatex Info: ... file 'biblatex.cfg' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/biblatex.cfg
-File: biblatex.cfg
-))
-Package biblatex Info: Trying to load language 'spanish'...
-Package biblatex Info: ... file 'spanish.lbx' found.
-
-(/TexLive/texmf-dist/tex/latex/biblatex/lbx/spanish.lbx
-File: spanish.lbx 2016/12/05 v3.7 biblatex localization (PK/JW/AB)
-)
-
-Package biblatex Warning: 'babel/polyglossia' detected but 'csquotes' missing.
-(biblatex) Loading 'csquotes' recommended.
-
-\@quotelevel=\count277
-\@quotereset=\count278
-(./parent.aux)
-\openout1 = `parent.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 6.
-LaTeX Font Info: ... okay on input line 6.
-LaTeX Info: Redefining \sptext on input line 6.
-LaTeX Info: Redefining \. on input line 6.
-LaTeX Info: Redefining \% on input line 6.
-Package biblatex Info: No input encoding detected.
-(biblatex) Assuming 'ascii'.
-Package biblatex Info: Automatic encoding selection.
-(biblatex) Assuming data encoding 'ascii'.
-\openout4 = `parent.bcf'.
-
-Package biblatex Info: Trying to load bibliographic data...
-Package biblatex Info: ... file 'parent.bbl' not found.
-
-No file parent.bbl.
-Package biblatex Info: Reference section=0 on input line 6.
-Package biblatex Info: Reference segment=0 on input line 6.
-(./parent.aux)
-
-LaTeX Warning: There were undefined references.
-
-Package biblatex Warning: Please (re)run Biber on the file:
-(biblatex) parent
-(biblatex) and rerun LaTeX afterwards.
-
-Package logreq Info: Writing requests to 'parent.run.xml'.
-\openout1 = `parent.run.xml'.
-
-)
-Here is how much of TeX's memory you used:
-7717 strings out of 492995
-133301 string characters out of 6138727
-557258 words of memory out of 5000000
-11248 multiletter control sequences out of 15000+600000
-3640 words of font info for 14 fonts, out of 8000000 for 9000
-1141 hyphenation exceptions out of 8191
-35i,1n,30p,856b,700s stack positions out of 5000i,500n,10000p,200000b,80000s
-
-No pages of output.
-PDF statistics:
-0 PDF objects out of 1000 (max. 8388607)
-0 named destinations out of 1000 (max. 500000)
-1 words of extra memory for PDF output out of 10000 (max. 10000000)"#;
-
- assert_eq!(
- parse(log).errors,
- vec![
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Warning,
- message: "'babel/polyglossia' detected but 'csquotes' missing. Loading 'csquotes' recommended.".into(),
- line: None
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Warning,
- message: "There were undefined references.".into(),
- line: None,
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Warning,
- message: "Please (re)run Biber on the file: parent and rerun LaTeX afterwards.".into(),
- line: None
- }
- ]
- );
- }
-
- #[test]
- fn parse_006() {
- let log = r#"
-This is pdfTeX, Version 3.14159265-2.6-1.40.18 (TeX Live 2017/W32TeX) (preloaded format=pdflatex 2018.3.30) 26 DEC 2018 16:33
-entering extended mode
-restricted \write18 enabled.
-%&-line parsing enabled.
-**./parent.tex
-(./parent.tex
-LaTeX2e <2017-04-15>
-Babel <3.10> and hyphenation patterns for 84 language(s) loaded.
-(/TexLive/texmf-dist/tex/latex/base/article.cls
-Document Class: article 2014/09/29 v1.4h Standard LaTeX document class
-(/TexLive/texmf-dist/tex/latex/base/size10.clo
-File: size10.clo 2014/09/29 v1.4h Standard LaTeX file (size option)
-)
-\c@part=\count79
-\c@section=\count80
-\c@subsection=\count81
-\c@subsubsection=\count82
-\c@paragraph=\count83
-\c@subparagraph=\count84
-\c@figure=\count85
-\c@table=\count86
-\abovecaptionskip=\skip41
-\belowcaptionskip=\skip42
-\bibindent=\dimen102
-) (./parent.aux
-(./child.tex.aux))
-\openout1 = `parent.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-\openout2 = `child.aux'.
-
-(./child.tex)
-! Undefined control sequence.
-l.7 \foo
-
-The control sequence at the end of the top line
-of your error message was never \def'ed. If you have
-misspelled it (e.g., `\hobx'), type `I' and the correct
-spelling (e.g., `I\hbox'). Otherwise just continue,
-and I'll forget about whatever was undefined.
-
-! Missing $ inserted.
-<inserted text>
- $
-l.8 \bar
-
-I've inserted a begin-math/end-math symbol since I think
-you left one out. Proceed, with fingers crossed.
-
-LaTeX Font Info: External font `cmex10' loaded for size
-(Font) <7> on input line 8.
-LaTeX Font Info: External font `cmex10' loaded for size
-(Font) <5> on input line 8.
-! Undefined control sequence.
-l.9 \baz
-
-The control sequence at the end of the top line
-of your error message was never \def'ed. If you have
-misspelled it (e.g., `\hobx'), type `I' and the correct
-spelling (e.g., `I\hbox'). Otherwise just continue,
-and I'll forget about whatever was undefined.
-
-! Missing { inserted.
-<to be read again>
- \par
-l.10
-
-A left brace was mandatory here, so I've put one in.
-You might want to delete and/or insert some corrections
-so that I will find a matching right brace soon.
-(If you're confused by all this, try typing `I}' now.)
-
-! Missing $ inserted.
-<inserted text>
- $
-l.10
-
-I've inserted a begin-math/end-math symbol since I think
-you left one out. Proceed, with fingers crossed.
-
-! Missing } inserted.
-<inserted text>
- }
-l.10
-
-I've inserted something that you may have forgotten.
-(See the <inserted text> above.)
-With luck, this will get me unwedged. But if you
-really didn't forget anything, try typing `2' now; then
-my insertion and my current dilemma will both disappear.
-
-[1
-
-{/TexLive/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./parent.aux
-(./child.aux)) )
-Here is how much of TeX's memory you used:
-212 strings out of 492995
-2238 string characters out of 6138727
-54074 words of memory out of 5000000
-3843 multiletter control sequences out of 15000+600000
-3640 words of font info for 14 fonts, out of 8000000 for 9000
-1141 hyphenation exceptions out of 8191
-23i,4n,17p,116b,107s stack positions out of 5000i,500n,10000p,200000b,80000s
-</TexLive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb
->
-Output written on parent.pdf (1 page, 8329 bytes).
-PDF statistics:
-12 PDF objects out of 1000 (max. 8388607)
-7 compressed objects within 1 object stream
-0 named destinations out of 1000 (max. 500000)
-1 words of extra memory for PDF output out of 10000 (max. 10000000)"#;
-
- assert_eq!(
- parse(log).errors,
- vec![
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Error,
- message: "Undefined control sequence.".into(),
- line: Some(6)
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Error,
- message: "Missing $ inserted.".into(),
- line: Some(7)
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Error,
- message: "Undefined control sequence.".into(),
- line: Some(8)
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Error,
- message: "Missing { inserted.".into(),
- line: Some(9)
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Error,
- message: "Missing $ inserted.".into(),
- line: Some(9)
- },
- BuildError {
- relative_path: "./parent.tex".into(),
- level: BuildErrorLevel::Error,
- message: "Missing } inserted.".into(),
- line: Some(9)
- },
- ]
- );
- }
-
- #[test]
- fn parse_007() {
- let log = r#"
-This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021/W32TeX) (preloaded format=pdflatex 2021.6.19) 5 NOV 2021 19:10
-entering extended mode
-restricted \write18 enabled.
-%&-line parsing enabled.
-**/some/folder/a.tex
-(/some/folder/a.tex
-LaTeX2e <2021-06-01> patch level 1
-L3 programming layer <2021-06-18>
-(/texlive/2021/texmf-dist/tex/latex/koma-script/scrartcl.cls
-Document Class: scrartcl 2021/03/17 v3.33 KOMA-Script document class (article)
-(/texlive/2021/texmf-dist/tex/latex/koma-script/scrkbase.sty
-Package: scrkbase 2021/03/17 v3.33 KOMA-Script package (KOMA-Script-dependent b
-asics and keyval usage)
-
-(/texlive/2021/texmf-dist/tex/latex/koma-script/scrbase.sty
-Package: scrbase 2021/03/17 v3.33 KOMA-Script package (KOMA-Script-independent
-basics and keyval usage)
-
-(/texlive/2021/texmf-dist/tex/latex/koma-script/scrlfile.sty
-Package: scrlfile 2021/03/17 v3.33 KOMA-Script package (file load hooks)
-
-(/texlive/2021/texmf-dist/tex/latex/koma-script/scrlfile-hook.sty
-Package: scrlfile-hook 2021/03/17 v3.33 KOMA-Script package (using LaTeX hooks)
-
-
-(/texlive/2021/texmf-dist/tex/latex/koma-script/scrlogo.sty
-Package: scrlogo 2021/03/17 v3.33 KOMA-Script package (logo)
-)))
-(/texlive/2021/texmf-dist/tex/latex/graphics/keyval.sty
-Package: keyval 2014/10/28 v1.15 key=value parser (DPC)
-\KV@toks@=\toks16
-)
-Applying: [2021/05/01] Usage of raw option list on input line 252.
-Already applied: [0000/00/00] compatibility for LaTeX before 2021/05/01 on inpu
-t line 337.
-))
-==> First Aid for scrkbase.sty no longer applied!
-(/texlive/2021/texmf-dist/tex/latex/koma-script/tocbasic.sty
-Package: tocbasic 2021/03/17 v3.33 KOMA-Script package (handling toc-files)
-\scr@dte@tocline@numberwidth=\skip47
-\scr@dte@tocline@numbox=\box50
-)
-Package tocbasic Info: babel extension for `toc' omitted
-(tocbasic) because of missing \bbl@set@language on input line 135.
-Class scrartcl Info: File `scrsize11pt.clo' used instead of
-(scrartcl) file `scrsize11.clo' to setup font sizes on input line 223
-9.
-
-(/texlive/2021/texmf-dist/tex/latex/koma-script/scrsize11pt.clo
-File: scrsize11pt.clo 2021/03/17 v3.33 KOMA-Script font size class option (11pt
-)
-)
-(/texlive/2021/texmf-dist/tex/latex/koma-script/typearea.sty
-Package: typearea 2021/03/17 v3.33 KOMA-Script package (type area)
-\ta@bcor=\skip48
-\ta@div=\count182
-\ta@hblk=\skip49
-\ta@vblk=\skip50
-\ta@temp=\skip51
-\footheight=\skip52
-Package typearea Info: These are the values describing the layout:
-(typearea) DIV = 10
-(typearea) BCOR = 0.0pt
-(typearea) \paperwidth = 597.50793pt
-(typearea) \textwidth = 418.25555pt
-(typearea) DIV departure = -6%
-(typearea) \evensidemargin = 17.3562pt
-(typearea) \oddsidemargin = 17.3562pt
-(typearea) \paperheight = 845.04694pt
-(typearea) \textheight = 595.80026pt
-(typearea) \topmargin = -25.16531pt
-(typearea) \headheight = 17.0pt
-(typearea) \headsep = 20.40001pt
-(typearea) \topskip = 11.0pt
-(typearea) \footskip = 47.6pt
-(typearea) \baselineskip = 13.6pt
-(typearea) on input line 1741.
-)
-\c@part=\count183
-\c@section=\count184
-\c@subsection=\count185
-\c@subsubsection=\count186
-\c@paragraph=\count187
-\c@subparagraph=\count188
-\scr@dte@section@maxnumwidth=\skip53
-Class scrartcl Info: using compatibility default `runin=bysign'
-(scrartcl) for `\section on input line 4846.
-Class scrartcl Info: using compatibility default `afterindent=bysign'
-(scrartcl) for `\section on input line 4846.
-\scr@dte@part@maxnumwidth=\skip54
-Class scrartcl Info: using compatibility default `afterindent=false'
-(scrartcl) for `\part on input line 4854.
-\scr@dte@subsection@maxnumwidth=\skip55
-Class scrartcl Info: using compatibility default `runin=bysign'
-(scrartcl) for `\subsection on input line 4864.
-Class scrartcl Info: using compatibility default `afterindent=bysign'
-(scrartcl) for `\subsection on input line 4864.
-\scr@dte@subsubsection@maxnumwidth=\skip56
-Class scrartcl Info: using compatibility default `runin=bysign'
-(scrartcl) for `\subsubsection on input line 4874.
-Class scrartcl Info: using compatibility default `afterindent=bysign'
-(scrartcl) for `\subsubsection on input line 4874.
-\scr@dte@paragraph@maxnumwidth=\skip57
-Class scrartcl Info: using compatibility default `runin=bysign'
-(scrartcl) for `\paragraph on input line 4885.
-Class scrartcl Info: using compatibility default `afterindent=bysign'
-(scrartcl) for `\paragraph on input line 4885.
-\scr@dte@subparagraph@maxnumwidth=\skip58
-Class scrartcl Info: using compatibility default `runin=bysign'
-(scrartcl) for `\subparagraph on input line 4895.
-Class scrartcl Info: using compatibility default `afterindent=bysign'
-(scrartcl) for `\subparagraph on input line 4895.
-\abovecaptionskip=\skip59
-\belowcaptionskip=\skip60
-\c@pti@nb@sid@b@x=\box51
-Package tocbasic Info: babel extension for `lof' omitted
-(tocbasic) because of missing \bbl@set@language on input line 6127.
-
-\scr@dte@figure@maxnumwidth=\skip61
-\c@figure=\count189
-Package tocbasic Info: babel extension for `lot' omitted
-(tocbasic) because of missing \bbl@set@language on input line 6139.
-
-\scr@dte@table@maxnumwidth=\skip62
-\c@table=\count190
-Class scrartcl Info: Redefining `\numberline' on input line 6303.
-\bibindent=\dimen138
-)
-(/texlive/2021/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def
-File: l3backend-pdftex.def 2021-05-07 L3 backend support: PDF output (pdfTeX)
-\l__color_backend_stack_int=\count191
-\l__pdf_internal_box=\box52
-) (./a.aux)
-\openout1 = `a.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 3.
-LaTeX Font Info: ... okay on input line 3.
-Package scrbase Info: activating english \contentsname on input line 3.
-Package scrbase Info: activating english \listfigurename on input line 3.
-Package scrbase Info: activating english \listtablename on input line 3.
-! Undefined control sequence.
-l.4 \lsdkfjlskdfj
-
-The control sequence at the end of the top line
-of your error message was never \def'ed. If you have
-misspelled it (e.g., `\hobx'), type `I' and the correct
-spelling (e.g., `I\hbox'). Otherwise just continue,
-and I'll forget about whatever was undefined.
-
-(./a.aux) )
-Here is how much of TeX's memory you used:
-3199 strings out of 478510
-74549 string characters out of 5853586
-510929 words of memory out of 5000000
-21227 multiletter control sequences out of 15000+600000
-403730 words of font info for 28 fonts, out of 8000000 for 9000
-1141 hyphenation exceptions out of 8191
-108i,1n,108p,10625b,270s stack positions out of 5000i,500n,10000p,200000b,80000s
-
-No pages of output.
-PDF statistics:
-0 PDF objects out of 1000 (max. 8388607)
-0 named destinations out of 1000 (max. 500000)
-1 words of extra memory for PDF output out of 10000 (max. 10000000)"#;
-
- assert_debug_snapshot!(parse(log).errors);
- }
-}
diff --git a/support/texlab/src/syntax/latex.rs b/support/texlab/src/syntax/latex.rs
index 2d8918e49e..ce1ca125fd 100644
--- a/support/texlab/src/syntax/latex.rs
+++ b/support/texlab/src/syntax/latex.rs
@@ -1,14 +1,9 @@
-mod analysis;
mod cst;
mod kind;
-mod lexer;
-mod parser;
pub use self::{
- analysis::*,
cst::*,
kind::SyntaxKind::{self, *},
- parser::{parse, Parse},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
diff --git a/support/texlab/src/syntax/latex/analysis.rs b/support/texlab/src/syntax/latex/analysis.rs
deleted file mode 100644
index 02d9b315ba..0000000000
--- a/support/texlab/src/syntax/latex/analysis.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-mod command;
-mod distro_file;
-mod environment;
-mod explicit_link;
-mod graphics_path;
-mod implicit_link;
-mod label_name;
-mod label_number;
-mod theorem;
-mod types;
-
-use crate::syntax::latex;
-
-pub use self::types::*;
-use self::{
- command::{analyze_command, analyze_command_definition},
- environment::analyze_begin,
- explicit_link::{analyze_import, analyze_include},
- graphics_path::analyze_graphics_path,
- implicit_link::analyze_implicit_links,
- label_name::analyze_label_name,
- label_number::analyze_label_number,
- theorem::analyze_theorem_definition,
-};
-
-pub fn analyze(context: &mut LatexAnalyzerContext, root: &latex::SyntaxNode) {
- analyze_implicit_links(context);
- for node in root.descendants() {
- analyze_command(context, node.clone())
- .or_else(|| analyze_command_definition(context, node.clone()))
- .or_else(|| analyze_begin(context, node.clone()))
- .or_else(|| analyze_include(context, node.clone()))
- .or_else(|| analyze_import(context, node.clone()))
- .or_else(|| analyze_label_name(context, node.clone()))
- .or_else(|| analyze_label_number(context, node.clone()))
- .or_else(|| analyze_theorem_definition(context, node.clone()))
- .or_else(|| analyze_graphics_path(context, node));
- }
- context.extras.has_document_environment = context.extras.environment_names.contains("document");
-}
diff --git a/support/texlab/src/syntax/latex/analysis/command.rs b/support/texlab/src/syntax/latex/analysis/command.rs
deleted file mode 100644
index 60aceef725..0000000000
--- a/support/texlab/src/syntax/latex/analysis/command.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use rowan::ast::AstNode;
-
-use crate::syntax::latex;
-
-use super::LatexAnalyzerContext;
-
-pub fn analyze_command(context: &mut LatexAnalyzerContext, node: latex::SyntaxNode) -> Option<()> {
- let command = latex::GenericCommand::cast(node)?;
- context
- .extras
- .command_names
- .insert(command.name()?.text().into());
- Some(())
-}
-
-pub fn analyze_command_definition(
- context: &mut LatexAnalyzerContext,
- node: latex::SyntaxNode,
-) -> Option<()> {
- let definition = latex::CommandDefinition::cast(node)?;
- context
- .extras
- .command_names
- .insert(definition.name()?.command()?.text().into());
- Some(())
-}
diff --git a/support/texlab/src/syntax/latex/analysis/distro_file.rs b/support/texlab/src/syntax/latex/analysis/distro_file.rs
deleted file mode 100644
index f278c33627..0000000000
--- a/support/texlab/src/syntax/latex/analysis/distro_file.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use lsp_types::Url;
-
-use crate::distro::Resolver;
-
-pub fn resolve_distro_file(resolver: &Resolver, stem: &str, extensions: &[&str]) -> Option<Url> {
- let mut document = resolver.files_by_name.get(stem);
- for extension in extensions {
- document = document.or_else(|| {
- let full_name = format!("{}.{}", stem, extension);
- resolver.files_by_name.get(full_name.as_str())
- });
- }
- document.and_then(|path| Url::from_file_path(path).ok())
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- #[cfg(windows)]
- fn test() {
- let mut resolver = Resolver::default();
- resolver
- .files_by_name
- .insert("foo.tex".into(), "C:/distro/foo.tex".into());
- resolver
- .files_by_name
- .insert("foo.sty".into(), "C:/distro/foo.sty".into());
- resolver
- .files_by_name
- .insert("bar.tex".into(), "C:/distro/bar.tex".into());
-
- assert_eq!(
- resolve_distro_file(&resolver, "foo", &["tex"]),
- Some(Url::from_file_path("C:/distro/foo.tex").unwrap())
- );
-
- assert_eq!(
- resolve_distro_file(&resolver, "foo", &["sty"]),
- Some(Url::from_file_path("C:/distro/foo.sty").unwrap())
- );
-
- assert_eq!(resolve_distro_file(&resolver, "foo", &["cls"]), None);
- }
-
- #[test]
- #[cfg(unix)]
- fn test() {
- let mut resolver = Resolver::default();
- resolver
- .files_by_name
- .insert("foo.tex".into(), "/distro/foo.tex".into());
- resolver
- .files_by_name
- .insert("foo.sty".into(), "/distro/foo.sty".into());
- resolver
- .files_by_name
- .insert("bar.tex".into(), "/distro/bar.tex".into());
-
- assert_eq!(
- resolve_distro_file(&resolver, "foo", &["tex"]),
- Some(Url::from_file_path("/distro/foo.tex").unwrap())
- );
-
- assert_eq!(
- resolve_distro_file(&resolver, "foo", &["sty"]),
- Some(Url::from_file_path("/distro/foo.sty").unwrap())
- );
-
- assert_eq!(resolve_distro_file(&resolver, "foo", &["cls"]), None);
- }
-}
diff --git a/support/texlab/src/syntax/latex/analysis/environment.rs b/support/texlab/src/syntax/latex/analysis/environment.rs
deleted file mode 100644
index e99483f706..0000000000
--- a/support/texlab/src/syntax/latex/analysis/environment.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use rowan::ast::AstNode;
-
-use crate::syntax::latex;
-
-use super::LatexAnalyzerContext;
-
-pub fn analyze_begin(context: &mut LatexAnalyzerContext, node: latex::SyntaxNode) -> Option<()> {
- let begin = latex::Begin::cast(node)?;
- let name = begin.name()?.key()?.to_string();
- let extras = &mut context.extras;
- extras.environment_names.insert(name);
- Some(())
-}
diff --git a/support/texlab/src/syntax/latex/analysis/explicit_link.rs b/support/texlab/src/syntax/latex/analysis/explicit_link.rs
deleted file mode 100644
index 77e2cfb696..0000000000
--- a/support/texlab/src/syntax/latex/analysis/explicit_link.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use std::sync::Arc;
-
-use rowan::ast::AstNode;
-
-use crate::syntax::latex;
-
-use super::{
- distro_file::resolve_distro_file, ExplicitLink, ExplicitLinkKind, LatexAnalyzerContext,
-};
-
-pub fn analyze_include(context: &mut LatexAnalyzerContext, node: latex::SyntaxNode) -> Option<()> {
- let include = latex::Include::cast(node)?;
- let kind = match include.syntax().kind() {
- latex::LATEX_INCLUDE => ExplicitLinkKind::Latex,
- latex::BIBLATEX_INCLUDE | latex::BIBTEX_INCLUDE => ExplicitLinkKind::Bibtex,
- latex::PACKAGE_INCLUDE => ExplicitLinkKind::Package,
- latex::CLASS_INCLUDE => ExplicitLinkKind::Class,
- _ => return None,
- };
-
- let extensions = match kind {
- ExplicitLinkKind::Latex => &["tex"],
- ExplicitLinkKind::Bibtex => &["bib"],
- ExplicitLinkKind::Package => &["sty"],
- ExplicitLinkKind::Class => &["cls"],
- };
-
- for path in include.path_list()?.keys() {
- let stem = path.to_string();
- let mut targets = vec![Arc::new(context.base_uri.join(&stem).ok()?)];
- for extension in extensions {
- let path = format!("{}.{}", stem, extension);
- targets.push(Arc::new(context.base_uri.join(&path).ok()?));
- }
-
- resolve_distro_file(&context.environment.resolver, &stem, extensions)
- .into_iter()
- .for_each(|target| targets.push(Arc::new(target)));
-
- context.extras.explicit_links.push(ExplicitLink {
- kind,
- stem: stem.into(),
- stem_range: latex::small_range(&path),
- targets,
- });
- }
-
- Some(())
-}
-
-pub fn analyze_import(context: &mut LatexAnalyzerContext, node: latex::SyntaxNode) -> Option<()> {
- let import = latex::Import::cast(node)?;
-
- let mut targets = Vec::new();
- let directory = match import.directory().and_then(|dir| dir.key()) {
- Some(dir) => Arc::new(context.base_uri.join(&dir.to_string()).ok()?),
- None => Arc::clone(&context.base_uri),
- };
-
- let file = import.file()?.key()?;
- let stem = file.to_string();
- targets.push(Arc::new(directory.join(&stem).ok()?));
- targets.push(Arc::new(directory.join(&format!("{}.tex", stem)).ok()?));
-
- context.extras.explicit_links.push(ExplicitLink {
- stem: stem.into(),
- stem_range: latex::small_range(&file),
- targets,
- kind: ExplicitLinkKind::Latex,
- });
- Some(())
-}
diff --git a/support/texlab/src/syntax/latex/analysis/graphics_path.rs b/support/texlab/src/syntax/latex/analysis/graphics_path.rs
deleted file mode 100644
index 477094b841..0000000000
--- a/support/texlab/src/syntax/latex/analysis/graphics_path.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use rowan::ast::AstNode;
-
-use crate::syntax::latex;
-
-use super::LatexAnalyzerContext;
-
-pub fn analyze_graphics_path(
- context: &mut LatexAnalyzerContext,
- node: latex::SyntaxNode,
-) -> Option<()> {
- let definition = latex::GraphicsPath::cast(node)?;
- for path in definition
- .path_list()
- .filter_map(|group| group.key())
- .map(|path| path.to_string())
- {
- context.extras.graphics_paths.insert(path);
- }
-
- Some(())
-}
diff --git a/support/texlab/src/syntax/latex/analysis/implicit_link.rs b/support/texlab/src/syntax/latex/analysis/implicit_link.rs
deleted file mode 100644
index 60524c623e..0000000000
--- a/support/texlab/src/syntax/latex/analysis/implicit_link.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use std::{path::Path, sync::Arc};
-
-use lsp_types::Url;
-
-use super::LatexAnalyzerContext;
-
-pub fn analyze_implicit_links(context: &mut LatexAnalyzerContext) {
- context.extras.implicit_links.aux = find_by_extension(context, "aux").unwrap_or_default();
- context.extras.implicit_links.log = find_by_extension(context, "log").unwrap_or_default();
- context.extras.implicit_links.pdf = find_by_extension(context, "pdf").unwrap_or_default();
-}
-
-fn find_by_extension(context: &LatexAnalyzerContext, extension: &str) -> Option<Vec<Arc<Url>>> {
- let mut targets = vec![Arc::new(with_extension(&context.document_uri, extension)?)];
- if context.document_uri.scheme() == "file" {
- let file_path = context.document_uri.to_file_path().ok()?;
- let file_stem = file_path.file_stem()?;
- let aux_name = format!("{}.{}", file_stem.to_str()?, extension);
-
- let options = &context.environment.options;
- if let Some(root_dir) = options.root_directory.as_ref() {
- find_inside_directory(context, root_dir, &aux_name, &mut targets)?;
- }
-
- if let Some(build_dir) = options.aux_directory.as_ref() {
- find_inside_directory(context, build_dir, &aux_name, &mut targets)?;
- }
- }
- Some(targets)
-}
-
-fn find_inside_directory(
- context: &LatexAnalyzerContext,
- dir: &Path,
- aux_name: &str,
- targets: &mut Vec<Arc<Url>>,
-) -> Option<()> {
- let path = context
- .environment
- .current_directory
- .join(dir)
- .join(aux_name);
-
- targets.push(Arc::new(Url::from_file_path(path).ok()?));
-
- targets.push(Arc::new(
- context
- .base_uri
- .join(&dir.join(aux_name).to_string_lossy())
- .ok()?,
- ));
-
- Some(())
-}
-
-fn with_extension(uri: &Url, extension: &str) -> Option<Url> {
- let file_name = uri.path_segments()?.last()?;
- let file_stem = file_name
- .rfind('.')
- .map(|i| &file_name[..i])
- .unwrap_or(file_name);
-
- uri.join(&format!("{}.{}", file_stem, extension)).ok()
-}
diff --git a/support/texlab/src/syntax/latex/analysis/label_name.rs b/support/texlab/src/syntax/latex/analysis/label_name.rs
deleted file mode 100644
index 1e3339db5e..0000000000
--- a/support/texlab/src/syntax/latex/analysis/label_name.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use latex::LabelReferenceRange;
-use rowan::ast::AstNode;
-
-use crate::syntax::latex;
-
-use super::{LabelName, LatexAnalyzerContext};
-
-pub fn analyze_label_name(
- context: &mut LatexAnalyzerContext,
- node: latex::SyntaxNode,
-) -> Option<()> {
- analyze_label_definition_name(context, node.clone())
- .or_else(|| analyze_label_reference_name(context, node.clone()))
- .or_else(|| analyze_label_reference_range_name(context, node))
-}
-
-fn analyze_label_definition_name(
- context: &mut LatexAnalyzerContext,
- node: latex::SyntaxNode,
-) -> Option<()> {
- let label = latex::LabelDefinition::cast(node)?;
- let name = label.name()?.key()?;
- context.extras.label_names.push(LabelName {
- text: name.to_string().into(),
- range: latex::small_range(&name),
- is_definition: true,
- });
- Some(())
-}
-
-fn analyze_label_reference_name(
- context: &mut LatexAnalyzerContext,
- node: latex::SyntaxNode,
-) -> Option<()> {
- let label = latex::LabelReference::cast(node)?;
- for name in label.name_list()?.keys() {
- context.extras.label_names.push(LabelName {
- text: name.to_string().into(),
- range: latex::small_range(&name),
- is_definition: false,
- });
- }
- Some(())
-}
-
-fn analyze_label_reference_range_name(
- context: &mut LatexAnalyzerContext,
- node: latex::SyntaxNode,
-) -> Option<()> {
- let label = LabelReferenceRange::cast(node)?;
- if let Some(name1) = label.from().and_then(|name| name.key()) {
- context.extras.label_names.push(LabelName {
- text: name1.to_string().into(),
- range: latex::small_range(&name1),
- is_definition: false,
- });
- }
-
- if let Some(name2) = label.to().and_then(|name| name.key()) {
- context.extras.label_names.push(LabelName {
- text: name2.to_string().into(),
- range: latex::small_range(&name2),
- is_definition: false,
- });
- }
- Some(())
-}
diff --git a/support/texlab/src/syntax/latex/analysis/label_number.rs b/support/texlab/src/syntax/latex/analysis/label_number.rs
deleted file mode 100644
index 61ad348680..0000000000
--- a/support/texlab/src/syntax/latex/analysis/label_number.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use rowan::ast::AstNode;
-
-use crate::syntax::latex;
-
-use super::LatexAnalyzerContext;
-
-pub fn analyze_label_number(
- context: &mut LatexAnalyzerContext,
- node: latex::SyntaxNode,
-) -> Option<()> {
- let number = latex::LabelNumber::cast(node)?;
- let name = number.name()?.key()?.to_string();
- let text = number
- .text()?
- .syntax()
- .descendants_with_tokens()
- .filter_map(|element| element.into_node())
- .find(|node| node.kind() == latex::TEXT || node.kind() == latex::MIXED_GROUP)?
- .text()
- .to_string();
-
- context.extras.label_numbers_by_name.insert(name, text);
- Some(())
-}
diff --git a/support/texlab/src/syntax/latex/analysis/theorem.rs b/support/texlab/src/syntax/latex/analysis/theorem.rs
deleted file mode 100644
index 70047362d1..0000000000
--- a/support/texlab/src/syntax/latex/analysis/theorem.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use rowan::ast::AstNode;
-
-use crate::syntax::latex::{self, HasCurly};
-
-use super::{LatexAnalyzerContext, TheoremEnvironment};
-
-pub fn analyze_theorem_definition(
- context: &mut LatexAnalyzerContext,
- node: latex::SyntaxNode,
-) -> Option<()> {
- let theorem = latex::TheoremDefinition::cast(node)?;
- let name = theorem.name()?.key()?.to_string();
- let description = theorem.description()?;
- let description = description.content_text()?;
-
- context
- .extras
- .theorem_environments
- .push(TheoremEnvironment { name, description });
-
- Some(())
-}
diff --git a/support/texlab/src/syntax/latex/analysis/types.rs b/support/texlab/src/syntax/latex/analysis/types.rs
deleted file mode 100644
index 7fb938e3d2..0000000000
--- a/support/texlab/src/syntax/latex/analysis/types.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use std::sync::Arc;
-
-use lsp_types::Url;
-use rowan::TextRange;
-use rustc_hash::{FxHashMap, FxHashSet};
-use smol_str::SmolStr;
-
-use crate::Environment;
-
-#[derive(Debug)]
-pub struct LatexAnalyzerContext<'a> {
- pub environment: &'a Environment,
- pub document_uri: Arc<Url>,
- pub base_uri: Arc<Url>,
- pub extras: Extras,
-}
-
-#[derive(Debug, Clone, Default)]
-pub struct Extras {
- pub implicit_links: ImplicitLinks,
- pub explicit_links: Vec<ExplicitLink>,
- pub has_document_environment: bool,
- pub command_names: FxHashSet<SmolStr>,
- pub environment_names: FxHashSet<String>,
- pub label_names: Vec<LabelName>,
- pub label_numbers_by_name: FxHashMap<String, String>,
- pub theorem_environments: Vec<TheoremEnvironment>,
- pub graphics_paths: FxHashSet<String>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)]
-pub struct ImplicitLinks {
- pub aux: Vec<Arc<Url>>,
- pub log: Vec<Arc<Url>>,
- pub pdf: Vec<Arc<Url>>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
-pub enum ExplicitLinkKind {
- Package,
- Class,
- Latex,
- Bibtex,
-}
-
-#[derive(Debug, Clone)]
-pub struct ExplicitLink {
- pub stem: SmolStr,
- pub stem_range: TextRange,
- pub targets: Vec<Arc<Url>>,
- pub kind: ExplicitLinkKind,
-}
-
-impl ExplicitLink {
- pub fn as_component_name(&self) -> Option<String> {
- match self.kind {
- ExplicitLinkKind::Package => Some(format!("{}.sty", self.stem)),
- ExplicitLinkKind::Class => Some(format!("{}.cls", self.stem)),
- ExplicitLinkKind::Latex | ExplicitLinkKind::Bibtex => None,
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)]
-pub struct TheoremEnvironment {
- pub name: String,
- pub description: String,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)]
-pub struct LabelName {
- pub text: SmolStr,
- pub range: TextRange,
- pub is_definition: bool,
-}
diff --git a/support/texlab/src/syntax/latex/cst.rs b/support/texlab/src/syntax/latex/cst.rs
index a83246571d..d7c9ec9bc7 100644
--- a/support/texlab/src/syntax/latex/cst.rs
+++ b/support/texlab/src/syntax/latex/cst.rs
@@ -683,6 +683,6 @@ impl GraphicsPath {
}
pub fn path_list(&self) -> impl Iterator<Item = CurlyGroupWord> {
- self.syntax().children().filter_map(CurlyGroupWord::cast)
+ self.syntax().descendants().filter_map(CurlyGroupWord::cast)
}
}
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__asymptote.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__asymptote.snap
deleted file mode 100644
index 12f0f3ca63..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__asymptote.snap
+++ /dev/null
@@ -1,43 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-assertion_line: 664
-expression: "verify(r#\"\\begin{asy}\n printf(\"Hello World\\n\");\n\\end{asy}\"#)"
----
-[
- (
- BEGIN_ENVIRONMENT_NAME,
- "\\begin",
- ),
- (
- L_CURLY,
- "{",
- ),
- (
- WORD,
- "asy",
- ),
- (
- R_CURLY,
- "}",
- ),
- (
- VERBATIM,
- "\n printf(\"Hello World\\n\");\n",
- ),
- (
- END_ENVIRONMENT_NAME,
- "\\end",
- ),
- (
- L_CURLY,
- "{",
- ),
- (
- WORD,
- "asy",
- ),
- (
- R_CURLY,
- "}",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__block_comment.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__block_comment.snap
deleted file mode 100644
index 5ced043aaf..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__block_comment.snap
+++ /dev/null
@@ -1,27 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-assertion_line: 601
-expression: "verify(\"Foo\\\\iffalse\\n\\\\Bar{Baz}\\n\\\\fi\\\\Qux\")"
----
-[
- (
- WORD,
- "Foo",
- ),
- (
- BEGIN_BLOCK_COMMENT_NAME,
- "\\iffalse",
- ),
- (
- VERBATIM,
- "\n\\Bar{Baz}\n",
- ),
- (
- END_BLOCK_COMMENT_NAME,
- "\\fi",
- ),
- (
- GENERIC_COMMAND_NAME,
- "\\Qux",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_parameter.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_parameter.snap
deleted file mode 100644
index a9a0e11ad7..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_parameter.snap
+++ /dev/null
@@ -1,47 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-expression: "verify(r#\"\\newcommand{\\id}[1]{#1}\"#)"
-
----
-[
- (
- COMMAND_DEFINITION_NAME,
- "\\newcommand",
- ),
- (
- L_CURLY,
- "{",
- ),
- (
- GENERIC_COMMAND_NAME,
- "\\id",
- ),
- (
- R_CURLY,
- "}",
- ),
- (
- L_BRACK,
- "[",
- ),
- (
- WORD,
- "1",
- ),
- (
- R_BRACK,
- "]",
- ),
- (
- L_CURLY,
- "{",
- ),
- (
- WORD,
- "#1",
- ),
- (
- R_CURLY,
- "}",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_star.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_star.snap
deleted file mode 100644
index 41310edaa1..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__command_with_star.snap
+++ /dev/null
@@ -1,23 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-expression: "verify(r#\"\\section*{Foo}\"#)"
-
----
-[
- (
- SECTION_NAME,
- "\\section*",
- ),
- (
- L_CURLY,
- "{",
- ),
- (
- WORD,
- "Foo",
- ),
- (
- R_CURLY,
- "}",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__comment.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__comment.snap
deleted file mode 100644
index 19db458200..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__comment.snap
+++ /dev/null
@@ -1,36 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-assertion_line: 248
-expression: "verify(\"hello %world\\r\\ntest %test\")"
-
----
-[
- (
- WORD,
- "hello",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- COMMENT,
- "%world",
- ),
- (
- LINE_BREAK,
- "\r\n",
- ),
- (
- WORD,
- "test",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- COMMENT,
- "%test",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__delimiters.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__delimiters.snap
deleted file mode 100644
index 36bec0a276..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__delimiters.snap
+++ /dev/null
@@ -1,79 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-expression: "verify(r#\"{foo} (bar) [baz, qux = foo-bar]\"#)"
-
----
-[
- (
- L_CURLY,
- "{",
- ),
- (
- WORD,
- "foo",
- ),
- (
- R_CURLY,
- "}",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- L_PAREN,
- "(",
- ),
- (
- WORD,
- "bar",
- ),
- (
- R_PAREN,
- ")",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- L_BRACK,
- "[",
- ),
- (
- WORD,
- "baz",
- ),
- (
- COMMA,
- ",",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- WORD,
- "qux",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- EQUALITY_SIGN,
- "=",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- WORD,
- "foo-bar",
- ),
- (
- R_BRACK,
- "]",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__empty.snap
deleted file mode 100644
index 61735b5087..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__empty.snap
+++ /dev/null
@@ -1,6 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-expression: "verify(r#\"\"#)"
-
----
-[]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__escape_sequence.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__escape_sequence.snap
deleted file mode 100644
index 4dbc1bb8f5..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__escape_sequence.snap
+++ /dev/null
@@ -1,19 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-expression: "verify(r#\"\\% hello\"#)"
-
----
-[
- (
- GENERIC_COMMAND_NAME,
- "\\%",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- WORD,
- "hello",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__formula.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__formula.snap
deleted file mode 100644
index 3fb7079384..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__formula.snap
+++ /dev/null
@@ -1,55 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-expression: "verify(r#\"$ f(x) = y $$\"#)"
-
----
-[
- (
- DOLLAR,
- "$",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- WORD,
- "f",
- ),
- (
- L_PAREN,
- "(",
- ),
- (
- WORD,
- "x",
- ),
- (
- R_PAREN,
- ")",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- EQUALITY_SIGN,
- "=",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- WORD,
- "y",
- ),
- (
- WHITESPACE,
- " ",
- ),
- (
- DOLLAR,
- "$$",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__invalid_parameter.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__invalid_parameter.snap
deleted file mode 100644
index e947ec3fb6..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__invalid_parameter.snap
+++ /dev/null
@@ -1,11 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-expression: "verify(r#\"#\"#)"
-
----
-[
- (
- WORD,
- "#",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__line_break.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__line_break.snap
deleted file mode 100644
index a8a392370e..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__lexer__tests__line_break.snap
+++ /dev/null
@@ -1,20 +0,0 @@
----
-source: src/syntax/latex/lexer.rs
-assertion_line: 258
-expression: "verify(\"hello\\nworld\")"
-
----
-[
- (
- WORD,
- "hello",
- ),
- (
- LINE_BREAK,
- "\n",
- ),
- (
- WORD,
- "world",
- ),
-]
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__empty.snap
deleted file mode 100644
index f01f7f9092..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__empty.snap
+++ /dev/null
@@ -1,8 +0,0 @@
----
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\"#)"
-
----
-ROOT@0..0
- PREAMBLE@0..0
-
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_empty.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_empty.snap
deleted file mode 100644
index 84e62ea81d..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_empty.snap
+++ /dev/null
@@ -1,10 +0,0 @@
----
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\foo\"#)"
-
----
-ROOT@0..4
- PREAMBLE@0..4
- GENERIC_COMMAND@0..4
- GENERIC_COMMAND_NAME@0..4 "\\foo"
-
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_escape.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_escape.snap
deleted file mode 100644
index a0d5d2e29b..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__generic_command_escape.snap
+++ /dev/null
@@ -1,10 +0,0 @@
----
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\#\"#)"
-
----
-ROOT@0..2
- PREAMBLE@0..2
- GENERIC_COMMAND@0..2
- GENERIC_COMMAND_NAME@0..2 "\\#"
-
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_path.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_path.snap
deleted file mode 100644
index 622a0fc869..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__graphics_path.snap
+++ /dev/null
@@ -1,17 +0,0 @@
----
-source: src/syntax/latex/parser.rs
-assertion_line: 1871
-expression: "setup(r#\"\\graphicspath{{../figures/}}\"#)"
----
-ROOT@0..28
- PREAMBLE@0..28
- GRAPHICS_PATH@0..28
- GRAPHICS_PATH_NAME@0..13 "\\graphicspath"
- L_CURLY@13..14 "{"
- CURLY_GROUP_WORD@14..27
- L_CURLY@14..15 "{"
- KEY@15..26
- WORD@15..26 "../figures/"
- R_CURLY@26..27 "}"
- R_CURLY@27..28 "}"
-
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_simple.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_simple.snap
deleted file mode 100644
index efa0d9b675..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__latex_input_simple.snap
+++ /dev/null
@@ -1,15 +0,0 @@
----
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"\\input{foo/bar.tex}\"#)"
-
----
-ROOT@0..19
- PREAMBLE@0..19
- LATEX_INCLUDE@0..19
- LATEX_INCLUDE_NAME@0..6 "\\input"
- CURLY_GROUP_WORD_LIST@6..19
- L_CURLY@6..7 "{"
- KEY@7..18
- WORD@7..18 "foo/bar.tex"
- R_CURLY@18..19 "}"
-
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter.snap
deleted file mode 100644
index 4888672c31..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter.snap
+++ /dev/null
@@ -1,10 +0,0 @@
----
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"#1\"#)"
-
----
-ROOT@0..2
- PREAMBLE@0..2
- TEXT@0..2
- WORD@0..2 "#1"
-
diff --git a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter_error.snap b/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter_error.snap
deleted file mode 100644
index 843327ab80..0000000000
--- a/support/texlab/src/syntax/latex/snapshots/texlab__syntax__latex__parser__tests__parameter_error.snap
+++ /dev/null
@@ -1,10 +0,0 @@
----
-source: src/syntax/latex/parser.rs
-expression: "setup(r#\"#\"#)"
-
----
-ROOT@0..1
- PREAMBLE@0..1
- TEXT@0..1
- WORD@0..1 "#"
-
diff --git a/support/texlab/src/syntax/snapshots/texlab__syntax__build_log__tests__parse_007.snap b/support/texlab/src/syntax/snapshots/texlab__syntax__build_log__tests__parse_007.snap
deleted file mode 100644
index 09d99c4f21..0000000000
--- a/support/texlab/src/syntax/snapshots/texlab__syntax__build_log__tests__parse_007.snap
+++ /dev/null
@@ -1,15 +0,0 @@
----
-source: src/syntax/build_log.rs
-expression: parse(&log).errors
-
----
-[
- BuildError {
- relative_path: "/some/folder/a.tex",
- level: Error,
- message: "Undefined control sequence.",
- line: Some(
- 3,
- ),
- },
-]
diff --git a/support/texlab/tests/integration/lsp.rs b/support/texlab/src/tests.rs
index 9ef1a4f2b4..c6afcfc20c 100644
--- a/support/texlab/tests/integration/lsp.rs
+++ b/support/texlab/src/tests.rs
@@ -1,4 +1,5 @@
mod client;
mod fixture;
+mod issues;
mod text_document;
mod workspace;
diff --git a/support/texlab/tests/integration/lsp/client.rs b/support/texlab/src/tests/client.rs
index 004422813a..ff6b23469b 100644
--- a/support/texlab/tests/integration/lsp/client.rs
+++ b/support/texlab/src/tests/client.rs
@@ -1,3 +1,5 @@
+use std::sync::Once;
+
use anyhow::{bail, Result};
use crossbeam_channel::{Receiver, Sender};
use lsp_server::{Connection, Message, Notification, Request, Response};
@@ -5,10 +7,13 @@ use lsp_types::{
notification::{Exit, Initialized},
request::{Initialize, Shutdown},
ClientCapabilities, ClientInfo, DidOpenTextDocumentParams, InitializeParams, InitializeResult,
- InitializedParams, Url,
+ InitializedParams, Url, WorkspaceFolder,
};
use tempfile::{tempdir, TempDir};
-use texlab::Server;
+
+use crate::Server;
+
+static INIT_LOGGER: Once = Once::new();
pub struct IncomingHandler {
_handle: jod_thread::JoinHandle<Result<()>>,
@@ -18,7 +23,7 @@ pub struct IncomingHandler {
}
impl IncomingHandler {
- pub fn spawn(receiver: Receiver<Message>) -> Result<Self> {
+ pub fn spawn(receiver: Receiver<Message>) -> Self {
let (req_sender, req_receiver) = crossbeam_channel::unbounded();
let (not_sender, not_receiver) = crossbeam_channel::unbounded();
let (res_sender, res_receiver) = crossbeam_channel::unbounded();
@@ -35,12 +40,12 @@ impl IncomingHandler {
Ok(())
});
- Ok(Self {
+ Self {
_handle,
requests: req_receiver,
notifications: not_receiver,
responses: res_receiver,
- })
+ }
}
}
@@ -58,45 +63,47 @@ pub struct Client {
}
impl Client {
- pub fn spawn() -> Result<Self> {
- let directory = tempdir()?;
+ pub fn spawn() -> Self {
+ INIT_LOGGER.call_once(|| env_logger::init());
+
+ let directory = tempdir().unwrap();
let (client, server) = Connection::memory();
- let incoming = IncomingHandler::spawn(client.receiver)?;
+ let incoming = IncomingHandler::spawn(client.receiver);
let outgoing = client.sender;
- let server = Server::with_connection(server, directory.path().to_path_buf(), false);
+ let server = Server::new(server);
let _handle = jod_thread::spawn(move || {
server.run().expect("server failed to run");
});
- Ok(Self {
+ Self {
outgoing,
incoming,
directory,
request_id: 0,
_handle,
- })
+ }
}
- #[allow(deprecated)]
pub fn initialize(
&mut self,
client_capabilities: ClientCapabilities,
client_info: Option<ClientInfo>,
- ) -> Result<InitializeResult> {
- let result = self.request::<Initialize>(InitializeParams {
- process_id: None,
- root_path: None,
- root_uri: None,
- initialization_options: None,
- capabilities: client_capabilities,
- trace: None,
- workspace_folders: None,
- client_info,
- locale: None,
- })?;
-
- self.notify::<Initialized>(InitializedParams {})?;
- Ok(result)
+ ) -> InitializeResult {
+ let result = self
+ .request::<Initialize>(InitializeParams {
+ initialization_options: Some(serde_json::json!({ "skipDistro": true })),
+ capabilities: client_capabilities,
+ workspace_folders: Some(vec![WorkspaceFolder {
+ name: "Test".into(),
+ uri: Url::from_directory_path(self.directory.path()).unwrap(),
+ }]),
+ client_info,
+ ..InitializeParams::default()
+ })
+ .unwrap();
+
+ self.notify::<Initialized>(InitializedParams {});
+ result
}
pub fn request<R: lsp_types::request::Request>(
@@ -106,9 +113,10 @@ impl Client {
self.request_id += 1;
self.outgoing
- .send(Request::new(self.request_id.into(), R::METHOD.into(), params).into())?;
+ .send(Request::new(self.request_id.into(), R::METHOD.into(), params).into())
+ .unwrap();
- let response = self.incoming.responses.recv()?;
+ let response = self.incoming.responses.recv().unwrap();
assert_eq!(response.id, self.request_id.into());
let result = match response.result {
@@ -119,47 +127,33 @@ impl Client {
Ok(serde_json::from_value(result)?)
}
- pub fn notify<N: lsp_types::notification::Notification>(
- &mut self,
- params: N::Params,
- ) -> Result<()> {
+ pub fn notify<N: lsp_types::notification::Notification>(&mut self, params: N::Params) {
self.outgoing
- .send(Notification::new(N::METHOD.into(), serde_json::to_value(params)?).into())?;
-
- Ok(())
+ .send(Notification::new(N::METHOD.into(), serde_json::to_value(params).unwrap()).into())
+ .unwrap();
}
- pub fn open(&mut self, name: &str, language_id: &str, text: String) -> Result<()> {
+ pub fn open(&mut self, name: &str, language_id: &str, text: String) {
self.notify::<lsp_types::notification::DidOpenTextDocument>(DidOpenTextDocumentParams {
text_document: lsp_types::TextDocumentItem {
- uri: self.uri(name)?,
+ uri: self.uri(name),
language_id: language_id.to_string(),
version: 0,
text,
},
- })?;
-
- Ok(())
- }
-
- pub fn store_on_disk(&mut self, name: &str, text: &str) -> Result<()> {
- let path = self.directory.path().join(name);
- std::fs::create_dir_all(path.parent().unwrap())?;
- std::fs::write(path, text)?;
- Ok(())
+ });
}
- pub fn shutdown(mut self) -> Result<ClientResult> {
- self.request::<Shutdown>(())?;
- self.notify::<Exit>(())?;
- Ok(ClientResult {
+ pub fn shutdown(mut self) -> ClientResult {
+ self.request::<Shutdown>(()).unwrap();
+ self.notify::<Exit>(());
+ ClientResult {
directory: self.directory,
incoming: self.incoming,
- })
+ }
}
- pub fn uri(&self, name: &str) -> Result<Url> {
- Url::from_file_path(self.directory.path().join(name))
- .map_err(|()| anyhow::anyhow!("failed to create uri"))
+ pub fn uri(&self, name: &str) -> Url {
+ Url::from_file_path(self.directory.path().join(name)).unwrap()
}
}
diff --git a/support/texlab/tests/integration/lsp/fixture.rs b/support/texlab/src/tests/fixture.rs
index 83d63cce60..b837a9f5b0 100644
--- a/support/texlab/tests/integration/lsp/fixture.rs
+++ b/support/texlab/src/tests/fixture.rs
@@ -1,10 +1,9 @@
use std::collections::BTreeMap;
-use anyhow::Result;
use lsp_types::{Position, Range, TextDocumentIdentifier, TextDocumentPositionParams};
use rustc_hash::FxHashMap;
-use crate::lsp::client::Client;
+use super::client::Client;
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
enum Line<'a> {
@@ -60,12 +59,12 @@ pub struct FileCursor<'a> {
}
impl<'a> FileCursor<'a> {
- pub fn into_params(self, server: &Client) -> Result<TextDocumentPositionParams> {
- let text_document = TextDocumentIdentifier::new(server.uri(self.name)?);
- Ok(TextDocumentPositionParams {
+ pub fn into_params(self, server: &Client) -> TextDocumentPositionParams {
+ let text_document = TextDocumentIdentifier::new(server.uri(self.name));
+ TextDocumentPositionParams {
text_document,
position: self.position,
- })
+ }
}
}
diff --git a/support/texlab/src/tests/issues.rs b/support/texlab/src/tests/issues.rs
new file mode 100644
index 0000000000..8f578f5ada
--- /dev/null
+++ b/support/texlab/src/tests/issues.rs
@@ -0,0 +1,12 @@
+use insta::assert_debug_snapshot;
+
+use crate::Options;
+
+#[test]
+fn issue_707() {
+ assert_debug_snapshot!(
+ serde_json::from_value::<Option<Options>>(serde_json::json!({}))
+ .unwrap()
+ .unwrap_or_default()
+ );
+}
diff --git a/support/texlab/src/tests/snapshots/texlab__tests__issues__issue_707.snap b/support/texlab/src/tests/snapshots/texlab__tests__issues__issue_707.snap
new file mode 100644
index 0000000000..1397a08fc0
--- /dev/null
+++ b/support/texlab/src/tests/snapshots/texlab__tests__issues__issue_707.snap
@@ -0,0 +1,45 @@
+---
+source: src/tests/issues.rs
+expression: "serde_json::from_value::<Option<Options>>(serde_json::json!({}))?.unwrap_or_default()"
+---
+Options {
+ root_directory: None,
+ aux_directory: None,
+ bibtex_formatter: Texlab,
+ latex_formatter: Latexindent,
+ formatter_line_length: None,
+ diagnostics: DiagnosticsOptions {
+ allowed_patterns: [],
+ ignored_patterns: [],
+ },
+ diagnostics_delay: DiagnosticsDelay(
+ 300ms,
+ ),
+ build: BuildOptions {
+ executable: BuildExecutable(
+ "latexmk",
+ ),
+ args: BuildArgs(
+ [
+ "-pdf",
+ "-interaction=nonstopmode",
+ "-synctex=1",
+ "%f",
+ ],
+ ),
+ on_save: false,
+ forward_search_after: false,
+ },
+ chktex: ChktexOptions {
+ on_open_and_save: false,
+ on_edit: false,
+ },
+ latexindent: LatexindentOptions {
+ local: None,
+ modify_line_breaks: false,
+ },
+ forward_search: ForwardSearchOptions {
+ executable: None,
+ args: None,
+ },
+}
diff --git a/support/texlab/tests/integration/lsp/text_document.rs b/support/texlab/src/tests/text_document.rs
index 283132d3c4..aac0553ec4 100644
--- a/support/texlab/tests/integration/lsp/text_document.rs
+++ b/support/texlab/src/tests/text_document.rs
@@ -1,4 +1,3 @@
-#[cfg(feature = "completion")]
mod completion;
mod definition;
mod did_change_configuration;
@@ -8,6 +7,6 @@ mod document_symbol;
mod folding_range;
mod formatting;
mod hover;
-mod publish_diagnostics;
+mod inlay_hint;
mod references;
mod rename;
diff --git a/support/texlab/tests/integration/lsp/text_document/completion.rs b/support/texlab/src/tests/text_document/completion.rs
index 5e160904fe..d4f256cdfb 100644
--- a/support/texlab/tests/integration/lsp/text_document/completion.rs
+++ b/support/texlab/src/tests/text_document/completion.rs
@@ -1,19 +1,31 @@
-use anyhow::Result;
use insta::assert_json_snapshot;
use lsp_types::{
request::{Completion, ResolveCompletionItem},
- ClientCapabilities, CompletionItem, CompletionList, CompletionParams, CompletionResponse,
- CompletionTextEdit, Range,
+ CompletionItem, CompletionList, CompletionParams, CompletionResponse, CompletionTextEdit,
+ Range,
};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
+
+fn complete(fixture: &str) -> Vec<CompletionItem> {
+ let mut client = Client::spawn();
+ client.initialize(
+ serde_json::from_value(serde_json::json!({
+ "textDocument": {
+ "completion": {
+ "completionItem": {
+ "documentationFormat": ["plaintext", "markdown"]
+ }
+ }
+ }
+ }))
+ .unwrap(),
+ None,
+ );
-fn complete(fixture: &str) -> Result<Vec<CompletionItem>, anyhow::Error> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let range = fixture
@@ -31,11 +43,12 @@ fn complete(fixture: &str) -> Result<Vec<CompletionItem>, anyhow::Error> {
let actual_list = client
.request::<Completion>(CompletionParams {
- text_document_position: fixture.cursor.unwrap().into_params(&client)?,
+ text_document_position: fixture.cursor.unwrap().into_params(&client),
partial_result_params: Default::default(),
work_done_progress_params: Default::default(),
context: None,
- })?
+ })
+ .unwrap()
.map_or(CompletionList::default(), |actual| match actual {
CompletionResponse::List(list) => list,
CompletionResponse::Array(_) => unreachable!(),
@@ -51,11 +64,11 @@ fn complete(fixture: &str) -> Result<Vec<CompletionItem>, anyhow::Error> {
.items
.into_iter()
.take(5)
- .map(|item| client.request::<ResolveCompletionItem>(item))
- .collect::<Result<Vec<_>>>()?;
+ .map(|item| client.request::<ResolveCompletionItem>(item).unwrap())
+ .collect();
- client.shutdown()?;
- Ok(actual_items)
+ client.shutdown();
+ actual_items
}
macro_rules! assert_items {
@@ -71,7 +84,7 @@ macro_rules! assert_items {
}
#[test]
-fn acronym_ref_simple() -> Result<()> {
+fn acronym_ref_simple() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -79,26 +92,22 @@ fn acronym_ref_simple() -> Result<()> {
%SRC \acrshort{f}
%CUR ^
%1.1 ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn acronym_ref_empty() -> Result<()> {
+fn acronym_ref_empty() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}
%SRC \acrshort{}
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn acronym_ref_after_group() -> Result<()> {
+fn acronym_ref_after_group() {
let actual_items = complete(
r#"
%TEX main.tex
@@ -106,14 +115,13 @@ fn acronym_ref_after_group() -> Result<()> {
%SRC \acrshort{}
%CUR ^
%1.1 ^"#,
- )?;
+ );
assert_eq!(actual_items, Vec::new());
- Ok(())
}
#[test]
-fn acronym_ref_open_brace() -> Result<()> {
+fn acronym_ref_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -121,13 +129,23 @@ fn acronym_ref_open_brace() -> Result<()> {
%SRC \acrshort{f
%CUR ^
%1.1 ^"#
- )?);
+ ));
+}
- Ok(())
+#[test]
+fn acronym_package_ref() {
+ assert_items!(complete(
+ r#"
+%TEX main.tex
+%SRC \acrodef{fpsLabel}[FPS]{Frames per Second}
+%SRC \ac{f
+%CUR ^
+%1.1 ^"#
+ ));
}
#[test]
-fn glossary_ref_simple() -> Result<()> {
+fn glossary_ref_simple() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -135,13 +153,11 @@ fn glossary_ref_simple() -> Result<()> {
%SRC \gls{f}
%CUR ^
%1.1 ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn glossary_ref_open_brace() -> Result<()> {
+fn glossary_ref_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -149,26 +165,22 @@ fn glossary_ref_open_brace() -> Result<()> {
%SRC \gls{f
%CUR ^
%1.1 ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn argument_empty() -> Result<()> {
+fn argument_empty() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \usepackage{amsfonts}
%SRC \mathbb{}
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn argument_word() -> Result<()> {
+fn argument_word() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -176,13 +188,11 @@ fn argument_word() -> Result<()> {
%SRC \mathbb{A}
%CUR ^
%1.1 ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn argument_open_brace() -> Result<()> {
+fn argument_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -190,13 +200,11 @@ fn argument_open_brace() -> Result<()> {
%SRC \mathbb{
%CUR ^
%SRC Test"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn argument_open_brace_unrelated() -> Result<()> {
+fn argument_open_brace_unrelated() {
let actual_items = complete(
r#"
%TEX main.tex
@@ -204,27 +212,24 @@ fn argument_open_brace_unrelated() -> Result<()> {
%SRC \mathbb{}{
%CUR ^
%SRC Test"#,
- )?;
+ );
assert_eq!(actual_items, Vec::new());
- Ok(())
}
#[test]
-fn begin_environment_without_snippet_support() -> Result<()> {
+fn begin_environment_without_snippet_support() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \beg
%CUR ^
%1.1 ^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn citation() -> Result<()> {
+fn citation() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -243,13 +248,11 @@ fn citation() -> Result<()> {
%SRC }
%SRC
%SRC @article{bar:2005,}"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn citation_open_brace() -> Result<()> {
+fn citation_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -259,13 +262,11 @@ fn citation_open_brace() -> Result<()> {
%BIB main.bib
%SRC @article{foo,}"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn citation_open_brace_multiple() -> Result<()> {
+fn citation_open_brace_multiple() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -276,13 +277,11 @@ fn citation_open_brace_multiple() -> Result<()> {
%BIB main.bib
%SRC @article{foo,}"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn citation_acronym() -> Result<()> {
+fn citation_acronym() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -292,13 +291,11 @@ fn citation_acronym() -> Result<()> {
%BIB main.bib
%SRC @article{foo,}"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn citation_after_brace() -> Result<()> {
+fn citation_after_brace() {
let actual_items = complete(
r#"
%TEX main.tex
@@ -311,124 +308,106 @@ fn citation_after_brace() -> Result<()> {
%BIB main.bib
%SRC @article{foo,}"#,
- )?;
+ );
assert_eq!(actual_items, Vec::new());
- Ok(())
}
#[test]
-fn color_model_definition_simple() -> Result<()> {
+fn color_model_definition_simple() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \definecolor{foo}{}
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn color_model_definition_open_brace() -> Result<()> {
+fn color_model_definition_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \definecolor{foo}{
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn color_model_definition_set_simple() -> Result<()> {
+fn color_model_definition_set_simple() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \definecolorset{}
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn color_model_definition_set_open_brace() -> Result<()> {
+fn color_model_definition_set_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \definecolorset{
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn color_simple() -> Result<()> {
+fn color_simple() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \color{}
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn color_word() -> Result<()> {
+fn color_word() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \color{re}
%CUR ^
%1.1 ^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn color_open_brace() -> Result<()> {
+fn color_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \color{
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn component_command_simple() -> Result<()> {
+fn component_command_simple() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn component_command_simple_before() -> Result<()> {
+fn component_command_simple_before() {
let actual_items = complete(
r#"
%TEX main.tex
%SRC \
%CUR ^"#,
- )?;
+ );
assert_eq!(actual_items, Vec::new());
- Ok(())
}
#[test]
-fn component_command_simple_package() -> Result<()> {
+fn component_command_simple_package() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -436,13 +415,11 @@ fn component_command_simple_package() -> Result<()> {
%SRC \lips
%CUR ^
%1.1 ^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn component_command_bibtex() -> Result<()> {
+fn component_command_bibtex() {
assert_items!(complete(
r#"
%BIB main.bib
@@ -451,39 +428,33 @@ fn component_command_bibtex() -> Result<()> {
%CUR ^
%1.1 ^^^
%SRC }"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn component_environment_simple() -> Result<()> {
+fn component_environment_simple() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \begin{doc
%CUR ^
%1.1 ^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn component_environment_simple_end() -> Result<()> {
+fn component_environment_simple_end() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \begin{document}
%SRC \end{
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn component_environment_class() -> Result<()> {
+fn component_environment_class() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -491,231 +462,195 @@ fn component_environment_class() -> Result<()> {
%SRC \begin{thein}
%CUR ^
%1.1 ^^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn component_environment_command_definition() -> Result<()> {
+fn component_environment_command_definition() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \newcommand{\foo}{\begin{doc}
%CUR ^
%1.1 ^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn entry_type_at_empty() -> Result<()> {
+fn entry_type_at_empty() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn entry_type_before_preamble() -> Result<()> {
+fn entry_type_before_preamble() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @preamble
%CUR ^
%1.1 ^^^^^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn entry_type_before_string() -> Result<()> {
+fn entry_type_before_string() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @string
%CUR ^
%1.1 ^^^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn entry_type_before_article() -> Result<()> {
+fn entry_type_before_article() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @article
%CUR ^
%1.1 ^^^^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn entry_type_after_preamble() -> Result<()> {
+fn entry_type_after_preamble() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @preamble{
%CUR ^
%1.1 ^^^^^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn entry_type_after_string() -> Result<()> {
+fn entry_type_after_string() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @string{
%CUR ^
%1.1 ^^^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn entry_type_complete_entry() -> Result<()> {
+fn entry_type_complete_entry() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @article{foo, author = {foo}}
%CUR ^
%1.1 ^^^^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn field_empty_entry_open() -> Result<()> {
+fn field_empty_entry_open() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @article{foo,
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn field_empty_entry_closed() -> Result<()> {
+fn field_empty_entry_closed() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @article{foo,}
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn field_entry_field_name() -> Result<()> {
+fn field_entry_field_name() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @article{foo, a
%CUR ^
%1.1 ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn field_entry_two_fields_name_open() -> Result<()> {
+fn field_entry_two_fields_name_open() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @article{foo, author = bar, edit
%CUR ^
%1.1 ^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn field_entry_two_fields_name_closed() -> Result<()> {
+fn field_entry_two_fields_name_closed() {
assert_items!(complete(
r#"
%BIB main.bib
%SRC @article{foo, author = bar, edit}
%CUR ^
%1.1 ^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn import_package_open_brace() -> Result<()> {
+fn import_package_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \usepackage{lips
%CUR ^
%1.1 ^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn import_package_closed_brace() -> Result<()> {
+fn import_package_closed_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \usepackage{lips}
%CUR ^
%1.1 ^^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn import_class_open_brace() -> Result<()> {
+fn import_class_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \documentclass{art \foo
%CUR ^
%1.1 ^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn import_class_closed_brace() -> Result<()> {
+fn import_class_closed_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \documentclass{art}
%CUR ^
%1.1 ^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn label() -> Result<()> {
+fn label() {
assert_items!(complete(
r#"
%TEX foo.tex
@@ -775,13 +710,11 @@ fn label() -> Result<()> {
%SRC \newlabel{eq:bar}{{2}{1}}
%SRC \newlabel{thm:foo}{{1}{1}}
%SRC \@input{bar.aux}"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn theorem_begin() -> Result<()> {
+fn theorem_begin() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -789,13 +722,11 @@ fn theorem_begin() -> Result<()> {
%SRC \begin{lem
%CUR ^
%1.1 ^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn theorem_end() -> Result<()> {
+fn theorem_end() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -804,37 +735,31 @@ fn theorem_end() -> Result<()> {
%SRC \end{lem
%CUR ^
%1.1 ^^^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn tikz_library_open_brace() -> Result<()> {
+fn tikz_library_open_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \usepgflibrary{
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn tikz_library_closed_brace() -> Result<()> {
+fn tikz_library_closed_brace() {
assert_items!(complete(
r#"
%TEX main.tex
%SRC \usepgflibrary{}
%CUR ^"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn test_user_command() -> Result<()> {
+fn test_user_command() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -846,13 +771,11 @@ fn test_user_command() -> Result<()> {
%SRC \end{foo}
%SRC \begin{fo}
"#
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn test_user_environment() -> Result<()> {
+fn test_user_environment() {
assert_items!(complete(
r#"
%TEX main.tex
@@ -864,7 +787,26 @@ fn test_user_environment() -> Result<()> {
%CUR ^
%1.1 ^^
"#
- )?);
+ ));
+}
+
+#[test]
+fn test_project_resolution() {
+ assert_items!(complete(
+ r#"
+%TEX main.tex
+%SRC \documentclass{article}
+%SRC \import{sub}{sub/sub.tex}
+%SRC \lipsu
+%CUR ^
+%1.1 ^^^^^
- Ok(())
+%TEX sub/sub.tex
+%SRC \input{child.tex}
+
+%TEX sub/child.tex
+%SRC \usepackage{lipsum}
+
+"#
+ ));
}
diff --git a/support/texlab/tests/integration/lsp/text_document/definition.rs b/support/texlab/src/tests/text_document/definition.rs
index 203c350464..b1b915c6c9 100644
--- a/support/texlab/tests/integration/lsp/text_document/definition.rs
+++ b/support/texlab/src/tests/text_document/definition.rs
@@ -1,26 +1,25 @@
-use anyhow::Result;
use assert_unordered::assert_eq_unordered;
use lsp_types::{
request::GotoDefinition, ClientCapabilities, GotoDefinitionParams, GotoDefinitionResponse,
LocationLink,
};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
-fn check(fixture: &str) -> Result<()> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn check(fixture: &str) {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let mut expected_links = Vec::new();
for ranges in fixture.ranges.values() {
expected_links.push(LocationLink {
origin_selection_range: Some(ranges[&1].range),
- target_uri: client.uri(ranges[&2].name)?,
+ target_uri: client.uri(ranges[&2].name),
target_range: ranges[&2].range,
target_selection_range: ranges[&3].range,
});
@@ -28,23 +27,22 @@ fn check(fixture: &str) -> Result<()> {
let actual_links = client
.request::<GotoDefinition>(GotoDefinitionParams {
- text_document_position_params: fixture.cursor.unwrap().into_params(&client)?,
+ text_document_position_params: fixture.cursor.unwrap().into_params(&client),
partial_result_params: Default::default(),
work_done_progress_params: Default::default(),
- })?
+ })
+ .unwrap()
.map_or(Vec::new(), |actual| match actual {
GotoDefinitionResponse::Link(links) => links,
GotoDefinitionResponse::Array(_) | GotoDefinitionResponse::Scalar(_) => unreachable!(),
});
- client.shutdown()?;
-
+ client.shutdown();
assert_eq_unordered!(actual_links, expected_links);
- Ok(())
}
#[test]
-fn command_definition() -> Result<()> {
+fn command_definition() {
check(
r#"
%TEX main.tex
@@ -59,7 +57,7 @@ fn command_definition() -> Result<()> {
}
#[test]
-fn document() -> Result<()> {
+fn document() {
check(
r#"
%TEX foo.tex
@@ -79,7 +77,7 @@ fn document() -> Result<()> {
}
#[test]
-fn entry() -> Result<()> {
+fn entry() {
check(
r#"
%TEX foo.tex
@@ -100,7 +98,7 @@ fn entry() -> Result<()> {
}
#[test]
-fn string_simple() -> Result<()> {
+fn string_simple() {
check(
r#"
%BIB main.bib
@@ -115,7 +113,7 @@ fn string_simple() -> Result<()> {
}
#[test]
-fn string_join() -> Result<()> {
+fn string_join() {
check(
r#"
%BIB main.bib
@@ -130,7 +128,7 @@ fn string_join() -> Result<()> {
}
#[test]
-fn string_field() -> Result<()> {
+fn string_field() {
check(
r#"
%BIB main.bib
diff --git a/support/texlab/tests/integration/lsp/text_document/did_change_configuration.rs b/support/texlab/src/tests/text_document/did_change_configuration.rs
index c45dca094b..15aae0ee4b 100644
--- a/support/texlab/tests/integration/lsp/text_document/did_change_configuration.rs
+++ b/support/texlab/src/tests/text_document/did_change_configuration.rs
@@ -1,16 +1,15 @@
-use anyhow::Result;
use insta::assert_snapshot;
use lsp_types::{
notification::{DidChangeConfiguration, Notification, ShowMessage},
ClientCapabilities, DidChangeConfigurationParams, ShowMessageParams,
};
-use crate::lsp::client::Client;
+use crate::tests::client::Client;
#[test]
-fn invalid_configuration() -> Result<()> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn invalid_configuration() {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
client.notify::<DidChangeConfiguration>(DidChangeConfigurationParams {
settings: serde_json::json!({
@@ -18,9 +17,9 @@ fn invalid_configuration() -> Result<()> {
"allowedPatterns": ["\\"]
}
}),
- })?;
+ });
- let result = client.shutdown()?;
+ let result = client.shutdown();
let message = result
.incoming
.notifications
@@ -35,5 +34,4 @@ fn invalid_configuration() -> Result<()> {
.message;
assert_snapshot!(message);
- Ok(())
}
diff --git a/support/texlab/tests/integration/lsp/text_document/document_highlight.rs b/support/texlab/src/tests/text_document/document_highlight.rs
index 92102ce0ca..01945ce342 100644
--- a/support/texlab/tests/integration/lsp/text_document/document_highlight.rs
+++ b/support/texlab/src/tests/text_document/document_highlight.rs
@@ -1,19 +1,18 @@
-use anyhow::Result;
use assert_unordered::assert_eq_unordered;
use lsp_types::{
request::DocumentHighlightRequest, ClientCapabilities, DocumentHighlight,
DocumentHighlightKind, DocumentHighlightParams,
};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
-fn check(fixture: &str) -> Result<()> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn check(fixture: &str) {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let mut expected_highlights = Vec::new();
@@ -34,20 +33,19 @@ fn check(fixture: &str) -> Result<()> {
let actual_highlights = client
.request::<DocumentHighlightRequest>(DocumentHighlightParams {
- text_document_position_params: fixture.cursor.unwrap().into_params(&client)?,
+ text_document_position_params: fixture.cursor.unwrap().into_params(&client),
partial_result_params: Default::default(),
work_done_progress_params: Default::default(),
- })?
+ })
+ .unwrap()
.unwrap_or_default();
- client.shutdown()?;
-
+ client.shutdown();
assert_eq_unordered!(actual_highlights, expected_highlights);
- Ok(())
}
#[test]
-fn test_label() -> Result<()> {
+fn test_label() {
check(
r#"
%TEX main.tex
diff --git a/support/texlab/tests/integration/lsp/text_document/document_link.rs b/support/texlab/src/tests/text_document/document_link.rs
index 1a773fd478..8b4a30ceeb 100644
--- a/support/texlab/tests/integration/lsp/text_document/document_link.rs
+++ b/support/texlab/src/tests/text_document/document_link.rs
@@ -1,26 +1,25 @@
-use anyhow::Result;
use assert_unordered::assert_eq_unordered;
use lsp_types::{
request::DocumentLinkRequest, ClientCapabilities, DocumentLink, DocumentLinkParams,
TextDocumentIdentifier,
};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
-fn check(fixture: &str) -> Result<()> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn check(fixture: &str) {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let mut expected_links = Vec::new();
for ranges in fixture.ranges.values() {
expected_links.push(DocumentLink {
range: ranges[&1].range,
- target: Some(client.uri(ranges[&2].name)?),
+ target: Some(client.uri(ranges[&2].name)),
tooltip: None,
data: None,
});
@@ -28,20 +27,19 @@ fn check(fixture: &str) -> Result<()> {
let actual_links = client
.request::<DocumentLinkRequest>(DocumentLinkParams {
- text_document: TextDocumentIdentifier::new(client.uri(fixture.cursor.unwrap().name)?),
+ text_document: TextDocumentIdentifier::new(client.uri(fixture.cursor.unwrap().name)),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
- })?
+ })
+ .unwrap()
.unwrap_or_default();
- client.shutdown()?;
-
+ client.shutdown();
assert_eq_unordered!(actual_links, expected_links);
- Ok(())
}
#[test]
-fn document_include() -> Result<()> {
+fn document_include() {
check(
r#"
%TEX foo.tex
@@ -57,12 +55,12 @@ fn document_include() -> Result<()> {
}
#[test]
-fn document_import() -> Result<()> {
+fn document_import() {
check(
r#"
%TEX foo.tex
-%SRC \import{bar/}{baz}
-%1.1 ^^^
+%SRC \import{.}{bar/baz}
+%1.1 ^^^^^^^
%CUR ^
%TEX bar/baz.tex
diff --git a/support/texlab/tests/integration/lsp/text_document/document_symbol.rs b/support/texlab/src/tests/text_document/document_symbol.rs
index 50bb9db3fe..2eab81631e 100644
--- a/support/texlab/tests/integration/lsp/text_document/document_symbol.rs
+++ b/support/texlab/src/tests/text_document/document_symbol.rs
@@ -1,42 +1,43 @@
-use anyhow::Result;
use insta::{assert_json_snapshot, internals::Redaction};
use lsp_types::{
request::DocumentSymbolRequest, DocumentSymbolParams, DocumentSymbolResponse,
TextDocumentIdentifier, Url,
};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
struct SymbolResult {
response: Option<DocumentSymbolResponse>,
uri_redaction: Redaction,
}
-fn find_symbols(fixture: &str, client_capabilities: serde_json::Value) -> Result<SymbolResult> {
- let mut client = Client::spawn()?;
- client.initialize(serde_json::from_value(client_capabilities)?, None)?;
+fn find_symbols(fixture: &str, client_capabilities: serde_json::Value) -> SymbolResult {
+ let mut client = Client::spawn();
+ client.initialize(serde_json::from_value(client_capabilities).unwrap(), None);
let fixture = fixture::parse(fixture);
let file = fixture.files.into_iter().next().unwrap();
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
- let response = client.request::<DocumentSymbolRequest>(DocumentSymbolParams {
- text_document: TextDocumentIdentifier::new(client.uri(file.name)?),
- work_done_progress_params: Default::default(),
- partial_result_params: Default::default(),
- })?;
+ let response = client
+ .request::<DocumentSymbolRequest>(DocumentSymbolParams {
+ text_document: TextDocumentIdentifier::new(client.uri(file.name)),
+ work_done_progress_params: Default::default(),
+ partial_result_params: Default::default(),
+ })
+ .unwrap();
- let result = client.shutdown()?;
+ let result = client.shutdown();
let uri = Url::from_directory_path(result.directory.path()).unwrap();
let uri_redaction = insta::dynamic_redaction(move |content, _path| {
content.as_str().unwrap().replace(uri.as_str(), "[tmp]/")
});
- Ok(SymbolResult {
+ SymbolResult {
response,
uri_redaction,
- })
+ }
}
macro_rules! assert_symbols {
@@ -49,7 +50,7 @@ macro_rules! assert_symbols {
}
#[test]
-fn enumerate_nested() -> Result<()> {
+fn enumerate_nested() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -78,13 +79,11 @@ fn enumerate_nested() -> Result<()> {
},
},
}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn enumerate_flat() -> Result<()> {
+fn enumerate_flat() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -107,13 +106,11 @@ fn enumerate_flat() -> Result<()> {
%SRC \newlabel{it:qux}{{2}{1}}
"#,
serde_json::json!({}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn equation_nested() -> Result<()> {
+fn equation_nested() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -146,13 +143,11 @@ fn equation_nested() -> Result<()> {
},
},
}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn equation_flat() -> Result<()> {
+fn equation_flat() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -179,13 +174,11 @@ fn equation_flat() -> Result<()> {
%SRC \newlabel{eq:foo}{{1}{1}}
"#,
serde_json::json!({}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn float_nested() -> Result<()> {
+fn float_nested() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -228,13 +221,11 @@ fn float_nested() -> Result<()> {
},
},
}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn float_flat() -> Result<()> {
+fn float_flat() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -271,13 +262,11 @@ fn float_flat() -> Result<()> {
%SRC \@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Baz}}{1}\protected@file@percent }
"#,
serde_json::json!({}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn section_nested() -> Result<()> {
+fn section_nested() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -306,13 +295,11 @@ fn section_nested() -> Result<()> {
},
},
}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn section_flat() -> Result<()> {
+fn section_flat() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -335,13 +322,11 @@ fn section_flat() -> Result<()> {
%SRC \newlabel{sec:bar}{{2}{1}}
"#,
serde_json::json!({}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn theorem_nested() -> Result<()> {
+fn theorem_nested() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -381,13 +366,11 @@ fn theorem_nested() -> Result<()> {
},
},
}),
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn theorem_flat() -> Result<()> {
+fn theorem_flat() {
assert_symbols!(find_symbols(
r#"
%TEX main.tex
@@ -421,7 +404,5 @@ fn theorem_flat() -> Result<()> {
%SRC \newlabel{thm:bar}{{2}{1}}
"#,
serde_json::json!({}),
- )?);
-
- Ok(())
+ ));
}
diff --git a/support/texlab/tests/integration/lsp/text_document/folding_range.rs b/support/texlab/src/tests/text_document/folding_range.rs
index 1d75ba3e0e..4b589222b1 100644
--- a/support/texlab/tests/integration/lsp/text_document/folding_range.rs
+++ b/support/texlab/src/tests/text_document/folding_range.rs
@@ -1,30 +1,30 @@
-use anyhow::Result;
use assert_unordered::assert_eq_unordered;
use lsp_types::{
request::FoldingRangeRequest, ClientCapabilities, FoldingRange, FoldingRangeKind,
FoldingRangeParams, TextDocumentIdentifier,
};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
-fn check(fixture: &str, expected_ranges: Vec<(u32, u32, u32, u32)>) -> Result<()> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn check(fixture: &str, expected_ranges: Vec<(u32, u32, u32, u32)>) {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let actual_foldings = client
.request::<FoldingRangeRequest>(FoldingRangeParams {
- text_document: TextDocumentIdentifier::new(client.uri(fixture.cursor.unwrap().name)?),
+ text_document: TextDocumentIdentifier::new(client.uri(fixture.cursor.unwrap().name)),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
- })?
+ })
+ .unwrap()
.unwrap_or_default();
- client.shutdown()?;
+ client.shutdown();
let expected_foldings = expected_ranges
.into_iter()
@@ -40,11 +40,10 @@ fn check(fixture: &str, expected_ranges: Vec<(u32, u32, u32, u32)>) -> Result<()
.collect();
assert_eq_unordered!(actual_foldings, expected_foldings);
- Ok(())
}
#[test]
-fn latex() -> Result<()> {
+fn latex() {
check(
r#"
%TEX main.tex
@@ -70,7 +69,7 @@ fn latex() -> Result<()> {
}
#[test]
-fn bibtex() -> Result<()> {
+fn bibtex() {
check(
r#"
%BIB main.bib
diff --git a/support/texlab/tests/integration/lsp/text_document/formatting.rs b/support/texlab/src/tests/text_document/formatting.rs
index a0c02bf4b1..eb6804ca66 100644
--- a/support/texlab/tests/integration/lsp/text_document/formatting.rs
+++ b/support/texlab/src/tests/text_document/formatting.rs
@@ -1,35 +1,37 @@
-use anyhow::Result;
use insta::assert_snapshot;
use lsp_types::{
request::Formatting, ClientCapabilities, DocumentFormattingParams, FormattingOptions,
TextDocumentIdentifier,
};
-use texlab::{LineIndex, LineIndexExt};
-use crate::lsp::{client::Client, fixture};
+use crate::{
+ tests::{client::Client, fixture},
+ util::{line_index::LineIndex, line_index_ext::LineIndexExt},
+};
-fn format(fixture: &str) -> Result<String> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn format(fixture: &str) -> String {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
let file = fixture.files.into_iter().next().unwrap();
let old_text = file.text.clone();
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
let actual_edits = client
.request::<Formatting>(DocumentFormattingParams {
- text_document: TextDocumentIdentifier::new(client.uri(file.name)?),
+ text_document: TextDocumentIdentifier::new(client.uri(file.name)),
work_done_progress_params: Default::default(),
options: FormattingOptions {
insert_spaces: true,
tab_size: 4,
..Default::default()
},
- })?
+ })
+ .unwrap()
.unwrap_or_default();
- client.shutdown()?;
+ client.shutdown();
let line_index = LineIndex::new(&old_text);
let mut actual_text = old_text;
@@ -38,24 +40,22 @@ fn format(fixture: &str) -> Result<String> {
actual_text.replace_range::<std::ops::Range<usize>>(range.into(), &edit.new_text);
}
- Ok(actual_text)
+ actual_text
}
#[test]
-fn bibtex_internal_wrap_long_lines() -> Result<()> {
+fn bibtex_internal_wrap_long_lines() {
assert_snapshot!(format(
r#"
%BIB main.bib
%SRC @article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit.
%SRC Lorem ipsum dolor sit amet,
%SRC consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}"#,
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn bibtex_internal_multiple_entries() -> Result<()> {
+fn bibtex_internal_multiple_entries() {
assert_snapshot!(format(
r#"
%BIB main.bib
@@ -64,85 +64,69 @@ fn bibtex_internal_multiple_entries() -> Result<()> {
%SRC
%SRC @article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet,
%SRC consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}""#,
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn bibtex_internal_trailing_comma() -> Result<()> {
+fn bibtex_internal_trailing_comma() {
assert_snapshot!(format(
r#"
%BIB main.bib
%SRC @article{foo, bar = baz}"#,
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn bibtex_internal_insert_braces() -> Result<()> {
+fn bibtex_internal_insert_braces() {
assert_snapshot!(format(
r#"
%BIB main.bib
%SRC @article{foo, bar = baz,"#,
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn bibtex_internal_command() -> Result<()> {
+fn bibtex_internal_command() {
assert_snapshot!(format(
r#"
%BIB main.bib
%SRC @article{foo, bar = "\baz",}"#,
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn bibtex_internal_join_strings() -> Result<()> {
+fn bibtex_internal_join_strings() {
assert_snapshot!(format(
r#"
%BIB main.bib
%SRC @article{foo, bar = "baz" # "qux"}"#,
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn bibtex_internal_parens() -> Result<()> {
+fn bibtex_internal_parens() {
assert_snapshot!(format(
r#"
%BIB main.bib
%SRC @article(foo,)"#,
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn bibtex_internal_string() -> Result<()> {
+fn bibtex_internal_string() {
assert_snapshot!(format(
r#"
%BIB main.bib
%SRC @string{foo="bar"}"#,
- )?);
-
- Ok(())
+ ));
}
#[test]
-fn bibtex_internal_preamble() -> Result<()> {
+fn bibtex_internal_preamble() {
assert_snapshot!(format(
r#"
%BIB main.bib
%SRC @preamble{
%SRC "foo bar baz" }"#,
- )?);
-
- Ok(())
+ ));
}
diff --git a/support/texlab/tests/integration/lsp/text_document/hover.rs b/support/texlab/src/tests/text_document/hover.rs
index 2a9e8c271f..302be82ca3 100644
--- a/support/texlab/tests/integration/lsp/text_document/hover.rs
+++ b/support/texlab/src/tests/text_document/hover.rs
@@ -1,19 +1,20 @@
-use anyhow::Result;
use lsp_types::{
request::HoverRequest, ClientCapabilities, Hover, HoverContents, HoverParams, MarkupContent,
MarkupKind,
};
-use texlab::{component_db::COMPONENT_DATABASE, LANGUAGE_DATA};
-use crate::lsp::{client::Client, fixture};
+use crate::{
+ tests::{client::Client, fixture},
+ util::{components::COMPONENT_DATABASE, lang_data::LANGUAGE_DATA},
+};
-fn check(fixture: &str, contents: Option<HoverContents>) -> Result<()> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn check(fixture: &str, contents: Option<HoverContents>) {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let range = fixture
@@ -23,21 +24,21 @@ fn check(fixture: &str, contents: Option<HoverContents>) -> Result<()> {
.and_then(|map| map.values().next())
.map(|file_range| file_range.range);
- let actual_hover = client.request::<HoverRequest>(HoverParams {
- text_document_position_params: fixture.cursor.unwrap().into_params(&client)?,
- work_done_progress_params: Default::default(),
- })?;
+ let actual_hover = client
+ .request::<HoverRequest>(HoverParams {
+ text_document_position_params: fixture.cursor.unwrap().into_params(&client),
+ work_done_progress_params: Default::default(),
+ })
+ .unwrap();
- client.shutdown()?;
+ client.shutdown();
let expected_hover = contents.map(|contents| Hover { range, contents });
-
assert_eq!(actual_hover, expected_hover);
- Ok(())
}
#[test]
-fn empty_latex_document() -> Result<()> {
+fn empty_latex_document() {
check(
r#"
%TEX main.tex
@@ -49,7 +50,7 @@ fn empty_latex_document() -> Result<()> {
}
#[test]
-fn empty_bibtex_document() -> Result<()> {
+fn empty_bibtex_document() {
check(
r#"
%BIB main.bib
@@ -61,7 +62,7 @@ fn empty_bibtex_document() -> Result<()> {
}
#[test]
-fn citation_inside_cite() -> Result<()> {
+fn citation_inside_cite() {
check(
r#"
%BIB main.bib
@@ -81,7 +82,7 @@ fn citation_inside_cite() -> Result<()> {
}
#[test]
-fn citation_inside_entry() -> Result<()> {
+fn citation_inside_entry() {
check(
r#"
%BIB main.bib
@@ -101,7 +102,7 @@ fn citation_inside_entry() -> Result<()> {
}
#[test]
-fn component_known_package() -> Result<()> {
+fn component_known_package() {
check(
r#"
%TEX main.tex
@@ -116,7 +117,7 @@ fn component_known_package() -> Result<()> {
}
#[test]
-fn component_unknown_class() -> Result<()> {
+fn component_unknown_class() {
check(
r#"
%TEX main.tex
@@ -128,7 +129,7 @@ fn component_unknown_class() -> Result<()> {
}
#[test]
-fn entry_type_known_type() -> Result<()> {
+fn entry_type_known_type() {
check(
r#"
%BIB main.bib
@@ -147,7 +148,7 @@ fn entry_type_known_type() -> Result<()> {
}
#[test]
-fn entry_type_unknown_field() -> Result<()> {
+fn entry_type_unknown_field() {
check(
r#"
%BIB main.bib
@@ -159,7 +160,7 @@ fn entry_type_unknown_field() -> Result<()> {
}
#[test]
-fn entry_type_key() -> Result<()> {
+fn entry_type_key() {
check(
r#"
%BIB main.bib
@@ -171,7 +172,7 @@ fn entry_type_key() -> Result<()> {
}
#[test]
-fn field_known() -> Result<()> {
+fn field_known() {
check(
r#"
%BIB main.bib
@@ -190,7 +191,7 @@ fn field_known() -> Result<()> {
}
#[test]
-fn field_unknown() -> Result<()> {
+fn field_unknown() {
check(
r#"
%BIB main.bib
@@ -202,7 +203,7 @@ fn field_unknown() -> Result<()> {
}
#[test]
-fn section() -> Result<()> {
+fn section() {
check(
r#"
%TEX main.tex
@@ -219,7 +220,7 @@ fn section() -> Result<()> {
}
#[test]
-fn string_inside_reference() -> Result<()> {
+fn string_inside_reference() {
check(
r#"
%BIB main.bib
@@ -237,7 +238,7 @@ fn string_inside_reference() -> Result<()> {
}
#[test]
-fn string_inside_field() -> Result<()> {
+fn string_inside_field() {
check(
r#"
%BIB main.bib
@@ -251,7 +252,7 @@ fn string_inside_field() -> Result<()> {
}
#[test]
-fn label_theorem_child_file() -> Result<()> {
+fn label_theorem_child_file() {
check(
r#"
%TEX main.tex
@@ -275,7 +276,7 @@ fn label_theorem_child_file() -> Result<()> {
}
#[test]
-fn label_theorem_child_file_mumber() -> Result<()> {
+fn label_theorem_child_file_mumber() {
check(
r#"
%TEX main.tex
diff --git a/support/texlab/src/tests/text_document/inlay_hint.rs b/support/texlab/src/tests/text_document/inlay_hint.rs
new file mode 100644
index 0000000000..acf5c3e132
--- /dev/null
+++ b/support/texlab/src/tests/text_document/inlay_hint.rs
@@ -0,0 +1,65 @@
+use insta::assert_json_snapshot;
+use lsp_types::{
+ request::InlayHintRequest, ClientCapabilities, InlayHint, InlayHintParams, Position, Range,
+ TextDocumentIdentifier,
+};
+
+use crate::tests::{client::Client, fixture};
+
+fn check(fixture: &str) -> Vec<InlayHint> {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
+
+ let fixture = fixture::parse(fixture);
+ let uri = client.uri(fixture.files[0].name);
+
+ for file in fixture.files {
+ client.open(file.name, file.lang, file.text);
+ }
+
+ let actual_hints = client
+ .request::<InlayHintRequest>(InlayHintParams {
+ text_document: TextDocumentIdentifier::new(uri),
+ range: Range::new(Position::new(0, 0), Position::new(12, 0)),
+ work_done_progress_params: Default::default(),
+ })
+ .unwrap()
+ .unwrap_or_default();
+
+ client.shutdown();
+ actual_hints
+}
+
+#[test]
+fn label_definition() {
+ assert_json_snapshot!(check(
+ r#"
+%TEX main.tex
+%SRC \documentclass{article}
+%SRC \usepackage{caption}
+%SRC \begin{document}
+%SRC \section{Foo}\label{sec:foo}
+%SRC \section{Bar}\label{sec:bar}
+%SRC \subsection{Baz}\label{sec:baz}
+%SRC \begin{figure}
+%SRC Test
+%SRC \label{fig:qux}
+%SRC \caption{Qux}
+%SRC \end{figure}
+%SRC \end{document}
+
+%TEX main.aux
+%SRC \relax
+%SRC \providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}}
+%SRC \newlabel{fig:qux}{{\caption@xref {fig:qux}{ on input line 15}}{1}}
+%SRC \@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Qux\relax }}{1}{}\protected@file@percent }
+%SRC \@writefile{toc}{\contentsline {section}{\numberline {1}Foo}{1}{}\protected@file@percent }
+%SRC \newlabel{sec:foo}{{1}{1}}
+%SRC \@writefile{toc}{\contentsline {section}{\numberline {2}Bar}{1}{}\protected@file@percent }
+%SRC \newlabel{sec:bar}{{2}{1}}
+%SRC \@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Baz}{1}{}\protected@file@percent }
+%SRC \newlabel{sec:baz}{{2.1}{1}}
+%SRC \gdef \@abspage@last{1}
+"#,
+ ));
+}
diff --git a/support/texlab/tests/integration/lsp/text_document/references.rs b/support/texlab/src/tests/text_document/references.rs
index ff272673dd..a0ebed1fb4 100644
--- a/support/texlab/tests/integration/lsp/text_document/references.rs
+++ b/support/texlab/src/tests/text_document/references.rs
@@ -1,45 +1,41 @@
-use anyhow::Result;
use assert_unordered::assert_eq_unordered;
use lsp_types::{
request::References, ClientCapabilities, Location, ReferenceContext, ReferenceParams,
};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
-fn check(fixture: &str, context: ReferenceContext) -> Result<()> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn check(fixture: &str, context: ReferenceContext) {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let mut expected_locations = Vec::new();
for ranges in fixture.ranges.values() {
- expected_locations.push(Location::new(
- client.uri(ranges[&1].name)?,
- ranges[&1].range,
- ));
+ expected_locations.push(Location::new(client.uri(ranges[&1].name), ranges[&1].range));
}
let actual_locations = client
.request::<References>(ReferenceParams {
- text_document_position: fixture.cursor.unwrap().into_params(&client)?,
+ text_document_position: fixture.cursor.unwrap().into_params(&client),
context,
partial_result_params: Default::default(),
work_done_progress_params: Default::default(),
- })?
+ })
+ .unwrap()
.unwrap_or_default();
- client.shutdown()?;
+ client.shutdown();
assert_eq_unordered!(actual_locations, expected_locations);
- Ok(())
}
#[test]
-fn entry_definition() -> Result<()> {
+fn entry_definition() {
check(
r#"
%BIB foo.bib
@@ -58,7 +54,7 @@ fn entry_definition() -> Result<()> {
}
#[test]
-fn entry_definition_include_decl() -> Result<()> {
+fn entry_definition_include_decl() {
check(
r#"
%BIB foo.bib
@@ -78,7 +74,7 @@ fn entry_definition_include_decl() -> Result<()> {
}
#[test]
-fn entry_reference() -> Result<()> {
+fn entry_reference() {
check(
r#"
%BIB foo.bib
@@ -97,7 +93,7 @@ fn entry_reference() -> Result<()> {
}
#[test]
-fn entry_reference_include_decl() -> Result<()> {
+fn entry_reference_include_decl() {
check(
r#"
%BIB foo.bib
@@ -117,7 +113,7 @@ fn entry_reference_include_decl() -> Result<()> {
}
#[test]
-fn label_definition() -> Result<()> {
+fn label_definition() {
check(
r#"
%TEX foo.tex
@@ -136,7 +132,7 @@ fn label_definition() -> Result<()> {
}
#[test]
-fn label_definition_include_decl() -> Result<()> {
+fn label_definition_include_decl() {
check(
r#"
%TEX foo.tex
@@ -156,7 +152,7 @@ fn label_definition_include_decl() -> Result<()> {
}
#[test]
-fn label_reference() -> Result<()> {
+fn label_reference() {
check(
r#"
%TEX foo.tex
@@ -180,7 +176,7 @@ fn label_reference() -> Result<()> {
}
#[test]
-fn label_reference_include_decl() -> Result<()> {
+fn label_reference_include_decl() {
check(
r#"
%TEX foo.tex
@@ -205,7 +201,7 @@ fn label_reference_include_decl() -> Result<()> {
}
#[test]
-fn string_reference() -> Result<()> {
+fn string_reference() {
check(
r#"
%BIB main.bib
@@ -222,7 +218,7 @@ fn string_reference() -> Result<()> {
}
#[test]
-fn string_reference_include_decl() -> Result<()> {
+fn string_reference_include_decl() {
check(
r#"
%BIB main.bib
@@ -240,7 +236,7 @@ fn string_reference_include_decl() -> Result<()> {
}
#[test]
-fn string_definition() -> Result<()> {
+fn string_definition() {
check(
r#"
%BIB main.bib
@@ -257,7 +253,7 @@ fn string_definition() -> Result<()> {
}
#[test]
-fn string_definition_include_decl() -> Result<()> {
+fn string_definition_include_decl() {
check(
r#"
%BIB main.bib
diff --git a/support/texlab/tests/integration/lsp/text_document/rename.rs b/support/texlab/src/tests/text_document/rename.rs
index 6b5a7e4978..2bbdfb1513 100644
--- a/support/texlab/tests/integration/lsp/text_document/rename.rs
+++ b/support/texlab/src/tests/text_document/rename.rs
@@ -1,43 +1,42 @@
use std::collections::HashMap;
-use anyhow::Result;
use lsp_types::{request::Rename, ClientCapabilities, RenameParams, TextEdit, Url, WorkspaceEdit};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
-fn check(fixture: &str, new_name: &str) -> Result<()> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn check(fixture: &str, new_name: &str) {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let mut expected_changes: HashMap<Url, Vec<TextEdit>> = HashMap::new();
for ranges in fixture.ranges.values() {
expected_changes
- .entry(client.uri(ranges[&1].name)?)
+ .entry(client.uri(ranges[&1].name))
.or_default()
.push(TextEdit::new(ranges[&1].range, new_name.to_string()));
}
let actual_edit = client
.request::<Rename>(RenameParams {
- text_document_position: fixture.cursor.unwrap().into_params(&client)?,
+ text_document_position: fixture.cursor.unwrap().into_params(&client),
new_name: new_name.to_string(),
work_done_progress_params: Default::default(),
- })?
+ })
+ .unwrap()
.unwrap_or_default();
- client.shutdown()?;
+ client.shutdown();
assert_eq!(actual_edit, WorkspaceEdit::new(expected_changes));
- Ok(())
}
#[test]
-fn command() -> Result<()> {
+fn command() {
check(
r#"
%TEX foo.tex
@@ -55,7 +54,7 @@ fn command() -> Result<()> {
}
#[test]
-fn entry() -> Result<()> {
+fn entry() {
check(
r#"
%BIB main.bib
@@ -73,7 +72,7 @@ fn entry() -> Result<()> {
}
#[test]
-fn citation() -> Result<()> {
+fn citation() {
check(
r#"
%BIB main.bib
@@ -91,7 +90,7 @@ fn citation() -> Result<()> {
}
#[test]
-fn label() -> Result<()> {
+fn label() {
check(
r#"
%TEX foo.tex
diff --git a/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_package_ref.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_package_ref.snap
new file mode 100644
index 0000000000..88ba06e91c
--- /dev/null
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_package_ref.snap
@@ -0,0 +1,16 @@
+---
+source: src/tests/text_document/completion.rs
+expression: "complete(r#\"\n%TEX main.tex\n%SRC \\acrodef{fpsLabel}[FPS]{Frames per Second}\n%SRC \\ac{f\n%CUR ^\n%1.1 ^\"#)?"
+---
+[
+ {
+ "kind": 1,
+ "label": "fpsLabel",
+ "preselect": false,
+ "sortText": "[sortText]",
+ "textEdit": {
+ "range": "[range]",
+ "newText": "fpsLabel"
+ }
+ }
+]
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_empty.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_empty.snap
index 33c5b459e1..65259d44a7 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_empty.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_empty.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 89
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n%SRC \\acrshort{}\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "fpsLabel",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_open_brace.snap
index 41a71b7951..f326640993 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_open_brace.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 117
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n%SRC \\acrshort{f\n%CUR ^\n%1.1 ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "fpsLabel",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_simple.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_simple.snap
index 3d31151a72..db7adf0259 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__acronym_ref_simple.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__acronym_ref_simple.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 75
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n%SRC \\acrshort{f}\n%CUR ^\n%1.1 ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "fpsLabel",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_empty.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_empty.snap
index 41c438baf6..75a73c5e32 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_empty.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_empty.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 159
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\mathbb{}\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "A",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\m
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "B",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\m
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "C",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\m
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "D",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\m
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "E",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_open_brace.snap
index 7009557720..dd33c0eac3 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_open_brace.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 186
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\mathbb{\n%CUR ^\n%SRC Test\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "A",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\m
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "B",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\m
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "C",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\m
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "D",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\m
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "E",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_word.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_word.snap
index 2ea7a4649d..cf88ba4b2b 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__argument_word.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__argument_word.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 172
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{amsfonts}\n%SRC \\mathbb{A}\n%CUR ^\n%1.1 ^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "A",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__begin_environment_without_snippet_support.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__begin_environment_without_snippet_support.snap
index 468ea3ea5f..167e764aef 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__begin_environment_without_snippet_support.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__begin_environment_without_snippet_support.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 215
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\beg\n%CUR ^\n%1.1 ^^^\"#)?"
---
[
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "begin",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\beg\n%CUR ^\n%1.1 ^^^\"#)
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "begingroup",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\beg\n%CUR ^\n%1.1 ^^^\"#)
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "AtBeginDocument",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\beg\n%CUR ^\n%1.1 ^^^\"#)
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "AtBeginDvi",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\beg\n%CUR ^\n%1.1 ^^^\"#)
}
},
{
- "data": "[data]",
"detail": "â‹€, built-in",
"documentation": "[documentation]",
"kind": 1,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation.snap
index 517df0a0df..70453476d5 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 228
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\documentclass{article}\n%SRC \\bibliography{main}\n%SRC \\begin{document}\n%SRC \\cite{\n%CUR ^\n%SRC \\end{document}\n\n%BIB main.bib\n%SRC @article{foo:2019,\n%SRC author = {Foo Bar},\n%SRC title = {Baz Qux},\n%SRC year = {2019},\n%SRC }\n%SRC \n%SRC @article{bar:2005,}\"#)?"
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_acronym.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_acronym.snap
index a679c4c42b..5cf8260317 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_acronym.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_acronym.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 286
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\addbibresource{main.bib}\n%SRC \\DeclareAcronym{foo}{cite={}}\n%CUR ^\n\n%BIB main.bib\n%SRC @article{foo,}\"#)?"
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_open_brace.snap
index cf2056b7e7..3143481442 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_open_brace.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 253
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\addbibresource{main.bib}\n%SRC \\cite{\n%CUR ^\n\n%BIB main.bib\n%SRC @article{foo,}\"#)?"
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_open_brace_multiple.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_open_brace_multiple.snap
index 7619c22002..21faa28ecc 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__citation_open_brace_multiple.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__citation_open_brace_multiple.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 269
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\addbibresource{main.bib}\n%SRC \\cite{foo,a\n%CUR ^\n%1.1 ^\n\n%BIB main.bib\n%SRC @article{foo,}\"#)?"
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_open_brace.snap
index 651c6e4f36..825d607885 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_open_brace.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 334
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "HTML",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "RGB",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "cmyk",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "gray",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "rgb",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_set_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_set_open_brace.snap
index 4fb23233c9..27dac7d130 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_set_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_set_open_brace.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 358
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "HTML",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "RGB",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "cmyk",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "gray",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "rgb",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_set_simple.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_set_simple.snap
index 4b7f137e4f..c2a2640786 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_set_simple.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_set_simple.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 346
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{}\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "HTML",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "RGB",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "cmyk",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "gray",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolorset{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "rgb",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_simple.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_simple.snap
index a160c859c3..da3431986d 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_model_definition_simple.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_model_definition_simple.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 322
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{}\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "HTML",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "RGB",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "cmyk",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "gray",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\definecolor{foo}{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "rgb",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_open_brace.snap
index df57a6e6ef..f2ae7d8db0 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_open_brace.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 395
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "Apricot",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Aquamarine",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Bittersweet",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Black",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Blue",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_simple.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_simple.snap
index fb4e2bee73..fc3db2911b 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_simple.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_simple.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 370
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{}\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "Apricot",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{}\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Aquamarine",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{}\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Bittersweet",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{}\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Black",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{}\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Blue",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_word.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_word.snap
index b730f14a42..cd671de9b9 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__color_word.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__color_word.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 382
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{re}\n%CUR ^\n%1.1 ^^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "red",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{re}\n%CUR ^\n%1.
}
},
{
- "data": "[data]",
"kind": 1,
"label": "Red",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{re}\n%CUR ^\n%1.
}
},
{
- "data": "[data]",
"kind": 1,
"label": "RedOrange",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{re}\n%CUR ^\n%1.
}
},
{
- "data": "[data]",
"kind": 1,
"label": "RedViolet",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\color{re}\n%CUR ^\n%1.
}
},
{
- "data": "[data]",
"kind": 1,
"label": "BrickRed",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_bibtex.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_bibtex.snap
index 545a13af3c..76dd1d07f8 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_bibtex.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_bibtex.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 446
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{b, \n%SRC c = {\\LaT }\n%CUR ^\n%1.1 ^^^\n%SRC }\"#)?"
---
[
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "LaTeX",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{b, \n%SRC c = {\\La
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "LaTeXe",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{b, \n%SRC c = {\\La
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "latexreleaseversion",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{b, \n%SRC c = {\\La
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "LastDeclaredEncoding",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{b, \n%SRC c = {\\La
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "last",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_simple.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_simple.snap
index 8414866ca1..c974de42b7 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_simple.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_simple.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 407
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "!",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"detail": "built-in",
"documentation": "[documentation]",
"kind": 1,
@@ -30,7 +27,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "#",
@@ -42,7 +38,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"detail": "$, built-in",
"documentation": "[documentation]",
"kind": 1,
@@ -55,7 +50,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "%",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_simple_package.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_simple_package.snap
index c08f480f7e..ada70e293a 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_command_simple_package.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_command_simple_package.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 432
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{lipsum}\n%SRC \\lips\n%CUR ^\n%1.1 ^^^^\"#)?"
---
[
{
- "data": "[data]",
"detail": "lipsum.sty",
"kind": 1,
"label": "lipsum",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{lipsum}\n%SRC \\lip
}
},
{
- "data": "[data]",
"detail": "lipsum.sty",
"kind": 1,
"label": "lipsumexp",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{lipsum}\n%SRC \\lip
}
},
{
- "data": "[data]",
"detail": "lipsum.sty",
"kind": 1,
"label": "LipsumPar",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{lipsum}\n%SRC \\lip
}
},
{
- "data": "[data]",
"detail": "lipsum.sty",
"kind": 1,
"label": "LipsumProtect",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{lipsum}\n%SRC \\lip
}
},
{
- "data": "[data]",
"detail": "lipsum.sty",
"kind": 1,
"label": "LipsumRestoreAll",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_class.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_class.snap
index ff16b8e7b6..bb409a442b 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_class.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_class.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 487
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\documentclass{article}\n%SRC \\begin{thein}\n%CUR ^\n%1.1 ^^^^^\"#)?"
---
[
{
- "data": "[data]",
"detail": "article.cls",
"kind": 1,
"label": "theindex",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_command_definition.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_command_definition.snap
index e07204dd14..d319eeb734 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_command_definition.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_command_definition.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 501
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\newcommand{\\foo}{\\begin{doc}\n%CUR ^\n%1.1 ^^^\"#)?"
---
[
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "document",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_simple.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_simple.snap
index 6c3be2426e..f6b8710db3 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_simple.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_simple.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 461
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\begin{doc\n%CUR ^\n%1.1 ^^^\"#)?"
---
[
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "document",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_simple_end.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_simple_end.snap
index af0e4ca762..e3ffa551d3 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__component_environment_simple_end.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__component_environment_simple_end.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 474
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\begin{document}\n%SRC \\end{\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "document",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\begin{document}\n%SRC \\end{\n
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "abstract",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\begin{document}\n%SRC \\end{\n
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "array",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\begin{document}\n%SRC \\end{\n
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "center",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\begin{document}\n%SRC \\end{\n
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "csname",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_after_preamble.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_after_preamble.snap
index 281254f2b8..5f29c307a7 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_after_preamble.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_after_preamble.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 565
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @preamble{\n%CUR ^\n%1.1 ^^^^^^^^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "preamble",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_after_string.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_after_string.snap
index 706bd78d07..5b18f17cfe 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_after_string.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_after_string.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 578
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @string{\n%CUR ^\n%1.1 ^^^^^^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "string",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_at_empty.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_at_empty.snap
index 19d2a451af..7928676b92 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_at_empty.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_at_empty.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 514
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "article",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "artwork",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "audio",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "bibnote",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @\n%CUR ^\"#)?"
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "book",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_article.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_article.snap
index 654258a594..1522a7594a 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_article.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_article.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 552
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @article\n%CUR ^\n%1.1 ^^^^^^^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "article",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_preamble.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_preamble.snap
index 6a4a79f14d..50e7a2162d 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_preamble.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_preamble.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 526
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @preamble\n%CUR ^\n%1.1 ^^^^^^^^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "preamble",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_string.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_string.snap
index b3b6f2928b..0c00ddd5fc 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_before_string.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_before_string.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 539
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @string\n%CUR ^\n%1.1 ^^^^^^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "string",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_complete_entry.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_complete_entry.snap
index 2a18a34789..6afb028f95 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__entry_type_complete_entry.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__entry_type_complete_entry.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 591
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = {foo}}\n%CUR ^\n%1.1 ^^^^^^^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "article",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_empty_entry_closed.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_empty_entry_closed.snap
index 10f3b1d89a..86a6e06c89 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_empty_entry_closed.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_empty_entry_closed.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 616
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,}\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "abstract",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,}\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "addendum",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,}\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "address",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,}\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "afterword",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,}\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "annotation",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_empty_entry_open.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_empty_entry_open.snap
index bb8b03efda..75a242d25d 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_empty_entry_open.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_empty_entry_open.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 604
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "abstract",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "addendum",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "address",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "afterword",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo,\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "annotation",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_field_name.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_field_name.snap
index 32f1df6369..3178da8d07 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_field_name.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_field_name.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 628
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, a\n%CUR ^\n%1.1 ^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "abstract",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, a\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "addendum",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, a\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "address",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, a\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "afterword",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, a\n%CUR
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "annotation",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_two_fields_name_closed.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_two_fields_name_closed.snap
index e1c61bab4c..80595edf98 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_two_fields_name_closed.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_two_fields_name_closed.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 654
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit}\n%CUR ^\n%1.1 ^^^^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "edition",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "editor",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "editora",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "editoratype",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "editorb",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_two_fields_name_open.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_two_fields_name_open.snap
index b86d4e96b0..8de75313e8 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__field_entry_two_fields_name_open.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__field_entry_two_fields_name_open.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 641
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit\n%CUR ^\n%1.1 ^^^^\"#)?"
---
[
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "edition",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "editor",
@@ -29,7 +26,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "editora",
@@ -41,7 +37,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "editoratype",
@@ -53,7 +48,6 @@ expression: "complete(r#\"\n%BIB main.bib\n%SRC @article{foo, author = bar, edit
}
},
{
- "data": "[data]",
"documentation": "[documentation]",
"kind": 1,
"label": "editorb",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__glossary_ref_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__glossary_ref_open_brace.snap
index 25c90c0a4e..36a77e92e5 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__glossary_ref_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__glossary_ref_open_brace.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 145
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n%SRC \\gls{f\n%CUR ^\n%1.1 ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "fpsLabel",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__glossary_ref_simple.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__glossary_ref_simple.snap
index a9c8bc5478..7a4d9a584b 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__glossary_ref_simple.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__glossary_ref_simple.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 131
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\newacronym[longplural={Frames per Second}]{fpsLabel}{FPS}{Frame per Second}\n%SRC \\gls{f}\n%CUR ^\n%1.1 ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "fpsLabel",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_class_closed_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_class_closed_brace.snap
index 1b15dff00b..f346f67f41 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_class_closed_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_class_closed_brace.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 706
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\documentclass{art}\n%CUR ^\n%1.1 ^^^\"#)?"
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_class_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_class_open_brace.snap
index 4118d60707..0d236ae496 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_class_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_class_open_brace.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 693
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\documentclass{art \\foo\n%CUR ^\n%1.1 ^^^\"#)?"
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_package_closed_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_package_closed_brace.snap
index 141441047f..2952c5d401 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_package_closed_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_package_closed_brace.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 680
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{lips}\n%CUR ^\n%1.1 ^^^^\"#)?"
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_package_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_package_open_brace.snap
index c188633107..349830d5f2 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__import_package_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__import_package_open_brace.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 667
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepackage{lips\n%CUR ^\n%1.1 ^^^^\"#)?"
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__label.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__label.snap
index e30dd28ab9..a4b26aa41d 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__label.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__label.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 719
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX foo.tex\n%SRC \\documentclass{article}\n%SRC \n%SRC \\usepackage{amsmath}\n%SRC \\usepackage{caption}\n%SRC \\usepackage{amsthm}\n%SRC \\newtheorem{lemma}{Lemma}\n%SRC \n%SRC \\begin{document}\n%SRC \n%SRC \\section{Foo}%\n%SRC \\label{sec:foo}\n%SRC \n%SRC \\begin{equation}%\n%SRC \\label{eq:foo}\n%SRC 1 + 1 = 2\n%SRC \\end{equation}\n%SRC \n%SRC \\begin{equation}%\n%SRC \\label{eq:bar}\n%SRC 1 + 1 = 2\n%SRC \\end{equation}\n%SRC \n%SRC \\begin{figure}%\n%SRC \\LaTeX{}\n%SRC \\caption{Baz}%\n%SRC \\label{fig:baz}\n%SRC \\end{figure}\n%SRC \n%SRC \\begin{lemma}%\n%SRC \\label{thm:foo}\n%SRC 1 + 1 = 2\n%SRC \\end{lemma}\n%SRC \n%SRC \\include{bar}\n%SRC \n%SRC \\end{document}\n\n%TEX bar.tex\n%SRC \\section{Bar}%\n%SRC \\label{sec:bar}\n%SRC \n%SRC Lorem ipsum dolor sit amet.\n%SRC \\ref{}\n%CUR ^\n\n%TEX foo.aux\n%SRC \\relax\n%SRC \\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Baz\\relax }}{1}\\protected@file@percent }\n%SRC \\providecommand*\\caption@xref[2]{\\@setref\\relax\\@undefined{#1}}\n%SRC \\newlabel{fig:baz}{{1}{1}}\n%SRC \\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}\\protected@file@percent }\n%SRC \\newlabel{sec:foo}{{1}{1}}\n%SRC \\newlabel{eq:foo}{{1}{1}}\n%SRC \\newlabel{eq:bar}{{2}{1}}\n%SRC \\newlabel{thm:foo}{{1}{1}}\n%SRC \\@input{bar.aux}\"#)?"
---
[
{
- "data": "[data]",
"detail": "Equation (2)",
"filterText": "eq:bar Equation (2)",
"kind": 1,
@@ -18,7 +16,6 @@ expression: "complete(r#\"\n%TEX foo.tex\n%SRC \\documentclass{article}\n%SRC \n
}
},
{
- "data": "[data]",
"detail": "Equation (1)",
"filterText": "eq:foo Equation (1)",
"kind": 1,
@@ -31,7 +28,6 @@ expression: "complete(r#\"\n%TEX foo.tex\n%SRC \\documentclass{article}\n%SRC \n
}
},
{
- "data": "[data]",
"detail": "Figure 1",
"documentation": "[documentation]",
"filterText": "fig:baz Figure 1: Baz",
@@ -45,7 +41,6 @@ expression: "complete(r#\"\n%TEX foo.tex\n%SRC \\documentclass{article}\n%SRC \n
}
},
{
- "data": "[data]",
"detail": "Section (Bar)",
"filterText": "sec:bar Section (Bar)",
"kind": 1,
@@ -58,7 +53,6 @@ expression: "complete(r#\"\n%TEX foo.tex\n%SRC \\documentclass{article}\n%SRC \n
}
},
{
- "data": "[data]",
"detail": "Section 1 (Foo)",
"filterText": "sec:foo Section 1 (Foo)",
"kind": 1,
diff --git a/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__project_resolution.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__project_resolution.snap
new file mode 100644
index 0000000000..5ee9c3c207
--- /dev/null
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__project_resolution.snap
@@ -0,0 +1,61 @@
+---
+source: src/tests/text_document/completion.rs
+expression: "complete(r#\"\n%TEX main.tex\n%SRC \\documentclass{article}\n%SRC \\import{sub}{sub/sub.tex}\n%SRC \\lipsu\n%CUR ^\n%1.1 ^^^^^\n\n%TEX sub/sub.tex\n%SRC \\input{child.tex}\n\n%TEX sub/child.tex\n%SRC \\usepackage{lipsum}\n\n\"#)"
+---
+[
+ {
+ "detail": "lipsum.sty",
+ "kind": 1,
+ "label": "lipsum",
+ "preselect": false,
+ "sortText": "[sortText]",
+ "textEdit": {
+ "range": "[range]",
+ "newText": "lipsum"
+ }
+ },
+ {
+ "detail": "lipsum.sty",
+ "kind": 1,
+ "label": "lipsumexp",
+ "preselect": false,
+ "sortText": "[sortText]",
+ "textEdit": {
+ "range": "[range]",
+ "newText": "lipsumexp"
+ }
+ },
+ {
+ "detail": "lipsum.sty",
+ "kind": 1,
+ "label": "LipsumPar",
+ "preselect": false,
+ "sortText": "[sortText]",
+ "textEdit": {
+ "range": "[range]",
+ "newText": "LipsumPar"
+ }
+ },
+ {
+ "detail": "lipsum.sty",
+ "kind": 1,
+ "label": "LipsumProtect",
+ "preselect": false,
+ "sortText": "[sortText]",
+ "textEdit": {
+ "range": "[range]",
+ "newText": "LipsumProtect"
+ }
+ },
+ {
+ "detail": "lipsum.sty",
+ "kind": 1,
+ "label": "LipsumRestoreAll",
+ "preselect": false,
+ "sortText": "[sortText]",
+ "textEdit": {
+ "range": "[range]",
+ "newText": "LipsumRestoreAll"
+ }
+ }
+]
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__theorem_begin.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__theorem_begin.snap
index b6964fe89c..a4de708b1b 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__theorem_begin.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__theorem_begin.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 785
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\newtheorem{lemma}{Lemma}\n%SRC \\begin{lem \n%CUR ^\n%1.1 ^^^\"#)?"
---
[
{
- "data": "[data]",
"detail": "user-defined",
"kind": 1,
"label": "lemma",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__theorem_end.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__theorem_end.snap
index 60fdc37edb..0c2c20083e 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__theorem_end.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__theorem_end.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 799
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\newtheorem{lemma}{Lemma}\n%SRC \\begin{}\n%SRC \\end{lem\n%CUR ^\n%1.1 ^^^\"#)?"
---
[
{
- "data": "[data]",
"detail": "user-defined",
"kind": 1,
"label": "lemma",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__tikz_library_closed_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__tikz_library_closed_brace.snap
index a1d7354f8f..f2a00d22bb 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__tikz_library_closed_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__tikz_library_closed_brace.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 826
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{}\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "arrows",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "arrows.meta",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "arrows.spaced",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "curvilinear",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{}\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "datavisualization.barcharts",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__tikz_library_open_brace.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__tikz_library_open_brace.snap
index 3c8a7a4b79..62bb3729b7 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__tikz_library_open_brace.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__tikz_library_open_brace.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 814
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{\n%CUR ^\"#)?"
---
[
{
- "data": "[data]",
"kind": 1,
"label": "arrows",
"preselect": false,
@@ -16,7 +14,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "arrows.meta",
"preselect": false,
@@ -27,7 +24,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "arrows.spaced",
"preselect": false,
@@ -38,7 +34,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "curvilinear",
"preselect": false,
@@ -49,7 +44,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\usepgflibrary{\n%CUR
}
},
{
- "data": "[data]",
"kind": 1,
"label": "datavisualization.barcharts",
"preselect": false,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__user_command.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__user_command.snap
index c5c6b741f3..fe0a397706 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__user_command.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__user_command.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 838
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\foobar\n%SRC \\fooba\n%CUR ^\n%1.1 ^^^^^\n%SRC \\begin{foo}\n%SRC \\end{foo}\n%SRC \\begin{fo}\n\"#)?"
---
[
{
- "data": "[data]",
"detail": "user-defined",
"kind": 1,
"label": "foobar",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__user_environment.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__user_environment.snap
index d760617880..7230e9a951 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__completion__user_environment.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__completion__user_environment.snap
@@ -1,11 +1,9 @@
---
-source: tests/integration/lsp/text_document/completion.rs
-assertion_line: 856
+source: src/tests/text_document/completion.rs
expression: "complete(r#\"\n%TEX main.tex\n%SRC \\foobar\n%SRC \\fooba\n%SRC \\begin{foo}\n%SRC \\end{foo}\n%SRC \\begin{fo}\n%CUR ^\n%1.1 ^^\n\"#)?"
---
[
{
- "data": "[data]",
"detail": "user-defined",
"kind": 1,
"label": "foo",
@@ -17,7 +15,6 @@ expression: "complete(r#\"\n%TEX main.tex\n%SRC \\foobar\n%SRC \\fooba\n%SRC \\b
}
},
{
- "data": "[data]",
"detail": "built-in",
"kind": 1,
"label": "filecontents",
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__did_change_configuration__invalid_configuration.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__did_change_configuration__invalid_configuration.snap
index 4f41cfbeb2..1400d80167 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__did_change_configuration__invalid_configuration.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__did_change_configuration__invalid_configuration.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/did_change_configuration.rs
-assertion_line: 37
+source: src/tests/text_document/did_change_configuration.rs
expression: message
---
The texlab configuration is invalid; using the default settings instead.
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__enumerate_flat.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__enumerate_flat.snap
index 3293d55600..4c5a17fb98 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__enumerate_flat.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__enumerate_flat.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 88
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__enumerate_nested.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__enumerate_nested.snap
index b2753ba69f..630311f32e 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__enumerate_nested.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__enumerate_nested.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 53
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__equation_flat.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__equation_flat.snap
index b1a4630dab..24ab44c772 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__equation_flat.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__equation_flat.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 156
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__equation_nested.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__equation_nested.snap
index fc707bd031..2efe7a4796 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__equation_nested.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__equation_nested.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 117
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__float_flat.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__float_flat.snap
index da456f914e..3d2537d85b 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__float_flat.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__float_flat.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 238
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__float_nested.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__float_nested.snap
index 4f60c21c92..18c5f3ca93 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__float_nested.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__float_nested.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 189
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__section_flat.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__section_flat.snap
index 85e72e90e1..87ff442db1 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__section_flat.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__section_flat.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 316
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__section_nested.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__section_nested.snap
index 97ae75eac4..bf4fea547e 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__section_nested.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__section_nested.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 281
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__theorem_flat.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__theorem_flat.snap
index 9af601da0d..d033c3ca62 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__theorem_flat.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__theorem_flat.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 391
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__theorem_nested.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__theorem_nested.snap
index 6a81f96fa6..22844dd700 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__document_symbol__theorem_nested.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__document_symbol__theorem_nested.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/document_symbol.rs
-assertion_line: 345
+source: src/tests/text_document/document_symbol.rs
expression: result.response
---
[
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_command.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_command.snap
index 1add9efc6a..c7d1491245 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_command.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_command.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 96
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @article{foo, bar = \"\\baz\",}\"#)?"
---
@article{foo,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_insert_braces.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_insert_braces.snap
index ee9be8c822..d05b077188 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_insert_braces.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_insert_braces.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 85
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @article{foo, bar = baz,\"#)?"
---
@article{foo,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_join_strings.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_join_strings.snap
index 8c2a21f579..8fb3765129 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_join_strings.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_join_strings.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 107
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @article{foo, bar = \"baz\" # \"qux\"}\"#)?"
---
@article{foo,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_multiple_entries.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_multiple_entries.snap
index cf228db867..2496f9b5e5 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_multiple_entries.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_multiple_entries.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 59
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, \n%SRC consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}\n%SRC \n%SRC @article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, \n%SRC consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}\"\"#)?"
---
@article{foo,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_parens.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_parens.snap
index 58e98f7ba5..883b97b375 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_parens.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_parens.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 118
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @article(foo,)\"#)?"
---
@article{foo,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_preamble.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_preamble.snap
index a82706dbf6..fdac219c35 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_preamble.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_preamble.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 140
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @preamble{\n%SRC \"foo bar baz\" }\"#)?"
---
@preamble{"foo bar baz"}
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_string.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_string.snap
index 3234fca52c..8f9589773e 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_string.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_string.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 129
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @string{foo=\"bar\"}\"#)?"
---
@string{foo = "bar"}
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_trailing_comma.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_trailing_comma.snap
index 1231f1795f..1051e00cf3 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_trailing_comma.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_trailing_comma.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 74
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @article{foo, bar = baz}\"#)?"
---
@article{foo,
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_wrap_long_lines.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_wrap_long_lines.snap
index fd9355025c..e7e1f39386 100644
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__formatting__bibtex_internal_wrap_long_lines.snap
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__formatting__bibtex_internal_wrap_long_lines.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/text_document/formatting.rs
-assertion_line: 46
+source: src/tests/text_document/formatting.rs
expression: "format(r#\"\n%BIB main.bib\n%SRC @article{foo, bar = {Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n%SRC Lorem ipsum dolor sit amet,\n%SRC consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit.},}\"#)?"
---
@article{foo,
diff --git a/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__inlay_hint__label_definition.snap b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__inlay_hint__label_definition.snap
new file mode 100644
index 0000000000..ff04d65efb
--- /dev/null
+++ b/support/texlab/src/tests/text_document/snapshots/texlab__tests__text_document__inlay_hint__label_definition.snap
@@ -0,0 +1,38 @@
+---
+source: src/tests/text_document/inlay_hint.rs
+expression: "check(r#\"\n%TEX main.tex\n%SRC \\documentclass{article}\n%SRC \\usepackage{caption}\n%SRC \\begin{document}\n%SRC \\section{Foo}\\label{sec:foo}\n%SRC \\section{Bar}\\label{sec:bar}\n%SRC \\subsection{Baz}\\label{sec:baz}\n%SRC \\begin{figure}\n%SRC Test\n%SRC \\label{fig:qux}\n%SRC \\caption{Qux}\n%SRC \\end{figure}\n%SRC \\end{document}\n\n%TEX main.aux\n%SRC \\relax \n%SRC \\providecommand*\\caption@xref[2]{\\@setref\\relax\\@undefined{#1}}\n%SRC \\newlabel{fig:qux}{{\\caption@xref {fig:qux}{ on input line 15}}{1}}\n%SRC \\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Qux\\relax }}{1}{}\\protected@file@percent }\n%SRC \\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}{}\\protected@file@percent }\n%SRC \\newlabel{sec:foo}{{1}{1}}\n%SRC \\@writefile{toc}{\\contentsline {section}{\\numberline {2}Bar}{1}{}\\protected@file@percent }\n%SRC \\newlabel{sec:bar}{{2}{1}}\n%SRC \\@writefile{toc}{\\contentsline {subsection}{\\numberline {2.1}Baz}{1}{}\\protected@file@percent }\n%SRC \\newlabel{sec:baz}{{2.1}{1}}\n%SRC \\gdef \\@abspage@last{1}\n\"#)?"
+---
+[
+ {
+ "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
+ }
+]
diff --git a/support/texlab/tests/integration/lsp/workspace.rs b/support/texlab/src/tests/workspace.rs
index 15e0679dea..15e0679dea 100644
--- a/support/texlab/tests/integration/lsp/workspace.rs
+++ b/support/texlab/src/tests/workspace.rs
diff --git a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_bibtex.snap b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_bibtex.snap
index 8b71b0519e..16963641bf 100644
--- a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_bibtex.snap
+++ b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_bibtex.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/workspace/symbol.rs
-assertion_line: 145
+source: src/tests/workspace/symbol.rs
expression: result.actual_symbols
---
[
diff --git a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_figure.snap b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_figure.snap
index a2343d994b..1b1d2371a4 100644
--- a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_figure.snap
+++ b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_figure.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/workspace/symbol.rs
-assertion_line: 127
+source: src/tests/workspace/symbol.rs
expression: result.actual_symbols
---
[
diff --git a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_item.snap b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_item.snap
index 37dad570c9..ed45c13cf1 100644
--- a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_item.snap
+++ b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_item.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/workspace/symbol.rs
-assertion_line: 133
+source: src/tests/workspace/symbol.rs
expression: result.actual_symbols
---
[
diff --git a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_math.snap b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_math.snap
index 8b98b614a3..d4cea99cc5 100644
--- a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_math.snap
+++ b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_math.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/workspace/symbol.rs
-assertion_line: 139
+source: src/tests/workspace/symbol.rs
expression: result.actual_symbols
---
[
diff --git a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_section.snap b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_section.snap
index b4974c9d7f..3a3ef78ab2 100644
--- a/support/texlab/tests/integration/lsp/workspace/snapshots/integration__lsp__workspace__symbol__filter_type_section.snap
+++ b/support/texlab/src/tests/workspace/snapshots/texlab__tests__workspace__symbol__filter_type_section.snap
@@ -1,6 +1,5 @@
---
-source: tests/integration/lsp/workspace/symbol.rs
-assertion_line: 121
+source: src/tests/workspace/symbol.rs
expression: result.actual_symbols
---
[
diff --git a/support/texlab/tests/integration/lsp/workspace/symbol.rs b/support/texlab/src/tests/workspace/symbol.rs
index 0af7534af3..626cce3c0b 100644
--- a/support/texlab/tests/integration/lsp/workspace/symbol.rs
+++ b/support/texlab/src/tests/workspace/symbol.rs
@@ -1,23 +1,22 @@
-use anyhow::Result;
use insta::{assert_json_snapshot, internals::Redaction};
use lsp_types::{
request::WorkspaceSymbol, ClientCapabilities, SymbolInformation, Url, WorkspaceSymbolParams,
};
-use crate::lsp::{client::Client, fixture};
+use crate::tests::{client::Client, fixture};
struct SymbolResult {
actual_symbols: Vec<SymbolInformation>,
uri_redaction: Redaction,
}
-fn find_symbols(fixture: &str, query: &str) -> Result<SymbolResult> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
+fn find_symbols(fixture: &str, query: &str) -> SymbolResult {
+ let mut client = Client::spawn();
+ client.initialize(ClientCapabilities::default(), None);
let fixture = fixture::parse(fixture);
for file in fixture.files {
- client.open(file.name, file.lang, file.text)?;
+ client.open(file.name, file.lang, file.text);
}
let actual_symbols = client
@@ -25,20 +24,21 @@ fn find_symbols(fixture: &str, query: &str) -> Result<SymbolResult> {
query: query.to_string(),
work_done_progress_params: Default::default(),
partial_result_params: Default::default(),
- })?
+ })
+ .unwrap()
.unwrap_or_default();
- let result = client.shutdown()?;
+ let result = client.shutdown();
let uri = Url::from_directory_path(result.directory.path()).unwrap();
let uri_redaction = insta::dynamic_redaction(move |content, _path| {
content.as_str().unwrap().replace(uri.as_str(), "[tmp]/")
});
- Ok(SymbolResult {
+ SymbolResult {
actual_symbols,
uri_redaction,
- })
+ }
}
macro_rules! assert_symbols {
@@ -117,31 +117,26 @@ const FIXTURE: &str = r#"
%SRC @string{bar = "bar"}"#;
#[test]
-fn filter_type_section() -> Result<()> {
- assert_symbols!(find_symbols(FIXTURE, "section")?);
- Ok(())
+fn filter_type_section() {
+ assert_symbols!(find_symbols(FIXTURE, "section"));
}
#[test]
-fn filter_type_figure() -> Result<()> {
- assert_symbols!(find_symbols(FIXTURE, "figure")?);
- Ok(())
+fn filter_type_figure() {
+ assert_symbols!(find_symbols(FIXTURE, "figure"));
}
#[test]
-fn filter_type_item() -> Result<()> {
- assert_symbols!(find_symbols(FIXTURE, "item")?);
- Ok(())
+fn filter_type_item() {
+ assert_symbols!(find_symbols(FIXTURE, "item"));
}
#[test]
-fn filter_type_math() -> Result<()> {
- assert_symbols!(find_symbols(FIXTURE, "math")?);
- Ok(())
+fn filter_type_math() {
+ assert_symbols!(find_symbols(FIXTURE, "math"));
}
#[test]
-fn filter_bibtex() -> Result<()> {
- assert_symbols!(find_symbols(FIXTURE, "bibtex")?);
- Ok(())
+fn filter_bibtex() {
+ assert_symbols!(find_symbols(FIXTURE, "bibtex"));
}
diff --git a/support/texlab/src/util.rs b/support/texlab/src/util.rs
new file mode 100644
index 0000000000..1c4d55a19d
--- /dev/null
+++ b/support/texlab/src/util.rs
@@ -0,0 +1,15 @@
+pub mod capabilities;
+pub mod chktex;
+pub mod components;
+pub mod cursor;
+pub mod label;
+pub mod lang_data;
+pub mod line_index;
+pub mod line_index_ext;
+pub mod lsp_enums;
+
+use std::path::PathBuf;
+
+use once_cell::sync::Lazy;
+
+pub static HOME_DIR: Lazy<Option<PathBuf>> = Lazy::new(|| dirs::home_dir());
diff --git a/support/texlab/src/capabilities.rs b/support/texlab/src/util/capabilities.rs
index bcb5bbba8b..987c0b48dd 100644
--- a/support/texlab/src/capabilities.rs
+++ b/support/texlab/src/util/capabilities.rs
@@ -7,6 +7,8 @@ pub trait ClientCapabilitiesExt {
fn has_work_done_progress_support(&self) -> bool;
+ fn has_completion_markdown_support(&self) -> bool;
+
fn has_hover_markdown_support(&self) -> bool;
fn has_pull_configuration_support(&self) -> bool;
@@ -14,6 +16,8 @@ pub trait ClientCapabilitiesExt {
fn has_push_configuration_support(&self) -> bool;
fn has_file_watching_support(&self) -> bool;
+
+ fn has_snippet_support(&self) -> bool;
}
impl ClientCapabilitiesExt for ClientCapabilities {
@@ -37,13 +41,21 @@ impl ClientCapabilitiesExt for ClientCapabilities {
self.window.as_ref().and_then(|cap| cap.work_done_progress) == Some(true)
}
+ fn has_completion_markdown_support(&self) -> bool {
+ self.text_document
+ .as_ref()
+ .and_then(|cap| cap.completion.as_ref())
+ .and_then(|cap| cap.completion_item.as_ref())
+ .and_then(|cap| cap.documentation_format.as_ref())
+ .map_or(false, |formats| formats.contains(&MarkupKind::Markdown))
+ }
+
fn has_hover_markdown_support(&self) -> bool {
self.text_document
.as_ref()
.and_then(|cap| cap.hover.as_ref())
.and_then(|cap| cap.content_format.as_ref())
- .filter(|formats| formats.contains(&MarkupKind::Markdown))
- .is_some()
+ .map_or(false, |formats| formats.contains(&MarkupKind::Markdown))
}
fn has_pull_configuration_support(&self) -> bool {
@@ -65,6 +77,15 @@ impl ClientCapabilitiesExt for ClientCapabilities {
.and_then(|cap| cap.dynamic_registration)
== Some(true)
}
+
+ fn has_snippet_support(&self) -> bool {
+ self.text_document
+ .as_ref()
+ .and_then(|cap| cap.completion.as_ref())
+ .and_then(|cap| cap.completion_item.as_ref())
+ .and_then(|cap| cap.snippet_support)
+ == Some(true)
+ }
}
#[cfg(test)]
diff --git a/support/texlab/src/util/chktex.rs b/support/texlab/src/util/chktex.rs
new file mode 100644
index 0000000000..29a7ac5630
--- /dev/null
+++ b/support/texlab/src/util/chktex.rs
@@ -0,0 +1,112 @@
+use std::{
+ io::{BufRead, BufReader, Write},
+ path::PathBuf,
+ process::Stdio,
+};
+
+use encoding_rs_io::DecodeReaderBytesBuilder;
+use lsp_types::{DiagnosticSeverity, Position, Range};
+use once_cell::sync::Lazy;
+use regex::Regex;
+
+use crate::{
+ db::{
+ diagnostics::{Diagnostic, DiagnosticCode},
+ Document, Workspace,
+ },
+ Db,
+};
+
+#[derive(Debug)]
+pub struct Command {
+ text: String,
+ working_dir: PathBuf,
+}
+
+impl Command {
+ pub fn new(db: &dyn Db, document: Document) -> Option<Self> {
+ document.parse(db).as_tex()?;
+
+ let workspace = Workspace::get(db);
+ let parent = workspace
+ .parents(db, document)
+ .iter()
+ .next()
+ .map_or(document, Clone::clone);
+
+ let working_dir = workspace
+ .working_dir(db, parent.directory(db))
+ .path(db)
+ .as_deref()?
+ .to_owned();
+
+ log::debug!("Calling ChkTeX from directory: {}", working_dir.display());
+
+ let text = document.contents(db).text(db).clone();
+
+ Some(Self { text, working_dir })
+ }
+
+ pub fn run(self) -> std::io::Result<Vec<Diagnostic>> {
+ let mut child = std::process::Command::new("chktex")
+ .args(&["-I0", "-f%l:%c:%d:%k:%n:%m\n"])
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::null())
+ .current_dir(self.working_dir)
+ .spawn()?;
+
+ let stdout = child.stdout.take().unwrap();
+ let reader = std::thread::spawn(move || {
+ let mut diagnostics = Vec::new();
+ let reader = BufReader::new(
+ DecodeReaderBytesBuilder::new()
+ .encoding(Some(encoding_rs::UTF_8))
+ .utf8_passthru(true)
+ .strip_bom(true)
+ .build(stdout),
+ );
+
+ for line in reader.lines().flatten() {
+ let captures = LINE_REGEX.captures(&line).unwrap();
+ let line = captures[1].parse::<u32>().unwrap() - 1;
+ let character = captures[2].parse::<u32>().unwrap() - 1;
+ let digit = captures[3].parse::<u32>().unwrap();
+ let kind = &captures[4];
+ let code = &captures[5];
+ let message = captures[6].into();
+ let range = Range::new(
+ Position::new(line, character),
+ Position::new(line, character + digit),
+ );
+
+ let severity = match kind {
+ "Message" => DiagnosticSeverity::INFORMATION,
+ "Warning" => DiagnosticSeverity::WARNING,
+ _ => DiagnosticSeverity::ERROR,
+ };
+
+ diagnostics.push(Diagnostic {
+ range,
+ severity,
+ code: DiagnosticCode::Chktex(code.into()),
+ message,
+ });
+ }
+
+ diagnostics
+ });
+
+ let mut stdin = child.stdin.take().unwrap();
+ let bytes = self.text.into_bytes();
+ let writer = std::thread::spawn(move || stdin.write_all(&bytes));
+
+ child.wait()?;
+ writer.join().unwrap()?;
+ let diagnostics = reader.join().unwrap();
+ Ok(diagnostics)
+ }
+}
+
+static LINE_REGEX: Lazy<Regex> =
+ Lazy::new(|| Regex::new("(\\d+):(\\d+):(\\d+):(\\w+):(\\w+):(.*)").unwrap());
diff --git a/support/texlab/src/util/components.rs b/support/texlab/src/util/components.rs
new file mode 100644
index 0000000000..022e7efbc8
--- /dev/null
+++ b/support/texlab/src/util/components.rs
@@ -0,0 +1,120 @@
+use std::io::Read;
+
+use flate2::read::GzDecoder;
+use itertools::Itertools;
+use lsp_types::{MarkupContent, MarkupKind};
+use once_cell::sync::Lazy;
+use serde::Deserialize;
+use smol_str::SmolStr;
+
+use crate::{
+ db::{analysis::TexLinkKind, Document, Workspace},
+ Db,
+};
+
+#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ComponentDatabase {
+ pub components: Vec<Component>,
+ pub metadata: Vec<ComponentMetadata>,
+}
+
+impl ComponentDatabase {
+ pub fn find(&self, name: &str) -> Option<&Component> {
+ self.components.iter().find(|component| {
+ component
+ .file_names
+ .iter()
+ .any(|file_name| file_name == name)
+ })
+ }
+
+ pub fn linked_components(&self, db: &dyn Db, child: Document) -> Vec<&Component> {
+ Workspace::get(db)
+ .related(db, child)
+ .iter()
+ .filter_map(|document| document.parse(db).as_tex())
+ .flat_map(|data| data.analyze(db).links(db))
+ .filter_map(|link| match link.kind(db) {
+ TexLinkKind::Sty => Some(format!("{}.sty", link.path(db).text(db))),
+ TexLinkKind::Cls => Some(format!("{}.cls", link.path(db).text(db))),
+ _ => None,
+ })
+ .filter_map(|name| self.find(&name))
+ .chain(std::iter::once(self.kernel()))
+ .flat_map(|comp| {
+ comp.references
+ .iter()
+ .filter_map(|name| self.find(name))
+ .chain(std::iter::once(comp))
+ })
+ .unique_by(|comp| &comp.file_names)
+ .collect()
+ }
+
+ pub fn kernel(&self) -> &Component {
+ self.components
+ .iter()
+ .find(|component| component.file_names.is_empty())
+ .unwrap()
+ }
+
+ pub fn documentation(&self, name: &str) -> Option<MarkupContent> {
+ let metadata = self
+ .metadata
+ .iter()
+ .find(|metadata| metadata.name == name)?;
+
+ let desc = metadata.description.clone()?;
+ Some(MarkupContent {
+ kind: MarkupKind::PlainText,
+ value: desc,
+ })
+ }
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Component {
+ pub file_names: Vec<SmolStr>,
+ pub references: Vec<SmolStr>,
+ pub commands: Vec<ComponentCommand>,
+ pub environments: Vec<SmolStr>,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ComponentCommand {
+ pub name: SmolStr,
+ pub image: Option<String>,
+ pub glyph: Option<SmolStr>,
+ pub parameters: Vec<ComponentParameter>,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ComponentParameter(pub Vec<ComponentArgument>);
+
+#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ComponentArgument {
+ pub name: SmolStr,
+ pub image: Option<String>,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ComponentMetadata {
+ pub name: String,
+ pub caption: Option<String>,
+ pub description: Option<String>,
+}
+
+const JSON_GZ: &[u8] = include_bytes!("../../data/components.json.gz");
+
+pub static COMPONENT_DATABASE: Lazy<ComponentDatabase> = Lazy::new(|| {
+ let mut decoder = GzDecoder::new(JSON_GZ);
+ let mut buf = String::new();
+ decoder.read_to_string(&mut buf).unwrap();
+ serde_json::from_str(&buf).unwrap()
+});
diff --git a/support/texlab/src/features/cursor.rs b/support/texlab/src/util/cursor.rs
index 84ee6e98c4..5c3758ef46 100644
--- a/support/texlab/src/features/cursor.rs
+++ b/support/texlab/src/util/cursor.rs
@@ -1,25 +1,23 @@
-use lsp_types::{
- CompletionParams, DocumentHighlightParams, GotoDefinitionParams, HoverParams, Position,
- ReferenceParams, RenameParams, TextDocumentPositionParams,
-};
+use lsp_types::{Position, Url};
use rowan::{ast::AstNode, TextRange, TextSize};
use crate::{
+ db::{parse::DocumentData, Document, Workspace},
syntax::{bibtex, latex},
- DocumentData, LineIndexExt,
+ Db,
};
-use super::FeatureRequest;
+use super::{line_index::LineIndex, line_index_ext::LineIndexExt};
#[derive(Debug)]
pub enum Cursor {
- Latex(latex::SyntaxToken),
- Bibtex(bibtex::SyntaxToken),
+ Tex(latex::SyntaxToken),
+ Bib(bibtex::SyntaxToken),
Nothing,
}
impl Cursor {
- pub fn new_latex(
+ pub fn new_tex(
left: Option<latex::SyntaxToken>,
right: Option<latex::SyntaxToken>,
) -> Option<Self> {
@@ -27,35 +25,35 @@ impl Cursor {
let right = right?;
if left.kind().is_command_name() {
- return Some(Self::Latex(left));
+ return Some(Self::Tex(left));
}
if right.kind() == latex::WORD {
- return Some(Self::Latex(right));
+ return Some(Self::Tex(right));
}
if left.kind() == latex::WORD {
- return Some(Self::Latex(left));
+ return Some(Self::Tex(left));
}
if right.kind().is_command_name() {
- return Some(Self::Latex(right));
+ return Some(Self::Tex(right));
}
if left.kind() == latex::WHITESPACE && left.parent()?.kind() == latex::KEY {
- return Some(Self::Latex(left));
+ return Some(Self::Tex(left));
}
if matches!(right.kind(), latex::WHITESPACE | latex::LINE_BREAK)
&& right.parent()?.kind() == latex::KEY
{
- return Some(Self::Latex(right));
+ return Some(Self::Tex(right));
}
- Some(Self::Latex(right))
+ Some(Self::Tex(right))
}
- pub fn new_bibtex(
+ pub fn new_bib(
left: Option<bibtex::SyntaxToken>,
right: Option<bibtex::SyntaxToken>,
) -> Option<Self> {
@@ -63,42 +61,42 @@ impl Cursor {
let right = right?;
if right.kind() == bibtex::TYPE {
- return Some(Self::Bibtex(right));
+ return Some(Self::Bib(right));
}
if left.kind() == bibtex::TYPE {
- return Some(Self::Bibtex(left));
+ return Some(Self::Bib(left));
}
if matches!(left.kind(), bibtex::COMMAND_NAME | bibtex::ACCENT_NAME) {
- return Some(Self::Bibtex(left));
+ return Some(Self::Bib(left));
}
if matches!(right.kind(), bibtex::WORD | bibtex::NAME) {
- return Some(Self::Bibtex(right));
+ return Some(Self::Bib(right));
}
if matches!(left.kind(), bibtex::WORD | bibtex::NAME) {
- return Some(Self::Bibtex(left));
+ return Some(Self::Bib(left));
}
if matches!(right.kind(), bibtex::COMMAND_NAME | bibtex::ACCENT_NAME) {
- return Some(Self::Bibtex(right));
+ return Some(Self::Bib(right));
}
- Some(Self::Bibtex(right))
+ Some(Self::Bib(right))
}
- pub fn as_latex(&self) -> Option<&latex::SyntaxToken> {
- if let Self::Latex(v) = self {
+ pub fn as_tex(&self) -> Option<&latex::SyntaxToken> {
+ if let Self::Tex(v) = self {
Some(v)
} else {
None
}
}
- pub fn as_bibtex(&self) -> Option<&bibtex::SyntaxToken> {
- if let Self::Bibtex(v) = self {
+ pub fn as_bib(&self) -> Option<&bibtex::SyntaxToken> {
+ if let Self::Bib(v) = self {
Some(v)
} else {
None
@@ -106,13 +104,13 @@ impl Cursor {
}
pub fn command_range(&self, offset: TextSize) -> Option<TextRange> {
- self.as_latex()
+ self.as_tex()
.filter(|token| token.kind().is_command_name())
.filter(|token| token.text_range().start() != offset)
.map(|token| token.text_range())
.map(|range| TextRange::new(range.start() + TextSize::from(1), range.end()))
.or_else(|| {
- self.as_bibtex()
+ self.as_bib()
.filter(|token| {
matches!(token.kind(), bibtex::COMMAND_NAME | bibtex::ACCENT_NAME)
})
@@ -123,40 +121,55 @@ impl Cursor {
}
}
-pub struct CursorContext<P> {
- pub request: FeatureRequest<P>,
+pub struct CursorContext<'db, T = ()> {
+ pub db: &'db dyn Db,
+ pub document: Document,
+ pub line_index: &'db LineIndex,
+ pub workspace: Workspace,
pub cursor: Cursor,
pub offset: TextSize,
+ pub params: T,
}
-impl<P: HasPosition> CursorContext<P> {
- pub fn new(request: FeatureRequest<P>) -> Self {
- let main_document = request.main_document();
- let offset = main_document
- .line_index
- .offset_lsp(request.params.position());
+impl<'db, T> CursorContext<'db, T> {
+ pub fn new(db: &'db dyn Db, uri: &Url, position: Position, params: T) -> Option<Self> {
+ let workspace = Workspace::get(db);
+ let document = workspace.lookup_uri(db, uri)?;
+ let line_index = document.contents(db).line_index(db);
+ let offset = line_index.offset_lsp(position);
- let cursor = match &main_document.data {
- DocumentData::Latex(data) => {
- let root = latex::SyntaxNode::new_root(data.green.clone());
+ let cursor = match document.parse(db) {
+ DocumentData::Tex(data) => {
+ let root = data.root(db);
let left = root.token_at_offset(offset).left_biased();
let right = root.token_at_offset(offset).right_biased();
- Cursor::new_latex(left, right)
+ Cursor::new_tex(left, right)
}
- DocumentData::Bibtex(data) => {
- let root = bibtex::SyntaxNode::new_root(data.green.clone());
+ DocumentData::Bib(data) => {
+ let root = data.root(db);
let left = root.token_at_offset(offset).left_biased();
let right = root.token_at_offset(offset).right_biased();
- Cursor::new_bibtex(left, right)
+ Cursor::new_bib(left, right)
}
- DocumentData::BuildLog(_) => None,
+ DocumentData::Log(_) => None,
};
- Self {
- request,
+ Some(Self {
+ db,
+ document,
+ line_index,
+ workspace,
cursor: cursor.unwrap_or(Cursor::Nothing),
offset,
- }
+ params,
+ })
+ }
+
+ pub fn related(&self) -> impl Iterator<Item = Document> + '_ {
+ self.workspace
+ .related(self.db, self.document)
+ .iter()
+ .copied()
}
pub fn is_inside_latex_curly(&self, group: &impl latex::HasCurly) -> bool {
@@ -166,7 +179,7 @@ impl<P: HasPosition> CursorContext<P> {
pub fn find_citation_key_word(&self) -> Option<(String, TextRange)> {
let word = self
.cursor
- .as_latex()
+ .as_tex()
.filter(|token| token.kind() == latex::WORD)?;
let key = latex::Key::cast(word.parent()?)?;
@@ -177,7 +190,7 @@ impl<P: HasPosition> CursorContext<P> {
}
pub fn find_citation_key_command(&self) -> Option<(String, TextRange)> {
- let command = self.cursor.as_latex()?;
+ let command = self.cursor.as_tex()?;
let citation = latex::Citation::cast(command.parent()?)?;
let key = citation.key_list()?.keys().next()?;
@@ -187,7 +200,7 @@ impl<P: HasPosition> CursorContext<P> {
pub fn find_entry_key(&self) -> Option<(String, TextRange)> {
let key = self
.cursor
- .as_bibtex()
+ .as_bib()
.filter(|token| token.kind() == bibtex::NAME)?;
bibtex::Entry::cast(key.parent()?)?;
@@ -197,7 +210,7 @@ impl<P: HasPosition> CursorContext<P> {
pub fn find_label_name_key(&self) -> Option<(String, TextRange)> {
let name = self
.cursor
- .as_latex()
+ .as_tex()
.filter(|token| token.kind() == latex::WORD)?;
let key = latex::Key::cast(name.parent()?)?;
@@ -213,7 +226,7 @@ impl<P: HasPosition> CursorContext<P> {
}
pub fn find_label_name_command(&self) -> Option<(String, TextRange)> {
- let node = self.cursor.as_latex()?.parent()?;
+ let node = self.cursor.as_tex()?.parent()?;
if let Some(label) = latex::LabelDefinition::cast(node.clone()) {
let name = label.name()?.key()?;
Some((name.to_string(), latex::small_range(&name)))
@@ -239,7 +252,7 @@ impl<P: HasPosition> CursorContext<P> {
}
pub fn find_curly_group_word(&self) -> Option<(String, TextRange, latex::CurlyGroupWord)> {
- let token = self.cursor.as_latex()?;
+ let token = self.cursor.as_tex()?;
let key = latex::Key::cast(token.parent()?);
let group = key
@@ -257,7 +270,7 @@ impl<P: HasPosition> CursorContext<P> {
pub fn find_curly_group_word_list(
&self,
) -> Option<(String, TextRange, latex::CurlyGroupWordList)> {
- let token = self.cursor.as_latex()?;
+ let token = self.cursor.as_tex()?;
let key = latex::Key::cast(token.parent()?);
let group = key
@@ -285,49 +298,3 @@ impl<P: HasPosition> CursorContext<P> {
.or_else(|| Some((String::new(), TextRange::empty(self.offset), group)))
}
}
-
-pub trait HasPosition {
- fn position(&self) -> Position;
-}
-
-impl HasPosition for CompletionParams {
- fn position(&self) -> Position {
- self.text_document_position.position
- }
-}
-
-impl HasPosition for TextDocumentPositionParams {
- fn position(&self) -> Position {
- self.position
- }
-}
-
-impl HasPosition for RenameParams {
- fn position(&self) -> Position {
- self.text_document_position.position
- }
-}
-
-impl HasPosition for ReferenceParams {
- fn position(&self) -> Position {
- self.text_document_position.position
- }
-}
-
-impl HasPosition for HoverParams {
- fn position(&self) -> Position {
- self.text_document_position_params.position
- }
-}
-
-impl HasPosition for GotoDefinitionParams {
- fn position(&self) -> Position {
- self.text_document_position_params.position
- }
-}
-
-impl HasPosition for DocumentHighlightParams {
- fn position(&self) -> Position {
- self.text_document_position_params.position
- }
-}
diff --git a/support/texlab/src/label.rs b/support/texlab/src/util/label.rs
index b66db836f2..f0fae34337 100644
--- a/support/texlab/src/label.rs
+++ b/support/texlab/src/util/label.rs
@@ -1,24 +1,26 @@
use std::str::FromStr;
-use lsp_types::{MarkupContent, MarkupKind};
use rowan::{ast::AstNode, TextRange};
use crate::{
+ db::{analysis::label, Document, Word, Workspace},
syntax::latex::{self, HasBrack, HasCurly},
- Workspace, LANGUAGE_DATA,
+ Db,
};
-use self::LabelledObject::*;
+use self::LabeledObject::*;
+
+use super::lang_data::LANGUAGE_DATA;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum LabelledFloatKind {
+pub enum LabeledFloatKind {
Figure,
Table,
Listing,
Algorithm,
}
-impl LabelledFloatKind {
+impl LabeledFloatKind {
pub fn as_str(self) -> &'static str {
match self {
Self::Figure => "Figure",
@@ -29,7 +31,7 @@ impl LabelledFloatKind {
}
}
-impl FromStr for LabelledFloatKind {
+impl FromStr for LabeledFloatKind {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -44,17 +46,17 @@ impl FromStr for LabelledFloatKind {
}
#[derive(Debug, PartialEq, Eq, Clone)]
-pub enum LabelledObject {
+pub enum LabeledObject {
Section {
prefix: &'static str,
text: String,
},
Float {
- kind: LabelledFloatKind,
+ kind: LabeledFloatKind,
caption: String,
},
Theorem {
- kind: String,
+ kind: Word,
description: Option<String>,
},
Equation,
@@ -64,27 +66,28 @@ pub enum LabelledObject {
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct RenderedLabel {
pub range: TextRange,
- pub number: Option<String>,
- pub object: LabelledObject,
+ pub number: Option<Word>,
+ pub object: LabeledObject,
}
impl RenderedLabel {
- #[must_use]
- pub fn reference(&self) -> String {
+ pub fn reference(&self, db: &dyn Db) -> String {
match &self.number {
Some(number) => match &self.object {
- Section { prefix, text } => format!("{} {} ({})", prefix, number, text),
- Float { kind, caption } => format!("{} {}: {}", kind.as_str(), number, caption),
+ Section { prefix, text } => format!("{} {} ({})", prefix, number.text(db), text),
+ Float { kind, caption } => {
+ format!("{} {}: {}", kind.as_str(), number.text(db), caption)
+ }
Theorem {
kind,
description: None,
- } => format!("{} {}", kind, number),
+ } => format!("{} {}", kind.text(db), number.text(db)),
Theorem {
kind,
description: Some(description),
- } => format!("{} {} ({})", kind, number, description),
- Equation => format!("Equation ({})", number),
- EnumItem => format!("Item {}", number),
+ } => format!("{} {} ({})", kind.text(db), number.text(db), description),
+ Equation => format!("Equation ({})", number.text(db)),
+ EnumItem => format!("Item {}", number.text(db)),
},
None => match &self.object {
Section { prefix, text } => format!("{} ({})", prefix, text),
@@ -92,117 +95,93 @@ impl RenderedLabel {
Theorem {
kind,
description: None,
- } => kind.into(),
+ } => kind.text(db).into(),
Theorem {
kind,
description: Some(description),
- } => format!("{} ({})", kind, description),
+ } => format!("{} ({})", kind.text(db), description),
Equation => "Equation".into(),
EnumItem => "Item".into(),
},
}
}
- #[must_use]
- pub fn detail(&self) -> Option<String> {
+ pub fn detail(&self, db: &dyn Db) -> Option<String> {
match &self.object {
- Section { .. } | Theorem { .. } | Equation | EnumItem => Some(self.reference()),
+ Section { .. } | Theorem { .. } | Equation | EnumItem => Some(self.reference(db)),
Float { kind, .. } => {
let result = match &self.number {
- Some(number) => format!("{} {}", kind.as_str(), number),
+ Some(number) => format!("{} {}", kind.as_str(), number.text(db)),
None => kind.as_str().to_owned(),
};
Some(result)
}
}
}
-
- #[must_use]
- pub fn documentation(&self) -> MarkupContent {
- MarkupContent {
- kind: MarkupKind::PlainText,
- value: self.reference(),
- }
- }
}
-pub fn render_label(
- workspace: &Workspace,
- label_name: &str,
- mut label: Option<latex::LabelDefinition>,
-) -> Option<RenderedLabel> {
- let mut number = find_label_number(workspace, label_name).map(ToString::to_string);
+pub fn render(db: &dyn Db, document: Document, label_def: label::Name) -> Option<RenderedLabel> {
+ let workspace = Workspace::get(db);
+ let label_num = workspace.number_of_label(db, document, label_def.name(db));
+ let root = document.parse(db).as_tex()?.root(db);
- for document in workspace.documents_by_uri.values() {
- if let Some(data) = document.data.as_latex() {
- label = label.or_else(|| {
- find_label_definition(&latex::SyntaxNode::new_root(data.green.clone()), label_name)
- });
- }
- }
-
- label?.syntax().ancestors().find_map(|parent| {
- render_label_float(parent.clone(), &mut number)
- .or_else(|| render_label_section(parent.clone(), &mut number))
- .or_else(|| render_label_enum_item(parent.clone(), &mut number))
- .or_else(|| render_label_equation(parent.clone(), &mut number))
- .or_else(|| render_label_theorem(workspace, parent, &mut number))
- })
+ label_def
+ .origin(db)
+ .as_definition()?
+ .to_node(&root)
+ .syntax()
+ .ancestors()
+ .find_map(|parent| {
+ render_label_float(parent.clone(), label_num)
+ .or_else(|| render_label_section(parent.clone(), label_num))
+ .or_else(|| render_label_enum_item(db, parent.clone(), label_num))
+ .or_else(|| render_label_equation(parent.clone(), label_num))
+ .or_else(|| render_label_theorem(db, document, parent, label_num))
+ })
}
pub fn find_label_definition(
- root: &latex::SyntaxNode,
- label_name: &str,
-) -> Option<latex::LabelDefinition> {
- root.descendants()
- .filter_map(latex::LabelDefinition::cast)
- .find(|label| {
- label
- .name()
- .and_then(|name| name.key())
- .map(|name| name.to_string())
- .as_deref()
- == Some(label_name)
- })
-}
+ db: &dyn Db,
+ child: Document,
+ name: Word,
+) -> Option<(Document, label::Name)> {
+ Workspace::get(db)
+ .related(db, child)
+ .iter()
+ .find_map(|document| {
+ let data = document.parse(db).as_tex()?;
+ let label = data
+ .analyze(db)
+ .labels(db)
+ .iter()
+ .filter(|label| label.origin(db).as_definition().is_some())
+ .find(|label| label.name(db) == name)?;
-pub fn find_label_number<'a>(workspace: &'a Workspace, label_name: &str) -> Option<&'a str> {
- workspace.documents_by_uri.values().find_map(|document| {
- document
- .data
- .as_latex()
- .and_then(|data| data.extras.label_numbers_by_name.get(label_name))
- .map(|number| number.as_str())
- })
+ Some((*document, *label))
+ })
}
-fn render_label_float(
- parent: latex::SyntaxNode,
- number: &mut Option<String>,
-) -> Option<RenderedLabel> {
+fn render_label_float(parent: latex::SyntaxNode, number: Option<Word>) -> Option<RenderedLabel> {
let environment = latex::Environment::cast(parent.clone())?;
let environment_name = environment.begin()?.name()?.key()?.to_string();
- let kind = LabelledFloatKind::from_str(&environment_name).ok()?;
+ let kind = LabeledFloatKind::from_str(&environment_name).ok()?;
let caption = find_caption_by_parent(&parent)?;
Some(RenderedLabel {
range: latex::small_range(&environment),
- number: number.take(),
- object: LabelledObject::Float { caption, kind },
+ number,
+ object: LabeledObject::Float { caption, kind },
})
}
-fn render_label_section(
- parent: latex::SyntaxNode,
- number: &mut Option<String>,
-) -> Option<RenderedLabel> {
+fn render_label_section(parent: latex::SyntaxNode, number: Option<Word>) -> Option<RenderedLabel> {
let section = latex::Section::cast(parent)?;
let text_group = section.name()?;
let text = text_group.content_text()?;
Some(RenderedLabel {
range: latex::small_range(&section),
- number: number.take(),
- object: LabelledObject::Section {
+ number,
+ object: LabeledObject::Section {
prefix: match section.syntax().kind() {
latex::PART => "Part",
latex::CHAPTER => "Chapter",
@@ -219,24 +198,23 @@ fn render_label_section(
}
fn render_label_enum_item(
+ db: &dyn Db,
parent: latex::SyntaxNode,
- number: &mut Option<String>,
+ number: Option<Word>,
) -> Option<RenderedLabel> {
let enum_item = latex::EnumItem::cast(parent)?;
Some(RenderedLabel {
range: latex::small_range(&enum_item),
number: enum_item
.label()
- .and_then(|number| number.content_text())
- .or_else(|| number.take()),
- object: LabelledObject::EnumItem,
+ .and_then(|label| label.content_text())
+ .map(|text| Word::new(db, text))
+ .or_else(|| number),
+ object: LabeledObject::EnumItem,
})
}
-fn render_label_equation(
- parent: latex::SyntaxNode,
- number: &mut Option<String>,
-) -> Option<RenderedLabel> {
+fn render_label_equation(parent: latex::SyntaxNode, number: Option<Word>) -> Option<RenderedLabel> {
let environment = latex::Environment::cast(parent)?;
let environment_name = environment.begin()?.name()?.key()?.to_string();
@@ -250,15 +228,16 @@ fn render_label_equation(
Some(RenderedLabel {
range: latex::small_range(&environment),
- number: number.take(),
- object: LabelledObject::Equation,
+ number,
+ object: LabeledObject::Equation,
})
}
fn render_label_theorem(
- workspace: &Workspace,
+ db: &dyn Db,
+ document: Document,
parent: latex::SyntaxNode,
- number: &mut Option<String>,
+ number: Option<Word>,
) -> Option<RenderedLabel> {
let environment = latex::Environment::cast(parent)?;
let begin = environment.begin()?;
@@ -266,22 +245,18 @@ fn render_label_theorem(
let environment_name = begin.name()?.key()?.to_string();
- let theorem = workspace.documents_by_uri.values().find_map(|document| {
- document.data.as_latex().and_then(|data| {
- data.extras
- .theorem_environments
- .iter()
- .find(|theorem| theorem.name.as_str() == environment_name)
- })
- })?;
+ let kind = Workspace::get(db)
+ .related(db, document)
+ .iter()
+ .filter_map(|document| document.parse(db).as_tex())
+ .flat_map(|data| data.analyze(db).theorem_environments(db))
+ .find(|env| env.name(db).text(db) == &environment_name)
+ .map(|env| env.description(db))?;
Some(RenderedLabel {
range: latex::small_range(&environment),
- number: number.take(),
- object: LabelledObject::Theorem {
- kind: theorem.description.clone(),
- description,
- },
+ number,
+ object: LabeledObject::Theorem { kind, description },
})
}
diff --git a/support/texlab/src/lang_data.rs b/support/texlab/src/util/lang_data.rs
index 28e6a540e0..f270c3f65e 100644
--- a/support/texlab/src/lang_data.rs
+++ b/support/texlab/src/util/lang_data.rs
@@ -65,6 +65,6 @@ impl LanguageData {
}
pub static LANGUAGE_DATA: Lazy<LanguageData> = Lazy::new(|| {
- const JSON: &str = include_str!("../data/lang_data.json");
+ const JSON: &str = include_str!("../../data/lang_data.json");
serde_json::from_str(JSON).expect("Failed to deserialize language.json")
});
diff --git a/support/texlab/src/line_index.rs b/support/texlab/src/util/line_index.rs
index 70e8f8128b..70e8f8128b 100644
--- a/support/texlab/src/line_index.rs
+++ b/support/texlab/src/util/line_index.rs
diff --git a/support/texlab/src/line_index_ext.rs b/support/texlab/src/util/line_index_ext.rs
index 9faccf1c86..becbb8bde7 100644
--- a/support/texlab/src/line_index_ext.rs
+++ b/support/texlab/src/util/line_index_ext.rs
@@ -1,7 +1,7 @@
use lsp_types::{Position, Range};
use rowan::{TextRange, TextSize};
-use crate::{LineColUtf16, LineIndex};
+use super::line_index::{LineColUtf16, LineIndex};
pub trait LineIndexExt {
fn offset_lsp(&self, line_col: Position) -> TextSize;
diff --git a/support/texlab/src/features/lsp_kinds.rs b/support/texlab/src/util/lsp_enums.rs
index 82706b5aee..75b97097c5 100644
--- a/support/texlab/src/features/lsp_kinds.rs
+++ b/support/texlab/src/util/lsp_enums.rs
@@ -1,6 +1,6 @@
use lsp_types::{CompletionItemKind, SymbolKind};
-use crate::BibtexEntryTypeCategory;
+use super::lang_data::BibtexEntryTypeCategory;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Structure {
diff --git a/support/texlab/src/workspace.rs b/support/texlab/src/workspace.rs
deleted file mode 100644
index e01a2fede4..0000000000
--- a/support/texlab/src/workspace.rs
+++ /dev/null
@@ -1,225 +0,0 @@
-use std::{
- fs::{self, FileType},
- path::PathBuf,
- sync::Arc,
-};
-
-use anyhow::Result;
-use crossbeam_channel::Sender;
-use lsp_types::Url;
-use petgraph::{graphmap::UnGraphMap, visit::Dfs};
-use rustc_hash::{FxHashMap, FxHashSet};
-
-use crate::{
- component_db::COMPONENT_DATABASE, syntax::latex::ExplicitLink, Document, DocumentLanguage,
- Environment,
-};
-
-#[derive(Debug, Clone)]
-pub enum WorkspaceEvent {
- Changed(Workspace, Document),
-}
-
-#[derive(Debug, Clone, Default)]
-pub struct Workspace {
- pub documents_by_uri: FxHashMap<Arc<Url>, Document>,
- pub viewport: FxHashSet<Arc<Url>>,
- pub listeners: Vec<Sender<WorkspaceEvent>>,
- pub environment: Environment,
-}
-
-impl Workspace {
- #[must_use]
- pub fn new(environment: Environment) -> Self {
- Self {
- environment,
- ..Self::default()
- }
- }
-
- pub fn open(
- &mut self,
- uri: Arc<Url>,
- text: Arc<String>,
- language: DocumentLanguage,
- ) -> Result<Document> {
- log::debug!("(Re)Loading document: {}", uri);
- let document = Document::parse(&self.environment, Arc::clone(&uri), text, language);
-
- self.documents_by_uri
- .insert(Arc::clone(&uri), document.clone());
-
- for listener in &self.listeners {
- listener.send(WorkspaceEvent::Changed(self.clone(), document.clone()))?;
- }
-
- self.expand_parent(&document);
- self.expand_children(&document);
- Ok(document)
- }
-
- pub fn reload(&mut self, path: PathBuf) -> Result<Option<Document>> {
- let uri = Arc::new(Url::from_file_path(path.clone()).unwrap());
-
- if self.is_open(&uri) && !uri.as_str().ends_with(".log") {
- return Ok(self.documents_by_uri.get(&uri).cloned());
- }
-
- if let Some(language) = DocumentLanguage::by_path(&path) {
- let data = fs::read(&path)?;
- let text = Arc::new(String::from_utf8_lossy(&data).into_owned());
- Ok(Some(self.open(uri, text, language)?))
- } else {
- Ok(None)
- }
- }
-
- pub fn load(&mut self, path: PathBuf) -> Result<Option<Document>> {
- let uri = Arc::new(Url::from_file_path(path.clone()).unwrap());
-
- if let Some(document) = self.documents_by_uri.get(&uri).cloned() {
- return Ok(Some(document));
- }
-
- let data = fs::read(&path)?;
- let text = Arc::new(String::from_utf8_lossy(&data).into_owned());
- if let Some(language) = DocumentLanguage::by_path(&path) {
- Ok(Some(self.open(uri, text, language)?))
- } else {
- Ok(None)
- }
- }
-
- pub fn close(&mut self, uri: &Url) {
- self.viewport.remove(uri);
- }
-
- pub fn is_open(&self, uri: &Url) -> bool {
- self.viewport.contains(uri)
- }
-
- pub fn slice(&self, uri: &Url) -> Self {
- let all_uris: Vec<_> = self.documents_by_uri.keys().cloned().collect();
-
- all_uris
- .iter()
- .position(|u| u.as_ref() == uri)
- .map(|start| {
- let mut edges = Vec::new();
- for (i, uri) in all_uris.iter().enumerate() {
- let document = self.documents_by_uri.get(uri);
- if let Some(data) = document
- .as_ref()
- .and_then(|document| document.data.as_latex())
- {
- let extras = &data.extras;
- let mut all_targets =
- vec![&extras.implicit_links.aux, &extras.implicit_links.log];
- for link in &extras.explicit_links {
- all_targets.push(&link.targets);
- }
-
- for targets in all_targets {
- for target in targets {
- if let Some(j) = all_uris.iter().position(|uri| uri == target) {
- edges.push((i, j, ()));
- break;
- }
- }
- }
- }
- }
-
- let mut slice = self.clone();
- slice.documents_by_uri = FxHashMap::default();
- let graph = UnGraphMap::from_edges(edges);
- let mut dfs = Dfs::new(&graph, start);
- while let Some(i) = dfs.next(&graph) {
- let uri = &all_uris[i];
- let doc = self.documents_by_uri[uri].clone();
- slice.documents_by_uri.insert(Arc::clone(uri), doc);
- }
-
- slice
- })
- .unwrap_or_default()
- }
-
- #[must_use]
- pub fn find_parent(&self, uri: &Url) -> Option<Document> {
- self.slice(uri)
- .documents_by_uri
- .values()
- .find(|document| {
- document.data.as_latex().map_or(false, |data| {
- data.extras.has_document_environment
- && !data
- .extras
- .explicit_links
- .iter()
- .filter_map(ExplicitLink::as_component_name)
- .any(|name| name == "subfiles.cls")
- })
- })
- .cloned()
- }
-
- fn expand_parent(&mut self, document: &Document) {
- let all_current_paths = self
- .documents_by_uri
- .values()
- .filter_map(|doc| doc.uri.to_file_path().ok())
- .collect::<FxHashSet<_>>();
-
- if document.uri.scheme() == "file" {
- if let Ok(mut path) = document.uri.to_file_path() {
- while path.pop() && self.find_parent(&document.uri).is_none() {
- std::fs::read_dir(&path)
- .into_iter()
- .flatten()
- .filter_map(Result::ok)
- .filter(|entry| entry.file_type().ok().filter(FileType::is_file).is_some())
- .map(|entry| entry.path())
- .filter(|path| {
- matches!(
- DocumentLanguage::by_path(path),
- Some(DocumentLanguage::Latex)
- )
- })
- .filter(|path| !all_current_paths.contains(path))
- .for_each(|path| {
- let _ = self.load(path);
- });
- }
- }
- }
- }
-
- fn expand_children(&mut self, document: &Document) {
- if let Some(data) = document.data.as_latex() {
- let extras = &data.extras;
- let mut all_targets = vec![&extras.implicit_links.aux, &extras.implicit_links.log];
- for link in &extras.explicit_links {
- if link
- .as_component_name()
- .and_then(|name| COMPONENT_DATABASE.find(&name))
- .is_none()
- {
- all_targets.push(&link.targets);
- }
- }
-
- for targets in all_targets {
- for path in targets
- .iter()
- .filter(|uri| uri.scheme() == "file" && uri.fragment().is_none())
- .filter_map(|uri| uri.to_file_path().ok())
- {
- if self.load(path).is_ok() {
- break;
- }
- }
- }
- }
- }
-}
diff --git a/support/texlab/tests/integration/lsp/text_document/publish_diagnostics.rs b/support/texlab/tests/integration/lsp/text_document/publish_diagnostics.rs
deleted file mode 100644
index 7e406b5319..0000000000
--- a/support/texlab/tests/integration/lsp/text_document/publish_diagnostics.rs
+++ /dev/null
@@ -1,264 +0,0 @@
-use anyhow::Result;
-use insta::{assert_json_snapshot, internals::Redaction};
-use lsp_types::{
- notification::{
- DidChangeConfiguration, DidChangeWatchedFiles, Notification, PublishDiagnostics,
- },
- ClientCapabilities, Diagnostic, DidChangeConfigurationParams, DidChangeWatchedFilesParams,
- FileChangeType, FileEvent, PublishDiagnosticsParams, Url,
-};
-use rustc_hash::FxHashMap;
-
-use crate::lsp::{client::Client, fixture};
-
-struct DiagnosticResult {
- all_diagnostics: FxHashMap<Url, Vec<Diagnostic>>,
- uri_redaction: Redaction,
-}
-
-fn find_diagnostics(fixture: &str, settings: serde_json::Value) -> Result<DiagnosticResult> {
- let mut client = Client::spawn()?;
- client.initialize(ClientCapabilities::default(), None)?;
-
- let mut disk_files = Vec::new();
- let fixture = fixture::parse(fixture);
- for file in fixture.files {
- if file.lang == "log" {
- client.store_on_disk(file.name, &file.text)?;
- disk_files.push(client.uri(file.name)?);
- } else {
- client.open(file.name, file.lang, file.text)?;
- }
- }
-
- client.notify::<DidChangeWatchedFiles>(DidChangeWatchedFilesParams {
- changes: disk_files
- .into_iter()
- .map(|uri| FileEvent::new(uri, FileChangeType::CHANGED))
- .collect(),
- })?;
-
- client.notify::<DidChangeConfiguration>(DidChangeConfigurationParams { settings })?;
-
- let result = client.shutdown()?;
-
- let uri = Url::from_directory_path(result.directory.path()).unwrap();
- let uri_redaction = insta::dynamic_redaction(move |content, _path| {
- content.as_str().unwrap().replace(uri.as_str(), "[tmp]/")
- });
-
- let all_diagnostics = result
- .incoming
- .notifications
- .into_iter()
- .filter_map(|notification| {
- notification
- .extract::<PublishDiagnosticsParams>(PublishDiagnostics::METHOD)
- .ok()
- })
- .map(|params| (params.uri, params.diagnostics))
- .collect();
-
- Ok(DiagnosticResult {
- all_diagnostics,
- uri_redaction,
- })
-}
-
-macro_rules! assert_symbols {
- ($result:expr) => {
- let result = $result;
- assert_json_snapshot!(result.all_diagnostics, {
- ".$key" => result.uri_redaction
- });
- };
-}
-
-static BUILD_LOG_FIXTURE: &str = r#"
-%TEX main.tex
-%SRC \documentclass{article}
-%SRC
-%SRC \usepackage{amsmath}
-%SRC
-%SRC \begin{document}
-%SRC
-%SRC \foo{}
-%SRC aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-%SRC
-%SRC \end{document}
-
-%LOG main.log
-%SRC This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021/W32TeX) (preloaded format=pdflatex 2022.1.23) 16 JUN 2022 11:04
-%SRC entering extended mode
-%SRC restricted \write18 enabled.
-%SRC %&-line parsing enabled.
-%SRC **main.tex
-%SRC (./main.tex
-%SRC LaTeX2e <2020-10-01> patch level 4
-%SRC L3 programming layer <2021-02-18>
-%SRC (c:/texlive/2021/texmf-dist/tex/latex/base/article.cls
-%SRC Document Class: article 2020/04/10 v1.4m Standard LaTeX document class
-%SRC (c:/texlive/2021/texmf-dist/tex/latex/base/size10.clo
-%SRC File: size10.clo 2020/04/10 v1.4m Standard LaTeX file (size option)
-%SRC )
-%SRC \c@part=\count179
-%SRC \c@section=\count180
-%SRC \c@subsection=\count181
-%SRC \c@subsubsection=\count182
-%SRC \c@paragraph=\count183
-%SRC \c@subparagraph=\count184
-%SRC \c@figure=\count185
-%SRC \c@table=\count186
-%SRC \abovecaptionskip=\skip47
-%SRC \belowcaptionskip=\skip48
-%SRC \bibindent=\dimen138
-%SRC )
-%SRC (c:/texlive/2021/texmf-dist/tex/latex/amsmath/amsmath.sty
-%SRC Package: amsmath 2020/09/23 v2.17i AMS math features
-%SRC \@mathmargin=\skip49
-%SRC
-%SRC For additional information on amsmath, use the `?' option.
-%SRC (c:/texlive/2021/texmf-dist/tex/latex/amsmath/amstext.sty
-%SRC Package: amstext 2000/06/29 v2.01 AMS text
-%SRC
-%SRC (c:/texlive/2021/texmf-dist/tex/latex/amsmath/amsgen.sty
-%SRC File: amsgen.sty 1999/11/30 v2.0 generic functions
-%SRC \@emptytoks=\toks15
-%SRC \ex@=\dimen139
-%SRC ))
-%SRC (c:/texlive/2021/texmf-dist/tex/latex/amsmath/amsbsy.sty
-%SRC Package: amsbsy 1999/11/29 v1.2d Bold Symbols
-%SRC \pmbraise@=\dimen140
-%SRC )
-%SRC (c:/texlive/2021/texmf-dist/tex/latex/amsmath/amsopn.sty
-%SRC Package: amsopn 2016/03/08 v2.02 operator names
-%SRC )
-%SRC \inf@bad=\count187
-%SRC LaTeX Info: Redefining \frac on input line 234.
-%SRC \uproot@=\count188
-%SRC \leftroot@=\count189
-%SRC LaTeX Info: Redefining \overline on input line 399.
-%SRC \classnum@=\count190
-%SRC \DOTSCASE@=\count191
-%SRC LaTeX Info: Redefining \ldots on input line 496.
-%SRC LaTeX Info: Redefining \dots on input line 499.
-%SRC LaTeX Info: Redefining \cdots on input line 620.
-%SRC \Mathstrutbox@=\box47
-%SRC \strutbox@=\box48
-%SRC \big@size=\dimen141
-%SRC LaTeX Font Info: Redeclaring font encoding OML on input line 743.
-%SRC LaTeX Font Info: Redeclaring font encoding OMS on input line 744.
-%SRC \macc@depth=\count192
-%SRC \c@MaxMatrixCols=\count193
-%SRC \dotsspace@=\muskip16
-%SRC \c@parentequation=\count194
-%SRC \dspbrk@lvl=\count195
-%SRC \tag@help=\toks16
-%SRC \row@=\count196
-%SRC \column@=\count197
-%SRC \maxfields@=\count198
-%SRC \andhelp@=\toks17
-%SRC \eqnshift@=\dimen142
-%SRC \alignsep@=\dimen143
-%SRC \tagshift@=\dimen144
-%SRC \tagwidth@=\dimen145
-%SRC \totwidth@=\dimen146
-%SRC \lineht@=\dimen147
-%SRC \@envbody=\toks18
-%SRC \multlinegap=\skip50
-%SRC \multlinetaggap=\skip51
-%SRC \mathdisplay@stack=\toks19
-%SRC LaTeX Info: Redefining \[ on input line 2923.
-%SRC LaTeX Info: Redefining \] on input line 2924.
-%SRC )
-%SRC (c:/texlive/2021/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def
-%SRC File: l3backend-pdftex.def 2021-03-18 L3 backend support: PDF output (pdfTeX)
-%SRC \l__color_backend_stack_int=\count199
-%SRC \l__pdf_internal_box=\box49
-%SRC )
-%SRC (./main.aux)
-%SRC \openout1 = `main.aux'.
-%SRC
-%SRC LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 5.
-%SRC LaTeX Font Info: ... okay on input line 5.
-%SRC LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 5.
-%SRC LaTeX Font Info: ... okay on input line 5.
-%SRC LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 5.
-%SRC LaTeX Font Info: ... okay on input line 5.
-%SRC LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 5.
-%SRC LaTeX Font Info: ... okay on input line 5.
-%SRC LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 5.
-%SRC LaTeX Font Info: ... okay on input line 5.
-%SRC LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 5.
-%SRC LaTeX Font Info: ... okay on input line 5.
-%SRC LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 5.
-%SRC LaTeX Font Info: ... okay on input line 5.
-%SRC
-%SRC ! Undefined control sequence.
-%SRC l.7 \foo
-%SRC {}
-%SRC The control sequence at the end of the top line
-%SRC of your error message was never \def'ed. If you have
-%SRC misspelled it (e.g., `\hobx'), type `I' and the correct
-%SRC spelling (e.g., `I\hbox'). Otherwise just continue,
-%SRC and I'll forget about whatever was undefined.
-%SRC
-%SRC
-%SRC Overfull \hbox (80.00125pt too wide) in paragraph at lines 8--9
-%SRC []\OT1/cmr/m/n/10 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-%SRC aaaaaaaaaaaaaaaaaaaaa
-%SRC []
-%SRC
-%SRC [1
-%SRC
-%SRC {c:/texlive/2021/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] (./main.aux) )
-%SRC Here is how much of TeX's memory you used:
-%SRC 1014 strings out of 478994
-%SRC 13996 string characters out of 5862207
-%SRC 300924 words of memory out of 5000000
-%SRC 18565 multiletter control sequences out of 15000+600000
-%SRC 403430 words of font info for 27 fonts, out of 8000000 for 9000
-%SRC 1141 hyphenation exceptions out of 8191
-%SRC 67i,4n,74p,200b,104s stack positions out of 5000i,500n,10000p,200000b,80000s
-%SRC <
-%SRC c:/texlive/2021/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb>
-%SRC Output written on main.pdf (1 page, 9741 bytes).
-%SRC PDF statistics:
-%SRC 12 PDF objects out of 1000 (max. 8388607)
-%SRC 7 compressed objects within 1 object stream
-%SRC 0 named destinations out of 1000 (max. 500000)
-%SRC 1 words of extra memory for PDF output out of 10000 (max. 10000000)"#;
-
-#[test]
-fn build_log_filter_none() -> Result<()> {
- assert_symbols!(find_diagnostics(BUILD_LOG_FIXTURE, serde_json::json!({}))?);
- Ok(())
-}
-
-#[test]
-fn build_log_filter_allowed() -> Result<()> {
- assert_symbols!(find_diagnostics(
- BUILD_LOG_FIXTURE,
- serde_json::json!({
- "diagnostics": {
- "allowedPatterns": ["Overfull \\\\[hv]box"]
- }
- })
- )?);
-
- Ok(())
-}
-
-#[test]
-fn build_log_filter_ignored() -> Result<()> {
- assert_symbols!(find_diagnostics(
- BUILD_LOG_FIXTURE,
- serde_json::json!({
- "diagnostics": {
- "ignoredPatterns": ["Overfull \\\\[hv]box"]
- }
- })
- )?);
-
- Ok(())
-}
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_allowed.snap b/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_allowed.snap
deleted file mode 100644
index 9fc11d295b..0000000000
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_allowed.snap
+++ /dev/null
@@ -1,24 +0,0 @@
----
-source: tests/integration/lsp/text_document/publish_diagnostics.rs
-assertion_line: 240
-expression: result.all_diagnostics
----
-{
- "[tmp]/main.tex": [
- {
- "range": {
- "start": {
- "line": 7,
- "character": 0
- },
- "end": {
- "line": 7,
- "character": 0
- }
- },
- "severity": 2,
- "source": "latex-build",
- "message": "Overfull \\hbox (80.00125pt too wide) in paragraph at lines 8--9"
- }
- ]
-}
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_ignored.snap b/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_ignored.snap
deleted file mode 100644
index 28e0308a72..0000000000
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_ignored.snap
+++ /dev/null
@@ -1,24 +0,0 @@
----
-source: tests/integration/lsp/text_document/publish_diagnostics.rs
-assertion_line: 254
-expression: result.all_diagnostics
----
-{
- "[tmp]/main.tex": [
- {
- "range": {
- "start": {
- "line": 6,
- "character": 0
- },
- "end": {
- "line": 6,
- "character": 0
- }
- },
- "severity": 1,
- "source": "latex-build",
- "message": "Undefined control sequence."
- }
- ]
-}
diff --git a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_none.snap b/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_none.snap
deleted file mode 100644
index b16238381b..0000000000
--- a/support/texlab/tests/integration/lsp/text_document/snapshots/integration__lsp__text_document__publish_diagnostics__build_log_filter_none.snap
+++ /dev/null
@@ -1,39 +0,0 @@
----
-source: tests/integration/lsp/text_document/publish_diagnostics.rs
-assertion_line: 234
-expression: result.all_diagnostics
----
-{
- "[tmp]/main.tex": [
- {
- "range": {
- "start": {
- "line": 6,
- "character": 0
- },
- "end": {
- "line": 6,
- "character": 0
- }
- },
- "severity": 1,
- "source": "latex-build",
- "message": "Undefined control sequence."
- },
- {
- "range": {
- "start": {
- "line": 7,
- "character": 0
- },
- "end": {
- "line": 7,
- "character": 0
- }
- },
- "severity": 2,
- "source": "latex-build",
- "message": "Overfull \\hbox (80.00125pt too wide) in paragraph at lines 8--9"
- }
- ]
-}
diff --git a/support/texlab/tests/integration/main.rs b/support/texlab/tests/integration/main.rs
deleted file mode 100644
index 44e0d3635a..0000000000
--- a/support/texlab/tests/integration/main.rs
+++ /dev/null
@@ -1 +0,0 @@
-mod lsp;
diff --git a/support/texlab/texlab.1 b/support/texlab/texlab.1
index 8dd6b664a4..25dd817248 100644
--- a/support/texlab/texlab.1
+++ b/support/texlab/texlab.1
@@ -1,26 +1,25 @@
-.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.15.
-.TH TEXLAB "1" "May 2020" "texlab " "User Commands"
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
+.TH TEXLAB "1" "December 2022" "texlab 5.0.0" "User Commands"
.SH NAME
-texlab \- manual page for texlab
+texlab \- manual page for texlab 5.0.0
+.SH SYNOPSIS
+.B texlab
+[\fI\,OPTIONS\/\fR]
.SH DESCRIPTION
An implementation of the Language Server Protocol for LaTeX
-.SS "USAGE:"
-.IP
-texlab [FLAGS] [OPTIONS]
-.SS "FLAGS:"
+.SH OPTIONS
.TP
-\fB\-h\fR, \fB\-\-help\fR
-Prints help information
+\fB\-v\fR, \fB\-\-verbosity\fR...
+Increase message verbosity (\fB\-vvvv\fR for max verbosity)
.TP
\fB\-q\fR, \fB\-\-quiet\fR
No output printed to stderr
.TP
-\fB\-V\fR, \fB\-\-version\fR
-Prints version information
-.TP
-\fB\-v\fR, \fB\-\-verbosity\fR
-Increase message verbosity (\fB\-vvvv\fR for max verbosity)
-.SS "OPTIONS:"
-.TP
\fB\-\-log\-file\fR <FILE>
Write the logging output to FILE
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+Print help information
+.TP
+\fB\-V\fR, \fB\-\-version\fR
+Print version information
diff --git a/support/texlab/texlab.pdf b/support/texlab/texlab.pdf
index 68e68c312d..b4749920ec 100644
--- a/support/texlab/texlab.pdf
+++ b/support/texlab/texlab.pdf
Binary files differ
diff --git a/support/texshop/README.txt b/support/texshop/README.txt
index 153afadffa..0a71877e3a 100644
--- a/support/texshop/README.txt
+++ b/support/texshop/README.txt
@@ -7,4 +7,4 @@ The main author is Richard Koch, koch@uoregon.edu, with supporting contributions
Consult the program web site, https://pages.uoregon.edu/koch/texshop/texshop.html,
for full source code, an extensive Changes document, and other information.
-The current version, 5.09, was released on December 27, 2022. \ No newline at end of file
+The current version, 5.10, was released on December 28, 2022. \ No newline at end of file
diff --git a/support/texshop/texshop509.html b/support/texshop/texshop510.html
index f1da483fa9..cd15081d9e 100644
--- a/support/texshop/texshop509.html
+++ b/support/texshop/texshop510.html
@@ -9,7 +9,9 @@
<body>
-TeXShop 5.09 has one addition and one bug fix.
+TeXShop 5.10 fixes one bug in version 5.09. The preference items to set the document and console fonts were broken in the English localization. Now they are fixed.
+
+<p> TeXShop 5.09 had one addition and one bug fix.
<p><ul>
<li> Marco Santi wanted a preference to set the font and size of text in the Macro Editor. There is already a preference to change the default font in the console. To avoid cluttering the Preference Dialog, version 5.09 allows users to also use this console font in the Macro Editor. Just check the box "Use Also for Macro Editor" under the Console Tab.
<p><li> Kurt Richard Todoroff reported an important bug that I could never reproduce. Just before typesettting concluded, his console would stop reporting output and the program would become unresponsive. Luckily, Todoroff knew exactly when this bug was introduced. Although he was using version 5.08, he told me that versions 5.00 and 5.01 typeset without problems but version 5.02 often failed.