1use std::collections::BTreeMap;
8
9use schemars::{JsonSchema, Schema};
10use serde::{Deserialize, Serialize};
11use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
12
13use super::{Meta, SessionId};
14use crate::{IntoOption, SkipListener};
15
16pub(crate) const NES_START_METHOD_NAME: &str = "nes/start";
20pub(crate) const NES_SUGGEST_METHOD_NAME: &str = "nes/suggest";
22pub(crate) const NES_ACCEPT_METHOD_NAME: &str = "nes/accept";
24pub(crate) const NES_REJECT_METHOD_NAME: &str = "nes/reject";
26pub(crate) const NES_CLOSE_METHOD_NAME: &str = "nes/close";
28pub(crate) const DOCUMENT_DID_OPEN_METHOD_NAME: &str = "document/didOpen";
30pub(crate) const DOCUMENT_DID_CHANGE_METHOD_NAME: &str = "document/didChange";
32pub(crate) const DOCUMENT_DID_CLOSE_METHOD_NAME: &str = "document/didClose";
34pub(crate) const DOCUMENT_DID_SAVE_METHOD_NAME: &str = "document/didSave";
36pub(crate) const DOCUMENT_DID_FOCUS_METHOD_NAME: &str = "document/didFocus";
38
39#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
45#[non_exhaustive]
46pub enum PositionEncodingKind {
47 #[serde(rename = "utf-16")]
49 Utf16,
50 #[serde(rename = "utf-32")]
52 Utf32,
53 #[serde(rename = "utf-8")]
55 Utf8,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
62#[serde(rename_all = "camelCase")]
63#[non_exhaustive]
64pub struct Position {
65 pub line: u32,
67 pub character: u32,
69}
70
71impl Position {
72 #[must_use]
73 pub fn new(line: u32, character: u32) -> Self {
74 Self { line, character }
75 }
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
80#[serde(rename_all = "camelCase")]
81#[non_exhaustive]
82pub struct Range {
83 pub start: Position,
85 pub end: Position,
87}
88
89impl Range {
90 #[must_use]
91 pub fn new(start: Position, end: Position) -> Self {
92 Self { start, end }
93 }
94}
95
96#[serde_as]
100#[skip_serializing_none]
101#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
102#[serde(rename_all = "camelCase")]
103#[non_exhaustive]
104pub struct NesCapabilities {
105 #[serde_as(deserialize_as = "DefaultOnError")]
107 #[schemars(extend("x-deserialize-default-on-error" = true))]
108 #[serde(default)]
109 pub events: Option<NesEventCapabilities>,
110 #[serde_as(deserialize_as = "DefaultOnError")]
112 #[schemars(extend("x-deserialize-default-on-error" = true))]
113 #[serde(default)]
114 pub context: Option<NesContextCapabilities>,
115 #[serde(rename = "_meta")]
121 pub meta: Option<Meta>,
122}
123
124impl NesCapabilities {
125 #[must_use]
126 pub fn new() -> Self {
127 Self::default()
128 }
129
130 #[must_use]
131 pub fn events(mut self, events: impl IntoOption<NesEventCapabilities>) -> Self {
132 self.events = events.into_option();
133 self
134 }
135
136 #[must_use]
137 pub fn context(mut self, context: impl IntoOption<NesContextCapabilities>) -> Self {
138 self.context = context.into_option();
139 self
140 }
141
142 #[must_use]
148 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
149 self.meta = meta.into_option();
150 self
151 }
152}
153
154#[serde_as]
156#[skip_serializing_none]
157#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
158#[serde(rename_all = "camelCase")]
159#[non_exhaustive]
160pub struct NesEventCapabilities {
161 #[serde_as(deserialize_as = "DefaultOnError")]
163 #[schemars(extend("x-deserialize-default-on-error" = true))]
164 #[serde(default)]
165 pub document: Option<NesDocumentEventCapabilities>,
166 #[serde(rename = "_meta")]
172 pub meta: Option<Meta>,
173}
174
175impl NesEventCapabilities {
176 #[must_use]
177 pub fn new() -> Self {
178 Self::default()
179 }
180
181 #[must_use]
182 pub fn document(mut self, document: impl IntoOption<NesDocumentEventCapabilities>) -> Self {
183 self.document = document.into_option();
184 self
185 }
186
187 #[must_use]
193 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
194 self.meta = meta.into_option();
195 self
196 }
197}
198
199#[serde_as]
201#[skip_serializing_none]
202#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
203#[serde(rename_all = "camelCase")]
204#[non_exhaustive]
205pub struct NesDocumentEventCapabilities {
206 #[serde_as(deserialize_as = "DefaultOnError")]
208 #[schemars(extend("x-deserialize-default-on-error" = true))]
209 #[serde(default)]
210 pub did_open: Option<NesDocumentDidOpenCapabilities>,
211 #[serde_as(deserialize_as = "DefaultOnError")]
213 #[schemars(extend("x-deserialize-default-on-error" = true))]
214 #[serde(default)]
215 pub did_change: Option<NesDocumentDidChangeCapabilities>,
216 #[serde_as(deserialize_as = "DefaultOnError")]
218 #[schemars(extend("x-deserialize-default-on-error" = true))]
219 #[serde(default)]
220 pub did_close: Option<NesDocumentDidCloseCapabilities>,
221 #[serde_as(deserialize_as = "DefaultOnError")]
223 #[schemars(extend("x-deserialize-default-on-error" = true))]
224 #[serde(default)]
225 pub did_save: Option<NesDocumentDidSaveCapabilities>,
226 #[serde_as(deserialize_as = "DefaultOnError")]
228 #[schemars(extend("x-deserialize-default-on-error" = true))]
229 #[serde(default)]
230 pub did_focus: Option<NesDocumentDidFocusCapabilities>,
231 #[serde(rename = "_meta")]
237 pub meta: Option<Meta>,
238}
239
240impl NesDocumentEventCapabilities {
241 #[must_use]
242 pub fn new() -> Self {
243 Self::default()
244 }
245
246 #[must_use]
247 pub fn did_open(mut self, did_open: impl IntoOption<NesDocumentDidOpenCapabilities>) -> Self {
248 self.did_open = did_open.into_option();
249 self
250 }
251
252 #[must_use]
253 pub fn did_change(
254 mut self,
255 did_change: impl IntoOption<NesDocumentDidChangeCapabilities>,
256 ) -> Self {
257 self.did_change = did_change.into_option();
258 self
259 }
260
261 #[must_use]
262 pub fn did_close(
263 mut self,
264 did_close: impl IntoOption<NesDocumentDidCloseCapabilities>,
265 ) -> Self {
266 self.did_close = did_close.into_option();
267 self
268 }
269
270 #[must_use]
271 pub fn did_save(mut self, did_save: impl IntoOption<NesDocumentDidSaveCapabilities>) -> Self {
272 self.did_save = did_save.into_option();
273 self
274 }
275
276 #[must_use]
277 pub fn did_focus(
278 mut self,
279 did_focus: impl IntoOption<NesDocumentDidFocusCapabilities>,
280 ) -> Self {
281 self.did_focus = did_focus.into_option();
282 self
283 }
284
285 #[must_use]
291 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
292 self.meta = meta.into_option();
293 self
294 }
295}
296
297#[skip_serializing_none]
299#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
300#[serde(rename_all = "camelCase")]
301#[non_exhaustive]
302pub struct NesDocumentDidOpenCapabilities {
303 #[serde(rename = "_meta")]
309 pub meta: Option<Meta>,
310}
311
312impl NesDocumentDidOpenCapabilities {
313 #[must_use]
314 pub fn new() -> Self {
315 Self::default()
316 }
317}
318
319#[skip_serializing_none]
321#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
322#[serde(rename_all = "camelCase")]
323#[non_exhaustive]
324pub struct NesDocumentDidChangeCapabilities {
325 pub sync_kind: TextDocumentSyncKind,
327 #[serde(rename = "_meta")]
333 pub meta: Option<Meta>,
334}
335
336impl NesDocumentDidChangeCapabilities {
337 #[must_use]
338 pub fn new(sync_kind: TextDocumentSyncKind) -> Self {
339 Self {
340 sync_kind,
341 meta: None,
342 }
343 }
344
345 #[must_use]
351 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
352 self.meta = meta.into_option();
353 self
354 }
355}
356
357#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
359#[non_exhaustive]
360pub enum TextDocumentSyncKind {
361 #[serde(rename = "full")]
363 Full,
364 #[serde(rename = "incremental")]
366 Incremental,
367}
368
369#[skip_serializing_none]
371#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
372#[serde(rename_all = "camelCase")]
373#[non_exhaustive]
374pub struct NesDocumentDidCloseCapabilities {
375 #[serde(rename = "_meta")]
381 pub meta: Option<Meta>,
382}
383
384impl NesDocumentDidCloseCapabilities {
385 #[must_use]
386 pub fn new() -> Self {
387 Self::default()
388 }
389}
390
391#[skip_serializing_none]
393#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
394#[serde(rename_all = "camelCase")]
395#[non_exhaustive]
396pub struct NesDocumentDidSaveCapabilities {
397 #[serde(rename = "_meta")]
403 pub meta: Option<Meta>,
404}
405
406impl NesDocumentDidSaveCapabilities {
407 #[must_use]
408 pub fn new() -> Self {
409 Self::default()
410 }
411}
412
413#[skip_serializing_none]
415#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
416#[serde(rename_all = "camelCase")]
417#[non_exhaustive]
418pub struct NesDocumentDidFocusCapabilities {
419 #[serde(rename = "_meta")]
425 pub meta: Option<Meta>,
426}
427
428impl NesDocumentDidFocusCapabilities {
429 #[must_use]
430 pub fn new() -> Self {
431 Self::default()
432 }
433}
434
435#[serde_as]
437#[skip_serializing_none]
438#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
439#[serde(rename_all = "camelCase")]
440#[non_exhaustive]
441pub struct NesContextCapabilities {
442 #[serde_as(deserialize_as = "DefaultOnError")]
444 #[schemars(extend("x-deserialize-default-on-error" = true))]
445 #[serde(default)]
446 pub recent_files: Option<NesRecentFilesCapabilities>,
447 #[serde_as(deserialize_as = "DefaultOnError")]
449 #[schemars(extend("x-deserialize-default-on-error" = true))]
450 #[serde(default)]
451 pub related_snippets: Option<NesRelatedSnippetsCapabilities>,
452 #[serde_as(deserialize_as = "DefaultOnError")]
454 #[schemars(extend("x-deserialize-default-on-error" = true))]
455 #[serde(default)]
456 pub edit_history: Option<NesEditHistoryCapabilities>,
457 #[serde_as(deserialize_as = "DefaultOnError")]
459 #[schemars(extend("x-deserialize-default-on-error" = true))]
460 #[serde(default)]
461 pub user_actions: Option<NesUserActionsCapabilities>,
462 #[serde_as(deserialize_as = "DefaultOnError")]
464 #[schemars(extend("x-deserialize-default-on-error" = true))]
465 #[serde(default)]
466 pub open_files: Option<NesOpenFilesCapabilities>,
467 #[serde_as(deserialize_as = "DefaultOnError")]
469 #[schemars(extend("x-deserialize-default-on-error" = true))]
470 #[serde(default)]
471 pub diagnostics: Option<NesDiagnosticsCapabilities>,
472 #[serde(rename = "_meta")]
478 pub meta: Option<Meta>,
479}
480
481impl NesContextCapabilities {
482 #[must_use]
483 pub fn new() -> Self {
484 Self::default()
485 }
486
487 #[must_use]
488 pub fn recent_files(
489 mut self,
490 recent_files: impl IntoOption<NesRecentFilesCapabilities>,
491 ) -> Self {
492 self.recent_files = recent_files.into_option();
493 self
494 }
495
496 #[must_use]
497 pub fn related_snippets(
498 mut self,
499 related_snippets: impl IntoOption<NesRelatedSnippetsCapabilities>,
500 ) -> Self {
501 self.related_snippets = related_snippets.into_option();
502 self
503 }
504
505 #[must_use]
506 pub fn edit_history(
507 mut self,
508 edit_history: impl IntoOption<NesEditHistoryCapabilities>,
509 ) -> Self {
510 self.edit_history = edit_history.into_option();
511 self
512 }
513
514 #[must_use]
515 pub fn user_actions(
516 mut self,
517 user_actions: impl IntoOption<NesUserActionsCapabilities>,
518 ) -> Self {
519 self.user_actions = user_actions.into_option();
520 self
521 }
522
523 #[must_use]
524 pub fn open_files(mut self, open_files: impl IntoOption<NesOpenFilesCapabilities>) -> Self {
525 self.open_files = open_files.into_option();
526 self
527 }
528
529 #[must_use]
530 pub fn diagnostics(mut self, diagnostics: impl IntoOption<NesDiagnosticsCapabilities>) -> Self {
531 self.diagnostics = diagnostics.into_option();
532 self
533 }
534
535 #[must_use]
541 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
542 self.meta = meta.into_option();
543 self
544 }
545}
546
547#[skip_serializing_none]
549#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
550#[serde(rename_all = "camelCase")]
551#[non_exhaustive]
552pub struct NesRecentFilesCapabilities {
553 pub max_count: Option<u32>,
555 #[serde(rename = "_meta")]
561 pub meta: Option<Meta>,
562}
563
564impl NesRecentFilesCapabilities {
565 #[must_use]
566 pub fn new() -> Self {
567 Self::default()
568 }
569}
570
571#[skip_serializing_none]
573#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
574#[serde(rename_all = "camelCase")]
575#[non_exhaustive]
576pub struct NesRelatedSnippetsCapabilities {
577 #[serde(rename = "_meta")]
583 pub meta: Option<Meta>,
584}
585
586impl NesRelatedSnippetsCapabilities {
587 #[must_use]
588 pub fn new() -> Self {
589 Self::default()
590 }
591}
592
593#[skip_serializing_none]
595#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
596#[serde(rename_all = "camelCase")]
597#[non_exhaustive]
598pub struct NesEditHistoryCapabilities {
599 pub max_count: Option<u32>,
601 #[serde(rename = "_meta")]
607 pub meta: Option<Meta>,
608}
609
610impl NesEditHistoryCapabilities {
611 #[must_use]
612 pub fn new() -> Self {
613 Self::default()
614 }
615}
616
617#[skip_serializing_none]
619#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
620#[serde(rename_all = "camelCase")]
621#[non_exhaustive]
622pub struct NesUserActionsCapabilities {
623 pub max_count: Option<u32>,
625 #[serde(rename = "_meta")]
631 pub meta: Option<Meta>,
632}
633
634impl NesUserActionsCapabilities {
635 #[must_use]
636 pub fn new() -> Self {
637 Self::default()
638 }
639}
640
641#[skip_serializing_none]
643#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
644#[serde(rename_all = "camelCase")]
645#[non_exhaustive]
646pub struct NesOpenFilesCapabilities {
647 #[serde(rename = "_meta")]
653 pub meta: Option<Meta>,
654}
655
656impl NesOpenFilesCapabilities {
657 #[must_use]
658 pub fn new() -> Self {
659 Self::default()
660 }
661}
662
663#[skip_serializing_none]
665#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
666#[serde(rename_all = "camelCase")]
667#[non_exhaustive]
668pub struct NesDiagnosticsCapabilities {
669 #[serde(rename = "_meta")]
675 pub meta: Option<Meta>,
676}
677
678impl NesDiagnosticsCapabilities {
679 #[must_use]
680 pub fn new() -> Self {
681 Self::default()
682 }
683}
684
685#[serde_as]
689#[skip_serializing_none]
690#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
691#[serde(rename_all = "camelCase")]
692#[non_exhaustive]
693pub struct ClientNesCapabilities {
694 #[serde_as(deserialize_as = "DefaultOnError")]
696 #[schemars(extend("x-deserialize-default-on-error" = true))]
697 #[serde(default)]
698 pub jump: Option<NesJumpCapabilities>,
699 #[serde_as(deserialize_as = "DefaultOnError")]
701 #[schemars(extend("x-deserialize-default-on-error" = true))]
702 #[serde(default)]
703 pub rename: Option<NesRenameCapabilities>,
704 #[serde_as(deserialize_as = "DefaultOnError")]
706 #[schemars(extend("x-deserialize-default-on-error" = true))]
707 #[serde(default)]
708 pub search_and_replace: Option<NesSearchAndReplaceCapabilities>,
709 #[serde(rename = "_meta")]
715 pub meta: Option<Meta>,
716}
717
718impl ClientNesCapabilities {
719 #[must_use]
720 pub fn new() -> Self {
721 Self::default()
722 }
723
724 #[must_use]
725 pub fn jump(mut self, jump: impl IntoOption<NesJumpCapabilities>) -> Self {
726 self.jump = jump.into_option();
727 self
728 }
729
730 #[must_use]
731 pub fn rename(mut self, rename: impl IntoOption<NesRenameCapabilities>) -> Self {
732 self.rename = rename.into_option();
733 self
734 }
735
736 #[must_use]
737 pub fn search_and_replace(
738 mut self,
739 search_and_replace: impl IntoOption<NesSearchAndReplaceCapabilities>,
740 ) -> Self {
741 self.search_and_replace = search_and_replace.into_option();
742 self
743 }
744
745 #[must_use]
751 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
752 self.meta = meta.into_option();
753 self
754 }
755}
756
757#[skip_serializing_none]
759#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
760#[serde(rename_all = "camelCase")]
761#[non_exhaustive]
762pub struct NesJumpCapabilities {
763 #[serde(rename = "_meta")]
769 pub meta: Option<Meta>,
770}
771
772impl NesJumpCapabilities {
773 #[must_use]
774 pub fn new() -> Self {
775 Self::default()
776 }
777}
778
779#[skip_serializing_none]
781#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
782#[serde(rename_all = "camelCase")]
783#[non_exhaustive]
784pub struct NesRenameCapabilities {
785 #[serde(rename = "_meta")]
791 pub meta: Option<Meta>,
792}
793
794impl NesRenameCapabilities {
795 #[must_use]
796 pub fn new() -> Self {
797 Self::default()
798 }
799}
800
801#[skip_serializing_none]
803#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
804#[serde(rename_all = "camelCase")]
805#[non_exhaustive]
806pub struct NesSearchAndReplaceCapabilities {
807 #[serde(rename = "_meta")]
813 pub meta: Option<Meta>,
814}
815
816impl NesSearchAndReplaceCapabilities {
817 #[must_use]
818 pub fn new() -> Self {
819 Self::default()
820 }
821}
822
823#[skip_serializing_none]
827#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
828#[schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_OPEN_METHOD_NAME))]
829#[serde(rename_all = "camelCase")]
830#[non_exhaustive]
831pub struct DidOpenDocumentNotification {
832 pub session_id: SessionId,
834 pub uri: String,
836 pub language_id: String,
838 pub version: i64,
840 pub text: String,
842 #[serde(rename = "_meta")]
848 pub meta: Option<Meta>,
849}
850
851impl DidOpenDocumentNotification {
852 #[must_use]
853 pub fn new(
854 session_id: impl Into<SessionId>,
855 uri: impl Into<String>,
856 language_id: impl Into<String>,
857 version: i64,
858 text: impl Into<String>,
859 ) -> Self {
860 Self {
861 session_id: session_id.into(),
862 uri: uri.into(),
863 language_id: language_id.into(),
864 version,
865 text: text.into(),
866 meta: None,
867 }
868 }
869
870 #[must_use]
876 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
877 self.meta = meta.into_option();
878 self
879 }
880}
881
882#[skip_serializing_none]
884#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
885#[schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_CHANGE_METHOD_NAME))]
886#[serde(rename_all = "camelCase")]
887#[non_exhaustive]
888pub struct DidChangeDocumentNotification {
889 pub session_id: SessionId,
891 pub uri: String,
893 pub version: i64,
895 pub content_changes: Vec<TextDocumentContentChangeEvent>,
897 #[serde(rename = "_meta")]
903 pub meta: Option<Meta>,
904}
905
906impl DidChangeDocumentNotification {
907 #[must_use]
908 pub fn new(
909 session_id: impl Into<SessionId>,
910 uri: impl Into<String>,
911 version: i64,
912 content_changes: Vec<TextDocumentContentChangeEvent>,
913 ) -> Self {
914 Self {
915 session_id: session_id.into(),
916 uri: uri.into(),
917 version,
918 content_changes,
919 meta: None,
920 }
921 }
922
923 #[must_use]
929 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
930 self.meta = meta.into_option();
931 self
932 }
933}
934
935#[skip_serializing_none]
940#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
941#[serde(rename_all = "camelCase")]
942#[non_exhaustive]
943pub struct TextDocumentContentChangeEvent {
944 pub range: Option<Range>,
946 pub text: String,
948}
949
950impl TextDocumentContentChangeEvent {
951 #[must_use]
952 pub fn full(text: impl Into<String>) -> Self {
953 Self {
954 range: None,
955 text: text.into(),
956 }
957 }
958
959 #[must_use]
960 pub fn incremental(range: Range, text: impl Into<String>) -> Self {
961 Self {
962 range: Some(range),
963 text: text.into(),
964 }
965 }
966}
967
968#[skip_serializing_none]
970#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
971#[schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_CLOSE_METHOD_NAME))]
972#[serde(rename_all = "camelCase")]
973#[non_exhaustive]
974pub struct DidCloseDocumentNotification {
975 pub session_id: SessionId,
977 pub uri: String,
979 #[serde(rename = "_meta")]
985 pub meta: Option<Meta>,
986}
987
988impl DidCloseDocumentNotification {
989 #[must_use]
990 pub fn new(session_id: impl Into<SessionId>, uri: impl Into<String>) -> Self {
991 Self {
992 session_id: session_id.into(),
993 uri: uri.into(),
994 meta: None,
995 }
996 }
997
998 #[must_use]
1004 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1005 self.meta = meta.into_option();
1006 self
1007 }
1008}
1009
1010#[skip_serializing_none]
1012#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1013#[schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_SAVE_METHOD_NAME))]
1014#[serde(rename_all = "camelCase")]
1015#[non_exhaustive]
1016pub struct DidSaveDocumentNotification {
1017 pub session_id: SessionId,
1019 pub uri: String,
1021 #[serde(rename = "_meta")]
1027 pub meta: Option<Meta>,
1028}
1029
1030impl DidSaveDocumentNotification {
1031 #[must_use]
1032 pub fn new(session_id: impl Into<SessionId>, uri: impl Into<String>) -> Self {
1033 Self {
1034 session_id: session_id.into(),
1035 uri: uri.into(),
1036 meta: None,
1037 }
1038 }
1039
1040 #[must_use]
1046 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1047 self.meta = meta.into_option();
1048 self
1049 }
1050}
1051
1052#[skip_serializing_none]
1054#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1055#[schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_FOCUS_METHOD_NAME))]
1056#[serde(rename_all = "camelCase")]
1057#[non_exhaustive]
1058pub struct DidFocusDocumentNotification {
1059 pub session_id: SessionId,
1061 pub uri: String,
1063 pub version: i64,
1065 pub position: Position,
1067 pub visible_range: Range,
1069 #[serde(rename = "_meta")]
1075 pub meta: Option<Meta>,
1076}
1077
1078impl DidFocusDocumentNotification {
1079 #[must_use]
1080 pub fn new(
1081 session_id: impl Into<SessionId>,
1082 uri: impl Into<String>,
1083 version: i64,
1084 position: Position,
1085 visible_range: Range,
1086 ) -> Self {
1087 Self {
1088 session_id: session_id.into(),
1089 uri: uri.into(),
1090 version,
1091 position,
1092 visible_range,
1093 meta: None,
1094 }
1095 }
1096
1097 #[must_use]
1103 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1104 self.meta = meta.into_option();
1105 self
1106 }
1107}
1108
1109#[serde_as]
1113#[skip_serializing_none]
1114#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1115#[schemars(extend("x-side" = "agent", "x-method" = NES_START_METHOD_NAME))]
1116#[serde(rename_all = "camelCase")]
1117#[non_exhaustive]
1118pub struct StartNesRequest {
1119 pub workspace_uri: Option<String>,
1121 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1123 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1124 #[serde(default)]
1125 pub workspace_folders: Option<Vec<WorkspaceFolder>>,
1126 #[serde_as(deserialize_as = "DefaultOnError")]
1128 #[schemars(extend("x-deserialize-default-on-error" = true))]
1129 #[serde(default)]
1130 pub repository: Option<NesRepository>,
1131 #[serde(rename = "_meta")]
1137 pub meta: Option<Meta>,
1138}
1139
1140impl StartNesRequest {
1141 #[must_use]
1142 pub fn new() -> Self {
1143 Self {
1144 workspace_uri: None,
1145 workspace_folders: None,
1146 repository: None,
1147 meta: None,
1148 }
1149 }
1150
1151 #[must_use]
1152 pub fn workspace_uri(mut self, workspace_uri: impl IntoOption<String>) -> Self {
1153 self.workspace_uri = workspace_uri.into_option();
1154 self
1155 }
1156
1157 #[must_use]
1158 pub fn workspace_folders(
1159 mut self,
1160 workspace_folders: impl IntoOption<Vec<WorkspaceFolder>>,
1161 ) -> Self {
1162 self.workspace_folders = workspace_folders.into_option();
1163 self
1164 }
1165
1166 #[must_use]
1167 pub fn repository(mut self, repository: impl IntoOption<NesRepository>) -> Self {
1168 self.repository = repository.into_option();
1169 self
1170 }
1171
1172 #[must_use]
1178 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1179 self.meta = meta.into_option();
1180 self
1181 }
1182}
1183
1184impl Default for StartNesRequest {
1185 fn default() -> Self {
1186 Self::new()
1187 }
1188}
1189
1190#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1192#[serde(rename_all = "camelCase")]
1193#[non_exhaustive]
1194pub struct WorkspaceFolder {
1195 pub uri: String,
1197 pub name: String,
1199}
1200
1201impl WorkspaceFolder {
1202 #[must_use]
1203 pub fn new(uri: impl Into<String>, name: impl Into<String>) -> Self {
1204 Self {
1205 uri: uri.into(),
1206 name: name.into(),
1207 }
1208 }
1209}
1210
1211#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1213#[serde(rename_all = "camelCase")]
1214#[non_exhaustive]
1215pub struct NesRepository {
1216 pub name: String,
1218 pub owner: String,
1220 pub remote_url: String,
1222}
1223
1224impl NesRepository {
1225 #[must_use]
1226 pub fn new(
1227 name: impl Into<String>,
1228 owner: impl Into<String>,
1229 remote_url: impl Into<String>,
1230 ) -> Self {
1231 Self {
1232 name: name.into(),
1233 owner: owner.into(),
1234 remote_url: remote_url.into(),
1235 }
1236 }
1237}
1238
1239#[skip_serializing_none]
1241#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1242#[schemars(extend("x-side" = "agent", "x-method" = NES_START_METHOD_NAME))]
1243#[serde(rename_all = "camelCase")]
1244#[non_exhaustive]
1245pub struct StartNesResponse {
1246 pub session_id: SessionId,
1248 #[serde(rename = "_meta")]
1254 pub meta: Option<Meta>,
1255}
1256
1257impl StartNesResponse {
1258 #[must_use]
1259 pub fn new(session_id: impl Into<SessionId>) -> Self {
1260 Self {
1261 session_id: session_id.into(),
1262 meta: None,
1263 }
1264 }
1265
1266 #[must_use]
1272 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1273 self.meta = meta.into_option();
1274 self
1275 }
1276}
1277
1278#[skip_serializing_none]
1285#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1286#[schemars(extend("x-side" = "agent", "x-method" = NES_CLOSE_METHOD_NAME))]
1287#[serde(rename_all = "camelCase")]
1288#[non_exhaustive]
1289pub struct CloseNesRequest {
1290 pub session_id: SessionId,
1292 #[serde(rename = "_meta")]
1298 pub meta: Option<Meta>,
1299}
1300
1301impl CloseNesRequest {
1302 #[must_use]
1303 pub fn new(session_id: impl Into<SessionId>) -> Self {
1304 Self {
1305 session_id: session_id.into(),
1306 meta: None,
1307 }
1308 }
1309
1310 #[must_use]
1316 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1317 self.meta = meta.into_option();
1318 self
1319 }
1320}
1321
1322#[skip_serializing_none]
1324#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1325#[schemars(extend("x-side" = "agent", "x-method" = NES_CLOSE_METHOD_NAME))]
1326#[serde(rename_all = "camelCase")]
1327#[non_exhaustive]
1328pub struct CloseNesResponse {
1329 #[serde(rename = "_meta")]
1335 pub meta: Option<Meta>,
1336}
1337
1338impl CloseNesResponse {
1339 #[must_use]
1340 pub fn new() -> Self {
1341 Self::default()
1342 }
1343
1344 #[must_use]
1350 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1351 self.meta = meta.into_option();
1352 self
1353 }
1354}
1355
1356#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1360#[non_exhaustive]
1361pub enum NesTriggerKind {
1362 #[serde(rename = "automatic")]
1364 Automatic,
1365 #[serde(rename = "diagnostic")]
1367 Diagnostic,
1368 #[serde(rename = "manual")]
1370 Manual,
1371 #[serde(untagged)]
1377 Other(String),
1378}
1379
1380#[serde_as]
1382#[skip_serializing_none]
1383#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1384#[schemars(extend("x-side" = "agent", "x-method" = NES_SUGGEST_METHOD_NAME))]
1385#[serde(rename_all = "camelCase")]
1386#[non_exhaustive]
1387pub struct SuggestNesRequest {
1388 pub session_id: SessionId,
1390 pub uri: String,
1392 pub version: i64,
1394 pub position: Position,
1396 #[serde_as(deserialize_as = "DefaultOnError")]
1398 #[schemars(extend("x-deserialize-default-on-error" = true))]
1399 #[serde(default)]
1400 pub selection: Option<Range>,
1401 pub trigger_kind: NesTriggerKind,
1403 #[serde_as(deserialize_as = "DefaultOnError")]
1405 #[schemars(extend("x-deserialize-default-on-error" = true))]
1406 #[serde(default)]
1407 pub context: Option<NesSuggestContext>,
1408 #[serde(rename = "_meta")]
1414 pub meta: Option<Meta>,
1415}
1416
1417impl SuggestNesRequest {
1418 #[must_use]
1419 pub fn new(
1420 session_id: impl Into<SessionId>,
1421 uri: impl Into<String>,
1422 version: i64,
1423 position: Position,
1424 trigger_kind: NesTriggerKind,
1425 ) -> Self {
1426 Self {
1427 session_id: session_id.into(),
1428 uri: uri.into(),
1429 version,
1430 position,
1431 selection: None,
1432 trigger_kind,
1433 context: None,
1434 meta: None,
1435 }
1436 }
1437
1438 #[must_use]
1439 pub fn selection(mut self, selection: impl IntoOption<Range>) -> Self {
1440 self.selection = selection.into_option();
1441 self
1442 }
1443
1444 #[must_use]
1445 pub fn context(mut self, context: impl IntoOption<NesSuggestContext>) -> Self {
1446 self.context = context.into_option();
1447 self
1448 }
1449
1450 #[must_use]
1456 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1457 self.meta = meta.into_option();
1458 self
1459 }
1460}
1461
1462#[serde_as]
1464#[skip_serializing_none]
1465#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1466#[serde(rename_all = "camelCase")]
1467#[non_exhaustive]
1468pub struct NesSuggestContext {
1469 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1471 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1472 #[serde(default)]
1473 pub recent_files: Option<Vec<NesRecentFile>>,
1474 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1476 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1477 #[serde(default)]
1478 pub related_snippets: Option<Vec<NesRelatedSnippet>>,
1479 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1481 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1482 #[serde(default)]
1483 pub edit_history: Option<Vec<NesEditHistoryEntry>>,
1484 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1486 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1487 #[serde(default)]
1488 pub user_actions: Option<Vec<NesUserAction>>,
1489 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1491 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1492 #[serde(default)]
1493 pub open_files: Option<Vec<NesOpenFile>>,
1494 #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1496 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1497 #[serde(default)]
1498 pub diagnostics: Option<Vec<NesDiagnostic>>,
1499 #[serde(rename = "_meta")]
1505 pub meta: Option<Meta>,
1506}
1507
1508impl NesSuggestContext {
1509 #[must_use]
1510 pub fn new() -> Self {
1511 Self::default()
1512 }
1513
1514 #[must_use]
1515 pub fn recent_files(mut self, recent_files: impl IntoOption<Vec<NesRecentFile>>) -> Self {
1516 self.recent_files = recent_files.into_option();
1517 self
1518 }
1519
1520 #[must_use]
1521 pub fn related_snippets(
1522 mut self,
1523 related_snippets: impl IntoOption<Vec<NesRelatedSnippet>>,
1524 ) -> Self {
1525 self.related_snippets = related_snippets.into_option();
1526 self
1527 }
1528
1529 #[must_use]
1530 pub fn edit_history(mut self, edit_history: impl IntoOption<Vec<NesEditHistoryEntry>>) -> Self {
1531 self.edit_history = edit_history.into_option();
1532 self
1533 }
1534
1535 #[must_use]
1536 pub fn user_actions(mut self, user_actions: impl IntoOption<Vec<NesUserAction>>) -> Self {
1537 self.user_actions = user_actions.into_option();
1538 self
1539 }
1540
1541 #[must_use]
1542 pub fn open_files(mut self, open_files: impl IntoOption<Vec<NesOpenFile>>) -> Self {
1543 self.open_files = open_files.into_option();
1544 self
1545 }
1546
1547 #[must_use]
1548 pub fn diagnostics(mut self, diagnostics: impl IntoOption<Vec<NesDiagnostic>>) -> Self {
1549 self.diagnostics = diagnostics.into_option();
1550 self
1551 }
1552
1553 #[must_use]
1559 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1560 self.meta = meta.into_option();
1561 self
1562 }
1563}
1564
1565#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1567#[serde(rename_all = "camelCase")]
1568#[non_exhaustive]
1569pub struct NesRecentFile {
1570 pub uri: String,
1572 pub language_id: String,
1574 pub text: String,
1576}
1577
1578impl NesRecentFile {
1579 #[must_use]
1580 pub fn new(
1581 uri: impl Into<String>,
1582 language_id: impl Into<String>,
1583 text: impl Into<String>,
1584 ) -> Self {
1585 Self {
1586 uri: uri.into(),
1587 language_id: language_id.into(),
1588 text: text.into(),
1589 }
1590 }
1591}
1592
1593#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1595#[serde(rename_all = "camelCase")]
1596#[non_exhaustive]
1597pub struct NesRelatedSnippet {
1598 pub uri: String,
1600 pub excerpts: Vec<NesExcerpt>,
1602}
1603
1604impl NesRelatedSnippet {
1605 #[must_use]
1606 pub fn new(uri: impl Into<String>, excerpts: Vec<NesExcerpt>) -> Self {
1607 Self {
1608 uri: uri.into(),
1609 excerpts,
1610 }
1611 }
1612}
1613
1614#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1616#[serde(rename_all = "camelCase")]
1617#[non_exhaustive]
1618pub struct NesExcerpt {
1619 pub start_line: u32,
1621 pub end_line: u32,
1623 pub text: String,
1625}
1626
1627impl NesExcerpt {
1628 #[must_use]
1629 pub fn new(start_line: u32, end_line: u32, text: impl Into<String>) -> Self {
1630 Self {
1631 start_line,
1632 end_line,
1633 text: text.into(),
1634 }
1635 }
1636}
1637
1638#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1640#[serde(rename_all = "camelCase")]
1641#[non_exhaustive]
1642pub struct NesEditHistoryEntry {
1643 pub uri: String,
1645 pub diff: String,
1647}
1648
1649impl NesEditHistoryEntry {
1650 #[must_use]
1651 pub fn new(uri: impl Into<String>, diff: impl Into<String>) -> Self {
1652 Self {
1653 uri: uri.into(),
1654 diff: diff.into(),
1655 }
1656 }
1657}
1658
1659#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1661#[serde(rename_all = "camelCase")]
1662#[non_exhaustive]
1663pub struct NesUserAction {
1664 pub action: String,
1666 pub uri: String,
1668 pub position: Position,
1670 pub timestamp_ms: u64,
1672}
1673
1674impl NesUserAction {
1675 #[must_use]
1676 pub fn new(
1677 action: impl Into<String>,
1678 uri: impl Into<String>,
1679 position: Position,
1680 timestamp_ms: u64,
1681 ) -> Self {
1682 Self {
1683 action: action.into(),
1684 uri: uri.into(),
1685 position,
1686 timestamp_ms,
1687 }
1688 }
1689}
1690
1691#[serde_as]
1693#[skip_serializing_none]
1694#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1695#[serde(rename_all = "camelCase")]
1696#[non_exhaustive]
1697pub struct NesOpenFile {
1698 pub uri: String,
1700 pub language_id: String,
1702 #[serde_as(deserialize_as = "DefaultOnError")]
1704 #[schemars(extend("x-deserialize-default-on-error" = true))]
1705 #[serde(default)]
1706 pub visible_range: Option<Range>,
1707 #[serde_as(deserialize_as = "DefaultOnError")]
1709 #[schemars(extend("x-deserialize-default-on-error" = true))]
1710 #[serde(default)]
1711 pub last_focused_ms: Option<u64>,
1712}
1713
1714impl NesOpenFile {
1715 #[must_use]
1716 pub fn new(uri: impl Into<String>, language_id: impl Into<String>) -> Self {
1717 Self {
1718 uri: uri.into(),
1719 language_id: language_id.into(),
1720 visible_range: None,
1721 last_focused_ms: None,
1722 }
1723 }
1724
1725 #[must_use]
1726 pub fn visible_range(mut self, visible_range: impl IntoOption<Range>) -> Self {
1727 self.visible_range = visible_range.into_option();
1728 self
1729 }
1730
1731 #[must_use]
1732 pub fn last_focused_ms(mut self, last_focused_ms: impl IntoOption<u64>) -> Self {
1733 self.last_focused_ms = last_focused_ms.into_option();
1734 self
1735 }
1736}
1737
1738#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1740#[serde(rename_all = "camelCase")]
1741#[non_exhaustive]
1742pub struct NesDiagnostic {
1743 pub uri: String,
1745 pub range: Range,
1747 pub severity: NesDiagnosticSeverity,
1749 pub message: String,
1751}
1752
1753impl NesDiagnostic {
1754 #[must_use]
1755 pub fn new(
1756 uri: impl Into<String>,
1757 range: Range,
1758 severity: NesDiagnosticSeverity,
1759 message: impl Into<String>,
1760 ) -> Self {
1761 Self {
1762 uri: uri.into(),
1763 range,
1764 severity,
1765 message: message.into(),
1766 }
1767 }
1768}
1769
1770#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1772#[non_exhaustive]
1773pub enum NesDiagnosticSeverity {
1774 #[serde(rename = "error")]
1776 Error,
1777 #[serde(rename = "warning")]
1779 Warning,
1780 #[serde(rename = "information")]
1782 Information,
1783 #[serde(rename = "hint")]
1785 Hint,
1786 #[serde(untagged)]
1792 Other(String),
1793}
1794
1795#[serde_as]
1799#[skip_serializing_none]
1800#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1801#[schemars(extend("x-side" = "agent", "x-method" = NES_SUGGEST_METHOD_NAME))]
1802#[serde(rename_all = "camelCase")]
1803#[non_exhaustive]
1804pub struct SuggestNesResponse {
1805 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1807 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1808 pub suggestions: Vec<NesSuggestion>,
1809 #[serde(rename = "_meta")]
1815 pub meta: Option<Meta>,
1816}
1817
1818impl SuggestNesResponse {
1819 #[must_use]
1820 pub fn new(suggestions: Vec<NesSuggestion>) -> Self {
1821 Self {
1822 suggestions,
1823 meta: None,
1824 }
1825 }
1826
1827 #[must_use]
1833 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1834 self.meta = meta.into_option();
1835 self
1836 }
1837}
1838
1839#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1841#[serde(tag = "kind", rename_all = "camelCase")]
1842#[schemars(extend("discriminator" = {"propertyName": "kind"}))]
1843#[non_exhaustive]
1844pub enum NesSuggestion {
1845 Edit(NesEditSuggestion),
1847 Jump(NesJumpSuggestion),
1849 Rename(NesRenameSuggestion),
1851 SearchAndReplace(NesSearchAndReplaceSuggestion),
1853 #[serde(untagged)]
1863 Other(OtherNesSuggestion),
1864}
1865
1866#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
1868#[schemars(inline)]
1869#[schemars(transform = other_nes_suggestion_schema)]
1870#[serde(rename_all = "camelCase")]
1871#[non_exhaustive]
1872pub struct OtherNesSuggestion {
1873 pub kind: String,
1879 #[serde(flatten)]
1881 pub fields: BTreeMap<String, serde_json::Value>,
1882}
1883
1884impl OtherNesSuggestion {
1885 #[must_use]
1886 pub fn new(kind: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
1887 fields.remove("kind");
1888 Self {
1889 kind: kind.into(),
1890 fields,
1891 }
1892 }
1893}
1894
1895impl<'de> Deserialize<'de> for OtherNesSuggestion {
1896 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1897 where
1898 D: serde::Deserializer<'de>,
1899 {
1900 let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
1901 let kind = fields
1902 .remove("kind")
1903 .ok_or_else(|| serde::de::Error::missing_field("kind"))?;
1904 let serde_json::Value::String(kind) = kind else {
1905 return Err(serde::de::Error::custom("`kind` must be a string"));
1906 };
1907
1908 if is_known_nes_suggestion_kind(&kind) {
1909 return Err(serde::de::Error::custom(format!(
1910 "known NES suggestion `{kind}` did not match its schema"
1911 )));
1912 }
1913
1914 Ok(Self { kind, fields })
1915 }
1916}
1917
1918fn is_known_nes_suggestion_kind(kind: &str) -> bool {
1919 matches!(kind, "edit" | "jump" | "rename" | "searchAndReplace")
1920}
1921
1922fn other_nes_suggestion_schema(schema: &mut Schema) {
1923 super::schema_util::reject_known_string_discriminators(
1924 schema,
1925 "kind",
1926 &["edit", "jump", "rename", "searchAndReplace"],
1927 );
1928}
1929
1930#[serde_as]
1932#[skip_serializing_none]
1933#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1934#[serde(rename_all = "camelCase")]
1935#[non_exhaustive]
1936pub struct NesEditSuggestion {
1937 pub id: String,
1939 pub uri: String,
1941 pub edits: Vec<NesTextEdit>,
1943 #[serde_as(deserialize_as = "DefaultOnError")]
1945 #[schemars(extend("x-deserialize-default-on-error" = true))]
1946 #[serde(default)]
1947 pub cursor_position: Option<Position>,
1948}
1949
1950impl NesEditSuggestion {
1951 #[must_use]
1952 pub fn new(id: impl Into<String>, uri: impl Into<String>, edits: Vec<NesTextEdit>) -> Self {
1953 Self {
1954 id: id.into(),
1955 uri: uri.into(),
1956 edits,
1957 cursor_position: None,
1958 }
1959 }
1960
1961 #[must_use]
1962 pub fn cursor_position(mut self, cursor_position: impl IntoOption<Position>) -> Self {
1963 self.cursor_position = cursor_position.into_option();
1964 self
1965 }
1966}
1967
1968#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1970#[serde(rename_all = "camelCase")]
1971#[non_exhaustive]
1972pub struct NesTextEdit {
1973 pub range: Range,
1975 pub new_text: String,
1977}
1978
1979impl NesTextEdit {
1980 #[must_use]
1981 pub fn new(range: Range, new_text: impl Into<String>) -> Self {
1982 Self {
1983 range,
1984 new_text: new_text.into(),
1985 }
1986 }
1987}
1988
1989#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1991#[serde(rename_all = "camelCase")]
1992#[non_exhaustive]
1993pub struct NesJumpSuggestion {
1994 pub id: String,
1996 pub uri: String,
1998 pub position: Position,
2000}
2001
2002impl NesJumpSuggestion {
2003 #[must_use]
2004 pub fn new(id: impl Into<String>, uri: impl Into<String>, position: Position) -> Self {
2005 Self {
2006 id: id.into(),
2007 uri: uri.into(),
2008 position,
2009 }
2010 }
2011}
2012
2013#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2015#[serde(rename_all = "camelCase")]
2016#[non_exhaustive]
2017pub struct NesRenameSuggestion {
2018 pub id: String,
2020 pub uri: String,
2022 pub position: Position,
2024 pub new_name: String,
2026}
2027
2028impl NesRenameSuggestion {
2029 #[must_use]
2030 pub fn new(
2031 id: impl Into<String>,
2032 uri: impl Into<String>,
2033 position: Position,
2034 new_name: impl Into<String>,
2035 ) -> Self {
2036 Self {
2037 id: id.into(),
2038 uri: uri.into(),
2039 position,
2040 new_name: new_name.into(),
2041 }
2042 }
2043}
2044
2045#[skip_serializing_none]
2047#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2048#[serde(rename_all = "camelCase")]
2049#[non_exhaustive]
2050pub struct NesSearchAndReplaceSuggestion {
2051 pub id: String,
2053 pub uri: String,
2055 pub search: String,
2057 pub replace: String,
2059 pub is_regex: Option<bool>,
2061}
2062
2063impl NesSearchAndReplaceSuggestion {
2064 #[must_use]
2065 pub fn new(
2066 id: impl Into<String>,
2067 uri: impl Into<String>,
2068 search: impl Into<String>,
2069 replace: impl Into<String>,
2070 ) -> Self {
2071 Self {
2072 id: id.into(),
2073 uri: uri.into(),
2074 search: search.into(),
2075 replace: replace.into(),
2076 is_regex: None,
2077 }
2078 }
2079
2080 #[must_use]
2081 pub fn is_regex(mut self, is_regex: impl IntoOption<bool>) -> Self {
2082 self.is_regex = is_regex.into_option();
2083 self
2084 }
2085}
2086
2087#[skip_serializing_none]
2091#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2092#[schemars(extend("x-side" = "agent", "x-method" = NES_ACCEPT_METHOD_NAME))]
2093#[serde(rename_all = "camelCase")]
2094#[non_exhaustive]
2095pub struct AcceptNesNotification {
2096 pub session_id: SessionId,
2098 pub id: String,
2100 #[serde(rename = "_meta")]
2106 pub meta: Option<Meta>,
2107}
2108
2109impl AcceptNesNotification {
2110 #[must_use]
2111 pub fn new(session_id: impl Into<SessionId>, id: impl Into<String>) -> Self {
2112 Self {
2113 session_id: session_id.into(),
2114 id: id.into(),
2115 meta: None,
2116 }
2117 }
2118
2119 #[must_use]
2125 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2126 self.meta = meta.into_option();
2127 self
2128 }
2129}
2130
2131#[serde_as]
2133#[skip_serializing_none]
2134#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2135#[schemars(extend("x-side" = "agent", "x-method" = NES_REJECT_METHOD_NAME))]
2136#[serde(rename_all = "camelCase")]
2137#[non_exhaustive]
2138pub struct RejectNesNotification {
2139 pub session_id: SessionId,
2141 pub id: String,
2143 #[serde_as(deserialize_as = "DefaultOnError")]
2145 #[schemars(extend("x-deserialize-default-on-error" = true))]
2146 #[serde(default)]
2147 pub reason: Option<NesRejectReason>,
2148 #[serde(rename = "_meta")]
2154 pub meta: Option<Meta>,
2155}
2156
2157impl RejectNesNotification {
2158 #[must_use]
2159 pub fn new(session_id: impl Into<SessionId>, id: impl Into<String>) -> Self {
2160 Self {
2161 session_id: session_id.into(),
2162 id: id.into(),
2163 reason: None,
2164 meta: None,
2165 }
2166 }
2167
2168 #[must_use]
2169 pub fn reason(mut self, reason: impl IntoOption<NesRejectReason>) -> Self {
2170 self.reason = reason.into_option();
2171 self
2172 }
2173
2174 #[must_use]
2180 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2181 self.meta = meta.into_option();
2182 self
2183 }
2184}
2185
2186#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2188#[non_exhaustive]
2189pub enum NesRejectReason {
2190 #[serde(rename = "rejected")]
2192 Rejected,
2193 #[serde(rename = "ignored")]
2195 Ignored,
2196 #[serde(rename = "replaced")]
2198 Replaced,
2199 #[serde(rename = "cancelled")]
2201 Cancelled,
2202 #[serde(untagged)]
2208 Other(String),
2209}
2210
2211#[cfg(test)]
2212mod tests {
2213 use super::*;
2214 use serde_json::json;
2215
2216 #[test]
2217 fn test_position_encoding_kind_serialization() {
2218 assert_eq!(
2219 serde_json::to_value(&PositionEncodingKind::Utf16).unwrap(),
2220 json!("utf-16")
2221 );
2222 assert_eq!(
2223 serde_json::to_value(&PositionEncodingKind::Utf32).unwrap(),
2224 json!("utf-32")
2225 );
2226 assert_eq!(
2227 serde_json::to_value(&PositionEncodingKind::Utf8).unwrap(),
2228 json!("utf-8")
2229 );
2230
2231 assert_eq!(
2232 serde_json::from_value::<PositionEncodingKind>(json!("utf-16")).unwrap(),
2233 PositionEncodingKind::Utf16
2234 );
2235 assert_eq!(
2236 serde_json::from_value::<PositionEncodingKind>(json!("utf-32")).unwrap(),
2237 PositionEncodingKind::Utf32
2238 );
2239 assert_eq!(
2240 serde_json::from_value::<PositionEncodingKind>(json!("utf-8")).unwrap(),
2241 PositionEncodingKind::Utf8
2242 );
2243 assert!(serde_json::from_value::<PositionEncodingKind>(json!("_future")).is_err());
2244 }
2245
2246 #[test]
2247 fn test_client_capabilities_skip_unknown_position_encodings() {
2248 let caps: crate::v2::ClientCapabilities = serde_json::from_value(json!({
2249 "positionEncodings": ["_future", "utf-8", "utf-16"]
2250 }))
2251 .unwrap();
2252
2253 assert_eq!(
2254 caps.position_encodings,
2255 vec![PositionEncodingKind::Utf8, PositionEncodingKind::Utf16]
2256 );
2257 }
2258
2259 #[test]
2260 fn test_agent_nes_capabilities_serialization() {
2261 let caps = NesCapabilities::new()
2262 .events(
2263 NesEventCapabilities::new().document(
2264 NesDocumentEventCapabilities::new()
2265 .did_open(NesDocumentDidOpenCapabilities::default())
2266 .did_change(NesDocumentDidChangeCapabilities::new(
2267 TextDocumentSyncKind::Incremental,
2268 ))
2269 .did_close(NesDocumentDidCloseCapabilities::default())
2270 .did_save(NesDocumentDidSaveCapabilities::default())
2271 .did_focus(NesDocumentDidFocusCapabilities::default()),
2272 ),
2273 )
2274 .context(
2275 NesContextCapabilities::new()
2276 .recent_files(NesRecentFilesCapabilities {
2277 max_count: Some(10),
2278 meta: None,
2279 })
2280 .related_snippets(NesRelatedSnippetsCapabilities::default())
2281 .edit_history(NesEditHistoryCapabilities {
2282 max_count: Some(6),
2283 meta: None,
2284 })
2285 .user_actions(NesUserActionsCapabilities {
2286 max_count: Some(16),
2287 meta: None,
2288 })
2289 .open_files(NesOpenFilesCapabilities::default())
2290 .diagnostics(NesDiagnosticsCapabilities::default()),
2291 );
2292
2293 let json = serde_json::to_value(&caps).unwrap();
2294 assert_eq!(
2295 json,
2296 json!({
2297 "events": {
2298 "document": {
2299 "didOpen": {},
2300 "didChange": {
2301 "syncKind": "incremental"
2302 },
2303 "didClose": {},
2304 "didSave": {},
2305 "didFocus": {}
2306 }
2307 },
2308 "context": {
2309 "recentFiles": {
2310 "maxCount": 10
2311 },
2312 "relatedSnippets": {},
2313 "editHistory": {
2314 "maxCount": 6
2315 },
2316 "userActions": {
2317 "maxCount": 16
2318 },
2319 "openFiles": {},
2320 "diagnostics": {}
2321 }
2322 })
2323 );
2324
2325 let deserialized: NesCapabilities = serde_json::from_value(json).unwrap();
2327 assert_eq!(deserialized, caps);
2328 }
2329
2330 #[test]
2331 fn test_client_nes_capabilities_serialization() {
2332 let caps = ClientNesCapabilities::new()
2333 .jump(NesJumpCapabilities::default())
2334 .rename(NesRenameCapabilities::default())
2335 .search_and_replace(NesSearchAndReplaceCapabilities::default());
2336
2337 let json = serde_json::to_value(&caps).unwrap();
2338 assert_eq!(
2339 json,
2340 json!({
2341 "jump": {},
2342 "rename": {},
2343 "searchAndReplace": {}
2344 })
2345 );
2346
2347 let deserialized: ClientNesCapabilities = serde_json::from_value(json).unwrap();
2348 assert_eq!(deserialized, caps);
2349 }
2350
2351 #[test]
2352 fn test_document_did_open_serialization() {
2353 let notification = DidOpenDocumentNotification::new(
2354 "session_123",
2355 "file:///path/to/file.rs",
2356 "rust",
2357 1,
2358 "fn main() {\n println!(\"hello\");\n}\n",
2359 );
2360
2361 let json = serde_json::to_value(¬ification).unwrap();
2362 assert_eq!(
2363 json,
2364 json!({
2365 "sessionId": "session_123",
2366 "uri": "file:///path/to/file.rs",
2367 "languageId": "rust",
2368 "version": 1,
2369 "text": "fn main() {\n println!(\"hello\");\n}\n"
2370 })
2371 );
2372
2373 let deserialized: DidOpenDocumentNotification = serde_json::from_value(json).unwrap();
2374 assert_eq!(deserialized, notification);
2375 }
2376
2377 #[test]
2378 fn test_document_did_change_incremental_serialization() {
2379 let notification = DidChangeDocumentNotification::new(
2380 "session_123",
2381 "file:///path/to/file.rs",
2382 2,
2383 vec![TextDocumentContentChangeEvent::incremental(
2384 Range::new(Position::new(1, 4), Position::new(1, 4)),
2385 "let x = 42;\n ",
2386 )],
2387 );
2388
2389 let json = serde_json::to_value(¬ification).unwrap();
2390 assert_eq!(
2391 json,
2392 json!({
2393 "sessionId": "session_123",
2394 "uri": "file:///path/to/file.rs",
2395 "version": 2,
2396 "contentChanges": [
2397 {
2398 "range": {
2399 "start": { "line": 1, "character": 4 },
2400 "end": { "line": 1, "character": 4 }
2401 },
2402 "text": "let x = 42;\n "
2403 }
2404 ]
2405 })
2406 );
2407 }
2408
2409 #[test]
2410 fn test_document_did_change_full_serialization() {
2411 let notification = DidChangeDocumentNotification::new(
2412 "session_123",
2413 "file:///path/to/file.rs",
2414 2,
2415 vec![TextDocumentContentChangeEvent::full(
2416 "fn main() {\n let x = 42;\n println!(\"hello\");\n}\n",
2417 )],
2418 );
2419
2420 let json = serde_json::to_value(¬ification).unwrap();
2421 assert_eq!(
2422 json,
2423 json!({
2424 "sessionId": "session_123",
2425 "uri": "file:///path/to/file.rs",
2426 "version": 2,
2427 "contentChanges": [
2428 {
2429 "text": "fn main() {\n let x = 42;\n println!(\"hello\");\n}\n"
2430 }
2431 ]
2432 })
2433 );
2434 }
2435
2436 #[test]
2437 fn test_document_did_close_serialization() {
2438 let notification =
2439 DidCloseDocumentNotification::new("session_123", "file:///path/to/file.rs");
2440 let json = serde_json::to_value(¬ification).unwrap();
2441 assert_eq!(
2442 json,
2443 json!({ "sessionId": "session_123", "uri": "file:///path/to/file.rs" })
2444 );
2445 }
2446
2447 #[test]
2448 fn test_document_did_save_serialization() {
2449 let notification =
2450 DidSaveDocumentNotification::new("session_123", "file:///path/to/file.rs");
2451 let json = serde_json::to_value(¬ification).unwrap();
2452 assert_eq!(
2453 json,
2454 json!({ "sessionId": "session_123", "uri": "file:///path/to/file.rs" })
2455 );
2456 }
2457
2458 #[test]
2459 fn test_document_did_focus_serialization() {
2460 let notification = DidFocusDocumentNotification::new(
2461 "session_123",
2462 "file:///path/to/file.rs",
2463 2,
2464 Position::new(5, 12),
2465 Range::new(Position::new(0, 0), Position::new(45, 0)),
2466 );
2467
2468 let json = serde_json::to_value(¬ification).unwrap();
2469 assert_eq!(
2470 json,
2471 json!({
2472 "sessionId": "session_123",
2473 "uri": "file:///path/to/file.rs",
2474 "version": 2,
2475 "position": { "line": 5, "character": 12 },
2476 "visibleRange": {
2477 "start": { "line": 0, "character": 0 },
2478 "end": { "line": 45, "character": 0 }
2479 }
2480 })
2481 );
2482 }
2483
2484 #[test]
2485 fn test_nes_suggestion_edit_serialization() {
2486 let suggestion = NesSuggestion::Edit(
2487 NesEditSuggestion::new(
2488 "sugg_001",
2489 "file:///path/to/other_file.rs",
2490 vec![NesTextEdit::new(
2491 Range::new(Position::new(5, 0), Position::new(5, 10)),
2492 "let result = helper();",
2493 )],
2494 )
2495 .cursor_position(Position::new(5, 22)),
2496 );
2497
2498 let json = serde_json::to_value(&suggestion).unwrap();
2499 assert_eq!(
2500 json,
2501 json!({
2502 "kind": "edit",
2503 "id": "sugg_001",
2504 "uri": "file:///path/to/other_file.rs",
2505 "edits": [
2506 {
2507 "range": {
2508 "start": { "line": 5, "character": 0 },
2509 "end": { "line": 5, "character": 10 }
2510 },
2511 "newText": "let result = helper();"
2512 }
2513 ],
2514 "cursorPosition": { "line": 5, "character": 22 }
2515 })
2516 );
2517
2518 let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
2519 assert_eq!(deserialized, suggestion);
2520 }
2521
2522 #[test]
2523 fn test_nes_suggestion_unknown_variant() {
2524 let suggestion: NesSuggestion = serde_json::from_value(json!({
2525 "kind": "_preview",
2526 "id": "sugg_001",
2527 "label": "Preview generated file"
2528 }))
2529 .unwrap();
2530
2531 let NesSuggestion::Other(unknown) = suggestion else {
2532 panic!("expected unknown NES suggestion");
2533 };
2534
2535 assert_eq!(unknown.kind, "_preview");
2536 assert_eq!(unknown.fields.get("id"), Some(&json!("sugg_001")));
2537 assert_eq!(
2538 serde_json::to_value(NesSuggestion::Other(unknown)).unwrap(),
2539 json!({
2540 "kind": "_preview",
2541 "id": "sugg_001",
2542 "label": "Preview generated file"
2543 })
2544 );
2545 }
2546
2547 #[test]
2548 fn test_nes_suggestion_unknown_does_not_hide_malformed_known_variant() {
2549 assert!(
2550 serde_json::from_value::<NesSuggestion>(json!({
2551 "kind": "edit"
2552 }))
2553 .is_err()
2554 );
2555 }
2556
2557 #[test]
2558 fn test_nes_suggestion_jump_serialization() {
2559 let suggestion = NesSuggestion::Jump(NesJumpSuggestion::new(
2560 "sugg_002",
2561 "file:///path/to/other_file.rs",
2562 Position::new(15, 4),
2563 ));
2564
2565 let json = serde_json::to_value(&suggestion).unwrap();
2566 assert_eq!(
2567 json,
2568 json!({
2569 "kind": "jump",
2570 "id": "sugg_002",
2571 "uri": "file:///path/to/other_file.rs",
2572 "position": { "line": 15, "character": 4 }
2573 })
2574 );
2575
2576 let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
2577 assert_eq!(deserialized, suggestion);
2578 }
2579
2580 #[test]
2581 fn test_nes_suggestion_rename_serialization() {
2582 let suggestion = NesSuggestion::Rename(NesRenameSuggestion::new(
2583 "sugg_003",
2584 "file:///path/to/file.rs",
2585 Position::new(5, 10),
2586 "calculateTotal",
2587 ));
2588
2589 let json = serde_json::to_value(&suggestion).unwrap();
2590 assert_eq!(
2591 json,
2592 json!({
2593 "kind": "rename",
2594 "id": "sugg_003",
2595 "uri": "file:///path/to/file.rs",
2596 "position": { "line": 5, "character": 10 },
2597 "newName": "calculateTotal"
2598 })
2599 );
2600
2601 let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
2602 assert_eq!(deserialized, suggestion);
2603 }
2604
2605 #[test]
2606 fn test_nes_suggestion_search_and_replace_serialization() {
2607 let suggestion = NesSuggestion::SearchAndReplace(
2608 NesSearchAndReplaceSuggestion::new(
2609 "sugg_004",
2610 "file:///path/to/file.rs",
2611 "oldFunction",
2612 "newFunction",
2613 )
2614 .is_regex(false),
2615 );
2616
2617 let json = serde_json::to_value(&suggestion).unwrap();
2618 assert_eq!(
2619 json,
2620 json!({
2621 "kind": "searchAndReplace",
2622 "id": "sugg_004",
2623 "uri": "file:///path/to/file.rs",
2624 "search": "oldFunction",
2625 "replace": "newFunction",
2626 "isRegex": false
2627 })
2628 );
2629
2630 let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
2631 assert_eq!(deserialized, suggestion);
2632 }
2633
2634 #[test]
2635 fn test_nes_start_request_serialization() {
2636 let request = StartNesRequest::new()
2637 .workspace_uri("file:///Users/alice/projects/my-app")
2638 .workspace_folders(vec![WorkspaceFolder::new(
2639 "file:///Users/alice/projects/my-app",
2640 "my-app",
2641 )])
2642 .repository(NesRepository::new(
2643 "my-app",
2644 "alice",
2645 "https://github.com/alice/my-app.git",
2646 ));
2647
2648 let json = serde_json::to_value(&request).unwrap();
2649 assert_eq!(
2650 json,
2651 json!({
2652 "workspaceUri": "file:///Users/alice/projects/my-app",
2653 "workspaceFolders": [
2654 {
2655 "uri": "file:///Users/alice/projects/my-app",
2656 "name": "my-app"
2657 }
2658 ],
2659 "repository": {
2660 "name": "my-app",
2661 "owner": "alice",
2662 "remoteUrl": "https://github.com/alice/my-app.git"
2663 }
2664 })
2665 );
2666 }
2667
2668 #[test]
2669 fn test_nes_start_response_serialization() {
2670 let response = StartNesResponse::new("session_abc123");
2671 let json = serde_json::to_value(&response).unwrap();
2672 assert_eq!(json, json!({ "sessionId": "session_abc123" }));
2673 }
2674
2675 #[test]
2676 fn test_nes_trigger_kind_serialization() {
2677 assert_eq!(
2678 serde_json::to_value(&NesTriggerKind::Automatic).unwrap(),
2679 json!("automatic")
2680 );
2681 assert_eq!(
2682 serde_json::to_value(&NesTriggerKind::Diagnostic).unwrap(),
2683 json!("diagnostic")
2684 );
2685 assert_eq!(
2686 serde_json::to_value(&NesTriggerKind::Manual).unwrap(),
2687 json!("manual")
2688 );
2689 }
2690
2691 #[test]
2692 fn test_nes_reject_reason_serialization() {
2693 assert_eq!(
2694 serde_json::to_value(&NesRejectReason::Rejected).unwrap(),
2695 json!("rejected")
2696 );
2697 assert_eq!(
2698 serde_json::to_value(&NesRejectReason::Ignored).unwrap(),
2699 json!("ignored")
2700 );
2701 assert_eq!(
2702 serde_json::to_value(&NesRejectReason::Replaced).unwrap(),
2703 json!("replaced")
2704 );
2705 assert_eq!(
2706 serde_json::to_value(&NesRejectReason::Cancelled).unwrap(),
2707 json!("cancelled")
2708 );
2709 }
2710
2711 #[test]
2712 fn test_nes_accept_notification_serialization() {
2713 let notification = AcceptNesNotification::new("session_123", "sugg_001");
2714 let json = serde_json::to_value(¬ification).unwrap();
2715 assert_eq!(
2716 json,
2717 json!({ "sessionId": "session_123", "id": "sugg_001" })
2718 );
2719 }
2720
2721 #[test]
2722 fn test_nes_reject_notification_serialization() {
2723 let notification =
2724 RejectNesNotification::new("session_123", "sugg_001").reason(NesRejectReason::Rejected);
2725 let json = serde_json::to_value(¬ification).unwrap();
2726 assert_eq!(
2727 json,
2728 json!({ "sessionId": "session_123", "id": "sugg_001", "reason": "rejected" })
2729 );
2730 }
2731
2732 #[test]
2733 fn test_nes_suggest_request_with_context_serialization() {
2734 let request = SuggestNesRequest::new(
2735 "session_123",
2736 "file:///path/to/file.rs",
2737 2,
2738 Position::new(5, 12),
2739 NesTriggerKind::Automatic,
2740 )
2741 .selection(Range::new(Position::new(5, 4), Position::new(5, 12)))
2742 .context(
2743 NesSuggestContext::new()
2744 .recent_files(vec![NesRecentFile::new(
2745 "file:///path/to/utils.rs",
2746 "rust",
2747 "pub fn helper() -> i32 { 42 }\n",
2748 )])
2749 .diagnostics(vec![NesDiagnostic::new(
2750 "file:///path/to/file.rs",
2751 Range::new(Position::new(5, 0), Position::new(5, 10)),
2752 NesDiagnosticSeverity::Error,
2753 "cannot find value `foo` in this scope",
2754 )]),
2755 );
2756
2757 let json = serde_json::to_value(&request).unwrap();
2758 assert_eq!(json["sessionId"], "session_123");
2759 assert_eq!(json["uri"], "file:///path/to/file.rs");
2760 assert_eq!(json["version"], 2);
2761 assert_eq!(json["triggerKind"], "automatic");
2762 assert_eq!(
2763 json["context"]["recentFiles"][0]["uri"],
2764 "file:///path/to/utils.rs"
2765 );
2766 assert_eq!(json["context"]["diagnostics"][0]["severity"], "error");
2767 }
2768
2769 #[test]
2770 fn test_text_document_sync_kind_serialization() {
2771 assert_eq!(
2772 serde_json::to_value(&TextDocumentSyncKind::Full).unwrap(),
2773 json!("full")
2774 );
2775 assert_eq!(
2776 serde_json::to_value(&TextDocumentSyncKind::Incremental).unwrap(),
2777 json!("incremental")
2778 );
2779 assert!(serde_json::from_value::<TextDocumentSyncKind>(json!("_future")).is_err());
2780 }
2781
2782 #[test]
2783 fn test_document_event_capabilities_drop_unknown_did_change_sync_kind() {
2784 let caps: NesDocumentEventCapabilities = serde_json::from_value(json!({
2785 "didChange": {
2786 "syncKind": "_future"
2787 }
2788 }))
2789 .unwrap();
2790
2791 assert_eq!(caps.did_change, None);
2792 }
2793
2794 #[test]
2795 fn test_document_did_change_capabilities_requires_sync_kind() {
2796 assert!(serde_json::from_value::<NesDocumentDidChangeCapabilities>(json!({})).is_err());
2797 }
2798
2799 #[test]
2800 fn test_nes_suggest_response_serialization() {
2801 let response = SuggestNesResponse::new(vec![
2802 NesSuggestion::Edit(NesEditSuggestion::new(
2803 "sugg_001",
2804 "file:///path/to/file.rs",
2805 vec![NesTextEdit::new(
2806 Range::new(Position::new(5, 0), Position::new(5, 10)),
2807 "let result = helper();",
2808 )],
2809 )),
2810 NesSuggestion::Jump(NesJumpSuggestion::new(
2811 "sugg_002",
2812 "file:///path/to/other.rs",
2813 Position::new(10, 0),
2814 )),
2815 ]);
2816
2817 let json = serde_json::to_value(&response).unwrap();
2818 assert_eq!(json["suggestions"].as_array().unwrap().len(), 2);
2819 assert_eq!(json["suggestions"][0]["kind"], "edit");
2820 assert_eq!(json["suggestions"][1]["kind"], "jump");
2821 }
2822}