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