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