1mod since_v0_0_1;
2mod since_v0_0_4;
3mod since_v0_0_6;
4mod since_v0_1_0;
5mod since_v0_2_0;
6mod since_v0_3_0;
7mod since_v0_4_0;
8mod since_v0_5_0;
9mod since_v0_6_0;
10use dap::DebugRequest;
11use extension::{DebugTaskDefinition, KeyValueStoreDelegate, WorktreeDelegate};
12use gpui::BackgroundExecutor;
13use language::LanguageName;
14use lsp::LanguageServerName;
15use release_channel::ReleaseChannel;
16use task::{DebugScenario, SpawnInTerminal, TaskTemplate, ZedDebugConfig};
17
18use crate::wasm_host::wit::since_v0_6_0::dap::StartDebuggingRequestArgumentsRequest;
19
20use super::{WasmState, wasm_engine};
21use anyhow::{Context as _, Result, anyhow};
22use semantic_version::SemanticVersion;
23use since_v0_6_0 as latest;
24use std::{ops::RangeInclusive, path::PathBuf, sync::Arc};
25use wasmtime::{
26 Store,
27 component::{Component, Linker, Resource},
28};
29
30#[cfg(test)]
31pub use latest::CodeLabelSpanLiteral;
32pub use latest::{
33 CodeLabel, CodeLabelSpan, Command, DebugAdapterBinary, ExtensionProject, Range, SlashCommand,
34 zed::extension::context_server::ContextServerConfiguration,
35 zed::extension::lsp::{
36 Completion, CompletionKind, CompletionLabelDetails, InsertTextFormat, Symbol, SymbolKind,
37 },
38 zed::extension::slash_command::{SlashCommandArgumentCompletion, SlashCommandOutput},
39};
40pub use since_v0_0_4::LanguageServerConfig;
41
42pub fn new_linker(
43 executor: &BackgroundExecutor,
44 f: impl Fn(&mut Linker<WasmState>, fn(&mut WasmState) -> &mut WasmState) -> Result<()>,
45) -> Linker<WasmState> {
46 let mut linker = Linker::new(&wasm_engine(executor));
47 wasmtime_wasi::add_to_linker_async(&mut linker).unwrap();
48 f(&mut linker, wasi_view).unwrap();
49 linker
50}
51
52fn wasi_view(state: &mut WasmState) -> &mut WasmState {
53 state
54}
55
56/// Returns whether the given Wasm API version is supported by the Wasm host.
57pub fn is_supported_wasm_api_version(
58 release_channel: ReleaseChannel,
59 version: SemanticVersion,
60) -> bool {
61 wasm_api_version_range(release_channel).contains(&version)
62}
63
64/// Returns the Wasm API version range that is supported by the Wasm host.
65#[inline(always)]
66pub fn wasm_api_version_range(release_channel: ReleaseChannel) -> RangeInclusive<SemanticVersion> {
67 // Note: The release channel can be used to stage a new version of the extension API.
68 let _ = release_channel;
69
70 let max_version = match release_channel {
71 ReleaseChannel::Dev | ReleaseChannel::Nightly => latest::MAX_VERSION,
72 ReleaseChannel::Stable | ReleaseChannel::Preview => latest::MAX_VERSION,
73 };
74
75 since_v0_0_1::MIN_VERSION..=max_version
76}
77
78/// Authorizes access to use unreleased versions of the Wasm API, based on the provided [`ReleaseChannel`].
79///
80/// Note: If there isn't currently an unreleased Wasm API version this function may be unused. Don't delete it!
81pub fn authorize_access_to_unreleased_wasm_api_version(
82 release_channel: ReleaseChannel,
83) -> Result<()> {
84 let allow_unreleased_version = match release_channel {
85 ReleaseChannel::Dev | ReleaseChannel::Nightly => true,
86 ReleaseChannel::Stable | ReleaseChannel::Preview => {
87 // We always allow the latest in tests so that the extension tests pass on release branches.
88 cfg!(any(test, feature = "test-support"))
89 }
90 };
91
92 anyhow::ensure!(
93 allow_unreleased_version,
94 "unreleased versions of the extension API can only be used on development builds of Zed"
95 );
96
97 Ok(())
98}
99
100pub enum Extension {
101 V0_6_0(since_v0_6_0::Extension),
102 V0_5_0(since_v0_5_0::Extension),
103 V0_4_0(since_v0_4_0::Extension),
104 V0_3_0(since_v0_3_0::Extension),
105 V0_2_0(since_v0_2_0::Extension),
106 V0_1_0(since_v0_1_0::Extension),
107 V0_0_6(since_v0_0_6::Extension),
108 V0_0_4(since_v0_0_4::Extension),
109 V0_0_1(since_v0_0_1::Extension),
110}
111
112impl Extension {
113 pub async fn instantiate_async(
114 executor: &BackgroundExecutor,
115 store: &mut Store<WasmState>,
116 release_channel: ReleaseChannel,
117 version: SemanticVersion,
118 component: &Component,
119 ) -> Result<Self> {
120 // Note: The release channel can be used to stage a new version of the extension API.
121 let _ = release_channel;
122
123 if version >= latest::MIN_VERSION {
124 let extension =
125 latest::Extension::instantiate_async(store, component, latest::linker(executor))
126 .await
127 .context("failed to instantiate wasm extension")?;
128 Ok(Self::V0_6_0(extension))
129 } else if version >= since_v0_5_0::MIN_VERSION {
130 let extension = since_v0_5_0::Extension::instantiate_async(
131 store,
132 component,
133 since_v0_5_0::linker(executor),
134 )
135 .await
136 .context("failed to instantiate wasm extension")?;
137 Ok(Self::V0_5_0(extension))
138 } else if version >= since_v0_4_0::MIN_VERSION {
139 let extension = since_v0_4_0::Extension::instantiate_async(
140 store,
141 component,
142 since_v0_4_0::linker(executor),
143 )
144 .await
145 .context("failed to instantiate wasm extension")?;
146 Ok(Self::V0_4_0(extension))
147 } else if version >= since_v0_3_0::MIN_VERSION {
148 let extension = since_v0_3_0::Extension::instantiate_async(
149 store,
150 component,
151 since_v0_3_0::linker(executor),
152 )
153 .await
154 .context("failed to instantiate wasm extension")?;
155 Ok(Self::V0_3_0(extension))
156 } else if version >= since_v0_2_0::MIN_VERSION {
157 let extension = since_v0_2_0::Extension::instantiate_async(
158 store,
159 component,
160 since_v0_2_0::linker(executor),
161 )
162 .await
163 .context("failed to instantiate wasm extension")?;
164 Ok(Self::V0_2_0(extension))
165 } else if version >= since_v0_1_0::MIN_VERSION {
166 let extension = since_v0_1_0::Extension::instantiate_async(
167 store,
168 component,
169 since_v0_1_0::linker(executor),
170 )
171 .await
172 .context("failed to instantiate wasm extension")?;
173 Ok(Self::V0_1_0(extension))
174 } else if version >= since_v0_0_6::MIN_VERSION {
175 let extension = since_v0_0_6::Extension::instantiate_async(
176 store,
177 component,
178 since_v0_0_6::linker(executor),
179 )
180 .await
181 .context("failed to instantiate wasm extension")?;
182 Ok(Self::V0_0_6(extension))
183 } else if version >= since_v0_0_4::MIN_VERSION {
184 let extension = since_v0_0_4::Extension::instantiate_async(
185 store,
186 component,
187 since_v0_0_4::linker(executor),
188 )
189 .await
190 .context("failed to instantiate wasm extension")?;
191 Ok(Self::V0_0_4(extension))
192 } else {
193 let extension = since_v0_0_1::Extension::instantiate_async(
194 store,
195 component,
196 since_v0_0_1::linker(executor),
197 )
198 .await
199 .context("failed to instantiate wasm extension")?;
200 Ok(Self::V0_0_1(extension))
201 }
202 }
203
204 pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
205 match self {
206 Extension::V0_6_0(ext) => ext.call_init_extension(store).await,
207 Extension::V0_5_0(ext) => ext.call_init_extension(store).await,
208 Extension::V0_4_0(ext) => ext.call_init_extension(store).await,
209 Extension::V0_3_0(ext) => ext.call_init_extension(store).await,
210 Extension::V0_2_0(ext) => ext.call_init_extension(store).await,
211 Extension::V0_1_0(ext) => ext.call_init_extension(store).await,
212 Extension::V0_0_6(ext) => ext.call_init_extension(store).await,
213 Extension::V0_0_4(ext) => ext.call_init_extension(store).await,
214 Extension::V0_0_1(ext) => ext.call_init_extension(store).await,
215 }
216 }
217
218 pub async fn call_language_server_command(
219 &self,
220 store: &mut Store<WasmState>,
221 language_server_id: &LanguageServerName,
222 language_name: &LanguageName,
223 resource: Resource<Arc<dyn WorktreeDelegate>>,
224 ) -> Result<Result<Command, String>> {
225 match self {
226 Extension::V0_6_0(ext) => {
227 ext.call_language_server_command(store, &language_server_id.0, resource)
228 .await
229 }
230 Extension::V0_5_0(ext) => {
231 ext.call_language_server_command(store, &language_server_id.0, resource)
232 .await
233 }
234 Extension::V0_4_0(ext) => {
235 ext.call_language_server_command(store, &language_server_id.0, resource)
236 .await
237 }
238 Extension::V0_3_0(ext) => {
239 ext.call_language_server_command(store, &language_server_id.0, resource)
240 .await
241 }
242 Extension::V0_2_0(ext) => Ok(ext
243 .call_language_server_command(store, &language_server_id.0, resource)
244 .await?
245 .map(|command| command.into())),
246 Extension::V0_1_0(ext) => Ok(ext
247 .call_language_server_command(store, &language_server_id.0, resource)
248 .await?
249 .map(|command| command.into())),
250 Extension::V0_0_6(ext) => Ok(ext
251 .call_language_server_command(store, &language_server_id.0, resource)
252 .await?
253 .map(|command| command.into())),
254 Extension::V0_0_4(ext) => Ok(ext
255 .call_language_server_command(
256 store,
257 &LanguageServerConfig {
258 name: language_server_id.0.to_string(),
259 language_name: language_name.to_string(),
260 },
261 resource,
262 )
263 .await?
264 .map(|command| command.into())),
265 Extension::V0_0_1(ext) => Ok(ext
266 .call_language_server_command(
267 store,
268 &LanguageServerConfig {
269 name: language_server_id.0.to_string(),
270 language_name: language_name.to_string(),
271 }
272 .into(),
273 resource,
274 )
275 .await?
276 .map(|command| command.into())),
277 }
278 }
279
280 pub async fn call_language_server_initialization_options(
281 &self,
282 store: &mut Store<WasmState>,
283 language_server_id: &LanguageServerName,
284 language_name: &LanguageName,
285 resource: Resource<Arc<dyn WorktreeDelegate>>,
286 ) -> Result<Result<Option<String>, String>> {
287 match self {
288 Extension::V0_6_0(ext) => {
289 ext.call_language_server_initialization_options(
290 store,
291 &language_server_id.0,
292 resource,
293 )
294 .await
295 }
296 Extension::V0_5_0(ext) => {
297 ext.call_language_server_initialization_options(
298 store,
299 &language_server_id.0,
300 resource,
301 )
302 .await
303 }
304 Extension::V0_4_0(ext) => {
305 ext.call_language_server_initialization_options(
306 store,
307 &language_server_id.0,
308 resource,
309 )
310 .await
311 }
312 Extension::V0_3_0(ext) => {
313 ext.call_language_server_initialization_options(
314 store,
315 &language_server_id.0,
316 resource,
317 )
318 .await
319 }
320 Extension::V0_2_0(ext) => {
321 ext.call_language_server_initialization_options(
322 store,
323 &language_server_id.0,
324 resource,
325 )
326 .await
327 }
328 Extension::V0_1_0(ext) => {
329 ext.call_language_server_initialization_options(
330 store,
331 &language_server_id.0,
332 resource,
333 )
334 .await
335 }
336 Extension::V0_0_6(ext) => {
337 ext.call_language_server_initialization_options(
338 store,
339 &language_server_id.0,
340 resource,
341 )
342 .await
343 }
344 Extension::V0_0_4(ext) => {
345 ext.call_language_server_initialization_options(
346 store,
347 &LanguageServerConfig {
348 name: language_server_id.0.to_string(),
349 language_name: language_name.to_string(),
350 },
351 resource,
352 )
353 .await
354 }
355 Extension::V0_0_1(ext) => {
356 ext.call_language_server_initialization_options(
357 store,
358 &LanguageServerConfig {
359 name: language_server_id.0.to_string(),
360 language_name: language_name.to_string(),
361 }
362 .into(),
363 resource,
364 )
365 .await
366 }
367 }
368 }
369
370 pub async fn call_language_server_workspace_configuration(
371 &self,
372 store: &mut Store<WasmState>,
373 language_server_id: &LanguageServerName,
374 resource: Resource<Arc<dyn WorktreeDelegate>>,
375 ) -> Result<Result<Option<String>, String>> {
376 match self {
377 Extension::V0_6_0(ext) => {
378 ext.call_language_server_workspace_configuration(
379 store,
380 &language_server_id.0,
381 resource,
382 )
383 .await
384 }
385 Extension::V0_5_0(ext) => {
386 ext.call_language_server_workspace_configuration(
387 store,
388 &language_server_id.0,
389 resource,
390 )
391 .await
392 }
393 Extension::V0_4_0(ext) => {
394 ext.call_language_server_workspace_configuration(
395 store,
396 &language_server_id.0,
397 resource,
398 )
399 .await
400 }
401 Extension::V0_3_0(ext) => {
402 ext.call_language_server_workspace_configuration(
403 store,
404 &language_server_id.0,
405 resource,
406 )
407 .await
408 }
409 Extension::V0_2_0(ext) => {
410 ext.call_language_server_workspace_configuration(
411 store,
412 &language_server_id.0,
413 resource,
414 )
415 .await
416 }
417 Extension::V0_1_0(ext) => {
418 ext.call_language_server_workspace_configuration(
419 store,
420 &language_server_id.0,
421 resource,
422 )
423 .await
424 }
425 Extension::V0_0_6(ext) => {
426 ext.call_language_server_workspace_configuration(
427 store,
428 &language_server_id.0,
429 resource,
430 )
431 .await
432 }
433 Extension::V0_0_4(_) | Extension::V0_0_1(_) => Ok(Ok(None)),
434 }
435 }
436
437 pub async fn call_language_server_additional_initialization_options(
438 &self,
439 store: &mut Store<WasmState>,
440 language_server_id: &LanguageServerName,
441 target_language_server_id: &LanguageServerName,
442 resource: Resource<Arc<dyn WorktreeDelegate>>,
443 ) -> Result<Result<Option<String>, String>> {
444 match self {
445 Extension::V0_6_0(ext) => {
446 ext.call_language_server_additional_initialization_options(
447 store,
448 &language_server_id.0,
449 &target_language_server_id.0,
450 resource,
451 )
452 .await
453 }
454 Extension::V0_5_0(ext) => {
455 ext.call_language_server_additional_initialization_options(
456 store,
457 &language_server_id.0,
458 &target_language_server_id.0,
459 resource,
460 )
461 .await
462 }
463 Extension::V0_4_0(ext) => {
464 ext.call_language_server_additional_initialization_options(
465 store,
466 &language_server_id.0,
467 &target_language_server_id.0,
468 resource,
469 )
470 .await
471 }
472 Extension::V0_3_0(_)
473 | Extension::V0_2_0(_)
474 | Extension::V0_1_0(_)
475 | Extension::V0_0_6(_)
476 | Extension::V0_0_4(_)
477 | Extension::V0_0_1(_) => Ok(Ok(None)),
478 }
479 }
480
481 pub async fn call_language_server_additional_workspace_configuration(
482 &self,
483 store: &mut Store<WasmState>,
484 language_server_id: &LanguageServerName,
485 target_language_server_id: &LanguageServerName,
486 resource: Resource<Arc<dyn WorktreeDelegate>>,
487 ) -> Result<Result<Option<String>, String>> {
488 match self {
489 Extension::V0_6_0(ext) => {
490 ext.call_language_server_additional_workspace_configuration(
491 store,
492 &language_server_id.0,
493 &target_language_server_id.0,
494 resource,
495 )
496 .await
497 }
498 Extension::V0_5_0(ext) => {
499 ext.call_language_server_additional_workspace_configuration(
500 store,
501 &language_server_id.0,
502 &target_language_server_id.0,
503 resource,
504 )
505 .await
506 }
507 Extension::V0_4_0(ext) => {
508 ext.call_language_server_additional_workspace_configuration(
509 store,
510 &language_server_id.0,
511 &target_language_server_id.0,
512 resource,
513 )
514 .await
515 }
516 Extension::V0_3_0(_)
517 | Extension::V0_2_0(_)
518 | Extension::V0_1_0(_)
519 | Extension::V0_0_6(_)
520 | Extension::V0_0_4(_)
521 | Extension::V0_0_1(_) => Ok(Ok(None)),
522 }
523 }
524
525 pub async fn call_labels_for_completions(
526 &self,
527 store: &mut Store<WasmState>,
528 language_server_id: &LanguageServerName,
529 completions: Vec<latest::Completion>,
530 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
531 match self {
532 Extension::V0_6_0(ext) => {
533 ext.call_labels_for_completions(store, &language_server_id.0, &completions)
534 .await
535 }
536 Extension::V0_5_0(ext) => Ok(ext
537 .call_labels_for_completions(
538 store,
539 &language_server_id.0,
540 &completions.into_iter().collect::<Vec<_>>(),
541 )
542 .await?
543 .map(|labels| {
544 labels
545 .into_iter()
546 .map(|label| label.map(Into::into))
547 .collect()
548 })),
549 Extension::V0_4_0(ext) => Ok(ext
550 .call_labels_for_completions(
551 store,
552 &language_server_id.0,
553 &completions.into_iter().collect::<Vec<_>>(),
554 )
555 .await?
556 .map(|labels| {
557 labels
558 .into_iter()
559 .map(|label| label.map(Into::into))
560 .collect()
561 })),
562 Extension::V0_3_0(ext) => Ok(ext
563 .call_labels_for_completions(
564 store,
565 &language_server_id.0,
566 &completions.into_iter().collect::<Vec<_>>(),
567 )
568 .await?
569 .map(|labels| {
570 labels
571 .into_iter()
572 .map(|label| label.map(Into::into))
573 .collect()
574 })),
575 Extension::V0_2_0(ext) => Ok(ext
576 .call_labels_for_completions(
577 store,
578 &language_server_id.0,
579 &completions.into_iter().collect::<Vec<_>>(),
580 )
581 .await?
582 .map(|labels| {
583 labels
584 .into_iter()
585 .map(|label| label.map(Into::into))
586 .collect()
587 })),
588 Extension::V0_1_0(ext) => Ok(ext
589 .call_labels_for_completions(
590 store,
591 &language_server_id.0,
592 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
593 )
594 .await?
595 .map(|labels| {
596 labels
597 .into_iter()
598 .map(|label| label.map(Into::into))
599 .collect()
600 })),
601 Extension::V0_0_6(ext) => Ok(ext
602 .call_labels_for_completions(
603 store,
604 &language_server_id.0,
605 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
606 )
607 .await?
608 .map(|labels| {
609 labels
610 .into_iter()
611 .map(|label| label.map(Into::into))
612 .collect()
613 })),
614 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
615 }
616 }
617
618 pub async fn call_labels_for_symbols(
619 &self,
620 store: &mut Store<WasmState>,
621 language_server_id: &LanguageServerName,
622 symbols: Vec<latest::Symbol>,
623 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
624 match self {
625 Extension::V0_6_0(ext) => {
626 ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
627 .await
628 }
629 Extension::V0_5_0(ext) => Ok(ext
630 .call_labels_for_symbols(
631 store,
632 &language_server_id.0,
633 &symbols.into_iter().collect::<Vec<_>>(),
634 )
635 .await?
636 .map(|labels| {
637 labels
638 .into_iter()
639 .map(|label| label.map(Into::into))
640 .collect()
641 })),
642 Extension::V0_4_0(ext) => Ok(ext
643 .call_labels_for_symbols(
644 store,
645 &language_server_id.0,
646 &symbols.into_iter().collect::<Vec<_>>(),
647 )
648 .await?
649 .map(|labels| {
650 labels
651 .into_iter()
652 .map(|label| label.map(Into::into))
653 .collect()
654 })),
655 Extension::V0_3_0(ext) => Ok(ext
656 .call_labels_for_symbols(
657 store,
658 &language_server_id.0,
659 &symbols.into_iter().collect::<Vec<_>>(),
660 )
661 .await?
662 .map(|labels| {
663 labels
664 .into_iter()
665 .map(|label| label.map(Into::into))
666 .collect()
667 })),
668 Extension::V0_2_0(ext) => Ok(ext
669 .call_labels_for_symbols(
670 store,
671 &language_server_id.0,
672 &symbols.into_iter().collect::<Vec<_>>(),
673 )
674 .await?
675 .map(|labels| {
676 labels
677 .into_iter()
678 .map(|label| label.map(Into::into))
679 .collect()
680 })),
681 Extension::V0_1_0(ext) => Ok(ext
682 .call_labels_for_symbols(
683 store,
684 &language_server_id.0,
685 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
686 )
687 .await?
688 .map(|labels| {
689 labels
690 .into_iter()
691 .map(|label| label.map(Into::into))
692 .collect()
693 })),
694 Extension::V0_0_6(ext) => Ok(ext
695 .call_labels_for_symbols(
696 store,
697 &language_server_id.0,
698 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
699 )
700 .await?
701 .map(|labels| {
702 labels
703 .into_iter()
704 .map(|label| label.map(Into::into))
705 .collect()
706 })),
707 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
708 }
709 }
710
711 pub async fn call_complete_slash_command_argument(
712 &self,
713 store: &mut Store<WasmState>,
714 command: &SlashCommand,
715 arguments: &[String],
716 ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
717 match self {
718 Extension::V0_6_0(ext) => {
719 ext.call_complete_slash_command_argument(store, command, arguments)
720 .await
721 }
722 Extension::V0_5_0(ext) => {
723 ext.call_complete_slash_command_argument(store, command, arguments)
724 .await
725 }
726 Extension::V0_4_0(ext) => {
727 ext.call_complete_slash_command_argument(store, command, arguments)
728 .await
729 }
730 Extension::V0_3_0(ext) => {
731 ext.call_complete_slash_command_argument(store, command, arguments)
732 .await
733 }
734 Extension::V0_2_0(ext) => {
735 ext.call_complete_slash_command_argument(store, command, arguments)
736 .await
737 }
738 Extension::V0_1_0(ext) => {
739 ext.call_complete_slash_command_argument(store, command, arguments)
740 .await
741 }
742 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
743 Ok(Ok(Vec::new()))
744 }
745 }
746 }
747
748 pub async fn call_run_slash_command(
749 &self,
750 store: &mut Store<WasmState>,
751 command: &SlashCommand,
752 arguments: &[String],
753 resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
754 ) -> Result<Result<SlashCommandOutput, String>> {
755 match self {
756 Extension::V0_6_0(ext) => {
757 ext.call_run_slash_command(store, command, arguments, resource)
758 .await
759 }
760 Extension::V0_5_0(ext) => {
761 ext.call_run_slash_command(store, command, arguments, resource)
762 .await
763 }
764 Extension::V0_4_0(ext) => {
765 ext.call_run_slash_command(store, command, arguments, resource)
766 .await
767 }
768 Extension::V0_3_0(ext) => {
769 ext.call_run_slash_command(store, command, arguments, resource)
770 .await
771 }
772 Extension::V0_2_0(ext) => {
773 ext.call_run_slash_command(store, command, arguments, resource)
774 .await
775 }
776 Extension::V0_1_0(ext) => {
777 ext.call_run_slash_command(store, command, arguments, resource)
778 .await
779 }
780 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
781 anyhow::bail!("`run_slash_command` not available prior to v0.1.0");
782 }
783 }
784 }
785
786 pub async fn call_context_server_command(
787 &self,
788 store: &mut Store<WasmState>,
789 context_server_id: Arc<str>,
790 project: Resource<ExtensionProject>,
791 ) -> Result<Result<Command, String>> {
792 match self {
793 Extension::V0_6_0(ext) => {
794 ext.call_context_server_command(store, &context_server_id, project)
795 .await
796 }
797 Extension::V0_5_0(ext) => {
798 ext.call_context_server_command(store, &context_server_id, project)
799 .await
800 }
801 Extension::V0_4_0(ext) => {
802 ext.call_context_server_command(store, &context_server_id, project)
803 .await
804 }
805 Extension::V0_3_0(ext) => {
806 ext.call_context_server_command(store, &context_server_id, project)
807 .await
808 }
809 Extension::V0_2_0(ext) => Ok(ext
810 .call_context_server_command(store, &context_server_id, project)
811 .await?
812 .map(Into::into)),
813 Extension::V0_0_1(_)
814 | Extension::V0_0_4(_)
815 | Extension::V0_0_6(_)
816 | Extension::V0_1_0(_) => {
817 anyhow::bail!("`context_server_command` not available prior to v0.2.0");
818 }
819 }
820 }
821
822 pub async fn call_context_server_configuration(
823 &self,
824 store: &mut Store<WasmState>,
825 context_server_id: Arc<str>,
826 project: Resource<ExtensionProject>,
827 ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
828 match self {
829 Extension::V0_6_0(ext) => {
830 ext.call_context_server_configuration(store, &context_server_id, project)
831 .await
832 }
833 Extension::V0_5_0(ext) => {
834 ext.call_context_server_configuration(store, &context_server_id, project)
835 .await
836 }
837 Extension::V0_0_1(_)
838 | Extension::V0_0_4(_)
839 | Extension::V0_0_6(_)
840 | Extension::V0_1_0(_)
841 | Extension::V0_2_0(_)
842 | Extension::V0_3_0(_)
843 | Extension::V0_4_0(_) => {
844 anyhow::bail!("`context_server_configuration` not available prior to v0.5.0");
845 }
846 }
847 }
848
849 pub async fn call_suggest_docs_packages(
850 &self,
851 store: &mut Store<WasmState>,
852 provider: &str,
853 ) -> Result<Result<Vec<String>, String>> {
854 match self {
855 Extension::V0_6_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
856 Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
857 Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
858 Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
859 Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
860 Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
861 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
862 anyhow::bail!("`suggest_docs_packages` not available prior to v0.1.0");
863 }
864 }
865 }
866
867 pub async fn call_index_docs(
868 &self,
869 store: &mut Store<WasmState>,
870 provider: &str,
871 package_name: &str,
872 kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
873 ) -> Result<Result<(), String>> {
874 match self {
875 Extension::V0_6_0(ext) => {
876 ext.call_index_docs(store, provider, package_name, kv_store)
877 .await
878 }
879 Extension::V0_5_0(ext) => {
880 ext.call_index_docs(store, provider, package_name, kv_store)
881 .await
882 }
883 Extension::V0_4_0(ext) => {
884 ext.call_index_docs(store, provider, package_name, kv_store)
885 .await
886 }
887 Extension::V0_3_0(ext) => {
888 ext.call_index_docs(store, provider, package_name, kv_store)
889 .await
890 }
891 Extension::V0_2_0(ext) => {
892 ext.call_index_docs(store, provider, package_name, kv_store)
893 .await
894 }
895 Extension::V0_1_0(ext) => {
896 ext.call_index_docs(store, provider, package_name, kv_store)
897 .await
898 }
899 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
900 anyhow::bail!("`index_docs` not available prior to v0.1.0");
901 }
902 }
903 }
904 pub async fn call_get_dap_binary(
905 &self,
906 store: &mut Store<WasmState>,
907 adapter_name: Arc<str>,
908 task: DebugTaskDefinition,
909 user_installed_path: Option<PathBuf>,
910 resource: Resource<Arc<dyn WorktreeDelegate>>,
911 ) -> Result<Result<DebugAdapterBinary, String>> {
912 match self {
913 Extension::V0_6_0(ext) => {
914 let dap_binary = ext
915 .call_get_dap_binary(
916 store,
917 &adapter_name,
918 &task.try_into()?,
919 user_installed_path.as_ref().and_then(|p| p.to_str()),
920 resource,
921 )
922 .await?
923 .map_err(|e| anyhow!("{e:?}"))?;
924
925 Ok(Ok(dap_binary))
926 }
927 _ => anyhow::bail!("`get_dap_binary` not available prior to v0.6.0"),
928 }
929 }
930 pub async fn call_dap_request_kind(
931 &self,
932 store: &mut Store<WasmState>,
933 adapter_name: Arc<str>,
934 config: serde_json::Value,
935 ) -> Result<Result<StartDebuggingRequestArgumentsRequest, String>> {
936 match self {
937 Extension::V0_6_0(ext) => {
938 let config =
939 serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
940 let dap_binary = ext
941 .call_dap_request_kind(store, &adapter_name, &config)
942 .await?
943 .map_err(|e| anyhow!("{e:?}"))?;
944
945 Ok(Ok(dap_binary))
946 }
947 _ => anyhow::bail!("`dap_request_kind` not available prior to v0.6.0"),
948 }
949 }
950 pub async fn call_dap_config_to_scenario(
951 &self,
952 store: &mut Store<WasmState>,
953 config: ZedDebugConfig,
954 ) -> Result<Result<DebugScenario, String>> {
955 match self {
956 Extension::V0_6_0(ext) => {
957 let config = config.into();
958 let dap_binary = ext
959 .call_dap_config_to_scenario(store, &config)
960 .await?
961 .map_err(|e| anyhow!("{e:?}"))?;
962
963 Ok(Ok(dap_binary.try_into()?))
964 }
965 _ => anyhow::bail!("`dap_config_to_scenario` not available prior to v0.6.0"),
966 }
967 }
968 pub async fn call_dap_locator_create_scenario(
969 &self,
970 store: &mut Store<WasmState>,
971 locator_name: String,
972 build_config_template: TaskTemplate,
973 resolved_label: String,
974 debug_adapter_name: String,
975 ) -> Result<Option<DebugScenario>> {
976 match self {
977 Extension::V0_6_0(ext) => {
978 let build_config_template = build_config_template.into();
979 let dap_binary = ext
980 .call_dap_locator_create_scenario(
981 store,
982 &locator_name,
983 &build_config_template,
984 &resolved_label,
985 &debug_adapter_name,
986 )
987 .await?;
988
989 Ok(dap_binary.map(TryInto::try_into).transpose()?)
990 }
991 _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
992 }
993 }
994 pub async fn call_run_dap_locator(
995 &self,
996 store: &mut Store<WasmState>,
997 locator_name: String,
998 resolved_build_task: SpawnInTerminal,
999 ) -> Result<Result<DebugRequest, String>> {
1000 match self {
1001 Extension::V0_6_0(ext) => {
1002 let build_config_template = resolved_build_task.try_into()?;
1003 let dap_request = ext
1004 .call_run_dap_locator(store, &locator_name, &build_config_template)
1005 .await?
1006 .map_err(|e| anyhow!("{e:?}"))?;
1007
1008 Ok(Ok(dap_request.into()))
1009 }
1010 _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1011 }
1012 }
1013}
1014
1015trait ToWasmtimeResult<T> {
1016 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
1017}
1018
1019impl<T> ToWasmtimeResult<T> for Result<T> {
1020 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
1021 Ok(self.map_err(|error| format!("{error:?}")))
1022 }
1023}