summaryrefslogtreecommitdiff
path: root/support/texlab/crates
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-05-07 03:01:42 +0000
committerNorbert Preining <norbert@preining.info>2023-05-07 03:01:42 +0000
commite2a7938bcd22a142fa92c5c5d91f038f7ae73231 (patch)
tree93e20c35b061ab13d971c4333d535243a076eece /support/texlab/crates
parent507fa9c669d7e4bc2c808f269113c6ced0b18827 (diff)
CTAN sync 202305070301
Diffstat (limited to 'support/texlab/crates')
-rw-r--r--support/texlab/crates/base-db/Cargo.toml1
-rw-r--r--support/texlab/crates/base-db/src/data.rs891
-rw-r--r--support/texlab/crates/base-db/src/document.rs13
-rw-r--r--support/texlab/crates/base-db/src/graph.rs17
-rw-r--r--support/texlab/crates/base-db/src/lib.rs5
-rw-r--r--support/texlab/crates/base-db/src/semantics.rs10
-rw-r--r--support/texlab/crates/base-db/src/semantics/tex.rs18
-rw-r--r--support/texlab/crates/base-db/src/util.rs9
-rw-r--r--support/texlab/crates/base-db/src/util/label.rs (renamed from support/texlab/crates/texlab/src/util/label.rs)46
-rw-r--r--support/texlab/crates/base-db/src/util/line_index.rs (renamed from support/texlab/crates/base-db/src/line_index.rs)0
-rw-r--r--support/texlab/crates/base-db/src/util/regex_filter.rs (renamed from support/texlab/crates/texlab/src/util/regex_filter.rs)6
-rw-r--r--support/texlab/crates/base-feature/src/lib.rs4
-rw-r--r--support/texlab/crates/base-feature/src/normalize_uri.rs56
-rw-r--r--support/texlab/crates/commands/Cargo.toml1
-rw-r--r--support/texlab/crates/commands/src/build.rs3
-rw-r--r--support/texlab/crates/commands/src/fwd_search.rs3
-rw-r--r--support/texlab/crates/commands/src/lib.rs1
-rw-r--r--support/texlab/crates/commands/src/placeholders.rs (renamed from support/texlab/crates/base-feature/src/placeholders.rs)0
-rw-r--r--support/texlab/crates/parser/src/config.rs18
-rw-r--r--support/texlab/crates/parser/src/latex.rs40
-rw-r--r--support/texlab/crates/parser/src/latex/lexer.rs1
-rw-r--r--support/texlab/crates/parser/src/latex/lexer/commands.rs1
-rw-r--r--support/texlab/crates/parser/src/latex/lexer/types.rs6
-rw-r--r--support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@issue_828.txt.snap22
-rw-r--r--support/texlab/crates/parser/src/test_data/latex/issue_828.txt1
-rw-r--r--support/texlab/crates/symbols/Cargo.toml24
-rw-r--r--support/texlab/crates/symbols/src/document.rs51
-rw-r--r--support/texlab/crates/symbols/src/document/bib.rs64
-rw-r--r--support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__allowed_patterns.snap31
-rw-r--r--support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__enumerate.snap62
-rw-r--r--support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__equation.snap40
-rw-r--r--support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__float.snap40
-rw-r--r--support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__ignored_patterns.snap19
-rw-r--r--support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__section.snap41
-rw-r--r--support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem.snap53
-rw-r--r--support/texlab/crates/symbols/src/document/tests.rs250
-rw-r--r--support/texlab/crates/symbols/src/document/tex.rs257
-rw-r--r--support/texlab/crates/symbols/src/lib.rs9
-rw-r--r--support/texlab/crates/symbols/src/types.rs89
-rw-r--r--support/texlab/crates/symbols/src/workspace.rs47
-rw-r--r--support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_bibtex.snap36
-rw-r--r--support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_figure.snap24
-rw-r--r--support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_item.snap60
-rw-r--r--support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_math.snap42
-rw-r--r--support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_section.snap78
-rw-r--r--support/texlab/crates/symbols/src/workspace/sort.rs (renamed from support/texlab/crates/texlab/src/features/symbol/project_order.rs)52
-rw-r--r--support/texlab/crates/symbols/src/workspace/tests.rs99
-rw-r--r--support/texlab/crates/syntax/src/latex/cst.rs2
-rw-r--r--support/texlab/crates/test-utils/Cargo.toml (renamed from support/texlab/crates/base-feature/Cargo.toml)7
-rw-r--r--support/texlab/crates/test-utils/src/fixture.rs103
-rw-r--r--support/texlab/crates/test-utils/src/lib.rs1
-rw-r--r--support/texlab/crates/texlab/Cargo.toml4
-rw-r--r--support/texlab/crates/texlab/data/lang_data.json1058
-rw-r--r--support/texlab/crates/texlab/src/features.rs2
-rw-r--r--support/texlab/crates/texlab/src/features/completion/builder.rs34
-rw-r--r--support/texlab/crates/texlab/src/features/completion/color.rs94
-rw-r--r--support/texlab/crates/texlab/src/features/completion/component_environment.rs2
-rw-r--r--support/texlab/crates/texlab/src/features/completion/entry_type.rs4
-rw-r--r--support/texlab/crates/texlab/src/features/completion/field.rs4
-rw-r--r--support/texlab/crates/texlab/src/features/completion/label.rs22
-rw-r--r--support/texlab/crates/texlab/src/features/completion/theorem.rs2
-rw-r--r--support/texlab/crates/texlab/src/features/completion/tikz_library.rs122
-rw-r--r--support/texlab/crates/texlab/src/features/completion/user_command.rs9
-rw-r--r--support/texlab/crates/texlab/src/features/completion/user_environment.rs6
-rw-r--r--support/texlab/crates/texlab/src/features/definition/label.rs6
-rw-r--r--support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs2
-rw-r--r--support/texlab/crates/texlab/src/features/hover/entry_type.rs7
-rw-r--r--support/texlab/crates/texlab/src/features/hover/field.rs7
-rw-r--r--support/texlab/crates/texlab/src/features/hover/label.rs6
-rw-r--r--support/texlab/crates/texlab/src/features/inlay_hint/label.rs20
-rw-r--r--support/texlab/crates/texlab/src/features/symbol.rs129
-rw-r--r--support/texlab/crates/texlab/src/features/symbol/bibtex.rs82
-rw-r--r--support/texlab/crates/texlab/src/features/symbol/latex.rs431
-rw-r--r--support/texlab/crates/texlab/src/features/symbol/types.rs133
-rw-r--r--support/texlab/crates/texlab/src/features/symbols.rs107
-rw-r--r--support/texlab/crates/texlab/src/server.rs37
-rw-r--r--support/texlab/crates/texlab/src/util.rs59
-rw-r--r--support/texlab/crates/texlab/src/util/cursor.rs6
-rw-r--r--support/texlab/crates/texlab/src/util/diagnostics.rs6
-rw-r--r--support/texlab/crates/texlab/src/util/lang_data.rs68
-rw-r--r--support/texlab/crates/texlab/src/util/line_index_ext.rs2
-rw-r--r--support/texlab/crates/texlab/src/util/lsp_enums.rs3
-rw-r--r--support/texlab/crates/texlab/tests/lsp/fixture.rs18
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/completion.rs12
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/document_symbol.rs454
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/formatting.rs2
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__issue_883.snap11
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_flat.snap96
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_nested.snap140
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_flat.snap60
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_nested.snap86
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_flat.snap60
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_nested.snap86
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__ignored_patterns.snap24
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_flat.snap60
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_nested.snap87
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__smoke.snap103
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_flat.snap78
-rw-r--r--support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_nested.snap113
-rw-r--r--support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_bibtex.snap42
-rw-r--r--support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_figure.snap24
-rw-r--r--support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_item.snap60
-rw-r--r--support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_math.snap42
-rw-r--r--support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_section.snap78
-rw-r--r--support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__smoke.snap78
-rw-r--r--support/texlab/crates/texlab/tests/lsp/workspace/symbol.rs126
106 files changed, 3356 insertions, 3812 deletions
diff --git a/support/texlab/crates/base-db/Cargo.toml b/support/texlab/crates/base-db/Cargo.toml
index 2c7efe9ac0..c968cefac9 100644
--- a/support/texlab/crates/base-db/Cargo.toml
+++ b/support/texlab/crates/base-db/Cargo.toml
@@ -14,6 +14,7 @@ log = "0.4.17"
notify = "5.1.0"
once_cell = "1.17.1"
parser = { path = "../parser" }
+percent-encoding = "2.2.0"
regex = "1.7.3"
rowan = "0.15.11"
rustc-hash = "1.1.0"
diff --git a/support/texlab/crates/base-db/src/data.rs b/support/texlab/crates/base-db/src/data.rs
new file mode 100644
index 0000000000..2ebb35cae2
--- /dev/null
+++ b/support/texlab/crates/base-db/src/data.rs
@@ -0,0 +1,891 @@
+#[derive(Debug, Clone, Copy)]
+pub struct BibtexEntryType<'a> {
+ pub name: &'a str,
+ pub category: BibtexEntryTypeCategory,
+ pub documentation: Option<&'a str>,
+}
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
+pub enum BibtexEntryTypeCategory {
+ Misc,
+ String,
+ Article,
+ Thesis,
+ Book,
+ Part,
+ Collection,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct BibtexFieldType<'a> {
+ pub name: &'a str,
+ pub documentation: &'a str,
+}
+
+impl<'a> BibtexEntryType<'a> {
+ pub fn find(name: &str) -> Option<&Self> {
+ BIBTEX_ENTRY_TYPES.iter().find(|ty| ty.name.eq_ignore_ascii_case(name))
+ }
+}
+
+impl<'a> BibtexFieldType<'a> {
+ pub fn find(name: &str) -> Option<&Self> {
+ BIBTEX_FIELD_TYPES.iter().find(|ty| ty.name.eq_ignore_ascii_case(name))
+ }
+}
+
+
+pub static BIBTEX_ENTRY_TYPES: &[BibtexEntryType<'static>] = &[
+ BibtexEntryType {
+ name: "preamble",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: None,
+ },
+ BibtexEntryType {
+ name: "string",
+ category: BibtexEntryTypeCategory::String,
+ documentation: None,
+ },
+ BibtexEntryType {
+ name: "comment",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: None,
+ },
+ BibtexEntryType {
+ name: "article",
+ category: BibtexEntryTypeCategory::Article,
+ documentation: Some("An article in a journal, magazine, newspaper, or other periodical which forms a \n self-contained unit with its own title. The title of the periodical is given in the \n journaltitle field. If the issue has its own title in addition to the main title of \n the periodical, it goes in the issuetitle field. Note that editor and related \n fields refer to the journal while translator and related fields refer to the article.\n\nRequired fields: `author`, `title`, `journaltitle`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "book",
+ category: BibtexEntryTypeCategory::Book,
+ documentation: Some("A single-volume book with one or more authors where the authors share credit for\n the work as a whole. This entry type also covers the function of the `@inbook` type\n of traditional BibTeX.\n\nRequired fields: `author`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "mvbook",
+ category: BibtexEntryTypeCategory::Book,
+ documentation: Some("A multi-volume `@book`. For backwards compatibility, multi-volume books are also\n supported by the entry type `@book`. However, it is advisable to make use of the\n dedicated entry type `@mvbook`.\n\nRequired fields: `author`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "inbook",
+ category: BibtexEntryTypeCategory::Part,
+ documentation: Some("A part of a book which forms a self-contained unit with its own title. Note that the\n profile of this entry type is different from standard BibTeX.\n\nRequired fields: `author`, `title`, `booktitle`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "bookinbook",
+ category: BibtexEntryTypeCategory::Part,
+ documentation: Some("This type is similar to `@inbook` but intended for works originally published as a\n stand-alone book. A typical example are books reprinted in the collected works of\n an author."),
+ },
+ BibtexEntryType {
+ name: "suppbook",
+ category: BibtexEntryTypeCategory::Book,
+ documentation: Some("Supplemental material in a `@book`. This type is closely related to the `@inbook`\n entry type. While `@inbook` is primarily intended for a part of a book with its own\n title (e. g., a single essay in a collection of essays by the same author), this type is\n provided for elements such as prefaces, introductions, forewords, afterwords, etc.\n which often have a generic title only. Style guides may require such items to be\n formatted differently from other `@inbook` items. The standard styles will treat this\n entry type as an alias for `@inbook`."),
+ },
+ BibtexEntryType {
+ name: "booklet",
+ category: BibtexEntryTypeCategory::Book,
+ documentation: Some("A book-like work without a formal publisher or sponsoring institution. Use the field\n howpublished to supply publishing information in free format, if applicable. The\n field type may be useful as well.\n\nRequired fields: `author/editor`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "collection",
+ category: BibtexEntryTypeCategory::Collection,
+ documentation: Some("A single-volume collection with multiple, self-contained contributions by distinct\n authors which have their own title. The work as a whole has no overall author but it\n will usually have an editor.\n\nRequired fields: `editor`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "mvcollection",
+ category: BibtexEntryTypeCategory::Collection,
+ documentation: Some("A multi-volume `@collection`. For backwards compatibility, multi-volume collections\n are also supported by the entry type `@collection`. However, it is advisable\n to make use of the dedicated entry type `@mvcollection`.\n\nRequired fields: `editor`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "incollection",
+ category: BibtexEntryTypeCategory::Part,
+ documentation: Some("A contribution to a collection which forms a self-contained unit with a distinct author\n and title. The `author` refers to the `title`, the `editor` to the `booktitle`, i. e.,\n the title of the collection.\n\nRequired fields: `author`, `title`, `booktitle`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "suppcollection",
+ category: BibtexEntryTypeCategory::Collection,
+ documentation: Some("Supplemental material in a `@collection`. This type is similar to `@suppbook` but\n related to the `@collection` entry type. The standard styles will treat this entry\n type as an alias for `@incollection`."),
+ },
+ BibtexEntryType {
+ name: "manual",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Technical or other documentation, not necessarily in printed form. The author or\n editor is omissible.\n\nRequired fields: `author/editor`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "misc",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("A fallback type for entries which do not fit into any other category. Use the field\n howpublished to supply publishing information in free format, if applicable. The\n field type may be useful as well. author, editor, and year are omissible.\n\nRequired fields: `author/editor`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "online",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("An online resource. `author`, `editor`, and `year` are omissible.\n This entry type is intended for sources such as web sites which are intrinsically\n online resources. Note that all entry types support the url field. For example, when\n adding an article from an online journal, it may be preferable to use the `@article`\n type and its url field.\n\nRequired fields: `author/editor`, `title`, `year/date`, `url`"),
+ },
+ BibtexEntryType {
+ name: "patent",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("A patent or patent request. The number or record token is given in the number\n field. Use the type field to specify the type and the location field to indicate the\n scope of the patent, if different from the scope implied by the type. Note that the\n location field is treated as a key list with this entry type.\n\nRequired fields: `author`, `title`, `number`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "periodical",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("An complete issue of a periodical, such as a special issue of a journal. The title of\n the periodical is given in the title field. If the issue has its own title in addition to\n the main title of the periodical, it goes in the issuetitle field. The editor is\n omissible.\n\nRequired fields: `editor`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "suppperiodical",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Supplemental material in a `@periodical`. This type is similar to `@suppbook`\n but related to the `@periodical` entry type. The role of this entry type may be\n more obvious if you bear in mind that the `@article` type could also be called\n `@inperiodical`. This type may be useful when referring to items such as regular\n columns, obituaries, letters to the editor, etc. which only have a generic title. Style\n guides may require such items to be formatted differently from articles in the strict\n sense of the word. The standard styles will treat this entry type as an alias for\n `@article`."),
+ },
+ BibtexEntryType {
+ name: "proceedings",
+ category: BibtexEntryTypeCategory::Book,
+ documentation: Some("A single-volume conference proceedings. This type is very similar to `@collection`.\n It supports an optional organization field which holds the sponsoring institution.\n The editor is omissible.\n\nRequired fields: `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "mvproceedings",
+ category: BibtexEntryTypeCategory::Book,
+ documentation: Some("A multi-volume `@proceedings` entry. For backwards compatibility, multi-volume\n proceedings are also supported by the entry type `@proceedings`. However, it is\n advisable to make use of the dedicated entry type `@mvproceedings`\n\nRequired fields: `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "inproceedings",
+ category: BibtexEntryTypeCategory::Part,
+ documentation: Some("An article in a conference proceedings. This type is similar to `@incollection`. It\n supports an optional `organization` field.\n\nRequired fields: `author`, `title`, `booktitle`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "reference",
+ category: BibtexEntryTypeCategory::Collection,
+ documentation: Some("A single-volume work of reference such as an encyclopedia or a dictionary. This is a\n more specific variant of the generic `@collection` entry type. The standard styles\n will treat this entry type as an alias for `@collection`."),
+ },
+ BibtexEntryType {
+ name: "mvreference",
+ category: BibtexEntryTypeCategory::Collection,
+ documentation: Some("A multi-volume `@reference` entry. The standard styles will treat this entry type\n as an alias for `@mvcollection`. For backwards compatibility, multi-volume references\n are also supported by the entry type `@reference`. However, it is advisable\n to make use of the dedicated entry type `@mvreference`."),
+ },
+ BibtexEntryType {
+ name: "inreference",
+ category: BibtexEntryTypeCategory::Part,
+ documentation: Some("An article in a work of reference. This is a more specific variant of the generic\n `@incollection` entry type. The standard styles will treat this entry type as an\n alias for `@incollection`."),
+ },
+ BibtexEntryType {
+ name: "report",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("A technical report, research report, or white paper published by a university or some\n other institution. Use the `type` field to specify the type of report. The sponsoring\n institution goes in the `institution` field.\n\nRequired fields: `author`, `title`, `type`, `institution`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "set",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("An entry set. This entry type is special."),
+ },
+ BibtexEntryType {
+ name: "thesis",
+ category: BibtexEntryTypeCategory::Thesis,
+ documentation: Some("A thesis written for an educational institution to satisfy the requirements for a degree.\n Use the `type` field to specify the type of thesis.\n\nRequired fields: `author`, `title`, `type`, `institution`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "unpublished",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("A work with an author and a title which has not been formally published, such as\n a manuscript or the script of a talk. Use the fields `howpublished` and `note` to\n supply additional information in free format, if applicable.\n\nRequired fields: `author`, `title`, `year/date`"),
+ },
+ BibtexEntryType {
+ name: "xdata",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("This entry type is special. `@xdata` entries hold data which may be inherited by other\n entries using the `xdata` field. Entries of this type only serve as data containers;\n they may not be cited or added to the bibliography."),
+ },
+ BibtexEntryType {
+ name: "conference",
+ category: BibtexEntryTypeCategory::Part,
+ documentation: Some("A legacy alias for `@inproceedings`."),
+ },
+ BibtexEntryType {
+ name: "electronic",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("An alias for `@online`."),
+ },
+ BibtexEntryType {
+ name: "mastersthesis",
+ category: BibtexEntryTypeCategory::Thesis,
+ documentation: Some("Similar to `@thesis` except that the `type` field is optional and defaults to the\n localised term ‘Master’s thesis’. You may still use the `type` field to override that."),
+ },
+ BibtexEntryType {
+ name: "phdthesis",
+ category: BibtexEntryTypeCategory::Thesis,
+ documentation: Some("Similar to `@thesis` except that the `type` field is optional and defaults to the\n localised term ‘PhD thesis’. You may still use the `type` field to override that."),
+ },
+ BibtexEntryType {
+ name: "techreport",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Similar to `@report` except that the `type` field is optional and defaults to the\n localised term ‘technical report’. You may still use the `type` field to override that."),
+ },
+ BibtexEntryType {
+ name: "www",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("An alias for `@online`, provided for `jurabib` compatibility."),
+ },
+ BibtexEntryType {
+ name: "artwork",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Works of the visual arts such as paintings, sculpture, and installations."),
+ },
+ BibtexEntryType {
+ name: "audio",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Audio recordings, typically on audio cd, dvd, audio cassette, or similar media. See\n also `@music`."),
+ },
+ BibtexEntryType {
+ name: "bibnote",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("This special entry type is not meant to be used in the `bib` file like other types. It is\n provided for third-party packages like `notes2bib` which merge notes into the bibliography.\n The notes should go into the `note` field. Be advised that the `@bibnote`\n type is not related to the `defbibnote` command in any way. `defbibnote`\n is for adding comments at the beginning or the end of the bibliography, whereas\n the `@bibnote` type is meant for packages which render endnotes as bibliography\n entries."),
+ },
+ BibtexEntryType {
+ name: "commentary",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Commentaries which have a status different from regular books, such as legal commentaries."),
+ },
+ BibtexEntryType {
+ name: "image",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Images, pictures, photographs, and similar media."),
+ },
+ BibtexEntryType {
+ name: "jurisdiction",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Court decisions, court recordings, and similar things."),
+ },
+ BibtexEntryType {
+ name: "legislation",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Laws, bills, legislative proposals, and similar things."),
+ },
+ BibtexEntryType {
+ name: "legal",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Legal documents such as treaties."),
+ },
+ BibtexEntryType {
+ name: "letter",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Personal correspondence such as letters, emails, memoranda, etc."),
+ },
+ BibtexEntryType {
+ name: "movie",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Motion pictures. See also `@video`."),
+ },
+ BibtexEntryType {
+ name: "music",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Musical recordings. This is a more specific variant of `@audio`."),
+ },
+ BibtexEntryType {
+ name: "performance",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Musical and theatrical performances as well as other works of the performing arts.\n This type refers to the event as opposed to a recording, a score, or a printed play."),
+ },
+ BibtexEntryType {
+ name: "review",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Reviews of some other work. This is a more specific variant of the `@article` type.\n The standard styles will treat this entry type as an alias for `@article`."),
+ },
+ BibtexEntryType {
+ name: "software",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Computer software."),
+ },
+ BibtexEntryType {
+ name: "standard",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("National and international standards issued by a standards body such as the International\n Organization for Standardization."),
+ },
+ BibtexEntryType {
+ name: "video",
+ category: BibtexEntryTypeCategory::Misc,
+ documentation: Some("Audiovisual recordings, typically on dvd, vhs cassette, or similar media. See also\n `@movie`."),
+ }
+];
+
+pub static BIBTEX_FIELD_TYPES: &[BibtexFieldType<'static>] = &[
+ BibtexFieldType {
+ name: "abstract",
+ documentation: "This field is intended for recording abstracts in a bib file, to be printed by a special bibliography style. It is not used by all standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "addendum",
+ documentation: "Miscellaneous bibliographic data to be printed at the end of the entry. This is similar to the `note` field except that it is printed at the end of the bibliography entry.",
+ },
+ BibtexFieldType {
+ name: "afterword",
+ documentation: "The author(s) of an afterword to the work. If the author of the afterword is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `introduction` and `foreword`.",
+ },
+ BibtexFieldType {
+ name: "annotation",
+ documentation: "This field may be useful when implementing a style for annotated bibliographies. It is not used by all standard bibliography styles. Note that this field is completely unrelated to `annotator`. The `annotator` is the author of annotations which are part of the work cited.",
+ },
+ BibtexFieldType {
+ name: "annotator",
+ documentation: "The author(s) of annotations to the work. If the annotator is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `commentator`.",
+ },
+ BibtexFieldType {
+ name: "author",
+ documentation: "The author(s) of the `title`.",
+ },
+ BibtexFieldType {
+ name: "authortype",
+ documentation: "The type of author. This field will affect the string (if any) used to introduce the author. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "bookauthor",
+ documentation: "The author(s) of the `booktitle`.",
+ },
+ BibtexFieldType {
+ name: "bookpagination",
+ documentation: "If the work is published as part of another one, this is the pagination scheme of the enclosing work, i. e., `bookpagination` relates to `pagination` like `booktitle` to `title`. The value of this field will affect the formatting of the `pages` and `pagetotal` fields. The key should be given in the singular form. Possible keys are `page`, `column`, `line`, `verse`, `section`, and `paragraph`. See also `pagination`.",
+ },
+ BibtexFieldType {
+ name: "booksubtitle",
+ documentation: "The subtitle related to the `booktitle`. If the subtitle field refers to a work which is part of a larger publication, a possible subtitle of the main work is given in this field. See also `subtitle`.",
+ },
+ BibtexFieldType {
+ name: "booktitle",
+ documentation: "If the `title` field indicates the title of a work which is part of a larger publication, the title of the main work is given in this field. See also `title`.",
+ },
+ BibtexFieldType {
+ name: "booktitleaddon",
+ documentation: "An annex to the `booktitle`, to be printed in a different font.",
+ },
+ BibtexFieldType {
+ name: "chapter",
+ documentation: "A chapter or section or any other unit of a work.",
+ },
+ BibtexFieldType {
+ name: "commentator",
+ documentation: "The author(s) of a commentary to the work. Note that this field is intended for commented editions which have a commentator in addition to the author. If the work is a stand-alone commentary, the commentator should be given in the `author` field. If the commentator is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `annotator`.",
+ },
+ BibtexFieldType {
+ name: "date",
+ documentation: "The publication date. See also `month` and `year`.",
+ },
+ BibtexFieldType {
+ name: "doi",
+ documentation: "The Digital Object Identifier of the work.",
+ },
+ BibtexFieldType {
+ name: "edition",
+ documentation: "The edition of a printed publication. This must be an integer, not an ordinal. Don’t say `edition={First}` or `edition={1st}` but `edition={1}`. The bibliography style converts this to a language dependent ordinal. It is also possible to give the edition as a literal string, for example \"Third, revised and expanded edition\".",
+ },
+ BibtexFieldType {
+ name: "editor",
+ documentation: "The editor(s) of the `title`, `booktitle`, or `maintitle`, depending on the entry type. Use the `editortype` field to specify the role if it is different from `editor`.",
+ },
+ BibtexFieldType {
+ name: "editora",
+ documentation: "A secondary editor performing a different editorial role, such as compiling, redacting, etc. Use the `editoratype` field to specify the role.",
+ },
+ BibtexFieldType {
+ name: "editorb",
+ documentation: "Another secondary editor performing a different role. Use the `editorbtype` field to specify the role.",
+ },
+ BibtexFieldType {
+ name: "editorc",
+ documentation: "Another secondary editor performing a different role. Use the `editorctype` field to specify the role.",
+ },
+ BibtexFieldType {
+ name: "editortype",
+ documentation: "The type of editorial role performed by the `editor`. Roles supported by default are `editor`, `compiler`, `founder`, `continuator`, `redactor`, `reviser`, `collaborator`, `organizer`. The role `editor` is the default. In this case, the field is omissible.",
+ },
+ BibtexFieldType {
+ name: "editoratype",
+ documentation: "Similar to `editortype` but referring to the `editora` field.",
+ },
+ BibtexFieldType {
+ name: "editorbtype",
+ documentation: "Similar to `editortype` but referring to the `editorb` field.",
+ },
+ BibtexFieldType {
+ name: "editorctype",
+ documentation: "Similar to `editortype` but referring to the `editorc` field.",
+ },
+ BibtexFieldType {
+ name: "eid",
+ documentation: "The electronic identifier of an `@article`.",
+ },
+ BibtexFieldType {
+ name: "entrysubtype",
+ documentation: "This field, which is not used by the standard styles, may be used to specify a subtype of an entry type. This may be useful for bibliography styles which support a finergrained set of entry types.",
+ },
+ BibtexFieldType {
+ name: "eprint",
+ documentation: "The electronic identifier of an online publication. This is roughly comparable to a doi but specific to a certain archive, repository, service, or system. See also `eprinttype` and `eprintclass`.",
+ },
+ BibtexFieldType {
+ name: "eprintclass",
+ documentation: "Additional information related to the resource indicated by the `eprinttype` field. This could be a section of an archive, a path indicating a service, a classification of some sort, etc. See also`eprint` and `eprinttype`.",
+ },
+ BibtexFieldType {
+ name: "eprinttype",
+ documentation: "The type of `eprint` identifier, e. g., the name of the archive, repository, service, or system the `eprint` field refers to. See also `eprint` and `eprintclass`.",
+ },
+ BibtexFieldType {
+ name: "eventdate",
+ documentation: "The date of a conference, a symposium, or some other event in `@proceedings` and `@inproceedings` entries. See also `eventtitle` and `venue`.",
+ },
+ BibtexFieldType {
+ name: "eventtitle",
+ documentation: "The title of a conference, a symposium, or some other event in `@proceedings` and `@inproceedings` entries. Note that this field holds the plain title of the event. Things like \"Proceedings of the Fifth XYZ Conference\" go into the `titleaddon` or `booktitleaddon` field, respectively. See also `eventdate` and `venue`.",
+ },
+ BibtexFieldType {
+ name: "eventtitleaddon",
+ documentation: "An annex to the `eventtitle` field. Can be used for known event acronyms, for example.",
+ },
+ BibtexFieldType {
+ name: "file",
+ documentation: "A local link to a PDF or other version of the work. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "foreword",
+ documentation: "The author(s) of a foreword to the work. If the author of the foreword is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `introduction` and `afterword`.",
+ },
+ BibtexFieldType {
+ name: "holder",
+ documentation: "The holder(s) of a `@patent`, if different from the `author`. Note that corporate holders need to be wrapped in an additional set of braces.",
+ },
+ BibtexFieldType {
+ name: "howpublished",
+ documentation: "A publication notice for unusual publications which do not fit into any of the common categories.",
+ },
+ BibtexFieldType {
+ name: "indextitle",
+ documentation: "A title to use for indexing instead of the regular `title` field. This field may be useful if you have an entry with a title like \"An Introduction to …\" and want that indexed as \"Introduction to …, An\". Style authors should note that `biblatex` automatically copies the value of the `title` field to `indextitle` if the latter field is undefined.",
+ },
+ BibtexFieldType {
+ name: "institution",
+ documentation: "The name of a university or some other institution, depending on the entry type. Traditional BibTeX uses the field name `school` for theses, which is supported as an alias.",
+ },
+ BibtexFieldType {
+ name: "introduction",
+ documentation: "The author(s) of an introduction to the work. If the author of the introduction is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `foreword` and `afterword`.",
+ },
+ BibtexFieldType {
+ name: "isan",
+ documentation: "The International Standard Audiovisual Number of an audiovisual work. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "isbn",
+ documentation: "The International Standard Book Number of a book.",
+ },
+ BibtexFieldType {
+ name: "ismn",
+ documentation: "The International Standard Music Number for printed music such as musical scores. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "isrn",
+ documentation: "The International Standard Technical Report Number of a technical report.",
+ },
+ BibtexFieldType {
+ name: "issn",
+ documentation: "The International Standard Serial Number of a periodical.",
+ },
+ BibtexFieldType {
+ name: "issue",
+ documentation: "The issue of a journal. This field is intended for journals whose individual issues are identified by a designation such as ‘Spring’ or ‘Summer’ rather than the month or a number. The placement of `issue` is similar to `month` and `number`, integer ranges and short designators are better written to the number field. See also `month` and `number`.",
+ },
+ BibtexFieldType {
+ name: "issuesubtitle",
+ documentation: "The subtitle of a specific issue of a journal or other periodical.",
+ },
+ BibtexFieldType {
+ name: "issuetitle",
+ documentation: "The title of a specific issue of a journal or other periodical.",
+ },
+ BibtexFieldType {
+ name: "iswc",
+ documentation: "The International Standard Work Code of a musical work. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "journalsubtitle",
+ documentation: "The subtitle of a journal, a newspaper, or some other periodical.",
+ },
+ BibtexFieldType {
+ name: "journaltitle",
+ documentation: "The name of a journal, a newspaper, or some other periodical.",
+ },
+ BibtexFieldType {
+ name: "label",
+ documentation: "A designation to be used by the citation style as a substitute for the regular label if any data required to generate the regular label is missing. For example, when an author-year citation style is generating a citation for an entry which is missing the author or the year, it may fall back to `label`. Note that, in contrast to `shorthand`, `label` is only used as a fallback. See also `shorthand`.",
+ },
+ BibtexFieldType {
+ name: "language",
+ documentation: "The language(s) of the work. Languages may be specified literally or as localisation keys. If localisation keys are used, the prefix lang is omissible. See also `origlanguage`.",
+ },
+ BibtexFieldType {
+ name: "library",
+ documentation: "This field may be useful to record information such as a library name and a call number. This may be printed by a special bibliography style if desired. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "location",
+ documentation: "The place(s) of publication, i. e., the location of the `publisher` or `institution`, depending on the entry type. Traditional BibTeX uses the field name `address`, which is supported as an alias. With `@patent` entries, this list indicates the scope of a patent.",
+ },
+ BibtexFieldType {
+ name: "mainsubtitle",
+ documentation: "The subtitle related to the `maintitle`. See also `subtitle`.",
+ },
+ BibtexFieldType {
+ name: "maintitle",
+ documentation: "The main title of a multi-volume book, such as *Collected Works*. If the `title` or `booktitle` field indicates the title of a single volume which is part of multi-volume book, the title of the complete work is given in this field.",
+ },
+ BibtexFieldType {
+ name: "maintitleaddon",
+ documentation: "An annex to the `maintitle`, to be printed in a different font.",
+ },
+ BibtexFieldType {
+ name: "month",
+ documentation: "The publication month. This must be an integer, not an ordinal or a string. Don’t say `month={January}` but `month={1}`. The bibliography style converts this to a language dependent string or ordinal where required. This field is a literal field only when given explicitly in the data (for plain BibTeX compatibility for example). It is however better to use the `date` field as this supports many more features.",
+ },
+ BibtexFieldType {
+ name: "nameaddon",
+ documentation: "An addon to be printed immediately after the author name in the bibliography. Not used by the standard bibliography styles. This field may be useful to add an alias or pen name (or give the real name if the pseudonym is commonly used to refer to that author).",
+ },
+ BibtexFieldType {
+ name: "note",
+ documentation: "Miscellaneous bibliographic data which does not fit into any other field. The note field may be used to record bibliographic data in a free format. Publication facts such as \"Reprint of the edition London 1831\" are typical candidates for the note field. See also `addendum`.",
+ },
+ BibtexFieldType {
+ name: "number",
+ documentation: "The number of a journal or the volume/number of a book in a `series`. See also `issue`. With `@patent` entries, this is the number or record token of a patent or patent request. Normally this field will be an integer or an integer range, but in certain cases it may also contain \"S1\", \"Suppl. 1\", in these cases the output should be scrutinised carefully.",
+ },
+ BibtexFieldType {
+ name: "organization",
+ documentation: "The organization(s) that published a `@manual` or an `@online` resource, or sponsored a conference.",
+ },
+ BibtexFieldType {
+ name: "origdate",
+ documentation: "If the work is a translation, a reprint, or something similar, the publication date of the original edition. Not used by the standard bibliography styles. See also `date`.",
+ },
+ BibtexFieldType {
+ name: "origlanguage",
+ documentation: "If the work is a translation, the language(s) of the original work. See also `language`.",
+ },
+ BibtexFieldType {
+ name: "origlocation",
+ documentation: "If the work is a translation, a reprint, or something similar, the location of the original edition. Not used by the standard bibliography styles. See also `location`.",
+ },
+ BibtexFieldType {
+ name: "origpublisher",
+ documentation: "If the work is a translation, a reprint, or something similar, the publisher of the original edition. Not used by the standard bibliography styles. See also `publisher`.",
+ },
+ BibtexFieldType {
+ name: "origtitle",
+ documentation: "If the work is a translation, the `title` of the original work. Not used by the standard bibliography styles. See also `title`.",
+ },
+ BibtexFieldType {
+ name: "pages",
+ documentation: "One or more page numbers or page ranges. If the work is published as part of another one, such as an article in a journal or a collection, this field holds the relevant page range in that other work. It may also be used to limit the reference to a specific part of a work (a chapter in a book, for example).",
+ },
+ BibtexFieldType {
+ name: "pagetotal",
+ documentation: "The total number of pages of the work.",
+ },
+ BibtexFieldType {
+ name: "pagination",
+ documentation: "The pagination of the work. The value of this field will affect the formatting the *postnote* argument to a citation command. The key should be given in the singular form. Possible keys are `page`, `column`, `line`, `verse`, `section`, and `paragraph`. See also `bookpagination`.",
+ },
+ BibtexFieldType {
+ name: "part",
+ documentation: "The number of a partial volume. This field applies to books only, not to journals. It may be used when a logical volume consists of two or more physical ones. In this case the number of the logical volume goes in the `volume` field and the number of the part of that volume in the `part` field. See also `volume`.",
+ },
+ BibtexFieldType {
+ name: "publisher",
+ documentation: "The name(s) of the publisher(s).",
+ },
+ BibtexFieldType {
+ name: "pubstate",
+ documentation: "The publication state of the work, e. g., 'in press'.",
+ },
+ BibtexFieldType {
+ name: "reprinttitle",
+ documentation: "The title of a reprint of the work. Not used by the standard styles.",
+ },
+ BibtexFieldType {
+ name: "series",
+ documentation: "The name of a publication series, such as \"Studies in …\", or the number of a journal series. Books in a publication series are usually numbered. The number or volume of a book in a series is given in the `number` field. Note that the `@article` entry type makes use of the `series` field as well, but handles it in a special way.",
+ },
+ BibtexFieldType {
+ name: "shortauthor",
+ documentation: "The author(s) of the work, given in an abbreviated form. This field is mainly intended for abbreviated forms of corporate authors.",
+ },
+ BibtexFieldType {
+ name: "shorteditor",
+ documentation: "The editor(s) of the work, given in an abbreviated form. This field is mainly intended for abbreviated forms of corporate editors.",
+ },
+ BibtexFieldType {
+ name: "shorthand",
+ documentation: "A special designation to be used by the citation style instead of the usual label. If defined, it overrides the default label. See also `label`.",
+ },
+ BibtexFieldType {
+ name: "shorthandintro",
+ documentation: "The verbose citation styles which comes with this package use a phrase like \"henceforth cited as [shorthand]\" to introduce shorthands on the first citation. If the `shorthandintro` field is defined, it overrides the standard phrase. Note that the alternative phrase must include the shorthand.",
+ },
+ BibtexFieldType {
+ name: "shortjournal",
+ documentation: "A short version or an acronym of the `journaltitle`. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "shortseries",
+ documentation: "A short version or an acronym of the `series` field. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "shorttitle",
+ documentation: "The title in an abridged form. This field is usually not included in the bibliography. It is intended for citations in author-title format. If present, the author-title citation styles use this field instead of `title`.",
+ },
+ BibtexFieldType {
+ name: "subtitle",
+ documentation: "The subtitle of the work.",
+ },
+ BibtexFieldType {
+ name: "title",
+ documentation: "The title of the work.",
+ },
+ BibtexFieldType {
+ name: "titleaddon",
+ documentation: "An annex to the `title`, to be printed in a different font.",
+ },
+ BibtexFieldType {
+ name: "translator",
+ documentation: "The translator(s) of the `title` or `booktitle`, depending on the entry type. If the translator is identical to the `editor`, the standard styles will automatically concatenate these fields in the bibliography.",
+ },
+ BibtexFieldType {
+ name: "type",
+ documentation: "The type of a `manual`, `patent`, `report`, or `thesis`.",
+ },
+ BibtexFieldType {
+ name: "url",
+ documentation: "The URL of an online publication. If it is not URL-escaped (no ‘%’ chars) it will be URI-escaped according to RFC 3987, that is, even Unicode chars will be correctly escaped.",
+ },
+ BibtexFieldType {
+ name: "urldate",
+ documentation: "The access date of the address specified in the `url` field.",
+ },
+ BibtexFieldType {
+ name: "venue",
+ documentation: "The location of a conference, a symposium, or some other event in `@proceedings` and `@inproceedings` entries. Note that the `location` list holds the place of publication. It therefore corresponds to the `publisher` and `institution` lists. The location of the event is given in the `venue` field. See also `eventdate` and `eventtitle`.",
+ },
+ BibtexFieldType {
+ name: "version",
+ documentation: "The revision number of a piece of software, a manual, etc.",
+ },
+ BibtexFieldType {
+ name: "volume",
+ documentation: "The volume of a multi-volume book or a periodical. It is expected to be an integer, not necessarily in arabic numerals since `biber` will automatically from roman numerals or arabic letter to integers internally for sorting purposes. See also `part`. See the `noroman` option which can be used to suppress roman numeral parsing. This can help in cases where there is an ambiguity between parsing as roman numerals or alphanumeric (e.g. ‘C’).",
+ },
+ BibtexFieldType {
+ name: "volumes",
+ documentation: "The total number of volumes of a multi-volume work. Depending on the entry type, this field refers to `title` or `maintitle`. It is expected to be an integer, not necessarily in arabic numerals since `biber` will automatically from roman numerals or arabic letter to integers internally for sorting purposes. See the `noroman` option which can be used to suppress roman numeral parsing. This can help in cases where there is an ambiguity between parsing as roman numerals or alphanumeric (e.g. ‘C’).",
+ },
+ BibtexFieldType {
+ name: "year",
+ documentation: "The year of publication. This field is a literal field only when given explicitly in the data (for plain BibTeX compatibility for example). It is however better to use the `date` field as this is compatible with plain years too and supports many more features.",
+ },
+ BibtexFieldType {
+ name: "crossref",
+ documentation: "This field holds an entry key for the cross-referencing feature. Child entries with a `crossref` field inherit data from the parent entry specified in the `crossref` field. If the number of child entries referencing a specific parent entry hits a certain threshold, the parent entry is automatically added to the bibliography even if it has not been cited explicitly. The threshold is settable with the `mincrossrefs` package option. Style authors should note that whether or not the `crossref` fields of the child entries are defined on the `biblatex` level depends on the availability of the parent entry. If the parent entry is available, the `crossref` fields of the child entries will be defined. If not, the child entries still inherit the data from the parent entry but their `crossref` fields will be undefined. Whether the parent entry is added to the bibliography implicitly because of the threshold or explicitly because it has been cited does not matter. See also the `xref` field.",
+ },
+ BibtexFieldType {
+ name: "entryset",
+ documentation: "This field is specific to entry sets. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "execute",
+ documentation: "A special field which holds arbitrary TeX code to be executed whenever the data of the respective entry is accessed. This may be useful to handle special cases. Conceptually, this field is comparable to the hooks `AtEveryBibitem`, `AtEveryLositem`, and `AtEveryCitekey`, except that it is definable on a per-entry basis in the `bib` file. Any code in this field is executed automatically immediately after these hooks.",
+ },
+ BibtexFieldType {
+ name: "gender",
+ documentation: "The gender of the author or the gender of the editor, if there is no author. The following identifiers are supported: `sf` (feminine singular, a single female name), `sm` (masculine singular, a single male name), `sn` (neuter singular, a single neuter name), `pf` (feminine plural, a list of female names), `pm` (masculine plural, a list of male names), `pn` (neuter plural, a list of neuter names),`pp` (plural, a mixed gender list of names). This information is only required by special bibliography and citation styles and only in certain languages. For example, a citation style may replace recurrent author names with a term such as 'idem'. If the Latin word is used, as is custom in English and French, there is no need to specify the gender. In German publications, however, such key terms are usually given in German and in this case they are gender-sensitive.",
+ },
+ BibtexFieldType {
+ name: "langid",
+ documentation: "The language id of the bibliography entry. The alias `hyphenation` is provided for backwards compatibility. The identifier must be a language name known to the `babel/polyglossia` packages. This information may be used to switch hyphenation patterns and localise strings in the bibliography. Note that the language names are case sensitive. The languages currently supported by this package are given in table 2. Note that `babel` treats the identifier `english` as an alias for `british` or `american`, depending on the `babel` version. The `biblatex` package always treats it as an alias for `american`. It is preferable to use the language identifiers `american` and `british` (`babel`) or a language specific option to specify a language variant (`polyglossia`, using the `langidopts` field) to avoid any possible confusion.",
+ },
+ BibtexFieldType {
+ name: "langidopts",
+ documentation: "For `polyglossia` users, allows per-entry language specific options. The literal value of this field is passed to `polyglossia`’s language switching facility when using the package option `autolang=langname`.",
+ },
+ BibtexFieldType {
+ name: "ids",
+ documentation: "Citation key aliases for the main citation key. An entry may be cited by any of its aliases and `biblatex` will treat the citation as if it had used the primary citation key. This is to aid users who change their citation keys but have legacy documents which use older keys for the same entry. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "indexsorttitle",
+ documentation: "The title used when sorting the index. In contrast to indextitle, this field is used for sorting only. The printed title in the index is the indextitle or the title field. This field may be useful if the title contains special characters or commands which interfere with the sorting of the index. Style authors should note that biblatex automatically copies the value of either the indextitle or the title field to indexsorttitle if the latter field is undefined.",
+ },
+ BibtexFieldType {
+ name: "keywords",
+ documentation: "A separated list of keywords. These keywords are intended for the bibliography filters, they are usually not printed. Note that with the default separator (comma), spaces around the separator are ignored.",
+ },
+ BibtexFieldType {
+ name: "options",
+ documentation: "A separated list of entry options in *key*=*value* notation. This field is used to set options on a per-entry basis. Note that citation and bibliography styles may define additional entry options.",
+ },
+ BibtexFieldType {
+ name: "presort",
+ documentation: "A special field used to modify the sorting order of the bibliography. This field is the first item the sorting routine considers when sorting the bibliography, hence it may be used to arrange the entries in groups. This may be useful when creating subdivided bibliographies with the bibliography filters. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "related",
+ documentation: "Citation keys of other entries which have a relationship to this entry. The relationship is specified by the `relatedtype` field.",
+ },
+ BibtexFieldType {
+ name: "relatedoptions",
+ documentation: "Per-type options to set for a related entry. Note that this does not set the options on the related entry itself, only the `dataonly` clone which is used as a datasource for the parent entry.",
+ },
+ BibtexFieldType {
+ name: "relatedtype",
+ documentation: "An identifier which specified the type of relationship for the keys listed in the `related` field. The identifier is a localised bibliography string printed before the data from the related entry list. It is also used to identify type-specific formatting directives and bibliography macros for the related entries.",
+ },
+ BibtexFieldType {
+ name: "relatedstring",
+ documentation: "A field used to override the bibliography string specified by `relatedtype`.",
+ },
+ BibtexFieldType {
+ name: "sortkey",
+ documentation: "A field used to modify the sorting order of the bibliography. Think of this field as the master sort key. If present, `biblatex` uses this field during sorting and ignores everything else, except for the presort field. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "sortname",
+ documentation: "A name or a list of names used to modify the sorting order of the bibliography. If present, this list is used instead of `author` or `editor` when sorting the bibliography. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "sortshorthand",
+ documentation: "Similar to sortkey but used in the list of shorthands. If present, biblatex uses this field instead of shorthand when sorting the list of shorthands. This is useful if the shorthand field holds shorthands with formatting commands such as `emph` or `\textbf`. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "sorttitle",
+ documentation: "A field used to modify the sorting order of the bibliography. If present, this field is used instead of the title field when sorting the bibliography. The sorttitle field may come in handy if you have an entry with a title like \"An Introduction to…\" and want that alphabetized under ‘I’ rather than ‘A’. In this case, you could put \"Introduction to…\" in the sorttitle field. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "sortyear",
+ documentation: "A field used to modify the sorting order of the bibliography. In the default sorting templates, if this field is present, it is used instead of the year field when sorting the bibliography. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "xdata",
+ documentation: "This field inherits data from one or more `@xdata` entries. Conceptually, the `xdata` field is related to crossref and xref: `crossref` establishes a logical parent/child relation and inherits data; `xref` establishes as logical parent/child relation without inheriting data; `xdata` inherits data without establishing a relation. The value of the `xdata` may be a single entry key or a separated list of keys. This field is consumed by the backend processing and does not appear in the `.bbl`.",
+ },
+ BibtexFieldType {
+ name: "xref",
+ documentation: "This field is an alternative cross-referencing mechanism. It differs from `crossref` in that the child entry will not inherit any data from the parent entry specified in the `xref` field. If the number of child entries referencing a specific parent entry hits a certain threshold, the parent entry is automatically added to the bibliography even if it has not been cited explicitly. The threshold is settable with the `minxrefs` package option. Style authors should note that whether or not the `xref` fields of the child entries are defined on the `biblatex` level depends on the availability of the parent entry. If the parent entry is available, the `xref` fields of the child entries will be defined. If not, their `xref` fields will be undefined. Whether the parent entry is added to the bibliography implicitly because of the threshold or explicitly because it has been cited does not matter. See also the `crossref` field.",
+ },
+ BibtexFieldType {
+ name: "namea",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "nameb",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "namec",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "nameatype",
+ documentation: "Similar to `authortype` and `editortype` but referring to the fields `name[a--c]`. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "namebtype",
+ documentation: "Similar to `authortype` and `editortype` but referring to the fields `name[a--c]`. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "namectype",
+ documentation: "Similar to `authortype` and `editortype` but referring to the fields `name[a--c]`. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "lista",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "listb",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "listc",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "listd",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "liste",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "listf",
+ documentation: "Custom lists for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "usera",
+ documentation: "Custom fields for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "userb",
+ documentation: "Custom fields for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "userc",
+ documentation: "Custom fields for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "userd",
+ documentation: "Custom fields for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "usere",
+ documentation: "Custom fields for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "userf",
+ documentation: "Custom fields for special bibliography styles. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "verba",
+ documentation: "Similar to the custom fields except that these are verbatim fields. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "verbb",
+ documentation: "Similar to the custom fields except that these are verbatim fields. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "verbc",
+ documentation: "Similar to the custom fields except that these are verbatim fields. Not used by the standard bibliography styles.",
+ },
+ BibtexFieldType {
+ name: "address",
+ documentation: "An alias for `location`, provided for BibTeX compatibility. Traditional BibTeX uses the slightly misleading field name `address` for the place of publication, i. e., the location of the publisher, while `biblatex` uses the generic field name `location`.",
+ },
+ BibtexFieldType {
+ name: "annote",
+ documentation: "An alias for `annotation`, provided for jurabib compatibility.",
+ },
+ BibtexFieldType {
+ name: "archiveprefix",
+ documentation: "An alias for `eprinttype`, provided for arXiv compatibility.",
+ },
+ BibtexFieldType {
+ name: "journal",
+ documentation: "An alias for `journaltitle`, provided for BibTeX compatibility.",
+ },
+ BibtexFieldType {
+ name: "key",
+ documentation: "An alias for `sortkey`, provided for BibTeX compatibility.",
+ },
+ BibtexFieldType {
+ name: "pdf",
+ documentation: "An alias for `file`, provided for JabRef compatibility.",
+ },
+ BibtexFieldType {
+ name: "primaryclass",
+ documentation: "An alias for `eprintclass`, provided for arXiv compatibility.",
+ },
+ BibtexFieldType {
+ name: "school",
+ documentation: "An alias for `institution`, provided for BibTeX compatibility. The `institution` field is used by traditional BibTeX for technical reports whereas the `school` field holds the institution associated with theses. The `biblatex` package employs the generic field name `institution` in both cases.",
+ }
+];
diff --git a/support/texlab/crates/base-db/src/document.rs b/support/texlab/crates/base-db/src/document.rs
index c6148deaa8..cc1a0d44e5 100644
--- a/support/texlab/crates/base-db/src/document.rs
+++ b/support/texlab/crates/base-db/src/document.rs
@@ -7,8 +7,9 @@ use url::Url;
use crate::{
diagnostics::{self, Diagnostic},
- line_index::LineIndex,
- semantics, Config,
+ semantics,
+ util::LineIndex,
+ Config,
};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
@@ -17,7 +18,7 @@ pub enum Owner {
Server,
}
-#[derive(Debug, Clone)]
+#[derive(Clone)]
pub struct Document {
pub uri: Url,
pub dir: Url,
@@ -99,6 +100,12 @@ impl Document {
}
}
+impl std::fmt::Debug for Document {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_tuple("Document").field(&self.uri.as_str()).finish()
+ }
+}
+
impl std::borrow::Borrow<Url> for Document {
fn borrow(&self) -> &Url {
&self.uri
diff --git a/support/texlab/crates/base-db/src/graph.rs b/support/texlab/crates/base-db/src/graph.rs
index 2103aa8a73..b16245e011 100644
--- a/support/texlab/crates/base-db/src/graph.rs
+++ b/support/texlab/crates/base-db/src/graph.rs
@@ -3,6 +3,7 @@ use std::{ffi::OsStr, path::PathBuf};
use distro::Language;
use itertools::Itertools;
use once_cell::sync::Lazy;
+use percent_encoding::percent_decode_str;
use rustc_hash::FxHashSet;
use url::Url;
@@ -138,12 +139,16 @@ impl<'a> Graph<'a> {
}
fn implicit_edge(&mut self, source: &'a Document, base_dir: &Url, extension: &str) {
- let Some(target_uri) = source.uri.to_file_path().ok().and_then(|mut path| {
- path.set_extension(extension);
- path.file_name()
- .and_then(OsStr::to_str)
- .and_then(|name| self.workspace.output_dir(base_dir).join(&name).ok())
- }) else { return };
+ let mut path = PathBuf::from(
+ percent_decode_str(source.uri.path())
+ .decode_utf8_lossy()
+ .as_ref(),
+ );
+
+ path.set_extension(extension);
+ let Some(target_uri) = path.file_name()
+ .and_then(OsStr::to_str)
+ .and_then(|name| self.workspace.output_dir(base_dir).join(&name).ok()) else { return };
match self.workspace.lookup(&target_uri) {
Some(target) => {
diff --git a/support/texlab/crates/base-db/src/lib.rs b/support/texlab/crates/base-db/src/lib.rs
index fae6ad5416..304888a42a 100644
--- a/support/texlab/crates/base-db/src/lib.rs
+++ b/support/texlab/crates/base-db/src/lib.rs
@@ -1,9 +1,10 @@
mod config;
+pub mod data;
pub mod diagnostics;
mod document;
pub mod graph;
-mod line_index;
pub mod semantics;
+pub mod util;
mod workspace;
-pub use self::{config::*, document::*, line_index::*, workspace::*};
+pub use self::{config::*, document::*, workspace::*};
diff --git a/support/texlab/crates/base-db/src/semantics.rs b/support/texlab/crates/base-db/src/semantics.rs
index 94a9c15973..1096eb2125 100644
--- a/support/texlab/crates/base-db/src/semantics.rs
+++ b/support/texlab/crates/base-db/src/semantics.rs
@@ -1,11 +1,19 @@
pub mod auxiliary;
pub mod tex;
-#[derive(Debug, PartialEq, Eq, Clone, Hash)]
+#[derive(PartialEq, Eq, Clone, Hash)]
pub struct Span {
pub text: String,
pub range: rowan::TextRange,
}
+impl std::fmt::Debug for Span {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_tuple("Span")
+ .field(&self.text)
+ .field(&self.range)
+ .finish()
+ }
+}
impl From<&syntax::latex::Key> for Span {
fn from(key: &syntax::latex::Key) -> Self {
diff --git a/support/texlab/crates/base-db/src/semantics/tex.rs b/support/texlab/crates/base-db/src/semantics/tex.rs
index 2b506ee878..6e238737b0 100644
--- a/support/texlab/crates/base-db/src/semantics/tex.rs
+++ b/support/texlab/crates/base-db/src/semantics/tex.rs
@@ -9,8 +9,8 @@ use super::Span;
pub struct Semantics {
pub links: Vec<Link>,
pub labels: Vec<Label>,
- pub commands: Vec<(TextRange, String)>,
- pub environments: FxHashSet<String>,
+ pub commands: Vec<Span>,
+ pub environments: Vec<Span>,
pub theorem_definitions: Vec<TheoremDefinition>,
pub graphics_paths: FxHashSet<String>,
pub can_be_root: bool,
@@ -29,14 +29,12 @@ impl Semantics {
let range = token.text_range();
let range = TextRange::new(range.start() + "\\".text_len(), range.end());
let text = String::from(&token.text()[1..]);
- self.commands.push((range, text));
+ self.commands.push(Span { range, text });
}
}
};
}
- self.can_be_compiled = self.environments.contains("document");
-
self.can_be_root = self.can_be_compiled
&& !self
.links
@@ -208,19 +206,21 @@ impl Semantics {
.and_then(|begin| begin.name())
.and_then(|group| group.key()) else { return };
- self.environments.insert(String::from(name.syntax().text()));
+ let name = Span::from(&name);
+ self.can_be_compiled = self.can_be_compiled || name.text == "document";
+ self.environments.push(name);
}
fn process_theorem_definition(&mut self, theorem_def: latex::TheoremDefinition) {
let Some(name) = theorem_def.name().and_then(|name| name.key()) else { return };
let Some(description) = theorem_def
- .description()
+ .heading()
.and_then(|group| group.content_text()) else { return };
self.theorem_definitions.push(TheoremDefinition {
name: Span::from(&name),
- description,
+ heading: description,
});
}
}
@@ -288,5 +288,5 @@ pub enum LabelObject {
#[derive(Debug, Clone)]
pub struct TheoremDefinition {
pub name: Span,
- pub description: String,
+ pub heading: String,
}
diff --git a/support/texlab/crates/base-db/src/util.rs b/support/texlab/crates/base-db/src/util.rs
new file mode 100644
index 0000000000..22b9309209
--- /dev/null
+++ b/support/texlab/crates/base-db/src/util.rs
@@ -0,0 +1,9 @@
+mod label;
+mod line_index;
+mod regex_filter;
+
+pub use self::{
+ label::{render_label, FloatKind, RenderedLabel, RenderedObject},
+ line_index::{LineCol, LineColUtf16, LineIndex},
+ regex_filter::filter_regex_patterns,
+};
diff --git a/support/texlab/crates/texlab/src/util/label.rs b/support/texlab/crates/base-db/src/util/label.rs
index 33b860a173..af0889bab0 100644
--- a/support/texlab/crates/texlab/src/util/label.rs
+++ b/support/texlab/crates/base-db/src/util/label.rs
@@ -1,23 +1,23 @@
use std::str::FromStr;
-use base_db::{
+use rowan::TextRange;
+
+use self::RenderedObject::*;
+
+use crate::{
semantics::tex::{Label, LabelObject},
Project, Workspace,
};
-use rowan::{ast::AstNode, TextRange};
-use syntax::latex::{self, HasCurly};
-
-use self::LabeledObject::*;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum LabeledFloatKind {
+pub enum FloatKind {
Figure,
Table,
Listing,
Algorithm,
}
-impl LabeledFloatKind {
+impl FloatKind {
pub fn as_str(self) -> &'static str {
match self {
Self::Figure => "Figure",
@@ -28,7 +28,7 @@ impl LabeledFloatKind {
}
}
-impl FromStr for LabeledFloatKind {
+impl FromStr for FloatKind {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -43,13 +43,13 @@ impl FromStr for LabeledFloatKind {
}
#[derive(Debug, PartialEq, Eq, Clone)]
-pub enum LabeledObject<'a> {
+pub enum RenderedObject<'a> {
Section {
prefix: &'a str,
text: &'a str,
},
Float {
- kind: LabeledFloatKind,
+ kind: FloatKind,
caption: &'a str,
},
Theorem {
@@ -64,7 +64,7 @@ pub enum LabeledObject<'a> {
pub struct RenderedLabel<'a> {
pub range: TextRange,
pub number: Option<&'a str>,
- pub object: LabeledObject<'a>,
+ pub object: RenderedObject<'a>,
}
impl<'a> RenderedLabel<'a> {
@@ -117,7 +117,7 @@ impl<'a> RenderedLabel<'a> {
}
}
-pub fn render<'a>(
+pub fn render_label<'a>(
workspace: &'a Workspace,
project: &Project<'a>,
label: &'a Label,
@@ -135,14 +135,14 @@ pub fn render<'a>(
return Some(RenderedLabel {
range: target.range,
number,
- object: LabeledObject::Section { prefix, text },
+ object: RenderedObject::Section { prefix, text },
});
}
LabelObject::EnumItem => {
return Some(RenderedLabel {
range: target.range,
number,
- object: LabeledObject::EnumItem,
+ object: RenderedObject::EnumItem,
});
}
LabelObject::Environment {
@@ -155,15 +155,15 @@ pub fn render<'a>(
return Some(RenderedLabel {
range: target.range,
number,
- object: LabeledObject::Equation,
+ object: RenderedObject::Equation,
});
}
- if let Ok(kind) = LabeledFloatKind::from_str(name) {
+ if let Ok(kind) = FloatKind::from_str(name) {
return Some(RenderedLabel {
range: target.range,
number,
- object: LabeledObject::Float {
+ object: RenderedObject::Float {
kind,
caption: caption.as_deref()?,
},
@@ -180,8 +180,8 @@ pub fn render<'a>(
return Some(RenderedLabel {
range: target.range,
number,
- object: LabeledObject::Theorem {
- kind: &theorem.description,
+ object: RenderedObject::Theorem {
+ kind: &theorem.heading,
description: options.as_deref(),
},
});
@@ -192,11 +192,3 @@ pub fn render<'a>(
None
}
-
-pub(crate) fn find_caption_by_parent(parent: &latex::SyntaxNode) -> Option<String> {
- parent
- .children()
- .filter_map(latex::Caption::cast)
- .find_map(|node| node.long())
- .and_then(|node| node.content_text())
-}
diff --git a/support/texlab/crates/base-db/src/line_index.rs b/support/texlab/crates/base-db/src/util/line_index.rs
index 70e8f8128b..70e8f8128b 100644
--- a/support/texlab/crates/base-db/src/line_index.rs
+++ b/support/texlab/crates/base-db/src/util/line_index.rs
diff --git a/support/texlab/crates/texlab/src/util/regex_filter.rs b/support/texlab/crates/base-db/src/util/regex_filter.rs
index a33417464e..f8d88113b5 100644
--- a/support/texlab/crates/texlab/src/util/regex_filter.rs
+++ b/support/texlab/crates/base-db/src/util/regex_filter.rs
@@ -1,6 +1,10 @@
use regex::Regex;
-pub fn filter(text: &str, allowed_patterns: &[Regex], ignored_patterns: &[Regex]) -> bool {
+pub fn filter_regex_patterns(
+ text: &str,
+ allowed_patterns: &[Regex],
+ ignored_patterns: &[Regex],
+) -> bool {
if !allowed_patterns.is_empty()
&& !allowed_patterns
.iter()
diff --git a/support/texlab/crates/base-feature/src/lib.rs b/support/texlab/crates/base-feature/src/lib.rs
deleted file mode 100644
index 589ec20de4..0000000000
--- a/support/texlab/crates/base-feature/src/lib.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-mod normalize_uri;
-mod placeholders;
-
-pub use self::{normalize_uri::normalize_uri, placeholders::*};
diff --git a/support/texlab/crates/base-feature/src/normalize_uri.rs b/support/texlab/crates/base-feature/src/normalize_uri.rs
deleted file mode 100644
index 041258e817..0000000000
--- a/support/texlab/crates/base-feature/src/normalize_uri.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use url::Url;
-
-pub fn normalize_uri(uri: &mut Url) {
- 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);
-}
-
-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,
- }
-}
-
-#[cfg(test)]
-mod tests {
- use url::Url;
-
- use super::normalize_uri;
-
- #[test]
- fn test_lowercase_drive_letter() {
- let mut uri = Url::parse("file://c:/foo/bar.txt").unwrap();
- normalize_uri(&mut uri);
- assert_eq!(uri.as_str(), "file:///C:/foo/bar.txt");
- }
-
- #[test]
- fn test_uppercase_drive_letter() {
- let mut uri = Url::parse("file://C:/foo/bar.txt").unwrap();
- normalize_uri(&mut uri);
- assert_eq!(uri.as_str(), "file:///C:/foo/bar.txt");
- }
-
- #[test]
- fn test_fragment() {
- let mut uri = Url::parse("foo:///bar/baz.txt#qux").unwrap();
- normalize_uri(&mut uri);
- assert_eq!(uri.as_str(), "foo:///bar/baz.txt");
- }
-}
diff --git a/support/texlab/crates/commands/Cargo.toml b/support/texlab/crates/commands/Cargo.toml
index e5a6f81a95..ea7358364f 100644
--- a/support/texlab/crates/commands/Cargo.toml
+++ b/support/texlab/crates/commands/Cargo.toml
@@ -9,7 +9,6 @@ rust-version.workspace = true
[dependencies]
anyhow = "1.0.70"
base-db = { path = "../base-db" }
-base-feature = { path = "../base-feature" }
bstr = "1.4.0"
crossbeam-channel = "0.5.8"
itertools = "0.10.5"
diff --git a/support/texlab/crates/commands/src/build.rs b/support/texlab/crates/commands/src/build.rs
index 9a115db888..3d93601e39 100644
--- a/support/texlab/crates/commands/src/build.rs
+++ b/support/texlab/crates/commands/src/build.rs
@@ -7,12 +7,13 @@ use std::{
use anyhow::Result;
use base_db::Workspace;
-use base_feature::replace_placeholders;
use bstr::io::BufReadExt;
use crossbeam_channel::Sender;
use thiserror::Error;
use url::Url;
+use crate::placeholders::replace_placeholders;
+
#[derive(Debug, Error)]
pub enum BuildError {
#[error("Document \"{0}\" was not found")]
diff --git a/support/texlab/crates/commands/src/fwd_search.rs b/support/texlab/crates/commands/src/fwd_search.rs
index eaa27e5013..c458f33cf1 100644
--- a/support/texlab/crates/commands/src/fwd_search.rs
+++ b/support/texlab/crates/commands/src/fwd_search.rs
@@ -6,10 +6,11 @@ use std::{
use anyhow::Result;
use base_db::Workspace;
-use base_feature::replace_placeholders;
use thiserror::Error;
use url::Url;
+use crate::placeholders::replace_placeholders;
+
#[derive(Debug, Error)]
pub enum ForwardSearchError {
#[error("Forward search is not configured")]
diff --git a/support/texlab/crates/commands/src/lib.rs b/support/texlab/crates/commands/src/lib.rs
index 6c8f1e8f4f..bcf4c8538f 100644
--- a/support/texlab/crates/commands/src/lib.rs
+++ b/support/texlab/crates/commands/src/lib.rs
@@ -3,6 +3,7 @@ mod change_env;
mod clean;
mod dep_graph;
mod fwd_search;
+mod placeholders;
pub use self::{
build::{BuildCommand, BuildError},
diff --git a/support/texlab/crates/base-feature/src/placeholders.rs b/support/texlab/crates/commands/src/placeholders.rs
index 913af33edf..913af33edf 100644
--- a/support/texlab/crates/base-feature/src/placeholders.rs
+++ b/support/texlab/crates/commands/src/placeholders.rs
diff --git a/support/texlab/crates/parser/src/config.rs b/support/texlab/crates/parser/src/config.rs
index b6f3e8476c..d2e0fb31ab 100644
--- a/support/texlab/crates/parser/src/config.rs
+++ b/support/texlab/crates/parser/src/config.rs
@@ -50,10 +50,10 @@ static DEFAULT_MATH_ENVIRONMENTS: &[&str] = &[
"alignedat*",
"array",
"array*",
- "Bmatrix",
- "Bmatrix*",
"bmatrix",
+ "Bmatrix",
"bmatrix*",
+ "Bmatrix*",
"cases",
"cases*",
"CD",
@@ -62,14 +62,14 @@ static DEFAULT_MATH_ENVIRONMENTS: &[&str] = &[
"eqnarray*",
"equation",
"equation*",
- "IEEEeqnarray",
- "IEEEeqnarray*",
- "subequations",
- "subequations*",
+ "flalign",
+ "flalign*",
"gather",
"gather*",
"gathered",
"gathered*",
+ "IEEEeqnarray",
+ "IEEEeqnarray*",
"matrix",
"matrix*",
"multline",
@@ -82,10 +82,12 @@ static DEFAULT_MATH_ENVIRONMENTS: &[&str] = &[
"split*",
"subarray",
"subarray*",
- "Vmatrix",
- "Vmatrix*",
+ "subequations",
+ "subequations*",
"vmatrix",
+ "Vmatrix",
"vmatrix*",
+ "Vmatrix*",
];
static DEFAULT_ENUM_ENVIRONMENTS: &[&str] = &["enumerate", "itemize", "description"];
diff --git a/support/texlab/crates/parser/src/latex.rs b/support/texlab/crates/parser/src/latex.rs
index f3e978a93b..c42031dcf1 100644
--- a/support/texlab/crates/parser/src/latex.rs
+++ b/support/texlab/crates/parser/src/latex.rs
@@ -44,6 +44,11 @@ impl<'a> Parser<'a> {
self.builder.token(kind.into(), text);
}
+ fn eat_remap(&mut self, kind: SyntaxKind) {
+ let (_, text) = self.lexer.eat().unwrap();
+ self.builder.token(kind.into(), text);
+ }
+
fn peek(&self) -> Option<Token> {
self.lexer.peek()
}
@@ -98,7 +103,7 @@ impl<'a> Parser<'a> {
self.eat();
self.builder.finish_node();
}
- Token::Word | Token::Comma => self.text(context),
+ Token::Pipe | Token::Word | Token::Comma => self.text(context),
Token::Eq => self.eat(),
Token::Dollar => self.formula(),
Token::CommandName(name) => match name {
@@ -141,6 +146,7 @@ impl<'a> Parser<'a> {
CommandName::EnvironmentDefinition => self.environment_definition(),
CommandName::BeginBlockComment => self.block_comment(),
CommandName::EndBlockComment => self.generic_command(),
+ CommandName::VerbatimBlock => self.verbatim_block(),
CommandName::GraphicsPath => self.graphics_path(),
},
}
@@ -158,6 +164,7 @@ impl<'a> Parser<'a> {
| Token::Whitespace
| Token::LineComment
| Token::Word
+ | Token::Pipe
| Token::Comma
) && (context.allow_comma || kind != Token::Comma)
})
@@ -219,7 +226,7 @@ impl<'a> Parser<'a> {
self.eat();
self.trivia();
match self.peek() {
- Some(Token::Word) => {
+ Some(Token::Word | Token::Pipe) => {
self.key();
}
Some(Token::CommandName(_)) => {
@@ -244,6 +251,7 @@ impl<'a> Parser<'a> {
| Token::Whitespace
| Token::LineComment
| Token::Word
+ | Token::Pipe
| Token::Comma
)
})
@@ -298,7 +306,7 @@ impl<'a> Parser<'a> {
self.eat();
self.trivia();
match self.peek() {
- Some(Token::Word) => {
+ Some(Token::Word | Token::Pipe) => {
self.key();
}
Some(_) | None => {}
@@ -334,7 +342,12 @@ impl<'a> Parser<'a> {
self.eat();
while self
.peek()
- .filter(|&kind| matches!(kind, Token::Whitespace | Token::LineComment | Token::Word))
+ .filter(|&kind| {
+ matches!(
+ kind,
+ Token::Whitespace | Token::LineComment | Token::Word | Token::Pipe
+ )
+ })
.is_some()
{
self.eat();
@@ -390,7 +403,7 @@ impl<'a> Parser<'a> {
while let Some(kind) = self.peek() {
match kind {
Token::LineBreak | Token::Whitespace | Token::LineComment => self.eat(),
- Token::Word => {
+ Token::Word | Token::Pipe => {
self.key_value_pair();
if self.peek() == Some(Token::Comma) {
self.eat();
@@ -1116,6 +1129,23 @@ impl<'a> Parser<'a> {
self.builder.finish_node();
}
+
+ fn verbatim_block(&mut self) {
+ self.builder.start_node(GENERIC_COMMAND.into());
+ self.eat();
+ self.builder.finish_node();
+ self.trivia();
+
+ if self.peek() == Some(Token::Pipe) {
+ self.eat_remap(SyntaxKind::VERBATIM);
+ while let Some(kind) = self.peek() {
+ self.eat_remap(SyntaxKind::VERBATIM);
+ if kind == Token::Pipe {
+ break;
+ }
+ }
+ }
+ }
}
pub fn parse_latex(text: &str, config: &SyntaxConfig) -> GreenNode {
diff --git a/support/texlab/crates/parser/src/latex/lexer.rs b/support/texlab/crates/parser/src/latex/lexer.rs
index e53a2ed042..47a6c43b06 100644
--- a/support/texlab/crates/parser/src/latex/lexer.rs
+++ b/support/texlab/crates/parser/src/latex/lexer.rs
@@ -38,6 +38,7 @@ impl<'a> Lexer<'a> {
Token::RParen => SyntaxKind::R_PAREN,
Token::Comma => SyntaxKind::COMMA,
Token::Eq => SyntaxKind::EQUALITY_SIGN,
+ Token::Pipe => SyntaxKind::WORD,
Token::Word => SyntaxKind::WORD,
Token::Dollar => SyntaxKind::DOLLAR,
Token::CommandName(_) => SyntaxKind::COMMAND_NAME,
diff --git a/support/texlab/crates/parser/src/latex/lexer/commands.rs b/support/texlab/crates/parser/src/latex/lexer/commands.rs
index 8354fa1bfc..c5fe48e0c9 100644
--- a/support/texlab/crates/parser/src/latex/lexer/commands.rs
+++ b/support/texlab/crates/parser/src/latex/lexer/commands.rs
@@ -80,6 +80,7 @@ pub fn classify(name: &str, config: &SyntaxConfig) -> CommandName {
"graphicspath" => CommandName::GraphicsPath,
"iffalse" => CommandName::BeginBlockComment,
"fi" => CommandName::EndBlockComment,
+ "verb" => CommandName::VerbatimBlock,
_ if config.citation_commands.contains(name) => CommandName::Citation,
_ => CommandName::Generic,
}
diff --git a/support/texlab/crates/parser/src/latex/lexer/types.rs b/support/texlab/crates/parser/src/latex/lexer/types.rs
index 4e6c67ab1f..eea6ea3b44 100644
--- a/support/texlab/crates/parser/src/latex/lexer/types.rs
+++ b/support/texlab/crates/parser/src/latex/lexer/types.rs
@@ -35,7 +35,10 @@ pub enum Token {
#[token("=")]
Eq,
- #[regex(r"[^\s\\%\{\},\$\[\]\(\)=]+")]
+ #[token("|")]
+ Pipe,
+
+ #[regex(r"[^\s\\%\{\},\$\[\]\(\)=\|]+")]
Word,
#[regex(r"\$\$?")]
@@ -117,6 +120,7 @@ pub enum CommandName {
GraphicsPath,
BeginBlockComment,
EndBlockComment,
+ VerbatimBlock,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
diff --git a/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@issue_828.txt.snap b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@issue_828.txt.snap
new file mode 100644
index 0000000000..059b957241
--- /dev/null
+++ b/support/texlab/crates/parser/src/snapshots/parser__latex__tests__parse@issue_828.txt.snap
@@ -0,0 +1,22 @@
+---
+source: crates/parser/src/latex.rs
+expression: root
+input_file: crates/parser/src/test_data/latex/issue_828.txt
+---
+ROOT@0..51
+ PREAMBLE@0..51
+ GENERIC_COMMAND@0..5
+ COMMAND_NAME@0..5 "\\verb"
+ VERBATIM@5..6 "|"
+ VERBATIM@6..17 "<STATEMENT>"
+ VERBATIM@17..22 " "
+ VERBATIM@22..24 "if"
+ VERBATIM@24..25 "("
+ VERBATIM@25..31 "<expr>"
+ VERBATIM@31..32 ")"
+ VERBATIM@32..33 "{"
+ VERBATIM@33..43 "<body>else"
+ VERBATIM@43..44 "{"
+ VERBATIM@44..50 "<body>"
+ VERBATIM@50..51 "|"
+
diff --git a/support/texlab/crates/parser/src/test_data/latex/issue_828.txt b/support/texlab/crates/parser/src/test_data/latex/issue_828.txt
new file mode 100644
index 0000000000..76f973bdbd
--- /dev/null
+++ b/support/texlab/crates/parser/src/test_data/latex/issue_828.txt
@@ -0,0 +1 @@
+\verb|<STATEMENT> if(<expr>){<body>else{<body>| \ No newline at end of file
diff --git a/support/texlab/crates/symbols/Cargo.toml b/support/texlab/crates/symbols/Cargo.toml
new file mode 100644
index 0000000000..d1d5bd2d8b
--- /dev/null
+++ b/support/texlab/crates/symbols/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "symbols"
+version = "0.0.0"
+license.workspace = true
+authors.workspace = true
+edition.workspace = true
+rust-version.workspace = true
+
+[lib]
+doctest = false
+
+[dependencies]
+base-db = { path = "../base-db" }
+distro = { path = "../distro" }
+itertools = "0.10.5"
+rowan = "0.15.11"
+syntax = { path = "../syntax" }
+titlecase = "2.2.1"
+url = "2.3.1"
+
+[dev-dependencies]
+insta = "1.29.0"
+regex = "1.7.3"
+test-utils = { path = "../test-utils" }
diff --git a/support/texlab/crates/symbols/src/document.rs b/support/texlab/crates/symbols/src/document.rs
new file mode 100644
index 0000000000..eb3d8d339f
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document.rs
@@ -0,0 +1,51 @@
+mod bib;
+mod tex;
+
+use base_db::{util, Document, DocumentData, SymbolConfig, Workspace};
+
+use crate::Symbol;
+
+pub fn document_symbols(workspace: &Workspace, document: &Document) -> Vec<Symbol> {
+ let project = workspace.project(document);
+ let mut symbols = match &document.data {
+ DocumentData::Tex(data) => {
+ let builder = tex::SymbolBuilder::new(&project, workspace.config());
+ builder.visit(&data.root_node())
+ }
+ DocumentData::Bib(data) => {
+ let builder = bib::SymbolBuilder;
+ data.root_node()
+ .children()
+ .filter_map(|node| builder.visit(&node))
+ .collect()
+ }
+ DocumentData::Aux(_)
+ | DocumentData::Log(_)
+ | DocumentData::Root
+ | DocumentData::Tectonic => Vec::new(),
+ };
+
+ filter_symbols(&mut symbols, &workspace.config().symbols);
+ symbols
+}
+
+fn filter_symbols(container: &mut Vec<Symbol>, config: &SymbolConfig) {
+ let allowed = &config.allowed_patterns;
+ let ignored = &config.ignored_patterns;
+
+ let mut i = 0;
+ while i < container.len() {
+ let symbol = &mut container[i];
+ if symbol.name.is_empty() || !util::filter_regex_patterns(&symbol.name, allowed, ignored) {
+ drop(symbol);
+ let mut symbol = container.remove(i);
+ container.append(&mut symbol.children);
+ } else {
+ filter_symbols(&mut symbol.children, config);
+ i += 1;
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/support/texlab/crates/symbols/src/document/bib.rs b/support/texlab/crates/symbols/src/document/bib.rs
new file mode 100644
index 0000000000..1e5d934a0d
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/bib.rs
@@ -0,0 +1,64 @@
+use base_db::data::{BibtexEntryType, BibtexEntryTypeCategory};
+use rowan::ast::AstNode;
+use syntax::bibtex::{self, HasName, HasType};
+
+use crate::{Symbol, SymbolKind};
+
+#[derive(Debug)]
+pub struct SymbolBuilder;
+
+impl SymbolBuilder {
+ pub fn visit(&self, node: &bibtex::SyntaxNode) -> Option<Symbol> {
+ if let Some(string) = bibtex::StringDef::cast(node.clone()) {
+ self.visit_string(&string)
+ } else if let Some(entry) = bibtex::Entry::cast(node.clone()) {
+ self.visit_entry(&entry)
+ } else {
+ None
+ }
+ }
+
+ fn visit_string(&self, string: &bibtex::StringDef) -> Option<Symbol> {
+ let name = string.name_token()?;
+ Some(Symbol {
+ name: name.text().into(),
+ kind: SymbolKind::Entry(BibtexEntryTypeCategory::String),
+ label: None,
+ full_range: string.syntax().text_range(),
+ selection_range: name.text_range(),
+ children: Vec::new(),
+ })
+ }
+
+ fn visit_entry(&self, entry: &bibtex::Entry) -> Option<Symbol> {
+ let ty = entry.type_token()?;
+ let key = entry.name_token()?;
+
+ let children = entry
+ .fields()
+ .filter_map(|field| self.visit_field(&field))
+ .collect();
+
+ let category = BibtexEntryType::find(&ty.text()[1..])
+ .map_or(BibtexEntryTypeCategory::Misc, |ty| ty.category);
+
+ Some(Symbol {
+ name: key.text().into(),
+ kind: SymbolKind::Entry(category),
+ label: None,
+ full_range: entry.syntax().text_range(),
+ selection_range: key.text_range(),
+ children,
+ })
+ }
+
+ fn visit_field(&self, field: &bibtex::Field) -> Option<Symbol> {
+ let name = field.name_token()?;
+ Some(Symbol::new_simple(
+ name.text().into(),
+ SymbolKind::Field,
+ field.syntax().text_range(),
+ name.text_range(),
+ ))
+ }
+}
diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__allowed_patterns.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__allowed_patterns.snap
new file mode 100644
index 0000000000..e22ce2a01d
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__allowed_patterns.snap
@@ -0,0 +1,31 @@
+---
+source: crates/symbols/src/document/tests.rs
+expression: "document_symbols(&fixture.workspace, document)"
+---
+[
+ Symbol {
+ name: "Enumerate",
+ kind: Enumeration,
+ label: None,
+ full_range: 98..159,
+ selection_range: 98..159,
+ children: [
+ Symbol {
+ name: "Item",
+ kind: EnumerationItem,
+ label: None,
+ full_range: 120..129,
+ selection_range: 120..129,
+ children: [],
+ },
+ Symbol {
+ name: "Item",
+ kind: EnumerationItem,
+ label: None,
+ full_range: 134..143,
+ selection_range: 134..143,
+ children: [],
+ },
+ ],
+ },
+]
diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__enumerate.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__enumerate.snap
new file mode 100644
index 0000000000..f94828c362
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__enumerate.snap
@@ -0,0 +1,62 @@
+---
+source: crates/symbols/src/document/tests.rs
+expression: "document_symbols(&fixture.workspace, document)"
+---
+[
+ Symbol {
+ name: "Enumerate",
+ kind: Enumeration,
+ label: None,
+ full_range: 43..184,
+ selection_range: 43..184,
+ children: [
+ Symbol {
+ name: "1",
+ kind: EnumerationItem,
+ label: Some(
+ Span(
+ "it:foo",
+ 70..84,
+ ),
+ ),
+ full_range: 65..88,
+ selection_range: 70..84,
+ children: [],
+ },
+ Symbol {
+ name: "Item",
+ kind: EnumerationItem,
+ label: Some(
+ Span(
+ "it:bar",
+ 98..112,
+ ),
+ ),
+ full_range: 93..116,
+ selection_range: 98..112,
+ children: [],
+ },
+ Symbol {
+ name: "Baz",
+ kind: EnumerationItem,
+ label: None,
+ full_range: 121..135,
+ selection_range: 121..135,
+ children: [],
+ },
+ Symbol {
+ name: "2",
+ kind: EnumerationItem,
+ label: Some(
+ Span(
+ "it:qux",
+ 150..164,
+ ),
+ ),
+ full_range: 140..168,
+ selection_range: 150..164,
+ children: [],
+ },
+ ],
+ },
+]
diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__equation.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__equation.snap
new file mode 100644
index 0000000000..0e284c1d71
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__equation.snap
@@ -0,0 +1,40 @@
+---
+source: crates/symbols/src/document/tests.rs
+expression: "document_symbols(&fixture.workspace, document)"
+---
+[
+ Symbol {
+ name: "Equation (1)",
+ kind: Equation,
+ label: Some(
+ Span(
+ "eq:foo",
+ 59..73,
+ ),
+ ),
+ full_range: 43..96,
+ selection_range: 59..73,
+ children: [],
+ },
+ Symbol {
+ name: "Equation",
+ kind: Equation,
+ label: Some(
+ Span(
+ "eq:bar",
+ 114..128,
+ ),
+ ),
+ full_range: 98..151,
+ selection_range: 114..128,
+ children: [],
+ },
+ Symbol {
+ name: "Equation",
+ kind: Equation,
+ label: None,
+ full_range: 153..192,
+ selection_range: 153..192,
+ children: [],
+ },
+]
diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__float.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__float.snap
new file mode 100644
index 0000000000..e9bd711c40
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__float.snap
@@ -0,0 +1,40 @@
+---
+source: crates/symbols/src/document/tests.rs
+expression: "document_symbols(&fixture.workspace, document)"
+---
+[
+ Symbol {
+ name: "Figure 1: Foo",
+ kind: Figure,
+ label: Some(
+ Span(
+ "fig:foo",
+ 83..98,
+ ),
+ ),
+ full_range: 43..111,
+ selection_range: 83..98,
+ children: [],
+ },
+ Symbol {
+ name: "Figure: Bar",
+ kind: Figure,
+ label: Some(
+ Span(
+ "fig:bar",
+ 153..168,
+ ),
+ ),
+ full_range: 113..181,
+ selection_range: 153..168,
+ children: [],
+ },
+ Symbol {
+ name: "Figure: Baz",
+ kind: Figure,
+ label: None,
+ full_range: 183..236,
+ selection_range: 183..236,
+ children: [],
+ },
+]
diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__ignored_patterns.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__ignored_patterns.snap
new file mode 100644
index 0000000000..044e2ca531
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__ignored_patterns.snap
@@ -0,0 +1,19 @@
+---
+source: crates/symbols/src/document/tests.rs
+expression: "document_symbols(&fixture.workspace, document)"
+---
+[
+ Symbol {
+ name: "Equation",
+ kind: Equation,
+ label: Some(
+ Span(
+ "eq:foo",
+ 59..73,
+ ),
+ ),
+ full_range: 43..96,
+ selection_range: 59..73,
+ children: [],
+ },
+]
diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__section.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__section.snap
new file mode 100644
index 0000000000..6cd44939cf
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__section.snap
@@ -0,0 +1,41 @@
+---
+source: crates/symbols/src/document/tests.rs
+expression: "document_symbols(&fixture.workspace, document)"
+---
+[
+ Symbol {
+ name: "Foo",
+ kind: Section,
+ label: None,
+ full_range: 43..56,
+ selection_range: 43..56,
+ children: [],
+ },
+ Symbol {
+ name: "2 Bar",
+ kind: Section,
+ label: Some(
+ Span(
+ "sec:bar",
+ 71..86,
+ ),
+ ),
+ full_range: 58..119,
+ selection_range: 71..86,
+ children: [
+ Symbol {
+ name: "Baz",
+ kind: Section,
+ label: Some(
+ Span(
+ "sec:baz",
+ 104..119,
+ ),
+ ),
+ full_range: 88..119,
+ selection_range: 104..119,
+ children: [],
+ },
+ ],
+ },
+]
diff --git a/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem.snap b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem.snap
new file mode 100644
index 0000000000..9d897532b1
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/snapshots/symbols__document__tests__theorem.snap
@@ -0,0 +1,53 @@
+---
+source: crates/symbols/src/document/tests.rs
+expression: "document_symbols(&fixture.workspace, document)"
+---
+[
+ Symbol {
+ name: "Lemma 1 (Foo)",
+ kind: Theorem,
+ label: Some(
+ Span(
+ "thm:foo",
+ 107..122,
+ ),
+ ),
+ full_range: 89..142,
+ selection_range: 107..122,
+ children: [],
+ },
+ Symbol {
+ name: "Lemma 2",
+ kind: Theorem,
+ label: Some(
+ Span(
+ "thm:bar",
+ 157..172,
+ ),
+ ),
+ full_range: 144..192,
+ selection_range: 157..172,
+ children: [],
+ },
+ Symbol {
+ name: "Lemma",
+ kind: Theorem,
+ label: Some(
+ Span(
+ "thm:baz",
+ 207..222,
+ ),
+ ),
+ full_range: 194..242,
+ selection_range: 207..222,
+ children: [],
+ },
+ Symbol {
+ name: "Lemma (Qux)",
+ kind: Theorem,
+ label: None,
+ full_range: 244..282,
+ selection_range: 244..282,
+ children: [],
+ },
+]
diff --git a/support/texlab/crates/symbols/src/document/tests.rs b/support/texlab/crates/symbols/src/document/tests.rs
new file mode 100644
index 0000000000..dcb3c17a7c
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/tests.rs
@@ -0,0 +1,250 @@
+use base_db::{Config, SymbolConfig};
+use insta::assert_debug_snapshot;
+use regex::Regex;
+use test_utils::fixture::Fixture;
+
+use crate::document_symbols;
+
+#[test]
+fn test_enumerate() {
+ let fixture = Fixture::parse(
+ r#"
+%! main.tex
+\documentclass{article}
+
+\begin{document}
+
+\begin{enumerate}
+ \item\label{it:foo} Foo
+ \item\label{it:bar} Bar
+ \item[Baz] Baz
+ \item[Qux]\label{it:qux} Qux
+\end{enumerate}
+
+\end{document}
+
+%! main.aux
+\relax
+\newlabel{it:foo}{{1}{1}}
+\newlabel{it:qux}{{2}{1}}"#,
+ );
+
+ let document = fixture.workspace.lookup(&fixture.documents[0].uri).unwrap();
+ assert_debug_snapshot!(document_symbols(&fixture.workspace, document));
+}
+
+#[test]
+fn test_equation() {
+ let fixture = Fixture::parse(
+ r#"
+%! main.tex
+\documentclass{article}
+
+\begin{document}
+
+\begin{equation}\label{eq:foo}
+ Foo
+\end{equation}
+
+\begin{equation}\label{eq:bar}
+ Bar
+\end{equation}
+
+\begin{equation}
+ Baz
+\end{equation}
+
+\end{document}
+
+%! main.aux
+\relax
+\newlabel{eq:foo}{{1}{1}}"#,
+ );
+
+ let document = fixture.workspace.lookup(&fixture.documents[0].uri).unwrap();
+ assert_debug_snapshot!(document_symbols(&fixture.workspace, document));
+}
+
+#[test]
+fn test_float() {
+ let fixture = Fixture::parse(
+ r#"
+%! main.tex
+\documentclass{article}
+
+\begin{document}
+
+\begin{figure}
+ Foo
+ \caption{Foo}\label{fig:foo}
+\end{figure}
+
+\begin{figure}
+ Bar
+ \caption{Bar}\label{fig:bar}
+\end{figure}
+
+\begin{figure}
+ Baz
+ \caption{Baz}
+\end{figure}
+
+\begin{figure}
+ Qux
+\end{figure}
+
+\end{document}
+|
+
+%! main.aux
+\relax
+\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Foo}}{1}\protected@file@percent }
+\newlabel{fig:foo}{{1}{1}}
+\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Bar}}{1}\protected@file@percent }
+\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Baz}}{1}\protected@file@percent }"#,
+ );
+
+ let document = fixture.workspace.lookup(&fixture.documents[0].uri).unwrap();
+ assert_debug_snapshot!(document_symbols(&fixture.workspace, document));
+}
+
+#[test]
+fn test_section() {
+ let fixture = Fixture::parse(
+ r#"
+%! main.tex
+\documentclass{article}
+
+\begin{document}
+
+\section{Foo}
+
+\section{Bar}\label{sec:bar}
+
+\subsection{Baz}\label{sec:baz}
+
+\end{document}
+|
+
+%! main.aux
+\relax
+\@writefile{toc}{\contentsline {section}{\numberline {1}Foo}{1}\protected@file@percent }
+\@writefile{toc}{\contentsline {section}{\numberline {2}Bar}{1}\protected@file@percent }
+\newlabel{sec:bar}{{2}{1}}"#,
+ );
+
+ let document = fixture.workspace.lookup(&fixture.documents[0].uri).unwrap();
+ assert_debug_snapshot!(document_symbols(&fixture.workspace, document));
+}
+
+#[test]
+fn test_theorem() {
+ let fixture = Fixture::parse(
+ r#"
+%! main.tex
+\documentclass{article}
+\usepackage{amsthm}
+\newtheorem{lemma}{Lemma}
+
+\begin{document}
+
+\begin{lemma}[Foo]\label{thm:foo}
+ Foo
+\end{lemma}
+
+\begin{lemma}\label{thm:bar}
+ Bar
+\end{lemma}
+
+\begin{lemma}\label{thm:baz}
+ Baz
+\end{lemma}
+
+\begin{lemma}[Qux]
+ Qux
+\end{lemma}
+
+\end{document}
+|
+
+%! main.aux
+\relax
+\newlabel{thm:foo}{{1}{1}}
+\newlabel{thm:bar}{{2}{1}}"#,
+ );
+
+ let document = fixture.workspace.lookup(&fixture.documents[0].uri).unwrap();
+ assert_debug_snapshot!(document_symbols(&fixture.workspace, document));
+}
+
+#[test]
+fn test_allowed_patterns() {
+ let mut fixture = Fixture::parse(
+ r#"
+%! main.tex
+\documentclass{article}
+
+\begin{document}
+
+\begin{equation}\label{eq:foo}
+ Foo
+\end{equation}
+
+\begin{enumerate}
+ \item Foo
+ \item Bar
+\end{enumerate}
+
+\end{document}"#,
+ );
+
+ fixture.workspace.set_config(Config {
+ symbols: SymbolConfig {
+ allowed_patterns: vec![
+ Regex::new("Item").unwrap(),
+ Regex::new("Enumerate").unwrap(),
+ ],
+ ignored_patterns: Vec::new(),
+ },
+ ..Config::default()
+ });
+
+ let document = fixture.workspace.lookup(&fixture.documents[0].uri).unwrap();
+ assert_debug_snapshot!(document_symbols(&fixture.workspace, document));
+}
+
+#[test]
+fn test_ignored_patterns() {
+ let mut fixture = Fixture::parse(
+ r#"
+%! main.tex
+\documentclass{article}
+
+\begin{document}
+
+\begin{equation}\label{eq:foo}
+ Foo
+\end{equation}
+
+\begin{enumerate}
+ \item Foo
+ \item Bar
+\end{enumerate}
+
+\end{document}"#,
+ );
+
+ fixture.workspace.set_config(Config {
+ symbols: SymbolConfig {
+ ignored_patterns: vec![
+ Regex::new("Item").unwrap(),
+ Regex::new("Enumerate").unwrap(),
+ ],
+ allowed_patterns: Vec::new(),
+ },
+ ..Config::default()
+ });
+
+ let document = fixture.workspace.lookup(&fixture.documents[0].uri).unwrap();
+ assert_debug_snapshot!(document_symbols(&fixture.workspace, document));
+}
diff --git a/support/texlab/crates/symbols/src/document/tex.rs b/support/texlab/crates/symbols/src/document/tex.rs
new file mode 100644
index 0000000000..55612ee11d
--- /dev/null
+++ b/support/texlab/crates/symbols/src/document/tex.rs
@@ -0,0 +1,257 @@
+use std::str::FromStr;
+
+use base_db::{semantics::Span, util::FloatKind, Config, Project};
+use rowan::ast::AstNode;
+use syntax::latex::{self, HasBrack, HasCurly, LatexLanguage};
+use titlecase::titlecase;
+
+use crate::{Symbol, SymbolKind};
+
+#[derive(Debug)]
+pub struct SymbolBuilder<'a> {
+ project: &'a Project<'a>,
+ config: &'a Config,
+}
+
+impl<'a> SymbolBuilder<'a> {
+ pub fn new(project: &'a Project<'a>, config: &'a Config) -> Self {
+ Self { project, config }
+ }
+
+ pub fn visit(&self, node: &latex::SyntaxNode) -> Vec<Symbol> {
+ let symbol = if let Some(section) = latex::Section::cast(node.clone()) {
+ self.visit_section(&section)
+ } else if let Some(enum_item) = latex::EnumItem::cast(node.clone()) {
+ self.visit_enum_item(&enum_item)
+ } else if let Some(equation) = latex::Equation::cast(node.clone()) {
+ self.visit_equation(&equation)
+ } else if let Some(environment) = latex::Environment::cast(node.clone()) {
+ environment.begin().and_then(|begin| {
+ let name = begin.name()?.key()?.to_string();
+ if self.config.syntax.math_environments.contains(&name) {
+ self.visit_equation(&environment)
+ } else if self.config.syntax.enum_environments.contains(&name) {
+ self.visit_enumeration(&environment, &name)
+ } else if let Ok(float_kind) = FloatKind::from_str(&name) {
+ self.visit_float(&environment, float_kind)
+ } else {
+ self.visit_theorem(&environment, &name)
+ }
+ })
+ } else {
+ None
+ };
+
+ match symbol {
+ Some(mut parent) => {
+ for child in node.children() {
+ parent.children.append(&mut self.visit(&child));
+ }
+
+ vec![parent]
+ }
+ None => {
+ let mut symbols = Vec::new();
+ for child in node.children() {
+ symbols.append(&mut self.visit(&child));
+ }
+
+ symbols
+ }
+ }
+ }
+
+ fn visit_section(&self, section: &latex::Section) -> Option<Symbol> {
+ let range = latex::small_range(section);
+ let group = section.name()?;
+ let group_text = group.content_text()?;
+ let kind = SymbolKind::Section;
+
+ let symbol = match self.find_label(section.syntax()) {
+ Some(label) => {
+ let name = match self.find_label_number(&label.text) {
+ Some(number) => format!("{number} {group_text}"),
+ None => group_text,
+ };
+
+ Symbol::new_label(name, kind, range, label)
+ }
+ None => Symbol::new_simple(group_text, kind, range, range),
+ };
+
+ Some(symbol)
+ }
+
+ fn visit_enum_item(&self, enum_item: &latex::EnumItem) -> Option<Symbol> {
+ let enum_envs = &self.config.syntax.enum_environments;
+ if !enum_item
+ .syntax()
+ .ancestors()
+ .filter_map(latex::Environment::cast)
+ .filter_map(|environment| environment.begin())
+ .filter_map(|begin| begin.name())
+ .filter_map(|name| name.key())
+ .any(|name| enum_envs.contains(&name.to_string()))
+ {
+ return None;
+ }
+
+ let range = latex::small_range(enum_item);
+ let kind = SymbolKind::EnumerationItem;
+ let name = enum_item
+ .label()
+ .and_then(|label| label.content_text())
+ .unwrap_or_else(|| "Item".into());
+
+ let symbol = match self.find_label(enum_item.syntax()) {
+ Some(label) => {
+ let name = self
+ .find_label_number(&label.text)
+ .map_or_else(|| name.clone(), String::from);
+
+ Symbol::new_label(name, kind, range, label)
+ }
+ None => Symbol::new_simple(name, kind, range, range),
+ };
+
+ Some(symbol)
+ }
+
+ fn visit_theorem(&self, environment: &latex::Environment, name: &str) -> Option<Symbol> {
+ let heading = self
+ .project
+ .documents
+ .iter()
+ .filter_map(|document| document.data.as_tex())
+ .flat_map(|data| data.semantics.theorem_definitions.iter())
+ .find(|theorem| theorem.name.text == name)
+ .map(|theorem| theorem.heading.as_str())?;
+
+ let options = environment.begin().and_then(|begin| begin.options());
+ let caption = options.and_then(|options| options.content_text());
+ let range = latex::small_range(environment);
+ let kind = SymbolKind::Theorem;
+
+ let symbol = match self.find_label(environment.syntax()) {
+ Some(label) => {
+ let name = match (self.find_label_number(&label.text), caption) {
+ (Some(number), Some(caption)) => {
+ format!("{heading} {number} ({caption})")
+ }
+ (Some(number), None) => format!("{heading} {number}"),
+ (None, Some(caption)) => format!("{heading} ({caption})"),
+ (None, None) => heading.into(),
+ };
+
+ Symbol::new_label(name, kind, range, label)
+ }
+ None => {
+ let name = caption.map_or_else(
+ || heading.into(),
+ |caption| format!("{heading} ({caption})"),
+ );
+
+ Symbol::new_simple(name, kind, range, range)
+ }
+ };
+
+ Some(symbol)
+ }
+
+ fn visit_float(
+ &self,
+ environment: &latex::Environment,
+ float_kind: FloatKind,
+ ) -> Option<Symbol> {
+ let range = latex::small_range(environment);
+
+ let (float_kind, symbol_kind) = match float_kind {
+ FloatKind::Algorithm => ("Algorithm", SymbolKind::Algorithm),
+ FloatKind::Figure => ("Figure", SymbolKind::Figure),
+ FloatKind::Listing => ("Listing", SymbolKind::Listing),
+ FloatKind::Table => ("Table", SymbolKind::Table),
+ };
+
+ let caption = environment
+ .syntax()
+ .children()
+ .filter_map(latex::Caption::cast)
+ .find_map(|node| node.long())
+ .and_then(|node| node.content_text())?;
+
+ let symbol = match self.find_label(environment.syntax()) {
+ Some(label) => {
+ let name = match self.find_label_number(&label.text) {
+ Some(number) => format!("{float_kind} {number}: {caption}"),
+ None => format!("{float_kind}: {caption}"),
+ };
+
+ Symbol::new_label(name, symbol_kind, range, label)
+ }
+ None => {
+ let name = format!("{float_kind}: {caption}");
+ Symbol::new_simple(name, symbol_kind, range, range)
+ }
+ };
+
+ Some(symbol)
+ }
+
+ fn visit_enumeration(
+ &self,
+ environment: &latex::Environment,
+ environment_name: &str,
+ ) -> Option<Symbol> {
+ let range = latex::small_range(environment);
+
+ let kind = SymbolKind::Enumeration;
+ let name = titlecase(environment_name);
+ let symbol = match self.find_label(environment.syntax()) {
+ Some(label) => {
+ let name = match self.find_label_number(&label.text) {
+ Some(number) => format!("{name} {number}"),
+ None => name,
+ };
+
+ Symbol::new_label(name, kind, range, label)
+ }
+ None => Symbol::new_simple(name, kind, range, range),
+ };
+
+ Some(symbol)
+ }
+
+ fn visit_equation(&self, node: &dyn AstNode<Language = LatexLanguage>) -> Option<Symbol> {
+ let range = latex::small_range(node);
+ let kind = SymbolKind::Equation;
+ let symbol = match self.find_label(node.syntax()) {
+ Some(label) => {
+ let name = match self.find_label_number(&label.text) {
+ Some(number) => format!("Equation ({number})"),
+ None => "Equation".into(),
+ };
+
+ Symbol::new_label(name, kind, range, label)
+ }
+ None => Symbol::new_simple("Equation".into(), kind, range, range),
+ };
+
+ Some(symbol)
+ }
+
+ fn find_label(&self, parent: &latex::SyntaxNode) -> Option<Span> {
+ let label = parent.children().find_map(latex::LabelDefinition::cast)?;
+ let range = latex::small_range(&label);
+ let text = label.name()?.key()?.to_string();
+ Some(Span { text, range })
+ }
+
+ fn find_label_number(&self, name: &str) -> Option<&str> {
+ self.project
+ .documents
+ .iter()
+ .filter_map(|document| document.data.as_aux())
+ .find_map(|data| data.semantics.label_numbers.get(name))
+ .map(String::as_str)
+ }
+}
diff --git a/support/texlab/crates/symbols/src/lib.rs b/support/texlab/crates/symbols/src/lib.rs
new file mode 100644
index 0000000000..99822a1993
--- /dev/null
+++ b/support/texlab/crates/symbols/src/lib.rs
@@ -0,0 +1,9 @@
+mod document;
+mod types;
+mod workspace;
+
+pub use self::{
+ document::document_symbols,
+ types::{Symbol, SymbolKind, SymbolLocation},
+ workspace::workspace_symbols,
+};
diff --git a/support/texlab/crates/symbols/src/types.rs b/support/texlab/crates/symbols/src/types.rs
new file mode 100644
index 0000000000..d78f9af200
--- /dev/null
+++ b/support/texlab/crates/symbols/src/types.rs
@@ -0,0 +1,89 @@
+use base_db::{data::BibtexEntryTypeCategory, semantics::Span, Document};
+use rowan::TextRange;
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum SymbolKind {
+ Section,
+ Figure,
+ Algorithm,
+ Table,
+ Listing,
+ Enumeration,
+ EnumerationItem,
+ Theorem,
+ Equation,
+ Entry(BibtexEntryTypeCategory),
+ Field,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct Symbol {
+ pub name: String,
+ pub kind: SymbolKind,
+ pub label: Option<Span>,
+ pub full_range: TextRange,
+ pub selection_range: TextRange,
+ pub children: Vec<Symbol>,
+}
+
+impl Symbol {
+ pub fn new_simple(
+ name: String,
+ kind: SymbolKind,
+ full_range: TextRange,
+ selection_range: TextRange,
+ ) -> Self {
+ Self {
+ name,
+ kind,
+ label: None,
+ full_range,
+ selection_range,
+ children: Vec::new(),
+ }
+ }
+
+ pub fn new_label(name: String, kind: SymbolKind, range: TextRange, label: Span) -> Self {
+ Self {
+ name,
+ kind,
+ full_range: range,
+ selection_range: label.range,
+ label: Some(label),
+ children: Vec::new(),
+ }
+ }
+
+ pub fn keywords<'a>(&'a self) -> Vec<&'a str> {
+ match self.kind {
+ SymbolKind::Section => vec![&self.name, "latex", "section"],
+ SymbolKind::Figure => vec![&self.name, "latex", "float", "figure"],
+ SymbolKind::Algorithm => vec![&self.name, "latex", "float", "algorithm"],
+ SymbolKind::Table => vec![&self.name, "latex", "float", "table"],
+ SymbolKind::Listing => vec![&self.name, "latex", "float", "listing"],
+ SymbolKind::Enumeration => vec![&self.name, "latex", "enumeration"],
+ SymbolKind::EnumerationItem => vec![&self.name, "latex", "enumeration", "item"],
+ SymbolKind::Theorem => vec![&self.name, "latex", "math"],
+ SymbolKind::Equation => vec![&self.name, "latex", "math", "equation"],
+ SymbolKind::Entry(BibtexEntryTypeCategory::String) => {
+ vec![&self.name, "bibtex", "string"]
+ }
+ SymbolKind::Entry(_) => vec![&self.name, "bibtex", "entry"],
+ SymbolKind::Field => vec![&self.name, "bibtex", "field"],
+ }
+ }
+
+ pub fn flatten(mut self, buffer: &mut Vec<Self>) {
+ for symbol in self.children.drain(..) {
+ symbol.flatten(buffer);
+ }
+
+ buffer.push(self);
+ }
+}
+
+#[derive(Debug)]
+pub struct SymbolLocation<'a> {
+ pub document: &'a Document,
+ pub symbol: Symbol,
+}
diff --git a/support/texlab/crates/symbols/src/workspace.rs b/support/texlab/crates/symbols/src/workspace.rs
new file mode 100644
index 0000000000..ad9206b2c5
--- /dev/null
+++ b/support/texlab/crates/symbols/src/workspace.rs
@@ -0,0 +1,47 @@
+mod sort;
+
+use std::cmp::Reverse;
+
+use base_db::Workspace;
+
+use crate::{document_symbols, types::SymbolLocation, SymbolKind};
+
+use self::sort::ProjectOrdering;
+
+pub fn workspace_symbols<'a>(workspace: &'a Workspace, query: &str) -> Vec<SymbolLocation<'a>> {
+ let query = query.split_whitespace().collect::<Vec<_>>();
+ let mut results = Vec::new();
+
+ for document in workspace.iter() {
+ let mut buf = Vec::new();
+ let symbols = document_symbols(workspace, document);
+ for symbol in symbols {
+ symbol.flatten(&mut buf);
+ }
+
+ for symbol in buf
+ .into_iter()
+ .filter(|symbol| symbol.kind != SymbolKind::Field)
+ {
+ let keywords = symbol.keywords();
+ if query.is_empty()
+ || itertools::iproduct!(keywords.iter(), query.iter())
+ .any(|(keyword, query)| keyword.eq_ignore_ascii_case(query))
+ {
+ results.push(SymbolLocation { document, symbol });
+ }
+ }
+ }
+
+ let ordering = ProjectOrdering::from(workspace);
+ results.sort_by_key(|item| {
+ let index = ordering.get(&item.document.uri);
+ let range = item.symbol.full_range;
+ (index, range.start(), Reverse(range.end()))
+ });
+
+ results
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_bibtex.snap b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_bibtex.snap
new file mode 100644
index 0000000000..5bd00182b0
--- /dev/null
+++ b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_bibtex.snap
@@ -0,0 +1,36 @@
+---
+source: crates/symbols/src/workspace/tests.rs
+expression: "workspace_symbols(&fixture.workspace, \"bibtex\")"
+---
+[
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.bib",
+ ),
+ symbol: Symbol {
+ name: "foo",
+ kind: Entry(
+ Article,
+ ),
+ label: None,
+ full_range: 0..14,
+ selection_range: 9..12,
+ children: [],
+ },
+ },
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.bib",
+ ),
+ symbol: Symbol {
+ name: "bar",
+ kind: Entry(
+ String,
+ ),
+ label: None,
+ full_range: 16..36,
+ selection_range: 24..27,
+ children: [],
+ },
+ },
+]
diff --git a/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_figure.snap b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_figure.snap
new file mode 100644
index 0000000000..412e7c14d2
--- /dev/null
+++ b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_figure.snap
@@ -0,0 +1,24 @@
+---
+source: crates/symbols/src/workspace/tests.rs
+expression: "workspace_symbols(&fixture.workspace, \"figure\")"
+---
+[
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "Figure 1: Bar",
+ kind: Figure,
+ label: Some(
+ Span(
+ "fig:bar",
+ 265..280,
+ ),
+ ),
+ full_range: 220..293,
+ selection_range: 265..280,
+ children: [],
+ },
+ },
+]
diff --git a/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_item.snap b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_item.snap
new file mode 100644
index 0000000000..993d046d3d
--- /dev/null
+++ b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_item.snap
@@ -0,0 +1,60 @@
+---
+source: crates/symbols/src/workspace/tests.rs
+expression: "workspace_symbols(&fixture.workspace, \"item\")"
+---
+[
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "1",
+ kind: EnumerationItem,
+ label: Some(
+ Span(
+ "itm:foo",
+ 352..367,
+ ),
+ ),
+ full_range: 347..371,
+ selection_range: 352..367,
+ children: [],
+ },
+ },
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "2",
+ kind: EnumerationItem,
+ label: Some(
+ Span(
+ "itm:bar",
+ 381..396,
+ ),
+ ),
+ full_range: 376..400,
+ selection_range: 381..396,
+ children: [],
+ },
+ },
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "3",
+ kind: EnumerationItem,
+ label: Some(
+ Span(
+ "itm:baz",
+ 410..425,
+ ),
+ ),
+ full_range: 405..429,
+ selection_range: 410..425,
+ children: [],
+ },
+ },
+]
diff --git a/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_math.snap b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_math.snap
new file mode 100644
index 0000000000..60a002fba5
--- /dev/null
+++ b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_math.snap
@@ -0,0 +1,42 @@
+---
+source: crates/symbols/src/workspace/tests.rs
+expression: "workspace_symbols(&fixture.workspace, \"math\")"
+---
+[
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "Equation (1)",
+ kind: Equation,
+ label: Some(
+ Span(
+ "eq:foo",
+ 151..165,
+ ),
+ ),
+ full_range: 135..188,
+ selection_range: 151..165,
+ children: [],
+ },
+ },
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "Lemma 1 (Qux)",
+ kind: Theorem,
+ label: Some(
+ Span(
+ "thm:qux",
+ 522..537,
+ ),
+ ),
+ full_range: 504..557,
+ selection_range: 522..537,
+ children: [],
+ },
+ },
+]
diff --git a/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_section.snap b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_section.snap
new file mode 100644
index 0000000000..4cf0cb5fe2
--- /dev/null
+++ b/support/texlab/crates/symbols/src/workspace/snapshots/symbols__workspace__tests__filter_type_section.snap
@@ -0,0 +1,78 @@
+---
+source: crates/symbols/src/workspace/tests.rs
+expression: "workspace_symbols(&fixture.workspace, \"section\")"
+---
+[
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "1 Foo",
+ kind: Section,
+ label: Some(
+ Span(
+ "sec:foo",
+ 118..133,
+ ),
+ ),
+ full_range: 105..188,
+ selection_range: 118..133,
+ children: [],
+ },
+ },
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "2 Bar",
+ kind: Section,
+ label: Some(
+ Span(
+ "sec:bar",
+ 203..218,
+ ),
+ ),
+ full_range: 190..293,
+ selection_range: 203..218,
+ children: [],
+ },
+ },
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "3 Baz",
+ kind: Section,
+ label: Some(
+ Span(
+ "sec:baz",
+ 308..323,
+ ),
+ ),
+ full_range: 295..445,
+ selection_range: 308..323,
+ children: [],
+ },
+ },
+ SymbolLocation {
+ document: Document(
+ "file:///texlab/main.tex",
+ ),
+ symbol: Symbol {
+ name: "4 Qux",
+ kind: Section,
+ label: Some(
+ Span(
+ "sec:qux",
+ 460..475,
+ ),
+ ),
+ full_range: 447..557,
+ selection_range: 460..475,
+ children: [],
+ },
+ },
+]
diff --git a/support/texlab/crates/texlab/src/features/symbol/project_order.rs b/support/texlab/crates/symbols/src/workspace/sort.rs
index 9dfb146f2b..bc30728da9 100644
--- a/support/texlab/crates/texlab/src/features/symbol/project_order.rs
+++ b/support/texlab/crates/symbols/src/workspace/sort.rs
@@ -1,40 +1,38 @@
use base_db::{graph, Document, Workspace};
use itertools::Itertools;
-use lsp_types::Url;
+use url::Url;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ProjectOrdering<'a> {
- ordering: Vec<&'a Document>,
+ inner: Vec<&'a Document>,
}
impl<'a> ProjectOrdering<'a> {
- pub fn new(workspace: &'a Workspace) -> Self {
- let ordering: Vec<_> = workspace
+ pub fn get(&self, uri: &Url) -> usize {
+ self.inner
+ .iter()
+ .position(|doc| doc.uri == *uri)
+ .unwrap_or(std::usize::MAX)
+ }
+}
+
+impl<'a> From<&'a Workspace> for ProjectOrdering<'a> {
+ fn from(workspace: &'a Workspace) -> Self {
+ let inner = workspace
.iter()
.filter(|document| {
- document
- .data
- .as_tex()
- .map_or(false, |data| data.semantics.can_be_root)
+ let data = document.data.as_tex();
+ data.map_or(false, |data| data.semantics.can_be_root)
})
.chain(workspace.iter())
.flat_map(|document| {
- graph::Graph::new(workspace, document)
- .preorder()
- .rev()
- .collect_vec()
+ let graph = graph::Graph::new(workspace, document);
+ graph.preorder().rev().collect_vec()
})
.unique()
- .collect();
+ .collect_vec();
- Self { ordering }
- }
-
- pub fn get(&self, uri: &Url) -> usize {
- self.ordering
- .iter()
- .position(|doc| doc.uri == *uri)
- .unwrap_or(std::usize::MAX)
+ Self { inner }
}
}
@@ -44,7 +42,7 @@ mod tests {
use distro::Language;
use rowan::TextSize;
- use super::*;
+ use super::{ProjectOrdering, Url, Workspace};
#[test]
fn test_no_cycles() {
@@ -78,7 +76,7 @@ mod tests {
TextSize::default(),
);
- let ordering = ProjectOrdering::new(&workspace);
+ let ordering = ProjectOrdering::from(&workspace);
assert_eq!(ordering.get(&a), 0);
assert_eq!(ordering.get(&b), 1);
assert_eq!(ordering.get(&c), 2);
@@ -99,6 +97,7 @@ mod tests {
Owner::Client,
TextSize::default(),
);
+
workspace.open(
b.clone(),
r#"\include{a}"#.to_string(),
@@ -106,6 +105,7 @@ mod tests {
Owner::Client,
TextSize::default(),
);
+
workspace.open(
c.clone(),
r#"\begin{documnent}\include{b}\end{document}"#.to_string(),
@@ -114,7 +114,7 @@ mod tests {
TextSize::default(),
);
- let ordering = ProjectOrdering::new(&workspace);
+ let ordering = ProjectOrdering::from(&workspace);
assert_eq!(ordering.get(&a), 0);
assert_eq!(ordering.get(&b), 1);
assert_eq!(ordering.get(&c), 2);
@@ -151,7 +151,7 @@ mod tests {
TextSize::default(),
);
- let ordering = ProjectOrdering::new(&workspace);
+ let ordering = ProjectOrdering::from(&workspace);
assert_ne!(ordering.get(&a), 0);
}
@@ -196,7 +196,7 @@ mod tests {
TextSize::default(),
);
- let ordering = ProjectOrdering::new(&workspace);
+ let ordering = ProjectOrdering::from(&workspace);
assert!(ordering.get(&b) < ordering.get(&a));
assert!(ordering.get(&c) < ordering.get(&d));
}
diff --git a/support/texlab/crates/symbols/src/workspace/tests.rs b/support/texlab/crates/symbols/src/workspace/tests.rs
new file mode 100644
index 0000000000..1231be869d
--- /dev/null
+++ b/support/texlab/crates/symbols/src/workspace/tests.rs
@@ -0,0 +1,99 @@
+use insta::assert_debug_snapshot;
+use test_utils::fixture::Fixture;
+
+use crate::workspace_symbols;
+
+static FIXTURE: &str = r#"
+%! main.tex
+\documentclass{article}
+\usepackage{caption}
+\usepackage{amsmath}
+\usepackage{amsthm}
+
+\begin{document}
+
+\section{Foo}\label{sec:foo}
+
+\begin{equation}\label{eq:foo}
+ Foo
+\end{equation}
+
+\section{Bar}\label{sec:bar}
+
+\begin{figure}
+ Bar
+ \caption{Bar}
+ \label{fig:bar}
+\end{figure}
+
+\section{Baz}\label{sec:baz}
+
+\begin{enumerate}
+ \item\label{itm:foo} Foo
+ \item\label{itm:bar} Bar
+ \item\label{itm:baz} Baz
+\end{enumerate}
+
+\section{Qux}\label{sec:qux}
+
+\newtheorem{lemma}{Lemma}
+
+\begin{lemma}[Qux]\label{thm:qux}
+ Qux
+\end{lemma}
+
+\end{document}
+
+%! main.aux
+\relax
+\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Bar\relax }}{1}\protected@file@percent }
+\providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}}
+\newlabel{fig:bar}{{1}{1}}
+\@writefile{toc}{\contentsline {section}{\numberline {1}Foo}{1}\protected@file@percent }
+\newlabel{sec:foo}{{1}{1}}
+\newlabel{eq:foo}{{1}{1}}
+\@writefile{toc}{\contentsline {section}{\numberline {2}Bar}{1}\protected@file@percent }
+\newlabel{sec:bar}{{2}{1}}
+\@writefile{toc}{\contentsline {section}{\numberline {3}Baz}{1}\protected@file@percent }
+\newlabel{sec:baz}{{3}{1}}
+\newlabel{itm:foo}{{1}{1}}
+\newlabel{itm:bar}{{2}{1}}
+\newlabel{itm:baz}{{3}{1}}
+\@writefile{toc}{\contentsline {section}{\numberline {4}Qux}{1}\protected@file@percent }
+\newlabel{sec:qux}{{4}{1}}
+\newlabel{thm:qux}{{1}{1}}
+
+%! main.bib
+@article{foo,}
+
+@string{bar = "bar"}"#;
+
+#[test]
+fn filter_type_section() {
+ let fixture = Fixture::parse(FIXTURE);
+ assert_debug_snapshot!(workspace_symbols(&fixture.workspace, "section"));
+}
+
+#[test]
+fn filter_type_figure() {
+ let fixture = Fixture::parse(FIXTURE);
+ assert_debug_snapshot!(workspace_symbols(&fixture.workspace, "figure"));
+}
+
+#[test]
+fn filter_type_item() {
+ let fixture = Fixture::parse(FIXTURE);
+ assert_debug_snapshot!(workspace_symbols(&fixture.workspace, "item"));
+}
+
+#[test]
+fn filter_type_math() {
+ let fixture = Fixture::parse(FIXTURE);
+ assert_debug_snapshot!(workspace_symbols(&fixture.workspace, "math"));
+}
+
+#[test]
+fn filter_bibtex() {
+ let fixture = Fixture::parse(FIXTURE);
+ assert_debug_snapshot!(workspace_symbols(&fixture.workspace, "bibtex"));
+}
diff --git a/support/texlab/crates/syntax/src/latex/cst.rs b/support/texlab/crates/syntax/src/latex/cst.rs
index 767aa50ecc..be64557886 100644
--- a/support/texlab/crates/syntax/src/latex/cst.rs
+++ b/support/texlab/crates/syntax/src/latex/cst.rs
@@ -539,7 +539,7 @@ impl TheoremDefinition {
self.syntax().children().find_map(CurlyGroupWord::cast)
}
- pub fn description(&self) -> Option<CurlyGroup> {
+ pub fn heading(&self) -> Option<CurlyGroup> {
self.syntax().children().find_map(CurlyGroup::cast)
}
}
diff --git a/support/texlab/crates/base-feature/Cargo.toml b/support/texlab/crates/test-utils/Cargo.toml
index efd9247f78..4ce7b1a5ca 100644
--- a/support/texlab/crates/base-feature/Cargo.toml
+++ b/support/texlab/crates/test-utils/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "base-feature"
+name = "test-utils"
version = "0.0.0"
license.workspace = true
authors.workspace = true
@@ -7,7 +7,10 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
-rustc-hash = "1.1.0"
+base-db = { path = "../base-db" }
+distro = { path = "../distro" }
+rowan = "0.15.11"
+syntax = { path = "../syntax" }
url = "2.3.1"
[lib]
diff --git a/support/texlab/crates/test-utils/src/fixture.rs b/support/texlab/crates/test-utils/src/fixture.rs
new file mode 100644
index 0000000000..2935b4f519
--- /dev/null
+++ b/support/texlab/crates/test-utils/src/fixture.rs
@@ -0,0 +1,103 @@
+use std::path::PathBuf;
+
+use base_db::{Owner, Workspace};
+use rowan::{TextRange, TextSize};
+use url::Url;
+
+#[derive(Debug)]
+pub struct Fixture {
+ pub workspace: Workspace,
+ pub documents: Vec<DocumentSpec>,
+}
+
+impl Fixture {
+ pub fn parse(input: &str) -> Fixture {
+ let mut documents = Vec::new();
+
+ let mut start = 0;
+ for end in input
+ .match_indices("%!")
+ .skip(1)
+ .map(|(i, _)| i)
+ .chain(std::iter::once(input.len()))
+ {
+ documents.push(DocumentSpec::parse(&input[start..end]));
+ start = end;
+ }
+
+ let mut workspace = Workspace::default();
+ for document in &documents {
+ let path = PathBuf::from(document.uri.path());
+ let language = distro::Language::from_path(&path).unwrap_or(distro::Language::Tex);
+
+ workspace.open(
+ document.uri.clone(),
+ document.text.clone(),
+ language,
+ Owner::Client,
+ TextSize::from(0),
+ );
+ }
+
+ Self {
+ workspace,
+ documents,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct DocumentSpec {
+ pub uri: Url,
+ pub text: String,
+ pub cursor: Option<TextSize>,
+ pub ranges: Vec<TextRange>,
+}
+
+impl DocumentSpec {
+ pub fn parse(input: &str) -> Self {
+ let (uri_str, input) = input
+ .trim()
+ .strip_prefix("%! ")
+ .map(|input| input.split_once('\n').unwrap_or((input, "")))
+ .unwrap();
+
+ let uri = Url::parse(&format!("file:///texlab/{uri_str}")).unwrap();
+
+ let mut ranges = Vec::new();
+ let mut cursor = None;
+
+ let mut text = String::new();
+ for line in input.lines().map(|line| line.trim_end()) {
+ if line.chars().all(|c| matches!(c, ' ' | '^' | '|' | '!')) && !line.is_empty() {
+ cursor = cursor.or_else(|| {
+ let offset = line.find('|')?;
+ Some(TextSize::from((text.len() + offset) as u32))
+ });
+
+ if let Some(start) = line.find('!') {
+ let position = TextSize::from((text.len() + start) as u32);
+ ranges.push(TextRange::new(position, position));
+ }
+
+ if let Some(start) = line.find('^') {
+ let end = line.rfind('^').unwrap() + 1;
+ ranges.push(TextRange::new(
+ TextSize::from((text.len() + start) as u32),
+ TextSize::from((text.len() + end) as u32),
+ ));
+ }
+ } else {
+ text.push_str(line);
+ text.push('\n');
+ }
+ }
+
+ Self {
+ uri,
+ text,
+ cursor,
+ ranges,
+ }
+ }
+}
diff --git a/support/texlab/crates/test-utils/src/lib.rs b/support/texlab/crates/test-utils/src/lib.rs
new file mode 100644
index 0000000000..8e0974bc65
--- /dev/null
+++ b/support/texlab/crates/test-utils/src/lib.rs
@@ -0,0 +1 @@
+pub mod fixture;
diff --git a/support/texlab/crates/texlab/Cargo.toml b/support/texlab/crates/texlab/Cargo.toml
index ebc7cd222d..dc1eb5b913 100644
--- a/support/texlab/crates/texlab/Cargo.toml
+++ b/support/texlab/crates/texlab/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "texlab"
description = "LaTeX Language Server"
-version = "5.5.0"
+version = "5.5.1"
license.workspace = true
readme = "README.md"
authors.workspace = true
@@ -33,7 +33,6 @@ doctest = false
[dependencies]
anyhow = "1.0.70"
base-db = { path = "../base-db" }
-base-feature = { path = "../base-feature" }
citeproc = { path = "../citeproc" }
clap = { version = "4.2.2", features = ["derive"] }
commands = { path = "../commands" }
@@ -65,6 +64,7 @@ syntax = { path = "../syntax" }
tempfile = "3.5.0"
threadpool = "1.8.1"
titlecase = "2.2.1"
+symbols = { path = "../symbols" }
[dev-dependencies]
assert_unordered = "0.3.5"
diff --git a/support/texlab/crates/texlab/data/lang_data.json b/support/texlab/crates/texlab/data/lang_data.json
deleted file mode 100644
index 3e22e41320..0000000000
--- a/support/texlab/crates/texlab/data/lang_data.json
+++ /dev/null
@@ -1,1058 +0,0 @@
-{
- "colors": [
- "black",
- "blue",
- "brown",
- "cyan",
- "darkgray",
- "gray",
- "green",
- "lightgray",
- "lime",
- "magenta",
- "olive",
- "orange",
- "pink",
- "purple",
- "red",
- "teal",
- "violet",
- "white",
- "yellow",
- "Apricot",
- "Bittersweet",
- "Blue",
- "BlueViolet",
- "Brown",
- "CadetBlue",
- "Cerulean",
- "Cyan",
- "DarkOrchid",
- "ForestGreen",
- "Goldenrod",
- "Green",
- "JungleGreen",
- "LimeGreen",
- "Mahogany",
- "Melon",
- "Mulberry",
- "OliveGreen",
- "OrangeRed",
- "Peach",
- "PineGreen",
- "ProcessBlue",
- "RawSienna",
- "RedOrange",
- "Rhodamine",
- "RoyalPurple",
- "Salmon",
- "Sepia",
- "SpringGreen",
- "TealBlue",
- "Turquoise",
- "VioletRed",
- "WildStrawberry",
- "YellowGreen",
- "Aquamarine",
- "Black",
- "BlueGreen",
- "BrickRed",
- "BurntOrange",
- "CarnationPink",
- "CornflowerBlue",
- "Dandelion",
- "Emerald",
- "Fuchsia",
- "Gray",
- "GreenYellow",
- "Lavender",
- "Magenta",
- "Maroon",
- "MidnightBlue",
- "NavyBlue",
- "Orange",
- "Orchid",
- "Periwinkle",
- "Plum",
- "Purple",
- "Red",
- "RedViolet",
- "RoyalBlue",
- "RubineRed",
- "SeaGreen",
- "SkyBlue",
- "Tan",
- "Thistle",
- "Violet",
- "White",
- "Yellow",
- "YellowOrange"
- ],
- "entryTypes": [
- {
- "name": "preamble",
- "category": "misc",
- "documentation": null
- },
- {
- "name": "string",
- "category": "string",
- "documentation": null
- },
- {
- "name": "comment",
- "category": "misc",
- "documentation": null
- },
- {
- "name": "article",
- "category": "article",
- "documentation": "An article in a journal, magazine, newspaper, or other periodical which forms a \n self-contained unit with its own title. The title of the periodical is given in the \n journaltitle field. If the issue has its own title in addition to the main title of \n the periodical, it goes in the issuetitle field. Note that editor and related \n fields refer to the journal while translator and related fields refer to the article.\n\nRequired fields: `author`, `title`, `journaltitle`, `year/date`"
- },
- {
- "name": "book",
- "category": "book",
- "documentation": "A single-volume book with one or more authors where the authors share credit for\n the work as a whole. This entry type also covers the function of the `@inbook` type\n of traditional BibTeX.\n\nRequired fields: `author`, `title`, `year/date`"
- },
- {
- "name": "mvbook",
- "category": "book",
- "documentation": "A multi-volume `@book`. For backwards compatibility, multi-volume books are also\n supported by the entry type `@book`. However, it is advisable to make use of the\n dedicated entry type `@mvbook`.\n\nRequired fields: `author`, `title`, `year/date`"
- },
- {
- "name": "inbook",
- "category": "part",
- "documentation": "A part of a book which forms a self-contained unit with its own title. Note that the\n profile of this entry type is different from standard BibTeX.\n\nRequired fields: `author`, `title`, `booktitle`, `year/date`"
- },
- {
- "name": "bookinbook",
- "category": "part",
- "documentation": "This type is similar to `@inbook` but intended for works originally published as a\n stand-alone book. A typical example are books reprinted in the collected works of\n an author."
- },
- {
- "name": "suppbook",
- "category": "book",
- "documentation": "Supplemental material in a `@book`. This type is closely related to the `@inbook`\n entry type. While `@inbook` is primarily intended for a part of a book with its own\n title (e. g., a single essay in a collection of essays by the same author), this type is\n provided for elements such as prefaces, introductions, forewords, afterwords, etc.\n which often have a generic title only. Style guides may require such items to be\n formatted differently from other `@inbook` items. The standard styles will treat this\n entry type as an alias for `@inbook`."
- },
- {
- "name": "booklet",
- "category": "book",
- "documentation": "A book-like work without a formal publisher or sponsoring institution. Use the field\n howpublished to supply publishing information in free format, if applicable. The\n field type may be useful as well.\n\nRequired fields: `author/editor`, `title`, `year/date`"
- },
- {
- "name": "collection",
- "category": "collection",
- "documentation": "A single-volume collection with multiple, self-contained contributions by distinct\n authors which have their own title. The work as a whole has no overall author but it\n will usually have an editor.\n\nRequired fields: `editor`, `title`, `year/date`"
- },
- {
- "name": "mvcollection",
- "category": "collection",
- "documentation": "A multi-volume `@collection`. For backwards compatibility, multi-volume collections\n are also supported by the entry type `@collection`. However, it is advisable\n to make use of the dedicated entry type `@mvcollection`.\n\nRequired fields: `editor`, `title`, `year/date`"
- },
- {
- "name": "incollection",
- "category": "part",
- "documentation": "A contribution to a collection which forms a self-contained unit with a distinct author\n and title. The `author` refers to the `title`, the `editor` to the `booktitle`, i. e.,\n the title of the collection.\n\nRequired fields: `author`, `title`, `booktitle`, `year/date`"
- },
- {
- "name": "suppcollection",
- "category": "collection",
- "documentation": "Supplemental material in a `@collection`. This type is similar to `@suppbook` but\n related to the `@collection` entry type. The standard styles will treat this entry\n type as an alias for `@incollection`."
- },
- {
- "name": "manual",
- "category": "misc",
- "documentation": "Technical or other documentation, not necessarily in printed form. The author or\n editor is omissible.\n\nRequired fields: `author/editor`, `title`, `year/date`"
- },
- {
- "name": "misc",
- "category": "misc",
- "documentation": "A fallback type for entries which do not fit into any other category. Use the field\n howpublished to supply publishing information in free format, if applicable. The\n field type may be useful as well. author, editor, and year are omissible.\n\nRequired fields: `author/editor`, `title`, `year/date`"
- },
- {
- "name": "online",
- "category": "misc",
- "documentation": "An online resource. `author`, `editor`, and `year` are omissible.\n This entry type is intended for sources such as web sites which are intrinsically\n online resources. Note that all entry types support the url field. For example, when\n adding an article from an online journal, it may be preferable to use the `@article`\n type and its url field.\n\nRequired fields: `author/editor`, `title`, `year/date`, `url`"
- },
- {
- "name": "patent",
- "category": "misc",
- "documentation": "A patent or patent request. The number or record token is given in the number\n field. Use the type field to specify the type and the location field to indicate the\n scope of the patent, if different from the scope implied by the type. Note that the\n location field is treated as a key list with this entry type.\n\nRequired fields: `author`, `title`, `number`, `year/date`"
- },
- {
- "name": "periodical",
- "category": "misc",
- "documentation": "An complete issue of a periodical, such as a special issue of a journal. The title of\n the periodical is given in the title field. If the issue has its own title in addition to\n the main title of the periodical, it goes in the issuetitle field. The editor is\n omissible.\n\nRequired fields: `editor`, `title`, `year/date`"
- },
- {
- "name": "suppperiodical",
- "category": "misc",
- "documentation": "Supplemental material in a `@periodical`. This type is similar to `@suppbook`\n but related to the `@periodical` entry type. The role of this entry type may be\n more obvious if you bear in mind that the `@article` type could also be called\n `@inperiodical`. This type may be useful when referring to items such as regular\n columns, obituaries, letters to the editor, etc. which only have a generic title. Style\n guides may require such items to be formatted differently from articles in the strict\n sense of the word. The standard styles will treat this entry type as an alias for\n `@article`."
- },
- {
- "name": "proceedings",
- "category": "book",
- "documentation": "A single-volume conference proceedings. This type is very similar to `@collection`.\n It supports an optional organization field which holds the sponsoring institution.\n The editor is omissible.\n\nRequired fields: `title`, `year/date`"
- },
- {
- "name": "mvproceedings",
- "category": "book",
- "documentation": "A multi-volume `@proceedings` entry. For backwards compatibility, multi-volume\n proceedings are also supported by the entry type `@proceedings`. However, it is\n advisable to make use of the dedicated entry type `@mvproceedings`\n\nRequired fields: `title`, `year/date`"
- },
- {
- "name": "inproceedings",
- "category": "part",
- "documentation": "An article in a conference proceedings. This type is similar to `@incollection`. It\n supports an optional `organization` field.\n\nRequired fields: `author`, `title`, `booktitle`, `year/date`"
- },
- {
- "name": "reference",
- "category": "collection",
- "documentation": "A single-volume work of reference such as an encyclopedia or a dictionary. This is a\n more specific variant of the generic `@collection` entry type. The standard styles\n will treat this entry type as an alias for `@collection`."
- },
- {
- "name": "mvreference",
- "category": "collection",
- "documentation": "A multi-volume `@reference` entry. The standard styles will treat this entry type\n as an alias for `@mvcollection`. For backwards compatibility, multi-volume references\n are also supported by the entry type `@reference`. However, it is advisable\n to make use of the dedicated entry type `@mvreference`."
- },
- {
- "name": "inreference",
- "category": "part",
- "documentation": "An article in a work of reference. This is a more specific variant of the generic\n `@incollection` entry type. The standard styles will treat this entry type as an\n alias for `@incollection`."
- },
- {
- "name": "report",
- "category": "misc",
- "documentation": "A technical report, research report, or white paper published by a university or some\n other institution. Use the `type` field to specify the type of report. The sponsoring\n institution goes in the `institution` field.\n\nRequired fields: `author`, `title`, `type`, `institution`, `year/date`"
- },
- {
- "name": "set",
- "category": "misc",
- "documentation": "An entry set. This entry type is special."
- },
- {
- "name": "thesis",
- "category": "thesis",
- "documentation": "A thesis written for an educational institution to satisfy the requirements for a degree.\n Use the `type` field to specify the type of thesis.\n\nRequired fields: `author`, `title`, `type`, `institution`, `year/date`"
- },
- {
- "name": "unpublished",
- "category": "misc",
- "documentation": "A work with an author and a title which has not been formally published, such as\n a manuscript or the script of a talk. Use the fields `howpublished` and `note` to\n supply additional information in free format, if applicable.\n\nRequired fields: `author`, `title`, `year/date`"
- },
- {
- "name": "xdata",
- "category": "misc",
- "documentation": "This entry type is special. `@xdata` entries hold data which may be inherited by other\n entries using the `xdata` field. Entries of this type only serve as data containers;\n they may not be cited or added to the bibliography."
- },
- {
- "name": "conference",
- "category": "part",
- "documentation": "A legacy alias for `@inproceedings`."
- },
- {
- "name": "electronic",
- "category": "misc",
- "documentation": "An alias for `@online`."
- },
- {
- "name": "mastersthesis",
- "category": "thesis",
- "documentation": "Similar to `@thesis` except that the `type` field is optional and defaults to the\n localised term ‘Master’s thesis’. You may still use the `type` field to override that."
- },
- {
- "name": "phdthesis",
- "category": "thesis",
- "documentation": "Similar to `@thesis` except that the `type` field is optional and defaults to the\n localised term ‘PhD thesis’. You may still use the `type` field to override that."
- },
- {
- "name": "techreport",
- "category": "misc",
- "documentation": "Similar to `@report` except that the `type` field is optional and defaults to the\n localised term ‘technical report’. You may still use the `type` field to override that."
- },
- {
- "name": "www",
- "category": "misc",
- "documentation": "An alias for `@online`, provided for `jurabib` compatibility."
- },
- {
- "name": "artwork",
- "category": "misc",
- "documentation": "Works of the visual arts such as paintings, sculpture, and installations."
- },
- {
- "name": "audio",
- "category": "misc",
- "documentation": "Audio recordings, typically on audio cd, dvd, audio cassette, or similar media. See\n also `@music`."
- },
- {
- "name": "bibnote",
- "category": "misc",
- "documentation": "This special entry type is not meant to be used in the `bib` file like other types. It is\n provided for third-party packages like `notes2bib` which merge notes into the bibliography.\n The notes should go into the `note` field. Be advised that the `@bibnote`\n type is not related to the `defbibnote` command in any way. `defbibnote`\n is for adding comments at the beginning or the end of the bibliography, whereas\n the `@bibnote` type is meant for packages which render endnotes as bibliography\n entries."
- },
- {
- "name": "commentary",
- "category": "misc",
- "documentation": "Commentaries which have a status different from regular books, such as legal commentaries."
- },
- {
- "name": "image",
- "category": "misc",
- "documentation": "Images, pictures, photographs, and similar media."
- },
- {
- "name": "jurisdiction",
- "category": "misc",
- "documentation": "Court decisions, court recordings, and similar things."
- },
- {
- "name": "legislation",
- "category": "misc",
- "documentation": "Laws, bills, legislative proposals, and similar things."
- },
- {
- "name": "legal",
- "category": "misc",
- "documentation": "Legal documents such as treaties."
- },
- {
- "name": "letter",
- "category": "misc",
- "documentation": "Personal correspondence such as letters, emails, memoranda, etc."
- },
- {
- "name": "movie",
- "category": "misc",
- "documentation": "Motion pictures. See also `@video`."
- },
- {
- "name": "music",
- "category": "misc",
- "documentation": "Musical recordings. This is a more specific variant of `@audio`."
- },
- {
- "name": "performance",
- "category": "misc",
- "documentation": "Musical and theatrical performances as well as other works of the performing arts.\n This type refers to the event as opposed to a recording, a score, or a printed play."
- },
- {
- "name": "review",
- "category": "misc",
- "documentation": "Reviews of some other work. This is a more specific variant of the `@article` type.\n The standard styles will treat this entry type as an alias for `@article`."
- },
- {
- "name": "software",
- "category": "misc",
- "documentation": "Computer software."
- },
- {
- "name": "standard",
- "category": "misc",
- "documentation": "National and international standards issued by a standards body such as the International\n Organization for Standardization."
- },
- {
- "name": "video",
- "category": "misc",
- "documentation": "Audiovisual recordings, typically on dvd, vhs cassette, or similar media. See also\n `@movie`."
- }
- ],
- "fields": [
- {
- "name": "abstract",
- "documentation": "This field is intended for recording abstracts in a bib file, to be printed by a special bibliography style. It is not used by all standard bibliography styles."
- },
- {
- "name": "addendum",
- "documentation": "Miscellaneous bibliographic data to be printed at the end of the entry. This is similar to the `note` field except that it is printed at the end of the bibliography entry."
- },
- {
- "name": "afterword",
- "documentation": "The author(s) of an afterword to the work. If the author of the afterword is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `introduction` and `foreword`."
- },
- {
- "name": "annotation",
- "documentation": "This field may be useful when implementing a style for annotated bibliographies. It is not used by all standard bibliography styles. Note that this field is completely unrelated to `annotator`. The `annotator` is the author of annotations which are part of the work cited."
- },
- {
- "name": "annotator",
- "documentation": "The author(s) of annotations to the work. If the annotator is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `commentator`."
- },
- {
- "name": "author",
- "documentation": "The author(s) of the `title`."
- },
- {
- "name": "authortype",
- "documentation": "The type of author. This field will affect the string (if any) used to introduce the author. Not used by the standard bibliography styles."
- },
- {
- "name": "bookauthor",
- "documentation": "The author(s) of the `booktitle`."
- },
- {
- "name": "bookpagination",
- "documentation": "If the work is published as part of another one, this is the pagination scheme of the enclosing work, i. e., `bookpagination` relates to `pagination` like `booktitle` to `title`. The value of this field will affect the formatting of the `pages` and `pagetotal` fields. The key should be given in the singular form. Possible keys are `page`, `column`, `line`, `verse`, `section`, and `paragraph`. See also `pagination`."
- },
- {
- "name": "booksubtitle",
- "documentation": "The subtitle related to the `booktitle`. If the subtitle field refers to a work which is part of a larger publication, a possible subtitle of the main work is given in this field. See also `subtitle`."
- },
- {
- "name": "booktitle",
- "documentation": "If the `title` field indicates the title of a work which is part of a larger publication, the title of the main work is given in this field. See also `title`."
- },
- {
- "name": "booktitleaddon",
- "documentation": "An annex to the `booktitle`, to be printed in a different font."
- },
- {
- "name": "chapter",
- "documentation": "A chapter or section or any other unit of a work."
- },
- {
- "name": "commentator",
- "documentation": "The author(s) of a commentary to the work. Note that this field is intended for commented editions which have a commentator in addition to the author. If the work is a stand-alone commentary, the commentator should be given in the `author` field. If the commentator is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `annotator`."
- },
- {
- "name": "date",
- "documentation": "The publication date. See also `month` and `year`."
- },
- {
- "name": "doi",
- "documentation": "The Digital Object Identifier of the work."
- },
- {
- "name": "edition",
- "documentation": "The edition of a printed publication. This must be an integer, not an ordinal. Don’t say `edition={First}` or `edition={1st}` but `edition={1}`. The bibliography style converts this to a language dependent ordinal. It is also possible to give the edition as a literal string, for example \"Third, revised and expanded edition\"."
- },
- {
- "name": "editor",
- "documentation": "The editor(s) of the `title`, `booktitle`, or `maintitle`, depending on the entry type. Use the `editortype` field to specify the role if it is different from `editor`."
- },
- {
- "name": "editora",
- "documentation": "A secondary editor performing a different editorial role, such as compiling, redacting, etc. Use the `editoratype` field to specify the role."
- },
- {
- "name": "editorb",
- "documentation": "Another secondary editor performing a different role. Use the `editorbtype` field to specify the role."
- },
- {
- "name": "editorc",
- "documentation": "Another secondary editor performing a different role. Use the `editorctype` field to specify the role."
- },
- {
- "name": "editortype",
- "documentation": "The type of editorial role performed by the `editor`. Roles supported by default are `editor`, `compiler`, `founder`, `continuator`, `redactor`, `reviser`, `collaborator`, `organizer`. The role `editor` is the default. In this case, the field is omissible."
- },
- {
- "name": "editoratype",
- "documentation": "Similar to `editortype` but referring to the `editora` field."
- },
- {
- "name": "editorbtype",
- "documentation": "Similar to `editortype` but referring to the `editorb` field."
- },
- {
- "name": "editorctype",
- "documentation": "Similar to `editortype` but referring to the `editorc` field."
- },
- {
- "name": "eid",
- "documentation": "The electronic identifier of an `@article`."
- },
- {
- "name": "entrysubtype",
- "documentation": "This field, which is not used by the standard styles, may be used to specify a subtype of an entry type. This may be useful for bibliography styles which support a finergrained set of entry types."
- },
- {
- "name": "eprint",
- "documentation": "The electronic identifier of an online publication. This is roughly comparable to a doi but specific to a certain archive, repository, service, or system. See also `eprinttype` and `eprintclass`."
- },
- {
- "name": "eprintclass",
- "documentation": "Additional information related to the resource indicated by the `eprinttype` field. This could be a section of an archive, a path indicating a service, a classification of some sort, etc. See also`eprint` and `eprinttype`."
- },
- {
- "name": "eprinttype",
- "documentation": "The type of `eprint` identifier, e. g., the name of the archive, repository, service, or system the `eprint` field refers to. See also `eprint` and `eprintclass`."
- },
- {
- "name": "eventdate",
- "documentation": "The date of a conference, a symposium, or some other event in `@proceedings` and `@inproceedings` entries. See also `eventtitle` and `venue`."
- },
- {
- "name": "eventtitle",
- "documentation": "The title of a conference, a symposium, or some other event in `@proceedings` and `@inproceedings` entries. Note that this field holds the plain title of the event. Things like \"Proceedings of the Fifth XYZ Conference\" go into the `titleaddon` or `booktitleaddon` field, respectively. See also `eventdate` and `venue`."
- },
- {
- "name": "eventtitleaddon",
- "documentation": "An annex to the `eventtitle` field. Can be used for known event acronyms, for example."
- },
- {
- "name": "file",
- "documentation": "A local link to a PDF or other version of the work. Not used by the standard bibliography styles."
- },
- {
- "name": "foreword",
- "documentation": "The author(s) of a foreword to the work. If the author of the foreword is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `introduction` and `afterword`."
- },
- {
- "name": "holder",
- "documentation": "The holder(s) of a `@patent`, if different from the `author`. Note that corporate holders need to be wrapped in an additional set of braces."
- },
- {
- "name": "howpublished",
- "documentation": "A publication notice for unusual publications which do not fit into any of the common categories."
- },
- {
- "name": "indextitle",
- "documentation": "A title to use for indexing instead of the regular `title` field. This field may be useful if you have an entry with a title like \"An Introduction to …\" and want that indexed as \"Introduction to …, An\". Style authors should note that `biblatex` automatically copies the value of the `title` field to `indextitle` if the latter field is undefined."
- },
- {
- "name": "institution",
- "documentation": "The name of a university or some other institution, depending on the entry type. Traditional BibTeX uses the field name `school` for theses, which is supported as an alias."
- },
- {
- "name": "introduction",
- "documentation": "The author(s) of an introduction to the work. If the author of the introduction is identical to the `editor` and/or `translator`, the standard styles will automatically concatenate these fields in the bibliography. See also `foreword` and `afterword`."
- },
- {
- "name": "isan",
- "documentation": "The International Standard Audiovisual Number of an audiovisual work. Not used by the standard bibliography styles."
- },
- {
- "name": "isbn",
- "documentation": "The International Standard Book Number of a book."
- },
- {
- "name": "ismn",
- "documentation": "The International Standard Music Number for printed music such as musical scores. Not used by the standard bibliography styles."
- },
- {
- "name": "isrn",
- "documentation": "The International Standard Technical Report Number of a technical report."
- },
- {
- "name": "issn",
- "documentation": "The International Standard Serial Number of a periodical."
- },
- {
- "name": "issue",
- "documentation": "The issue of a journal. This field is intended for journals whose individual issues are identified by a designation such as ‘Spring’ or ‘Summer’ rather than the month or a number. The placement of `issue` is similar to `month` and `number`, integer ranges and short designators are better written to the number field. See also `month` and `number`."
- },
- {
- "name": "issuesubtitle",
- "documentation": "The subtitle of a specific issue of a journal or other periodical."
- },
- {
- "name": "issuetitle",
- "documentation": "The title of a specific issue of a journal or other periodical."
- },
- {
- "name": "iswc",
- "documentation": "The International Standard Work Code of a musical work. Not used by the standard bibliography styles."
- },
- {
- "name": "journalsubtitle",
- "documentation": "The subtitle of a journal, a newspaper, or some other periodical."
- },
- {
- "name": "journaltitle",
- "documentation": "The name of a journal, a newspaper, or some other periodical."
- },
- {
- "name": "label",
- "documentation": "A designation to be used by the citation style as a substitute for the regular label if any data required to generate the regular label is missing. For example, when an author-year citation style is generating a citation for an entry which is missing the author or the year, it may fall back to `label`. Note that, in contrast to `shorthand`, `label` is only used as a fallback. See also `shorthand`."
- },
- {
- "name": "language",
- "documentation": "The language(s) of the work. Languages may be specified literally or as localisation keys. If localisation keys are used, the prefix lang is omissible. See also `origlanguage`."
- },
- {
- "name": "library",
- "documentation": "This field may be useful to record information such as a library name and a call number. This may be printed by a special bibliography style if desired. Not used by the standard bibliography styles."
- },
- {
- "name": "location",
- "documentation": "The place(s) of publication, i. e., the location of the `publisher` or `institution`, depending on the entry type. Traditional BibTeX uses the field name `address`, which is supported as an alias. With `@patent` entries, this list indicates the scope of a patent."
- },
- {
- "name": "mainsubtitle",
- "documentation": "The subtitle related to the `maintitle`. See also `subtitle`."
- },
- {
- "name": "maintitle",
- "documentation": "The main title of a multi-volume book, such as *Collected Works*. If the `title` or `booktitle` field indicates the title of a single volume which is part of multi-volume book, the title of the complete work is given in this field."
- },
- {
- "name": "maintitleaddon",
- "documentation": "An annex to the `maintitle`, to be printed in a different font."
- },
- {
- "name": "month",
- "documentation": "The publication month. This must be an integer, not an ordinal or a string. Don’t say `month={January}` but `month={1}`. The bibliography style converts this to a language dependent string or ordinal where required. This field is a literal field only when given explicitly in the data (for plain BibTeX compatibility for example). It is however better to use the `date` field as this supports many more features."
- },
- {
- "name": "nameaddon",
- "documentation": "An addon to be printed immediately after the author name in the bibliography. Not used by the standard bibliography styles. This field may be useful to add an alias or pen name (or give the real name if the pseudonym is commonly used to refer to that author)."
- },
- {
- "name": "note",
- "documentation": "Miscellaneous bibliographic data which does not fit into any other field. The note field may be used to record bibliographic data in a free format. Publication facts such as \"Reprint of the edition London 1831\" are typical candidates for the note field. See also `addendum`."
- },
- {
- "name": "number",
- "documentation": "The number of a journal or the volume/number of a book in a `series`. See also `issue`. With `@patent` entries, this is the number or record token of a patent or patent request. Normally this field will be an integer or an integer range, but in certain cases it may also contain \"S1\", \"Suppl. 1\", in these cases the output should be scrutinised carefully."
- },
- {
- "name": "organization",
- "documentation": "The organization(s) that published a `@manual` or an `@online` resource, or sponsored a conference."
- },
- {
- "name": "origdate",
- "documentation": "If the work is a translation, a reprint, or something similar, the publication date of the original edition. Not used by the standard bibliography styles. See also `date`."
- },
- {
- "name": "origlanguage",
- "documentation": "If the work is a translation, the language(s) of the original work. See also `language`."
- },
- {
- "name": "origlocation",
- "documentation": "If the work is a translation, a reprint, or something similar, the location of the original edition. Not used by the standard bibliography styles. See also `location`."
- },
- {
- "name": "origpublisher",
- "documentation": "If the work is a translation, a reprint, or something similar, the publisher of the original edition. Not used by the standard bibliography styles. See also `publisher`."
- },
- {
- "name": "origtitle",
- "documentation": "If the work is a translation, the `title` of the original work. Not used by the standard bibliography styles. See also `title`."
- },
- {
- "name": "pages",
- "documentation": "One or more page numbers or page ranges. If the work is published as part of another one, such as an article in a journal or a collection, this field holds the relevant page range in that other work. It may also be used to limit the reference to a specific part of a work (a chapter in a book, for example)."
- },
- {
- "name": "pagetotal",
- "documentation": "The total number of pages of the work."
- },
- {
- "name": "pagination",
- "documentation": "The pagination of the work. The value of this field will affect the formatting the *postnote* argument to a citation command. The key should be given in the singular form. Possible keys are `page`, `column`, `line`, `verse`, `section`, and `paragraph`. See also `bookpagination`."
- },
- {
- "name": "part",
- "documentation": "The number of a partial volume. This field applies to books only, not to journals. It may be used when a logical volume consists of two or more physical ones. In this case the number of the logical volume goes in the `volume` field and the number of the part of that volume in the `part` field. See also `volume`."
- },
- {
- "name": "publisher",
- "documentation": "The name(s) of the publisher(s)."
- },
- {
- "name": "pubstate",
- "documentation": "The publication state of the work, e. g., 'in press'."
- },
- {
- "name": "reprinttitle",
- "documentation": "The title of a reprint of the work. Not used by the standard styles."
- },
- {
- "name": "series",
- "documentation": "The name of a publication series, such as \"Studies in …\", or the number of a journal series. Books in a publication series are usually numbered. The number or volume of a book in a series is given in the `number` field. Note that the `@article` entry type makes use of the `series` field as well, but handles it in a special way."
- },
- {
- "name": "shortauthor",
- "documentation": "The author(s) of the work, given in an abbreviated form. This field is mainly intended for abbreviated forms of corporate authors."
- },
- {
- "name": "shorteditor",
- "documentation": "The editor(s) of the work, given in an abbreviated form. This field is mainly intended for abbreviated forms of corporate editors."
- },
- {
- "name": "shorthand",
- "documentation": "A special designation to be used by the citation style instead of the usual label. If defined, it overrides the default label. See also `label`."
- },
- {
- "name": "shorthandintro",
- "documentation": "The verbose citation styles which comes with this package use a phrase like \"henceforth cited as [shorthand]\" to introduce shorthands on the first citation. If the `shorthandintro` field is defined, it overrides the standard phrase. Note that the alternative phrase must include the shorthand."
- },
- {
- "name": "shortjournal",
- "documentation": "A short version or an acronym of the `journaltitle`. Not used by the standard bibliography styles."
- },
- {
- "name": "shortseries",
- "documentation": "A short version or an acronym of the `series` field. Not used by the standard bibliography styles."
- },
- {
- "name": "shorttitle",
- "documentation": "The title in an abridged form. This field is usually not included in the bibliography. It is intended for citations in author-title format. If present, the author-title citation styles use this field instead of `title`."
- },
- {
- "name": "subtitle",
- "documentation": "The subtitle of the work."
- },
- {
- "name": "title",
- "documentation": "The title of the work."
- },
- {
- "name": "titleaddon",
- "documentation": "An annex to the `title`, to be printed in a different font."
- },
- {
- "name": "translator",
- "documentation": "The translator(s) of the `title` or `booktitle`, depending on the entry type. If the translator is identical to the `editor`, the standard styles will automatically concatenate these fields in the bibliography."
- },
- {
- "name": "type",
- "documentation": "The type of a `manual`, `patent`, `report`, or `thesis`."
- },
- {
- "name": "url",
- "documentation": "The URL of an online publication. If it is not URL-escaped (no ‘%’ chars) it will be URI-escaped according to RFC 3987, that is, even Unicode chars will be correctly escaped."
- },
- {
- "name": "urldate",
- "documentation": "The access date of the address specified in the `url` field."
- },
- {
- "name": "venue",
- "documentation": "The location of a conference, a symposium, or some other event in `@proceedings` and `@inproceedings` entries. Note that the `location` list holds the place of publication. It therefore corresponds to the `publisher` and `institution` lists. The location of the event is given in the `venue` field. See also `eventdate` and `eventtitle`."
- },
- {
- "name": "version",
- "documentation": "The revision number of a piece of software, a manual, etc."
- },
- {
- "name": "volume",
- "documentation": "The volume of a multi-volume book or a periodical. It is expected to be an integer, not necessarily in arabic numerals since `biber` will automatically from roman numerals or arabic letter to integers internally for sorting purposes. See also `part`. See the `noroman` option which can be used to suppress roman numeral parsing. This can help in cases where there is an ambiguity between parsing as roman numerals or alphanumeric (e.g. ‘C’)."
- },
- {
- "name": "volumes",
- "documentation": "The total number of volumes of a multi-volume work. Depending on the entry type, this field refers to `title` or `maintitle`. It is expected to be an integer, not necessarily in arabic numerals since `biber` will automatically from roman numerals or arabic letter to integers internally for sorting purposes. See the `noroman` option which can be used to suppress roman numeral parsing. This can help in cases where there is an ambiguity between parsing as roman numerals or alphanumeric (e.g. ‘C’)."
- },
- {
- "name": "year",
- "documentation": "The year of publication. This field is a literal field only when given explicitly in the data (for plain BibTeX compatibility for example). It is however better to use the `date` field as this is compatible with plain years too and supports many more features."
- },
- {
- "name": "crossref",
- "documentation": "This field holds an entry key for the cross-referencing feature. Child entries with a `crossref` field inherit data from the parent entry specified in the `crossref` field. If the number of child entries referencing a specific parent entry hits a certain threshold, the parent entry is automatically added to the bibliography even if it has not been cited explicitly. The threshold is settable with the `mincrossrefs` package option. Style authors should note that whether or not the `crossref` fields of the child entries are defined on the `biblatex` level depends on the availability of the parent entry. If the parent entry is available, the `crossref` fields of the child entries will be defined. If not, the child entries still inherit the data from the parent entry but their `crossref` fields will be undefined. Whether the parent entry is added to the bibliography implicitly because of the threshold or explicitly because it has been cited does not matter. See also the `xref` field."
- },
- {
- "name": "entryset",
- "documentation": "This field is specific to entry sets. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "execute",
- "documentation": "A special field which holds arbitrary TeX code to be executed whenever the data of the respective entry is accessed. This may be useful to handle special cases. Conceptually, this field is comparable to the hooks `AtEveryBibitem`, `AtEveryLositem`, and `AtEveryCitekey`, except that it is definable on a per-entry basis in the `bib` file. Any code in this field is executed automatically immediately after these hooks."
- },
- {
- "name": "gender",
- "documentation": "The gender of the author or the gender of the editor, if there is no author. The following identifiers are supported: `sf` (feminine singular, a single female name), `sm` (masculine singular, a single male name), `sn` (neuter singular, a single neuter name), `pf` (feminine plural, a list of female names), `pm` (masculine plural, a list of male names), `pn` (neuter plural, a list of neuter names),`pp` (plural, a mixed gender list of names). This information is only required by special bibliography and citation styles and only in certain languages. For example, a citation style may replace recurrent author names with a term such as 'idem'. If the Latin word is used, as is custom in English and French, there is no need to specify the gender. In German publications, however, such key terms are usually given in German and in this case they are gender-sensitive."
- },
- {
- "name": "langid",
- "documentation": "The language id of the bibliography entry. The alias `hyphenation` is provided for backwards compatibility. The identifier must be a language name known to the `babel/polyglossia` packages. This information may be used to switch hyphenation patterns and localise strings in the bibliography. Note that the language names are case sensitive. The languages currently supported by this package are given in table 2. Note that `babel` treats the identifier `english` as an alias for `british` or `american`, depending on the `babel` version. The `biblatex` package always treats it as an alias for `american`. It is preferable to use the language identifiers `american` and `british` (`babel`) or a language specific option to specify a language variant (`polyglossia`, using the `langidopts` field) to avoid any possible confusion."
- },
- {
- "name": "langidopts",
- "documentation": "For `polyglossia` users, allows per-entry language specific options. The literal value of this field is passed to `polyglossia`’s language switching facility when using the package option `autolang=langname`."
- },
- {
- "name": "ids",
- "documentation": "Citation key aliases for the main citation key. An entry may be cited by any of its aliases and `biblatex` will treat the citation as if it had used the primary citation key. This is to aid users who change their citation keys but have legacy documents which use older keys for the same entry. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "indexsorttitle",
- "documentation": "The title used when sorting the index. In contrast to indextitle, this field is used for sorting only. The printed title in the index is the indextitle or the title field. This field may be useful if the title contains special characters or commands which interfere with the sorting of the index. Style authors should note that biblatex automatically copies the value of either the indextitle or the title field to indexsorttitle if the latter field is undefined."
- },
- {
- "name": "keywords",
- "documentation": "A separated list of keywords. These keywords are intended for the bibliography filters, they are usually not printed. Note that with the default separator (comma), spaces around the separator are ignored."
- },
- {
- "name": "options",
- "documentation": "A separated list of entry options in *key*=*value* notation. This field is used to set options on a per-entry basis. Note that citation and bibliography styles may define additional entry options."
- },
- {
- "name": "presort",
- "documentation": "A special field used to modify the sorting order of the bibliography. This field is the first item the sorting routine considers when sorting the bibliography, hence it may be used to arrange the entries in groups. This may be useful when creating subdivided bibliographies with the bibliography filters. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "related",
- "documentation": "Citation keys of other entries which have a relationship to this entry. The relationship is specified by the `relatedtype` field."
- },
- {
- "name": "relatedoptions",
- "documentation": "Per-type options to set for a related entry. Note that this does not set the options on the related entry itself, only the `dataonly` clone which is used as a datasource for the parent entry."
- },
- {
- "name": "relatedtype",
- "documentation": "An identifier which specified the type of relationship for the keys listed in the `related` field. The identifier is a localised bibliography string printed before the data from the related entry list. It is also used to identify type-specific formatting directives and bibliography macros for the related entries."
- },
- {
- "name": "relatedstring",
- "documentation": "A field used to override the bibliography string specified by `relatedtype`."
- },
- {
- "name": "sortkey",
- "documentation": "A field used to modify the sorting order of the bibliography. Think of this field as the master sort key. If present, `biblatex` uses this field during sorting and ignores everything else, except for the presort field. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "sortname",
- "documentation": "A name or a list of names used to modify the sorting order of the bibliography. If present, this list is used instead of `author` or `editor` when sorting the bibliography. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "sortshorthand",
- "documentation": "Similar to sortkey but used in the list of shorthands. If present, biblatex uses this field instead of shorthand when sorting the list of shorthands. This is useful if the shorthand field holds shorthands with formatting commands such as `emph` or `\textbf`. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "sorttitle",
- "documentation": "A field used to modify the sorting order of the bibliography. If present, this field is used instead of the title field when sorting the bibliography. The sorttitle field may come in handy if you have an entry with a title like \"An Introduction to…\" and want that alphabetized under ‘I’ rather than ‘A’. In this case, you could put \"Introduction to…\" in the sorttitle field. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "sortyear",
- "documentation": "A field used to modify the sorting order of the bibliography. In the default sorting templates, if this field is present, it is used instead of the year field when sorting the bibliography. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "xdata",
- "documentation": "This field inherits data from one or more `@xdata` entries. Conceptually, the `xdata` field is related to crossref and xref: `crossref` establishes a logical parent/child relation and inherits data; `xref` establishes as logical parent/child relation without inheriting data; `xdata` inherits data without establishing a relation. The value of the `xdata` may be a single entry key or a separated list of keys. This field is consumed by the backend processing and does not appear in the `.bbl`."
- },
- {
- "name": "xref",
- "documentation": "This field is an alternative cross-referencing mechanism. It differs from `crossref` in that the child entry will not inherit any data from the parent entry specified in the `xref` field. If the number of child entries referencing a specific parent entry hits a certain threshold, the parent entry is automatically added to the bibliography even if it has not been cited explicitly. The threshold is settable with the `minxrefs` package option. Style authors should note that whether or not the `xref` fields of the child entries are defined on the `biblatex` level depends on the availability of the parent entry. If the parent entry is available, the `xref` fields of the child entries will be defined. If not, their `xref` fields will be undefined. Whether the parent entry is added to the bibliography implicitly because of the threshold or explicitly because it has been cited does not matter. See also the `crossref` field."
- },
- {
- "name": "namea",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "nameb",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "namec",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "nameatype",
- "documentation": "Similar to `authortype` and `editortype` but referring to the fields `name[a--c]`. Not used by the standard bibliography styles."
- },
- {
- "name": "namebtype",
- "documentation": "Similar to `authortype` and `editortype` but referring to the fields `name[a--c]`. Not used by the standard bibliography styles."
- },
- {
- "name": "namectype",
- "documentation": "Similar to `authortype` and `editortype` but referring to the fields `name[a--c]`. Not used by the standard bibliography styles."
- },
- {
- "name": "lista",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "listb",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "listc",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "listd",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "liste",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "listf",
- "documentation": "Custom lists for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "usera",
- "documentation": "Custom fields for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "userb",
- "documentation": "Custom fields for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "userc",
- "documentation": "Custom fields for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "userd",
- "documentation": "Custom fields for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "usere",
- "documentation": "Custom fields for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "userf",
- "documentation": "Custom fields for special bibliography styles. Not used by the standard bibliography styles."
- },
- {
- "name": "verba",
- "documentation": "Similar to the custom fields except that these are verbatim fields. Not used by the standard bibliography styles."
- },
- {
- "name": "verbb",
- "documentation": "Similar to the custom fields except that these are verbatim fields. Not used by the standard bibliography styles."
- },
- {
- "name": "verbc",
- "documentation": "Similar to the custom fields except that these are verbatim fields. Not used by the standard bibliography styles."
- },
- {
- "name": "address",
- "documentation": "An alias for `location`, provided for BibTeX compatibility. Traditional BibTeX uses the slightly misleading field name `address` for the place of publication, i. e., the location of the publisher, while `biblatex` uses the generic field name `location`."
- },
- {
- "name": "annote",
- "documentation": "An alias for `annotation`, provided for jurabib compatibility."
- },
- {
- "name": "archiveprefix",
- "documentation": "An alias for `eprinttype`, provided for arXiv compatibility."
- },
- {
- "name": "journal",
- "documentation": "An alias for `journaltitle`, provided for BibTeX compatibility."
- },
- {
- "name": "key",
- "documentation": "An alias for `sortkey`, provided for BibTeX compatibility."
- },
- {
- "name": "pdf",
- "documentation": "An alias for `file`, provided for JabRef compatibility."
- },
- {
- "name": "primaryclass",
- "documentation": "An alias for `eprintclass`, provided for arXiv compatibility."
- },
- {
- "name": "school",
- "documentation": "An alias for `institution`, provided for BibTeX compatibility. The `institution` field is used by traditional BibTeX for technical reports whereas the `school` field holds the institution associated with theses. The `biblatex` package employs the generic field name `institution` in both cases."
- }
- ],
- "pgfLibraries": [
- "arrows",
- "arrows.meta",
- "arrows.spaced",
- "curvilinear",
- "datavisualization.barcharts",
- "datavisualization.formats.functions",
- "datavisualization.polar",
- "decorations.footprints",
- "decorations.fractals",
- "decorations.markings",
- "decorations.pathmorphing",
- "decorations.pathreplacing",
- "decorations.shapes",
- "decorations.text",
- "fadings",
- "fixedpointarithmetic",
- "fpu",
- "intersections",
- "lindenmayersystems",
- "luamath",
- "patterns",
- "patterns.meta",
- "plothandlers",
- "plotmarks",
- "profiler",
- "shadings",
- "shapes.arrows",
- "shapes.callouts",
- "shapes",
- "shapes.gates.ee",
- "shapes.gates.ee.IEC",
- "shapes.gates.logic",
- "shapes.gates.logic.IEC",
- "shapes.gates.logic.US",
- "shapes.geometric",
- "shapes.misc",
- "shapes.multipart",
- "shapes.symbols",
- "snakes",
- "svg.path"
- ],
- "tikzLibraries": [
- "3d",
- "angles",
- "arrows",
- "automata",
- "babel",
- "backgrounds",
- "bending",
- "calc",
- "calendar",
- "chains",
- "circuits",
- "circuits.ee",
- "circuits.ee.IEC",
- "circuits.logic.CDH",
- "circuits.logic",
- "circuits.logic.IEC",
- "circuits.logic.US",
- "datavisualization.3d",
- "datavisualization.barcharts",
- "datavisualization",
- "datavisualization.formats.functions",
- "datavisualization.polar",
- "datavisualization.sparklines",
- "decorations",
- "decorations.footprints",
- "decorations.fractals",
- "decorations.markings",
- "decorations.pathmorphing",
- "decorations.pathreplacing",
- "decorations.shapes",
- "decorations.text",
- "er",
- "fadings",
- "fit",
- "fixedpointarithmetic",
- "folding",
- "fpu",
- "graphs",
- "graphs.standard",
- "intersections",
- "lindenmayersystems",
- "math",
- "matrix",
- "mindmap",
- "patterns",
- "patterns.meta",
- "petri",
- "plothandlers",
- "plotmarks",
- "positioning",
- "quotes",
- "scopes",
- "shadings",
- "shadows",
- "shapes.arrows",
- "shapes.callouts",
- "shapes",
- "shapes.gates.logic.IEC",
- "shapes.gates.logic.US",
- "shapes.geometric",
- "shapes.misc",
- "shapes.multipart",
- "shapes.symbols",
- "snakes",
- "spy",
- "svg.path",
- "through",
- "topaths",
- "trees",
- "turtle"
- ]
-}
diff --git a/support/texlab/crates/texlab/src/features.rs b/support/texlab/crates/texlab/src/features.rs
index 9115580ce0..a92df28d8c 100644
--- a/support/texlab/crates/texlab/src/features.rs
+++ b/support/texlab/crates/texlab/src/features.rs
@@ -8,4 +8,4 @@ pub mod inlay_hint;
pub mod link;
pub mod reference;
pub mod rename;
-pub mod symbol;
+pub mod symbols;
diff --git a/support/texlab/crates/texlab/src/features/completion/builder.rs b/support/texlab/crates/texlab/src/features/completion/builder.rs
index f37718a4ba..b325cd183b 100644
--- a/support/texlab/crates/texlab/src/features/completion/builder.rs
+++ b/support/texlab/crates/texlab/src/features/completion/builder.rs
@@ -1,4 +1,7 @@
-use base_db::{Document, MatchingAlgo};
+use base_db::{
+ data::{BibtexEntryType, BibtexEntryTypeCategory, BibtexFieldType},
+ Document, MatchingAlgo,
+};
use fuzzy_matcher::skim::SkimMatcherV2;
use itertools::Itertools;
use lsp_types::{
@@ -18,7 +21,6 @@ use syntax::{
use crate::util::{
capabilities::ClientCapabilitiesExt,
cursor::{Cursor, CursorContext},
- lang_data::{BibtexEntryTypeCategory, BibtexEntryTypeDoc, BibtexFieldDoc, LANGUAGE_DATA},
line_index_ext::LineIndexExt,
lsp_enums::Structure,
};
@@ -183,8 +185,7 @@ impl<'a> CompletionBuilder<'a> {
) -> Option<()> {
let key = entry.name_token()?.to_string();
- let category = LANGUAGE_DATA
- .find_entry_type(&entry.type_token()?.text()[1..])
+ let category = BibtexEntryType::find(&entry.type_token()?.text()[1..])
.map_or(BibtexEntryTypeCategory::Misc, |ty| ty.category);
let code = entry.syntax().text().to_string();
@@ -285,7 +286,7 @@ impl<'a> CompletionBuilder<'a> {
pub fn entry_type(
&mut self,
range: TextRange,
- entry_type: &'a BibtexEntryTypeDoc,
+ entry_type: &'a BibtexEntryType<'a>,
) -> Option<()> {
let score = self
.matcher
@@ -301,7 +302,7 @@ impl<'a> CompletionBuilder<'a> {
Some(())
}
- pub fn field(&mut self, range: TextRange, field: &'a BibtexFieldDoc) -> Option<()> {
+ pub fn field(&mut self, range: TextRange, field: &'a BibtexFieldType<'a>) -> Option<()> {
let score = self.matcher.score(&field.name, &self.text_pattern)?;
self.items.push(Item {
range,
@@ -453,23 +454,26 @@ impl<'a> CompletionBuilder<'a> {
let preselect = item.preselect;
let mut item = match item.data {
Data::EntryType { entry_type } => CompletionItem {
- label: entry_type.name.clone(),
+ label: entry_type.name.into(),
kind: Some(Structure::Entry(entry_type.category).completion_kind()),
- documentation: entry_type.documentation.clone().map(|value| {
+ documentation: entry_type.documentation.map(|value| {
let kind = MarkupKind::Markdown;
- Documentation::MarkupContent(MarkupContent { kind, value })
+ Documentation::MarkupContent(MarkupContent {
+ kind,
+ value: value.into(),
+ })
}),
- text_edit: Some(TextEdit::new(range, entry_type.name.clone()).into()),
+ text_edit: Some(TextEdit::new(range, entry_type.name.into()).into()),
..CompletionItem::default()
},
Data::Field { field } => CompletionItem {
- label: field.name.clone(),
+ label: field.name.into(),
kind: Some(Structure::Field.completion_kind()),
documentation: Some(Documentation::MarkupContent(MarkupContent {
kind: MarkupKind::Markdown,
- value: field.documentation.clone(),
+ value: field.documentation.into(),
})),
- text_edit: Some(TextEdit::new(range, field.name.clone()).into()),
+ text_edit: Some(TextEdit::new(range, field.name.into()).into()),
..CompletionItem::default()
},
Data::Argument { name, image } => {
@@ -678,10 +682,10 @@ struct Item<'a> {
#[derive(Debug, Clone)]
enum Data<'a> {
EntryType {
- entry_type: &'a BibtexEntryTypeDoc,
+ entry_type: &'a BibtexEntryType<'a>,
},
Field {
- field: &'a BibtexFieldDoc,
+ field: &'a BibtexFieldType<'a>,
},
Argument {
name: &'a str,
diff --git a/support/texlab/crates/texlab/src/features/completion/color.rs b/support/texlab/crates/texlab/src/features/completion/color.rs
index 6a636cc687..e415409844 100644
--- a/support/texlab/crates/texlab/src/features/completion/color.rs
+++ b/support/texlab/crates/texlab/src/features/completion/color.rs
@@ -1,7 +1,7 @@
use rowan::ast::AstNode;
use syntax::latex;
-use crate::util::{cursor::CursorContext, lang_data::LANGUAGE_DATA};
+use crate::util::cursor::CursorContext;
use super::builder::CompletionBuilder;
@@ -12,9 +12,99 @@ pub fn complete<'db>(
let (_, range, group) = context.find_curly_group_word()?;
latex::ColorReference::cast(group.syntax().parent()?)?;
- for name in &LANGUAGE_DATA.colors {
+ for name in COLORS {
builder.color(range, name);
}
Some(())
}
+
+static COLORS: &[&str] = &[
+ "black",
+ "blue",
+ "brown",
+ "cyan",
+ "darkgray",
+ "gray",
+ "green",
+ "lightgray",
+ "lime",
+ "magenta",
+ "olive",
+ "orange",
+ "pink",
+ "purple",
+ "red",
+ "teal",
+ "violet",
+ "white",
+ "yellow",
+ "Apricot",
+ "Bittersweet",
+ "Blue",
+ "BlueViolet",
+ "Brown",
+ "CadetBlue",
+ "Cerulean",
+ "Cyan",
+ "DarkOrchid",
+ "ForestGreen",
+ "Goldenrod",
+ "Green",
+ "JungleGreen",
+ "LimeGreen",
+ "Mahogany",
+ "Melon",
+ "Mulberry",
+ "OliveGreen",
+ "OrangeRed",
+ "Peach",
+ "PineGreen",
+ "ProcessBlue",
+ "RawSienna",
+ "RedOrange",
+ "Rhodamine",
+ "RoyalPurple",
+ "Salmon",
+ "Sepia",
+ "SpringGreen",
+ "TealBlue",
+ "Turquoise",
+ "VioletRed",
+ "WildStrawberry",
+ "YellowGreen",
+ "Aquamarine",
+ "Black",
+ "BlueGreen",
+ "BrickRed",
+ "BurntOrange",
+ "CarnationPink",
+ "CornflowerBlue",
+ "Dandelion",
+ "Emerald",
+ "Fuchsia",
+ "Gray",
+ "GreenYellow",
+ "Lavender",
+ "Magenta",
+ "Maroon",
+ "MidnightBlue",
+ "NavyBlue",
+ "Orange",
+ "Orchid",
+ "Periwinkle",
+ "Plum",
+ "Purple",
+ "Red",
+ "RedViolet",
+ "RoyalBlue",
+ "RubineRed",
+ "SeaGreen",
+ "SkyBlue",
+ "Tan",
+ "Thistle",
+ "Violet",
+ "White",
+ "Yellow",
+ "YellowOrange",
+];
diff --git a/support/texlab/crates/texlab/src/features/completion/component_environment.rs b/support/texlab/crates/texlab/src/features/completion/component_environment.rs
index 496fb7ed85..85c29558ca 100644
--- a/support/texlab/crates/texlab/src/features/completion/component_environment.rs
+++ b/support/texlab/crates/texlab/src/features/completion/component_environment.rs
@@ -6,7 +6,7 @@ pub fn complete<'db>(
context: &'db CursorContext,
builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
- let (_, range) = context.find_environment_name()?;
+ let range = context.find_environment_name()?;
for component in COMPONENT_DATABASE.linked_components(&context.project) {
for name in &component.environments {
diff --git a/support/texlab/crates/texlab/src/features/completion/entry_type.rs b/support/texlab/crates/texlab/src/features/completion/entry_type.rs
index 73a93a5a40..767839189d 100644
--- a/support/texlab/crates/texlab/src/features/completion/entry_type.rs
+++ b/support/texlab/crates/texlab/src/features/completion/entry_type.rs
@@ -1,7 +1,7 @@
use rowan::{TextRange, TextSize};
use syntax::bibtex;
-use crate::util::{cursor::CursorContext, lang_data::LANGUAGE_DATA};
+use crate::util::cursor::CursorContext;
use super::builder::CompletionBuilder;
@@ -17,7 +17,7 @@ pub fn complete<'db>(
.filter(|range| range.start() != context.offset)
.map(|range| TextRange::new(range.start() + TextSize::from(1), range.end()))?;
- for entry_type in &LANGUAGE_DATA.entry_types {
+ for entry_type in base_db::data::BIBTEX_ENTRY_TYPES {
builder.entry_type(range, entry_type);
}
diff --git a/support/texlab/crates/texlab/src/features/completion/field.rs b/support/texlab/crates/texlab/src/features/completion/field.rs
index d1f6a5e856..01786b5e93 100644
--- a/support/texlab/crates/texlab/src/features/completion/field.rs
+++ b/support/texlab/crates/texlab/src/features/completion/field.rs
@@ -1,7 +1,7 @@
use rowan::{ast::AstNode, TextRange};
use syntax::bibtex::{self, HasName};
-use crate::util::{cursor::CursorContext, lang_data::LANGUAGE_DATA};
+use crate::util::cursor::CursorContext;
use super::builder::CompletionBuilder;
@@ -26,7 +26,7 @@ pub fn complete<'db>(
bibtex::Field::cast(parent)?;
}
- for field in &LANGUAGE_DATA.fields {
+ for field in base_db::data::BIBTEX_FIELD_TYPES {
builder.field(range, field);
}
diff --git a/support/texlab/crates/texlab/src/features/completion/label.rs b/support/texlab/crates/texlab/src/features/completion/label.rs
index c85093b748..800c7b7581 100644
--- a/support/texlab/crates/texlab/src/features/completion/label.rs
+++ b/support/texlab/crates/texlab/src/features/completion/label.rs
@@ -1,8 +1,12 @@
-use base_db::{semantics::tex::LabelKind, DocumentData};
+use base_db::{
+ semantics::tex::LabelKind,
+ util::{render_label, RenderedObject},
+ DocumentData,
+};
use rowan::{ast::AstNode, TextRange};
use syntax::latex;
-use crate::util::{self, cursor::CursorContext, label::LabeledObject, lsp_enums::Structure};
+use crate::util::{cursor::CursorContext, lsp_enums::Structure};
use super::builder::CompletionBuilder;
@@ -20,14 +24,14 @@ pub fn complete<'db>(
.iter()
.filter(|label| label.kind == LabelKind::Definition)
{
- match util::label::render(context.workspace, &context.project, label) {
+ match render_label(context.workspace, &context.project, 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,
+ RenderedObject::Section { .. } => Structure::Section,
+ RenderedObject::Float { .. } => Structure::Float,
+ RenderedObject::Theorem { .. } => Structure::Theorem,
+ RenderedObject::Equation => Structure::Equation,
+ RenderedObject::EnumItem => Structure::Item,
};
if is_math && kind != Structure::Equation {
@@ -36,7 +40,7 @@ pub fn complete<'db>(
let header = rendered_label.detail();
let footer = match &rendered_label.object {
- LabeledObject::Float { caption, .. } => Some(caption.clone()),
+ RenderedObject::Float { caption, .. } => Some(caption.clone()),
_ => None,
};
diff --git a/support/texlab/crates/texlab/src/features/completion/theorem.rs b/support/texlab/crates/texlab/src/features/completion/theorem.rs
index 1ac904234c..a0ff71c9f4 100644
--- a/support/texlab/crates/texlab/src/features/completion/theorem.rs
+++ b/support/texlab/crates/texlab/src/features/completion/theorem.rs
@@ -8,7 +8,7 @@ pub fn complete<'db>(
context: &'db CursorContext,
builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
- let (_, range) = context.find_environment_name()?;
+ let range = context.find_environment_name()?;
for document in &context.project.documents {
let DocumentData::Tex(data) = &document.data else { continue };
diff --git a/support/texlab/crates/texlab/src/features/completion/tikz_library.rs b/support/texlab/crates/texlab/src/features/completion/tikz_library.rs
index 5f09142cfd..adb3fb9c66 100644
--- a/support/texlab/crates/texlab/src/features/completion/tikz_library.rs
+++ b/support/texlab/crates/texlab/src/features/completion/tikz_library.rs
@@ -1,7 +1,7 @@
use rowan::ast::AstNode;
use syntax::latex;
-use crate::util::{cursor::CursorContext, lang_data::LANGUAGE_DATA};
+use crate::util::cursor::CursorContext;
use super::builder::CompletionBuilder;
@@ -14,14 +14,130 @@ pub fn complete<'db>(
let import = latex::TikzLibraryImport::cast(group.syntax().parent()?)?;
if import.command()?.text() == "\\usepgflibrary" {
- for name in &LANGUAGE_DATA.pgf_libraries {
+ for name in PGF_LIBRARIES {
builder.tikz_library(range, name);
}
} else {
- for name in &LANGUAGE_DATA.tikz_libraries {
+ for name in TIKZ_LIBRARIES {
builder.tikz_library(range, name);
}
}
Some(())
}
+
+static PGF_LIBRARIES: &[&str] = &[
+ "arrows",
+ "arrows.meta",
+ "arrows.spaced",
+ "curvilinear",
+ "datavisualization.barcharts",
+ "datavisualization.formats.functions",
+ "datavisualization.polar",
+ "decorations.footprints",
+ "decorations.fractals",
+ "decorations.markings",
+ "decorations.pathmorphing",
+ "decorations.pathreplacing",
+ "decorations.shapes",
+ "decorations.text",
+ "fadings",
+ "fixedpointarithmetic",
+ "fpu",
+ "intersections",
+ "lindenmayersystems",
+ "luamath",
+ "patterns",
+ "patterns.meta",
+ "plothandlers",
+ "plotmarks",
+ "profiler",
+ "shadings",
+ "shapes.arrows",
+ "shapes.callouts",
+ "shapes",
+ "shapes.gates.ee",
+ "shapes.gates.ee.IEC",
+ "shapes.gates.logic",
+ "shapes.gates.logic.IEC",
+ "shapes.gates.logic.US",
+ "shapes.geometric",
+ "shapes.misc",
+ "shapes.multipart",
+ "shapes.symbols",
+ "snakes",
+ "svg.path",
+];
+
+static TIKZ_LIBRARIES: &[&str] = &[
+ "3d",
+ "angles",
+ "arrows",
+ "automata",
+ "babel",
+ "backgrounds",
+ "bending",
+ "calc",
+ "calendar",
+ "chains",
+ "circuits",
+ "circuits.ee",
+ "circuits.ee.IEC",
+ "circuits.logic.CDH",
+ "circuits.logic",
+ "circuits.logic.IEC",
+ "circuits.logic.US",
+ "datavisualization.3d",
+ "datavisualization.barcharts",
+ "datavisualization",
+ "datavisualization.formats.functions",
+ "datavisualization.polar",
+ "datavisualization.sparklines",
+ "decorations",
+ "decorations.footprints",
+ "decorations.fractals",
+ "decorations.markings",
+ "decorations.pathmorphing",
+ "decorations.pathreplacing",
+ "decorations.shapes",
+ "decorations.text",
+ "er",
+ "fadings",
+ "fit",
+ "fixedpointarithmetic",
+ "folding",
+ "fpu",
+ "graphs",
+ "graphs.standard",
+ "intersections",
+ "lindenmayersystems",
+ "math",
+ "matrix",
+ "mindmap",
+ "patterns",
+ "patterns.meta",
+ "petri",
+ "plothandlers",
+ "plotmarks",
+ "positioning",
+ "quotes",
+ "scopes",
+ "shadings",
+ "shadows",
+ "shapes.arrows",
+ "shapes.callouts",
+ "shapes",
+ "shapes.gates.logic.IEC",
+ "shapes.gates.logic.US",
+ "shapes.geometric",
+ "shapes.misc",
+ "shapes.multipart",
+ "shapes.symbols",
+ "snakes",
+ "spy",
+ "svg.path",
+ "through",
+ "topaths",
+ "trees",
+ "turtle",
+];
diff --git a/support/texlab/crates/texlab/src/features/completion/user_command.rs b/support/texlab/crates/texlab/src/features/completion/user_command.rs
index 26708e69ec..e1c517e6aa 100644
--- a/support/texlab/crates/texlab/src/features/completion/user_command.rs
+++ b/support/texlab/crates/texlab/src/features/completion/user_command.rs
@@ -12,8 +12,13 @@ pub fn complete<'db>(
for document in &context.project.documents {
let DocumentData::Tex(data) = &document.data else { continue };
- for (_, name) in data.semantics.commands.iter().filter(|(r, _)| *r != range) {
- builder.user_command(range, name);
+ for name in data
+ .semantics
+ .commands
+ .iter()
+ .filter(|name| name.range != range)
+ {
+ builder.user_command(range, &name.text);
}
}
diff --git a/support/texlab/crates/texlab/src/features/completion/user_environment.rs b/support/texlab/crates/texlab/src/features/completion/user_environment.rs
index 4e06eac6da..109925d623 100644
--- a/support/texlab/crates/texlab/src/features/completion/user_environment.rs
+++ b/support/texlab/crates/texlab/src/features/completion/user_environment.rs
@@ -8,7 +8,7 @@ pub fn complete<'db>(
context: &'db CursorContext,
builder: &mut CompletionBuilder<'db>,
) -> Option<()> {
- let (name, range) = context.find_environment_name()?;
+ let range = context.find_environment_name()?;
for document in &context.project.documents {
let DocumentData::Tex(data) = &document.data else { continue };
@@ -16,9 +16,9 @@ pub fn complete<'db>(
.semantics
.environments
.iter()
- .filter(|n| n.as_str() != name)
+ .filter(|name| name.range != range)
{
- builder.user_environment(range, name);
+ builder.user_environment(range, &name.text);
}
}
diff --git a/support/texlab/crates/texlab/src/features/definition/label.rs b/support/texlab/crates/texlab/src/features/definition/label.rs
index 84f17b5704..9a518974b7 100644
--- a/support/texlab/crates/texlab/src/features/definition/label.rs
+++ b/support/texlab/crates/texlab/src/features/definition/label.rs
@@ -1,6 +1,6 @@
-use base_db::{semantics::tex::LabelKind, DocumentData};
+use base_db::{semantics::tex::LabelKind, util::render_label, DocumentData};
-use crate::util::{self, cursor::CursorContext};
+use crate::util::cursor::CursorContext;
use super::DefinitionResult;
@@ -22,7 +22,7 @@ pub(super) fn goto_definition<'a>(
.find(|label| label.name.text == name_text) else { continue };
let target_selection_range = label.name.range;
- let target_range = util::label::render(context.workspace, &context.project, label)
+ let target_range = render_label(context.workspace, &context.project, label)
.map_or(target_selection_range, |label| label.range);
return Some(vec![DefinitionResult {
diff --git a/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs b/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs
index 7ffca6e840..2b16939f43 100644
--- a/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs
+++ b/support/texlab/crates/texlab/src/features/formatting/bibtex_internal.rs
@@ -1,4 +1,4 @@
-use base_db::{Document, LineIndex, Workspace};
+use base_db::{util::LineIndex, Document, Workspace};
use lsp_types::{FormattingOptions, TextEdit};
use rowan::{ast::AstNode, NodeOrToken};
use syntax::bibtex::{self, HasName, HasType, HasValue};
diff --git a/support/texlab/crates/texlab/src/features/hover/entry_type.rs b/support/texlab/crates/texlab/src/features/hover/entry_type.rs
index 8875b30b2e..da737a148f 100644
--- a/support/texlab/crates/texlab/src/features/hover/entry_type.rs
+++ b/support/texlab/crates/texlab/src/features/hover/entry_type.rs
@@ -1,7 +1,8 @@
+use base_db::data::BibtexEntryType;
use lsp_types::MarkupKind;
use syntax::bibtex;
-use crate::util::{cursor::CursorContext, lang_data::LANGUAGE_DATA};
+use crate::util::cursor::CursorContext;
use super::HoverResult;
@@ -11,10 +12,10 @@ pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
.as_bib()
.filter(|token| token.kind() == bibtex::TYPE)?;
- let docs = LANGUAGE_DATA.entry_type_documentation(&name.text()[1..])?;
+ let documentation = BibtexEntryType::find(&name.text()[1..]).and_then(|ty| ty.documentation)?;
Some(HoverResult {
range: name.text_range(),
- value: docs.to_string(),
+ value: String::from(documentation),
value_kind: MarkupKind::Markdown,
})
}
diff --git a/support/texlab/crates/texlab/src/features/hover/field.rs b/support/texlab/crates/texlab/src/features/hover/field.rs
index 8787a45c09..d16bea6157 100644
--- a/support/texlab/crates/texlab/src/features/hover/field.rs
+++ b/support/texlab/crates/texlab/src/features/hover/field.rs
@@ -1,8 +1,9 @@
+use base_db::data::BibtexFieldType;
use lsp_types::MarkupKind;
use rowan::ast::AstNode;
use syntax::bibtex;
-use crate::util::{cursor::CursorContext, lang_data::LANGUAGE_DATA};
+use crate::util::cursor::CursorContext;
use super::HoverResult;
@@ -14,10 +15,10 @@ pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
bibtex::Field::cast(name.parent()?)?;
- let docs = LANGUAGE_DATA.field_documentation(name.text())?;
+ let docs = BibtexFieldType::find(name.text())?.documentation;
Some(HoverResult {
range: name.text_range(),
- value: docs.to_string(),
+ value: docs.into(),
value_kind: MarkupKind::Markdown,
})
}
diff --git a/support/texlab/crates/texlab/src/features/hover/label.rs b/support/texlab/crates/texlab/src/features/hover/label.rs
index 5ed7ce5121..bb5768d2b0 100644
--- a/support/texlab/crates/texlab/src/features/hover/label.rs
+++ b/support/texlab/crates/texlab/src/features/hover/label.rs
@@ -1,7 +1,7 @@
-use base_db::semantics::tex::LabelKind;
+use base_db::{semantics::tex::LabelKind, util::render_label};
use lsp_types::MarkupKind;
-use crate::util::{self, cursor::CursorContext};
+use crate::util::cursor::CursorContext;
use super::HoverResult;
@@ -17,7 +17,7 @@ pub(super) fn find_hover(context: &CursorContext) -> Option<HoverResult> {
.filter_map(|document| document.data.as_tex())
.flat_map(|data| data.semantics.labels.iter())
.find(|label| label.kind == LabelKind::Definition && label.name.text == name_text)
- .and_then(|label| util::label::render(context.workspace, &context.project, label))
+ .and_then(|label| render_label(context.workspace, &context.project, label))
.map(|label| HoverResult {
range,
value: label.reference(),
diff --git a/support/texlab/crates/texlab/src/features/inlay_hint/label.rs b/support/texlab/crates/texlab/src/features/inlay_hint/label.rs
index 5269b5742d..dd33990f45 100644
--- a/support/texlab/crates/texlab/src/features/inlay_hint/label.rs
+++ b/support/texlab/crates/texlab/src/features/inlay_hint/label.rs
@@ -1,6 +1,8 @@
-use base_db::{semantics::tex::LabelKind, DocumentData};
-
-use crate::util::{self, label::LabeledObject};
+use base_db::{
+ semantics::tex::LabelKind,
+ util::{render_label, RenderedObject},
+ DocumentData,
+};
use super::InlayHintBuilder;
@@ -15,21 +17,21 @@ pub(super) fn find_hints(builder: &mut InlayHintBuilder) -> Option<()> {
.filter(|label| label.kind == LabelKind::Definition)
.filter(|label| label.name.range.intersect(range).is_some())
{
- let Some(rendered) = util::label::render(builder.workspace, &builder.project, label) else { continue };
+ let Some(rendered) = render_label(builder.workspace, &builder.project, label) else { continue };
let Some(number) = &rendered.number else { continue };
let text = match &rendered.object {
- LabeledObject::Section { prefix, .. } => {
+ RenderedObject::Section { prefix, .. } => {
format!("{} {}", prefix, number)
}
- LabeledObject::Float { kind, .. } => {
+ RenderedObject::Float { kind, .. } => {
format!("{} {}", kind.as_str(), number)
}
- LabeledObject::Theorem { kind, .. } => {
+ RenderedObject::Theorem { kind, .. } => {
format!("{} {}", kind, number)
}
- LabeledObject::Equation => format!("Equation ({})", number),
- LabeledObject::EnumItem => format!("Item {}", number),
+ RenderedObject::Equation => format!("Equation ({})", number),
+ RenderedObject::EnumItem => format!("Item {}", number),
};
builder.push(label.name.range.end(), text);
diff --git a/support/texlab/crates/texlab/src/features/symbol.rs b/support/texlab/crates/texlab/src/features/symbol.rs
deleted file mode 100644
index b8005eaf44..0000000000
--- a/support/texlab/crates/texlab/src/features/symbol.rs
+++ /dev/null
@@ -1,129 +0,0 @@
-mod bibtex;
-mod latex;
-mod project_order;
-mod types;
-
-use std::cmp::Reverse;
-
-use base_db::Workspace;
-use lsp_types::{
- ClientCapabilities, DocumentSymbolResponse, SymbolInformation, Url, WorkspaceSymbolParams,
-};
-
-use crate::util::capabilities::ClientCapabilitiesExt;
-
-use self::{project_order::ProjectOrdering, types::InternalSymbol};
-
-pub fn find_document_symbols(
- workspace: &Workspace,
- uri: &Url,
- client_capabilties: &ClientCapabilities,
-) -> Option<DocumentSymbolResponse> {
- let document = workspace.lookup(uri)?;
- let project = workspace.project(document);
-
- let mut buf = Vec::new();
- latex::find_symbols(workspace, &project, document, &mut buf);
- bibtex::find_symbols(document, &mut buf);
-
- let config = &workspace.config().symbols;
-
- InternalSymbol::filter(&mut buf, config);
-
- if client_capabilties.has_hierarchical_document_symbol_support() {
- let symbols = buf
- .into_iter()
- .map(|symbol| symbol.into_document_symbol())
- .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(uri.clone()))
- .collect();
-
- sort_symbols(workspace, &mut new_buf);
- Some(DocumentSymbolResponse::Flat(new_buf))
- }
-}
-
-#[derive(Debug, Clone)]
-struct WorkspaceSymbol {
- info: SymbolInformation,
- search_text: String,
-}
-
-#[must_use]
-pub fn find_workspace_symbols(
- workspace: &Workspace,
- params: &WorkspaceSymbolParams,
-) -> Vec<SymbolInformation> {
- let mut symbols = Vec::new();
-
- for document in workspace.iter() {
- let project = workspace.project(document);
-
- let mut buf = Vec::new();
- latex::find_symbols(workspace, &project, document, &mut buf);
- bibtex::find_symbols(document, &mut buf);
- let mut new_buf = Vec::new();
-
- for symbol in buf {
- symbol.flatten(&mut new_buf);
- }
-
- for symbol in new_buf {
- symbols.push(WorkspaceSymbol {
- search_text: symbol.search_text(),
- info: symbol.into_symbol_info(document.uri.clone()),
- });
- }
- }
-
- let query_words: Vec<_> = params
- .query
- .split_whitespace()
- .map(str::to_lowercase)
- .collect();
-
- let mut filtered = Vec::new();
- for symbol in symbols {
- let mut included = true;
- for word in &query_words {
- if !symbol.search_text.contains(word) {
- included = false;
- break;
- }
- }
-
- if included {
- filtered.push(symbol.info);
- }
- }
-
- sort_symbols(workspace, &mut filtered);
- filtered
-}
-
-fn sort_symbols(workspace: &Workspace, symbols: &mut [SymbolInformation]) {
- let ordering = ProjectOrdering::new(workspace);
- symbols.sort_by(|left, right| {
- let left_key = (
- ordering.get(&left.location.uri),
- left.location.range.start,
- Reverse(left.location.range.end),
- );
- let right_key = (
- ordering.get(&right.location.uri),
- right.location.range.start,
- Reverse(right.location.range.end),
- );
- left_key.cmp(&right_key)
- });
-}
diff --git a/support/texlab/crates/texlab/src/features/symbol/bibtex.rs b/support/texlab/crates/texlab/src/features/symbol/bibtex.rs
deleted file mode 100644
index 6ddfe964ce..0000000000
--- a/support/texlab/crates/texlab/src/features/symbol/bibtex.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use base_db::{Document, DocumentData, LineIndex};
-use rowan::ast::AstNode;
-use syntax::bibtex::{self, HasName, HasType};
-
-use crate::util::{
- lang_data::{BibtexEntryTypeCategory, LANGUAGE_DATA},
- line_index_ext::LineIndexExt,
-};
-
-use super::types::{InternalSymbol, InternalSymbolKind};
-
-pub fn find_symbols(document: &Document, buf: &mut Vec<InternalSymbol>) {
- let DocumentData::Bib(data) = &document.data else { return };
-
- let line_index = &document.line_index;
- for node in data.root_node().children() {
- process_string(node.clone(), line_index, buf)
- .or_else(|| process_entry(node, line_index, buf));
- }
-}
-
-fn process_string(
- node: bibtex::SyntaxNode,
- line_index: &LineIndex,
- buf: &mut Vec<InternalSymbol>,
-) -> Option<()> {
- 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(),
- });
-
- Some(())
-}
-
-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/crates/texlab/src/features/symbol/latex.rs b/support/texlab/crates/texlab/src/features/symbol/latex.rs
deleted file mode 100644
index 0f67f4fbc5..0000000000
--- a/support/texlab/crates/texlab/src/features/symbol/latex.rs
+++ /dev/null
@@ -1,431 +0,0 @@
-use std::str::FromStr;
-
-use base_db::{semantics::Span, Document, DocumentData, Project, Workspace};
-use lsp_types::Range;
-use rowan::{ast::AstNode, TextRange};
-use syntax::latex::{self, HasBrack, HasCurly};
-use titlecase::titlecase;
-
-use crate::util::{
- label::{find_caption_by_parent, LabeledFloatKind},
- line_index_ext::LineIndexExt,
-};
-
-use super::types::{InternalSymbol, InternalSymbolKind};
-
-pub fn find_symbols(
- workspace: &Workspace,
- project: &Project,
- document: &Document,
- buf: &mut Vec<InternalSymbol>,
-) {
- let DocumentData::Tex(data) = &document.data else { return };
-
- let mut symbols = visit(workspace, project, document, data.root_node());
- buf.append(&mut symbols);
-}
-
-fn visit(
- workspace: &Workspace,
- project: &Project,
- document: &Document,
- node: latex::SyntaxNode,
-) -> Vec<InternalSymbol> {
- let symbol = match node.kind() {
- latex::PART
- | latex::CHAPTER
- | latex::SECTION
- | latex::SUBSECTION
- | latex::SUBSUBSECTION
- | latex::PARAGRAPH
- | latex::SUBPARAGRAPH => visit_section(project, document, node.clone()),
- latex::ENUM_ITEM => visit_enum_item(workspace, project, document, node.clone()),
- latex::EQUATION => visit_equation(project, document, node.clone()),
- latex::ENVIRONMENT => latex::Environment::cast(node.clone())
- .and_then(|env| env.begin())
- .and_then(|begin| begin.name())
- .and_then(|name| name.key())
- .map(|name| name.to_string())
- .and_then(|name| {
- let config = &workspace.config().syntax;
-
- if config.math_environments.contains(&name) {
- visit_equation_environment(project, document, node.clone())
- } else if config.enum_environments.contains(&name) {
- visit_enumeration(project, document, node.clone(), &name)
- } else if let Ok(float_kind) = LabeledFloatKind::from_str(&name) {
- visit_float(project, document, node.clone(), float_kind)
- } else {
- visit_theorem(project, document, node.clone(), &name)
- }
- }),
- _ => None,
- };
-
- match symbol {
- Some(mut parent) => {
- for child in node.children() {
- parent
- .children
- .append(&mut visit(workspace, project, document, child));
- }
-
- vec![parent]
- }
- None => {
- let mut symbols = Vec::new();
- for child in node.children() {
- symbols.append(&mut visit(workspace, project, document, child));
- }
-
- symbols
- }
- }
-}
-
-fn visit_section(
- project: &Project,
- document: &Document,
- node: latex::SyntaxNode,
-) -> Option<InternalSymbol> {
- let section = latex::Section::cast(node)?;
- let full_range = document
- .line_index
- .line_col_lsp_range(latex::small_range(&section));
-
- let group = section.name()?;
- let group_text = group.content_text()?;
-
- let label = NumberedLabel::find(project, section.syntax());
-
- let symbol = match label {
- Some(label) => {
- let name = match label.number {
- Some(number) => format!("{} {}", number, group_text),
- None => group_text,
- };
-
- InternalSymbol {
- name,
- label: Some(label.name.text),
- kind: InternalSymbolKind::Section,
- deprecated: false,
- full_range,
- selection_range: document.line_index.line_col_lsp_range(label.range),
- children: Vec::new(),
- }
- }
- None => InternalSymbol {
- name: group_text,
- label: None,
- kind: InternalSymbolKind::Section,
- deprecated: false,
- full_range,
- selection_range: full_range,
- children: Vec::new(),
- },
- };
-
- Some(symbol)
-}
-
-fn visit_enum_item(
- workspace: &Workspace,
- project: &Project,
- document: &Document,
- node: latex::SyntaxNode,
-) -> Option<InternalSymbol> {
- let enum_envs = &workspace.config().syntax.enum_environments;
- let enum_item = latex::EnumItem::cast(node.clone())?;
- if !enum_item
- .syntax()
- .ancestors()
- .filter_map(latex::Environment::cast)
- .filter_map(|environment| environment.begin())
- .filter_map(|begin| begin.name())
- .filter_map(|name| name.key())
- .any(|name| enum_envs.contains(&name.to_string()))
- {
- return None;
- }
-
- let full_range = document
- .line_index
- .line_col_lsp_range(latex::small_range(&enum_item));
-
- let name = enum_item
- .label()
- .and_then(|label| label.content_text())
- .unwrap_or_else(|| "Item".to_string());
-
- let symbol = match NumberedLabel::find(project, &node) {
- Some(label) => InternalSymbol {
- name: label.number.map_or_else(|| name.clone(), String::from),
- label: Some(label.name.text),
- kind: InternalSymbolKind::EnumerationItem,
- deprecated: false,
- full_range,
- selection_range: document.line_index.line_col_lsp_range(label.range),
- children: Vec::new(),
- },
- None => InternalSymbol {
- name,
- label: None,
- kind: InternalSymbolKind::EnumerationItem,
- deprecated: false,
- full_range,
- selection_range: full_range,
- children: Vec::new(),
- },
- };
-
- Some(symbol)
-}
-
-fn visit_equation(
- project: &Project,
- document: &Document,
- node: latex::SyntaxNode,
-) -> Option<InternalSymbol> {
- let equation = latex::Equation::cast(node)?;
-
- let full_range = document
- .line_index
- .line_col_lsp_range(latex::small_range(&equation));
-
- make_equation_symbol(project, document, equation.syntax(), full_range)
-}
-
-fn visit_equation_environment(
- project: &Project,
- document: &Document,
- node: latex::SyntaxNode,
-) -> Option<InternalSymbol> {
- let environment = latex::Environment::cast(node)?;
-
- let full_range = document
- .line_index
- .line_col_lsp_range(latex::small_range(&environment));
-
- make_equation_symbol(project, document, environment.syntax(), full_range)
-}
-
-fn make_equation_symbol(
- project: &Project,
- document: &Document,
- node: &latex::SyntaxNode,
- full_range: Range,
-) -> Option<InternalSymbol> {
- let symbol = match NumberedLabel::find(project, node) {
- Some(label) => {
- let name = match label.number {
- Some(number) => format!("Equation ({})", number),
- None => "Equation".to_string(),
- };
-
- InternalSymbol {
- name,
- label: Some(label.name.text),
- kind: InternalSymbolKind::Equation,
- deprecated: false,
- full_range,
- selection_range: document.line_index.line_col_lsp_range(label.range),
- children: Vec::new(),
- }
- }
- None => InternalSymbol {
- name: "Equation".to_string(),
- label: None,
- kind: InternalSymbolKind::Equation,
- deprecated: false,
- full_range,
- selection_range: full_range,
- children: Vec::new(),
- },
- };
-
- Some(symbol)
-}
-
-fn visit_enumeration(
- project: &Project,
- document: &Document,
- node: latex::SyntaxNode,
- env_name: &str,
-) -> Option<InternalSymbol> {
- let environment = latex::Environment::cast(node)?;
- let full_range = document
- .line_index
- .line_col_lsp_range(latex::small_range(&environment));
-
- let name = titlecase(env_name);
- let symbol = match NumberedLabel::find(project, environment.syntax()) {
- Some(label) => {
- let name = match label.number {
- Some(number) => format!("{} {}", name, number),
- None => name,
- };
-
- InternalSymbol {
- name,
- label: Some(label.name.text),
- kind: InternalSymbolKind::Enumeration,
- deprecated: false,
- full_range,
- selection_range: document.line_index.line_col_lsp_range(label.range),
- children: Vec::new(),
- }
- }
- None => InternalSymbol {
- name,
- label: None,
- kind: InternalSymbolKind::Enumeration,
- deprecated: false,
- full_range,
- selection_range: full_range,
- children: Vec::new(),
- },
- };
- Some(symbol)
-}
-
-fn visit_float(
- project: &Project,
- document: &Document,
- node: latex::SyntaxNode,
- float_kind: LabeledFloatKind,
-) -> Option<InternalSymbol> {
- let environment = latex::Environment::cast(node)?;
- let full_range = document
- .line_index
- .line_col_lsp_range(latex::small_range(&environment));
-
- let (float_kind, symbol_kind) = match float_kind {
- 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 NumberedLabel::find(project, environment.syntax()) {
- Some(label) => {
- let name = match label.number {
- Some(number) => format!("{} {}: {}", float_kind, number, caption),
- None => format!("{}: {}", float_kind, caption),
- };
-
- InternalSymbol {
- name,
- label: Some(label.name.text),
- kind: symbol_kind,
- deprecated: false,
- full_range,
- selection_range: document.line_index.line_col_lsp_range(label.range),
- children: Vec::new(),
- }
- }
- None => InternalSymbol {
- name: format!("{}: {}", float_kind, caption),
- label: None,
- kind: symbol_kind,
- deprecated: false,
- full_range,
- selection_range: full_range,
- children: Vec::new(),
- },
- };
-
- Some(symbol)
-}
-
-fn visit_theorem(
- project: &Project,
- document: &Document,
- node: latex::SyntaxNode,
- environment_name: &str,
-) -> Option<InternalSymbol> {
- let definition = project
- .documents
- .iter()
- .filter_map(|document| document.data.as_tex())
- .flat_map(|data| data.semantics.theorem_definitions.iter())
- .find(|theorem| theorem.name.text == environment_name)?;
-
- let node = latex::Environment::cast(node)?;
- let theorem_description = node
- .begin()?
- .options()
- .and_then(|option| option.content_text());
-
- let full_range = document
- .line_index
- .line_col_lsp_range(latex::small_range(&node));
-
- let symbol = match NumberedLabel::find(project, node.syntax()) {
- Some(label) => {
- let name = match (label.number, theorem_description) {
- (Some(number), Some(desc)) => {
- format!("{} {} ({})", definition.description, number, desc)
- }
- (Some(number), None) => format!("{} {}", definition.description, number),
- (None, Some(desc)) => format!("{} ({})", definition.description, desc),
- (None, None) => definition.description.clone(),
- };
-
- InternalSymbol {
- name,
- label: Some(label.name.text),
- kind: InternalSymbolKind::Theorem,
- deprecated: false,
- full_range,
- selection_range: document.line_index.line_col_lsp_range(label.range),
- children: Vec::new(),
- }
- }
- None => {
- let name = match theorem_description {
- Some(desc) => format!("{} ({})", definition.description, desc),
- None => definition.description.clone(),
- };
-
- InternalSymbol {
- name,
- label: None,
- kind: InternalSymbolKind::Theorem,
- deprecated: false,
- full_range,
- selection_range: full_range,
- children: Vec::new(),
- }
- }
- };
-
- Some(symbol)
-}
-
-#[derive(Debug)]
-struct NumberedLabel<'a> {
- name: Span,
- range: TextRange,
- number: Option<&'a str>,
-}
-
-impl<'a> NumberedLabel<'a> {
- fn find(project: &Project<'a>, parent: &latex::SyntaxNode) -> Option<Self> {
- let label = parent.children().find_map(latex::LabelDefinition::cast)?;
- let name = Span::from(&label.name()?.key()?);
- let number = project
- .documents
- .iter()
- .filter_map(|document| document.data.as_aux())
- .find_map(|data| data.semantics.label_numbers.get(&name.text))
- .map(|number| number.as_str());
-
- Some(NumberedLabel {
- name,
- range: latex::small_range(&label),
- number,
- })
- }
-}
diff --git a/support/texlab/crates/texlab/src/features/symbol/types.rs b/support/texlab/crates/texlab/src/features/symbol/types.rs
deleted file mode 100644
index b8fc9b462f..0000000000
--- a/support/texlab/crates/texlab/src/features/symbol/types.rs
+++ /dev/null
@@ -1,133 +0,0 @@
-use base_db::SymbolConfig;
-use lsp_types::{DocumentSymbol, Location, Range, SymbolInformation, SymbolKind, Url};
-
-use crate::util::{self, lang_data::BibtexEntryTypeCategory, lsp_enums::Structure};
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum InternalSymbolKind {
- Section,
- Figure,
- Algorithm,
- Table,
- Listing,
- Enumeration,
- EnumerationItem,
- Theorem,
- Equation,
- Entry(BibtexEntryTypeCategory),
- Field,
- String,
-}
-
-impl InternalSymbolKind {
- pub fn into_symbol_kind(self) -> SymbolKind {
- match self {
- Self::Section => Structure::Section.symbol_kind(),
- Self::Figure | Self::Algorithm | Self::Table | Self::Listing => {
- Structure::Float.symbol_kind()
- }
- Self::Enumeration => Structure::Environment.symbol_kind(),
- Self::EnumerationItem => Structure::Item.symbol_kind(),
- Self::Theorem => Structure::Theorem.symbol_kind(),
- Self::Equation => Structure::Equation.symbol_kind(),
- Self::Entry(category) => Structure::Entry(category).symbol_kind(),
- Self::Field => Structure::Field.symbol_kind(),
- Self::String => Structure::Entry(BibtexEntryTypeCategory::String).symbol_kind(),
- }
- }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone)]
-pub struct InternalSymbol {
- pub name: String,
- pub label: Option<String>,
- pub kind: InternalSymbolKind,
- pub deprecated: bool,
- pub full_range: Range,
- pub selection_range: Range,
- pub children: Vec<InternalSymbol>,
-}
-
-impl InternalSymbol {
- pub fn search_text(&self) -> String {
- let kind = match self.kind {
- InternalSymbolKind::Section => "latex section",
- InternalSymbolKind::Figure => "latex float figure",
- InternalSymbolKind::Algorithm => "latex float algorithm",
- InternalSymbolKind::Table => "latex float table",
- InternalSymbolKind::Listing => "latex float listing",
- InternalSymbolKind::Enumeration => "latex enumeration",
- InternalSymbolKind::EnumerationItem => "latex enumeration item",
- InternalSymbolKind::Theorem => "latex math",
- InternalSymbolKind::Equation => "latex math equation",
- InternalSymbolKind::Entry(_) => "bibtex entry",
- InternalSymbolKind::Field => "bibtex field",
- InternalSymbolKind::String => "bibtex string",
- };
- format!("{} {}", kind, self.name).to_lowercase()
- }
-
- pub fn flatten(mut self, buffer: &mut Vec<Self>) {
- if self.kind == InternalSymbolKind::Field {
- return;
- }
- for symbol in self.children.drain(..) {
- symbol.flatten(buffer);
- }
- buffer.push(self);
- }
-
- pub fn filter(container: &mut Vec<InternalSymbol>, config: &SymbolConfig) {
- let mut i = 0;
- while i < container.len() {
- let symbol = &mut container[i];
-
- if !symbol.name.is_empty()
- && util::regex_filter::filter(
- &symbol.name,
- &config.allowed_patterns,
- &config.ignored_patterns,
- )
- {
- Self::filter(&mut symbol.children, config);
- i += 1;
- } else {
- drop(symbol);
- let mut symbol = container.remove(i);
- container.append(&mut symbol.children);
- }
- }
- }
-
- pub fn into_document_symbol(self) -> DocumentSymbol {
- let children = self
- .children
- .into_iter()
- .map(|child| child.into_document_symbol())
- .collect();
-
- #[allow(deprecated)]
- DocumentSymbol {
- name: self.name,
- detail: self.label,
- kind: self.kind.into_symbol_kind(),
- deprecated: Some(self.deprecated),
- range: self.full_range,
- selection_range: self.selection_range,
- children: Some(children),
- tags: None,
- }
- }
-
- pub fn into_symbol_info(self, uri: Url) -> SymbolInformation {
- #[allow(deprecated)]
- SymbolInformation {
- name: self.name,
- kind: self.kind.into_symbol_kind(),
- deprecated: Some(self.deprecated),
- location: Location::new(uri, self.full_range),
- container_name: None,
- tags: None,
- }
- }
-}
diff --git a/support/texlab/crates/texlab/src/features/symbols.rs b/support/texlab/crates/texlab/src/features/symbols.rs
new file mode 100644
index 0000000000..170705e05c
--- /dev/null
+++ b/support/texlab/crates/texlab/src/features/symbols.rs
@@ -0,0 +1,107 @@
+use base_db::{data::BibtexEntryTypeCategory, Document, Workspace};
+use lsp_types::{
+ ClientCapabilities, DocumentSymbol, DocumentSymbolResponse, Location, WorkspaceSymbolResponse,
+};
+
+use crate::util::{capabilities::ClientCapabilitiesExt, line_index_ext::LineIndexExt};
+
+pub fn document_symbols(
+ workspace: &Workspace,
+ document: &Document,
+ capabilities: &ClientCapabilities,
+) -> DocumentSymbolResponse {
+ let symbols = symbols::document_symbols(workspace, document);
+ if capabilities.has_hierarchical_document_symbol_support() {
+ let results = symbols
+ .into_iter()
+ .map(|symbol| convert_to_nested_symbol(symbol, document))
+ .collect();
+
+ DocumentSymbolResponse::Nested(results)
+ } else {
+ let mut results = Vec::new();
+ for symbol in symbols {
+ convert_to_flat_symbols(symbol, document, &mut results);
+ }
+
+ DocumentSymbolResponse::Flat(results)
+ }
+}
+
+pub fn workspace_symbols(workspace: &Workspace, query: &str) -> WorkspaceSymbolResponse {
+ let symbols = symbols::workspace_symbols(workspace, query);
+ let mut results = Vec::new();
+ for symbols::SymbolLocation { symbol, document } in symbols {
+ convert_to_flat_symbols(symbol, document, &mut results);
+ }
+
+ WorkspaceSymbolResponse::Flat(results)
+}
+
+fn convert_to_nested_symbol(symbol: symbols::Symbol, document: &Document) -> DocumentSymbol {
+ let children = symbol
+ .children
+ .into_iter()
+ .map(|child| convert_to_nested_symbol(child, document))
+ .collect();
+
+ #[allow(deprecated)]
+ DocumentSymbol {
+ name: symbol.name,
+ detail: symbol.label.map(|label| label.text),
+ kind: convert_symbol_kind(symbol.kind),
+ deprecated: Some(false),
+ range: document.line_index.line_col_lsp_range(symbol.full_range),
+ selection_range: document
+ .line_index
+ .line_col_lsp_range(symbol.selection_range),
+ children: Some(children),
+ tags: None,
+ }
+}
+
+fn convert_to_flat_symbols(
+ symbol: symbols::Symbol,
+ document: &Document,
+ results: &mut Vec<lsp_types::SymbolInformation>,
+) {
+ let range = document.line_index.line_col_lsp_range(symbol.full_range);
+
+ #[allow(deprecated)]
+ results.push(lsp_types::SymbolInformation {
+ name: symbol.name,
+ kind: convert_symbol_kind(symbol.kind),
+ deprecated: Some(false),
+ location: Location::new(document.uri.clone(), range),
+ tags: None,
+ container_name: None,
+ });
+
+ for child in symbol.children {
+ convert_to_flat_symbols(child, document, results);
+ }
+}
+
+fn convert_symbol_kind(value: symbols::SymbolKind) -> lsp_types::SymbolKind {
+ match value {
+ symbols::SymbolKind::Section => lsp_types::SymbolKind::MODULE,
+ symbols::SymbolKind::Figure => lsp_types::SymbolKind::METHOD,
+ symbols::SymbolKind::Algorithm => lsp_types::SymbolKind::METHOD,
+ symbols::SymbolKind::Table => lsp_types::SymbolKind::METHOD,
+ symbols::SymbolKind::Listing => lsp_types::SymbolKind::METHOD,
+ symbols::SymbolKind::Enumeration => lsp_types::SymbolKind::ENUM,
+ symbols::SymbolKind::EnumerationItem => lsp_types::SymbolKind::ENUM_MEMBER,
+ symbols::SymbolKind::Theorem => lsp_types::SymbolKind::VARIABLE,
+ symbols::SymbolKind::Equation => lsp_types::SymbolKind::CONSTANT,
+ symbols::SymbolKind::Entry(category) => match category {
+ BibtexEntryTypeCategory::Misc => lsp_types::SymbolKind::INTERFACE,
+ BibtexEntryTypeCategory::String => lsp_types::SymbolKind::STRING,
+ BibtexEntryTypeCategory::Article => lsp_types::SymbolKind::EVENT,
+ BibtexEntryTypeCategory::Thesis => lsp_types::SymbolKind::OBJECT,
+ BibtexEntryTypeCategory::Book => lsp_types::SymbolKind::STRUCT,
+ BibtexEntryTypeCategory::Part => lsp_types::SymbolKind::OPERATOR,
+ BibtexEntryTypeCategory::Collection => lsp_types::SymbolKind::TYPE_PARAMETER,
+ },
+ symbols::SymbolKind::Field => lsp_types::SymbolKind::FIELD,
+ }
+}
diff --git a/support/texlab/crates/texlab/src/server.rs b/support/texlab/crates/texlab/src/server.rs
index 9cc0575e28..6b118655bc 100644
--- a/support/texlab/crates/texlab/src/server.rs
+++ b/support/texlab/crates/texlab/src/server.rs
@@ -11,10 +11,10 @@ use std::{
use anyhow::Result;
use base_db::{Config, Owner, Workspace};
-use base_feature::normalize_uri;
use commands::{BuildCommand, CleanCommand, CleanTarget, ForwardSearch};
use crossbeam_channel::{Receiver, Sender};
use distro::{Distro, Language};
+use itertools::{FoldWhile, Itertools};
use lsp_server::{Connection, ErrorCode, Message, RequestId};
use lsp_types::{notification::*, request::*, *};
use parking_lot::{Mutex, RwLock};
@@ -29,11 +29,11 @@ use crate::{
features::{
completion::{self, builder::CompletionItemData},
definition, folding, formatting, highlight, hover, inlay_hint, link, reference, rename,
- symbol,
+ symbols,
},
util::{
self, capabilities::ClientCapabilitiesExt, components::COMPONENT_DATABASE,
- line_index_ext::LineIndexExt,
+ line_index_ext::LineIndexExt, normalize_uri,
},
};
@@ -388,13 +388,27 @@ impl Server {
}
None => {
let language = document.language;
+ let line_col = document.line_index.line_col(document.cursor);
+
+ let (_, new_cursor) = change
+ .text
+ .lines()
+ .fold_while((0, 0), |(number, index), line| {
+ if number == line_col.line {
+ FoldWhile::Done((number, index))
+ } else {
+ itertools::FoldWhile::Continue((number + 1, index + line.len()))
+ }
+ })
+ .into_inner();
+
drop(document);
workspace.open(
uri.clone(),
change.text,
language,
Owner::Client,
- TextSize::default(),
+ TextSize::from(new_cursor as u32),
);
}
};
@@ -468,15 +482,24 @@ impl Server {
fn document_symbols(&self, id: RequestId, params: DocumentSymbolParams) -> Result<()> {
let mut uri = params.text_document.uri;
normalize_uri(&mut uri);
- let client_capabilities = Arc::clone(&self.client_capabilities);
+
+ let capabilities = Arc::clone(&self.client_capabilities);
self.run_query(id, move |workspace| {
- symbol::find_document_symbols(workspace, &uri, &client_capabilities)
+ let Some(document) = workspace.lookup(&uri) else {
+ return DocumentSymbolResponse::Flat(vec![]);
+ };
+
+ symbols::document_symbols(workspace, document, &capabilities)
});
+
Ok(())
}
fn workspace_symbols(&self, id: RequestId, params: WorkspaceSymbolParams) -> Result<()> {
- self.run_query(id, move |db| symbol::find_workspace_symbols(db, &params));
+ self.run_query(id, move |workspace| {
+ symbols::workspace_symbols(workspace, &params.query)
+ });
+
Ok(())
}
diff --git a/support/texlab/crates/texlab/src/util.rs b/support/texlab/crates/texlab/src/util.rs
index 5eed8a3357..b1e1adc396 100644
--- a/support/texlab/crates/texlab/src/util.rs
+++ b/support/texlab/crates/texlab/src/util.rs
@@ -3,14 +3,67 @@ pub mod chktex;
pub mod components;
pub mod cursor;
pub mod diagnostics;
-pub mod label;
-pub mod lang_data;
pub mod line_index_ext;
pub mod lsp_enums;
-pub mod regex_filter;
use std::path::PathBuf;
+use lsp_types::Url;
use once_cell::sync::Lazy;
pub static HOME_DIR: Lazy<Option<PathBuf>> = Lazy::new(dirs::home_dir);
+
+pub fn normalize_uri(uri: &mut Url) {
+ 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);
+}
+
+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,
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use lsp_types::Url;
+
+ use super::normalize_uri;
+
+ #[test]
+ fn test_lowercase_drive_letter() {
+ let mut uri = Url::parse("file://c:/foo/bar.txt").unwrap();
+ normalize_uri(&mut uri);
+ assert_eq!(uri.as_str(), "file:///C:/foo/bar.txt");
+ }
+
+ #[test]
+ fn test_uppercase_drive_letter() {
+ let mut uri = Url::parse("file://C:/foo/bar.txt").unwrap();
+ normalize_uri(&mut uri);
+ assert_eq!(uri.as_str(), "file:///C:/foo/bar.txt");
+ }
+
+ #[test]
+ fn test_fragment() {
+ let mut uri = Url::parse("foo:///bar/baz.txt#qux").unwrap();
+ normalize_uri(&mut uri);
+ assert_eq!(uri.as_str(), "foo:///bar/baz.txt");
+ }
+}
diff --git a/support/texlab/crates/texlab/src/util/cursor.rs b/support/texlab/crates/texlab/src/util/cursor.rs
index 8db642c0bf..b03036386c 100644
--- a/support/texlab/crates/texlab/src/util/cursor.rs
+++ b/support/texlab/crates/texlab/src/util/cursor.rs
@@ -229,14 +229,14 @@ impl<'a, T> CursorContext<'a, T> {
}
}
- pub fn find_environment_name(&self) -> Option<(String, TextRange)> {
- let (name, range, group) = self.find_curly_group_word()?;
+ pub fn find_environment_name(&self) -> Option<TextRange> {
+ let (_, range, group) = self.find_curly_group_word()?;
if !matches!(group.syntax().parent()?.kind(), latex::BEGIN | latex::END) {
return None;
}
- Some((name, range))
+ Some(range)
}
pub fn find_environment(&self) -> Option<(latex::Key, latex::Key)> {
diff --git a/support/texlab/crates/texlab/src/util/diagnostics.rs b/support/texlab/crates/texlab/src/util/diagnostics.rs
index 9bac4df44e..b6f1efbce9 100644
--- a/support/texlab/crates/texlab/src/util/diagnostics.rs
+++ b/support/texlab/crates/texlab/src/util/diagnostics.rs
@@ -1,11 +1,9 @@
-use base_db::{diagnostics::ErrorCode, Document, Workspace};
+use base_db::{diagnostics::ErrorCode, util::filter_regex_patterns, Document, Workspace};
use distro::Language;
use lsp_types::{DiagnosticSeverity, NumberOrString};
use rustc_hash::FxHashMap;
use syntax::BuildErrorLevel;
-use crate::util;
-
use super::line_index_ext::LineIndexExt;
pub fn collect(workspace: &Workspace) -> FxHashMap<&Document, Vec<lsp_types::Diagnostic>> {
@@ -110,7 +108,7 @@ pub fn filter(
let config = &workspace.config().diagnostics;
for diagnostics in all_diagnostics.values_mut() {
diagnostics.retain(|diagnostic| {
- util::regex_filter::filter(
+ filter_regex_patterns(
&diagnostic.message,
&config.allowed_patterns,
&config.ignored_patterns,
diff --git a/support/texlab/crates/texlab/src/util/lang_data.rs b/support/texlab/crates/texlab/src/util/lang_data.rs
deleted file mode 100644
index 734ceb6df2..0000000000
--- a/support/texlab/crates/texlab/src/util/lang_data.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use once_cell::sync::Lazy;
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub enum BibtexEntryTypeCategory {
- Misc,
- String,
- Article,
- Book,
- Collection,
- Part,
- Thesis,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct BibtexEntryTypeDoc {
- pub name: String,
- pub category: BibtexEntryTypeCategory,
- pub documentation: Option<String>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct BibtexFieldDoc {
- pub name: String,
- pub documentation: String,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct LanguageData {
- pub colors: Vec<String>,
- pub entry_types: Vec<BibtexEntryTypeDoc>,
- pub fields: Vec<BibtexFieldDoc>,
- pub pgf_libraries: Vec<String>,
- pub tikz_libraries: Vec<String>,
-}
-
-impl LanguageData {
- #[must_use]
- pub fn find_entry_type(&self, name: &str) -> Option<&BibtexEntryTypeDoc> {
- let name = name.to_lowercase();
- self.entry_types
- .iter()
- .find(|ty| ty.name.to_lowercase() == name)
- }
-
- #[must_use]
- pub fn entry_type_documentation(&self, name: &str) -> Option<&str> {
- self.find_entry_type(name)
- .and_then(|ty| ty.documentation.as_ref().map(AsRef::as_ref))
- }
-
- #[must_use]
- pub fn field_documentation(&self, name: &str) -> Option<&str> {
- self.fields
- .iter()
- .find(|field| field.name.to_lowercase() == name.to_lowercase())
- .map(|field| field.documentation.as_ref())
- }
-}
-
-pub static LANGUAGE_DATA: Lazy<LanguageData> = Lazy::new(|| {
- 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/crates/texlab/src/util/line_index_ext.rs b/support/texlab/crates/texlab/src/util/line_index_ext.rs
index bf4d9fa422..a7b0fa8953 100644
--- a/support/texlab/crates/texlab/src/util/line_index_ext.rs
+++ b/support/texlab/crates/texlab/src/util/line_index_ext.rs
@@ -1,4 +1,4 @@
-use base_db::{LineCol, LineColUtf16, LineIndex};
+use base_db::util::{LineCol, LineColUtf16, LineIndex};
use lsp_types::{Position, Range};
use rowan::{TextRange, TextSize};
diff --git a/support/texlab/crates/texlab/src/util/lsp_enums.rs b/support/texlab/crates/texlab/src/util/lsp_enums.rs
index 75b97097c5..e79297af8a 100644
--- a/support/texlab/crates/texlab/src/util/lsp_enums.rs
+++ b/support/texlab/crates/texlab/src/util/lsp_enums.rs
@@ -1,7 +1,6 @@
+use base_db::data::BibtexEntryTypeCategory;
use lsp_types::{CompletionItemKind, SymbolKind};
-use super::lang_data::BibtexEntryTypeCategory;
-
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Structure {
Command,
diff --git a/support/texlab/crates/texlab/tests/lsp/fixture.rs b/support/texlab/crates/texlab/tests/lsp/fixture.rs
index 02bed8c38a..a10105eb7f 100644
--- a/support/texlab/crates/texlab/tests/lsp/fixture.rs
+++ b/support/texlab/crates/texlab/tests/lsp/fixture.rs
@@ -26,14 +26,16 @@ impl Fixture {
let mut documents = Vec::new();
let mut start = 0;
- for end in input
- .match_indices("%!")
- .skip(1)
- .map(|(i, _)| i)
- .chain(std::iter::once(input.len()))
- {
- documents.push(Document::parse(&input[start..end]));
- start = end;
+ if !input.is_empty() {
+ for end in input
+ .match_indices("%!")
+ .skip(1)
+ .map(|(i, _)| i)
+ .chain(std::iter::once(input.len()))
+ {
+ documents.push(Document::parse(&input[start..end]));
+ start = end;
+ }
}
Self { documents }
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/completion.rs b/support/texlab/crates/texlab/tests/lsp/text_document/completion.rs
index 3c2e7962d4..78df56c583 100644
--- a/support/texlab/crates/texlab/tests/lsp/text_document/completion.rs
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/completion.rs
@@ -852,3 +852,15 @@ fn issue_864() {
\end{document}"#
))
}
+
+#[test]
+fn issue_883() {
+ assert_json_snapshot!(complete(
+ r#"
+%! bug.tex
+\begin{doc
+ |
+ ^^^
+% Comment"#
+ ))
+}
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/document_symbol.rs b/support/texlab/crates/texlab/tests/lsp/text_document/document_symbol.rs
index 6ac00176b9..e22c9374ad 100644
--- a/support/texlab/crates/texlab/tests/lsp/text_document/document_symbol.rs
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/document_symbol.rs
@@ -1,441 +1,45 @@
-use insta::assert_json_snapshot;
-use lsp_types::{
- notification::DidChangeConfiguration, request::DocumentSymbolRequest,
- DidChangeConfigurationParams, DocumentSymbolParams, DocumentSymbolResponse,
-};
+use insta::assert_debug_snapshot;
+use lsp_types::{notification::DidOpenTextDocument, request::DocumentSymbolRequest, *};
use crate::fixture::TestBed;
-fn find_symbols(
- fixture: &str,
- capabilities: serde_json::Value,
- settings: serde_json::Value,
-) -> DocumentSymbolResponse {
- let test_bed = TestBed::new(fixture).unwrap();
-
+#[test]
+fn test_smoke() {
+ let test_bed = TestBed::new("").unwrap();
test_bed
- .initialize(serde_json::from_value(capabilities).unwrap())
+ .initialize(ClientCapabilities {
+ text_document: Some(TextDocumentClientCapabilities {
+ document_symbol: Some(DocumentSymbolClientCapabilities {
+ hierarchical_document_symbol_support: Some(true),
+ ..Default::default()
+ }),
+ ..Default::default()
+ }),
+ ..Default::default()
+ })
.unwrap();
+ let uri = Url::parse("file:///texlab/main.tex").unwrap();
test_bed
.client()
- .send_notification::<DidChangeConfiguration>(DidChangeConfigurationParams { settings })
+ .send_notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
+ text_document: TextDocumentItem::new(
+ uri.clone(),
+ "latex".into(),
+ 0,
+ r#"\section{Foo} \subsection{Bar} \section{Baz}"#.into(),
+ ),
+ })
.unwrap();
- let text_document = test_bed.cursor().unwrap().text_document;
-
- let mut response = test_bed
+ let Some(DocumentSymbolResponse::Nested(symbols)) = test_bed
.client()
.send_request::<DocumentSymbolRequest>(DocumentSymbolParams {
- text_document,
- work_done_progress_params: Default::default(),
+ text_document: TextDocumentIdentifier { uri },
partial_result_params: Default::default(),
+ work_done_progress_params: Default::default(),
})
- .unwrap()
- .unwrap_or_else(|| DocumentSymbolResponse::Flat(vec![]));
-
- if let DocumentSymbolResponse::Flat(symbols) = &mut response {
- for symbol in symbols {
- symbol.location.uri = test_bed.redact(&symbol.location.uri);
- }
- }
-
- response
-}
-
-#[test]
-fn enumerate_nested() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\begin{enumerate}
- \item\label{it:foo} Foo
- \item\label{it:bar} Bar
- \item[Baz] Baz
- \item[Qux]\label{it:qux} Qux
-\end{enumerate}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\newlabel{it:foo}{{1}{1}}
-\newlabel{it:qux}{{2}{1}}"#,
- serde_json::json!({
- "textDocument": {
- "documentSymbol": {
- "hierarchicalDocumentSymbolSupport": true,
- },
- },
- }),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn enumerate_flat() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\begin{enumerate}
- \item\label{it:foo} Foo
- \item\label{it:bar} Bar
- \item[Baz] Baz
- \item[Qux]\label{it:qux} Qux
-\end{enumerate}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\newlabel{it:foo}{{1}{1}}
-\newlabel{it:qux}{{2}{1}}"#,
- serde_json::json!({}),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn equation_nested() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\begin{equation}\label{eq:foo}
- Foo
-\end{equation}
-
-\begin{equation}\label{eq:bar}
- Bar
-\end{equation}
-
-\begin{equation}
- Baz
-\end{equation}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\newlabel{eq:foo}{{1}{1}}"#,
- serde_json::json!({
- "textDocument": {
- "documentSymbol": {
- "hierarchicalDocumentSymbolSupport": true,
- },
- },
- }),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn equation_flat() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\begin{equation}\label{eq:foo}
- Foo
-\end{equation}
-
-\begin{equation}\label{eq:bar}
- Bar
-\end{equation}
-
-\begin{equation}
- Baz
-\end{equation}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\newlabel{eq:foo}{{1}{1}}"#,
- serde_json::json!({}),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn float_nested() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\begin{figure}
- Foo
- \caption{Foo}\label{fig:foo}
-\end{figure}
-
-\begin{figure}
- Bar
- \caption{Bar}\label{fig:bar}
-\end{figure}
-
-\begin{figure}
- Baz
- \caption{Baz}
-\end{figure}
-
-\begin{figure}
- Qux
-\end{figure}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Foo}}{1}\protected@file@percent }
-\newlabel{fig:foo}{{1}{1}}
-\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Bar}}{1}\protected@file@percent }
-\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Baz}}{1}\protected@file@percent }"#,
- serde_json::json!({
- "textDocument": {
- "documentSymbol": {
- "hierarchicalDocumentSymbolSupport": true,
- },
- },
- }),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn float_flat() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\begin{figure}
- Foo
- \caption{Foo}\label{fig:foo}
-\end{figure}
-
-\begin{figure}
- Bar
- \caption{Bar}\label{fig:bar}
-\end{figure}
-
-\begin{figure}
- Baz
- \caption{Baz}
-\end{figure}
-
-\begin{figure}
- Qux
-\end{figure}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Foo}}{1}\protected@file@percent }
-\newlabel{fig:foo}{{1}{1}}
-\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Bar}}{1}\protected@file@percent }
-\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces Baz}}{1}\protected@file@percent }"#,
- serde_json::json!({}),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn section_nested() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\section{Foo}
-
-\section{Bar}\label{sec:bar}
-
-\subsection{Baz}\label{sec:baz}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\@writefile{toc}{\contentsline {section}{\numberline {1}Foo}{1}\protected@file@percent }
-\@writefile{toc}{\contentsline {section}{\numberline {2}Bar}{1}\protected@file@percent }
-\newlabel{sec:bar}{{2}{1}}"#,
- serde_json::json!({
- "textDocument": {
- "documentSymbol": {
- "hierarchicalDocumentSymbolSupport": true,
- },
- },
- }),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn section_flat() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\section{Foo}
-
-\section{Bar}\label{sec:bar}
-
-\subsection{Baz}\label{sec:baz}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\@writefile{toc}{\contentsline {section}{\numberline {1}Foo}{1}\protected@file@percent }
-\@writefile{toc}{\contentsline {section}{\numberline {2}Bar}{1}\protected@file@percent }
-\newlabel{sec:bar}{{2}{1}}"#,
- serde_json::json!({}),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn theorem_nested() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-\usepackage{amsthm}
-\newtheorem{lemma}{Lemma}
-
-\begin{document}
-
-\begin{lemma}[Foo]\label{thm:foo}
- Foo
-\end{lemma}
-
-\begin{lemma}\label{thm:bar}
- Bar
-\end{lemma}
-
-\begin{lemma}\label{thm:baz}
- Baz
-\end{lemma}
-
-\begin{lemma}[Qux]
- Qux
-\end{lemma}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\newlabel{thm:foo}{{1}{1}}
-\newlabel{thm:bar}{{2}{1}}"#,
- serde_json::json!({
- "textDocument": {
- "documentSymbol": {
- "hierarchicalDocumentSymbolSupport": true,
- },
- },
- }),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn theorem_flat() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-\usepackage{amsthm}
-\newtheorem{lemma}{Lemma}
-
-\begin{document}
-
-\begin{lemma}[Foo]\label{thm:foo}
- Foo
-\end{lemma}
-
-\begin{lemma}\label{thm:bar}
- Bar
-\end{lemma}
-
-\begin{lemma}\label{thm:baz}
- Baz
-\end{lemma}
-
-\begin{lemma}[Qux]
- Qux
-\end{lemma}
-
-\end{document}
-|
-
-%! main.aux
-\relax
-\newlabel{thm:foo}{{1}{1}}
-\newlabel{thm:bar}{{2}{1}}"#,
- serde_json::json!({}),
- serde_json::Value::Null,
- ));
-}
-
-#[test]
-fn ignored_patterns() {
- assert_json_snapshot!(find_symbols(
- r#"
-%! main.tex
-\documentclass{article}
-
-\begin{document}
-
-\begin{equation}\label{eq:foo}
- Foo
-\end{equation}
-
-\begin{enumerate}
- \item Foo
- \item Bar
-\end{enumerate}
+ .unwrap() else { unreachable!() };
-\end{document}
-|"#,
- serde_json::json!({}),
- serde_json::json!({
- "symbols": {
- "ignoredPatterns": ["Item", "Enumerate"]
- }
- }),
- ));
+ assert_debug_snapshot!(symbols);
}
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/formatting.rs b/support/texlab/crates/texlab/tests/lsp/text_document/formatting.rs
index 65200b1d84..05f8f768de 100644
--- a/support/texlab/crates/texlab/tests/lsp/text_document/formatting.rs
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/formatting.rs
@@ -1,4 +1,4 @@
-use base_db::LineIndex;
+use base_db::util::LineIndex;
use insta::assert_snapshot;
use lsp_types::{
request::Formatting, ClientCapabilities, DocumentFormattingParams, FormattingOptions,
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__issue_883.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__issue_883.snap
new file mode 100644
index 0000000000..2f17e08bdb
--- /dev/null
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__completion__issue_883.snap
@@ -0,0 +1,11 @@
+---
+source: crates/texlab/tests/lsp/text_document/completion.rs
+expression: "complete(r#\"\n%! bug.tex\n\\begin{doc\n |\n ^^^\n% Comment\"#)"
+---
+[
+ {
+ "label": "document",
+ "detail": "built-in",
+ "preselect": false
+ }
+]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_flat.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_flat.snap
deleted file mode 100644
index b160196d26..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_flat.snap
+++ /dev/null
@@ -1,96 +0,0 @@
----
-source: crates/texlab/tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{enumerate}\n \\item\\label{it:foo} Foo\n \\item\\label{it:bar} Bar\n \\item[Baz] Baz\n \\item[Qux]\\label{it:qux} Qux\n\\end{enumerate}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{it:foo}{{1}{1}}\n\\newlabel{it:qux}{{2}{1}}\"#,\n serde_json::json!({}), serde_json::Value::Null)"
----
-[
- {
- "name": "Enumerate",
- "kind": 10,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 9,
- "character": 15
- }
- }
- }
- },
- {
- "name": "1",
- "kind": 22,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 5,
- "character": 4
- },
- "end": {
- "line": 5,
- "character": 27
- }
- }
- }
- },
- {
- "name": "Item",
- "kind": 22,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 6,
- "character": 4
- },
- "end": {
- "line": 6,
- "character": 27
- }
- }
- }
- },
- {
- "name": "Baz",
- "kind": 22,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 7,
- "character": 4
- },
- "end": {
- "line": 7,
- "character": 18
- }
- }
- }
- },
- {
- "name": "2",
- "kind": 22,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 8,
- "character": 4
- },
- "end": {
- "line": 8,
- "character": 32
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_nested.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_nested.snap
deleted file mode 100644
index 8f777b6d8f..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__enumerate_nested.snap
+++ /dev/null
@@ -1,140 +0,0 @@
----
-source: tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{enumerate}\n \\item\\label{it:foo} Foo\n \\item\\label{it:bar} Bar\n \\item[Baz] Baz\n \\item[Qux]\\label{it:qux} Qux\n\\end{enumerate}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{it:foo}{{1}{1}}\n\\newlabel{it:qux}{{2}{1}}\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
----
-[
- {
- "name": "Enumerate",
- "kind": 10,
- "deprecated": false,
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 9,
- "character": 15
- }
- },
- "selectionRange": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 9,
- "character": 15
- }
- },
- "children": [
- {
- "name": "1",
- "detail": "it:foo",
- "kind": 22,
- "deprecated": false,
- "range": {
- "start": {
- "line": 5,
- "character": 4
- },
- "end": {
- "line": 5,
- "character": 27
- }
- },
- "selectionRange": {
- "start": {
- "line": 5,
- "character": 9
- },
- "end": {
- "line": 5,
- "character": 23
- }
- },
- "children": []
- },
- {
- "name": "Item",
- "detail": "it:bar",
- "kind": 22,
- "deprecated": false,
- "range": {
- "start": {
- "line": 6,
- "character": 4
- },
- "end": {
- "line": 6,
- "character": 27
- }
- },
- "selectionRange": {
- "start": {
- "line": 6,
- "character": 9
- },
- "end": {
- "line": 6,
- "character": 23
- }
- },
- "children": []
- },
- {
- "name": "Baz",
- "kind": 22,
- "deprecated": false,
- "range": {
- "start": {
- "line": 7,
- "character": 4
- },
- "end": {
- "line": 7,
- "character": 18
- }
- },
- "selectionRange": {
- "start": {
- "line": 7,
- "character": 4
- },
- "end": {
- "line": 7,
- "character": 18
- }
- },
- "children": []
- },
- {
- "name": "2",
- "detail": "it:qux",
- "kind": 22,
- "deprecated": false,
- "range": {
- "start": {
- "line": 8,
- "character": 4
- },
- "end": {
- "line": 8,
- "character": 32
- }
- },
- "selectionRange": {
- "start": {
- "line": 8,
- "character": 14
- },
- "end": {
- "line": 8,
- "character": 28
- }
- },
- "children": []
- }
- ]
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_flat.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_flat.snap
deleted file mode 100644
index 6ff985fa81..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_flat.snap
+++ /dev/null
@@ -1,60 +0,0 @@
----
-source: crates/texlab/tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{equation}\\label{eq:foo}\n Foo\n\\end{equation}\n\n\\begin{equation}\\label{eq:bar}\n Bar\n\\end{equation}\n\n\\begin{equation}\n Baz\n\\end{equation}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{eq:foo}{{1}{1}}\"#,\n serde_json::json!({}), serde_json::Value::Null)"
----
-[
- {
- "name": "Equation (1)",
- "kind": 14,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 6,
- "character": 14
- }
- }
- }
- },
- {
- "name": "Equation",
- "kind": 14,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 8,
- "character": 0
- },
- "end": {
- "line": 10,
- "character": 14
- }
- }
- }
- },
- {
- "name": "Equation",
- "kind": 14,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 12,
- "character": 0
- },
- "end": {
- "line": 14,
- "character": 14
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_nested.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_nested.snap
deleted file mode 100644
index 5965400814..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__equation_nested.snap
+++ /dev/null
@@ -1,86 +0,0 @@
----
-source: tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{equation}\\label{eq:foo}\n Foo\n\\end{equation}\n\n\\begin{equation}\\label{eq:bar}\n Bar\n\\end{equation}\n\n\\begin{equation}\n Baz\n\\end{equation}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{eq:foo}{{1}{1}}\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
----
-[
- {
- "name": "Equation (1)",
- "detail": "eq:foo",
- "kind": 14,
- "deprecated": false,
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 6,
- "character": 14
- }
- },
- "selectionRange": {
- "start": {
- "line": 4,
- "character": 16
- },
- "end": {
- "line": 4,
- "character": 30
- }
- },
- "children": []
- },
- {
- "name": "Equation",
- "detail": "eq:bar",
- "kind": 14,
- "deprecated": false,
- "range": {
- "start": {
- "line": 8,
- "character": 0
- },
- "end": {
- "line": 10,
- "character": 14
- }
- },
- "selectionRange": {
- "start": {
- "line": 8,
- "character": 16
- },
- "end": {
- "line": 8,
- "character": 30
- }
- },
- "children": []
- },
- {
- "name": "Equation",
- "kind": 14,
- "deprecated": false,
- "range": {
- "start": {
- "line": 12,
- "character": 0
- },
- "end": {
- "line": 14,
- "character": 14
- }
- },
- "selectionRange": {
- "start": {
- "line": 12,
- "character": 0
- },
- "end": {
- "line": 14,
- "character": 14
- }
- },
- "children": []
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_flat.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_flat.snap
deleted file mode 100644
index 742e405e0f..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_flat.snap
+++ /dev/null
@@ -1,60 +0,0 @@
----
-source: crates/texlab/tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{figure}\n Foo\n \\caption{Foo}\\label{fig:foo}\n\\end{figure}\n\n\\begin{figure}\n Bar\n \\caption{Bar}\\label{fig:bar}\n\\end{figure}\n\n\\begin{figure}\n Baz\n \\caption{Baz}\n\\end{figure}\n\n\\begin{figure}\n Qux\n\\end{figure}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Foo}}{1}\\protected@file@percent }\n\\newlabel{fig:foo}{{1}{1}}\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {2}{\\ignorespaces Bar}}{1}\\protected@file@percent }\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {3}{\\ignorespaces Baz}}{1}\\protected@file@percent }\"#,\n serde_json::json!({}), serde_json::Value::Null)"
----
-[
- {
- "name": "Figure 1: Foo",
- "kind": 6,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 7,
- "character": 12
- }
- }
- }
- },
- {
- "name": "Figure: Bar",
- "kind": 6,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 9,
- "character": 0
- },
- "end": {
- "line": 12,
- "character": 12
- }
- }
- }
- },
- {
- "name": "Figure: Baz",
- "kind": 6,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 14,
- "character": 0
- },
- "end": {
- "line": 17,
- "character": 12
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_nested.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_nested.snap
deleted file mode 100644
index a625beb1fb..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__float_nested.snap
+++ /dev/null
@@ -1,86 +0,0 @@
----
-source: tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{figure}\n Foo\n \\caption{Foo}\\label{fig:foo}\n\\end{figure}\n\n\\begin{figure}\n Bar\n \\caption{Bar}\\label{fig:bar}\n\\end{figure}\n\n\\begin{figure}\n Baz\n \\caption{Baz}\n\\end{figure}\n\n\\begin{figure}\n Qux\n\\end{figure}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {1}{\\ignorespaces Foo}}{1}\\protected@file@percent }\n\\newlabel{fig:foo}{{1}{1}}\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {2}{\\ignorespaces Bar}}{1}\\protected@file@percent }\n\\@writefile{lof}{\\contentsline {figure}{\\numberline {3}{\\ignorespaces Baz}}{1}\\protected@file@percent }\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
----
-[
- {
- "name": "Figure 1: Foo",
- "detail": "fig:foo",
- "kind": 6,
- "deprecated": false,
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 7,
- "character": 12
- }
- },
- "selectionRange": {
- "start": {
- "line": 6,
- "character": 17
- },
- "end": {
- "line": 6,
- "character": 32
- }
- },
- "children": []
- },
- {
- "name": "Figure: Bar",
- "detail": "fig:bar",
- "kind": 6,
- "deprecated": false,
- "range": {
- "start": {
- "line": 9,
- "character": 0
- },
- "end": {
- "line": 12,
- "character": 12
- }
- },
- "selectionRange": {
- "start": {
- "line": 11,
- "character": 17
- },
- "end": {
- "line": 11,
- "character": 32
- }
- },
- "children": []
- },
- {
- "name": "Figure: Baz",
- "kind": 6,
- "deprecated": false,
- "range": {
- "start": {
- "line": 14,
- "character": 0
- },
- "end": {
- "line": 17,
- "character": 12
- }
- },
- "selectionRange": {
- "start": {
- "line": 14,
- "character": 0
- },
- "end": {
- "line": 17,
- "character": 12
- }
- },
- "children": []
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__ignored_patterns.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__ignored_patterns.snap
deleted file mode 100644
index c1981e9db2..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__ignored_patterns.snap
+++ /dev/null
@@ -1,24 +0,0 @@
----
-source: crates/texlab/tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\begin{equation}\\label{eq:foo}\n Foo\n\\end{equation}\n \n\\begin{enumerate}\n \\item Foo\n \\item Bar\n\\end{enumerate}\n\n\\end{document}\n|\"#,\n serde_json::json!({}),\n serde_json::json!({\n \"symbols\" : { \"ignoredPatterns\" : [\"Item\", \"Enumerate\"] }\n }))"
----
-[
- {
- "name": "Equation",
- "kind": 14,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 6,
- "character": 14
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_flat.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_flat.snap
deleted file mode 100644
index 5ab04f4e60..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_flat.snap
+++ /dev/null
@@ -1,60 +0,0 @@
----
-source: crates/texlab/tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\section{Foo}\n\n\\section{Bar}\\label{sec:bar}\n\n\\subsection{Baz}\\label{sec:baz}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}\\protected@file@percent }\n\\@writefile{toc}{\\contentsline {section}{\\numberline {2}Bar}{1}\\protected@file@percent }\n\\newlabel{sec:bar}{{2}{1}}\"#,\n serde_json::json!({}), serde_json::Value::Null)"
----
-[
- {
- "name": "Foo",
- "kind": 2,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 4,
- "character": 13
- }
- }
- }
- },
- {
- "name": "2 Bar",
- "kind": 2,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 6,
- "character": 0
- },
- "end": {
- "line": 8,
- "character": 31
- }
- }
- }
- },
- {
- "name": "Baz",
- "kind": 2,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 8,
- "character": 0
- },
- "end": {
- "line": 8,
- "character": 31
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_nested.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_nested.snap
deleted file mode 100644
index bac292bf01..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__section_nested.snap
+++ /dev/null
@@ -1,87 +0,0 @@
----
-source: tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\n\\begin{document}\n\n\\section{Foo}\n\n\\section{Bar}\\label{sec:bar}\n\n\\subsection{Baz}\\label{sec:baz}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\@writefile{toc}{\\contentsline {section}{\\numberline {1}Foo}{1}\\protected@file@percent }\n\\@writefile{toc}{\\contentsline {section}{\\numberline {2}Bar}{1}\\protected@file@percent }\n\\newlabel{sec:bar}{{2}{1}}\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
----
-[
- {
- "name": "Foo",
- "kind": 2,
- "deprecated": false,
- "range": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 4,
- "character": 13
- }
- },
- "selectionRange": {
- "start": {
- "line": 4,
- "character": 0
- },
- "end": {
- "line": 4,
- "character": 13
- }
- },
- "children": []
- },
- {
- "name": "2 Bar",
- "detail": "sec:bar",
- "kind": 2,
- "deprecated": false,
- "range": {
- "start": {
- "line": 6,
- "character": 0
- },
- "end": {
- "line": 8,
- "character": 31
- }
- },
- "selectionRange": {
- "start": {
- "line": 6,
- "character": 13
- },
- "end": {
- "line": 6,
- "character": 28
- }
- },
- "children": [
- {
- "name": "Baz",
- "detail": "sec:baz",
- "kind": 2,
- "deprecated": false,
- "range": {
- "start": {
- "line": 8,
- "character": 0
- },
- "end": {
- "line": 8,
- "character": 31
- }
- },
- "selectionRange": {
- "start": {
- "line": 8,
- "character": 16
- },
- "end": {
- "line": 8,
- "character": 31
- }
- },
- "children": []
- }
- ]
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__smoke.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__smoke.snap
new file mode 100644
index 0000000000..061fc93c95
--- /dev/null
+++ b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__smoke.snap
@@ -0,0 +1,103 @@
+---
+source: crates/texlab/tests/lsp/text_document/document_symbol.rs
+expression: symbols
+---
+[
+ DocumentSymbol {
+ name: "Foo",
+ detail: None,
+ kind: Module,
+ tags: None,
+ deprecated: Some(
+ false,
+ ),
+ range: Range {
+ start: Position {
+ line: 0,
+ character: 0,
+ },
+ end: Position {
+ line: 0,
+ character: 30,
+ },
+ },
+ selection_range: Range {
+ start: Position {
+ line: 0,
+ character: 0,
+ },
+ end: Position {
+ line: 0,
+ character: 30,
+ },
+ },
+ children: Some(
+ [
+ DocumentSymbol {
+ name: "Bar",
+ detail: None,
+ kind: Module,
+ tags: None,
+ deprecated: Some(
+ false,
+ ),
+ range: Range {
+ start: Position {
+ line: 0,
+ character: 14,
+ },
+ end: Position {
+ line: 0,
+ character: 30,
+ },
+ },
+ selection_range: Range {
+ start: Position {
+ line: 0,
+ character: 14,
+ },
+ end: Position {
+ line: 0,
+ character: 30,
+ },
+ },
+ children: Some(
+ [],
+ ),
+ },
+ ],
+ ),
+ },
+ DocumentSymbol {
+ name: "Baz",
+ detail: None,
+ kind: Module,
+ tags: None,
+ deprecated: Some(
+ false,
+ ),
+ range: Range {
+ start: Position {
+ line: 0,
+ character: 31,
+ },
+ end: Position {
+ line: 0,
+ character: 44,
+ },
+ },
+ selection_range: Range {
+ start: Position {
+ line: 0,
+ character: 31,
+ },
+ end: Position {
+ line: 0,
+ character: 44,
+ },
+ },
+ children: Some(
+ [],
+ ),
+ },
+]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_flat.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_flat.snap
deleted file mode 100644
index a20b9bb236..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_flat.snap
+++ /dev/null
@@ -1,78 +0,0 @@
----
-source: crates/texlab/tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\\usepackage{amsthm}\n\\newtheorem{lemma}{Lemma}\n\n\\begin{document}\n\n\\begin{lemma}[Foo]\\label{thm:foo}\n Foo\n\\end{lemma}\n\n\\begin{lemma}\\label{thm:bar}\n Bar\n\\end{lemma}\n\n\\begin{lemma}\\label{thm:baz}\n Baz\n\\end{lemma}\n\n\\begin{lemma}[Qux]\n Qux\n\\end{lemma}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{thm:foo}{{1}{1}}\n\\newlabel{thm:bar}{{2}{1}}\"#,\n serde_json::json!({}), serde_json::Value::Null)"
----
-[
- {
- "name": "Lemma 1 (Foo)",
- "kind": 13,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 6,
- "character": 0
- },
- "end": {
- "line": 8,
- "character": 11
- }
- }
- }
- },
- {
- "name": "Lemma 2",
- "kind": 13,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 10,
- "character": 0
- },
- "end": {
- "line": 12,
- "character": 11
- }
- }
- }
- },
- {
- "name": "Lemma",
- "kind": 13,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 14,
- "character": 0
- },
- "end": {
- "line": 16,
- "character": 11
- }
- }
- }
- },
- {
- "name": "Lemma (Qux)",
- "kind": 13,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 18,
- "character": 0
- },
- "end": {
- "line": 20,
- "character": 11
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_nested.snap b/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_nested.snap
deleted file mode 100644
index 82bdd6d1d9..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/text_document/snapshots/lsp__text_document__document_symbol__theorem_nested.snap
+++ /dev/null
@@ -1,113 +0,0 @@
----
-source: tests/lsp/text_document/document_symbol.rs
-expression: "find_symbols(r#\"\n%! main.tex\n\\documentclass{article}\n\\usepackage{amsthm}\n\\newtheorem{lemma}{Lemma}\n\n\\begin{document}\n\n\\begin{lemma}[Foo]\\label{thm:foo}\n Foo\n\\end{lemma}\n\n\\begin{lemma}\\label{thm:bar}\n Bar\n\\end{lemma}\n\n\\begin{lemma}\\label{thm:baz}\n Baz\n\\end{lemma}\n\n\\begin{lemma}[Qux]\n Qux\n\\end{lemma}\n\n\\end{document}\n|\n\n%! main.aux\n\\relax\n\\newlabel{thm:foo}{{1}{1}}\n\\newlabel{thm:bar}{{2}{1}}\"#,\n serde_json::json!({\n \"textDocument\" :\n {\n \"documentSymbol\" :\n { \"hierarchicalDocumentSymbolSupport\" : true, },\n },\n }), serde_json::Value::Null)"
----
-[
- {
- "name": "Lemma 1 (Foo)",
- "detail": "thm:foo",
- "kind": 13,
- "deprecated": false,
- "range": {
- "start": {
- "line": 6,
- "character": 0
- },
- "end": {
- "line": 8,
- "character": 11
- }
- },
- "selectionRange": {
- "start": {
- "line": 6,
- "character": 18
- },
- "end": {
- "line": 6,
- "character": 33
- }
- },
- "children": []
- },
- {
- "name": "Lemma 2",
- "detail": "thm:bar",
- "kind": 13,
- "deprecated": false,
- "range": {
- "start": {
- "line": 10,
- "character": 0
- },
- "end": {
- "line": 12,
- "character": 11
- }
- },
- "selectionRange": {
- "start": {
- "line": 10,
- "character": 13
- },
- "end": {
- "line": 10,
- "character": 28
- }
- },
- "children": []
- },
- {
- "name": "Lemma",
- "detail": "thm:baz",
- "kind": 13,
- "deprecated": false,
- "range": {
- "start": {
- "line": 14,
- "character": 0
- },
- "end": {
- "line": 16,
- "character": 11
- }
- },
- "selectionRange": {
- "start": {
- "line": 14,
- "character": 13
- },
- "end": {
- "line": 14,
- "character": 28
- }
- },
- "children": []
- },
- {
- "name": "Lemma (Qux)",
- "kind": 13,
- "deprecated": false,
- "range": {
- "start": {
- "line": 18,
- "character": 0
- },
- "end": {
- "line": 20,
- "character": 11
- }
- },
- "selectionRange": {
- "start": {
- "line": 18,
- "character": 0
- },
- "end": {
- "line": 20,
- "character": 11
- }
- },
- "children": []
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_bibtex.snap b/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_bibtex.snap
deleted file mode 100644
index 3e74634e7b..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_bibtex.snap
+++ /dev/null
@@ -1,42 +0,0 @@
----
-source: crates/texlab/tests/lsp/workspace/symbol.rs
-expression: "find_symbols(FIXTURE, \"bibtex\")"
----
-[
- {
- "name": "foo",
- "kind": 24,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.bib",
- "range": {
- "start": {
- "line": 0,
- "character": 0
- },
- "end": {
- "line": 0,
- "character": 14
- }
- }
- }
- },
- {
- "name": "bar",
- "kind": 15,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.bib",
- "range": {
- "start": {
- "line": 2,
- "character": 0
- },
- "end": {
- "line": 2,
- "character": 20
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_figure.snap b/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_figure.snap
deleted file mode 100644
index 66758aa90e..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_figure.snap
+++ /dev/null
@@ -1,24 +0,0 @@
----
-source: crates/texlab/tests/lsp/workspace/symbol.rs
-expression: "find_symbols(FIXTURE, \"figure\")"
----
-[
- {
- "name": "Figure 1: Bar",
- "kind": 6,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 15,
- "character": 0
- },
- "end": {
- "line": 19,
- "character": 12
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_item.snap b/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_item.snap
deleted file mode 100644
index fdc506b308..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_item.snap
+++ /dev/null
@@ -1,60 +0,0 @@
----
-source: crates/texlab/tests/lsp/workspace/symbol.rs
-expression: "find_symbols(FIXTURE, \"item\")"
----
-[
- {
- "name": "1",
- "kind": 22,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 24,
- "character": 4
- },
- "end": {
- "line": 24,
- "character": 28
- }
- }
- }
- },
- {
- "name": "2",
- "kind": 22,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 25,
- "character": 4
- },
- "end": {
- "line": 25,
- "character": 28
- }
- }
- }
- },
- {
- "name": "3",
- "kind": 22,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 26,
- "character": 4
- },
- "end": {
- "line": 26,
- "character": 28
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_math.snap b/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_math.snap
deleted file mode 100644
index 2dc59f021b..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_math.snap
+++ /dev/null
@@ -1,42 +0,0 @@
----
-source: crates/texlab/tests/lsp/workspace/symbol.rs
-expression: "find_symbols(FIXTURE, \"math\")"
----
-[
- {
- "name": "Equation (1)",
- "kind": 14,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 9,
- "character": 0
- },
- "end": {
- "line": 11,
- "character": 14
- }
- }
- }
- },
- {
- "name": "Lemma 1 (Qux)",
- "kind": 13,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 33,
- "character": 0
- },
- "end": {
- "line": 35,
- "character": 11
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_section.snap b/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_section.snap
deleted file mode 100644
index eff280251a..0000000000
--- a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__filter_type_section.snap
+++ /dev/null
@@ -1,78 +0,0 @@
----
-source: crates/texlab/tests/lsp/workspace/symbol.rs
-expression: "find_symbols(FIXTURE, \"section\")"
----
-[
- {
- "name": "1 Foo",
- "kind": 2,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 7,
- "character": 0
- },
- "end": {
- "line": 11,
- "character": 14
- }
- }
- }
- },
- {
- "name": "2 Bar",
- "kind": 2,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 13,
- "character": 0
- },
- "end": {
- "line": 19,
- "character": 12
- }
- }
- }
- },
- {
- "name": "3 Baz",
- "kind": 2,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 21,
- "character": 0
- },
- "end": {
- "line": 27,
- "character": 15
- }
- }
- }
- },
- {
- "name": "4 Qux",
- "kind": 2,
- "deprecated": false,
- "location": {
- "uri": "redacted://main.tex",
- "range": {
- "start": {
- "line": 29,
- "character": 0
- },
- "end": {
- "line": 35,
- "character": 11
- }
- }
- }
- }
-]
diff --git a/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__smoke.snap b/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__smoke.snap
new file mode 100644
index 0000000000..20c012bec9
--- /dev/null
+++ b/support/texlab/crates/texlab/tests/lsp/workspace/snapshots/lsp__workspace__symbol__smoke.snap
@@ -0,0 +1,78 @@
+---
+source: crates/texlab/tests/lsp/workspace/symbol.rs
+expression: symbols
+---
+[
+ SymbolInformation {
+ name: "Foo",
+ kind: Module,
+ tags: None,
+ deprecated: Some(
+ false,
+ ),
+ location: Location {
+ uri: Url {
+ scheme: "redacted",
+ cannot_be_a_base: false,
+ username: "",
+ password: None,
+ host: Some(
+ Domain(
+ "main.tex",
+ ),
+ ),
+ port: None,
+ path: "",
+ query: None,
+ fragment: None,
+ },
+ range: Range {
+ start: Position {
+ line: 7,
+ character: 0,
+ },
+ end: Position {
+ line: 8,
+ character: 3,
+ },
+ },
+ },
+ container_name: None,
+ },
+ SymbolInformation {
+ name: "Bar",
+ kind: Module,
+ tags: None,
+ deprecated: Some(
+ false,
+ ),
+ location: Location {
+ uri: Url {
+ scheme: "redacted",
+ cannot_be_a_base: false,
+ username: "",
+ password: None,
+ host: Some(
+ Domain(
+ "main.tex",
+ ),
+ ),
+ port: None,
+ path: "",
+ query: None,
+ fragment: None,
+ },
+ range: Range {
+ start: Position {
+ line: 10,
+ character: 0,
+ },
+ end: Position {
+ line: 11,
+ character: 3,
+ },
+ },
+ },
+ container_name: None,
+ },
+]
diff --git a/support/texlab/crates/texlab/tests/lsp/workspace/symbol.rs b/support/texlab/crates/texlab/tests/lsp/workspace/symbol.rs
index e726ed6860..8deae20a44 100644
--- a/support/texlab/crates/texlab/tests/lsp/workspace/symbol.rs
+++ b/support/texlab/crates/texlab/tests/lsp/workspace/symbol.rs
@@ -1,38 +1,15 @@
-use insta::assert_json_snapshot;
+use insta::assert_debug_snapshot;
use lsp_types::{
- request::WorkspaceSymbolRequest, ClientCapabilities, SymbolInformation, WorkspaceSymbolParams,
+ request::WorkspaceSymbolRequest, ClientCapabilities, WorkspaceSymbolParams,
WorkspaceSymbolResponse,
};
use crate::fixture::TestBed;
-fn find_symbols(fixture: &str, query: &str) -> Vec<SymbolInformation> {
- let test_bed = TestBed::new(fixture).unwrap();
-
- test_bed.initialize(ClientCapabilities::default()).unwrap();
-
- let mut symbols = match test_bed
- .client()
- .send_request::<WorkspaceSymbolRequest>(WorkspaceSymbolParams {
- query: query.to_string(),
- work_done_progress_params: Default::default(),
- partial_result_params: Default::default(),
- })
- .unwrap()
- {
- Some(WorkspaceSymbolResponse::Flat(symbols)) => symbols,
- Some(WorkspaceSymbolResponse::Nested(_)) => unreachable!(),
- None => Vec::new(),
- };
-
- for symbol in &mut symbols {
- symbol.location.uri = test_bed.redact(&symbol.location.uri);
- }
-
- symbols
-}
-
-const FIXTURE: &str = r#"
+#[test]
+fn test_smoke() {
+ let test_bed = TestBed::new(
+ r#"
%! main.tex
\documentclass{article}
\usepackage{caption}
@@ -42,83 +19,30 @@ const FIXTURE: &str = r#"
\begin{document}
\section{Foo}\label{sec:foo}
+Foo
-\begin{equation}\label{eq:foo}
- Foo
-\end{equation}
-
-\section{Bar}\label{sec:bar}
-
-\begin{figure}
- Bar
- \caption{Bar}
- \label{fig:bar}
-\end{figure}
-
-\section{Baz}\label{sec:baz}
-
-\begin{enumerate}
- \item\label{itm:foo} Foo
- \item\label{itm:bar} Bar
- \item\label{itm:baz} Baz
-\end{enumerate}
-
-\section{Qux}\label{sec:qux}
-
-\newtheorem{lemma}{Lemma}
-
-\begin{lemma}[Qux]\label{thm:qux}
- Qux
-\end{lemma}
+\section{Bar}
+Bar
\end{document}
-|
+"#,
+ )
+ .unwrap();
-%! main.aux
-\relax
-\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Bar\relax }}{1}\protected@file@percent }
-\providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}}
-\newlabel{fig:bar}{{1}{1}}
-\@writefile{toc}{\contentsline {section}{\numberline {1}Foo}{1}\protected@file@percent }
-\newlabel{sec:foo}{{1}{1}}
-\newlabel{eq:foo}{{1}{1}}
-\@writefile{toc}{\contentsline {section}{\numberline {2}Bar}{1}\protected@file@percent }
-\newlabel{sec:bar}{{2}{1}}
-\@writefile{toc}{\contentsline {section}{\numberline {3}Baz}{1}\protected@file@percent }
-\newlabel{sec:baz}{{3}{1}}
-\newlabel{itm:foo}{{1}{1}}
-\newlabel{itm:bar}{{2}{1}}
-\newlabel{itm:baz}{{3}{1}}
-\@writefile{toc}{\contentsline {section}{\numberline {4}Qux}{1}\protected@file@percent }
-\newlabel{sec:qux}{{4}{1}}
-\newlabel{thm:qux}{{1}{1}}
-
-%! main.bib
-@article{foo,}
-
-@string{bar = "bar"}"#;
-
-#[test]
-fn filter_type_section() {
- assert_json_snapshot!(find_symbols(FIXTURE, "section"));
-}
-
-#[test]
-fn filter_type_figure() {
- assert_json_snapshot!(find_symbols(FIXTURE, "figure"));
-}
+ test_bed.initialize(ClientCapabilities::default()).unwrap();
-#[test]
-fn filter_type_item() {
- assert_json_snapshot!(find_symbols(FIXTURE, "item"));
-}
+ let Some(WorkspaceSymbolResponse::Flat(mut symbols)) = test_bed
+ .client()
+ .send_request::<WorkspaceSymbolRequest>(WorkspaceSymbolParams {
+ query: String::new(),
+ work_done_progress_params: Default::default(),
+ partial_result_params: Default::default(),
+ })
+ .unwrap() else { unreachable!() };
-#[test]
-fn filter_type_math() {
- assert_json_snapshot!(find_symbols(FIXTURE, "math"));
-}
+ for symbol in &mut symbols {
+ symbol.location.uri = test_bed.redact(&symbol.location.uri);
+ }
-#[test]
-fn filter_bibtex() {
- assert_json_snapshot!(find_symbols(FIXTURE, "bibtex"));
+ assert_debug_snapshot!(symbols);
}