1use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use mant_ir::{
7 Block, DefinitionCase, DefinitionItem, DefinitionRole, Diagnostic, DocumentMeta,
8 DocumentSource, NodeId, Section, TldrDocument,
9};
10
11use crate::{NodePath, Producer};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
15pub enum OutlineSchema {
16 #[serde(rename = "mant.outline/v0.8")]
18 V0Dot8,
19}
20
21impl OutlineSchema {
22 pub const ID: &'static str = "mant.outline/v0.8";
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
28#[serde(rename_all = "kebab-case")]
29pub enum OutlineDetail {
30 Sections,
32 Entries,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
38#[serde(rename_all = "camelCase")]
39#[schemars(extend("$id" = "urn:mant:outline:v0.8"))]
40pub struct QueryOutline {
41 pub schema: OutlineSchema,
43 pub detail: OutlineDetail,
45 pub label: String,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub source: Option<DocumentSource>,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub meta: Option<DocumentMeta>,
53 #[serde(default, skip_serializing_if = "Vec::is_empty")]
55 pub diagnostics: Vec<Diagnostic>,
56 #[serde(default = "default_true", skip_serializing_if = "is_true")]
61 pub entries_complete: bool,
62 pub nodes: Vec<OutlineNode>,
64}
65
66const fn default_true() -> bool {
67 true
68}
69
70#[allow(clippy::trivially_copy_pass_by_ref)]
72const fn is_true(value: &bool) -> bool {
73 *value
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
78#[serde(
79 tag = "kind",
80 rename_all = "kebab-case",
81 rename_all_fields = "camelCase"
82)]
83pub enum OutlineNode {
84 Tldr {
86 path: NodePath,
88 id: NodeId,
90 title: String,
92 },
93 DocumentRoot {
95 path: NodePath,
97 id: NodeId,
99 title: String,
101 },
102 DocumentSection {
104 path: NodePath,
106 id: NodeId,
108 title: String,
110 children: Vec<OutlineNode>,
112 },
113 DocumentEntry {
115 path: NodePath,
117 id: NodeId,
119 title: String,
121 role: DefinitionRole,
123 case: DefinitionCase,
125 names: Vec<String>,
127 },
128}
129
130impl OutlineNode {
131 #[must_use]
133 pub fn path(&self) -> &str {
134 match self {
135 Self::Tldr { path, .. }
136 | Self::DocumentRoot { path, .. }
137 | Self::DocumentSection { path, .. }
138 | Self::DocumentEntry { path, .. } => path,
139 }
140 }
141
142 #[must_use]
144 pub fn id(&self) -> &str {
145 match self {
146 Self::Tldr { id, .. }
147 | Self::DocumentRoot { id, .. }
148 | Self::DocumentSection { id, .. }
149 | Self::DocumentEntry { id, .. } => id,
150 }
151 }
152
153 #[must_use]
155 pub fn title(&self) -> &str {
156 match self {
157 Self::Tldr { title, .. }
158 | Self::DocumentRoot { title, .. }
159 | Self::DocumentSection { title, .. }
160 | Self::DocumentEntry { title, .. } => title,
161 }
162 }
163
164 #[must_use]
166 pub fn children(&self) -> &[Self] {
167 match self {
168 Self::DocumentSection { children, .. } => children,
169 Self::Tldr { .. } | Self::DocumentRoot { .. } | Self::DocumentEntry { .. } => &[],
170 }
171 }
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
176pub enum ExcerptSchema {
177 #[serde(rename = "mant.excerpt/v0.8")]
179 V0Dot8,
180}
181
182impl ExcerptSchema {
183 pub const ID: &'static str = "mant.excerpt/v0.8";
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
189#[serde(rename_all = "camelCase")]
190#[schemars(extend("$id" = "urn:mant:excerpt:v0.8"))]
191pub struct QueryExcerpt {
192 pub schema: ExcerptSchema,
194 pub label: String,
196 #[serde(skip_serializing_if = "Option::is_none")]
198 pub producer: Option<Producer>,
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub source: Option<DocumentSource>,
202 #[serde(skip_serializing_if = "Option::is_none")]
204 pub meta: Option<DocumentMeta>,
205 #[serde(default, skip_serializing_if = "Vec::is_empty")]
207 pub diagnostics: Vec<Diagnostic>,
208 pub selections: Vec<ExcerptSelection>,
210}
211
212#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
214#[serde(
215 tag = "kind",
216 rename_all = "kebab-case",
217 rename_all_fields = "camelCase"
218)]
219pub enum ExcerptSelection {
220 Tldr {
222 outline: OutlineTrail,
224 document: TldrDocument,
226 },
227 DocumentRoot {
229 outline: OutlineTrail,
231 blocks: Vec<Block>,
233 },
234 DocumentSection {
236 outline: OutlineTrail,
238 section: Section,
240 },
241 DocumentEntry {
243 outline: OutlineTrail,
245 entry: DefinitionItem,
247 },
248}
249
250impl ExcerptSelection {
251 #[must_use]
253 pub const fn outline(&self) -> &OutlineTrail {
254 match self {
255 Self::Tldr { outline, .. }
256 | Self::DocumentRoot { outline, .. }
257 | Self::DocumentSection { outline, .. }
258 | Self::DocumentEntry { outline, .. } => outline,
259 }
260 }
261}
262
263#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
265#[serde(rename_all = "camelCase")]
266pub struct OutlineTrail {
267 #[serde(default, skip_serializing_if = "Vec::is_empty")]
269 pub ancestors: Vec<OutlineReference>,
270 pub node: OutlineNodeReference,
272}
273
274impl OutlineTrail {
275 #[must_use]
277 pub fn path(&self) -> &str {
278 self.node.path()
279 }
280
281 #[must_use]
283 pub fn title(&self) -> &str {
284 self.node.title()
285 }
286}
287
288#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
290#[serde(rename_all = "camelCase")]
291pub struct OutlineReference {
292 pub path: NodePath,
294 pub id: NodeId,
296 pub title: String,
298}
299
300#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
302#[serde(
303 tag = "kind",
304 rename_all = "kebab-case",
305 rename_all_fields = "camelCase"
306)]
307pub enum OutlineNodeReference {
308 Tldr {
310 path: NodePath,
312 id: NodeId,
314 title: String,
316 },
317 DocumentRoot {
319 path: NodePath,
321 id: NodeId,
323 title: String,
325 },
326 DocumentSection {
328 path: NodePath,
330 id: NodeId,
332 title: String,
334 },
335 DocumentEntry {
337 path: NodePath,
339 id: NodeId,
341 title: String,
343 role: DefinitionRole,
345 case: DefinitionCase,
347 names: Vec<String>,
349 },
350}
351
352impl OutlineNodeReference {
353 #[must_use]
355 pub fn path(&self) -> &str {
356 match self {
357 Self::Tldr { path, .. }
358 | Self::DocumentRoot { path, .. }
359 | Self::DocumentSection { path, .. }
360 | Self::DocumentEntry { path, .. } => path,
361 }
362 }
363
364 #[must_use]
366 pub fn id(&self) -> &str {
367 match self {
368 Self::Tldr { id, .. }
369 | Self::DocumentRoot { id, .. }
370 | Self::DocumentSection { id, .. }
371 | Self::DocumentEntry { id, .. } => id,
372 }
373 }
374
375 #[must_use]
377 pub fn title(&self) -> &str {
378 match self {
379 Self::Tldr { title, .. }
380 | Self::DocumentRoot { title, .. }
381 | Self::DocumentSection { title, .. }
382 | Self::DocumentEntry { title, .. } => title,
383 }
384 }
385}