1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
9pub struct Position {
10 pub line:u32,
12
13 pub character:u32,
15}
16
17impl Position {
18 pub fn new(line:u32, character:u32) -> Self { Self { line, character } }
20
21 pub fn zero() -> Self { Self { line:0, character:0 } }
23
24 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
36pub struct Range {
37 pub start:Position,
39
40 pub end:Position,
42}
43
44impl Range {
45 pub fn new(start:Position, end:Position) -> Self { Self { start, end } }
47
48 pub fn empty(position:Position) -> Self { Self { start:position, end:position } }
50
51 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#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
61pub struct Location {
62 pub uri:String,
64
65 pub range:Range,
67}
68
69impl Location {
70 pub fn new(uri:String, range:Range) -> Self { Self { uri, range } }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct Diagnostic {
77 pub range:Range,
79
80 pub severity:Option<DiagnosticSeverity>,
82
83 pub code:Option<DiagnosticCode>,
85
86 pub source:Option<String>,
88
89 pub message:String,
91
92 pub tags:Option<Vec<DiagnosticTag>>,
94
95 pub related_information:Option<Vec<DiagnosticRelatedInformation>>,
97}
98
99impl Diagnostic {
100 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
116pub enum DiagnosticSeverity {
117 Hint = 3,
119
120 Information = 2,
122
123 Warning = 1,
125
126 Error = 0,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
132#[serde(untagged)]
133pub enum DiagnosticCode {
134 Number(i64),
136
137 String(String),
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
143pub enum DiagnosticTag {
144 Unnecessary = 1,
146
147 Deprecated = 2,
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct DiagnosticRelatedInformation {
154 pub location:Location,
156
157 pub message:String,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct TextEdit {
164 pub range:Range,
166
167 pub new_text:String,
169}
170
171impl TextEdit {
172 pub fn new(range:Range, new_text:String) -> Self { Self { range, new_text } }
174
175 pub fn delete(range:Range) -> Self { Self { range, new_text:String::new() } }
177
178 pub fn insert(position:Position, new_text:String) -> Self { Self { range:Range::empty(position), new_text } }
180
181 pub fn replace(range:Range, new_text:String) -> Self { Self { range, new_text } }
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct WorkspaceEdit {
188 pub changes:Option<std::collections::HashMap<String, Vec<TextEdit>>>,
190}
191
192impl WorkspaceEdit {
193 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#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct CompletionItem {
204 pub label:String,
206
207 pub kind:Option<CompletionItemKind>,
209
210 pub detail:Option<String>,
212
213 pub documentation:Option<CompletionItemDocumentation>,
215
216 #[serde(rename = "preselect")]
218 pub preselect:Option<bool>,
219
220 pub sort_text:Option<String>,
222
223 pub filter_text:Option<String>,
225}
226
227impl CompletionItem {
228 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
244pub enum CompletionItemKind {
245Text = 1,
247Method = 2,
249Function = 3,
251Constructor = 4,
253Field = 5,
255Variable = 6,
257Class = 7,
259Interface = 8,
261Module = 9,
263Property = 10,
265Unit = 11,
267Value = 12,
269Enum = 13,
271Keyword = 14,
273Snippet = 15,
275Color = 16,
277File = 17,
279Reference = 18,
281Folder = 19,
283EnumMember = 20,
285Constant = 21,
287Struct = 22,
289Event = 23,
291Operator = 24,
293TypeParameter = 25,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
299#[serde(untagged)]
300pub enum CompletionItemDocumentation {
301 String(String),
303
304 Value(CompletionItemDocumentationValue),
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct CompletionItemDocumentationValue {
311 pub kind:String,
313
314 pub value:String,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
320pub struct PartialResultParams {
321 #[serde(rename = "partialResultToken")]
323 pub partial_result_token:Option<String>,
324}
325
326#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct WorkDoneProgressParams {
329 #[serde(rename = "workDoneToken")]
331 pub work_done_token:Option<String>,
332}
333
334#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
336pub struct TextDocumentIdentifier {
337 pub uri:String,
339}
340
341impl TextDocumentIdentifier {
342 pub fn new(uri:String) -> Self { Self { uri } }
344}
345
346#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
348pub struct VersionedTextDocumentIdentifier {
349 pub uri:String,
351
352 pub version:i32,
354}
355
356impl VersionedTextDocumentIdentifier {
357 pub fn new(uri:String, version:i32) -> Self { Self { uri, version } }
359}
360
361#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
363pub struct TextDocumentItem {
364 pub uri:String,
366
367 #[serde(rename = "languageId")]
369 pub language_id:String,
370
371 pub version:i32,
373
374 pub text:String,
376}
377
378impl TextDocumentItem {
379 pub fn new(uri:String, language_id:String, version:i32, text:String) -> Self {
381 Self { uri, language_id, version, text }
382 }
383}
384
385#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct CreateFilesParams {
389 pub files:Vec<FileCreate>,
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize)]
395pub struct FileCreate {
396 pub uri:String,
398
399 #[serde(rename = "options")]
401 pub options:Option<CreateFileOptions>,
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize)]
406pub struct CreateFileOptions {
407 #[serde(rename = "overwrite")]
409 pub overwrite:Option<bool>,
410
411 #[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}