1pub mod clangd_ext;
2pub mod json_language_server_ext;
3pub mod lsp_ext_command;
4pub mod rust_analyzer_ext;
5
6use crate::{
7 CodeAction, ColorPresentation, Completion, CompletionResponse, CompletionSource,
8 CoreCompletion, DocumentColor, Hover, InlayHint, LocationLink, LspAction, LspPullDiagnostics,
9 ProjectItem, ProjectPath, ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
10 ToolchainStore,
11 buffer_store::{BufferStore, BufferStoreEvent},
12 environment::ProjectEnvironment,
13 lsp_command::{self, *},
14 lsp_store,
15 manifest_tree::{
16 AdapterQuery, LanguageServerTree, LanguageServerTreeNode, LaunchDisposition,
17 ManifestQueryDelegate, ManifestTree,
18 },
19 prettier_store::{self, PrettierStore, PrettierStoreEvent},
20 project_settings::{LspSettings, ProjectSettings},
21 relativize_path, resolve_path,
22 toolchain_store::{EmptyToolchainStore, ToolchainStoreEvent},
23 worktree_store::{WorktreeStore, WorktreeStoreEvent},
24 yarn::YarnPathStore,
25};
26use anyhow::{Context as _, Result, anyhow};
27use async_trait::async_trait;
28use client::{TypedEnvelope, proto};
29use clock::Global;
30use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
31use futures::{
32 AsyncWriteExt, Future, FutureExt, StreamExt,
33 future::{Either, Shared, join_all, pending, select},
34 select, select_biased,
35 stream::FuturesUnordered,
36};
37use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
38use gpui::{
39 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString, Task,
40 WeakEntity,
41};
42use http_client::HttpClient;
43use itertools::Itertools as _;
44use language::{
45 Bias, BinaryStatus, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
46 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
47 LanguageRegistry, LanguageToolchainStore, LocalFile, LspAdapter, LspAdapterDelegate, Patch,
48 PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,
49 WorkspaceFoldersContent,
50 language_settings::{
51 FormatOnSave, Formatter, LanguageSettings, SelectedFormatter, language_settings,
52 },
53 point_to_lsp,
54 proto::{
55 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
56 serialize_lsp_edit, serialize_version,
57 },
58 range_from_lsp, range_to_lsp,
59};
60use lsp::{
61 AdapterServerCapabilities, CodeActionKind, CompletionContext, DiagnosticSeverity,
62 DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter,
63 FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
64 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
65 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
66 OneOf, RenameFilesParams, SymbolKind, TextEdit, WillRenameFiles, WorkDoneProgressCancelParams,
67 WorkspaceFolder, notification::DidRenameFiles,
68};
69use node_runtime::read_package_installed_version;
70use parking_lot::Mutex;
71use postage::{mpsc, sink::Sink, stream::Stream, watch};
72use rand::prelude::*;
73
74use rpc::{
75 AnyProtoClient,
76 proto::{FromProto, ToProto},
77};
78use serde::Serialize;
79use settings::{Settings, SettingsLocation, SettingsStore};
80use sha2::{Digest, Sha256};
81use smol::channel::Sender;
82use snippet::Snippet;
83use std::{
84 any::Any,
85 borrow::Cow,
86 cell::RefCell,
87 cmp::{Ordering, Reverse},
88 convert::TryInto,
89 ffi::OsStr,
90 future::ready,
91 iter, mem,
92 ops::{ControlFlow, Range},
93 path::{self, Path, PathBuf},
94 pin::pin,
95 rc::Rc,
96 sync::Arc,
97 time::{Duration, Instant},
98};
99use sum_tree::Dimensions;
100use text::{Anchor, BufferId, LineEnding, OffsetRangeExt};
101use url::Url;
102use util::{
103 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
104 paths::{PathExt, SanitizedPath},
105 post_inc,
106};
107
108pub use fs::*;
109pub use language::Location;
110#[cfg(any(test, feature = "test-support"))]
111pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
112pub use worktree::{
113 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
114 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
115};
116
117const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
118pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121pub enum FormatTrigger {
122 Save,
123 Manual,
124}
125
126pub enum LspFormatTarget {
127 Buffers,
128 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
129}
130
131pub type OpenLspBufferHandle = Entity<Entity<Buffer>>;
132
133impl FormatTrigger {
134 fn from_proto(value: i32) -> FormatTrigger {
135 match value {
136 0 => FormatTrigger::Save,
137 1 => FormatTrigger::Manual,
138 _ => FormatTrigger::Save,
139 }
140 }
141}
142
143#[derive(Debug)]
144pub struct DocumentDiagnosticsUpdate<'a, D> {
145 pub diagnostics: D,
146 pub result_id: Option<String>,
147 pub server_id: LanguageServerId,
148 pub disk_based_sources: Cow<'a, [String]>,
149}
150
151pub struct DocumentDiagnostics {
152 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
153 document_abs_path: PathBuf,
154 version: Option<i32>,
155}
156
157pub struct LocalLspStore {
158 weak: WeakEntity<LspStore>,
159 worktree_store: Entity<WorktreeStore>,
160 toolchain_store: Entity<ToolchainStore>,
161 http_client: Arc<dyn HttpClient>,
162 environment: Entity<ProjectEnvironment>,
163 fs: Arc<dyn Fs>,
164 languages: Arc<LanguageRegistry>,
165 language_server_ids: HashMap<(WorktreeId, LanguageServerName), BTreeSet<LanguageServerId>>,
166 yarn: Entity<YarnPathStore>,
167 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
168 buffers_being_formatted: HashSet<BufferId>,
169 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
170 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
171 language_server_paths_watched_for_rename:
172 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
173 language_server_watcher_registrations:
174 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
175 supplementary_language_servers:
176 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
177 prettier_store: Entity<PrettierStore>,
178 next_diagnostic_group_id: usize,
179 diagnostics: HashMap<
180 WorktreeId,
181 HashMap<
182 Arc<Path>,
183 Vec<(
184 LanguageServerId,
185 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
186 )>,
187 >,
188 >,
189 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
190 _subscription: gpui::Subscription,
191 lsp_tree: Entity<LanguageServerTree>,
192 registered_buffers: HashMap<BufferId, usize>,
193 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
194 buffer_pull_diagnostics_result_ids: HashMap<LanguageServerId, HashMap<PathBuf, Option<String>>>,
195}
196
197impl LocalLspStore {
198 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
199 pub fn running_language_server_for_id(
200 &self,
201 id: LanguageServerId,
202 ) -> Option<&Arc<LanguageServer>> {
203 let language_server_state = self.language_servers.get(&id)?;
204
205 match language_server_state {
206 LanguageServerState::Running { server, .. } => Some(server),
207 LanguageServerState::Starting { .. } => None,
208 }
209 }
210
211 fn start_language_server(
212 &mut self,
213 worktree_handle: &Entity<Worktree>,
214 delegate: Arc<LocalLspAdapterDelegate>,
215 adapter: Arc<CachedLspAdapter>,
216 settings: Arc<LspSettings>,
217 cx: &mut App,
218 ) -> LanguageServerId {
219 let worktree = worktree_handle.read(cx);
220 let worktree_id = worktree.id();
221 let root_path = worktree.abs_path();
222 let key = (worktree_id, adapter.name.clone());
223
224 let override_options = settings.initialization_options.clone();
225
226 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
227
228 let server_id = self.languages.next_language_server_id();
229 log::info!(
230 "attempting to start language server {:?}, path: {root_path:?}, id: {server_id}",
231 adapter.name.0
232 );
233
234 let binary = self.get_language_server_binary(adapter.clone(), delegate.clone(), true, cx);
235 let pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>> = Default::default();
236
237 let pending_server = cx.spawn({
238 let adapter = adapter.clone();
239 let server_name = adapter.name.clone();
240 let stderr_capture = stderr_capture.clone();
241 #[cfg(any(test, feature = "test-support"))]
242 let lsp_store = self.weak.clone();
243 let pending_workspace_folders = pending_workspace_folders.clone();
244 async move |cx| {
245 let binary = binary.await?;
246 #[cfg(any(test, feature = "test-support"))]
247 if let Some(server) = lsp_store
248 .update(&mut cx.clone(), |this, cx| {
249 this.languages.create_fake_language_server(
250 server_id,
251 &server_name,
252 binary.clone(),
253 &mut cx.to_async(),
254 )
255 })
256 .ok()
257 .flatten()
258 {
259 return Ok(server);
260 }
261
262 let code_action_kinds = adapter.code_action_kinds();
263 lsp::LanguageServer::new(
264 stderr_capture,
265 server_id,
266 server_name,
267 binary,
268 &root_path,
269 code_action_kinds,
270 Some(pending_workspace_folders).filter(|_| {
271 adapter.adapter.workspace_folders_content()
272 == WorkspaceFoldersContent::SubprojectRoots
273 }),
274 cx,
275 )
276 }
277 });
278
279 let startup = {
280 let server_name = adapter.name.0.clone();
281 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
282 let key = key.clone();
283 let adapter = adapter.clone();
284 let lsp_store = self.weak.clone();
285 let pending_workspace_folders = pending_workspace_folders.clone();
286 let fs = self.fs.clone();
287 let pull_diagnostics = ProjectSettings::get_global(cx)
288 .diagnostics
289 .lsp_pull_diagnostics
290 .enabled;
291 cx.spawn(async move |cx| {
292 let result = async {
293 let toolchains =
294 lsp_store.update(cx, |lsp_store, cx| lsp_store.toolchain_store(cx))?;
295 let language_server = pending_server.await?;
296
297 let workspace_config = Self::workspace_configuration_for_adapter(
298 adapter.adapter.clone(),
299 fs.as_ref(),
300 &delegate,
301 toolchains.clone(),
302 cx,
303 )
304 .await?;
305
306 let mut initialization_options = Self::initialization_options_for_adapter(
307 adapter.adapter.clone(),
308 fs.as_ref(),
309 &delegate,
310 )
311 .await?;
312
313 match (&mut initialization_options, override_options) {
314 (Some(initialization_options), Some(override_options)) => {
315 merge_json_value_into(override_options, initialization_options);
316 }
317 (None, override_options) => initialization_options = override_options,
318 _ => {}
319 }
320
321 let initialization_params = cx.update(|cx| {
322 let mut params =
323 language_server.default_initialize_params(pull_diagnostics, cx);
324 params.initialization_options = initialization_options;
325 adapter.adapter.prepare_initialize_params(params, cx)
326 })??;
327
328 Self::setup_lsp_messages(
329 lsp_store.clone(),
330 fs,
331 &language_server,
332 delegate.clone(),
333 adapter.clone(),
334 );
335
336 let did_change_configuration_params =
337 Arc::new(lsp::DidChangeConfigurationParams {
338 settings: workspace_config,
339 });
340 let language_server = cx
341 .update(|cx| {
342 language_server.initialize(
343 initialization_params,
344 did_change_configuration_params.clone(),
345 cx,
346 )
347 })?
348 .await
349 .inspect_err(|_| {
350 if let Some(lsp_store) = lsp_store.upgrade() {
351 lsp_store
352 .update(cx, |lsp_store, cx| {
353 lsp_store.cleanup_lsp_data(server_id);
354 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
355 })
356 .ok();
357 }
358 })?;
359
360 language_server
361 .notify::<lsp::notification::DidChangeConfiguration>(
362 &did_change_configuration_params,
363 )
364 .ok();
365
366 anyhow::Ok(language_server)
367 }
368 .await;
369
370 match result {
371 Ok(server) => {
372 lsp_store
373 .update(cx, |lsp_store, mut cx| {
374 lsp_store.insert_newly_running_language_server(
375 adapter,
376 server.clone(),
377 server_id,
378 key,
379 pending_workspace_folders,
380 &mut cx,
381 );
382 })
383 .ok();
384 stderr_capture.lock().take();
385 Some(server)
386 }
387
388 Err(err) => {
389 let log = stderr_capture.lock().take().unwrap_or_default();
390 delegate.update_status(
391 adapter.name(),
392 BinaryStatus::Failed {
393 error: format!("{err}\n-- stderr--\n{log}"),
394 },
395 );
396 let message =
397 format!("Failed to start language server {server_name:?}: {err:#?}");
398 log::error!("{message}");
399 log::error!("server stderr: {log}");
400 None
401 }
402 }
403 })
404 };
405 let state = LanguageServerState::Starting {
406 startup,
407 pending_workspace_folders,
408 };
409
410 self.languages
411 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
412
413 self.language_servers.insert(server_id, state);
414 self.language_server_ids
415 .entry(key)
416 .or_default()
417 .insert(server_id);
418 server_id
419 }
420
421 fn get_language_server_binary(
422 &self,
423 adapter: Arc<CachedLspAdapter>,
424 delegate: Arc<dyn LspAdapterDelegate>,
425 allow_binary_download: bool,
426 cx: &mut App,
427 ) -> Task<Result<LanguageServerBinary>> {
428 let settings = ProjectSettings::get(
429 Some(SettingsLocation {
430 worktree_id: delegate.worktree_id(),
431 path: Path::new(""),
432 }),
433 cx,
434 )
435 .lsp
436 .get(&adapter.name)
437 .and_then(|s| s.binary.clone());
438
439 if settings.as_ref().is_some_and(|b| b.path.is_some()) {
440 let settings = settings.unwrap();
441
442 return cx.background_spawn(async move {
443 let mut env = delegate.shell_env().await;
444 env.extend(settings.env.unwrap_or_default());
445
446 Ok(LanguageServerBinary {
447 path: PathBuf::from(&settings.path.unwrap()),
448 env: Some(env),
449 arguments: settings
450 .arguments
451 .unwrap_or_default()
452 .iter()
453 .map(Into::into)
454 .collect(),
455 })
456 });
457 }
458 let lsp_binary_options = LanguageServerBinaryOptions {
459 allow_path_lookup: !settings
460 .as_ref()
461 .and_then(|b| b.ignore_system_version)
462 .unwrap_or_default(),
463 allow_binary_download,
464 };
465 let toolchains = self.toolchain_store.read(cx).as_language_toolchain_store();
466 cx.spawn(async move |cx| {
467 let binary_result = adapter
468 .clone()
469 .get_language_server_command(delegate.clone(), toolchains, lsp_binary_options, cx)
470 .await;
471
472 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
473
474 let mut binary = binary_result?;
475 let mut shell_env = delegate.shell_env().await;
476
477 shell_env.extend(binary.env.unwrap_or_default());
478
479 if let Some(settings) = settings {
480 if let Some(arguments) = settings.arguments {
481 binary.arguments = arguments.into_iter().map(Into::into).collect();
482 }
483 if let Some(env) = settings.env {
484 shell_env.extend(env);
485 }
486 }
487
488 binary.env = Some(shell_env);
489 Ok(binary)
490 })
491 }
492
493 fn setup_lsp_messages(
494 this: WeakEntity<LspStore>,
495 fs: Arc<dyn Fs>,
496 language_server: &LanguageServer,
497 delegate: Arc<dyn LspAdapterDelegate>,
498 adapter: Arc<CachedLspAdapter>,
499 ) {
500 let name = language_server.name();
501 let server_id = language_server.server_id();
502 language_server
503 .on_notification::<lsp::notification::PublishDiagnostics, _>({
504 let adapter = adapter.clone();
505 let this = this.clone();
506 move |mut params, cx| {
507 let adapter = adapter.clone();
508 if let Some(this) = this.upgrade() {
509 this.update(cx, |this, cx| {
510 {
511 let buffer = params
512 .uri
513 .to_file_path()
514 .map(|file_path| this.get_buffer(&file_path, cx))
515 .ok()
516 .flatten();
517 adapter.process_diagnostics(&mut params, server_id, buffer);
518 }
519
520 this.merge_lsp_diagnostics(
521 DiagnosticSourceKind::Pushed,
522 vec![DocumentDiagnosticsUpdate {
523 server_id,
524 diagnostics: params,
525 result_id: None,
526 disk_based_sources: Cow::Borrowed(
527 &adapter.disk_based_diagnostic_sources,
528 ),
529 }],
530 |_, diagnostic, cx| match diagnostic.source_kind {
531 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
532 adapter.retain_old_diagnostic(diagnostic, cx)
533 }
534 DiagnosticSourceKind::Pulled => true,
535 },
536 cx,
537 )
538 .log_err();
539 })
540 .ok();
541 }
542 }
543 })
544 .detach();
545 language_server
546 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
547 let adapter = adapter.adapter.clone();
548 let delegate = delegate.clone();
549 let this = this.clone();
550 let fs = fs.clone();
551 move |params, cx| {
552 let adapter = adapter.clone();
553 let delegate = delegate.clone();
554 let this = this.clone();
555 let fs = fs.clone();
556 let mut cx = cx.clone();
557 async move {
558 let toolchains =
559 this.update(&mut cx, |this, cx| this.toolchain_store(cx))?;
560
561 let workspace_config = Self::workspace_configuration_for_adapter(
562 adapter.clone(),
563 fs.as_ref(),
564 &delegate,
565 toolchains.clone(),
566 &mut cx,
567 )
568 .await?;
569
570 Ok(params
571 .items
572 .into_iter()
573 .map(|item| {
574 if let Some(section) = &item.section {
575 workspace_config
576 .get(section)
577 .cloned()
578 .unwrap_or(serde_json::Value::Null)
579 } else {
580 workspace_config.clone()
581 }
582 })
583 .collect())
584 }
585 }
586 })
587 .detach();
588
589 language_server
590 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
591 let this = this.clone();
592 move |_, cx| {
593 let this = this.clone();
594 let mut cx = cx.clone();
595 async move {
596 let Some(server) = this
597 .read_with(&mut cx, |this, _| this.language_server_for_id(server_id))?
598 else {
599 return Ok(None);
600 };
601 let root = server.workspace_folders();
602 Ok(Some(
603 root.into_iter()
604 .map(|uri| WorkspaceFolder {
605 uri,
606 name: Default::default(),
607 })
608 .collect(),
609 ))
610 }
611 }
612 })
613 .detach();
614 // Even though we don't have handling for these requests, respond to them to
615 // avoid stalling any language server like `gopls` which waits for a response
616 // to these requests when initializing.
617 language_server
618 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
619 let this = this.clone();
620 move |params, cx| {
621 let this = this.clone();
622 let mut cx = cx.clone();
623 async move {
624 this.update(&mut cx, |this, _| {
625 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
626 {
627 if let lsp::NumberOrString::String(token) = params.token {
628 status.progress_tokens.insert(token);
629 }
630 }
631 })?;
632
633 Ok(())
634 }
635 }
636 })
637 .detach();
638
639 language_server
640 .on_request::<lsp::request::RegisterCapability, _, _>({
641 let this = this.clone();
642 move |params, cx| {
643 let lsp_store = this.clone();
644 let mut cx = cx.clone();
645 async move {
646 for reg in params.registrations {
647 match reg.method.as_str() {
648 "workspace/didChangeWatchedFiles" => {
649 if let Some(options) = reg.register_options {
650 let options = serde_json::from_value(options)?;
651 lsp_store.update(&mut cx, |this, cx| {
652 this.as_local_mut()?.on_lsp_did_change_watched_files(
653 server_id, ®.id, options, cx,
654 );
655 Some(())
656 })?;
657 }
658 }
659 "textDocument/rangeFormatting" => {
660 lsp_store.update(&mut cx, |lsp_store, cx| {
661 if let Some(server) =
662 lsp_store.language_server_for_id(server_id)
663 {
664 let options = reg
665 .register_options
666 .map(|options| {
667 serde_json::from_value::<
668 lsp::DocumentRangeFormattingOptions,
669 >(
670 options
671 )
672 })
673 .transpose()?;
674 let provider = match options {
675 None => OneOf::Left(true),
676 Some(options) => OneOf::Right(options),
677 };
678 server.update_capabilities(|capabilities| {
679 capabilities.document_range_formatting_provider =
680 Some(provider);
681 });
682 notify_server_capabilities_updated(&server, cx);
683 }
684 anyhow::Ok(())
685 })??;
686 }
687 "textDocument/onTypeFormatting" => {
688 lsp_store.update(&mut cx, |lsp_store, cx| {
689 if let Some(server) =
690 lsp_store.language_server_for_id(server_id)
691 {
692 let options = reg
693 .register_options
694 .map(|options| {
695 serde_json::from_value::<
696 lsp::DocumentOnTypeFormattingOptions,
697 >(
698 options
699 )
700 })
701 .transpose()?;
702 if let Some(options) = options {
703 server.update_capabilities(|capabilities| {
704 capabilities
705 .document_on_type_formatting_provider =
706 Some(options);
707 });
708 notify_server_capabilities_updated(&server, cx);
709 }
710 }
711 anyhow::Ok(())
712 })??;
713 }
714 "textDocument/formatting" => {
715 lsp_store.update(&mut cx, |lsp_store, cx| {
716 if let Some(server) =
717 lsp_store.language_server_for_id(server_id)
718 {
719 let options = reg
720 .register_options
721 .map(|options| {
722 serde_json::from_value::<
723 lsp::DocumentFormattingOptions,
724 >(
725 options
726 )
727 })
728 .transpose()?;
729 let provider = match options {
730 None => OneOf::Left(true),
731 Some(options) => OneOf::Right(options),
732 };
733 server.update_capabilities(|capabilities| {
734 capabilities.document_formatting_provider =
735 Some(provider);
736 });
737 notify_server_capabilities_updated(&server, cx);
738 }
739 anyhow::Ok(())
740 })??;
741 }
742 "workspace/didChangeConfiguration" => {
743 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
744 }
745 "textDocument/rename" => {
746 lsp_store.update(&mut cx, |lsp_store, cx| {
747 if let Some(server) =
748 lsp_store.language_server_for_id(server_id)
749 {
750 let options = reg
751 .register_options
752 .map(|options| {
753 serde_json::from_value::<lsp::RenameOptions>(
754 options,
755 )
756 })
757 .transpose()?;
758 let options = match options {
759 None => OneOf::Left(true),
760 Some(options) => OneOf::Right(options),
761 };
762
763 server.update_capabilities(|capabilities| {
764 capabilities.rename_provider = Some(options);
765 });
766 notify_server_capabilities_updated(&server, cx);
767 }
768 anyhow::Ok(())
769 })??;
770 }
771 _ => log::warn!("unhandled capability registration: {reg:?}"),
772 }
773 }
774 Ok(())
775 }
776 }
777 })
778 .detach();
779
780 language_server
781 .on_request::<lsp::request::UnregisterCapability, _, _>({
782 let this = this.clone();
783 move |params, cx| {
784 let lsp_store = this.clone();
785 let mut cx = cx.clone();
786 async move {
787 for unreg in params.unregisterations.iter() {
788 match unreg.method.as_str() {
789 "workspace/didChangeWatchedFiles" => {
790 lsp_store.update(&mut cx, |lsp_store, cx| {
791 lsp_store
792 .as_local_mut()?
793 .on_lsp_unregister_did_change_watched_files(
794 server_id, &unreg.id, cx,
795 );
796 Some(())
797 })?;
798 }
799 "workspace/didChangeConfiguration" => {
800 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
801 }
802 "textDocument/rename" => {
803 lsp_store.update(&mut cx, |lsp_store, cx| {
804 if let Some(server) =
805 lsp_store.language_server_for_id(server_id)
806 {
807 server.update_capabilities(|capabilities| {
808 capabilities.rename_provider = None
809 });
810 notify_server_capabilities_updated(&server, cx);
811 }
812 })?;
813 }
814 "textDocument/rangeFormatting" => {
815 lsp_store.update(&mut cx, |lsp_store, cx| {
816 if let Some(server) =
817 lsp_store.language_server_for_id(server_id)
818 {
819 server.update_capabilities(|capabilities| {
820 capabilities.document_range_formatting_provider =
821 None
822 });
823 notify_server_capabilities_updated(&server, cx);
824 }
825 })?;
826 }
827 "textDocument/onTypeFormatting" => {
828 lsp_store.update(&mut cx, |lsp_store, cx| {
829 if let Some(server) =
830 lsp_store.language_server_for_id(server_id)
831 {
832 server.update_capabilities(|capabilities| {
833 capabilities.document_on_type_formatting_provider =
834 None;
835 });
836 notify_server_capabilities_updated(&server, cx);
837 }
838 })?;
839 }
840 "textDocument/formatting" => {
841 lsp_store.update(&mut cx, |lsp_store, cx| {
842 if let Some(server) =
843 lsp_store.language_server_for_id(server_id)
844 {
845 server.update_capabilities(|capabilities| {
846 capabilities.document_formatting_provider = None;
847 });
848 notify_server_capabilities_updated(&server, cx);
849 }
850 })?;
851 }
852 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
853 }
854 }
855 Ok(())
856 }
857 }
858 })
859 .detach();
860
861 language_server
862 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
863 let adapter = adapter.clone();
864 let this = this.clone();
865 move |params, cx| {
866 let mut cx = cx.clone();
867 let this = this.clone();
868 let adapter = adapter.clone();
869 async move {
870 LocalLspStore::on_lsp_workspace_edit(
871 this.clone(),
872 params,
873 server_id,
874 adapter.clone(),
875 &mut cx,
876 )
877 .await
878 }
879 }
880 })
881 .detach();
882
883 language_server
884 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
885 let this = this.clone();
886 move |(), cx| {
887 let this = this.clone();
888 let mut cx = cx.clone();
889 async move {
890 this.update(&mut cx, |this, cx| {
891 cx.emit(LspStoreEvent::RefreshInlayHints);
892 this.downstream_client.as_ref().map(|(client, project_id)| {
893 client.send(proto::RefreshInlayHints {
894 project_id: *project_id,
895 })
896 })
897 })?
898 .transpose()?;
899 Ok(())
900 }
901 }
902 })
903 .detach();
904
905 language_server
906 .on_request::<lsp::request::CodeLensRefresh, _, _>({
907 let this = this.clone();
908 move |(), cx| {
909 let this = this.clone();
910 let mut cx = cx.clone();
911 async move {
912 this.update(&mut cx, |this, cx| {
913 cx.emit(LspStoreEvent::RefreshCodeLens);
914 this.downstream_client.as_ref().map(|(client, project_id)| {
915 client.send(proto::RefreshCodeLens {
916 project_id: *project_id,
917 })
918 })
919 })?
920 .transpose()?;
921 Ok(())
922 }
923 }
924 })
925 .detach();
926
927 language_server
928 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
929 let this = this.clone();
930 move |(), cx| {
931 let this = this.clone();
932 let mut cx = cx.clone();
933 async move {
934 this.update(&mut cx, |lsp_store, _| {
935 lsp_store.pull_workspace_diagnostics(server_id);
936 lsp_store
937 .downstream_client
938 .as_ref()
939 .map(|(client, project_id)| {
940 client.send(proto::PullWorkspaceDiagnostics {
941 project_id: *project_id,
942 server_id: server_id.to_proto(),
943 })
944 })
945 })?
946 .transpose()?;
947 Ok(())
948 }
949 }
950 })
951 .detach();
952
953 language_server
954 .on_request::<lsp::request::ShowMessageRequest, _, _>({
955 let this = this.clone();
956 let name = name.to_string();
957 move |params, cx| {
958 let this = this.clone();
959 let name = name.to_string();
960 let mut cx = cx.clone();
961 async move {
962 let actions = params.actions.unwrap_or_default();
963 let (tx, rx) = smol::channel::bounded(1);
964 let request = LanguageServerPromptRequest {
965 level: match params.typ {
966 lsp::MessageType::ERROR => PromptLevel::Critical,
967 lsp::MessageType::WARNING => PromptLevel::Warning,
968 _ => PromptLevel::Info,
969 },
970 message: params.message,
971 actions,
972 response_channel: tx,
973 lsp_name: name.clone(),
974 };
975
976 let did_update = this
977 .update(&mut cx, |_, cx| {
978 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
979 })
980 .is_ok();
981 if did_update {
982 let response = rx.recv().await.ok();
983 Ok(response)
984 } else {
985 Ok(None)
986 }
987 }
988 }
989 })
990 .detach();
991 language_server
992 .on_notification::<lsp::notification::ShowMessage, _>({
993 let this = this.clone();
994 let name = name.to_string();
995 move |params, cx| {
996 let this = this.clone();
997 let name = name.to_string();
998 let mut cx = cx.clone();
999
1000 let (tx, _) = smol::channel::bounded(1);
1001 let request = LanguageServerPromptRequest {
1002 level: match params.typ {
1003 lsp::MessageType::ERROR => PromptLevel::Critical,
1004 lsp::MessageType::WARNING => PromptLevel::Warning,
1005 _ => PromptLevel::Info,
1006 },
1007 message: params.message,
1008 actions: vec![],
1009 response_channel: tx,
1010 lsp_name: name.clone(),
1011 };
1012
1013 let _ = this.update(&mut cx, |_, cx| {
1014 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1015 });
1016 }
1017 })
1018 .detach();
1019
1020 let disk_based_diagnostics_progress_token =
1021 adapter.disk_based_diagnostics_progress_token.clone();
1022
1023 language_server
1024 .on_notification::<lsp::notification::Progress, _>({
1025 let this = this.clone();
1026 move |params, cx| {
1027 if let Some(this) = this.upgrade() {
1028 this.update(cx, |this, cx| {
1029 this.on_lsp_progress(
1030 params,
1031 server_id,
1032 disk_based_diagnostics_progress_token.clone(),
1033 cx,
1034 );
1035 })
1036 .ok();
1037 }
1038 }
1039 })
1040 .detach();
1041
1042 language_server
1043 .on_notification::<lsp::notification::LogMessage, _>({
1044 let this = this.clone();
1045 move |params, cx| {
1046 if let Some(this) = this.upgrade() {
1047 this.update(cx, |_, cx| {
1048 cx.emit(LspStoreEvent::LanguageServerLog(
1049 server_id,
1050 LanguageServerLogType::Log(params.typ),
1051 params.message,
1052 ));
1053 })
1054 .ok();
1055 }
1056 }
1057 })
1058 .detach();
1059
1060 language_server
1061 .on_notification::<lsp::notification::LogTrace, _>({
1062 let this = this.clone();
1063 move |params, cx| {
1064 let mut cx = cx.clone();
1065 if let Some(this) = this.upgrade() {
1066 this.update(&mut cx, |_, cx| {
1067 cx.emit(LspStoreEvent::LanguageServerLog(
1068 server_id,
1069 LanguageServerLogType::Trace(params.verbose),
1070 params.message,
1071 ));
1072 })
1073 .ok();
1074 }
1075 }
1076 })
1077 .detach();
1078
1079 json_language_server_ext::register_requests(this.clone(), language_server);
1080 rust_analyzer_ext::register_notifications(this.clone(), language_server);
1081 clangd_ext::register_notifications(this, language_server, adapter);
1082 }
1083
1084 fn shutdown_language_servers_on_quit(
1085 &mut self,
1086 _: &mut Context<LspStore>,
1087 ) -> impl Future<Output = ()> + use<> {
1088 let shutdown_futures = self
1089 .language_servers
1090 .drain()
1091 .map(|(_, server_state)| Self::shutdown_server(server_state))
1092 .collect::<Vec<_>>();
1093
1094 async move {
1095 join_all(shutdown_futures).await;
1096 }
1097 }
1098
1099 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1100 match server_state {
1101 LanguageServerState::Running { server, .. } => {
1102 if let Some(shutdown) = server.shutdown() {
1103 shutdown.await;
1104 }
1105 }
1106 LanguageServerState::Starting { startup, .. } => {
1107 if let Some(server) = startup.await {
1108 if let Some(shutdown) = server.shutdown() {
1109 shutdown.await;
1110 }
1111 }
1112 }
1113 }
1114 Ok(())
1115 }
1116
1117 fn language_servers_for_worktree(
1118 &self,
1119 worktree_id: WorktreeId,
1120 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1121 self.language_server_ids
1122 .iter()
1123 .flat_map(move |((language_server_path, _), ids)| {
1124 ids.iter().filter_map(move |id| {
1125 if *language_server_path != worktree_id {
1126 return None;
1127 }
1128 if let Some(LanguageServerState::Running { server, .. }) =
1129 self.language_servers.get(id)
1130 {
1131 return Some(server);
1132 } else {
1133 None
1134 }
1135 })
1136 })
1137 }
1138
1139 fn language_server_ids_for_project_path(
1140 &self,
1141 project_path: ProjectPath,
1142 language: &Language,
1143 cx: &mut App,
1144 ) -> Vec<LanguageServerId> {
1145 let Some(worktree) = self
1146 .worktree_store
1147 .read(cx)
1148 .worktree_for_id(project_path.worktree_id, cx)
1149 else {
1150 return Vec::new();
1151 };
1152 let delegate = Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1153 let root = self.lsp_tree.update(cx, |this, cx| {
1154 this.get(
1155 project_path,
1156 AdapterQuery::Language(&language.name()),
1157 delegate,
1158 cx,
1159 )
1160 .filter_map(|node| node.server_id())
1161 .collect::<Vec<_>>()
1162 });
1163
1164 root
1165 }
1166
1167 fn language_server_ids_for_buffer(
1168 &self,
1169 buffer: &Buffer,
1170 cx: &mut App,
1171 ) -> Vec<LanguageServerId> {
1172 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1173 let worktree_id = file.worktree_id(cx);
1174
1175 let path: Arc<Path> = file
1176 .path()
1177 .parent()
1178 .map(Arc::from)
1179 .unwrap_or_else(|| file.path().clone());
1180 let worktree_path = ProjectPath { worktree_id, path };
1181 self.language_server_ids_for_project_path(worktree_path, language, cx)
1182 } else {
1183 Vec::new()
1184 }
1185 }
1186
1187 fn language_servers_for_buffer<'a>(
1188 &'a self,
1189 buffer: &'a Buffer,
1190 cx: &'a mut App,
1191 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1192 self.language_server_ids_for_buffer(buffer, cx)
1193 .into_iter()
1194 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1195 LanguageServerState::Running {
1196 adapter, server, ..
1197 } => Some((adapter, server)),
1198 _ => None,
1199 })
1200 }
1201
1202 async fn execute_code_action_kind_locally(
1203 lsp_store: WeakEntity<LspStore>,
1204 mut buffers: Vec<Entity<Buffer>>,
1205 kind: CodeActionKind,
1206 push_to_history: bool,
1207 cx: &mut AsyncApp,
1208 ) -> anyhow::Result<ProjectTransaction> {
1209 // Do not allow multiple concurrent code actions requests for the
1210 // same buffer.
1211 lsp_store.update(cx, |this, cx| {
1212 let this = this.as_local_mut().unwrap();
1213 buffers.retain(|buffer| {
1214 this.buffers_being_formatted
1215 .insert(buffer.read(cx).remote_id())
1216 });
1217 })?;
1218 let _cleanup = defer({
1219 let this = lsp_store.clone();
1220 let mut cx = cx.clone();
1221 let buffers = &buffers;
1222 move || {
1223 this.update(&mut cx, |this, cx| {
1224 let this = this.as_local_mut().unwrap();
1225 for buffer in buffers {
1226 this.buffers_being_formatted
1227 .remove(&buffer.read(cx).remote_id());
1228 }
1229 })
1230 .ok();
1231 }
1232 });
1233 let mut project_transaction = ProjectTransaction::default();
1234
1235 for buffer in &buffers {
1236 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1237 buffer.update(cx, |buffer, cx| {
1238 lsp_store
1239 .as_local()
1240 .unwrap()
1241 .language_servers_for_buffer(buffer, cx)
1242 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1243 .collect::<Vec<_>>()
1244 })
1245 })?;
1246 for (lsp_adapter, language_server) in adapters_and_servers.iter() {
1247 let actions = Self::get_server_code_actions_from_action_kinds(
1248 &lsp_store,
1249 language_server.server_id(),
1250 vec![kind.clone()],
1251 buffer,
1252 cx,
1253 )
1254 .await?;
1255 Self::execute_code_actions_on_server(
1256 &lsp_store,
1257 language_server,
1258 lsp_adapter,
1259 actions,
1260 push_to_history,
1261 &mut project_transaction,
1262 cx,
1263 )
1264 .await?;
1265 }
1266 }
1267 Ok(project_transaction)
1268 }
1269
1270 async fn format_locally(
1271 lsp_store: WeakEntity<LspStore>,
1272 mut buffers: Vec<FormattableBuffer>,
1273 push_to_history: bool,
1274 trigger: FormatTrigger,
1275 logger: zlog::Logger,
1276 cx: &mut AsyncApp,
1277 ) -> anyhow::Result<ProjectTransaction> {
1278 // Do not allow multiple concurrent formatting requests for the
1279 // same buffer.
1280 lsp_store.update(cx, |this, cx| {
1281 let this = this.as_local_mut().unwrap();
1282 buffers.retain(|buffer| {
1283 this.buffers_being_formatted
1284 .insert(buffer.handle.read(cx).remote_id())
1285 });
1286 })?;
1287
1288 let _cleanup = defer({
1289 let this = lsp_store.clone();
1290 let mut cx = cx.clone();
1291 let buffers = &buffers;
1292 move || {
1293 this.update(&mut cx, |this, cx| {
1294 let this = this.as_local_mut().unwrap();
1295 for buffer in buffers {
1296 this.buffers_being_formatted
1297 .remove(&buffer.handle.read(cx).remote_id());
1298 }
1299 })
1300 .ok();
1301 }
1302 });
1303
1304 let mut project_transaction = ProjectTransaction::default();
1305
1306 for buffer in &buffers {
1307 zlog::debug!(
1308 logger =>
1309 "formatting buffer '{:?}'",
1310 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1311 );
1312 // Create an empty transaction to hold all of the formatting edits.
1313 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1314 // ensure no transactions created while formatting are
1315 // grouped with the previous transaction in the history
1316 // based on the transaction group interval
1317 buffer.finalize_last_transaction();
1318 buffer
1319 .start_transaction()
1320 .context("transaction already open")?;
1321 buffer.end_transaction(cx);
1322 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1323 buffer.finalize_last_transaction();
1324 anyhow::Ok(transaction_id)
1325 })??;
1326
1327 let result = Self::format_buffer_locally(
1328 lsp_store.clone(),
1329 buffer,
1330 formatting_transaction_id,
1331 trigger,
1332 logger,
1333 cx,
1334 )
1335 .await;
1336
1337 buffer.handle.update(cx, |buffer, cx| {
1338 let Some(formatting_transaction) =
1339 buffer.get_transaction(formatting_transaction_id).cloned()
1340 else {
1341 zlog::warn!(logger => "no formatting transaction");
1342 return;
1343 };
1344 if formatting_transaction.edit_ids.is_empty() {
1345 zlog::debug!(logger => "no changes made while formatting");
1346 buffer.forget_transaction(formatting_transaction_id);
1347 return;
1348 }
1349 if !push_to_history {
1350 zlog::trace!(logger => "forgetting format transaction");
1351 buffer.forget_transaction(formatting_transaction.id);
1352 }
1353 project_transaction
1354 .0
1355 .insert(cx.entity(), formatting_transaction);
1356 })?;
1357
1358 result?;
1359 }
1360
1361 Ok(project_transaction)
1362 }
1363
1364 async fn format_buffer_locally(
1365 lsp_store: WeakEntity<LspStore>,
1366 buffer: &FormattableBuffer,
1367 formatting_transaction_id: clock::Lamport,
1368 trigger: FormatTrigger,
1369 logger: zlog::Logger,
1370 cx: &mut AsyncApp,
1371 ) -> Result<()> {
1372 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1373 buffer.handle.update(cx, |buffer, cx| {
1374 let adapters_and_servers = lsp_store
1375 .as_local()
1376 .unwrap()
1377 .language_servers_for_buffer(buffer, cx)
1378 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1379 .collect::<Vec<_>>();
1380 let settings =
1381 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1382 .into_owned();
1383 (adapters_and_servers, settings)
1384 })
1385 })?;
1386
1387 /// Apply edits to the buffer that will become part of the formatting transaction.
1388 /// Fails if the buffer has been edited since the start of that transaction.
1389 fn extend_formatting_transaction(
1390 buffer: &FormattableBuffer,
1391 formatting_transaction_id: text::TransactionId,
1392 cx: &mut AsyncApp,
1393 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1394 ) -> anyhow::Result<()> {
1395 buffer.handle.update(cx, |buffer, cx| {
1396 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1397 if last_transaction_id != Some(formatting_transaction_id) {
1398 anyhow::bail!("Buffer edited while formatting. Aborting")
1399 }
1400 buffer.start_transaction();
1401 operation(buffer, cx);
1402 if let Some(transaction_id) = buffer.end_transaction(cx) {
1403 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1404 }
1405 Ok(())
1406 })?
1407 }
1408
1409 // handle whitespace formatting
1410 if settings.remove_trailing_whitespace_on_save {
1411 zlog::trace!(logger => "removing trailing whitespace");
1412 let diff = buffer
1413 .handle
1414 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1415 .await;
1416 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1417 buffer.apply_diff(diff, cx);
1418 })?;
1419 }
1420
1421 if settings.ensure_final_newline_on_save {
1422 zlog::trace!(logger => "ensuring final newline");
1423 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1424 buffer.ensure_final_newline(cx);
1425 })?;
1426 }
1427
1428 // Formatter for `code_actions_on_format` that runs before
1429 // the rest of the formatters
1430 let mut code_actions_on_format_formatter = None;
1431 let should_run_code_actions_on_format = !matches!(
1432 (trigger, &settings.format_on_save),
1433 (FormatTrigger::Save, &FormatOnSave::Off)
1434 );
1435 if should_run_code_actions_on_format {
1436 let have_code_actions_to_run_on_format = settings
1437 .code_actions_on_format
1438 .values()
1439 .any(|enabled| *enabled);
1440 if have_code_actions_to_run_on_format {
1441 zlog::trace!(logger => "going to run code actions on format");
1442 code_actions_on_format_formatter = Some(Formatter::CodeActions(
1443 settings.code_actions_on_format.clone(),
1444 ));
1445 }
1446 }
1447
1448 let formatters = match (trigger, &settings.format_on_save) {
1449 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1450 (FormatTrigger::Save, FormatOnSave::List(formatters)) => formatters.as_ref(),
1451 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1452 match &settings.formatter {
1453 SelectedFormatter::Auto => {
1454 if settings.prettier.allowed {
1455 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1456 std::slice::from_ref(&Formatter::Prettier)
1457 } else {
1458 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1459 std::slice::from_ref(&Formatter::LanguageServer { name: None })
1460 }
1461 }
1462 SelectedFormatter::List(formatter_list) => formatter_list.as_ref(),
1463 }
1464 }
1465 };
1466
1467 let formatters = code_actions_on_format_formatter.iter().chain(formatters);
1468
1469 for formatter in formatters {
1470 match formatter {
1471 Formatter::Prettier => {
1472 let logger = zlog::scoped!(logger => "prettier");
1473 zlog::trace!(logger => "formatting");
1474 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1475
1476 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1477 lsp_store.prettier_store().unwrap().downgrade()
1478 })?;
1479 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1480 .await
1481 .transpose()?;
1482 let Some(diff) = diff else {
1483 zlog::trace!(logger => "No changes");
1484 continue;
1485 };
1486
1487 extend_formatting_transaction(
1488 buffer,
1489 formatting_transaction_id,
1490 cx,
1491 |buffer, cx| {
1492 buffer.apply_diff(diff, cx);
1493 },
1494 )?;
1495 }
1496 Formatter::External { command, arguments } => {
1497 let logger = zlog::scoped!(logger => "command");
1498 zlog::trace!(logger => "formatting");
1499 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1500
1501 let diff = Self::format_via_external_command(
1502 buffer,
1503 command.as_ref(),
1504 arguments.as_deref(),
1505 cx,
1506 )
1507 .await
1508 .with_context(|| {
1509 format!("Failed to format buffer via external command: {}", command)
1510 })?;
1511 let Some(diff) = diff else {
1512 zlog::trace!(logger => "No changes");
1513 continue;
1514 };
1515
1516 extend_formatting_transaction(
1517 buffer,
1518 formatting_transaction_id,
1519 cx,
1520 |buffer, cx| {
1521 buffer.apply_diff(diff, cx);
1522 },
1523 )?;
1524 }
1525 Formatter::LanguageServer { name } => {
1526 let logger = zlog::scoped!(logger => "language-server");
1527 zlog::trace!(logger => "formatting");
1528 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1529
1530 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1531 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1532 continue;
1533 };
1534
1535 let language_server = if let Some(name) = name.as_deref() {
1536 adapters_and_servers.iter().find_map(|(adapter, server)| {
1537 if adapter.name.0.as_ref() == name {
1538 Some(server.clone())
1539 } else {
1540 None
1541 }
1542 })
1543 } else {
1544 adapters_and_servers.first().map(|e| e.1.clone())
1545 };
1546
1547 let Some(language_server) = language_server else {
1548 log::debug!(
1549 "No language server found to format buffer '{:?}'. Skipping",
1550 buffer_path_abs.as_path().to_string_lossy()
1551 );
1552 continue;
1553 };
1554
1555 zlog::trace!(
1556 logger =>
1557 "Formatting buffer '{:?}' using language server '{:?}'",
1558 buffer_path_abs.as_path().to_string_lossy(),
1559 language_server.name()
1560 );
1561
1562 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1563 zlog::trace!(logger => "formatting ranges");
1564 Self::format_ranges_via_lsp(
1565 &lsp_store,
1566 &buffer.handle,
1567 ranges,
1568 buffer_path_abs,
1569 &language_server,
1570 &settings,
1571 cx,
1572 )
1573 .await
1574 .context("Failed to format ranges via language server")?
1575 } else {
1576 zlog::trace!(logger => "formatting full");
1577 Self::format_via_lsp(
1578 &lsp_store,
1579 &buffer.handle,
1580 buffer_path_abs,
1581 &language_server,
1582 &settings,
1583 cx,
1584 )
1585 .await
1586 .context("failed to format via language server")?
1587 };
1588
1589 if edits.is_empty() {
1590 zlog::trace!(logger => "No changes");
1591 continue;
1592 }
1593 extend_formatting_transaction(
1594 buffer,
1595 formatting_transaction_id,
1596 cx,
1597 |buffer, cx| {
1598 buffer.edit(edits, None, cx);
1599 },
1600 )?;
1601 }
1602 Formatter::CodeActions(code_actions) => {
1603 let logger = zlog::scoped!(logger => "code-actions");
1604 zlog::trace!(logger => "formatting");
1605 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1606
1607 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1608 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1609 continue;
1610 };
1611 let code_action_kinds = code_actions
1612 .iter()
1613 .filter_map(|(action_kind, enabled)| {
1614 enabled.then_some(action_kind.clone().into())
1615 })
1616 .collect::<Vec<_>>();
1617 if code_action_kinds.is_empty() {
1618 zlog::trace!(logger => "No code action kinds enabled, skipping");
1619 continue;
1620 }
1621 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kinds);
1622
1623 let mut actions_and_servers = Vec::new();
1624
1625 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1626 let actions_result = Self::get_server_code_actions_from_action_kinds(
1627 &lsp_store,
1628 language_server.server_id(),
1629 code_action_kinds.clone(),
1630 &buffer.handle,
1631 cx,
1632 )
1633 .await
1634 .with_context(
1635 || format!("Failed to resolve code actions with kinds {:?} for language server {}",
1636 code_action_kinds.iter().map(|kind| kind.as_str()).join(", "),
1637 language_server.name())
1638 );
1639 let Ok(actions) = actions_result else {
1640 // note: it may be better to set result to the error and break formatters here
1641 // but for now we try to execute the actions that we can resolve and skip the rest
1642 zlog::error!(
1643 logger =>
1644 "Failed to resolve code actions with kinds {:?} with language server {}",
1645 code_action_kinds.iter().map(|kind| kind.as_str()).join(", "),
1646 language_server.name()
1647 );
1648 continue;
1649 };
1650 for action in actions {
1651 actions_and_servers.push((action, index));
1652 }
1653 }
1654
1655 if actions_and_servers.is_empty() {
1656 zlog::warn!(logger => "No code actions were resolved, continuing");
1657 continue;
1658 }
1659
1660 'actions: for (mut action, server_index) in actions_and_servers {
1661 let server = &adapters_and_servers[server_index].1;
1662
1663 let describe_code_action = |action: &CodeAction| {
1664 format!(
1665 "code action '{}' with title \"{}\" on server {}",
1666 action
1667 .lsp_action
1668 .action_kind()
1669 .unwrap_or("unknown".into())
1670 .as_str(),
1671 action.lsp_action.title(),
1672 server.name(),
1673 )
1674 };
1675
1676 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1677
1678 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1679 zlog::error!(
1680 logger =>
1681 "Failed to resolve {}. Error: {}",
1682 describe_code_action(&action),
1683 err
1684 );
1685 continue;
1686 }
1687
1688 if let Some(edit) = action.lsp_action.edit().cloned() {
1689 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1690 // but filters out and logs warnings for code actions that cause unreasonably
1691 // difficult handling on our part, such as:
1692 // - applying edits that call commands
1693 // which can result in arbitrary workspace edits being sent from the server that
1694 // have no way of being tied back to the command that initiated them (i.e. we
1695 // can't know which edits are part of the format request, or if the server is done sending
1696 // actions in response to the command)
1697 // - actions that create/delete/modify/rename files other than the one we are formatting
1698 // as we then would need to handle such changes correctly in the local history as well
1699 // as the remote history through the ProjectTransaction
1700 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1701 // Supporting these actions is not impossible, but not supported as of yet.
1702 if edit.changes.is_none() && edit.document_changes.is_none() {
1703 zlog::trace!(
1704 logger =>
1705 "No changes for code action. Skipping {}",
1706 describe_code_action(&action),
1707 );
1708 continue;
1709 }
1710
1711 let mut operations = Vec::new();
1712 if let Some(document_changes) = edit.document_changes {
1713 match document_changes {
1714 lsp::DocumentChanges::Edits(edits) => operations.extend(
1715 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1716 ),
1717 lsp::DocumentChanges::Operations(ops) => operations = ops,
1718 }
1719 } else if let Some(changes) = edit.changes {
1720 operations.extend(changes.into_iter().map(|(uri, edits)| {
1721 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1722 text_document:
1723 lsp::OptionalVersionedTextDocumentIdentifier {
1724 uri,
1725 version: None,
1726 },
1727 edits: edits.into_iter().map(Edit::Plain).collect(),
1728 })
1729 }));
1730 }
1731
1732 let mut edits = Vec::with_capacity(operations.len());
1733
1734 if operations.is_empty() {
1735 zlog::trace!(
1736 logger =>
1737 "No changes for code action. Skipping {}",
1738 describe_code_action(&action),
1739 );
1740 continue;
1741 }
1742 for operation in operations {
1743 let op = match operation {
1744 lsp::DocumentChangeOperation::Edit(op) => op,
1745 lsp::DocumentChangeOperation::Op(_) => {
1746 zlog::warn!(
1747 logger =>
1748 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1749 describe_code_action(&action),
1750 );
1751 continue 'actions;
1752 }
1753 };
1754 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1755 zlog::warn!(
1756 logger =>
1757 "Failed to convert URI '{:?}' to file path. Skipping {}",
1758 &op.text_document.uri,
1759 describe_code_action(&action),
1760 );
1761 continue 'actions;
1762 };
1763 if &file_path != buffer_path_abs {
1764 zlog::warn!(
1765 logger =>
1766 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1767 file_path,
1768 buffer_path_abs,
1769 describe_code_action(&action),
1770 );
1771 continue 'actions;
1772 }
1773
1774 let mut lsp_edits = Vec::new();
1775 for edit in op.edits {
1776 match edit {
1777 Edit::Plain(edit) => {
1778 if !lsp_edits.contains(&edit) {
1779 lsp_edits.push(edit);
1780 }
1781 }
1782 Edit::Annotated(edit) => {
1783 if !lsp_edits.contains(&edit.text_edit) {
1784 lsp_edits.push(edit.text_edit);
1785 }
1786 }
1787 Edit::Snippet(_) => {
1788 zlog::warn!(
1789 logger =>
1790 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1791 describe_code_action(&action),
1792 );
1793 continue 'actions;
1794 }
1795 }
1796 }
1797 let edits_result = lsp_store
1798 .update(cx, |lsp_store, cx| {
1799 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1800 &buffer.handle,
1801 lsp_edits,
1802 server.server_id(),
1803 op.text_document.version,
1804 cx,
1805 )
1806 })?
1807 .await;
1808 let Ok(resolved_edits) = edits_result else {
1809 zlog::warn!(
1810 logger =>
1811 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1812 buffer_path_abs.as_path(),
1813 describe_code_action(&action),
1814 );
1815 continue 'actions;
1816 };
1817 edits.extend(resolved_edits);
1818 }
1819
1820 if edits.is_empty() {
1821 zlog::warn!(logger => "No edits resolved from LSP");
1822 continue;
1823 }
1824
1825 extend_formatting_transaction(
1826 buffer,
1827 formatting_transaction_id,
1828 cx,
1829 |buffer, cx| {
1830 buffer.edit(edits, None, cx);
1831 },
1832 )?;
1833 }
1834
1835 if let Some(command) = action.lsp_action.command() {
1836 zlog::warn!(
1837 logger =>
1838 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1839 &command.command,
1840 );
1841
1842 // bail early if command is invalid
1843 let server_capabilities = server.capabilities();
1844 let available_commands = server_capabilities
1845 .execute_command_provider
1846 .as_ref()
1847 .map(|options| options.commands.as_slice())
1848 .unwrap_or_default();
1849 if !available_commands.contains(&command.command) {
1850 zlog::warn!(
1851 logger =>
1852 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1853 command.command,
1854 server.name(),
1855 );
1856 continue;
1857 }
1858
1859 // noop so we just ensure buffer hasn't been edited since resolving code actions
1860 extend_formatting_transaction(
1861 buffer,
1862 formatting_transaction_id,
1863 cx,
1864 |_, _| {},
1865 )?;
1866 zlog::info!(logger => "Executing command {}", &command.command);
1867
1868 lsp_store.update(cx, |this, _| {
1869 this.as_local_mut()
1870 .unwrap()
1871 .last_workspace_edits_by_language_server
1872 .remove(&server.server_id());
1873 })?;
1874
1875 let execute_command_result = server
1876 .request::<lsp::request::ExecuteCommand>(
1877 lsp::ExecuteCommandParams {
1878 command: command.command.clone(),
1879 arguments: command.arguments.clone().unwrap_or_default(),
1880 ..Default::default()
1881 },
1882 )
1883 .await
1884 .into_response();
1885
1886 if execute_command_result.is_err() {
1887 zlog::error!(
1888 logger =>
1889 "Failed to execute command '{}' as part of {}",
1890 &command.command,
1891 describe_code_action(&action),
1892 );
1893 continue 'actions;
1894 }
1895
1896 let mut project_transaction_command =
1897 lsp_store.update(cx, |this, _| {
1898 this.as_local_mut()
1899 .unwrap()
1900 .last_workspace_edits_by_language_server
1901 .remove(&server.server_id())
1902 .unwrap_or_default()
1903 })?;
1904
1905 if let Some(transaction) =
1906 project_transaction_command.0.remove(&buffer.handle)
1907 {
1908 zlog::trace!(
1909 logger =>
1910 "Successfully captured {} edits that resulted from command {}",
1911 transaction.edit_ids.len(),
1912 &command.command,
1913 );
1914 let transaction_id_project_transaction = transaction.id;
1915 buffer.handle.update(cx, |buffer, _| {
1916 // it may have been removed from history if push_to_history was
1917 // false in deserialize_workspace_edit. If so push it so we
1918 // can merge it with the format transaction
1919 // and pop the combined transaction off the history stack
1920 // later if push_to_history is false
1921 if buffer.get_transaction(transaction.id).is_none() {
1922 buffer.push_transaction(transaction, Instant::now());
1923 }
1924 buffer.merge_transactions(
1925 transaction_id_project_transaction,
1926 formatting_transaction_id,
1927 );
1928 })?;
1929 }
1930
1931 if !project_transaction_command.0.is_empty() {
1932 let extra_buffers = project_transaction_command
1933 .0
1934 .keys()
1935 .filter_map(|buffer_handle| {
1936 buffer_handle
1937 .read_with(cx, |b, cx| b.project_path(cx))
1938 .ok()
1939 .flatten()
1940 })
1941 .map(|p| p.path.to_sanitized_string())
1942 .join(", ");
1943 zlog::warn!(
1944 logger =>
1945 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
1946 &command.command,
1947 extra_buffers,
1948 );
1949 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
1950 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
1951 // add it so it's included, and merge it into the format transaction when its created later
1952 }
1953 }
1954 }
1955 }
1956 }
1957 }
1958
1959 Ok(())
1960 }
1961
1962 pub async fn format_ranges_via_lsp(
1963 this: &WeakEntity<LspStore>,
1964 buffer_handle: &Entity<Buffer>,
1965 ranges: &[Range<Anchor>],
1966 abs_path: &Path,
1967 language_server: &Arc<LanguageServer>,
1968 settings: &LanguageSettings,
1969 cx: &mut AsyncApp,
1970 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
1971 let capabilities = &language_server.capabilities();
1972 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1973 if range_formatting_provider.map_or(false, |provider| provider == &OneOf::Left(false)) {
1974 anyhow::bail!(
1975 "{} language server does not support range formatting",
1976 language_server.name()
1977 );
1978 }
1979
1980 let uri = file_path_to_lsp_url(abs_path)?;
1981 let text_document = lsp::TextDocumentIdentifier::new(uri);
1982
1983 let lsp_edits = {
1984 let mut lsp_ranges = Vec::new();
1985 this.update(cx, |_this, cx| {
1986 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
1987 // not have been sent to the language server. This seems like a fairly systemic
1988 // issue, though, the resolution probably is not specific to formatting.
1989 //
1990 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
1991 // LSP.
1992 let snapshot = buffer_handle.read(cx).snapshot();
1993 for range in ranges {
1994 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
1995 }
1996 anyhow::Ok(())
1997 })??;
1998
1999 let mut edits = None;
2000 for range in lsp_ranges {
2001 if let Some(mut edit) = language_server
2002 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2003 text_document: text_document.clone(),
2004 range,
2005 options: lsp_command::lsp_formatting_options(settings),
2006 work_done_progress_params: Default::default(),
2007 })
2008 .await
2009 .into_response()?
2010 {
2011 edits.get_or_insert_with(Vec::new).append(&mut edit);
2012 }
2013 }
2014 edits
2015 };
2016
2017 if let Some(lsp_edits) = lsp_edits {
2018 this.update(cx, |this, cx| {
2019 this.as_local_mut().unwrap().edits_from_lsp(
2020 &buffer_handle,
2021 lsp_edits,
2022 language_server.server_id(),
2023 None,
2024 cx,
2025 )
2026 })?
2027 .await
2028 } else {
2029 Ok(Vec::with_capacity(0))
2030 }
2031 }
2032
2033 async fn format_via_lsp(
2034 this: &WeakEntity<LspStore>,
2035 buffer: &Entity<Buffer>,
2036 abs_path: &Path,
2037 language_server: &Arc<LanguageServer>,
2038 settings: &LanguageSettings,
2039 cx: &mut AsyncApp,
2040 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2041 let logger = zlog::scoped!("lsp_format");
2042 zlog::info!(logger => "Formatting via LSP");
2043
2044 let uri = file_path_to_lsp_url(abs_path)?;
2045 let text_document = lsp::TextDocumentIdentifier::new(uri);
2046 let capabilities = &language_server.capabilities();
2047
2048 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2049 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2050
2051 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2052 let _timer = zlog::time!(logger => "format-full");
2053 language_server
2054 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2055 text_document,
2056 options: lsp_command::lsp_formatting_options(settings),
2057 work_done_progress_params: Default::default(),
2058 })
2059 .await
2060 .into_response()?
2061 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2062 let _timer = zlog::time!(logger => "format-range");
2063 let buffer_start = lsp::Position::new(0, 0);
2064 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2065 language_server
2066 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2067 text_document: text_document.clone(),
2068 range: lsp::Range::new(buffer_start, buffer_end),
2069 options: lsp_command::lsp_formatting_options(settings),
2070 work_done_progress_params: Default::default(),
2071 })
2072 .await
2073 .into_response()?
2074 } else {
2075 None
2076 };
2077
2078 if let Some(lsp_edits) = lsp_edits {
2079 this.update(cx, |this, cx| {
2080 this.as_local_mut().unwrap().edits_from_lsp(
2081 buffer,
2082 lsp_edits,
2083 language_server.server_id(),
2084 None,
2085 cx,
2086 )
2087 })?
2088 .await
2089 } else {
2090 Ok(Vec::with_capacity(0))
2091 }
2092 }
2093
2094 async fn format_via_external_command(
2095 buffer: &FormattableBuffer,
2096 command: &str,
2097 arguments: Option<&[String]>,
2098 cx: &mut AsyncApp,
2099 ) -> Result<Option<Diff>> {
2100 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2101 let file = File::from_dyn(buffer.file())?;
2102 let worktree = file.worktree.read(cx);
2103 let mut worktree_path = worktree.abs_path().to_path_buf();
2104 if worktree.root_entry()?.is_file() {
2105 worktree_path.pop();
2106 }
2107 Some(worktree_path)
2108 })?;
2109
2110 let mut child = util::command::new_smol_command(command);
2111
2112 if let Some(buffer_env) = buffer.env.as_ref() {
2113 child.envs(buffer_env);
2114 }
2115
2116 if let Some(working_dir_path) = working_dir_path {
2117 child.current_dir(working_dir_path);
2118 }
2119
2120 if let Some(arguments) = arguments {
2121 child.args(arguments.iter().map(|arg| {
2122 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2123 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2124 } else {
2125 arg.replace("{buffer_path}", "Untitled")
2126 }
2127 }));
2128 }
2129
2130 let mut child = child
2131 .stdin(smol::process::Stdio::piped())
2132 .stdout(smol::process::Stdio::piped())
2133 .stderr(smol::process::Stdio::piped())
2134 .spawn()?;
2135
2136 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2137 let text = buffer
2138 .handle
2139 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2140 for chunk in text.chunks() {
2141 stdin.write_all(chunk.as_bytes()).await?;
2142 }
2143 stdin.flush().await?;
2144
2145 let output = child.output().await?;
2146 anyhow::ensure!(
2147 output.status.success(),
2148 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2149 output.status.code(),
2150 String::from_utf8_lossy(&output.stdout),
2151 String::from_utf8_lossy(&output.stderr),
2152 );
2153
2154 let stdout = String::from_utf8(output.stdout)?;
2155 Ok(Some(
2156 buffer
2157 .handle
2158 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2159 .await,
2160 ))
2161 }
2162
2163 async fn try_resolve_code_action(
2164 lang_server: &LanguageServer,
2165 action: &mut CodeAction,
2166 ) -> anyhow::Result<()> {
2167 match &mut action.lsp_action {
2168 LspAction::Action(lsp_action) => {
2169 if !action.resolved
2170 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2171 && lsp_action.data.is_some()
2172 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2173 {
2174 *lsp_action = Box::new(
2175 lang_server
2176 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2177 .await
2178 .into_response()?,
2179 );
2180 }
2181 }
2182 LspAction::CodeLens(lens) => {
2183 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2184 *lens = lang_server
2185 .request::<lsp::request::CodeLensResolve>(lens.clone())
2186 .await
2187 .into_response()?;
2188 }
2189 }
2190 LspAction::Command(_) => {}
2191 }
2192
2193 action.resolved = true;
2194 anyhow::Ok(())
2195 }
2196
2197 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2198 let buffer = buffer_handle.read(cx);
2199
2200 let file = buffer.file().cloned();
2201 let Some(file) = File::from_dyn(file.as_ref()) else {
2202 return;
2203 };
2204 if !file.is_local() {
2205 return;
2206 }
2207
2208 let worktree_id = file.worktree_id(cx);
2209 let language = buffer.language().cloned();
2210
2211 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2212 for (server_id, diagnostics) in
2213 diagnostics.get(file.path()).cloned().unwrap_or_default()
2214 {
2215 self.update_buffer_diagnostics(
2216 buffer_handle,
2217 server_id,
2218 None,
2219 None,
2220 diagnostics,
2221 Vec::new(),
2222 cx,
2223 )
2224 .log_err();
2225 }
2226 }
2227 let Some(language) = language else {
2228 return;
2229 };
2230 for adapter in self.languages.lsp_adapters(&language.name()) {
2231 let servers = self
2232 .language_server_ids
2233 .get(&(worktree_id, adapter.name.clone()));
2234 if let Some(server_ids) = servers {
2235 for server_id in server_ids {
2236 let server = self
2237 .language_servers
2238 .get(server_id)
2239 .and_then(|server_state| {
2240 if let LanguageServerState::Running { server, .. } = server_state {
2241 Some(server.clone())
2242 } else {
2243 None
2244 }
2245 });
2246 let server = match server {
2247 Some(server) => server,
2248 None => continue,
2249 };
2250
2251 buffer_handle.update(cx, |buffer, cx| {
2252 buffer.set_completion_triggers(
2253 server.server_id(),
2254 server
2255 .capabilities()
2256 .completion_provider
2257 .as_ref()
2258 .and_then(|provider| {
2259 provider
2260 .trigger_characters
2261 .as_ref()
2262 .map(|characters| characters.iter().cloned().collect())
2263 })
2264 .unwrap_or_default(),
2265 cx,
2266 );
2267 });
2268 }
2269 }
2270 }
2271 }
2272
2273 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2274 buffer.update(cx, |buffer, cx| {
2275 let Some(language) = buffer.language() else {
2276 return;
2277 };
2278 let path = ProjectPath {
2279 worktree_id: old_file.worktree_id(cx),
2280 path: old_file.path.clone(),
2281 };
2282 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2283 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2284 buffer.set_completion_triggers(server_id, Default::default(), cx);
2285 }
2286 });
2287 }
2288
2289 fn update_buffer_diagnostics(
2290 &mut self,
2291 buffer: &Entity<Buffer>,
2292 server_id: LanguageServerId,
2293 result_id: Option<String>,
2294 version: Option<i32>,
2295 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2296 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2297 cx: &mut Context<LspStore>,
2298 ) -> Result<()> {
2299 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2300 Ordering::Equal
2301 .then_with(|| b.is_primary.cmp(&a.is_primary))
2302 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2303 .then_with(|| a.severity.cmp(&b.severity))
2304 .then_with(|| a.message.cmp(&b.message))
2305 }
2306
2307 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2308 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2309 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2310
2311 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2312 Ordering::Equal
2313 .then_with(|| a.range.start.cmp(&b.range.start))
2314 .then_with(|| b.range.end.cmp(&a.range.end))
2315 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2316 });
2317
2318 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2319
2320 let edits_since_save = std::cell::LazyCell::new(|| {
2321 let saved_version = buffer.read(cx).saved_version();
2322 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2323 });
2324
2325 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2326
2327 for (new_diagnostic, entry) in diagnostics {
2328 let start;
2329 let end;
2330 if new_diagnostic && entry.diagnostic.is_disk_based {
2331 // Some diagnostics are based on files on disk instead of buffers'
2332 // current contents. Adjust these diagnostics' ranges to reflect
2333 // any unsaved edits.
2334 // Do not alter the reused ones though, as their coordinates were stored as anchors
2335 // and were properly adjusted on reuse.
2336 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2337 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2338 } else {
2339 start = entry.range.start;
2340 end = entry.range.end;
2341 }
2342
2343 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2344 ..snapshot.clip_point_utf16(end, Bias::Right);
2345
2346 // Expand empty ranges by one codepoint
2347 if range.start == range.end {
2348 // This will be go to the next boundary when being clipped
2349 range.end.column += 1;
2350 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2351 if range.start == range.end && range.end.column > 0 {
2352 range.start.column -= 1;
2353 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2354 }
2355 }
2356
2357 sanitized_diagnostics.push(DiagnosticEntry {
2358 range,
2359 diagnostic: entry.diagnostic,
2360 });
2361 }
2362 drop(edits_since_save);
2363
2364 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2365 buffer.update(cx, |buffer, cx| {
2366 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2367 self.buffer_pull_diagnostics_result_ids
2368 .entry(server_id)
2369 .or_default()
2370 .insert(abs_path, result_id);
2371 }
2372
2373 buffer.update_diagnostics(server_id, set, cx)
2374 });
2375
2376 Ok(())
2377 }
2378
2379 fn register_buffer_with_language_servers(
2380 &mut self,
2381 buffer_handle: &Entity<Buffer>,
2382 only_register_servers: HashSet<LanguageServerSelector>,
2383 cx: &mut Context<LspStore>,
2384 ) {
2385 let buffer = buffer_handle.read(cx);
2386 let buffer_id = buffer.remote_id();
2387
2388 let Some(file) = File::from_dyn(buffer.file()) else {
2389 return;
2390 };
2391 if !file.is_local() {
2392 return;
2393 }
2394
2395 let abs_path = file.abs_path(cx);
2396 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2397 return;
2398 };
2399 let initial_snapshot = buffer.text_snapshot();
2400 let worktree_id = file.worktree_id(cx);
2401
2402 let Some(language) = buffer.language().cloned() else {
2403 return;
2404 };
2405 let path: Arc<Path> = file
2406 .path()
2407 .parent()
2408 .map(Arc::from)
2409 .unwrap_or_else(|| file.path().clone());
2410 let Some(worktree) = self
2411 .worktree_store
2412 .read(cx)
2413 .worktree_for_id(worktree_id, cx)
2414 else {
2415 return;
2416 };
2417 let language_name = language.name();
2418 let (reused, delegate, servers) = self
2419 .lsp_tree
2420 .update(cx, |lsp_tree, cx| {
2421 self.reuse_existing_language_server(lsp_tree, &worktree, &language_name, cx)
2422 })
2423 .map(|(delegate, servers)| (true, delegate, servers))
2424 .unwrap_or_else(|| {
2425 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2426 let delegate = Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2427 let servers = self
2428 .lsp_tree
2429 .clone()
2430 .update(cx, |language_server_tree, cx| {
2431 language_server_tree
2432 .get(
2433 ProjectPath { worktree_id, path },
2434 AdapterQuery::Language(&language.name()),
2435 delegate.clone(),
2436 cx,
2437 )
2438 .collect::<Vec<_>>()
2439 });
2440 (false, lsp_delegate, servers)
2441 });
2442 let servers_and_adapters = servers
2443 .into_iter()
2444 .filter_map(|server_node| {
2445 if reused && server_node.server_id().is_none() {
2446 return None;
2447 }
2448 if !only_register_servers.is_empty() {
2449 if let Some(server_id) = server_node.server_id() {
2450 if !only_register_servers.contains(&LanguageServerSelector::Id(server_id)) {
2451 return None;
2452 }
2453 }
2454 if let Some(name) = server_node.name() {
2455 if !only_register_servers.contains(&LanguageServerSelector::Name(name)) {
2456 return None;
2457 }
2458 }
2459 }
2460
2461 let server_id = server_node.server_id_or_init(
2462 |LaunchDisposition {
2463 server_name,
2464 path,
2465 settings,
2466 }| {
2467 let server_id =
2468 {
2469 let uri = Url::from_file_path(
2470 worktree.read(cx).abs_path().join(&path.path),
2471 );
2472 let key = (worktree_id, server_name.clone());
2473 if !self.language_server_ids.contains_key(&key) {
2474 let language_name = language.name();
2475 let adapter = self.languages
2476 .lsp_adapters(&language_name)
2477 .into_iter()
2478 .find(|adapter| &adapter.name() == server_name)
2479 .expect("To find LSP adapter");
2480 self.start_language_server(
2481 &worktree,
2482 delegate.clone(),
2483 adapter,
2484 settings,
2485 cx,
2486 );
2487 }
2488 if let Some(server_ids) = self
2489 .language_server_ids
2490 .get(&key)
2491 {
2492 debug_assert_eq!(server_ids.len(), 1);
2493 let server_id = server_ids.iter().cloned().next().unwrap();
2494 if let Some(state) = self.language_servers.get(&server_id) {
2495 if let Ok(uri) = uri {
2496 state.add_workspace_folder(uri);
2497 };
2498 }
2499 server_id
2500 } else {
2501 unreachable!("Language server ID should be available, as it's registered on demand")
2502 }
2503
2504 };
2505 server_id
2506 },
2507 )?;
2508 let server_state = self.language_servers.get(&server_id)?;
2509 if let LanguageServerState::Running { server, adapter, .. } = server_state {
2510 Some((server.clone(), adapter.clone()))
2511 } else {
2512 None
2513 }
2514 })
2515 .collect::<Vec<_>>();
2516 for (server, adapter) in servers_and_adapters {
2517 buffer_handle.update(cx, |buffer, cx| {
2518 buffer.set_completion_triggers(
2519 server.server_id(),
2520 server
2521 .capabilities()
2522 .completion_provider
2523 .as_ref()
2524 .and_then(|provider| {
2525 provider
2526 .trigger_characters
2527 .as_ref()
2528 .map(|characters| characters.iter().cloned().collect())
2529 })
2530 .unwrap_or_default(),
2531 cx,
2532 );
2533 });
2534
2535 let snapshot = LspBufferSnapshot {
2536 version: 0,
2537 snapshot: initial_snapshot.clone(),
2538 };
2539
2540 let mut registered = false;
2541 self.buffer_snapshots
2542 .entry(buffer_id)
2543 .or_default()
2544 .entry(server.server_id())
2545 .or_insert_with(|| {
2546 registered = true;
2547 server.register_buffer(
2548 uri.clone(),
2549 adapter.language_id(&language.name()),
2550 0,
2551 initial_snapshot.text(),
2552 );
2553
2554 vec![snapshot]
2555 });
2556
2557 self.buffers_opened_in_servers
2558 .entry(buffer_id)
2559 .or_default()
2560 .insert(server.server_id());
2561 if registered {
2562 cx.emit(LspStoreEvent::LanguageServerUpdate {
2563 language_server_id: server.server_id(),
2564 name: None,
2565 message: proto::update_language_server::Variant::RegisteredForBuffer(
2566 proto::RegisteredForBuffer {
2567 buffer_abs_path: abs_path.to_string_lossy().to_string(),
2568 buffer_id: buffer_id.to_proto(),
2569 },
2570 ),
2571 });
2572 }
2573 }
2574 }
2575
2576 fn reuse_existing_language_server(
2577 &self,
2578 server_tree: &mut LanguageServerTree,
2579 worktree: &Entity<Worktree>,
2580 language_name: &LanguageName,
2581 cx: &mut App,
2582 ) -> Option<(Arc<LocalLspAdapterDelegate>, Vec<LanguageServerTreeNode>)> {
2583 if worktree.read(cx).is_visible() {
2584 return None;
2585 }
2586
2587 let worktree_store = self.worktree_store.read(cx);
2588 let servers = server_tree
2589 .instances
2590 .iter()
2591 .filter(|(worktree_id, _)| {
2592 worktree_store
2593 .worktree_for_id(**worktree_id, cx)
2594 .is_some_and(|worktree| worktree.read(cx).is_visible())
2595 })
2596 .flat_map(|(worktree_id, servers)| {
2597 servers
2598 .roots
2599 .iter()
2600 .flat_map(|(_, language_servers)| language_servers)
2601 .map(move |(_, (server_node, server_languages))| {
2602 (worktree_id, server_node, server_languages)
2603 })
2604 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2605 .map(|(worktree_id, server_node, _)| {
2606 (
2607 *worktree_id,
2608 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2609 )
2610 })
2611 })
2612 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2613 acc.entry(worktree_id)
2614 .or_insert_with(Vec::new)
2615 .push(server_node);
2616 acc
2617 })
2618 .into_values()
2619 .max_by_key(|servers| servers.len())?;
2620
2621 for server_node in &servers {
2622 server_tree.register_reused(
2623 worktree.read(cx).id(),
2624 language_name.clone(),
2625 server_node.clone(),
2626 );
2627 }
2628
2629 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2630 Some((delegate, servers))
2631 }
2632
2633 pub(crate) fn unregister_old_buffer_from_language_servers(
2634 &mut self,
2635 buffer: &Entity<Buffer>,
2636 old_file: &File,
2637 cx: &mut App,
2638 ) {
2639 let old_path = match old_file.as_local() {
2640 Some(local) => local.abs_path(cx),
2641 None => return,
2642 };
2643
2644 let Ok(file_url) = lsp::Url::from_file_path(old_path.as_path()) else {
2645 debug_panic!(
2646 "`{}` is not parseable as an URI",
2647 old_path.to_string_lossy()
2648 );
2649 return;
2650 };
2651 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2652 }
2653
2654 pub(crate) fn unregister_buffer_from_language_servers(
2655 &mut self,
2656 buffer: &Entity<Buffer>,
2657 file_url: &lsp::Url,
2658 cx: &mut App,
2659 ) {
2660 buffer.update(cx, |buffer, cx| {
2661 let _ = self.buffer_snapshots.remove(&buffer.remote_id());
2662
2663 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2664 language_server.unregister_buffer(file_url.clone());
2665 }
2666 });
2667 }
2668
2669 fn buffer_snapshot_for_lsp_version(
2670 &mut self,
2671 buffer: &Entity<Buffer>,
2672 server_id: LanguageServerId,
2673 version: Option<i32>,
2674 cx: &App,
2675 ) -> Result<TextBufferSnapshot> {
2676 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2677
2678 if let Some(version) = version {
2679 let buffer_id = buffer.read(cx).remote_id();
2680 let snapshots = if let Some(snapshots) = self
2681 .buffer_snapshots
2682 .get_mut(&buffer_id)
2683 .and_then(|m| m.get_mut(&server_id))
2684 {
2685 snapshots
2686 } else if version == 0 {
2687 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2688 // We detect this case and treat it as if the version was `None`.
2689 return Ok(buffer.read(cx).text_snapshot());
2690 } else {
2691 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2692 };
2693
2694 let found_snapshot = snapshots
2695 .binary_search_by_key(&version, |e| e.version)
2696 .map(|ix| snapshots[ix].snapshot.clone())
2697 .map_err(|_| {
2698 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2699 })?;
2700
2701 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2702 Ok(found_snapshot)
2703 } else {
2704 Ok((buffer.read(cx)).text_snapshot())
2705 }
2706 }
2707
2708 async fn get_server_code_actions_from_action_kinds(
2709 lsp_store: &WeakEntity<LspStore>,
2710 language_server_id: LanguageServerId,
2711 code_action_kinds: Vec<lsp::CodeActionKind>,
2712 buffer: &Entity<Buffer>,
2713 cx: &mut AsyncApp,
2714 ) -> Result<Vec<CodeAction>> {
2715 let actions = lsp_store
2716 .update(cx, move |this, cx| {
2717 let request = GetCodeActions {
2718 range: text::Anchor::MIN..text::Anchor::MAX,
2719 kinds: Some(code_action_kinds),
2720 };
2721 let server = LanguageServerToQuery::Other(language_server_id);
2722 this.request_lsp(buffer.clone(), server, request, cx)
2723 })?
2724 .await?;
2725 return Ok(actions);
2726 }
2727
2728 pub async fn execute_code_actions_on_server(
2729 lsp_store: &WeakEntity<LspStore>,
2730 language_server: &Arc<LanguageServer>,
2731 lsp_adapter: &Arc<CachedLspAdapter>,
2732 actions: Vec<CodeAction>,
2733 push_to_history: bool,
2734 project_transaction: &mut ProjectTransaction,
2735 cx: &mut AsyncApp,
2736 ) -> anyhow::Result<()> {
2737 for mut action in actions {
2738 Self::try_resolve_code_action(language_server, &mut action)
2739 .await
2740 .context("resolving a formatting code action")?;
2741
2742 if let Some(edit) = action.lsp_action.edit() {
2743 if edit.changes.is_none() && edit.document_changes.is_none() {
2744 continue;
2745 }
2746
2747 let new = Self::deserialize_workspace_edit(
2748 lsp_store.upgrade().context("project dropped")?,
2749 edit.clone(),
2750 push_to_history,
2751 lsp_adapter.clone(),
2752 language_server.clone(),
2753 cx,
2754 )
2755 .await?;
2756 project_transaction.0.extend(new.0);
2757 }
2758
2759 if let Some(command) = action.lsp_action.command() {
2760 let server_capabilities = language_server.capabilities();
2761 let available_commands = server_capabilities
2762 .execute_command_provider
2763 .as_ref()
2764 .map(|options| options.commands.as_slice())
2765 .unwrap_or_default();
2766 if available_commands.contains(&command.command) {
2767 lsp_store.update(cx, |lsp_store, _| {
2768 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2769 mode.last_workspace_edits_by_language_server
2770 .remove(&language_server.server_id());
2771 }
2772 })?;
2773
2774 language_server
2775 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2776 command: command.command.clone(),
2777 arguments: command.arguments.clone().unwrap_or_default(),
2778 ..Default::default()
2779 })
2780 .await
2781 .into_response()
2782 .context("execute command")?;
2783
2784 lsp_store.update(cx, |this, _| {
2785 if let LspStoreMode::Local(mode) = &mut this.mode {
2786 project_transaction.0.extend(
2787 mode.last_workspace_edits_by_language_server
2788 .remove(&language_server.server_id())
2789 .unwrap_or_default()
2790 .0,
2791 )
2792 }
2793 })?;
2794 } else {
2795 log::warn!(
2796 "Cannot execute a command {} not listed in the language server capabilities",
2797 command.command
2798 )
2799 }
2800 }
2801 }
2802 return Ok(());
2803 }
2804
2805 pub async fn deserialize_text_edits(
2806 this: Entity<LspStore>,
2807 buffer_to_edit: Entity<Buffer>,
2808 edits: Vec<lsp::TextEdit>,
2809 push_to_history: bool,
2810 _: Arc<CachedLspAdapter>,
2811 language_server: Arc<LanguageServer>,
2812 cx: &mut AsyncApp,
2813 ) -> Result<Option<Transaction>> {
2814 let edits = this
2815 .update(cx, |this, cx| {
2816 this.as_local_mut().unwrap().edits_from_lsp(
2817 &buffer_to_edit,
2818 edits,
2819 language_server.server_id(),
2820 None,
2821 cx,
2822 )
2823 })?
2824 .await?;
2825
2826 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2827 buffer.finalize_last_transaction();
2828 buffer.start_transaction();
2829 for (range, text) in edits {
2830 buffer.edit([(range, text)], None, cx);
2831 }
2832
2833 if buffer.end_transaction(cx).is_some() {
2834 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2835 if !push_to_history {
2836 buffer.forget_transaction(transaction.id);
2837 }
2838 Some(transaction)
2839 } else {
2840 None
2841 }
2842 })?;
2843
2844 Ok(transaction)
2845 }
2846
2847 #[allow(clippy::type_complexity)]
2848 pub(crate) fn edits_from_lsp(
2849 &mut self,
2850 buffer: &Entity<Buffer>,
2851 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2852 server_id: LanguageServerId,
2853 version: Option<i32>,
2854 cx: &mut Context<LspStore>,
2855 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2856 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2857 cx.background_spawn(async move {
2858 let snapshot = snapshot?;
2859 let mut lsp_edits = lsp_edits
2860 .into_iter()
2861 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2862 .collect::<Vec<_>>();
2863
2864 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2865
2866 let mut lsp_edits = lsp_edits.into_iter().peekable();
2867 let mut edits = Vec::new();
2868 while let Some((range, mut new_text)) = lsp_edits.next() {
2869 // Clip invalid ranges provided by the language server.
2870 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
2871 ..snapshot.clip_point_utf16(range.end, Bias::Left);
2872
2873 // Combine any LSP edits that are adjacent.
2874 //
2875 // Also, combine LSP edits that are separated from each other by only
2876 // a newline. This is important because for some code actions,
2877 // Rust-analyzer rewrites the entire buffer via a series of edits that
2878 // are separated by unchanged newline characters.
2879 //
2880 // In order for the diffing logic below to work properly, any edits that
2881 // cancel each other out must be combined into one.
2882 while let Some((next_range, next_text)) = lsp_edits.peek() {
2883 if next_range.start.0 > range.end {
2884 if next_range.start.0.row > range.end.row + 1
2885 || next_range.start.0.column > 0
2886 || snapshot.clip_point_utf16(
2887 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
2888 Bias::Left,
2889 ) > range.end
2890 {
2891 break;
2892 }
2893 new_text.push('\n');
2894 }
2895 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
2896 new_text.push_str(next_text);
2897 lsp_edits.next();
2898 }
2899
2900 // For multiline edits, perform a diff of the old and new text so that
2901 // we can identify the changes more precisely, preserving the locations
2902 // of any anchors positioned in the unchanged regions.
2903 if range.end.row > range.start.row {
2904 let offset = range.start.to_offset(&snapshot);
2905 let old_text = snapshot.text_for_range(range).collect::<String>();
2906 let range_edits = language::text_diff(old_text.as_str(), &new_text);
2907 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
2908 (
2909 snapshot.anchor_after(offset + range.start)
2910 ..snapshot.anchor_before(offset + range.end),
2911 replacement,
2912 )
2913 }));
2914 } else if range.end == range.start {
2915 let anchor = snapshot.anchor_after(range.start);
2916 edits.push((anchor..anchor, new_text.into()));
2917 } else {
2918 let edit_start = snapshot.anchor_after(range.start);
2919 let edit_end = snapshot.anchor_before(range.end);
2920 edits.push((edit_start..edit_end, new_text.into()));
2921 }
2922 }
2923
2924 Ok(edits)
2925 })
2926 }
2927
2928 pub(crate) async fn deserialize_workspace_edit(
2929 this: Entity<LspStore>,
2930 edit: lsp::WorkspaceEdit,
2931 push_to_history: bool,
2932 lsp_adapter: Arc<CachedLspAdapter>,
2933 language_server: Arc<LanguageServer>,
2934 cx: &mut AsyncApp,
2935 ) -> Result<ProjectTransaction> {
2936 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
2937
2938 let mut operations = Vec::new();
2939 if let Some(document_changes) = edit.document_changes {
2940 match document_changes {
2941 lsp::DocumentChanges::Edits(edits) => {
2942 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
2943 }
2944 lsp::DocumentChanges::Operations(ops) => operations = ops,
2945 }
2946 } else if let Some(changes) = edit.changes {
2947 operations.extend(changes.into_iter().map(|(uri, edits)| {
2948 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2949 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2950 uri,
2951 version: None,
2952 },
2953 edits: edits.into_iter().map(Edit::Plain).collect(),
2954 })
2955 }));
2956 }
2957
2958 let mut project_transaction = ProjectTransaction::default();
2959 for operation in operations {
2960 match operation {
2961 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
2962 let abs_path = op
2963 .uri
2964 .to_file_path()
2965 .map_err(|()| anyhow!("can't convert URI to path"))?;
2966
2967 if let Some(parent_path) = abs_path.parent() {
2968 fs.create_dir(parent_path).await?;
2969 }
2970 if abs_path.ends_with("/") {
2971 fs.create_dir(&abs_path).await?;
2972 } else {
2973 fs.create_file(
2974 &abs_path,
2975 op.options
2976 .map(|options| fs::CreateOptions {
2977 overwrite: options.overwrite.unwrap_or(false),
2978 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
2979 })
2980 .unwrap_or_default(),
2981 )
2982 .await?;
2983 }
2984 }
2985
2986 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
2987 let source_abs_path = op
2988 .old_uri
2989 .to_file_path()
2990 .map_err(|()| anyhow!("can't convert URI to path"))?;
2991 let target_abs_path = op
2992 .new_uri
2993 .to_file_path()
2994 .map_err(|()| anyhow!("can't convert URI to path"))?;
2995 fs.rename(
2996 &source_abs_path,
2997 &target_abs_path,
2998 op.options
2999 .map(|options| fs::RenameOptions {
3000 overwrite: options.overwrite.unwrap_or(false),
3001 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3002 })
3003 .unwrap_or_default(),
3004 )
3005 .await?;
3006 }
3007
3008 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3009 let abs_path = op
3010 .uri
3011 .to_file_path()
3012 .map_err(|()| anyhow!("can't convert URI to path"))?;
3013 let options = op
3014 .options
3015 .map(|options| fs::RemoveOptions {
3016 recursive: options.recursive.unwrap_or(false),
3017 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3018 })
3019 .unwrap_or_default();
3020 if abs_path.ends_with("/") {
3021 fs.remove_dir(&abs_path, options).await?;
3022 } else {
3023 fs.remove_file(&abs_path, options).await?;
3024 }
3025 }
3026
3027 lsp::DocumentChangeOperation::Edit(op) => {
3028 let buffer_to_edit = this
3029 .update(cx, |this, cx| {
3030 this.open_local_buffer_via_lsp(
3031 op.text_document.uri.clone(),
3032 language_server.server_id(),
3033 lsp_adapter.name.clone(),
3034 cx,
3035 )
3036 })?
3037 .await?;
3038
3039 let edits = this
3040 .update(cx, |this, cx| {
3041 let path = buffer_to_edit.read(cx).project_path(cx);
3042 let active_entry = this.active_entry;
3043 let is_active_entry = path.clone().map_or(false, |project_path| {
3044 this.worktree_store
3045 .read(cx)
3046 .entry_for_path(&project_path, cx)
3047 .map_or(false, |entry| Some(entry.id) == active_entry)
3048 });
3049 let local = this.as_local_mut().unwrap();
3050
3051 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3052 for edit in op.edits {
3053 match edit {
3054 Edit::Plain(edit) => {
3055 if !edits.contains(&edit) {
3056 edits.push(edit)
3057 }
3058 }
3059 Edit::Annotated(edit) => {
3060 if !edits.contains(&edit.text_edit) {
3061 edits.push(edit.text_edit)
3062 }
3063 }
3064 Edit::Snippet(edit) => {
3065 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3066 else {
3067 continue;
3068 };
3069
3070 if is_active_entry {
3071 snippet_edits.push((edit.range, snippet));
3072 } else {
3073 // Since this buffer is not focused, apply a normal edit.
3074 let new_edit = TextEdit {
3075 range: edit.range,
3076 new_text: snippet.text,
3077 };
3078 if !edits.contains(&new_edit) {
3079 edits.push(new_edit);
3080 }
3081 }
3082 }
3083 }
3084 }
3085 if !snippet_edits.is_empty() {
3086 let buffer_id = buffer_to_edit.read(cx).remote_id();
3087 let version = if let Some(buffer_version) = op.text_document.version
3088 {
3089 local
3090 .buffer_snapshot_for_lsp_version(
3091 &buffer_to_edit,
3092 language_server.server_id(),
3093 Some(buffer_version),
3094 cx,
3095 )
3096 .ok()
3097 .map(|snapshot| snapshot.version)
3098 } else {
3099 Some(buffer_to_edit.read(cx).saved_version().clone())
3100 };
3101
3102 let most_recent_edit = version.and_then(|version| {
3103 version.iter().max_by_key(|timestamp| timestamp.value)
3104 });
3105 // Check if the edit that triggered that edit has been made by this participant.
3106
3107 if let Some(most_recent_edit) = most_recent_edit {
3108 cx.emit(LspStoreEvent::SnippetEdit {
3109 buffer_id,
3110 edits: snippet_edits,
3111 most_recent_edit,
3112 });
3113 }
3114 }
3115
3116 local.edits_from_lsp(
3117 &buffer_to_edit,
3118 edits,
3119 language_server.server_id(),
3120 op.text_document.version,
3121 cx,
3122 )
3123 })?
3124 .await?;
3125
3126 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3127 buffer.finalize_last_transaction();
3128 buffer.start_transaction();
3129 for (range, text) in edits {
3130 buffer.edit([(range, text)], None, cx);
3131 }
3132
3133 let transaction = buffer.end_transaction(cx).and_then(|transaction_id| {
3134 if push_to_history {
3135 buffer.finalize_last_transaction();
3136 buffer.get_transaction(transaction_id).cloned()
3137 } else {
3138 buffer.forget_transaction(transaction_id)
3139 }
3140 });
3141
3142 transaction
3143 })?;
3144 if let Some(transaction) = transaction {
3145 project_transaction.0.insert(buffer_to_edit, transaction);
3146 }
3147 }
3148 }
3149 }
3150
3151 Ok(project_transaction)
3152 }
3153
3154 async fn on_lsp_workspace_edit(
3155 this: WeakEntity<LspStore>,
3156 params: lsp::ApplyWorkspaceEditParams,
3157 server_id: LanguageServerId,
3158 adapter: Arc<CachedLspAdapter>,
3159 cx: &mut AsyncApp,
3160 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3161 let this = this.upgrade().context("project project closed")?;
3162 let language_server = this
3163 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3164 .context("language server not found")?;
3165 let transaction = Self::deserialize_workspace_edit(
3166 this.clone(),
3167 params.edit,
3168 true,
3169 adapter.clone(),
3170 language_server.clone(),
3171 cx,
3172 )
3173 .await
3174 .log_err();
3175 this.update(cx, |this, _| {
3176 if let Some(transaction) = transaction {
3177 this.as_local_mut()
3178 .unwrap()
3179 .last_workspace_edits_by_language_server
3180 .insert(server_id, transaction);
3181 }
3182 })?;
3183 Ok(lsp::ApplyWorkspaceEditResponse {
3184 applied: true,
3185 failed_change: None,
3186 failure_reason: None,
3187 })
3188 }
3189
3190 fn remove_worktree(
3191 &mut self,
3192 id_to_remove: WorktreeId,
3193 cx: &mut Context<LspStore>,
3194 ) -> Vec<LanguageServerId> {
3195 self.diagnostics.remove(&id_to_remove);
3196 self.prettier_store.update(cx, |prettier_store, cx| {
3197 prettier_store.remove_worktree(id_to_remove, cx);
3198 });
3199
3200 let mut servers_to_remove = BTreeMap::default();
3201 let mut servers_to_preserve = HashSet::default();
3202 for ((path, server_name), ref server_ids) in &self.language_server_ids {
3203 if *path == id_to_remove {
3204 servers_to_remove.extend(server_ids.iter().map(|id| (*id, server_name.clone())));
3205 } else {
3206 servers_to_preserve.extend(server_ids.iter().cloned());
3207 }
3208 }
3209 servers_to_remove.retain(|server_id, _| !servers_to_preserve.contains(server_id));
3210
3211 for (server_id_to_remove, _) in &servers_to_remove {
3212 self.language_server_ids
3213 .values_mut()
3214 .for_each(|server_ids| {
3215 server_ids.remove(server_id_to_remove);
3216 });
3217 self.language_server_watched_paths
3218 .remove(server_id_to_remove);
3219 self.language_server_paths_watched_for_rename
3220 .remove(server_id_to_remove);
3221 self.last_workspace_edits_by_language_server
3222 .remove(server_id_to_remove);
3223 self.language_servers.remove(server_id_to_remove);
3224 self.buffer_pull_diagnostics_result_ids
3225 .remove(server_id_to_remove);
3226 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3227 buffer_servers.remove(server_id_to_remove);
3228 }
3229 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3230 }
3231 servers_to_remove.into_keys().collect()
3232 }
3233
3234 fn rebuild_watched_paths_inner<'a>(
3235 &'a self,
3236 language_server_id: LanguageServerId,
3237 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3238 cx: &mut Context<LspStore>,
3239 ) -> LanguageServerWatchedPathsBuilder {
3240 let worktrees = self
3241 .worktree_store
3242 .read(cx)
3243 .worktrees()
3244 .filter_map(|worktree| {
3245 self.language_servers_for_worktree(worktree.read(cx).id())
3246 .find(|server| server.server_id() == language_server_id)
3247 .map(|_| worktree)
3248 })
3249 .collect::<Vec<_>>();
3250
3251 let mut worktree_globs = HashMap::default();
3252 let mut abs_globs = HashMap::default();
3253 log::trace!(
3254 "Processing new watcher paths for language server with id {}",
3255 language_server_id
3256 );
3257
3258 for watcher in watchers {
3259 if let Some((worktree, literal_prefix, pattern)) =
3260 self.worktree_and_path_for_file_watcher(&worktrees, &watcher, cx)
3261 {
3262 worktree.update(cx, |worktree, _| {
3263 if let Some((tree, glob)) =
3264 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3265 {
3266 tree.add_path_prefix_to_scan(literal_prefix.into());
3267 worktree_globs
3268 .entry(tree.id())
3269 .or_insert_with(GlobSetBuilder::new)
3270 .add(glob);
3271 }
3272 });
3273 } else {
3274 let (path, pattern) = match &watcher.glob_pattern {
3275 lsp::GlobPattern::String(s) => {
3276 let watcher_path = SanitizedPath::from(s);
3277 let path = glob_literal_prefix(watcher_path.as_path());
3278 let pattern = watcher_path
3279 .as_path()
3280 .strip_prefix(&path)
3281 .map(|p| p.to_string_lossy().to_string())
3282 .unwrap_or_else(|e| {
3283 debug_panic!(
3284 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3285 s,
3286 path.display(),
3287 e
3288 );
3289 watcher_path.as_path().to_string_lossy().to_string()
3290 });
3291 (path, pattern)
3292 }
3293 lsp::GlobPattern::Relative(rp) => {
3294 let Ok(mut base_uri) = match &rp.base_uri {
3295 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3296 lsp::OneOf::Right(base_uri) => base_uri,
3297 }
3298 .to_file_path() else {
3299 continue;
3300 };
3301
3302 let path = glob_literal_prefix(Path::new(&rp.pattern));
3303 let pattern = Path::new(&rp.pattern)
3304 .strip_prefix(&path)
3305 .map(|p| p.to_string_lossy().to_string())
3306 .unwrap_or_else(|e| {
3307 debug_panic!(
3308 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3309 rp.pattern,
3310 path.display(),
3311 e
3312 );
3313 rp.pattern.clone()
3314 });
3315 base_uri.push(path);
3316 (base_uri, pattern)
3317 }
3318 };
3319
3320 if let Some(glob) = Glob::new(&pattern).log_err() {
3321 if !path
3322 .components()
3323 .any(|c| matches!(c, path::Component::Normal(_)))
3324 {
3325 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3326 // rather than adding a new watcher for `/`.
3327 for worktree in &worktrees {
3328 worktree_globs
3329 .entry(worktree.read(cx).id())
3330 .or_insert_with(GlobSetBuilder::new)
3331 .add(glob.clone());
3332 }
3333 } else {
3334 abs_globs
3335 .entry(path.into())
3336 .or_insert_with(GlobSetBuilder::new)
3337 .add(glob);
3338 }
3339 }
3340 }
3341 }
3342
3343 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3344 for (worktree_id, builder) in worktree_globs {
3345 if let Ok(globset) = builder.build() {
3346 watch_builder.watch_worktree(worktree_id, globset);
3347 }
3348 }
3349 for (abs_path, builder) in abs_globs {
3350 if let Ok(globset) = builder.build() {
3351 watch_builder.watch_abs_path(abs_path, globset);
3352 }
3353 }
3354 watch_builder
3355 }
3356
3357 fn worktree_and_path_for_file_watcher(
3358 &self,
3359 worktrees: &[Entity<Worktree>],
3360 watcher: &FileSystemWatcher,
3361 cx: &App,
3362 ) -> Option<(Entity<Worktree>, PathBuf, String)> {
3363 worktrees.iter().find_map(|worktree| {
3364 let tree = worktree.read(cx);
3365 let worktree_root_path = tree.abs_path();
3366 match &watcher.glob_pattern {
3367 lsp::GlobPattern::String(s) => {
3368 let watcher_path = SanitizedPath::from(s);
3369 let relative = watcher_path
3370 .as_path()
3371 .strip_prefix(&worktree_root_path)
3372 .ok()?;
3373 let literal_prefix = glob_literal_prefix(relative);
3374 Some((
3375 worktree.clone(),
3376 literal_prefix,
3377 relative.to_string_lossy().to_string(),
3378 ))
3379 }
3380 lsp::GlobPattern::Relative(rp) => {
3381 let base_uri = match &rp.base_uri {
3382 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3383 lsp::OneOf::Right(base_uri) => base_uri,
3384 }
3385 .to_file_path()
3386 .ok()?;
3387 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3388 let mut literal_prefix = relative.to_owned();
3389 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3390 Some((worktree.clone(), literal_prefix, rp.pattern.clone()))
3391 }
3392 }
3393 })
3394 }
3395
3396 fn rebuild_watched_paths(
3397 &mut self,
3398 language_server_id: LanguageServerId,
3399 cx: &mut Context<LspStore>,
3400 ) {
3401 let Some(watchers) = self
3402 .language_server_watcher_registrations
3403 .get(&language_server_id)
3404 else {
3405 return;
3406 };
3407
3408 let watch_builder =
3409 self.rebuild_watched_paths_inner(language_server_id, watchers.values().flatten(), cx);
3410 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3411 self.language_server_watched_paths
3412 .insert(language_server_id, watcher);
3413
3414 cx.notify();
3415 }
3416
3417 fn on_lsp_did_change_watched_files(
3418 &mut self,
3419 language_server_id: LanguageServerId,
3420 registration_id: &str,
3421 params: DidChangeWatchedFilesRegistrationOptions,
3422 cx: &mut Context<LspStore>,
3423 ) {
3424 let registrations = self
3425 .language_server_watcher_registrations
3426 .entry(language_server_id)
3427 .or_default();
3428
3429 registrations.insert(registration_id.to_string(), params.watchers);
3430
3431 self.rebuild_watched_paths(language_server_id, cx);
3432 }
3433
3434 fn on_lsp_unregister_did_change_watched_files(
3435 &mut self,
3436 language_server_id: LanguageServerId,
3437 registration_id: &str,
3438 cx: &mut Context<LspStore>,
3439 ) {
3440 let registrations = self
3441 .language_server_watcher_registrations
3442 .entry(language_server_id)
3443 .or_default();
3444
3445 if registrations.remove(registration_id).is_some() {
3446 log::info!(
3447 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3448 language_server_id,
3449 registration_id
3450 );
3451 } else {
3452 log::warn!(
3453 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3454 language_server_id,
3455 registration_id
3456 );
3457 }
3458
3459 self.rebuild_watched_paths(language_server_id, cx);
3460 }
3461
3462 async fn initialization_options_for_adapter(
3463 adapter: Arc<dyn LspAdapter>,
3464 fs: &dyn Fs,
3465 delegate: &Arc<dyn LspAdapterDelegate>,
3466 ) -> Result<Option<serde_json::Value>> {
3467 let Some(mut initialization_config) =
3468 adapter.clone().initialization_options(fs, delegate).await?
3469 else {
3470 return Ok(None);
3471 };
3472
3473 for other_adapter in delegate.registered_lsp_adapters() {
3474 if other_adapter.name() == adapter.name() {
3475 continue;
3476 }
3477 if let Ok(Some(target_config)) = other_adapter
3478 .clone()
3479 .additional_initialization_options(adapter.name(), fs, delegate)
3480 .await
3481 {
3482 merge_json_value_into(target_config.clone(), &mut initialization_config);
3483 }
3484 }
3485
3486 Ok(Some(initialization_config))
3487 }
3488
3489 async fn workspace_configuration_for_adapter(
3490 adapter: Arc<dyn LspAdapter>,
3491 fs: &dyn Fs,
3492 delegate: &Arc<dyn LspAdapterDelegate>,
3493 toolchains: Arc<dyn LanguageToolchainStore>,
3494 cx: &mut AsyncApp,
3495 ) -> Result<serde_json::Value> {
3496 let mut workspace_config = adapter
3497 .clone()
3498 .workspace_configuration(fs, delegate, toolchains.clone(), cx)
3499 .await?;
3500
3501 for other_adapter in delegate.registered_lsp_adapters() {
3502 if other_adapter.name() == adapter.name() {
3503 continue;
3504 }
3505 if let Ok(Some(target_config)) = other_adapter
3506 .clone()
3507 .additional_workspace_configuration(
3508 adapter.name(),
3509 fs,
3510 delegate,
3511 toolchains.clone(),
3512 cx,
3513 )
3514 .await
3515 {
3516 merge_json_value_into(target_config.clone(), &mut workspace_config);
3517 }
3518 }
3519
3520 Ok(workspace_config)
3521 }
3522}
3523
3524fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3525 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3526 cx.emit(LspStoreEvent::LanguageServerUpdate {
3527 language_server_id: server.server_id(),
3528 name: Some(server.name()),
3529 message: proto::update_language_server::Variant::MetadataUpdated(
3530 proto::ServerMetadataUpdated {
3531 capabilities: Some(capabilities),
3532 },
3533 ),
3534 });
3535 }
3536}
3537
3538#[derive(Debug)]
3539pub struct FormattableBuffer {
3540 handle: Entity<Buffer>,
3541 abs_path: Option<PathBuf>,
3542 env: Option<HashMap<String, String>>,
3543 ranges: Option<Vec<Range<Anchor>>>,
3544}
3545
3546pub struct RemoteLspStore {
3547 upstream_client: Option<AnyProtoClient>,
3548 upstream_project_id: u64,
3549}
3550
3551pub(crate) enum LspStoreMode {
3552 Local(LocalLspStore), // ssh host and collab host
3553 Remote(RemoteLspStore), // collab guest
3554}
3555
3556impl LspStoreMode {
3557 fn is_local(&self) -> bool {
3558 matches!(self, LspStoreMode::Local(_))
3559 }
3560}
3561
3562pub struct LspStore {
3563 mode: LspStoreMode,
3564 last_formatting_failure: Option<String>,
3565 downstream_client: Option<(AnyProtoClient, u64)>,
3566 nonce: u128,
3567 buffer_store: Entity<BufferStore>,
3568 worktree_store: Entity<WorktreeStore>,
3569 toolchain_store: Option<Entity<ToolchainStore>>,
3570 pub languages: Arc<LanguageRegistry>,
3571 language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3572 active_entry: Option<ProjectEntryId>,
3573 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3574 _maintain_buffer_languages: Task<()>,
3575 diagnostic_summaries:
3576 HashMap<WorktreeId, HashMap<Arc<Path>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3577 pub(super) lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3578 lsp_document_colors: HashMap<BufferId, DocumentColorData>,
3579 lsp_code_lens: HashMap<BufferId, CodeLensData>,
3580}
3581
3582#[derive(Debug, Default, Clone)]
3583pub struct DocumentColors {
3584 pub colors: HashSet<DocumentColor>,
3585 pub cache_version: Option<usize>,
3586}
3587
3588type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3589type CodeLensTask = Shared<Task<std::result::Result<Vec<CodeAction>, Arc<anyhow::Error>>>>;
3590
3591#[derive(Debug, Default)]
3592struct DocumentColorData {
3593 colors_for_version: Global,
3594 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3595 cache_version: usize,
3596 colors_update: Option<(Global, DocumentColorTask)>,
3597}
3598
3599#[derive(Debug, Default)]
3600struct CodeLensData {
3601 lens_for_version: Global,
3602 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3603 update: Option<(Global, CodeLensTask)>,
3604}
3605
3606#[derive(Debug, PartialEq, Eq, Clone, Copy)]
3607pub enum LspFetchStrategy {
3608 IgnoreCache,
3609 UseCache { known_cache_version: Option<usize> },
3610}
3611
3612#[derive(Debug)]
3613pub enum LspStoreEvent {
3614 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3615 LanguageServerRemoved(LanguageServerId),
3616 LanguageServerUpdate {
3617 language_server_id: LanguageServerId,
3618 name: Option<LanguageServerName>,
3619 message: proto::update_language_server::Variant,
3620 },
3621 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3622 LanguageServerPrompt(LanguageServerPromptRequest),
3623 LanguageDetected {
3624 buffer: Entity<Buffer>,
3625 new_language: Option<Arc<Language>>,
3626 },
3627 Notification(String),
3628 RefreshInlayHints,
3629 RefreshCodeLens,
3630 DiagnosticsUpdated {
3631 server_id: LanguageServerId,
3632 paths: Vec<ProjectPath>,
3633 },
3634 DiskBasedDiagnosticsStarted {
3635 language_server_id: LanguageServerId,
3636 },
3637 DiskBasedDiagnosticsFinished {
3638 language_server_id: LanguageServerId,
3639 },
3640 SnippetEdit {
3641 buffer_id: BufferId,
3642 edits: Vec<(lsp::Range, Snippet)>,
3643 most_recent_edit: clock::Lamport,
3644 },
3645}
3646
3647#[derive(Clone, Debug, Serialize)]
3648pub struct LanguageServerStatus {
3649 pub name: LanguageServerName,
3650 pub pending_work: BTreeMap<String, LanguageServerProgress>,
3651 pub has_pending_diagnostic_updates: bool,
3652 progress_tokens: HashSet<String>,
3653}
3654
3655#[derive(Clone, Debug)]
3656struct CoreSymbol {
3657 pub language_server_name: LanguageServerName,
3658 pub source_worktree_id: WorktreeId,
3659 pub source_language_server_id: LanguageServerId,
3660 pub path: ProjectPath,
3661 pub name: String,
3662 pub kind: lsp::SymbolKind,
3663 pub range: Range<Unclipped<PointUtf16>>,
3664 pub signature: [u8; 32],
3665}
3666
3667impl LspStore {
3668 pub fn init(client: &AnyProtoClient) {
3669 client.add_entity_request_handler(Self::handle_multi_lsp_query);
3670 client.add_entity_request_handler(Self::handle_restart_language_servers);
3671 client.add_entity_request_handler(Self::handle_stop_language_servers);
3672 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3673 client.add_entity_message_handler(Self::handle_start_language_server);
3674 client.add_entity_message_handler(Self::handle_update_language_server);
3675 client.add_entity_message_handler(Self::handle_language_server_log);
3676 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3677 client.add_entity_request_handler(Self::handle_format_buffers);
3678 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3679 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3680 client.add_entity_request_handler(Self::handle_apply_code_action);
3681 client.add_entity_request_handler(Self::handle_inlay_hints);
3682 client.add_entity_request_handler(Self::handle_get_project_symbols);
3683 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3684 client.add_entity_request_handler(Self::handle_get_color_presentation);
3685 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3686 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3687 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3688 client.add_entity_request_handler(Self::handle_on_type_formatting);
3689 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3690 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3691 client.add_entity_request_handler(Self::handle_rename_project_entry);
3692 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3693 client.add_entity_request_handler(Self::handle_lsp_command::<GetCodeActions>);
3694 client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
3695 client.add_entity_request_handler(Self::handle_lsp_command::<GetHover>);
3696 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3697 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3698 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3699 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3700 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3701
3702 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3703 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3704 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3705 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3706 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3707 client.add_entity_request_handler(
3708 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3709 );
3710 client.add_entity_request_handler(
3711 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3712 );
3713 client.add_entity_request_handler(
3714 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3715 );
3716 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentDiagnostics>);
3717 }
3718
3719 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3720 match &self.mode {
3721 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3722 _ => None,
3723 }
3724 }
3725
3726 pub fn as_local(&self) -> Option<&LocalLspStore> {
3727 match &self.mode {
3728 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3729 _ => None,
3730 }
3731 }
3732
3733 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3734 match &mut self.mode {
3735 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3736 _ => None,
3737 }
3738 }
3739
3740 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3741 match &self.mode {
3742 LspStoreMode::Remote(RemoteLspStore {
3743 upstream_client: Some(upstream_client),
3744 upstream_project_id,
3745 ..
3746 }) => Some((upstream_client.clone(), *upstream_project_id)),
3747
3748 LspStoreMode::Remote(RemoteLspStore {
3749 upstream_client: None,
3750 ..
3751 }) => None,
3752 LspStoreMode::Local(_) => None,
3753 }
3754 }
3755
3756 pub fn new_local(
3757 buffer_store: Entity<BufferStore>,
3758 worktree_store: Entity<WorktreeStore>,
3759 prettier_store: Entity<PrettierStore>,
3760 toolchain_store: Entity<ToolchainStore>,
3761 environment: Entity<ProjectEnvironment>,
3762 manifest_tree: Entity<ManifestTree>,
3763 languages: Arc<LanguageRegistry>,
3764 http_client: Arc<dyn HttpClient>,
3765 fs: Arc<dyn Fs>,
3766 cx: &mut Context<Self>,
3767 ) -> Self {
3768 let yarn = YarnPathStore::new(fs.clone(), cx);
3769 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3770 .detach();
3771 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3772 .detach();
3773 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3774 .detach();
3775 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3776 .detach();
3777 if let Some(extension_events) = extension::ExtensionEvents::try_global(cx).as_ref() {
3778 cx.subscribe(
3779 extension_events,
3780 Self::reload_zed_json_schemas_on_extensions_changed,
3781 )
3782 .detach();
3783 } else {
3784 log::debug!("No extension events global found. Skipping JSON schema auto-reload setup");
3785 }
3786 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3787 .detach();
3788 subscribe_to_binary_statuses(&languages, cx).detach();
3789
3790 let _maintain_workspace_config = {
3791 let (sender, receiver) = watch::channel();
3792 (
3793 Self::maintain_workspace_config(fs.clone(), receiver, cx),
3794 sender,
3795 )
3796 };
3797
3798 Self {
3799 mode: LspStoreMode::Local(LocalLspStore {
3800 weak: cx.weak_entity(),
3801 worktree_store: worktree_store.clone(),
3802 toolchain_store: toolchain_store.clone(),
3803 supplementary_language_servers: Default::default(),
3804 languages: languages.clone(),
3805 language_server_ids: Default::default(),
3806 language_servers: Default::default(),
3807 last_workspace_edits_by_language_server: Default::default(),
3808 language_server_watched_paths: Default::default(),
3809 language_server_paths_watched_for_rename: Default::default(),
3810 language_server_watcher_registrations: Default::default(),
3811 buffers_being_formatted: Default::default(),
3812 buffer_snapshots: Default::default(),
3813 prettier_store,
3814 environment,
3815 http_client,
3816 fs,
3817 yarn,
3818 next_diagnostic_group_id: Default::default(),
3819 diagnostics: Default::default(),
3820 _subscription: cx.on_app_quit(|this, cx| {
3821 this.as_local_mut()
3822 .unwrap()
3823 .shutdown_language_servers_on_quit(cx)
3824 }),
3825 lsp_tree: LanguageServerTree::new(manifest_tree, languages.clone(), cx),
3826 registered_buffers: HashMap::default(),
3827 buffers_opened_in_servers: HashMap::default(),
3828 buffer_pull_diagnostics_result_ids: HashMap::default(),
3829 }),
3830 last_formatting_failure: None,
3831 downstream_client: None,
3832 buffer_store,
3833 worktree_store,
3834 toolchain_store: Some(toolchain_store),
3835 languages: languages.clone(),
3836 language_server_statuses: Default::default(),
3837 nonce: StdRng::from_entropy().r#gen(),
3838 diagnostic_summaries: HashMap::default(),
3839 lsp_server_capabilities: HashMap::default(),
3840 lsp_document_colors: HashMap::default(),
3841 lsp_code_lens: HashMap::default(),
3842 active_entry: None,
3843 _maintain_workspace_config,
3844 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
3845 }
3846 }
3847
3848 fn send_lsp_proto_request<R: LspCommand>(
3849 &self,
3850 buffer: Entity<Buffer>,
3851 client: AnyProtoClient,
3852 upstream_project_id: u64,
3853 request: R,
3854 cx: &mut Context<LspStore>,
3855 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
3856 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
3857 return Task::ready(Ok(R::Response::default()));
3858 }
3859 let message = request.to_proto(upstream_project_id, buffer.read(cx));
3860 cx.spawn(async move |this, cx| {
3861 let response = client.request(message).await?;
3862 let this = this.upgrade().context("project dropped")?;
3863 request
3864 .response_from_proto(response, this, buffer, cx.clone())
3865 .await
3866 })
3867 }
3868
3869 pub(super) fn new_remote(
3870 buffer_store: Entity<BufferStore>,
3871 worktree_store: Entity<WorktreeStore>,
3872 toolchain_store: Option<Entity<ToolchainStore>>,
3873 languages: Arc<LanguageRegistry>,
3874 upstream_client: AnyProtoClient,
3875 project_id: u64,
3876 fs: Arc<dyn Fs>,
3877 cx: &mut Context<Self>,
3878 ) -> Self {
3879 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3880 .detach();
3881 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3882 .detach();
3883 subscribe_to_binary_statuses(&languages, cx).detach();
3884 let _maintain_workspace_config = {
3885 let (sender, receiver) = watch::channel();
3886 (Self::maintain_workspace_config(fs, receiver, cx), sender)
3887 };
3888 Self {
3889 mode: LspStoreMode::Remote(RemoteLspStore {
3890 upstream_client: Some(upstream_client),
3891 upstream_project_id: project_id,
3892 }),
3893 downstream_client: None,
3894 last_formatting_failure: None,
3895 buffer_store,
3896 worktree_store,
3897 languages: languages.clone(),
3898 language_server_statuses: Default::default(),
3899 nonce: StdRng::from_entropy().r#gen(),
3900 diagnostic_summaries: HashMap::default(),
3901 lsp_server_capabilities: HashMap::default(),
3902 lsp_document_colors: HashMap::default(),
3903 lsp_code_lens: HashMap::default(),
3904 active_entry: None,
3905 toolchain_store,
3906 _maintain_workspace_config,
3907 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
3908 }
3909 }
3910
3911 fn on_buffer_store_event(
3912 &mut self,
3913 _: Entity<BufferStore>,
3914 event: &BufferStoreEvent,
3915 cx: &mut Context<Self>,
3916 ) {
3917 match event {
3918 BufferStoreEvent::BufferAdded(buffer) => {
3919 self.on_buffer_added(buffer, cx).log_err();
3920 }
3921 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
3922 let buffer_id = buffer.read(cx).remote_id();
3923 if let Some(local) = self.as_local_mut() {
3924 if let Some(old_file) = File::from_dyn(old_file.as_ref()) {
3925 local.reset_buffer(buffer, old_file, cx);
3926
3927 if local.registered_buffers.contains_key(&buffer_id) {
3928 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
3929 }
3930 }
3931 }
3932
3933 self.detect_language_for_buffer(buffer, cx);
3934 if let Some(local) = self.as_local_mut() {
3935 local.initialize_buffer(buffer, cx);
3936 if local.registered_buffers.contains_key(&buffer_id) {
3937 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
3938 }
3939 }
3940 }
3941 _ => {}
3942 }
3943 }
3944
3945 fn on_worktree_store_event(
3946 &mut self,
3947 _: Entity<WorktreeStore>,
3948 event: &WorktreeStoreEvent,
3949 cx: &mut Context<Self>,
3950 ) {
3951 match event {
3952 WorktreeStoreEvent::WorktreeAdded(worktree) => {
3953 if !worktree.read(cx).is_local() {
3954 return;
3955 }
3956 cx.subscribe(worktree, |this, worktree, event, cx| match event {
3957 worktree::Event::UpdatedEntries(changes) => {
3958 this.update_local_worktree_language_servers(&worktree, changes, cx);
3959 }
3960 worktree::Event::UpdatedGitRepositories(_)
3961 | worktree::Event::DeletedEntry(_) => {}
3962 })
3963 .detach()
3964 }
3965 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
3966 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
3967 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
3968 }
3969 WorktreeStoreEvent::WorktreeReleased(..)
3970 | WorktreeStoreEvent::WorktreeOrderChanged
3971 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
3972 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
3973 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
3974 }
3975 }
3976
3977 fn on_prettier_store_event(
3978 &mut self,
3979 _: Entity<PrettierStore>,
3980 event: &PrettierStoreEvent,
3981 cx: &mut Context<Self>,
3982 ) {
3983 match event {
3984 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
3985 self.unregister_supplementary_language_server(*prettier_server_id, cx);
3986 }
3987 PrettierStoreEvent::LanguageServerAdded {
3988 new_server_id,
3989 name,
3990 prettier_server,
3991 } => {
3992 self.register_supplementary_language_server(
3993 *new_server_id,
3994 name.clone(),
3995 prettier_server.clone(),
3996 cx,
3997 );
3998 }
3999 }
4000 }
4001
4002 fn on_toolchain_store_event(
4003 &mut self,
4004 _: Entity<ToolchainStore>,
4005 event: &ToolchainStoreEvent,
4006 _: &mut Context<Self>,
4007 ) {
4008 match event {
4009 ToolchainStoreEvent::ToolchainActivated { .. } => {
4010 self.request_workspace_config_refresh()
4011 }
4012 }
4013 }
4014
4015 fn request_workspace_config_refresh(&mut self) {
4016 *self._maintain_workspace_config.1.borrow_mut() = ();
4017 }
4018
4019 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4020 self.as_local().map(|local| local.prettier_store.clone())
4021 }
4022
4023 fn on_buffer_event(
4024 &mut self,
4025 buffer: Entity<Buffer>,
4026 event: &language::BufferEvent,
4027 cx: &mut Context<Self>,
4028 ) {
4029 match event {
4030 language::BufferEvent::Edited => {
4031 self.on_buffer_edited(buffer, cx);
4032 }
4033
4034 language::BufferEvent::Saved => {
4035 self.on_buffer_saved(buffer, cx);
4036 }
4037
4038 _ => {}
4039 }
4040 }
4041
4042 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4043 buffer
4044 .read(cx)
4045 .set_language_registry(self.languages.clone());
4046
4047 cx.subscribe(buffer, |this, buffer, event, cx| {
4048 this.on_buffer_event(buffer, event, cx);
4049 })
4050 .detach();
4051
4052 self.detect_language_for_buffer(buffer, cx);
4053 if let Some(local) = self.as_local_mut() {
4054 local.initialize_buffer(buffer, cx);
4055 }
4056
4057 Ok(())
4058 }
4059
4060 pub fn reload_zed_json_schemas_on_extensions_changed(
4061 &mut self,
4062 _: Entity<extension::ExtensionEvents>,
4063 evt: &extension::Event,
4064 cx: &mut Context<Self>,
4065 ) {
4066 match evt {
4067 extension::Event::ExtensionInstalled(_)
4068 | extension::Event::ExtensionUninstalled(_)
4069 | extension::Event::ConfigureExtensionRequested(_) => return,
4070 extension::Event::ExtensionsInstalledChanged => {}
4071 }
4072 if self.as_local().is_none() {
4073 return;
4074 }
4075 cx.spawn(async move |this, cx| {
4076 let weak_ref = this.clone();
4077
4078 let servers = this
4079 .update(cx, |this, cx| {
4080 let local = this.as_local()?;
4081
4082 let mut servers = Vec::new();
4083 for ((worktree_id, _), server_ids) in &local.language_server_ids {
4084 for server_id in server_ids {
4085 let Some(states) = local.language_servers.get(server_id) else {
4086 continue;
4087 };
4088 let (json_adapter, json_server) = match states {
4089 LanguageServerState::Running {
4090 adapter, server, ..
4091 } if adapter.adapter.is_primary_zed_json_schema_adapter() => {
4092 (adapter.adapter.clone(), server.clone())
4093 }
4094 _ => continue,
4095 };
4096
4097 let Some(worktree) = this
4098 .worktree_store
4099 .read(cx)
4100 .worktree_for_id(*worktree_id, cx)
4101 else {
4102 continue;
4103 };
4104 let json_delegate: Arc<dyn LspAdapterDelegate> =
4105 LocalLspAdapterDelegate::new(
4106 local.languages.clone(),
4107 &local.environment,
4108 weak_ref.clone(),
4109 &worktree,
4110 local.http_client.clone(),
4111 local.fs.clone(),
4112 cx,
4113 );
4114
4115 servers.push((json_adapter, json_server, json_delegate));
4116 }
4117 }
4118 return Some(servers);
4119 })
4120 .ok()
4121 .flatten();
4122
4123 let Some(servers) = servers else {
4124 return;
4125 };
4126
4127 let Ok(Some((fs, toolchain_store))) = this.read_with(cx, |this, cx| {
4128 let local = this.as_local()?;
4129 let toolchain_store = this.toolchain_store(cx);
4130 return Some((local.fs.clone(), toolchain_store));
4131 }) else {
4132 return;
4133 };
4134 for (adapter, server, delegate) in servers {
4135 adapter.clear_zed_json_schema_cache().await;
4136
4137 let Some(json_workspace_config) = LocalLspStore::workspace_configuration_for_adapter(
4138 adapter,
4139 fs.as_ref(),
4140 &delegate,
4141 toolchain_store.clone(),
4142 cx,
4143 )
4144 .await
4145 .context("generate new workspace configuration for JSON language server while trying to refresh JSON Schemas")
4146 .ok()
4147 else {
4148 continue;
4149 };
4150 server
4151 .notify::<lsp::notification::DidChangeConfiguration>(
4152 &lsp::DidChangeConfigurationParams {
4153 settings: json_workspace_config,
4154 },
4155 )
4156 .ok();
4157 }
4158 })
4159 .detach();
4160 }
4161
4162 pub(crate) fn register_buffer_with_language_servers(
4163 &mut self,
4164 buffer: &Entity<Buffer>,
4165 only_register_servers: HashSet<LanguageServerSelector>,
4166 ignore_refcounts: bool,
4167 cx: &mut Context<Self>,
4168 ) -> OpenLspBufferHandle {
4169 let buffer_id = buffer.read(cx).remote_id();
4170 let handle = cx.new(|_| buffer.clone());
4171 if let Some(local) = self.as_local_mut() {
4172 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4173 if !ignore_refcounts {
4174 *refcount += 1;
4175 }
4176
4177 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4178 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4179 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4180 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4181 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4182 return handle;
4183 };
4184 if !file.is_local() {
4185 return handle;
4186 }
4187
4188 if ignore_refcounts || *refcount == 1 {
4189 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4190 }
4191 if !ignore_refcounts {
4192 cx.observe_release(&handle, move |lsp_store, buffer, cx| {
4193 let refcount = {
4194 let local = lsp_store.as_local_mut().unwrap();
4195 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4196 debug_panic!("bad refcounting");
4197 return;
4198 };
4199
4200 *refcount -= 1;
4201 *refcount
4202 };
4203 if refcount == 0 {
4204 lsp_store.lsp_document_colors.remove(&buffer_id);
4205 lsp_store.lsp_code_lens.remove(&buffer_id);
4206 let local = lsp_store.as_local_mut().unwrap();
4207 local.registered_buffers.remove(&buffer_id);
4208 local.buffers_opened_in_servers.remove(&buffer_id);
4209 if let Some(file) = File::from_dyn(buffer.read(cx).file()).cloned() {
4210 local.unregister_old_buffer_from_language_servers(&buffer, &file, cx);
4211 }
4212 }
4213 })
4214 .detach();
4215 }
4216 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4217 let buffer_id = buffer.read(cx).remote_id().to_proto();
4218 cx.background_spawn(async move {
4219 upstream_client
4220 .request(proto::RegisterBufferWithLanguageServers {
4221 project_id: upstream_project_id,
4222 buffer_id,
4223 only_servers: only_register_servers
4224 .into_iter()
4225 .map(|selector| {
4226 let selector = match selector {
4227 LanguageServerSelector::Id(language_server_id) => {
4228 proto::language_server_selector::Selector::ServerId(
4229 language_server_id.to_proto(),
4230 )
4231 }
4232 LanguageServerSelector::Name(language_server_name) => {
4233 proto::language_server_selector::Selector::Name(
4234 language_server_name.to_string(),
4235 )
4236 }
4237 };
4238 proto::LanguageServerSelector {
4239 selector: Some(selector),
4240 }
4241 })
4242 .collect(),
4243 })
4244 .await
4245 })
4246 .detach();
4247 } else {
4248 panic!("oops!");
4249 }
4250 handle
4251 }
4252
4253 fn maintain_buffer_languages(
4254 languages: Arc<LanguageRegistry>,
4255 cx: &mut Context<Self>,
4256 ) -> Task<()> {
4257 let mut subscription = languages.subscribe();
4258 let mut prev_reload_count = languages.reload_count();
4259 cx.spawn(async move |this, cx| {
4260 while let Some(()) = subscription.next().await {
4261 if let Some(this) = this.upgrade() {
4262 // If the language registry has been reloaded, then remove and
4263 // re-assign the languages on all open buffers.
4264 let reload_count = languages.reload_count();
4265 if reload_count > prev_reload_count {
4266 prev_reload_count = reload_count;
4267 this.update(cx, |this, cx| {
4268 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4269 for buffer in buffer_store.buffers() {
4270 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4271 {
4272 buffer
4273 .update(cx, |buffer, cx| buffer.set_language(None, cx));
4274 if let Some(local) = this.as_local_mut() {
4275 local.reset_buffer(&buffer, &f, cx);
4276
4277 if local
4278 .registered_buffers
4279 .contains_key(&buffer.read(cx).remote_id())
4280 {
4281 if let Some(file_url) =
4282 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4283 {
4284 local.unregister_buffer_from_language_servers(
4285 &buffer, &file_url, cx,
4286 );
4287 }
4288 }
4289 }
4290 }
4291 }
4292 });
4293 })
4294 .ok();
4295 }
4296
4297 this.update(cx, |this, cx| {
4298 let mut plain_text_buffers = Vec::new();
4299 let mut buffers_with_unknown_injections = Vec::new();
4300 for handle in this.buffer_store.read(cx).buffers() {
4301 let buffer = handle.read(cx);
4302 if buffer.language().is_none()
4303 || buffer.language() == Some(&*language::PLAIN_TEXT)
4304 {
4305 plain_text_buffers.push(handle);
4306 } else if buffer.contains_unknown_injections() {
4307 buffers_with_unknown_injections.push(handle);
4308 }
4309 }
4310
4311 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4312 // and reused later in the invisible worktrees.
4313 plain_text_buffers.sort_by_key(|buffer| {
4314 Reverse(
4315 File::from_dyn(buffer.read(cx).file())
4316 .map(|file| file.worktree.read(cx).is_visible()),
4317 )
4318 });
4319
4320 for buffer in plain_text_buffers {
4321 this.detect_language_for_buffer(&buffer, cx);
4322 if let Some(local) = this.as_local_mut() {
4323 local.initialize_buffer(&buffer, cx);
4324 if local
4325 .registered_buffers
4326 .contains_key(&buffer.read(cx).remote_id())
4327 {
4328 local.register_buffer_with_language_servers(
4329 &buffer,
4330 HashSet::default(),
4331 cx,
4332 );
4333 }
4334 }
4335 }
4336
4337 for buffer in buffers_with_unknown_injections {
4338 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
4339 }
4340 })
4341 .ok();
4342 }
4343 }
4344 })
4345 }
4346
4347 fn detect_language_for_buffer(
4348 &mut self,
4349 buffer_handle: &Entity<Buffer>,
4350 cx: &mut Context<Self>,
4351 ) -> Option<language::AvailableLanguage> {
4352 // If the buffer has a language, set it and start the language server if we haven't already.
4353 let buffer = buffer_handle.read(cx);
4354 let file = buffer.file()?;
4355
4356 let content = buffer.as_rope();
4357 let available_language = self.languages.language_for_file(file, Some(content), cx);
4358 if let Some(available_language) = &available_language {
4359 if let Some(Ok(Ok(new_language))) = self
4360 .languages
4361 .load_language(available_language)
4362 .now_or_never()
4363 {
4364 self.set_language_for_buffer(buffer_handle, new_language, cx);
4365 }
4366 } else {
4367 cx.emit(LspStoreEvent::LanguageDetected {
4368 buffer: buffer_handle.clone(),
4369 new_language: None,
4370 });
4371 }
4372
4373 available_language
4374 }
4375
4376 pub(crate) fn set_language_for_buffer(
4377 &mut self,
4378 buffer_entity: &Entity<Buffer>,
4379 new_language: Arc<Language>,
4380 cx: &mut Context<Self>,
4381 ) {
4382 let buffer = buffer_entity.read(cx);
4383 let buffer_file = buffer.file().cloned();
4384 let buffer_id = buffer.remote_id();
4385 if let Some(local_store) = self.as_local_mut() {
4386 if local_store.registered_buffers.contains_key(&buffer_id) {
4387 if let Some(abs_path) =
4388 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4389 {
4390 if let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err() {
4391 local_store.unregister_buffer_from_language_servers(
4392 buffer_entity,
4393 &file_url,
4394 cx,
4395 );
4396 }
4397 }
4398 }
4399 }
4400 buffer_entity.update(cx, |buffer, cx| {
4401 if buffer.language().map_or(true, |old_language| {
4402 !Arc::ptr_eq(old_language, &new_language)
4403 }) {
4404 buffer.set_language(Some(new_language.clone()), cx);
4405 }
4406 });
4407
4408 let settings =
4409 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4410 let buffer_file = File::from_dyn(buffer_file.as_ref());
4411
4412 let worktree_id = if let Some(file) = buffer_file {
4413 let worktree = file.worktree.clone();
4414
4415 if let Some(local) = self.as_local_mut() {
4416 if local.registered_buffers.contains_key(&buffer_id) {
4417 local.register_buffer_with_language_servers(
4418 buffer_entity,
4419 HashSet::default(),
4420 cx,
4421 );
4422 }
4423 }
4424 Some(worktree.read(cx).id())
4425 } else {
4426 None
4427 };
4428
4429 if settings.prettier.allowed {
4430 if let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4431 {
4432 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4433 if let Some(prettier_store) = prettier_store {
4434 prettier_store.update(cx, |prettier_store, cx| {
4435 prettier_store.install_default_prettier(
4436 worktree_id,
4437 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4438 cx,
4439 )
4440 })
4441 }
4442 }
4443 }
4444
4445 cx.emit(LspStoreEvent::LanguageDetected {
4446 buffer: buffer_entity.clone(),
4447 new_language: Some(new_language),
4448 })
4449 }
4450
4451 pub fn buffer_store(&self) -> Entity<BufferStore> {
4452 self.buffer_store.clone()
4453 }
4454
4455 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4456 self.active_entry = active_entry;
4457 }
4458
4459 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4460 if let Some((client, downstream_project_id)) = self.downstream_client.clone() {
4461 if let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id()) {
4462 let mut summaries =
4463 diangostic_summaries
4464 .into_iter()
4465 .flat_map(|(path, summaries)| {
4466 summaries
4467 .into_iter()
4468 .map(|(server_id, summary)| summary.to_proto(*server_id, path))
4469 });
4470 if let Some(summary) = summaries.next() {
4471 client
4472 .send(proto::UpdateDiagnosticSummary {
4473 project_id: downstream_project_id,
4474 worktree_id: worktree.id().to_proto(),
4475 summary: Some(summary),
4476 more_summaries: summaries.collect(),
4477 })
4478 .log_err();
4479 }
4480 }
4481 }
4482 }
4483
4484 // TODO: remove MultiLspQuery: instead, the proto handler should pick appropriate server(s)
4485 // Then, use `send_lsp_proto_request` or analogue for most of the LSP proto requests and inline this check inside
4486 fn is_capable_for_proto_request<R>(
4487 &self,
4488 buffer: &Entity<Buffer>,
4489 request: &R,
4490 cx: &Context<Self>,
4491 ) -> bool
4492 where
4493 R: LspCommand,
4494 {
4495 self.check_if_capable_for_proto_request(
4496 buffer,
4497 |capabilities| {
4498 request.check_capabilities(AdapterServerCapabilities {
4499 server_capabilities: capabilities.clone(),
4500 code_action_kinds: None,
4501 })
4502 },
4503 cx,
4504 )
4505 }
4506
4507 fn check_if_capable_for_proto_request<F>(
4508 &self,
4509 buffer: &Entity<Buffer>,
4510 check: F,
4511 cx: &Context<Self>,
4512 ) -> bool
4513 where
4514 F: Fn(&lsp::ServerCapabilities) -> bool,
4515 {
4516 let Some(language) = buffer.read(cx).language().cloned() else {
4517 return false;
4518 };
4519 let relevant_language_servers = self
4520 .languages
4521 .lsp_adapters(&language.name())
4522 .into_iter()
4523 .map(|lsp_adapter| lsp_adapter.name())
4524 .collect::<HashSet<_>>();
4525 self.language_server_statuses
4526 .iter()
4527 .filter_map(|(server_id, server_status)| {
4528 relevant_language_servers
4529 .contains(&server_status.name)
4530 .then_some(server_id)
4531 })
4532 .filter_map(|server_id| self.lsp_server_capabilities.get(&server_id))
4533 .any(check)
4534 }
4535
4536 pub fn request_lsp<R>(
4537 &mut self,
4538 buffer: Entity<Buffer>,
4539 server: LanguageServerToQuery,
4540 request: R,
4541 cx: &mut Context<Self>,
4542 ) -> Task<Result<R::Response>>
4543 where
4544 R: LspCommand,
4545 <R::LspRequest as lsp::request::Request>::Result: Send,
4546 <R::LspRequest as lsp::request::Request>::Params: Send,
4547 {
4548 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4549 return self.send_lsp_proto_request(
4550 buffer,
4551 upstream_client,
4552 upstream_project_id,
4553 request,
4554 cx,
4555 );
4556 }
4557
4558 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4559 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4560 local
4561 .language_servers_for_buffer(buffer, cx)
4562 .find(|(_, server)| {
4563 request.check_capabilities(server.adapter_server_capabilities())
4564 })
4565 .map(|(_, server)| server.clone())
4566 }),
4567 LanguageServerToQuery::Other(id) => self
4568 .language_server_for_local_buffer(buffer, id, cx)
4569 .and_then(|(_, server)| {
4570 request
4571 .check_capabilities(server.adapter_server_capabilities())
4572 .then(|| Arc::clone(server))
4573 }),
4574 }) else {
4575 return Task::ready(Ok(Default::default()));
4576 };
4577
4578 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4579
4580 let Some(file) = file else {
4581 return Task::ready(Ok(Default::default()));
4582 };
4583
4584 let lsp_params = match request.to_lsp_params_or_response(
4585 &file.abs_path(cx),
4586 buffer.read(cx),
4587 &language_server,
4588 cx,
4589 ) {
4590 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4591 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4592
4593 Err(err) => {
4594 let message = format!(
4595 "{} via {} failed: {}",
4596 request.display_name(),
4597 language_server.name(),
4598 err
4599 );
4600 log::warn!("{message}");
4601 return Task::ready(Err(anyhow!(message)));
4602 }
4603 };
4604
4605 let status = request.status();
4606 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4607 return Task::ready(Ok(Default::default()));
4608 }
4609 return cx.spawn(async move |this, cx| {
4610 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4611
4612 let id = lsp_request.id();
4613 let _cleanup = if status.is_some() {
4614 cx.update(|cx| {
4615 this.update(cx, |this, cx| {
4616 this.on_lsp_work_start(
4617 language_server.server_id(),
4618 id.to_string(),
4619 LanguageServerProgress {
4620 is_disk_based_diagnostics_progress: false,
4621 is_cancellable: false,
4622 title: None,
4623 message: status.clone(),
4624 percentage: None,
4625 last_update_at: cx.background_executor().now(),
4626 },
4627 cx,
4628 );
4629 })
4630 })
4631 .log_err();
4632
4633 Some(defer(|| {
4634 cx.update(|cx| {
4635 this.update(cx, |this, cx| {
4636 this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
4637 })
4638 })
4639 .log_err();
4640 }))
4641 } else {
4642 None
4643 };
4644
4645 let result = lsp_request.await.into_response();
4646
4647 let response = result.map_err(|err| {
4648 let message = format!(
4649 "{} via {} failed: {}",
4650 request.display_name(),
4651 language_server.name(),
4652 err
4653 );
4654 log::warn!("{message}");
4655 anyhow::anyhow!(message)
4656 })?;
4657
4658 let response = request
4659 .response_from_lsp(
4660 response,
4661 this.upgrade().context("no app context")?,
4662 buffer,
4663 language_server.server_id(),
4664 cx.clone(),
4665 )
4666 .await;
4667 response
4668 });
4669 }
4670
4671 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4672 let mut language_formatters_to_check = Vec::new();
4673 for buffer in self.buffer_store.read(cx).buffers() {
4674 let buffer = buffer.read(cx);
4675 let buffer_file = File::from_dyn(buffer.file());
4676 let buffer_language = buffer.language();
4677 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4678 if buffer_language.is_some() {
4679 language_formatters_to_check.push((
4680 buffer_file.map(|f| f.worktree_id(cx)),
4681 settings.into_owned(),
4682 ));
4683 }
4684 }
4685
4686 self.refresh_server_tree(cx);
4687
4688 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4689 prettier_store.update(cx, |prettier_store, cx| {
4690 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4691 })
4692 }
4693
4694 cx.notify();
4695 }
4696
4697 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4698 let buffer_store = self.buffer_store.clone();
4699 if let Some(local) = self.as_local_mut() {
4700 let mut adapters = BTreeMap::default();
4701 let get_adapter = {
4702 let languages = local.languages.clone();
4703 let environment = local.environment.clone();
4704 let weak = local.weak.clone();
4705 let worktree_store = local.worktree_store.clone();
4706 let http_client = local.http_client.clone();
4707 let fs = local.fs.clone();
4708 move |worktree_id, cx: &mut App| {
4709 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4710 Some(LocalLspAdapterDelegate::new(
4711 languages.clone(),
4712 &environment,
4713 weak.clone(),
4714 &worktree,
4715 http_client.clone(),
4716 fs.clone(),
4717 cx,
4718 ))
4719 }
4720 };
4721
4722 let mut messages_to_report = Vec::new();
4723 let to_stop = local.lsp_tree.clone().update(cx, |lsp_tree, cx| {
4724 let mut rebase = lsp_tree.rebase();
4725 for buffer_handle in buffer_store.read(cx).buffers().sorted_by_key(|buffer| {
4726 Reverse(
4727 File::from_dyn(buffer.read(cx).file())
4728 .map(|file| file.worktree.read(cx).is_visible()),
4729 )
4730 }) {
4731 let buffer = buffer_handle.read(cx);
4732 let buffer_id = buffer.remote_id();
4733 if !local.registered_buffers.contains_key(&buffer_id) {
4734 continue;
4735 }
4736 if let Some((file, language)) = File::from_dyn(buffer.file())
4737 .cloned()
4738 .zip(buffer.language().map(|l| l.name()))
4739 {
4740 let worktree_id = file.worktree_id(cx);
4741 let Some(worktree) = local
4742 .worktree_store
4743 .read(cx)
4744 .worktree_for_id(worktree_id, cx)
4745 else {
4746 continue;
4747 };
4748
4749 let Some((reused, delegate, nodes)) = local
4750 .reuse_existing_language_server(
4751 rebase.server_tree(),
4752 &worktree,
4753 &language,
4754 cx,
4755 )
4756 .map(|(delegate, servers)| (true, delegate, servers))
4757 .or_else(|| {
4758 let lsp_delegate = adapters
4759 .entry(worktree_id)
4760 .or_insert_with(|| get_adapter(worktree_id, cx))
4761 .clone()?;
4762 let delegate = Arc::new(ManifestQueryDelegate::new(
4763 worktree.read(cx).snapshot(),
4764 ));
4765 let path = file
4766 .path()
4767 .parent()
4768 .map(Arc::from)
4769 .unwrap_or_else(|| file.path().clone());
4770 let worktree_path = ProjectPath { worktree_id, path };
4771
4772 let nodes = rebase.get(
4773 worktree_path,
4774 AdapterQuery::Language(&language),
4775 delegate.clone(),
4776 cx,
4777 );
4778
4779 Some((false, lsp_delegate, nodes.collect()))
4780 })
4781 else {
4782 continue;
4783 };
4784
4785 let abs_path = file.abs_path(cx);
4786 for node in nodes {
4787 if !reused {
4788 let server_id = node.server_id_or_init(
4789 |LaunchDisposition {
4790 server_name,
4791
4792 path,
4793 settings,
4794 }|
4795 {
4796 let uri = Url::from_file_path(
4797 worktree.read(cx).abs_path().join(&path.path),
4798 );
4799 let key = (worktree_id, server_name.clone());
4800 local.language_server_ids.remove(&key);
4801
4802 let adapter = local
4803 .languages
4804 .lsp_adapters(&language)
4805 .into_iter()
4806 .find(|adapter| &adapter.name() == server_name)
4807 .expect("To find LSP adapter");
4808 let server_id = local.start_language_server(
4809 &worktree,
4810 delegate.clone(),
4811 adapter,
4812 settings,
4813 cx,
4814 );
4815 if let Some(state) =
4816 local.language_servers.get(&server_id)
4817 {
4818 if let Ok(uri) = uri {
4819 state.add_workspace_folder(uri);
4820 };
4821 }
4822 server_id
4823 }
4824 );
4825
4826 if let Some(language_server_id) = server_id {
4827 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4828 language_server_id,
4829 name: node.name(),
4830 message:
4831 proto::update_language_server::Variant::RegisteredForBuffer(
4832 proto::RegisteredForBuffer {
4833 buffer_abs_path: abs_path.to_string_lossy().to_string(),
4834 buffer_id: buffer_id.to_proto(),
4835 },
4836 ),
4837 });
4838 }
4839 }
4840 }
4841 }
4842 }
4843 rebase.finish()
4844 });
4845 for message in messages_to_report {
4846 cx.emit(message);
4847 }
4848 for (id, _) in to_stop {
4849 self.stop_local_language_server(id, cx).detach();
4850 }
4851 }
4852 }
4853
4854 pub fn apply_code_action(
4855 &self,
4856 buffer_handle: Entity<Buffer>,
4857 mut action: CodeAction,
4858 push_to_history: bool,
4859 cx: &mut Context<Self>,
4860 ) -> Task<Result<ProjectTransaction>> {
4861 if let Some((upstream_client, project_id)) = self.upstream_client() {
4862 let request = proto::ApplyCodeAction {
4863 project_id,
4864 buffer_id: buffer_handle.read(cx).remote_id().into(),
4865 action: Some(Self::serialize_code_action(&action)),
4866 };
4867 let buffer_store = self.buffer_store();
4868 cx.spawn(async move |_, cx| {
4869 let response = upstream_client
4870 .request(request)
4871 .await?
4872 .transaction
4873 .context("missing transaction")?;
4874
4875 buffer_store
4876 .update(cx, |buffer_store, cx| {
4877 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
4878 })?
4879 .await
4880 })
4881 } else if self.mode.is_local() {
4882 let Some((lsp_adapter, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
4883 self.language_server_for_local_buffer(buffer, action.server_id, cx)
4884 .map(|(adapter, server)| (adapter.clone(), server.clone()))
4885 }) else {
4886 return Task::ready(Ok(ProjectTransaction::default()));
4887 };
4888 cx.spawn(async move |this, cx| {
4889 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
4890 .await
4891 .context("resolving a code action")?;
4892 if let Some(edit) = action.lsp_action.edit() {
4893 if edit.changes.is_some() || edit.document_changes.is_some() {
4894 return LocalLspStore::deserialize_workspace_edit(
4895 this.upgrade().context("no app present")?,
4896 edit.clone(),
4897 push_to_history,
4898 lsp_adapter.clone(),
4899 lang_server.clone(),
4900 cx,
4901 )
4902 .await;
4903 }
4904 }
4905
4906 if let Some(command) = action.lsp_action.command() {
4907 let server_capabilities = lang_server.capabilities();
4908 let available_commands = server_capabilities
4909 .execute_command_provider
4910 .as_ref()
4911 .map(|options| options.commands.as_slice())
4912 .unwrap_or_default();
4913 if available_commands.contains(&command.command) {
4914 this.update(cx, |this, _| {
4915 this.as_local_mut()
4916 .unwrap()
4917 .last_workspace_edits_by_language_server
4918 .remove(&lang_server.server_id());
4919 })?;
4920
4921 let _result = lang_server
4922 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
4923 command: command.command.clone(),
4924 arguments: command.arguments.clone().unwrap_or_default(),
4925 ..lsp::ExecuteCommandParams::default()
4926 })
4927 .await.into_response()
4928 .context("execute command")?;
4929
4930 return this.update(cx, |this, _| {
4931 this.as_local_mut()
4932 .unwrap()
4933 .last_workspace_edits_by_language_server
4934 .remove(&lang_server.server_id())
4935 .unwrap_or_default()
4936 });
4937 } else {
4938 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
4939 }
4940 }
4941
4942 Ok(ProjectTransaction::default())
4943 })
4944 } else {
4945 Task::ready(Err(anyhow!("no upstream client and not local")))
4946 }
4947 }
4948
4949 pub fn apply_code_action_kind(
4950 &mut self,
4951 buffers: HashSet<Entity<Buffer>>,
4952 kind: CodeActionKind,
4953 push_to_history: bool,
4954 cx: &mut Context<Self>,
4955 ) -> Task<anyhow::Result<ProjectTransaction>> {
4956 if let Some(_) = self.as_local() {
4957 cx.spawn(async move |lsp_store, cx| {
4958 let buffers = buffers.into_iter().collect::<Vec<_>>();
4959 let result = LocalLspStore::execute_code_action_kind_locally(
4960 lsp_store.clone(),
4961 buffers,
4962 kind,
4963 push_to_history,
4964 cx,
4965 )
4966 .await;
4967 lsp_store.update(cx, |lsp_store, _| {
4968 lsp_store.update_last_formatting_failure(&result);
4969 })?;
4970 result
4971 })
4972 } else if let Some((client, project_id)) = self.upstream_client() {
4973 let buffer_store = self.buffer_store();
4974 cx.spawn(async move |lsp_store, cx| {
4975 let result = client
4976 .request(proto::ApplyCodeActionKind {
4977 project_id,
4978 kind: kind.as_str().to_owned(),
4979 buffer_ids: buffers
4980 .iter()
4981 .map(|buffer| {
4982 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
4983 })
4984 .collect::<Result<_>>()?,
4985 })
4986 .await
4987 .and_then(|result| result.transaction.context("missing transaction"));
4988 lsp_store.update(cx, |lsp_store, _| {
4989 lsp_store.update_last_formatting_failure(&result);
4990 })?;
4991
4992 let transaction_response = result?;
4993 buffer_store
4994 .update(cx, |buffer_store, cx| {
4995 buffer_store.deserialize_project_transaction(
4996 transaction_response,
4997 push_to_history,
4998 cx,
4999 )
5000 })?
5001 .await
5002 })
5003 } else {
5004 Task::ready(Ok(ProjectTransaction::default()))
5005 }
5006 }
5007
5008 pub fn resolve_inlay_hint(
5009 &self,
5010 mut hint: InlayHint,
5011 buffer: Entity<Buffer>,
5012 server_id: LanguageServerId,
5013 cx: &mut Context<Self>,
5014 ) -> Task<anyhow::Result<InlayHint>> {
5015 if let Some((upstream_client, project_id)) = self.upstream_client() {
5016 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5017 {
5018 hint.resolve_state = ResolveState::Resolved;
5019 return Task::ready(Ok(hint));
5020 }
5021 let request = proto::ResolveInlayHint {
5022 project_id,
5023 buffer_id: buffer.read(cx).remote_id().into(),
5024 language_server_id: server_id.0 as u64,
5025 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5026 };
5027 cx.background_spawn(async move {
5028 let response = upstream_client
5029 .request(request)
5030 .await
5031 .context("inlay hints proto request")?;
5032 match response.hint {
5033 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5034 .context("inlay hints proto resolve response conversion"),
5035 None => Ok(hint),
5036 }
5037 })
5038 } else {
5039 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5040 self.language_server_for_local_buffer(buffer, server_id, cx)
5041 .map(|(_, server)| server.clone())
5042 }) else {
5043 return Task::ready(Ok(hint));
5044 };
5045 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5046 return Task::ready(Ok(hint));
5047 }
5048 let buffer_snapshot = buffer.read(cx).snapshot();
5049 cx.spawn(async move |_, cx| {
5050 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5051 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5052 );
5053 let resolved_hint = resolve_task
5054 .await
5055 .into_response()
5056 .context("inlay hint resolve LSP request")?;
5057 let resolved_hint = InlayHints::lsp_to_project_hint(
5058 resolved_hint,
5059 &buffer,
5060 server_id,
5061 ResolveState::Resolved,
5062 false,
5063 cx,
5064 )
5065 .await?;
5066 Ok(resolved_hint)
5067 })
5068 }
5069 }
5070
5071 pub fn resolve_color_presentation(
5072 &mut self,
5073 mut color: DocumentColor,
5074 buffer: Entity<Buffer>,
5075 server_id: LanguageServerId,
5076 cx: &mut Context<Self>,
5077 ) -> Task<Result<DocumentColor>> {
5078 if color.resolved {
5079 return Task::ready(Ok(color));
5080 }
5081
5082 if let Some((upstream_client, project_id)) = self.upstream_client() {
5083 let start = color.lsp_range.start;
5084 let end = color.lsp_range.end;
5085 let request = proto::GetColorPresentation {
5086 project_id,
5087 server_id: server_id.to_proto(),
5088 buffer_id: buffer.read(cx).remote_id().into(),
5089 color: Some(proto::ColorInformation {
5090 red: color.color.red,
5091 green: color.color.green,
5092 blue: color.color.blue,
5093 alpha: color.color.alpha,
5094 lsp_range_start: Some(proto::PointUtf16 {
5095 row: start.line,
5096 column: start.character,
5097 }),
5098 lsp_range_end: Some(proto::PointUtf16 {
5099 row: end.line,
5100 column: end.character,
5101 }),
5102 }),
5103 };
5104 cx.background_spawn(async move {
5105 let response = upstream_client
5106 .request(request)
5107 .await
5108 .context("color presentation proto request")?;
5109 color.resolved = true;
5110 color.color_presentations = response
5111 .presentations
5112 .into_iter()
5113 .map(|presentation| ColorPresentation {
5114 label: SharedString::from(presentation.label),
5115 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5116 additional_text_edits: presentation
5117 .additional_text_edits
5118 .into_iter()
5119 .filter_map(deserialize_lsp_edit)
5120 .collect(),
5121 })
5122 .collect();
5123 Ok(color)
5124 })
5125 } else {
5126 let path = match buffer
5127 .update(cx, |buffer, cx| {
5128 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5129 })
5130 .context("buffer with the missing path")
5131 {
5132 Ok(path) => path,
5133 Err(e) => return Task::ready(Err(e)),
5134 };
5135 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5136 self.language_server_for_local_buffer(buffer, server_id, cx)
5137 .map(|(_, server)| server.clone())
5138 }) else {
5139 return Task::ready(Ok(color));
5140 };
5141 cx.background_spawn(async move {
5142 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5143 lsp::ColorPresentationParams {
5144 text_document: make_text_document_identifier(&path)?,
5145 color: color.color,
5146 range: color.lsp_range,
5147 work_done_progress_params: Default::default(),
5148 partial_result_params: Default::default(),
5149 },
5150 );
5151 color.color_presentations = resolve_task
5152 .await
5153 .into_response()
5154 .context("color presentation resolve LSP request")?
5155 .into_iter()
5156 .map(|presentation| ColorPresentation {
5157 label: SharedString::from(presentation.label),
5158 text_edit: presentation.text_edit,
5159 additional_text_edits: presentation
5160 .additional_text_edits
5161 .unwrap_or_default(),
5162 })
5163 .collect();
5164 color.resolved = true;
5165 Ok(color)
5166 })
5167 }
5168 }
5169
5170 pub(crate) fn linked_edits(
5171 &mut self,
5172 buffer: &Entity<Buffer>,
5173 position: Anchor,
5174 cx: &mut Context<Self>,
5175 ) -> Task<Result<Vec<Range<Anchor>>>> {
5176 let snapshot = buffer.read(cx).snapshot();
5177 let scope = snapshot.language_scope_at(position);
5178 let Some(server_id) = self
5179 .as_local()
5180 .and_then(|local| {
5181 buffer.update(cx, |buffer, cx| {
5182 local
5183 .language_servers_for_buffer(buffer, cx)
5184 .filter(|(_, server)| {
5185 LinkedEditingRange::check_server_capabilities(server.capabilities())
5186 })
5187 .filter(|(adapter, _)| {
5188 scope
5189 .as_ref()
5190 .map(|scope| scope.language_allowed(&adapter.name))
5191 .unwrap_or(true)
5192 })
5193 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5194 .next()
5195 })
5196 })
5197 .or_else(|| {
5198 self.upstream_client()
5199 .is_some()
5200 .then_some(LanguageServerToQuery::FirstCapable)
5201 })
5202 .filter(|_| {
5203 maybe!({
5204 let language = buffer.read(cx).language_at(position)?;
5205 Some(
5206 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5207 .linked_edits,
5208 )
5209 }) == Some(true)
5210 })
5211 else {
5212 return Task::ready(Ok(Vec::new()));
5213 };
5214
5215 self.request_lsp(
5216 buffer.clone(),
5217 server_id,
5218 LinkedEditingRange { position },
5219 cx,
5220 )
5221 }
5222
5223 fn apply_on_type_formatting(
5224 &mut self,
5225 buffer: Entity<Buffer>,
5226 position: Anchor,
5227 trigger: String,
5228 cx: &mut Context<Self>,
5229 ) -> Task<Result<Option<Transaction>>> {
5230 if let Some((client, project_id)) = self.upstream_client() {
5231 if !self.check_if_capable_for_proto_request(
5232 &buffer,
5233 |capabilities| {
5234 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5235 },
5236 cx,
5237 ) {
5238 return Task::ready(Ok(None));
5239 }
5240 let request = proto::OnTypeFormatting {
5241 project_id,
5242 buffer_id: buffer.read(cx).remote_id().into(),
5243 position: Some(serialize_anchor(&position)),
5244 trigger,
5245 version: serialize_version(&buffer.read(cx).version()),
5246 };
5247 cx.background_spawn(async move {
5248 client
5249 .request(request)
5250 .await?
5251 .transaction
5252 .map(language::proto::deserialize_transaction)
5253 .transpose()
5254 })
5255 } else if let Some(local) = self.as_local_mut() {
5256 let buffer_id = buffer.read(cx).remote_id();
5257 local.buffers_being_formatted.insert(buffer_id);
5258 cx.spawn(async move |this, cx| {
5259 let _cleanup = defer({
5260 let this = this.clone();
5261 let mut cx = cx.clone();
5262 move || {
5263 this.update(&mut cx, |this, _| {
5264 if let Some(local) = this.as_local_mut() {
5265 local.buffers_being_formatted.remove(&buffer_id);
5266 }
5267 })
5268 .ok();
5269 }
5270 });
5271
5272 buffer
5273 .update(cx, |buffer, _| {
5274 buffer.wait_for_edits(Some(position.timestamp))
5275 })?
5276 .await?;
5277 this.update(cx, |this, cx| {
5278 let position = position.to_point_utf16(buffer.read(cx));
5279 this.on_type_format(buffer, position, trigger, false, cx)
5280 })?
5281 .await
5282 })
5283 } else {
5284 Task::ready(Err(anyhow!("No upstream client or local language server")))
5285 }
5286 }
5287
5288 pub fn on_type_format<T: ToPointUtf16>(
5289 &mut self,
5290 buffer: Entity<Buffer>,
5291 position: T,
5292 trigger: String,
5293 push_to_history: bool,
5294 cx: &mut Context<Self>,
5295 ) -> Task<Result<Option<Transaction>>> {
5296 let position = position.to_point_utf16(buffer.read(cx));
5297 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5298 }
5299
5300 fn on_type_format_impl(
5301 &mut self,
5302 buffer: Entity<Buffer>,
5303 position: PointUtf16,
5304 trigger: String,
5305 push_to_history: bool,
5306 cx: &mut Context<Self>,
5307 ) -> Task<Result<Option<Transaction>>> {
5308 let options = buffer.update(cx, |buffer, cx| {
5309 lsp_command::lsp_formatting_options(
5310 language_settings(
5311 buffer.language_at(position).map(|l| l.name()),
5312 buffer.file(),
5313 cx,
5314 )
5315 .as_ref(),
5316 )
5317 });
5318
5319 cx.spawn(async move |this, cx| {
5320 if let Some(waiter) =
5321 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5322 {
5323 waiter.await?;
5324 }
5325 cx.update(|cx| {
5326 this.update(cx, |this, cx| {
5327 this.request_lsp(
5328 buffer.clone(),
5329 LanguageServerToQuery::FirstCapable,
5330 OnTypeFormatting {
5331 position,
5332 trigger,
5333 options,
5334 push_to_history,
5335 },
5336 cx,
5337 )
5338 })
5339 })??
5340 .await
5341 })
5342 }
5343
5344 pub fn definitions(
5345 &mut self,
5346 buffer_handle: &Entity<Buffer>,
5347 position: PointUtf16,
5348 cx: &mut Context<Self>,
5349 ) -> Task<Result<Vec<LocationLink>>> {
5350 if let Some((upstream_client, project_id)) = self.upstream_client() {
5351 let request = GetDefinitions { position };
5352 if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
5353 return Task::ready(Ok(Vec::new()));
5354 }
5355 let request_task = upstream_client.request(proto::MultiLspQuery {
5356 buffer_id: buffer_handle.read(cx).remote_id().into(),
5357 version: serialize_version(&buffer_handle.read(cx).version()),
5358 project_id,
5359 strategy: Some(proto::multi_lsp_query::Strategy::All(
5360 proto::AllLanguageServers {},
5361 )),
5362 request: Some(proto::multi_lsp_query::Request::GetDefinition(
5363 request.to_proto(project_id, buffer_handle.read(cx)),
5364 )),
5365 });
5366 let buffer = buffer_handle.clone();
5367 cx.spawn(async move |weak_project, cx| {
5368 let Some(project) = weak_project.upgrade() else {
5369 return Ok(Vec::new());
5370 };
5371 let responses = request_task.await?.responses;
5372 let actions = join_all(
5373 responses
5374 .into_iter()
5375 .filter_map(|lsp_response| match lsp_response.response? {
5376 proto::lsp_response::Response::GetDefinitionResponse(response) => {
5377 Some(response)
5378 }
5379 unexpected => {
5380 debug_panic!("Unexpected response: {unexpected:?}");
5381 None
5382 }
5383 })
5384 .map(|definitions_response| {
5385 GetDefinitions { position }.response_from_proto(
5386 definitions_response,
5387 project.clone(),
5388 buffer.clone(),
5389 cx.clone(),
5390 )
5391 }),
5392 )
5393 .await;
5394
5395 Ok(actions
5396 .into_iter()
5397 .collect::<Result<Vec<Vec<_>>>>()?
5398 .into_iter()
5399 .flatten()
5400 .dedup()
5401 .collect())
5402 })
5403 } else {
5404 let definitions_task = self.request_multiple_lsp_locally(
5405 buffer_handle,
5406 Some(position),
5407 GetDefinitions { position },
5408 cx,
5409 );
5410 cx.background_spawn(async move {
5411 Ok(definitions_task
5412 .await
5413 .into_iter()
5414 .flat_map(|(_, definitions)| definitions)
5415 .dedup()
5416 .collect())
5417 })
5418 }
5419 }
5420
5421 pub fn declarations(
5422 &mut self,
5423 buffer_handle: &Entity<Buffer>,
5424 position: PointUtf16,
5425 cx: &mut Context<Self>,
5426 ) -> Task<Result<Vec<LocationLink>>> {
5427 if let Some((upstream_client, project_id)) = self.upstream_client() {
5428 let request = GetDeclarations { position };
5429 if !self.is_capable_for_proto_request(buffer_handle, &request, cx) {
5430 return Task::ready(Ok(Vec::new()));
5431 }
5432 let request_task = upstream_client.request(proto::MultiLspQuery {
5433 buffer_id: buffer_handle.read(cx).remote_id().into(),
5434 version: serialize_version(&buffer_handle.read(cx).version()),
5435 project_id,
5436 strategy: Some(proto::multi_lsp_query::Strategy::All(
5437 proto::AllLanguageServers {},
5438 )),
5439 request: Some(proto::multi_lsp_query::Request::GetDeclaration(
5440 request.to_proto(project_id, buffer_handle.read(cx)),
5441 )),
5442 });
5443 let buffer = buffer_handle.clone();
5444 cx.spawn(async move |weak_project, cx| {
5445 let Some(project) = weak_project.upgrade() else {
5446 return Ok(Vec::new());
5447 };
5448 let responses = request_task.await?.responses;
5449 let actions = join_all(
5450 responses
5451 .into_iter()
5452 .filter_map(|lsp_response| match lsp_response.response? {
5453 proto::lsp_response::Response::GetDeclarationResponse(response) => {
5454 Some(response)
5455 }
5456 unexpected => {
5457 debug_panic!("Unexpected response: {unexpected:?}");
5458 None
5459 }
5460 })
5461 .map(|declarations_response| {
5462 GetDeclarations { position }.response_from_proto(
5463 declarations_response,
5464 project.clone(),
5465 buffer.clone(),
5466 cx.clone(),
5467 )
5468 }),
5469 )
5470 .await;
5471
5472 Ok(actions
5473 .into_iter()
5474 .collect::<Result<Vec<Vec<_>>>>()?
5475 .into_iter()
5476 .flatten()
5477 .dedup()
5478 .collect())
5479 })
5480 } else {
5481 let declarations_task = self.request_multiple_lsp_locally(
5482 buffer_handle,
5483 Some(position),
5484 GetDeclarations { position },
5485 cx,
5486 );
5487 cx.background_spawn(async move {
5488 Ok(declarations_task
5489 .await
5490 .into_iter()
5491 .flat_map(|(_, declarations)| declarations)
5492 .dedup()
5493 .collect())
5494 })
5495 }
5496 }
5497
5498 pub fn type_definitions(
5499 &mut self,
5500 buffer: &Entity<Buffer>,
5501 position: PointUtf16,
5502 cx: &mut Context<Self>,
5503 ) -> Task<Result<Vec<LocationLink>>> {
5504 if let Some((upstream_client, project_id)) = self.upstream_client() {
5505 let request = GetTypeDefinitions { position };
5506 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
5507 return Task::ready(Ok(Vec::new()));
5508 }
5509 let request_task = upstream_client.request(proto::MultiLspQuery {
5510 buffer_id: buffer.read(cx).remote_id().into(),
5511 version: serialize_version(&buffer.read(cx).version()),
5512 project_id,
5513 strategy: Some(proto::multi_lsp_query::Strategy::All(
5514 proto::AllLanguageServers {},
5515 )),
5516 request: Some(proto::multi_lsp_query::Request::GetTypeDefinition(
5517 request.to_proto(project_id, buffer.read(cx)),
5518 )),
5519 });
5520 let buffer = buffer.clone();
5521 cx.spawn(async move |weak_project, cx| {
5522 let Some(project) = weak_project.upgrade() else {
5523 return Ok(Vec::new());
5524 };
5525 let responses = request_task.await?.responses;
5526 let actions = join_all(
5527 responses
5528 .into_iter()
5529 .filter_map(|lsp_response| match lsp_response.response? {
5530 proto::lsp_response::Response::GetTypeDefinitionResponse(response) => {
5531 Some(response)
5532 }
5533 unexpected => {
5534 debug_panic!("Unexpected response: {unexpected:?}");
5535 None
5536 }
5537 })
5538 .map(|type_definitions_response| {
5539 GetTypeDefinitions { position }.response_from_proto(
5540 type_definitions_response,
5541 project.clone(),
5542 buffer.clone(),
5543 cx.clone(),
5544 )
5545 }),
5546 )
5547 .await;
5548
5549 Ok(actions
5550 .into_iter()
5551 .collect::<Result<Vec<Vec<_>>>>()?
5552 .into_iter()
5553 .flatten()
5554 .dedup()
5555 .collect())
5556 })
5557 } else {
5558 let type_definitions_task = self.request_multiple_lsp_locally(
5559 buffer,
5560 Some(position),
5561 GetTypeDefinitions { position },
5562 cx,
5563 );
5564 cx.background_spawn(async move {
5565 Ok(type_definitions_task
5566 .await
5567 .into_iter()
5568 .flat_map(|(_, type_definitions)| type_definitions)
5569 .dedup()
5570 .collect())
5571 })
5572 }
5573 }
5574
5575 pub fn implementations(
5576 &mut self,
5577 buffer: &Entity<Buffer>,
5578 position: PointUtf16,
5579 cx: &mut Context<Self>,
5580 ) -> Task<Result<Vec<LocationLink>>> {
5581 if let Some((upstream_client, project_id)) = self.upstream_client() {
5582 let request = GetImplementations { position };
5583 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5584 return Task::ready(Ok(Vec::new()));
5585 }
5586 let request_task = upstream_client.request(proto::MultiLspQuery {
5587 buffer_id: buffer.read(cx).remote_id().into(),
5588 version: serialize_version(&buffer.read(cx).version()),
5589 project_id,
5590 strategy: Some(proto::multi_lsp_query::Strategy::All(
5591 proto::AllLanguageServers {},
5592 )),
5593 request: Some(proto::multi_lsp_query::Request::GetImplementation(
5594 request.to_proto(project_id, buffer.read(cx)),
5595 )),
5596 });
5597 let buffer = buffer.clone();
5598 cx.spawn(async move |weak_project, cx| {
5599 let Some(project) = weak_project.upgrade() else {
5600 return Ok(Vec::new());
5601 };
5602 let responses = request_task.await?.responses;
5603 let actions = join_all(
5604 responses
5605 .into_iter()
5606 .filter_map(|lsp_response| match lsp_response.response? {
5607 proto::lsp_response::Response::GetImplementationResponse(response) => {
5608 Some(response)
5609 }
5610 unexpected => {
5611 debug_panic!("Unexpected response: {unexpected:?}");
5612 None
5613 }
5614 })
5615 .map(|implementations_response| {
5616 GetImplementations { position }.response_from_proto(
5617 implementations_response,
5618 project.clone(),
5619 buffer.clone(),
5620 cx.clone(),
5621 )
5622 }),
5623 )
5624 .await;
5625
5626 Ok(actions
5627 .into_iter()
5628 .collect::<Result<Vec<Vec<_>>>>()?
5629 .into_iter()
5630 .flatten()
5631 .dedup()
5632 .collect())
5633 })
5634 } else {
5635 let implementations_task = self.request_multiple_lsp_locally(
5636 buffer,
5637 Some(position),
5638 GetImplementations { position },
5639 cx,
5640 );
5641 cx.background_spawn(async move {
5642 Ok(implementations_task
5643 .await
5644 .into_iter()
5645 .flat_map(|(_, implementations)| implementations)
5646 .dedup()
5647 .collect())
5648 })
5649 }
5650 }
5651
5652 pub fn references(
5653 &mut self,
5654 buffer: &Entity<Buffer>,
5655 position: PointUtf16,
5656 cx: &mut Context<Self>,
5657 ) -> Task<Result<Vec<Location>>> {
5658 if let Some((upstream_client, project_id)) = self.upstream_client() {
5659 let request = GetReferences { position };
5660 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
5661 return Task::ready(Ok(Vec::new()));
5662 }
5663 let request_task = upstream_client.request(proto::MultiLspQuery {
5664 buffer_id: buffer.read(cx).remote_id().into(),
5665 version: serialize_version(&buffer.read(cx).version()),
5666 project_id,
5667 strategy: Some(proto::multi_lsp_query::Strategy::All(
5668 proto::AllLanguageServers {},
5669 )),
5670 request: Some(proto::multi_lsp_query::Request::GetReferences(
5671 request.to_proto(project_id, buffer.read(cx)),
5672 )),
5673 });
5674 let buffer = buffer.clone();
5675 cx.spawn(async move |weak_project, cx| {
5676 let Some(project) = weak_project.upgrade() else {
5677 return Ok(Vec::new());
5678 };
5679 let responses = request_task.await?.responses;
5680 let actions = join_all(
5681 responses
5682 .into_iter()
5683 .filter_map(|lsp_response| match lsp_response.response? {
5684 proto::lsp_response::Response::GetReferencesResponse(response) => {
5685 Some(response)
5686 }
5687 unexpected => {
5688 debug_panic!("Unexpected response: {unexpected:?}");
5689 None
5690 }
5691 })
5692 .map(|references_response| {
5693 GetReferences { position }.response_from_proto(
5694 references_response,
5695 project.clone(),
5696 buffer.clone(),
5697 cx.clone(),
5698 )
5699 }),
5700 )
5701 .await;
5702
5703 Ok(actions
5704 .into_iter()
5705 .collect::<Result<Vec<Vec<_>>>>()?
5706 .into_iter()
5707 .flatten()
5708 .dedup()
5709 .collect())
5710 })
5711 } else {
5712 let references_task = self.request_multiple_lsp_locally(
5713 buffer,
5714 Some(position),
5715 GetReferences { position },
5716 cx,
5717 );
5718 cx.background_spawn(async move {
5719 Ok(references_task
5720 .await
5721 .into_iter()
5722 .flat_map(|(_, references)| references)
5723 .dedup()
5724 .collect())
5725 })
5726 }
5727 }
5728
5729 pub fn code_actions(
5730 &mut self,
5731 buffer: &Entity<Buffer>,
5732 range: Range<Anchor>,
5733 kinds: Option<Vec<CodeActionKind>>,
5734 cx: &mut Context<Self>,
5735 ) -> Task<Result<Vec<CodeAction>>> {
5736 if let Some((upstream_client, project_id)) = self.upstream_client() {
5737 let request = GetCodeActions {
5738 range: range.clone(),
5739 kinds: kinds.clone(),
5740 };
5741 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5742 return Task::ready(Ok(Vec::new()));
5743 }
5744 let request_task = upstream_client.request(proto::MultiLspQuery {
5745 buffer_id: buffer.read(cx).remote_id().into(),
5746 version: serialize_version(&buffer.read(cx).version()),
5747 project_id,
5748 strategy: Some(proto::multi_lsp_query::Strategy::All(
5749 proto::AllLanguageServers {},
5750 )),
5751 request: Some(proto::multi_lsp_query::Request::GetCodeActions(
5752 request.to_proto(project_id, buffer.read(cx)),
5753 )),
5754 });
5755 let buffer = buffer.clone();
5756 cx.spawn(async move |weak_project, cx| {
5757 let Some(project) = weak_project.upgrade() else {
5758 return Ok(Vec::new());
5759 };
5760 let responses = request_task.await?.responses;
5761 let actions = join_all(
5762 responses
5763 .into_iter()
5764 .filter_map(|lsp_response| match lsp_response.response? {
5765 proto::lsp_response::Response::GetCodeActionsResponse(response) => {
5766 Some(response)
5767 }
5768 unexpected => {
5769 debug_panic!("Unexpected response: {unexpected:?}");
5770 None
5771 }
5772 })
5773 .map(|code_actions_response| {
5774 GetCodeActions {
5775 range: range.clone(),
5776 kinds: kinds.clone(),
5777 }
5778 .response_from_proto(
5779 code_actions_response,
5780 project.clone(),
5781 buffer.clone(),
5782 cx.clone(),
5783 )
5784 }),
5785 )
5786 .await;
5787
5788 Ok(actions
5789 .into_iter()
5790 .collect::<Result<Vec<Vec<_>>>>()?
5791 .into_iter()
5792 .flatten()
5793 .collect())
5794 })
5795 } else {
5796 let all_actions_task = self.request_multiple_lsp_locally(
5797 buffer,
5798 Some(range.start),
5799 GetCodeActions {
5800 range: range.clone(),
5801 kinds: kinds.clone(),
5802 },
5803 cx,
5804 );
5805 cx.background_spawn(async move {
5806 Ok(all_actions_task
5807 .await
5808 .into_iter()
5809 .flat_map(|(_, actions)| actions)
5810 .collect())
5811 })
5812 }
5813 }
5814
5815 pub fn code_lens_actions(
5816 &mut self,
5817 buffer: &Entity<Buffer>,
5818 cx: &mut Context<Self>,
5819 ) -> CodeLensTask {
5820 let version_queried_for = buffer.read(cx).version();
5821 let buffer_id = buffer.read(cx).remote_id();
5822
5823 if let Some(cached_data) = self.lsp_code_lens.get(&buffer_id) {
5824 if !version_queried_for.changed_since(&cached_data.lens_for_version) {
5825 let has_different_servers = self.as_local().is_some_and(|local| {
5826 local
5827 .buffers_opened_in_servers
5828 .get(&buffer_id)
5829 .cloned()
5830 .unwrap_or_default()
5831 != cached_data.lens.keys().copied().collect()
5832 });
5833 if !has_different_servers {
5834 return Task::ready(Ok(cached_data.lens.values().flatten().cloned().collect()))
5835 .shared();
5836 }
5837 }
5838 }
5839
5840 let lsp_data = self.lsp_code_lens.entry(buffer_id).or_default();
5841 if let Some((updating_for, running_update)) = &lsp_data.update {
5842 if !version_queried_for.changed_since(&updating_for) {
5843 return running_update.clone();
5844 }
5845 }
5846 let buffer = buffer.clone();
5847 let query_version_queried_for = version_queried_for.clone();
5848 let new_task = cx
5849 .spawn(async move |lsp_store, cx| {
5850 cx.background_executor()
5851 .timer(Duration::from_millis(30))
5852 .await;
5853 let fetched_lens = lsp_store
5854 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
5855 .map_err(Arc::new)?
5856 .await
5857 .context("fetching code lens")
5858 .map_err(Arc::new);
5859 let fetched_lens = match fetched_lens {
5860 Ok(fetched_lens) => fetched_lens,
5861 Err(e) => {
5862 lsp_store
5863 .update(cx, |lsp_store, _| {
5864 lsp_store.lsp_code_lens.entry(buffer_id).or_default().update = None;
5865 })
5866 .ok();
5867 return Err(e);
5868 }
5869 };
5870
5871 lsp_store
5872 .update(cx, |lsp_store, _| {
5873 let lsp_data = lsp_store.lsp_code_lens.entry(buffer_id).or_default();
5874 if lsp_data.lens_for_version == query_version_queried_for {
5875 lsp_data.lens.extend(fetched_lens.clone());
5876 } else if !lsp_data
5877 .lens_for_version
5878 .changed_since(&query_version_queried_for)
5879 {
5880 lsp_data.lens_for_version = query_version_queried_for;
5881 lsp_data.lens = fetched_lens.clone();
5882 }
5883 lsp_data.update = None;
5884 lsp_data.lens.values().flatten().cloned().collect()
5885 })
5886 .map_err(Arc::new)
5887 })
5888 .shared();
5889 lsp_data.update = Some((version_queried_for, new_task.clone()));
5890 new_task
5891 }
5892
5893 fn fetch_code_lens(
5894 &mut self,
5895 buffer: &Entity<Buffer>,
5896 cx: &mut Context<Self>,
5897 ) -> Task<Result<HashMap<LanguageServerId, Vec<CodeAction>>>> {
5898 if let Some((upstream_client, project_id)) = self.upstream_client() {
5899 let request = GetCodeLens;
5900 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5901 return Task::ready(Ok(HashMap::default()));
5902 }
5903 let request_task = upstream_client.request(proto::MultiLspQuery {
5904 buffer_id: buffer.read(cx).remote_id().into(),
5905 version: serialize_version(&buffer.read(cx).version()),
5906 project_id,
5907 strategy: Some(proto::multi_lsp_query::Strategy::All(
5908 proto::AllLanguageServers {},
5909 )),
5910 request: Some(proto::multi_lsp_query::Request::GetCodeLens(
5911 request.to_proto(project_id, buffer.read(cx)),
5912 )),
5913 });
5914 let buffer = buffer.clone();
5915 cx.spawn(async move |weak_lsp_store, cx| {
5916 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5917 return Ok(HashMap::default());
5918 };
5919 let responses = request_task.await?.responses;
5920 let code_lens_actions = join_all(
5921 responses
5922 .into_iter()
5923 .filter_map(|lsp_response| {
5924 let response = match lsp_response.response? {
5925 proto::lsp_response::Response::GetCodeLensResponse(response) => {
5926 Some(response)
5927 }
5928 unexpected => {
5929 debug_panic!("Unexpected response: {unexpected:?}");
5930 None
5931 }
5932 }?;
5933 let server_id = LanguageServerId::from_proto(lsp_response.server_id);
5934 Some((server_id, response))
5935 })
5936 .map(|(server_id, code_lens_response)| {
5937 let lsp_store = lsp_store.clone();
5938 let buffer = buffer.clone();
5939 let cx = cx.clone();
5940 async move {
5941 (
5942 server_id,
5943 GetCodeLens
5944 .response_from_proto(
5945 code_lens_response,
5946 lsp_store,
5947 buffer,
5948 cx,
5949 )
5950 .await,
5951 )
5952 }
5953 }),
5954 )
5955 .await;
5956
5957 let mut has_errors = false;
5958 let code_lens_actions = code_lens_actions
5959 .into_iter()
5960 .filter_map(|(server_id, code_lens)| match code_lens {
5961 Ok(code_lens) => Some((server_id, code_lens)),
5962 Err(e) => {
5963 has_errors = true;
5964 log::error!("{e:#}");
5965 None
5966 }
5967 })
5968 .collect::<HashMap<_, _>>();
5969 anyhow::ensure!(
5970 !has_errors || !code_lens_actions.is_empty(),
5971 "Failed to fetch code lens"
5972 );
5973 Ok(code_lens_actions)
5974 })
5975 } else {
5976 let code_lens_actions_task =
5977 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
5978 cx.background_spawn(
5979 async move { Ok(code_lens_actions_task.await.into_iter().collect()) },
5980 )
5981 }
5982 }
5983
5984 #[inline(never)]
5985 pub fn completions(
5986 &self,
5987 buffer: &Entity<Buffer>,
5988 position: PointUtf16,
5989 context: CompletionContext,
5990 cx: &mut Context<Self>,
5991 ) -> Task<Result<Vec<CompletionResponse>>> {
5992 let language_registry = self.languages.clone();
5993
5994 if let Some((upstream_client, project_id)) = self.upstream_client() {
5995 let request = GetCompletions { position, context };
5996 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5997 return Task::ready(Ok(Vec::new()));
5998 }
5999 let task = self.send_lsp_proto_request(
6000 buffer.clone(),
6001 upstream_client,
6002 project_id,
6003 request,
6004 cx,
6005 );
6006 let language = buffer.read(cx).language().cloned();
6007
6008 // In the future, we should provide project guests with the names of LSP adapters,
6009 // so that they can use the correct LSP adapter when computing labels. For now,
6010 // guests just use the first LSP adapter associated with the buffer's language.
6011 let lsp_adapter = language.as_ref().and_then(|language| {
6012 language_registry
6013 .lsp_adapters(&language.name())
6014 .first()
6015 .cloned()
6016 });
6017
6018 cx.foreground_executor().spawn(async move {
6019 let completion_response = task.await?;
6020 let completions = populate_labels_for_completions(
6021 completion_response.completions,
6022 language,
6023 lsp_adapter,
6024 )
6025 .await;
6026 Ok(vec![CompletionResponse {
6027 completions,
6028 is_incomplete: completion_response.is_incomplete,
6029 }])
6030 })
6031 } else if let Some(local) = self.as_local() {
6032 let snapshot = buffer.read(cx).snapshot();
6033 let offset = position.to_offset(&snapshot);
6034 let scope = snapshot.language_scope_at(offset);
6035 let language = snapshot.language().cloned();
6036 let completion_settings = language_settings(
6037 language.as_ref().map(|language| language.name()),
6038 buffer.read(cx).file(),
6039 cx,
6040 )
6041 .completions;
6042 if !completion_settings.lsp {
6043 return Task::ready(Ok(Vec::new()));
6044 }
6045
6046 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6047 local
6048 .language_servers_for_buffer(buffer, cx)
6049 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6050 .filter(|(adapter, _)| {
6051 scope
6052 .as_ref()
6053 .map(|scope| scope.language_allowed(&adapter.name))
6054 .unwrap_or(true)
6055 })
6056 .map(|(_, server)| server.server_id())
6057 .collect()
6058 });
6059
6060 let buffer = buffer.clone();
6061 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6062 let lsp_timeout = if lsp_timeout > 0 {
6063 Some(Duration::from_millis(lsp_timeout))
6064 } else {
6065 None
6066 };
6067 cx.spawn(async move |this, cx| {
6068 let mut tasks = Vec::with_capacity(server_ids.len());
6069 this.update(cx, |lsp_store, cx| {
6070 for server_id in server_ids {
6071 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6072 let lsp_timeout = lsp_timeout
6073 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6074 let mut timeout = cx.background_spawn(async move {
6075 match lsp_timeout {
6076 Some(lsp_timeout) => {
6077 lsp_timeout.await;
6078 true
6079 },
6080 None => false,
6081 }
6082 }).fuse();
6083 let mut lsp_request = lsp_store.request_lsp(
6084 buffer.clone(),
6085 LanguageServerToQuery::Other(server_id),
6086 GetCompletions {
6087 position,
6088 context: context.clone(),
6089 },
6090 cx,
6091 ).fuse();
6092 let new_task = cx.background_spawn(async move {
6093 select_biased! {
6094 response = lsp_request => anyhow::Ok(Some(response?)),
6095 timeout_happened = timeout => {
6096 if timeout_happened {
6097 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6098 Ok(None)
6099 } else {
6100 let completions = lsp_request.await?;
6101 Ok(Some(completions))
6102 }
6103 },
6104 }
6105 });
6106 tasks.push((lsp_adapter, new_task));
6107 }
6108 })?;
6109
6110 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6111 let completion_response = task.await.ok()??;
6112 let completions = populate_labels_for_completions(
6113 completion_response.completions,
6114 language.clone(),
6115 lsp_adapter,
6116 )
6117 .await;
6118 Some(CompletionResponse {
6119 completions,
6120 is_incomplete: completion_response.is_incomplete,
6121 })
6122 });
6123
6124 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6125
6126 Ok(responses.into_iter().flatten().collect())
6127 })
6128 } else {
6129 Task::ready(Err(anyhow!("No upstream client or local language server")))
6130 }
6131 }
6132
6133 pub fn resolve_completions(
6134 &self,
6135 buffer: Entity<Buffer>,
6136 completion_indices: Vec<usize>,
6137 completions: Rc<RefCell<Box<[Completion]>>>,
6138 cx: &mut Context<Self>,
6139 ) -> Task<Result<bool>> {
6140 let client = self.upstream_client();
6141 let buffer_id = buffer.read(cx).remote_id();
6142 let buffer_snapshot = buffer.read(cx).snapshot();
6143
6144 if !self.check_if_capable_for_proto_request(
6145 &buffer,
6146 GetCompletions::can_resolve_completions,
6147 cx,
6148 ) {
6149 return Task::ready(Ok(false));
6150 }
6151 cx.spawn(async move |lsp_store, cx| {
6152 let mut did_resolve = false;
6153 if let Some((client, project_id)) = client {
6154 for completion_index in completion_indices {
6155 let server_id = {
6156 let completion = &completions.borrow()[completion_index];
6157 completion.source.server_id()
6158 };
6159 if let Some(server_id) = server_id {
6160 if Self::resolve_completion_remote(
6161 project_id,
6162 server_id,
6163 buffer_id,
6164 completions.clone(),
6165 completion_index,
6166 client.clone(),
6167 )
6168 .await
6169 .log_err()
6170 .is_some()
6171 {
6172 did_resolve = true;
6173 }
6174 } else {
6175 resolve_word_completion(
6176 &buffer_snapshot,
6177 &mut completions.borrow_mut()[completion_index],
6178 );
6179 }
6180 }
6181 } else {
6182 for completion_index in completion_indices {
6183 let server_id = {
6184 let completion = &completions.borrow()[completion_index];
6185 completion.source.server_id()
6186 };
6187 if let Some(server_id) = server_id {
6188 let server_and_adapter = lsp_store
6189 .read_with(cx, |lsp_store, _| {
6190 let server = lsp_store.language_server_for_id(server_id)?;
6191 let adapter =
6192 lsp_store.language_server_adapter_for_id(server.server_id())?;
6193 Some((server, adapter))
6194 })
6195 .ok()
6196 .flatten();
6197 let Some((server, adapter)) = server_and_adapter else {
6198 continue;
6199 };
6200
6201 let resolved = Self::resolve_completion_local(
6202 server,
6203 completions.clone(),
6204 completion_index,
6205 )
6206 .await
6207 .log_err()
6208 .is_some();
6209 if resolved {
6210 Self::regenerate_completion_labels(
6211 adapter,
6212 &buffer_snapshot,
6213 completions.clone(),
6214 completion_index,
6215 )
6216 .await
6217 .log_err();
6218 did_resolve = true;
6219 }
6220 } else {
6221 resolve_word_completion(
6222 &buffer_snapshot,
6223 &mut completions.borrow_mut()[completion_index],
6224 );
6225 }
6226 }
6227 }
6228
6229 Ok(did_resolve)
6230 })
6231 }
6232
6233 async fn resolve_completion_local(
6234 server: Arc<lsp::LanguageServer>,
6235 completions: Rc<RefCell<Box<[Completion]>>>,
6236 completion_index: usize,
6237 ) -> Result<()> {
6238 let server_id = server.server_id();
6239 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6240 return Ok(());
6241 }
6242
6243 let request = {
6244 let completion = &completions.borrow()[completion_index];
6245 match &completion.source {
6246 CompletionSource::Lsp {
6247 lsp_completion,
6248 resolved,
6249 server_id: completion_server_id,
6250 ..
6251 } => {
6252 if *resolved {
6253 return Ok(());
6254 }
6255 anyhow::ensure!(
6256 server_id == *completion_server_id,
6257 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6258 );
6259 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6260 }
6261 CompletionSource::BufferWord { .. }
6262 | CompletionSource::Dap { .. }
6263 | CompletionSource::Custom => {
6264 return Ok(());
6265 }
6266 }
6267 };
6268 let resolved_completion = request
6269 .await
6270 .into_response()
6271 .context("resolve completion")?;
6272
6273 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6274 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6275
6276 let mut completions = completions.borrow_mut();
6277 let completion = &mut completions[completion_index];
6278 if let CompletionSource::Lsp {
6279 lsp_completion,
6280 resolved,
6281 server_id: completion_server_id,
6282 ..
6283 } = &mut completion.source
6284 {
6285 if *resolved {
6286 return Ok(());
6287 }
6288 anyhow::ensure!(
6289 server_id == *completion_server_id,
6290 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6291 );
6292 *lsp_completion = Box::new(resolved_completion);
6293 *resolved = true;
6294 }
6295 Ok(())
6296 }
6297
6298 async fn regenerate_completion_labels(
6299 adapter: Arc<CachedLspAdapter>,
6300 snapshot: &BufferSnapshot,
6301 completions: Rc<RefCell<Box<[Completion]>>>,
6302 completion_index: usize,
6303 ) -> Result<()> {
6304 let completion_item = completions.borrow()[completion_index]
6305 .source
6306 .lsp_completion(true)
6307 .map(Cow::into_owned);
6308 if let Some(lsp_documentation) = completion_item
6309 .as_ref()
6310 .and_then(|completion_item| completion_item.documentation.clone())
6311 {
6312 let mut completions = completions.borrow_mut();
6313 let completion = &mut completions[completion_index];
6314 completion.documentation = Some(lsp_documentation.into());
6315 } else {
6316 let mut completions = completions.borrow_mut();
6317 let completion = &mut completions[completion_index];
6318 completion.documentation = Some(CompletionDocumentation::Undocumented);
6319 }
6320
6321 let mut new_label = match completion_item {
6322 Some(completion_item) => {
6323 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6324 // So we have to update the label here anyway...
6325 let language = snapshot.language();
6326 match language {
6327 Some(language) => {
6328 adapter
6329 .labels_for_completions(
6330 std::slice::from_ref(&completion_item),
6331 language,
6332 )
6333 .await?
6334 }
6335 None => Vec::new(),
6336 }
6337 .pop()
6338 .flatten()
6339 .unwrap_or_else(|| {
6340 CodeLabel::fallback_for_completion(
6341 &completion_item,
6342 language.map(|language| language.as_ref()),
6343 )
6344 })
6345 }
6346 None => CodeLabel::plain(
6347 completions.borrow()[completion_index].new_text.clone(),
6348 None,
6349 ),
6350 };
6351 ensure_uniform_list_compatible_label(&mut new_label);
6352
6353 let mut completions = completions.borrow_mut();
6354 let completion = &mut completions[completion_index];
6355 if completion.label.filter_text() == new_label.filter_text() {
6356 completion.label = new_label;
6357 } else {
6358 log::error!(
6359 "Resolved completion changed display label from {} to {}. \
6360 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6361 completion.label.text(),
6362 new_label.text(),
6363 completion.label.filter_text(),
6364 new_label.filter_text()
6365 );
6366 }
6367
6368 Ok(())
6369 }
6370
6371 async fn resolve_completion_remote(
6372 project_id: u64,
6373 server_id: LanguageServerId,
6374 buffer_id: BufferId,
6375 completions: Rc<RefCell<Box<[Completion]>>>,
6376 completion_index: usize,
6377 client: AnyProtoClient,
6378 ) -> Result<()> {
6379 let lsp_completion = {
6380 let completion = &completions.borrow()[completion_index];
6381 match &completion.source {
6382 CompletionSource::Lsp {
6383 lsp_completion,
6384 resolved,
6385 server_id: completion_server_id,
6386 ..
6387 } => {
6388 anyhow::ensure!(
6389 server_id == *completion_server_id,
6390 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6391 );
6392 if *resolved {
6393 return Ok(());
6394 }
6395 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6396 }
6397 CompletionSource::Custom
6398 | CompletionSource::Dap { .. }
6399 | CompletionSource::BufferWord { .. } => {
6400 return Ok(());
6401 }
6402 }
6403 };
6404 let request = proto::ResolveCompletionDocumentation {
6405 project_id,
6406 language_server_id: server_id.0 as u64,
6407 lsp_completion,
6408 buffer_id: buffer_id.into(),
6409 };
6410
6411 let response = client
6412 .request(request)
6413 .await
6414 .context("completion documentation resolve proto request")?;
6415 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6416
6417 let documentation = if response.documentation.is_empty() {
6418 CompletionDocumentation::Undocumented
6419 } else if response.documentation_is_markdown {
6420 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6421 } else if response.documentation.lines().count() <= 1 {
6422 CompletionDocumentation::SingleLine(response.documentation.into())
6423 } else {
6424 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6425 };
6426
6427 let mut completions = completions.borrow_mut();
6428 let completion = &mut completions[completion_index];
6429 completion.documentation = Some(documentation);
6430 if let CompletionSource::Lsp {
6431 insert_range,
6432 lsp_completion,
6433 resolved,
6434 server_id: completion_server_id,
6435 lsp_defaults: _,
6436 } = &mut completion.source
6437 {
6438 let completion_insert_range = response
6439 .old_insert_start
6440 .and_then(deserialize_anchor)
6441 .zip(response.old_insert_end.and_then(deserialize_anchor));
6442 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6443
6444 if *resolved {
6445 return Ok(());
6446 }
6447 anyhow::ensure!(
6448 server_id == *completion_server_id,
6449 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6450 );
6451 *lsp_completion = Box::new(resolved_lsp_completion);
6452 *resolved = true;
6453 }
6454
6455 let replace_range = response
6456 .old_replace_start
6457 .and_then(deserialize_anchor)
6458 .zip(response.old_replace_end.and_then(deserialize_anchor));
6459 if let Some((old_replace_start, old_replace_end)) = replace_range {
6460 if !response.new_text.is_empty() {
6461 completion.new_text = response.new_text;
6462 completion.replace_range = old_replace_start..old_replace_end;
6463 }
6464 }
6465
6466 Ok(())
6467 }
6468
6469 pub fn apply_additional_edits_for_completion(
6470 &self,
6471 buffer_handle: Entity<Buffer>,
6472 completions: Rc<RefCell<Box<[Completion]>>>,
6473 completion_index: usize,
6474 push_to_history: bool,
6475 cx: &mut Context<Self>,
6476 ) -> Task<Result<Option<Transaction>>> {
6477 if let Some((client, project_id)) = self.upstream_client() {
6478 let buffer = buffer_handle.read(cx);
6479 let buffer_id = buffer.remote_id();
6480 cx.spawn(async move |_, cx| {
6481 let request = {
6482 let completion = completions.borrow()[completion_index].clone();
6483 proto::ApplyCompletionAdditionalEdits {
6484 project_id,
6485 buffer_id: buffer_id.into(),
6486 completion: Some(Self::serialize_completion(&CoreCompletion {
6487 replace_range: completion.replace_range,
6488 new_text: completion.new_text,
6489 source: completion.source,
6490 })),
6491 }
6492 };
6493
6494 if let Some(transaction) = client.request(request).await?.transaction {
6495 let transaction = language::proto::deserialize_transaction(transaction)?;
6496 buffer_handle
6497 .update(cx, |buffer, _| {
6498 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6499 })?
6500 .await?;
6501 if push_to_history {
6502 buffer_handle.update(cx, |buffer, _| {
6503 buffer.push_transaction(transaction.clone(), Instant::now());
6504 buffer.finalize_last_transaction();
6505 })?;
6506 }
6507 Ok(Some(transaction))
6508 } else {
6509 Ok(None)
6510 }
6511 })
6512 } else {
6513 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6514 let completion = &completions.borrow()[completion_index];
6515 let server_id = completion.source.server_id()?;
6516 Some(
6517 self.language_server_for_local_buffer(buffer, server_id, cx)?
6518 .1
6519 .clone(),
6520 )
6521 }) else {
6522 return Task::ready(Ok(None));
6523 };
6524
6525 cx.spawn(async move |this, cx| {
6526 Self::resolve_completion_local(
6527 server.clone(),
6528 completions.clone(),
6529 completion_index,
6530 )
6531 .await
6532 .context("resolving completion")?;
6533 let completion = completions.borrow()[completion_index].clone();
6534 let additional_text_edits = completion
6535 .source
6536 .lsp_completion(true)
6537 .as_ref()
6538 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6539 if let Some(edits) = additional_text_edits {
6540 let edits = this
6541 .update(cx, |this, cx| {
6542 this.as_local_mut().unwrap().edits_from_lsp(
6543 &buffer_handle,
6544 edits,
6545 server.server_id(),
6546 None,
6547 cx,
6548 )
6549 })?
6550 .await?;
6551
6552 buffer_handle.update(cx, |buffer, cx| {
6553 buffer.finalize_last_transaction();
6554 buffer.start_transaction();
6555
6556 for (range, text) in edits {
6557 let primary = &completion.replace_range;
6558 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6559 && primary.end.cmp(&range.start, buffer).is_ge();
6560 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6561 && range.end.cmp(&primary.end, buffer).is_ge();
6562
6563 //Skip additional edits which overlap with the primary completion edit
6564 //https://github.com/zed-industries/zed/pull/1871
6565 if !start_within && !end_within {
6566 buffer.edit([(range, text)], None, cx);
6567 }
6568 }
6569
6570 let transaction = if buffer.end_transaction(cx).is_some() {
6571 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6572 if !push_to_history {
6573 buffer.forget_transaction(transaction.id);
6574 }
6575 Some(transaction)
6576 } else {
6577 None
6578 };
6579 Ok(transaction)
6580 })?
6581 } else {
6582 Ok(None)
6583 }
6584 })
6585 }
6586 }
6587
6588 pub fn pull_diagnostics(
6589 &mut self,
6590 buffer: Entity<Buffer>,
6591 cx: &mut Context<Self>,
6592 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6593 let buffer_id = buffer.read(cx).remote_id();
6594
6595 if let Some((client, upstream_project_id)) = self.upstream_client() {
6596 if !self.is_capable_for_proto_request(
6597 &buffer,
6598 &GetDocumentDiagnostics {
6599 previous_result_id: None,
6600 },
6601 cx,
6602 ) {
6603 return Task::ready(Ok(None));
6604 }
6605 let request_task = client.request(proto::MultiLspQuery {
6606 buffer_id: buffer_id.to_proto(),
6607 version: serialize_version(&buffer.read(cx).version()),
6608 project_id: upstream_project_id,
6609 strategy: Some(proto::multi_lsp_query::Strategy::All(
6610 proto::AllLanguageServers {},
6611 )),
6612 request: Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(
6613 proto::GetDocumentDiagnostics {
6614 project_id: upstream_project_id,
6615 buffer_id: buffer_id.to_proto(),
6616 version: serialize_version(&buffer.read(cx).version()),
6617 },
6618 )),
6619 });
6620 cx.background_spawn(async move {
6621 let _proto_responses = request_task
6622 .await?
6623 .responses
6624 .into_iter()
6625 .filter_map(|lsp_response| match lsp_response.response? {
6626 proto::lsp_response::Response::GetDocumentDiagnosticsResponse(response) => {
6627 Some(response)
6628 }
6629 unexpected => {
6630 debug_panic!("Unexpected response: {unexpected:?}");
6631 None
6632 }
6633 })
6634 .collect::<Vec<_>>();
6635 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6636 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6637 // Do not attempt to further process the dummy responses here.
6638 Ok(None)
6639 })
6640 } else {
6641 let server_ids = buffer.update(cx, |buffer, cx| {
6642 self.language_servers_for_local_buffer(buffer, cx)
6643 .map(|(_, server)| server.server_id())
6644 .collect::<Vec<_>>()
6645 });
6646 let pull_diagnostics = server_ids
6647 .into_iter()
6648 .map(|server_id| {
6649 let result_id = self.result_id(server_id, buffer_id, cx);
6650 self.request_lsp(
6651 buffer.clone(),
6652 LanguageServerToQuery::Other(server_id),
6653 GetDocumentDiagnostics {
6654 previous_result_id: result_id,
6655 },
6656 cx,
6657 )
6658 })
6659 .collect::<Vec<_>>();
6660
6661 cx.background_spawn(async move {
6662 let mut responses = Vec::new();
6663 for diagnostics in join_all(pull_diagnostics).await {
6664 responses.extend(diagnostics?);
6665 }
6666 Ok(Some(responses))
6667 })
6668 }
6669 }
6670
6671 pub fn inlay_hints(
6672 &mut self,
6673 buffer: Entity<Buffer>,
6674 range: Range<Anchor>,
6675 cx: &mut Context<Self>,
6676 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
6677 let range_start = range.start;
6678 let range_end = range.end;
6679 let buffer_id = buffer.read(cx).remote_id().into();
6680 let request = InlayHints { range };
6681
6682 if let Some((client, project_id)) = self.upstream_client() {
6683 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
6684 return Task::ready(Ok(Vec::new()));
6685 }
6686 let proto_request = proto::InlayHints {
6687 project_id,
6688 buffer_id,
6689 start: Some(serialize_anchor(&range_start)),
6690 end: Some(serialize_anchor(&range_end)),
6691 version: serialize_version(&buffer.read(cx).version()),
6692 };
6693 cx.spawn(async move |project, cx| {
6694 let response = client
6695 .request(proto_request)
6696 .await
6697 .context("inlay hints proto request")?;
6698 LspCommand::response_from_proto(
6699 request,
6700 response,
6701 project.upgrade().context("No project")?,
6702 buffer.clone(),
6703 cx.clone(),
6704 )
6705 .await
6706 .context("inlay hints proto response conversion")
6707 })
6708 } else {
6709 let lsp_request_task = self.request_lsp(
6710 buffer.clone(),
6711 LanguageServerToQuery::FirstCapable,
6712 request,
6713 cx,
6714 );
6715 cx.spawn(async move |_, cx| {
6716 buffer
6717 .update(cx, |buffer, _| {
6718 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
6719 })?
6720 .await
6721 .context("waiting for inlay hint request range edits")?;
6722 lsp_request_task.await.context("inlay hints LSP request")
6723 })
6724 }
6725 }
6726
6727 pub fn pull_diagnostics_for_buffer(
6728 &mut self,
6729 buffer: Entity<Buffer>,
6730 cx: &mut Context<Self>,
6731 ) -> Task<anyhow::Result<()>> {
6732 let diagnostics = self.pull_diagnostics(buffer, cx);
6733 cx.spawn(async move |lsp_store, cx| {
6734 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
6735 return Ok(());
6736 };
6737 lsp_store.update(cx, |lsp_store, cx| {
6738 if lsp_store.as_local().is_none() {
6739 return;
6740 }
6741
6742 let mut unchanged_buffers = HashSet::default();
6743 let mut changed_buffers = HashSet::default();
6744 let server_diagnostics_updates = diagnostics
6745 .into_iter()
6746 .filter_map(|diagnostics_set| match diagnostics_set {
6747 LspPullDiagnostics::Response {
6748 server_id,
6749 uri,
6750 diagnostics,
6751 } => Some((server_id, uri, diagnostics)),
6752 LspPullDiagnostics::Default => None,
6753 })
6754 .fold(
6755 HashMap::default(),
6756 |mut acc, (server_id, uri, diagnostics)| {
6757 let (result_id, diagnostics) = match diagnostics {
6758 PulledDiagnostics::Unchanged { result_id } => {
6759 unchanged_buffers.insert(uri.clone());
6760 (Some(result_id), Vec::new())
6761 }
6762 PulledDiagnostics::Changed {
6763 result_id,
6764 diagnostics,
6765 } => {
6766 changed_buffers.insert(uri.clone());
6767 (result_id, diagnostics)
6768 }
6769 };
6770 let disk_based_sources = Cow::Owned(
6771 lsp_store
6772 .language_server_adapter_for_id(server_id)
6773 .as_ref()
6774 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
6775 .unwrap_or(&[])
6776 .to_vec(),
6777 );
6778 acc.entry(server_id).or_insert_with(Vec::new).push(
6779 DocumentDiagnosticsUpdate {
6780 server_id,
6781 diagnostics: lsp::PublishDiagnosticsParams {
6782 uri,
6783 diagnostics,
6784 version: None,
6785 },
6786 result_id,
6787 disk_based_sources,
6788 },
6789 );
6790 acc
6791 },
6792 );
6793
6794 for diagnostic_updates in server_diagnostics_updates.into_values() {
6795 lsp_store
6796 .merge_lsp_diagnostics(
6797 DiagnosticSourceKind::Pulled,
6798 diagnostic_updates,
6799 |buffer, old_diagnostic, cx| {
6800 File::from_dyn(buffer.file())
6801 .and_then(|file| {
6802 let abs_path = file.as_local()?.abs_path(cx);
6803 lsp::Url::from_file_path(abs_path).ok()
6804 })
6805 .is_none_or(|buffer_uri| {
6806 unchanged_buffers.contains(&buffer_uri)
6807 || match old_diagnostic.source_kind {
6808 DiagnosticSourceKind::Pulled => {
6809 !changed_buffers.contains(&buffer_uri)
6810 }
6811 DiagnosticSourceKind::Other
6812 | DiagnosticSourceKind::Pushed => true,
6813 }
6814 })
6815 },
6816 cx,
6817 )
6818 .log_err();
6819 }
6820 })
6821 })
6822 }
6823
6824 pub fn document_colors(
6825 &mut self,
6826 fetch_strategy: LspFetchStrategy,
6827 buffer: Entity<Buffer>,
6828 cx: &mut Context<Self>,
6829 ) -> Option<DocumentColorTask> {
6830 let version_queried_for = buffer.read(cx).version();
6831 let buffer_id = buffer.read(cx).remote_id();
6832
6833 match fetch_strategy {
6834 LspFetchStrategy::IgnoreCache => {}
6835 LspFetchStrategy::UseCache {
6836 known_cache_version,
6837 } => {
6838 if let Some(cached_data) = self.lsp_document_colors.get(&buffer_id) {
6839 if !version_queried_for.changed_since(&cached_data.colors_for_version) {
6840 let has_different_servers = self.as_local().is_some_and(|local| {
6841 local
6842 .buffers_opened_in_servers
6843 .get(&buffer_id)
6844 .cloned()
6845 .unwrap_or_default()
6846 != cached_data.colors.keys().copied().collect()
6847 });
6848 if !has_different_servers {
6849 if Some(cached_data.cache_version) == known_cache_version {
6850 return None;
6851 } else {
6852 return Some(
6853 Task::ready(Ok(DocumentColors {
6854 colors: cached_data
6855 .colors
6856 .values()
6857 .flatten()
6858 .cloned()
6859 .collect(),
6860 cache_version: Some(cached_data.cache_version),
6861 }))
6862 .shared(),
6863 );
6864 }
6865 }
6866 }
6867 }
6868 }
6869 }
6870
6871 let lsp_data = self.lsp_document_colors.entry(buffer_id).or_default();
6872 if let Some((updating_for, running_update)) = &lsp_data.colors_update {
6873 if !version_queried_for.changed_since(&updating_for) {
6874 return Some(running_update.clone());
6875 }
6876 }
6877 let query_version_queried_for = version_queried_for.clone();
6878 let new_task = cx
6879 .spawn(async move |lsp_store, cx| {
6880 cx.background_executor()
6881 .timer(Duration::from_millis(30))
6882 .await;
6883 let fetched_colors = lsp_store
6884 .update(cx, |lsp_store, cx| {
6885 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
6886 })?
6887 .await
6888 .context("fetching document colors")
6889 .map_err(Arc::new);
6890 let fetched_colors = match fetched_colors {
6891 Ok(fetched_colors) => {
6892 if fetch_strategy != LspFetchStrategy::IgnoreCache
6893 && Some(true)
6894 == buffer
6895 .update(cx, |buffer, _| {
6896 buffer.version() != query_version_queried_for
6897 })
6898 .ok()
6899 {
6900 return Ok(DocumentColors::default());
6901 }
6902 fetched_colors
6903 }
6904 Err(e) => {
6905 lsp_store
6906 .update(cx, |lsp_store, _| {
6907 lsp_store
6908 .lsp_document_colors
6909 .entry(buffer_id)
6910 .or_default()
6911 .colors_update = None;
6912 })
6913 .ok();
6914 return Err(e);
6915 }
6916 };
6917
6918 lsp_store
6919 .update(cx, |lsp_store, _| {
6920 let lsp_data = lsp_store.lsp_document_colors.entry(buffer_id).or_default();
6921
6922 if lsp_data.colors_for_version == query_version_queried_for {
6923 lsp_data.colors.extend(fetched_colors.clone());
6924 lsp_data.cache_version += 1;
6925 } else if !lsp_data
6926 .colors_for_version
6927 .changed_since(&query_version_queried_for)
6928 {
6929 lsp_data.colors_for_version = query_version_queried_for;
6930 lsp_data.colors = fetched_colors.clone();
6931 lsp_data.cache_version += 1;
6932 }
6933 lsp_data.colors_update = None;
6934 let colors = lsp_data
6935 .colors
6936 .values()
6937 .flatten()
6938 .cloned()
6939 .collect::<HashSet<_>>();
6940 DocumentColors {
6941 colors,
6942 cache_version: Some(lsp_data.cache_version),
6943 }
6944 })
6945 .map_err(Arc::new)
6946 })
6947 .shared();
6948 lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
6949 Some(new_task)
6950 }
6951
6952 fn fetch_document_colors_for_buffer(
6953 &mut self,
6954 buffer: &Entity<Buffer>,
6955 cx: &mut Context<Self>,
6956 ) -> Task<anyhow::Result<HashMap<LanguageServerId, HashSet<DocumentColor>>>> {
6957 if let Some((client, project_id)) = self.upstream_client() {
6958 let request = GetDocumentColor {};
6959 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6960 return Task::ready(Ok(HashMap::default()));
6961 }
6962
6963 let request_task = client.request(proto::MultiLspQuery {
6964 project_id,
6965 buffer_id: buffer.read(cx).remote_id().to_proto(),
6966 version: serialize_version(&buffer.read(cx).version()),
6967 strategy: Some(proto::multi_lsp_query::Strategy::All(
6968 proto::AllLanguageServers {},
6969 )),
6970 request: Some(proto::multi_lsp_query::Request::GetDocumentColor(
6971 request.to_proto(project_id, buffer.read(cx)),
6972 )),
6973 });
6974 let buffer = buffer.clone();
6975 cx.spawn(async move |project, cx| {
6976 let Some(project) = project.upgrade() else {
6977 return Ok(HashMap::default());
6978 };
6979 let colors = join_all(
6980 request_task
6981 .await
6982 .log_err()
6983 .map(|response| response.responses)
6984 .unwrap_or_default()
6985 .into_iter()
6986 .filter_map(|lsp_response| match lsp_response.response? {
6987 proto::lsp_response::Response::GetDocumentColorResponse(response) => {
6988 Some((
6989 LanguageServerId::from_proto(lsp_response.server_id),
6990 response,
6991 ))
6992 }
6993 unexpected => {
6994 debug_panic!("Unexpected response: {unexpected:?}");
6995 None
6996 }
6997 })
6998 .map(|(server_id, color_response)| {
6999 let response = request.response_from_proto(
7000 color_response,
7001 project.clone(),
7002 buffer.clone(),
7003 cx.clone(),
7004 );
7005 async move { (server_id, response.await.log_err().unwrap_or_default()) }
7006 }),
7007 )
7008 .await
7009 .into_iter()
7010 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7011 acc.entry(server_id)
7012 .or_insert_with(HashSet::default)
7013 .extend(colors);
7014 acc
7015 });
7016 Ok(colors)
7017 })
7018 } else {
7019 let document_colors_task =
7020 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7021 cx.background_spawn(async move {
7022 Ok(document_colors_task
7023 .await
7024 .into_iter()
7025 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7026 acc.entry(server_id)
7027 .or_insert_with(HashSet::default)
7028 .extend(colors);
7029 acc
7030 })
7031 .into_iter()
7032 .collect())
7033 })
7034 }
7035 }
7036
7037 pub fn signature_help<T: ToPointUtf16>(
7038 &mut self,
7039 buffer: &Entity<Buffer>,
7040 position: T,
7041 cx: &mut Context<Self>,
7042 ) -> Task<Vec<SignatureHelp>> {
7043 let position = position.to_point_utf16(buffer.read(cx));
7044
7045 if let Some((client, upstream_project_id)) = self.upstream_client() {
7046 let request = GetSignatureHelp { position };
7047 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7048 return Task::ready(Vec::new());
7049 }
7050 let request_task = client.request(proto::MultiLspQuery {
7051 buffer_id: buffer.read(cx).remote_id().into(),
7052 version: serialize_version(&buffer.read(cx).version()),
7053 project_id: upstream_project_id,
7054 strategy: Some(proto::multi_lsp_query::Strategy::All(
7055 proto::AllLanguageServers {},
7056 )),
7057 request: Some(proto::multi_lsp_query::Request::GetSignatureHelp(
7058 request.to_proto(upstream_project_id, buffer.read(cx)),
7059 )),
7060 });
7061 let buffer = buffer.clone();
7062 cx.spawn(async move |weak_project, cx| {
7063 let Some(project) = weak_project.upgrade() else {
7064 return Vec::new();
7065 };
7066 join_all(
7067 request_task
7068 .await
7069 .log_err()
7070 .map(|response| response.responses)
7071 .unwrap_or_default()
7072 .into_iter()
7073 .filter_map(|lsp_response| match lsp_response.response? {
7074 proto::lsp_response::Response::GetSignatureHelpResponse(response) => {
7075 Some(response)
7076 }
7077 unexpected => {
7078 debug_panic!("Unexpected response: {unexpected:?}");
7079 None
7080 }
7081 })
7082 .map(|signature_response| {
7083 let response = GetSignatureHelp { position }.response_from_proto(
7084 signature_response,
7085 project.clone(),
7086 buffer.clone(),
7087 cx.clone(),
7088 );
7089 async move { response.await.log_err().flatten() }
7090 }),
7091 )
7092 .await
7093 .into_iter()
7094 .flatten()
7095 .collect()
7096 })
7097 } else {
7098 let all_actions_task = self.request_multiple_lsp_locally(
7099 buffer,
7100 Some(position),
7101 GetSignatureHelp { position },
7102 cx,
7103 );
7104 cx.background_spawn(async move {
7105 all_actions_task
7106 .await
7107 .into_iter()
7108 .flat_map(|(_, actions)| actions)
7109 .collect::<Vec<_>>()
7110 })
7111 }
7112 }
7113
7114 pub fn hover(
7115 &mut self,
7116 buffer: &Entity<Buffer>,
7117 position: PointUtf16,
7118 cx: &mut Context<Self>,
7119 ) -> Task<Vec<Hover>> {
7120 if let Some((client, upstream_project_id)) = self.upstream_client() {
7121 let request = GetHover { position };
7122 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7123 return Task::ready(Vec::new());
7124 }
7125 let request_task = client.request(proto::MultiLspQuery {
7126 buffer_id: buffer.read(cx).remote_id().into(),
7127 version: serialize_version(&buffer.read(cx).version()),
7128 project_id: upstream_project_id,
7129 strategy: Some(proto::multi_lsp_query::Strategy::All(
7130 proto::AllLanguageServers {},
7131 )),
7132 request: Some(proto::multi_lsp_query::Request::GetHover(
7133 request.to_proto(upstream_project_id, buffer.read(cx)),
7134 )),
7135 });
7136 let buffer = buffer.clone();
7137 cx.spawn(async move |weak_project, cx| {
7138 let Some(project) = weak_project.upgrade() else {
7139 return Vec::new();
7140 };
7141 join_all(
7142 request_task
7143 .await
7144 .log_err()
7145 .map(|response| response.responses)
7146 .unwrap_or_default()
7147 .into_iter()
7148 .filter_map(|lsp_response| match lsp_response.response? {
7149 proto::lsp_response::Response::GetHoverResponse(response) => {
7150 Some(response)
7151 }
7152 unexpected => {
7153 debug_panic!("Unexpected response: {unexpected:?}");
7154 None
7155 }
7156 })
7157 .map(|hover_response| {
7158 let response = GetHover { position }.response_from_proto(
7159 hover_response,
7160 project.clone(),
7161 buffer.clone(),
7162 cx.clone(),
7163 );
7164 async move {
7165 response
7166 .await
7167 .log_err()
7168 .flatten()
7169 .and_then(remove_empty_hover_blocks)
7170 }
7171 }),
7172 )
7173 .await
7174 .into_iter()
7175 .flatten()
7176 .collect()
7177 })
7178 } else {
7179 let all_actions_task = self.request_multiple_lsp_locally(
7180 buffer,
7181 Some(position),
7182 GetHover { position },
7183 cx,
7184 );
7185 cx.background_spawn(async move {
7186 all_actions_task
7187 .await
7188 .into_iter()
7189 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7190 .collect::<Vec<Hover>>()
7191 })
7192 }
7193 }
7194
7195 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7196 let language_registry = self.languages.clone();
7197
7198 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7199 let request = upstream_client.request(proto::GetProjectSymbols {
7200 project_id: *project_id,
7201 query: query.to_string(),
7202 });
7203 cx.foreground_executor().spawn(async move {
7204 let response = request.await?;
7205 let mut symbols = Vec::new();
7206 let core_symbols = response
7207 .symbols
7208 .into_iter()
7209 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7210 .collect::<Vec<_>>();
7211 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7212 .await;
7213 Ok(symbols)
7214 })
7215 } else if let Some(local) = self.as_local() {
7216 struct WorkspaceSymbolsResult {
7217 server_id: LanguageServerId,
7218 lsp_adapter: Arc<CachedLspAdapter>,
7219 worktree: WeakEntity<Worktree>,
7220 worktree_abs_path: Arc<Path>,
7221 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7222 }
7223
7224 let mut requests = Vec::new();
7225 let mut requested_servers = BTreeSet::new();
7226 'next_server: for ((worktree_id, _), server_ids) in local.language_server_ids.iter() {
7227 let Some(worktree_handle) = self
7228 .worktree_store
7229 .read(cx)
7230 .worktree_for_id(*worktree_id, cx)
7231 else {
7232 continue;
7233 };
7234 let worktree = worktree_handle.read(cx);
7235 if !worktree.is_visible() {
7236 continue;
7237 }
7238
7239 let mut servers_to_query = server_ids
7240 .difference(&requested_servers)
7241 .cloned()
7242 .collect::<BTreeSet<_>>();
7243 for server_id in &servers_to_query {
7244 let (lsp_adapter, server) = match local.language_servers.get(server_id) {
7245 Some(LanguageServerState::Running {
7246 adapter, server, ..
7247 }) => (adapter.clone(), server),
7248
7249 _ => continue 'next_server,
7250 };
7251 let supports_workspace_symbol_request =
7252 match server.capabilities().workspace_symbol_provider {
7253 Some(OneOf::Left(supported)) => supported,
7254 Some(OneOf::Right(_)) => true,
7255 None => false,
7256 };
7257 if !supports_workspace_symbol_request {
7258 continue 'next_server;
7259 }
7260 let worktree_abs_path = worktree.abs_path().clone();
7261 let worktree_handle = worktree_handle.clone();
7262 let server_id = server.server_id();
7263 requests.push(
7264 server
7265 .request::<lsp::request::WorkspaceSymbolRequest>(
7266 lsp::WorkspaceSymbolParams {
7267 query: query.to_string(),
7268 ..Default::default()
7269 },
7270 )
7271 .map(move |response| {
7272 let lsp_symbols = response.into_response()
7273 .context("workspace symbols request")
7274 .log_err()
7275 .flatten()
7276 .map(|symbol_response| match symbol_response {
7277 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7278 flat_responses.into_iter().map(|lsp_symbol| {
7279 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7280 }).collect::<Vec<_>>()
7281 }
7282 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7283 nested_responses.into_iter().filter_map(|lsp_symbol| {
7284 let location = match lsp_symbol.location {
7285 OneOf::Left(location) => location,
7286 OneOf::Right(_) => {
7287 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7288 return None
7289 }
7290 };
7291 Some((lsp_symbol.name, lsp_symbol.kind, location))
7292 }).collect::<Vec<_>>()
7293 }
7294 }).unwrap_or_default();
7295
7296 WorkspaceSymbolsResult {
7297 server_id,
7298 lsp_adapter,
7299 worktree: worktree_handle.downgrade(),
7300 worktree_abs_path,
7301 lsp_symbols,
7302 }
7303 }),
7304 );
7305 }
7306 requested_servers.append(&mut servers_to_query);
7307 }
7308
7309 cx.spawn(async move |this, cx| {
7310 let responses = futures::future::join_all(requests).await;
7311 let this = match this.upgrade() {
7312 Some(this) => this,
7313 None => return Ok(Vec::new()),
7314 };
7315
7316 let mut symbols = Vec::new();
7317 for result in responses {
7318 let core_symbols = this.update(cx, |this, cx| {
7319 result
7320 .lsp_symbols
7321 .into_iter()
7322 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7323 let abs_path = symbol_location.uri.to_file_path().ok()?;
7324 let source_worktree = result.worktree.upgrade()?;
7325 let source_worktree_id = source_worktree.read(cx).id();
7326
7327 let path;
7328 let worktree;
7329 if let Some((tree, rel_path)) =
7330 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7331 {
7332 worktree = tree;
7333 path = rel_path;
7334 } else {
7335 worktree = source_worktree.clone();
7336 path = relativize_path(&result.worktree_abs_path, &abs_path);
7337 }
7338
7339 let worktree_id = worktree.read(cx).id();
7340 let project_path = ProjectPath {
7341 worktree_id,
7342 path: path.into(),
7343 };
7344 let signature = this.symbol_signature(&project_path);
7345 Some(CoreSymbol {
7346 source_language_server_id: result.server_id,
7347 language_server_name: result.lsp_adapter.name.clone(),
7348 source_worktree_id,
7349 path: project_path,
7350 kind: symbol_kind,
7351 name: symbol_name,
7352 range: range_from_lsp(symbol_location.range),
7353 signature,
7354 })
7355 })
7356 .collect()
7357 })?;
7358
7359 populate_labels_for_symbols(
7360 core_symbols,
7361 &language_registry,
7362 Some(result.lsp_adapter),
7363 &mut symbols,
7364 )
7365 .await;
7366 }
7367
7368 Ok(symbols)
7369 })
7370 } else {
7371 Task::ready(Err(anyhow!("No upstream client or local language server")))
7372 }
7373 }
7374
7375 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7376 let mut summary = DiagnosticSummary::default();
7377 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7378 summary.error_count += path_summary.error_count;
7379 summary.warning_count += path_summary.warning_count;
7380 }
7381 summary
7382 }
7383
7384 pub fn diagnostic_summaries<'a>(
7385 &'a self,
7386 include_ignored: bool,
7387 cx: &'a App,
7388 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7389 self.worktree_store
7390 .read(cx)
7391 .visible_worktrees(cx)
7392 .filter_map(|worktree| {
7393 let worktree = worktree.read(cx);
7394 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7395 })
7396 .flat_map(move |(worktree, summaries)| {
7397 let worktree_id = worktree.id();
7398 summaries
7399 .iter()
7400 .filter(move |(path, _)| {
7401 include_ignored
7402 || worktree
7403 .entry_for_path(path.as_ref())
7404 .map_or(false, |entry| !entry.is_ignored)
7405 })
7406 .flat_map(move |(path, summaries)| {
7407 summaries.iter().map(move |(server_id, summary)| {
7408 (
7409 ProjectPath {
7410 worktree_id,
7411 path: path.clone(),
7412 },
7413 *server_id,
7414 *summary,
7415 )
7416 })
7417 })
7418 })
7419 }
7420
7421 pub fn on_buffer_edited(
7422 &mut self,
7423 buffer: Entity<Buffer>,
7424 cx: &mut Context<Self>,
7425 ) -> Option<()> {
7426 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7427 Some(
7428 self.as_local()?
7429 .language_servers_for_buffer(buffer, cx)
7430 .map(|i| i.1.clone())
7431 .collect(),
7432 )
7433 })?;
7434
7435 let buffer = buffer.read(cx);
7436 let file = File::from_dyn(buffer.file())?;
7437 let abs_path = file.as_local()?.abs_path(cx);
7438 let uri = lsp::Url::from_file_path(abs_path).unwrap();
7439 let next_snapshot = buffer.text_snapshot();
7440 for language_server in language_servers {
7441 let language_server = language_server.clone();
7442
7443 let buffer_snapshots = self
7444 .as_local_mut()
7445 .unwrap()
7446 .buffer_snapshots
7447 .get_mut(&buffer.remote_id())
7448 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7449 let previous_snapshot = buffer_snapshots.last()?;
7450
7451 let build_incremental_change = || {
7452 buffer
7453 .edits_since::<Dimensions<PointUtf16, usize>>(
7454 previous_snapshot.snapshot.version(),
7455 )
7456 .map(|edit| {
7457 let edit_start = edit.new.start.0;
7458 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7459 let new_text = next_snapshot
7460 .text_for_range(edit.new.start.1..edit.new.end.1)
7461 .collect();
7462 lsp::TextDocumentContentChangeEvent {
7463 range: Some(lsp::Range::new(
7464 point_to_lsp(edit_start),
7465 point_to_lsp(edit_end),
7466 )),
7467 range_length: None,
7468 text: new_text,
7469 }
7470 })
7471 .collect()
7472 };
7473
7474 let document_sync_kind = language_server
7475 .capabilities()
7476 .text_document_sync
7477 .as_ref()
7478 .and_then(|sync| match sync {
7479 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7480 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7481 });
7482
7483 let content_changes: Vec<_> = match document_sync_kind {
7484 Some(lsp::TextDocumentSyncKind::FULL) => {
7485 vec![lsp::TextDocumentContentChangeEvent {
7486 range: None,
7487 range_length: None,
7488 text: next_snapshot.text(),
7489 }]
7490 }
7491 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7492 _ => {
7493 #[cfg(any(test, feature = "test-support"))]
7494 {
7495 build_incremental_change()
7496 }
7497
7498 #[cfg(not(any(test, feature = "test-support")))]
7499 {
7500 continue;
7501 }
7502 }
7503 };
7504
7505 let next_version = previous_snapshot.version + 1;
7506 buffer_snapshots.push(LspBufferSnapshot {
7507 version: next_version,
7508 snapshot: next_snapshot.clone(),
7509 });
7510
7511 language_server
7512 .notify::<lsp::notification::DidChangeTextDocument>(
7513 &lsp::DidChangeTextDocumentParams {
7514 text_document: lsp::VersionedTextDocumentIdentifier::new(
7515 uri.clone(),
7516 next_version,
7517 ),
7518 content_changes,
7519 },
7520 )
7521 .ok();
7522 self.pull_workspace_diagnostics(language_server.server_id());
7523 }
7524
7525 None
7526 }
7527
7528 pub fn on_buffer_saved(
7529 &mut self,
7530 buffer: Entity<Buffer>,
7531 cx: &mut Context<Self>,
7532 ) -> Option<()> {
7533 let file = File::from_dyn(buffer.read(cx).file())?;
7534 let worktree_id = file.worktree_id(cx);
7535 let abs_path = file.as_local()?.abs_path(cx);
7536 let text_document = lsp::TextDocumentIdentifier {
7537 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7538 };
7539 let local = self.as_local()?;
7540
7541 for server in local.language_servers_for_worktree(worktree_id) {
7542 if let Some(include_text) = include_text(server.as_ref()) {
7543 let text = if include_text {
7544 Some(buffer.read(cx).text())
7545 } else {
7546 None
7547 };
7548 server
7549 .notify::<lsp::notification::DidSaveTextDocument>(
7550 &lsp::DidSaveTextDocumentParams {
7551 text_document: text_document.clone(),
7552 text,
7553 },
7554 )
7555 .ok();
7556 }
7557 }
7558
7559 let language_servers = buffer.update(cx, |buffer, cx| {
7560 local.language_server_ids_for_buffer(buffer, cx)
7561 });
7562 for language_server_id in language_servers {
7563 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7564 }
7565
7566 None
7567 }
7568
7569 pub(crate) async fn refresh_workspace_configurations(
7570 lsp_store: &WeakEntity<Self>,
7571 fs: Arc<dyn Fs>,
7572 cx: &mut AsyncApp,
7573 ) {
7574 maybe!(async move {
7575 let mut refreshed_servers = HashSet::default();
7576 let servers = lsp_store
7577 .update(cx, |lsp_store, cx| {
7578 let toolchain_store = lsp_store.toolchain_store(cx);
7579 let Some(local) = lsp_store.as_local() else {
7580 return Vec::default();
7581 };
7582 local
7583 .language_server_ids
7584 .iter()
7585 .flat_map(|((worktree_id, _), server_ids)| {
7586 let worktree = lsp_store
7587 .worktree_store
7588 .read(cx)
7589 .worktree_for_id(*worktree_id, cx);
7590 let delegate = worktree.map(|worktree| {
7591 LocalLspAdapterDelegate::new(
7592 local.languages.clone(),
7593 &local.environment,
7594 cx.weak_entity(),
7595 &worktree,
7596 local.http_client.clone(),
7597 local.fs.clone(),
7598 cx,
7599 )
7600 });
7601
7602 let fs = fs.clone();
7603 let toolchain_store = toolchain_store.clone();
7604 server_ids.iter().filter_map(|server_id| {
7605 let delegate = delegate.clone()? as Arc<dyn LspAdapterDelegate>;
7606 let states = local.language_servers.get(server_id)?;
7607
7608 match states {
7609 LanguageServerState::Starting { .. } => None,
7610 LanguageServerState::Running {
7611 adapter, server, ..
7612 } => {
7613 let fs = fs.clone();
7614 let toolchain_store = toolchain_store.clone();
7615 let adapter = adapter.clone();
7616 let server = server.clone();
7617 refreshed_servers.insert(server.name());
7618 Some(cx.spawn(async move |_, cx| {
7619 let settings =
7620 LocalLspStore::workspace_configuration_for_adapter(
7621 adapter.adapter.clone(),
7622 fs.as_ref(),
7623 &delegate,
7624 toolchain_store,
7625 cx,
7626 )
7627 .await
7628 .ok()?;
7629 server
7630 .notify::<lsp::notification::DidChangeConfiguration>(
7631 &lsp::DidChangeConfigurationParams { settings },
7632 )
7633 .ok()?;
7634 Some(())
7635 }))
7636 }
7637 }
7638 }).collect::<Vec<_>>()
7639 })
7640 .collect::<Vec<_>>()
7641 })
7642 .ok()?;
7643
7644 log::info!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7645 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7646 // to stop and unregister its language server wrapper.
7647 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7648 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7649 let _: Vec<Option<()>> = join_all(servers).await;
7650 Some(())
7651 })
7652 .await;
7653 }
7654
7655 fn toolchain_store(&self, cx: &App) -> Arc<dyn LanguageToolchainStore> {
7656 if let Some(toolchain_store) = self.toolchain_store.as_ref() {
7657 toolchain_store.read(cx).as_language_toolchain_store()
7658 } else {
7659 Arc::new(EmptyToolchainStore)
7660 }
7661 }
7662 fn maintain_workspace_config(
7663 fs: Arc<dyn Fs>,
7664 external_refresh_requests: watch::Receiver<()>,
7665 cx: &mut Context<Self>,
7666 ) -> Task<Result<()>> {
7667 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
7668 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
7669
7670 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
7671 *settings_changed_tx.borrow_mut() = ();
7672 });
7673
7674 let mut joint_future =
7675 futures::stream::select(settings_changed_rx, external_refresh_requests);
7676 cx.spawn(async move |this, cx| {
7677 while let Some(()) = joint_future.next().await {
7678 Self::refresh_workspace_configurations(&this, fs.clone(), cx).await;
7679 }
7680
7681 drop(settings_observation);
7682 anyhow::Ok(())
7683 })
7684 }
7685
7686 pub fn language_servers_for_local_buffer<'a>(
7687 &'a self,
7688 buffer: &Buffer,
7689 cx: &mut App,
7690 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7691 let local = self.as_local();
7692 let language_server_ids = local
7693 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
7694 .unwrap_or_default();
7695
7696 language_server_ids
7697 .into_iter()
7698 .filter_map(
7699 move |server_id| match local?.language_servers.get(&server_id)? {
7700 LanguageServerState::Running {
7701 adapter, server, ..
7702 } => Some((adapter, server)),
7703 _ => None,
7704 },
7705 )
7706 }
7707
7708 pub fn language_server_for_local_buffer<'a>(
7709 &'a self,
7710 buffer: &'a Buffer,
7711 server_id: LanguageServerId,
7712 cx: &'a mut App,
7713 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
7714 self.as_local()?
7715 .language_servers_for_buffer(buffer, cx)
7716 .find(|(_, s)| s.server_id() == server_id)
7717 }
7718
7719 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
7720 self.diagnostic_summaries.remove(&id_to_remove);
7721 if let Some(local) = self.as_local_mut() {
7722 let to_remove = local.remove_worktree(id_to_remove, cx);
7723 for server in to_remove {
7724 self.language_server_statuses.remove(&server);
7725 }
7726 }
7727 }
7728
7729 pub fn shared(
7730 &mut self,
7731 project_id: u64,
7732 downstream_client: AnyProtoClient,
7733 _: &mut Context<Self>,
7734 ) {
7735 self.downstream_client = Some((downstream_client.clone(), project_id));
7736
7737 for (server_id, status) in &self.language_server_statuses {
7738 if let Some(server) = self.language_server_for_id(*server_id) {
7739 downstream_client
7740 .send(proto::StartLanguageServer {
7741 project_id,
7742 server: Some(proto::LanguageServer {
7743 id: server_id.to_proto(),
7744 name: status.name.to_string(),
7745 worktree_id: None,
7746 }),
7747 capabilities: serde_json::to_string(&server.capabilities())
7748 .expect("serializing server LSP capabilities"),
7749 })
7750 .log_err();
7751 }
7752 }
7753 }
7754
7755 pub fn disconnected_from_host(&mut self) {
7756 self.downstream_client.take();
7757 }
7758
7759 pub fn disconnected_from_ssh_remote(&mut self) {
7760 if let LspStoreMode::Remote(RemoteLspStore {
7761 upstream_client, ..
7762 }) = &mut self.mode
7763 {
7764 upstream_client.take();
7765 }
7766 }
7767
7768 pub(crate) fn set_language_server_statuses_from_proto(
7769 &mut self,
7770 language_servers: Vec<proto::LanguageServer>,
7771 ) {
7772 self.language_server_statuses = language_servers
7773 .into_iter()
7774 .map(|server| {
7775 (
7776 LanguageServerId(server.id as usize),
7777 LanguageServerStatus {
7778 name: LanguageServerName::from_proto(server.name),
7779 pending_work: Default::default(),
7780 has_pending_diagnostic_updates: false,
7781 progress_tokens: Default::default(),
7782 },
7783 )
7784 })
7785 .collect();
7786 }
7787
7788 fn register_local_language_server(
7789 &mut self,
7790 worktree: Entity<Worktree>,
7791 language_server_name: LanguageServerName,
7792 language_server_id: LanguageServerId,
7793 cx: &mut App,
7794 ) {
7795 let Some(local) = self.as_local_mut() else {
7796 return;
7797 };
7798
7799 let worktree_id = worktree.read(cx).id();
7800 if worktree.read(cx).is_visible() {
7801 let path = ProjectPath {
7802 worktree_id,
7803 path: Arc::from("".as_ref()),
7804 };
7805 let delegate = Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
7806 local.lsp_tree.update(cx, |language_server_tree, cx| {
7807 for node in language_server_tree.get(
7808 path,
7809 AdapterQuery::Adapter(&language_server_name),
7810 delegate,
7811 cx,
7812 ) {
7813 node.server_id_or_init(|disposition| {
7814 assert_eq!(disposition.server_name, &language_server_name);
7815
7816 language_server_id
7817 });
7818 }
7819 });
7820 }
7821
7822 local
7823 .language_server_ids
7824 .entry((worktree_id, language_server_name))
7825 .or_default()
7826 .insert(language_server_id);
7827 }
7828
7829 #[cfg(test)]
7830 pub fn update_diagnostic_entries(
7831 &mut self,
7832 server_id: LanguageServerId,
7833 abs_path: PathBuf,
7834 result_id: Option<String>,
7835 version: Option<i32>,
7836 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7837 cx: &mut Context<Self>,
7838 ) -> anyhow::Result<()> {
7839 self.merge_diagnostic_entries(
7840 vec![DocumentDiagnosticsUpdate {
7841 diagnostics: DocumentDiagnostics {
7842 diagnostics,
7843 document_abs_path: abs_path,
7844 version,
7845 },
7846 result_id,
7847 server_id,
7848 disk_based_sources: Cow::Borrowed(&[]),
7849 }],
7850 |_, _, _| false,
7851 cx,
7852 )?;
7853 Ok(())
7854 }
7855
7856 pub fn merge_diagnostic_entries<'a>(
7857 &mut self,
7858 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
7859 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
7860 cx: &mut Context<Self>,
7861 ) -> anyhow::Result<()> {
7862 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
7863 let mut updated_diagnostics_paths = HashMap::default();
7864 for mut update in diagnostic_updates {
7865 let abs_path = &update.diagnostics.document_abs_path;
7866 let server_id = update.server_id;
7867 let Some((worktree, relative_path)) =
7868 self.worktree_store.read(cx).find_worktree(abs_path, cx)
7869 else {
7870 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
7871 return Ok(());
7872 };
7873
7874 let worktree_id = worktree.read(cx).id();
7875 let project_path = ProjectPath {
7876 worktree_id,
7877 path: relative_path.into(),
7878 };
7879
7880 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
7881 let snapshot = buffer_handle.read(cx).snapshot();
7882 let buffer = buffer_handle.read(cx);
7883 let reused_diagnostics = buffer
7884 .get_diagnostics(server_id)
7885 .into_iter()
7886 .flat_map(|diag| {
7887 diag.iter()
7888 .filter(|v| merge(buffer, &v.diagnostic, cx))
7889 .map(|v| {
7890 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
7891 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
7892 DiagnosticEntry {
7893 range: start..end,
7894 diagnostic: v.diagnostic.clone(),
7895 }
7896 })
7897 })
7898 .collect::<Vec<_>>();
7899
7900 self.as_local_mut()
7901 .context("cannot merge diagnostics on a remote LspStore")?
7902 .update_buffer_diagnostics(
7903 &buffer_handle,
7904 server_id,
7905 update.result_id,
7906 update.diagnostics.version,
7907 update.diagnostics.diagnostics.clone(),
7908 reused_diagnostics.clone(),
7909 cx,
7910 )?;
7911
7912 update.diagnostics.diagnostics.extend(reused_diagnostics);
7913 }
7914
7915 let updated = worktree.update(cx, |worktree, cx| {
7916 self.update_worktree_diagnostics(
7917 worktree.id(),
7918 server_id,
7919 project_path.path.clone(),
7920 update.diagnostics.diagnostics,
7921 cx,
7922 )
7923 })?;
7924 match updated {
7925 ControlFlow::Continue(new_summary) => {
7926 if let Some((project_id, new_summary)) = new_summary {
7927 match &mut diagnostics_summary {
7928 Some(diagnostics_summary) => {
7929 diagnostics_summary
7930 .more_summaries
7931 .push(proto::DiagnosticSummary {
7932 path: project_path.path.as_ref().to_proto(),
7933 language_server_id: server_id.0 as u64,
7934 error_count: new_summary.error_count,
7935 warning_count: new_summary.warning_count,
7936 })
7937 }
7938 None => {
7939 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
7940 project_id: project_id,
7941 worktree_id: worktree_id.to_proto(),
7942 summary: Some(proto::DiagnosticSummary {
7943 path: project_path.path.as_ref().to_proto(),
7944 language_server_id: server_id.0 as u64,
7945 error_count: new_summary.error_count,
7946 warning_count: new_summary.warning_count,
7947 }),
7948 more_summaries: Vec::new(),
7949 })
7950 }
7951 }
7952 }
7953 updated_diagnostics_paths
7954 .entry(server_id)
7955 .or_insert_with(Vec::new)
7956 .push(project_path);
7957 }
7958 ControlFlow::Break(()) => {}
7959 }
7960 }
7961
7962 if let Some((diagnostics_summary, (downstream_client, _))) =
7963 diagnostics_summary.zip(self.downstream_client.as_ref())
7964 {
7965 downstream_client.send(diagnostics_summary).log_err();
7966 }
7967 for (server_id, paths) in updated_diagnostics_paths {
7968 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
7969 }
7970 Ok(())
7971 }
7972
7973 fn update_worktree_diagnostics(
7974 &mut self,
7975 worktree_id: WorktreeId,
7976 server_id: LanguageServerId,
7977 path_in_worktree: Arc<Path>,
7978 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
7979 _: &mut Context<Worktree>,
7980 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
7981 let local = match &mut self.mode {
7982 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
7983 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
7984 };
7985
7986 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
7987 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
7988 let summaries_by_server_id = summaries_for_tree
7989 .entry(path_in_worktree.clone())
7990 .or_default();
7991
7992 let old_summary = summaries_by_server_id
7993 .remove(&server_id)
7994 .unwrap_or_default();
7995
7996 let new_summary = DiagnosticSummary::new(&diagnostics);
7997 if new_summary.is_empty() {
7998 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
7999 {
8000 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8001 diagnostics_by_server_id.remove(ix);
8002 }
8003 if diagnostics_by_server_id.is_empty() {
8004 diagnostics_for_tree.remove(&path_in_worktree);
8005 }
8006 }
8007 } else {
8008 summaries_by_server_id.insert(server_id, new_summary);
8009 let diagnostics_by_server_id = diagnostics_for_tree
8010 .entry(path_in_worktree.clone())
8011 .or_default();
8012 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8013 Ok(ix) => {
8014 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8015 }
8016 Err(ix) => {
8017 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8018 }
8019 }
8020 }
8021
8022 if !old_summary.is_empty() || !new_summary.is_empty() {
8023 if let Some((_, project_id)) = &self.downstream_client {
8024 Ok(ControlFlow::Continue(Some((
8025 *project_id,
8026 proto::DiagnosticSummary {
8027 path: path_in_worktree.to_proto(),
8028 language_server_id: server_id.0 as u64,
8029 error_count: new_summary.error_count as u32,
8030 warning_count: new_summary.warning_count as u32,
8031 },
8032 ))))
8033 } else {
8034 Ok(ControlFlow::Continue(None))
8035 }
8036 } else {
8037 Ok(ControlFlow::Break(()))
8038 }
8039 }
8040
8041 pub fn open_buffer_for_symbol(
8042 &mut self,
8043 symbol: &Symbol,
8044 cx: &mut Context<Self>,
8045 ) -> Task<Result<Entity<Buffer>>> {
8046 if let Some((client, project_id)) = self.upstream_client() {
8047 let request = client.request(proto::OpenBufferForSymbol {
8048 project_id,
8049 symbol: Some(Self::serialize_symbol(symbol)),
8050 });
8051 cx.spawn(async move |this, cx| {
8052 let response = request.await?;
8053 let buffer_id = BufferId::new(response.buffer_id)?;
8054 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8055 .await
8056 })
8057 } else if let Some(local) = self.as_local() {
8058 let Some(language_server_id) = local
8059 .language_server_ids
8060 .get(&(
8061 symbol.source_worktree_id,
8062 symbol.language_server_name.clone(),
8063 ))
8064 .and_then(|ids| {
8065 ids.contains(&symbol.source_language_server_id)
8066 .then_some(symbol.source_language_server_id)
8067 })
8068 else {
8069 return Task::ready(Err(anyhow!(
8070 "language server for worktree and language not found"
8071 )));
8072 };
8073
8074 let worktree_abs_path = if let Some(worktree_abs_path) = self
8075 .worktree_store
8076 .read(cx)
8077 .worktree_for_id(symbol.path.worktree_id, cx)
8078 .map(|worktree| worktree.read(cx).abs_path())
8079 {
8080 worktree_abs_path
8081 } else {
8082 return Task::ready(Err(anyhow!("worktree not found for symbol")));
8083 };
8084
8085 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
8086 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
8087 uri
8088 } else {
8089 return Task::ready(Err(anyhow!("invalid symbol path")));
8090 };
8091
8092 self.open_local_buffer_via_lsp(
8093 symbol_uri,
8094 language_server_id,
8095 symbol.language_server_name.clone(),
8096 cx,
8097 )
8098 } else {
8099 Task::ready(Err(anyhow!("no upstream client or local store")))
8100 }
8101 }
8102
8103 pub fn open_local_buffer_via_lsp(
8104 &mut self,
8105 mut abs_path: lsp::Url,
8106 language_server_id: LanguageServerId,
8107 language_server_name: LanguageServerName,
8108 cx: &mut Context<Self>,
8109 ) -> Task<Result<Entity<Buffer>>> {
8110 cx.spawn(async move |lsp_store, cx| {
8111 // Escape percent-encoded string.
8112 let current_scheme = abs_path.scheme().to_owned();
8113 let _ = abs_path.set_scheme("file");
8114
8115 let abs_path = abs_path
8116 .to_file_path()
8117 .map_err(|()| anyhow!("can't convert URI to path"))?;
8118 let p = abs_path.clone();
8119 let yarn_worktree = lsp_store
8120 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8121 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8122 cx.spawn(async move |this, cx| {
8123 let t = this
8124 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8125 .ok()?;
8126 t.await
8127 })
8128 }),
8129 None => Task::ready(None),
8130 })?
8131 .await;
8132 let (worktree_root_target, known_relative_path) =
8133 if let Some((zip_root, relative_path)) = yarn_worktree {
8134 (zip_root, Some(relative_path))
8135 } else {
8136 (Arc::<Path>::from(abs_path.as_path()), None)
8137 };
8138 let (worktree, relative_path) = if let Some(result) =
8139 lsp_store.update(cx, |lsp_store, cx| {
8140 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8141 worktree_store.find_worktree(&worktree_root_target, cx)
8142 })
8143 })? {
8144 let relative_path =
8145 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
8146 (result.0, relative_path)
8147 } else {
8148 let worktree = lsp_store
8149 .update(cx, |lsp_store, cx| {
8150 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8151 worktree_store.create_worktree(&worktree_root_target, false, cx)
8152 })
8153 })?
8154 .await?;
8155 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8156 lsp_store
8157 .update(cx, |lsp_store, cx| {
8158 lsp_store.register_local_language_server(
8159 worktree.clone(),
8160 language_server_name,
8161 language_server_id,
8162 cx,
8163 )
8164 })
8165 .ok();
8166 }
8167 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8168 let relative_path = if let Some(known_path) = known_relative_path {
8169 known_path
8170 } else {
8171 abs_path.strip_prefix(worktree_root)?.into()
8172 };
8173 (worktree, relative_path)
8174 };
8175 let project_path = ProjectPath {
8176 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8177 path: relative_path,
8178 };
8179 lsp_store
8180 .update(cx, |lsp_store, cx| {
8181 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8182 buffer_store.open_buffer(project_path, cx)
8183 })
8184 })?
8185 .await
8186 })
8187 }
8188
8189 fn request_multiple_lsp_locally<P, R>(
8190 &mut self,
8191 buffer: &Entity<Buffer>,
8192 position: Option<P>,
8193 request: R,
8194 cx: &mut Context<Self>,
8195 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8196 where
8197 P: ToOffset,
8198 R: LspCommand + Clone,
8199 <R::LspRequest as lsp::request::Request>::Result: Send,
8200 <R::LspRequest as lsp::request::Request>::Params: Send,
8201 {
8202 let Some(local) = self.as_local() else {
8203 return Task::ready(Vec::new());
8204 };
8205
8206 let snapshot = buffer.read(cx).snapshot();
8207 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8208
8209 let server_ids = buffer.update(cx, |buffer, cx| {
8210 local
8211 .language_servers_for_buffer(buffer, cx)
8212 .filter(|(adapter, _)| {
8213 scope
8214 .as_ref()
8215 .map(|scope| scope.language_allowed(&adapter.name))
8216 .unwrap_or(true)
8217 })
8218 .map(|(_, server)| server.server_id())
8219 .filter(|server_id| {
8220 self.as_local().is_none_or(|local| {
8221 local
8222 .buffers_opened_in_servers
8223 .get(&snapshot.remote_id())
8224 .is_some_and(|servers| servers.contains(server_id))
8225 })
8226 })
8227 .collect::<Vec<_>>()
8228 });
8229
8230 let mut response_results = server_ids
8231 .into_iter()
8232 .map(|server_id| {
8233 let task = self.request_lsp(
8234 buffer.clone(),
8235 LanguageServerToQuery::Other(server_id),
8236 request.clone(),
8237 cx,
8238 );
8239 async move { (server_id, task.await) }
8240 })
8241 .collect::<FuturesUnordered<_>>();
8242
8243 cx.background_spawn(async move {
8244 let mut responses = Vec::with_capacity(response_results.len());
8245 while let Some((server_id, response_result)) = response_results.next().await {
8246 if let Some(response) = response_result.log_err() {
8247 responses.push((server_id, response));
8248 }
8249 }
8250 responses
8251 })
8252 }
8253
8254 async fn handle_lsp_command<T: LspCommand>(
8255 this: Entity<Self>,
8256 envelope: TypedEnvelope<T::ProtoRequest>,
8257 mut cx: AsyncApp,
8258 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8259 where
8260 <T::LspRequest as lsp::request::Request>::Params: Send,
8261 <T::LspRequest as lsp::request::Request>::Result: Send,
8262 {
8263 let sender_id = envelope.original_sender_id().unwrap_or_default();
8264 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8265 let buffer_handle = this.update(&mut cx, |this, cx| {
8266 this.buffer_store.read(cx).get_existing(buffer_id)
8267 })??;
8268 let request = T::from_proto(
8269 envelope.payload,
8270 this.clone(),
8271 buffer_handle.clone(),
8272 cx.clone(),
8273 )
8274 .await?;
8275 let response = this
8276 .update(&mut cx, |this, cx| {
8277 this.request_lsp(
8278 buffer_handle.clone(),
8279 LanguageServerToQuery::FirstCapable,
8280 request,
8281 cx,
8282 )
8283 })?
8284 .await?;
8285 this.update(&mut cx, |this, cx| {
8286 Ok(T::response_to_proto(
8287 response,
8288 this,
8289 sender_id,
8290 &buffer_handle.read(cx).version(),
8291 cx,
8292 ))
8293 })?
8294 }
8295
8296 async fn handle_multi_lsp_query(
8297 lsp_store: Entity<Self>,
8298 envelope: TypedEnvelope<proto::MultiLspQuery>,
8299 mut cx: AsyncApp,
8300 ) -> Result<proto::MultiLspQueryResponse> {
8301 let response_from_ssh = lsp_store.read_with(&mut cx, |this, _| {
8302 let (upstream_client, project_id) = this.upstream_client()?;
8303 let mut payload = envelope.payload.clone();
8304 payload.project_id = project_id;
8305
8306 Some(upstream_client.request(payload))
8307 })?;
8308 if let Some(response_from_ssh) = response_from_ssh {
8309 return response_from_ssh.await;
8310 }
8311
8312 let sender_id = envelope.original_sender_id().unwrap_or_default();
8313 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8314 let version = deserialize_version(&envelope.payload.version);
8315 let buffer = lsp_store.update(&mut cx, |this, cx| {
8316 this.buffer_store.read(cx).get_existing(buffer_id)
8317 })??;
8318 buffer
8319 .update(&mut cx, |buffer, _| {
8320 buffer.wait_for_version(version.clone())
8321 })?
8322 .await?;
8323 let buffer_version = buffer.read_with(&mut cx, |buffer, _| buffer.version())?;
8324 match envelope
8325 .payload
8326 .strategy
8327 .context("invalid request without the strategy")?
8328 {
8329 proto::multi_lsp_query::Strategy::All(_) => {
8330 // currently, there's only one multiple language servers query strategy,
8331 // so just ensure it's specified correctly
8332 }
8333 }
8334 match envelope.payload.request {
8335 Some(proto::multi_lsp_query::Request::GetHover(message)) => {
8336 buffer
8337 .update(&mut cx, |buffer, _| {
8338 buffer.wait_for_version(deserialize_version(&message.version))
8339 })?
8340 .await?;
8341 let get_hover =
8342 GetHover::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8343 .await?;
8344 let all_hovers = lsp_store
8345 .update(&mut cx, |this, cx| {
8346 this.request_multiple_lsp_locally(
8347 &buffer,
8348 Some(get_hover.position),
8349 get_hover,
8350 cx,
8351 )
8352 })?
8353 .await
8354 .into_iter()
8355 .filter_map(|(server_id, hover)| {
8356 Some((server_id, remove_empty_hover_blocks(hover?)?))
8357 });
8358 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8359 responses: all_hovers
8360 .map(|(server_id, hover)| proto::LspResponse {
8361 server_id: server_id.to_proto(),
8362 response: Some(proto::lsp_response::Response::GetHoverResponse(
8363 GetHover::response_to_proto(
8364 Some(hover),
8365 project,
8366 sender_id,
8367 &buffer_version,
8368 cx,
8369 ),
8370 )),
8371 })
8372 .collect(),
8373 })
8374 }
8375 Some(proto::multi_lsp_query::Request::GetCodeActions(message)) => {
8376 buffer
8377 .update(&mut cx, |buffer, _| {
8378 buffer.wait_for_version(deserialize_version(&message.version))
8379 })?
8380 .await?;
8381 let get_code_actions = GetCodeActions::from_proto(
8382 message,
8383 lsp_store.clone(),
8384 buffer.clone(),
8385 cx.clone(),
8386 )
8387 .await?;
8388
8389 let all_actions = lsp_store
8390 .update(&mut cx, |project, cx| {
8391 project.request_multiple_lsp_locally(
8392 &buffer,
8393 Some(get_code_actions.range.start),
8394 get_code_actions,
8395 cx,
8396 )
8397 })?
8398 .await
8399 .into_iter();
8400
8401 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8402 responses: all_actions
8403 .map(|(server_id, code_actions)| proto::LspResponse {
8404 server_id: server_id.to_proto(),
8405 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
8406 GetCodeActions::response_to_proto(
8407 code_actions,
8408 project,
8409 sender_id,
8410 &buffer_version,
8411 cx,
8412 ),
8413 )),
8414 })
8415 .collect(),
8416 })
8417 }
8418 Some(proto::multi_lsp_query::Request::GetSignatureHelp(message)) => {
8419 buffer
8420 .update(&mut cx, |buffer, _| {
8421 buffer.wait_for_version(deserialize_version(&message.version))
8422 })?
8423 .await?;
8424 let get_signature_help = GetSignatureHelp::from_proto(
8425 message,
8426 lsp_store.clone(),
8427 buffer.clone(),
8428 cx.clone(),
8429 )
8430 .await?;
8431
8432 let all_signatures = lsp_store
8433 .update(&mut cx, |project, cx| {
8434 project.request_multiple_lsp_locally(
8435 &buffer,
8436 Some(get_signature_help.position),
8437 get_signature_help,
8438 cx,
8439 )
8440 })?
8441 .await
8442 .into_iter();
8443
8444 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8445 responses: all_signatures
8446 .map(|(server_id, signature_help)| proto::LspResponse {
8447 server_id: server_id.to_proto(),
8448 response: Some(
8449 proto::lsp_response::Response::GetSignatureHelpResponse(
8450 GetSignatureHelp::response_to_proto(
8451 signature_help,
8452 project,
8453 sender_id,
8454 &buffer_version,
8455 cx,
8456 ),
8457 ),
8458 ),
8459 })
8460 .collect(),
8461 })
8462 }
8463 Some(proto::multi_lsp_query::Request::GetCodeLens(message)) => {
8464 buffer
8465 .update(&mut cx, |buffer, _| {
8466 buffer.wait_for_version(deserialize_version(&message.version))
8467 })?
8468 .await?;
8469 let get_code_lens =
8470 GetCodeLens::from_proto(message, lsp_store.clone(), buffer.clone(), cx.clone())
8471 .await?;
8472
8473 let code_lens_actions = lsp_store
8474 .update(&mut cx, |project, cx| {
8475 project.request_multiple_lsp_locally(
8476 &buffer,
8477 None::<usize>,
8478 get_code_lens,
8479 cx,
8480 )
8481 })?
8482 .await
8483 .into_iter();
8484
8485 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8486 responses: code_lens_actions
8487 .map(|(server_id, actions)| proto::LspResponse {
8488 server_id: server_id.to_proto(),
8489 response: Some(proto::lsp_response::Response::GetCodeLensResponse(
8490 GetCodeLens::response_to_proto(
8491 actions,
8492 project,
8493 sender_id,
8494 &buffer_version,
8495 cx,
8496 ),
8497 )),
8498 })
8499 .collect(),
8500 })
8501 }
8502 Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(message)) => {
8503 buffer
8504 .update(&mut cx, |buffer, _| {
8505 buffer.wait_for_version(deserialize_version(&message.version))
8506 })?
8507 .await?;
8508 lsp_store
8509 .update(&mut cx, |lsp_store, cx| {
8510 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
8511 })?
8512 .await?;
8513 // `pull_diagnostics_for_buffer` will merge in the new diagnostics and send them to the client.
8514 // The client cannot merge anything into its non-local LspStore, so we do not need to return anything.
8515 Ok(proto::MultiLspQueryResponse {
8516 responses: Vec::new(),
8517 })
8518 }
8519 Some(proto::multi_lsp_query::Request::GetDocumentColor(message)) => {
8520 buffer
8521 .update(&mut cx, |buffer, _| {
8522 buffer.wait_for_version(deserialize_version(&message.version))
8523 })?
8524 .await?;
8525 let get_document_color = GetDocumentColor::from_proto(
8526 message,
8527 lsp_store.clone(),
8528 buffer.clone(),
8529 cx.clone(),
8530 )
8531 .await?;
8532
8533 let all_colors = lsp_store
8534 .update(&mut cx, |project, cx| {
8535 project.request_multiple_lsp_locally(
8536 &buffer,
8537 None::<usize>,
8538 get_document_color,
8539 cx,
8540 )
8541 })?
8542 .await
8543 .into_iter();
8544
8545 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8546 responses: all_colors
8547 .map(|(server_id, colors)| proto::LspResponse {
8548 server_id: server_id.to_proto(),
8549 response: Some(
8550 proto::lsp_response::Response::GetDocumentColorResponse(
8551 GetDocumentColor::response_to_proto(
8552 colors,
8553 project,
8554 sender_id,
8555 &buffer_version,
8556 cx,
8557 ),
8558 ),
8559 ),
8560 })
8561 .collect(),
8562 })
8563 }
8564 Some(proto::multi_lsp_query::Request::GetDefinition(message)) => {
8565 let get_definitions = GetDefinitions::from_proto(
8566 message,
8567 lsp_store.clone(),
8568 buffer.clone(),
8569 cx.clone(),
8570 )
8571 .await?;
8572
8573 let definitions = lsp_store
8574 .update(&mut cx, |project, cx| {
8575 project.request_multiple_lsp_locally(
8576 &buffer,
8577 Some(get_definitions.position),
8578 get_definitions,
8579 cx,
8580 )
8581 })?
8582 .await
8583 .into_iter();
8584
8585 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8586 responses: definitions
8587 .map(|(server_id, definitions)| proto::LspResponse {
8588 server_id: server_id.to_proto(),
8589 response: Some(proto::lsp_response::Response::GetDefinitionResponse(
8590 GetDefinitions::response_to_proto(
8591 definitions,
8592 project,
8593 sender_id,
8594 &buffer_version,
8595 cx,
8596 ),
8597 )),
8598 })
8599 .collect(),
8600 })
8601 }
8602 Some(proto::multi_lsp_query::Request::GetDeclaration(message)) => {
8603 let get_declarations = GetDeclarations::from_proto(
8604 message,
8605 lsp_store.clone(),
8606 buffer.clone(),
8607 cx.clone(),
8608 )
8609 .await?;
8610
8611 let declarations = lsp_store
8612 .update(&mut cx, |project, cx| {
8613 project.request_multiple_lsp_locally(
8614 &buffer,
8615 Some(get_declarations.position),
8616 get_declarations,
8617 cx,
8618 )
8619 })?
8620 .await
8621 .into_iter();
8622
8623 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8624 responses: declarations
8625 .map(|(server_id, declarations)| proto::LspResponse {
8626 server_id: server_id.to_proto(),
8627 response: Some(proto::lsp_response::Response::GetDeclarationResponse(
8628 GetDeclarations::response_to_proto(
8629 declarations,
8630 project,
8631 sender_id,
8632 &buffer_version,
8633 cx,
8634 ),
8635 )),
8636 })
8637 .collect(),
8638 })
8639 }
8640 Some(proto::multi_lsp_query::Request::GetTypeDefinition(message)) => {
8641 let get_type_definitions = GetTypeDefinitions::from_proto(
8642 message,
8643 lsp_store.clone(),
8644 buffer.clone(),
8645 cx.clone(),
8646 )
8647 .await?;
8648
8649 let type_definitions = lsp_store
8650 .update(&mut cx, |project, cx| {
8651 project.request_multiple_lsp_locally(
8652 &buffer,
8653 Some(get_type_definitions.position),
8654 get_type_definitions,
8655 cx,
8656 )
8657 })?
8658 .await
8659 .into_iter();
8660
8661 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8662 responses: type_definitions
8663 .map(|(server_id, type_definitions)| proto::LspResponse {
8664 server_id: server_id.to_proto(),
8665 response: Some(
8666 proto::lsp_response::Response::GetTypeDefinitionResponse(
8667 GetTypeDefinitions::response_to_proto(
8668 type_definitions,
8669 project,
8670 sender_id,
8671 &buffer_version,
8672 cx,
8673 ),
8674 ),
8675 ),
8676 })
8677 .collect(),
8678 })
8679 }
8680 Some(proto::multi_lsp_query::Request::GetImplementation(message)) => {
8681 let get_implementations = GetImplementations::from_proto(
8682 message,
8683 lsp_store.clone(),
8684 buffer.clone(),
8685 cx.clone(),
8686 )
8687 .await?;
8688
8689 let implementations = lsp_store
8690 .update(&mut cx, |project, cx| {
8691 project.request_multiple_lsp_locally(
8692 &buffer,
8693 Some(get_implementations.position),
8694 get_implementations,
8695 cx,
8696 )
8697 })?
8698 .await
8699 .into_iter();
8700
8701 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8702 responses: implementations
8703 .map(|(server_id, implementations)| proto::LspResponse {
8704 server_id: server_id.to_proto(),
8705 response: Some(
8706 proto::lsp_response::Response::GetImplementationResponse(
8707 GetImplementations::response_to_proto(
8708 implementations,
8709 project,
8710 sender_id,
8711 &buffer_version,
8712 cx,
8713 ),
8714 ),
8715 ),
8716 })
8717 .collect(),
8718 })
8719 }
8720 Some(proto::multi_lsp_query::Request::GetReferences(message)) => {
8721 let get_references = GetReferences::from_proto(
8722 message,
8723 lsp_store.clone(),
8724 buffer.clone(),
8725 cx.clone(),
8726 )
8727 .await?;
8728
8729 let references = lsp_store
8730 .update(&mut cx, |project, cx| {
8731 project.request_multiple_lsp_locally(
8732 &buffer,
8733 Some(get_references.position),
8734 get_references,
8735 cx,
8736 )
8737 })?
8738 .await
8739 .into_iter();
8740
8741 lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
8742 responses: references
8743 .map(|(server_id, references)| proto::LspResponse {
8744 server_id: server_id.to_proto(),
8745 response: Some(proto::lsp_response::Response::GetReferencesResponse(
8746 GetReferences::response_to_proto(
8747 references,
8748 project,
8749 sender_id,
8750 &buffer_version,
8751 cx,
8752 ),
8753 )),
8754 })
8755 .collect(),
8756 })
8757 }
8758 None => anyhow::bail!("empty multi lsp query request"),
8759 }
8760 }
8761
8762 async fn handle_apply_code_action(
8763 this: Entity<Self>,
8764 envelope: TypedEnvelope<proto::ApplyCodeAction>,
8765 mut cx: AsyncApp,
8766 ) -> Result<proto::ApplyCodeActionResponse> {
8767 let sender_id = envelope.original_sender_id().unwrap_or_default();
8768 let action =
8769 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
8770 let apply_code_action = this.update(&mut cx, |this, cx| {
8771 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8772 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
8773 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
8774 })??;
8775
8776 let project_transaction = apply_code_action.await?;
8777 let project_transaction = this.update(&mut cx, |this, cx| {
8778 this.buffer_store.update(cx, |buffer_store, cx| {
8779 buffer_store.serialize_project_transaction_for_peer(
8780 project_transaction,
8781 sender_id,
8782 cx,
8783 )
8784 })
8785 })?;
8786 Ok(proto::ApplyCodeActionResponse {
8787 transaction: Some(project_transaction),
8788 })
8789 }
8790
8791 async fn handle_register_buffer_with_language_servers(
8792 this: Entity<Self>,
8793 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
8794 mut cx: AsyncApp,
8795 ) -> Result<proto::Ack> {
8796 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
8797 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
8798 this.update(&mut cx, |this, cx| {
8799 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
8800 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
8801 project_id: upstream_project_id,
8802 buffer_id: buffer_id.to_proto(),
8803 only_servers: envelope.payload.only_servers,
8804 });
8805 }
8806
8807 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
8808 anyhow::bail!("buffer is not open");
8809 };
8810
8811 let handle = this.register_buffer_with_language_servers(
8812 &buffer,
8813 envelope
8814 .payload
8815 .only_servers
8816 .into_iter()
8817 .filter_map(|selector| {
8818 Some(match selector.selector? {
8819 proto::language_server_selector::Selector::ServerId(server_id) => {
8820 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
8821 }
8822 proto::language_server_selector::Selector::Name(name) => {
8823 LanguageServerSelector::Name(LanguageServerName(
8824 SharedString::from(name),
8825 ))
8826 }
8827 })
8828 })
8829 .collect(),
8830 false,
8831 cx,
8832 );
8833 this.buffer_store().update(cx, |buffer_store, _| {
8834 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
8835 });
8836
8837 Ok(())
8838 })??;
8839 Ok(proto::Ack {})
8840 }
8841
8842 async fn handle_rename_project_entry(
8843 this: Entity<Self>,
8844 envelope: TypedEnvelope<proto::RenameProjectEntry>,
8845 mut cx: AsyncApp,
8846 ) -> Result<proto::ProjectEntryResponse> {
8847 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
8848 let (worktree_id, worktree, old_path, is_dir) = this
8849 .update(&mut cx, |this, cx| {
8850 this.worktree_store
8851 .read(cx)
8852 .worktree_and_entry_for_id(entry_id, cx)
8853 .map(|(worktree, entry)| {
8854 (
8855 worktree.read(cx).id(),
8856 worktree,
8857 entry.path.clone(),
8858 entry.is_dir(),
8859 )
8860 })
8861 })?
8862 .context("worktree not found")?;
8863 let (old_abs_path, new_abs_path) = {
8864 let root_path = worktree.read_with(&mut cx, |this, _| this.abs_path())?;
8865 let new_path = PathBuf::from_proto(envelope.payload.new_path.clone());
8866 (root_path.join(&old_path), root_path.join(&new_path))
8867 };
8868
8869 Self::will_rename_entry(
8870 this.downgrade(),
8871 worktree_id,
8872 &old_abs_path,
8873 &new_abs_path,
8874 is_dir,
8875 cx.clone(),
8876 )
8877 .await;
8878 let response = Worktree::handle_rename_entry(worktree, envelope.payload, cx.clone()).await;
8879 this.read_with(&mut cx, |this, _| {
8880 this.did_rename_entry(worktree_id, &old_abs_path, &new_abs_path, is_dir);
8881 })
8882 .ok();
8883 response
8884 }
8885
8886 async fn handle_update_diagnostic_summary(
8887 this: Entity<Self>,
8888 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
8889 mut cx: AsyncApp,
8890 ) -> Result<()> {
8891 this.update(&mut cx, |lsp_store, cx| {
8892 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
8893 let mut updated_diagnostics_paths = HashMap::default();
8894 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8895 for message_summary in envelope
8896 .payload
8897 .summary
8898 .into_iter()
8899 .chain(envelope.payload.more_summaries)
8900 {
8901 let project_path = ProjectPath {
8902 worktree_id,
8903 path: Arc::<Path>::from_proto(message_summary.path),
8904 };
8905 let path = project_path.path.clone();
8906 let server_id = LanguageServerId(message_summary.language_server_id as usize);
8907 let summary = DiagnosticSummary {
8908 error_count: message_summary.error_count as usize,
8909 warning_count: message_summary.warning_count as usize,
8910 };
8911
8912 if summary.is_empty() {
8913 if let Some(worktree_summaries) =
8914 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
8915 {
8916 if let Some(summaries) = worktree_summaries.get_mut(&path) {
8917 summaries.remove(&server_id);
8918 if summaries.is_empty() {
8919 worktree_summaries.remove(&path);
8920 }
8921 }
8922 }
8923 } else {
8924 lsp_store
8925 .diagnostic_summaries
8926 .entry(worktree_id)
8927 .or_default()
8928 .entry(path)
8929 .or_default()
8930 .insert(server_id, summary);
8931 }
8932
8933 if let Some((_, project_id)) = &lsp_store.downstream_client {
8934 match &mut diagnostics_summary {
8935 Some(diagnostics_summary) => {
8936 diagnostics_summary
8937 .more_summaries
8938 .push(proto::DiagnosticSummary {
8939 path: project_path.path.as_ref().to_proto(),
8940 language_server_id: server_id.0 as u64,
8941 error_count: summary.error_count as u32,
8942 warning_count: summary.warning_count as u32,
8943 })
8944 }
8945 None => {
8946 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8947 project_id: *project_id,
8948 worktree_id: worktree_id.to_proto(),
8949 summary: Some(proto::DiagnosticSummary {
8950 path: project_path.path.as_ref().to_proto(),
8951 language_server_id: server_id.0 as u64,
8952 error_count: summary.error_count as u32,
8953 warning_count: summary.warning_count as u32,
8954 }),
8955 more_summaries: Vec::new(),
8956 })
8957 }
8958 }
8959 }
8960 updated_diagnostics_paths
8961 .entry(server_id)
8962 .or_insert_with(Vec::new)
8963 .push(project_path);
8964 }
8965
8966 if let Some((diagnostics_summary, (downstream_client, _))) =
8967 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
8968 {
8969 downstream_client.send(diagnostics_summary).log_err();
8970 }
8971 for (server_id, paths) in updated_diagnostics_paths {
8972 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8973 }
8974 Ok(())
8975 })?
8976 }
8977
8978 async fn handle_start_language_server(
8979 lsp_store: Entity<Self>,
8980 envelope: TypedEnvelope<proto::StartLanguageServer>,
8981 mut cx: AsyncApp,
8982 ) -> Result<()> {
8983 let server = envelope.payload.server.context("invalid server")?;
8984 let server_capabilities =
8985 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
8986 .with_context(|| {
8987 format!(
8988 "incorrect server capabilities {}",
8989 envelope.payload.capabilities
8990 )
8991 })?;
8992 lsp_store.update(&mut cx, |lsp_store, cx| {
8993 let server_id = LanguageServerId(server.id as usize);
8994 let server_name = LanguageServerName::from_proto(server.name.clone());
8995 lsp_store
8996 .lsp_server_capabilities
8997 .insert(server_id, server_capabilities);
8998 lsp_store.language_server_statuses.insert(
8999 server_id,
9000 LanguageServerStatus {
9001 name: server_name.clone(),
9002 pending_work: Default::default(),
9003 has_pending_diagnostic_updates: false,
9004 progress_tokens: Default::default(),
9005 },
9006 );
9007 cx.emit(LspStoreEvent::LanguageServerAdded(
9008 server_id,
9009 server_name,
9010 server.worktree_id.map(WorktreeId::from_proto),
9011 ));
9012 cx.notify();
9013 })?;
9014 Ok(())
9015 }
9016
9017 async fn handle_update_language_server(
9018 lsp_store: Entity<Self>,
9019 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9020 mut cx: AsyncApp,
9021 ) -> Result<()> {
9022 lsp_store.update(&mut cx, |lsp_store, cx| {
9023 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9024
9025 match envelope.payload.variant.context("invalid variant")? {
9026 proto::update_language_server::Variant::WorkStart(payload) => {
9027 lsp_store.on_lsp_work_start(
9028 language_server_id,
9029 payload.token,
9030 LanguageServerProgress {
9031 title: payload.title,
9032 is_disk_based_diagnostics_progress: false,
9033 is_cancellable: payload.is_cancellable.unwrap_or(false),
9034 message: payload.message,
9035 percentage: payload.percentage.map(|p| p as usize),
9036 last_update_at: cx.background_executor().now(),
9037 },
9038 cx,
9039 );
9040 }
9041 proto::update_language_server::Variant::WorkProgress(payload) => {
9042 lsp_store.on_lsp_work_progress(
9043 language_server_id,
9044 payload.token,
9045 LanguageServerProgress {
9046 title: None,
9047 is_disk_based_diagnostics_progress: false,
9048 is_cancellable: payload.is_cancellable.unwrap_or(false),
9049 message: payload.message,
9050 percentage: payload.percentage.map(|p| p as usize),
9051 last_update_at: cx.background_executor().now(),
9052 },
9053 cx,
9054 );
9055 }
9056
9057 proto::update_language_server::Variant::WorkEnd(payload) => {
9058 lsp_store.on_lsp_work_end(language_server_id, payload.token, cx);
9059 }
9060
9061 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9062 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9063 }
9064
9065 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9066 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9067 }
9068
9069 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9070 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9071 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9072 cx.emit(LspStoreEvent::LanguageServerUpdate {
9073 language_server_id,
9074 name: envelope
9075 .payload
9076 .server_name
9077 .map(SharedString::new)
9078 .map(LanguageServerName),
9079 message: non_lsp,
9080 });
9081 }
9082 }
9083
9084 Ok(())
9085 })?
9086 }
9087
9088 async fn handle_language_server_log(
9089 this: Entity<Self>,
9090 envelope: TypedEnvelope<proto::LanguageServerLog>,
9091 mut cx: AsyncApp,
9092 ) -> Result<()> {
9093 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9094 let log_type = envelope
9095 .payload
9096 .log_type
9097 .map(LanguageServerLogType::from_proto)
9098 .context("invalid language server log type")?;
9099
9100 let message = envelope.payload.message;
9101
9102 this.update(&mut cx, |_, cx| {
9103 cx.emit(LspStoreEvent::LanguageServerLog(
9104 language_server_id,
9105 log_type,
9106 message,
9107 ));
9108 })
9109 }
9110
9111 async fn handle_lsp_ext_cancel_flycheck(
9112 lsp_store: Entity<Self>,
9113 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9114 mut cx: AsyncApp,
9115 ) -> Result<proto::Ack> {
9116 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9117 lsp_store.read_with(&mut cx, |lsp_store, _| {
9118 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9119 server
9120 .notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(&())
9121 .context("handling lsp ext cancel flycheck")
9122 } else {
9123 anyhow::Ok(())
9124 }
9125 })??;
9126
9127 Ok(proto::Ack {})
9128 }
9129
9130 async fn handle_lsp_ext_run_flycheck(
9131 lsp_store: Entity<Self>,
9132 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9133 mut cx: AsyncApp,
9134 ) -> Result<proto::Ack> {
9135 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9136 lsp_store.update(&mut cx, |lsp_store, cx| {
9137 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9138 let text_document = if envelope.payload.current_file_only {
9139 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9140 lsp_store
9141 .buffer_store()
9142 .read(cx)
9143 .get(buffer_id)
9144 .and_then(|buffer| Some(buffer.read(cx).file()?.as_local()?.abs_path(cx)))
9145 .map(|path| make_text_document_identifier(&path))
9146 .transpose()?
9147 } else {
9148 None
9149 };
9150 server
9151 .notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9152 &lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9153 )
9154 .context("handling lsp ext run flycheck")
9155 } else {
9156 anyhow::Ok(())
9157 }
9158 })??;
9159
9160 Ok(proto::Ack {})
9161 }
9162
9163 async fn handle_lsp_ext_clear_flycheck(
9164 lsp_store: Entity<Self>,
9165 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9166 mut cx: AsyncApp,
9167 ) -> Result<proto::Ack> {
9168 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9169 lsp_store.read_with(&mut cx, |lsp_store, _| {
9170 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9171 server
9172 .notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(&())
9173 .context("handling lsp ext clear flycheck")
9174 } else {
9175 anyhow::Ok(())
9176 }
9177 })??;
9178
9179 Ok(proto::Ack {})
9180 }
9181
9182 pub fn disk_based_diagnostics_started(
9183 &mut self,
9184 language_server_id: LanguageServerId,
9185 cx: &mut Context<Self>,
9186 ) {
9187 if let Some(language_server_status) =
9188 self.language_server_statuses.get_mut(&language_server_id)
9189 {
9190 language_server_status.has_pending_diagnostic_updates = true;
9191 }
9192
9193 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9194 cx.emit(LspStoreEvent::LanguageServerUpdate {
9195 language_server_id,
9196 name: self
9197 .language_server_adapter_for_id(language_server_id)
9198 .map(|adapter| adapter.name()),
9199 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9200 Default::default(),
9201 ),
9202 })
9203 }
9204
9205 pub fn disk_based_diagnostics_finished(
9206 &mut self,
9207 language_server_id: LanguageServerId,
9208 cx: &mut Context<Self>,
9209 ) {
9210 if let Some(language_server_status) =
9211 self.language_server_statuses.get_mut(&language_server_id)
9212 {
9213 language_server_status.has_pending_diagnostic_updates = false;
9214 }
9215
9216 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9217 cx.emit(LspStoreEvent::LanguageServerUpdate {
9218 language_server_id,
9219 name: self
9220 .language_server_adapter_for_id(language_server_id)
9221 .map(|adapter| adapter.name()),
9222 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9223 Default::default(),
9224 ),
9225 })
9226 }
9227
9228 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9229 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9230 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9231 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9232 // the language server might take some time to publish diagnostics.
9233 fn simulate_disk_based_diagnostics_events_if_needed(
9234 &mut self,
9235 language_server_id: LanguageServerId,
9236 cx: &mut Context<Self>,
9237 ) {
9238 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9239
9240 let Some(LanguageServerState::Running {
9241 simulate_disk_based_diagnostics_completion,
9242 adapter,
9243 ..
9244 }) = self
9245 .as_local_mut()
9246 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9247 else {
9248 return;
9249 };
9250
9251 if adapter.disk_based_diagnostics_progress_token.is_some() {
9252 return;
9253 }
9254
9255 let prev_task =
9256 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9257 cx.background_executor()
9258 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9259 .await;
9260
9261 this.update(cx, |this, cx| {
9262 this.disk_based_diagnostics_finished(language_server_id, cx);
9263
9264 if let Some(LanguageServerState::Running {
9265 simulate_disk_based_diagnostics_completion,
9266 ..
9267 }) = this.as_local_mut().and_then(|local_store| {
9268 local_store.language_servers.get_mut(&language_server_id)
9269 }) {
9270 *simulate_disk_based_diagnostics_completion = None;
9271 }
9272 })
9273 .ok();
9274 }));
9275
9276 if prev_task.is_none() {
9277 self.disk_based_diagnostics_started(language_server_id, cx);
9278 }
9279 }
9280
9281 pub fn language_server_statuses(
9282 &self,
9283 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9284 self.language_server_statuses
9285 .iter()
9286 .map(|(key, value)| (*key, value))
9287 }
9288
9289 pub(super) fn did_rename_entry(
9290 &self,
9291 worktree_id: WorktreeId,
9292 old_path: &Path,
9293 new_path: &Path,
9294 is_dir: bool,
9295 ) {
9296 maybe!({
9297 let local_store = self.as_local()?;
9298
9299 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from)?;
9300 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from)?;
9301
9302 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9303 let Some(filter) = local_store
9304 .language_server_paths_watched_for_rename
9305 .get(&language_server.server_id())
9306 else {
9307 continue;
9308 };
9309
9310 if filter.should_send_did_rename(&old_uri, is_dir) {
9311 language_server
9312 .notify::<DidRenameFiles>(&RenameFilesParams {
9313 files: vec![FileRename {
9314 old_uri: old_uri.clone(),
9315 new_uri: new_uri.clone(),
9316 }],
9317 })
9318 .ok();
9319 }
9320 }
9321 Some(())
9322 });
9323 }
9324
9325 pub(super) fn will_rename_entry(
9326 this: WeakEntity<Self>,
9327 worktree_id: WorktreeId,
9328 old_path: &Path,
9329 new_path: &Path,
9330 is_dir: bool,
9331 cx: AsyncApp,
9332 ) -> Task<()> {
9333 let old_uri = lsp::Url::from_file_path(old_path).ok().map(String::from);
9334 let new_uri = lsp::Url::from_file_path(new_path).ok().map(String::from);
9335 cx.spawn(async move |cx| {
9336 let mut tasks = vec![];
9337 this.update(cx, |this, cx| {
9338 let local_store = this.as_local()?;
9339 let old_uri = old_uri?;
9340 let new_uri = new_uri?;
9341 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9342 let Some(filter) = local_store
9343 .language_server_paths_watched_for_rename
9344 .get(&language_server.server_id())
9345 else {
9346 continue;
9347 };
9348 let Some(adapter) =
9349 this.language_server_adapter_for_id(language_server.server_id())
9350 else {
9351 continue;
9352 };
9353 if filter.should_send_will_rename(&old_uri, is_dir) {
9354 let apply_edit = cx.spawn({
9355 let old_uri = old_uri.clone();
9356 let new_uri = new_uri.clone();
9357 let language_server = language_server.clone();
9358 async move |this, cx| {
9359 let edit = language_server
9360 .request::<WillRenameFiles>(RenameFilesParams {
9361 files: vec![FileRename { old_uri, new_uri }],
9362 })
9363 .await
9364 .into_response()
9365 .context("will rename files")
9366 .log_err()
9367 .flatten()?;
9368
9369 LocalLspStore::deserialize_workspace_edit(
9370 this.upgrade()?,
9371 edit,
9372 false,
9373 adapter.clone(),
9374 language_server.clone(),
9375 cx,
9376 )
9377 .await
9378 .ok();
9379 Some(())
9380 }
9381 });
9382 tasks.push(apply_edit);
9383 }
9384 }
9385 Some(())
9386 })
9387 .ok()
9388 .flatten();
9389 for task in tasks {
9390 // Await on tasks sequentially so that the order of application of edits is deterministic
9391 // (at least with regards to the order of registration of language servers)
9392 task.await;
9393 }
9394 })
9395 }
9396
9397 fn lsp_notify_abs_paths_changed(
9398 &mut self,
9399 server_id: LanguageServerId,
9400 changes: Vec<PathEvent>,
9401 ) {
9402 maybe!({
9403 let server = self.language_server_for_id(server_id)?;
9404 let changes = changes
9405 .into_iter()
9406 .filter_map(|event| {
9407 let typ = match event.kind? {
9408 PathEventKind::Created => lsp::FileChangeType::CREATED,
9409 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9410 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9411 };
9412 Some(lsp::FileEvent {
9413 uri: file_path_to_lsp_url(&event.path).log_err()?,
9414 typ,
9415 })
9416 })
9417 .collect::<Vec<_>>();
9418 if !changes.is_empty() {
9419 server
9420 .notify::<lsp::notification::DidChangeWatchedFiles>(
9421 &lsp::DidChangeWatchedFilesParams { changes },
9422 )
9423 .ok();
9424 }
9425 Some(())
9426 });
9427 }
9428
9429 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9430 let local_lsp_store = self.as_local()?;
9431 if let Some(LanguageServerState::Running { server, .. }) =
9432 local_lsp_store.language_servers.get(&id)
9433 {
9434 Some(server.clone())
9435 } else if let Some((_, server)) = local_lsp_store.supplementary_language_servers.get(&id) {
9436 Some(Arc::clone(server))
9437 } else {
9438 None
9439 }
9440 }
9441
9442 fn on_lsp_progress(
9443 &mut self,
9444 progress: lsp::ProgressParams,
9445 language_server_id: LanguageServerId,
9446 disk_based_diagnostics_progress_token: Option<String>,
9447 cx: &mut Context<Self>,
9448 ) {
9449 let token = match progress.token {
9450 lsp::NumberOrString::String(token) => token,
9451 lsp::NumberOrString::Number(token) => {
9452 log::info!("skipping numeric progress token {}", token);
9453 return;
9454 }
9455 };
9456
9457 match progress.value {
9458 lsp::ProgressParamsValue::WorkDone(progress) => {
9459 self.handle_work_done_progress(
9460 progress,
9461 language_server_id,
9462 disk_based_diagnostics_progress_token,
9463 token,
9464 cx,
9465 );
9466 }
9467 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9468 if let Some(LanguageServerState::Running {
9469 workspace_refresh_task: Some(workspace_refresh_task),
9470 ..
9471 }) = self
9472 .as_local_mut()
9473 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9474 {
9475 workspace_refresh_task.progress_tx.try_send(()).ok();
9476 self.apply_workspace_diagnostic_report(language_server_id, report, cx)
9477 }
9478 }
9479 }
9480 }
9481
9482 fn handle_work_done_progress(
9483 &mut self,
9484 progress: lsp::WorkDoneProgress,
9485 language_server_id: LanguageServerId,
9486 disk_based_diagnostics_progress_token: Option<String>,
9487 token: String,
9488 cx: &mut Context<Self>,
9489 ) {
9490 let language_server_status =
9491 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9492 status
9493 } else {
9494 return;
9495 };
9496
9497 if !language_server_status.progress_tokens.contains(&token) {
9498 return;
9499 }
9500
9501 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
9502 .as_ref()
9503 .map_or(false, |disk_based_token| {
9504 token.starts_with(disk_based_token)
9505 });
9506
9507 match progress {
9508 lsp::WorkDoneProgress::Begin(report) => {
9509 if is_disk_based_diagnostics_progress {
9510 self.disk_based_diagnostics_started(language_server_id, cx);
9511 }
9512 self.on_lsp_work_start(
9513 language_server_id,
9514 token.clone(),
9515 LanguageServerProgress {
9516 title: Some(report.title),
9517 is_disk_based_diagnostics_progress,
9518 is_cancellable: report.cancellable.unwrap_or(false),
9519 message: report.message.clone(),
9520 percentage: report.percentage.map(|p| p as usize),
9521 last_update_at: cx.background_executor().now(),
9522 },
9523 cx,
9524 );
9525 }
9526 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9527 language_server_id,
9528 token,
9529 LanguageServerProgress {
9530 title: None,
9531 is_disk_based_diagnostics_progress,
9532 is_cancellable: report.cancellable.unwrap_or(false),
9533 message: report.message,
9534 percentage: report.percentage.map(|p| p as usize),
9535 last_update_at: cx.background_executor().now(),
9536 },
9537 cx,
9538 ),
9539 lsp::WorkDoneProgress::End(_) => {
9540 language_server_status.progress_tokens.remove(&token);
9541 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9542 if is_disk_based_diagnostics_progress {
9543 self.disk_based_diagnostics_finished(language_server_id, cx);
9544 }
9545 }
9546 }
9547 }
9548
9549 fn on_lsp_work_start(
9550 &mut self,
9551 language_server_id: LanguageServerId,
9552 token: String,
9553 progress: LanguageServerProgress,
9554 cx: &mut Context<Self>,
9555 ) {
9556 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9557 status.pending_work.insert(token.clone(), progress.clone());
9558 cx.notify();
9559 }
9560 cx.emit(LspStoreEvent::LanguageServerUpdate {
9561 language_server_id,
9562 name: self
9563 .language_server_adapter_for_id(language_server_id)
9564 .map(|adapter| adapter.name()),
9565 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9566 token,
9567 title: progress.title,
9568 message: progress.message,
9569 percentage: progress.percentage.map(|p| p as u32),
9570 is_cancellable: Some(progress.is_cancellable),
9571 }),
9572 })
9573 }
9574
9575 fn on_lsp_work_progress(
9576 &mut self,
9577 language_server_id: LanguageServerId,
9578 token: String,
9579 progress: LanguageServerProgress,
9580 cx: &mut Context<Self>,
9581 ) {
9582 let mut did_update = false;
9583 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9584 match status.pending_work.entry(token.clone()) {
9585 btree_map::Entry::Vacant(entry) => {
9586 entry.insert(progress.clone());
9587 did_update = true;
9588 }
9589 btree_map::Entry::Occupied(mut entry) => {
9590 let entry = entry.get_mut();
9591 if (progress.last_update_at - entry.last_update_at)
9592 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9593 {
9594 entry.last_update_at = progress.last_update_at;
9595 if progress.message.is_some() {
9596 entry.message = progress.message.clone();
9597 }
9598 if progress.percentage.is_some() {
9599 entry.percentage = progress.percentage;
9600 }
9601 if progress.is_cancellable != entry.is_cancellable {
9602 entry.is_cancellable = progress.is_cancellable;
9603 }
9604 did_update = true;
9605 }
9606 }
9607 }
9608 }
9609
9610 if did_update {
9611 cx.emit(LspStoreEvent::LanguageServerUpdate {
9612 language_server_id,
9613 name: self
9614 .language_server_adapter_for_id(language_server_id)
9615 .map(|adapter| adapter.name()),
9616 message: proto::update_language_server::Variant::WorkProgress(
9617 proto::LspWorkProgress {
9618 token,
9619 message: progress.message,
9620 percentage: progress.percentage.map(|p| p as u32),
9621 is_cancellable: Some(progress.is_cancellable),
9622 },
9623 ),
9624 })
9625 }
9626 }
9627
9628 fn on_lsp_work_end(
9629 &mut self,
9630 language_server_id: LanguageServerId,
9631 token: String,
9632 cx: &mut Context<Self>,
9633 ) {
9634 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9635 if let Some(work) = status.pending_work.remove(&token) {
9636 if !work.is_disk_based_diagnostics_progress {
9637 cx.emit(LspStoreEvent::RefreshInlayHints);
9638 }
9639 }
9640 cx.notify();
9641 }
9642
9643 cx.emit(LspStoreEvent::LanguageServerUpdate {
9644 language_server_id,
9645 name: self
9646 .language_server_adapter_for_id(language_server_id)
9647 .map(|adapter| adapter.name()),
9648 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
9649 })
9650 }
9651
9652 pub async fn handle_resolve_completion_documentation(
9653 this: Entity<Self>,
9654 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
9655 mut cx: AsyncApp,
9656 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
9657 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
9658
9659 let completion = this
9660 .read_with(&cx, |this, cx| {
9661 let id = LanguageServerId(envelope.payload.language_server_id as usize);
9662 let server = this
9663 .language_server_for_id(id)
9664 .with_context(|| format!("No language server {id}"))?;
9665
9666 anyhow::Ok(cx.background_spawn(async move {
9667 let can_resolve = server
9668 .capabilities()
9669 .completion_provider
9670 .as_ref()
9671 .and_then(|options| options.resolve_provider)
9672 .unwrap_or(false);
9673 if can_resolve {
9674 server
9675 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
9676 .await
9677 .into_response()
9678 .context("resolve completion item")
9679 } else {
9680 anyhow::Ok(lsp_completion)
9681 }
9682 }))
9683 })??
9684 .await?;
9685
9686 let mut documentation_is_markdown = false;
9687 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
9688 let documentation = match completion.documentation {
9689 Some(lsp::Documentation::String(text)) => text,
9690
9691 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
9692 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
9693 value
9694 }
9695
9696 _ => String::new(),
9697 };
9698
9699 // If we have a new buffer_id, that means we're talking to a new client
9700 // and want to check for new text_edits in the completion too.
9701 let mut old_replace_start = None;
9702 let mut old_replace_end = None;
9703 let mut old_insert_start = None;
9704 let mut old_insert_end = None;
9705 let mut new_text = String::default();
9706 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
9707 let buffer_snapshot = this.update(&mut cx, |this, cx| {
9708 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9709 anyhow::Ok(buffer.read(cx).snapshot())
9710 })??;
9711
9712 if let Some(text_edit) = completion.text_edit.as_ref() {
9713 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
9714
9715 if let Some(mut edit) = edit {
9716 LineEnding::normalize(&mut edit.new_text);
9717
9718 new_text = edit.new_text;
9719 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
9720 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
9721 if let Some(insert_range) = edit.insert_range {
9722 old_insert_start = Some(serialize_anchor(&insert_range.start));
9723 old_insert_end = Some(serialize_anchor(&insert_range.end));
9724 }
9725 }
9726 }
9727 }
9728
9729 Ok(proto::ResolveCompletionDocumentationResponse {
9730 documentation,
9731 documentation_is_markdown,
9732 old_replace_start,
9733 old_replace_end,
9734 new_text,
9735 lsp_completion,
9736 old_insert_start,
9737 old_insert_end,
9738 })
9739 }
9740
9741 async fn handle_on_type_formatting(
9742 this: Entity<Self>,
9743 envelope: TypedEnvelope<proto::OnTypeFormatting>,
9744 mut cx: AsyncApp,
9745 ) -> Result<proto::OnTypeFormattingResponse> {
9746 let on_type_formatting = this.update(&mut cx, |this, cx| {
9747 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9748 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9749 let position = envelope
9750 .payload
9751 .position
9752 .and_then(deserialize_anchor)
9753 .context("invalid position")?;
9754 anyhow::Ok(this.apply_on_type_formatting(
9755 buffer,
9756 position,
9757 envelope.payload.trigger.clone(),
9758 cx,
9759 ))
9760 })??;
9761
9762 let transaction = on_type_formatting
9763 .await?
9764 .as_ref()
9765 .map(language::proto::serialize_transaction);
9766 Ok(proto::OnTypeFormattingResponse { transaction })
9767 }
9768
9769 async fn handle_refresh_inlay_hints(
9770 this: Entity<Self>,
9771 _: TypedEnvelope<proto::RefreshInlayHints>,
9772 mut cx: AsyncApp,
9773 ) -> Result<proto::Ack> {
9774 this.update(&mut cx, |_, cx| {
9775 cx.emit(LspStoreEvent::RefreshInlayHints);
9776 })?;
9777 Ok(proto::Ack {})
9778 }
9779
9780 async fn handle_pull_workspace_diagnostics(
9781 lsp_store: Entity<Self>,
9782 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
9783 mut cx: AsyncApp,
9784 ) -> Result<proto::Ack> {
9785 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
9786 lsp_store.update(&mut cx, |lsp_store, _| {
9787 lsp_store.pull_workspace_diagnostics(server_id);
9788 })?;
9789 Ok(proto::Ack {})
9790 }
9791
9792 async fn handle_inlay_hints(
9793 this: Entity<Self>,
9794 envelope: TypedEnvelope<proto::InlayHints>,
9795 mut cx: AsyncApp,
9796 ) -> Result<proto::InlayHintsResponse> {
9797 let sender_id = envelope.original_sender_id().unwrap_or_default();
9798 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9799 let buffer = this.update(&mut cx, |this, cx| {
9800 this.buffer_store.read(cx).get_existing(buffer_id)
9801 })??;
9802 buffer
9803 .update(&mut cx, |buffer, _| {
9804 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
9805 })?
9806 .await
9807 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
9808
9809 let start = envelope
9810 .payload
9811 .start
9812 .and_then(deserialize_anchor)
9813 .context("missing range start")?;
9814 let end = envelope
9815 .payload
9816 .end
9817 .and_then(deserialize_anchor)
9818 .context("missing range end")?;
9819 let buffer_hints = this
9820 .update(&mut cx, |lsp_store, cx| {
9821 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
9822 })?
9823 .await
9824 .context("inlay hints fetch")?;
9825
9826 this.update(&mut cx, |project, cx| {
9827 InlayHints::response_to_proto(
9828 buffer_hints,
9829 project,
9830 sender_id,
9831 &buffer.read(cx).version(),
9832 cx,
9833 )
9834 })
9835 }
9836
9837 async fn handle_get_color_presentation(
9838 lsp_store: Entity<Self>,
9839 envelope: TypedEnvelope<proto::GetColorPresentation>,
9840 mut cx: AsyncApp,
9841 ) -> Result<proto::GetColorPresentationResponse> {
9842 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9843 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
9844 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
9845 })??;
9846
9847 let color = envelope
9848 .payload
9849 .color
9850 .context("invalid color resolve request")?;
9851 let start = color
9852 .lsp_range_start
9853 .context("invalid color resolve request")?;
9854 let end = color
9855 .lsp_range_end
9856 .context("invalid color resolve request")?;
9857
9858 let color = DocumentColor {
9859 lsp_range: lsp::Range {
9860 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
9861 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
9862 },
9863 color: lsp::Color {
9864 red: color.red,
9865 green: color.green,
9866 blue: color.blue,
9867 alpha: color.alpha,
9868 },
9869 resolved: false,
9870 color_presentations: Vec::new(),
9871 };
9872 let resolved_color = lsp_store
9873 .update(&mut cx, |lsp_store, cx| {
9874 lsp_store.resolve_color_presentation(
9875 color,
9876 buffer.clone(),
9877 LanguageServerId(envelope.payload.server_id as usize),
9878 cx,
9879 )
9880 })?
9881 .await
9882 .context("resolving color presentation")?;
9883
9884 Ok(proto::GetColorPresentationResponse {
9885 presentations: resolved_color
9886 .color_presentations
9887 .into_iter()
9888 .map(|presentation| proto::ColorPresentation {
9889 label: presentation.label.to_string(),
9890 text_edit: presentation.text_edit.map(serialize_lsp_edit),
9891 additional_text_edits: presentation
9892 .additional_text_edits
9893 .into_iter()
9894 .map(serialize_lsp_edit)
9895 .collect(),
9896 })
9897 .collect(),
9898 })
9899 }
9900
9901 async fn handle_resolve_inlay_hint(
9902 this: Entity<Self>,
9903 envelope: TypedEnvelope<proto::ResolveInlayHint>,
9904 mut cx: AsyncApp,
9905 ) -> Result<proto::ResolveInlayHintResponse> {
9906 let proto_hint = envelope
9907 .payload
9908 .hint
9909 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
9910 let hint = InlayHints::proto_to_project_hint(proto_hint)
9911 .context("resolved proto inlay hint conversion")?;
9912 let buffer = this.update(&mut cx, |this, cx| {
9913 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9914 this.buffer_store.read(cx).get_existing(buffer_id)
9915 })??;
9916 let response_hint = this
9917 .update(&mut cx, |this, cx| {
9918 this.resolve_inlay_hint(
9919 hint,
9920 buffer,
9921 LanguageServerId(envelope.payload.language_server_id as usize),
9922 cx,
9923 )
9924 })?
9925 .await
9926 .context("inlay hints fetch")?;
9927 Ok(proto::ResolveInlayHintResponse {
9928 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
9929 })
9930 }
9931
9932 async fn handle_refresh_code_lens(
9933 this: Entity<Self>,
9934 _: TypedEnvelope<proto::RefreshCodeLens>,
9935 mut cx: AsyncApp,
9936 ) -> Result<proto::Ack> {
9937 this.update(&mut cx, |_, cx| {
9938 cx.emit(LspStoreEvent::RefreshCodeLens);
9939 })?;
9940 Ok(proto::Ack {})
9941 }
9942
9943 async fn handle_open_buffer_for_symbol(
9944 this: Entity<Self>,
9945 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
9946 mut cx: AsyncApp,
9947 ) -> Result<proto::OpenBufferForSymbolResponse> {
9948 let peer_id = envelope.original_sender_id().unwrap_or_default();
9949 let symbol = envelope.payload.symbol.context("invalid symbol")?;
9950 let symbol = Self::deserialize_symbol(symbol)?;
9951 let symbol = this.read_with(&mut cx, |this, _| {
9952 let signature = this.symbol_signature(&symbol.path);
9953 anyhow::ensure!(signature == symbol.signature, "invalid symbol signature");
9954 Ok(symbol)
9955 })??;
9956 let buffer = this
9957 .update(&mut cx, |this, cx| {
9958 this.open_buffer_for_symbol(
9959 &Symbol {
9960 language_server_name: symbol.language_server_name,
9961 source_worktree_id: symbol.source_worktree_id,
9962 source_language_server_id: symbol.source_language_server_id,
9963 path: symbol.path,
9964 name: symbol.name,
9965 kind: symbol.kind,
9966 range: symbol.range,
9967 signature: symbol.signature,
9968 label: CodeLabel {
9969 text: Default::default(),
9970 runs: Default::default(),
9971 filter_range: Default::default(),
9972 },
9973 },
9974 cx,
9975 )
9976 })?
9977 .await?;
9978
9979 this.update(&mut cx, |this, cx| {
9980 let is_private = buffer
9981 .read(cx)
9982 .file()
9983 .map(|f| f.is_private())
9984 .unwrap_or_default();
9985 if is_private {
9986 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
9987 } else {
9988 this.buffer_store
9989 .update(cx, |buffer_store, cx| {
9990 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
9991 })
9992 .detach_and_log_err(cx);
9993 let buffer_id = buffer.read(cx).remote_id().to_proto();
9994 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
9995 }
9996 })?
9997 }
9998
9999 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
10000 let mut hasher = Sha256::new();
10001 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
10002 hasher.update(project_path.path.to_string_lossy().as_bytes());
10003 hasher.update(self.nonce.to_be_bytes());
10004 hasher.finalize().as_slice().try_into().unwrap()
10005 }
10006
10007 pub async fn handle_get_project_symbols(
10008 this: Entity<Self>,
10009 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10010 mut cx: AsyncApp,
10011 ) -> Result<proto::GetProjectSymbolsResponse> {
10012 let symbols = this
10013 .update(&mut cx, |this, cx| {
10014 this.symbols(&envelope.payload.query, cx)
10015 })?
10016 .await?;
10017
10018 Ok(proto::GetProjectSymbolsResponse {
10019 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10020 })
10021 }
10022
10023 pub async fn handle_restart_language_servers(
10024 this: Entity<Self>,
10025 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10026 mut cx: AsyncApp,
10027 ) -> Result<proto::Ack> {
10028 this.update(&mut cx, |lsp_store, cx| {
10029 let buffers =
10030 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10031 lsp_store.restart_language_servers_for_buffers(
10032 buffers,
10033 envelope
10034 .payload
10035 .only_servers
10036 .into_iter()
10037 .filter_map(|selector| {
10038 Some(match selector.selector? {
10039 proto::language_server_selector::Selector::ServerId(server_id) => {
10040 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10041 }
10042 proto::language_server_selector::Selector::Name(name) => {
10043 LanguageServerSelector::Name(LanguageServerName(
10044 SharedString::from(name),
10045 ))
10046 }
10047 })
10048 })
10049 .collect(),
10050 cx,
10051 );
10052 })?;
10053
10054 Ok(proto::Ack {})
10055 }
10056
10057 pub async fn handle_stop_language_servers(
10058 lsp_store: Entity<Self>,
10059 envelope: TypedEnvelope<proto::StopLanguageServers>,
10060 mut cx: AsyncApp,
10061 ) -> Result<proto::Ack> {
10062 lsp_store.update(&mut cx, |lsp_store, cx| {
10063 if envelope.payload.all
10064 && envelope.payload.also_servers.is_empty()
10065 && envelope.payload.buffer_ids.is_empty()
10066 {
10067 lsp_store.stop_all_language_servers(cx);
10068 } else {
10069 let buffers =
10070 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10071 lsp_store
10072 .stop_language_servers_for_buffers(
10073 buffers,
10074 envelope
10075 .payload
10076 .also_servers
10077 .into_iter()
10078 .filter_map(|selector| {
10079 Some(match selector.selector? {
10080 proto::language_server_selector::Selector::ServerId(
10081 server_id,
10082 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10083 server_id,
10084 )),
10085 proto::language_server_selector::Selector::Name(name) => {
10086 LanguageServerSelector::Name(LanguageServerName(
10087 SharedString::from(name),
10088 ))
10089 }
10090 })
10091 })
10092 .collect(),
10093 cx,
10094 )
10095 .detach_and_log_err(cx);
10096 }
10097 })?;
10098
10099 Ok(proto::Ack {})
10100 }
10101
10102 pub async fn handle_cancel_language_server_work(
10103 this: Entity<Self>,
10104 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10105 mut cx: AsyncApp,
10106 ) -> Result<proto::Ack> {
10107 this.update(&mut cx, |this, cx| {
10108 if let Some(work) = envelope.payload.work {
10109 match work {
10110 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10111 let buffers =
10112 this.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10113 this.cancel_language_server_work_for_buffers(buffers, cx);
10114 }
10115 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10116 let server_id = LanguageServerId::from_proto(work.language_server_id);
10117 this.cancel_language_server_work(server_id, work.token, cx);
10118 }
10119 }
10120 }
10121 })?;
10122
10123 Ok(proto::Ack {})
10124 }
10125
10126 fn buffer_ids_to_buffers(
10127 &mut self,
10128 buffer_ids: impl Iterator<Item = u64>,
10129 cx: &mut Context<Self>,
10130 ) -> Vec<Entity<Buffer>> {
10131 buffer_ids
10132 .into_iter()
10133 .flat_map(|buffer_id| {
10134 self.buffer_store
10135 .read(cx)
10136 .get(BufferId::new(buffer_id).log_err()?)
10137 })
10138 .collect::<Vec<_>>()
10139 }
10140
10141 async fn handle_apply_additional_edits_for_completion(
10142 this: Entity<Self>,
10143 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10144 mut cx: AsyncApp,
10145 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10146 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10147 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10148 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10149 let completion = Self::deserialize_completion(
10150 envelope.payload.completion.context("invalid completion")?,
10151 )?;
10152 anyhow::Ok((buffer, completion))
10153 })??;
10154
10155 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10156 this.apply_additional_edits_for_completion(
10157 buffer,
10158 Rc::new(RefCell::new(Box::new([Completion {
10159 replace_range: completion.replace_range,
10160 new_text: completion.new_text,
10161 source: completion.source,
10162 documentation: None,
10163 label: CodeLabel {
10164 text: Default::default(),
10165 runs: Default::default(),
10166 filter_range: Default::default(),
10167 },
10168 insert_text_mode: None,
10169 icon_path: None,
10170 confirm: None,
10171 }]))),
10172 0,
10173 false,
10174 cx,
10175 )
10176 })?;
10177
10178 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10179 transaction: apply_additional_edits
10180 .await?
10181 .as_ref()
10182 .map(language::proto::serialize_transaction),
10183 })
10184 }
10185
10186 pub fn last_formatting_failure(&self) -> Option<&str> {
10187 self.last_formatting_failure.as_deref()
10188 }
10189
10190 pub fn reset_last_formatting_failure(&mut self) {
10191 self.last_formatting_failure = None;
10192 }
10193
10194 pub fn environment_for_buffer(
10195 &self,
10196 buffer: &Entity<Buffer>,
10197 cx: &mut Context<Self>,
10198 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10199 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10200 environment.update(cx, |env, cx| {
10201 env.get_buffer_environment(&buffer, &self.worktree_store, cx)
10202 })
10203 } else {
10204 Task::ready(None).shared()
10205 }
10206 }
10207
10208 pub fn format(
10209 &mut self,
10210 buffers: HashSet<Entity<Buffer>>,
10211 target: LspFormatTarget,
10212 push_to_history: bool,
10213 trigger: FormatTrigger,
10214 cx: &mut Context<Self>,
10215 ) -> Task<anyhow::Result<ProjectTransaction>> {
10216 let logger = zlog::scoped!("format");
10217 if let Some(_) = self.as_local() {
10218 zlog::trace!(logger => "Formatting locally");
10219 let logger = zlog::scoped!(logger => "local");
10220 let buffers = buffers
10221 .into_iter()
10222 .map(|buffer_handle| {
10223 let buffer = buffer_handle.read(cx);
10224 let buffer_abs_path = File::from_dyn(buffer.file())
10225 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10226
10227 (buffer_handle, buffer_abs_path, buffer.remote_id())
10228 })
10229 .collect::<Vec<_>>();
10230
10231 cx.spawn(async move |lsp_store, cx| {
10232 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10233
10234 for (handle, abs_path, id) in buffers {
10235 let env = lsp_store
10236 .update(cx, |lsp_store, cx| {
10237 lsp_store.environment_for_buffer(&handle, cx)
10238 })?
10239 .await;
10240
10241 let ranges = match &target {
10242 LspFormatTarget::Buffers => None,
10243 LspFormatTarget::Ranges(ranges) => {
10244 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10245 }
10246 };
10247
10248 formattable_buffers.push(FormattableBuffer {
10249 handle,
10250 abs_path,
10251 env,
10252 ranges,
10253 });
10254 }
10255 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10256
10257 let format_timer = zlog::time!(logger => "Formatting buffers");
10258 let result = LocalLspStore::format_locally(
10259 lsp_store.clone(),
10260 formattable_buffers,
10261 push_to_history,
10262 trigger,
10263 logger,
10264 cx,
10265 )
10266 .await;
10267 format_timer.end();
10268
10269 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10270
10271 lsp_store.update(cx, |lsp_store, _| {
10272 lsp_store.update_last_formatting_failure(&result);
10273 })?;
10274
10275 result
10276 })
10277 } else if let Some((client, project_id)) = self.upstream_client() {
10278 zlog::trace!(logger => "Formatting remotely");
10279 let logger = zlog::scoped!(logger => "remote");
10280 // Don't support formatting ranges via remote
10281 match target {
10282 LspFormatTarget::Buffers => {}
10283 LspFormatTarget::Ranges(_) => {
10284 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10285 return Task::ready(Ok(ProjectTransaction::default()));
10286 }
10287 }
10288
10289 let buffer_store = self.buffer_store();
10290 cx.spawn(async move |lsp_store, cx| {
10291 zlog::trace!(logger => "Sending remote format request");
10292 let request_timer = zlog::time!(logger => "remote format request");
10293 let result = client
10294 .request(proto::FormatBuffers {
10295 project_id,
10296 trigger: trigger as i32,
10297 buffer_ids: buffers
10298 .iter()
10299 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10300 .collect::<Result<_>>()?,
10301 })
10302 .await
10303 .and_then(|result| result.transaction.context("missing transaction"));
10304 request_timer.end();
10305
10306 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10307
10308 lsp_store.update(cx, |lsp_store, _| {
10309 lsp_store.update_last_formatting_failure(&result);
10310 })?;
10311
10312 let transaction_response = result?;
10313 let _timer = zlog::time!(logger => "deserializing project transaction");
10314 buffer_store
10315 .update(cx, |buffer_store, cx| {
10316 buffer_store.deserialize_project_transaction(
10317 transaction_response,
10318 push_to_history,
10319 cx,
10320 )
10321 })?
10322 .await
10323 })
10324 } else {
10325 zlog::trace!(logger => "Not formatting");
10326 Task::ready(Ok(ProjectTransaction::default()))
10327 }
10328 }
10329
10330 async fn handle_format_buffers(
10331 this: Entity<Self>,
10332 envelope: TypedEnvelope<proto::FormatBuffers>,
10333 mut cx: AsyncApp,
10334 ) -> Result<proto::FormatBuffersResponse> {
10335 let sender_id = envelope.original_sender_id().unwrap_or_default();
10336 let format = this.update(&mut cx, |this, cx| {
10337 let mut buffers = HashSet::default();
10338 for buffer_id in &envelope.payload.buffer_ids {
10339 let buffer_id = BufferId::new(*buffer_id)?;
10340 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10341 }
10342 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10343 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10344 })??;
10345
10346 let project_transaction = format.await?;
10347 let project_transaction = this.update(&mut cx, |this, cx| {
10348 this.buffer_store.update(cx, |buffer_store, cx| {
10349 buffer_store.serialize_project_transaction_for_peer(
10350 project_transaction,
10351 sender_id,
10352 cx,
10353 )
10354 })
10355 })?;
10356 Ok(proto::FormatBuffersResponse {
10357 transaction: Some(project_transaction),
10358 })
10359 }
10360
10361 async fn handle_apply_code_action_kind(
10362 this: Entity<Self>,
10363 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10364 mut cx: AsyncApp,
10365 ) -> Result<proto::ApplyCodeActionKindResponse> {
10366 let sender_id = envelope.original_sender_id().unwrap_or_default();
10367 let format = this.update(&mut cx, |this, cx| {
10368 let mut buffers = HashSet::default();
10369 for buffer_id in &envelope.payload.buffer_ids {
10370 let buffer_id = BufferId::new(*buffer_id)?;
10371 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10372 }
10373 let kind = match envelope.payload.kind.as_str() {
10374 "" => CodeActionKind::EMPTY,
10375 "quickfix" => CodeActionKind::QUICKFIX,
10376 "refactor" => CodeActionKind::REFACTOR,
10377 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10378 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10379 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10380 "source" => CodeActionKind::SOURCE,
10381 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10382 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10383 _ => anyhow::bail!(
10384 "Invalid code action kind {}",
10385 envelope.payload.kind.as_str()
10386 ),
10387 };
10388 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10389 })??;
10390
10391 let project_transaction = format.await?;
10392 let project_transaction = this.update(&mut cx, |this, cx| {
10393 this.buffer_store.update(cx, |buffer_store, cx| {
10394 buffer_store.serialize_project_transaction_for_peer(
10395 project_transaction,
10396 sender_id,
10397 cx,
10398 )
10399 })
10400 })?;
10401 Ok(proto::ApplyCodeActionKindResponse {
10402 transaction: Some(project_transaction),
10403 })
10404 }
10405
10406 async fn shutdown_language_server(
10407 server_state: Option<LanguageServerState>,
10408 name: LanguageServerName,
10409 cx: &mut AsyncApp,
10410 ) {
10411 let server = match server_state {
10412 Some(LanguageServerState::Starting { startup, .. }) => {
10413 let mut timer = cx
10414 .background_executor()
10415 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10416 .fuse();
10417
10418 select! {
10419 server = startup.fuse() => server,
10420 () = timer => {
10421 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10422 None
10423 },
10424 }
10425 }
10426
10427 Some(LanguageServerState::Running { server, .. }) => Some(server),
10428
10429 None => None,
10430 };
10431
10432 if let Some(server) = server {
10433 if let Some(shutdown) = server.shutdown() {
10434 shutdown.await;
10435 }
10436 }
10437 }
10438
10439 // Returns a list of all of the worktrees which no longer have a language server and the root path
10440 // for the stopped server
10441 fn stop_local_language_server(
10442 &mut self,
10443 server_id: LanguageServerId,
10444 cx: &mut Context<Self>,
10445 ) -> Task<Vec<WorktreeId>> {
10446 let local = match &mut self.mode {
10447 LspStoreMode::Local(local) => local,
10448 _ => {
10449 return Task::ready(Vec::new());
10450 }
10451 };
10452
10453 let mut orphaned_worktrees = Vec::new();
10454 // Remove this server ID from all entries in the given worktree.
10455 local.language_server_ids.retain(|(worktree, _), ids| {
10456 if !ids.remove(&server_id) {
10457 return true;
10458 }
10459
10460 if ids.is_empty() {
10461 orphaned_worktrees.push(*worktree);
10462 false
10463 } else {
10464 true
10465 }
10466 });
10467 self.buffer_store.update(cx, |buffer_store, cx| {
10468 for buffer in buffer_store.buffers() {
10469 buffer.update(cx, |buffer, cx| {
10470 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10471 buffer.set_completion_triggers(server_id, Default::default(), cx);
10472 });
10473 }
10474 });
10475
10476 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10477 summaries.retain(|path, summaries_by_server_id| {
10478 if summaries_by_server_id.remove(&server_id).is_some() {
10479 if let Some((client, project_id)) = self.downstream_client.clone() {
10480 client
10481 .send(proto::UpdateDiagnosticSummary {
10482 project_id,
10483 worktree_id: worktree_id.to_proto(),
10484 summary: Some(proto::DiagnosticSummary {
10485 path: path.as_ref().to_proto(),
10486 language_server_id: server_id.0 as u64,
10487 error_count: 0,
10488 warning_count: 0,
10489 }),
10490 more_summaries: Vec::new(),
10491 })
10492 .log_err();
10493 }
10494 !summaries_by_server_id.is_empty()
10495 } else {
10496 true
10497 }
10498 });
10499 }
10500
10501 let local = self.as_local_mut().unwrap();
10502 for diagnostics in local.diagnostics.values_mut() {
10503 diagnostics.retain(|_, diagnostics_by_server_id| {
10504 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10505 diagnostics_by_server_id.remove(ix);
10506 !diagnostics_by_server_id.is_empty()
10507 } else {
10508 true
10509 }
10510 });
10511 }
10512 local.language_server_watched_paths.remove(&server_id);
10513
10514 let server_state = local.language_servers.remove(&server_id);
10515 self.cleanup_lsp_data(server_id);
10516 let name = self
10517 .language_server_statuses
10518 .remove(&server_id)
10519 .map(|status| status.name.clone())
10520 .or_else(|| {
10521 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10522 Some(adapter.name())
10523 } else {
10524 None
10525 }
10526 });
10527
10528 if let Some(name) = name {
10529 log::info!("stopping language server {name}");
10530 self.languages
10531 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10532 cx.notify();
10533
10534 return cx.spawn(async move |lsp_store, cx| {
10535 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10536 lsp_store
10537 .update(cx, |lsp_store, cx| {
10538 lsp_store
10539 .languages
10540 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10541 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10542 cx.notify();
10543 })
10544 .ok();
10545 orphaned_worktrees
10546 });
10547 }
10548
10549 if server_state.is_some() {
10550 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10551 }
10552 Task::ready(orphaned_worktrees)
10553 }
10554
10555 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10556 if let Some((client, project_id)) = self.upstream_client() {
10557 let request = client.request(proto::StopLanguageServers {
10558 project_id,
10559 buffer_ids: Vec::new(),
10560 also_servers: Vec::new(),
10561 all: true,
10562 });
10563 cx.background_spawn(request).detach_and_log_err(cx);
10564 } else {
10565 let Some(local) = self.as_local_mut() else {
10566 return;
10567 };
10568 let language_servers_to_stop = local
10569 .language_server_ids
10570 .values()
10571 .flatten()
10572 .copied()
10573 .collect();
10574 local.lsp_tree.update(cx, |this, _| {
10575 this.remove_nodes(&language_servers_to_stop);
10576 });
10577 let tasks = language_servers_to_stop
10578 .into_iter()
10579 .map(|server| self.stop_local_language_server(server, cx))
10580 .collect::<Vec<_>>();
10581 cx.background_spawn(async move {
10582 futures::future::join_all(tasks).await;
10583 })
10584 .detach();
10585 }
10586 }
10587
10588 pub fn restart_language_servers_for_buffers(
10589 &mut self,
10590 buffers: Vec<Entity<Buffer>>,
10591 only_restart_servers: HashSet<LanguageServerSelector>,
10592 cx: &mut Context<Self>,
10593 ) {
10594 if let Some((client, project_id)) = self.upstream_client() {
10595 let request = client.request(proto::RestartLanguageServers {
10596 project_id,
10597 buffer_ids: buffers
10598 .into_iter()
10599 .map(|b| b.read(cx).remote_id().to_proto())
10600 .collect(),
10601 only_servers: only_restart_servers
10602 .into_iter()
10603 .map(|selector| {
10604 let selector = match selector {
10605 LanguageServerSelector::Id(language_server_id) => {
10606 proto::language_server_selector::Selector::ServerId(
10607 language_server_id.to_proto(),
10608 )
10609 }
10610 LanguageServerSelector::Name(language_server_name) => {
10611 proto::language_server_selector::Selector::Name(
10612 language_server_name.to_string(),
10613 )
10614 }
10615 };
10616 proto::LanguageServerSelector {
10617 selector: Some(selector),
10618 }
10619 })
10620 .collect(),
10621 all: false,
10622 });
10623 cx.background_spawn(request).detach_and_log_err(cx);
10624 } else {
10625 let stop_task = if only_restart_servers.is_empty() {
10626 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10627 } else {
10628 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10629 };
10630 cx.spawn(async move |lsp_store, cx| {
10631 stop_task.await;
10632 lsp_store
10633 .update(cx, |lsp_store, cx| {
10634 for buffer in buffers {
10635 lsp_store.register_buffer_with_language_servers(
10636 &buffer,
10637 only_restart_servers.clone(),
10638 true,
10639 cx,
10640 );
10641 }
10642 })
10643 .ok()
10644 })
10645 .detach();
10646 }
10647 }
10648
10649 pub fn stop_language_servers_for_buffers(
10650 &mut self,
10651 buffers: Vec<Entity<Buffer>>,
10652 also_stop_servers: HashSet<LanguageServerSelector>,
10653 cx: &mut Context<Self>,
10654 ) -> Task<Result<()>> {
10655 if let Some((client, project_id)) = self.upstream_client() {
10656 let request = client.request(proto::StopLanguageServers {
10657 project_id,
10658 buffer_ids: buffers
10659 .into_iter()
10660 .map(|b| b.read(cx).remote_id().to_proto())
10661 .collect(),
10662 also_servers: also_stop_servers
10663 .into_iter()
10664 .map(|selector| {
10665 let selector = match selector {
10666 LanguageServerSelector::Id(language_server_id) => {
10667 proto::language_server_selector::Selector::ServerId(
10668 language_server_id.to_proto(),
10669 )
10670 }
10671 LanguageServerSelector::Name(language_server_name) => {
10672 proto::language_server_selector::Selector::Name(
10673 language_server_name.to_string(),
10674 )
10675 }
10676 };
10677 proto::LanguageServerSelector {
10678 selector: Some(selector),
10679 }
10680 })
10681 .collect(),
10682 all: false,
10683 });
10684 cx.background_spawn(async move {
10685 let _ = request.await?;
10686 Ok(())
10687 })
10688 } else {
10689 let task =
10690 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10691 cx.background_spawn(async move {
10692 task.await;
10693 Ok(())
10694 })
10695 }
10696 }
10697
10698 fn stop_local_language_servers_for_buffers(
10699 &mut self,
10700 buffers: &[Entity<Buffer>],
10701 also_stop_servers: HashSet<LanguageServerSelector>,
10702 cx: &mut Context<Self>,
10703 ) -> Task<()> {
10704 let Some(local) = self.as_local_mut() else {
10705 return Task::ready(());
10706 };
10707 let mut language_server_names_to_stop = BTreeSet::default();
10708 let mut language_servers_to_stop = also_stop_servers
10709 .into_iter()
10710 .flat_map(|selector| match selector {
10711 LanguageServerSelector::Id(id) => Some(id),
10712 LanguageServerSelector::Name(name) => {
10713 language_server_names_to_stop.insert(name);
10714 None
10715 }
10716 })
10717 .collect::<BTreeSet<_>>();
10718
10719 let mut covered_worktrees = HashSet::default();
10720 for buffer in buffers {
10721 buffer.update(cx, |buffer, cx| {
10722 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10723 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
10724 if covered_worktrees.insert(worktree_id) {
10725 language_server_names_to_stop.retain(|name| {
10726 match local.language_server_ids.get(&(worktree_id, name.clone())) {
10727 Some(server_ids) => {
10728 language_servers_to_stop
10729 .extend(server_ids.into_iter().copied());
10730 false
10731 }
10732 None => true,
10733 }
10734 });
10735 }
10736 }
10737 });
10738 }
10739 for name in language_server_names_to_stop {
10740 if let Some(server_ids) = local
10741 .language_server_ids
10742 .iter()
10743 .filter(|((_, server_name), _)| server_name == &name)
10744 .map(|((_, _), server_ids)| server_ids)
10745 .max_by_key(|server_ids| server_ids.len())
10746 {
10747 language_servers_to_stop.extend(server_ids.into_iter().copied());
10748 }
10749 }
10750
10751 local.lsp_tree.update(cx, |this, _| {
10752 this.remove_nodes(&language_servers_to_stop);
10753 });
10754 let tasks = language_servers_to_stop
10755 .into_iter()
10756 .map(|server| self.stop_local_language_server(server, cx))
10757 .collect::<Vec<_>>();
10758
10759 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
10760 }
10761
10762 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
10763 let (worktree, relative_path) =
10764 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
10765
10766 let project_path = ProjectPath {
10767 worktree_id: worktree.read(cx).id(),
10768 path: relative_path.into(),
10769 };
10770
10771 Some(
10772 self.buffer_store()
10773 .read(cx)
10774 .get_by_path(&project_path)?
10775 .read(cx),
10776 )
10777 }
10778
10779 #[cfg(any(test, feature = "test-support"))]
10780 pub fn update_diagnostics(
10781 &mut self,
10782 server_id: LanguageServerId,
10783 diagnostics: lsp::PublishDiagnosticsParams,
10784 result_id: Option<String>,
10785 source_kind: DiagnosticSourceKind,
10786 disk_based_sources: &[String],
10787 cx: &mut Context<Self>,
10788 ) -> Result<()> {
10789 self.merge_lsp_diagnostics(
10790 source_kind,
10791 vec![DocumentDiagnosticsUpdate {
10792 diagnostics,
10793 result_id,
10794 server_id,
10795 disk_based_sources: Cow::Borrowed(disk_based_sources),
10796 }],
10797 |_, _, _| false,
10798 cx,
10799 )
10800 }
10801
10802 pub fn merge_lsp_diagnostics(
10803 &mut self,
10804 source_kind: DiagnosticSourceKind,
10805 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
10806 merge: impl Fn(&Buffer, &Diagnostic, &App) -> bool + Clone,
10807 cx: &mut Context<Self>,
10808 ) -> Result<()> {
10809 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
10810 let updates = lsp_diagnostics
10811 .into_iter()
10812 .filter_map(|update| {
10813 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
10814 Some(DocumentDiagnosticsUpdate {
10815 diagnostics: self.lsp_to_document_diagnostics(
10816 abs_path,
10817 source_kind,
10818 update.server_id,
10819 update.diagnostics,
10820 &update.disk_based_sources,
10821 ),
10822 result_id: update.result_id,
10823 server_id: update.server_id,
10824 disk_based_sources: update.disk_based_sources,
10825 })
10826 })
10827 .collect();
10828 self.merge_diagnostic_entries(updates, merge, cx)?;
10829 Ok(())
10830 }
10831
10832 fn lsp_to_document_diagnostics(
10833 &mut self,
10834 document_abs_path: PathBuf,
10835 source_kind: DiagnosticSourceKind,
10836 server_id: LanguageServerId,
10837 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
10838 disk_based_sources: &[String],
10839 ) -> DocumentDiagnostics {
10840 let mut diagnostics = Vec::default();
10841 let mut primary_diagnostic_group_ids = HashMap::default();
10842 let mut sources_by_group_id = HashMap::default();
10843 let mut supporting_diagnostics = HashMap::default();
10844
10845 let adapter = self.language_server_adapter_for_id(server_id);
10846
10847 // Ensure that primary diagnostics are always the most severe
10848 lsp_diagnostics
10849 .diagnostics
10850 .sort_by_key(|item| item.severity);
10851
10852 for diagnostic in &lsp_diagnostics.diagnostics {
10853 let source = diagnostic.source.as_ref();
10854 let range = range_from_lsp(diagnostic.range);
10855 let is_supporting = diagnostic
10856 .related_information
10857 .as_ref()
10858 .map_or(false, |infos| {
10859 infos.iter().any(|info| {
10860 primary_diagnostic_group_ids.contains_key(&(
10861 source,
10862 diagnostic.code.clone(),
10863 range_from_lsp(info.location.range),
10864 ))
10865 })
10866 });
10867
10868 let is_unnecessary = diagnostic
10869 .tags
10870 .as_ref()
10871 .map_or(false, |tags| tags.contains(&DiagnosticTag::UNNECESSARY));
10872
10873 let underline = self
10874 .language_server_adapter_for_id(server_id)
10875 .map_or(true, |adapter| adapter.underline_diagnostic(diagnostic));
10876
10877 if is_supporting {
10878 supporting_diagnostics.insert(
10879 (source, diagnostic.code.clone(), range),
10880 (diagnostic.severity, is_unnecessary),
10881 );
10882 } else {
10883 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
10884 let is_disk_based =
10885 source.map_or(false, |source| disk_based_sources.contains(source));
10886
10887 sources_by_group_id.insert(group_id, source);
10888 primary_diagnostic_group_ids
10889 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
10890
10891 diagnostics.push(DiagnosticEntry {
10892 range,
10893 diagnostic: Diagnostic {
10894 source: diagnostic.source.clone(),
10895 source_kind,
10896 code: diagnostic.code.clone(),
10897 code_description: diagnostic
10898 .code_description
10899 .as_ref()
10900 .and_then(|d| d.href.clone()),
10901 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
10902 markdown: adapter.as_ref().and_then(|adapter| {
10903 adapter.diagnostic_message_to_markdown(&diagnostic.message)
10904 }),
10905 message: diagnostic.message.trim().to_string(),
10906 group_id,
10907 is_primary: true,
10908 is_disk_based,
10909 is_unnecessary,
10910 underline,
10911 data: diagnostic.data.clone(),
10912 },
10913 });
10914 if let Some(infos) = &diagnostic.related_information {
10915 for info in infos {
10916 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
10917 let range = range_from_lsp(info.location.range);
10918 diagnostics.push(DiagnosticEntry {
10919 range,
10920 diagnostic: Diagnostic {
10921 source: diagnostic.source.clone(),
10922 source_kind,
10923 code: diagnostic.code.clone(),
10924 code_description: diagnostic
10925 .code_description
10926 .as_ref()
10927 .and_then(|d| d.href.clone()),
10928 severity: DiagnosticSeverity::INFORMATION,
10929 markdown: adapter.as_ref().and_then(|adapter| {
10930 adapter.diagnostic_message_to_markdown(&info.message)
10931 }),
10932 message: info.message.trim().to_string(),
10933 group_id,
10934 is_primary: false,
10935 is_disk_based,
10936 is_unnecessary: false,
10937 underline,
10938 data: diagnostic.data.clone(),
10939 },
10940 });
10941 }
10942 }
10943 }
10944 }
10945 }
10946
10947 for entry in &mut diagnostics {
10948 let diagnostic = &mut entry.diagnostic;
10949 if !diagnostic.is_primary {
10950 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
10951 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
10952 source,
10953 diagnostic.code.clone(),
10954 entry.range.clone(),
10955 )) {
10956 if let Some(severity) = severity {
10957 diagnostic.severity = severity;
10958 }
10959 diagnostic.is_unnecessary = is_unnecessary;
10960 }
10961 }
10962 }
10963
10964 DocumentDiagnostics {
10965 diagnostics,
10966 document_abs_path,
10967 version: lsp_diagnostics.version,
10968 }
10969 }
10970
10971 fn insert_newly_running_language_server(
10972 &mut self,
10973 adapter: Arc<CachedLspAdapter>,
10974 language_server: Arc<LanguageServer>,
10975 server_id: LanguageServerId,
10976 key: (WorktreeId, LanguageServerName),
10977 workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
10978 cx: &mut Context<Self>,
10979 ) {
10980 let Some(local) = self.as_local_mut() else {
10981 return;
10982 };
10983 // If the language server for this key doesn't match the server id, don't store the
10984 // server. Which will cause it to be dropped, killing the process
10985 if local
10986 .language_server_ids
10987 .get(&key)
10988 .map(|ids| !ids.contains(&server_id))
10989 .unwrap_or(false)
10990 {
10991 return;
10992 }
10993
10994 // Update language_servers collection with Running variant of LanguageServerState
10995 // indicating that the server is up and running and ready
10996 let workspace_folders = workspace_folders.lock().clone();
10997 language_server.set_workspace_folders(workspace_folders);
10998
10999 local.language_servers.insert(
11000 server_id,
11001 LanguageServerState::Running {
11002 workspace_refresh_task: lsp_workspace_diagnostics_refresh(
11003 language_server.clone(),
11004 cx,
11005 ),
11006 adapter: adapter.clone(),
11007 server: language_server.clone(),
11008 simulate_disk_based_diagnostics_completion: None,
11009 },
11010 );
11011 local
11012 .languages
11013 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11014 if let Some(file_ops_caps) = language_server
11015 .capabilities()
11016 .workspace
11017 .as_ref()
11018 .and_then(|ws| ws.file_operations.as_ref())
11019 {
11020 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11021 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11022 if did_rename_caps.or(will_rename_caps).is_some() {
11023 let watcher = RenamePathsWatchedForServer::default()
11024 .with_did_rename_patterns(did_rename_caps)
11025 .with_will_rename_patterns(will_rename_caps);
11026 local
11027 .language_server_paths_watched_for_rename
11028 .insert(server_id, watcher);
11029 }
11030 }
11031
11032 self.language_server_statuses.insert(
11033 server_id,
11034 LanguageServerStatus {
11035 name: language_server.name(),
11036 pending_work: Default::default(),
11037 has_pending_diagnostic_updates: false,
11038 progress_tokens: Default::default(),
11039 },
11040 );
11041
11042 cx.emit(LspStoreEvent::LanguageServerAdded(
11043 server_id,
11044 language_server.name(),
11045 Some(key.0),
11046 ));
11047 cx.emit(LspStoreEvent::RefreshInlayHints);
11048
11049 let server_capabilities = language_server.capabilities();
11050 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11051 downstream_client
11052 .send(proto::StartLanguageServer {
11053 project_id: *project_id,
11054 server: Some(proto::LanguageServer {
11055 id: server_id.to_proto(),
11056 name: language_server.name().to_string(),
11057 worktree_id: Some(key.0.to_proto()),
11058 }),
11059 capabilities: serde_json::to_string(&server_capabilities)
11060 .expect("serializing server LSP capabilities"),
11061 })
11062 .log_err();
11063 }
11064 self.lsp_server_capabilities
11065 .insert(server_id, server_capabilities);
11066
11067 // Tell the language server about every open buffer in the worktree that matches the language.
11068 // Also check for buffers in worktrees that reused this server
11069 let mut worktrees_using_server = vec![key.0];
11070 if let Some(local) = self.as_local() {
11071 // Find all worktrees that have this server in their language server tree
11072 for (worktree_id, servers) in &local.lsp_tree.read(cx).instances {
11073 if *worktree_id != key.0 {
11074 for (_, server_map) in &servers.roots {
11075 if server_map.contains_key(&key.1) {
11076 worktrees_using_server.push(*worktree_id);
11077 }
11078 }
11079 }
11080 }
11081 }
11082
11083 let mut buffer_paths_registered = Vec::new();
11084 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11085 for buffer_handle in buffer_store.buffers() {
11086 let buffer = buffer_handle.read(cx);
11087 let file = match File::from_dyn(buffer.file()) {
11088 Some(file) => file,
11089 None => continue,
11090 };
11091 let language = match buffer.language() {
11092 Some(language) => language,
11093 None => continue,
11094 };
11095
11096 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11097 || !self
11098 .languages
11099 .lsp_adapters(&language.name())
11100 .iter()
11101 .any(|a| a.name == key.1)
11102 {
11103 continue;
11104 }
11105 // didOpen
11106 let file = match file.as_local() {
11107 Some(file) => file,
11108 None => continue,
11109 };
11110
11111 let local = self.as_local_mut().unwrap();
11112
11113 let buffer_id = buffer.remote_id();
11114 if local.registered_buffers.contains_key(&buffer_id) {
11115 let versions = local
11116 .buffer_snapshots
11117 .entry(buffer_id)
11118 .or_default()
11119 .entry(server_id)
11120 .and_modify(|_| {
11121 assert!(
11122 false,
11123 "There should not be an existing snapshot for a newly inserted buffer"
11124 )
11125 })
11126 .or_insert_with(|| {
11127 vec![LspBufferSnapshot {
11128 version: 0,
11129 snapshot: buffer.text_snapshot(),
11130 }]
11131 });
11132
11133 let snapshot = versions.last().unwrap();
11134 let version = snapshot.version;
11135 let initial_snapshot = &snapshot.snapshot;
11136 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
11137 language_server.register_buffer(
11138 uri,
11139 adapter.language_id(&language.name()),
11140 version,
11141 initial_snapshot.text(),
11142 );
11143 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11144 local
11145 .buffers_opened_in_servers
11146 .entry(buffer_id)
11147 .or_default()
11148 .insert(server_id);
11149 }
11150 buffer_handle.update(cx, |buffer, cx| {
11151 buffer.set_completion_triggers(
11152 server_id,
11153 language_server
11154 .capabilities()
11155 .completion_provider
11156 .as_ref()
11157 .and_then(|provider| {
11158 provider
11159 .trigger_characters
11160 .as_ref()
11161 .map(|characters| characters.iter().cloned().collect())
11162 })
11163 .unwrap_or_default(),
11164 cx,
11165 )
11166 });
11167 }
11168 });
11169
11170 for (buffer_id, abs_path) in buffer_paths_registered {
11171 cx.emit(LspStoreEvent::LanguageServerUpdate {
11172 language_server_id: server_id,
11173 name: Some(adapter.name()),
11174 message: proto::update_language_server::Variant::RegisteredForBuffer(
11175 proto::RegisteredForBuffer {
11176 buffer_abs_path: abs_path.to_string_lossy().to_string(),
11177 buffer_id: buffer_id.to_proto(),
11178 },
11179 ),
11180 });
11181 }
11182
11183 cx.notify();
11184 }
11185
11186 pub fn language_servers_running_disk_based_diagnostics(
11187 &self,
11188 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11189 self.language_server_statuses
11190 .iter()
11191 .filter_map(|(id, status)| {
11192 if status.has_pending_diagnostic_updates {
11193 Some(*id)
11194 } else {
11195 None
11196 }
11197 })
11198 }
11199
11200 pub(crate) fn cancel_language_server_work_for_buffers(
11201 &mut self,
11202 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11203 cx: &mut Context<Self>,
11204 ) {
11205 if let Some((client, project_id)) = self.upstream_client() {
11206 let request = client.request(proto::CancelLanguageServerWork {
11207 project_id,
11208 work: Some(proto::cancel_language_server_work::Work::Buffers(
11209 proto::cancel_language_server_work::Buffers {
11210 buffer_ids: buffers
11211 .into_iter()
11212 .map(|b| b.read(cx).remote_id().to_proto())
11213 .collect(),
11214 },
11215 )),
11216 });
11217 cx.background_spawn(request).detach_and_log_err(cx);
11218 } else if let Some(local) = self.as_local() {
11219 let servers = buffers
11220 .into_iter()
11221 .flat_map(|buffer| {
11222 buffer.update(cx, |buffer, cx| {
11223 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11224 })
11225 })
11226 .collect::<HashSet<_>>();
11227 for server_id in servers {
11228 self.cancel_language_server_work(server_id, None, cx);
11229 }
11230 }
11231 }
11232
11233 pub(crate) fn cancel_language_server_work(
11234 &mut self,
11235 server_id: LanguageServerId,
11236 token_to_cancel: Option<String>,
11237 cx: &mut Context<Self>,
11238 ) {
11239 if let Some(local) = self.as_local() {
11240 let status = self.language_server_statuses.get(&server_id);
11241 let server = local.language_servers.get(&server_id);
11242 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11243 {
11244 for (token, progress) in &status.pending_work {
11245 if let Some(token_to_cancel) = token_to_cancel.as_ref() {
11246 if token != token_to_cancel {
11247 continue;
11248 }
11249 }
11250 if progress.is_cancellable {
11251 server
11252 .notify::<lsp::notification::WorkDoneProgressCancel>(
11253 &WorkDoneProgressCancelParams {
11254 token: lsp::NumberOrString::String(token.clone()),
11255 },
11256 )
11257 .ok();
11258 }
11259 }
11260 }
11261 } else if let Some((client, project_id)) = self.upstream_client() {
11262 let request = client.request(proto::CancelLanguageServerWork {
11263 project_id,
11264 work: Some(
11265 proto::cancel_language_server_work::Work::LanguageServerWork(
11266 proto::cancel_language_server_work::LanguageServerWork {
11267 language_server_id: server_id.to_proto(),
11268 token: token_to_cancel,
11269 },
11270 ),
11271 ),
11272 });
11273 cx.background_spawn(request).detach_and_log_err(cx);
11274 }
11275 }
11276
11277 fn register_supplementary_language_server(
11278 &mut self,
11279 id: LanguageServerId,
11280 name: LanguageServerName,
11281 server: Arc<LanguageServer>,
11282 cx: &mut Context<Self>,
11283 ) {
11284 if let Some(local) = self.as_local_mut() {
11285 local
11286 .supplementary_language_servers
11287 .insert(id, (name.clone(), server));
11288 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11289 }
11290 }
11291
11292 fn unregister_supplementary_language_server(
11293 &mut self,
11294 id: LanguageServerId,
11295 cx: &mut Context<Self>,
11296 ) {
11297 if let Some(local) = self.as_local_mut() {
11298 local.supplementary_language_servers.remove(&id);
11299 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11300 }
11301 }
11302
11303 pub(crate) fn supplementary_language_servers(
11304 &self,
11305 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11306 self.as_local().into_iter().flat_map(|local| {
11307 local
11308 .supplementary_language_servers
11309 .iter()
11310 .map(|(id, (name, _))| (*id, name.clone()))
11311 })
11312 }
11313
11314 pub fn language_server_adapter_for_id(
11315 &self,
11316 id: LanguageServerId,
11317 ) -> Option<Arc<CachedLspAdapter>> {
11318 self.as_local()
11319 .and_then(|local| local.language_servers.get(&id))
11320 .and_then(|language_server_state| match language_server_state {
11321 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11322 _ => None,
11323 })
11324 }
11325
11326 pub(super) fn update_local_worktree_language_servers(
11327 &mut self,
11328 worktree_handle: &Entity<Worktree>,
11329 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
11330 cx: &mut Context<Self>,
11331 ) {
11332 if changes.is_empty() {
11333 return;
11334 }
11335
11336 let Some(local) = self.as_local() else { return };
11337
11338 local.prettier_store.update(cx, |prettier_store, cx| {
11339 prettier_store.update_prettier_settings(&worktree_handle, changes, cx)
11340 });
11341
11342 let worktree_id = worktree_handle.read(cx).id();
11343 let mut language_server_ids = local
11344 .language_server_ids
11345 .iter()
11346 .flat_map(|((server_worktree, _), server_ids)| {
11347 server_ids
11348 .iter()
11349 .filter_map(|server_id| server_worktree.eq(&worktree_id).then(|| *server_id))
11350 })
11351 .collect::<Vec<_>>();
11352 language_server_ids.sort();
11353 language_server_ids.dedup();
11354
11355 let abs_path = worktree_handle.read(cx).abs_path();
11356 for server_id in &language_server_ids {
11357 if let Some(LanguageServerState::Running { server, .. }) =
11358 local.language_servers.get(server_id)
11359 {
11360 if let Some(watched_paths) = local
11361 .language_server_watched_paths
11362 .get(server_id)
11363 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11364 {
11365 let params = lsp::DidChangeWatchedFilesParams {
11366 changes: changes
11367 .iter()
11368 .filter_map(|(path, _, change)| {
11369 if !watched_paths.is_match(path) {
11370 return None;
11371 }
11372 let typ = match change {
11373 PathChange::Loaded => return None,
11374 PathChange::Added => lsp::FileChangeType::CREATED,
11375 PathChange::Removed => lsp::FileChangeType::DELETED,
11376 PathChange::Updated => lsp::FileChangeType::CHANGED,
11377 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11378 };
11379 Some(lsp::FileEvent {
11380 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
11381 typ,
11382 })
11383 })
11384 .collect(),
11385 };
11386 if !params.changes.is_empty() {
11387 server
11388 .notify::<lsp::notification::DidChangeWatchedFiles>(¶ms)
11389 .ok();
11390 }
11391 }
11392 }
11393 }
11394 }
11395
11396 pub fn wait_for_remote_buffer(
11397 &mut self,
11398 id: BufferId,
11399 cx: &mut Context<Self>,
11400 ) -> Task<Result<Entity<Buffer>>> {
11401 self.buffer_store.update(cx, |buffer_store, cx| {
11402 buffer_store.wait_for_remote_buffer(id, cx)
11403 })
11404 }
11405
11406 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11407 proto::Symbol {
11408 language_server_name: symbol.language_server_name.0.to_string(),
11409 source_worktree_id: symbol.source_worktree_id.to_proto(),
11410 language_server_id: symbol.source_language_server_id.to_proto(),
11411 worktree_id: symbol.path.worktree_id.to_proto(),
11412 path: symbol.path.path.as_ref().to_proto(),
11413 name: symbol.name.clone(),
11414 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11415 start: Some(proto::PointUtf16 {
11416 row: symbol.range.start.0.row,
11417 column: symbol.range.start.0.column,
11418 }),
11419 end: Some(proto::PointUtf16 {
11420 row: symbol.range.end.0.row,
11421 column: symbol.range.end.0.column,
11422 }),
11423 signature: symbol.signature.to_vec(),
11424 }
11425 }
11426
11427 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11428 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11429 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11430 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11431 let path = ProjectPath {
11432 worktree_id,
11433 path: Arc::<Path>::from_proto(serialized_symbol.path),
11434 };
11435
11436 let start = serialized_symbol.start.context("invalid start")?;
11437 let end = serialized_symbol.end.context("invalid end")?;
11438 Ok(CoreSymbol {
11439 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11440 source_worktree_id,
11441 source_language_server_id: LanguageServerId::from_proto(
11442 serialized_symbol.language_server_id,
11443 ),
11444 path,
11445 name: serialized_symbol.name,
11446 range: Unclipped(PointUtf16::new(start.row, start.column))
11447 ..Unclipped(PointUtf16::new(end.row, end.column)),
11448 kind,
11449 signature: serialized_symbol
11450 .signature
11451 .try_into()
11452 .map_err(|_| anyhow!("invalid signature"))?,
11453 })
11454 }
11455
11456 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11457 let mut serialized_completion = proto::Completion {
11458 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11459 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11460 new_text: completion.new_text.clone(),
11461 ..proto::Completion::default()
11462 };
11463 match &completion.source {
11464 CompletionSource::Lsp {
11465 insert_range,
11466 server_id,
11467 lsp_completion,
11468 lsp_defaults,
11469 resolved,
11470 } => {
11471 let (old_insert_start, old_insert_end) = insert_range
11472 .as_ref()
11473 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11474 .unzip();
11475
11476 serialized_completion.old_insert_start = old_insert_start;
11477 serialized_completion.old_insert_end = old_insert_end;
11478 serialized_completion.source = proto::completion::Source::Lsp as i32;
11479 serialized_completion.server_id = server_id.0 as u64;
11480 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11481 serialized_completion.lsp_defaults = lsp_defaults
11482 .as_deref()
11483 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11484 serialized_completion.resolved = *resolved;
11485 }
11486 CompletionSource::BufferWord {
11487 word_range,
11488 resolved,
11489 } => {
11490 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11491 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11492 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11493 serialized_completion.resolved = *resolved;
11494 }
11495 CompletionSource::Custom => {
11496 serialized_completion.source = proto::completion::Source::Custom as i32;
11497 serialized_completion.resolved = true;
11498 }
11499 CompletionSource::Dap { sort_text } => {
11500 serialized_completion.source = proto::completion::Source::Dap as i32;
11501 serialized_completion.sort_text = Some(sort_text.clone());
11502 }
11503 }
11504
11505 serialized_completion
11506 }
11507
11508 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11509 let old_replace_start = completion
11510 .old_replace_start
11511 .and_then(deserialize_anchor)
11512 .context("invalid old start")?;
11513 let old_replace_end = completion
11514 .old_replace_end
11515 .and_then(deserialize_anchor)
11516 .context("invalid old end")?;
11517 let insert_range = {
11518 match completion.old_insert_start.zip(completion.old_insert_end) {
11519 Some((start, end)) => {
11520 let start = deserialize_anchor(start).context("invalid insert old start")?;
11521 let end = deserialize_anchor(end).context("invalid insert old end")?;
11522 Some(start..end)
11523 }
11524 None => None,
11525 }
11526 };
11527 Ok(CoreCompletion {
11528 replace_range: old_replace_start..old_replace_end,
11529 new_text: completion.new_text,
11530 source: match proto::completion::Source::from_i32(completion.source) {
11531 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11532 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11533 insert_range,
11534 server_id: LanguageServerId::from_proto(completion.server_id),
11535 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11536 lsp_defaults: completion
11537 .lsp_defaults
11538 .as_deref()
11539 .map(serde_json::from_slice)
11540 .transpose()?,
11541 resolved: completion.resolved,
11542 },
11543 Some(proto::completion::Source::BufferWord) => {
11544 let word_range = completion
11545 .buffer_word_start
11546 .and_then(deserialize_anchor)
11547 .context("invalid buffer word start")?
11548 ..completion
11549 .buffer_word_end
11550 .and_then(deserialize_anchor)
11551 .context("invalid buffer word end")?;
11552 CompletionSource::BufferWord {
11553 word_range,
11554 resolved: completion.resolved,
11555 }
11556 }
11557 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11558 sort_text: completion
11559 .sort_text
11560 .context("expected sort text to exist")?,
11561 },
11562 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11563 },
11564 })
11565 }
11566
11567 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11568 let (kind, lsp_action) = match &action.lsp_action {
11569 LspAction::Action(code_action) => (
11570 proto::code_action::Kind::Action as i32,
11571 serde_json::to_vec(code_action).unwrap(),
11572 ),
11573 LspAction::Command(command) => (
11574 proto::code_action::Kind::Command as i32,
11575 serde_json::to_vec(command).unwrap(),
11576 ),
11577 LspAction::CodeLens(code_lens) => (
11578 proto::code_action::Kind::CodeLens as i32,
11579 serde_json::to_vec(code_lens).unwrap(),
11580 ),
11581 };
11582
11583 proto::CodeAction {
11584 server_id: action.server_id.0 as u64,
11585 start: Some(serialize_anchor(&action.range.start)),
11586 end: Some(serialize_anchor(&action.range.end)),
11587 lsp_action,
11588 kind,
11589 resolved: action.resolved,
11590 }
11591 }
11592
11593 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11594 let start = action
11595 .start
11596 .and_then(deserialize_anchor)
11597 .context("invalid start")?;
11598 let end = action
11599 .end
11600 .and_then(deserialize_anchor)
11601 .context("invalid end")?;
11602 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11603 Some(proto::code_action::Kind::Action) => {
11604 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11605 }
11606 Some(proto::code_action::Kind::Command) => {
11607 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11608 }
11609 Some(proto::code_action::Kind::CodeLens) => {
11610 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11611 }
11612 None => anyhow::bail!("Unknown action kind {}", action.kind),
11613 };
11614 Ok(CodeAction {
11615 server_id: LanguageServerId(action.server_id as usize),
11616 range: start..end,
11617 resolved: action.resolved,
11618 lsp_action,
11619 })
11620 }
11621
11622 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11623 match &formatting_result {
11624 Ok(_) => self.last_formatting_failure = None,
11625 Err(error) => {
11626 let error_string = format!("{error:#}");
11627 log::error!("Formatting failed: {error_string}");
11628 self.last_formatting_failure
11629 .replace(error_string.lines().join(" "));
11630 }
11631 }
11632 }
11633
11634 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11635 self.lsp_server_capabilities.remove(&for_server);
11636 for buffer_colors in self.lsp_document_colors.values_mut() {
11637 buffer_colors.colors.remove(&for_server);
11638 buffer_colors.cache_version += 1;
11639 }
11640 for buffer_lens in self.lsp_code_lens.values_mut() {
11641 buffer_lens.lens.remove(&for_server);
11642 }
11643 if let Some(local) = self.as_local_mut() {
11644 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11645 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11646 buffer_servers.remove(&for_server);
11647 }
11648 }
11649 }
11650
11651 pub fn result_id(
11652 &self,
11653 server_id: LanguageServerId,
11654 buffer_id: BufferId,
11655 cx: &App,
11656 ) -> Option<String> {
11657 let abs_path = self
11658 .buffer_store
11659 .read(cx)
11660 .get(buffer_id)
11661 .and_then(|b| File::from_dyn(b.read(cx).file()))
11662 .map(|f| f.abs_path(cx))?;
11663 self.as_local()?
11664 .buffer_pull_diagnostics_result_ids
11665 .get(&server_id)?
11666 .get(&abs_path)?
11667 .clone()
11668 }
11669
11670 pub fn all_result_ids(&self, server_id: LanguageServerId) -> HashMap<PathBuf, String> {
11671 let Some(local) = self.as_local() else {
11672 return HashMap::default();
11673 };
11674 local
11675 .buffer_pull_diagnostics_result_ids
11676 .get(&server_id)
11677 .into_iter()
11678 .flatten()
11679 .filter_map(|(abs_path, result_id)| Some((abs_path.clone(), result_id.clone()?)))
11680 .collect()
11681 }
11682
11683 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
11684 if let Some(LanguageServerState::Running {
11685 workspace_refresh_task: Some(workspace_refresh_task),
11686 ..
11687 }) = self
11688 .as_local_mut()
11689 .and_then(|local| local.language_servers.get_mut(&server_id))
11690 {
11691 workspace_refresh_task.refresh_tx.try_send(()).ok();
11692 }
11693 }
11694
11695 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
11696 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
11697 return;
11698 };
11699 let Some(local) = self.as_local_mut() else {
11700 return;
11701 };
11702
11703 for server_id in buffer.update(cx, |buffer, cx| {
11704 local.language_server_ids_for_buffer(buffer, cx)
11705 }) {
11706 if let Some(LanguageServerState::Running {
11707 workspace_refresh_task: Some(workspace_refresh_task),
11708 ..
11709 }) = local.language_servers.get_mut(&server_id)
11710 {
11711 workspace_refresh_task.refresh_tx.try_send(()).ok();
11712 }
11713 }
11714 }
11715
11716 fn apply_workspace_diagnostic_report(
11717 &mut self,
11718 server_id: LanguageServerId,
11719 report: lsp::WorkspaceDiagnosticReportResult,
11720 cx: &mut Context<Self>,
11721 ) {
11722 let workspace_diagnostics =
11723 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(report, server_id);
11724 let mut unchanged_buffers = HashSet::default();
11725 let mut changed_buffers = HashSet::default();
11726 let workspace_diagnostics_updates = workspace_diagnostics
11727 .into_iter()
11728 .filter_map(
11729 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
11730 LspPullDiagnostics::Response {
11731 server_id,
11732 uri,
11733 diagnostics,
11734 } => Some((server_id, uri, diagnostics, workspace_diagnostics.version)),
11735 LspPullDiagnostics::Default => None,
11736 },
11737 )
11738 .fold(
11739 HashMap::default(),
11740 |mut acc, (server_id, uri, diagnostics, version)| {
11741 let (result_id, diagnostics) = match diagnostics {
11742 PulledDiagnostics::Unchanged { result_id } => {
11743 unchanged_buffers.insert(uri.clone());
11744 (Some(result_id), Vec::new())
11745 }
11746 PulledDiagnostics::Changed {
11747 result_id,
11748 diagnostics,
11749 } => {
11750 changed_buffers.insert(uri.clone());
11751 (result_id, diagnostics)
11752 }
11753 };
11754 let disk_based_sources = Cow::Owned(
11755 self.language_server_adapter_for_id(server_id)
11756 .as_ref()
11757 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
11758 .unwrap_or(&[])
11759 .to_vec(),
11760 );
11761 acc.entry(server_id)
11762 .or_insert_with(Vec::new)
11763 .push(DocumentDiagnosticsUpdate {
11764 server_id,
11765 diagnostics: lsp::PublishDiagnosticsParams {
11766 uri,
11767 diagnostics,
11768 version,
11769 },
11770 result_id,
11771 disk_based_sources,
11772 });
11773 acc
11774 },
11775 );
11776
11777 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
11778 self.merge_lsp_diagnostics(
11779 DiagnosticSourceKind::Pulled,
11780 diagnostic_updates,
11781 |buffer, old_diagnostic, cx| {
11782 File::from_dyn(buffer.file())
11783 .and_then(|file| {
11784 let abs_path = file.as_local()?.abs_path(cx);
11785 lsp::Url::from_file_path(abs_path).ok()
11786 })
11787 .is_none_or(|buffer_uri| {
11788 unchanged_buffers.contains(&buffer_uri)
11789 || match old_diagnostic.source_kind {
11790 DiagnosticSourceKind::Pulled => {
11791 !changed_buffers.contains(&buffer_uri)
11792 }
11793 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
11794 true
11795 }
11796 }
11797 })
11798 },
11799 cx,
11800 )
11801 .log_err();
11802 }
11803 }
11804}
11805
11806fn subscribe_to_binary_statuses(
11807 languages: &Arc<LanguageRegistry>,
11808 cx: &mut Context<'_, LspStore>,
11809) -> Task<()> {
11810 let mut server_statuses = languages.language_server_binary_statuses();
11811 cx.spawn(async move |lsp_store, cx| {
11812 while let Some((server_name, binary_status)) = server_statuses.next().await {
11813 if lsp_store
11814 .update(cx, |_, cx| {
11815 let mut message = None;
11816 let binary_status = match binary_status {
11817 BinaryStatus::None => proto::ServerBinaryStatus::None,
11818 BinaryStatus::CheckingForUpdate => {
11819 proto::ServerBinaryStatus::CheckingForUpdate
11820 }
11821 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
11822 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
11823 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
11824 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
11825 BinaryStatus::Failed { error } => {
11826 message = Some(error);
11827 proto::ServerBinaryStatus::Failed
11828 }
11829 };
11830 cx.emit(LspStoreEvent::LanguageServerUpdate {
11831 // Binary updates are about the binary that might not have any language server id at that point.
11832 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
11833 language_server_id: LanguageServerId(0),
11834 name: Some(server_name),
11835 message: proto::update_language_server::Variant::StatusUpdate(
11836 proto::StatusUpdate {
11837 message,
11838 status: Some(proto::status_update::Status::Binary(
11839 binary_status as i32,
11840 )),
11841 },
11842 ),
11843 });
11844 })
11845 .is_err()
11846 {
11847 break;
11848 }
11849 }
11850 })
11851}
11852
11853fn lsp_workspace_diagnostics_refresh(
11854 server: Arc<LanguageServer>,
11855 cx: &mut Context<'_, LspStore>,
11856) -> Option<WorkspaceRefreshTask> {
11857 let identifier = match server.capabilities().diagnostic_provider? {
11858 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
11859 if !diagnostic_options.workspace_diagnostics {
11860 return None;
11861 }
11862 diagnostic_options.identifier
11863 }
11864 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
11865 let diagnostic_options = registration_options.diagnostic_options;
11866 if !diagnostic_options.workspace_diagnostics {
11867 return None;
11868 }
11869 diagnostic_options.identifier
11870 }
11871 };
11872
11873 let (progress_tx, mut progress_rx) = mpsc::channel(1);
11874 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
11875 refresh_tx.try_send(()).ok();
11876
11877 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
11878 let mut attempts = 0;
11879 let max_attempts = 50;
11880 let mut requests = 0;
11881
11882 loop {
11883 let Some(()) = refresh_rx.recv().await else {
11884 return;
11885 };
11886
11887 'request: loop {
11888 requests += 1;
11889 if attempts > max_attempts {
11890 log::error!(
11891 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
11892 );
11893 return;
11894 }
11895 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
11896 cx.background_executor()
11897 .timer(Duration::from_millis(backoff_millis))
11898 .await;
11899 attempts += 1;
11900
11901 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
11902 lsp_store
11903 .all_result_ids(server.server_id())
11904 .into_iter()
11905 .filter_map(|(abs_path, result_id)| {
11906 let uri = file_path_to_lsp_url(&abs_path).ok()?;
11907 Some(lsp::PreviousResultId {
11908 uri,
11909 value: result_id,
11910 })
11911 })
11912 .collect()
11913 }) else {
11914 return;
11915 };
11916
11917 let token = format!("workspace/diagnostic-{}-{}", server.server_id(), requests);
11918
11919 progress_rx.try_recv().ok();
11920 let timer =
11921 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
11922 let progress = pin!(progress_rx.recv().fuse());
11923 let response_result = server
11924 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
11925 lsp::WorkspaceDiagnosticParams {
11926 previous_result_ids,
11927 identifier: identifier.clone(),
11928 work_done_progress_params: Default::default(),
11929 partial_result_params: lsp::PartialResultParams {
11930 partial_result_token: Some(lsp::ProgressToken::String(token)),
11931 },
11932 },
11933 select(timer, progress).then(|either| match either {
11934 Either::Left((message, ..)) => ready(message).left_future(),
11935 Either::Right(..) => pending::<String>().right_future(),
11936 }),
11937 )
11938 .await;
11939
11940 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
11941 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
11942 match response_result {
11943 ConnectionResult::Timeout => {
11944 log::error!("Timeout during workspace diagnostics pull");
11945 continue 'request;
11946 }
11947 ConnectionResult::ConnectionReset => {
11948 log::error!("Server closed a workspace diagnostics pull request");
11949 continue 'request;
11950 }
11951 ConnectionResult::Result(Err(e)) => {
11952 log::error!("Error during workspace diagnostics pull: {e:#}");
11953 break 'request;
11954 }
11955 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
11956 attempts = 0;
11957 if lsp_store
11958 .update(cx, |lsp_store, cx| {
11959 lsp_store.apply_workspace_diagnostic_report(
11960 server.server_id(),
11961 pulled_diagnostics,
11962 cx,
11963 )
11964 })
11965 .is_err()
11966 {
11967 return;
11968 }
11969 break 'request;
11970 }
11971 }
11972 }
11973 }
11974 });
11975
11976 Some(WorkspaceRefreshTask {
11977 refresh_tx,
11978 progress_tx,
11979 task: workspace_query_language_server,
11980 })
11981}
11982
11983fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
11984 let CompletionSource::BufferWord {
11985 word_range,
11986 resolved,
11987 } = &mut completion.source
11988 else {
11989 return;
11990 };
11991 if *resolved {
11992 return;
11993 }
11994
11995 if completion.new_text
11996 != snapshot
11997 .text_for_range(word_range.clone())
11998 .collect::<String>()
11999 {
12000 return;
12001 }
12002
12003 let mut offset = 0;
12004 for chunk in snapshot.chunks(word_range.clone(), true) {
12005 let end_offset = offset + chunk.text.len();
12006 if let Some(highlight_id) = chunk.syntax_highlight_id {
12007 completion
12008 .label
12009 .runs
12010 .push((offset..end_offset, highlight_id));
12011 }
12012 offset = end_offset;
12013 }
12014 *resolved = true;
12015}
12016
12017impl EventEmitter<LspStoreEvent> for LspStore {}
12018
12019fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
12020 hover
12021 .contents
12022 .retain(|hover_block| !hover_block.text.trim().is_empty());
12023 if hover.contents.is_empty() {
12024 None
12025 } else {
12026 Some(hover)
12027 }
12028}
12029
12030async fn populate_labels_for_completions(
12031 new_completions: Vec<CoreCompletion>,
12032 language: Option<Arc<Language>>,
12033 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12034) -> Vec<Completion> {
12035 let lsp_completions = new_completions
12036 .iter()
12037 .filter_map(|new_completion| {
12038 if let Some(lsp_completion) = new_completion.source.lsp_completion(true) {
12039 Some(lsp_completion.into_owned())
12040 } else {
12041 None
12042 }
12043 })
12044 .collect::<Vec<_>>();
12045
12046 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
12047 lsp_adapter
12048 .labels_for_completions(&lsp_completions, language)
12049 .await
12050 .log_err()
12051 .unwrap_or_default()
12052 } else {
12053 Vec::new()
12054 }
12055 .into_iter()
12056 .fuse();
12057
12058 let mut completions = Vec::new();
12059 for completion in new_completions {
12060 match completion.source.lsp_completion(true) {
12061 Some(lsp_completion) => {
12062 let documentation = if let Some(docs) = lsp_completion.documentation.clone() {
12063 Some(docs.into())
12064 } else {
12065 None
12066 };
12067
12068 let mut label = labels.next().flatten().unwrap_or_else(|| {
12069 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
12070 });
12071 ensure_uniform_list_compatible_label(&mut label);
12072 completions.push(Completion {
12073 label,
12074 documentation,
12075 replace_range: completion.replace_range,
12076 new_text: completion.new_text,
12077 insert_text_mode: lsp_completion.insert_text_mode,
12078 source: completion.source,
12079 icon_path: None,
12080 confirm: None,
12081 });
12082 }
12083 None => {
12084 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
12085 ensure_uniform_list_compatible_label(&mut label);
12086 completions.push(Completion {
12087 label,
12088 documentation: None,
12089 replace_range: completion.replace_range,
12090 new_text: completion.new_text,
12091 source: completion.source,
12092 insert_text_mode: None,
12093 icon_path: None,
12094 confirm: None,
12095 });
12096 }
12097 }
12098 }
12099 completions
12100}
12101
12102#[derive(Debug)]
12103pub enum LanguageServerToQuery {
12104 /// Query language servers in order of users preference, up until one capable of handling the request is found.
12105 FirstCapable,
12106 /// Query a specific language server.
12107 Other(LanguageServerId),
12108}
12109
12110#[derive(Default)]
12111struct RenamePathsWatchedForServer {
12112 did_rename: Vec<RenameActionPredicate>,
12113 will_rename: Vec<RenameActionPredicate>,
12114}
12115
12116impl RenamePathsWatchedForServer {
12117 fn with_did_rename_patterns(
12118 mut self,
12119 did_rename: Option<&FileOperationRegistrationOptions>,
12120 ) -> Self {
12121 if let Some(did_rename) = did_rename {
12122 self.did_rename = did_rename
12123 .filters
12124 .iter()
12125 .filter_map(|filter| filter.try_into().log_err())
12126 .collect();
12127 }
12128 self
12129 }
12130 fn with_will_rename_patterns(
12131 mut self,
12132 will_rename: Option<&FileOperationRegistrationOptions>,
12133 ) -> Self {
12134 if let Some(will_rename) = will_rename {
12135 self.will_rename = will_rename
12136 .filters
12137 .iter()
12138 .filter_map(|filter| filter.try_into().log_err())
12139 .collect();
12140 }
12141 self
12142 }
12143
12144 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
12145 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
12146 }
12147 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
12148 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
12149 }
12150}
12151
12152impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
12153 type Error = globset::Error;
12154 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
12155 Ok(Self {
12156 kind: ops.pattern.matches.clone(),
12157 glob: GlobBuilder::new(&ops.pattern.glob)
12158 .case_insensitive(
12159 ops.pattern
12160 .options
12161 .as_ref()
12162 .map_or(false, |ops| ops.ignore_case.unwrap_or(false)),
12163 )
12164 .build()?
12165 .compile_matcher(),
12166 })
12167 }
12168}
12169struct RenameActionPredicate {
12170 glob: GlobMatcher,
12171 kind: Option<FileOperationPatternKind>,
12172}
12173
12174impl RenameActionPredicate {
12175 // Returns true if language server should be notified
12176 fn eval(&self, path: &str, is_dir: bool) -> bool {
12177 self.kind.as_ref().map_or(true, |kind| {
12178 let expected_kind = if is_dir {
12179 FileOperationPatternKind::Folder
12180 } else {
12181 FileOperationPatternKind::File
12182 };
12183 kind == &expected_kind
12184 }) && self.glob.is_match(path)
12185 }
12186}
12187
12188#[derive(Default)]
12189struct LanguageServerWatchedPaths {
12190 worktree_paths: HashMap<WorktreeId, GlobSet>,
12191 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
12192}
12193
12194#[derive(Default)]
12195struct LanguageServerWatchedPathsBuilder {
12196 worktree_paths: HashMap<WorktreeId, GlobSet>,
12197 abs_paths: HashMap<Arc<Path>, GlobSet>,
12198}
12199
12200impl LanguageServerWatchedPathsBuilder {
12201 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
12202 self.worktree_paths.insert(worktree_id, glob_set);
12203 }
12204 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
12205 self.abs_paths.insert(path, glob_set);
12206 }
12207 fn build(
12208 self,
12209 fs: Arc<dyn Fs>,
12210 language_server_id: LanguageServerId,
12211 cx: &mut Context<LspStore>,
12212 ) -> LanguageServerWatchedPaths {
12213 let project = cx.weak_entity();
12214
12215 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
12216 let abs_paths = self
12217 .abs_paths
12218 .into_iter()
12219 .map(|(abs_path, globset)| {
12220 let task = cx.spawn({
12221 let abs_path = abs_path.clone();
12222 let fs = fs.clone();
12223
12224 let lsp_store = project.clone();
12225 async move |_, cx| {
12226 maybe!(async move {
12227 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
12228 while let Some(update) = push_updates.0.next().await {
12229 let action = lsp_store
12230 .update(cx, |this, _| {
12231 let Some(local) = this.as_local() else {
12232 return ControlFlow::Break(());
12233 };
12234 let Some(watcher) = local
12235 .language_server_watched_paths
12236 .get(&language_server_id)
12237 else {
12238 return ControlFlow::Break(());
12239 };
12240 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
12241 "Watched abs path is not registered with a watcher",
12242 );
12243 let matching_entries = update
12244 .into_iter()
12245 .filter(|event| globs.is_match(&event.path))
12246 .collect::<Vec<_>>();
12247 this.lsp_notify_abs_paths_changed(
12248 language_server_id,
12249 matching_entries,
12250 );
12251 ControlFlow::Continue(())
12252 })
12253 .ok()?;
12254
12255 if action.is_break() {
12256 break;
12257 }
12258 }
12259 Some(())
12260 })
12261 .await;
12262 }
12263 });
12264 (abs_path, (globset, task))
12265 })
12266 .collect();
12267 LanguageServerWatchedPaths {
12268 worktree_paths: self.worktree_paths,
12269 abs_paths,
12270 }
12271 }
12272}
12273
12274struct LspBufferSnapshot {
12275 version: i32,
12276 snapshot: TextBufferSnapshot,
12277}
12278
12279/// A prompt requested by LSP server.
12280#[derive(Clone, Debug)]
12281pub struct LanguageServerPromptRequest {
12282 pub level: PromptLevel,
12283 pub message: String,
12284 pub actions: Vec<MessageActionItem>,
12285 pub lsp_name: String,
12286 pub(crate) response_channel: Sender<MessageActionItem>,
12287}
12288
12289impl LanguageServerPromptRequest {
12290 pub async fn respond(self, index: usize) -> Option<()> {
12291 if let Some(response) = self.actions.into_iter().nth(index) {
12292 self.response_channel.send(response).await.ok()
12293 } else {
12294 None
12295 }
12296 }
12297}
12298impl PartialEq for LanguageServerPromptRequest {
12299 fn eq(&self, other: &Self) -> bool {
12300 self.message == other.message && self.actions == other.actions
12301 }
12302}
12303
12304#[derive(Clone, Debug, PartialEq)]
12305pub enum LanguageServerLogType {
12306 Log(MessageType),
12307 Trace(Option<String>),
12308}
12309
12310impl LanguageServerLogType {
12311 pub fn to_proto(&self) -> proto::language_server_log::LogType {
12312 match self {
12313 Self::Log(log_type) => {
12314 let message_type = match *log_type {
12315 MessageType::ERROR => 1,
12316 MessageType::WARNING => 2,
12317 MessageType::INFO => 3,
12318 MessageType::LOG => 4,
12319 other => {
12320 log::warn!("Unknown lsp log message type: {:?}", other);
12321 4
12322 }
12323 };
12324 proto::language_server_log::LogType::LogMessageType(message_type)
12325 }
12326 Self::Trace(message) => {
12327 proto::language_server_log::LogType::LogTrace(proto::LspLogTrace {
12328 message: message.clone(),
12329 })
12330 }
12331 }
12332 }
12333
12334 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
12335 match log_type {
12336 proto::language_server_log::LogType::LogMessageType(message_type) => {
12337 Self::Log(match message_type {
12338 1 => MessageType::ERROR,
12339 2 => MessageType::WARNING,
12340 3 => MessageType::INFO,
12341 4 => MessageType::LOG,
12342 _ => MessageType::LOG,
12343 })
12344 }
12345 proto::language_server_log::LogType::LogTrace(trace) => Self::Trace(trace.message),
12346 }
12347 }
12348}
12349
12350pub struct WorkspaceRefreshTask {
12351 refresh_tx: mpsc::Sender<()>,
12352 progress_tx: mpsc::Sender<()>,
12353 #[allow(dead_code)]
12354 task: Task<()>,
12355}
12356
12357pub enum LanguageServerState {
12358 Starting {
12359 startup: Task<Option<Arc<LanguageServer>>>,
12360 /// List of language servers that will be added to the workspace once it's initialization completes.
12361 pending_workspace_folders: Arc<Mutex<BTreeSet<Url>>>,
12362 },
12363
12364 Running {
12365 adapter: Arc<CachedLspAdapter>,
12366 server: Arc<LanguageServer>,
12367 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
12368 workspace_refresh_task: Option<WorkspaceRefreshTask>,
12369 },
12370}
12371
12372impl LanguageServerState {
12373 fn add_workspace_folder(&self, uri: Url) {
12374 match self {
12375 LanguageServerState::Starting {
12376 pending_workspace_folders,
12377 ..
12378 } => {
12379 pending_workspace_folders.lock().insert(uri);
12380 }
12381 LanguageServerState::Running { server, .. } => {
12382 server.add_workspace_folder(uri);
12383 }
12384 }
12385 }
12386 fn _remove_workspace_folder(&self, uri: Url) {
12387 match self {
12388 LanguageServerState::Starting {
12389 pending_workspace_folders,
12390 ..
12391 } => {
12392 pending_workspace_folders.lock().remove(&uri);
12393 }
12394 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
12395 }
12396 }
12397}
12398
12399impl std::fmt::Debug for LanguageServerState {
12400 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12401 match self {
12402 LanguageServerState::Starting { .. } => {
12403 f.debug_struct("LanguageServerState::Starting").finish()
12404 }
12405 LanguageServerState::Running { .. } => {
12406 f.debug_struct("LanguageServerState::Running").finish()
12407 }
12408 }
12409 }
12410}
12411
12412#[derive(Clone, Debug, Serialize)]
12413pub struct LanguageServerProgress {
12414 pub is_disk_based_diagnostics_progress: bool,
12415 pub is_cancellable: bool,
12416 pub title: Option<String>,
12417 pub message: Option<String>,
12418 pub percentage: Option<usize>,
12419 #[serde(skip_serializing)]
12420 pub last_update_at: Instant,
12421}
12422
12423#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
12424pub struct DiagnosticSummary {
12425 pub error_count: usize,
12426 pub warning_count: usize,
12427}
12428
12429impl DiagnosticSummary {
12430 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
12431 let mut this = Self {
12432 error_count: 0,
12433 warning_count: 0,
12434 };
12435
12436 for entry in diagnostics {
12437 if entry.diagnostic.is_primary {
12438 match entry.diagnostic.severity {
12439 DiagnosticSeverity::ERROR => this.error_count += 1,
12440 DiagnosticSeverity::WARNING => this.warning_count += 1,
12441 _ => {}
12442 }
12443 }
12444 }
12445
12446 this
12447 }
12448
12449 pub fn is_empty(&self) -> bool {
12450 self.error_count == 0 && self.warning_count == 0
12451 }
12452
12453 pub fn to_proto(
12454 &self,
12455 language_server_id: LanguageServerId,
12456 path: &Path,
12457 ) -> proto::DiagnosticSummary {
12458 proto::DiagnosticSummary {
12459 path: path.to_proto(),
12460 language_server_id: language_server_id.0 as u64,
12461 error_count: self.error_count as u32,
12462 warning_count: self.warning_count as u32,
12463 }
12464 }
12465}
12466
12467#[derive(Clone, Debug)]
12468pub enum CompletionDocumentation {
12469 /// There is no documentation for this completion.
12470 Undocumented,
12471 /// A single line of documentation.
12472 SingleLine(SharedString),
12473 /// Multiple lines of plain text documentation.
12474 MultiLinePlainText(SharedString),
12475 /// Markdown documentation.
12476 MultiLineMarkdown(SharedString),
12477 /// Both single line and multiple lines of plain text documentation.
12478 SingleLineAndMultiLinePlainText {
12479 single_line: SharedString,
12480 plain_text: Option<SharedString>,
12481 },
12482}
12483
12484impl From<lsp::Documentation> for CompletionDocumentation {
12485 fn from(docs: lsp::Documentation) -> Self {
12486 match docs {
12487 lsp::Documentation::String(text) => {
12488 if text.lines().count() <= 1 {
12489 CompletionDocumentation::SingleLine(text.into())
12490 } else {
12491 CompletionDocumentation::MultiLinePlainText(text.into())
12492 }
12493 }
12494
12495 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
12496 lsp::MarkupKind::PlainText => {
12497 if value.lines().count() <= 1 {
12498 CompletionDocumentation::SingleLine(value.into())
12499 } else {
12500 CompletionDocumentation::MultiLinePlainText(value.into())
12501 }
12502 }
12503
12504 lsp::MarkupKind::Markdown => {
12505 CompletionDocumentation::MultiLineMarkdown(value.into())
12506 }
12507 },
12508 }
12509 }
12510}
12511
12512fn glob_literal_prefix(glob: &Path) -> PathBuf {
12513 glob.components()
12514 .take_while(|component| match component {
12515 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
12516 _ => true,
12517 })
12518 .collect()
12519}
12520
12521pub struct SshLspAdapter {
12522 name: LanguageServerName,
12523 binary: LanguageServerBinary,
12524 initialization_options: Option<String>,
12525 code_action_kinds: Option<Vec<CodeActionKind>>,
12526}
12527
12528impl SshLspAdapter {
12529 pub fn new(
12530 name: LanguageServerName,
12531 binary: LanguageServerBinary,
12532 initialization_options: Option<String>,
12533 code_action_kinds: Option<String>,
12534 ) -> Self {
12535 Self {
12536 name,
12537 binary,
12538 initialization_options,
12539 code_action_kinds: code_action_kinds
12540 .as_ref()
12541 .and_then(|c| serde_json::from_str(c).ok()),
12542 }
12543 }
12544}
12545
12546#[async_trait(?Send)]
12547impl LspAdapter for SshLspAdapter {
12548 fn name(&self) -> LanguageServerName {
12549 self.name.clone()
12550 }
12551
12552 async fn initialization_options(
12553 self: Arc<Self>,
12554 _: &dyn Fs,
12555 _: &Arc<dyn LspAdapterDelegate>,
12556 ) -> Result<Option<serde_json::Value>> {
12557 let Some(options) = &self.initialization_options else {
12558 return Ok(None);
12559 };
12560 let result = serde_json::from_str(options)?;
12561 Ok(result)
12562 }
12563
12564 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
12565 self.code_action_kinds.clone()
12566 }
12567
12568 async fn check_if_user_installed(
12569 &self,
12570 _: &dyn LspAdapterDelegate,
12571 _: Arc<dyn LanguageToolchainStore>,
12572 _: &AsyncApp,
12573 ) -> Option<LanguageServerBinary> {
12574 Some(self.binary.clone())
12575 }
12576
12577 async fn cached_server_binary(
12578 &self,
12579 _: PathBuf,
12580 _: &dyn LspAdapterDelegate,
12581 ) -> Option<LanguageServerBinary> {
12582 None
12583 }
12584
12585 async fn fetch_latest_server_version(
12586 &self,
12587 _: &dyn LspAdapterDelegate,
12588 ) -> Result<Box<dyn 'static + Send + Any>> {
12589 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
12590 }
12591
12592 async fn fetch_server_binary(
12593 &self,
12594 _: Box<dyn 'static + Send + Any>,
12595 _: PathBuf,
12596 _: &dyn LspAdapterDelegate,
12597 ) -> Result<LanguageServerBinary> {
12598 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
12599 }
12600}
12601
12602pub fn language_server_settings<'a>(
12603 delegate: &'a dyn LspAdapterDelegate,
12604 language: &LanguageServerName,
12605 cx: &'a App,
12606) -> Option<&'a LspSettings> {
12607 language_server_settings_for(
12608 SettingsLocation {
12609 worktree_id: delegate.worktree_id(),
12610 path: delegate.worktree_root_path(),
12611 },
12612 language,
12613 cx,
12614 )
12615}
12616
12617pub(crate) fn language_server_settings_for<'a>(
12618 location: SettingsLocation<'a>,
12619 language: &LanguageServerName,
12620 cx: &'a App,
12621) -> Option<&'a LspSettings> {
12622 ProjectSettings::get(Some(location), cx).lsp.get(language)
12623}
12624
12625pub struct LocalLspAdapterDelegate {
12626 lsp_store: WeakEntity<LspStore>,
12627 worktree: worktree::Snapshot,
12628 fs: Arc<dyn Fs>,
12629 http_client: Arc<dyn HttpClient>,
12630 language_registry: Arc<LanguageRegistry>,
12631 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
12632}
12633
12634impl LocalLspAdapterDelegate {
12635 pub fn new(
12636 language_registry: Arc<LanguageRegistry>,
12637 environment: &Entity<ProjectEnvironment>,
12638 lsp_store: WeakEntity<LspStore>,
12639 worktree: &Entity<Worktree>,
12640 http_client: Arc<dyn HttpClient>,
12641 fs: Arc<dyn Fs>,
12642 cx: &mut App,
12643 ) -> Arc<Self> {
12644 let load_shell_env_task = environment.update(cx, |env, cx| {
12645 env.get_worktree_environment(worktree.clone(), cx)
12646 });
12647
12648 Arc::new(Self {
12649 lsp_store,
12650 worktree: worktree.read(cx).snapshot(),
12651 fs,
12652 http_client,
12653 language_registry,
12654 load_shell_env_task,
12655 })
12656 }
12657
12658 fn from_local_lsp(
12659 local: &LocalLspStore,
12660 worktree: &Entity<Worktree>,
12661 cx: &mut App,
12662 ) -> Arc<Self> {
12663 Self::new(
12664 local.languages.clone(),
12665 &local.environment,
12666 local.weak.clone(),
12667 worktree,
12668 local.http_client.clone(),
12669 local.fs.clone(),
12670 cx,
12671 )
12672 }
12673}
12674
12675#[async_trait]
12676impl LspAdapterDelegate for LocalLspAdapterDelegate {
12677 fn show_notification(&self, message: &str, cx: &mut App) {
12678 self.lsp_store
12679 .update(cx, |_, cx| {
12680 cx.emit(LspStoreEvent::Notification(message.to_owned()))
12681 })
12682 .ok();
12683 }
12684
12685 fn http_client(&self) -> Arc<dyn HttpClient> {
12686 self.http_client.clone()
12687 }
12688
12689 fn worktree_id(&self) -> WorktreeId {
12690 self.worktree.id()
12691 }
12692
12693 fn worktree_root_path(&self) -> &Path {
12694 self.worktree.abs_path().as_ref()
12695 }
12696
12697 async fn shell_env(&self) -> HashMap<String, String> {
12698 let task = self.load_shell_env_task.clone();
12699 task.await.unwrap_or_default()
12700 }
12701
12702 async fn npm_package_installed_version(
12703 &self,
12704 package_name: &str,
12705 ) -> Result<Option<(PathBuf, String)>> {
12706 let local_package_directory = self.worktree_root_path();
12707 let node_modules_directory = local_package_directory.join("node_modules");
12708
12709 if let Some(version) =
12710 read_package_installed_version(node_modules_directory.clone(), package_name).await?
12711 {
12712 return Ok(Some((node_modules_directory, version)));
12713 }
12714 let Some(npm) = self.which("npm".as_ref()).await else {
12715 log::warn!(
12716 "Failed to find npm executable for {:?}",
12717 local_package_directory
12718 );
12719 return Ok(None);
12720 };
12721
12722 let env = self.shell_env().await;
12723 let output = util::command::new_smol_command(&npm)
12724 .args(["root", "-g"])
12725 .envs(env)
12726 .current_dir(local_package_directory)
12727 .output()
12728 .await?;
12729 let global_node_modules =
12730 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
12731
12732 if let Some(version) =
12733 read_package_installed_version(global_node_modules.clone(), package_name).await?
12734 {
12735 return Ok(Some((global_node_modules, version)));
12736 }
12737 return Ok(None);
12738 }
12739
12740 #[cfg(not(target_os = "windows"))]
12741 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12742 let worktree_abs_path = self.worktree.abs_path();
12743 let shell_path = self.shell_env().await.get("PATH").cloned();
12744 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
12745 }
12746
12747 #[cfg(target_os = "windows")]
12748 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
12749 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
12750 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
12751 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
12752 which::which(command).ok()
12753 }
12754
12755 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
12756 let working_dir = self.worktree_root_path();
12757 let output = util::command::new_smol_command(&command.path)
12758 .args(command.arguments)
12759 .envs(command.env.clone().unwrap_or_default())
12760 .current_dir(working_dir)
12761 .output()
12762 .await?;
12763
12764 anyhow::ensure!(
12765 output.status.success(),
12766 "{}, stdout: {:?}, stderr: {:?}",
12767 output.status,
12768 String::from_utf8_lossy(&output.stdout),
12769 String::from_utf8_lossy(&output.stderr)
12770 );
12771 Ok(())
12772 }
12773
12774 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
12775 self.language_registry
12776 .update_lsp_binary_status(server_name, status);
12777 }
12778
12779 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
12780 self.language_registry
12781 .all_lsp_adapters()
12782 .into_iter()
12783 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
12784 .collect()
12785 }
12786
12787 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
12788 let dir = self.language_registry.language_server_download_dir(name)?;
12789
12790 if !dir.exists() {
12791 smol::fs::create_dir_all(&dir)
12792 .await
12793 .context("failed to create container directory")
12794 .log_err()?;
12795 }
12796
12797 Some(dir)
12798 }
12799
12800 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
12801 let entry = self
12802 .worktree
12803 .entry_for_path(&path)
12804 .with_context(|| format!("no worktree entry for path {path:?}"))?;
12805 let abs_path = self
12806 .worktree
12807 .absolutize(&entry.path)
12808 .with_context(|| format!("cannot absolutize path {path:?}"))?;
12809
12810 self.fs.load(&abs_path).await
12811 }
12812}
12813
12814async fn populate_labels_for_symbols(
12815 symbols: Vec<CoreSymbol>,
12816 language_registry: &Arc<LanguageRegistry>,
12817 lsp_adapter: Option<Arc<CachedLspAdapter>>,
12818 output: &mut Vec<Symbol>,
12819) {
12820 #[allow(clippy::mutable_key_type)]
12821 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
12822
12823 let mut unknown_paths = BTreeSet::new();
12824 for symbol in symbols {
12825 let language = language_registry
12826 .language_for_file_path(&symbol.path.path)
12827 .await
12828 .ok()
12829 .or_else(|| {
12830 unknown_paths.insert(symbol.path.path.clone());
12831 None
12832 });
12833 symbols_by_language
12834 .entry(language)
12835 .or_default()
12836 .push(symbol);
12837 }
12838
12839 for unknown_path in unknown_paths {
12840 log::info!(
12841 "no language found for symbol path {}",
12842 unknown_path.display()
12843 );
12844 }
12845
12846 let mut label_params = Vec::new();
12847 for (language, mut symbols) in symbols_by_language {
12848 label_params.clear();
12849 label_params.extend(
12850 symbols
12851 .iter_mut()
12852 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
12853 );
12854
12855 let mut labels = Vec::new();
12856 if let Some(language) = language {
12857 let lsp_adapter = lsp_adapter.clone().or_else(|| {
12858 language_registry
12859 .lsp_adapters(&language.name())
12860 .first()
12861 .cloned()
12862 });
12863 if let Some(lsp_adapter) = lsp_adapter {
12864 labels = lsp_adapter
12865 .labels_for_symbols(&label_params, &language)
12866 .await
12867 .log_err()
12868 .unwrap_or_default();
12869 }
12870 }
12871
12872 for ((symbol, (name, _)), label) in symbols
12873 .into_iter()
12874 .zip(label_params.drain(..))
12875 .zip(labels.into_iter().chain(iter::repeat(None)))
12876 {
12877 output.push(Symbol {
12878 language_server_name: symbol.language_server_name,
12879 source_worktree_id: symbol.source_worktree_id,
12880 source_language_server_id: symbol.source_language_server_id,
12881 path: symbol.path,
12882 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
12883 name,
12884 kind: symbol.kind,
12885 range: symbol.range,
12886 signature: symbol.signature,
12887 });
12888 }
12889 }
12890}
12891
12892fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
12893 match server.capabilities().text_document_sync.as_ref()? {
12894 lsp::TextDocumentSyncCapability::Kind(kind) => match *kind {
12895 lsp::TextDocumentSyncKind::NONE => None,
12896 lsp::TextDocumentSyncKind::FULL => Some(true),
12897 lsp::TextDocumentSyncKind::INCREMENTAL => Some(false),
12898 _ => None,
12899 },
12900 lsp::TextDocumentSyncCapability::Options(options) => match options.save.as_ref()? {
12901 lsp::TextDocumentSyncSaveOptions::Supported(supported) => {
12902 if *supported {
12903 Some(true)
12904 } else {
12905 None
12906 }
12907 }
12908 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
12909 Some(save_options.include_text.unwrap_or(false))
12910 }
12911 },
12912 }
12913}
12914
12915/// Completion items are displayed in a `UniformList`.
12916/// Usually, those items are single-line strings, but in LSP responses,
12917/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
12918/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
12919/// All that may lead to a newline being inserted into resulting `CodeLabel.text`, which will force `UniformList` to bloat each entry to occupy more space,
12920/// breaking the completions menu presentation.
12921///
12922/// Sanitize the text to ensure there are no newlines, or, if there are some, remove them and also remove long space sequences if there were newlines.
12923fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
12924 let mut new_text = String::with_capacity(label.text.len());
12925 let mut offset_map = vec![0; label.text.len() + 1];
12926 let mut last_char_was_space = false;
12927 let mut new_idx = 0;
12928 let mut chars = label.text.char_indices().fuse();
12929 let mut newlines_removed = false;
12930
12931 while let Some((idx, c)) = chars.next() {
12932 offset_map[idx] = new_idx;
12933
12934 match c {
12935 '\n' if last_char_was_space => {
12936 newlines_removed = true;
12937 }
12938 '\t' | ' ' if last_char_was_space => {}
12939 '\n' if !last_char_was_space => {
12940 new_text.push(' ');
12941 new_idx += 1;
12942 last_char_was_space = true;
12943 newlines_removed = true;
12944 }
12945 ' ' | '\t' => {
12946 new_text.push(' ');
12947 new_idx += 1;
12948 last_char_was_space = true;
12949 }
12950 _ => {
12951 new_text.push(c);
12952 new_idx += c.len_utf8();
12953 last_char_was_space = false;
12954 }
12955 }
12956 }
12957 offset_map[label.text.len()] = new_idx;
12958
12959 // Only modify the label if newlines were removed.
12960 if !newlines_removed {
12961 return;
12962 }
12963
12964 let last_index = new_idx;
12965 let mut run_ranges_errors = Vec::new();
12966 label.runs.retain_mut(|(range, _)| {
12967 match offset_map.get(range.start) {
12968 Some(&start) => range.start = start,
12969 None => {
12970 run_ranges_errors.push(range.clone());
12971 return false;
12972 }
12973 }
12974
12975 match offset_map.get(range.end) {
12976 Some(&end) => range.end = end,
12977 None => {
12978 run_ranges_errors.push(range.clone());
12979 range.end = last_index;
12980 }
12981 }
12982 true
12983 });
12984 if !run_ranges_errors.is_empty() {
12985 log::error!(
12986 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
12987 label.text
12988 );
12989 }
12990
12991 let mut wrong_filter_range = None;
12992 if label.filter_range == (0..label.text.len()) {
12993 label.filter_range = 0..new_text.len();
12994 } else {
12995 let mut original_filter_range = Some(label.filter_range.clone());
12996 match offset_map.get(label.filter_range.start) {
12997 Some(&start) => label.filter_range.start = start,
12998 None => {
12999 wrong_filter_range = original_filter_range.take();
13000 label.filter_range.start = last_index;
13001 }
13002 }
13003
13004 match offset_map.get(label.filter_range.end) {
13005 Some(&end) => label.filter_range.end = end,
13006 None => {
13007 wrong_filter_range = original_filter_range.take();
13008 label.filter_range.end = last_index;
13009 }
13010 }
13011 }
13012 if let Some(wrong_filter_range) = wrong_filter_range {
13013 log::error!(
13014 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
13015 label.text
13016 );
13017 }
13018
13019 label.text = new_text;
13020}
13021
13022#[cfg(test)]
13023mod tests {
13024 use language::HighlightId;
13025
13026 use super::*;
13027
13028 #[test]
13029 fn test_glob_literal_prefix() {
13030 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
13031 assert_eq!(
13032 glob_literal_prefix(Path::new("node_modules/**/*.js")),
13033 Path::new("node_modules")
13034 );
13035 assert_eq!(
13036 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13037 Path::new("foo")
13038 );
13039 assert_eq!(
13040 glob_literal_prefix(Path::new("foo/bar/baz.js")),
13041 Path::new("foo/bar/baz.js")
13042 );
13043
13044 #[cfg(target_os = "windows")]
13045 {
13046 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
13047 assert_eq!(
13048 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
13049 Path::new("node_modules")
13050 );
13051 assert_eq!(
13052 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
13053 Path::new("foo")
13054 );
13055 assert_eq!(
13056 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
13057 Path::new("foo/bar/baz.js")
13058 );
13059 }
13060 }
13061
13062 #[test]
13063 fn test_multi_len_chars_normalization() {
13064 let mut label = CodeLabel {
13065 text: "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
13066 runs: vec![(0..6, HighlightId(1))],
13067 filter_range: 0..6,
13068 };
13069 ensure_uniform_list_compatible_label(&mut label);
13070 assert_eq!(
13071 label,
13072 CodeLabel {
13073 text: "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
13074 runs: vec![(0..6, HighlightId(1))],
13075 filter_range: 0..6,
13076 }
13077 );
13078 }
13079}