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_7_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_7_0::dap::StartDebuggingRequestArgumentsRequest;
20
21use super::{WasmState, wasm_engine};
22use anyhow::{Context as _, Result, anyhow};
23use semver::Version;
24use since_v0_7_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, CredentialType as LlmCredentialType,
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::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 => latest::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_7_0(since_v0_7_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 let extension =
137 latest::Extension::instantiate_async(store, component, latest::linker(executor))
138 .await
139 .context("failed to instantiate wasm extension")?;
140 Ok(Self::V0_7_0(extension))
141 } else if version >= since_v0_6_0::MIN_VERSION {
142 let extension = since_v0_6_0::Extension::instantiate_async(
143 store,
144 component,
145 since_v0_6_0::linker(executor),
146 )
147 .await
148 .context("failed to instantiate wasm extension")?;
149 Ok(Self::V0_6_0(extension))
150 } else if version >= since_v0_5_0::MIN_VERSION {
151 let extension = since_v0_5_0::Extension::instantiate_async(
152 store,
153 component,
154 since_v0_5_0::linker(executor),
155 )
156 .await
157 .context("failed to instantiate wasm extension")?;
158 Ok(Self::V0_5_0(extension))
159 } else if version >= since_v0_4_0::MIN_VERSION {
160 let extension = since_v0_4_0::Extension::instantiate_async(
161 store,
162 component,
163 since_v0_4_0::linker(executor),
164 )
165 .await
166 .context("failed to instantiate wasm extension")?;
167 Ok(Self::V0_4_0(extension))
168 } else if version >= since_v0_3_0::MIN_VERSION {
169 let extension = since_v0_3_0::Extension::instantiate_async(
170 store,
171 component,
172 since_v0_3_0::linker(executor),
173 )
174 .await
175 .context("failed to instantiate wasm extension")?;
176 Ok(Self::V0_3_0(extension))
177 } else if version >= since_v0_2_0::MIN_VERSION {
178 let extension = since_v0_2_0::Extension::instantiate_async(
179 store,
180 component,
181 since_v0_2_0::linker(executor),
182 )
183 .await
184 .context("failed to instantiate wasm extension")?;
185 Ok(Self::V0_2_0(extension))
186 } else if version >= since_v0_1_0::MIN_VERSION {
187 let extension = since_v0_1_0::Extension::instantiate_async(
188 store,
189 component,
190 since_v0_1_0::linker(executor),
191 )
192 .await
193 .context("failed to instantiate wasm extension")?;
194 Ok(Self::V0_1_0(extension))
195 } else if version >= since_v0_0_6::MIN_VERSION {
196 let extension = since_v0_0_6::Extension::instantiate_async(
197 store,
198 component,
199 since_v0_0_6::linker(executor),
200 )
201 .await
202 .context("failed to instantiate wasm extension")?;
203 Ok(Self::V0_0_6(extension))
204 } else if version >= since_v0_0_4::MIN_VERSION {
205 let extension = since_v0_0_4::Extension::instantiate_async(
206 store,
207 component,
208 since_v0_0_4::linker(executor),
209 )
210 .await
211 .context("failed to instantiate wasm extension")?;
212 Ok(Self::V0_0_4(extension))
213 } else {
214 let extension = since_v0_0_1::Extension::instantiate_async(
215 store,
216 component,
217 since_v0_0_1::linker(executor),
218 )
219 .await
220 .context("failed to instantiate wasm extension")?;
221 Ok(Self::V0_0_1(extension))
222 }
223 }
224
225 pub async fn call_init_extension(&self, store: &mut Store<WasmState>) -> Result<()> {
226 match self {
227 Extension::V0_7_0(ext) => ext.call_init_extension(store).await,
228 Extension::V0_6_0(ext) => ext.call_init_extension(store).await,
229 Extension::V0_5_0(ext) => ext.call_init_extension(store).await,
230 Extension::V0_4_0(ext) => ext.call_init_extension(store).await,
231 Extension::V0_3_0(ext) => ext.call_init_extension(store).await,
232 Extension::V0_2_0(ext) => ext.call_init_extension(store).await,
233 Extension::V0_1_0(ext) => ext.call_init_extension(store).await,
234 Extension::V0_0_6(ext) => ext.call_init_extension(store).await,
235 Extension::V0_0_4(ext) => ext.call_init_extension(store).await,
236 Extension::V0_0_1(ext) => ext.call_init_extension(store).await,
237 }
238 }
239
240 pub async fn call_language_server_command(
241 &self,
242 store: &mut Store<WasmState>,
243 language_server_id: &LanguageServerName,
244 language_name: &LanguageName,
245 resource: Resource<Arc<dyn WorktreeDelegate>>,
246 ) -> Result<Result<Command, String>> {
247 match self {
248 Extension::V0_7_0(ext) => {
249 ext.call_language_server_command(store, &language_server_id.0, resource)
250 .await
251 }
252 Extension::V0_6_0(ext) => {
253 ext.call_language_server_command(store, &language_server_id.0, resource)
254 .await
255 }
256 Extension::V0_5_0(ext) => {
257 ext.call_language_server_command(store, &language_server_id.0, resource)
258 .await
259 }
260 Extension::V0_4_0(ext) => {
261 ext.call_language_server_command(store, &language_server_id.0, resource)
262 .await
263 }
264 Extension::V0_3_0(ext) => {
265 ext.call_language_server_command(store, &language_server_id.0, resource)
266 .await
267 }
268 Extension::V0_2_0(ext) => Ok(ext
269 .call_language_server_command(store, &language_server_id.0, resource)
270 .await?
271 .map(|command| command.into())),
272 Extension::V0_1_0(ext) => Ok(ext
273 .call_language_server_command(store, &language_server_id.0, resource)
274 .await?
275 .map(|command| command.into())),
276 Extension::V0_0_6(ext) => Ok(ext
277 .call_language_server_command(store, &language_server_id.0, resource)
278 .await?
279 .map(|command| command.into())),
280 Extension::V0_0_4(ext) => Ok(ext
281 .call_language_server_command(
282 store,
283 &LanguageServerConfig {
284 name: language_server_id.0.to_string(),
285 language_name: language_name.to_string(),
286 },
287 resource,
288 )
289 .await?
290 .map(|command| command.into())),
291 Extension::V0_0_1(ext) => Ok(ext
292 .call_language_server_command(
293 store,
294 &LanguageServerConfig {
295 name: language_server_id.0.to_string(),
296 language_name: language_name.to_string(),
297 }
298 .into(),
299 resource,
300 )
301 .await?
302 .map(|command| command.into())),
303 }
304 }
305
306 pub async fn call_language_server_initialization_options(
307 &self,
308 store: &mut Store<WasmState>,
309 language_server_id: &LanguageServerName,
310 language_name: &LanguageName,
311 resource: Resource<Arc<dyn WorktreeDelegate>>,
312 ) -> Result<Result<Option<String>, String>> {
313 match self {
314 Extension::V0_7_0(ext) => {
315 ext.call_language_server_initialization_options(
316 store,
317 &language_server_id.0,
318 resource,
319 )
320 .await
321 }
322 Extension::V0_6_0(ext) => {
323 ext.call_language_server_initialization_options(
324 store,
325 &language_server_id.0,
326 resource,
327 )
328 .await
329 }
330 Extension::V0_5_0(ext) => {
331 ext.call_language_server_initialization_options(
332 store,
333 &language_server_id.0,
334 resource,
335 )
336 .await
337 }
338 Extension::V0_4_0(ext) => {
339 ext.call_language_server_initialization_options(
340 store,
341 &language_server_id.0,
342 resource,
343 )
344 .await
345 }
346 Extension::V0_3_0(ext) => {
347 ext.call_language_server_initialization_options(
348 store,
349 &language_server_id.0,
350 resource,
351 )
352 .await
353 }
354 Extension::V0_2_0(ext) => {
355 ext.call_language_server_initialization_options(
356 store,
357 &language_server_id.0,
358 resource,
359 )
360 .await
361 }
362 Extension::V0_1_0(ext) => {
363 ext.call_language_server_initialization_options(
364 store,
365 &language_server_id.0,
366 resource,
367 )
368 .await
369 }
370 Extension::V0_0_6(ext) => {
371 ext.call_language_server_initialization_options(
372 store,
373 &language_server_id.0,
374 resource,
375 )
376 .await
377 }
378 Extension::V0_0_4(ext) => {
379 ext.call_language_server_initialization_options(
380 store,
381 &LanguageServerConfig {
382 name: language_server_id.0.to_string(),
383 language_name: language_name.to_string(),
384 },
385 resource,
386 )
387 .await
388 }
389 Extension::V0_0_1(ext) => {
390 ext.call_language_server_initialization_options(
391 store,
392 &LanguageServerConfig {
393 name: language_server_id.0.to_string(),
394 language_name: language_name.to_string(),
395 }
396 .into(),
397 resource,
398 )
399 .await
400 }
401 }
402 }
403
404 pub async fn call_language_server_workspace_configuration(
405 &self,
406 store: &mut Store<WasmState>,
407 language_server_id: &LanguageServerName,
408 resource: Resource<Arc<dyn WorktreeDelegate>>,
409 ) -> Result<Result<Option<String>, String>> {
410 match self {
411 Extension::V0_7_0(ext) => {
412 ext.call_language_server_workspace_configuration(
413 store,
414 &language_server_id.0,
415 resource,
416 )
417 .await
418 }
419 Extension::V0_6_0(ext) => {
420 ext.call_language_server_workspace_configuration(
421 store,
422 &language_server_id.0,
423 resource,
424 )
425 .await
426 }
427 Extension::V0_5_0(ext) => {
428 ext.call_language_server_workspace_configuration(
429 store,
430 &language_server_id.0,
431 resource,
432 )
433 .await
434 }
435 Extension::V0_4_0(ext) => {
436 ext.call_language_server_workspace_configuration(
437 store,
438 &language_server_id.0,
439 resource,
440 )
441 .await
442 }
443 Extension::V0_3_0(ext) => {
444 ext.call_language_server_workspace_configuration(
445 store,
446 &language_server_id.0,
447 resource,
448 )
449 .await
450 }
451 Extension::V0_2_0(ext) => {
452 ext.call_language_server_workspace_configuration(
453 store,
454 &language_server_id.0,
455 resource,
456 )
457 .await
458 }
459 Extension::V0_1_0(ext) => {
460 ext.call_language_server_workspace_configuration(
461 store,
462 &language_server_id.0,
463 resource,
464 )
465 .await
466 }
467 Extension::V0_0_6(ext) => {
468 ext.call_language_server_workspace_configuration(
469 store,
470 &language_server_id.0,
471 resource,
472 )
473 .await
474 }
475 Extension::V0_0_4(_) | Extension::V0_0_1(_) => Ok(Ok(None)),
476 }
477 }
478
479 pub async fn call_language_server_additional_initialization_options(
480 &self,
481 store: &mut Store<WasmState>,
482 language_server_id: &LanguageServerName,
483 target_language_server_id: &LanguageServerName,
484 resource: Resource<Arc<dyn WorktreeDelegate>>,
485 ) -> Result<Result<Option<String>, String>> {
486 match self {
487 Extension::V0_7_0(ext) => {
488 ext.call_language_server_additional_initialization_options(
489 store,
490 &language_server_id.0,
491 &target_language_server_id.0,
492 resource,
493 )
494 .await
495 }
496 Extension::V0_6_0(ext) => {
497 ext.call_language_server_additional_initialization_options(
498 store,
499 &language_server_id.0,
500 &target_language_server_id.0,
501 resource,
502 )
503 .await
504 }
505 Extension::V0_5_0(ext) => {
506 ext.call_language_server_additional_initialization_options(
507 store,
508 &language_server_id.0,
509 &target_language_server_id.0,
510 resource,
511 )
512 .await
513 }
514 Extension::V0_4_0(ext) => {
515 ext.call_language_server_additional_initialization_options(
516 store,
517 &language_server_id.0,
518 &target_language_server_id.0,
519 resource,
520 )
521 .await
522 }
523 Extension::V0_3_0(_)
524 | Extension::V0_2_0(_)
525 | Extension::V0_1_0(_)
526 | Extension::V0_0_6(_)
527 | Extension::V0_0_4(_)
528 | Extension::V0_0_1(_) => Ok(Ok(None)),
529 }
530 }
531
532 pub async fn call_language_server_additional_workspace_configuration(
533 &self,
534 store: &mut Store<WasmState>,
535 language_server_id: &LanguageServerName,
536 target_language_server_id: &LanguageServerName,
537 resource: Resource<Arc<dyn WorktreeDelegate>>,
538 ) -> Result<Result<Option<String>, String>> {
539 match self {
540 Extension::V0_7_0(ext) => {
541 ext.call_language_server_additional_workspace_configuration(
542 store,
543 &language_server_id.0,
544 &target_language_server_id.0,
545 resource,
546 )
547 .await
548 }
549 Extension::V0_6_0(ext) => {
550 ext.call_language_server_additional_workspace_configuration(
551 store,
552 &language_server_id.0,
553 &target_language_server_id.0,
554 resource,
555 )
556 .await
557 }
558 Extension::V0_5_0(ext) => {
559 ext.call_language_server_additional_workspace_configuration(
560 store,
561 &language_server_id.0,
562 &target_language_server_id.0,
563 resource,
564 )
565 .await
566 }
567 Extension::V0_4_0(ext) => {
568 ext.call_language_server_additional_workspace_configuration(
569 store,
570 &language_server_id.0,
571 &target_language_server_id.0,
572 resource,
573 )
574 .await
575 }
576 Extension::V0_3_0(_)
577 | Extension::V0_2_0(_)
578 | Extension::V0_1_0(_)
579 | Extension::V0_0_6(_)
580 | Extension::V0_0_4(_)
581 | Extension::V0_0_1(_) => Ok(Ok(None)),
582 }
583 }
584
585 pub async fn call_labels_for_completions(
586 &self,
587 store: &mut Store<WasmState>,
588 language_server_id: &LanguageServerName,
589 completions: Vec<latest::Completion>,
590 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
591 match self {
592 Extension::V0_7_0(ext) => {
593 ext.call_labels_for_completions(store, &language_server_id.0, &completions)
594 .await
595 }
596 Extension::V0_6_0(ext) => Ok(ext
597 .call_labels_for_completions(
598 store,
599 &language_server_id.0,
600 &completions.into_iter().collect::<Vec<_>>(),
601 )
602 .await?
603 .map(|labels| {
604 labels
605 .into_iter()
606 .map(|label| label.map(Into::into))
607 .collect()
608 })),
609 Extension::V0_5_0(ext) => Ok(ext
610 .call_labels_for_completions(
611 store,
612 &language_server_id.0,
613 &completions.into_iter().collect::<Vec<_>>(),
614 )
615 .await?
616 .map(|labels| {
617 labels
618 .into_iter()
619 .map(|label| label.map(Into::into))
620 .collect()
621 })),
622 Extension::V0_4_0(ext) => Ok(ext
623 .call_labels_for_completions(
624 store,
625 &language_server_id.0,
626 &completions.into_iter().collect::<Vec<_>>(),
627 )
628 .await?
629 .map(|labels| {
630 labels
631 .into_iter()
632 .map(|label| label.map(Into::into))
633 .collect()
634 })),
635 Extension::V0_3_0(ext) => Ok(ext
636 .call_labels_for_completions(
637 store,
638 &language_server_id.0,
639 &completions.into_iter().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_2_0(ext) => Ok(ext
649 .call_labels_for_completions(
650 store,
651 &language_server_id.0,
652 &completions.into_iter().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_1_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_0_6(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_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
688 }
689 }
690
691 pub async fn call_labels_for_symbols(
692 &self,
693 store: &mut Store<WasmState>,
694 language_server_id: &LanguageServerName,
695 symbols: Vec<latest::Symbol>,
696 ) -> Result<Result<Vec<Option<CodeLabel>>, String>> {
697 match self {
698 Extension::V0_7_0(ext) => {
699 ext.call_labels_for_symbols(store, &language_server_id.0, &symbols)
700 .await
701 }
702 Extension::V0_6_0(ext) => Ok(ext
703 .call_labels_for_symbols(
704 store,
705 &language_server_id.0,
706 &symbols.into_iter().collect::<Vec<_>>(),
707 )
708 .await?
709 .map(|labels| {
710 labels
711 .into_iter()
712 .map(|label| label.map(Into::into))
713 .collect()
714 })),
715 Extension::V0_5_0(ext) => Ok(ext
716 .call_labels_for_symbols(
717 store,
718 &language_server_id.0,
719 &symbols.into_iter().collect::<Vec<_>>(),
720 )
721 .await?
722 .map(|labels| {
723 labels
724 .into_iter()
725 .map(|label| label.map(Into::into))
726 .collect()
727 })),
728 Extension::V0_4_0(ext) => Ok(ext
729 .call_labels_for_symbols(
730 store,
731 &language_server_id.0,
732 &symbols.into_iter().collect::<Vec<_>>(),
733 )
734 .await?
735 .map(|labels| {
736 labels
737 .into_iter()
738 .map(|label| label.map(Into::into))
739 .collect()
740 })),
741 Extension::V0_3_0(ext) => Ok(ext
742 .call_labels_for_symbols(
743 store,
744 &language_server_id.0,
745 &symbols.into_iter().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_2_0(ext) => Ok(ext
755 .call_labels_for_symbols(
756 store,
757 &language_server_id.0,
758 &symbols.into_iter().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_1_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_0_6(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_0_1(_) | Extension::V0_0_4(_) => Ok(Ok(Vec::new())),
794 }
795 }
796
797 pub async fn call_complete_slash_command_argument(
798 &self,
799 store: &mut Store<WasmState>,
800 command: &SlashCommand,
801 arguments: &[String],
802 ) -> Result<Result<Vec<SlashCommandArgumentCompletion>, String>> {
803 match self {
804 Extension::V0_7_0(ext) => {
805 ext.call_complete_slash_command_argument(store, command, arguments)
806 .await
807 }
808 Extension::V0_6_0(ext) => {
809 ext.call_complete_slash_command_argument(store, command, arguments)
810 .await
811 }
812 Extension::V0_5_0(ext) => {
813 ext.call_complete_slash_command_argument(store, command, arguments)
814 .await
815 }
816 Extension::V0_4_0(ext) => {
817 ext.call_complete_slash_command_argument(store, command, arguments)
818 .await
819 }
820 Extension::V0_3_0(ext) => {
821 ext.call_complete_slash_command_argument(store, command, arguments)
822 .await
823 }
824 Extension::V0_2_0(ext) => {
825 ext.call_complete_slash_command_argument(store, command, arguments)
826 .await
827 }
828 Extension::V0_1_0(ext) => {
829 ext.call_complete_slash_command_argument(store, command, arguments)
830 .await
831 }
832 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
833 Ok(Ok(Vec::new()))
834 }
835 }
836 }
837
838 pub async fn call_run_slash_command(
839 &self,
840 store: &mut Store<WasmState>,
841 command: &SlashCommand,
842 arguments: &[String],
843 resource: Option<Resource<Arc<dyn WorktreeDelegate>>>,
844 ) -> Result<Result<SlashCommandOutput, String>> {
845 match self {
846 Extension::V0_7_0(ext) => {
847 ext.call_run_slash_command(store, command, arguments, resource)
848 .await
849 }
850 Extension::V0_6_0(ext) => {
851 ext.call_run_slash_command(store, command, arguments, resource)
852 .await
853 }
854 Extension::V0_5_0(ext) => {
855 ext.call_run_slash_command(store, command, arguments, resource)
856 .await
857 }
858 Extension::V0_4_0(ext) => {
859 ext.call_run_slash_command(store, command, arguments, resource)
860 .await
861 }
862 Extension::V0_3_0(ext) => {
863 ext.call_run_slash_command(store, command, arguments, resource)
864 .await
865 }
866 Extension::V0_2_0(ext) => {
867 ext.call_run_slash_command(store, command, arguments, resource)
868 .await
869 }
870 Extension::V0_1_0(ext) => {
871 ext.call_run_slash_command(store, command, arguments, resource)
872 .await
873 }
874 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
875 anyhow::bail!("`run_slash_command` not available prior to v0.1.0");
876 }
877 }
878 }
879
880 pub async fn call_context_server_command(
881 &self,
882 store: &mut Store<WasmState>,
883 context_server_id: Arc<str>,
884 project: Resource<ExtensionProject>,
885 ) -> Result<Result<Command, String>> {
886 match self {
887 Extension::V0_7_0(ext) => {
888 ext.call_context_server_command(store, &context_server_id, project)
889 .await
890 }
891 Extension::V0_6_0(ext) => {
892 ext.call_context_server_command(store, &context_server_id, project)
893 .await
894 }
895 Extension::V0_5_0(ext) => {
896 ext.call_context_server_command(store, &context_server_id, project)
897 .await
898 }
899 Extension::V0_4_0(ext) => {
900 ext.call_context_server_command(store, &context_server_id, project)
901 .await
902 }
903 Extension::V0_3_0(ext) => {
904 ext.call_context_server_command(store, &context_server_id, project)
905 .await
906 }
907 Extension::V0_2_0(ext) => Ok(ext
908 .call_context_server_command(store, &context_server_id, project)
909 .await?
910 .map(Into::into)),
911 Extension::V0_0_1(_)
912 | Extension::V0_0_4(_)
913 | Extension::V0_0_6(_)
914 | Extension::V0_1_0(_) => {
915 anyhow::bail!("`context_server_command` not available prior to v0.2.0");
916 }
917 }
918 }
919
920 pub async fn call_context_server_configuration(
921 &self,
922 store: &mut Store<WasmState>,
923 context_server_id: Arc<str>,
924 project: Resource<ExtensionProject>,
925 ) -> Result<Result<Option<ContextServerConfiguration>, String>> {
926 match self {
927 Extension::V0_7_0(ext) => {
928 ext.call_context_server_configuration(store, &context_server_id, project)
929 .await
930 }
931 Extension::V0_6_0(ext) => {
932 ext.call_context_server_configuration(store, &context_server_id, project)
933 .await
934 }
935 Extension::V0_5_0(ext) => {
936 ext.call_context_server_configuration(store, &context_server_id, project)
937 .await
938 }
939 Extension::V0_0_1(_)
940 | Extension::V0_0_4(_)
941 | Extension::V0_0_6(_)
942 | Extension::V0_1_0(_)
943 | Extension::V0_2_0(_)
944 | Extension::V0_3_0(_)
945 | Extension::V0_4_0(_) => {
946 anyhow::bail!("`context_server_configuration` not available prior to v0.5.0");
947 }
948 }
949 }
950
951 pub async fn call_suggest_docs_packages(
952 &self,
953 store: &mut Store<WasmState>,
954 provider: &str,
955 ) -> Result<Result<Vec<String>, String>> {
956 match self {
957 Extension::V0_7_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
958 Extension::V0_6_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
959 Extension::V0_5_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
960 Extension::V0_4_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
961 Extension::V0_3_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
962 Extension::V0_2_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
963 Extension::V0_1_0(ext) => ext.call_suggest_docs_packages(store, provider).await,
964 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
965 anyhow::bail!("`suggest_docs_packages` not available prior to v0.1.0");
966 }
967 }
968 }
969
970 pub async fn call_index_docs(
971 &self,
972 store: &mut Store<WasmState>,
973 provider: &str,
974 package_name: &str,
975 kv_store: Resource<Arc<dyn KeyValueStoreDelegate>>,
976 ) -> Result<Result<(), String>> {
977 match self {
978 Extension::V0_7_0(ext) => {
979 ext.call_index_docs(store, provider, package_name, kv_store)
980 .await
981 }
982 Extension::V0_6_0(ext) => {
983 ext.call_index_docs(store, provider, package_name, kv_store)
984 .await
985 }
986 Extension::V0_5_0(ext) => {
987 ext.call_index_docs(store, provider, package_name, kv_store)
988 .await
989 }
990 Extension::V0_4_0(ext) => {
991 ext.call_index_docs(store, provider, package_name, kv_store)
992 .await
993 }
994 Extension::V0_3_0(ext) => {
995 ext.call_index_docs(store, provider, package_name, kv_store)
996 .await
997 }
998 Extension::V0_2_0(ext) => {
999 ext.call_index_docs(store, provider, package_name, kv_store)
1000 .await
1001 }
1002 Extension::V0_1_0(ext) => {
1003 ext.call_index_docs(store, provider, package_name, kv_store)
1004 .await
1005 }
1006 Extension::V0_0_1(_) | Extension::V0_0_4(_) | Extension::V0_0_6(_) => {
1007 anyhow::bail!("`index_docs` not available prior to v0.1.0");
1008 }
1009 }
1010 }
1011 pub async fn call_get_dap_binary(
1012 &self,
1013 store: &mut Store<WasmState>,
1014 adapter_name: Arc<str>,
1015 task: DebugTaskDefinition,
1016 user_installed_path: Option<PathBuf>,
1017 resource: Resource<Arc<dyn WorktreeDelegate>>,
1018 ) -> Result<Result<DebugAdapterBinary, String>> {
1019 match self {
1020 Extension::V0_7_0(ext) => {
1021 let dap_binary = ext
1022 .call_get_dap_binary(
1023 store,
1024 &adapter_name,
1025 &task.try_into()?,
1026 user_installed_path.as_ref().and_then(|p| p.to_str()),
1027 resource,
1028 )
1029 .await?
1030 .map_err(|e| anyhow!("{e:?}"))?;
1031
1032 Ok(Ok(dap_binary))
1033 }
1034 Extension::V0_6_0(ext) => {
1035 let dap_binary = ext
1036 .call_get_dap_binary(
1037 store,
1038 &adapter_name,
1039 &task.try_into()?,
1040 user_installed_path.as_ref().and_then(|p| p.to_str()),
1041 resource,
1042 )
1043 .await?
1044 .map_err(|e| anyhow!("{e:?}"))?;
1045
1046 Ok(Ok(dap_binary))
1047 }
1048 _ => anyhow::bail!("`get_dap_binary` not available prior to v0.6.0"),
1049 }
1050 }
1051 pub async fn call_dap_request_kind(
1052 &self,
1053 store: &mut Store<WasmState>,
1054 adapter_name: Arc<str>,
1055 config: serde_json::Value,
1056 ) -> Result<Result<StartDebuggingRequestArgumentsRequest, String>> {
1057 match self {
1058 Extension::V0_7_0(ext) => {
1059 let config =
1060 serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
1061 let dap_binary = ext
1062 .call_dap_request_kind(store, &adapter_name, &config)
1063 .await?
1064 .map_err(|e| anyhow!("{e:?}"))?;
1065
1066 Ok(Ok(dap_binary))
1067 }
1068 Extension::V0_6_0(ext) => {
1069 let config =
1070 serde_json::to_string(&config).context("Adapter config is not a valid JSON")?;
1071 let dap_binary = ext
1072 .call_dap_request_kind(store, &adapter_name, &config)
1073 .await?
1074 .map_err(|e| anyhow!("{e:?}"))?;
1075
1076 Ok(Ok(dap_binary))
1077 }
1078 _ => anyhow::bail!("`dap_request_kind` not available prior to v0.6.0"),
1079 }
1080 }
1081 pub async fn call_dap_config_to_scenario(
1082 &self,
1083 store: &mut Store<WasmState>,
1084 config: ZedDebugConfig,
1085 ) -> Result<Result<DebugScenario, String>> {
1086 match self {
1087 Extension::V0_7_0(ext) => {
1088 let config = config.into();
1089 let dap_binary = ext
1090 .call_dap_config_to_scenario(store, &config)
1091 .await?
1092 .map_err(|e| anyhow!("{e:?}"))?;
1093
1094 Ok(Ok(dap_binary.try_into()?))
1095 }
1096 Extension::V0_6_0(ext) => {
1097 let config = config.into();
1098 let dap_binary = ext
1099 .call_dap_config_to_scenario(store, &config)
1100 .await?
1101 .map_err(|e| anyhow!("{e:?}"))?;
1102
1103 Ok(Ok(dap_binary.try_into()?))
1104 }
1105 _ => anyhow::bail!("`dap_config_to_scenario` not available prior to v0.6.0"),
1106 }
1107 }
1108 pub async fn call_dap_locator_create_scenario(
1109 &self,
1110 store: &mut Store<WasmState>,
1111 locator_name: String,
1112 build_config_template: TaskTemplate,
1113 resolved_label: String,
1114 debug_adapter_name: String,
1115 ) -> Result<Option<DebugScenario>> {
1116 match self {
1117 Extension::V0_7_0(ext) => {
1118 let build_config_template = build_config_template.into();
1119 let dap_binary = ext
1120 .call_dap_locator_create_scenario(
1121 store,
1122 &locator_name,
1123 &build_config_template,
1124 &resolved_label,
1125 &debug_adapter_name,
1126 )
1127 .await?;
1128
1129 Ok(dap_binary.map(TryInto::try_into).transpose()?)
1130 }
1131 Extension::V0_6_0(ext) => {
1132 let build_config_template = build_config_template.into();
1133 let dap_binary = ext
1134 .call_dap_locator_create_scenario(
1135 store,
1136 &locator_name,
1137 &build_config_template,
1138 &resolved_label,
1139 &debug_adapter_name,
1140 )
1141 .await?;
1142
1143 Ok(dap_binary.map(TryInto::try_into).transpose()?)
1144 }
1145 _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1146 }
1147 }
1148 pub async fn call_run_dap_locator(
1149 &self,
1150 store: &mut Store<WasmState>,
1151 locator_name: String,
1152 resolved_build_task: SpawnInTerminal,
1153 ) -> Result<Result<DebugRequest, String>> {
1154 match self {
1155 Extension::V0_7_0(ext) => {
1156 let build_config_template = resolved_build_task.try_into()?;
1157 let dap_request = ext
1158 .call_run_dap_locator(store, &locator_name, &build_config_template)
1159 .await?
1160 .map_err(|e| anyhow!("{e:?}"))?;
1161
1162 Ok(Ok(dap_request.into()))
1163 }
1164 Extension::V0_6_0(ext) => {
1165 let build_config_template = resolved_build_task.try_into()?;
1166 let dap_request = ext
1167 .call_run_dap_locator(store, &locator_name, &build_config_template)
1168 .await?
1169 .map_err(|e| anyhow!("{e:?}"))?;
1170
1171 Ok(Ok(dap_request.into()))
1172 }
1173 _ => anyhow::bail!("`dap_locator_create_scenario` not available prior to v0.6.0"),
1174 }
1175 }
1176
1177 // =========================================================================
1178 // LLM Provider Methods (v0.7.0+)
1179 // =========================================================================
1180
1181 pub async fn call_llm_providers(
1182 &self,
1183 store: &mut Store<WasmState>,
1184 ) -> Result<Vec<latest::llm_provider::ProviderInfo>> {
1185 match self {
1186 Extension::V0_7_0(ext) => ext.call_llm_providers(store).await,
1187 _ => Ok(Vec::new()),
1188 }
1189 }
1190
1191 pub async fn call_llm_provider_models(
1192 &self,
1193 store: &mut Store<WasmState>,
1194 provider_id: &str,
1195 ) -> Result<Result<Vec<latest::llm_provider::ModelInfo>, String>> {
1196 match self {
1197 Extension::V0_7_0(ext) => ext.call_llm_provider_models(store, provider_id).await,
1198 _ => anyhow::bail!("`llm_provider_models` not available prior to v0.7.0"),
1199 }
1200 }
1201
1202 pub async fn call_llm_provider_is_authenticated(
1203 &self,
1204 store: &mut Store<WasmState>,
1205 provider_id: &str,
1206 ) -> Result<bool> {
1207 match self {
1208 Extension::V0_7_0(ext) => {
1209 ext.call_llm_provider_is_authenticated(store, provider_id)
1210 .await
1211 }
1212 _ => Ok(false),
1213 }
1214 }
1215
1216 pub async fn call_llm_provider_authenticate(
1217 &self,
1218 store: &mut Store<WasmState>,
1219 provider_id: &str,
1220 ) -> Result<Result<(), String>> {
1221 match self {
1222 Extension::V0_7_0(ext) => ext.call_llm_provider_authenticate(store, provider_id).await,
1223 _ => anyhow::bail!("`llm_provider_authenticate` not available prior to v0.7.0"),
1224 }
1225 }
1226
1227 pub async fn call_llm_provider_reset_credentials(
1228 &self,
1229 store: &mut Store<WasmState>,
1230 provider_id: &str,
1231 ) -> Result<Result<(), String>> {
1232 match self {
1233 Extension::V0_7_0(ext) => {
1234 ext.call_llm_provider_reset_credentials(store, provider_id)
1235 .await
1236 }
1237 _ => anyhow::bail!("`llm_provider_reset_credentials` not available prior to v0.7.0"),
1238 }
1239 }
1240
1241 pub async fn call_llm_count_tokens(
1242 &self,
1243 store: &mut Store<WasmState>,
1244 provider_id: &str,
1245 model_id: &str,
1246 request: &latest::llm_provider::CompletionRequest,
1247 ) -> Result<Result<u64, String>> {
1248 match self {
1249 Extension::V0_7_0(ext) => {
1250 ext.call_llm_count_tokens(store, provider_id, model_id, request)
1251 .await
1252 }
1253 _ => anyhow::bail!("`llm_count_tokens` not available prior to v0.7.0"),
1254 }
1255 }
1256
1257 pub async fn call_llm_stream_completion_start(
1258 &self,
1259 store: &mut Store<WasmState>,
1260 provider_id: &str,
1261 model_id: &str,
1262 request: &latest::llm_provider::CompletionRequest,
1263 ) -> Result<Result<String, String>> {
1264 match self {
1265 Extension::V0_7_0(ext) => {
1266 ext.call_llm_stream_completion_start(store, provider_id, model_id, request)
1267 .await
1268 }
1269 _ => anyhow::bail!("`llm_stream_completion_start` not available prior to v0.7.0"),
1270 }
1271 }
1272
1273 pub async fn call_llm_stream_completion_next(
1274 &self,
1275 store: &mut Store<WasmState>,
1276 stream_id: &str,
1277 ) -> Result<Result<Option<latest::llm_provider::CompletionEvent>, String>> {
1278 match self {
1279 Extension::V0_7_0(ext) => ext.call_llm_stream_completion_next(store, stream_id).await,
1280 _ => anyhow::bail!("`llm_stream_completion_next` not available prior to v0.7.0"),
1281 }
1282 }
1283
1284 pub async fn call_llm_stream_completion_close(
1285 &self,
1286 store: &mut Store<WasmState>,
1287 stream_id: &str,
1288 ) -> Result<()> {
1289 match self {
1290 Extension::V0_7_0(ext) => ext.call_llm_stream_completion_close(store, stream_id).await,
1291 _ => anyhow::bail!("`llm_stream_completion_close` not available prior to v0.7.0"),
1292 }
1293 }
1294
1295 pub async fn call_llm_cache_configuration(
1296 &self,
1297 store: &mut Store<WasmState>,
1298 provider_id: &str,
1299 model_id: &str,
1300 ) -> Result<Option<latest::llm_provider::CacheConfiguration>> {
1301 match self {
1302 Extension::V0_7_0(ext) => {
1303 ext.call_llm_cache_configuration(store, provider_id, model_id)
1304 .await
1305 }
1306 _ => Ok(None),
1307 }
1308 }
1309}
1310
1311trait ToWasmtimeResult<T> {
1312 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>>;
1313}
1314
1315impl<T> ToWasmtimeResult<T> for Result<T> {
1316 fn to_wasmtime_result(self) -> wasmtime::Result<Result<T, String>> {
1317 Ok(self.map_err(|error| format!("{error:?}")))
1318 }
1319}