1use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use mant_ir::{ResolvedContent, TldrDocument};
7
8use crate::{
9 DocumentAddress, DocumentResponse, NodeSelector, OutlineDetail, SearchCase, SearchScope,
10 SearchSyntax, default_search_limit,
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
15pub enum QuerySchema {
16 #[serde(rename = "mant.query/v7")]
18 V7,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
23pub enum RequestSchema {
24 #[serde(rename = "mant.request/v7")]
26 V7,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
31#[serde(
32 tag = "kind",
33 rename_all = "kebab-case",
34 rename_all_fields = "camelCase",
35 deny_unknown_fields
36)]
37pub enum QueryInput {
38 Document {
41 selector: String,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 source: Option<String>,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 manual_section: Option<String>,
49 },
50 File {
52 path: String,
54 format: InputFormat,
56 },
57}
58
59#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
61#[serde(rename_all = "kebab-case")]
62pub enum InputFormat {
63 #[default]
65 Auto,
66 Markdown,
68 Roff,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
74#[serde(
75 tag = "kind",
76 rename_all = "kebab-case",
77 rename_all_fields = "camelCase",
78 deny_unknown_fields
79)]
80pub enum QueryView {
81 Full {},
83 Outline {
85 detail: OutlineDetail,
87 },
88 Excerpt {
90 #[schemars(length(min = 1))]
92 selectors: Vec<NodeSelector>,
93 },
94 Explain {
96 #[schemars(length(min = 1))]
98 entry: String,
99 },
100 Search {
102 #[schemars(length(min = 1, max = 4096))]
104 pattern: String,
105 #[serde(default)]
107 syntax: SearchSyntax,
108 #[serde(default)]
110 case: SearchCase,
111 #[serde(default)]
113 scope: SearchScope,
114 #[serde(default)]
116 word: bool,
117 #[serde(default)]
119 #[schemars(range(max = 100))]
120 context_lines: u16,
121 #[serde(default = "default_search_limit")]
123 #[schemars(range(min = 1, max = 10000))]
124 limit: u32,
125 #[serde(default)]
127 offset: u32,
128 },
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
133#[serde(rename_all = "camelCase", deny_unknown_fields)]
134#[schemars(extend("$id" = "urn:mant:request:v7"))]
135pub struct QueryRequest {
136 pub schema: RequestSchema,
138 pub input: QueryInput,
140 pub view: QueryView,
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
146#[serde(rename_all = "camelCase")]
147#[schemars(extend("$id" = "urn:mant:query:v7"))]
148pub struct QueryBundle {
149 pub schema: QuerySchema,
151 pub label: String,
153 #[serde(skip_serializing_if = "Option::is_none")]
156 pub address: Option<DocumentAddress>,
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub document: Option<DocumentResponse>,
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub tldr: Option<TldrDocument>,
163}
164
165impl From<&ResolvedContent> for QueryBundle {
166 fn from(content: &ResolvedContent) -> Self {
167 Self {
168 schema: QuerySchema::V7,
169 label: content.label.clone(),
170 address: content.address.clone(),
171 document: content.document.as_ref().map(Into::into),
172 tldr: content.tldr.clone(),
173 }
174 }
175}
176
177impl From<QueryBundle> for ResolvedContent {
178 fn from(bundle: QueryBundle) -> Self {
179 Self {
180 label: bundle.label,
181 address: bundle.address,
182 document: bundle.document.map(Into::into),
183 tldr: bundle.tldr,
184 }
185 }
186}