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