1use std::sync::{
8 Arc,
9 Mutex,
10 atomic::{AtomicU32, Ordering},
11};
12
13use serde::{Deserialize, Serialize};
14
15use crate::API::types::*;
16
17#[derive(Debug, Default)]
26struct ProviderStore {
27 entries:Mutex<std::collections::HashMap<u32, (String, String)>>,
29 next_handle:AtomicU32,
31}
32
33impl ProviderStore {
34 fn insert(&self, provider_type:&str, selector:&str) -> u32 {
36 let Handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
37 if let Ok(mut Guard) = self.entries.lock() {
38 Guard.insert(Handle, (provider_type.to_string(), selector.to_string()));
39 }
40 Handle
41 }
42
43 fn remove(&self, handle:u32) {
45 if let Ok(mut Guard) = self.entries.lock() {
46 Guard.remove(&handle);
47 }
48 }
49
50 #[allow(dead_code)]
52 fn len(&self) -> usize {
53 self.entries
54 .lock()
55 .map(|G| G.len())
56 .unwrap_or(0)
57 }
58}
59
60#[derive(Debug, Clone)]
62pub struct VSCodeAPI {
63 pub commands:Arc<CommandNamespace>,
65 pub window:Arc<Window>,
67 pub workspace:Arc<Workspace>,
69 pub languages:Arc<LanguageNamespace>,
71 pub extensions:Arc<ExtensionNamespace>,
73 pub env:Arc<Env>,
75}
76
77impl VSCodeAPI {
78 pub fn new() -> Self {
80 Self {
81 commands:Arc::new(CommandNamespace::new()),
82 window:Arc::new(Window::new()),
83 workspace:Arc::new(Workspace::new()),
84 languages:Arc::new(LanguageNamespace::new()),
85 extensions:Arc::new(ExtensionNamespace::new()),
86 env:Arc::new(Env::new()),
87 }
88 }
89}
90
91impl Default for VSCodeAPI {
92 fn default() -> Self { Self::new() }
93}
94
95#[derive(Debug, Clone)]
97pub struct CommandNamespace;
98
99impl CommandNamespace {
100 pub fn new() -> Self { Self }
102
103 pub fn register_command(&self, command_id:String, _callback:CommandCallback) -> Result<Command, String> {
105 Ok(Command { id:command_id.clone() })
106 }
107
108 pub async fn execute_command<T:serde::de::DeserializeOwned>(
110 &self,
111 command_id:String,
112 _args:Vec<serde_json::Value>,
113 ) -> Result<T, String> {
114 Err(format!("Command not implemented: {}", command_id))
116 }
117}
118
119pub type CommandCallback = Box<dyn Fn(Vec<serde_json::Value>) -> Result<serde_json::Value, String> + Send + Sync>;
121
122#[derive(Debug, Clone)]
124pub struct Command {
125 pub id:String,
127}
128
129#[derive(Debug, Clone)]
131pub struct Window;
132
133impl Window {
134 pub fn new() -> Self { Self }
136
137 pub async fn show_information_message(&self, _message:String) -> Result<String, String> {
139 Ok("OK".to_string())
141 }
142
143 pub async fn show_warning_message(&self, _message:String) -> Result<String, String> {
145 Ok("OK".to_string())
147 }
148
149 pub async fn show_error_message(&self, _message:String) -> Result<String, String> {
151 Ok("OK".to_string())
153 }
154
155 pub fn create_output_channel(&self, name:String) -> OutputChannel { OutputChannel::new(name) }
157}
158
159#[derive(Debug, Clone)]
161pub struct OutputChannel {
162 name:String,
164}
165
166impl OutputChannel {
167 pub fn new(name:String) -> Self { Self { name } }
173
174 pub fn append_line(&self, line:&str) {
176 tracing::info!("[{}] {}", self.name, line);
177 }
178
179 pub fn append(&self, value:&str) {
181 tracing::info!("[{}] {}", self.name, value);
182 }
183
184 pub fn show(&self) {
186 }
188
189 pub fn hide(&self) {
191 }
193
194 pub fn dispose(&self) {
196 }
198}
199
200#[derive(Debug, Clone)]
202pub struct Workspace;
203
204impl Workspace {
205 pub fn new() -> Self { Self }
207
208 pub fn workspace_folders(&self) -> Vec<WorkspaceFolder> {
210 Vec::new()
212 }
213
214 pub fn get_configuration(&self, section:Option<String>) -> WorkspaceConfiguration {
216 WorkspaceConfiguration::new(section)
217 }
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct WorkspaceFolder {
223 pub uri:String,
225
226 pub name:String,
228
229 pub index:u32,
231}
232
233#[derive(Debug, Clone)]
235pub struct WorkspaceConfiguration {
236 #[allow(dead_code)]
238 section:Option<String>,
239}
240
241impl WorkspaceConfiguration {
242 pub fn new(section:Option<String>) -> Self { Self { section } }
248
249 pub fn get<T:serde::de::DeserializeOwned>(&self, _key:String) -> Result<T, String> {
251 Err("Configuration not implemented".to_string())
253 }
254
255 pub fn has(&self, _key:String) -> bool { false }
257
258 pub async fn update(&self, _key:String, _value:serde_json::Value) -> Result<(), String> {
260 Err("Update configuration not implemented".to_string())
262 }
263}
264
265#[derive(Debug)]
276pub struct LanguageNamespace {
277 store:Arc<ProviderStore>,
279}
280
281impl Clone for LanguageNamespace {
282 fn clone(&self) -> Self { Self { store:Arc::clone(&self.store) } }
283}
284
285impl LanguageNamespace {
286 pub fn new() -> Self { Self { store:Arc::new(ProviderStore::default()) } }
288
289 pub fn active_registration_count(&self) -> usize { self.store.len() }
291
292 fn register(&self, provider_type:&str, selector:&DocumentSelector) -> Disposable {
294 let SelectorStr = selector
295 .iter()
296 .filter_map(|F| F.language.as_deref())
297 .collect::<Vec<_>>()
298 .join(",");
299 let Handle = self.store.insert(provider_type, &SelectorStr);
300 let Store = Arc::clone(&self.store);
301 tracing::debug!("[LanguageNamespace] registered {} handle={} selector={}", provider_type, Handle, SelectorStr);
302 Disposable::with_callback(Box::new(move || {
303 Store.remove(Handle);
304 tracing::debug!("[LanguageNamespace] disposed {} handle={}", provider_type, Handle);
305 }))
306 }
307
308 pub async fn register_completion_item_provider<T:CompletionItemProvider>(
310 &self,
311 selector:DocumentSelector,
312 _provider:T,
313 _trigger_characters:Option<Vec<String>>,
314 ) -> Result<Disposable, String> {
315 Ok(self.register("completion", &selector))
316 }
317
318 pub fn register_hover_provider(&self, selector:DocumentSelector) -> Disposable {
320 self.register("hover", &selector)
321 }
322
323 pub fn register_definition_provider(&self, selector:DocumentSelector) -> Disposable {
325 self.register("definition", &selector)
326 }
327
328 pub fn register_reference_provider(&self, selector:DocumentSelector) -> Disposable {
330 self.register("references", &selector)
331 }
332
333 pub fn register_code_actions_provider(&self, selector:DocumentSelector) -> Disposable {
335 self.register("codeAction", &selector)
336 }
337
338 pub fn register_document_highlight_provider(&self, selector:DocumentSelector) -> Disposable {
340 self.register("documentHighlight", &selector)
341 }
342
343 pub fn register_document_symbol_provider(&self, selector:DocumentSelector) -> Disposable {
345 self.register("documentSymbol", &selector)
346 }
347
348 pub fn register_workspace_symbol_provider(&self) -> Disposable {
350 self.register("workspaceSymbol", &Vec::new())
351 }
352
353 pub fn register_rename_provider(&self, selector:DocumentSelector) -> Disposable {
355 self.register("rename", &selector)
356 }
357
358 pub fn register_document_formatting_edit_provider(&self, selector:DocumentSelector) -> Disposable {
360 self.register("documentFormatting", &selector)
361 }
362
363 pub fn register_document_range_formatting_edit_provider(&self, selector:DocumentSelector) -> Disposable {
365 self.register("documentRangeFormatting", &selector)
366 }
367
368 pub fn register_on_type_formatting_edit_provider(
370 &self,
371 selector:DocumentSelector,
372 _trigger_characters:Vec<String>,
373 ) -> Disposable {
374 self.register("onTypeFormatting", &selector)
375 }
376
377 pub fn register_signature_help_provider(&self, selector:DocumentSelector) -> Disposable {
379 self.register("signatureHelp", &selector)
380 }
381
382 pub fn register_code_lens_provider(&self, selector:DocumentSelector) -> Disposable {
384 self.register("codeLens", &selector)
385 }
386
387 pub fn register_folding_range_provider(&self, selector:DocumentSelector) -> Disposable {
389 self.register("foldingRange", &selector)
390 }
391
392 pub fn register_selection_range_provider(&self, selector:DocumentSelector) -> Disposable {
394 self.register("selectionRange", &selector)
395 }
396
397 pub fn register_document_semantic_tokens_provider(&self, selector:DocumentSelector) -> Disposable {
399 self.register("semanticTokens", &selector)
400 }
401
402 pub fn register_inlay_hints_provider(&self, selector:DocumentSelector) -> Disposable {
404 self.register("inlayHints", &selector)
405 }
406
407 pub fn register_type_hierarchy_provider(&self, selector:DocumentSelector) -> Disposable {
409 self.register("typeHierarchy", &selector)
410 }
411
412 pub fn register_call_hierarchy_provider(&self, selector:DocumentSelector) -> Disposable {
414 self.register("callHierarchy", &selector)
415 }
416
417 pub fn register_linked_editing_range_provider(&self, selector:DocumentSelector) -> Disposable {
419 self.register("linkedEditingRange", &selector)
420 }
421
422 pub fn register_declaration_provider(&self, selector:DocumentSelector) -> Disposable {
424 self.register("declaration", &selector)
425 }
426
427 pub fn register_implementation_provider(&self, selector:DocumentSelector) -> Disposable {
429 self.register("implementation", &selector)
430 }
431
432 pub fn register_type_definition_provider(&self, selector:DocumentSelector) -> Disposable {
434 self.register("typeDefinition", &selector)
435 }
436
437 pub fn create_diagnostic_collection(&self, name:Option<String>) -> DiagnosticCollection {
439 DiagnosticCollection::new(name)
440 }
441
442 pub fn set_language_configuration(&self, language:String) -> Disposable {
444 self.register("languageConfiguration", &vec![DocumentFilter { language:Some(language), scheme:None, pattern:None }])
445 }
446}
447
448#[derive(Debug, Clone, Serialize, Deserialize)]
450pub struct DocumentFilter {
451 pub language:Option<String>,
453
454 pub scheme:Option<String>,
456
457 pub pattern:Option<String>,
459}
460
461pub type DocumentSelector = Vec<DocumentFilter>;
463
464pub trait CompletionItemProvider: Send + Sync {
466 fn provide_completion_items(
479 &self,
480 document:TextDocumentIdentifier,
481 position:Position,
482 context:CompletionContext,
483 token:Option<String>,
484 ) -> Vec<CompletionItem>;
485}
486
487#[derive(Debug, Clone, Serialize, Deserialize)]
489pub struct CompletionContext {
490 #[serde(rename = "triggerKind")]
492 pub trigger_kind:CompletionTriggerKind,
493
494 #[serde(rename = "triggerCharacter")]
496 pub trigger_character:Option<String>,
497}
498
499#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
501pub enum CompletionTriggerKind {
502 #[serde(rename = "Invoke")]
504 Invoke = 0,
505
506 #[serde(rename = "TriggerCharacter")]
508 TriggerCharacter = 1,
509
510 #[serde(rename = "TriggerForIncompleteCompletions")]
512 TriggerForIncompleteCompletions = 2,
513}
514
515#[derive(Debug, Clone)]
517pub struct DiagnosticCollection {
518 #[allow(dead_code)]
520 name:Option<String>,
521}
522
523impl DiagnosticCollection {
524 pub fn new(name:Option<String>) -> Self { Self { name } }
530
531 pub fn set(&self, _uri:String, _diagnostics:Vec<Diagnostic>) {
533 }
535
536 pub fn delete(&self, _uri:String) {
538 }
540
541 pub fn clear(&self) {
543 }
545
546 pub fn dispose(&self) {
548 }
550}
551
552pub struct Disposable {
557 callback:Option<Box<dyn FnOnce() + Send + Sync>>,
558}
559
560impl std::fmt::Debug for Disposable {
561 fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result {
562 f.debug_struct("Disposable").field("has_callback", &self.callback.is_some()).finish()
563 }
564}
565
566impl Clone for Disposable {
567 fn clone(&self) -> Self { Self { callback:None } }
570}
571
572impl Disposable {
573 pub fn new() -> Self { Self { callback:None } }
575
576 pub fn with_callback(callback:Box<dyn FnOnce() + Send + Sync>) -> Self {
578 Self { callback:Some(callback) }
579 }
580
581 pub fn dispose(mut self) {
583 if let Some(Callback) = self.callback.take() {
584 Callback();
585 }
586 }
587}
588
589impl Default for Disposable {
590 fn default() -> Self { Self::new() }
591}
592
593#[derive(Debug, Clone)]
595pub struct ExtensionNamespace;
596
597impl ExtensionNamespace {
598 pub fn new() -> Self { Self }
600
601 pub fn all(&self) -> Vec<Extension> { Vec::new() }
603
604 pub fn get_extension(&self, _extension_id:String) -> Option<Extension> { None }
606}
607
608#[derive(Debug, Clone, Serialize, Deserialize)]
610pub struct Extension {
611 pub id:String,
613
614 #[serde(rename = "extensionPath")]
616 pub extension_path:String,
617
618 pub is_active:bool,
620
621 #[serde(rename = "packageJSON")]
623 pub package_json:serde_json::Value,
624}
625
626#[derive(Debug, Clone)]
628pub struct Env;
629
630impl Env {
631 pub fn new() -> Self { Self }
633
634 pub fn get_env_var(&self, name:String) -> Option<String> { std::env::var(name).ok() }
636
637 pub fn is_windows(&self) -> bool { cfg!(windows) }
639
640 pub fn is_mac(&self) -> bool { cfg!(target_os = "macos") }
642
643 pub fn is_linux(&self) -> bool { cfg!(target_os = "linux") }
645
646 pub fn app_name(&self) -> String { "VS Code".to_string() }
648
649 pub fn app_root(&self) -> Option<String> { std::env::var("VSCODE_APP_ROOT").ok() }
651}
652
653#[cfg(test)]
654mod tests {
655 use super::*;
656
657 #[test]
658 fn test_vscode_api_creation() {
659 let _api = VSCodeAPI::new();
660 }
662
663 #[test]
664 fn test_position_operations() {
665 let pos = Position::new(5, 10);
666 assert_eq!(pos.line, 5);
667 assert_eq!(pos.character, 10);
668 }
669
670 #[test]
671 fn test_output_channel() {
672 let channel = OutputChannel::new("test".to_string());
673 channel.append_line("test message");
674 }
675
676 #[test]
677 fn test_disposable() {
678 let disposable = Disposable::new();
679 disposable.dispose();
680 }
681}