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;
10mod since_v0_8_0;
11use dap::DebugRequest;
12use extension::{DebugTaskDefinition, KeyValueStoreDelegate, WorktreeDelegate};
13use gpui::BackgroundExecutor;
14use language::LanguageName;
15use lsp::LanguageServerName;
16use release_channel::ReleaseChannel;
17use task::{DebugScenario, SpawnInTerminal, TaskTemplate, ZedDebugConfig};
18
19use crate::wasm_host::wit::since_v0_6_0::dap::StartDebuggingRequestArgumentsRequest;
20
21use super::{WasmState, wasm_engine};
22use anyhow::{Context as _, Result, anyhow};
23use semver::Version;
24use since_v0_8_0 as latest;
25use std::{ops::RangeInclusive, path::PathBuf, sync::Arc};
26use wasmtime::{
27 Store,
28 component::{Component, Linker, Resource},
29};
30
31#[cfg(test)]
32pub use latest::CodeLabelSpanLiteral;
33pub use latest::{
34 CodeLabel, CodeLabelSpan, Command, DebugAdapterBinary, ExtensionProject, Range, SlashCommand,
35 zed::extension::context_server::ContextServerConfiguration,
36 zed::extension::lsp::{
37 Completion, CompletionKind, CompletionLabelDetails, InsertTextFormat, Symbol, SymbolKind,
38 },
39 zed::extension::slash_command::{SlashCommandArgumentCompletion, SlashCommandOutput},
40};
41pub use since_v0_0_4::LanguageServerConfig;
42
43pub fn new_linker(
44 executor: &BackgroundExecutor,
45 f: impl Fn(&mut Linker<WasmState>, fn(&mut WasmState) -> &mut WasmState) -> Result<()>,
46) -> Linker<WasmState> {
47 let mut linker = Linker::new(&wasm_engine(executor));
48 wasmtime_wasi::p2::add_to_linker_async(&mut linker).unwrap();
49 f(&mut linker, wasi_view).unwrap();
50 linker
51}
52
53fn wasi_view(state: &mut WasmState) -> &mut WasmState {
54 state
55}
56
57/// Returns whether the given Wasm API version is supported by the Wasm host.
58pub fn is_supported_wasm_api_version(release_channel: ReleaseChannel, version: Version) -> 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<Version> {
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_6_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_8_0(since_v0_8_0::Extension),
100 V0_6_0(since_v0_6_0::Extension),
101 V0_5_0(since_v0_5_0::Extension),
102 V0_4_0(since_v0_4_0::Extension),
103 V0_3_0(since_v0_3_0::Extension),
104 V0_2_0(since_v0_2_0::Extension),
105 V0_1_0(since_v0_1_0::Extension),
106 V0_0_6(since_v0_0_6::Extension),
107 V0_0_4(since_v0_0_4::Extension),
108 V0_0_1(since_v0_0_1::Extension),
109}
110
111impl Extension {
112 pub async fn instantiate_async(
113 executor: &BackgroundExecutor,
114 store: &mut Store<WasmState>,
115 release_channel: ReleaseChannel,
116 version: Version,
117 component: &Component,
118 ) -> Result<Self> {
119 // Note: The release channel can be used to stage a new version of the extension API.
120 let _ = release_channel;
121
122 if version >= latest::MIN_VERSION {
123 authorize_access_to_unreleased_wasm_api_version(release_channel)?;
124
125 let extension =
126 latest::Extension::instantiate_async(store, component, latest::linker(executor))
127 .await
128 .context("failed to instantiate wasm extension")?;
129 Ok(Self::V0_8_0(extension))
130 } else if version >= since_v0_6_0::MIN_VERSION {
131 let extension = since_v0_6_0::Extension::instantiate_async(
132 store,
133 component,
134 since_v0_6_0::linker(executor),
135 )
136 .await
137 .context("failed to instantiate wasm extension")?;
138 Ok(Self::V0_6_0(extension))
139 } else if version >= since_v0_5_0::MIN_VERSION {
140 let extension = since_v0_5_0::Extension::instantiate_async(
141 store,
142 component,
143 since_v0_5_0::linker(executor),
144 )
145 .await
146 .context("failed to instantiate wasm extension")?;
147 Ok(Self::V0_5_0(extension))
148 } else if version >= since_v0_4_0::MIN_VERSION {
149 let extension = since_v0_4_0::Extension::instantiate_async(
150 store,
151 component,
152 since_v0_4_0::linker(executor),
153 )
154 .await
155 .context("failed to instantiate wasm extension")?;
156 Ok(Self::V0_4_0(extension))
157 } else if version >= since_v0_3_0::MIN_VERSION {
158 let extension = since_v0_3_0::Extension::instantiate_async(
159 store,
160 component,
161 since_v0_3_0::linker(executor),
162 )
163 .await
164 .context("failed to instantiate wasm extension")?;
165 Ok(Self::V0_3_0(extension))
166 } else if version >= since_v0_2_0::MIN_VERSION {
167 let extension = since_v0_2_0::Extension::instantiate_async(
168 store,
169 component,
170 since_v0_2_0::linker(executor),
171 )
172 .await
173 .context("failed to instantiate wasm extension")?;
174 Ok(Self::V0_2_0(extension))
175 } else if version >= since_v0_1_0::MIN_VERSION {
176 let extension = since_v0_1_0::Extension::instantiate_async(
177 store,
178 component,
179 since_v0_1_0::linker(executor),
180 )
181 .await
182 .context("failed to instantiate wasm extension")?;
183 Ok(Self::V0_1_0(extension))
184 } else if version >= since_v0_0_6::MIN_VERSION {
185 let extension = since_v0_0_6::Extension::instantiate_async(
186 store,
187 component,
188 since_v0_0_6::linker(executor),
189 )
190 .await
191 .context("failed to instantiate wasm extension")?;
192 Ok(Self::V0_0_6(extension))
193 } else if version >= since_v0_0_4::MIN_VERSION {
194 let extension = since_v0_0_4::Extension::instantiate_async(
195 store,
196 component,
197 since_v0_0_4::linker(executor),
198 )
199 .await
200 .context("failed to instantiate wasm extension")?;
201 Ok(Self::V0_0_4(extension))
202 } else {
203 let extension = since_v0_0_1::Extension::instantiate_async(
204 store,
205 component,
206 since_v0_0_1::linker(executor),
207 )
208 .await
209 .context("failed to instantiate wasm extension")?;
210 Ok(Self::V0_0_1(extension))
211 }
212 }
213
214 pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
215 match self {
216 Extension::V0_8_0(ext) => ext.call_init_extension(store).await,
217 Extension::V0_6_0(ext) => ext.call_init_extension(store).await,
218 Extension::V0_5_0(ext) => ext.call_init_extension(store).await,
219 Extension::V0_4_0(ext) => ext.call_init_extension(store).await,
220 Extension::V0_3_0(ext) => ext.call_init_extension(store).await,
221 Extension::V0_2_0(ext) => ext.call_init_extension(store).await,
222 Extension::V0_1_0(ext) => ext.call_init_extension(store).await,
223 Extension::V0_0_6(ext) => ext.call_init_extension(store).await,
224 Extension::V0_0_4(ext) => ext.call_init_extension(store).await,
225 Extension::V0_0_1(ext) => ext.call_init_extension(store).await,
226 }
227 }
228
229 pub async fn call_language_server_command(
230 &self,
231 store: &mut Store<WasmState>,
232 language_server_id: &LanguageServerName,
233 language_name: &LanguageName,
234 resource: Resource<Arc<dyn WorktreeDelegate>>,
235 ) -> Result<Result<Command, String>> {
236 match self {
237 Extension::V0_8_0(ext) => {
238 ext.call_language_server_command(store, &language_server_id.0, resource)
239 .await
240 }
241 Extension::V0_6_0(ext) => {
242 ext.call_language_server_command(store, &language_server_id.0, resource)
243 .await
244 }
245 Extension::V0_5_0(ext) => {
246 ext.call_language_server_command(store, &language_server_id.0, resource)
247 .await
248 }
249 Extension::V0_4_0(ext) => {
250 ext.call_language_server_command(store, &language_server_id.0, resource)
251 .await
252 }
253 Extension::V0_3_0(ext) => {
254 ext.call_language_server_command(store, &language_server_id.0, resource)
255 .await
256 }
257 Extension::V0_2_0(ext) => Ok(ext
258 .call_language_server_command(store, &language_server_id.0, resource)
259 .await?
260 .map(|command| command.into())),
261 Extension::V0_1_0(ext) => Ok(ext
262 .call_language_server_command(store, &language_server_id.0, resource)
263 .await?
264 .map(|command| command.into())),
265 Extension::V0_0_6(ext) => Ok(ext
266 .call_language_server_command(store, &language_server_id.0, resource)
267 .await?
268 .map(|command| command.into())),
269 Extension::V0_0_4(ext) => Ok(ext
270 .call_language_server_command(
271 store,
272 &LanguageServerConfig {
273 name: language_server_id.0.to_string(),
274 language_name: language_name.to_string(),
275 },
276 resource,
277 )
278 .await?
279 .map(|command| command.into())),
280 Extension::V0_0_1(ext) => Ok(ext
281 .call_language_server_command(
282 store,
283 &LanguageServerConfig {
284 name: language_server_id.0.to_string(),
285 language_name: language_name.to_string(),
286 }
287 .into(),
288 resource,
289 )
290 .await?
291 .map(|command| command.into())),
292 }
293 }
294
295 pub async fn call_language_server_initialization_options(
296 &self,
297 store: &mut Store<WasmState>,
298 language_server_id: &LanguageServerName,
299 language_name: &LanguageName,
300 resource: Resource<Arc<dyn WorktreeDelegate>>,
301 ) -> Result<Result<Option<String>, String>> {
302 match self {
303 Extension::V0_8_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_6_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_5_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_4_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_3_0(ext) => {
336 ext.call_language_server_initialization_options(
337 store,
338 &language_server_id.0,
339 resource,
340 )
341 .await
342 }
343 Extension::V0_2_0(ext) => {
344 ext.call_language_server_initialization_options(
345 store,
346 &language_server_id.0,
347 resource,
348 )
349 .await
350 }
351 Extension::V0_1_0(ext) => {
352 ext.call_language_server_initialization_options(
353 store,
354 &language_server_id.0,
355 resource,
356 )
357 .await
358 }
359 Extension::V0_0_6(ext) => {
360 ext.call_language_server_initialization_options(
361 store,
362 &language_server_id.0,
363 resource,
364 )
365 .await
366 }
367 Extension::V0_0_4(ext) => {
368 ext.call_language_server_initialization_options(
369 store,
370 &LanguageServerConfig {
371 name: language_server_id.0.to_string(),
372 language_name: language_name.to_string(),
373 },
374 resource,
375 )
376 .await
377 }
378 Extension::V0_0_1(ext) => {
379 ext.call_language_server_initialization_options(
380 store,
381 &LanguageServerConfig {
382 name: language_server_id.0.to_string(),
383 language_name: language_name.to_string(),
384 }
385 .into(),
386 resource,
387 )
388 .await
389 }
390 }
391 }
392
393 pub async fn call_language_server_workspace_configuration(
394 &self,
395 store: &mut Store<WasmState>,
396 language_server_id: &LanguageServerName,
397 resource: Resource<Arc<dyn WorktreeDelegate>>,
398 ) -> Result<Result<Option<String>, String>> {
399 match self {
400 Extension::V0_8_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_6_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_5_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_4_0(ext) => {
425 ext.call_language_server_workspace_configuration(
426 store,
427 &language_server_id.0,
428 resource,
429 )
430 .await
431 }
432 Extension::V0_3_0(ext) => {
433 ext.call_language_server_workspace_configuration(
434 store,
435 &language_server_id.0,
436 resource,
437 )
438 .await
439 }
440 Extension::V0_2_0(ext) => {
441 ext.call_language_server_workspace_configuration(
442 store,
443 &language_server_id.0,
444 resource,
445 )
446 .await
447 }
448 Extension::V0_1_0(ext) => {
449 ext.call_language_server_workspace_configuration(
450 store,
451 &language_server_id.0,
452 resource,
453 )
454 .await
455 }
456 Extension::V0_0_6(ext) => {
457 ext.call_language_server_workspace_configuration(
458 store,
459 &language_server_id.0,
460 resource,
461 )
462 .await
463 }
464 Extension::V0_0_4(_) | Extension::V0_0_1(_) => Ok(Ok(None)),
465 }
466 }
467
468 pub async fn call_language_server_initialization_options_schema(
469 &self,
470 store: &mut Store<WasmState>,
471 language_server_id: &LanguageServerName,
472 resource: Resource<Arc<dyn WorktreeDelegate>>,
473 ) -> Result<Option<String>> {
474 match self {
475 Extension::V0_8_0(ext) => {
476 ext.call_language_server_initialization_options_schema(
477 store,
478 &language_server_id.0,
479 resource,
480 )
481 .await
482 }
483 Extension::V0_6_0(_)
484 | Extension::V0_5_0(_)
485 | Extension::V0_4_0(_)
486 | Extension::V0_3_0(_)
487 | Extension::V0_2_0(_)
488 | Extension::V0_1_0(_)
489 | Extension::V0_0_6(_)
490 | Extension::V0_0_4(_)
491 | Extension::V0_0_1(_) => Ok(None),
492 }
493 }
494
495 pub async fn call_language_server_workspace_configuration_schema(
496 &self,
497 store: &mut Store<WasmState>,
498 language_server_id: &LanguageServerName,
499 resource: Resource<Arc<dyn WorktreeDelegate>>,
500 ) -> Result<Option<String>> {
501 match self {
502 Extension::V0_8_0(ext) => {
503 ext.call_language_server_workspace_configuration_schema(
504 store,
505 &language_server_id.0,
506 resource,
507 )
508 .await
509 }
510 Extension::V0_6_0(_)
511 | Extension::V0_5_0(_)
512 | Extension::V0_4_0(_)
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(None),
519 }
520 }
521
522 pub async fn call_language_server_additional_initialization_options(
523 &self,
524 store: &mut Store<WasmState>,
525 language_server_id: &LanguageServerName,
526 target_language_server_id: &LanguageServerName,
527 resource: Resource<Arc<dyn WorktreeDelegate>>,
528 ) -> Result<Result<Option<String>, String>> {
529 match self {
530 Extension::V0_8_0(ext) => {
531 ext.call_language_server_additional_initialization_options(
532 store,
533 &language_server_id.0,
534 &target_language_server_id.0,
535 resource,
536 )
537 .await
538 }
539 Extension::V0_6_0(ext) => {
540 ext.call_language_server_additional_initialization_options(
541 store,
542 &language_server_id.0,
543 &target_language_server_id.0,
544 resource,
545 )
546 .await
547 }
548 Extension::V0_5_0(ext) => {
549 ext.call_language_server_additional_initialization_options(
550 store,
551 &language_server_id.0,
552 &target_language_server_id.0,
553 resource,
554 )
555 .await
556 }
557 Extension::V0_4_0(ext) => {
558 ext.call_language_server_additional_initialization_options(
559 store,
560 &language_server_id.0,
561 &target_language_server_id.0,
562 resource,
563 )
564 .await
565 }
566 Extension::V0_3_0(_)
567 | Extension::V0_2_0(_)
568 | Extension::V0_1_0(_)
569 | Extension::V0_0_6(_)
570 | Extension::V0_0_4(_)
571 | Extension::V0_0_1(_) => Ok(Ok(None)),
572 }
573 }
574
575 pub async fn call_language_server_additional_workspace_configuration(
576 &self,
577 store: &mut Store<WasmState>,
578 language_server_id: &LanguageServerName,
579 target_language_server_id: &LanguageServerName,
580 resource: Resource<Arc<dyn WorktreeDelegate>>,
581 ) -> Result<Result<Option<String>, String>> {
582 match self {
583 Extension::V0_8_0(ext) => {
584 ext.call_language_server_additional_workspace_configuration(
585 store,
586 &language_server_id.0,
587 &target_language_server_id.0,
588 resource,
589 )
590 .await
591 }
592 Extension::V0_6_0(ext) => {
593 ext.call_language_server_additional_workspace_configuration(
594 store,
595 &language_server_id.0,
596 &target_language_server_id.0,
597 resource,
598 )
599 .await
600 }
601 Extension::V0_5_0(ext) => {
602 ext.call_language_server_additional_workspace_configuration(
603 store,
604 &language_server_id.0,
605 &target_language_server_id.0,
606 resource,
607 )
608 .await
609 }
610 Extension::V0_4_0(ext) => {
611 ext.call_language_server_additional_workspace_configuration(
612 store,
613 &language_server_id.0,
614 &target_language_server_id.0,
615 resource,
616 )
617 .await
618 }
619 Extension::V0_3_0(_)
620 | Extension::V0_2_0(_)
621 | Extension::V0_1_0(_)
622 | Extension::V0_0_6(_)
623 | Extension::V0_0_4(_)
624 | Extension::V0_0_1(_) => Ok(Ok(None)),
625 }
626 }
627
628 pub async fn call_labels_for_completions(
629 &self,
630 store: &mut Store<WasmState>,
631 language_server_id: &LanguageServerName,
632 completions: Vec<latest::Completion>,
633 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
634 match self {
635 Extension::V0_8_0(ext) => {
636 ext.call_labels_for_completions(store, &language_server_id.0, &completions)
637 .await
638 }
639 Extension::V0_6_0(ext) => Ok(ext
640 .call_labels_for_completions(
641 store,
642 &language_server_id.0,
643 &completions.into_iter().map(Into::into).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_5_0(ext) => Ok(ext
653 .call_labels_for_completions(
654 store,
655 &language_server_id.0,
656 &completions.into_iter().map(Into::into).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_4_0(ext) => Ok(ext
666 .call_labels_for_completions(
667 store,
668 &language_server_id.0,
669 &completions.into_iter().map(Into::into).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_3_0(ext) => Ok(ext
679 .call_labels_for_completions(
680 store,
681 &language_server_id.0,
682 &completions.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_2_0(ext) => Ok(ext
692 .call_labels_for_completions(
693 store,
694 &language_server_id.0,
695 &completions.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_1_0(ext) => Ok(ext
705 .call_labels_for_completions(
706 store,
707 &language_server_id.0,
708 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
709 )
710 .await?
711 .map(|labels| {
712 labels
713 .into_iter()
714 .map(|label| label.map(Into::into))
715 .collect()
716 })),
717 Extension::V0_0_6(ext) => Ok(ext
718 .call_labels_for_completions(
719 store,
720 &language_server_id.0,
721 &completions.into_iter().map(Into::into).collect::<Vec<_>>(),
722 )
723 .await?
724 .map(|labels| {
725 labels
726 .into_iter()
727 .map(|label| label.map(Into::into))
728 .collect()
729 })),
730 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
731 }
732 }
733
734 pub async fn call_labels_for_symbols(
735 &self,
736 store: &mut Store<WasmState>,
737 language_server_id: &LanguageServerName,
738 symbols: Vec<latest::Symbol>,
739 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
740 match self {
741 Extension::V0_8_0(ext) => {
742 ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
743 .await
744 }
745 Extension::V0_6_0(ext) => Ok(ext
746 .call_labels_for_symbols(
747 store,
748 &language_server_id.0,
749 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
750 )
751 .await?
752 .map(|labels| {
753 labels
754 .into_iter()
755 .map(|label| label.map(Into::into))
756 .collect()
757 })),
758 Extension::V0_5_0(ext) => Ok(ext
759 .call_labels_for_symbols(
760 store,
761 &language_server_id.0,
762 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
763 )
764 .await?
765 .map(|labels| {
766 labels
767 .into_iter()
768 .map(|label| label.map(Into::into))
769 .collect()
770 })),
771 Extension::V0_4_0(ext) => Ok(ext
772 .call_labels_for_symbols(
773 store,
774 &language_server_id.0,
775 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
776 )
777 .await?
778 .map(|labels| {
779 labels
780 .into_iter()
781 .map(|label| label.map(Into::into))
782 .collect()
783 })),
784 Extension::V0_3_0(ext) => Ok(ext
785 .call_labels_for_symbols(
786 store,
787 &language_server_id.0,
788 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
789 )
790 .await?
791 .map(|labels| {
792 labels
793 .into_iter()
794 .map(|label| label.map(Into::into))
795 .collect()
796 })),
797 Extension::V0_2_0(ext) => Ok(ext
798 .call_labels_for_symbols(
799 store,
800 &language_server_id.0,
801 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
802 )
803 .await?
804 .map(|labels| {
805 labels
806 .into_iter()
807 .map(|label| label.map(Into::into))
808 .collect()
809 })),
810 Extension::V0_1_0(ext) => Ok(ext
811 .call_labels_for_symbols(
812 store,
813 &language_server_id.0,
814 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
815 )
816 .await?
817 .map(|labels| {
818 labels
819 .into_iter()
820 .map(|label| label.map(Into::into))
821 .collect()
822 })),
823 Extension::V0_0_6(ext) => Ok(ext
824 .call_labels_for_symbols(
825 store,
826 &language_server_id.0,
827 &symbols.into_iter().map(Into::into).collect::<Vec<_>>(),
828 )
829 .await?
830 .map(|labels| {
831 labels
832 .into_iter()
833 .map(|label| label.map(Into::into))
834 .collect()
835 })),
836 Extension::V0_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
837 }
838 }
839
840 pub async fn call_complete_slash_command_argument(
841 &self,
842 store: &mut Store<WasmState>,
843 command: &SlashCommand,
844 arguments: &[String],
845 ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
846 match self {
847 Extension::V0_8_0(ext) => {
848 ext.call_complete_slash_command_argument(store, command, arguments)
849 .await
850 }
851 Extension::V0_6_0(ext) => {
852 ext.call_complete_slash_command_argument(store, command, arguments)
853 .await
854 }
855 Extension::V0_5_0(ext) => {
856 ext.call_complete_slash_command_argument(store, command, arguments)
857 .await
858 }
859 Extension::V0_4_0(ext) => {
860 ext.call_complete_slash_command_argument(store, command, arguments)
861 .await
862 }
863 Extension::V0_3_0(ext) => {
864 ext.call_complete_slash_command_argument(store, command, arguments)
865 .await
866 }
867 Extension::V0_2_0(ext) => {
868 ext.call_complete_slash_command_argument(store, command, arguments)
869 .await
870 }
871 Extension::V0_1_0(ext) => {
872 ext.call_complete_slash_command_argument(store, command, arguments)
873 .await
874 }
875 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
876 Ok(Ok(Vec::new()))
877 }
878 }
879 }
880
881 pub async fn call_run_slash_command(
882 &self,
883 store: &mut Store<WasmState>,
884 command: &SlashCommand,
885 arguments: &[String],
886 resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
887 ) -> Result<Result<SlashCommandOutput, String>> {
888 match self {
889 Extension::V0_8_0(ext) => {
890 ext.call_run_slash_command(store, command, arguments, resource)
891 .await
892 }
893 Extension::V0_6_0(ext) => {
894 ext.call_run_slash_command(store, command, arguments, resource)
895 .await
896 }
897 Extension::V0_5_0(ext) => {
898 ext.call_run_slash_command(store, command, arguments, resource)
899 .await
900 }
901 Extension::V0_4_0(ext) => {
902 ext.call_run_slash_command(store, command, arguments, resource)
903 .await
904 }
905 Extension::V0_3_0(ext) => {
906 ext.call_run_slash_command(store, command, arguments, resource)
907 .await
908 }
909 Extension::V0_2_0(ext) => {
910 ext.call_run_slash_command(store, command, arguments, resource)
911 .await
912 }
913 Extension::V0_1_0(ext) => {
914 ext.call_run_slash_command(store, command, arguments, resource)
915 .await
916 }
917 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
918 anyhow::bail!("`run_slash_command` not available prior to v0.1.0");
919 }
920 }
921 }
922
923 pub async fn call_context_server_command(
924 &self,
925 store: &mut Store<WasmState>,
926 context_server_id: Arc<str>,
927 project: Resource<ExtensionProject>,
928 ) -> Result<Result<Command, String>> {
929 match self {
930 Extension::V0_8_0(ext) => {
931 ext.call_context_server_command(store, &context_server_id, project)
932 .await
933 }
934 Extension::V0_6_0(ext) => {
935 ext.call_context_server_command(store, &context_server_id, project)
936 .await
937 }
938 Extension::V0_5_0(ext) => {
939 ext.call_context_server_command(store, &context_server_id, project)
940 .await
941 }
942 Extension::V0_4_0(ext) => {
943 ext.call_context_server_command(store, &context_server_id, project)
944 .await
945 }
946 Extension::V0_3_0(ext) => {
947 ext.call_context_server_command(store, &context_server_id, project)
948 .await
949 }
950 Extension::V0_2_0(ext) => Ok(ext
951 .call_context_server_command(store, &context_server_id, project)
952 .await?
953 .map(Into::into)),
954 Extension::V0_0_1(_)
955 | Extension::V0_0_4(_)
956 | Extension::V0_0_6(_)
957 | Extension::V0_1_0(_) => {
958 anyhow::bail!("`context_server_command` not available prior to v0.2.0");
959 }
960 }
961 }
962
963 pub async fn call_context_server_configuration(
964 &self,
965 store: &mut Store<WasmState>,
966 context_server_id: Arc<str>,
967 project: Resource<ExtensionProject>,
968 ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
969 match self {
970 Extension::V0_8_0(ext) => {
971 ext.call_context_server_configuration(store, &context_server_id, project)
972 .await
973 }
974 Extension::V0_6_0(ext) => {
975 ext.call_context_server_configuration(store, &context_server_id, project)
976 .await
977 }
978 Extension::V0_5_0(ext) => {
979 ext.call_context_server_configuration(store, &context_server_id, project)
980 .await
981 }
982 Extension::V0_0_1(_)
983 | Extension::V0_0_4(_)
984 | Extension::V0_0_6(_)
985 | Extension::V0_1_0(_)
986 | Extension::V0_2_0(_)
987 | Extension::V0_3_0(_)
988 | Extension::V0_4_0(_) => {
989 anyhow::bail!("`context_server_configuration` not available prior to v0.5.0");
990 }
991 }
992 }
993
994 pub async fn call_suggest_docs_packages(
995 &self,
996 store: &mut Store<WasmState>,
997 provider: &str,
998 ) -> Result<Result<Vec<String>, String>> {
999 match self {
1000 Extension::V0_8_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
1001 Extension::V0_6_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
1002 Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
1003 Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
1004 Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
1005 Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
1006 Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
1007 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
1008 anyhow::bail!("`suggest_docs_packages` not available prior to v0.1.0");
1009 }
1010 }
1011 }
1012
1013 pub async fn call_index_docs(
1014 &self,
1015 store: &mut Store<WasmState>,
1016 provider: &str,
1017 package_name: &str,
1018 kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
1019 ) -> Result<Result<(), String>> {
1020 match self {
1021 Extension::V0_8_0(ext) => {
1022 ext.call_index_docs(store, provider, package_name, kv_store)
1023 .await
1024 }
1025 Extension::V0_6_0(ext) => {
1026 ext.call_index_docs(store, provider, package_name, kv_store)
1027 .await
1028 }
1029 Extension::V0_5_0(ext) => {
1030 ext.call_index_docs(store, provider, package_name, kv_store)
1031 .await
1032 }
1033 Extension::V0_4_0(ext) => {
1034 ext.call_index_docs(store, provider, package_name, kv_store)
1035 .await
1036 }
1037 Extension::V0_3_0(ext) => {
1038 ext.call_index_docs(store, provider, package_name, kv_store)
1039 .await
1040 }
1041 Extension::V0_2_0(ext) => {
1042 ext.call_index_docs(store, provider, package_name, kv_store)
1043 .await
1044 }
1045 Extension::V0_1_0(ext) => {
1046 ext.call_index_docs(store, provider, package_name, kv_store)
1047 .await
1048 }
1049 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
1050 anyhow::bail!("`index_docs` not available prior to v0.1.0");
1051 }
1052 }
1053 }
1054
1055 pub async fn call_get_dap_binary(
1056 &self,
1057 store: &mut Store<WasmState>,
1058 adapter_name: Arc<str>,
1059 task: DebugTaskDefinition,
1060 user_installed_path: Option<PathBuf>,
1061 resource: Resource<Arc<dyn WorktreeDelegate>>,
1062 ) -> Result<Result<DebugAdapterBinary, String>> {
1063 match self {
1064 Extension::V0_8_0(ext) => {
1065 let dap_binary = ext
1066 .call_get_dap_binary(
1067 store,
1068 &adapter_name,
1069 &task.try_into()?,
1070 user_installed_path.as_ref().and_then(|p| p.to_str()),
1071 resource,
1072 )
1073 .await?
1074 .map_err(|e| anyhow!("{e:?}"))?;
1075
1076 Ok(Ok(dap_binary))
1077 }
1078 Extension::V0_6_0(ext) => {
1079 let dap_binary = ext
1080 .call_get_dap_binary(
1081 store,
1082 &adapter_name,
1083 &task.try_into()?,
1084 user_installed_path.as_ref().and_then(|p| p.to_str()),
1085 resource,
1086 )
1087 .await?
1088 .map_err(|e| anyhow!("{e:?}"))?;
1089
1090 Ok(Ok(dap_binary))
1091 }
1092 Extension::V0_5_0(_)
1093 | Extension::V0_4_0(_)
1094 | Extension::V0_3_0(_)
1095 | Extension::V0_2_0(_)
1096 | Extension::V0_1_0(_)
1097 | Extension::V0_0_6(_)
1098 | Extension::V0_0_4(_)
1099 | Extension::V0_0_1(_) => {
1100 anyhow::bail!("`get_dap_binary` not available prior to v0.6.0");
1101 }
1102 }
1103 }
1104
1105 pub async fn call_dap_request_kind(
1106 &self,
1107 store: &mut Store<WasmState>,
1108 adapter_name: Arc<str>,
1109 config: serde_json::Value,
1110 ) -> Result<Result<StartDebuggingRequestArgumentsRequest, String>> {
1111 match self {
1112 Extension::V0_8_0(ext) => {
1113 let config =
1114 serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
1115 let dap_binary = ext
1116 .call_dap_request_kind(store, &adapter_name, &config)
1117 .await?
1118 .map_err(|e| anyhow!("{e:?}"))?;
1119
1120 Ok(Ok(dap_binary))
1121 }
1122 Extension::V0_6_0(ext) => {
1123 let config =
1124 serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
1125 let dap_binary = ext
1126 .call_dap_request_kind(store, &adapter_name, &config)
1127 .await?
1128 .map_err(|e| anyhow!("{e:?}"))?;
1129
1130 Ok(Ok(dap_binary))
1131 }
1132 Extension::V0_5_0(_)
1133 | Extension::V0_4_0(_)
1134 | Extension::V0_3_0(_)
1135 | Extension::V0_2_0(_)
1136 | Extension::V0_1_0(_)
1137 | Extension::V0_0_6(_)
1138 | Extension::V0_0_4(_)
1139 | Extension::V0_0_1(_) => {
1140 anyhow::bail!("`dap_request_kind` not available prior to v0.6.0");
1141 }
1142 }
1143 }
1144
1145 pub async fn call_dap_config_to_scenario(
1146 &self,
1147 store: &mut Store<WasmState>,
1148 config: ZedDebugConfig,
1149 ) -> Result<Result<DebugScenario, String>> {
1150 match self {
1151 Extension::V0_8_0(ext) => {
1152 let config = config.into();
1153 let dap_binary = ext
1154 .call_dap_config_to_scenario(store, &config)
1155 .await?
1156 .map_err(|e| anyhow!("{e:?}"))?;
1157
1158 Ok(Ok(dap_binary.try_into()?))
1159 }
1160 Extension::V0_6_0(ext) => {
1161 let config = config.into();
1162 let dap_binary = ext
1163 .call_dap_config_to_scenario(store, &config)
1164 .await?
1165 .map_err(|e| anyhow!("{e:?}"))?;
1166
1167 Ok(Ok(dap_binary.try_into()?))
1168 }
1169 Extension::V0_5_0(_)
1170 | Extension::V0_4_0(_)
1171 | Extension::V0_3_0(_)
1172 | Extension::V0_2_0(_)
1173 | Extension::V0_1_0(_)
1174 | Extension::V0_0_6(_)
1175 | Extension::V0_0_4(_)
1176 | Extension::V0_0_1(_) => {
1177 anyhow::bail!("`dap_config_to_scenario` not available prior to v0.6.0");
1178 }
1179 }
1180 }
1181
1182 pub async fn call_dap_locator_create_scenario(
1183 &self,
1184 store: &mut Store<WasmState>,
1185 locator_name: String,
1186 build_config_template: TaskTemplate,
1187 resolved_label: String,
1188 debug_adapter_name: String,
1189 ) -> Result<Option<DebugScenario>> {
1190 match self {
1191 Extension::V0_8_0(ext) => {
1192 let build_config_template = build_config_template.into();
1193 let dap_binary = ext
1194 .call_dap_locator_create_scenario(
1195 store,
1196 &locator_name,
1197 &build_config_template,
1198 &resolved_label,
1199 &debug_adapter_name,
1200 )
1201 .await?;
1202
1203 Ok(dap_binary.map(TryInto::try_into).transpose()?)
1204 }
1205 Extension::V0_6_0(ext) => {
1206 let build_config_template = build_config_template.into();
1207 let dap_binary = ext
1208 .call_dap_locator_create_scenario(
1209 store,
1210 &locator_name,
1211 &build_config_template,
1212 &resolved_label,
1213 &debug_adapter_name,
1214 )
1215 .await?;
1216
1217 Ok(dap_binary.map(TryInto::try_into).transpose()?)
1218 }
1219 Extension::V0_5_0(_)
1220 | Extension::V0_4_0(_)
1221 | Extension::V0_3_0(_)
1222 | Extension::V0_2_0(_)
1223 | Extension::V0_1_0(_)
1224 | Extension::V0_0_6(_)
1225 | Extension::V0_0_4(_)
1226 | Extension::V0_0_1(_) => {
1227 anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0");
1228 }
1229 }
1230 }
1231
1232 pub async fn call_run_dap_locator(
1233 &self,
1234 store: &mut Store<WasmState>,
1235 locator_name: String,
1236 resolved_build_task: SpawnInTerminal,
1237 ) -> Result<Result<DebugRequest, String>> {
1238 match self {
1239 Extension::V0_8_0(ext) => {
1240 let build_config_template = resolved_build_task.try_into()?;
1241 let dap_request = ext
1242 .call_run_dap_locator(store, &locator_name, &build_config_template)
1243 .await?
1244 .map_err(|e| anyhow!("{e:?}"))?;
1245
1246 Ok(Ok(dap_request.into()))
1247 }
1248 Extension::V0_6_0(ext) => {
1249 let build_config_template = resolved_build_task.try_into()?;
1250 let dap_request = ext
1251 .call_run_dap_locator(store, &locator_name, &build_config_template)
1252 .await?
1253 .map_err(|e| anyhow!("{e:?}"))?;
1254
1255 Ok(Ok(dap_request.into()))
1256 }
1257 Extension::V0_5_0(_)
1258 | Extension::V0_4_0(_)
1259 | Extension::V0_3_0(_)
1260 | Extension::V0_2_0(_)
1261 | Extension::V0_1_0(_)
1262 | Extension::V0_0_6(_)
1263 | Extension::V0_0_4(_)
1264 | Extension::V0_0_1(_) => {
1265 anyhow::bail!("`run_dap_locator` not available prior to v0.6.0");
1266 }
1267 }
1268 }
1269}
1270
1271trait ToWasmtimeResult<T> {
1272 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
1273}
1274
1275impl<T> ToWasmtimeResult<T> for Result<T> {
1276 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
1277 Ok(self.map_err(|error| format!("{error:?}")))
1278 }
1279}