1//! The Zed Rust Extension API allows you write extensions for [Zed](https://zed.dev/) in Rust.
2
3pub mod http_client;
4pub mod process;
5pub mod settings;
6
7use core::fmt;
8
9use wit::*;
10
11pub use serde_json;
12
13// WIT re-exports.
14//
15// We explicitly enumerate the symbols we want to re-export, as there are some
16// that we may want to shadow to provide a cleaner Rust API.
17pub use wit::{
18 CodeLabel, CodeLabelSpan, CodeLabelSpanLiteral, Command, DownloadedFileType, EnvVars,
19 KeyValueStore, LanguageServerInstallationStatus, Project, Range, Worktree, download_file,
20 llm_delete_credential, llm_get_credential, llm_get_env_var, llm_request_credential,
21 llm_store_credential, make_file_executable,
22 zed::extension::context_server::ContextServerConfiguration,
23 zed::extension::dap::{
24 AttachRequest, BuildTaskDefinition, BuildTaskDefinitionTemplatePayload, BuildTaskTemplate,
25 DebugAdapterBinary, DebugConfig, DebugRequest, DebugScenario, DebugTaskDefinition,
26 LaunchRequest, StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
27 TaskTemplate, TcpArguments, TcpArgumentsTemplate, resolve_tcp_template,
28 },
29 zed::extension::github::{
30 GithubRelease, GithubReleaseAsset, GithubReleaseOptions, github_release_by_tag_name,
31 latest_github_release,
32 },
33 zed::extension::llm_provider::{
34 CacheConfiguration as LlmCacheConfiguration, CompletionEvent as LlmCompletionEvent,
35 CompletionRequest as LlmCompletionRequest, CredentialType as LlmCredentialType,
36 ImageData as LlmImageData, MessageContent as LlmMessageContent,
37 MessageRole as LlmMessageRole, ModelCapabilities as LlmModelCapabilities,
38 ModelInfo as LlmModelInfo, ProviderInfo as LlmProviderInfo,
39 RequestMessage as LlmRequestMessage, StopReason as LlmStopReason,
40 ThinkingContent as LlmThinkingContent, TokenUsage as LlmTokenUsage,
41 ToolChoice as LlmToolChoice, ToolDefinition as LlmToolDefinition,
42 ToolInputFormat as LlmToolInputFormat, ToolResult as LlmToolResult,
43 ToolResultContent as LlmToolResultContent, ToolUse as LlmToolUse,
44 ToolUseJsonParseError as LlmToolUseJsonParseError,
45 },
46 zed::extension::nodejs::{
47 node_binary_path, npm_install_package, npm_package_installed_version,
48 npm_package_latest_version,
49 },
50 zed::extension::platform::{Architecture, Os, current_platform},
51 zed::extension::slash_command::{
52 SlashCommand, SlashCommandArgumentCompletion, SlashCommandOutput, SlashCommandOutputSection,
53 },
54};
55
56// Undocumented WIT re-exports.
57//
58// These are symbols that need to be public for the purposes of implementing
59// the extension host, but aren't relevant to extension authors.
60#[doc(hidden)]
61pub use wit::Guest;
62
63/// Constructs for interacting with language servers over the
64/// Language Server Protocol (LSP).
65pub mod lsp {
66 pub use crate::wit::zed::extension::lsp::{
67 Completion, CompletionKind, InsertTextFormat, Symbol, SymbolKind,
68 };
69}
70
71/// A result returned from a Zed extension.
72pub type Result<T, E = String> = core::result::Result<T, E>;
73
74/// Updates the installation status for the given language server.
75pub fn set_language_server_installation_status(
76 language_server_id: &LanguageServerId,
77 status: &LanguageServerInstallationStatus,
78) {
79 wit::set_language_server_installation_status(&language_server_id.0, status)
80}
81
82/// A Zed extension.
83pub trait Extension: Send + Sync {
84 /// Returns a new instance of the extension.
85 fn new() -> Self
86 where
87 Self: Sized;
88
89 /// Returns the command used to start the language server for the specified
90 /// language.
91 fn language_server_command(
92 &mut self,
93 _language_server_id: &LanguageServerId,
94 _worktree: &Worktree,
95 ) -> Result<Command> {
96 Err("`language_server_command` not implemented".to_string())
97 }
98
99 /// Returns the initialization options to pass to the specified language server.
100 fn language_server_initialization_options(
101 &mut self,
102 _language_server_id: &LanguageServerId,
103 _worktree: &Worktree,
104 ) -> Result<Option<serde_json::Value>> {
105 Ok(None)
106 }
107
108 /// Returns the workspace configuration options to pass to the language server.
109 fn language_server_workspace_configuration(
110 &mut self,
111 _language_server_id: &LanguageServerId,
112 _worktree: &Worktree,
113 ) -> Result<Option<serde_json::Value>> {
114 Ok(None)
115 }
116
117 /// Returns the initialization options to pass to the other language server.
118 fn language_server_additional_initialization_options(
119 &mut self,
120 _language_server_id: &LanguageServerId,
121 _target_language_server_id: &LanguageServerId,
122 _worktree: &Worktree,
123 ) -> Result<Option<serde_json::Value>> {
124 Ok(None)
125 }
126
127 /// Returns the workspace configuration options to pass to the other language server.
128 fn language_server_additional_workspace_configuration(
129 &mut self,
130 _language_server_id: &LanguageServerId,
131 _target_language_server_id: &LanguageServerId,
132 _worktree: &Worktree,
133 ) -> Result<Option<serde_json::Value>> {
134 Ok(None)
135 }
136
137 /// Returns the label for the given completion.
138 fn label_for_completion(
139 &self,
140 _language_server_id: &LanguageServerId,
141 _completion: Completion,
142 ) -> Option<CodeLabel> {
143 None
144 }
145
146 /// Returns the label for the given symbol.
147 fn label_for_symbol(
148 &self,
149 _language_server_id: &LanguageServerId,
150 _symbol: Symbol,
151 ) -> Option<CodeLabel> {
152 None
153 }
154
155 /// Returns the completions that should be shown when completing the provided slash command with the given query.
156 fn complete_slash_command_argument(
157 &self,
158 _command: SlashCommand,
159 _args: Vec<String>,
160 ) -> Result<Vec<SlashCommandArgumentCompletion>, String> {
161 Ok(Vec::new())
162 }
163
164 /// Returns the output from running the provided slash command.
165 fn run_slash_command(
166 &self,
167 _command: SlashCommand,
168 _args: Vec<String>,
169 _worktree: Option<&Worktree>,
170 ) -> Result<SlashCommandOutput, String> {
171 Err("`run_slash_command` not implemented".to_string())
172 }
173
174 /// Returns the command used to start a context server.
175 fn context_server_command(
176 &mut self,
177 _context_server_id: &ContextServerId,
178 _project: &Project,
179 ) -> Result<Command> {
180 Err("`context_server_command` not implemented".to_string())
181 }
182
183 /// Returns the configuration options for the specified context server.
184 fn context_server_configuration(
185 &mut self,
186 _context_server_id: &ContextServerId,
187 _project: &Project,
188 ) -> Result<Option<ContextServerConfiguration>> {
189 Ok(None)
190 }
191
192 /// Returns a list of package names as suggestions to be included in the
193 /// search results of the `/docs` slash command.
194 ///
195 /// This can be used to provide completions for known packages (e.g., from the
196 /// local project or a registry) before a package has been indexed.
197 fn suggest_docs_packages(&self, _provider: String) -> Result<Vec<String>, String> {
198 Ok(Vec::new())
199 }
200
201 /// Indexes the docs for the specified package.
202 fn index_docs(
203 &self,
204 _provider: String,
205 _package: String,
206 _database: &KeyValueStore,
207 ) -> Result<(), String> {
208 Err("`index_docs` not implemented".to_string())
209 }
210
211 /// Returns the debug adapter binary for the specified adapter name and configuration.
212 fn get_dap_binary(
213 &mut self,
214 _adapter_name: String,
215 _config: DebugTaskDefinition,
216 _user_provided_debug_adapter_path: Option<String>,
217 _worktree: &Worktree,
218 ) -> Result<DebugAdapterBinary, String> {
219 Err("`get_dap_binary` not implemented".to_string())
220 }
221
222 /// Determines whether the specified adapter configuration should *launch* a new debuggee process
223 /// or *attach* to an existing one. This function should not perform any further validation (outside of determining the kind of a request).
224 /// This function should return an error when the kind cannot be determined (rather than fall back to a known default).
225 fn dap_request_kind(
226 &mut self,
227 _adapter_name: String,
228 _config: serde_json::Value,
229 ) -> Result<StartDebuggingRequestArgumentsRequest, String> {
230 Err("`dap_request_kind` not implemented".to_string())
231 }
232 /// Converts a high-level definition of a debug scenario (originating in a new session UI) to a "low-level" configuration suitable for a particular adapter.
233 ///
234 /// In layman's terms: given a program, list of arguments, current working directory and environment variables,
235 /// create a configuration that can be used to start a debug session.
236 fn dap_config_to_scenario(&mut self, _config: DebugConfig) -> Result<DebugScenario, String> {
237 Err("`dap_config_to_scenario` not implemented".to_string())
238 }
239
240 /// Locators are entities that convert a Zed task into a debug scenario.
241 ///
242 /// They can be provided even by extensions that don't provide a debug adapter.
243 /// For all tasks applicable to a given buffer, Zed will query all locators to find one that can turn the task into a debug scenario.
244 /// A converted debug scenario can include a build task (it shouldn't contain any configuration in such case); a build task result will later
245 /// be resolved with [`Extension::run_dap_locator`].
246 ///
247 /// To work through a real-world example, take a `cargo run` task and a hypothetical `cargo` locator:
248 /// 1. We may need to modify the task; in this case, it is problematic that `cargo run` spawns a binary. We should turn `cargo run` into a debug scenario with
249 /// `cargo build` task. This is the decision we make at `dap_locator_create_scenario` scope.
250 /// 2. Then, after the build task finishes, we will run `run_dap_locator` of the locator that produced the build task to find the program to be debugged. This function
251 /// should give us a debugger-agnostic configuration for launching a debug target (that we end up resolving with [`Extension::dap_config_to_scenario`]). It's almost as if the user
252 /// found the artifact path by themselves.
253 ///
254 /// Note that you're not obliged to use build tasks with locators. Specifically, it is sufficient to provide a debug configuration directly in the return value of
255 /// `dap_locator_create_scenario` if you're able to do that. Make sure to not fill out `build` field in that case, as that will prevent Zed from running second phase of resolution in such case.
256 /// This might be of particular relevance to interpreted languages.
257 fn dap_locator_create_scenario(
258 &mut self,
259 _locator_name: String,
260 _build_task: TaskTemplate,
261 _resolved_label: String,
262 _debug_adapter_name: String,
263 ) -> Option<DebugScenario> {
264 None
265 }
266
267 /// Runs the second phase of locator resolution.
268 /// See [`Extension::dap_locator_create_scenario`] for a hefty comment on locators.
269 fn run_dap_locator(
270 &mut self,
271 _locator_name: String,
272 _build_task: TaskTemplate,
273 ) -> Result<DebugRequest, String> {
274 Err("`run_dap_locator` not implemented".to_string())
275 }
276
277 // =========================================================================
278 // Language Model Provider Methods
279 // =========================================================================
280
281 /// Returns information about language model providers offered by this extension.
282 fn llm_providers(&self) -> Vec<LlmProviderInfo> {
283 Vec::new()
284 }
285
286 /// Returns the models available for a provider.
287 fn llm_provider_models(&self, _provider_id: &str) -> Result<Vec<LlmModelInfo>, String> {
288 Ok(Vec::new())
289 }
290
291 /// Check if the provider is authenticated.
292 fn llm_provider_is_authenticated(&self, _provider_id: &str) -> bool {
293 false
294 }
295
296 /// Attempt to authenticate the provider.
297 fn llm_provider_authenticate(&mut self, _provider_id: &str) -> Result<(), String> {
298 Err("`llm_provider_authenticate` not implemented".to_string())
299 }
300
301 /// Reset credentials for the provider.
302 fn llm_provider_reset_credentials(&mut self, _provider_id: &str) -> Result<(), String> {
303 Err("`llm_provider_reset_credentials` not implemented".to_string())
304 }
305
306 /// Count tokens for a request.
307 fn llm_count_tokens(
308 &self,
309 _provider_id: &str,
310 _model_id: &str,
311 _request: &LlmCompletionRequest,
312 ) -> Result<u64, String> {
313 Err("`llm_count_tokens` not implemented".to_string())
314 }
315
316 /// Start streaming a completion from the model.
317 /// Returns a stream ID that can be used with `llm_stream_completion_next` and `llm_stream_completion_close`.
318 fn llm_stream_completion_start(
319 &mut self,
320 _provider_id: &str,
321 _model_id: &str,
322 _request: &LlmCompletionRequest,
323 ) -> Result<String, String> {
324 Err("`llm_stream_completion_start` not implemented".to_string())
325 }
326
327 /// Get the next event from a completion stream.
328 /// Returns `Ok(None)` when the stream is complete.
329 fn llm_stream_completion_next(
330 &mut self,
331 _stream_id: &str,
332 ) -> Result<Option<LlmCompletionEvent>, String> {
333 Err("`llm_stream_completion_next` not implemented".to_string())
334 }
335
336 /// Close a completion stream and release its resources.
337 fn llm_stream_completion_close(&mut self, _stream_id: &str) {
338 // Default implementation does nothing
339 }
340
341 /// Get cache configuration for a model (if prompt caching is supported).
342 fn llm_cache_configuration(
343 &self,
344 _provider_id: &str,
345 _model_id: &str,
346 ) -> Option<LlmCacheConfiguration> {
347 None
348 }
349}
350
351/// Registers the provided type as a Zed extension.
352///
353/// The type must implement the [`Extension`] trait.
354#[macro_export]
355macro_rules! register_extension {
356 ($extension_type:ty) => {
357 #[cfg(target_os = "wasi")]
358 mod wasi_ext {
359 unsafe extern "C" {
360 static mut errno: i32;
361 pub static mut __wasilibc_cwd: *mut std::ffi::c_char;
362 }
363
364 pub fn init_cwd() {
365 unsafe {
366 // Ensure that our chdir function is linked, instead of the
367 // one from wasi-libc in the chdir.o translation unit. Otherwise
368 // we risk linking in `__wasilibc_find_relpath_alloc` which
369 // is a weak symbol and is being used by
370 // `__wasilibc_find_relpath`, which we do not want on
371 // Windows.
372 chdir(std::ptr::null());
373
374 __wasilibc_cwd = std::ffi::CString::new(std::env::var("PWD").unwrap())
375 .unwrap()
376 .into_raw()
377 .cast();
378 }
379 }
380
381 #[unsafe(no_mangle)]
382 pub unsafe extern "C" fn chdir(raw_path: *const std::ffi::c_char) -> i32 {
383 // Forbid extensions from changing CWD and so return an appropriate error code.
384 errno = 58; // NOTSUP
385 return -1;
386 }
387 }
388
389 #[unsafe(export_name = "init-extension")]
390 pub extern "C" fn __init_extension() {
391 #[cfg(target_os = "wasi")]
392 wasi_ext::init_cwd();
393
394 zed_extension_api::register_extension(|| {
395 Box::new(<$extension_type as zed_extension_api::Extension>::new())
396 });
397 }
398 };
399}
400
401#[doc(hidden)]
402pub fn register_extension(build_extension: fn() -> Box<dyn Extension>) {
403 unsafe { EXTENSION = Some((build_extension)()) }
404}
405
406fn extension() -> &'static mut dyn Extension {
407 #[expect(static_mut_refs)]
408 unsafe {
409 EXTENSION.as_deref_mut().unwrap()
410 }
411}
412
413static mut EXTENSION: Option<Box<dyn Extension>> = None;
414
415#[cfg(target_arch = "wasm32")]
416#[unsafe(link_section = "zed:api-version")]
417#[doc(hidden)]
418pub static ZED_API_VERSION: [u8; 6] = *include_bytes!(concat!(env!("OUT_DIR"), "/version_bytes"));
419
420mod wit {
421
422 wit_bindgen::generate!({
423 skip: ["init-extension"],
424 path: "./wit/since_v0.7.0",
425 });
426}
427
428wit::export!(Component);
429
430struct Component;
431
432impl wit::Guest for Component {
433 fn language_server_command(
434 language_server_id: String,
435 worktree: &wit::Worktree,
436 ) -> Result<wit::Command> {
437 let language_server_id = LanguageServerId(language_server_id);
438 extension().language_server_command(&language_server_id, worktree)
439 }
440
441 fn language_server_initialization_options(
442 language_server_id: String,
443 worktree: &Worktree,
444 ) -> Result<Option<String>, String> {
445 let language_server_id = LanguageServerId(language_server_id);
446 Ok(extension()
447 .language_server_initialization_options(&language_server_id, worktree)?
448 .and_then(|value| serde_json::to_string(&value).ok()))
449 }
450
451 fn language_server_workspace_configuration(
452 language_server_id: String,
453 worktree: &Worktree,
454 ) -> Result<Option<String>, String> {
455 let language_server_id = LanguageServerId(language_server_id);
456 Ok(extension()
457 .language_server_workspace_configuration(&language_server_id, worktree)?
458 .and_then(|value| serde_json::to_string(&value).ok()))
459 }
460
461 fn language_server_additional_initialization_options(
462 language_server_id: String,
463 target_language_server_id: String,
464 worktree: &Worktree,
465 ) -> Result<Option<String>, String> {
466 let language_server_id = LanguageServerId(language_server_id);
467 let target_language_server_id = LanguageServerId(target_language_server_id);
468 Ok(extension()
469 .language_server_additional_initialization_options(
470 &language_server_id,
471 &target_language_server_id,
472 worktree,
473 )?
474 .and_then(|value| serde_json::to_string(&value).ok()))
475 }
476
477 fn language_server_additional_workspace_configuration(
478 language_server_id: String,
479 target_language_server_id: String,
480 worktree: &Worktree,
481 ) -> Result<Option<String>, String> {
482 let language_server_id = LanguageServerId(language_server_id);
483 let target_language_server_id = LanguageServerId(target_language_server_id);
484 Ok(extension()
485 .language_server_additional_workspace_configuration(
486 &language_server_id,
487 &target_language_server_id,
488 worktree,
489 )?
490 .and_then(|value| serde_json::to_string(&value).ok()))
491 }
492
493 fn labels_for_completions(
494 language_server_id: String,
495 completions: Vec<Completion>,
496 ) -> Result<Vec<Option<CodeLabel>>, String> {
497 let language_server_id = LanguageServerId(language_server_id);
498 let mut labels = Vec::new();
499 for (ix, completion) in completions.into_iter().enumerate() {
500 let label = extension().label_for_completion(&language_server_id, completion);
501 if let Some(label) = label {
502 labels.resize(ix + 1, None);
503 *labels.last_mut().unwrap() = Some(label);
504 }
505 }
506 Ok(labels)
507 }
508
509 fn labels_for_symbols(
510 language_server_id: String,
511 symbols: Vec<Symbol>,
512 ) -> Result<Vec<Option<CodeLabel>>, String> {
513 let language_server_id = LanguageServerId(language_server_id);
514 let mut labels = Vec::new();
515 for (ix, symbol) in symbols.into_iter().enumerate() {
516 let label = extension().label_for_symbol(&language_server_id, symbol);
517 if let Some(label) = label {
518 labels.resize(ix + 1, None);
519 *labels.last_mut().unwrap() = Some(label);
520 }
521 }
522 Ok(labels)
523 }
524
525 fn complete_slash_command_argument(
526 command: SlashCommand,
527 args: Vec<String>,
528 ) -> Result<Vec<SlashCommandArgumentCompletion>, String> {
529 extension().complete_slash_command_argument(command, args)
530 }
531
532 fn run_slash_command(
533 command: SlashCommand,
534 args: Vec<String>,
535 worktree: Option<&Worktree>,
536 ) -> Result<SlashCommandOutput, String> {
537 extension().run_slash_command(command, args, worktree)
538 }
539
540 fn context_server_command(
541 context_server_id: String,
542 project: &Project,
543 ) -> Result<wit::Command> {
544 let context_server_id = ContextServerId(context_server_id);
545 extension().context_server_command(&context_server_id, project)
546 }
547
548 fn context_server_configuration(
549 context_server_id: String,
550 project: &Project,
551 ) -> Result<Option<ContextServerConfiguration>, String> {
552 let context_server_id = ContextServerId(context_server_id);
553 extension().context_server_configuration(&context_server_id, project)
554 }
555
556 fn suggest_docs_packages(provider: String) -> Result<Vec<String>, String> {
557 extension().suggest_docs_packages(provider)
558 }
559
560 fn index_docs(
561 provider: String,
562 package: String,
563 database: &KeyValueStore,
564 ) -> Result<(), String> {
565 extension().index_docs(provider, package, database)
566 }
567
568 fn get_dap_binary(
569 adapter_name: String,
570 config: DebugTaskDefinition,
571 user_installed_path: Option<String>,
572 worktree: &Worktree,
573 ) -> Result<wit::DebugAdapterBinary, String> {
574 extension().get_dap_binary(adapter_name, config, user_installed_path, worktree)
575 }
576
577 fn dap_request_kind(
578 adapter_name: String,
579 config: String,
580 ) -> Result<StartDebuggingRequestArgumentsRequest, String> {
581 extension().dap_request_kind(
582 adapter_name,
583 serde_json::from_str(&config).map_err(|e| format!("Failed to parse config: {e}"))?,
584 )
585 }
586 fn dap_config_to_scenario(config: DebugConfig) -> Result<DebugScenario, String> {
587 extension().dap_config_to_scenario(config)
588 }
589 fn dap_locator_create_scenario(
590 locator_name: String,
591 build_task: TaskTemplate,
592 resolved_label: String,
593 debug_adapter_name: String,
594 ) -> Option<DebugScenario> {
595 extension().dap_locator_create_scenario(
596 locator_name,
597 build_task,
598 resolved_label,
599 debug_adapter_name,
600 )
601 }
602 fn run_dap_locator(
603 locator_name: String,
604 build_task: TaskTemplate,
605 ) -> Result<DebugRequest, String> {
606 extension().run_dap_locator(locator_name, build_task)
607 }
608
609 // =========================================================================
610 // Language Model Provider Methods
611 // =========================================================================
612
613 fn llm_providers() -> Vec<LlmProviderInfo> {
614 extension().llm_providers()
615 }
616
617 fn llm_provider_models(provider_id: String) -> Result<Vec<LlmModelInfo>, String> {
618 extension().llm_provider_models(&provider_id)
619 }
620
621 fn llm_provider_is_authenticated(provider_id: String) -> bool {
622 extension().llm_provider_is_authenticated(&provider_id)
623 }
624
625 fn llm_provider_authenticate(provider_id: String) -> Result<(), String> {
626 extension().llm_provider_authenticate(&provider_id)
627 }
628
629 fn llm_provider_reset_credentials(provider_id: String) -> Result<(), String> {
630 extension().llm_provider_reset_credentials(&provider_id)
631 }
632
633 fn llm_count_tokens(
634 provider_id: String,
635 model_id: String,
636 request: LlmCompletionRequest,
637 ) -> Result<u64, String> {
638 extension().llm_count_tokens(&provider_id, &model_id, &request)
639 }
640
641 fn llm_stream_completion_start(
642 provider_id: String,
643 model_id: String,
644 request: LlmCompletionRequest,
645 ) -> Result<String, String> {
646 extension().llm_stream_completion_start(&provider_id, &model_id, &request)
647 }
648
649 fn llm_stream_completion_next(stream_id: String) -> Result<Option<LlmCompletionEvent>, String> {
650 extension().llm_stream_completion_next(&stream_id)
651 }
652
653 fn llm_stream_completion_close(stream_id: String) {
654 extension().llm_stream_completion_close(&stream_id)
655 }
656
657 fn llm_cache_configuration(
658 provider_id: String,
659 model_id: String,
660 ) -> Option<LlmCacheConfiguration> {
661 extension().llm_cache_configuration(&provider_id, &model_id)
662 }
663}
664
665/// The ID of a language server.
666#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
667pub struct LanguageServerId(String);
668
669impl AsRef<str> for LanguageServerId {
670 fn as_ref(&self) -> &str {
671 &self.0
672 }
673}
674
675impl fmt::Display for LanguageServerId {
676 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
677 write!(f, "{}", self.0)
678 }
679}
680
681/// The ID of a context server.
682#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
683pub struct ContextServerId(String);
684
685impl AsRef<str> for ContextServerId {
686 fn as_ref(&self) -> &str {
687 &self.0
688 }
689}
690
691impl fmt::Display for ContextServerId {
692 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693 write!(f, "{}", self.0)
694 }
695}
696
697impl CodeLabelSpan {
698 /// Returns a [`CodeLabelSpan::CodeRange`].
699 pub fn code_range(range: impl Into<wit::Range>) -> Self {
700 Self::CodeRange(range.into())
701 }
702
703 /// Returns a [`CodeLabelSpan::Literal`].
704 pub fn literal(text: impl Into<String>, highlight_name: Option<String>) -> Self {
705 Self::Literal(CodeLabelSpanLiteral {
706 text: text.into(),
707 highlight_name,
708 })
709 }
710}
711
712impl From<std::ops::Range<u32>> for wit::Range {
713 fn from(value: std::ops::Range<u32>) -> Self {
714 Self {
715 start: value.start,
716 end: value.end,
717 }
718 }
719}
720
721impl From<std::ops::Range<usize>> for wit::Range {
722 fn from(value: std::ops::Range<usize>) -> Self {
723 Self {
724 start: value.start as u32,
725 end: value.end as u32,
726 }
727 }
728}