badness_parser/semantic/label.rs
1//! Label definitions and reference uses — the data of the per-file
2//! label/reference model: `Vec`-stored records addressed by newtype ids.
3
4use rowan::TextRange;
5use smol_str::SmolStr;
6
7/// Index of a [`LabelDef`] in [`SemanticModel::labels`](super::SemanticModel).
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct LabelId(pub(crate) u32);
10
11impl LabelId {
12 pub(crate) fn from_index(i: usize) -> Self {
13 Self(i as u32)
14 }
15}
16
17/// Index of a [`LabelRef`] in [`SemanticModel::refs`](super::SemanticModel).
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub struct RefId(pub(crate) u32);
20
21impl RefId {
22 pub(crate) fn from_index(i: usize) -> Self {
23 Self(i as u32)
24 }
25}
26
27/// A `\label{key}` definition site.
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct LabelDef {
30 pub name: SmolStr,
31 /// Range of the `\label{key}` command — the control word through its key
32 /// group — for diagnostics / go-to-def. Excludes any *second* group the
33 /// greedy parser may have over-attached (`\label`'s arity is unknown at parse
34 /// time; see `builder::label_range`).
35 pub range: TextRange,
36 /// Range of just the key text inside the braces (`sec:intro` in
37 /// `\label{sec:intro}`), trimmed of surrounding whitespace. The precise span a
38 /// rename rewrites — narrower than [`range`](Self::range), which spans the whole
39 /// command.
40 pub key_range: TextRange,
41 /// Set by the resolve pass when any reference in this file uses `name`.
42 /// Per-file only — a label referenced solely from an `\input`-ed file looks
43 /// unreferenced here until the (deferred) cross-file resolver lands.
44 pub referenced: bool,
45}
46
47/// Which reference-family command produced a [`LabelRef`]. A small explicit
48/// table (the analog of `project::IncludeKind`) kept distinct so later passes
49/// can honor differences (`\cref` capitalization, `\nameref` text, …).
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub enum RefCommand {
52 // Single-key (LaTeX / amsmath / hyperref).
53 Ref,
54 PageRef,
55 EqRef,
56 AutoRef,
57 NameRef,
58 // Comma-separated key list (cleveref / varioref).
59 Cref,
60 CrefUpper,
61 Vref,
62 VrefUpper,
63 CpageRef,
64}
65
66impl RefCommand {
67 /// Whether this command accepts a comma-separated key list (cleveref /
68 /// varioref) rather than a single key.
69 pub fn is_key_list(self) -> bool {
70 matches!(
71 self,
72 RefCommand::Cref
73 | RefCommand::CrefUpper
74 | RefCommand::Vref
75 | RefCommand::VrefUpper
76 | RefCommand::CpageRef
77 )
78 }
79}
80
81/// A reference *use* site — one per key. A `\cref{a,b,c}` produces three
82/// `LabelRef`s, each carrying the same command kind and command range.
83#[derive(Debug, Clone, PartialEq, Eq)]
84pub struct LabelRef {
85 pub name: SmolStr,
86 pub command: RefCommand,
87 /// Range of the enclosing command, shared by all keys split from one
88 /// `\cref{a,b,c}` — used for go-to-def / find-references navigation, which
89 /// jumps to the whole command.
90 pub range: TextRange,
91 /// Range of just this key inside the braces (`b` in `\cref{a,b}`), trimmed of
92 /// surrounding whitespace. Unlike [`range`](Self::range), this *is* per-key, so
93 /// a rename rewrites exactly one key of a list command.
94 pub key_range: TextRange,
95 /// Set by the resolve pass when `name` matches a `\label` in *this* file.
96 pub resolved: bool,
97}
98
99/// Which definer command produced a [`GlossaryDef`]. Kept distinct so a later
100/// hover/goto-def pass can render the entry appropriately (an acronym has
101/// short/long groups; an entry has a key=value settings group).
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
103pub enum GlossaryDefKind {
104 /// `\newglossaryentry` / `\longnewglossaryentry`.
105 Entry,
106 /// `\newacronym` (glossaries).
107 Acronym,
108 /// `\newabbreviation` (glossaries-extra).
109 Abbreviation,
110}
111
112/// A glossary/acronym key definition site (`\newglossaryentry{key}{…}`,
113/// `\newacronym[opts]{key}{short}{long}`, …). The definition-side analog of
114/// [`LabelDef`]; the reference side (`\gls{key}`) is classified directly off the
115/// CST by completion and carries no stored model record yet.
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub struct GlossaryDef {
118 /// The entry key, as authored.
119 pub key: SmolStr,
120 pub kind: GlossaryDefKind,
121 /// Range of the command through its key group (like [`LabelDef::range`]) —
122 /// the navigation target for a future go-to-definition.
123 pub range: TextRange,
124 /// Range of just the trimmed key text inside the braces — the precise span a
125 /// future rename would rewrite.
126 pub key_range: TextRange,
127}
128
129/// Which definer command produced a [`ColorDef`]. Kept distinct so a later
130/// hover/goto-def pass can render the definition appropriately (`\definecolor`
131/// carries a model + spec; `\colorlet` aliases an existing color).
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
133pub enum ColorDefKind {
134 /// `\definecolor{name}{model}{spec}`.
135 DefineColor,
136 /// `\providecolor{name}{model}{spec}`.
137 ProvideColor,
138 /// `\colorlet{name}{base}`.
139 Colorlet,
140}
141
142/// A color-name definition site (`\definecolor{name}{model}{spec}`,
143/// `\colorlet{name}{base}`, …). The definition-side analog of [`LabelDef`],
144/// collected so color-name completion can offer document-defined colors
145/// alongside the built-in list; the reference side (`\textcolor{name}{…}`) is
146/// classified directly off the CST by completion and carries no stored record.
147#[derive(Debug, Clone, PartialEq, Eq)]
148pub struct ColorDef {
149 /// The color name, as authored (the first `{…}` group).
150 pub name: SmolStr,
151 pub kind: ColorDefKind,
152 /// Range of the command through its name group (like [`LabelDef::range`]) —
153 /// the navigation target for a future go-to-definition.
154 pub range: TextRange,
155 /// Range of just the trimmed name text inside the braces — the precise span a
156 /// future rename would rewrite.
157 pub key_range: TextRange,
158}
159
160/// A citation *use* site — one per key. A `\cite{a,b}` produces two
161/// `CitationRef`s. Citations are always cross-file: cite keys live in `.bib`
162/// files, so there is no in-file resolution (no `resolved` flag); the
163/// `undefined-citation` lint resolves them against the project's bibliography via
164/// `project::citations::ResolvedCitations` (in the `badness` crate).
165#[derive(Debug, Clone, PartialEq, Eq)]
166pub struct CitationRef {
167 /// The cite key, as authored.
168 pub name: SmolStr,
169 /// The citation command that introduced it, sans backslash (`cite`,
170 /// `parencite`, `nocite`, …) — informational, for diagnostics.
171 pub command: SmolStr,
172 /// Range of the enclosing command (shared by keys split from one `\cite{a,b}`,
173 /// like [`LabelRef::range`]).
174 pub range: TextRange,
175 /// Range of just this key inside the braces (`b` in `\cite{a,b}`), trimmed of
176 /// surrounding whitespace — the precise span a rename rewrites.
177 pub key_range: TextRange,
178}