Skip to main content

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}