1use std::sync::{
8 Arc,
9 Mutex,
10 atomic::{AtomicU32, Ordering},
11};
12
13use serde::{Deserialize, Serialize};
14
15use crate::{API::Types::*, Transport::Strategy::Transport, dev_log};
16
17#[derive(Debug, Default)]
26struct ProviderStore {
27 entries:Mutex<std::collections::HashMap<u32, (String, String)>>,
29
30 next_handle:AtomicU32,
32}
33
34impl ProviderStore {
35 fn insert(&self, provider_type:&str, selector:&str) -> u32 {
37 let Handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
38
39 if let Ok(mut Guard) = self.entries.lock() {
40 Guard.insert(Handle, (provider_type.to_string(), selector.to_string()));
41 }
42
43 Handle
44 }
45
46 fn remove(&self, handle:u32) {
48 if let Ok(mut Guard) = self.entries.lock() {
49 Guard.remove(&handle);
50 }
51 }
52
53 #[allow(dead_code)]
55 fn len(&self) -> usize { self.entries.lock().map(|G| G.len()).unwrap_or(0) }
56}
57
58#[derive(Debug, Clone)]
60pub struct VSCodeAPI {
61 pub commands:Arc<CommandNamespace>,
63
64 pub window:Arc<Window>,
66
67 pub workspace:Arc<Workspace>,
69
70 pub languages:Arc<LanguageNamespace>,
72
73 pub extensions:Arc<ExtensionNamespace>,
75
76 pub env:Arc<Env>,
78}
79
80impl VSCodeAPI {
81 pub fn new() -> Self {
84 Self {
85 commands:Arc::new(CommandNamespace::new()),
86
87 window:Arc::new(Window::new()),
88
89 workspace:Arc::new(Workspace::new()),
90
91 languages:Arc::new(LanguageNamespace::new()),
92
93 extensions:Arc::new(ExtensionNamespace::new()),
94
95 env:Arc::new(Env::new()),
96 }
97 }
98
99 pub fn new_with_transport(transport:Arc<Transport>) -> Self {
103 Self {
104 commands:Arc::new(CommandNamespace::new()),
105
106 window:Arc::new(Window::new()),
107
108 workspace:Arc::new(Workspace::new()),
109
110 languages:Arc::new(LanguageNamespace::new_with_transport(Arc::clone(&transport))),
111
112 extensions:Arc::new(ExtensionNamespace::new()),
113
114 env:Arc::new(Env::new()),
115 }
116 }
117}
118
119impl Default for VSCodeAPI {
120 fn default() -> Self { Self::new() }
121}
122
123#[derive(Debug, Clone)]
125pub struct CommandNamespace;
126
127impl CommandNamespace {
128 pub fn new() -> Self { Self }
130
131 pub fn register_command(&self, command_id:String, _callback:CommandCallback) -> Result<Command, String> {
133 Ok(Command { id:command_id.clone() })
134 }
135
136 pub async fn execute_command<T:serde::de::DeserializeOwned>(
138 &self,
139
140 command_id:String,
141
142 _args:Vec<serde_json::Value>,
143 ) -> Result<T, String> {
144 Err(format!("Command not implemented: {}", command_id))
146 }
147}
148
149pub type CommandCallback = Box<dyn Fn(Vec<serde_json::Value>) -> Result<serde_json::Value, String> + Send + Sync>;
151
152#[derive(Debug, Clone)]
154pub struct Command {
155 pub id:String,
157}
158
159#[derive(Debug, Clone)]
161pub struct Window;
162
163impl Window {
164 pub fn new() -> Self { Self }
166
167 pub async fn show_information_message(&self, _message:String) -> Result<String, String> {
169 Ok("OK".to_string())
171 }
172
173 pub async fn show_warning_message(&self, _message:String) -> Result<String, String> {
175 Ok("OK".to_string())
177 }
178
179 pub async fn show_error_message(&self, _message:String) -> Result<String, String> {
181 Ok("OK".to_string())
183 }
184
185 pub fn create_output_channel(&self, name:String) -> OutputChannel { OutputChannel::new(name) }
187}
188
189#[derive(Debug, Clone)]
191pub struct OutputChannel {
192 name:String,
194}
195
196impl OutputChannel {
197 pub fn new(name:String) -> Self { Self { name } }
203
204 pub fn append_line(&self, line:&str) {
206 dev_log!("output", "[{}] {}", self.name, line);
207 }
208
209 pub fn append(&self, value:&str) {
211 dev_log!("output", "[{}] {}", self.name, value);
212 }
213
214 pub fn show(&self) {
216
217 }
219
220 pub fn hide(&self) {
222
223 }
225
226 pub fn dispose(&self) {
228
229 }
231}
232
233#[derive(Debug, Clone)]
235pub struct Workspace;
236
237impl Workspace {
238 pub fn new() -> Self { Self }
240
241 pub fn workspace_folders(&self) -> Vec<WorkspaceFolder> {
243 Vec::new()
245 }
246
247 pub fn get_configuration(&self, section:Option<String>) -> WorkspaceConfiguration {
249 WorkspaceConfiguration::new(section)
250 }
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct WorkspaceFolder {
256 pub uri:String,
258
259 pub name:String,
261
262 pub index:u32,
264}
265
266#[derive(Debug, Clone)]
268pub struct WorkspaceConfiguration {
269 #[allow(dead_code)]
271 section:Option<String>,
272}
273
274impl WorkspaceConfiguration {
275 pub fn new(section:Option<String>) -> Self { Self { section } }
281
282 pub fn get<T:serde::de::DeserializeOwned>(&self, _key:String) -> Result<T, String> {
284 Err("Configuration not implemented".to_string())
286 }
287
288 pub fn has(&self, _key:String) -> bool { false }
290
291 pub async fn update(&self, _key:String, _value:serde_json::Value) -> Result<(), String> {
293 Err("Update configuration not implemented".to_string())
295 }
296}
297
298#[derive(Debug)]
308pub struct LanguageNamespace {
309 store:Arc<ProviderStore>,
311
312 transport:Option<Arc<Transport>>,
314}
315
316impl Clone for LanguageNamespace {
317 fn clone(&self) -> Self { Self { store:Arc::clone(&self.store), transport:self.transport.clone() } }
318}
319
320impl LanguageNamespace {
321 pub fn new() -> Self { Self { store:Arc::new(ProviderStore::default()), transport:None } }
323
324 pub fn new_with_transport(transport:Arc<Transport>) -> Self {
328 Self { store:Arc::new(ProviderStore::default()), transport:Some(transport) }
329 }
330
331 pub fn active_registration_count(&self) -> usize { self.store.len() }
333
334 fn register(&self, provider_type:&str, selector:&DocumentSelector) -> Disposable {
336 let ProviderTypeOwned = provider_type.to_string();
337
338 let SelectorStr = selector
339 .iter()
340 .filter_map(|F| F.language.as_deref())
341 .collect::<Vec<_>>()
342 .join(",");
343
344 let Handle = self.store.insert(&ProviderTypeOwned, &SelectorStr);
345
346 let Store = Arc::clone(&self.store);
347
348 dev_log!(
349 "extensions",
350 "[LanguageNamespace] registered {} handle={} selector={}",
351 ProviderTypeOwned,
352 Handle,
353 SelectorStr
354 );
355
356 if let Some(Transport) = &self.transport {
358 let Notification = serde_json::json!({
359 "method": format!("register_{}", ProviderTypeOwned),
360 "parameters": {
361 "handle": Handle,
362 "language_selector": SelectorStr,
363 "extension_id": "grove-extension",
364 }
365 });
366
367 if let Ok(Bytes) = serde_json::to_vec(&Notification) {
368 let TransportClone = Arc::clone(Transport);
369
370 tokio::spawn(async move {
371 let _ = TransportClone.send_no_response(&Bytes).await;
372 });
373 }
374 }
375
376 Disposable::with_callback(Box::new(move || {
377 Store.remove(Handle);
378 dev_log!(
379 "extensions",
380 "[LanguageNamespace] disposed {} handle={}",
381 ProviderTypeOwned,
382 Handle
383 );
384 }))
385 }
386
387 pub async fn register_completion_item_provider<T:CompletionItemProvider>(
389 &self,
390
391 selector:DocumentSelector,
392
393 _provider:T,
394
395 _trigger_characters:Option<Vec<String>>,
396 ) -> Result<Disposable, String> {
397 Ok(self.register("completion", &selector))
398 }
399
400 pub fn register_hover_provider(&self, selector:DocumentSelector) -> Disposable { self.register("hover", &selector) }
402
403 pub fn register_definition_provider(&self, selector:DocumentSelector) -> Disposable {
405 self.register("definition", &selector)
406 }
407
408 pub fn register_reference_provider(&self, selector:DocumentSelector) -> Disposable {
410 self.register("references", &selector)
411 }
412
413 pub fn register_code_actions_provider(&self, selector:DocumentSelector) -> Disposable {
415 self.register("codeAction", &selector)
416 }
417
418 pub fn register_document_highlight_provider(&self, selector:DocumentSelector) -> Disposable {
420 self.register("documentHighlight", &selector)
421 }
422
423 pub fn register_document_symbol_provider(&self, selector:DocumentSelector) -> Disposable {
425 self.register("documentSymbol", &selector)
426 }
427
428 pub fn register_workspace_symbol_provider(&self) -> Disposable { self.register("workspaceSymbol", &Vec::new()) }
430
431 pub fn register_rename_provider(&self, selector:DocumentSelector) -> Disposable {
433 self.register("rename", &selector)
434 }
435
436 pub fn register_document_formatting_edit_provider(&self, selector:DocumentSelector) -> Disposable {
438 self.register("documentFormatting", &selector)
439 }
440
441 pub fn register_document_range_formatting_edit_provider(&self, selector:DocumentSelector) -> Disposable {
443 self.register("documentRangeFormatting", &selector)
444 }
445
446 pub fn register_on_type_formatting_edit_provider(
448 &self,
449
450 selector:DocumentSelector,
451
452 _trigger_characters:Vec<String>,
453 ) -> Disposable {
454 self.register("onTypeFormatting", &selector)
455 }
456
457 pub fn register_signature_help_provider(&self, selector:DocumentSelector) -> Disposable {
459 self.register("signatureHelp", &selector)
460 }
461
462 pub fn register_code_lens_provider(&self, selector:DocumentSelector) -> Disposable {
464 self.register("codeLens", &selector)
465 }
466
467 pub fn register_folding_range_provider(&self, selector:DocumentSelector) -> Disposable {
469 self.register("foldingRange", &selector)
470 }
471
472 pub fn register_selection_range_provider(&self, selector:DocumentSelector) -> Disposable {
474 self.register("selectionRange", &selector)
475 }
476
477 pub fn register_document_semantic_tokens_provider(&self, selector:DocumentSelector) -> Disposable {
479 self.register("semanticTokens", &selector)
480 }
481
482 pub fn register_inlay_hints_provider(&self, selector:DocumentSelector) -> Disposable {
484 self.register("inlayHints", &selector)
485 }
486
487 pub fn register_type_hierarchy_provider(&self, selector:DocumentSelector) -> Disposable {
489 self.register("typeHierarchy", &selector)
490 }
491
492 pub fn register_call_hierarchy_provider(&self, selector:DocumentSelector) -> Disposable {
494 self.register("callHierarchy", &selector)
495 }
496
497 pub fn register_linked_editing_range_provider(&self, selector:DocumentSelector) -> Disposable {
499 self.register("linkedEditingRange", &selector)
500 }
501
502 pub fn register_declaration_provider(&self, selector:DocumentSelector) -> Disposable {
504 self.register("declaration", &selector)
505 }
506
507 pub fn register_implementation_provider(&self, selector:DocumentSelector) -> Disposable {
509 self.register("implementation", &selector)
510 }
511
512 pub fn register_type_definition_provider(&self, selector:DocumentSelector) -> Disposable {
514 self.register("typeDefinition", &selector)
515 }
516
517 pub fn create_diagnostic_collection(&self, name:Option<String>) -> DiagnosticCollection {
519 DiagnosticCollection::new(name)
520 }
521
522 pub fn set_language_configuration(&self, language:String) -> Disposable {
524 self.register(
525 "languageConfiguration",
526 &vec![DocumentFilter { language:Some(language), scheme:None, pattern:None }],
527 )
528 }
529}
530
531#[derive(Debug, Clone, Serialize, Deserialize)]
533pub struct DocumentFilter {
534 pub language:Option<String>,
536
537 pub scheme:Option<String>,
539
540 pub pattern:Option<String>,
542}
543
544pub type DocumentSelector = Vec<DocumentFilter>;
546
547pub trait CompletionItemProvider: Send + Sync {
549 fn provide_completion_items(
562 &self,
563
564 document:TextDocumentIdentifier,
565
566 position:Position,
567
568 context:CompletionContext,
569
570 token:Option<String>,
571 ) -> Vec<CompletionItem>;
572}
573
574#[derive(Debug, Clone, Serialize, Deserialize)]
576pub struct CompletionContext {
577 #[serde(rename = "triggerKind")]
579 pub trigger_kind:CompletionTriggerKind,
580
581 #[serde(rename = "triggerCharacter")]
583 pub trigger_character:Option<String>,
584}
585
586#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
588pub enum CompletionTriggerKind {
589 #[serde(rename = "Invoke")]
591 Invoke = 0,
592
593 #[serde(rename = "TriggerCharacter")]
595 TriggerCharacter = 1,
596
597 #[serde(rename = "TriggerForIncompleteCompletions")]
599 TriggerForIncompleteCompletions = 2,
600}
601
602#[derive(Debug, Clone)]
604pub struct DiagnosticCollection {
605 #[allow(dead_code)]
607 name:Option<String>,
608}
609
610impl DiagnosticCollection {
611 pub fn new(name:Option<String>) -> Self { Self { name } }
617
618 pub fn set(&self, _uri:String, _diagnostics:Vec<Diagnostic>) {
620
621 }
623
624 pub fn delete(&self, _uri:String) {
626
627 }
629
630 pub fn clear(&self) {
632
633 }
635
636 pub fn dispose(&self) {
638
639 }
641}
642
643pub struct Disposable {
648 callback:Option<Box<dyn FnOnce() + Send + Sync>>,
649}
650
651impl std::fmt::Debug for Disposable {
652 fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result {
653 f.debug_struct("Disposable")
654 .field("has_callback", &self.callback.is_some())
655 .finish()
656 }
657}
658
659impl Clone for Disposable {
660 fn clone(&self) -> Self { Self { callback:None } }
663}
664
665impl Disposable {
666 pub fn new() -> Self { Self { callback:None } }
668
669 pub fn with_callback(callback:Box<dyn FnOnce() + Send + Sync>) -> Self { Self { callback:Some(callback) } }
671
672 pub fn dispose(mut self) {
674 if let Some(Callback) = self.callback.take() {
675 Callback();
676 }
677 }
678}
679
680impl Default for Disposable {
681 fn default() -> Self { Self::new() }
682}
683
684#[derive(Debug, Clone)]
686pub struct ExtensionNamespace;
687
688impl ExtensionNamespace {
689 pub fn new() -> Self { Self }
691
692 pub fn all(&self) -> Vec<Extension> { Vec::new() }
694
695 pub fn get_extension(&self, _extension_id:String) -> Option<Extension> { None }
697}
698
699#[derive(Debug, Clone, Serialize, Deserialize)]
701pub struct Extension {
702 pub id:String,
704
705 #[serde(rename = "extensionPath")]
707 pub extension_path:String,
708
709 pub is_active:bool,
711
712 #[serde(rename = "packageJSON")]
714 pub package_json:serde_json::Value,
715}
716
717#[derive(Debug, Clone)]
719pub struct Env;
720
721impl Env {
722 pub fn new() -> Self { Self }
724
725 pub fn get_env_var(&self, name:String) -> Option<String> { std::env::var(name).ok() }
727
728 pub fn is_windows(&self) -> bool { cfg!(windows) }
730
731 pub fn is_mac(&self) -> bool { cfg!(target_os = "macos") }
733
734 pub fn is_linux(&self) -> bool { cfg!(target_os = "linux") }
736
737 pub fn app_name(&self) -> String { "VS Code".to_string() }
739
740 pub fn app_root(&self) -> Option<String> { std::env::var("VSCODE_APP_ROOT").ok() }
742}
743
744#[cfg(test)]
745mod tests {
746
747 use super::*;
748
749 #[test]
750 fn test_vscode_api_creation() {
751 let _api = VSCodeAPI::new();
752
753 }
755
756 #[test]
757 fn test_position_operations() {
758 let pos = Position::new(5, 10);
759
760 assert_eq!(pos.line, 5);
761
762 assert_eq!(pos.character, 10);
763 }
764
765 #[test]
766 fn test_output_channel() {
767 let channel = OutputChannel::new("test".to_string());
768
769 channel.append_line("test message");
770 }
771
772 #[test]
773 fn test_disposable() {
774 let disposable = Disposable::new();
775
776 disposable.dispose();
777 }
778}