grove/API/
types.rs

1//! Common API Types Module
2//!
3//! Defines common types used throughout the VS Code API facade.
4
5use serde::{Deserialize, Serialize};
6
7/// Position in a text document
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
9pub struct Position {
10	/// Line position in a document (0-based)
11	pub line:u32,
12
13	/// Character offset on a line in a document (0-based)
14	pub character:u32,
15}
16
17impl Position {
18	/// Create a new position
19	pub fn new(line:u32, character:u32) -> Self { Self { line, character } }
20
21	/// Position at line 0, character 0
22	pub fn zero() -> Self { Self { line:0, character:0 } }
23
24	/// Create a position from a line and column (1-based to 0-based)
25	pub fn from_line_column(line:u32, column:u32) -> Self {
26		Self { line:line.saturating_sub(1), character:column.saturating_sub(1) }
27	}
28}
29
30impl Default for Position {
31	fn default() -> Self { Self::zero() }
32}
33
34/// A range in a text document
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
36pub struct Range {
37	/// The range's start position
38	pub start:Position,
39
40	/// The range's end position
41	pub end:Position,
42}
43
44impl Range {
45	/// Create a new range
46	pub fn new(start:Position, end:Position) -> Self { Self { start, end } }
47
48	/// Create a range covering a single position
49	pub fn empty(position:Position) -> Self { Self { start:position, end:position } }
50
51	/// Check if the position is in this range
52	pub fn contains(&self, position:Position) -> bool { position >= self.start && position <= self.end }
53}
54
55impl Default for Range {
56	fn default() -> Self { Self::empty(Position::zero()) }
57}
58
59/// Represents a location inside a resource
60#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
61pub struct Location {
62	/// The resource identifier of this location
63	pub uri:String,
64
65	/// The document range
66	pub range:Range,
67}
68
69impl Location {
70	/// Create a new location
71	pub fn new(uri:String, range:Range) -> Self { Self { uri, range } }
72}
73
74/// Represents a diagnostic message
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct Diagnostic {
77	/// The range at which the message applies
78	pub range:Range,
79
80	/// The diagnostic's severity
81	pub severity:Option<DiagnosticSeverity>,
82
83	/// The diagnostic's code
84	pub code:Option<DiagnosticCode>,
85
86	/// A human-readable string describing the source of this diagnostic
87	pub source:Option<String>,
88
89	/// The diagnostic's message
90	pub message:String,
91
92	/// Additional metadata about the diagnostic
93	pub tags:Option<Vec<DiagnosticTag>>,
94
95	/// Related diagnostic information
96	pub related_information:Option<Vec<DiagnosticRelatedInformation>>,
97}
98
99impl Diagnostic {
100	/// Create a new diagnostic
101	pub fn new(range:Range, message:String) -> Self {
102		Self {
103			range,
104			severity:None,
105			code:None,
106			source:None,
107			message,
108			tags:None,
109			related_information:None,
110		}
111	}
112}
113
114/// The severity of a diagnostic
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
116pub enum DiagnosticSeverity {
117	/// Not an error, but something to be aware of
118	Hint = 3,
119
120	/// Informational
121	Information = 2,
122
123	/// Something to warn about
124	Warning = 1,
125
126	/// An error
127	Error = 0,
128}
129
130/// Diagnostic code
131#[derive(Debug, Clone, Serialize, Deserialize)]
132#[serde(untagged)]
133pub enum DiagnosticCode {
134	/// Numeric code
135	Number(i64),
136
137	/// String code
138	String(String),
139}
140
141/// Diagnostic tags
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
143pub enum DiagnosticTag {
144	/// Unused or unnecessary code
145	Unnecessary = 1,
146
147	/// Deprecated code
148	Deprecated = 2,
149}
150
151/// Related diagnostic information
152#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct DiagnosticRelatedInformation {
154	/// The location of this related diagnostic information
155	pub location:Location,
156
157	/// The message of this related diagnostic information
158	pub message:String,
159}
160
161/// Represents a text change
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct TextEdit {
164	/// The range of the text document to be manipulated
165	pub range:Range,
166
167	/// The new text for the provided range
168	pub new_text:String,
169}
170
171impl TextEdit {
172	/// Create a new text edit
173	pub fn new(range:Range, new_text:String) -> Self { Self { range, new_text } }
174
175	/// Delete the text at the given range
176	pub fn delete(range:Range) -> Self { Self { range, new_text:String::new() } }
177
178	/// Insert the given text at the given position
179	pub fn insert(position:Position, new_text:String) -> Self { Self { range:Range::empty(position), new_text } }
180
181	/// Replace the text at the given range with the given text
182	pub fn replace(range:Range, new_text:String) -> Self { Self { range, new_text } }
183}
184
185/// Workspace edit
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct WorkspaceEdit {
188	/// Holds changes to existing resources
189	pub changes:Option<std::collections::HashMap<String, Vec<TextEdit>>>,
190}
191
192impl WorkspaceEdit {
193	/// Create a new workspace edit
194	pub fn new() -> Self { Self { changes:Some(std::collections::HashMap::new()) } }
195}
196
197impl Default for WorkspaceEdit {
198	fn default() -> Self { Self::new() }
199}
200
201/// Completion item
202#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct CompletionItem {
204	/// The label of this completion item
205	pub label:String,
206
207	/// The kind of this completion item
208	pub kind:Option<CompletionItemKind>,
209
210	/// A human-readable string with additional information
211	pub detail:Option<String>,
212
213	/// A human-readable string that represents a doc-comment
214	pub documentation:Option<CompletionItemDocumentation>,
215
216	/// Select this item when showing
217	#[serde(rename = "preselect")]
218	pub preselect:Option<bool>,
219
220	/// A string that should be used when comparing this item with other items
221	pub sort_text:Option<String>,
222
223	/// A string that should be used when filtering items
224	pub filter_text:Option<String>,
225}
226
227impl CompletionItem {
228	/// Create a new completion item
229	pub fn new(label:String) -> Self {
230		Self {
231			label,
232			kind:None,
233			detail:None,
234			documentation:None,
235			preselect:None,
236			sort_text:None,
237			filter_text:None,
238		}
239	}
240}
241
242/// Completion item kind
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
244pub enum CompletionItemKind {
245/// Text completion
246Text = 1,
247/// Method completion
248Method = 2,
249/// Function completion
250Function = 3,
251/// Constructor completion
252Constructor = 4,
253/// Field completion
254Field = 5,
255/// Variable completion
256Variable = 6,
257/// Class completion
258Class = 7,
259/// Interface completion
260Interface = 8,
261/// Module completion
262Module = 9,
263/// Property completion
264Property = 10,
265/// Unit completion
266Unit = 11,
267/// Value completion
268Value = 12,
269/// Enum completion
270Enum = 13,
271/// Keyword completion
272Keyword = 14,
273/// Snippet completion
274Snippet = 15,
275/// Color completion
276Color = 16,
277/// File completion
278File = 17,
279/// Reference completion
280Reference = 18,
281/// Folder completion
282Folder = 19,
283/// Enum member completion
284EnumMember = 20,
285/// Constant completion
286Constant = 21,
287/// Struct completion
288Struct = 22,
289/// Event completion
290Event = 23,
291/// Operator completion
292Operator = 24,
293/// Type parameter completion
294TypeParameter = 25,
295}
296
297/// Completion item documentation
298#[derive(Debug, Clone, Serialize, Deserialize)]
299#[serde(untagged)]
300pub enum CompletionItemDocumentation {
301	/// Markdown string
302	String(String),
303
304	/// Value object
305	Value(CompletionItemDocumentationValue),
306}
307
308/// Completion item documentation value object
309#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct CompletionItemDocumentationValue {
311	/// The kind of documentation
312	pub kind:String,
313
314	/// The documentation content
315	pub value:String,
316}
317
318/// Partial result token
319#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct PartialResultParams {
321	/// An optional token that a server can use to report partial results
322	#[serde(rename = "partialResultToken")]
323	pub partial_result_token:Option<String>,
324}
325
326/// Work done progress params
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct WorkDoneProgressParams {
329	/// An optional token that a server can use to report work done progress
330	#[serde(rename = "workDoneToken")]
331	pub work_done_token:Option<String>,
332}
333
334/// Text document identifier
335#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
336pub struct TextDocumentIdentifier {
337	/// The text document's uri
338	pub uri:String,
339}
340
341impl TextDocumentIdentifier {
342	/// Create a new text document identifier
343	pub fn new(uri:String) -> Self { Self { uri } }
344}
345
346/// Versioned text document identifier
347#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
348pub struct VersionedTextDocumentIdentifier {
349	/// The text document's uri
350	pub uri:String,
351
352	/// The version number of this document
353	pub version:i32,
354}
355
356impl VersionedTextDocumentIdentifier {
357	/// Create a new versioned text document identifier
358	pub fn new(uri:String, version:i32) -> Self { Self { uri, version } }
359}
360
361/// Text document item
362#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
363pub struct TextDocumentItem {
364	/// The text document's uri
365	pub uri:String,
366
367	/// The text document's language identifier
368	#[serde(rename = "languageId")]
369	pub language_id:String,
370
371	/// The version number of this document
372	pub version:i32,
373
374	/// The content of the opened text document
375	pub text:String,
376}
377
378impl TextDocumentItem {
379	/// Create a new text document item
380	pub fn new(uri:String, language_id:String, version:i32, text:String) -> Self {
381		Self { uri, language_id, version, text }
382	}
383}
384
385/// The parameters sent in notifications/requests for user-initiated creation of
386/// files
387#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct CreateFilesParams {
389	/// An array of all files/folders created in this operation
390	pub files:Vec<FileCreate>,
391}
392
393/// Represents information to create a file
394#[derive(Debug, Clone, Serialize, Deserialize)]
395pub struct FileCreate {
396	/// A file or folder uri
397	pub uri:String,
398
399	/// Additional options
400	#[serde(rename = "options")]
401	pub options:Option<CreateFileOptions>,
402}
403
404/// Options when creating a file
405#[derive(Debug, Clone, Serialize, Deserialize)]
406pub struct CreateFileOptions {
407	/// Overwrite existing file
408	#[serde(rename = "overwrite")]
409	pub overwrite:Option<bool>,
410
411	/// Ignore if exists
412	#[serde(rename = "ignoreIfExists")]
413	pub ignore_if_exists:Option<bool>,
414}
415
416#[cfg(test)]
417mod tests {
418	use super::*;
419
420	#[test]
421	fn test_position() {
422		let pos = Position::new(5, 10);
423		assert_eq!(pos.line, 5);
424		assert_eq!(pos.character, 10);
425
426		let default = Position::default();
427		assert_eq!(default.line, 0);
428		assert_eq!(default.character, 0);
429	}
430
431	#[test]
432	fn test_range() {
433		let start = Position::new(0, 0);
434		let end = Position::new(5, 10);
435		let range = Range::new(start, end);
436
437		assert!(range.contains(Position::new(3, 5)));
438		assert!(!range.contains(Position::new(6, 0)));
439	}
440
441	#[test]
442	fn test_text_edit_operations() {
443		let range = Range::new(Position::new(0, 0), Position::new(0, 5));
444
445		let replace = TextEdit::replace(range, "new text".to_string());
446		assert_eq!(replace.new_text, "new text");
447
448		let delete = TextEdit::delete(range);
449		assert_eq!(delete.new_text, "");
450
451		let insert = TextEdit::insert(Position::new(0, 0), "inserted".to_string());
452		assert_eq!(insert.new_text, "inserted");
453	}
454
455	#[test]
456	fn test_completion_item() {
457		let item = CompletionItem::new("testFunction".to_string());
458		assert_eq!(item.label, "testFunction");
459	}
460}