1use std::any::Any;
2use std::ops::Range;
3use std::path::PathBuf;
4use std::pin::Pin;
5use std::sync::Arc;
6
7use anyhow::{Context as _, Result};
8use async_trait::async_trait;
9use collections::HashMap;
10use extension::{Extension, ExtensionLanguageServerProxy, WorktreeDelegate};
11use fs::Fs;
12use futures::{Future, FutureExt};
13use gpui::AsyncApp;
14use language::{
15 BinaryStatus, CodeLabel, HighlightId, Language, LanguageName, LanguageServerStatusUpdate,
16 LanguageToolchainStore, LspAdapter, LspAdapterDelegate,
17};
18use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName};
19use serde::Serialize;
20use serde_json::Value;
21use util::{ResultExt, fs::make_file_executable, maybe};
22
23use crate::LanguageServerRegistryProxy;
24
25/// An adapter that allows an [`LspAdapterDelegate`] to be used as a [`WorktreeDelegate`].
26struct WorktreeDelegateAdapter(pub Arc<dyn LspAdapterDelegate>);
27
28#[async_trait]
29impl WorktreeDelegate for WorktreeDelegateAdapter {
30 fn id(&self) -> u64 {
31 self.0.worktree_id().to_proto()
32 }
33
34 fn root_path(&self) -> String {
35 self.0.worktree_root_path().to_string_lossy().to_string()
36 }
37
38 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
39 self.0.read_text_file(path).await
40 }
41
42 async fn which(&self, binary_name: String) -> Option<String> {
43 self.0
44 .which(binary_name.as_ref())
45 .await
46 .map(|path| path.to_string_lossy().to_string())
47 }
48
49 async fn shell_env(&self) -> Vec<(String, String)> {
50 self.0.shell_env().await.into_iter().collect()
51 }
52}
53
54impl ExtensionLanguageServerProxy for LanguageServerRegistryProxy {
55 fn register_language_server(
56 &self,
57 extension: Arc<dyn Extension>,
58 language_server_id: LanguageServerName,
59 language: LanguageName,
60 ) {
61 self.language_registry.register_lsp_adapter(
62 language.clone(),
63 Arc::new(ExtensionLspAdapter::new(
64 extension,
65 language_server_id,
66 language,
67 )),
68 );
69 }
70
71 fn remove_language_server(
72 &self,
73 language: &LanguageName,
74 language_server_id: &LanguageServerName,
75 ) {
76 self.language_registry
77 .remove_lsp_adapter(language, language_server_id);
78 }
79
80 fn update_language_server_status(
81 &self,
82 language_server_id: LanguageServerName,
83 status: BinaryStatus,
84 ) {
85 self.language_registry.update_lsp_status(
86 language_server_id,
87 LanguageServerStatusUpdate::Binary(status),
88 );
89 }
90}
91
92struct ExtensionLspAdapter {
93 extension: Arc<dyn Extension>,
94 language_server_id: LanguageServerName,
95 language_name: LanguageName,
96}
97
98impl ExtensionLspAdapter {
99 fn new(
100 extension: Arc<dyn Extension>,
101 language_server_id: LanguageServerName,
102 language_name: LanguageName,
103 ) -> Self {
104 Self {
105 extension,
106 language_server_id,
107 language_name,
108 }
109 }
110}
111
112#[async_trait(?Send)]
113impl LspAdapter for ExtensionLspAdapter {
114 fn name(&self) -> LanguageServerName {
115 self.language_server_id.clone()
116 }
117
118 fn get_language_server_command<'a>(
119 self: Arc<Self>,
120 delegate: Arc<dyn LspAdapterDelegate>,
121 _: Arc<dyn LanguageToolchainStore>,
122 _: LanguageServerBinaryOptions,
123 _: futures::lock::MutexGuard<'a, Option<LanguageServerBinary>>,
124 _: &'a mut AsyncApp,
125 ) -> Pin<Box<dyn 'a + Future<Output = Result<LanguageServerBinary>>>> {
126 async move {
127 let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
128 let command = self
129 .extension
130 .language_server_command(
131 self.language_server_id.clone(),
132 self.language_name.clone(),
133 delegate,
134 )
135 .await?;
136
137 let path = self.extension.path_from_extension(command.command.as_ref());
138
139 // TODO: This should now be done via the `zed::make_file_executable` function in
140 // Zed extension API, but we're leaving these existing usages in place temporarily
141 // to avoid any compatibility issues between Zed and the extension versions.
142 //
143 // We can remove once the following extension versions no longer see any use:
144 // - toml@0.0.2
145 // - zig@0.0.1
146 if ["toml", "zig"].contains(&self.extension.manifest().id.as_ref())
147 && path.starts_with(&self.extension.work_dir())
148 {
149 make_file_executable(&path)
150 .await
151 .context("failed to set file permissions")?;
152 }
153
154 Ok(LanguageServerBinary {
155 path,
156 arguments: command.args.into_iter().map(|arg| arg.into()).collect(),
157 env: Some(command.env.into_iter().collect()),
158 })
159 }
160 .boxed_local()
161 }
162
163 async fn fetch_latest_server_version(
164 &self,
165 _: &dyn LspAdapterDelegate,
166 ) -> Result<Box<dyn 'static + Send + Any>> {
167 unreachable!("get_language_server_command is overridden")
168 }
169
170 async fn fetch_server_binary(
171 &self,
172 _: Box<dyn 'static + Send + Any>,
173 _: PathBuf,
174 _: &dyn LspAdapterDelegate,
175 ) -> Result<LanguageServerBinary> {
176 unreachable!("get_language_server_command is overridden")
177 }
178
179 async fn cached_server_binary(
180 &self,
181 _: PathBuf,
182 _: &dyn LspAdapterDelegate,
183 ) -> Option<LanguageServerBinary> {
184 unreachable!("get_language_server_command is overridden")
185 }
186
187 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
188 let code_action_kinds = self
189 .extension
190 .manifest()
191 .language_servers
192 .get(&self.language_server_id)
193 .and_then(|server| server.code_action_kinds.clone());
194
195 code_action_kinds.or(Some(vec![
196 CodeActionKind::EMPTY,
197 CodeActionKind::QUICKFIX,
198 CodeActionKind::REFACTOR,
199 CodeActionKind::REFACTOR_EXTRACT,
200 CodeActionKind::SOURCE,
201 ]))
202 }
203
204 fn language_ids(&self) -> HashMap<String, String> {
205 // TODO: The language IDs can be provided via the language server options
206 // in `extension.toml now but we're leaving these existing usages in place temporarily
207 // to avoid any compatibility issues between Zed and the extension versions.
208 //
209 // We can remove once the following extension versions no longer see any use:
210 // - php@0.0.1
211 if self.extension.manifest().id.as_ref() == "php" {
212 return HashMap::from_iter([("PHP".into(), "php".into())]);
213 }
214
215 self.extension
216 .manifest()
217 .language_servers
218 .get(&self.language_server_id)
219 .map(|server| server.language_ids.clone())
220 .unwrap_or_default()
221 }
222
223 async fn initialization_options(
224 self: Arc<Self>,
225 _: &dyn Fs,
226 delegate: &Arc<dyn LspAdapterDelegate>,
227 ) -> Result<Option<serde_json::Value>> {
228 let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
229 let json_options = self
230 .extension
231 .language_server_initialization_options(
232 self.language_server_id.clone(),
233 self.language_name.clone(),
234 delegate,
235 )
236 .await?;
237 Ok(if let Some(json_options) = json_options {
238 serde_json::from_str(&json_options).with_context(|| {
239 format!("failed to parse initialization_options from extension: {json_options}")
240 })?
241 } else {
242 None
243 })
244 }
245
246 async fn workspace_configuration(
247 self: Arc<Self>,
248 _: &dyn Fs,
249 delegate: &Arc<dyn LspAdapterDelegate>,
250 _: Arc<dyn LanguageToolchainStore>,
251 _cx: &mut AsyncApp,
252 ) -> Result<Value> {
253 let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
254 let json_options: Option<String> = self
255 .extension
256 .language_server_workspace_configuration(self.language_server_id.clone(), delegate)
257 .await?;
258 Ok(if let Some(json_options) = json_options {
259 serde_json::from_str(&json_options).with_context(|| {
260 format!("failed to parse workspace_configuration from extension: {json_options}")
261 })?
262 } else {
263 serde_json::json!({})
264 })
265 }
266
267 async fn additional_initialization_options(
268 self: Arc<Self>,
269 target_language_server_id: LanguageServerName,
270 _: &dyn Fs,
271 delegate: &Arc<dyn LspAdapterDelegate>,
272 ) -> Result<Option<serde_json::Value>> {
273 let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
274 let json_options: Option<String> = self
275 .extension
276 .language_server_additional_initialization_options(
277 self.language_server_id.clone(),
278 target_language_server_id.clone(),
279 delegate,
280 )
281 .await?;
282 Ok(if let Some(json_options) = json_options {
283 serde_json::from_str(&json_options).with_context(|| {
284 format!(
285 "failed to parse additional_initialization_options from extension: {json_options}"
286 )
287 })?
288 } else {
289 None
290 })
291 }
292
293 async fn additional_workspace_configuration(
294 self: Arc<Self>,
295 target_language_server_id: LanguageServerName,
296 _: &dyn Fs,
297 delegate: &Arc<dyn LspAdapterDelegate>,
298 _: Arc<dyn LanguageToolchainStore>,
299 _cx: &mut AsyncApp,
300 ) -> Result<Option<serde_json::Value>> {
301 let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _;
302 let json_options: Option<String> = self
303 .extension
304 .language_server_additional_workspace_configuration(
305 self.language_server_id.clone(),
306 target_language_server_id.clone(),
307 delegate,
308 )
309 .await?;
310 Ok(if let Some(json_options) = json_options {
311 serde_json::from_str(&json_options).with_context(|| {
312 format!("failed to parse additional_workspace_configuration from extension: {json_options}")
313 })?
314 } else {
315 None
316 })
317 }
318
319 async fn labels_for_completions(
320 self: Arc<Self>,
321 completions: &[lsp::CompletionItem],
322 language: &Arc<Language>,
323 ) -> Result<Vec<Option<CodeLabel>>> {
324 let completions = completions
325 .iter()
326 .cloned()
327 .map(lsp_completion_to_extension)
328 .collect::<Vec<_>>();
329
330 let labels = self
331 .extension
332 .labels_for_completions(self.language_server_id.clone(), completions)
333 .await?;
334
335 Ok(labels_from_extension(labels, language))
336 }
337
338 async fn labels_for_symbols(
339 self: Arc<Self>,
340 symbols: &[(String, lsp::SymbolKind)],
341 language: &Arc<Language>,
342 ) -> Result<Vec<Option<CodeLabel>>> {
343 let symbols = symbols
344 .iter()
345 .cloned()
346 .map(|(name, kind)| extension::Symbol {
347 name,
348 kind: lsp_symbol_kind_to_extension(kind),
349 })
350 .collect::<Vec<_>>();
351
352 let labels = self
353 .extension
354 .labels_for_symbols(self.language_server_id.clone(), symbols)
355 .await?;
356
357 Ok(labels_from_extension(labels, language))
358 }
359}
360
361fn labels_from_extension(
362 labels: Vec<Option<extension::CodeLabel>>,
363 language: &Arc<Language>,
364) -> Vec<Option<CodeLabel>> {
365 labels
366 .into_iter()
367 .map(|label| {
368 let label = label?;
369 let runs = if label.code.is_empty() {
370 Vec::new()
371 } else {
372 language.highlight_text(&label.code.as_str().into(), 0..label.code.len())
373 };
374 build_code_label(&label, &runs, language)
375 })
376 .collect()
377}
378
379fn build_code_label(
380 label: &extension::CodeLabel,
381 parsed_runs: &[(Range<usize>, HighlightId)],
382 language: &Arc<Language>,
383) -> Option<CodeLabel> {
384 let mut text = String::new();
385 let mut runs = vec![];
386
387 for span in &label.spans {
388 match span {
389 extension::CodeLabelSpan::CodeRange(range) => {
390 let code_span = &label.code.get(range.clone())?;
391 let mut input_ix = range.start;
392 let mut output_ix = text.len();
393 for (run_range, id) in parsed_runs {
394 if run_range.start >= range.end {
395 break;
396 }
397 if run_range.end <= input_ix {
398 continue;
399 }
400
401 if run_range.start > input_ix {
402 let len = run_range.start - input_ix;
403 output_ix += len;
404 input_ix += len;
405 }
406
407 let len = range.end.min(run_range.end) - input_ix;
408 runs.push((output_ix..output_ix + len, *id));
409 output_ix += len;
410 input_ix += len;
411 }
412
413 text.push_str(code_span);
414 }
415 extension::CodeLabelSpan::Literal(span) => {
416 let highlight_id = language
417 .grammar()
418 .zip(span.highlight_name.as_ref())
419 .and_then(|(grammar, highlight_name)| {
420 grammar.highlight_id_for_name(highlight_name)
421 })
422 .unwrap_or_default();
423 let ix = text.len();
424 runs.push((ix..ix + span.text.len(), highlight_id));
425 text.push_str(&span.text);
426 }
427 }
428 }
429
430 let filter_range = label.filter_range.clone();
431 text.get(filter_range.clone())?;
432 Some(CodeLabel {
433 text,
434 runs,
435 filter_range,
436 })
437}
438
439fn lsp_completion_to_extension(value: lsp::CompletionItem) -> extension::Completion {
440 extension::Completion {
441 label: value.label,
442 label_details: value
443 .label_details
444 .map(lsp_completion_item_label_details_to_extension),
445 detail: value.detail,
446 kind: value.kind.map(lsp_completion_item_kind_to_extension),
447 insert_text_format: value
448 .insert_text_format
449 .map(lsp_insert_text_format_to_extension),
450 }
451}
452
453fn lsp_completion_item_label_details_to_extension(
454 value: lsp::CompletionItemLabelDetails,
455) -> extension::CompletionLabelDetails {
456 extension::CompletionLabelDetails {
457 detail: value.detail,
458 description: value.description,
459 }
460}
461
462fn lsp_completion_item_kind_to_extension(
463 value: lsp::CompletionItemKind,
464) -> extension::CompletionKind {
465 match value {
466 lsp::CompletionItemKind::TEXT => extension::CompletionKind::Text,
467 lsp::CompletionItemKind::METHOD => extension::CompletionKind::Method,
468 lsp::CompletionItemKind::FUNCTION => extension::CompletionKind::Function,
469 lsp::CompletionItemKind::CONSTRUCTOR => extension::CompletionKind::Constructor,
470 lsp::CompletionItemKind::FIELD => extension::CompletionKind::Field,
471 lsp::CompletionItemKind::VARIABLE => extension::CompletionKind::Variable,
472 lsp::CompletionItemKind::CLASS => extension::CompletionKind::Class,
473 lsp::CompletionItemKind::INTERFACE => extension::CompletionKind::Interface,
474 lsp::CompletionItemKind::MODULE => extension::CompletionKind::Module,
475 lsp::CompletionItemKind::PROPERTY => extension::CompletionKind::Property,
476 lsp::CompletionItemKind::UNIT => extension::CompletionKind::Unit,
477 lsp::CompletionItemKind::VALUE => extension::CompletionKind::Value,
478 lsp::CompletionItemKind::ENUM => extension::CompletionKind::Enum,
479 lsp::CompletionItemKind::KEYWORD => extension::CompletionKind::Keyword,
480 lsp::CompletionItemKind::SNIPPET => extension::CompletionKind::Snippet,
481 lsp::CompletionItemKind::COLOR => extension::CompletionKind::Color,
482 lsp::CompletionItemKind::FILE => extension::CompletionKind::File,
483 lsp::CompletionItemKind::REFERENCE => extension::CompletionKind::Reference,
484 lsp::CompletionItemKind::FOLDER => extension::CompletionKind::Folder,
485 lsp::CompletionItemKind::ENUM_MEMBER => extension::CompletionKind::EnumMember,
486 lsp::CompletionItemKind::CONSTANT => extension::CompletionKind::Constant,
487 lsp::CompletionItemKind::STRUCT => extension::CompletionKind::Struct,
488 lsp::CompletionItemKind::EVENT => extension::CompletionKind::Event,
489 lsp::CompletionItemKind::OPERATOR => extension::CompletionKind::Operator,
490 lsp::CompletionItemKind::TYPE_PARAMETER => extension::CompletionKind::TypeParameter,
491 _ => extension::CompletionKind::Other(extract_int(value)),
492 }
493}
494
495fn lsp_insert_text_format_to_extension(
496 value: lsp::InsertTextFormat,
497) -> extension::InsertTextFormat {
498 match value {
499 lsp::InsertTextFormat::PLAIN_TEXT => extension::InsertTextFormat::PlainText,
500 lsp::InsertTextFormat::SNIPPET => extension::InsertTextFormat::Snippet,
501 _ => extension::InsertTextFormat::Other(extract_int(value)),
502 }
503}
504
505fn lsp_symbol_kind_to_extension(value: lsp::SymbolKind) -> extension::SymbolKind {
506 match value {
507 lsp::SymbolKind::FILE => extension::SymbolKind::File,
508 lsp::SymbolKind::MODULE => extension::SymbolKind::Module,
509 lsp::SymbolKind::NAMESPACE => extension::SymbolKind::Namespace,
510 lsp::SymbolKind::PACKAGE => extension::SymbolKind::Package,
511 lsp::SymbolKind::CLASS => extension::SymbolKind::Class,
512 lsp::SymbolKind::METHOD => extension::SymbolKind::Method,
513 lsp::SymbolKind::PROPERTY => extension::SymbolKind::Property,
514 lsp::SymbolKind::FIELD => extension::SymbolKind::Field,
515 lsp::SymbolKind::CONSTRUCTOR => extension::SymbolKind::Constructor,
516 lsp::SymbolKind::ENUM => extension::SymbolKind::Enum,
517 lsp::SymbolKind::INTERFACE => extension::SymbolKind::Interface,
518 lsp::SymbolKind::FUNCTION => extension::SymbolKind::Function,
519 lsp::SymbolKind::VARIABLE => extension::SymbolKind::Variable,
520 lsp::SymbolKind::CONSTANT => extension::SymbolKind::Constant,
521 lsp::SymbolKind::STRING => extension::SymbolKind::String,
522 lsp::SymbolKind::NUMBER => extension::SymbolKind::Number,
523 lsp::SymbolKind::BOOLEAN => extension::SymbolKind::Boolean,
524 lsp::SymbolKind::ARRAY => extension::SymbolKind::Array,
525 lsp::SymbolKind::OBJECT => extension::SymbolKind::Object,
526 lsp::SymbolKind::KEY => extension::SymbolKind::Key,
527 lsp::SymbolKind::NULL => extension::SymbolKind::Null,
528 lsp::SymbolKind::ENUM_MEMBER => extension::SymbolKind::EnumMember,
529 lsp::SymbolKind::STRUCT => extension::SymbolKind::Struct,
530 lsp::SymbolKind::EVENT => extension::SymbolKind::Event,
531 lsp::SymbolKind::OPERATOR => extension::SymbolKind::Operator,
532 lsp::SymbolKind::TYPE_PARAMETER => extension::SymbolKind::TypeParameter,
533 _ => extension::SymbolKind::Other(extract_int(value)),
534 }
535}
536
537fn extract_int<T: Serialize>(value: T) -> i32 {
538 maybe!({
539 let kind = serde_json::to_value(&value)?;
540 serde_json::from_value(kind)
541 })
542 .log_err()
543 .unwrap_or(-1)
544}
545
546#[test]
547fn test_build_code_label() {
548 use util::test::marked_text_ranges;
549
550 let (code, code_ranges) = marked_text_ranges(
551 "«const» «a»: «fn»(«Bcd»(«Efgh»)) -> «Ijklm» = pqrs.tuv",
552 false,
553 );
554 let code_runs = code_ranges
555 .into_iter()
556 .map(|range| (range, HighlightId(0)))
557 .collect::<Vec<_>>();
558
559 let label = build_code_label(
560 &extension::CodeLabel {
561 spans: vec![
562 extension::CodeLabelSpan::CodeRange(code.find("pqrs").unwrap()..code.len()),
563 extension::CodeLabelSpan::CodeRange(
564 code.find(": fn").unwrap()..code.find(" = ").unwrap(),
565 ),
566 ],
567 filter_range: 0.."pqrs.tuv".len(),
568 code,
569 },
570 &code_runs,
571 &language::PLAIN_TEXT,
572 )
573 .unwrap();
574
575 let (label_text, label_ranges) =
576 marked_text_ranges("pqrs.tuv: «fn»(«Bcd»(«Efgh»)) -> «Ijklm»", false);
577 let label_runs = label_ranges
578 .into_iter()
579 .map(|range| (range, HighlightId(0)))
580 .collect::<Vec<_>>();
581
582 assert_eq!(
583 label,
584 CodeLabel {
585 text: label_text,
586 runs: label_runs,
587 filter_range: label.filter_range.clone()
588 }
589 )
590}
591
592#[test]
593fn test_build_code_label_with_invalid_ranges() {
594 use util::test::marked_text_ranges;
595
596 let (code, code_ranges) = marked_text_ranges("const «a»: «B» = '🏀'", false);
597 let code_runs = code_ranges
598 .into_iter()
599 .map(|range| (range, HighlightId(0)))
600 .collect::<Vec<_>>();
601
602 // A span uses a code range that is invalid because it starts inside of
603 // a multi-byte character.
604 let label = build_code_label(
605 &extension::CodeLabel {
606 spans: vec![
607 extension::CodeLabelSpan::CodeRange(
608 code.find('B').unwrap()..code.find(" = ").unwrap(),
609 ),
610 extension::CodeLabelSpan::CodeRange((code.find('🏀').unwrap() + 1)..code.len()),
611 ],
612 filter_range: 0.."B".len(),
613 code,
614 },
615 &code_runs,
616 &language::PLAIN_TEXT,
617 );
618 assert!(label.is_none());
619
620 // Filter range extends beyond actual text
621 let label = build_code_label(
622 &extension::CodeLabel {
623 spans: vec![extension::CodeLabelSpan::Literal(
624 extension::CodeLabelSpanLiteral {
625 text: "abc".into(),
626 highlight_name: Some("type".into()),
627 },
628 )],
629 filter_range: 0..5,
630 code: String::new(),
631 },
632 &code_runs,
633 &language::PLAIN_TEXT,
634 );
635 assert!(label.is_none());
636}