1use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
9pub struct PositionParams {
10 #[schemars(description = "Absolute path to the file.")]
12 pub file_path: String,
13 #[schemars(description = "Line number (1-based).")]
15 pub line: u32,
16 #[schemars(description = "Character/column number (1-based).")]
18 pub character: u32,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
24pub struct RangeParams {
25 #[schemars(description = "Start line (1-based).")]
27 pub start_line: u32,
28 #[schemars(description = "Start character (1-based).")]
30 pub start_character: u32,
31 #[schemars(description = "End line (1-based).")]
33 pub end_line: u32,
34 #[schemars(description = "End character (1-based).")]
36 pub end_character: u32,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
41#[schemars(description = "Parameters for finding all references to a symbol.")]
42pub struct ReferencesParams {
43 #[serde(flatten)]
45 pub position: PositionParams,
46 #[schemars(description = "Whether to include the declaration in the results.")]
48 #[serde(default)]
49 pub include_declaration: bool,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
54#[schemars(description = "Parameters for getting diagnostics (errors, warnings) for a file.")]
55pub struct DiagnosticsParams {
56 #[schemars(description = "Absolute path to the file.")]
58 pub file_path: String,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
63#[schemars(description = "Parameters for renaming a symbol across the workspace.")]
64pub struct RenameParams {
65 #[serde(flatten)]
67 pub position: PositionParams,
68 #[schemars(description = "New name for the symbol.")]
70 pub new_name: String,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
75#[schemars(description = "Parameters for getting code completion suggestions.")]
76pub struct CompletionsParams {
77 #[serde(flatten)]
79 pub position: PositionParams,
80 #[schemars(description = "Optional trigger character (e.g., '.', ':', '->').")]
82 pub trigger: Option<String>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
87#[schemars(description = "Parameters for getting all symbols in a document.")]
88pub struct DocumentSymbolsParams {
89 #[schemars(description = "Absolute path to the file.")]
91 pub file_path: String,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
96#[schemars(description = "Parameters for formatting a document.")]
97pub struct FormatDocumentParams {
98 #[schemars(description = "Absolute path to the file.")]
100 pub file_path: String,
101 #[schemars(description = "Tab size for formatting (default: 4).")]
103 #[serde(default = "default_tab_size")]
104 pub tab_size: u32,
105 #[schemars(description = "Whether to use spaces instead of tabs (default: true).")]
107 #[serde(default = "default_insert_spaces")]
108 pub insert_spaces: bool,
109}
110
111const fn default_tab_size() -> u32 {
112 4
113}
114
115const fn default_insert_spaces() -> bool {
116 true
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
121#[schemars(description = "Parameters for searching symbols across the workspace.")]
122pub struct WorkspaceSymbolParams {
123 #[schemars(description = "Search query for symbol names (supports partial matching).")]
125 pub query: String,
126 #[schemars(description = "Optional filter by symbol kind (function, class, variable, etc.).")]
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub kind_filter: Option<String>,
130 #[schemars(description = "Maximum results to return (default: 100).")]
132 #[serde(default = "default_max_results")]
133 pub limit: u32,
134}
135
136const fn default_max_results() -> u32 {
137 100
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
142#[schemars(
143 description = "Parameters for getting available code actions (quick fixes, refactorings) for a range."
144)]
145pub struct CodeActionsParams {
146 #[schemars(description = "Absolute path to the file.")]
148 pub file_path: String,
149 #[serde(flatten)]
151 pub range: RangeParams,
152 #[schemars(description = "Optional filter by action kind (quickfix, refactor, source, etc.).")]
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub kind_filter: Option<String>,
156}
157
158#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
160#[schemars(
161 description = "Parameters for getting incoming or outgoing calls for a call hierarchy item."
162)]
163pub struct CallHierarchyCallsParams {
164 #[schemars(description = "The call hierarchy item to get calls for (from prepare response).")]
166 pub item: serde_json::Value,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
171#[schemars(
172 description = "Parameters for getting cached diagnostics from LSP server notifications."
173)]
174pub struct CachedDiagnosticsParams {
175 #[schemars(description = "Absolute path to the file.")]
177 pub file_path: String,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
182#[schemars(description = "Parameters for getting recent LSP server log messages.")]
183pub struct ServerLogsParams {
184 #[schemars(description = "Maximum number of log entries to return (default: 50).")]
186 #[serde(default = "default_log_limit")]
187 pub limit: usize,
188 #[schemars(description = "Minimum log level to include: error, warning, info, debug.")]
190 #[serde(skip_serializing_if = "Option::is_none")]
191 pub min_level: Option<String>,
192}
193
194const fn default_log_limit() -> usize {
195 50
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
200#[schemars(
201 description = "Parameters for getting recent LSP server messages (showMessage notifications)."
202)]
203pub struct ServerMessagesParams {
204 #[schemars(description = "Maximum number of messages to return (default: 20).")]
206 #[serde(default = "default_message_limit")]
207 pub limit: usize,
208}
209
210const fn default_message_limit() -> usize {
211 20
212}
213
214#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
216#[schemars(description = "Parameters for getting inlay hints in a range.")]
217pub struct InlayHintsParams {
218 #[schemars(description = "Absolute path to the file.")]
220 pub file_path: String,
221 #[serde(flatten)]
223 pub range: RangeParams,
224}
225
226#[cfg(test)]
227#[allow(clippy::unwrap_used)]
228mod tests {
229 use super::*;
230
231 #[test]
235 fn flattened_params_serialize_to_flat_json() {
236 let references = ReferencesParams {
237 position: PositionParams {
238 file_path: "/a.rs".to_string(),
239 line: 1,
240 character: 2,
241 },
242 include_declaration: true,
243 };
244 let json = serde_json::to_value(&references).unwrap();
245 assert_eq!(
246 json,
247 serde_json::json!({
248 "file_path": "/a.rs",
249 "line": 1,
250 "character": 2,
251 "include_declaration": true,
252 })
253 );
254
255 let inlay = InlayHintsParams {
256 file_path: "/b.rs".to_string(),
257 range: RangeParams {
258 start_line: 1,
259 start_character: 2,
260 end_line: 3,
261 end_character: 4,
262 },
263 };
264 let json = serde_json::to_value(&inlay).unwrap();
265 assert_eq!(
266 json,
267 serde_json::json!({
268 "file_path": "/b.rs",
269 "start_line": 1,
270 "start_character": 2,
271 "end_line": 3,
272 "end_character": 4,
273 })
274 );
275 }
276
277 #[test]
280 fn flat_json_deserializes_into_flattened_params() {
281 let json = serde_json::json!({"file_path": "/a.rs", "line": 1, "character": 2});
282 let references: ReferencesParams = serde_json::from_value(json).unwrap();
283 assert_eq!(references.position.file_path, "/a.rs");
284 assert_eq!(references.position.line, 1);
285 assert_eq!(references.position.character, 2);
286 assert!(!references.include_declaration);
287 }
288
289 #[test]
294 fn generated_schema_exposes_flattened_fields_at_top_level() {
295 let schema = schemars::schema_for!(ReferencesParams);
296 let properties = schema
297 .as_object()
298 .unwrap()
299 .get("properties")
300 .unwrap()
301 .as_object()
302 .unwrap();
303 assert!(properties.contains_key("file_path"));
304 assert!(properties.contains_key("line"));
305 assert!(properties.contains_key("character"));
306 assert!(properties.contains_key("include_declaration"));
307 assert!(!properties.contains_key("position"));
308
309 let schema = schemars::schema_for!(InlayHintsParams);
310 let properties = schema
311 .as_object()
312 .unwrap()
313 .get("properties")
314 .unwrap()
315 .as_object()
316 .unwrap();
317 assert!(properties.contains_key("file_path"));
318 assert!(properties.contains_key("start_line"));
319 assert!(properties.contains_key("start_character"));
320 assert!(properties.contains_key("end_line"));
321 assert!(properties.contains_key("end_character"));
322 assert!(!properties.contains_key("range"));
323 }
324}