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