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