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