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