1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
59 Subscription, Task, WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76 row_chunk::RowChunk,
77};
78use lsp::{
79 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
80 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
81 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
82 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
83 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
84 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
85 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
86 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
87};
88use node_runtime::read_package_installed_version;
89use parking_lot::Mutex;
90use postage::{mpsc, sink::Sink, stream::Stream, watch};
91use rand::prelude::*;
92use rpc::{
93 AnyProtoClient, ErrorCode, ErrorExt as _,
94 proto::{LspRequestId, LspRequestMessage as _},
95};
96use serde::Serialize;
97use serde_json::Value;
98use settings::{Settings, SettingsLocation, SettingsStore};
99use sha2::{Digest, Sha256};
100use snippet::Snippet;
101use std::{
102 any::TypeId,
103 borrow::Cow,
104 cell::RefCell,
105 cmp::{Ordering, Reverse},
106 collections::hash_map,
107 convert::TryInto,
108 ffi::OsStr,
109 future::ready,
110 iter, mem,
111 ops::{ControlFlow, Range},
112 path::{self, Path, PathBuf},
113 pin::pin,
114 rc::Rc,
115 sync::{
116 Arc,
117 atomic::{self, AtomicUsize},
118 },
119 time::{Duration, Instant},
120 vec,
121};
122use sum_tree::Dimensions;
123use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
124
125use util::{
126 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
127 paths::{PathStyle, SanitizedPath},
128 post_inc,
129 rel_path::RelPath,
130};
131
132pub use fs::*;
133pub use language::Location;
134pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
135#[cfg(any(test, feature = "test-support"))]
136pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
137pub use worktree::{
138 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
139 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
140};
141
142const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
143pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
144const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
145const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
146
147#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
148pub enum ProgressToken {
149 Number(i32),
150 String(SharedString),
151}
152
153impl std::fmt::Display for ProgressToken {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 match self {
156 Self::Number(number) => write!(f, "{number}"),
157 Self::String(string) => write!(f, "{string}"),
158 }
159 }
160}
161
162impl ProgressToken {
163 fn from_lsp(value: lsp::NumberOrString) -> Self {
164 match value {
165 lsp::NumberOrString::Number(number) => Self::Number(number),
166 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
167 }
168 }
169
170 fn to_lsp(&self) -> lsp::NumberOrString {
171 match self {
172 Self::Number(number) => lsp::NumberOrString::Number(*number),
173 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
174 }
175 }
176
177 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
178 Some(match value.value? {
179 proto::progress_token::Value::Number(number) => Self::Number(number),
180 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
181 })
182 }
183
184 fn to_proto(&self) -> proto::ProgressToken {
185 proto::ProgressToken {
186 value: Some(match self {
187 Self::Number(number) => proto::progress_token::Value::Number(*number),
188 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
189 }),
190 }
191 }
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq)]
195pub enum FormatTrigger {
196 Save,
197 Manual,
198}
199
200pub enum LspFormatTarget {
201 Buffers,
202 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
203}
204
205#[derive(Clone, PartialEq, Eq, Hash)]
206pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
207
208struct OpenLspBuffer(Entity<Buffer>);
209
210impl FormatTrigger {
211 fn from_proto(value: i32) -> FormatTrigger {
212 match value {
213 0 => FormatTrigger::Save,
214 1 => FormatTrigger::Manual,
215 _ => FormatTrigger::Save,
216 }
217 }
218}
219
220#[derive(Clone)]
221struct UnifiedLanguageServer {
222 id: LanguageServerId,
223 project_roots: HashSet<Arc<RelPath>>,
224}
225
226#[derive(Clone, Debug, Hash, PartialEq, Eq)]
227struct LanguageServerSeed {
228 worktree_id: WorktreeId,
229 name: LanguageServerName,
230 toolchain: Option<Toolchain>,
231 settings: Arc<LspSettings>,
232}
233
234#[derive(Debug)]
235pub struct DocumentDiagnosticsUpdate<'a, D> {
236 pub diagnostics: D,
237 pub result_id: Option<SharedString>,
238 pub registration_id: Option<SharedString>,
239 pub server_id: LanguageServerId,
240 pub disk_based_sources: Cow<'a, [String]>,
241}
242
243pub struct DocumentDiagnostics {
244 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
245 document_abs_path: PathBuf,
246 version: Option<i32>,
247}
248
249#[derive(Default, Debug)]
250struct DynamicRegistrations {
251 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
252 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
253}
254
255pub struct LocalLspStore {
256 weak: WeakEntity<LspStore>,
257 worktree_store: Entity<WorktreeStore>,
258 toolchain_store: Entity<LocalToolchainStore>,
259 http_client: Arc<dyn HttpClient>,
260 environment: Entity<ProjectEnvironment>,
261 fs: Arc<dyn Fs>,
262 languages: Arc<LanguageRegistry>,
263 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
264 yarn: Entity<YarnPathStore>,
265 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
266 buffers_being_formatted: HashSet<BufferId>,
267 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
268 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
269 watched_manifest_filenames: HashSet<ManifestName>,
270 language_server_paths_watched_for_rename:
271 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
272 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
273 supplementary_language_servers:
274 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
275 prettier_store: Entity<PrettierStore>,
276 next_diagnostic_group_id: usize,
277 diagnostics: HashMap<
278 WorktreeId,
279 HashMap<
280 Arc<RelPath>,
281 Vec<(
282 LanguageServerId,
283 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
284 )>,
285 >,
286 >,
287 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
288 _subscription: gpui::Subscription,
289 lsp_tree: LanguageServerTree,
290 registered_buffers: HashMap<BufferId, usize>,
291 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
292 buffer_pull_diagnostics_result_ids: HashMap<
293 LanguageServerId,
294 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
295 >,
296 workspace_pull_diagnostics_result_ids: HashMap<
297 LanguageServerId,
298 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
299 >,
300 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
301}
302
303impl LocalLspStore {
304 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
305 pub fn running_language_server_for_id(
306 &self,
307 id: LanguageServerId,
308 ) -> Option<&Arc<LanguageServer>> {
309 let language_server_state = self.language_servers.get(&id)?;
310
311 match language_server_state {
312 LanguageServerState::Running { server, .. } => Some(server),
313 LanguageServerState::Starting { .. } => None,
314 }
315 }
316
317 fn get_or_insert_language_server(
318 &mut self,
319 worktree_handle: &Entity<Worktree>,
320 delegate: Arc<LocalLspAdapterDelegate>,
321 disposition: &Arc<LaunchDisposition>,
322 language_name: &LanguageName,
323 cx: &mut App,
324 ) -> LanguageServerId {
325 let key = LanguageServerSeed {
326 worktree_id: worktree_handle.read(cx).id(),
327 name: disposition.server_name.clone(),
328 settings: disposition.settings.clone(),
329 toolchain: disposition.toolchain.clone(),
330 };
331 if let Some(state) = self.language_server_ids.get_mut(&key) {
332 state.project_roots.insert(disposition.path.path.clone());
333 state.id
334 } else {
335 let adapter = self
336 .languages
337 .lsp_adapters(language_name)
338 .into_iter()
339 .find(|adapter| adapter.name() == disposition.server_name)
340 .expect("To find LSP adapter");
341 let new_language_server_id = self.start_language_server(
342 worktree_handle,
343 delegate,
344 adapter,
345 disposition.settings.clone(),
346 key.clone(),
347 cx,
348 );
349 if let Some(state) = self.language_server_ids.get_mut(&key) {
350 state.project_roots.insert(disposition.path.path.clone());
351 } else {
352 debug_assert!(
353 false,
354 "Expected `start_language_server` to ensure that `key` exists in a map"
355 );
356 }
357 new_language_server_id
358 }
359 }
360
361 fn start_language_server(
362 &mut self,
363 worktree_handle: &Entity<Worktree>,
364 delegate: Arc<LocalLspAdapterDelegate>,
365 adapter: Arc<CachedLspAdapter>,
366 settings: Arc<LspSettings>,
367 key: LanguageServerSeed,
368 cx: &mut App,
369 ) -> LanguageServerId {
370 let worktree = worktree_handle.read(cx);
371
372 let worktree_id = worktree.id();
373 let worktree_abs_path = worktree.abs_path();
374 let toolchain = key.toolchain.clone();
375 let override_options = settings.initialization_options.clone();
376
377 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
378
379 let server_id = self.languages.next_language_server_id();
380 log::trace!(
381 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
382 adapter.name.0
383 );
384
385 let wait_until_worktree_trust =
386 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
387 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
388 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
389 });
390 if can_trust {
391 self.restricted_worktrees_tasks.remove(&worktree_id);
392 None
393 } else {
394 match self.restricted_worktrees_tasks.entry(worktree_id) {
395 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
396 hash_map::Entry::Vacant(v) => {
397 let (mut tx, rx) = watch::channel::<bool>();
398 let lsp_store = self.weak.clone();
399 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
400 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
401 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
402 tx.blocking_send(true).ok();
403 lsp_store
404 .update(cx, |lsp_store, _| {
405 if let Some(local_lsp_store) =
406 lsp_store.as_local_mut()
407 {
408 local_lsp_store
409 .restricted_worktrees_tasks
410 .remove(&worktree_id);
411 }
412 })
413 .ok();
414 }
415 }
416 });
417 v.insert((subscription, rx.clone()));
418 Some(rx)
419 }
420 }
421 }
422 });
423 let update_binary_status = wait_until_worktree_trust.is_none();
424
425 let binary = self.get_language_server_binary(
426 worktree_abs_path.clone(),
427 adapter.clone(),
428 settings,
429 toolchain.clone(),
430 delegate.clone(),
431 true,
432 wait_until_worktree_trust,
433 cx,
434 );
435 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
436
437 let pending_server = cx.spawn({
438 let adapter = adapter.clone();
439 let server_name = adapter.name.clone();
440 let stderr_capture = stderr_capture.clone();
441 #[cfg(any(test, feature = "test-support"))]
442 let lsp_store = self.weak.clone();
443 let pending_workspace_folders = pending_workspace_folders.clone();
444 async move |cx| {
445 let binary = binary.await?;
446 #[cfg(any(test, feature = "test-support"))]
447 if let Some(server) = lsp_store
448 .update(&mut cx.clone(), |this, cx| {
449 this.languages.create_fake_language_server(
450 server_id,
451 &server_name,
452 binary.clone(),
453 &mut cx.to_async(),
454 )
455 })
456 .ok()
457 .flatten()
458 {
459 return Ok(server);
460 }
461
462 let code_action_kinds = adapter.code_action_kinds();
463 lsp::LanguageServer::new(
464 stderr_capture,
465 server_id,
466 server_name,
467 binary,
468 &worktree_abs_path,
469 code_action_kinds,
470 Some(pending_workspace_folders),
471 cx,
472 )
473 }
474 });
475
476 let startup = {
477 let server_name = adapter.name.0.clone();
478 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
479 let key = key.clone();
480 let adapter = adapter.clone();
481 let lsp_store = self.weak.clone();
482 let pending_workspace_folders = pending_workspace_folders.clone();
483
484 let pull_diagnostics = ProjectSettings::get_global(cx)
485 .diagnostics
486 .lsp_pull_diagnostics
487 .enabled;
488 cx.spawn(async move |cx| {
489 let result = async {
490 let language_server = pending_server.await?;
491
492 let workspace_config = Self::workspace_configuration_for_adapter(
493 adapter.adapter.clone(),
494 &delegate,
495 toolchain,
496 None,
497 cx,
498 )
499 .await?;
500
501 let mut initialization_options = Self::initialization_options_for_adapter(
502 adapter.adapter.clone(),
503 &delegate,
504 )
505 .await?;
506
507 match (&mut initialization_options, override_options) {
508 (Some(initialization_options), Some(override_options)) => {
509 merge_json_value_into(override_options, initialization_options);
510 }
511 (None, override_options) => initialization_options = override_options,
512 _ => {}
513 }
514
515 let initialization_params = cx.update(|cx| {
516 let mut params =
517 language_server.default_initialize_params(pull_diagnostics, cx);
518 params.initialization_options = initialization_options;
519 adapter.adapter.prepare_initialize_params(params, cx)
520 })??;
521
522 Self::setup_lsp_messages(
523 lsp_store.clone(),
524 &language_server,
525 delegate.clone(),
526 adapter.clone(),
527 );
528
529 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
530 settings: workspace_config,
531 };
532 let language_server = cx
533 .update(|cx| {
534 language_server.initialize(
535 initialization_params,
536 Arc::new(did_change_configuration_params.clone()),
537 cx,
538 )
539 })?
540 .await
541 .inspect_err(|_| {
542 if let Some(lsp_store) = lsp_store.upgrade() {
543 lsp_store
544 .update(cx, |lsp_store, cx| {
545 lsp_store.cleanup_lsp_data(server_id);
546 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
547 })
548 .ok();
549 }
550 })?;
551
552 language_server.notify::<lsp::notification::DidChangeConfiguration>(
553 did_change_configuration_params,
554 )?;
555
556 anyhow::Ok(language_server)
557 }
558 .await;
559
560 match result {
561 Ok(server) => {
562 lsp_store
563 .update(cx, |lsp_store, cx| {
564 lsp_store.insert_newly_running_language_server(
565 adapter,
566 server.clone(),
567 server_id,
568 key,
569 pending_workspace_folders,
570 cx,
571 );
572 })
573 .ok();
574 stderr_capture.lock().take();
575 Some(server)
576 }
577
578 Err(err) => {
579 let log = stderr_capture.lock().take().unwrap_or_default();
580 delegate.update_status(
581 adapter.name(),
582 BinaryStatus::Failed {
583 error: if log.is_empty() {
584 format!("{err:#}")
585 } else {
586 format!("{err:#}\n-- stderr --\n{log}")
587 },
588 },
589 );
590 log::error!("Failed to start language server {server_name:?}: {err:?}");
591 if !log.is_empty() {
592 log::error!("server stderr: {log}");
593 }
594 None
595 }
596 }
597 })
598 };
599 let state = LanguageServerState::Starting {
600 startup,
601 pending_workspace_folders,
602 };
603
604 if update_binary_status {
605 self.languages
606 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
607 }
608
609 self.language_servers.insert(server_id, state);
610 self.language_server_ids
611 .entry(key)
612 .or_insert(UnifiedLanguageServer {
613 id: server_id,
614 project_roots: Default::default(),
615 });
616 server_id
617 }
618
619 fn get_language_server_binary(
620 &self,
621 worktree_abs_path: Arc<Path>,
622 adapter: Arc<CachedLspAdapter>,
623 settings: Arc<LspSettings>,
624 toolchain: Option<Toolchain>,
625 delegate: Arc<dyn LspAdapterDelegate>,
626 allow_binary_download: bool,
627 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
628 cx: &mut App,
629 ) -> Task<Result<LanguageServerBinary>> {
630 if let Some(settings) = &settings.binary
631 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
632 {
633 let settings = settings.clone();
634 let languages = self.languages.clone();
635 return cx.background_spawn(async move {
636 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
637 let already_trusted = *wait_until_worktree_trust.borrow();
638 if !already_trusted {
639 log::info!(
640 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
641 adapter.name(),
642 );
643 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
644 if worktree_trusted {
645 break;
646 }
647 }
648 log::info!(
649 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
650 adapter.name(),
651 );
652 }
653 languages
654 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
655 }
656 let mut env = delegate.shell_env().await;
657 env.extend(settings.env.unwrap_or_default());
658
659 Ok(LanguageServerBinary {
660 path: delegate.resolve_executable_path(path),
661 env: Some(env),
662 arguments: settings
663 .arguments
664 .unwrap_or_default()
665 .iter()
666 .map(Into::into)
667 .collect(),
668 })
669 });
670 }
671 let lsp_binary_options = LanguageServerBinaryOptions {
672 allow_path_lookup: !settings
673 .binary
674 .as_ref()
675 .and_then(|b| b.ignore_system_version)
676 .unwrap_or_default(),
677 allow_binary_download,
678 pre_release: settings
679 .fetch
680 .as_ref()
681 .and_then(|f| f.pre_release)
682 .unwrap_or(false),
683 };
684
685 cx.spawn(async move |cx| {
686 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
687 let already_trusted = *wait_until_worktree_trust.borrow();
688 if !already_trusted {
689 log::info!(
690 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
691 adapter.name(),
692 );
693 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
694 if worktree_trusted {
695 break;
696 }
697 }
698 log::info!(
699 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
700 adapter.name(),
701 );
702 }
703 }
704
705 let (existing_binary, maybe_download_binary) = adapter
706 .clone()
707 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
708 .await
709 .await;
710
711 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
712
713 let mut binary = match (existing_binary, maybe_download_binary) {
714 (binary, None) => binary?,
715 (Err(_), Some(downloader)) => downloader.await?,
716 (Ok(existing_binary), Some(downloader)) => {
717 let mut download_timeout = cx
718 .background_executor()
719 .timer(SERVER_DOWNLOAD_TIMEOUT)
720 .fuse();
721 let mut downloader = downloader.fuse();
722 futures::select! {
723 _ = download_timeout => {
724 // Return existing binary and kick the existing work to the background.
725 cx.spawn(async move |_| downloader.await).detach();
726 Ok(existing_binary)
727 },
728 downloaded_or_existing_binary = downloader => {
729 // If download fails, this results in the existing binary.
730 downloaded_or_existing_binary
731 }
732 }?
733 }
734 };
735 let mut shell_env = delegate.shell_env().await;
736
737 shell_env.extend(binary.env.unwrap_or_default());
738
739 if let Some(settings) = settings.binary.as_ref() {
740 if let Some(arguments) = &settings.arguments {
741 binary.arguments = arguments.iter().map(Into::into).collect();
742 }
743 if let Some(env) = &settings.env {
744 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
745 }
746 }
747
748 binary.env = Some(shell_env);
749 Ok(binary)
750 })
751 }
752
753 fn setup_lsp_messages(
754 lsp_store: WeakEntity<LspStore>,
755 language_server: &LanguageServer,
756 delegate: Arc<dyn LspAdapterDelegate>,
757 adapter: Arc<CachedLspAdapter>,
758 ) {
759 let name = language_server.name();
760 let server_id = language_server.server_id();
761 language_server
762 .on_notification::<lsp::notification::PublishDiagnostics, _>({
763 let adapter = adapter.clone();
764 let this = lsp_store.clone();
765 move |mut params, cx| {
766 let adapter = adapter.clone();
767 if let Some(this) = this.upgrade() {
768 this.update(cx, |this, cx| {
769 {
770 let buffer = params
771 .uri
772 .to_file_path()
773 .map(|file_path| this.get_buffer(&file_path, cx))
774 .ok()
775 .flatten();
776 adapter.process_diagnostics(&mut params, server_id, buffer);
777 }
778
779 this.merge_lsp_diagnostics(
780 DiagnosticSourceKind::Pushed,
781 vec![DocumentDiagnosticsUpdate {
782 server_id,
783 diagnostics: params,
784 result_id: None,
785 disk_based_sources: Cow::Borrowed(
786 &adapter.disk_based_diagnostic_sources,
787 ),
788 registration_id: None,
789 }],
790 |_, diagnostic, cx| match diagnostic.source_kind {
791 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
792 adapter.retain_old_diagnostic(diagnostic, cx)
793 }
794 DiagnosticSourceKind::Pulled => true,
795 },
796 cx,
797 )
798 .log_err();
799 })
800 .ok();
801 }
802 }
803 })
804 .detach();
805 language_server
806 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
807 let adapter = adapter.adapter.clone();
808 let delegate = delegate.clone();
809 let this = lsp_store.clone();
810 move |params, cx| {
811 let adapter = adapter.clone();
812 let delegate = delegate.clone();
813 let this = this.clone();
814 let mut cx = cx.clone();
815 async move {
816 let toolchain_for_id = this
817 .update(&mut cx, |this, _| {
818 this.as_local()?.language_server_ids.iter().find_map(
819 |(seed, value)| {
820 (value.id == server_id).then(|| seed.toolchain.clone())
821 },
822 )
823 })?
824 .context("Expected the LSP store to be in a local mode")?;
825
826 let mut scope_uri_to_workspace_config = BTreeMap::new();
827 for item in ¶ms.items {
828 let scope_uri = item.scope_uri.clone();
829 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
830 scope_uri_to_workspace_config.entry(scope_uri.clone())
831 else {
832 // We've already queried workspace configuration of this URI.
833 continue;
834 };
835 let workspace_config = Self::workspace_configuration_for_adapter(
836 adapter.clone(),
837 &delegate,
838 toolchain_for_id.clone(),
839 scope_uri,
840 &mut cx,
841 )
842 .await?;
843 new_scope_uri.insert(workspace_config);
844 }
845
846 Ok(params
847 .items
848 .into_iter()
849 .filter_map(|item| {
850 let workspace_config =
851 scope_uri_to_workspace_config.get(&item.scope_uri)?;
852 if let Some(section) = &item.section {
853 Some(
854 workspace_config
855 .get(section)
856 .cloned()
857 .unwrap_or(serde_json::Value::Null),
858 )
859 } else {
860 Some(workspace_config.clone())
861 }
862 })
863 .collect())
864 }
865 }
866 })
867 .detach();
868
869 language_server
870 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
871 let this = lsp_store.clone();
872 move |_, cx| {
873 let this = this.clone();
874 let cx = cx.clone();
875 async move {
876 let Some(server) =
877 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
878 else {
879 return Ok(None);
880 };
881 let root = server.workspace_folders();
882 Ok(Some(
883 root.into_iter()
884 .map(|uri| WorkspaceFolder {
885 uri,
886 name: Default::default(),
887 })
888 .collect(),
889 ))
890 }
891 }
892 })
893 .detach();
894 // Even though we don't have handling for these requests, respond to them to
895 // avoid stalling any language server like `gopls` which waits for a response
896 // to these requests when initializing.
897 language_server
898 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
899 let this = lsp_store.clone();
900 move |params, cx| {
901 let this = this.clone();
902 let mut cx = cx.clone();
903 async move {
904 this.update(&mut cx, |this, _| {
905 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
906 {
907 status
908 .progress_tokens
909 .insert(ProgressToken::from_lsp(params.token));
910 }
911 })?;
912
913 Ok(())
914 }
915 }
916 })
917 .detach();
918
919 language_server
920 .on_request::<lsp::request::RegisterCapability, _, _>({
921 let lsp_store = lsp_store.clone();
922 move |params, cx| {
923 let lsp_store = lsp_store.clone();
924 let mut cx = cx.clone();
925 async move {
926 lsp_store
927 .update(&mut cx, |lsp_store, cx| {
928 if lsp_store.as_local().is_some() {
929 match lsp_store
930 .register_server_capabilities(server_id, params, cx)
931 {
932 Ok(()) => {}
933 Err(e) => {
934 log::error!(
935 "Failed to register server capabilities: {e:#}"
936 );
937 }
938 };
939 }
940 })
941 .ok();
942 Ok(())
943 }
944 }
945 })
946 .detach();
947
948 language_server
949 .on_request::<lsp::request::UnregisterCapability, _, _>({
950 let lsp_store = lsp_store.clone();
951 move |params, cx| {
952 let lsp_store = lsp_store.clone();
953 let mut cx = cx.clone();
954 async move {
955 lsp_store
956 .update(&mut cx, |lsp_store, cx| {
957 if lsp_store.as_local().is_some() {
958 match lsp_store
959 .unregister_server_capabilities(server_id, params, cx)
960 {
961 Ok(()) => {}
962 Err(e) => {
963 log::error!(
964 "Failed to unregister server capabilities: {e:#}"
965 );
966 }
967 }
968 }
969 })
970 .ok();
971 Ok(())
972 }
973 }
974 })
975 .detach();
976
977 language_server
978 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
979 let this = lsp_store.clone();
980 move |params, cx| {
981 let mut cx = cx.clone();
982 let this = this.clone();
983 async move {
984 LocalLspStore::on_lsp_workspace_edit(
985 this.clone(),
986 params,
987 server_id,
988 &mut cx,
989 )
990 .await
991 }
992 }
993 })
994 .detach();
995
996 language_server
997 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
998 let lsp_store = lsp_store.clone();
999 let request_id = Arc::new(AtomicUsize::new(0));
1000 move |(), cx| {
1001 let lsp_store = lsp_store.clone();
1002 let request_id = request_id.clone();
1003 let mut cx = cx.clone();
1004 async move {
1005 lsp_store
1006 .update(&mut cx, |lsp_store, cx| {
1007 let request_id =
1008 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1009 cx.emit(LspStoreEvent::RefreshInlayHints {
1010 server_id,
1011 request_id,
1012 });
1013 lsp_store
1014 .downstream_client
1015 .as_ref()
1016 .map(|(client, project_id)| {
1017 client.send(proto::RefreshInlayHints {
1018 project_id: *project_id,
1019 server_id: server_id.to_proto(),
1020 request_id: request_id.map(|id| id as u64),
1021 })
1022 })
1023 })?
1024 .transpose()?;
1025 Ok(())
1026 }
1027 }
1028 })
1029 .detach();
1030
1031 language_server
1032 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1033 let this = lsp_store.clone();
1034 move |(), cx| {
1035 let this = this.clone();
1036 let mut cx = cx.clone();
1037 async move {
1038 this.update(&mut cx, |this, cx| {
1039 cx.emit(LspStoreEvent::RefreshCodeLens);
1040 this.downstream_client.as_ref().map(|(client, project_id)| {
1041 client.send(proto::RefreshCodeLens {
1042 project_id: *project_id,
1043 })
1044 })
1045 })?
1046 .transpose()?;
1047 Ok(())
1048 }
1049 }
1050 })
1051 .detach();
1052
1053 language_server
1054 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1055 let this = lsp_store.clone();
1056 move |(), cx| {
1057 let this = this.clone();
1058 let mut cx = cx.clone();
1059 async move {
1060 this.update(&mut cx, |lsp_store, _| {
1061 lsp_store.pull_workspace_diagnostics(server_id);
1062 lsp_store
1063 .downstream_client
1064 .as_ref()
1065 .map(|(client, project_id)| {
1066 client.send(proto::PullWorkspaceDiagnostics {
1067 project_id: *project_id,
1068 server_id: server_id.to_proto(),
1069 })
1070 })
1071 })?
1072 .transpose()?;
1073 Ok(())
1074 }
1075 }
1076 })
1077 .detach();
1078
1079 language_server
1080 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1081 let this = lsp_store.clone();
1082 let name = name.to_string();
1083 move |params, cx| {
1084 let this = this.clone();
1085 let name = name.to_string();
1086 let mut cx = cx.clone();
1087 async move {
1088 let actions = params.actions.unwrap_or_default();
1089 let (tx, rx) = smol::channel::bounded(1);
1090 let request = LanguageServerPromptRequest {
1091 level: match params.typ {
1092 lsp::MessageType::ERROR => PromptLevel::Critical,
1093 lsp::MessageType::WARNING => PromptLevel::Warning,
1094 _ => PromptLevel::Info,
1095 },
1096 message: params.message,
1097 actions,
1098 response_channel: tx,
1099 lsp_name: name.clone(),
1100 };
1101
1102 let did_update = this
1103 .update(&mut cx, |_, cx| {
1104 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1105 })
1106 .is_ok();
1107 if did_update {
1108 let response = rx.recv().await.ok();
1109 Ok(response)
1110 } else {
1111 Ok(None)
1112 }
1113 }
1114 }
1115 })
1116 .detach();
1117 language_server
1118 .on_notification::<lsp::notification::ShowMessage, _>({
1119 let this = lsp_store.clone();
1120 let name = name.to_string();
1121 move |params, cx| {
1122 let this = this.clone();
1123 let name = name.to_string();
1124 let mut cx = cx.clone();
1125
1126 let (tx, _) = smol::channel::bounded(1);
1127 let request = LanguageServerPromptRequest {
1128 level: match params.typ {
1129 lsp::MessageType::ERROR => PromptLevel::Critical,
1130 lsp::MessageType::WARNING => PromptLevel::Warning,
1131 _ => PromptLevel::Info,
1132 },
1133 message: params.message,
1134 actions: vec![],
1135 response_channel: tx,
1136 lsp_name: name,
1137 };
1138
1139 let _ = this.update(&mut cx, |_, cx| {
1140 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1141 });
1142 }
1143 })
1144 .detach();
1145
1146 let disk_based_diagnostics_progress_token =
1147 adapter.disk_based_diagnostics_progress_token.clone();
1148
1149 language_server
1150 .on_notification::<lsp::notification::Progress, _>({
1151 let this = lsp_store.clone();
1152 move |params, cx| {
1153 if let Some(this) = this.upgrade() {
1154 this.update(cx, |this, cx| {
1155 this.on_lsp_progress(
1156 params,
1157 server_id,
1158 disk_based_diagnostics_progress_token.clone(),
1159 cx,
1160 );
1161 })
1162 .ok();
1163 }
1164 }
1165 })
1166 .detach();
1167
1168 language_server
1169 .on_notification::<lsp::notification::LogMessage, _>({
1170 let this = lsp_store.clone();
1171 move |params, cx| {
1172 if let Some(this) = this.upgrade() {
1173 this.update(cx, |_, cx| {
1174 cx.emit(LspStoreEvent::LanguageServerLog(
1175 server_id,
1176 LanguageServerLogType::Log(params.typ),
1177 params.message,
1178 ));
1179 })
1180 .ok();
1181 }
1182 }
1183 })
1184 .detach();
1185
1186 language_server
1187 .on_notification::<lsp::notification::LogTrace, _>({
1188 let this = lsp_store.clone();
1189 move |params, cx| {
1190 let mut cx = cx.clone();
1191 if let Some(this) = this.upgrade() {
1192 this.update(&mut cx, |_, cx| {
1193 cx.emit(LspStoreEvent::LanguageServerLog(
1194 server_id,
1195 LanguageServerLogType::Trace {
1196 verbose_info: params.verbose,
1197 },
1198 params.message,
1199 ));
1200 })
1201 .ok();
1202 }
1203 }
1204 })
1205 .detach();
1206
1207 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1208 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1209 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1210 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1211 }
1212
1213 fn shutdown_language_servers_on_quit(
1214 &mut self,
1215 _: &mut Context<LspStore>,
1216 ) -> impl Future<Output = ()> + use<> {
1217 let shutdown_futures = self
1218 .language_servers
1219 .drain()
1220 .map(|(_, server_state)| Self::shutdown_server(server_state))
1221 .collect::<Vec<_>>();
1222
1223 async move {
1224 join_all(shutdown_futures).await;
1225 }
1226 }
1227
1228 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1229 match server_state {
1230 LanguageServerState::Running { server, .. } => {
1231 if let Some(shutdown) = server.shutdown() {
1232 shutdown.await;
1233 }
1234 }
1235 LanguageServerState::Starting { startup, .. } => {
1236 if let Some(server) = startup.await
1237 && let Some(shutdown) = server.shutdown()
1238 {
1239 shutdown.await;
1240 }
1241 }
1242 }
1243 Ok(())
1244 }
1245
1246 fn language_servers_for_worktree(
1247 &self,
1248 worktree_id: WorktreeId,
1249 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1250 self.language_server_ids
1251 .iter()
1252 .filter_map(move |(seed, state)| {
1253 if seed.worktree_id != worktree_id {
1254 return None;
1255 }
1256
1257 if let Some(LanguageServerState::Running { server, .. }) =
1258 self.language_servers.get(&state.id)
1259 {
1260 Some(server)
1261 } else {
1262 None
1263 }
1264 })
1265 }
1266
1267 fn language_server_ids_for_project_path(
1268 &self,
1269 project_path: ProjectPath,
1270 language: &Language,
1271 cx: &mut App,
1272 ) -> Vec<LanguageServerId> {
1273 let Some(worktree) = self
1274 .worktree_store
1275 .read(cx)
1276 .worktree_for_id(project_path.worktree_id, cx)
1277 else {
1278 return Vec::new();
1279 };
1280 let delegate: Arc<dyn ManifestDelegate> =
1281 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1282
1283 self.lsp_tree
1284 .get(
1285 project_path,
1286 language.name(),
1287 language.manifest(),
1288 &delegate,
1289 cx,
1290 )
1291 .collect::<Vec<_>>()
1292 }
1293
1294 fn language_server_ids_for_buffer(
1295 &self,
1296 buffer: &Buffer,
1297 cx: &mut App,
1298 ) -> Vec<LanguageServerId> {
1299 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1300 let worktree_id = file.worktree_id(cx);
1301
1302 let path: Arc<RelPath> = file
1303 .path()
1304 .parent()
1305 .map(Arc::from)
1306 .unwrap_or_else(|| file.path().clone());
1307 let worktree_path = ProjectPath { worktree_id, path };
1308 self.language_server_ids_for_project_path(worktree_path, language, cx)
1309 } else {
1310 Vec::new()
1311 }
1312 }
1313
1314 fn language_servers_for_buffer<'a>(
1315 &'a self,
1316 buffer: &'a Buffer,
1317 cx: &'a mut App,
1318 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1319 self.language_server_ids_for_buffer(buffer, cx)
1320 .into_iter()
1321 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1322 LanguageServerState::Running {
1323 adapter, server, ..
1324 } => Some((adapter, server)),
1325 _ => None,
1326 })
1327 }
1328
1329 async fn execute_code_action_kind_locally(
1330 lsp_store: WeakEntity<LspStore>,
1331 mut buffers: Vec<Entity<Buffer>>,
1332 kind: CodeActionKind,
1333 push_to_history: bool,
1334 cx: &mut AsyncApp,
1335 ) -> anyhow::Result<ProjectTransaction> {
1336 // Do not allow multiple concurrent code actions requests for the
1337 // same buffer.
1338 lsp_store.update(cx, |this, cx| {
1339 let this = this.as_local_mut().unwrap();
1340 buffers.retain(|buffer| {
1341 this.buffers_being_formatted
1342 .insert(buffer.read(cx).remote_id())
1343 });
1344 })?;
1345 let _cleanup = defer({
1346 let this = lsp_store.clone();
1347 let mut cx = cx.clone();
1348 let buffers = &buffers;
1349 move || {
1350 this.update(&mut cx, |this, cx| {
1351 let this = this.as_local_mut().unwrap();
1352 for buffer in buffers {
1353 this.buffers_being_formatted
1354 .remove(&buffer.read(cx).remote_id());
1355 }
1356 })
1357 .ok();
1358 }
1359 });
1360 let mut project_transaction = ProjectTransaction::default();
1361
1362 for buffer in &buffers {
1363 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1364 buffer.update(cx, |buffer, cx| {
1365 lsp_store
1366 .as_local()
1367 .unwrap()
1368 .language_servers_for_buffer(buffer, cx)
1369 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1370 .collect::<Vec<_>>()
1371 })
1372 })?;
1373 for (_, language_server) in adapters_and_servers.iter() {
1374 let actions = Self::get_server_code_actions_from_action_kinds(
1375 &lsp_store,
1376 language_server.server_id(),
1377 vec![kind.clone()],
1378 buffer,
1379 cx,
1380 )
1381 .await?;
1382 Self::execute_code_actions_on_server(
1383 &lsp_store,
1384 language_server,
1385 actions,
1386 push_to_history,
1387 &mut project_transaction,
1388 cx,
1389 )
1390 .await?;
1391 }
1392 }
1393 Ok(project_transaction)
1394 }
1395
1396 async fn format_locally(
1397 lsp_store: WeakEntity<LspStore>,
1398 mut buffers: Vec<FormattableBuffer>,
1399 push_to_history: bool,
1400 trigger: FormatTrigger,
1401 logger: zlog::Logger,
1402 cx: &mut AsyncApp,
1403 ) -> anyhow::Result<ProjectTransaction> {
1404 // Do not allow multiple concurrent formatting requests for the
1405 // same buffer.
1406 lsp_store.update(cx, |this, cx| {
1407 let this = this.as_local_mut().unwrap();
1408 buffers.retain(|buffer| {
1409 this.buffers_being_formatted
1410 .insert(buffer.handle.read(cx).remote_id())
1411 });
1412 })?;
1413
1414 let _cleanup = defer({
1415 let this = lsp_store.clone();
1416 let mut cx = cx.clone();
1417 let buffers = &buffers;
1418 move || {
1419 this.update(&mut cx, |this, cx| {
1420 let this = this.as_local_mut().unwrap();
1421 for buffer in buffers {
1422 this.buffers_being_formatted
1423 .remove(&buffer.handle.read(cx).remote_id());
1424 }
1425 })
1426 .ok();
1427 }
1428 });
1429
1430 let mut project_transaction = ProjectTransaction::default();
1431
1432 for buffer in &buffers {
1433 zlog::debug!(
1434 logger =>
1435 "formatting buffer '{:?}'",
1436 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1437 );
1438 // Create an empty transaction to hold all of the formatting edits.
1439 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1440 // ensure no transactions created while formatting are
1441 // grouped with the previous transaction in the history
1442 // based on the transaction group interval
1443 buffer.finalize_last_transaction();
1444 buffer
1445 .start_transaction()
1446 .context("transaction already open")?;
1447 buffer.end_transaction(cx);
1448 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1449 buffer.finalize_last_transaction();
1450 anyhow::Ok(transaction_id)
1451 })??;
1452
1453 let result = Self::format_buffer_locally(
1454 lsp_store.clone(),
1455 buffer,
1456 formatting_transaction_id,
1457 trigger,
1458 logger,
1459 cx,
1460 )
1461 .await;
1462
1463 buffer.handle.update(cx, |buffer, cx| {
1464 let Some(formatting_transaction) =
1465 buffer.get_transaction(formatting_transaction_id).cloned()
1466 else {
1467 zlog::warn!(logger => "no formatting transaction");
1468 return;
1469 };
1470 if formatting_transaction.edit_ids.is_empty() {
1471 zlog::debug!(logger => "no changes made while formatting");
1472 buffer.forget_transaction(formatting_transaction_id);
1473 return;
1474 }
1475 if !push_to_history {
1476 zlog::trace!(logger => "forgetting format transaction");
1477 buffer.forget_transaction(formatting_transaction.id);
1478 }
1479 project_transaction
1480 .0
1481 .insert(cx.entity(), formatting_transaction);
1482 })?;
1483
1484 result?;
1485 }
1486
1487 Ok(project_transaction)
1488 }
1489
1490 async fn format_buffer_locally(
1491 lsp_store: WeakEntity<LspStore>,
1492 buffer: &FormattableBuffer,
1493 formatting_transaction_id: clock::Lamport,
1494 trigger: FormatTrigger,
1495 logger: zlog::Logger,
1496 cx: &mut AsyncApp,
1497 ) -> Result<()> {
1498 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1499 buffer.handle.update(cx, |buffer, cx| {
1500 let adapters_and_servers = lsp_store
1501 .as_local()
1502 .unwrap()
1503 .language_servers_for_buffer(buffer, cx)
1504 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1505 .collect::<Vec<_>>();
1506 let settings =
1507 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1508 .into_owned();
1509 (adapters_and_servers, settings)
1510 })
1511 })?;
1512
1513 /// Apply edits to the buffer that will become part of the formatting transaction.
1514 /// Fails if the buffer has been edited since the start of that transaction.
1515 fn extend_formatting_transaction(
1516 buffer: &FormattableBuffer,
1517 formatting_transaction_id: text::TransactionId,
1518 cx: &mut AsyncApp,
1519 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1520 ) -> anyhow::Result<()> {
1521 buffer.handle.update(cx, |buffer, cx| {
1522 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1523 if last_transaction_id != Some(formatting_transaction_id) {
1524 anyhow::bail!("Buffer edited while formatting. Aborting")
1525 }
1526 buffer.start_transaction();
1527 operation(buffer, cx);
1528 if let Some(transaction_id) = buffer.end_transaction(cx) {
1529 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1530 }
1531 Ok(())
1532 })?
1533 }
1534
1535 // handle whitespace formatting
1536 if settings.remove_trailing_whitespace_on_save {
1537 zlog::trace!(logger => "removing trailing whitespace");
1538 let diff = buffer
1539 .handle
1540 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1541 .await;
1542 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1543 buffer.apply_diff(diff, cx);
1544 })?;
1545 }
1546
1547 if settings.ensure_final_newline_on_save {
1548 zlog::trace!(logger => "ensuring final newline");
1549 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1550 buffer.ensure_final_newline(cx);
1551 })?;
1552 }
1553
1554 // Formatter for `code_actions_on_format` that runs before
1555 // the rest of the formatters
1556 let mut code_actions_on_format_formatters = None;
1557 let should_run_code_actions_on_format = !matches!(
1558 (trigger, &settings.format_on_save),
1559 (FormatTrigger::Save, &FormatOnSave::Off)
1560 );
1561 if should_run_code_actions_on_format {
1562 let have_code_actions_to_run_on_format = settings
1563 .code_actions_on_format
1564 .values()
1565 .any(|enabled| *enabled);
1566 if have_code_actions_to_run_on_format {
1567 zlog::trace!(logger => "going to run code actions on format");
1568 code_actions_on_format_formatters = Some(
1569 settings
1570 .code_actions_on_format
1571 .iter()
1572 .filter_map(|(action, enabled)| enabled.then_some(action))
1573 .cloned()
1574 .map(Formatter::CodeAction)
1575 .collect::<Vec<_>>(),
1576 );
1577 }
1578 }
1579
1580 let formatters = match (trigger, &settings.format_on_save) {
1581 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1582 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1583 settings.formatter.as_ref()
1584 }
1585 };
1586
1587 let formatters = code_actions_on_format_formatters
1588 .iter()
1589 .flatten()
1590 .chain(formatters);
1591
1592 for formatter in formatters {
1593 let formatter = if formatter == &Formatter::Auto {
1594 if settings.prettier.allowed {
1595 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1596 &Formatter::Prettier
1597 } else {
1598 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1599 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1600 }
1601 } else {
1602 formatter
1603 };
1604 match formatter {
1605 Formatter::Auto => unreachable!("Auto resolved above"),
1606 Formatter::Prettier => {
1607 let logger = zlog::scoped!(logger => "prettier");
1608 zlog::trace!(logger => "formatting");
1609 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1610
1611 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1612 lsp_store.prettier_store().unwrap().downgrade()
1613 })?;
1614 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1615 .await
1616 .transpose()?;
1617 let Some(diff) = diff else {
1618 zlog::trace!(logger => "No changes");
1619 continue;
1620 };
1621
1622 extend_formatting_transaction(
1623 buffer,
1624 formatting_transaction_id,
1625 cx,
1626 |buffer, cx| {
1627 buffer.apply_diff(diff, cx);
1628 },
1629 )?;
1630 }
1631 Formatter::External { command, arguments } => {
1632 let logger = zlog::scoped!(logger => "command");
1633 zlog::trace!(logger => "formatting");
1634 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1635
1636 let diff = Self::format_via_external_command(
1637 buffer,
1638 command.as_ref(),
1639 arguments.as_deref(),
1640 cx,
1641 )
1642 .await
1643 .with_context(|| {
1644 format!("Failed to format buffer via external command: {}", command)
1645 })?;
1646 let Some(diff) = diff else {
1647 zlog::trace!(logger => "No changes");
1648 continue;
1649 };
1650
1651 extend_formatting_transaction(
1652 buffer,
1653 formatting_transaction_id,
1654 cx,
1655 |buffer, cx| {
1656 buffer.apply_diff(diff, cx);
1657 },
1658 )?;
1659 }
1660 Formatter::LanguageServer(specifier) => {
1661 let logger = zlog::scoped!(logger => "language-server");
1662 zlog::trace!(logger => "formatting");
1663 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1664
1665 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1666 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1667 continue;
1668 };
1669
1670 let language_server = match specifier {
1671 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1672 adapters_and_servers.iter().find_map(|(adapter, server)| {
1673 if adapter.name.0.as_ref() == name {
1674 Some(server.clone())
1675 } else {
1676 None
1677 }
1678 })
1679 }
1680 settings::LanguageServerFormatterSpecifier::Current => {
1681 adapters_and_servers.first().map(|e| e.1.clone())
1682 }
1683 };
1684
1685 let Some(language_server) = language_server else {
1686 log::debug!(
1687 "No language server found to format buffer '{:?}'. Skipping",
1688 buffer_path_abs.as_path().to_string_lossy()
1689 );
1690 continue;
1691 };
1692
1693 zlog::trace!(
1694 logger =>
1695 "Formatting buffer '{:?}' using language server '{:?}'",
1696 buffer_path_abs.as_path().to_string_lossy(),
1697 language_server.name()
1698 );
1699
1700 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1701 zlog::trace!(logger => "formatting ranges");
1702 Self::format_ranges_via_lsp(
1703 &lsp_store,
1704 &buffer.handle,
1705 ranges,
1706 buffer_path_abs,
1707 &language_server,
1708 &settings,
1709 cx,
1710 )
1711 .await
1712 .context("Failed to format ranges via language server")?
1713 } else {
1714 zlog::trace!(logger => "formatting full");
1715 Self::format_via_lsp(
1716 &lsp_store,
1717 &buffer.handle,
1718 buffer_path_abs,
1719 &language_server,
1720 &settings,
1721 cx,
1722 )
1723 .await
1724 .context("failed to format via language server")?
1725 };
1726
1727 if edits.is_empty() {
1728 zlog::trace!(logger => "No changes");
1729 continue;
1730 }
1731 extend_formatting_transaction(
1732 buffer,
1733 formatting_transaction_id,
1734 cx,
1735 |buffer, cx| {
1736 buffer.edit(edits, None, cx);
1737 },
1738 )?;
1739 }
1740 Formatter::CodeAction(code_action_name) => {
1741 let logger = zlog::scoped!(logger => "code-actions");
1742 zlog::trace!(logger => "formatting");
1743 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1744
1745 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1746 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1747 continue;
1748 };
1749
1750 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1751 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1752
1753 let mut actions_and_servers = Vec::new();
1754
1755 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1756 let actions_result = Self::get_server_code_actions_from_action_kinds(
1757 &lsp_store,
1758 language_server.server_id(),
1759 vec![code_action_kind.clone()],
1760 &buffer.handle,
1761 cx,
1762 )
1763 .await
1764 .with_context(|| {
1765 format!(
1766 "Failed to resolve code action {:?} with language server {}",
1767 code_action_kind,
1768 language_server.name()
1769 )
1770 });
1771 let Ok(actions) = actions_result else {
1772 // note: it may be better to set result to the error and break formatters here
1773 // but for now we try to execute the actions that we can resolve and skip the rest
1774 zlog::error!(
1775 logger =>
1776 "Failed to resolve code action {:?} with language server {}",
1777 code_action_kind,
1778 language_server.name()
1779 );
1780 continue;
1781 };
1782 for action in actions {
1783 actions_and_servers.push((action, index));
1784 }
1785 }
1786
1787 if actions_and_servers.is_empty() {
1788 zlog::warn!(logger => "No code actions were resolved, continuing");
1789 continue;
1790 }
1791
1792 'actions: for (mut action, server_index) in actions_and_servers {
1793 let server = &adapters_and_servers[server_index].1;
1794
1795 let describe_code_action = |action: &CodeAction| {
1796 format!(
1797 "code action '{}' with title \"{}\" on server {}",
1798 action
1799 .lsp_action
1800 .action_kind()
1801 .unwrap_or("unknown".into())
1802 .as_str(),
1803 action.lsp_action.title(),
1804 server.name(),
1805 )
1806 };
1807
1808 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1809
1810 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1811 zlog::error!(
1812 logger =>
1813 "Failed to resolve {}. Error: {}",
1814 describe_code_action(&action),
1815 err
1816 );
1817 continue;
1818 }
1819
1820 if let Some(edit) = action.lsp_action.edit().cloned() {
1821 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1822 // but filters out and logs warnings for code actions that require unreasonably
1823 // difficult handling on our part, such as:
1824 // - applying edits that call commands
1825 // which can result in arbitrary workspace edits being sent from the server that
1826 // have no way of being tied back to the command that initiated them (i.e. we
1827 // can't know which edits are part of the format request, or if the server is done sending
1828 // actions in response to the command)
1829 // - actions that create/delete/modify/rename files other than the one we are formatting
1830 // as we then would need to handle such changes correctly in the local history as well
1831 // as the remote history through the ProjectTransaction
1832 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1833 // Supporting these actions is not impossible, but not supported as of yet.
1834 if edit.changes.is_none() && edit.document_changes.is_none() {
1835 zlog::trace!(
1836 logger =>
1837 "No changes for code action. Skipping {}",
1838 describe_code_action(&action),
1839 );
1840 continue;
1841 }
1842
1843 let mut operations = Vec::new();
1844 if let Some(document_changes) = edit.document_changes {
1845 match document_changes {
1846 lsp::DocumentChanges::Edits(edits) => operations.extend(
1847 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1848 ),
1849 lsp::DocumentChanges::Operations(ops) => operations = ops,
1850 }
1851 } else if let Some(changes) = edit.changes {
1852 operations.extend(changes.into_iter().map(|(uri, edits)| {
1853 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1854 text_document:
1855 lsp::OptionalVersionedTextDocumentIdentifier {
1856 uri,
1857 version: None,
1858 },
1859 edits: edits.into_iter().map(Edit::Plain).collect(),
1860 })
1861 }));
1862 }
1863
1864 let mut edits = Vec::with_capacity(operations.len());
1865
1866 if operations.is_empty() {
1867 zlog::trace!(
1868 logger =>
1869 "No changes for code action. Skipping {}",
1870 describe_code_action(&action),
1871 );
1872 continue;
1873 }
1874 for operation in operations {
1875 let op = match operation {
1876 lsp::DocumentChangeOperation::Edit(op) => op,
1877 lsp::DocumentChangeOperation::Op(_) => {
1878 zlog::warn!(
1879 logger =>
1880 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1881 describe_code_action(&action),
1882 );
1883 continue 'actions;
1884 }
1885 };
1886 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1887 zlog::warn!(
1888 logger =>
1889 "Failed to convert URI '{:?}' to file path. Skipping {}",
1890 &op.text_document.uri,
1891 describe_code_action(&action),
1892 );
1893 continue 'actions;
1894 };
1895 if &file_path != buffer_path_abs {
1896 zlog::warn!(
1897 logger =>
1898 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1899 file_path,
1900 buffer_path_abs,
1901 describe_code_action(&action),
1902 );
1903 continue 'actions;
1904 }
1905
1906 let mut lsp_edits = Vec::new();
1907 for edit in op.edits {
1908 match edit {
1909 Edit::Plain(edit) => {
1910 if !lsp_edits.contains(&edit) {
1911 lsp_edits.push(edit);
1912 }
1913 }
1914 Edit::Annotated(edit) => {
1915 if !lsp_edits.contains(&edit.text_edit) {
1916 lsp_edits.push(edit.text_edit);
1917 }
1918 }
1919 Edit::Snippet(_) => {
1920 zlog::warn!(
1921 logger =>
1922 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1923 describe_code_action(&action),
1924 );
1925 continue 'actions;
1926 }
1927 }
1928 }
1929 let edits_result = lsp_store
1930 .update(cx, |lsp_store, cx| {
1931 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1932 &buffer.handle,
1933 lsp_edits,
1934 server.server_id(),
1935 op.text_document.version,
1936 cx,
1937 )
1938 })?
1939 .await;
1940 let Ok(resolved_edits) = edits_result else {
1941 zlog::warn!(
1942 logger =>
1943 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1944 buffer_path_abs.as_path(),
1945 describe_code_action(&action),
1946 );
1947 continue 'actions;
1948 };
1949 edits.extend(resolved_edits);
1950 }
1951
1952 if edits.is_empty() {
1953 zlog::warn!(logger => "No edits resolved from LSP");
1954 continue;
1955 }
1956
1957 extend_formatting_transaction(
1958 buffer,
1959 formatting_transaction_id,
1960 cx,
1961 |buffer, cx| {
1962 zlog::info!(
1963 "Applying edits {edits:?}. Content: {:?}",
1964 buffer.text()
1965 );
1966 buffer.edit(edits, None, cx);
1967 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1968 },
1969 )?;
1970 }
1971
1972 if let Some(command) = action.lsp_action.command() {
1973 zlog::warn!(
1974 logger =>
1975 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1976 &command.command,
1977 );
1978
1979 // bail early if command is invalid
1980 let server_capabilities = server.capabilities();
1981 let available_commands = server_capabilities
1982 .execute_command_provider
1983 .as_ref()
1984 .map(|options| options.commands.as_slice())
1985 .unwrap_or_default();
1986 if !available_commands.contains(&command.command) {
1987 zlog::warn!(
1988 logger =>
1989 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1990 command.command,
1991 server.name(),
1992 );
1993 continue;
1994 }
1995
1996 // noop so we just ensure buffer hasn't been edited since resolving code actions
1997 extend_formatting_transaction(
1998 buffer,
1999 formatting_transaction_id,
2000 cx,
2001 |_, _| {},
2002 )?;
2003 zlog::info!(logger => "Executing command {}", &command.command);
2004
2005 lsp_store.update(cx, |this, _| {
2006 this.as_local_mut()
2007 .unwrap()
2008 .last_workspace_edits_by_language_server
2009 .remove(&server.server_id());
2010 })?;
2011
2012 let execute_command_result = server
2013 .request::<lsp::request::ExecuteCommand>(
2014 lsp::ExecuteCommandParams {
2015 command: command.command.clone(),
2016 arguments: command.arguments.clone().unwrap_or_default(),
2017 ..Default::default()
2018 },
2019 )
2020 .await
2021 .into_response();
2022
2023 if execute_command_result.is_err() {
2024 zlog::error!(
2025 logger =>
2026 "Failed to execute command '{}' as part of {}",
2027 &command.command,
2028 describe_code_action(&action),
2029 );
2030 continue 'actions;
2031 }
2032
2033 let mut project_transaction_command =
2034 lsp_store.update(cx, |this, _| {
2035 this.as_local_mut()
2036 .unwrap()
2037 .last_workspace_edits_by_language_server
2038 .remove(&server.server_id())
2039 .unwrap_or_default()
2040 })?;
2041
2042 if let Some(transaction) =
2043 project_transaction_command.0.remove(&buffer.handle)
2044 {
2045 zlog::trace!(
2046 logger =>
2047 "Successfully captured {} edits that resulted from command {}",
2048 transaction.edit_ids.len(),
2049 &command.command,
2050 );
2051 let transaction_id_project_transaction = transaction.id;
2052 buffer.handle.update(cx, |buffer, _| {
2053 // it may have been removed from history if push_to_history was
2054 // false in deserialize_workspace_edit. If so push it so we
2055 // can merge it with the format transaction
2056 // and pop the combined transaction off the history stack
2057 // later if push_to_history is false
2058 if buffer.get_transaction(transaction.id).is_none() {
2059 buffer.push_transaction(transaction, Instant::now());
2060 }
2061 buffer.merge_transactions(
2062 transaction_id_project_transaction,
2063 formatting_transaction_id,
2064 );
2065 })?;
2066 }
2067
2068 if !project_transaction_command.0.is_empty() {
2069 let mut extra_buffers = String::new();
2070 for buffer in project_transaction_command.0.keys() {
2071 buffer
2072 .read_with(cx, |b, cx| {
2073 if let Some(path) = b.project_path(cx) {
2074 if !extra_buffers.is_empty() {
2075 extra_buffers.push_str(", ");
2076 }
2077 extra_buffers.push_str(path.path.as_unix_str());
2078 }
2079 })
2080 .ok();
2081 }
2082 zlog::warn!(
2083 logger =>
2084 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2085 &command.command,
2086 extra_buffers,
2087 );
2088 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2089 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2090 // add it so it's included, and merge it into the format transaction when its created later
2091 }
2092 }
2093 }
2094 }
2095 }
2096 }
2097
2098 Ok(())
2099 }
2100
2101 pub async fn format_ranges_via_lsp(
2102 this: &WeakEntity<LspStore>,
2103 buffer_handle: &Entity<Buffer>,
2104 ranges: &[Range<Anchor>],
2105 abs_path: &Path,
2106 language_server: &Arc<LanguageServer>,
2107 settings: &LanguageSettings,
2108 cx: &mut AsyncApp,
2109 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2110 let capabilities = &language_server.capabilities();
2111 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2112 if range_formatting_provider == Some(&OneOf::Left(false)) {
2113 anyhow::bail!(
2114 "{} language server does not support range formatting",
2115 language_server.name()
2116 );
2117 }
2118
2119 let uri = file_path_to_lsp_url(abs_path)?;
2120 let text_document = lsp::TextDocumentIdentifier::new(uri);
2121
2122 let lsp_edits = {
2123 let mut lsp_ranges = Vec::new();
2124 this.update(cx, |_this, cx| {
2125 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2126 // not have been sent to the language server. This seems like a fairly systemic
2127 // issue, though, the resolution probably is not specific to formatting.
2128 //
2129 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2130 // LSP.
2131 let snapshot = buffer_handle.read(cx).snapshot();
2132 for range in ranges {
2133 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2134 }
2135 anyhow::Ok(())
2136 })??;
2137
2138 let mut edits = None;
2139 for range in lsp_ranges {
2140 if let Some(mut edit) = language_server
2141 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2142 text_document: text_document.clone(),
2143 range,
2144 options: lsp_command::lsp_formatting_options(settings),
2145 work_done_progress_params: Default::default(),
2146 })
2147 .await
2148 .into_response()?
2149 {
2150 edits.get_or_insert_with(Vec::new).append(&mut edit);
2151 }
2152 }
2153 edits
2154 };
2155
2156 if let Some(lsp_edits) = lsp_edits {
2157 this.update(cx, |this, cx| {
2158 this.as_local_mut().unwrap().edits_from_lsp(
2159 buffer_handle,
2160 lsp_edits,
2161 language_server.server_id(),
2162 None,
2163 cx,
2164 )
2165 })?
2166 .await
2167 } else {
2168 Ok(Vec::with_capacity(0))
2169 }
2170 }
2171
2172 async fn format_via_lsp(
2173 this: &WeakEntity<LspStore>,
2174 buffer: &Entity<Buffer>,
2175 abs_path: &Path,
2176 language_server: &Arc<LanguageServer>,
2177 settings: &LanguageSettings,
2178 cx: &mut AsyncApp,
2179 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2180 let logger = zlog::scoped!("lsp_format");
2181 zlog::debug!(logger => "Formatting via LSP");
2182
2183 let uri = file_path_to_lsp_url(abs_path)?;
2184 let text_document = lsp::TextDocumentIdentifier::new(uri);
2185 let capabilities = &language_server.capabilities();
2186
2187 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2188 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2189
2190 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2191 let _timer = zlog::time!(logger => "format-full");
2192 language_server
2193 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2194 text_document,
2195 options: lsp_command::lsp_formatting_options(settings),
2196 work_done_progress_params: Default::default(),
2197 })
2198 .await
2199 .into_response()?
2200 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2201 let _timer = zlog::time!(logger => "format-range");
2202 let buffer_start = lsp::Position::new(0, 0);
2203 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2204 language_server
2205 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2206 text_document: text_document.clone(),
2207 range: lsp::Range::new(buffer_start, buffer_end),
2208 options: lsp_command::lsp_formatting_options(settings),
2209 work_done_progress_params: Default::default(),
2210 })
2211 .await
2212 .into_response()?
2213 } else {
2214 None
2215 };
2216
2217 if let Some(lsp_edits) = lsp_edits {
2218 this.update(cx, |this, cx| {
2219 this.as_local_mut().unwrap().edits_from_lsp(
2220 buffer,
2221 lsp_edits,
2222 language_server.server_id(),
2223 None,
2224 cx,
2225 )
2226 })?
2227 .await
2228 } else {
2229 Ok(Vec::with_capacity(0))
2230 }
2231 }
2232
2233 async fn format_via_external_command(
2234 buffer: &FormattableBuffer,
2235 command: &str,
2236 arguments: Option<&[String]>,
2237 cx: &mut AsyncApp,
2238 ) -> Result<Option<Diff>> {
2239 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2240 let file = File::from_dyn(buffer.file())?;
2241 let worktree = file.worktree.read(cx);
2242 let mut worktree_path = worktree.abs_path().to_path_buf();
2243 if worktree.root_entry()?.is_file() {
2244 worktree_path.pop();
2245 }
2246 Some(worktree_path)
2247 })?;
2248
2249 let mut child = util::command::new_smol_command(command);
2250
2251 if let Some(buffer_env) = buffer.env.as_ref() {
2252 child.envs(buffer_env);
2253 }
2254
2255 if let Some(working_dir_path) = working_dir_path {
2256 child.current_dir(working_dir_path);
2257 }
2258
2259 if let Some(arguments) = arguments {
2260 child.args(arguments.iter().map(|arg| {
2261 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2262 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2263 } else {
2264 arg.replace("{buffer_path}", "Untitled")
2265 }
2266 }));
2267 }
2268
2269 let mut child = child
2270 .stdin(smol::process::Stdio::piped())
2271 .stdout(smol::process::Stdio::piped())
2272 .stderr(smol::process::Stdio::piped())
2273 .spawn()?;
2274
2275 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2276 let text = buffer
2277 .handle
2278 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2279 for chunk in text.chunks() {
2280 stdin.write_all(chunk.as_bytes()).await?;
2281 }
2282 stdin.flush().await?;
2283
2284 let output = child.output().await?;
2285 anyhow::ensure!(
2286 output.status.success(),
2287 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2288 output.status.code(),
2289 String::from_utf8_lossy(&output.stdout),
2290 String::from_utf8_lossy(&output.stderr),
2291 );
2292
2293 let stdout = String::from_utf8(output.stdout)?;
2294 Ok(Some(
2295 buffer
2296 .handle
2297 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2298 .await,
2299 ))
2300 }
2301
2302 async fn try_resolve_code_action(
2303 lang_server: &LanguageServer,
2304 action: &mut CodeAction,
2305 ) -> anyhow::Result<()> {
2306 match &mut action.lsp_action {
2307 LspAction::Action(lsp_action) => {
2308 if !action.resolved
2309 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2310 && lsp_action.data.is_some()
2311 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2312 {
2313 *lsp_action = Box::new(
2314 lang_server
2315 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2316 .await
2317 .into_response()?,
2318 );
2319 }
2320 }
2321 LspAction::CodeLens(lens) => {
2322 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2323 *lens = lang_server
2324 .request::<lsp::request::CodeLensResolve>(lens.clone())
2325 .await
2326 .into_response()?;
2327 }
2328 }
2329 LspAction::Command(_) => {}
2330 }
2331
2332 action.resolved = true;
2333 anyhow::Ok(())
2334 }
2335
2336 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2337 let buffer = buffer_handle.read(cx);
2338
2339 let file = buffer.file().cloned();
2340
2341 let Some(file) = File::from_dyn(file.as_ref()) else {
2342 return;
2343 };
2344 if !file.is_local() {
2345 return;
2346 }
2347 let path = ProjectPath::from_file(file, cx);
2348 let worktree_id = file.worktree_id(cx);
2349 let language = buffer.language().cloned();
2350
2351 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2352 for (server_id, diagnostics) in
2353 diagnostics.get(file.path()).cloned().unwrap_or_default()
2354 {
2355 self.update_buffer_diagnostics(
2356 buffer_handle,
2357 server_id,
2358 None,
2359 None,
2360 None,
2361 Vec::new(),
2362 diagnostics,
2363 cx,
2364 )
2365 .log_err();
2366 }
2367 }
2368 let Some(language) = language else {
2369 return;
2370 };
2371 let Some(snapshot) = self
2372 .worktree_store
2373 .read(cx)
2374 .worktree_for_id(worktree_id, cx)
2375 .map(|worktree| worktree.read(cx).snapshot())
2376 else {
2377 return;
2378 };
2379 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2380
2381 for server_id in
2382 self.lsp_tree
2383 .get(path, language.name(), language.manifest(), &delegate, cx)
2384 {
2385 let server = self
2386 .language_servers
2387 .get(&server_id)
2388 .and_then(|server_state| {
2389 if let LanguageServerState::Running { server, .. } = server_state {
2390 Some(server.clone())
2391 } else {
2392 None
2393 }
2394 });
2395 let server = match server {
2396 Some(server) => server,
2397 None => continue,
2398 };
2399
2400 buffer_handle.update(cx, |buffer, cx| {
2401 buffer.set_completion_triggers(
2402 server.server_id(),
2403 server
2404 .capabilities()
2405 .completion_provider
2406 .as_ref()
2407 .and_then(|provider| {
2408 provider
2409 .trigger_characters
2410 .as_ref()
2411 .map(|characters| characters.iter().cloned().collect())
2412 })
2413 .unwrap_or_default(),
2414 cx,
2415 );
2416 });
2417 }
2418 }
2419
2420 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2421 buffer.update(cx, |buffer, cx| {
2422 let Some(language) = buffer.language() else {
2423 return;
2424 };
2425 let path = ProjectPath {
2426 worktree_id: old_file.worktree_id(cx),
2427 path: old_file.path.clone(),
2428 };
2429 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2430 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2431 buffer.set_completion_triggers(server_id, Default::default(), cx);
2432 }
2433 });
2434 }
2435
2436 fn update_buffer_diagnostics(
2437 &mut self,
2438 buffer: &Entity<Buffer>,
2439 server_id: LanguageServerId,
2440 registration_id: Option<Option<SharedString>>,
2441 result_id: Option<SharedString>,
2442 version: Option<i32>,
2443 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2444 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2445 cx: &mut Context<LspStore>,
2446 ) -> Result<()> {
2447 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2448 Ordering::Equal
2449 .then_with(|| b.is_primary.cmp(&a.is_primary))
2450 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2451 .then_with(|| a.severity.cmp(&b.severity))
2452 .then_with(|| a.message.cmp(&b.message))
2453 }
2454
2455 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2456 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2457 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2458
2459 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2460 Ordering::Equal
2461 .then_with(|| a.range.start.cmp(&b.range.start))
2462 .then_with(|| b.range.end.cmp(&a.range.end))
2463 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2464 });
2465
2466 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2467
2468 let edits_since_save = std::cell::LazyCell::new(|| {
2469 let saved_version = buffer.read(cx).saved_version();
2470 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2471 });
2472
2473 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2474
2475 for (new_diagnostic, entry) in diagnostics {
2476 let start;
2477 let end;
2478 if new_diagnostic && entry.diagnostic.is_disk_based {
2479 // Some diagnostics are based on files on disk instead of buffers'
2480 // current contents. Adjust these diagnostics' ranges to reflect
2481 // any unsaved edits.
2482 // Do not alter the reused ones though, as their coordinates were stored as anchors
2483 // and were properly adjusted on reuse.
2484 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2485 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2486 } else {
2487 start = entry.range.start;
2488 end = entry.range.end;
2489 }
2490
2491 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2492 ..snapshot.clip_point_utf16(end, Bias::Right);
2493
2494 // Expand empty ranges by one codepoint
2495 if range.start == range.end {
2496 // This will be go to the next boundary when being clipped
2497 range.end.column += 1;
2498 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2499 if range.start == range.end && range.end.column > 0 {
2500 range.start.column -= 1;
2501 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2502 }
2503 }
2504
2505 sanitized_diagnostics.push(DiagnosticEntry {
2506 range,
2507 diagnostic: entry.diagnostic,
2508 });
2509 }
2510 drop(edits_since_save);
2511
2512 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2513 buffer.update(cx, |buffer, cx| {
2514 if let Some(registration_id) = registration_id {
2515 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2516 self.buffer_pull_diagnostics_result_ids
2517 .entry(server_id)
2518 .or_default()
2519 .entry(registration_id)
2520 .or_default()
2521 .insert(abs_path, result_id);
2522 }
2523 }
2524
2525 buffer.update_diagnostics(server_id, set, cx)
2526 });
2527
2528 Ok(())
2529 }
2530
2531 fn register_language_server_for_invisible_worktree(
2532 &mut self,
2533 worktree: &Entity<Worktree>,
2534 language_server_id: LanguageServerId,
2535 cx: &mut App,
2536 ) {
2537 let worktree = worktree.read(cx);
2538 let worktree_id = worktree.id();
2539 debug_assert!(!worktree.is_visible());
2540 let Some(mut origin_seed) = self
2541 .language_server_ids
2542 .iter()
2543 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2544 else {
2545 return;
2546 };
2547 origin_seed.worktree_id = worktree_id;
2548 self.language_server_ids
2549 .entry(origin_seed)
2550 .or_insert_with(|| UnifiedLanguageServer {
2551 id: language_server_id,
2552 project_roots: Default::default(),
2553 });
2554 }
2555
2556 fn register_buffer_with_language_servers(
2557 &mut self,
2558 buffer_handle: &Entity<Buffer>,
2559 only_register_servers: HashSet<LanguageServerSelector>,
2560 cx: &mut Context<LspStore>,
2561 ) {
2562 let buffer = buffer_handle.read(cx);
2563 let buffer_id = buffer.remote_id();
2564
2565 let Some(file) = File::from_dyn(buffer.file()) else {
2566 return;
2567 };
2568 if !file.is_local() {
2569 return;
2570 }
2571
2572 let abs_path = file.abs_path(cx);
2573 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2574 return;
2575 };
2576 let initial_snapshot = buffer.text_snapshot();
2577 let worktree_id = file.worktree_id(cx);
2578
2579 let Some(language) = buffer.language().cloned() else {
2580 return;
2581 };
2582 let path: Arc<RelPath> = file
2583 .path()
2584 .parent()
2585 .map(Arc::from)
2586 .unwrap_or_else(|| file.path().clone());
2587 let Some(worktree) = self
2588 .worktree_store
2589 .read(cx)
2590 .worktree_for_id(worktree_id, cx)
2591 else {
2592 return;
2593 };
2594 let language_name = language.name();
2595 let (reused, delegate, servers) = self
2596 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2597 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2598 .unwrap_or_else(|| {
2599 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2600 let delegate: Arc<dyn ManifestDelegate> =
2601 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2602
2603 let servers = self
2604 .lsp_tree
2605 .walk(
2606 ProjectPath { worktree_id, path },
2607 language.name(),
2608 language.manifest(),
2609 &delegate,
2610 cx,
2611 )
2612 .collect::<Vec<_>>();
2613 (false, lsp_delegate, servers)
2614 });
2615 let servers_and_adapters = servers
2616 .into_iter()
2617 .filter_map(|server_node| {
2618 if reused && server_node.server_id().is_none() {
2619 return None;
2620 }
2621 if !only_register_servers.is_empty() {
2622 if let Some(server_id) = server_node.server_id()
2623 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2624 {
2625 return None;
2626 }
2627 if let Some(name) = server_node.name()
2628 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2629 {
2630 return None;
2631 }
2632 }
2633
2634 let server_id = server_node.server_id_or_init(|disposition| {
2635 let path = &disposition.path;
2636
2637 {
2638 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2639
2640 let server_id = self.get_or_insert_language_server(
2641 &worktree,
2642 delegate.clone(),
2643 disposition,
2644 &language_name,
2645 cx,
2646 );
2647
2648 if let Some(state) = self.language_servers.get(&server_id)
2649 && let Ok(uri) = uri
2650 {
2651 state.add_workspace_folder(uri);
2652 };
2653 server_id
2654 }
2655 })?;
2656 let server_state = self.language_servers.get(&server_id)?;
2657 if let LanguageServerState::Running {
2658 server, adapter, ..
2659 } = server_state
2660 {
2661 Some((server.clone(), adapter.clone()))
2662 } else {
2663 None
2664 }
2665 })
2666 .collect::<Vec<_>>();
2667 for (server, adapter) in servers_and_adapters {
2668 buffer_handle.update(cx, |buffer, cx| {
2669 buffer.set_completion_triggers(
2670 server.server_id(),
2671 server
2672 .capabilities()
2673 .completion_provider
2674 .as_ref()
2675 .and_then(|provider| {
2676 provider
2677 .trigger_characters
2678 .as_ref()
2679 .map(|characters| characters.iter().cloned().collect())
2680 })
2681 .unwrap_or_default(),
2682 cx,
2683 );
2684 });
2685
2686 let snapshot = LspBufferSnapshot {
2687 version: 0,
2688 snapshot: initial_snapshot.clone(),
2689 };
2690
2691 let mut registered = false;
2692 self.buffer_snapshots
2693 .entry(buffer_id)
2694 .or_default()
2695 .entry(server.server_id())
2696 .or_insert_with(|| {
2697 registered = true;
2698 server.register_buffer(
2699 uri.clone(),
2700 adapter.language_id(&language.name()),
2701 0,
2702 initial_snapshot.text(),
2703 );
2704
2705 vec![snapshot]
2706 });
2707
2708 self.buffers_opened_in_servers
2709 .entry(buffer_id)
2710 .or_default()
2711 .insert(server.server_id());
2712 if registered {
2713 cx.emit(LspStoreEvent::LanguageServerUpdate {
2714 language_server_id: server.server_id(),
2715 name: None,
2716 message: proto::update_language_server::Variant::RegisteredForBuffer(
2717 proto::RegisteredForBuffer {
2718 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2719 buffer_id: buffer_id.to_proto(),
2720 },
2721 ),
2722 });
2723 }
2724 }
2725 }
2726
2727 fn reuse_existing_language_server<'lang_name>(
2728 &self,
2729 server_tree: &LanguageServerTree,
2730 worktree: &Entity<Worktree>,
2731 language_name: &'lang_name LanguageName,
2732 cx: &mut App,
2733 ) -> Option<(
2734 Arc<LocalLspAdapterDelegate>,
2735 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2736 )> {
2737 if worktree.read(cx).is_visible() {
2738 return None;
2739 }
2740
2741 let worktree_store = self.worktree_store.read(cx);
2742 let servers = server_tree
2743 .instances
2744 .iter()
2745 .filter(|(worktree_id, _)| {
2746 worktree_store
2747 .worktree_for_id(**worktree_id, cx)
2748 .is_some_and(|worktree| worktree.read(cx).is_visible())
2749 })
2750 .flat_map(|(worktree_id, servers)| {
2751 servers
2752 .roots
2753 .iter()
2754 .flat_map(|(_, language_servers)| language_servers)
2755 .map(move |(_, (server_node, server_languages))| {
2756 (worktree_id, server_node, server_languages)
2757 })
2758 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2759 .map(|(worktree_id, server_node, _)| {
2760 (
2761 *worktree_id,
2762 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2763 )
2764 })
2765 })
2766 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2767 acc.entry(worktree_id)
2768 .or_insert_with(Vec::new)
2769 .push(server_node);
2770 acc
2771 })
2772 .into_values()
2773 .max_by_key(|servers| servers.len())?;
2774
2775 let worktree_id = worktree.read(cx).id();
2776 let apply = move |tree: &mut LanguageServerTree| {
2777 for server_node in &servers {
2778 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2779 }
2780 servers
2781 };
2782
2783 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2784 Some((delegate, apply))
2785 }
2786
2787 pub(crate) fn unregister_old_buffer_from_language_servers(
2788 &mut self,
2789 buffer: &Entity<Buffer>,
2790 old_file: &File,
2791 cx: &mut App,
2792 ) {
2793 let old_path = match old_file.as_local() {
2794 Some(local) => local.abs_path(cx),
2795 None => return,
2796 };
2797
2798 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2799 debug_panic!("{old_path:?} is not parseable as an URI");
2800 return;
2801 };
2802 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2803 }
2804
2805 pub(crate) fn unregister_buffer_from_language_servers(
2806 &mut self,
2807 buffer: &Entity<Buffer>,
2808 file_url: &lsp::Uri,
2809 cx: &mut App,
2810 ) {
2811 buffer.update(cx, |buffer, cx| {
2812 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2813
2814 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2815 if snapshots
2816 .as_mut()
2817 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2818 {
2819 language_server.unregister_buffer(file_url.clone());
2820 }
2821 }
2822 });
2823 }
2824
2825 fn buffer_snapshot_for_lsp_version(
2826 &mut self,
2827 buffer: &Entity<Buffer>,
2828 server_id: LanguageServerId,
2829 version: Option<i32>,
2830 cx: &App,
2831 ) -> Result<TextBufferSnapshot> {
2832 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2833
2834 if let Some(version) = version {
2835 let buffer_id = buffer.read(cx).remote_id();
2836 let snapshots = if let Some(snapshots) = self
2837 .buffer_snapshots
2838 .get_mut(&buffer_id)
2839 .and_then(|m| m.get_mut(&server_id))
2840 {
2841 snapshots
2842 } else if version == 0 {
2843 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2844 // We detect this case and treat it as if the version was `None`.
2845 return Ok(buffer.read(cx).text_snapshot());
2846 } else {
2847 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2848 };
2849
2850 let found_snapshot = snapshots
2851 .binary_search_by_key(&version, |e| e.version)
2852 .map(|ix| snapshots[ix].snapshot.clone())
2853 .map_err(|_| {
2854 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2855 })?;
2856
2857 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2858 Ok(found_snapshot)
2859 } else {
2860 Ok((buffer.read(cx)).text_snapshot())
2861 }
2862 }
2863
2864 async fn get_server_code_actions_from_action_kinds(
2865 lsp_store: &WeakEntity<LspStore>,
2866 language_server_id: LanguageServerId,
2867 code_action_kinds: Vec<lsp::CodeActionKind>,
2868 buffer: &Entity<Buffer>,
2869 cx: &mut AsyncApp,
2870 ) -> Result<Vec<CodeAction>> {
2871 let actions = lsp_store
2872 .update(cx, move |this, cx| {
2873 let request = GetCodeActions {
2874 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2875 kinds: Some(code_action_kinds),
2876 };
2877 let server = LanguageServerToQuery::Other(language_server_id);
2878 this.request_lsp(buffer.clone(), server, request, cx)
2879 })?
2880 .await?;
2881 Ok(actions)
2882 }
2883
2884 pub async fn execute_code_actions_on_server(
2885 lsp_store: &WeakEntity<LspStore>,
2886 language_server: &Arc<LanguageServer>,
2887
2888 actions: Vec<CodeAction>,
2889 push_to_history: bool,
2890 project_transaction: &mut ProjectTransaction,
2891 cx: &mut AsyncApp,
2892 ) -> anyhow::Result<()> {
2893 for mut action in actions {
2894 Self::try_resolve_code_action(language_server, &mut action)
2895 .await
2896 .context("resolving a formatting code action")?;
2897
2898 if let Some(edit) = action.lsp_action.edit() {
2899 if edit.changes.is_none() && edit.document_changes.is_none() {
2900 continue;
2901 }
2902
2903 let new = Self::deserialize_workspace_edit(
2904 lsp_store.upgrade().context("project dropped")?,
2905 edit.clone(),
2906 push_to_history,
2907 language_server.clone(),
2908 cx,
2909 )
2910 .await?;
2911 project_transaction.0.extend(new.0);
2912 }
2913
2914 if let Some(command) = action.lsp_action.command() {
2915 let server_capabilities = language_server.capabilities();
2916 let available_commands = server_capabilities
2917 .execute_command_provider
2918 .as_ref()
2919 .map(|options| options.commands.as_slice())
2920 .unwrap_or_default();
2921 if available_commands.contains(&command.command) {
2922 lsp_store.update(cx, |lsp_store, _| {
2923 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2924 mode.last_workspace_edits_by_language_server
2925 .remove(&language_server.server_id());
2926 }
2927 })?;
2928
2929 language_server
2930 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2931 command: command.command.clone(),
2932 arguments: command.arguments.clone().unwrap_or_default(),
2933 ..Default::default()
2934 })
2935 .await
2936 .into_response()
2937 .context("execute command")?;
2938
2939 lsp_store.update(cx, |this, _| {
2940 if let LspStoreMode::Local(mode) = &mut this.mode {
2941 project_transaction.0.extend(
2942 mode.last_workspace_edits_by_language_server
2943 .remove(&language_server.server_id())
2944 .unwrap_or_default()
2945 .0,
2946 )
2947 }
2948 })?;
2949 } else {
2950 log::warn!(
2951 "Cannot execute a command {} not listed in the language server capabilities",
2952 command.command
2953 )
2954 }
2955 }
2956 }
2957 Ok(())
2958 }
2959
2960 pub async fn deserialize_text_edits(
2961 this: Entity<LspStore>,
2962 buffer_to_edit: Entity<Buffer>,
2963 edits: Vec<lsp::TextEdit>,
2964 push_to_history: bool,
2965 _: Arc<CachedLspAdapter>,
2966 language_server: Arc<LanguageServer>,
2967 cx: &mut AsyncApp,
2968 ) -> Result<Option<Transaction>> {
2969 let edits = this
2970 .update(cx, |this, cx| {
2971 this.as_local_mut().unwrap().edits_from_lsp(
2972 &buffer_to_edit,
2973 edits,
2974 language_server.server_id(),
2975 None,
2976 cx,
2977 )
2978 })?
2979 .await?;
2980
2981 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2982 buffer.finalize_last_transaction();
2983 buffer.start_transaction();
2984 for (range, text) in edits {
2985 buffer.edit([(range, text)], None, cx);
2986 }
2987
2988 if buffer.end_transaction(cx).is_some() {
2989 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2990 if !push_to_history {
2991 buffer.forget_transaction(transaction.id);
2992 }
2993 Some(transaction)
2994 } else {
2995 None
2996 }
2997 })?;
2998
2999 Ok(transaction)
3000 }
3001
3002 #[allow(clippy::type_complexity)]
3003 pub(crate) fn edits_from_lsp(
3004 &mut self,
3005 buffer: &Entity<Buffer>,
3006 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3007 server_id: LanguageServerId,
3008 version: Option<i32>,
3009 cx: &mut Context<LspStore>,
3010 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3011 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3012 cx.background_spawn(async move {
3013 let snapshot = snapshot?;
3014 let mut lsp_edits = lsp_edits
3015 .into_iter()
3016 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3017 .collect::<Vec<_>>();
3018
3019 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3020
3021 let mut lsp_edits = lsp_edits.into_iter().peekable();
3022 let mut edits = Vec::new();
3023 while let Some((range, mut new_text)) = lsp_edits.next() {
3024 // Clip invalid ranges provided by the language server.
3025 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3026 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3027
3028 // Combine any LSP edits that are adjacent.
3029 //
3030 // Also, combine LSP edits that are separated from each other by only
3031 // a newline. This is important because for some code actions,
3032 // Rust-analyzer rewrites the entire buffer via a series of edits that
3033 // are separated by unchanged newline characters.
3034 //
3035 // In order for the diffing logic below to work properly, any edits that
3036 // cancel each other out must be combined into one.
3037 while let Some((next_range, next_text)) = lsp_edits.peek() {
3038 if next_range.start.0 > range.end {
3039 if next_range.start.0.row > range.end.row + 1
3040 || next_range.start.0.column > 0
3041 || snapshot.clip_point_utf16(
3042 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3043 Bias::Left,
3044 ) > range.end
3045 {
3046 break;
3047 }
3048 new_text.push('\n');
3049 }
3050 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3051 new_text.push_str(next_text);
3052 lsp_edits.next();
3053 }
3054
3055 // For multiline edits, perform a diff of the old and new text so that
3056 // we can identify the changes more precisely, preserving the locations
3057 // of any anchors positioned in the unchanged regions.
3058 if range.end.row > range.start.row {
3059 let offset = range.start.to_offset(&snapshot);
3060 let old_text = snapshot.text_for_range(range).collect::<String>();
3061 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3062 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3063 (
3064 snapshot.anchor_after(offset + range.start)
3065 ..snapshot.anchor_before(offset + range.end),
3066 replacement,
3067 )
3068 }));
3069 } else if range.end == range.start {
3070 let anchor = snapshot.anchor_after(range.start);
3071 edits.push((anchor..anchor, new_text.into()));
3072 } else {
3073 let edit_start = snapshot.anchor_after(range.start);
3074 let edit_end = snapshot.anchor_before(range.end);
3075 edits.push((edit_start..edit_end, new_text.into()));
3076 }
3077 }
3078
3079 Ok(edits)
3080 })
3081 }
3082
3083 pub(crate) async fn deserialize_workspace_edit(
3084 this: Entity<LspStore>,
3085 edit: lsp::WorkspaceEdit,
3086 push_to_history: bool,
3087 language_server: Arc<LanguageServer>,
3088 cx: &mut AsyncApp,
3089 ) -> Result<ProjectTransaction> {
3090 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3091
3092 let mut operations = Vec::new();
3093 if let Some(document_changes) = edit.document_changes {
3094 match document_changes {
3095 lsp::DocumentChanges::Edits(edits) => {
3096 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3097 }
3098 lsp::DocumentChanges::Operations(ops) => operations = ops,
3099 }
3100 } else if let Some(changes) = edit.changes {
3101 operations.extend(changes.into_iter().map(|(uri, edits)| {
3102 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3103 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3104 uri,
3105 version: None,
3106 },
3107 edits: edits.into_iter().map(Edit::Plain).collect(),
3108 })
3109 }));
3110 }
3111
3112 let mut project_transaction = ProjectTransaction::default();
3113 for operation in operations {
3114 match operation {
3115 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3116 let abs_path = op
3117 .uri
3118 .to_file_path()
3119 .map_err(|()| anyhow!("can't convert URI to path"))?;
3120
3121 if let Some(parent_path) = abs_path.parent() {
3122 fs.create_dir(parent_path).await?;
3123 }
3124 if abs_path.ends_with("/") {
3125 fs.create_dir(&abs_path).await?;
3126 } else {
3127 fs.create_file(
3128 &abs_path,
3129 op.options
3130 .map(|options| fs::CreateOptions {
3131 overwrite: options.overwrite.unwrap_or(false),
3132 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3133 })
3134 .unwrap_or_default(),
3135 )
3136 .await?;
3137 }
3138 }
3139
3140 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3141 let source_abs_path = op
3142 .old_uri
3143 .to_file_path()
3144 .map_err(|()| anyhow!("can't convert URI to path"))?;
3145 let target_abs_path = op
3146 .new_uri
3147 .to_file_path()
3148 .map_err(|()| anyhow!("can't convert URI to path"))?;
3149
3150 let options = fs::RenameOptions {
3151 overwrite: op
3152 .options
3153 .as_ref()
3154 .and_then(|options| options.overwrite)
3155 .unwrap_or(false),
3156 ignore_if_exists: op
3157 .options
3158 .as_ref()
3159 .and_then(|options| options.ignore_if_exists)
3160 .unwrap_or(false),
3161 create_parents: true,
3162 };
3163
3164 fs.rename(&source_abs_path, &target_abs_path, options)
3165 .await?;
3166 }
3167
3168 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3169 let abs_path = op
3170 .uri
3171 .to_file_path()
3172 .map_err(|()| anyhow!("can't convert URI to path"))?;
3173 let options = op
3174 .options
3175 .map(|options| fs::RemoveOptions {
3176 recursive: options.recursive.unwrap_or(false),
3177 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3178 })
3179 .unwrap_or_default();
3180 if abs_path.ends_with("/") {
3181 fs.remove_dir(&abs_path, options).await?;
3182 } else {
3183 fs.remove_file(&abs_path, options).await?;
3184 }
3185 }
3186
3187 lsp::DocumentChangeOperation::Edit(op) => {
3188 let buffer_to_edit = this
3189 .update(cx, |this, cx| {
3190 this.open_local_buffer_via_lsp(
3191 op.text_document.uri.clone(),
3192 language_server.server_id(),
3193 cx,
3194 )
3195 })?
3196 .await?;
3197
3198 let edits = this
3199 .update(cx, |this, cx| {
3200 let path = buffer_to_edit.read(cx).project_path(cx);
3201 let active_entry = this.active_entry;
3202 let is_active_entry = path.is_some_and(|project_path| {
3203 this.worktree_store
3204 .read(cx)
3205 .entry_for_path(&project_path, cx)
3206 .is_some_and(|entry| Some(entry.id) == active_entry)
3207 });
3208 let local = this.as_local_mut().unwrap();
3209
3210 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3211 for edit in op.edits {
3212 match edit {
3213 Edit::Plain(edit) => {
3214 if !edits.contains(&edit) {
3215 edits.push(edit)
3216 }
3217 }
3218 Edit::Annotated(edit) => {
3219 if !edits.contains(&edit.text_edit) {
3220 edits.push(edit.text_edit)
3221 }
3222 }
3223 Edit::Snippet(edit) => {
3224 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3225 else {
3226 continue;
3227 };
3228
3229 if is_active_entry {
3230 snippet_edits.push((edit.range, snippet));
3231 } else {
3232 // Since this buffer is not focused, apply a normal edit.
3233 let new_edit = TextEdit {
3234 range: edit.range,
3235 new_text: snippet.text,
3236 };
3237 if !edits.contains(&new_edit) {
3238 edits.push(new_edit);
3239 }
3240 }
3241 }
3242 }
3243 }
3244 if !snippet_edits.is_empty() {
3245 let buffer_id = buffer_to_edit.read(cx).remote_id();
3246 let version = if let Some(buffer_version) = op.text_document.version
3247 {
3248 local
3249 .buffer_snapshot_for_lsp_version(
3250 &buffer_to_edit,
3251 language_server.server_id(),
3252 Some(buffer_version),
3253 cx,
3254 )
3255 .ok()
3256 .map(|snapshot| snapshot.version)
3257 } else {
3258 Some(buffer_to_edit.read(cx).saved_version().clone())
3259 };
3260
3261 let most_recent_edit =
3262 version.and_then(|version| version.most_recent());
3263 // Check if the edit that triggered that edit has been made by this participant.
3264
3265 if let Some(most_recent_edit) = most_recent_edit {
3266 cx.emit(LspStoreEvent::SnippetEdit {
3267 buffer_id,
3268 edits: snippet_edits,
3269 most_recent_edit,
3270 });
3271 }
3272 }
3273
3274 local.edits_from_lsp(
3275 &buffer_to_edit,
3276 edits,
3277 language_server.server_id(),
3278 op.text_document.version,
3279 cx,
3280 )
3281 })?
3282 .await?;
3283
3284 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3285 buffer.finalize_last_transaction();
3286 buffer.start_transaction();
3287 for (range, text) in edits {
3288 buffer.edit([(range, text)], None, cx);
3289 }
3290
3291 buffer.end_transaction(cx).and_then(|transaction_id| {
3292 if push_to_history {
3293 buffer.finalize_last_transaction();
3294 buffer.get_transaction(transaction_id).cloned()
3295 } else {
3296 buffer.forget_transaction(transaction_id)
3297 }
3298 })
3299 })?;
3300 if let Some(transaction) = transaction {
3301 project_transaction.0.insert(buffer_to_edit, transaction);
3302 }
3303 }
3304 }
3305 }
3306
3307 Ok(project_transaction)
3308 }
3309
3310 async fn on_lsp_workspace_edit(
3311 this: WeakEntity<LspStore>,
3312 params: lsp::ApplyWorkspaceEditParams,
3313 server_id: LanguageServerId,
3314 cx: &mut AsyncApp,
3315 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3316 let this = this.upgrade().context("project project closed")?;
3317 let language_server = this
3318 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3319 .context("language server not found")?;
3320 let transaction = Self::deserialize_workspace_edit(
3321 this.clone(),
3322 params.edit,
3323 true,
3324 language_server.clone(),
3325 cx,
3326 )
3327 .await
3328 .log_err();
3329 this.update(cx, |this, _| {
3330 if let Some(transaction) = transaction {
3331 this.as_local_mut()
3332 .unwrap()
3333 .last_workspace_edits_by_language_server
3334 .insert(server_id, transaction);
3335 }
3336 })?;
3337 Ok(lsp::ApplyWorkspaceEditResponse {
3338 applied: true,
3339 failed_change: None,
3340 failure_reason: None,
3341 })
3342 }
3343
3344 fn remove_worktree(
3345 &mut self,
3346 id_to_remove: WorktreeId,
3347 cx: &mut Context<LspStore>,
3348 ) -> Vec<LanguageServerId> {
3349 self.restricted_worktrees_tasks.remove(&id_to_remove);
3350 self.diagnostics.remove(&id_to_remove);
3351 self.prettier_store.update(cx, |prettier_store, cx| {
3352 prettier_store.remove_worktree(id_to_remove, cx);
3353 });
3354
3355 let mut servers_to_remove = BTreeSet::default();
3356 let mut servers_to_preserve = HashSet::default();
3357 for (seed, state) in &self.language_server_ids {
3358 if seed.worktree_id == id_to_remove {
3359 servers_to_remove.insert(state.id);
3360 } else {
3361 servers_to_preserve.insert(state.id);
3362 }
3363 }
3364 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3365 self.language_server_ids
3366 .retain(|_, state| !servers_to_remove.contains(&state.id));
3367 for server_id_to_remove in &servers_to_remove {
3368 self.language_server_watched_paths
3369 .remove(server_id_to_remove);
3370 self.language_server_paths_watched_for_rename
3371 .remove(server_id_to_remove);
3372 self.last_workspace_edits_by_language_server
3373 .remove(server_id_to_remove);
3374 self.language_servers.remove(server_id_to_remove);
3375 self.buffer_pull_diagnostics_result_ids
3376 .remove(server_id_to_remove);
3377 self.workspace_pull_diagnostics_result_ids
3378 .remove(server_id_to_remove);
3379 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3380 buffer_servers.remove(server_id_to_remove);
3381 }
3382 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3383 }
3384 servers_to_remove.into_iter().collect()
3385 }
3386
3387 fn rebuild_watched_paths_inner<'a>(
3388 &'a self,
3389 language_server_id: LanguageServerId,
3390 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3391 cx: &mut Context<LspStore>,
3392 ) -> LanguageServerWatchedPathsBuilder {
3393 let worktrees = self
3394 .worktree_store
3395 .read(cx)
3396 .worktrees()
3397 .filter_map(|worktree| {
3398 self.language_servers_for_worktree(worktree.read(cx).id())
3399 .find(|server| server.server_id() == language_server_id)
3400 .map(|_| worktree)
3401 })
3402 .collect::<Vec<_>>();
3403
3404 let mut worktree_globs = HashMap::default();
3405 let mut abs_globs = HashMap::default();
3406 log::trace!(
3407 "Processing new watcher paths for language server with id {}",
3408 language_server_id
3409 );
3410
3411 for watcher in watchers {
3412 if let Some((worktree, literal_prefix, pattern)) =
3413 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3414 {
3415 worktree.update(cx, |worktree, _| {
3416 if let Some((tree, glob)) =
3417 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3418 {
3419 tree.add_path_prefix_to_scan(literal_prefix);
3420 worktree_globs
3421 .entry(tree.id())
3422 .or_insert_with(GlobSetBuilder::new)
3423 .add(glob);
3424 }
3425 });
3426 } else {
3427 let (path, pattern) = match &watcher.glob_pattern {
3428 lsp::GlobPattern::String(s) => {
3429 let watcher_path = SanitizedPath::new(s);
3430 let path = glob_literal_prefix(watcher_path.as_path());
3431 let pattern = watcher_path
3432 .as_path()
3433 .strip_prefix(&path)
3434 .map(|p| p.to_string_lossy().into_owned())
3435 .unwrap_or_else(|e| {
3436 debug_panic!(
3437 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3438 s,
3439 path.display(),
3440 e
3441 );
3442 watcher_path.as_path().to_string_lossy().into_owned()
3443 });
3444 (path, pattern)
3445 }
3446 lsp::GlobPattern::Relative(rp) => {
3447 let Ok(mut base_uri) = match &rp.base_uri {
3448 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3449 lsp::OneOf::Right(base_uri) => base_uri,
3450 }
3451 .to_file_path() else {
3452 continue;
3453 };
3454
3455 let path = glob_literal_prefix(Path::new(&rp.pattern));
3456 let pattern = Path::new(&rp.pattern)
3457 .strip_prefix(&path)
3458 .map(|p| p.to_string_lossy().into_owned())
3459 .unwrap_or_else(|e| {
3460 debug_panic!(
3461 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3462 rp.pattern,
3463 path.display(),
3464 e
3465 );
3466 rp.pattern.clone()
3467 });
3468 base_uri.push(path);
3469 (base_uri, pattern)
3470 }
3471 };
3472
3473 if let Some(glob) = Glob::new(&pattern).log_err() {
3474 if !path
3475 .components()
3476 .any(|c| matches!(c, path::Component::Normal(_)))
3477 {
3478 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3479 // rather than adding a new watcher for `/`.
3480 for worktree in &worktrees {
3481 worktree_globs
3482 .entry(worktree.read(cx).id())
3483 .or_insert_with(GlobSetBuilder::new)
3484 .add(glob.clone());
3485 }
3486 } else {
3487 abs_globs
3488 .entry(path.into())
3489 .or_insert_with(GlobSetBuilder::new)
3490 .add(glob);
3491 }
3492 }
3493 }
3494 }
3495
3496 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3497 for (worktree_id, builder) in worktree_globs {
3498 if let Ok(globset) = builder.build() {
3499 watch_builder.watch_worktree(worktree_id, globset);
3500 }
3501 }
3502 for (abs_path, builder) in abs_globs {
3503 if let Ok(globset) = builder.build() {
3504 watch_builder.watch_abs_path(abs_path, globset);
3505 }
3506 }
3507 watch_builder
3508 }
3509
3510 fn worktree_and_path_for_file_watcher(
3511 worktrees: &[Entity<Worktree>],
3512 watcher: &FileSystemWatcher,
3513 cx: &App,
3514 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3515 worktrees.iter().find_map(|worktree| {
3516 let tree = worktree.read(cx);
3517 let worktree_root_path = tree.abs_path();
3518 let path_style = tree.path_style();
3519 match &watcher.glob_pattern {
3520 lsp::GlobPattern::String(s) => {
3521 let watcher_path = SanitizedPath::new(s);
3522 let relative = watcher_path
3523 .as_path()
3524 .strip_prefix(&worktree_root_path)
3525 .ok()?;
3526 let literal_prefix = glob_literal_prefix(relative);
3527 Some((
3528 worktree.clone(),
3529 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3530 relative.to_string_lossy().into_owned(),
3531 ))
3532 }
3533 lsp::GlobPattern::Relative(rp) => {
3534 let base_uri = match &rp.base_uri {
3535 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3536 lsp::OneOf::Right(base_uri) => base_uri,
3537 }
3538 .to_file_path()
3539 .ok()?;
3540 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3541 let mut literal_prefix = relative.to_owned();
3542 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3543 Some((
3544 worktree.clone(),
3545 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3546 rp.pattern.clone(),
3547 ))
3548 }
3549 }
3550 })
3551 }
3552
3553 fn rebuild_watched_paths(
3554 &mut self,
3555 language_server_id: LanguageServerId,
3556 cx: &mut Context<LspStore>,
3557 ) {
3558 let Some(registrations) = self
3559 .language_server_dynamic_registrations
3560 .get(&language_server_id)
3561 else {
3562 return;
3563 };
3564
3565 let watch_builder = self.rebuild_watched_paths_inner(
3566 language_server_id,
3567 registrations.did_change_watched_files.values().flatten(),
3568 cx,
3569 );
3570 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3571 self.language_server_watched_paths
3572 .insert(language_server_id, watcher);
3573
3574 cx.notify();
3575 }
3576
3577 fn on_lsp_did_change_watched_files(
3578 &mut self,
3579 language_server_id: LanguageServerId,
3580 registration_id: &str,
3581 params: DidChangeWatchedFilesRegistrationOptions,
3582 cx: &mut Context<LspStore>,
3583 ) {
3584 let registrations = self
3585 .language_server_dynamic_registrations
3586 .entry(language_server_id)
3587 .or_default();
3588
3589 registrations
3590 .did_change_watched_files
3591 .insert(registration_id.to_string(), params.watchers);
3592
3593 self.rebuild_watched_paths(language_server_id, cx);
3594 }
3595
3596 fn on_lsp_unregister_did_change_watched_files(
3597 &mut self,
3598 language_server_id: LanguageServerId,
3599 registration_id: &str,
3600 cx: &mut Context<LspStore>,
3601 ) {
3602 let registrations = self
3603 .language_server_dynamic_registrations
3604 .entry(language_server_id)
3605 .or_default();
3606
3607 if registrations
3608 .did_change_watched_files
3609 .remove(registration_id)
3610 .is_some()
3611 {
3612 log::info!(
3613 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3614 language_server_id,
3615 registration_id
3616 );
3617 } else {
3618 log::warn!(
3619 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3620 language_server_id,
3621 registration_id
3622 );
3623 }
3624
3625 self.rebuild_watched_paths(language_server_id, cx);
3626 }
3627
3628 async fn initialization_options_for_adapter(
3629 adapter: Arc<dyn LspAdapter>,
3630 delegate: &Arc<dyn LspAdapterDelegate>,
3631 ) -> Result<Option<serde_json::Value>> {
3632 let Some(mut initialization_config) =
3633 adapter.clone().initialization_options(delegate).await?
3634 else {
3635 return Ok(None);
3636 };
3637
3638 for other_adapter in delegate.registered_lsp_adapters() {
3639 if other_adapter.name() == adapter.name() {
3640 continue;
3641 }
3642 if let Ok(Some(target_config)) = other_adapter
3643 .clone()
3644 .additional_initialization_options(adapter.name(), delegate)
3645 .await
3646 {
3647 merge_json_value_into(target_config.clone(), &mut initialization_config);
3648 }
3649 }
3650
3651 Ok(Some(initialization_config))
3652 }
3653
3654 async fn workspace_configuration_for_adapter(
3655 adapter: Arc<dyn LspAdapter>,
3656 delegate: &Arc<dyn LspAdapterDelegate>,
3657 toolchain: Option<Toolchain>,
3658 requested_uri: Option<Uri>,
3659 cx: &mut AsyncApp,
3660 ) -> Result<serde_json::Value> {
3661 let mut workspace_config = adapter
3662 .clone()
3663 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3664 .await?;
3665
3666 for other_adapter in delegate.registered_lsp_adapters() {
3667 if other_adapter.name() == adapter.name() {
3668 continue;
3669 }
3670 if let Ok(Some(target_config)) = other_adapter
3671 .clone()
3672 .additional_workspace_configuration(adapter.name(), delegate, cx)
3673 .await
3674 {
3675 merge_json_value_into(target_config.clone(), &mut workspace_config);
3676 }
3677 }
3678
3679 Ok(workspace_config)
3680 }
3681
3682 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3683 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3684 Some(server.clone())
3685 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3686 Some(Arc::clone(server))
3687 } else {
3688 None
3689 }
3690 }
3691}
3692
3693fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3694 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3695 cx.emit(LspStoreEvent::LanguageServerUpdate {
3696 language_server_id: server.server_id(),
3697 name: Some(server.name()),
3698 message: proto::update_language_server::Variant::MetadataUpdated(
3699 proto::ServerMetadataUpdated {
3700 capabilities: Some(capabilities),
3701 binary: Some(proto::LanguageServerBinaryInfo {
3702 path: server.binary().path.to_string_lossy().into_owned(),
3703 arguments: server
3704 .binary()
3705 .arguments
3706 .iter()
3707 .map(|arg| arg.to_string_lossy().into_owned())
3708 .collect(),
3709 }),
3710 configuration: serde_json::to_string(server.configuration()).ok(),
3711 workspace_folders: server
3712 .workspace_folders()
3713 .iter()
3714 .map(|uri| uri.to_string())
3715 .collect(),
3716 },
3717 ),
3718 });
3719 }
3720}
3721
3722#[derive(Debug)]
3723pub struct FormattableBuffer {
3724 handle: Entity<Buffer>,
3725 abs_path: Option<PathBuf>,
3726 env: Option<HashMap<String, String>>,
3727 ranges: Option<Vec<Range<Anchor>>>,
3728}
3729
3730pub struct RemoteLspStore {
3731 upstream_client: Option<AnyProtoClient>,
3732 upstream_project_id: u64,
3733}
3734
3735pub(crate) enum LspStoreMode {
3736 Local(LocalLspStore), // ssh host and collab host
3737 Remote(RemoteLspStore), // collab guest
3738}
3739
3740impl LspStoreMode {
3741 fn is_local(&self) -> bool {
3742 matches!(self, LspStoreMode::Local(_))
3743 }
3744}
3745
3746pub struct LspStore {
3747 mode: LspStoreMode,
3748 last_formatting_failure: Option<String>,
3749 downstream_client: Option<(AnyProtoClient, u64)>,
3750 nonce: u128,
3751 buffer_store: Entity<BufferStore>,
3752 worktree_store: Entity<WorktreeStore>,
3753 pub languages: Arc<LanguageRegistry>,
3754 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3755 active_entry: Option<ProjectEntryId>,
3756 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3757 _maintain_buffer_languages: Task<()>,
3758 diagnostic_summaries:
3759 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3760 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3761 lsp_data: HashMap<BufferId, BufferLspData>,
3762 next_hint_id: Arc<AtomicUsize>,
3763}
3764
3765#[derive(Debug)]
3766pub struct BufferLspData {
3767 buffer_version: Global,
3768 document_colors: Option<DocumentColorData>,
3769 code_lens: Option<CodeLensData>,
3770 inlay_hints: BufferInlayHints,
3771 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3772 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3773}
3774
3775#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3776struct LspKey {
3777 request_type: TypeId,
3778 server_queried: Option<LanguageServerId>,
3779}
3780
3781impl BufferLspData {
3782 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3783 Self {
3784 buffer_version: buffer.read(cx).version(),
3785 document_colors: None,
3786 code_lens: None,
3787 inlay_hints: BufferInlayHints::new(buffer, cx),
3788 lsp_requests: HashMap::default(),
3789 chunk_lsp_requests: HashMap::default(),
3790 }
3791 }
3792
3793 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3794 if let Some(document_colors) = &mut self.document_colors {
3795 document_colors.colors.remove(&for_server);
3796 document_colors.cache_version += 1;
3797 }
3798
3799 if let Some(code_lens) = &mut self.code_lens {
3800 code_lens.lens.remove(&for_server);
3801 }
3802
3803 self.inlay_hints.remove_server_data(for_server);
3804 }
3805
3806 #[cfg(any(test, feature = "test-support"))]
3807 pub fn inlay_hints(&self) -> &BufferInlayHints {
3808 &self.inlay_hints
3809 }
3810}
3811
3812#[derive(Debug, Default, Clone)]
3813pub struct DocumentColors {
3814 pub colors: HashSet<DocumentColor>,
3815 pub cache_version: Option<usize>,
3816}
3817
3818type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3819type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3820
3821#[derive(Debug, Default)]
3822struct DocumentColorData {
3823 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3824 cache_version: usize,
3825 colors_update: Option<(Global, DocumentColorTask)>,
3826}
3827
3828#[derive(Debug, Default)]
3829struct CodeLensData {
3830 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3831 update: Option<(Global, CodeLensTask)>,
3832}
3833
3834#[derive(Debug)]
3835pub enum LspStoreEvent {
3836 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3837 LanguageServerRemoved(LanguageServerId),
3838 LanguageServerUpdate {
3839 language_server_id: LanguageServerId,
3840 name: Option<LanguageServerName>,
3841 message: proto::update_language_server::Variant,
3842 },
3843 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3844 LanguageServerPrompt(LanguageServerPromptRequest),
3845 LanguageDetected {
3846 buffer: Entity<Buffer>,
3847 new_language: Option<Arc<Language>>,
3848 },
3849 Notification(String),
3850 RefreshInlayHints {
3851 server_id: LanguageServerId,
3852 request_id: Option<usize>,
3853 },
3854 RefreshCodeLens,
3855 DiagnosticsUpdated {
3856 server_id: LanguageServerId,
3857 paths: Vec<ProjectPath>,
3858 },
3859 DiskBasedDiagnosticsStarted {
3860 language_server_id: LanguageServerId,
3861 },
3862 DiskBasedDiagnosticsFinished {
3863 language_server_id: LanguageServerId,
3864 },
3865 SnippetEdit {
3866 buffer_id: BufferId,
3867 edits: Vec<(lsp::Range, Snippet)>,
3868 most_recent_edit: clock::Lamport,
3869 },
3870}
3871
3872#[derive(Clone, Debug, Serialize)]
3873pub struct LanguageServerStatus {
3874 pub name: LanguageServerName,
3875 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3876 pub has_pending_diagnostic_updates: bool,
3877 pub progress_tokens: HashSet<ProgressToken>,
3878 pub worktree: Option<WorktreeId>,
3879 pub binary: Option<LanguageServerBinary>,
3880 pub configuration: Option<Value>,
3881 pub workspace_folders: BTreeSet<Uri>,
3882}
3883
3884#[derive(Clone, Debug)]
3885struct CoreSymbol {
3886 pub language_server_name: LanguageServerName,
3887 pub source_worktree_id: WorktreeId,
3888 pub source_language_server_id: LanguageServerId,
3889 pub path: SymbolLocation,
3890 pub name: String,
3891 pub kind: lsp::SymbolKind,
3892 pub range: Range<Unclipped<PointUtf16>>,
3893}
3894
3895#[derive(Clone, Debug, PartialEq, Eq)]
3896pub enum SymbolLocation {
3897 InProject(ProjectPath),
3898 OutsideProject {
3899 abs_path: Arc<Path>,
3900 signature: [u8; 32],
3901 },
3902}
3903
3904impl SymbolLocation {
3905 fn file_name(&self) -> Option<&str> {
3906 match self {
3907 Self::InProject(path) => path.path.file_name(),
3908 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3909 }
3910 }
3911}
3912
3913impl LspStore {
3914 pub fn init(client: &AnyProtoClient) {
3915 client.add_entity_request_handler(Self::handle_lsp_query);
3916 client.add_entity_message_handler(Self::handle_lsp_query_response);
3917 client.add_entity_request_handler(Self::handle_restart_language_servers);
3918 client.add_entity_request_handler(Self::handle_stop_language_servers);
3919 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3920 client.add_entity_message_handler(Self::handle_start_language_server);
3921 client.add_entity_message_handler(Self::handle_update_language_server);
3922 client.add_entity_message_handler(Self::handle_language_server_log);
3923 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3924 client.add_entity_request_handler(Self::handle_format_buffers);
3925 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3926 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3927 client.add_entity_request_handler(Self::handle_apply_code_action);
3928 client.add_entity_request_handler(Self::handle_get_project_symbols);
3929 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3930 client.add_entity_request_handler(Self::handle_get_color_presentation);
3931 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3932 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3933 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3934 client.add_entity_request_handler(Self::handle_on_type_formatting);
3935 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3936 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3937 client.add_entity_request_handler(Self::handle_rename_project_entry);
3938 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3939 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3940 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3941 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3942 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3943 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3944 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3945
3946 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3947 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3948 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3949 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3950 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3951 client.add_entity_request_handler(
3952 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3953 );
3954 client.add_entity_request_handler(
3955 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3956 );
3957 client.add_entity_request_handler(
3958 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3959 );
3960 }
3961
3962 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3963 match &self.mode {
3964 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3965 _ => None,
3966 }
3967 }
3968
3969 pub fn as_local(&self) -> Option<&LocalLspStore> {
3970 match &self.mode {
3971 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3972 _ => None,
3973 }
3974 }
3975
3976 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3977 match &mut self.mode {
3978 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3979 _ => None,
3980 }
3981 }
3982
3983 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3984 match &self.mode {
3985 LspStoreMode::Remote(RemoteLspStore {
3986 upstream_client: Some(upstream_client),
3987 upstream_project_id,
3988 ..
3989 }) => Some((upstream_client.clone(), *upstream_project_id)),
3990
3991 LspStoreMode::Remote(RemoteLspStore {
3992 upstream_client: None,
3993 ..
3994 }) => None,
3995 LspStoreMode::Local(_) => None,
3996 }
3997 }
3998
3999 pub fn new_local(
4000 buffer_store: Entity<BufferStore>,
4001 worktree_store: Entity<WorktreeStore>,
4002 prettier_store: Entity<PrettierStore>,
4003 toolchain_store: Entity<LocalToolchainStore>,
4004 environment: Entity<ProjectEnvironment>,
4005 manifest_tree: Entity<ManifestTree>,
4006 languages: Arc<LanguageRegistry>,
4007 http_client: Arc<dyn HttpClient>,
4008 fs: Arc<dyn Fs>,
4009 cx: &mut Context<Self>,
4010 ) -> Self {
4011 let yarn = YarnPathStore::new(fs.clone(), cx);
4012 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4013 .detach();
4014 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4015 .detach();
4016 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4017 .detach();
4018 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4019 .detach();
4020 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4021 .detach();
4022 subscribe_to_binary_statuses(&languages, cx).detach();
4023
4024 let _maintain_workspace_config = {
4025 let (sender, receiver) = watch::channel();
4026 (Self::maintain_workspace_config(receiver, cx), sender)
4027 };
4028
4029 Self {
4030 mode: LspStoreMode::Local(LocalLspStore {
4031 weak: cx.weak_entity(),
4032 worktree_store: worktree_store.clone(),
4033
4034 supplementary_language_servers: Default::default(),
4035 languages: languages.clone(),
4036 language_server_ids: Default::default(),
4037 language_servers: Default::default(),
4038 last_workspace_edits_by_language_server: Default::default(),
4039 language_server_watched_paths: Default::default(),
4040 language_server_paths_watched_for_rename: Default::default(),
4041 language_server_dynamic_registrations: Default::default(),
4042 buffers_being_formatted: Default::default(),
4043 buffer_snapshots: Default::default(),
4044 prettier_store,
4045 environment,
4046 http_client,
4047 fs,
4048 yarn,
4049 next_diagnostic_group_id: Default::default(),
4050 diagnostics: Default::default(),
4051 _subscription: cx.on_app_quit(|this, cx| {
4052 this.as_local_mut()
4053 .unwrap()
4054 .shutdown_language_servers_on_quit(cx)
4055 }),
4056 lsp_tree: LanguageServerTree::new(
4057 manifest_tree,
4058 languages.clone(),
4059 toolchain_store.clone(),
4060 ),
4061 toolchain_store,
4062 registered_buffers: HashMap::default(),
4063 buffers_opened_in_servers: HashMap::default(),
4064 buffer_pull_diagnostics_result_ids: HashMap::default(),
4065 workspace_pull_diagnostics_result_ids: HashMap::default(),
4066 restricted_worktrees_tasks: HashMap::default(),
4067 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4068 .manifest_file_names(),
4069 }),
4070 last_formatting_failure: None,
4071 downstream_client: None,
4072 buffer_store,
4073 worktree_store,
4074 languages: languages.clone(),
4075 language_server_statuses: Default::default(),
4076 nonce: StdRng::from_os_rng().random(),
4077 diagnostic_summaries: HashMap::default(),
4078 lsp_server_capabilities: HashMap::default(),
4079 lsp_data: HashMap::default(),
4080 next_hint_id: Arc::default(),
4081 active_entry: None,
4082 _maintain_workspace_config,
4083 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4084 }
4085 }
4086
4087 fn send_lsp_proto_request<R: LspCommand>(
4088 &self,
4089 buffer: Entity<Buffer>,
4090 client: AnyProtoClient,
4091 upstream_project_id: u64,
4092 request: R,
4093 cx: &mut Context<LspStore>,
4094 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4095 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4096 return Task::ready(Ok(R::Response::default()));
4097 }
4098 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4099 cx.spawn(async move |this, cx| {
4100 let response = client.request(message).await?;
4101 let this = this.upgrade().context("project dropped")?;
4102 request
4103 .response_from_proto(response, this, buffer, cx.clone())
4104 .await
4105 })
4106 }
4107
4108 pub(super) fn new_remote(
4109 buffer_store: Entity<BufferStore>,
4110 worktree_store: Entity<WorktreeStore>,
4111 languages: Arc<LanguageRegistry>,
4112 upstream_client: AnyProtoClient,
4113 project_id: u64,
4114 cx: &mut Context<Self>,
4115 ) -> Self {
4116 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4117 .detach();
4118 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4119 .detach();
4120 subscribe_to_binary_statuses(&languages, cx).detach();
4121 let _maintain_workspace_config = {
4122 let (sender, receiver) = watch::channel();
4123 (Self::maintain_workspace_config(receiver, cx), sender)
4124 };
4125 Self {
4126 mode: LspStoreMode::Remote(RemoteLspStore {
4127 upstream_client: Some(upstream_client),
4128 upstream_project_id: project_id,
4129 }),
4130 downstream_client: None,
4131 last_formatting_failure: None,
4132 buffer_store,
4133 worktree_store,
4134 languages: languages.clone(),
4135 language_server_statuses: Default::default(),
4136 nonce: StdRng::from_os_rng().random(),
4137 diagnostic_summaries: HashMap::default(),
4138 lsp_server_capabilities: HashMap::default(),
4139 next_hint_id: Arc::default(),
4140 lsp_data: HashMap::default(),
4141 active_entry: None,
4142
4143 _maintain_workspace_config,
4144 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4145 }
4146 }
4147
4148 fn on_buffer_store_event(
4149 &mut self,
4150 _: Entity<BufferStore>,
4151 event: &BufferStoreEvent,
4152 cx: &mut Context<Self>,
4153 ) {
4154 match event {
4155 BufferStoreEvent::BufferAdded(buffer) => {
4156 self.on_buffer_added(buffer, cx).log_err();
4157 }
4158 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4159 let buffer_id = buffer.read(cx).remote_id();
4160 if let Some(local) = self.as_local_mut()
4161 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4162 {
4163 local.reset_buffer(buffer, old_file, cx);
4164
4165 if local.registered_buffers.contains_key(&buffer_id) {
4166 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4167 }
4168 }
4169
4170 self.detect_language_for_buffer(buffer, cx);
4171 if let Some(local) = self.as_local_mut() {
4172 local.initialize_buffer(buffer, cx);
4173 if local.registered_buffers.contains_key(&buffer_id) {
4174 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4175 }
4176 }
4177 }
4178 _ => {}
4179 }
4180 }
4181
4182 fn on_worktree_store_event(
4183 &mut self,
4184 _: Entity<WorktreeStore>,
4185 event: &WorktreeStoreEvent,
4186 cx: &mut Context<Self>,
4187 ) {
4188 match event {
4189 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4190 if !worktree.read(cx).is_local() {
4191 return;
4192 }
4193 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4194 worktree::Event::UpdatedEntries(changes) => {
4195 this.update_local_worktree_language_servers(&worktree, changes, cx);
4196 }
4197 worktree::Event::UpdatedGitRepositories(_)
4198 | worktree::Event::DeletedEntry(_) => {}
4199 })
4200 .detach()
4201 }
4202 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4203 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4204 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4205 }
4206 WorktreeStoreEvent::WorktreeReleased(..)
4207 | WorktreeStoreEvent::WorktreeOrderChanged
4208 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4209 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4210 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4211 }
4212 }
4213
4214 fn on_prettier_store_event(
4215 &mut self,
4216 _: Entity<PrettierStore>,
4217 event: &PrettierStoreEvent,
4218 cx: &mut Context<Self>,
4219 ) {
4220 match event {
4221 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4222 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4223 }
4224 PrettierStoreEvent::LanguageServerAdded {
4225 new_server_id,
4226 name,
4227 prettier_server,
4228 } => {
4229 self.register_supplementary_language_server(
4230 *new_server_id,
4231 name.clone(),
4232 prettier_server.clone(),
4233 cx,
4234 );
4235 }
4236 }
4237 }
4238
4239 fn on_toolchain_store_event(
4240 &mut self,
4241 _: Entity<LocalToolchainStore>,
4242 event: &ToolchainStoreEvent,
4243 _: &mut Context<Self>,
4244 ) {
4245 if let ToolchainStoreEvent::ToolchainActivated = event {
4246 self.request_workspace_config_refresh()
4247 }
4248 }
4249
4250 fn request_workspace_config_refresh(&mut self) {
4251 *self._maintain_workspace_config.1.borrow_mut() = ();
4252 }
4253
4254 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4255 self.as_local().map(|local| local.prettier_store.clone())
4256 }
4257
4258 fn on_buffer_event(
4259 &mut self,
4260 buffer: Entity<Buffer>,
4261 event: &language::BufferEvent,
4262 cx: &mut Context<Self>,
4263 ) {
4264 match event {
4265 language::BufferEvent::Edited => {
4266 self.on_buffer_edited(buffer, cx);
4267 }
4268
4269 language::BufferEvent::Saved => {
4270 self.on_buffer_saved(buffer, cx);
4271 }
4272
4273 _ => {}
4274 }
4275 }
4276
4277 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4278 buffer
4279 .read(cx)
4280 .set_language_registry(self.languages.clone());
4281
4282 cx.subscribe(buffer, |this, buffer, event, cx| {
4283 this.on_buffer_event(buffer, event, cx);
4284 })
4285 .detach();
4286
4287 self.detect_language_for_buffer(buffer, cx);
4288 if let Some(local) = self.as_local_mut() {
4289 local.initialize_buffer(buffer, cx);
4290 }
4291
4292 Ok(())
4293 }
4294
4295 pub(crate) fn register_buffer_with_language_servers(
4296 &mut self,
4297 buffer: &Entity<Buffer>,
4298 only_register_servers: HashSet<LanguageServerSelector>,
4299 ignore_refcounts: bool,
4300 cx: &mut Context<Self>,
4301 ) -> OpenLspBufferHandle {
4302 let buffer_id = buffer.read(cx).remote_id();
4303 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4304 if let Some(local) = self.as_local_mut() {
4305 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4306 if !ignore_refcounts {
4307 *refcount += 1;
4308 }
4309
4310 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4311 // 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
4312 // 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
4313 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4314 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4315 return handle;
4316 };
4317 if !file.is_local() {
4318 return handle;
4319 }
4320
4321 if ignore_refcounts || *refcount == 1 {
4322 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4323 }
4324 if !ignore_refcounts {
4325 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4326 let refcount = {
4327 let local = lsp_store.as_local_mut().unwrap();
4328 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4329 debug_panic!("bad refcounting");
4330 return;
4331 };
4332
4333 *refcount -= 1;
4334 *refcount
4335 };
4336 if refcount == 0 {
4337 lsp_store.lsp_data.remove(&buffer_id);
4338 let local = lsp_store.as_local_mut().unwrap();
4339 local.registered_buffers.remove(&buffer_id);
4340
4341 local.buffers_opened_in_servers.remove(&buffer_id);
4342 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4343 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4344
4345 let buffer_abs_path = file.abs_path(cx);
4346 for (_, buffer_pull_diagnostics_result_ids) in
4347 &mut local.buffer_pull_diagnostics_result_ids
4348 {
4349 buffer_pull_diagnostics_result_ids.retain(
4350 |_, buffer_result_ids| {
4351 buffer_result_ids.remove(&buffer_abs_path);
4352 !buffer_result_ids.is_empty()
4353 },
4354 );
4355 }
4356
4357 let diagnostic_updates = local
4358 .language_servers
4359 .keys()
4360 .cloned()
4361 .map(|server_id| DocumentDiagnosticsUpdate {
4362 diagnostics: DocumentDiagnostics {
4363 document_abs_path: buffer_abs_path.clone(),
4364 version: None,
4365 diagnostics: Vec::new(),
4366 },
4367 result_id: None,
4368 registration_id: None,
4369 server_id: server_id,
4370 disk_based_sources: Cow::Borrowed(&[]),
4371 })
4372 .collect::<Vec<_>>();
4373
4374 lsp_store
4375 .merge_diagnostic_entries(
4376 diagnostic_updates,
4377 |_, diagnostic, _| {
4378 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4379 },
4380 cx,
4381 )
4382 .context("Clearing diagnostics for the closed buffer")
4383 .log_err();
4384 }
4385 }
4386 })
4387 .detach();
4388 }
4389 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4390 let buffer_id = buffer.read(cx).remote_id().to_proto();
4391 cx.background_spawn(async move {
4392 upstream_client
4393 .request(proto::RegisterBufferWithLanguageServers {
4394 project_id: upstream_project_id,
4395 buffer_id,
4396 only_servers: only_register_servers
4397 .into_iter()
4398 .map(|selector| {
4399 let selector = match selector {
4400 LanguageServerSelector::Id(language_server_id) => {
4401 proto::language_server_selector::Selector::ServerId(
4402 language_server_id.to_proto(),
4403 )
4404 }
4405 LanguageServerSelector::Name(language_server_name) => {
4406 proto::language_server_selector::Selector::Name(
4407 language_server_name.to_string(),
4408 )
4409 }
4410 };
4411 proto::LanguageServerSelector {
4412 selector: Some(selector),
4413 }
4414 })
4415 .collect(),
4416 })
4417 .await
4418 })
4419 .detach();
4420 } else {
4421 // Our remote connection got closed
4422 }
4423 handle
4424 }
4425
4426 fn maintain_buffer_languages(
4427 languages: Arc<LanguageRegistry>,
4428 cx: &mut Context<Self>,
4429 ) -> Task<()> {
4430 let mut subscription = languages.subscribe();
4431 let mut prev_reload_count = languages.reload_count();
4432 cx.spawn(async move |this, cx| {
4433 while let Some(()) = subscription.next().await {
4434 if let Some(this) = this.upgrade() {
4435 // If the language registry has been reloaded, then remove and
4436 // re-assign the languages on all open buffers.
4437 let reload_count = languages.reload_count();
4438 if reload_count > prev_reload_count {
4439 prev_reload_count = reload_count;
4440 this.update(cx, |this, cx| {
4441 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4442 for buffer in buffer_store.buffers() {
4443 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4444 {
4445 buffer.update(cx, |buffer, cx| {
4446 buffer.set_language_async(None, cx)
4447 });
4448 if let Some(local) = this.as_local_mut() {
4449 local.reset_buffer(&buffer, &f, cx);
4450
4451 if local
4452 .registered_buffers
4453 .contains_key(&buffer.read(cx).remote_id())
4454 && let Some(file_url) =
4455 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4456 {
4457 local.unregister_buffer_from_language_servers(
4458 &buffer, &file_url, cx,
4459 );
4460 }
4461 }
4462 }
4463 }
4464 });
4465 })
4466 .ok();
4467 }
4468
4469 this.update(cx, |this, cx| {
4470 let mut plain_text_buffers = Vec::new();
4471 let mut buffers_with_unknown_injections = Vec::new();
4472 for handle in this.buffer_store.read(cx).buffers() {
4473 let buffer = handle.read(cx);
4474 if buffer.language().is_none()
4475 || buffer.language() == Some(&*language::PLAIN_TEXT)
4476 {
4477 plain_text_buffers.push(handle);
4478 } else if buffer.contains_unknown_injections() {
4479 buffers_with_unknown_injections.push(handle);
4480 }
4481 }
4482
4483 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4484 // and reused later in the invisible worktrees.
4485 plain_text_buffers.sort_by_key(|buffer| {
4486 Reverse(
4487 File::from_dyn(buffer.read(cx).file())
4488 .map(|file| file.worktree.read(cx).is_visible()),
4489 )
4490 });
4491
4492 for buffer in plain_text_buffers {
4493 this.detect_language_for_buffer(&buffer, cx);
4494 if let Some(local) = this.as_local_mut() {
4495 local.initialize_buffer(&buffer, cx);
4496 if local
4497 .registered_buffers
4498 .contains_key(&buffer.read(cx).remote_id())
4499 {
4500 local.register_buffer_with_language_servers(
4501 &buffer,
4502 HashSet::default(),
4503 cx,
4504 );
4505 }
4506 }
4507 }
4508
4509 for buffer in buffers_with_unknown_injections {
4510 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4511 }
4512 })
4513 .ok();
4514 }
4515 }
4516 })
4517 }
4518
4519 fn detect_language_for_buffer(
4520 &mut self,
4521 buffer_handle: &Entity<Buffer>,
4522 cx: &mut Context<Self>,
4523 ) -> Option<language::AvailableLanguage> {
4524 // If the buffer has a language, set it and start the language server if we haven't already.
4525 let buffer = buffer_handle.read(cx);
4526 let file = buffer.file()?;
4527
4528 let content = buffer.as_rope();
4529 let available_language = self.languages.language_for_file(file, Some(content), cx);
4530 if let Some(available_language) = &available_language {
4531 if let Some(Ok(Ok(new_language))) = self
4532 .languages
4533 .load_language(available_language)
4534 .now_or_never()
4535 {
4536 self.set_language_for_buffer(buffer_handle, new_language, cx);
4537 }
4538 } else {
4539 cx.emit(LspStoreEvent::LanguageDetected {
4540 buffer: buffer_handle.clone(),
4541 new_language: None,
4542 });
4543 }
4544
4545 available_language
4546 }
4547
4548 pub(crate) fn set_language_for_buffer(
4549 &mut self,
4550 buffer_entity: &Entity<Buffer>,
4551 new_language: Arc<Language>,
4552 cx: &mut Context<Self>,
4553 ) {
4554 let buffer = buffer_entity.read(cx);
4555 let buffer_file = buffer.file().cloned();
4556 let buffer_id = buffer.remote_id();
4557 if let Some(local_store) = self.as_local_mut()
4558 && local_store.registered_buffers.contains_key(&buffer_id)
4559 && let Some(abs_path) =
4560 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4561 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4562 {
4563 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4564 }
4565 buffer_entity.update(cx, |buffer, cx| {
4566 if buffer
4567 .language()
4568 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4569 {
4570 buffer.set_language_async(Some(new_language.clone()), cx);
4571 }
4572 });
4573
4574 let settings =
4575 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4576 let buffer_file = File::from_dyn(buffer_file.as_ref());
4577
4578 let worktree_id = if let Some(file) = buffer_file {
4579 let worktree = file.worktree.clone();
4580
4581 if let Some(local) = self.as_local_mut()
4582 && local.registered_buffers.contains_key(&buffer_id)
4583 {
4584 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4585 }
4586 Some(worktree.read(cx).id())
4587 } else {
4588 None
4589 };
4590
4591 if settings.prettier.allowed
4592 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4593 {
4594 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4595 if let Some(prettier_store) = prettier_store {
4596 prettier_store.update(cx, |prettier_store, cx| {
4597 prettier_store.install_default_prettier(
4598 worktree_id,
4599 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4600 cx,
4601 )
4602 })
4603 }
4604 }
4605
4606 cx.emit(LspStoreEvent::LanguageDetected {
4607 buffer: buffer_entity.clone(),
4608 new_language: Some(new_language),
4609 })
4610 }
4611
4612 pub fn buffer_store(&self) -> Entity<BufferStore> {
4613 self.buffer_store.clone()
4614 }
4615
4616 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4617 self.active_entry = active_entry;
4618 }
4619
4620 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4621 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4622 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4623 {
4624 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4625 summaries
4626 .iter()
4627 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4628 });
4629 if let Some(summary) = summaries.next() {
4630 client
4631 .send(proto::UpdateDiagnosticSummary {
4632 project_id: downstream_project_id,
4633 worktree_id: worktree.id().to_proto(),
4634 summary: Some(summary),
4635 more_summaries: summaries.collect(),
4636 })
4637 .log_err();
4638 }
4639 }
4640 }
4641
4642 fn is_capable_for_proto_request<R>(
4643 &self,
4644 buffer: &Entity<Buffer>,
4645 request: &R,
4646 cx: &App,
4647 ) -> bool
4648 where
4649 R: LspCommand,
4650 {
4651 self.check_if_capable_for_proto_request(
4652 buffer,
4653 |capabilities| {
4654 request.check_capabilities(AdapterServerCapabilities {
4655 server_capabilities: capabilities.clone(),
4656 code_action_kinds: None,
4657 })
4658 },
4659 cx,
4660 )
4661 }
4662
4663 fn check_if_capable_for_proto_request<F>(
4664 &self,
4665 buffer: &Entity<Buffer>,
4666 check: F,
4667 cx: &App,
4668 ) -> bool
4669 where
4670 F: FnMut(&lsp::ServerCapabilities) -> bool,
4671 {
4672 let Some(language) = buffer.read(cx).language().cloned() else {
4673 return false;
4674 };
4675 let relevant_language_servers = self
4676 .languages
4677 .lsp_adapters(&language.name())
4678 .into_iter()
4679 .map(|lsp_adapter| lsp_adapter.name())
4680 .collect::<HashSet<_>>();
4681 self.language_server_statuses
4682 .iter()
4683 .filter_map(|(server_id, server_status)| {
4684 relevant_language_servers
4685 .contains(&server_status.name)
4686 .then_some(server_id)
4687 })
4688 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4689 .any(check)
4690 }
4691
4692 fn all_capable_for_proto_request<F>(
4693 &self,
4694 buffer: &Entity<Buffer>,
4695 mut check: F,
4696 cx: &App,
4697 ) -> Vec<lsp::LanguageServerId>
4698 where
4699 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4700 {
4701 let Some(language) = buffer.read(cx).language().cloned() else {
4702 return Vec::default();
4703 };
4704 let relevant_language_servers = self
4705 .languages
4706 .lsp_adapters(&language.name())
4707 .into_iter()
4708 .map(|lsp_adapter| lsp_adapter.name())
4709 .collect::<HashSet<_>>();
4710 self.language_server_statuses
4711 .iter()
4712 .filter_map(|(server_id, server_status)| {
4713 relevant_language_servers
4714 .contains(&server_status.name)
4715 .then_some((server_id, &server_status.name))
4716 })
4717 .filter_map(|(server_id, server_name)| {
4718 self.lsp_server_capabilities
4719 .get(server_id)
4720 .map(|c| (server_id, server_name, c))
4721 })
4722 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4723 .map(|(server_id, _, _)| *server_id)
4724 .collect()
4725 }
4726
4727 pub fn request_lsp<R>(
4728 &mut self,
4729 buffer: Entity<Buffer>,
4730 server: LanguageServerToQuery,
4731 request: R,
4732 cx: &mut Context<Self>,
4733 ) -> Task<Result<R::Response>>
4734 where
4735 R: LspCommand,
4736 <R::LspRequest as lsp::request::Request>::Result: Send,
4737 <R::LspRequest as lsp::request::Request>::Params: Send,
4738 {
4739 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4740 return self.send_lsp_proto_request(
4741 buffer,
4742 upstream_client,
4743 upstream_project_id,
4744 request,
4745 cx,
4746 );
4747 }
4748
4749 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4750 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4751 local
4752 .language_servers_for_buffer(buffer, cx)
4753 .find(|(_, server)| {
4754 request.check_capabilities(server.adapter_server_capabilities())
4755 })
4756 .map(|(_, server)| server.clone())
4757 }),
4758 LanguageServerToQuery::Other(id) => self
4759 .language_server_for_local_buffer(buffer, id, cx)
4760 .and_then(|(_, server)| {
4761 request
4762 .check_capabilities(server.adapter_server_capabilities())
4763 .then(|| Arc::clone(server))
4764 }),
4765 }) else {
4766 return Task::ready(Ok(Default::default()));
4767 };
4768
4769 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4770
4771 let Some(file) = file else {
4772 return Task::ready(Ok(Default::default()));
4773 };
4774
4775 let lsp_params = match request.to_lsp_params_or_response(
4776 &file.abs_path(cx),
4777 buffer.read(cx),
4778 &language_server,
4779 cx,
4780 ) {
4781 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4782 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4783 Err(err) => {
4784 let message = format!(
4785 "{} via {} failed: {}",
4786 request.display_name(),
4787 language_server.name(),
4788 err
4789 );
4790 // rust-analyzer likes to error with this when its still loading up
4791 if !message.ends_with("content modified") {
4792 log::warn!("{message}");
4793 }
4794 return Task::ready(Err(anyhow!(message)));
4795 }
4796 };
4797
4798 let status = request.status();
4799 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4800 return Task::ready(Ok(Default::default()));
4801 }
4802 cx.spawn(async move |this, cx| {
4803 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4804
4805 let id = lsp_request.id();
4806 let _cleanup = if status.is_some() {
4807 cx.update(|cx| {
4808 this.update(cx, |this, cx| {
4809 this.on_lsp_work_start(
4810 language_server.server_id(),
4811 ProgressToken::Number(id),
4812 LanguageServerProgress {
4813 is_disk_based_diagnostics_progress: false,
4814 is_cancellable: false,
4815 title: None,
4816 message: status.clone(),
4817 percentage: None,
4818 last_update_at: cx.background_executor().now(),
4819 },
4820 cx,
4821 );
4822 })
4823 })
4824 .log_err();
4825
4826 Some(defer(|| {
4827 cx.update(|cx| {
4828 this.update(cx, |this, cx| {
4829 this.on_lsp_work_end(
4830 language_server.server_id(),
4831 ProgressToken::Number(id),
4832 cx,
4833 );
4834 })
4835 })
4836 .log_err();
4837 }))
4838 } else {
4839 None
4840 };
4841
4842 let result = lsp_request.await.into_response();
4843
4844 let response = result.map_err(|err| {
4845 let message = format!(
4846 "{} via {} failed: {}",
4847 request.display_name(),
4848 language_server.name(),
4849 err
4850 );
4851 // rust-analyzer likes to error with this when its still loading up
4852 if !message.ends_with("content modified") {
4853 log::warn!("{message}");
4854 }
4855 anyhow::anyhow!(message)
4856 })?;
4857
4858 request
4859 .response_from_lsp(
4860 response,
4861 this.upgrade().context("no app context")?,
4862 buffer,
4863 language_server.server_id(),
4864 cx.clone(),
4865 )
4866 .await
4867 })
4868 }
4869
4870 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4871 let mut language_formatters_to_check = Vec::new();
4872 for buffer in self.buffer_store.read(cx).buffers() {
4873 let buffer = buffer.read(cx);
4874 let buffer_file = File::from_dyn(buffer.file());
4875 let buffer_language = buffer.language();
4876 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4877 if buffer_language.is_some() {
4878 language_formatters_to_check.push((
4879 buffer_file.map(|f| f.worktree_id(cx)),
4880 settings.into_owned(),
4881 ));
4882 }
4883 }
4884
4885 self.request_workspace_config_refresh();
4886
4887 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4888 prettier_store.update(cx, |prettier_store, cx| {
4889 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4890 })
4891 }
4892
4893 cx.notify();
4894 }
4895
4896 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4897 let buffer_store = self.buffer_store.clone();
4898 let Some(local) = self.as_local_mut() else {
4899 return;
4900 };
4901 let mut adapters = BTreeMap::default();
4902 let get_adapter = {
4903 let languages = local.languages.clone();
4904 let environment = local.environment.clone();
4905 let weak = local.weak.clone();
4906 let worktree_store = local.worktree_store.clone();
4907 let http_client = local.http_client.clone();
4908 let fs = local.fs.clone();
4909 move |worktree_id, cx: &mut App| {
4910 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4911 Some(LocalLspAdapterDelegate::new(
4912 languages.clone(),
4913 &environment,
4914 weak.clone(),
4915 &worktree,
4916 http_client.clone(),
4917 fs.clone(),
4918 cx,
4919 ))
4920 }
4921 };
4922
4923 let mut messages_to_report = Vec::new();
4924 let (new_tree, to_stop) = {
4925 let mut rebase = local.lsp_tree.rebase();
4926 let buffers = buffer_store
4927 .read(cx)
4928 .buffers()
4929 .filter_map(|buffer| {
4930 let raw_buffer = buffer.read(cx);
4931 if !local
4932 .registered_buffers
4933 .contains_key(&raw_buffer.remote_id())
4934 {
4935 return None;
4936 }
4937 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4938 let language = raw_buffer.language().cloned()?;
4939 Some((file, language, raw_buffer.remote_id()))
4940 })
4941 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4942 for (file, language, buffer_id) in buffers {
4943 let worktree_id = file.worktree_id(cx);
4944 let Some(worktree) = local
4945 .worktree_store
4946 .read(cx)
4947 .worktree_for_id(worktree_id, cx)
4948 else {
4949 continue;
4950 };
4951
4952 if let Some((_, apply)) = local.reuse_existing_language_server(
4953 rebase.server_tree(),
4954 &worktree,
4955 &language.name(),
4956 cx,
4957 ) {
4958 (apply)(rebase.server_tree());
4959 } else if let Some(lsp_delegate) = adapters
4960 .entry(worktree_id)
4961 .or_insert_with(|| get_adapter(worktree_id, cx))
4962 .clone()
4963 {
4964 let delegate =
4965 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4966 let path = file
4967 .path()
4968 .parent()
4969 .map(Arc::from)
4970 .unwrap_or_else(|| file.path().clone());
4971 let worktree_path = ProjectPath { worktree_id, path };
4972 let abs_path = file.abs_path(cx);
4973 let nodes = rebase
4974 .walk(
4975 worktree_path,
4976 language.name(),
4977 language.manifest(),
4978 delegate.clone(),
4979 cx,
4980 )
4981 .collect::<Vec<_>>();
4982 for node in nodes {
4983 let server_id = node.server_id_or_init(|disposition| {
4984 let path = &disposition.path;
4985 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4986 let key = LanguageServerSeed {
4987 worktree_id,
4988 name: disposition.server_name.clone(),
4989 settings: disposition.settings.clone(),
4990 toolchain: local.toolchain_store.read(cx).active_toolchain(
4991 path.worktree_id,
4992 &path.path,
4993 language.name(),
4994 ),
4995 };
4996 local.language_server_ids.remove(&key);
4997
4998 let server_id = local.get_or_insert_language_server(
4999 &worktree,
5000 lsp_delegate.clone(),
5001 disposition,
5002 &language.name(),
5003 cx,
5004 );
5005 if let Some(state) = local.language_servers.get(&server_id)
5006 && let Ok(uri) = uri
5007 {
5008 state.add_workspace_folder(uri);
5009 };
5010 server_id
5011 });
5012
5013 if let Some(language_server_id) = server_id {
5014 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5015 language_server_id,
5016 name: node.name(),
5017 message:
5018 proto::update_language_server::Variant::RegisteredForBuffer(
5019 proto::RegisteredForBuffer {
5020 buffer_abs_path: abs_path
5021 .to_string_lossy()
5022 .into_owned(),
5023 buffer_id: buffer_id.to_proto(),
5024 },
5025 ),
5026 });
5027 }
5028 }
5029 } else {
5030 continue;
5031 }
5032 }
5033 rebase.finish()
5034 };
5035 for message in messages_to_report {
5036 cx.emit(message);
5037 }
5038 local.lsp_tree = new_tree;
5039 for (id, _) in to_stop {
5040 self.stop_local_language_server(id, cx).detach();
5041 }
5042 }
5043
5044 pub fn apply_code_action(
5045 &self,
5046 buffer_handle: Entity<Buffer>,
5047 mut action: CodeAction,
5048 push_to_history: bool,
5049 cx: &mut Context<Self>,
5050 ) -> Task<Result<ProjectTransaction>> {
5051 if let Some((upstream_client, project_id)) = self.upstream_client() {
5052 let request = proto::ApplyCodeAction {
5053 project_id,
5054 buffer_id: buffer_handle.read(cx).remote_id().into(),
5055 action: Some(Self::serialize_code_action(&action)),
5056 };
5057 let buffer_store = self.buffer_store();
5058 cx.spawn(async move |_, cx| {
5059 let response = upstream_client
5060 .request(request)
5061 .await?
5062 .transaction
5063 .context("missing transaction")?;
5064
5065 buffer_store
5066 .update(cx, |buffer_store, cx| {
5067 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5068 })?
5069 .await
5070 })
5071 } else if self.mode.is_local() {
5072 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5073 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5074 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5075 }) else {
5076 return Task::ready(Ok(ProjectTransaction::default()));
5077 };
5078 cx.spawn(async move |this, cx| {
5079 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5080 .await
5081 .context("resolving a code action")?;
5082 if let Some(edit) = action.lsp_action.edit()
5083 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5084 return LocalLspStore::deserialize_workspace_edit(
5085 this.upgrade().context("no app present")?,
5086 edit.clone(),
5087 push_to_history,
5088
5089 lang_server.clone(),
5090 cx,
5091 )
5092 .await;
5093 }
5094
5095 if let Some(command) = action.lsp_action.command() {
5096 let server_capabilities = lang_server.capabilities();
5097 let available_commands = server_capabilities
5098 .execute_command_provider
5099 .as_ref()
5100 .map(|options| options.commands.as_slice())
5101 .unwrap_or_default();
5102 if available_commands.contains(&command.command) {
5103 this.update(cx, |this, _| {
5104 this.as_local_mut()
5105 .unwrap()
5106 .last_workspace_edits_by_language_server
5107 .remove(&lang_server.server_id());
5108 })?;
5109
5110 let _result = lang_server
5111 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5112 command: command.command.clone(),
5113 arguments: command.arguments.clone().unwrap_or_default(),
5114 ..lsp::ExecuteCommandParams::default()
5115 })
5116 .await.into_response()
5117 .context("execute command")?;
5118
5119 return this.update(cx, |this, _| {
5120 this.as_local_mut()
5121 .unwrap()
5122 .last_workspace_edits_by_language_server
5123 .remove(&lang_server.server_id())
5124 .unwrap_or_default()
5125 });
5126 } else {
5127 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5128 }
5129 }
5130
5131 Ok(ProjectTransaction::default())
5132 })
5133 } else {
5134 Task::ready(Err(anyhow!("no upstream client and not local")))
5135 }
5136 }
5137
5138 pub fn apply_code_action_kind(
5139 &mut self,
5140 buffers: HashSet<Entity<Buffer>>,
5141 kind: CodeActionKind,
5142 push_to_history: bool,
5143 cx: &mut Context<Self>,
5144 ) -> Task<anyhow::Result<ProjectTransaction>> {
5145 if self.as_local().is_some() {
5146 cx.spawn(async move |lsp_store, cx| {
5147 let buffers = buffers.into_iter().collect::<Vec<_>>();
5148 let result = LocalLspStore::execute_code_action_kind_locally(
5149 lsp_store.clone(),
5150 buffers,
5151 kind,
5152 push_to_history,
5153 cx,
5154 )
5155 .await;
5156 lsp_store.update(cx, |lsp_store, _| {
5157 lsp_store.update_last_formatting_failure(&result);
5158 })?;
5159 result
5160 })
5161 } else if let Some((client, project_id)) = self.upstream_client() {
5162 let buffer_store = self.buffer_store();
5163 cx.spawn(async move |lsp_store, cx| {
5164 let result = client
5165 .request(proto::ApplyCodeActionKind {
5166 project_id,
5167 kind: kind.as_str().to_owned(),
5168 buffer_ids: buffers
5169 .iter()
5170 .map(|buffer| {
5171 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5172 })
5173 .collect::<Result<_>>()?,
5174 })
5175 .await
5176 .and_then(|result| result.transaction.context("missing transaction"));
5177 lsp_store.update(cx, |lsp_store, _| {
5178 lsp_store.update_last_formatting_failure(&result);
5179 })?;
5180
5181 let transaction_response = result?;
5182 buffer_store
5183 .update(cx, |buffer_store, cx| {
5184 buffer_store.deserialize_project_transaction(
5185 transaction_response,
5186 push_to_history,
5187 cx,
5188 )
5189 })?
5190 .await
5191 })
5192 } else {
5193 Task::ready(Ok(ProjectTransaction::default()))
5194 }
5195 }
5196
5197 pub fn resolved_hint(
5198 &mut self,
5199 buffer_id: BufferId,
5200 id: InlayId,
5201 cx: &mut Context<Self>,
5202 ) -> Option<ResolvedHint> {
5203 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5204
5205 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5206 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5207 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5208 let (server_id, resolve_data) = match &hint.resolve_state {
5209 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5210 ResolveState::Resolving => {
5211 return Some(ResolvedHint::Resolving(
5212 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5213 ));
5214 }
5215 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5216 };
5217
5218 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5219 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5220 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5221 id,
5222 cx.spawn(async move |lsp_store, cx| {
5223 let resolved_hint = resolve_task.await;
5224 lsp_store
5225 .update(cx, |lsp_store, _| {
5226 if let Some(old_inlay_hint) = lsp_store
5227 .lsp_data
5228 .get_mut(&buffer_id)
5229 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5230 {
5231 match resolved_hint {
5232 Ok(resolved_hint) => {
5233 *old_inlay_hint = resolved_hint;
5234 }
5235 Err(e) => {
5236 old_inlay_hint.resolve_state =
5237 ResolveState::CanResolve(server_id, resolve_data);
5238 log::error!("Inlay hint resolve failed: {e:#}");
5239 }
5240 }
5241 }
5242 })
5243 .ok();
5244 })
5245 .shared(),
5246 );
5247 debug_assert!(
5248 previous_task.is_none(),
5249 "Did not change hint's resolve state after spawning its resolve"
5250 );
5251 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5252 None
5253 }
5254
5255 fn resolve_inlay_hint(
5256 &self,
5257 mut hint: InlayHint,
5258 buffer: Entity<Buffer>,
5259 server_id: LanguageServerId,
5260 cx: &mut Context<Self>,
5261 ) -> Task<anyhow::Result<InlayHint>> {
5262 if let Some((upstream_client, project_id)) = self.upstream_client() {
5263 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5264 {
5265 hint.resolve_state = ResolveState::Resolved;
5266 return Task::ready(Ok(hint));
5267 }
5268 let request = proto::ResolveInlayHint {
5269 project_id,
5270 buffer_id: buffer.read(cx).remote_id().into(),
5271 language_server_id: server_id.0 as u64,
5272 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5273 };
5274 cx.background_spawn(async move {
5275 let response = upstream_client
5276 .request(request)
5277 .await
5278 .context("inlay hints proto request")?;
5279 match response.hint {
5280 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5281 .context("inlay hints proto resolve response conversion"),
5282 None => Ok(hint),
5283 }
5284 })
5285 } else {
5286 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5287 self.language_server_for_local_buffer(buffer, server_id, cx)
5288 .map(|(_, server)| server.clone())
5289 }) else {
5290 return Task::ready(Ok(hint));
5291 };
5292 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5293 return Task::ready(Ok(hint));
5294 }
5295 let buffer_snapshot = buffer.read(cx).snapshot();
5296 cx.spawn(async move |_, cx| {
5297 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5298 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5299 );
5300 let resolved_hint = resolve_task
5301 .await
5302 .into_response()
5303 .context("inlay hint resolve LSP request")?;
5304 let resolved_hint = InlayHints::lsp_to_project_hint(
5305 resolved_hint,
5306 &buffer,
5307 server_id,
5308 ResolveState::Resolved,
5309 false,
5310 cx,
5311 )
5312 .await?;
5313 Ok(resolved_hint)
5314 })
5315 }
5316 }
5317
5318 pub fn resolve_color_presentation(
5319 &mut self,
5320 mut color: DocumentColor,
5321 buffer: Entity<Buffer>,
5322 server_id: LanguageServerId,
5323 cx: &mut Context<Self>,
5324 ) -> Task<Result<DocumentColor>> {
5325 if color.resolved {
5326 return Task::ready(Ok(color));
5327 }
5328
5329 if let Some((upstream_client, project_id)) = self.upstream_client() {
5330 let start = color.lsp_range.start;
5331 let end = color.lsp_range.end;
5332 let request = proto::GetColorPresentation {
5333 project_id,
5334 server_id: server_id.to_proto(),
5335 buffer_id: buffer.read(cx).remote_id().into(),
5336 color: Some(proto::ColorInformation {
5337 red: color.color.red,
5338 green: color.color.green,
5339 blue: color.color.blue,
5340 alpha: color.color.alpha,
5341 lsp_range_start: Some(proto::PointUtf16 {
5342 row: start.line,
5343 column: start.character,
5344 }),
5345 lsp_range_end: Some(proto::PointUtf16 {
5346 row: end.line,
5347 column: end.character,
5348 }),
5349 }),
5350 };
5351 cx.background_spawn(async move {
5352 let response = upstream_client
5353 .request(request)
5354 .await
5355 .context("color presentation proto request")?;
5356 color.resolved = true;
5357 color.color_presentations = response
5358 .presentations
5359 .into_iter()
5360 .map(|presentation| ColorPresentation {
5361 label: SharedString::from(presentation.label),
5362 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5363 additional_text_edits: presentation
5364 .additional_text_edits
5365 .into_iter()
5366 .filter_map(deserialize_lsp_edit)
5367 .collect(),
5368 })
5369 .collect();
5370 Ok(color)
5371 })
5372 } else {
5373 let path = match buffer
5374 .update(cx, |buffer, cx| {
5375 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5376 })
5377 .context("buffer with the missing path")
5378 {
5379 Ok(path) => path,
5380 Err(e) => return Task::ready(Err(e)),
5381 };
5382 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5383 self.language_server_for_local_buffer(buffer, server_id, cx)
5384 .map(|(_, server)| server.clone())
5385 }) else {
5386 return Task::ready(Ok(color));
5387 };
5388 cx.background_spawn(async move {
5389 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5390 lsp::ColorPresentationParams {
5391 text_document: make_text_document_identifier(&path)?,
5392 color: color.color,
5393 range: color.lsp_range,
5394 work_done_progress_params: Default::default(),
5395 partial_result_params: Default::default(),
5396 },
5397 );
5398 color.color_presentations = resolve_task
5399 .await
5400 .into_response()
5401 .context("color presentation resolve LSP request")?
5402 .into_iter()
5403 .map(|presentation| ColorPresentation {
5404 label: SharedString::from(presentation.label),
5405 text_edit: presentation.text_edit,
5406 additional_text_edits: presentation
5407 .additional_text_edits
5408 .unwrap_or_default(),
5409 })
5410 .collect();
5411 color.resolved = true;
5412 Ok(color)
5413 })
5414 }
5415 }
5416
5417 pub(crate) fn linked_edits(
5418 &mut self,
5419 buffer: &Entity<Buffer>,
5420 position: Anchor,
5421 cx: &mut Context<Self>,
5422 ) -> Task<Result<Vec<Range<Anchor>>>> {
5423 let snapshot = buffer.read(cx).snapshot();
5424 let scope = snapshot.language_scope_at(position);
5425 let Some(server_id) = self
5426 .as_local()
5427 .and_then(|local| {
5428 buffer.update(cx, |buffer, cx| {
5429 local
5430 .language_servers_for_buffer(buffer, cx)
5431 .filter(|(_, server)| {
5432 LinkedEditingRange::check_server_capabilities(server.capabilities())
5433 })
5434 .filter(|(adapter, _)| {
5435 scope
5436 .as_ref()
5437 .map(|scope| scope.language_allowed(&adapter.name))
5438 .unwrap_or(true)
5439 })
5440 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5441 .next()
5442 })
5443 })
5444 .or_else(|| {
5445 self.upstream_client()
5446 .is_some()
5447 .then_some(LanguageServerToQuery::FirstCapable)
5448 })
5449 .filter(|_| {
5450 maybe!({
5451 let language = buffer.read(cx).language_at(position)?;
5452 Some(
5453 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5454 .linked_edits,
5455 )
5456 }) == Some(true)
5457 })
5458 else {
5459 return Task::ready(Ok(Vec::new()));
5460 };
5461
5462 self.request_lsp(
5463 buffer.clone(),
5464 server_id,
5465 LinkedEditingRange { position },
5466 cx,
5467 )
5468 }
5469
5470 fn apply_on_type_formatting(
5471 &mut self,
5472 buffer: Entity<Buffer>,
5473 position: Anchor,
5474 trigger: String,
5475 cx: &mut Context<Self>,
5476 ) -> Task<Result<Option<Transaction>>> {
5477 if let Some((client, project_id)) = self.upstream_client() {
5478 if !self.check_if_capable_for_proto_request(
5479 &buffer,
5480 |capabilities| {
5481 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5482 },
5483 cx,
5484 ) {
5485 return Task::ready(Ok(None));
5486 }
5487 let request = proto::OnTypeFormatting {
5488 project_id,
5489 buffer_id: buffer.read(cx).remote_id().into(),
5490 position: Some(serialize_anchor(&position)),
5491 trigger,
5492 version: serialize_version(&buffer.read(cx).version()),
5493 };
5494 cx.background_spawn(async move {
5495 client
5496 .request(request)
5497 .await?
5498 .transaction
5499 .map(language::proto::deserialize_transaction)
5500 .transpose()
5501 })
5502 } else if let Some(local) = self.as_local_mut() {
5503 let buffer_id = buffer.read(cx).remote_id();
5504 local.buffers_being_formatted.insert(buffer_id);
5505 cx.spawn(async move |this, cx| {
5506 let _cleanup = defer({
5507 let this = this.clone();
5508 let mut cx = cx.clone();
5509 move || {
5510 this.update(&mut cx, |this, _| {
5511 if let Some(local) = this.as_local_mut() {
5512 local.buffers_being_formatted.remove(&buffer_id);
5513 }
5514 })
5515 .ok();
5516 }
5517 });
5518
5519 buffer
5520 .update(cx, |buffer, _| {
5521 buffer.wait_for_edits(Some(position.timestamp))
5522 })?
5523 .await?;
5524 this.update(cx, |this, cx| {
5525 let position = position.to_point_utf16(buffer.read(cx));
5526 this.on_type_format(buffer, position, trigger, false, cx)
5527 })?
5528 .await
5529 })
5530 } else {
5531 Task::ready(Err(anyhow!("No upstream client or local language server")))
5532 }
5533 }
5534
5535 pub fn on_type_format<T: ToPointUtf16>(
5536 &mut self,
5537 buffer: Entity<Buffer>,
5538 position: T,
5539 trigger: String,
5540 push_to_history: bool,
5541 cx: &mut Context<Self>,
5542 ) -> Task<Result<Option<Transaction>>> {
5543 let position = position.to_point_utf16(buffer.read(cx));
5544 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5545 }
5546
5547 fn on_type_format_impl(
5548 &mut self,
5549 buffer: Entity<Buffer>,
5550 position: PointUtf16,
5551 trigger: String,
5552 push_to_history: bool,
5553 cx: &mut Context<Self>,
5554 ) -> Task<Result<Option<Transaction>>> {
5555 let options = buffer.update(cx, |buffer, cx| {
5556 lsp_command::lsp_formatting_options(
5557 language_settings(
5558 buffer.language_at(position).map(|l| l.name()),
5559 buffer.file(),
5560 cx,
5561 )
5562 .as_ref(),
5563 )
5564 });
5565
5566 cx.spawn(async move |this, cx| {
5567 if let Some(waiter) =
5568 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5569 {
5570 waiter.await?;
5571 }
5572 cx.update(|cx| {
5573 this.update(cx, |this, cx| {
5574 this.request_lsp(
5575 buffer.clone(),
5576 LanguageServerToQuery::FirstCapable,
5577 OnTypeFormatting {
5578 position,
5579 trigger,
5580 options,
5581 push_to_history,
5582 },
5583 cx,
5584 )
5585 })
5586 })??
5587 .await
5588 })
5589 }
5590
5591 pub fn definitions(
5592 &mut self,
5593 buffer: &Entity<Buffer>,
5594 position: PointUtf16,
5595 cx: &mut Context<Self>,
5596 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5597 if let Some((upstream_client, project_id)) = self.upstream_client() {
5598 let request = GetDefinitions { position };
5599 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5600 return Task::ready(Ok(None));
5601 }
5602 let request_task = upstream_client.request_lsp(
5603 project_id,
5604 None,
5605 LSP_REQUEST_TIMEOUT,
5606 cx.background_executor().clone(),
5607 request.to_proto(project_id, buffer.read(cx)),
5608 );
5609 let buffer = buffer.clone();
5610 cx.spawn(async move |weak_lsp_store, cx| {
5611 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5612 return Ok(None);
5613 };
5614 let Some(responses) = request_task.await? else {
5615 return Ok(None);
5616 };
5617 let actions = join_all(responses.payload.into_iter().map(|response| {
5618 GetDefinitions { position }.response_from_proto(
5619 response.response,
5620 lsp_store.clone(),
5621 buffer.clone(),
5622 cx.clone(),
5623 )
5624 }))
5625 .await;
5626
5627 Ok(Some(
5628 actions
5629 .into_iter()
5630 .collect::<Result<Vec<Vec<_>>>>()?
5631 .into_iter()
5632 .flatten()
5633 .dedup()
5634 .collect(),
5635 ))
5636 })
5637 } else {
5638 let definitions_task = self.request_multiple_lsp_locally(
5639 buffer,
5640 Some(position),
5641 GetDefinitions { position },
5642 cx,
5643 );
5644 cx.background_spawn(async move {
5645 Ok(Some(
5646 definitions_task
5647 .await
5648 .into_iter()
5649 .flat_map(|(_, definitions)| definitions)
5650 .dedup()
5651 .collect(),
5652 ))
5653 })
5654 }
5655 }
5656
5657 pub fn declarations(
5658 &mut self,
5659 buffer: &Entity<Buffer>,
5660 position: PointUtf16,
5661 cx: &mut Context<Self>,
5662 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5663 if let Some((upstream_client, project_id)) = self.upstream_client() {
5664 let request = GetDeclarations { position };
5665 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5666 return Task::ready(Ok(None));
5667 }
5668 let request_task = upstream_client.request_lsp(
5669 project_id,
5670 None,
5671 LSP_REQUEST_TIMEOUT,
5672 cx.background_executor().clone(),
5673 request.to_proto(project_id, buffer.read(cx)),
5674 );
5675 let buffer = buffer.clone();
5676 cx.spawn(async move |weak_lsp_store, cx| {
5677 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5678 return Ok(None);
5679 };
5680 let Some(responses) = request_task.await? else {
5681 return Ok(None);
5682 };
5683 let actions = join_all(responses.payload.into_iter().map(|response| {
5684 GetDeclarations { position }.response_from_proto(
5685 response.response,
5686 lsp_store.clone(),
5687 buffer.clone(),
5688 cx.clone(),
5689 )
5690 }))
5691 .await;
5692
5693 Ok(Some(
5694 actions
5695 .into_iter()
5696 .collect::<Result<Vec<Vec<_>>>>()?
5697 .into_iter()
5698 .flatten()
5699 .dedup()
5700 .collect(),
5701 ))
5702 })
5703 } else {
5704 let declarations_task = self.request_multiple_lsp_locally(
5705 buffer,
5706 Some(position),
5707 GetDeclarations { position },
5708 cx,
5709 );
5710 cx.background_spawn(async move {
5711 Ok(Some(
5712 declarations_task
5713 .await
5714 .into_iter()
5715 .flat_map(|(_, declarations)| declarations)
5716 .dedup()
5717 .collect(),
5718 ))
5719 })
5720 }
5721 }
5722
5723 pub fn type_definitions(
5724 &mut self,
5725 buffer: &Entity<Buffer>,
5726 position: PointUtf16,
5727 cx: &mut Context<Self>,
5728 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5729 if let Some((upstream_client, project_id)) = self.upstream_client() {
5730 let request = GetTypeDefinitions { position };
5731 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5732 return Task::ready(Ok(None));
5733 }
5734 let request_task = upstream_client.request_lsp(
5735 project_id,
5736 None,
5737 LSP_REQUEST_TIMEOUT,
5738 cx.background_executor().clone(),
5739 request.to_proto(project_id, buffer.read(cx)),
5740 );
5741 let buffer = buffer.clone();
5742 cx.spawn(async move |weak_lsp_store, cx| {
5743 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5744 return Ok(None);
5745 };
5746 let Some(responses) = request_task.await? else {
5747 return Ok(None);
5748 };
5749 let actions = join_all(responses.payload.into_iter().map(|response| {
5750 GetTypeDefinitions { position }.response_from_proto(
5751 response.response,
5752 lsp_store.clone(),
5753 buffer.clone(),
5754 cx.clone(),
5755 )
5756 }))
5757 .await;
5758
5759 Ok(Some(
5760 actions
5761 .into_iter()
5762 .collect::<Result<Vec<Vec<_>>>>()?
5763 .into_iter()
5764 .flatten()
5765 .dedup()
5766 .collect(),
5767 ))
5768 })
5769 } else {
5770 let type_definitions_task = self.request_multiple_lsp_locally(
5771 buffer,
5772 Some(position),
5773 GetTypeDefinitions { position },
5774 cx,
5775 );
5776 cx.background_spawn(async move {
5777 Ok(Some(
5778 type_definitions_task
5779 .await
5780 .into_iter()
5781 .flat_map(|(_, type_definitions)| type_definitions)
5782 .dedup()
5783 .collect(),
5784 ))
5785 })
5786 }
5787 }
5788
5789 pub fn implementations(
5790 &mut self,
5791 buffer: &Entity<Buffer>,
5792 position: PointUtf16,
5793 cx: &mut Context<Self>,
5794 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5795 if let Some((upstream_client, project_id)) = self.upstream_client() {
5796 let request = GetImplementations { position };
5797 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5798 return Task::ready(Ok(None));
5799 }
5800 let request_task = upstream_client.request_lsp(
5801 project_id,
5802 None,
5803 LSP_REQUEST_TIMEOUT,
5804 cx.background_executor().clone(),
5805 request.to_proto(project_id, buffer.read(cx)),
5806 );
5807 let buffer = buffer.clone();
5808 cx.spawn(async move |weak_lsp_store, cx| {
5809 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5810 return Ok(None);
5811 };
5812 let Some(responses) = request_task.await? else {
5813 return Ok(None);
5814 };
5815 let actions = join_all(responses.payload.into_iter().map(|response| {
5816 GetImplementations { position }.response_from_proto(
5817 response.response,
5818 lsp_store.clone(),
5819 buffer.clone(),
5820 cx.clone(),
5821 )
5822 }))
5823 .await;
5824
5825 Ok(Some(
5826 actions
5827 .into_iter()
5828 .collect::<Result<Vec<Vec<_>>>>()?
5829 .into_iter()
5830 .flatten()
5831 .dedup()
5832 .collect(),
5833 ))
5834 })
5835 } else {
5836 let implementations_task = self.request_multiple_lsp_locally(
5837 buffer,
5838 Some(position),
5839 GetImplementations { position },
5840 cx,
5841 );
5842 cx.background_spawn(async move {
5843 Ok(Some(
5844 implementations_task
5845 .await
5846 .into_iter()
5847 .flat_map(|(_, implementations)| implementations)
5848 .dedup()
5849 .collect(),
5850 ))
5851 })
5852 }
5853 }
5854
5855 pub fn references(
5856 &mut self,
5857 buffer: &Entity<Buffer>,
5858 position: PointUtf16,
5859 cx: &mut Context<Self>,
5860 ) -> Task<Result<Option<Vec<Location>>>> {
5861 if let Some((upstream_client, project_id)) = self.upstream_client() {
5862 let request = GetReferences { position };
5863 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5864 return Task::ready(Ok(None));
5865 }
5866
5867 let request_task = upstream_client.request_lsp(
5868 project_id,
5869 None,
5870 LSP_REQUEST_TIMEOUT,
5871 cx.background_executor().clone(),
5872 request.to_proto(project_id, buffer.read(cx)),
5873 );
5874 let buffer = buffer.clone();
5875 cx.spawn(async move |weak_lsp_store, cx| {
5876 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5877 return Ok(None);
5878 };
5879 let Some(responses) = request_task.await? else {
5880 return Ok(None);
5881 };
5882
5883 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5884 GetReferences { position }.response_from_proto(
5885 lsp_response.response,
5886 lsp_store.clone(),
5887 buffer.clone(),
5888 cx.clone(),
5889 )
5890 }))
5891 .await
5892 .into_iter()
5893 .collect::<Result<Vec<Vec<_>>>>()?
5894 .into_iter()
5895 .flatten()
5896 .dedup()
5897 .collect();
5898 Ok(Some(locations))
5899 })
5900 } else {
5901 let references_task = self.request_multiple_lsp_locally(
5902 buffer,
5903 Some(position),
5904 GetReferences { position },
5905 cx,
5906 );
5907 cx.background_spawn(async move {
5908 Ok(Some(
5909 references_task
5910 .await
5911 .into_iter()
5912 .flat_map(|(_, references)| references)
5913 .dedup()
5914 .collect(),
5915 ))
5916 })
5917 }
5918 }
5919
5920 pub fn code_actions(
5921 &mut self,
5922 buffer: &Entity<Buffer>,
5923 range: Range<Anchor>,
5924 kinds: Option<Vec<CodeActionKind>>,
5925 cx: &mut Context<Self>,
5926 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5927 if let Some((upstream_client, project_id)) = self.upstream_client() {
5928 let request = GetCodeActions {
5929 range: range.clone(),
5930 kinds: kinds.clone(),
5931 };
5932 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5933 return Task::ready(Ok(None));
5934 }
5935 let request_task = upstream_client.request_lsp(
5936 project_id,
5937 None,
5938 LSP_REQUEST_TIMEOUT,
5939 cx.background_executor().clone(),
5940 request.to_proto(project_id, buffer.read(cx)),
5941 );
5942 let buffer = buffer.clone();
5943 cx.spawn(async move |weak_lsp_store, cx| {
5944 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5945 return Ok(None);
5946 };
5947 let Some(responses) = request_task.await? else {
5948 return Ok(None);
5949 };
5950 let actions = join_all(responses.payload.into_iter().map(|response| {
5951 GetCodeActions {
5952 range: range.clone(),
5953 kinds: kinds.clone(),
5954 }
5955 .response_from_proto(
5956 response.response,
5957 lsp_store.clone(),
5958 buffer.clone(),
5959 cx.clone(),
5960 )
5961 }))
5962 .await;
5963
5964 Ok(Some(
5965 actions
5966 .into_iter()
5967 .collect::<Result<Vec<Vec<_>>>>()?
5968 .into_iter()
5969 .flatten()
5970 .collect(),
5971 ))
5972 })
5973 } else {
5974 let all_actions_task = self.request_multiple_lsp_locally(
5975 buffer,
5976 Some(range.start),
5977 GetCodeActions { range, kinds },
5978 cx,
5979 );
5980 cx.background_spawn(async move {
5981 Ok(Some(
5982 all_actions_task
5983 .await
5984 .into_iter()
5985 .flat_map(|(_, actions)| actions)
5986 .collect(),
5987 ))
5988 })
5989 }
5990 }
5991
5992 pub fn code_lens_actions(
5993 &mut self,
5994 buffer: &Entity<Buffer>,
5995 cx: &mut Context<Self>,
5996 ) -> CodeLensTask {
5997 let version_queried_for = buffer.read(cx).version();
5998 let buffer_id = buffer.read(cx).remote_id();
5999 let existing_servers = self.as_local().map(|local| {
6000 local
6001 .buffers_opened_in_servers
6002 .get(&buffer_id)
6003 .cloned()
6004 .unwrap_or_default()
6005 });
6006
6007 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6008 if let Some(cached_lens) = &lsp_data.code_lens {
6009 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6010 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6011 existing_servers != cached_lens.lens.keys().copied().collect()
6012 });
6013 if !has_different_servers {
6014 return Task::ready(Ok(Some(
6015 cached_lens.lens.values().flatten().cloned().collect(),
6016 )))
6017 .shared();
6018 }
6019 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6020 if !version_queried_for.changed_since(updating_for) {
6021 return running_update.clone();
6022 }
6023 }
6024 }
6025 }
6026
6027 let lens_lsp_data = self
6028 .latest_lsp_data(buffer, cx)
6029 .code_lens
6030 .get_or_insert_default();
6031 let buffer = buffer.clone();
6032 let query_version_queried_for = version_queried_for.clone();
6033 let new_task = cx
6034 .spawn(async move |lsp_store, cx| {
6035 cx.background_executor()
6036 .timer(Duration::from_millis(30))
6037 .await;
6038 let fetched_lens = lsp_store
6039 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6040 .map_err(Arc::new)?
6041 .await
6042 .context("fetching code lens")
6043 .map_err(Arc::new);
6044 let fetched_lens = match fetched_lens {
6045 Ok(fetched_lens) => fetched_lens,
6046 Err(e) => {
6047 lsp_store
6048 .update(cx, |lsp_store, _| {
6049 if let Some(lens_lsp_data) = lsp_store
6050 .lsp_data
6051 .get_mut(&buffer_id)
6052 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6053 {
6054 lens_lsp_data.update = None;
6055 }
6056 })
6057 .ok();
6058 return Err(e);
6059 }
6060 };
6061
6062 lsp_store
6063 .update(cx, |lsp_store, _| {
6064 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6065 let code_lens = lsp_data.code_lens.as_mut()?;
6066 if let Some(fetched_lens) = fetched_lens {
6067 if lsp_data.buffer_version == query_version_queried_for {
6068 code_lens.lens.extend(fetched_lens);
6069 } else if !lsp_data
6070 .buffer_version
6071 .changed_since(&query_version_queried_for)
6072 {
6073 lsp_data.buffer_version = query_version_queried_for;
6074 code_lens.lens = fetched_lens;
6075 }
6076 }
6077 code_lens.update = None;
6078 Some(code_lens.lens.values().flatten().cloned().collect())
6079 })
6080 .map_err(Arc::new)
6081 })
6082 .shared();
6083 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6084 new_task
6085 }
6086
6087 fn fetch_code_lens(
6088 &mut self,
6089 buffer: &Entity<Buffer>,
6090 cx: &mut Context<Self>,
6091 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6092 if let Some((upstream_client, project_id)) = self.upstream_client() {
6093 let request = GetCodeLens;
6094 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6095 return Task::ready(Ok(None));
6096 }
6097 let request_task = upstream_client.request_lsp(
6098 project_id,
6099 None,
6100 LSP_REQUEST_TIMEOUT,
6101 cx.background_executor().clone(),
6102 request.to_proto(project_id, buffer.read(cx)),
6103 );
6104 let buffer = buffer.clone();
6105 cx.spawn(async move |weak_lsp_store, cx| {
6106 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6107 return Ok(None);
6108 };
6109 let Some(responses) = request_task.await? else {
6110 return Ok(None);
6111 };
6112
6113 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6114 let lsp_store = lsp_store.clone();
6115 let buffer = buffer.clone();
6116 let cx = cx.clone();
6117 async move {
6118 (
6119 LanguageServerId::from_proto(response.server_id),
6120 GetCodeLens
6121 .response_from_proto(response.response, lsp_store, buffer, cx)
6122 .await,
6123 )
6124 }
6125 }))
6126 .await;
6127
6128 let mut has_errors = false;
6129 let code_lens_actions = code_lens_actions
6130 .into_iter()
6131 .filter_map(|(server_id, code_lens)| match code_lens {
6132 Ok(code_lens) => Some((server_id, code_lens)),
6133 Err(e) => {
6134 has_errors = true;
6135 log::error!("{e:#}");
6136 None
6137 }
6138 })
6139 .collect::<HashMap<_, _>>();
6140 anyhow::ensure!(
6141 !has_errors || !code_lens_actions.is_empty(),
6142 "Failed to fetch code lens"
6143 );
6144 Ok(Some(code_lens_actions))
6145 })
6146 } else {
6147 let code_lens_actions_task =
6148 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6149 cx.background_spawn(async move {
6150 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6151 })
6152 }
6153 }
6154
6155 #[inline(never)]
6156 pub fn completions(
6157 &self,
6158 buffer: &Entity<Buffer>,
6159 position: PointUtf16,
6160 context: CompletionContext,
6161 cx: &mut Context<Self>,
6162 ) -> Task<Result<Vec<CompletionResponse>>> {
6163 let language_registry = self.languages.clone();
6164
6165 if let Some((upstream_client, project_id)) = self.upstream_client() {
6166 let snapshot = buffer.read(cx).snapshot();
6167 let offset = position.to_offset(&snapshot);
6168 let scope = snapshot.language_scope_at(offset);
6169 let capable_lsps = self.all_capable_for_proto_request(
6170 buffer,
6171 |server_name, capabilities| {
6172 capabilities.completion_provider.is_some()
6173 && scope
6174 .as_ref()
6175 .map(|scope| scope.language_allowed(server_name))
6176 .unwrap_or(true)
6177 },
6178 cx,
6179 );
6180 if capable_lsps.is_empty() {
6181 return Task::ready(Ok(Vec::new()));
6182 }
6183
6184 let language = buffer.read(cx).language().cloned();
6185
6186 // In the future, we should provide project guests with the names of LSP adapters,
6187 // so that they can use the correct LSP adapter when computing labels. For now,
6188 // guests just use the first LSP adapter associated with the buffer's language.
6189 let lsp_adapter = language.as_ref().and_then(|language| {
6190 language_registry
6191 .lsp_adapters(&language.name())
6192 .first()
6193 .cloned()
6194 });
6195
6196 let buffer = buffer.clone();
6197
6198 cx.spawn(async move |this, cx| {
6199 let requests = join_all(
6200 capable_lsps
6201 .into_iter()
6202 .map(|id| {
6203 let request = GetCompletions {
6204 position,
6205 context: context.clone(),
6206 server_id: Some(id),
6207 };
6208 let buffer = buffer.clone();
6209 let language = language.clone();
6210 let lsp_adapter = lsp_adapter.clone();
6211 let upstream_client = upstream_client.clone();
6212 let response = this
6213 .update(cx, |this, cx| {
6214 this.send_lsp_proto_request(
6215 buffer,
6216 upstream_client,
6217 project_id,
6218 request,
6219 cx,
6220 )
6221 })
6222 .log_err();
6223 async move {
6224 let response = response?.await.log_err()?;
6225
6226 let completions = populate_labels_for_completions(
6227 response.completions,
6228 language,
6229 lsp_adapter,
6230 )
6231 .await;
6232
6233 Some(CompletionResponse {
6234 completions,
6235 display_options: CompletionDisplayOptions::default(),
6236 is_incomplete: response.is_incomplete,
6237 })
6238 }
6239 })
6240 .collect::<Vec<_>>(),
6241 );
6242 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6243 })
6244 } else if let Some(local) = self.as_local() {
6245 let snapshot = buffer.read(cx).snapshot();
6246 let offset = position.to_offset(&snapshot);
6247 let scope = snapshot.language_scope_at(offset);
6248 let language = snapshot.language().cloned();
6249 let completion_settings = language_settings(
6250 language.as_ref().map(|language| language.name()),
6251 buffer.read(cx).file(),
6252 cx,
6253 )
6254 .completions
6255 .clone();
6256 if !completion_settings.lsp {
6257 return Task::ready(Ok(Vec::new()));
6258 }
6259
6260 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6261 local
6262 .language_servers_for_buffer(buffer, cx)
6263 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6264 .filter(|(adapter, _)| {
6265 scope
6266 .as_ref()
6267 .map(|scope| scope.language_allowed(&adapter.name))
6268 .unwrap_or(true)
6269 })
6270 .map(|(_, server)| server.server_id())
6271 .collect()
6272 });
6273
6274 let buffer = buffer.clone();
6275 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6276 let lsp_timeout = if lsp_timeout > 0 {
6277 Some(Duration::from_millis(lsp_timeout))
6278 } else {
6279 None
6280 };
6281 cx.spawn(async move |this, cx| {
6282 let mut tasks = Vec::with_capacity(server_ids.len());
6283 this.update(cx, |lsp_store, cx| {
6284 for server_id in server_ids {
6285 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6286 let lsp_timeout = lsp_timeout
6287 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6288 let mut timeout = cx.background_spawn(async move {
6289 match lsp_timeout {
6290 Some(lsp_timeout) => {
6291 lsp_timeout.await;
6292 true
6293 },
6294 None => false,
6295 }
6296 }).fuse();
6297 let mut lsp_request = lsp_store.request_lsp(
6298 buffer.clone(),
6299 LanguageServerToQuery::Other(server_id),
6300 GetCompletions {
6301 position,
6302 context: context.clone(),
6303 server_id: Some(server_id),
6304 },
6305 cx,
6306 ).fuse();
6307 let new_task = cx.background_spawn(async move {
6308 select_biased! {
6309 response = lsp_request => anyhow::Ok(Some(response?)),
6310 timeout_happened = timeout => {
6311 if timeout_happened {
6312 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6313 Ok(None)
6314 } else {
6315 let completions = lsp_request.await?;
6316 Ok(Some(completions))
6317 }
6318 },
6319 }
6320 });
6321 tasks.push((lsp_adapter, new_task));
6322 }
6323 })?;
6324
6325 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6326 let completion_response = task.await.ok()??;
6327 let completions = populate_labels_for_completions(
6328 completion_response.completions,
6329 language.clone(),
6330 lsp_adapter,
6331 )
6332 .await;
6333 Some(CompletionResponse {
6334 completions,
6335 display_options: CompletionDisplayOptions::default(),
6336 is_incomplete: completion_response.is_incomplete,
6337 })
6338 });
6339
6340 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6341
6342 Ok(responses.into_iter().flatten().collect())
6343 })
6344 } else {
6345 Task::ready(Err(anyhow!("No upstream client or local language server")))
6346 }
6347 }
6348
6349 pub fn resolve_completions(
6350 &self,
6351 buffer: Entity<Buffer>,
6352 completion_indices: Vec<usize>,
6353 completions: Rc<RefCell<Box<[Completion]>>>,
6354 cx: &mut Context<Self>,
6355 ) -> Task<Result<bool>> {
6356 let client = self.upstream_client();
6357 let buffer_id = buffer.read(cx).remote_id();
6358 let buffer_snapshot = buffer.read(cx).snapshot();
6359
6360 if !self.check_if_capable_for_proto_request(
6361 &buffer,
6362 GetCompletions::can_resolve_completions,
6363 cx,
6364 ) {
6365 return Task::ready(Ok(false));
6366 }
6367 cx.spawn(async move |lsp_store, cx| {
6368 let mut did_resolve = false;
6369 if let Some((client, project_id)) = client {
6370 for completion_index in completion_indices {
6371 let server_id = {
6372 let completion = &completions.borrow()[completion_index];
6373 completion.source.server_id()
6374 };
6375 if let Some(server_id) = server_id {
6376 if Self::resolve_completion_remote(
6377 project_id,
6378 server_id,
6379 buffer_id,
6380 completions.clone(),
6381 completion_index,
6382 client.clone(),
6383 )
6384 .await
6385 .log_err()
6386 .is_some()
6387 {
6388 did_resolve = true;
6389 }
6390 } else {
6391 resolve_word_completion(
6392 &buffer_snapshot,
6393 &mut completions.borrow_mut()[completion_index],
6394 );
6395 }
6396 }
6397 } else {
6398 for completion_index in completion_indices {
6399 let server_id = {
6400 let completion = &completions.borrow()[completion_index];
6401 completion.source.server_id()
6402 };
6403 if let Some(server_id) = server_id {
6404 let server_and_adapter = lsp_store
6405 .read_with(cx, |lsp_store, _| {
6406 let server = lsp_store.language_server_for_id(server_id)?;
6407 let adapter =
6408 lsp_store.language_server_adapter_for_id(server.server_id())?;
6409 Some((server, adapter))
6410 })
6411 .ok()
6412 .flatten();
6413 let Some((server, adapter)) = server_and_adapter else {
6414 continue;
6415 };
6416
6417 let resolved = Self::resolve_completion_local(
6418 server,
6419 completions.clone(),
6420 completion_index,
6421 )
6422 .await
6423 .log_err()
6424 .is_some();
6425 if resolved {
6426 Self::regenerate_completion_labels(
6427 adapter,
6428 &buffer_snapshot,
6429 completions.clone(),
6430 completion_index,
6431 )
6432 .await
6433 .log_err();
6434 did_resolve = true;
6435 }
6436 } else {
6437 resolve_word_completion(
6438 &buffer_snapshot,
6439 &mut completions.borrow_mut()[completion_index],
6440 );
6441 }
6442 }
6443 }
6444
6445 Ok(did_resolve)
6446 })
6447 }
6448
6449 async fn resolve_completion_local(
6450 server: Arc<lsp::LanguageServer>,
6451 completions: Rc<RefCell<Box<[Completion]>>>,
6452 completion_index: usize,
6453 ) -> Result<()> {
6454 let server_id = server.server_id();
6455 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6456 return Ok(());
6457 }
6458
6459 let request = {
6460 let completion = &completions.borrow()[completion_index];
6461 match &completion.source {
6462 CompletionSource::Lsp {
6463 lsp_completion,
6464 resolved,
6465 server_id: completion_server_id,
6466 ..
6467 } => {
6468 if *resolved {
6469 return Ok(());
6470 }
6471 anyhow::ensure!(
6472 server_id == *completion_server_id,
6473 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6474 );
6475 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6476 }
6477 CompletionSource::BufferWord { .. }
6478 | CompletionSource::Dap { .. }
6479 | CompletionSource::Custom => {
6480 return Ok(());
6481 }
6482 }
6483 };
6484 let resolved_completion = request
6485 .await
6486 .into_response()
6487 .context("resolve completion")?;
6488
6489 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6490 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6491
6492 let mut completions = completions.borrow_mut();
6493 let completion = &mut completions[completion_index];
6494 if let CompletionSource::Lsp {
6495 lsp_completion,
6496 resolved,
6497 server_id: completion_server_id,
6498 ..
6499 } = &mut completion.source
6500 {
6501 if *resolved {
6502 return Ok(());
6503 }
6504 anyhow::ensure!(
6505 server_id == *completion_server_id,
6506 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6507 );
6508 *lsp_completion = Box::new(resolved_completion);
6509 *resolved = true;
6510 }
6511 Ok(())
6512 }
6513
6514 async fn regenerate_completion_labels(
6515 adapter: Arc<CachedLspAdapter>,
6516 snapshot: &BufferSnapshot,
6517 completions: Rc<RefCell<Box<[Completion]>>>,
6518 completion_index: usize,
6519 ) -> Result<()> {
6520 let completion_item = completions.borrow()[completion_index]
6521 .source
6522 .lsp_completion(true)
6523 .map(Cow::into_owned);
6524 if let Some(lsp_documentation) = completion_item
6525 .as_ref()
6526 .and_then(|completion_item| completion_item.documentation.clone())
6527 {
6528 let mut completions = completions.borrow_mut();
6529 let completion = &mut completions[completion_index];
6530 completion.documentation = Some(lsp_documentation.into());
6531 } else {
6532 let mut completions = completions.borrow_mut();
6533 let completion = &mut completions[completion_index];
6534 completion.documentation = Some(CompletionDocumentation::Undocumented);
6535 }
6536
6537 let mut new_label = match completion_item {
6538 Some(completion_item) => {
6539 // 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
6540 // So we have to update the label here anyway...
6541 let language = snapshot.language();
6542 match language {
6543 Some(language) => {
6544 adapter
6545 .labels_for_completions(
6546 std::slice::from_ref(&completion_item),
6547 language,
6548 )
6549 .await?
6550 }
6551 None => Vec::new(),
6552 }
6553 .pop()
6554 .flatten()
6555 .unwrap_or_else(|| {
6556 CodeLabel::fallback_for_completion(
6557 &completion_item,
6558 language.map(|language| language.as_ref()),
6559 )
6560 })
6561 }
6562 None => CodeLabel::plain(
6563 completions.borrow()[completion_index].new_text.clone(),
6564 None,
6565 ),
6566 };
6567 ensure_uniform_list_compatible_label(&mut new_label);
6568
6569 let mut completions = completions.borrow_mut();
6570 let completion = &mut completions[completion_index];
6571 if completion.label.filter_text() == new_label.filter_text() {
6572 completion.label = new_label;
6573 } else {
6574 log::error!(
6575 "Resolved completion changed display label from {} to {}. \
6576 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6577 completion.label.text(),
6578 new_label.text(),
6579 completion.label.filter_text(),
6580 new_label.filter_text()
6581 );
6582 }
6583
6584 Ok(())
6585 }
6586
6587 async fn resolve_completion_remote(
6588 project_id: u64,
6589 server_id: LanguageServerId,
6590 buffer_id: BufferId,
6591 completions: Rc<RefCell<Box<[Completion]>>>,
6592 completion_index: usize,
6593 client: AnyProtoClient,
6594 ) -> Result<()> {
6595 let lsp_completion = {
6596 let completion = &completions.borrow()[completion_index];
6597 match &completion.source {
6598 CompletionSource::Lsp {
6599 lsp_completion,
6600 resolved,
6601 server_id: completion_server_id,
6602 ..
6603 } => {
6604 anyhow::ensure!(
6605 server_id == *completion_server_id,
6606 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6607 );
6608 if *resolved {
6609 return Ok(());
6610 }
6611 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6612 }
6613 CompletionSource::Custom
6614 | CompletionSource::Dap { .. }
6615 | CompletionSource::BufferWord { .. } => {
6616 return Ok(());
6617 }
6618 }
6619 };
6620 let request = proto::ResolveCompletionDocumentation {
6621 project_id,
6622 language_server_id: server_id.0 as u64,
6623 lsp_completion,
6624 buffer_id: buffer_id.into(),
6625 };
6626
6627 let response = client
6628 .request(request)
6629 .await
6630 .context("completion documentation resolve proto request")?;
6631 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6632
6633 let documentation = if response.documentation.is_empty() {
6634 CompletionDocumentation::Undocumented
6635 } else if response.documentation_is_markdown {
6636 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6637 } else if response.documentation.lines().count() <= 1 {
6638 CompletionDocumentation::SingleLine(response.documentation.into())
6639 } else {
6640 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6641 };
6642
6643 let mut completions = completions.borrow_mut();
6644 let completion = &mut completions[completion_index];
6645 completion.documentation = Some(documentation);
6646 if let CompletionSource::Lsp {
6647 insert_range,
6648 lsp_completion,
6649 resolved,
6650 server_id: completion_server_id,
6651 lsp_defaults: _,
6652 } = &mut completion.source
6653 {
6654 let completion_insert_range = response
6655 .old_insert_start
6656 .and_then(deserialize_anchor)
6657 .zip(response.old_insert_end.and_then(deserialize_anchor));
6658 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6659
6660 if *resolved {
6661 return Ok(());
6662 }
6663 anyhow::ensure!(
6664 server_id == *completion_server_id,
6665 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6666 );
6667 *lsp_completion = Box::new(resolved_lsp_completion);
6668 *resolved = true;
6669 }
6670
6671 let replace_range = response
6672 .old_replace_start
6673 .and_then(deserialize_anchor)
6674 .zip(response.old_replace_end.and_then(deserialize_anchor));
6675 if let Some((old_replace_start, old_replace_end)) = replace_range
6676 && !response.new_text.is_empty()
6677 {
6678 completion.new_text = response.new_text;
6679 completion.replace_range = old_replace_start..old_replace_end;
6680 }
6681
6682 Ok(())
6683 }
6684
6685 pub fn apply_additional_edits_for_completion(
6686 &self,
6687 buffer_handle: Entity<Buffer>,
6688 completions: Rc<RefCell<Box<[Completion]>>>,
6689 completion_index: usize,
6690 push_to_history: bool,
6691 cx: &mut Context<Self>,
6692 ) -> Task<Result<Option<Transaction>>> {
6693 if let Some((client, project_id)) = self.upstream_client() {
6694 let buffer = buffer_handle.read(cx);
6695 let buffer_id = buffer.remote_id();
6696 cx.spawn(async move |_, cx| {
6697 let request = {
6698 let completion = completions.borrow()[completion_index].clone();
6699 proto::ApplyCompletionAdditionalEdits {
6700 project_id,
6701 buffer_id: buffer_id.into(),
6702 completion: Some(Self::serialize_completion(&CoreCompletion {
6703 replace_range: completion.replace_range,
6704 new_text: completion.new_text,
6705 source: completion.source,
6706 })),
6707 }
6708 };
6709
6710 if let Some(transaction) = client.request(request).await?.transaction {
6711 let transaction = language::proto::deserialize_transaction(transaction)?;
6712 buffer_handle
6713 .update(cx, |buffer, _| {
6714 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6715 })?
6716 .await?;
6717 if push_to_history {
6718 buffer_handle.update(cx, |buffer, _| {
6719 buffer.push_transaction(transaction.clone(), Instant::now());
6720 buffer.finalize_last_transaction();
6721 })?;
6722 }
6723 Ok(Some(transaction))
6724 } else {
6725 Ok(None)
6726 }
6727 })
6728 } else {
6729 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6730 let completion = &completions.borrow()[completion_index];
6731 let server_id = completion.source.server_id()?;
6732 Some(
6733 self.language_server_for_local_buffer(buffer, server_id, cx)?
6734 .1
6735 .clone(),
6736 )
6737 }) else {
6738 return Task::ready(Ok(None));
6739 };
6740
6741 cx.spawn(async move |this, cx| {
6742 Self::resolve_completion_local(
6743 server.clone(),
6744 completions.clone(),
6745 completion_index,
6746 )
6747 .await
6748 .context("resolving completion")?;
6749 let completion = completions.borrow()[completion_index].clone();
6750 let additional_text_edits = completion
6751 .source
6752 .lsp_completion(true)
6753 .as_ref()
6754 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6755 if let Some(edits) = additional_text_edits {
6756 let edits = this
6757 .update(cx, |this, cx| {
6758 this.as_local_mut().unwrap().edits_from_lsp(
6759 &buffer_handle,
6760 edits,
6761 server.server_id(),
6762 None,
6763 cx,
6764 )
6765 })?
6766 .await?;
6767
6768 buffer_handle.update(cx, |buffer, cx| {
6769 buffer.finalize_last_transaction();
6770 buffer.start_transaction();
6771
6772 for (range, text) in edits {
6773 let primary = &completion.replace_range;
6774
6775 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6776 // and the primary completion is just an insertion (empty range), then this is likely
6777 // an auto-import scenario and should not be considered overlapping
6778 // https://github.com/zed-industries/zed/issues/26136
6779 let is_file_start_auto_import = {
6780 let snapshot = buffer.snapshot();
6781 let primary_start_point = primary.start.to_point(&snapshot);
6782 let range_start_point = range.start.to_point(&snapshot);
6783
6784 let result = primary_start_point.row == 0
6785 && primary_start_point.column == 0
6786 && range_start_point.row == 0
6787 && range_start_point.column == 0;
6788
6789 result
6790 };
6791
6792 let has_overlap = if is_file_start_auto_import {
6793 false
6794 } else {
6795 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6796 && primary.end.cmp(&range.start, buffer).is_ge();
6797 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6798 && range.end.cmp(&primary.end, buffer).is_ge();
6799 let result = start_within || end_within;
6800 result
6801 };
6802
6803 //Skip additional edits which overlap with the primary completion edit
6804 //https://github.com/zed-industries/zed/pull/1871
6805 if !has_overlap {
6806 buffer.edit([(range, text)], None, cx);
6807 }
6808 }
6809
6810 let transaction = if buffer.end_transaction(cx).is_some() {
6811 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6812 if !push_to_history {
6813 buffer.forget_transaction(transaction.id);
6814 }
6815 Some(transaction)
6816 } else {
6817 None
6818 };
6819 Ok(transaction)
6820 })?
6821 } else {
6822 Ok(None)
6823 }
6824 })
6825 }
6826 }
6827
6828 pub fn pull_diagnostics(
6829 &mut self,
6830 buffer: Entity<Buffer>,
6831 cx: &mut Context<Self>,
6832 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6833 let buffer_id = buffer.read(cx).remote_id();
6834
6835 if let Some((client, upstream_project_id)) = self.upstream_client() {
6836 let mut suitable_capabilities = None;
6837 // Are we capable for proto request?
6838 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6839 &buffer,
6840 |capabilities| {
6841 if let Some(caps) = &capabilities.diagnostic_provider {
6842 suitable_capabilities = Some(caps.clone());
6843 true
6844 } else {
6845 false
6846 }
6847 },
6848 cx,
6849 );
6850 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6851 let Some(dynamic_caps) = suitable_capabilities else {
6852 return Task::ready(Ok(None));
6853 };
6854 assert!(any_server_has_diagnostics_provider);
6855
6856 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6857 let request = GetDocumentDiagnostics {
6858 previous_result_id: None,
6859 identifier,
6860 registration_id: None,
6861 };
6862 let request_task = client.request_lsp(
6863 upstream_project_id,
6864 None,
6865 LSP_REQUEST_TIMEOUT,
6866 cx.background_executor().clone(),
6867 request.to_proto(upstream_project_id, buffer.read(cx)),
6868 );
6869 cx.background_spawn(async move {
6870 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6871 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6872 // Do not attempt to further process the dummy responses here.
6873 let _response = request_task.await?;
6874 Ok(None)
6875 })
6876 } else {
6877 let servers = buffer.update(cx, |buffer, cx| {
6878 self.running_language_servers_for_local_buffer(buffer, cx)
6879 .map(|(_, server)| server.clone())
6880 .collect::<Vec<_>>()
6881 });
6882
6883 let pull_diagnostics = servers
6884 .into_iter()
6885 .flat_map(|server| {
6886 let result = maybe!({
6887 let local = self.as_local()?;
6888 let server_id = server.server_id();
6889 let providers_with_identifiers = local
6890 .language_server_dynamic_registrations
6891 .get(&server_id)
6892 .into_iter()
6893 .flat_map(|registrations| registrations.diagnostics.clone())
6894 .collect::<Vec<_>>();
6895 Some(
6896 providers_with_identifiers
6897 .into_iter()
6898 .map(|(registration_id, dynamic_caps)| {
6899 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6900 let registration_id = registration_id.map(SharedString::from);
6901 let result_id = self.result_id_for_buffer_pull(
6902 server_id,
6903 buffer_id,
6904 ®istration_id,
6905 cx,
6906 );
6907 self.request_lsp(
6908 buffer.clone(),
6909 LanguageServerToQuery::Other(server_id),
6910 GetDocumentDiagnostics {
6911 previous_result_id: result_id,
6912 registration_id,
6913 identifier,
6914 },
6915 cx,
6916 )
6917 })
6918 .collect::<Vec<_>>(),
6919 )
6920 });
6921
6922 result.unwrap_or_default()
6923 })
6924 .collect::<Vec<_>>();
6925
6926 cx.background_spawn(async move {
6927 let mut responses = Vec::new();
6928 for diagnostics in join_all(pull_diagnostics).await {
6929 responses.extend(diagnostics?);
6930 }
6931 Ok(Some(responses))
6932 })
6933 }
6934 }
6935
6936 pub fn applicable_inlay_chunks(
6937 &mut self,
6938 buffer: &Entity<Buffer>,
6939 ranges: &[Range<text::Anchor>],
6940 cx: &mut Context<Self>,
6941 ) -> Vec<Range<BufferRow>> {
6942 let buffer_snapshot = buffer.read(cx).snapshot();
6943 let ranges = ranges
6944 .iter()
6945 .map(|range| range.to_point(&buffer_snapshot))
6946 .collect::<Vec<_>>();
6947
6948 self.latest_lsp_data(buffer, cx)
6949 .inlay_hints
6950 .applicable_chunks(ranges.as_slice())
6951 .map(|chunk| chunk.row_range())
6952 .collect()
6953 }
6954
6955 pub fn invalidate_inlay_hints<'a>(
6956 &'a mut self,
6957 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6958 ) {
6959 for buffer_id in for_buffers {
6960 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6961 lsp_data.inlay_hints.clear();
6962 }
6963 }
6964 }
6965
6966 pub fn inlay_hints(
6967 &mut self,
6968 invalidate: InvalidationStrategy,
6969 buffer: Entity<Buffer>,
6970 ranges: Vec<Range<text::Anchor>>,
6971 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6972 cx: &mut Context<Self>,
6973 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6974 let next_hint_id = self.next_hint_id.clone();
6975 let lsp_data = self.latest_lsp_data(&buffer, cx);
6976 let query_version = lsp_data.buffer_version.clone();
6977 let mut lsp_refresh_requested = false;
6978 let for_server = if let InvalidationStrategy::RefreshRequested {
6979 server_id,
6980 request_id,
6981 } = invalidate
6982 {
6983 let invalidated = lsp_data
6984 .inlay_hints
6985 .invalidate_for_server_refresh(server_id, request_id);
6986 lsp_refresh_requested = invalidated;
6987 Some(server_id)
6988 } else {
6989 None
6990 };
6991 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6992 let known_chunks = known_chunks
6993 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6994 .map(|(_, known_chunks)| known_chunks)
6995 .unwrap_or_default();
6996
6997 let buffer_snapshot = buffer.read(cx).snapshot();
6998 let ranges = ranges
6999 .iter()
7000 .map(|range| range.to_point(&buffer_snapshot))
7001 .collect::<Vec<_>>();
7002
7003 let mut hint_fetch_tasks = Vec::new();
7004 let mut cached_inlay_hints = None;
7005 let mut ranges_to_query = None;
7006 let applicable_chunks = existing_inlay_hints
7007 .applicable_chunks(ranges.as_slice())
7008 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7009 .collect::<Vec<_>>();
7010 if applicable_chunks.is_empty() {
7011 return HashMap::default();
7012 }
7013
7014 for row_chunk in applicable_chunks {
7015 match (
7016 existing_inlay_hints
7017 .cached_hints(&row_chunk)
7018 .filter(|_| !lsp_refresh_requested)
7019 .cloned(),
7020 existing_inlay_hints
7021 .fetched_hints(&row_chunk)
7022 .as_ref()
7023 .filter(|_| !lsp_refresh_requested)
7024 .cloned(),
7025 ) {
7026 (None, None) => {
7027 let chunk_range = row_chunk.anchor_range();
7028 ranges_to_query
7029 .get_or_insert_with(Vec::new)
7030 .push((row_chunk, chunk_range));
7031 }
7032 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7033 (Some(cached_hints), None) => {
7034 for (server_id, cached_hints) in cached_hints {
7035 if for_server.is_none_or(|for_server| for_server == server_id) {
7036 cached_inlay_hints
7037 .get_or_insert_with(HashMap::default)
7038 .entry(row_chunk.row_range())
7039 .or_insert_with(HashMap::default)
7040 .entry(server_id)
7041 .or_insert_with(Vec::new)
7042 .extend(cached_hints);
7043 }
7044 }
7045 }
7046 (Some(cached_hints), Some(fetched_hints)) => {
7047 hint_fetch_tasks.push((row_chunk, fetched_hints));
7048 for (server_id, cached_hints) in cached_hints {
7049 if for_server.is_none_or(|for_server| for_server == server_id) {
7050 cached_inlay_hints
7051 .get_or_insert_with(HashMap::default)
7052 .entry(row_chunk.row_range())
7053 .or_insert_with(HashMap::default)
7054 .entry(server_id)
7055 .or_insert_with(Vec::new)
7056 .extend(cached_hints);
7057 }
7058 }
7059 }
7060 }
7061 }
7062
7063 if hint_fetch_tasks.is_empty()
7064 && ranges_to_query
7065 .as_ref()
7066 .is_none_or(|ranges| ranges.is_empty())
7067 && let Some(cached_inlay_hints) = cached_inlay_hints
7068 {
7069 cached_inlay_hints
7070 .into_iter()
7071 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7072 .collect()
7073 } else {
7074 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7075 let next_hint_id = next_hint_id.clone();
7076 let buffer = buffer.clone();
7077 let query_version = query_version.clone();
7078 let new_inlay_hints = cx
7079 .spawn(async move |lsp_store, cx| {
7080 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7081 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7082 })?;
7083 new_fetch_task
7084 .await
7085 .and_then(|new_hints_by_server| {
7086 lsp_store.update(cx, |lsp_store, cx| {
7087 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7088 let update_cache = lsp_data.buffer_version == query_version;
7089 if new_hints_by_server.is_empty() {
7090 if update_cache {
7091 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7092 }
7093 HashMap::default()
7094 } else {
7095 new_hints_by_server
7096 .into_iter()
7097 .map(|(server_id, new_hints)| {
7098 let new_hints = new_hints
7099 .into_iter()
7100 .map(|new_hint| {
7101 (
7102 InlayId::Hint(next_hint_id.fetch_add(
7103 1,
7104 atomic::Ordering::AcqRel,
7105 )),
7106 new_hint,
7107 )
7108 })
7109 .collect::<Vec<_>>();
7110 if update_cache {
7111 lsp_data.inlay_hints.insert_new_hints(
7112 chunk,
7113 server_id,
7114 new_hints.clone(),
7115 );
7116 }
7117 (server_id, new_hints)
7118 })
7119 .collect()
7120 }
7121 })
7122 })
7123 .map_err(Arc::new)
7124 })
7125 .shared();
7126
7127 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7128 *fetch_task = Some(new_inlay_hints.clone());
7129 hint_fetch_tasks.push((chunk, new_inlay_hints));
7130 }
7131
7132 cached_inlay_hints
7133 .unwrap_or_default()
7134 .into_iter()
7135 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7136 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7137 (
7138 chunk.row_range(),
7139 cx.spawn(async move |_, _| {
7140 hints_fetch.await.map_err(|e| {
7141 if e.error_code() != ErrorCode::Internal {
7142 anyhow!(e.error_code())
7143 } else {
7144 anyhow!("{e:#}")
7145 }
7146 })
7147 }),
7148 )
7149 }))
7150 .collect()
7151 }
7152 }
7153
7154 fn fetch_inlay_hints(
7155 &mut self,
7156 for_server: Option<LanguageServerId>,
7157 buffer: &Entity<Buffer>,
7158 range: Range<Anchor>,
7159 cx: &mut Context<Self>,
7160 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7161 let request = InlayHints {
7162 range: range.clone(),
7163 };
7164 if let Some((upstream_client, project_id)) = self.upstream_client() {
7165 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7166 return Task::ready(Ok(HashMap::default()));
7167 }
7168 let request_task = upstream_client.request_lsp(
7169 project_id,
7170 for_server.map(|id| id.to_proto()),
7171 LSP_REQUEST_TIMEOUT,
7172 cx.background_executor().clone(),
7173 request.to_proto(project_id, buffer.read(cx)),
7174 );
7175 let buffer = buffer.clone();
7176 cx.spawn(async move |weak_lsp_store, cx| {
7177 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7178 return Ok(HashMap::default());
7179 };
7180 let Some(responses) = request_task.await? else {
7181 return Ok(HashMap::default());
7182 };
7183
7184 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7185 let lsp_store = lsp_store.clone();
7186 let buffer = buffer.clone();
7187 let cx = cx.clone();
7188 let request = request.clone();
7189 async move {
7190 (
7191 LanguageServerId::from_proto(response.server_id),
7192 request
7193 .response_from_proto(response.response, lsp_store, buffer, cx)
7194 .await,
7195 )
7196 }
7197 }))
7198 .await;
7199
7200 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7201 let mut has_errors = false;
7202 let inlay_hints = inlay_hints
7203 .into_iter()
7204 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7205 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7206 Err(e) => {
7207 has_errors = true;
7208 log::error!("{e:#}");
7209 None
7210 }
7211 })
7212 .map(|(server_id, mut new_hints)| {
7213 new_hints.retain(|hint| {
7214 hint.position.is_valid(&buffer_snapshot)
7215 && range.start.is_valid(&buffer_snapshot)
7216 && range.end.is_valid(&buffer_snapshot)
7217 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7218 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7219 });
7220 (server_id, new_hints)
7221 })
7222 .collect::<HashMap<_, _>>();
7223 anyhow::ensure!(
7224 !has_errors || !inlay_hints.is_empty(),
7225 "Failed to fetch inlay hints"
7226 );
7227 Ok(inlay_hints)
7228 })
7229 } else {
7230 let inlay_hints_task = match for_server {
7231 Some(server_id) => {
7232 let server_task = self.request_lsp(
7233 buffer.clone(),
7234 LanguageServerToQuery::Other(server_id),
7235 request,
7236 cx,
7237 );
7238 cx.background_spawn(async move {
7239 let mut responses = Vec::new();
7240 match server_task.await {
7241 Ok(response) => responses.push((server_id, response)),
7242 // rust-analyzer likes to error with this when its still loading up
7243 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7244 Err(e) => log::error!(
7245 "Error handling response for inlay hints request: {e:#}"
7246 ),
7247 }
7248 responses
7249 })
7250 }
7251 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7252 };
7253 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7254 cx.background_spawn(async move {
7255 Ok(inlay_hints_task
7256 .await
7257 .into_iter()
7258 .map(|(server_id, mut new_hints)| {
7259 new_hints.retain(|hint| {
7260 hint.position.is_valid(&buffer_snapshot)
7261 && range.start.is_valid(&buffer_snapshot)
7262 && range.end.is_valid(&buffer_snapshot)
7263 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7264 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7265 });
7266 (server_id, new_hints)
7267 })
7268 .collect())
7269 })
7270 }
7271 }
7272
7273 fn diagnostic_registration_exists(
7274 &self,
7275 server_id: LanguageServerId,
7276 registration_id: &Option<SharedString>,
7277 ) -> bool {
7278 let Some(local) = self.as_local() else {
7279 return false;
7280 };
7281 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7282 else {
7283 return false;
7284 };
7285 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7286 registrations.diagnostics.contains_key(®istration_key)
7287 }
7288
7289 pub fn pull_diagnostics_for_buffer(
7290 &mut self,
7291 buffer: Entity<Buffer>,
7292 cx: &mut Context<Self>,
7293 ) -> Task<anyhow::Result<()>> {
7294 let diagnostics = self.pull_diagnostics(buffer, cx);
7295 cx.spawn(async move |lsp_store, cx| {
7296 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7297 return Ok(());
7298 };
7299 lsp_store.update(cx, |lsp_store, cx| {
7300 if lsp_store.as_local().is_none() {
7301 return;
7302 }
7303
7304 let mut unchanged_buffers = HashMap::default();
7305 let server_diagnostics_updates = diagnostics
7306 .into_iter()
7307 .filter_map(|diagnostics_set| match diagnostics_set {
7308 LspPullDiagnostics::Response {
7309 server_id,
7310 uri,
7311 diagnostics,
7312 registration_id,
7313 } => Some((server_id, uri, diagnostics, registration_id)),
7314 LspPullDiagnostics::Default => None,
7315 })
7316 .filter(|(server_id, _, _, registration_id)| {
7317 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7318 })
7319 .fold(
7320 HashMap::default(),
7321 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7322 let (result_id, diagnostics) = match diagnostics {
7323 PulledDiagnostics::Unchanged { result_id } => {
7324 unchanged_buffers
7325 .entry(new_registration_id.clone())
7326 .or_insert_with(HashSet::default)
7327 .insert(uri.clone());
7328 (Some(result_id), Vec::new())
7329 }
7330 PulledDiagnostics::Changed {
7331 result_id,
7332 diagnostics,
7333 } => (result_id, diagnostics),
7334 };
7335 let disk_based_sources = Cow::Owned(
7336 lsp_store
7337 .language_server_adapter_for_id(server_id)
7338 .as_ref()
7339 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7340 .unwrap_or(&[])
7341 .to_vec(),
7342 );
7343 acc.entry(server_id)
7344 .or_insert_with(HashMap::default)
7345 .entry(new_registration_id.clone())
7346 .or_insert_with(Vec::new)
7347 .push(DocumentDiagnosticsUpdate {
7348 server_id,
7349 diagnostics: lsp::PublishDiagnosticsParams {
7350 uri,
7351 diagnostics,
7352 version: None,
7353 },
7354 result_id,
7355 disk_based_sources,
7356 registration_id: new_registration_id,
7357 });
7358 acc
7359 },
7360 );
7361
7362 for diagnostic_updates in server_diagnostics_updates.into_values() {
7363 for (registration_id, diagnostic_updates) in diagnostic_updates {
7364 lsp_store
7365 .merge_lsp_diagnostics(
7366 DiagnosticSourceKind::Pulled,
7367 diagnostic_updates,
7368 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7369 DiagnosticSourceKind::Pulled => {
7370 old_diagnostic.registration_id != registration_id
7371 || unchanged_buffers
7372 .get(&old_diagnostic.registration_id)
7373 .is_some_and(|unchanged_buffers| {
7374 unchanged_buffers.contains(&document_uri)
7375 })
7376 }
7377 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7378 true
7379 }
7380 },
7381 cx,
7382 )
7383 .log_err();
7384 }
7385 }
7386 })
7387 })
7388 }
7389
7390 pub fn document_colors(
7391 &mut self,
7392 known_cache_version: Option<usize>,
7393 buffer: Entity<Buffer>,
7394 cx: &mut Context<Self>,
7395 ) -> Option<DocumentColorTask> {
7396 let version_queried_for = buffer.read(cx).version();
7397 let buffer_id = buffer.read(cx).remote_id();
7398
7399 let current_language_servers = self.as_local().map(|local| {
7400 local
7401 .buffers_opened_in_servers
7402 .get(&buffer_id)
7403 .cloned()
7404 .unwrap_or_default()
7405 });
7406
7407 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7408 if let Some(cached_colors) = &lsp_data.document_colors {
7409 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7410 let has_different_servers =
7411 current_language_servers.is_some_and(|current_language_servers| {
7412 current_language_servers
7413 != cached_colors.colors.keys().copied().collect()
7414 });
7415 if !has_different_servers {
7416 let cache_version = cached_colors.cache_version;
7417 if Some(cache_version) == known_cache_version {
7418 return None;
7419 } else {
7420 return Some(
7421 Task::ready(Ok(DocumentColors {
7422 colors: cached_colors
7423 .colors
7424 .values()
7425 .flatten()
7426 .cloned()
7427 .collect(),
7428 cache_version: Some(cache_version),
7429 }))
7430 .shared(),
7431 );
7432 }
7433 }
7434 }
7435 }
7436 }
7437
7438 let color_lsp_data = self
7439 .latest_lsp_data(&buffer, cx)
7440 .document_colors
7441 .get_or_insert_default();
7442 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7443 && !version_queried_for.changed_since(updating_for)
7444 {
7445 return Some(running_update.clone());
7446 }
7447 let buffer_version_queried_for = version_queried_for.clone();
7448 let new_task = cx
7449 .spawn(async move |lsp_store, cx| {
7450 cx.background_executor()
7451 .timer(Duration::from_millis(30))
7452 .await;
7453 let fetched_colors = lsp_store
7454 .update(cx, |lsp_store, cx| {
7455 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7456 })?
7457 .await
7458 .context("fetching document colors")
7459 .map_err(Arc::new);
7460 let fetched_colors = match fetched_colors {
7461 Ok(fetched_colors) => {
7462 if Some(true)
7463 == buffer
7464 .update(cx, |buffer, _| {
7465 buffer.version() != buffer_version_queried_for
7466 })
7467 .ok()
7468 {
7469 return Ok(DocumentColors::default());
7470 }
7471 fetched_colors
7472 }
7473 Err(e) => {
7474 lsp_store
7475 .update(cx, |lsp_store, _| {
7476 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7477 if let Some(document_colors) = &mut lsp_data.document_colors {
7478 document_colors.colors_update = None;
7479 }
7480 }
7481 })
7482 .ok();
7483 return Err(e);
7484 }
7485 };
7486
7487 lsp_store
7488 .update(cx, |lsp_store, cx| {
7489 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7490 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7491
7492 if let Some(fetched_colors) = fetched_colors {
7493 if lsp_data.buffer_version == buffer_version_queried_for {
7494 lsp_colors.colors.extend(fetched_colors);
7495 lsp_colors.cache_version += 1;
7496 } else if !lsp_data
7497 .buffer_version
7498 .changed_since(&buffer_version_queried_for)
7499 {
7500 lsp_data.buffer_version = buffer_version_queried_for;
7501 lsp_colors.colors = fetched_colors;
7502 lsp_colors.cache_version += 1;
7503 }
7504 }
7505 lsp_colors.colors_update = None;
7506 let colors = lsp_colors
7507 .colors
7508 .values()
7509 .flatten()
7510 .cloned()
7511 .collect::<HashSet<_>>();
7512 DocumentColors {
7513 colors,
7514 cache_version: Some(lsp_colors.cache_version),
7515 }
7516 })
7517 .map_err(Arc::new)
7518 })
7519 .shared();
7520 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7521 Some(new_task)
7522 }
7523
7524 fn fetch_document_colors_for_buffer(
7525 &mut self,
7526 buffer: &Entity<Buffer>,
7527 cx: &mut Context<Self>,
7528 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7529 if let Some((client, project_id)) = self.upstream_client() {
7530 let request = GetDocumentColor {};
7531 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7532 return Task::ready(Ok(None));
7533 }
7534
7535 let request_task = client.request_lsp(
7536 project_id,
7537 None,
7538 LSP_REQUEST_TIMEOUT,
7539 cx.background_executor().clone(),
7540 request.to_proto(project_id, buffer.read(cx)),
7541 );
7542 let buffer = buffer.clone();
7543 cx.spawn(async move |lsp_store, cx| {
7544 let Some(lsp_store) = lsp_store.upgrade() else {
7545 return Ok(None);
7546 };
7547 let colors = join_all(
7548 request_task
7549 .await
7550 .log_err()
7551 .flatten()
7552 .map(|response| response.payload)
7553 .unwrap_or_default()
7554 .into_iter()
7555 .map(|color_response| {
7556 let response = request.response_from_proto(
7557 color_response.response,
7558 lsp_store.clone(),
7559 buffer.clone(),
7560 cx.clone(),
7561 );
7562 async move {
7563 (
7564 LanguageServerId::from_proto(color_response.server_id),
7565 response.await.log_err().unwrap_or_default(),
7566 )
7567 }
7568 }),
7569 )
7570 .await
7571 .into_iter()
7572 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7573 acc.entry(server_id)
7574 .or_insert_with(HashSet::default)
7575 .extend(colors);
7576 acc
7577 });
7578 Ok(Some(colors))
7579 })
7580 } else {
7581 let document_colors_task =
7582 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7583 cx.background_spawn(async move {
7584 Ok(Some(
7585 document_colors_task
7586 .await
7587 .into_iter()
7588 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7589 acc.entry(server_id)
7590 .or_insert_with(HashSet::default)
7591 .extend(colors);
7592 acc
7593 })
7594 .into_iter()
7595 .collect(),
7596 ))
7597 })
7598 }
7599 }
7600
7601 pub fn signature_help<T: ToPointUtf16>(
7602 &mut self,
7603 buffer: &Entity<Buffer>,
7604 position: T,
7605 cx: &mut Context<Self>,
7606 ) -> Task<Option<Vec<SignatureHelp>>> {
7607 let position = position.to_point_utf16(buffer.read(cx));
7608
7609 if let Some((client, upstream_project_id)) = self.upstream_client() {
7610 let request = GetSignatureHelp { position };
7611 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7612 return Task::ready(None);
7613 }
7614 let request_task = client.request_lsp(
7615 upstream_project_id,
7616 None,
7617 LSP_REQUEST_TIMEOUT,
7618 cx.background_executor().clone(),
7619 request.to_proto(upstream_project_id, buffer.read(cx)),
7620 );
7621 let buffer = buffer.clone();
7622 cx.spawn(async move |weak_lsp_store, cx| {
7623 let lsp_store = weak_lsp_store.upgrade()?;
7624 let signatures = join_all(
7625 request_task
7626 .await
7627 .log_err()
7628 .flatten()
7629 .map(|response| response.payload)
7630 .unwrap_or_default()
7631 .into_iter()
7632 .map(|response| {
7633 let response = GetSignatureHelp { position }.response_from_proto(
7634 response.response,
7635 lsp_store.clone(),
7636 buffer.clone(),
7637 cx.clone(),
7638 );
7639 async move { response.await.log_err().flatten() }
7640 }),
7641 )
7642 .await
7643 .into_iter()
7644 .flatten()
7645 .collect();
7646 Some(signatures)
7647 })
7648 } else {
7649 let all_actions_task = self.request_multiple_lsp_locally(
7650 buffer,
7651 Some(position),
7652 GetSignatureHelp { position },
7653 cx,
7654 );
7655 cx.background_spawn(async move {
7656 Some(
7657 all_actions_task
7658 .await
7659 .into_iter()
7660 .flat_map(|(_, actions)| actions)
7661 .collect::<Vec<_>>(),
7662 )
7663 })
7664 }
7665 }
7666
7667 pub fn hover(
7668 &mut self,
7669 buffer: &Entity<Buffer>,
7670 position: PointUtf16,
7671 cx: &mut Context<Self>,
7672 ) -> Task<Option<Vec<Hover>>> {
7673 if let Some((client, upstream_project_id)) = self.upstream_client() {
7674 let request = GetHover { position };
7675 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7676 return Task::ready(None);
7677 }
7678 let request_task = client.request_lsp(
7679 upstream_project_id,
7680 None,
7681 LSP_REQUEST_TIMEOUT,
7682 cx.background_executor().clone(),
7683 request.to_proto(upstream_project_id, buffer.read(cx)),
7684 );
7685 let buffer = buffer.clone();
7686 cx.spawn(async move |weak_lsp_store, cx| {
7687 let lsp_store = weak_lsp_store.upgrade()?;
7688 let hovers = join_all(
7689 request_task
7690 .await
7691 .log_err()
7692 .flatten()
7693 .map(|response| response.payload)
7694 .unwrap_or_default()
7695 .into_iter()
7696 .map(|response| {
7697 let response = GetHover { position }.response_from_proto(
7698 response.response,
7699 lsp_store.clone(),
7700 buffer.clone(),
7701 cx.clone(),
7702 );
7703 async move {
7704 response
7705 .await
7706 .log_err()
7707 .flatten()
7708 .and_then(remove_empty_hover_blocks)
7709 }
7710 }),
7711 )
7712 .await
7713 .into_iter()
7714 .flatten()
7715 .collect();
7716 Some(hovers)
7717 })
7718 } else {
7719 let all_actions_task = self.request_multiple_lsp_locally(
7720 buffer,
7721 Some(position),
7722 GetHover { position },
7723 cx,
7724 );
7725 cx.background_spawn(async move {
7726 Some(
7727 all_actions_task
7728 .await
7729 .into_iter()
7730 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7731 .collect::<Vec<Hover>>(),
7732 )
7733 })
7734 }
7735 }
7736
7737 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7738 let language_registry = self.languages.clone();
7739
7740 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7741 let request = upstream_client.request(proto::GetProjectSymbols {
7742 project_id: *project_id,
7743 query: query.to_string(),
7744 });
7745 cx.foreground_executor().spawn(async move {
7746 let response = request.await?;
7747 let mut symbols = Vec::new();
7748 let core_symbols = response
7749 .symbols
7750 .into_iter()
7751 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7752 .collect::<Vec<_>>();
7753 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7754 .await;
7755 Ok(symbols)
7756 })
7757 } else if let Some(local) = self.as_local() {
7758 struct WorkspaceSymbolsResult {
7759 server_id: LanguageServerId,
7760 lsp_adapter: Arc<CachedLspAdapter>,
7761 worktree: WeakEntity<Worktree>,
7762 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7763 }
7764
7765 let mut requests = Vec::new();
7766 let mut requested_servers = BTreeSet::new();
7767 for (seed, state) in local.language_server_ids.iter() {
7768 let Some(worktree_handle) = self
7769 .worktree_store
7770 .read(cx)
7771 .worktree_for_id(seed.worktree_id, cx)
7772 else {
7773 continue;
7774 };
7775 let worktree = worktree_handle.read(cx);
7776 if !worktree.is_visible() {
7777 continue;
7778 }
7779
7780 if !requested_servers.insert(state.id) {
7781 continue;
7782 }
7783
7784 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7785 Some(LanguageServerState::Running {
7786 adapter, server, ..
7787 }) => (adapter.clone(), server),
7788
7789 _ => continue,
7790 };
7791 let supports_workspace_symbol_request =
7792 match server.capabilities().workspace_symbol_provider {
7793 Some(OneOf::Left(supported)) => supported,
7794 Some(OneOf::Right(_)) => true,
7795 None => false,
7796 };
7797 if !supports_workspace_symbol_request {
7798 continue;
7799 }
7800 let worktree_handle = worktree_handle.clone();
7801 let server_id = server.server_id();
7802 requests.push(
7803 server
7804 .request::<lsp::request::WorkspaceSymbolRequest>(
7805 lsp::WorkspaceSymbolParams {
7806 query: query.to_string(),
7807 ..Default::default()
7808 },
7809 )
7810 .map(move |response| {
7811 let lsp_symbols = response.into_response()
7812 .context("workspace symbols request")
7813 .log_err()
7814 .flatten()
7815 .map(|symbol_response| match symbol_response {
7816 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7817 flat_responses.into_iter().map(|lsp_symbol| {
7818 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7819 }).collect::<Vec<_>>()
7820 }
7821 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7822 nested_responses.into_iter().filter_map(|lsp_symbol| {
7823 let location = match lsp_symbol.location {
7824 OneOf::Left(location) => location,
7825 OneOf::Right(_) => {
7826 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7827 return None
7828 }
7829 };
7830 Some((lsp_symbol.name, lsp_symbol.kind, location))
7831 }).collect::<Vec<_>>()
7832 }
7833 }).unwrap_or_default();
7834
7835 WorkspaceSymbolsResult {
7836 server_id,
7837 lsp_adapter,
7838 worktree: worktree_handle.downgrade(),
7839 lsp_symbols,
7840 }
7841 }),
7842 );
7843 }
7844
7845 cx.spawn(async move |this, cx| {
7846 let responses = futures::future::join_all(requests).await;
7847 let this = match this.upgrade() {
7848 Some(this) => this,
7849 None => return Ok(Vec::new()),
7850 };
7851
7852 let mut symbols = Vec::new();
7853 for result in responses {
7854 let core_symbols = this.update(cx, |this, cx| {
7855 result
7856 .lsp_symbols
7857 .into_iter()
7858 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7859 let abs_path = symbol_location.uri.to_file_path().ok()?;
7860 let source_worktree = result.worktree.upgrade()?;
7861 let source_worktree_id = source_worktree.read(cx).id();
7862
7863 let path = if let Some((tree, rel_path)) =
7864 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7865 {
7866 let worktree_id = tree.read(cx).id();
7867 SymbolLocation::InProject(ProjectPath {
7868 worktree_id,
7869 path: rel_path,
7870 })
7871 } else {
7872 SymbolLocation::OutsideProject {
7873 signature: this.symbol_signature(&abs_path),
7874 abs_path: abs_path.into(),
7875 }
7876 };
7877
7878 Some(CoreSymbol {
7879 source_language_server_id: result.server_id,
7880 language_server_name: result.lsp_adapter.name.clone(),
7881 source_worktree_id,
7882 path,
7883 kind: symbol_kind,
7884 name: symbol_name,
7885 range: range_from_lsp(symbol_location.range),
7886 })
7887 })
7888 .collect()
7889 })?;
7890
7891 populate_labels_for_symbols(
7892 core_symbols,
7893 &language_registry,
7894 Some(result.lsp_adapter),
7895 &mut symbols,
7896 )
7897 .await;
7898 }
7899
7900 Ok(symbols)
7901 })
7902 } else {
7903 Task::ready(Err(anyhow!("No upstream client or local language server")))
7904 }
7905 }
7906
7907 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7908 let mut summary = DiagnosticSummary::default();
7909 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7910 summary.error_count += path_summary.error_count;
7911 summary.warning_count += path_summary.warning_count;
7912 }
7913 summary
7914 }
7915
7916 /// Returns the diagnostic summary for a specific project path.
7917 pub fn diagnostic_summary_for_path(
7918 &self,
7919 project_path: &ProjectPath,
7920 _: &App,
7921 ) -> DiagnosticSummary {
7922 if let Some(summaries) = self
7923 .diagnostic_summaries
7924 .get(&project_path.worktree_id)
7925 .and_then(|map| map.get(&project_path.path))
7926 {
7927 let (error_count, warning_count) = summaries.iter().fold(
7928 (0, 0),
7929 |(error_count, warning_count), (_language_server_id, summary)| {
7930 (
7931 error_count + summary.error_count,
7932 warning_count + summary.warning_count,
7933 )
7934 },
7935 );
7936
7937 DiagnosticSummary {
7938 error_count,
7939 warning_count,
7940 }
7941 } else {
7942 DiagnosticSummary::default()
7943 }
7944 }
7945
7946 pub fn diagnostic_summaries<'a>(
7947 &'a self,
7948 include_ignored: bool,
7949 cx: &'a App,
7950 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7951 self.worktree_store
7952 .read(cx)
7953 .visible_worktrees(cx)
7954 .filter_map(|worktree| {
7955 let worktree = worktree.read(cx);
7956 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7957 })
7958 .flat_map(move |(worktree, summaries)| {
7959 let worktree_id = worktree.id();
7960 summaries
7961 .iter()
7962 .filter(move |(path, _)| {
7963 include_ignored
7964 || worktree
7965 .entry_for_path(path.as_ref())
7966 .is_some_and(|entry| !entry.is_ignored)
7967 })
7968 .flat_map(move |(path, summaries)| {
7969 summaries.iter().map(move |(server_id, summary)| {
7970 (
7971 ProjectPath {
7972 worktree_id,
7973 path: path.clone(),
7974 },
7975 *server_id,
7976 *summary,
7977 )
7978 })
7979 })
7980 })
7981 }
7982
7983 pub fn on_buffer_edited(
7984 &mut self,
7985 buffer: Entity<Buffer>,
7986 cx: &mut Context<Self>,
7987 ) -> Option<()> {
7988 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7989 Some(
7990 self.as_local()?
7991 .language_servers_for_buffer(buffer, cx)
7992 .map(|i| i.1.clone())
7993 .collect(),
7994 )
7995 })?;
7996
7997 let buffer = buffer.read(cx);
7998 let file = File::from_dyn(buffer.file())?;
7999 let abs_path = file.as_local()?.abs_path(cx);
8000 let uri = lsp::Uri::from_file_path(&abs_path)
8001 .ok()
8002 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8003 .log_err()?;
8004 let next_snapshot = buffer.text_snapshot();
8005 for language_server in language_servers {
8006 let language_server = language_server.clone();
8007
8008 let buffer_snapshots = self
8009 .as_local_mut()?
8010 .buffer_snapshots
8011 .get_mut(&buffer.remote_id())
8012 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8013 let previous_snapshot = buffer_snapshots.last()?;
8014
8015 let build_incremental_change = || {
8016 buffer
8017 .edits_since::<Dimensions<PointUtf16, usize>>(
8018 previous_snapshot.snapshot.version(),
8019 )
8020 .map(|edit| {
8021 let edit_start = edit.new.start.0;
8022 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8023 let new_text = next_snapshot
8024 .text_for_range(edit.new.start.1..edit.new.end.1)
8025 .collect();
8026 lsp::TextDocumentContentChangeEvent {
8027 range: Some(lsp::Range::new(
8028 point_to_lsp(edit_start),
8029 point_to_lsp(edit_end),
8030 )),
8031 range_length: None,
8032 text: new_text,
8033 }
8034 })
8035 .collect()
8036 };
8037
8038 let document_sync_kind = language_server
8039 .capabilities()
8040 .text_document_sync
8041 .as_ref()
8042 .and_then(|sync| match sync {
8043 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8044 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8045 });
8046
8047 let content_changes: Vec<_> = match document_sync_kind {
8048 Some(lsp::TextDocumentSyncKind::FULL) => {
8049 vec![lsp::TextDocumentContentChangeEvent {
8050 range: None,
8051 range_length: None,
8052 text: next_snapshot.text(),
8053 }]
8054 }
8055 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8056 _ => {
8057 #[cfg(any(test, feature = "test-support"))]
8058 {
8059 build_incremental_change()
8060 }
8061
8062 #[cfg(not(any(test, feature = "test-support")))]
8063 {
8064 continue;
8065 }
8066 }
8067 };
8068
8069 let next_version = previous_snapshot.version + 1;
8070 buffer_snapshots.push(LspBufferSnapshot {
8071 version: next_version,
8072 snapshot: next_snapshot.clone(),
8073 });
8074
8075 language_server
8076 .notify::<lsp::notification::DidChangeTextDocument>(
8077 lsp::DidChangeTextDocumentParams {
8078 text_document: lsp::VersionedTextDocumentIdentifier::new(
8079 uri.clone(),
8080 next_version,
8081 ),
8082 content_changes,
8083 },
8084 )
8085 .ok();
8086 self.pull_workspace_diagnostics(language_server.server_id());
8087 }
8088
8089 None
8090 }
8091
8092 pub fn on_buffer_saved(
8093 &mut self,
8094 buffer: Entity<Buffer>,
8095 cx: &mut Context<Self>,
8096 ) -> Option<()> {
8097 let file = File::from_dyn(buffer.read(cx).file())?;
8098 let worktree_id = file.worktree_id(cx);
8099 let abs_path = file.as_local()?.abs_path(cx);
8100 let text_document = lsp::TextDocumentIdentifier {
8101 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8102 };
8103 let local = self.as_local()?;
8104
8105 for server in local.language_servers_for_worktree(worktree_id) {
8106 if let Some(include_text) = include_text(server.as_ref()) {
8107 let text = if include_text {
8108 Some(buffer.read(cx).text())
8109 } else {
8110 None
8111 };
8112 server
8113 .notify::<lsp::notification::DidSaveTextDocument>(
8114 lsp::DidSaveTextDocumentParams {
8115 text_document: text_document.clone(),
8116 text,
8117 },
8118 )
8119 .ok();
8120 }
8121 }
8122
8123 let language_servers = buffer.update(cx, |buffer, cx| {
8124 local.language_server_ids_for_buffer(buffer, cx)
8125 });
8126 for language_server_id in language_servers {
8127 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8128 }
8129
8130 None
8131 }
8132
8133 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8134 maybe!(async move {
8135 let mut refreshed_servers = HashSet::default();
8136 let servers = lsp_store
8137 .update(cx, |lsp_store, cx| {
8138 let local = lsp_store.as_local()?;
8139
8140 let servers = local
8141 .language_server_ids
8142 .iter()
8143 .filter_map(|(seed, state)| {
8144 let worktree = lsp_store
8145 .worktree_store
8146 .read(cx)
8147 .worktree_for_id(seed.worktree_id, cx);
8148 let delegate: Arc<dyn LspAdapterDelegate> =
8149 worktree.map(|worktree| {
8150 LocalLspAdapterDelegate::new(
8151 local.languages.clone(),
8152 &local.environment,
8153 cx.weak_entity(),
8154 &worktree,
8155 local.http_client.clone(),
8156 local.fs.clone(),
8157 cx,
8158 )
8159 })?;
8160 let server_id = state.id;
8161
8162 let states = local.language_servers.get(&server_id)?;
8163
8164 match states {
8165 LanguageServerState::Starting { .. } => None,
8166 LanguageServerState::Running {
8167 adapter, server, ..
8168 } => {
8169 let adapter = adapter.clone();
8170 let server = server.clone();
8171 refreshed_servers.insert(server.name());
8172 let toolchain = seed.toolchain.clone();
8173 Some(cx.spawn(async move |_, cx| {
8174 let settings =
8175 LocalLspStore::workspace_configuration_for_adapter(
8176 adapter.adapter.clone(),
8177 &delegate,
8178 toolchain,
8179 None,
8180 cx,
8181 )
8182 .await
8183 .ok()?;
8184 server
8185 .notify::<lsp::notification::DidChangeConfiguration>(
8186 lsp::DidChangeConfigurationParams { settings },
8187 )
8188 .ok()?;
8189 Some(())
8190 }))
8191 }
8192 }
8193 })
8194 .collect::<Vec<_>>();
8195
8196 Some(servers)
8197 })
8198 .ok()
8199 .flatten()?;
8200
8201 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8202 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8203 // to stop and unregister its language server wrapper.
8204 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8205 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8206 let _: Vec<Option<()>> = join_all(servers).await;
8207
8208 Some(())
8209 })
8210 .await;
8211 }
8212
8213 fn maintain_workspace_config(
8214 external_refresh_requests: watch::Receiver<()>,
8215 cx: &mut Context<Self>,
8216 ) -> Task<Result<()>> {
8217 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8218 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8219
8220 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8221 *settings_changed_tx.borrow_mut() = ();
8222 });
8223
8224 let mut joint_future =
8225 futures::stream::select(settings_changed_rx, external_refresh_requests);
8226 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8227 // - We might shut down a language server if it's no longer enabled for a given language (and there are no buffers using it otherwise).
8228 // - We might also shut it down when the workspace configuration of all of the users of a given language server converges onto that of the other.
8229 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8230 // - In the easiest case (where we're not wrangling the lifetime of a language server anyhow), if none of the roots of a single language server diverge in their configuration,
8231 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8232 cx.spawn(async move |this, cx| {
8233 while let Some(()) = joint_future.next().await {
8234 this.update(cx, |this, cx| {
8235 this.refresh_server_tree(cx);
8236 })
8237 .ok();
8238
8239 Self::refresh_workspace_configurations(&this, cx).await;
8240 }
8241
8242 drop(settings_observation);
8243 anyhow::Ok(())
8244 })
8245 }
8246
8247 pub fn running_language_servers_for_local_buffer<'a>(
8248 &'a self,
8249 buffer: &Buffer,
8250 cx: &mut App,
8251 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8252 let local = self.as_local();
8253 let language_server_ids = local
8254 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8255 .unwrap_or_default();
8256
8257 language_server_ids
8258 .into_iter()
8259 .filter_map(
8260 move |server_id| match local?.language_servers.get(&server_id)? {
8261 LanguageServerState::Running {
8262 adapter, server, ..
8263 } => Some((adapter, server)),
8264 _ => None,
8265 },
8266 )
8267 }
8268
8269 pub fn language_servers_for_local_buffer(
8270 &self,
8271 buffer: &Buffer,
8272 cx: &mut App,
8273 ) -> Vec<LanguageServerId> {
8274 let local = self.as_local();
8275 local
8276 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8277 .unwrap_or_default()
8278 }
8279
8280 pub fn language_server_for_local_buffer<'a>(
8281 &'a self,
8282 buffer: &'a Buffer,
8283 server_id: LanguageServerId,
8284 cx: &'a mut App,
8285 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8286 self.as_local()?
8287 .language_servers_for_buffer(buffer, cx)
8288 .find(|(_, s)| s.server_id() == server_id)
8289 }
8290
8291 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8292 self.diagnostic_summaries.remove(&id_to_remove);
8293 if let Some(local) = self.as_local_mut() {
8294 let to_remove = local.remove_worktree(id_to_remove, cx);
8295 for server in to_remove {
8296 self.language_server_statuses.remove(&server);
8297 }
8298 }
8299 }
8300
8301 pub fn shared(
8302 &mut self,
8303 project_id: u64,
8304 downstream_client: AnyProtoClient,
8305 _: &mut Context<Self>,
8306 ) {
8307 self.downstream_client = Some((downstream_client.clone(), project_id));
8308
8309 for (server_id, status) in &self.language_server_statuses {
8310 if let Some(server) = self.language_server_for_id(*server_id) {
8311 downstream_client
8312 .send(proto::StartLanguageServer {
8313 project_id,
8314 server: Some(proto::LanguageServer {
8315 id: server_id.to_proto(),
8316 name: status.name.to_string(),
8317 worktree_id: status.worktree.map(|id| id.to_proto()),
8318 }),
8319 capabilities: serde_json::to_string(&server.capabilities())
8320 .expect("serializing server LSP capabilities"),
8321 })
8322 .log_err();
8323 }
8324 }
8325 }
8326
8327 pub fn disconnected_from_host(&mut self) {
8328 self.downstream_client.take();
8329 }
8330
8331 pub fn disconnected_from_ssh_remote(&mut self) {
8332 if let LspStoreMode::Remote(RemoteLspStore {
8333 upstream_client, ..
8334 }) = &mut self.mode
8335 {
8336 upstream_client.take();
8337 }
8338 }
8339
8340 pub(crate) fn set_language_server_statuses_from_proto(
8341 &mut self,
8342 project: WeakEntity<Project>,
8343 language_servers: Vec<proto::LanguageServer>,
8344 server_capabilities: Vec<String>,
8345 cx: &mut Context<Self>,
8346 ) {
8347 let lsp_logs = cx
8348 .try_global::<GlobalLogStore>()
8349 .map(|lsp_store| lsp_store.0.clone());
8350
8351 self.language_server_statuses = language_servers
8352 .into_iter()
8353 .zip(server_capabilities)
8354 .map(|(server, server_capabilities)| {
8355 let server_id = LanguageServerId(server.id as usize);
8356 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8357 self.lsp_server_capabilities
8358 .insert(server_id, server_capabilities);
8359 }
8360
8361 let name = LanguageServerName::from_proto(server.name);
8362 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8363
8364 if let Some(lsp_logs) = &lsp_logs {
8365 lsp_logs.update(cx, |lsp_logs, cx| {
8366 lsp_logs.add_language_server(
8367 // Only remote clients get their language servers set from proto
8368 LanguageServerKind::Remote {
8369 project: project.clone(),
8370 },
8371 server_id,
8372 Some(name.clone()),
8373 worktree,
8374 None,
8375 cx,
8376 );
8377 });
8378 }
8379
8380 (
8381 server_id,
8382 LanguageServerStatus {
8383 name,
8384 pending_work: Default::default(),
8385 has_pending_diagnostic_updates: false,
8386 progress_tokens: Default::default(),
8387 worktree,
8388 binary: None,
8389 configuration: None,
8390 workspace_folders: BTreeSet::new(),
8391 },
8392 )
8393 })
8394 .collect();
8395 }
8396
8397 #[cfg(test)]
8398 pub fn update_diagnostic_entries(
8399 &mut self,
8400 server_id: LanguageServerId,
8401 abs_path: PathBuf,
8402 result_id: Option<SharedString>,
8403 version: Option<i32>,
8404 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8405 cx: &mut Context<Self>,
8406 ) -> anyhow::Result<()> {
8407 self.merge_diagnostic_entries(
8408 vec![DocumentDiagnosticsUpdate {
8409 diagnostics: DocumentDiagnostics {
8410 diagnostics,
8411 document_abs_path: abs_path,
8412 version,
8413 },
8414 result_id,
8415 server_id,
8416 disk_based_sources: Cow::Borrowed(&[]),
8417 registration_id: None,
8418 }],
8419 |_, _, _| false,
8420 cx,
8421 )?;
8422 Ok(())
8423 }
8424
8425 pub fn merge_diagnostic_entries<'a>(
8426 &mut self,
8427 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8428 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8429 cx: &mut Context<Self>,
8430 ) -> anyhow::Result<()> {
8431 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8432 let mut updated_diagnostics_paths = HashMap::default();
8433 for mut update in diagnostic_updates {
8434 let abs_path = &update.diagnostics.document_abs_path;
8435 let server_id = update.server_id;
8436 let Some((worktree, relative_path)) =
8437 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8438 else {
8439 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8440 return Ok(());
8441 };
8442
8443 let worktree_id = worktree.read(cx).id();
8444 let project_path = ProjectPath {
8445 worktree_id,
8446 path: relative_path,
8447 };
8448
8449 let document_uri = lsp::Uri::from_file_path(abs_path)
8450 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8451 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8452 let snapshot = buffer_handle.read(cx).snapshot();
8453 let buffer = buffer_handle.read(cx);
8454 let reused_diagnostics = buffer
8455 .buffer_diagnostics(Some(server_id))
8456 .iter()
8457 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8458 .map(|v| {
8459 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8460 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8461 DiagnosticEntry {
8462 range: start..end,
8463 diagnostic: v.diagnostic.clone(),
8464 }
8465 })
8466 .collect::<Vec<_>>();
8467
8468 self.as_local_mut()
8469 .context("cannot merge diagnostics on a remote LspStore")?
8470 .update_buffer_diagnostics(
8471 &buffer_handle,
8472 server_id,
8473 Some(update.registration_id),
8474 update.result_id,
8475 update.diagnostics.version,
8476 update.diagnostics.diagnostics.clone(),
8477 reused_diagnostics.clone(),
8478 cx,
8479 )?;
8480
8481 update.diagnostics.diagnostics.extend(reused_diagnostics);
8482 } else if let Some(local) = self.as_local() {
8483 let reused_diagnostics = local
8484 .diagnostics
8485 .get(&worktree_id)
8486 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8487 .and_then(|diagnostics_by_server_id| {
8488 diagnostics_by_server_id
8489 .binary_search_by_key(&server_id, |e| e.0)
8490 .ok()
8491 .map(|ix| &diagnostics_by_server_id[ix].1)
8492 })
8493 .into_iter()
8494 .flatten()
8495 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8496
8497 update
8498 .diagnostics
8499 .diagnostics
8500 .extend(reused_diagnostics.cloned());
8501 }
8502
8503 let updated = worktree.update(cx, |worktree, cx| {
8504 self.update_worktree_diagnostics(
8505 worktree.id(),
8506 server_id,
8507 project_path.path.clone(),
8508 update.diagnostics.diagnostics,
8509 cx,
8510 )
8511 })?;
8512 match updated {
8513 ControlFlow::Continue(new_summary) => {
8514 if let Some((project_id, new_summary)) = new_summary {
8515 match &mut diagnostics_summary {
8516 Some(diagnostics_summary) => {
8517 diagnostics_summary
8518 .more_summaries
8519 .push(proto::DiagnosticSummary {
8520 path: project_path.path.as_ref().to_proto(),
8521 language_server_id: server_id.0 as u64,
8522 error_count: new_summary.error_count,
8523 warning_count: new_summary.warning_count,
8524 })
8525 }
8526 None => {
8527 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8528 project_id,
8529 worktree_id: worktree_id.to_proto(),
8530 summary: Some(proto::DiagnosticSummary {
8531 path: project_path.path.as_ref().to_proto(),
8532 language_server_id: server_id.0 as u64,
8533 error_count: new_summary.error_count,
8534 warning_count: new_summary.warning_count,
8535 }),
8536 more_summaries: Vec::new(),
8537 })
8538 }
8539 }
8540 }
8541 updated_diagnostics_paths
8542 .entry(server_id)
8543 .or_insert_with(Vec::new)
8544 .push(project_path);
8545 }
8546 ControlFlow::Break(()) => {}
8547 }
8548 }
8549
8550 if let Some((diagnostics_summary, (downstream_client, _))) =
8551 diagnostics_summary.zip(self.downstream_client.as_ref())
8552 {
8553 downstream_client.send(diagnostics_summary).log_err();
8554 }
8555 for (server_id, paths) in updated_diagnostics_paths {
8556 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8557 }
8558 Ok(())
8559 }
8560
8561 fn update_worktree_diagnostics(
8562 &mut self,
8563 worktree_id: WorktreeId,
8564 server_id: LanguageServerId,
8565 path_in_worktree: Arc<RelPath>,
8566 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8567 _: &mut Context<Worktree>,
8568 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8569 let local = match &mut self.mode {
8570 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8571 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8572 };
8573
8574 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8575 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8576 let summaries_by_server_id = summaries_for_tree
8577 .entry(path_in_worktree.clone())
8578 .or_default();
8579
8580 let old_summary = summaries_by_server_id
8581 .remove(&server_id)
8582 .unwrap_or_default();
8583
8584 let new_summary = DiagnosticSummary::new(&diagnostics);
8585 if diagnostics.is_empty() {
8586 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8587 {
8588 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8589 diagnostics_by_server_id.remove(ix);
8590 }
8591 if diagnostics_by_server_id.is_empty() {
8592 diagnostics_for_tree.remove(&path_in_worktree);
8593 }
8594 }
8595 } else {
8596 summaries_by_server_id.insert(server_id, new_summary);
8597 let diagnostics_by_server_id = diagnostics_for_tree
8598 .entry(path_in_worktree.clone())
8599 .or_default();
8600 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8601 Ok(ix) => {
8602 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8603 }
8604 Err(ix) => {
8605 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8606 }
8607 }
8608 }
8609
8610 if !old_summary.is_empty() || !new_summary.is_empty() {
8611 if let Some((_, project_id)) = &self.downstream_client {
8612 Ok(ControlFlow::Continue(Some((
8613 *project_id,
8614 proto::DiagnosticSummary {
8615 path: path_in_worktree.to_proto(),
8616 language_server_id: server_id.0 as u64,
8617 error_count: new_summary.error_count as u32,
8618 warning_count: new_summary.warning_count as u32,
8619 },
8620 ))))
8621 } else {
8622 Ok(ControlFlow::Continue(None))
8623 }
8624 } else {
8625 Ok(ControlFlow::Break(()))
8626 }
8627 }
8628
8629 pub fn open_buffer_for_symbol(
8630 &mut self,
8631 symbol: &Symbol,
8632 cx: &mut Context<Self>,
8633 ) -> Task<Result<Entity<Buffer>>> {
8634 if let Some((client, project_id)) = self.upstream_client() {
8635 let request = client.request(proto::OpenBufferForSymbol {
8636 project_id,
8637 symbol: Some(Self::serialize_symbol(symbol)),
8638 });
8639 cx.spawn(async move |this, cx| {
8640 let response = request.await?;
8641 let buffer_id = BufferId::new(response.buffer_id)?;
8642 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8643 .await
8644 })
8645 } else if let Some(local) = self.as_local() {
8646 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8647 seed.worktree_id == symbol.source_worktree_id
8648 && state.id == symbol.source_language_server_id
8649 && symbol.language_server_name == seed.name
8650 });
8651 if !is_valid {
8652 return Task::ready(Err(anyhow!(
8653 "language server for worktree and language not found"
8654 )));
8655 };
8656
8657 let symbol_abs_path = match &symbol.path {
8658 SymbolLocation::InProject(project_path) => self
8659 .worktree_store
8660 .read(cx)
8661 .absolutize(&project_path, cx)
8662 .context("no such worktree"),
8663 SymbolLocation::OutsideProject {
8664 abs_path,
8665 signature: _,
8666 } => Ok(abs_path.to_path_buf()),
8667 };
8668 let symbol_abs_path = match symbol_abs_path {
8669 Ok(abs_path) => abs_path,
8670 Err(err) => return Task::ready(Err(err)),
8671 };
8672 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8673 uri
8674 } else {
8675 return Task::ready(Err(anyhow!("invalid symbol path")));
8676 };
8677
8678 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8679 } else {
8680 Task::ready(Err(anyhow!("no upstream client or local store")))
8681 }
8682 }
8683
8684 pub(crate) fn open_local_buffer_via_lsp(
8685 &mut self,
8686 abs_path: lsp::Uri,
8687 language_server_id: LanguageServerId,
8688 cx: &mut Context<Self>,
8689 ) -> Task<Result<Entity<Buffer>>> {
8690 cx.spawn(async move |lsp_store, cx| {
8691 // Escape percent-encoded string.
8692 let current_scheme = abs_path.scheme().to_owned();
8693 // Uri is immutable, so we can't modify the scheme
8694
8695 let abs_path = abs_path
8696 .to_file_path()
8697 .map_err(|()| anyhow!("can't convert URI to path"))?;
8698 let p = abs_path.clone();
8699 let yarn_worktree = lsp_store
8700 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8701 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8702 cx.spawn(async move |this, cx| {
8703 let t = this
8704 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8705 .ok()?;
8706 t.await
8707 })
8708 }),
8709 None => Task::ready(None),
8710 })?
8711 .await;
8712 let (worktree_root_target, known_relative_path) =
8713 if let Some((zip_root, relative_path)) = yarn_worktree {
8714 (zip_root, Some(relative_path))
8715 } else {
8716 (Arc::<Path>::from(abs_path.as_path()), None)
8717 };
8718 let (worktree, relative_path) = if let Some(result) =
8719 lsp_store.update(cx, |lsp_store, cx| {
8720 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8721 worktree_store.find_worktree(&worktree_root_target, cx)
8722 })
8723 })? {
8724 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8725 (result.0, relative_path)
8726 } else {
8727 let worktree = lsp_store
8728 .update(cx, |lsp_store, cx| {
8729 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8730 worktree_store.create_worktree(&worktree_root_target, false, cx)
8731 })
8732 })?
8733 .await?;
8734 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8735 lsp_store
8736 .update(cx, |lsp_store, cx| {
8737 if let Some(local) = lsp_store.as_local_mut() {
8738 local.register_language_server_for_invisible_worktree(
8739 &worktree,
8740 language_server_id,
8741 cx,
8742 )
8743 }
8744 })
8745 .ok();
8746 }
8747 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8748 let relative_path = if let Some(known_path) = known_relative_path {
8749 known_path
8750 } else {
8751 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8752 .into_arc()
8753 };
8754 (worktree, relative_path)
8755 };
8756 let project_path = ProjectPath {
8757 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8758 path: relative_path,
8759 };
8760 lsp_store
8761 .update(cx, |lsp_store, cx| {
8762 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8763 buffer_store.open_buffer(project_path, cx)
8764 })
8765 })?
8766 .await
8767 })
8768 }
8769
8770 fn request_multiple_lsp_locally<P, R>(
8771 &mut self,
8772 buffer: &Entity<Buffer>,
8773 position: Option<P>,
8774 request: R,
8775 cx: &mut Context<Self>,
8776 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8777 where
8778 P: ToOffset,
8779 R: LspCommand + Clone,
8780 <R::LspRequest as lsp::request::Request>::Result: Send,
8781 <R::LspRequest as lsp::request::Request>::Params: Send,
8782 {
8783 let Some(local) = self.as_local() else {
8784 return Task::ready(Vec::new());
8785 };
8786
8787 let snapshot = buffer.read(cx).snapshot();
8788 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8789
8790 let server_ids = buffer.update(cx, |buffer, cx| {
8791 local
8792 .language_servers_for_buffer(buffer, cx)
8793 .filter(|(adapter, _)| {
8794 scope
8795 .as_ref()
8796 .map(|scope| scope.language_allowed(&adapter.name))
8797 .unwrap_or(true)
8798 })
8799 .map(|(_, server)| server.server_id())
8800 .filter(|server_id| {
8801 self.as_local().is_none_or(|local| {
8802 local
8803 .buffers_opened_in_servers
8804 .get(&snapshot.remote_id())
8805 .is_some_and(|servers| servers.contains(server_id))
8806 })
8807 })
8808 .collect::<Vec<_>>()
8809 });
8810
8811 let mut response_results = server_ids
8812 .into_iter()
8813 .map(|server_id| {
8814 let task = self.request_lsp(
8815 buffer.clone(),
8816 LanguageServerToQuery::Other(server_id),
8817 request.clone(),
8818 cx,
8819 );
8820 async move { (server_id, task.await) }
8821 })
8822 .collect::<FuturesUnordered<_>>();
8823
8824 cx.background_spawn(async move {
8825 let mut responses = Vec::with_capacity(response_results.len());
8826 while let Some((server_id, response_result)) = response_results.next().await {
8827 match response_result {
8828 Ok(response) => responses.push((server_id, response)),
8829 // rust-analyzer likes to error with this when its still loading up
8830 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8831 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8832 }
8833 }
8834 responses
8835 })
8836 }
8837
8838 async fn handle_lsp_get_completions(
8839 this: Entity<Self>,
8840 envelope: TypedEnvelope<proto::GetCompletions>,
8841 mut cx: AsyncApp,
8842 ) -> Result<proto::GetCompletionsResponse> {
8843 let sender_id = envelope.original_sender_id().unwrap_or_default();
8844
8845 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8846 let buffer_handle = this.update(&mut cx, |this, cx| {
8847 this.buffer_store.read(cx).get_existing(buffer_id)
8848 })??;
8849 let request = GetCompletions::from_proto(
8850 envelope.payload,
8851 this.clone(),
8852 buffer_handle.clone(),
8853 cx.clone(),
8854 )
8855 .await?;
8856
8857 let server_to_query = match request.server_id {
8858 Some(server_id) => LanguageServerToQuery::Other(server_id),
8859 None => LanguageServerToQuery::FirstCapable,
8860 };
8861
8862 let response = this
8863 .update(&mut cx, |this, cx| {
8864 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8865 })?
8866 .await?;
8867 this.update(&mut cx, |this, cx| {
8868 Ok(GetCompletions::response_to_proto(
8869 response,
8870 this,
8871 sender_id,
8872 &buffer_handle.read(cx).version(),
8873 cx,
8874 ))
8875 })?
8876 }
8877
8878 async fn handle_lsp_command<T: LspCommand>(
8879 this: Entity<Self>,
8880 envelope: TypedEnvelope<T::ProtoRequest>,
8881 mut cx: AsyncApp,
8882 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8883 where
8884 <T::LspRequest as lsp::request::Request>::Params: Send,
8885 <T::LspRequest as lsp::request::Request>::Result: Send,
8886 {
8887 let sender_id = envelope.original_sender_id().unwrap_or_default();
8888 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8889 let buffer_handle = this.update(&mut cx, |this, cx| {
8890 this.buffer_store.read(cx).get_existing(buffer_id)
8891 })??;
8892 let request = T::from_proto(
8893 envelope.payload,
8894 this.clone(),
8895 buffer_handle.clone(),
8896 cx.clone(),
8897 )
8898 .await?;
8899 let response = this
8900 .update(&mut cx, |this, cx| {
8901 this.request_lsp(
8902 buffer_handle.clone(),
8903 LanguageServerToQuery::FirstCapable,
8904 request,
8905 cx,
8906 )
8907 })?
8908 .await?;
8909 this.update(&mut cx, |this, cx| {
8910 Ok(T::response_to_proto(
8911 response,
8912 this,
8913 sender_id,
8914 &buffer_handle.read(cx).version(),
8915 cx,
8916 ))
8917 })?
8918 }
8919
8920 async fn handle_lsp_query(
8921 lsp_store: Entity<Self>,
8922 envelope: TypedEnvelope<proto::LspQuery>,
8923 mut cx: AsyncApp,
8924 ) -> Result<proto::Ack> {
8925 use proto::lsp_query::Request;
8926 let sender_id = envelope.original_sender_id().unwrap_or_default();
8927 let lsp_query = envelope.payload;
8928 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8929 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8930 match lsp_query.request.context("invalid LSP query request")? {
8931 Request::GetReferences(get_references) => {
8932 let position = get_references.position.clone().and_then(deserialize_anchor);
8933 Self::query_lsp_locally::<GetReferences>(
8934 lsp_store,
8935 server_id,
8936 sender_id,
8937 lsp_request_id,
8938 get_references,
8939 position,
8940 &mut cx,
8941 )
8942 .await?;
8943 }
8944 Request::GetDocumentColor(get_document_color) => {
8945 Self::query_lsp_locally::<GetDocumentColor>(
8946 lsp_store,
8947 server_id,
8948 sender_id,
8949 lsp_request_id,
8950 get_document_color,
8951 None,
8952 &mut cx,
8953 )
8954 .await?;
8955 }
8956 Request::GetHover(get_hover) => {
8957 let position = get_hover.position.clone().and_then(deserialize_anchor);
8958 Self::query_lsp_locally::<GetHover>(
8959 lsp_store,
8960 server_id,
8961 sender_id,
8962 lsp_request_id,
8963 get_hover,
8964 position,
8965 &mut cx,
8966 )
8967 .await?;
8968 }
8969 Request::GetCodeActions(get_code_actions) => {
8970 Self::query_lsp_locally::<GetCodeActions>(
8971 lsp_store,
8972 server_id,
8973 sender_id,
8974 lsp_request_id,
8975 get_code_actions,
8976 None,
8977 &mut cx,
8978 )
8979 .await?;
8980 }
8981 Request::GetSignatureHelp(get_signature_help) => {
8982 let position = get_signature_help
8983 .position
8984 .clone()
8985 .and_then(deserialize_anchor);
8986 Self::query_lsp_locally::<GetSignatureHelp>(
8987 lsp_store,
8988 server_id,
8989 sender_id,
8990 lsp_request_id,
8991 get_signature_help,
8992 position,
8993 &mut cx,
8994 )
8995 .await?;
8996 }
8997 Request::GetCodeLens(get_code_lens) => {
8998 Self::query_lsp_locally::<GetCodeLens>(
8999 lsp_store,
9000 server_id,
9001 sender_id,
9002 lsp_request_id,
9003 get_code_lens,
9004 None,
9005 &mut cx,
9006 )
9007 .await?;
9008 }
9009 Request::GetDefinition(get_definition) => {
9010 let position = get_definition.position.clone().and_then(deserialize_anchor);
9011 Self::query_lsp_locally::<GetDefinitions>(
9012 lsp_store,
9013 server_id,
9014 sender_id,
9015 lsp_request_id,
9016 get_definition,
9017 position,
9018 &mut cx,
9019 )
9020 .await?;
9021 }
9022 Request::GetDeclaration(get_declaration) => {
9023 let position = get_declaration
9024 .position
9025 .clone()
9026 .and_then(deserialize_anchor);
9027 Self::query_lsp_locally::<GetDeclarations>(
9028 lsp_store,
9029 server_id,
9030 sender_id,
9031 lsp_request_id,
9032 get_declaration,
9033 position,
9034 &mut cx,
9035 )
9036 .await?;
9037 }
9038 Request::GetTypeDefinition(get_type_definition) => {
9039 let position = get_type_definition
9040 .position
9041 .clone()
9042 .and_then(deserialize_anchor);
9043 Self::query_lsp_locally::<GetTypeDefinitions>(
9044 lsp_store,
9045 server_id,
9046 sender_id,
9047 lsp_request_id,
9048 get_type_definition,
9049 position,
9050 &mut cx,
9051 )
9052 .await?;
9053 }
9054 Request::GetImplementation(get_implementation) => {
9055 let position = get_implementation
9056 .position
9057 .clone()
9058 .and_then(deserialize_anchor);
9059 Self::query_lsp_locally::<GetImplementations>(
9060 lsp_store,
9061 server_id,
9062 sender_id,
9063 lsp_request_id,
9064 get_implementation,
9065 position,
9066 &mut cx,
9067 )
9068 .await?;
9069 }
9070 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9071 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9072 let version = deserialize_version(get_document_diagnostics.buffer_version());
9073 let buffer = lsp_store.update(&mut cx, |this, cx| {
9074 this.buffer_store.read(cx).get_existing(buffer_id)
9075 })??;
9076 buffer
9077 .update(&mut cx, |buffer, _| {
9078 buffer.wait_for_version(version.clone())
9079 })?
9080 .await?;
9081 lsp_store.update(&mut cx, |lsp_store, cx| {
9082 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9083 let key = LspKey {
9084 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9085 server_queried: server_id,
9086 };
9087 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9088 ) {
9089 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9090 lsp_requests.clear();
9091 };
9092 }
9093
9094 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9095 existing_queries.insert(
9096 lsp_request_id,
9097 cx.spawn(async move |lsp_store, cx| {
9098 let diagnostics_pull = lsp_store
9099 .update(cx, |lsp_store, cx| {
9100 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9101 })
9102 .ok();
9103 if let Some(diagnostics_pull) = diagnostics_pull {
9104 match diagnostics_pull.await {
9105 Ok(()) => {}
9106 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9107 };
9108 }
9109 }),
9110 );
9111 })?;
9112 }
9113 Request::InlayHints(inlay_hints) => {
9114 let query_start = inlay_hints
9115 .start
9116 .clone()
9117 .and_then(deserialize_anchor)
9118 .context("invalid inlay hints range start")?;
9119 let query_end = inlay_hints
9120 .end
9121 .clone()
9122 .and_then(deserialize_anchor)
9123 .context("invalid inlay hints range end")?;
9124 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9125 &lsp_store,
9126 server_id,
9127 lsp_request_id,
9128 &inlay_hints,
9129 query_start..query_end,
9130 &mut cx,
9131 )
9132 .await
9133 .context("preparing inlay hints request")?;
9134 Self::query_lsp_locally::<InlayHints>(
9135 lsp_store,
9136 server_id,
9137 sender_id,
9138 lsp_request_id,
9139 inlay_hints,
9140 None,
9141 &mut cx,
9142 )
9143 .await
9144 .context("querying for inlay hints")?
9145 }
9146 }
9147 Ok(proto::Ack {})
9148 }
9149
9150 async fn handle_lsp_query_response(
9151 lsp_store: Entity<Self>,
9152 envelope: TypedEnvelope<proto::LspQueryResponse>,
9153 cx: AsyncApp,
9154 ) -> Result<()> {
9155 lsp_store.read_with(&cx, |lsp_store, _| {
9156 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9157 upstream_client.handle_lsp_response(envelope.clone());
9158 }
9159 })?;
9160 Ok(())
9161 }
9162
9163 async fn handle_apply_code_action(
9164 this: Entity<Self>,
9165 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9166 mut cx: AsyncApp,
9167 ) -> Result<proto::ApplyCodeActionResponse> {
9168 let sender_id = envelope.original_sender_id().unwrap_or_default();
9169 let action =
9170 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9171 let apply_code_action = this.update(&mut cx, |this, cx| {
9172 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9173 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9174 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9175 })??;
9176
9177 let project_transaction = apply_code_action.await?;
9178 let project_transaction = this.update(&mut cx, |this, cx| {
9179 this.buffer_store.update(cx, |buffer_store, cx| {
9180 buffer_store.serialize_project_transaction_for_peer(
9181 project_transaction,
9182 sender_id,
9183 cx,
9184 )
9185 })
9186 })?;
9187 Ok(proto::ApplyCodeActionResponse {
9188 transaction: Some(project_transaction),
9189 })
9190 }
9191
9192 async fn handle_register_buffer_with_language_servers(
9193 this: Entity<Self>,
9194 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9195 mut cx: AsyncApp,
9196 ) -> Result<proto::Ack> {
9197 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9198 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9199 this.update(&mut cx, |this, cx| {
9200 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9201 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9202 project_id: upstream_project_id,
9203 buffer_id: buffer_id.to_proto(),
9204 only_servers: envelope.payload.only_servers,
9205 });
9206 }
9207
9208 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9209 anyhow::bail!("buffer is not open");
9210 };
9211
9212 let handle = this.register_buffer_with_language_servers(
9213 &buffer,
9214 envelope
9215 .payload
9216 .only_servers
9217 .into_iter()
9218 .filter_map(|selector| {
9219 Some(match selector.selector? {
9220 proto::language_server_selector::Selector::ServerId(server_id) => {
9221 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9222 }
9223 proto::language_server_selector::Selector::Name(name) => {
9224 LanguageServerSelector::Name(LanguageServerName(
9225 SharedString::from(name),
9226 ))
9227 }
9228 })
9229 })
9230 .collect(),
9231 false,
9232 cx,
9233 );
9234 this.buffer_store().update(cx, |buffer_store, _| {
9235 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9236 });
9237
9238 Ok(())
9239 })??;
9240 Ok(proto::Ack {})
9241 }
9242
9243 async fn handle_rename_project_entry(
9244 this: Entity<Self>,
9245 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9246 mut cx: AsyncApp,
9247 ) -> Result<proto::ProjectEntryResponse> {
9248 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9249 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9250 let new_path =
9251 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9252
9253 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9254 .update(&mut cx, |this, cx| {
9255 let (worktree, entry) = this
9256 .worktree_store
9257 .read(cx)
9258 .worktree_and_entry_for_id(entry_id, cx)?;
9259 let new_worktree = this
9260 .worktree_store
9261 .read(cx)
9262 .worktree_for_id(new_worktree_id, cx)?;
9263 Some((
9264 this.worktree_store.clone(),
9265 worktree,
9266 new_worktree,
9267 entry.clone(),
9268 ))
9269 })?
9270 .context("worktree not found")?;
9271 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9272 (worktree.absolutize(&old_entry.path), worktree.id())
9273 })?;
9274 let new_abs_path =
9275 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9276
9277 let _transaction = Self::will_rename_entry(
9278 this.downgrade(),
9279 old_worktree_id,
9280 &old_abs_path,
9281 &new_abs_path,
9282 old_entry.is_dir(),
9283 cx.clone(),
9284 )
9285 .await;
9286 let response = WorktreeStore::handle_rename_project_entry(
9287 worktree_store,
9288 envelope.payload,
9289 cx.clone(),
9290 )
9291 .await;
9292 this.read_with(&cx, |this, _| {
9293 this.did_rename_entry(
9294 old_worktree_id,
9295 &old_abs_path,
9296 &new_abs_path,
9297 old_entry.is_dir(),
9298 );
9299 })
9300 .ok();
9301 response
9302 }
9303
9304 async fn handle_update_diagnostic_summary(
9305 this: Entity<Self>,
9306 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9307 mut cx: AsyncApp,
9308 ) -> Result<()> {
9309 this.update(&mut cx, |lsp_store, cx| {
9310 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9311 let mut updated_diagnostics_paths = HashMap::default();
9312 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9313 for message_summary in envelope
9314 .payload
9315 .summary
9316 .into_iter()
9317 .chain(envelope.payload.more_summaries)
9318 {
9319 let project_path = ProjectPath {
9320 worktree_id,
9321 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9322 };
9323 let path = project_path.path.clone();
9324 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9325 let summary = DiagnosticSummary {
9326 error_count: message_summary.error_count as usize,
9327 warning_count: message_summary.warning_count as usize,
9328 };
9329
9330 if summary.is_empty() {
9331 if let Some(worktree_summaries) =
9332 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9333 && let Some(summaries) = worktree_summaries.get_mut(&path)
9334 {
9335 summaries.remove(&server_id);
9336 if summaries.is_empty() {
9337 worktree_summaries.remove(&path);
9338 }
9339 }
9340 } else {
9341 lsp_store
9342 .diagnostic_summaries
9343 .entry(worktree_id)
9344 .or_default()
9345 .entry(path)
9346 .or_default()
9347 .insert(server_id, summary);
9348 }
9349
9350 if let Some((_, project_id)) = &lsp_store.downstream_client {
9351 match &mut diagnostics_summary {
9352 Some(diagnostics_summary) => {
9353 diagnostics_summary
9354 .more_summaries
9355 .push(proto::DiagnosticSummary {
9356 path: project_path.path.as_ref().to_proto(),
9357 language_server_id: server_id.0 as u64,
9358 error_count: summary.error_count as u32,
9359 warning_count: summary.warning_count as u32,
9360 })
9361 }
9362 None => {
9363 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9364 project_id: *project_id,
9365 worktree_id: worktree_id.to_proto(),
9366 summary: Some(proto::DiagnosticSummary {
9367 path: project_path.path.as_ref().to_proto(),
9368 language_server_id: server_id.0 as u64,
9369 error_count: summary.error_count as u32,
9370 warning_count: summary.warning_count as u32,
9371 }),
9372 more_summaries: Vec::new(),
9373 })
9374 }
9375 }
9376 }
9377 updated_diagnostics_paths
9378 .entry(server_id)
9379 .or_insert_with(Vec::new)
9380 .push(project_path);
9381 }
9382
9383 if let Some((diagnostics_summary, (downstream_client, _))) =
9384 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9385 {
9386 downstream_client.send(diagnostics_summary).log_err();
9387 }
9388 for (server_id, paths) in updated_diagnostics_paths {
9389 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9390 }
9391 Ok(())
9392 })?
9393 }
9394
9395 async fn handle_start_language_server(
9396 lsp_store: Entity<Self>,
9397 envelope: TypedEnvelope<proto::StartLanguageServer>,
9398 mut cx: AsyncApp,
9399 ) -> Result<()> {
9400 let server = envelope.payload.server.context("invalid server")?;
9401 let server_capabilities =
9402 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9403 .with_context(|| {
9404 format!(
9405 "incorrect server capabilities {}",
9406 envelope.payload.capabilities
9407 )
9408 })?;
9409 lsp_store.update(&mut cx, |lsp_store, cx| {
9410 let server_id = LanguageServerId(server.id as usize);
9411 let server_name = LanguageServerName::from_proto(server.name.clone());
9412 lsp_store
9413 .lsp_server_capabilities
9414 .insert(server_id, server_capabilities);
9415 lsp_store.language_server_statuses.insert(
9416 server_id,
9417 LanguageServerStatus {
9418 name: server_name.clone(),
9419 pending_work: Default::default(),
9420 has_pending_diagnostic_updates: false,
9421 progress_tokens: Default::default(),
9422 worktree: server.worktree_id.map(WorktreeId::from_proto),
9423 binary: None,
9424 configuration: None,
9425 workspace_folders: BTreeSet::new(),
9426 },
9427 );
9428 cx.emit(LspStoreEvent::LanguageServerAdded(
9429 server_id,
9430 server_name,
9431 server.worktree_id.map(WorktreeId::from_proto),
9432 ));
9433 cx.notify();
9434 })?;
9435 Ok(())
9436 }
9437
9438 async fn handle_update_language_server(
9439 lsp_store: Entity<Self>,
9440 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9441 mut cx: AsyncApp,
9442 ) -> Result<()> {
9443 lsp_store.update(&mut cx, |lsp_store, cx| {
9444 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9445
9446 match envelope.payload.variant.context("invalid variant")? {
9447 proto::update_language_server::Variant::WorkStart(payload) => {
9448 lsp_store.on_lsp_work_start(
9449 language_server_id,
9450 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9451 .context("invalid progress token value")?,
9452 LanguageServerProgress {
9453 title: payload.title,
9454 is_disk_based_diagnostics_progress: false,
9455 is_cancellable: payload.is_cancellable.unwrap_or(false),
9456 message: payload.message,
9457 percentage: payload.percentage.map(|p| p as usize),
9458 last_update_at: cx.background_executor().now(),
9459 },
9460 cx,
9461 );
9462 }
9463 proto::update_language_server::Variant::WorkProgress(payload) => {
9464 lsp_store.on_lsp_work_progress(
9465 language_server_id,
9466 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9467 .context("invalid progress token value")?,
9468 LanguageServerProgress {
9469 title: None,
9470 is_disk_based_diagnostics_progress: false,
9471 is_cancellable: payload.is_cancellable.unwrap_or(false),
9472 message: payload.message,
9473 percentage: payload.percentage.map(|p| p as usize),
9474 last_update_at: cx.background_executor().now(),
9475 },
9476 cx,
9477 );
9478 }
9479
9480 proto::update_language_server::Variant::WorkEnd(payload) => {
9481 lsp_store.on_lsp_work_end(
9482 language_server_id,
9483 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9484 .context("invalid progress token value")?,
9485 cx,
9486 );
9487 }
9488
9489 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9490 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9491 }
9492
9493 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9494 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9495 }
9496
9497 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9498 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9499 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9500 cx.emit(LspStoreEvent::LanguageServerUpdate {
9501 language_server_id,
9502 name: envelope
9503 .payload
9504 .server_name
9505 .map(SharedString::new)
9506 .map(LanguageServerName),
9507 message: non_lsp,
9508 });
9509 }
9510 }
9511
9512 Ok(())
9513 })?
9514 }
9515
9516 async fn handle_language_server_log(
9517 this: Entity<Self>,
9518 envelope: TypedEnvelope<proto::LanguageServerLog>,
9519 mut cx: AsyncApp,
9520 ) -> Result<()> {
9521 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9522 let log_type = envelope
9523 .payload
9524 .log_type
9525 .map(LanguageServerLogType::from_proto)
9526 .context("invalid language server log type")?;
9527
9528 let message = envelope.payload.message;
9529
9530 this.update(&mut cx, |_, cx| {
9531 cx.emit(LspStoreEvent::LanguageServerLog(
9532 language_server_id,
9533 log_type,
9534 message,
9535 ));
9536 })
9537 }
9538
9539 async fn handle_lsp_ext_cancel_flycheck(
9540 lsp_store: Entity<Self>,
9541 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9542 cx: AsyncApp,
9543 ) -> Result<proto::Ack> {
9544 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9545 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9546 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9547 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9548 } else {
9549 None
9550 }
9551 })?;
9552 if let Some(task) = task {
9553 task.context("handling lsp ext cancel flycheck")?;
9554 }
9555
9556 Ok(proto::Ack {})
9557 }
9558
9559 async fn handle_lsp_ext_run_flycheck(
9560 lsp_store: Entity<Self>,
9561 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9562 mut cx: AsyncApp,
9563 ) -> Result<proto::Ack> {
9564 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9565 lsp_store.update(&mut cx, |lsp_store, cx| {
9566 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9567 let text_document = if envelope.payload.current_file_only {
9568 let buffer_id = envelope
9569 .payload
9570 .buffer_id
9571 .map(|id| BufferId::new(id))
9572 .transpose()?;
9573 buffer_id
9574 .and_then(|buffer_id| {
9575 lsp_store
9576 .buffer_store()
9577 .read(cx)
9578 .get(buffer_id)
9579 .and_then(|buffer| {
9580 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9581 })
9582 .map(|path| make_text_document_identifier(&path))
9583 })
9584 .transpose()?
9585 } else {
9586 None
9587 };
9588 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9589 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9590 )?;
9591 }
9592 anyhow::Ok(())
9593 })??;
9594
9595 Ok(proto::Ack {})
9596 }
9597
9598 async fn handle_lsp_ext_clear_flycheck(
9599 lsp_store: Entity<Self>,
9600 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9601 cx: AsyncApp,
9602 ) -> Result<proto::Ack> {
9603 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9604 lsp_store
9605 .read_with(&cx, |lsp_store, _| {
9606 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9607 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9608 } else {
9609 None
9610 }
9611 })
9612 .context("handling lsp ext clear flycheck")?;
9613
9614 Ok(proto::Ack {})
9615 }
9616
9617 pub fn disk_based_diagnostics_started(
9618 &mut self,
9619 language_server_id: LanguageServerId,
9620 cx: &mut Context<Self>,
9621 ) {
9622 if let Some(language_server_status) =
9623 self.language_server_statuses.get_mut(&language_server_id)
9624 {
9625 language_server_status.has_pending_diagnostic_updates = true;
9626 }
9627
9628 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9629 cx.emit(LspStoreEvent::LanguageServerUpdate {
9630 language_server_id,
9631 name: self
9632 .language_server_adapter_for_id(language_server_id)
9633 .map(|adapter| adapter.name()),
9634 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9635 Default::default(),
9636 ),
9637 })
9638 }
9639
9640 pub fn disk_based_diagnostics_finished(
9641 &mut self,
9642 language_server_id: LanguageServerId,
9643 cx: &mut Context<Self>,
9644 ) {
9645 if let Some(language_server_status) =
9646 self.language_server_statuses.get_mut(&language_server_id)
9647 {
9648 language_server_status.has_pending_diagnostic_updates = false;
9649 }
9650
9651 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9652 cx.emit(LspStoreEvent::LanguageServerUpdate {
9653 language_server_id,
9654 name: self
9655 .language_server_adapter_for_id(language_server_id)
9656 .map(|adapter| adapter.name()),
9657 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9658 Default::default(),
9659 ),
9660 })
9661 }
9662
9663 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9664 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9665 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9666 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9667 // the language server might take some time to publish diagnostics.
9668 fn simulate_disk_based_diagnostics_events_if_needed(
9669 &mut self,
9670 language_server_id: LanguageServerId,
9671 cx: &mut Context<Self>,
9672 ) {
9673 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9674
9675 let Some(LanguageServerState::Running {
9676 simulate_disk_based_diagnostics_completion,
9677 adapter,
9678 ..
9679 }) = self
9680 .as_local_mut()
9681 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9682 else {
9683 return;
9684 };
9685
9686 if adapter.disk_based_diagnostics_progress_token.is_some() {
9687 return;
9688 }
9689
9690 let prev_task =
9691 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9692 cx.background_executor()
9693 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9694 .await;
9695
9696 this.update(cx, |this, cx| {
9697 this.disk_based_diagnostics_finished(language_server_id, cx);
9698
9699 if let Some(LanguageServerState::Running {
9700 simulate_disk_based_diagnostics_completion,
9701 ..
9702 }) = this.as_local_mut().and_then(|local_store| {
9703 local_store.language_servers.get_mut(&language_server_id)
9704 }) {
9705 *simulate_disk_based_diagnostics_completion = None;
9706 }
9707 })
9708 .ok();
9709 }));
9710
9711 if prev_task.is_none() {
9712 self.disk_based_diagnostics_started(language_server_id, cx);
9713 }
9714 }
9715
9716 pub fn language_server_statuses(
9717 &self,
9718 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9719 self.language_server_statuses
9720 .iter()
9721 .map(|(key, value)| (*key, value))
9722 }
9723
9724 pub(super) fn did_rename_entry(
9725 &self,
9726 worktree_id: WorktreeId,
9727 old_path: &Path,
9728 new_path: &Path,
9729 is_dir: bool,
9730 ) {
9731 maybe!({
9732 let local_store = self.as_local()?;
9733
9734 let old_uri = lsp::Uri::from_file_path(old_path)
9735 .ok()
9736 .map(|uri| uri.to_string())?;
9737 let new_uri = lsp::Uri::from_file_path(new_path)
9738 .ok()
9739 .map(|uri| uri.to_string())?;
9740
9741 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9742 let Some(filter) = local_store
9743 .language_server_paths_watched_for_rename
9744 .get(&language_server.server_id())
9745 else {
9746 continue;
9747 };
9748
9749 if filter.should_send_did_rename(&old_uri, is_dir) {
9750 language_server
9751 .notify::<DidRenameFiles>(RenameFilesParams {
9752 files: vec![FileRename {
9753 old_uri: old_uri.clone(),
9754 new_uri: new_uri.clone(),
9755 }],
9756 })
9757 .ok();
9758 }
9759 }
9760 Some(())
9761 });
9762 }
9763
9764 pub(super) fn will_rename_entry(
9765 this: WeakEntity<Self>,
9766 worktree_id: WorktreeId,
9767 old_path: &Path,
9768 new_path: &Path,
9769 is_dir: bool,
9770 cx: AsyncApp,
9771 ) -> Task<ProjectTransaction> {
9772 let old_uri = lsp::Uri::from_file_path(old_path)
9773 .ok()
9774 .map(|uri| uri.to_string());
9775 let new_uri = lsp::Uri::from_file_path(new_path)
9776 .ok()
9777 .map(|uri| uri.to_string());
9778 cx.spawn(async move |cx| {
9779 let mut tasks = vec![];
9780 this.update(cx, |this, cx| {
9781 let local_store = this.as_local()?;
9782 let old_uri = old_uri?;
9783 let new_uri = new_uri?;
9784 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9785 let Some(filter) = local_store
9786 .language_server_paths_watched_for_rename
9787 .get(&language_server.server_id())
9788 else {
9789 continue;
9790 };
9791
9792 if filter.should_send_will_rename(&old_uri, is_dir) {
9793 let apply_edit = cx.spawn({
9794 let old_uri = old_uri.clone();
9795 let new_uri = new_uri.clone();
9796 let language_server = language_server.clone();
9797 async move |this, cx| {
9798 let edit = language_server
9799 .request::<WillRenameFiles>(RenameFilesParams {
9800 files: vec![FileRename { old_uri, new_uri }],
9801 })
9802 .await
9803 .into_response()
9804 .context("will rename files")
9805 .log_err()
9806 .flatten()?;
9807
9808 let transaction = LocalLspStore::deserialize_workspace_edit(
9809 this.upgrade()?,
9810 edit,
9811 false,
9812 language_server.clone(),
9813 cx,
9814 )
9815 .await
9816 .ok()?;
9817 Some(transaction)
9818 }
9819 });
9820 tasks.push(apply_edit);
9821 }
9822 }
9823 Some(())
9824 })
9825 .ok()
9826 .flatten();
9827 let mut merged_transaction = ProjectTransaction::default();
9828 for task in tasks {
9829 // Await on tasks sequentially so that the order of application of edits is deterministic
9830 // (at least with regards to the order of registration of language servers)
9831 if let Some(transaction) = task.await {
9832 for (buffer, buffer_transaction) in transaction.0 {
9833 merged_transaction.0.insert(buffer, buffer_transaction);
9834 }
9835 }
9836 }
9837 merged_transaction
9838 })
9839 }
9840
9841 fn lsp_notify_abs_paths_changed(
9842 &mut self,
9843 server_id: LanguageServerId,
9844 changes: Vec<PathEvent>,
9845 ) {
9846 maybe!({
9847 let server = self.language_server_for_id(server_id)?;
9848 let changes = changes
9849 .into_iter()
9850 .filter_map(|event| {
9851 let typ = match event.kind? {
9852 PathEventKind::Created => lsp::FileChangeType::CREATED,
9853 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9854 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9855 };
9856 Some(lsp::FileEvent {
9857 uri: file_path_to_lsp_url(&event.path).log_err()?,
9858 typ,
9859 })
9860 })
9861 .collect::<Vec<_>>();
9862 if !changes.is_empty() {
9863 server
9864 .notify::<lsp::notification::DidChangeWatchedFiles>(
9865 lsp::DidChangeWatchedFilesParams { changes },
9866 )
9867 .ok();
9868 }
9869 Some(())
9870 });
9871 }
9872
9873 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9874 self.as_local()?.language_server_for_id(id)
9875 }
9876
9877 fn on_lsp_progress(
9878 &mut self,
9879 progress_params: lsp::ProgressParams,
9880 language_server_id: LanguageServerId,
9881 disk_based_diagnostics_progress_token: Option<String>,
9882 cx: &mut Context<Self>,
9883 ) {
9884 match progress_params.value {
9885 lsp::ProgressParamsValue::WorkDone(progress) => {
9886 self.handle_work_done_progress(
9887 progress,
9888 language_server_id,
9889 disk_based_diagnostics_progress_token,
9890 ProgressToken::from_lsp(progress_params.token),
9891 cx,
9892 );
9893 }
9894 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9895 let registration_id = match progress_params.token {
9896 lsp::NumberOrString::Number(_) => None,
9897 lsp::NumberOrString::String(token) => token
9898 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9899 .map(|(_, id)| id.to_owned()),
9900 };
9901 if let Some(LanguageServerState::Running {
9902 workspace_diagnostics_refresh_tasks,
9903 ..
9904 }) = self
9905 .as_local_mut()
9906 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9907 && let Some(workspace_diagnostics) =
9908 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9909 {
9910 workspace_diagnostics.progress_tx.try_send(()).ok();
9911 self.apply_workspace_diagnostic_report(
9912 language_server_id,
9913 report,
9914 registration_id.map(SharedString::from),
9915 cx,
9916 )
9917 }
9918 }
9919 }
9920 }
9921
9922 fn handle_work_done_progress(
9923 &mut self,
9924 progress: lsp::WorkDoneProgress,
9925 language_server_id: LanguageServerId,
9926 disk_based_diagnostics_progress_token: Option<String>,
9927 token: ProgressToken,
9928 cx: &mut Context<Self>,
9929 ) {
9930 let language_server_status =
9931 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9932 status
9933 } else {
9934 return;
9935 };
9936
9937 if !language_server_status.progress_tokens.contains(&token) {
9938 return;
9939 }
9940
9941 let is_disk_based_diagnostics_progress =
9942 if let (Some(disk_based_token), ProgressToken::String(token)) =
9943 (&disk_based_diagnostics_progress_token, &token)
9944 {
9945 token.starts_with(disk_based_token)
9946 } else {
9947 false
9948 };
9949
9950 match progress {
9951 lsp::WorkDoneProgress::Begin(report) => {
9952 if is_disk_based_diagnostics_progress {
9953 self.disk_based_diagnostics_started(language_server_id, cx);
9954 }
9955 self.on_lsp_work_start(
9956 language_server_id,
9957 token.clone(),
9958 LanguageServerProgress {
9959 title: Some(report.title),
9960 is_disk_based_diagnostics_progress,
9961 is_cancellable: report.cancellable.unwrap_or(false),
9962 message: report.message.clone(),
9963 percentage: report.percentage.map(|p| p as usize),
9964 last_update_at: cx.background_executor().now(),
9965 },
9966 cx,
9967 );
9968 }
9969 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9970 language_server_id,
9971 token,
9972 LanguageServerProgress {
9973 title: None,
9974 is_disk_based_diagnostics_progress,
9975 is_cancellable: report.cancellable.unwrap_or(false),
9976 message: report.message,
9977 percentage: report.percentage.map(|p| p as usize),
9978 last_update_at: cx.background_executor().now(),
9979 },
9980 cx,
9981 ),
9982 lsp::WorkDoneProgress::End(_) => {
9983 language_server_status.progress_tokens.remove(&token);
9984 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9985 if is_disk_based_diagnostics_progress {
9986 self.disk_based_diagnostics_finished(language_server_id, cx);
9987 }
9988 }
9989 }
9990 }
9991
9992 fn on_lsp_work_start(
9993 &mut self,
9994 language_server_id: LanguageServerId,
9995 token: ProgressToken,
9996 progress: LanguageServerProgress,
9997 cx: &mut Context<Self>,
9998 ) {
9999 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10000 status.pending_work.insert(token.clone(), progress.clone());
10001 cx.notify();
10002 }
10003 cx.emit(LspStoreEvent::LanguageServerUpdate {
10004 language_server_id,
10005 name: self
10006 .language_server_adapter_for_id(language_server_id)
10007 .map(|adapter| adapter.name()),
10008 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10009 token: Some(token.to_proto()),
10010 title: progress.title,
10011 message: progress.message,
10012 percentage: progress.percentage.map(|p| p as u32),
10013 is_cancellable: Some(progress.is_cancellable),
10014 }),
10015 })
10016 }
10017
10018 fn on_lsp_work_progress(
10019 &mut self,
10020 language_server_id: LanguageServerId,
10021 token: ProgressToken,
10022 progress: LanguageServerProgress,
10023 cx: &mut Context<Self>,
10024 ) {
10025 let mut did_update = false;
10026 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10027 match status.pending_work.entry(token.clone()) {
10028 btree_map::Entry::Vacant(entry) => {
10029 entry.insert(progress.clone());
10030 did_update = true;
10031 }
10032 btree_map::Entry::Occupied(mut entry) => {
10033 let entry = entry.get_mut();
10034 if (progress.last_update_at - entry.last_update_at)
10035 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10036 {
10037 entry.last_update_at = progress.last_update_at;
10038 if progress.message.is_some() {
10039 entry.message = progress.message.clone();
10040 }
10041 if progress.percentage.is_some() {
10042 entry.percentage = progress.percentage;
10043 }
10044 if progress.is_cancellable != entry.is_cancellable {
10045 entry.is_cancellable = progress.is_cancellable;
10046 }
10047 did_update = true;
10048 }
10049 }
10050 }
10051 }
10052
10053 if did_update {
10054 cx.emit(LspStoreEvent::LanguageServerUpdate {
10055 language_server_id,
10056 name: self
10057 .language_server_adapter_for_id(language_server_id)
10058 .map(|adapter| adapter.name()),
10059 message: proto::update_language_server::Variant::WorkProgress(
10060 proto::LspWorkProgress {
10061 token: Some(token.to_proto()),
10062 message: progress.message,
10063 percentage: progress.percentage.map(|p| p as u32),
10064 is_cancellable: Some(progress.is_cancellable),
10065 },
10066 ),
10067 })
10068 }
10069 }
10070
10071 fn on_lsp_work_end(
10072 &mut self,
10073 language_server_id: LanguageServerId,
10074 token: ProgressToken,
10075 cx: &mut Context<Self>,
10076 ) {
10077 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10078 if let Some(work) = status.pending_work.remove(&token)
10079 && !work.is_disk_based_diagnostics_progress
10080 {
10081 cx.emit(LspStoreEvent::RefreshInlayHints {
10082 server_id: language_server_id,
10083 request_id: None,
10084 });
10085 }
10086 cx.notify();
10087 }
10088
10089 cx.emit(LspStoreEvent::LanguageServerUpdate {
10090 language_server_id,
10091 name: self
10092 .language_server_adapter_for_id(language_server_id)
10093 .map(|adapter| adapter.name()),
10094 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10095 token: Some(token.to_proto()),
10096 }),
10097 })
10098 }
10099
10100 pub async fn handle_resolve_completion_documentation(
10101 this: Entity<Self>,
10102 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10103 mut cx: AsyncApp,
10104 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10105 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10106
10107 let completion = this
10108 .read_with(&cx, |this, cx| {
10109 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10110 let server = this
10111 .language_server_for_id(id)
10112 .with_context(|| format!("No language server {id}"))?;
10113
10114 anyhow::Ok(cx.background_spawn(async move {
10115 let can_resolve = server
10116 .capabilities()
10117 .completion_provider
10118 .as_ref()
10119 .and_then(|options| options.resolve_provider)
10120 .unwrap_or(false);
10121 if can_resolve {
10122 server
10123 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10124 .await
10125 .into_response()
10126 .context("resolve completion item")
10127 } else {
10128 anyhow::Ok(lsp_completion)
10129 }
10130 }))
10131 })??
10132 .await?;
10133
10134 let mut documentation_is_markdown = false;
10135 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10136 let documentation = match completion.documentation {
10137 Some(lsp::Documentation::String(text)) => text,
10138
10139 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10140 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10141 value
10142 }
10143
10144 _ => String::new(),
10145 };
10146
10147 // If we have a new buffer_id, that means we're talking to a new client
10148 // and want to check for new text_edits in the completion too.
10149 let mut old_replace_start = None;
10150 let mut old_replace_end = None;
10151 let mut old_insert_start = None;
10152 let mut old_insert_end = None;
10153 let mut new_text = String::default();
10154 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10155 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10156 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10157 anyhow::Ok(buffer.read(cx).snapshot())
10158 })??;
10159
10160 if let Some(text_edit) = completion.text_edit.as_ref() {
10161 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10162
10163 if let Some(mut edit) = edit {
10164 LineEnding::normalize(&mut edit.new_text);
10165
10166 new_text = edit.new_text;
10167 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10168 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10169 if let Some(insert_range) = edit.insert_range {
10170 old_insert_start = Some(serialize_anchor(&insert_range.start));
10171 old_insert_end = Some(serialize_anchor(&insert_range.end));
10172 }
10173 }
10174 }
10175 }
10176
10177 Ok(proto::ResolveCompletionDocumentationResponse {
10178 documentation,
10179 documentation_is_markdown,
10180 old_replace_start,
10181 old_replace_end,
10182 new_text,
10183 lsp_completion,
10184 old_insert_start,
10185 old_insert_end,
10186 })
10187 }
10188
10189 async fn handle_on_type_formatting(
10190 this: Entity<Self>,
10191 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10192 mut cx: AsyncApp,
10193 ) -> Result<proto::OnTypeFormattingResponse> {
10194 let on_type_formatting = this.update(&mut cx, |this, cx| {
10195 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10196 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10197 let position = envelope
10198 .payload
10199 .position
10200 .and_then(deserialize_anchor)
10201 .context("invalid position")?;
10202 anyhow::Ok(this.apply_on_type_formatting(
10203 buffer,
10204 position,
10205 envelope.payload.trigger.clone(),
10206 cx,
10207 ))
10208 })??;
10209
10210 let transaction = on_type_formatting
10211 .await?
10212 .as_ref()
10213 .map(language::proto::serialize_transaction);
10214 Ok(proto::OnTypeFormattingResponse { transaction })
10215 }
10216
10217 async fn handle_refresh_inlay_hints(
10218 lsp_store: Entity<Self>,
10219 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10220 mut cx: AsyncApp,
10221 ) -> Result<proto::Ack> {
10222 lsp_store.update(&mut cx, |_, cx| {
10223 cx.emit(LspStoreEvent::RefreshInlayHints {
10224 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10225 request_id: envelope.payload.request_id.map(|id| id as usize),
10226 });
10227 })?;
10228 Ok(proto::Ack {})
10229 }
10230
10231 async fn handle_pull_workspace_diagnostics(
10232 lsp_store: Entity<Self>,
10233 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10234 mut cx: AsyncApp,
10235 ) -> Result<proto::Ack> {
10236 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10237 lsp_store.update(&mut cx, |lsp_store, _| {
10238 lsp_store.pull_workspace_diagnostics(server_id);
10239 })?;
10240 Ok(proto::Ack {})
10241 }
10242
10243 async fn handle_get_color_presentation(
10244 lsp_store: Entity<Self>,
10245 envelope: TypedEnvelope<proto::GetColorPresentation>,
10246 mut cx: AsyncApp,
10247 ) -> Result<proto::GetColorPresentationResponse> {
10248 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10249 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10250 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10251 })??;
10252
10253 let color = envelope
10254 .payload
10255 .color
10256 .context("invalid color resolve request")?;
10257 let start = color
10258 .lsp_range_start
10259 .context("invalid color resolve request")?;
10260 let end = color
10261 .lsp_range_end
10262 .context("invalid color resolve request")?;
10263
10264 let color = DocumentColor {
10265 lsp_range: lsp::Range {
10266 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10267 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10268 },
10269 color: lsp::Color {
10270 red: color.red,
10271 green: color.green,
10272 blue: color.blue,
10273 alpha: color.alpha,
10274 },
10275 resolved: false,
10276 color_presentations: Vec::new(),
10277 };
10278 let resolved_color = lsp_store
10279 .update(&mut cx, |lsp_store, cx| {
10280 lsp_store.resolve_color_presentation(
10281 color,
10282 buffer.clone(),
10283 LanguageServerId(envelope.payload.server_id as usize),
10284 cx,
10285 )
10286 })?
10287 .await
10288 .context("resolving color presentation")?;
10289
10290 Ok(proto::GetColorPresentationResponse {
10291 presentations: resolved_color
10292 .color_presentations
10293 .into_iter()
10294 .map(|presentation| proto::ColorPresentation {
10295 label: presentation.label.to_string(),
10296 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10297 additional_text_edits: presentation
10298 .additional_text_edits
10299 .into_iter()
10300 .map(serialize_lsp_edit)
10301 .collect(),
10302 })
10303 .collect(),
10304 })
10305 }
10306
10307 async fn handle_resolve_inlay_hint(
10308 lsp_store: Entity<Self>,
10309 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10310 mut cx: AsyncApp,
10311 ) -> Result<proto::ResolveInlayHintResponse> {
10312 let proto_hint = envelope
10313 .payload
10314 .hint
10315 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10316 let hint = InlayHints::proto_to_project_hint(proto_hint)
10317 .context("resolved proto inlay hint conversion")?;
10318 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10319 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10320 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10321 })??;
10322 let response_hint = lsp_store
10323 .update(&mut cx, |lsp_store, cx| {
10324 lsp_store.resolve_inlay_hint(
10325 hint,
10326 buffer,
10327 LanguageServerId(envelope.payload.language_server_id as usize),
10328 cx,
10329 )
10330 })?
10331 .await
10332 .context("inlay hints fetch")?;
10333 Ok(proto::ResolveInlayHintResponse {
10334 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10335 })
10336 }
10337
10338 async fn handle_refresh_code_lens(
10339 this: Entity<Self>,
10340 _: TypedEnvelope<proto::RefreshCodeLens>,
10341 mut cx: AsyncApp,
10342 ) -> Result<proto::Ack> {
10343 this.update(&mut cx, |_, cx| {
10344 cx.emit(LspStoreEvent::RefreshCodeLens);
10345 })?;
10346 Ok(proto::Ack {})
10347 }
10348
10349 async fn handle_open_buffer_for_symbol(
10350 this: Entity<Self>,
10351 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10352 mut cx: AsyncApp,
10353 ) -> Result<proto::OpenBufferForSymbolResponse> {
10354 let peer_id = envelope.original_sender_id().unwrap_or_default();
10355 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10356 let symbol = Self::deserialize_symbol(symbol)?;
10357 this.read_with(&cx, |this, _| {
10358 if let SymbolLocation::OutsideProject {
10359 abs_path,
10360 signature,
10361 } = &symbol.path
10362 {
10363 let new_signature = this.symbol_signature(&abs_path);
10364 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10365 }
10366 Ok(())
10367 })??;
10368 let buffer = this
10369 .update(&mut cx, |this, cx| {
10370 this.open_buffer_for_symbol(
10371 &Symbol {
10372 language_server_name: symbol.language_server_name,
10373 source_worktree_id: symbol.source_worktree_id,
10374 source_language_server_id: symbol.source_language_server_id,
10375 path: symbol.path,
10376 name: symbol.name,
10377 kind: symbol.kind,
10378 range: symbol.range,
10379 label: CodeLabel::default(),
10380 },
10381 cx,
10382 )
10383 })?
10384 .await?;
10385
10386 this.update(&mut cx, |this, cx| {
10387 let is_private = buffer
10388 .read(cx)
10389 .file()
10390 .map(|f| f.is_private())
10391 .unwrap_or_default();
10392 if is_private {
10393 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10394 } else {
10395 this.buffer_store
10396 .update(cx, |buffer_store, cx| {
10397 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10398 })
10399 .detach_and_log_err(cx);
10400 let buffer_id = buffer.read(cx).remote_id().to_proto();
10401 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10402 }
10403 })?
10404 }
10405
10406 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10407 let mut hasher = Sha256::new();
10408 hasher.update(abs_path.to_string_lossy().as_bytes());
10409 hasher.update(self.nonce.to_be_bytes());
10410 hasher.finalize().as_slice().try_into().unwrap()
10411 }
10412
10413 pub async fn handle_get_project_symbols(
10414 this: Entity<Self>,
10415 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10416 mut cx: AsyncApp,
10417 ) -> Result<proto::GetProjectSymbolsResponse> {
10418 let symbols = this
10419 .update(&mut cx, |this, cx| {
10420 this.symbols(&envelope.payload.query, cx)
10421 })?
10422 .await?;
10423
10424 Ok(proto::GetProjectSymbolsResponse {
10425 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10426 })
10427 }
10428
10429 pub async fn handle_restart_language_servers(
10430 this: Entity<Self>,
10431 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10432 mut cx: AsyncApp,
10433 ) -> Result<proto::Ack> {
10434 this.update(&mut cx, |lsp_store, cx| {
10435 let buffers =
10436 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10437 lsp_store.restart_language_servers_for_buffers(
10438 buffers,
10439 envelope
10440 .payload
10441 .only_servers
10442 .into_iter()
10443 .filter_map(|selector| {
10444 Some(match selector.selector? {
10445 proto::language_server_selector::Selector::ServerId(server_id) => {
10446 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10447 }
10448 proto::language_server_selector::Selector::Name(name) => {
10449 LanguageServerSelector::Name(LanguageServerName(
10450 SharedString::from(name),
10451 ))
10452 }
10453 })
10454 })
10455 .collect(),
10456 cx,
10457 );
10458 })?;
10459
10460 Ok(proto::Ack {})
10461 }
10462
10463 pub async fn handle_stop_language_servers(
10464 lsp_store: Entity<Self>,
10465 envelope: TypedEnvelope<proto::StopLanguageServers>,
10466 mut cx: AsyncApp,
10467 ) -> Result<proto::Ack> {
10468 lsp_store.update(&mut cx, |lsp_store, cx| {
10469 if envelope.payload.all
10470 && envelope.payload.also_servers.is_empty()
10471 && envelope.payload.buffer_ids.is_empty()
10472 {
10473 lsp_store.stop_all_language_servers(cx);
10474 } else {
10475 let buffers =
10476 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10477 lsp_store
10478 .stop_language_servers_for_buffers(
10479 buffers,
10480 envelope
10481 .payload
10482 .also_servers
10483 .into_iter()
10484 .filter_map(|selector| {
10485 Some(match selector.selector? {
10486 proto::language_server_selector::Selector::ServerId(
10487 server_id,
10488 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10489 server_id,
10490 )),
10491 proto::language_server_selector::Selector::Name(name) => {
10492 LanguageServerSelector::Name(LanguageServerName(
10493 SharedString::from(name),
10494 ))
10495 }
10496 })
10497 })
10498 .collect(),
10499 cx,
10500 )
10501 .detach_and_log_err(cx);
10502 }
10503 })?;
10504
10505 Ok(proto::Ack {})
10506 }
10507
10508 pub async fn handle_cancel_language_server_work(
10509 lsp_store: Entity<Self>,
10510 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10511 mut cx: AsyncApp,
10512 ) -> Result<proto::Ack> {
10513 lsp_store.update(&mut cx, |lsp_store, cx| {
10514 if let Some(work) = envelope.payload.work {
10515 match work {
10516 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10517 let buffers =
10518 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10519 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10520 }
10521 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10522 let server_id = LanguageServerId::from_proto(work.language_server_id);
10523 let token = work
10524 .token
10525 .map(|token| {
10526 ProgressToken::from_proto(token)
10527 .context("invalid work progress token")
10528 })
10529 .transpose()?;
10530 lsp_store.cancel_language_server_work(server_id, token, cx);
10531 }
10532 }
10533 }
10534 anyhow::Ok(())
10535 })??;
10536
10537 Ok(proto::Ack {})
10538 }
10539
10540 fn buffer_ids_to_buffers(
10541 &mut self,
10542 buffer_ids: impl Iterator<Item = u64>,
10543 cx: &mut Context<Self>,
10544 ) -> Vec<Entity<Buffer>> {
10545 buffer_ids
10546 .into_iter()
10547 .flat_map(|buffer_id| {
10548 self.buffer_store
10549 .read(cx)
10550 .get(BufferId::new(buffer_id).log_err()?)
10551 })
10552 .collect::<Vec<_>>()
10553 }
10554
10555 async fn handle_apply_additional_edits_for_completion(
10556 this: Entity<Self>,
10557 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10558 mut cx: AsyncApp,
10559 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10560 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10561 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10562 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10563 let completion = Self::deserialize_completion(
10564 envelope.payload.completion.context("invalid completion")?,
10565 )?;
10566 anyhow::Ok((buffer, completion))
10567 })??;
10568
10569 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10570 this.apply_additional_edits_for_completion(
10571 buffer,
10572 Rc::new(RefCell::new(Box::new([Completion {
10573 replace_range: completion.replace_range,
10574 new_text: completion.new_text,
10575 source: completion.source,
10576 documentation: None,
10577 label: CodeLabel::default(),
10578 match_start: None,
10579 snippet_deduplication_key: None,
10580 insert_text_mode: None,
10581 icon_path: None,
10582 confirm: None,
10583 }]))),
10584 0,
10585 false,
10586 cx,
10587 )
10588 })?;
10589
10590 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10591 transaction: apply_additional_edits
10592 .await?
10593 .as_ref()
10594 .map(language::proto::serialize_transaction),
10595 })
10596 }
10597
10598 pub fn last_formatting_failure(&self) -> Option<&str> {
10599 self.last_formatting_failure.as_deref()
10600 }
10601
10602 pub fn reset_last_formatting_failure(&mut self) {
10603 self.last_formatting_failure = None;
10604 }
10605
10606 pub fn environment_for_buffer(
10607 &self,
10608 buffer: &Entity<Buffer>,
10609 cx: &mut Context<Self>,
10610 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10611 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10612 environment.update(cx, |env, cx| {
10613 env.buffer_environment(buffer, &self.worktree_store, cx)
10614 })
10615 } else {
10616 Task::ready(None).shared()
10617 }
10618 }
10619
10620 pub fn format(
10621 &mut self,
10622 buffers: HashSet<Entity<Buffer>>,
10623 target: LspFormatTarget,
10624 push_to_history: bool,
10625 trigger: FormatTrigger,
10626 cx: &mut Context<Self>,
10627 ) -> Task<anyhow::Result<ProjectTransaction>> {
10628 let logger = zlog::scoped!("format");
10629 if self.as_local().is_some() {
10630 zlog::trace!(logger => "Formatting locally");
10631 let logger = zlog::scoped!(logger => "local");
10632 let buffers = buffers
10633 .into_iter()
10634 .map(|buffer_handle| {
10635 let buffer = buffer_handle.read(cx);
10636 let buffer_abs_path = File::from_dyn(buffer.file())
10637 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10638
10639 (buffer_handle, buffer_abs_path, buffer.remote_id())
10640 })
10641 .collect::<Vec<_>>();
10642
10643 cx.spawn(async move |lsp_store, cx| {
10644 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10645
10646 for (handle, abs_path, id) in buffers {
10647 let env = lsp_store
10648 .update(cx, |lsp_store, cx| {
10649 lsp_store.environment_for_buffer(&handle, cx)
10650 })?
10651 .await;
10652
10653 let ranges = match &target {
10654 LspFormatTarget::Buffers => None,
10655 LspFormatTarget::Ranges(ranges) => {
10656 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10657 }
10658 };
10659
10660 formattable_buffers.push(FormattableBuffer {
10661 handle,
10662 abs_path,
10663 env,
10664 ranges,
10665 });
10666 }
10667 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10668
10669 let format_timer = zlog::time!(logger => "Formatting buffers");
10670 let result = LocalLspStore::format_locally(
10671 lsp_store.clone(),
10672 formattable_buffers,
10673 push_to_history,
10674 trigger,
10675 logger,
10676 cx,
10677 )
10678 .await;
10679 format_timer.end();
10680
10681 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10682
10683 lsp_store.update(cx, |lsp_store, _| {
10684 lsp_store.update_last_formatting_failure(&result);
10685 })?;
10686
10687 result
10688 })
10689 } else if let Some((client, project_id)) = self.upstream_client() {
10690 zlog::trace!(logger => "Formatting remotely");
10691 let logger = zlog::scoped!(logger => "remote");
10692 // Don't support formatting ranges via remote
10693 match target {
10694 LspFormatTarget::Buffers => {}
10695 LspFormatTarget::Ranges(_) => {
10696 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10697 return Task::ready(Ok(ProjectTransaction::default()));
10698 }
10699 }
10700
10701 let buffer_store = self.buffer_store();
10702 cx.spawn(async move |lsp_store, cx| {
10703 zlog::trace!(logger => "Sending remote format request");
10704 let request_timer = zlog::time!(logger => "remote format request");
10705 let result = client
10706 .request(proto::FormatBuffers {
10707 project_id,
10708 trigger: trigger as i32,
10709 buffer_ids: buffers
10710 .iter()
10711 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10712 .collect::<Result<_>>()?,
10713 })
10714 .await
10715 .and_then(|result| result.transaction.context("missing transaction"));
10716 request_timer.end();
10717
10718 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10719
10720 lsp_store.update(cx, |lsp_store, _| {
10721 lsp_store.update_last_formatting_failure(&result);
10722 })?;
10723
10724 let transaction_response = result?;
10725 let _timer = zlog::time!(logger => "deserializing project transaction");
10726 buffer_store
10727 .update(cx, |buffer_store, cx| {
10728 buffer_store.deserialize_project_transaction(
10729 transaction_response,
10730 push_to_history,
10731 cx,
10732 )
10733 })?
10734 .await
10735 })
10736 } else {
10737 zlog::trace!(logger => "Not formatting");
10738 Task::ready(Ok(ProjectTransaction::default()))
10739 }
10740 }
10741
10742 async fn handle_format_buffers(
10743 this: Entity<Self>,
10744 envelope: TypedEnvelope<proto::FormatBuffers>,
10745 mut cx: AsyncApp,
10746 ) -> Result<proto::FormatBuffersResponse> {
10747 let sender_id = envelope.original_sender_id().unwrap_or_default();
10748 let format = this.update(&mut cx, |this, cx| {
10749 let mut buffers = HashSet::default();
10750 for buffer_id in &envelope.payload.buffer_ids {
10751 let buffer_id = BufferId::new(*buffer_id)?;
10752 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10753 }
10754 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10755 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10756 })??;
10757
10758 let project_transaction = format.await?;
10759 let project_transaction = this.update(&mut cx, |this, cx| {
10760 this.buffer_store.update(cx, |buffer_store, cx| {
10761 buffer_store.serialize_project_transaction_for_peer(
10762 project_transaction,
10763 sender_id,
10764 cx,
10765 )
10766 })
10767 })?;
10768 Ok(proto::FormatBuffersResponse {
10769 transaction: Some(project_transaction),
10770 })
10771 }
10772
10773 async fn handle_apply_code_action_kind(
10774 this: Entity<Self>,
10775 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10776 mut cx: AsyncApp,
10777 ) -> Result<proto::ApplyCodeActionKindResponse> {
10778 let sender_id = envelope.original_sender_id().unwrap_or_default();
10779 let format = this.update(&mut cx, |this, cx| {
10780 let mut buffers = HashSet::default();
10781 for buffer_id in &envelope.payload.buffer_ids {
10782 let buffer_id = BufferId::new(*buffer_id)?;
10783 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10784 }
10785 let kind = match envelope.payload.kind.as_str() {
10786 "" => CodeActionKind::EMPTY,
10787 "quickfix" => CodeActionKind::QUICKFIX,
10788 "refactor" => CodeActionKind::REFACTOR,
10789 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10790 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10791 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10792 "source" => CodeActionKind::SOURCE,
10793 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10794 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10795 _ => anyhow::bail!(
10796 "Invalid code action kind {}",
10797 envelope.payload.kind.as_str()
10798 ),
10799 };
10800 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10801 })??;
10802
10803 let project_transaction = format.await?;
10804 let project_transaction = this.update(&mut cx, |this, cx| {
10805 this.buffer_store.update(cx, |buffer_store, cx| {
10806 buffer_store.serialize_project_transaction_for_peer(
10807 project_transaction,
10808 sender_id,
10809 cx,
10810 )
10811 })
10812 })?;
10813 Ok(proto::ApplyCodeActionKindResponse {
10814 transaction: Some(project_transaction),
10815 })
10816 }
10817
10818 async fn shutdown_language_server(
10819 server_state: Option<LanguageServerState>,
10820 name: LanguageServerName,
10821 cx: &mut AsyncApp,
10822 ) {
10823 let server = match server_state {
10824 Some(LanguageServerState::Starting { startup, .. }) => {
10825 let mut timer = cx
10826 .background_executor()
10827 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10828 .fuse();
10829
10830 select! {
10831 server = startup.fuse() => server,
10832 () = timer => {
10833 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10834 None
10835 },
10836 }
10837 }
10838
10839 Some(LanguageServerState::Running { server, .. }) => Some(server),
10840
10841 None => None,
10842 };
10843
10844 if let Some(server) = server
10845 && let Some(shutdown) = server.shutdown()
10846 {
10847 shutdown.await;
10848 }
10849 }
10850
10851 // Returns a list of all of the worktrees which no longer have a language server and the root path
10852 // for the stopped server
10853 fn stop_local_language_server(
10854 &mut self,
10855 server_id: LanguageServerId,
10856 cx: &mut Context<Self>,
10857 ) -> Task<()> {
10858 let local = match &mut self.mode {
10859 LspStoreMode::Local(local) => local,
10860 _ => {
10861 return Task::ready(());
10862 }
10863 };
10864
10865 // Remove this server ID from all entries in the given worktree.
10866 local
10867 .language_server_ids
10868 .retain(|_, state| state.id != server_id);
10869 self.buffer_store.update(cx, |buffer_store, cx| {
10870 for buffer in buffer_store.buffers() {
10871 buffer.update(cx, |buffer, cx| {
10872 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10873 buffer.set_completion_triggers(server_id, Default::default(), cx);
10874 });
10875 }
10876 });
10877
10878 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10879 summaries.retain(|path, summaries_by_server_id| {
10880 if summaries_by_server_id.remove(&server_id).is_some() {
10881 if let Some((client, project_id)) = self.downstream_client.clone() {
10882 client
10883 .send(proto::UpdateDiagnosticSummary {
10884 project_id,
10885 worktree_id: worktree_id.to_proto(),
10886 summary: Some(proto::DiagnosticSummary {
10887 path: path.as_ref().to_proto(),
10888 language_server_id: server_id.0 as u64,
10889 error_count: 0,
10890 warning_count: 0,
10891 }),
10892 more_summaries: Vec::new(),
10893 })
10894 .log_err();
10895 }
10896 !summaries_by_server_id.is_empty()
10897 } else {
10898 true
10899 }
10900 });
10901 }
10902
10903 let local = self.as_local_mut().unwrap();
10904 for diagnostics in local.diagnostics.values_mut() {
10905 diagnostics.retain(|_, diagnostics_by_server_id| {
10906 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10907 diagnostics_by_server_id.remove(ix);
10908 !diagnostics_by_server_id.is_empty()
10909 } else {
10910 true
10911 }
10912 });
10913 }
10914 local.language_server_watched_paths.remove(&server_id);
10915
10916 let server_state = local.language_servers.remove(&server_id);
10917 self.cleanup_lsp_data(server_id);
10918 let name = self
10919 .language_server_statuses
10920 .remove(&server_id)
10921 .map(|status| status.name)
10922 .or_else(|| {
10923 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10924 Some(adapter.name())
10925 } else {
10926 None
10927 }
10928 });
10929
10930 if let Some(name) = name {
10931 log::info!("stopping language server {name}");
10932 self.languages
10933 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10934 cx.notify();
10935
10936 return cx.spawn(async move |lsp_store, cx| {
10937 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10938 lsp_store
10939 .update(cx, |lsp_store, cx| {
10940 lsp_store
10941 .languages
10942 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10943 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10944 cx.notify();
10945 })
10946 .ok();
10947 });
10948 }
10949
10950 if server_state.is_some() {
10951 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10952 }
10953 Task::ready(())
10954 }
10955
10956 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10957 if let Some((client, project_id)) = self.upstream_client() {
10958 let request = client.request(proto::StopLanguageServers {
10959 project_id,
10960 buffer_ids: Vec::new(),
10961 also_servers: Vec::new(),
10962 all: true,
10963 });
10964 cx.background_spawn(request).detach_and_log_err(cx);
10965 } else {
10966 let Some(local) = self.as_local_mut() else {
10967 return;
10968 };
10969 let language_servers_to_stop = local
10970 .language_server_ids
10971 .values()
10972 .map(|state| state.id)
10973 .collect();
10974 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10975 let tasks = language_servers_to_stop
10976 .into_iter()
10977 .map(|server| self.stop_local_language_server(server, cx))
10978 .collect::<Vec<_>>();
10979 cx.background_spawn(async move {
10980 futures::future::join_all(tasks).await;
10981 })
10982 .detach();
10983 }
10984 }
10985
10986 pub fn restart_language_servers_for_buffers(
10987 &mut self,
10988 buffers: Vec<Entity<Buffer>>,
10989 only_restart_servers: HashSet<LanguageServerSelector>,
10990 cx: &mut Context<Self>,
10991 ) {
10992 if let Some((client, project_id)) = self.upstream_client() {
10993 let request = client.request(proto::RestartLanguageServers {
10994 project_id,
10995 buffer_ids: buffers
10996 .into_iter()
10997 .map(|b| b.read(cx).remote_id().to_proto())
10998 .collect(),
10999 only_servers: only_restart_servers
11000 .into_iter()
11001 .map(|selector| {
11002 let selector = match selector {
11003 LanguageServerSelector::Id(language_server_id) => {
11004 proto::language_server_selector::Selector::ServerId(
11005 language_server_id.to_proto(),
11006 )
11007 }
11008 LanguageServerSelector::Name(language_server_name) => {
11009 proto::language_server_selector::Selector::Name(
11010 language_server_name.to_string(),
11011 )
11012 }
11013 };
11014 proto::LanguageServerSelector {
11015 selector: Some(selector),
11016 }
11017 })
11018 .collect(),
11019 all: false,
11020 });
11021 cx.background_spawn(request).detach_and_log_err(cx);
11022 } else {
11023 let stop_task = if only_restart_servers.is_empty() {
11024 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11025 } else {
11026 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11027 };
11028 cx.spawn(async move |lsp_store, cx| {
11029 stop_task.await;
11030 lsp_store
11031 .update(cx, |lsp_store, cx| {
11032 for buffer in buffers {
11033 lsp_store.register_buffer_with_language_servers(
11034 &buffer,
11035 only_restart_servers.clone(),
11036 true,
11037 cx,
11038 );
11039 }
11040 })
11041 .ok()
11042 })
11043 .detach();
11044 }
11045 }
11046
11047 pub fn stop_language_servers_for_buffers(
11048 &mut self,
11049 buffers: Vec<Entity<Buffer>>,
11050 also_stop_servers: HashSet<LanguageServerSelector>,
11051 cx: &mut Context<Self>,
11052 ) -> Task<Result<()>> {
11053 if let Some((client, project_id)) = self.upstream_client() {
11054 let request = client.request(proto::StopLanguageServers {
11055 project_id,
11056 buffer_ids: buffers
11057 .into_iter()
11058 .map(|b| b.read(cx).remote_id().to_proto())
11059 .collect(),
11060 also_servers: also_stop_servers
11061 .into_iter()
11062 .map(|selector| {
11063 let selector = match selector {
11064 LanguageServerSelector::Id(language_server_id) => {
11065 proto::language_server_selector::Selector::ServerId(
11066 language_server_id.to_proto(),
11067 )
11068 }
11069 LanguageServerSelector::Name(language_server_name) => {
11070 proto::language_server_selector::Selector::Name(
11071 language_server_name.to_string(),
11072 )
11073 }
11074 };
11075 proto::LanguageServerSelector {
11076 selector: Some(selector),
11077 }
11078 })
11079 .collect(),
11080 all: false,
11081 });
11082 cx.background_spawn(async move {
11083 let _ = request.await?;
11084 Ok(())
11085 })
11086 } else {
11087 let task =
11088 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11089 cx.background_spawn(async move {
11090 task.await;
11091 Ok(())
11092 })
11093 }
11094 }
11095
11096 fn stop_local_language_servers_for_buffers(
11097 &mut self,
11098 buffers: &[Entity<Buffer>],
11099 also_stop_servers: HashSet<LanguageServerSelector>,
11100 cx: &mut Context<Self>,
11101 ) -> Task<()> {
11102 let Some(local) = self.as_local_mut() else {
11103 return Task::ready(());
11104 };
11105 let mut language_server_names_to_stop = BTreeSet::default();
11106 let mut language_servers_to_stop = also_stop_servers
11107 .into_iter()
11108 .flat_map(|selector| match selector {
11109 LanguageServerSelector::Id(id) => Some(id),
11110 LanguageServerSelector::Name(name) => {
11111 language_server_names_to_stop.insert(name);
11112 None
11113 }
11114 })
11115 .collect::<BTreeSet<_>>();
11116
11117 let mut covered_worktrees = HashSet::default();
11118 for buffer in buffers {
11119 buffer.update(cx, |buffer, cx| {
11120 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11121 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11122 && covered_worktrees.insert(worktree_id)
11123 {
11124 language_server_names_to_stop.retain(|name| {
11125 let old_ids_count = language_servers_to_stop.len();
11126 let all_language_servers_with_this_name = local
11127 .language_server_ids
11128 .iter()
11129 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11130 language_servers_to_stop.extend(all_language_servers_with_this_name);
11131 old_ids_count == language_servers_to_stop.len()
11132 });
11133 }
11134 });
11135 }
11136 for name in language_server_names_to_stop {
11137 language_servers_to_stop.extend(
11138 local
11139 .language_server_ids
11140 .iter()
11141 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11142 );
11143 }
11144
11145 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11146 let tasks = language_servers_to_stop
11147 .into_iter()
11148 .map(|server| self.stop_local_language_server(server, cx))
11149 .collect::<Vec<_>>();
11150
11151 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11152 }
11153
11154 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11155 let (worktree, relative_path) =
11156 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11157
11158 let project_path = ProjectPath {
11159 worktree_id: worktree.read(cx).id(),
11160 path: relative_path,
11161 };
11162
11163 Some(
11164 self.buffer_store()
11165 .read(cx)
11166 .get_by_path(&project_path)?
11167 .read(cx),
11168 )
11169 }
11170
11171 #[cfg(any(test, feature = "test-support"))]
11172 pub fn update_diagnostics(
11173 &mut self,
11174 server_id: LanguageServerId,
11175 diagnostics: lsp::PublishDiagnosticsParams,
11176 result_id: Option<SharedString>,
11177 source_kind: DiagnosticSourceKind,
11178 disk_based_sources: &[String],
11179 cx: &mut Context<Self>,
11180 ) -> Result<()> {
11181 self.merge_lsp_diagnostics(
11182 source_kind,
11183 vec![DocumentDiagnosticsUpdate {
11184 diagnostics,
11185 result_id,
11186 server_id,
11187 disk_based_sources: Cow::Borrowed(disk_based_sources),
11188 registration_id: None,
11189 }],
11190 |_, _, _| false,
11191 cx,
11192 )
11193 }
11194
11195 pub fn merge_lsp_diagnostics(
11196 &mut self,
11197 source_kind: DiagnosticSourceKind,
11198 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11199 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11200 cx: &mut Context<Self>,
11201 ) -> Result<()> {
11202 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11203 let updates = lsp_diagnostics
11204 .into_iter()
11205 .filter_map(|update| {
11206 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11207 Some(DocumentDiagnosticsUpdate {
11208 diagnostics: self.lsp_to_document_diagnostics(
11209 abs_path,
11210 source_kind,
11211 update.server_id,
11212 update.diagnostics,
11213 &update.disk_based_sources,
11214 update.registration_id.clone(),
11215 ),
11216 result_id: update.result_id,
11217 server_id: update.server_id,
11218 disk_based_sources: update.disk_based_sources,
11219 registration_id: update.registration_id,
11220 })
11221 })
11222 .collect();
11223 self.merge_diagnostic_entries(updates, merge, cx)?;
11224 Ok(())
11225 }
11226
11227 fn lsp_to_document_diagnostics(
11228 &mut self,
11229 document_abs_path: PathBuf,
11230 source_kind: DiagnosticSourceKind,
11231 server_id: LanguageServerId,
11232 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11233 disk_based_sources: &[String],
11234 registration_id: Option<SharedString>,
11235 ) -> DocumentDiagnostics {
11236 let mut diagnostics = Vec::default();
11237 let mut primary_diagnostic_group_ids = HashMap::default();
11238 let mut sources_by_group_id = HashMap::default();
11239 let mut supporting_diagnostics = HashMap::default();
11240
11241 let adapter = self.language_server_adapter_for_id(server_id);
11242
11243 // Ensure that primary diagnostics are always the most severe
11244 lsp_diagnostics
11245 .diagnostics
11246 .sort_by_key(|item| item.severity);
11247
11248 for diagnostic in &lsp_diagnostics.diagnostics {
11249 let source = diagnostic.source.as_ref();
11250 let range = range_from_lsp(diagnostic.range);
11251 let is_supporting = diagnostic
11252 .related_information
11253 .as_ref()
11254 .is_some_and(|infos| {
11255 infos.iter().any(|info| {
11256 primary_diagnostic_group_ids.contains_key(&(
11257 source,
11258 diagnostic.code.clone(),
11259 range_from_lsp(info.location.range),
11260 ))
11261 })
11262 });
11263
11264 let is_unnecessary = diagnostic
11265 .tags
11266 .as_ref()
11267 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11268
11269 let underline = self
11270 .language_server_adapter_for_id(server_id)
11271 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11272
11273 if is_supporting {
11274 supporting_diagnostics.insert(
11275 (source, diagnostic.code.clone(), range),
11276 (diagnostic.severity, is_unnecessary),
11277 );
11278 } else {
11279 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11280 let is_disk_based =
11281 source.is_some_and(|source| disk_based_sources.contains(source));
11282
11283 sources_by_group_id.insert(group_id, source);
11284 primary_diagnostic_group_ids
11285 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11286
11287 diagnostics.push(DiagnosticEntry {
11288 range,
11289 diagnostic: Diagnostic {
11290 source: diagnostic.source.clone(),
11291 source_kind,
11292 code: diagnostic.code.clone(),
11293 code_description: diagnostic
11294 .code_description
11295 .as_ref()
11296 .and_then(|d| d.href.clone()),
11297 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11298 markdown: adapter.as_ref().and_then(|adapter| {
11299 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11300 }),
11301 message: diagnostic.message.trim().to_string(),
11302 group_id,
11303 is_primary: true,
11304 is_disk_based,
11305 is_unnecessary,
11306 underline,
11307 data: diagnostic.data.clone(),
11308 registration_id: registration_id.clone(),
11309 },
11310 });
11311 if let Some(infos) = &diagnostic.related_information {
11312 for info in infos {
11313 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11314 let range = range_from_lsp(info.location.range);
11315 diagnostics.push(DiagnosticEntry {
11316 range,
11317 diagnostic: Diagnostic {
11318 source: diagnostic.source.clone(),
11319 source_kind,
11320 code: diagnostic.code.clone(),
11321 code_description: diagnostic
11322 .code_description
11323 .as_ref()
11324 .and_then(|d| d.href.clone()),
11325 severity: DiagnosticSeverity::INFORMATION,
11326 markdown: adapter.as_ref().and_then(|adapter| {
11327 adapter.diagnostic_message_to_markdown(&info.message)
11328 }),
11329 message: info.message.trim().to_string(),
11330 group_id,
11331 is_primary: false,
11332 is_disk_based,
11333 is_unnecessary: false,
11334 underline,
11335 data: diagnostic.data.clone(),
11336 registration_id: registration_id.clone(),
11337 },
11338 });
11339 }
11340 }
11341 }
11342 }
11343 }
11344
11345 for entry in &mut diagnostics {
11346 let diagnostic = &mut entry.diagnostic;
11347 if !diagnostic.is_primary {
11348 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11349 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11350 source,
11351 diagnostic.code.clone(),
11352 entry.range.clone(),
11353 )) {
11354 if let Some(severity) = severity {
11355 diagnostic.severity = severity;
11356 }
11357 diagnostic.is_unnecessary = is_unnecessary;
11358 }
11359 }
11360 }
11361
11362 DocumentDiagnostics {
11363 diagnostics,
11364 document_abs_path,
11365 version: lsp_diagnostics.version,
11366 }
11367 }
11368
11369 fn insert_newly_running_language_server(
11370 &mut self,
11371 adapter: Arc<CachedLspAdapter>,
11372 language_server: Arc<LanguageServer>,
11373 server_id: LanguageServerId,
11374 key: LanguageServerSeed,
11375 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11376 cx: &mut Context<Self>,
11377 ) {
11378 let Some(local) = self.as_local_mut() else {
11379 return;
11380 };
11381 // If the language server for this key doesn't match the server id, don't store the
11382 // server. Which will cause it to be dropped, killing the process
11383 if local
11384 .language_server_ids
11385 .get(&key)
11386 .map(|state| state.id != server_id)
11387 .unwrap_or(false)
11388 {
11389 return;
11390 }
11391
11392 // Update language_servers collection with Running variant of LanguageServerState
11393 // indicating that the server is up and running and ready
11394 let workspace_folders = workspace_folders.lock().clone();
11395 language_server.set_workspace_folders(workspace_folders);
11396
11397 let workspace_diagnostics_refresh_tasks = language_server
11398 .capabilities()
11399 .diagnostic_provider
11400 .and_then(|provider| {
11401 local
11402 .language_server_dynamic_registrations
11403 .entry(server_id)
11404 .or_default()
11405 .diagnostics
11406 .entry(None)
11407 .or_insert(provider.clone());
11408 let workspace_refresher =
11409 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11410
11411 Some((None, workspace_refresher))
11412 })
11413 .into_iter()
11414 .collect();
11415 local.language_servers.insert(
11416 server_id,
11417 LanguageServerState::Running {
11418 workspace_diagnostics_refresh_tasks,
11419 adapter: adapter.clone(),
11420 server: language_server.clone(),
11421 simulate_disk_based_diagnostics_completion: None,
11422 },
11423 );
11424 local
11425 .languages
11426 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11427 if let Some(file_ops_caps) = language_server
11428 .capabilities()
11429 .workspace
11430 .as_ref()
11431 .and_then(|ws| ws.file_operations.as_ref())
11432 {
11433 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11434 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11435 if did_rename_caps.or(will_rename_caps).is_some() {
11436 let watcher = RenamePathsWatchedForServer::default()
11437 .with_did_rename_patterns(did_rename_caps)
11438 .with_will_rename_patterns(will_rename_caps);
11439 local
11440 .language_server_paths_watched_for_rename
11441 .insert(server_id, watcher);
11442 }
11443 }
11444
11445 self.language_server_statuses.insert(
11446 server_id,
11447 LanguageServerStatus {
11448 name: language_server.name(),
11449 pending_work: Default::default(),
11450 has_pending_diagnostic_updates: false,
11451 progress_tokens: Default::default(),
11452 worktree: Some(key.worktree_id),
11453 binary: Some(language_server.binary().clone()),
11454 configuration: Some(language_server.configuration().clone()),
11455 workspace_folders: language_server.workspace_folders(),
11456 },
11457 );
11458
11459 cx.emit(LspStoreEvent::LanguageServerAdded(
11460 server_id,
11461 language_server.name(),
11462 Some(key.worktree_id),
11463 ));
11464
11465 let server_capabilities = language_server.capabilities();
11466 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11467 downstream_client
11468 .send(proto::StartLanguageServer {
11469 project_id: *project_id,
11470 server: Some(proto::LanguageServer {
11471 id: server_id.to_proto(),
11472 name: language_server.name().to_string(),
11473 worktree_id: Some(key.worktree_id.to_proto()),
11474 }),
11475 capabilities: serde_json::to_string(&server_capabilities)
11476 .expect("serializing server LSP capabilities"),
11477 })
11478 .log_err();
11479 }
11480 self.lsp_server_capabilities
11481 .insert(server_id, server_capabilities);
11482
11483 // Tell the language server about every open buffer in the worktree that matches the language.
11484 // Also check for buffers in worktrees that reused this server
11485 let mut worktrees_using_server = vec![key.worktree_id];
11486 if let Some(local) = self.as_local() {
11487 // Find all worktrees that have this server in their language server tree
11488 for (worktree_id, servers) in &local.lsp_tree.instances {
11489 if *worktree_id != key.worktree_id {
11490 for server_map in servers.roots.values() {
11491 if server_map
11492 .values()
11493 .any(|(node, _)| node.id() == Some(server_id))
11494 {
11495 worktrees_using_server.push(*worktree_id);
11496 }
11497 }
11498 }
11499 }
11500 }
11501
11502 let mut buffer_paths_registered = Vec::new();
11503 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11504 let mut lsp_adapters = HashMap::default();
11505 for buffer_handle in buffer_store.buffers() {
11506 let buffer = buffer_handle.read(cx);
11507 let file = match File::from_dyn(buffer.file()) {
11508 Some(file) => file,
11509 None => continue,
11510 };
11511 let language = match buffer.language() {
11512 Some(language) => language,
11513 None => continue,
11514 };
11515
11516 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11517 || !lsp_adapters
11518 .entry(language.name())
11519 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11520 .iter()
11521 .any(|a| a.name == key.name)
11522 {
11523 continue;
11524 }
11525 // didOpen
11526 let file = match file.as_local() {
11527 Some(file) => file,
11528 None => continue,
11529 };
11530
11531 let local = self.as_local_mut().unwrap();
11532
11533 let buffer_id = buffer.remote_id();
11534 if local.registered_buffers.contains_key(&buffer_id) {
11535 let versions = local
11536 .buffer_snapshots
11537 .entry(buffer_id)
11538 .or_default()
11539 .entry(server_id)
11540 .and_modify(|_| {
11541 assert!(
11542 false,
11543 "There should not be an existing snapshot for a newly inserted buffer"
11544 )
11545 })
11546 .or_insert_with(|| {
11547 vec![LspBufferSnapshot {
11548 version: 0,
11549 snapshot: buffer.text_snapshot(),
11550 }]
11551 });
11552
11553 let snapshot = versions.last().unwrap();
11554 let version = snapshot.version;
11555 let initial_snapshot = &snapshot.snapshot;
11556 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11557 language_server.register_buffer(
11558 uri,
11559 adapter.language_id(&language.name()),
11560 version,
11561 initial_snapshot.text(),
11562 );
11563 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11564 local
11565 .buffers_opened_in_servers
11566 .entry(buffer_id)
11567 .or_default()
11568 .insert(server_id);
11569 }
11570 buffer_handle.update(cx, |buffer, cx| {
11571 buffer.set_completion_triggers(
11572 server_id,
11573 language_server
11574 .capabilities()
11575 .completion_provider
11576 .as_ref()
11577 .and_then(|provider| {
11578 provider
11579 .trigger_characters
11580 .as_ref()
11581 .map(|characters| characters.iter().cloned().collect())
11582 })
11583 .unwrap_or_default(),
11584 cx,
11585 )
11586 });
11587 }
11588 });
11589
11590 for (buffer_id, abs_path) in buffer_paths_registered {
11591 cx.emit(LspStoreEvent::LanguageServerUpdate {
11592 language_server_id: server_id,
11593 name: Some(adapter.name()),
11594 message: proto::update_language_server::Variant::RegisteredForBuffer(
11595 proto::RegisteredForBuffer {
11596 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11597 buffer_id: buffer_id.to_proto(),
11598 },
11599 ),
11600 });
11601 }
11602
11603 cx.notify();
11604 }
11605
11606 pub fn language_servers_running_disk_based_diagnostics(
11607 &self,
11608 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11609 self.language_server_statuses
11610 .iter()
11611 .filter_map(|(id, status)| {
11612 if status.has_pending_diagnostic_updates {
11613 Some(*id)
11614 } else {
11615 None
11616 }
11617 })
11618 }
11619
11620 pub(crate) fn cancel_language_server_work_for_buffers(
11621 &mut self,
11622 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11623 cx: &mut Context<Self>,
11624 ) {
11625 if let Some((client, project_id)) = self.upstream_client() {
11626 let request = client.request(proto::CancelLanguageServerWork {
11627 project_id,
11628 work: Some(proto::cancel_language_server_work::Work::Buffers(
11629 proto::cancel_language_server_work::Buffers {
11630 buffer_ids: buffers
11631 .into_iter()
11632 .map(|b| b.read(cx).remote_id().to_proto())
11633 .collect(),
11634 },
11635 )),
11636 });
11637 cx.background_spawn(request).detach_and_log_err(cx);
11638 } else if let Some(local) = self.as_local() {
11639 let servers = buffers
11640 .into_iter()
11641 .flat_map(|buffer| {
11642 buffer.update(cx, |buffer, cx| {
11643 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11644 })
11645 })
11646 .collect::<HashSet<_>>();
11647 for server_id in servers {
11648 self.cancel_language_server_work(server_id, None, cx);
11649 }
11650 }
11651 }
11652
11653 pub(crate) fn cancel_language_server_work(
11654 &mut self,
11655 server_id: LanguageServerId,
11656 token_to_cancel: Option<ProgressToken>,
11657 cx: &mut Context<Self>,
11658 ) {
11659 if let Some(local) = self.as_local() {
11660 let status = self.language_server_statuses.get(&server_id);
11661 let server = local.language_servers.get(&server_id);
11662 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11663 {
11664 for (token, progress) in &status.pending_work {
11665 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11666 && token != token_to_cancel
11667 {
11668 continue;
11669 }
11670 if progress.is_cancellable {
11671 server
11672 .notify::<lsp::notification::WorkDoneProgressCancel>(
11673 WorkDoneProgressCancelParams {
11674 token: token.to_lsp(),
11675 },
11676 )
11677 .ok();
11678 }
11679 }
11680 }
11681 } else if let Some((client, project_id)) = self.upstream_client() {
11682 let request = client.request(proto::CancelLanguageServerWork {
11683 project_id,
11684 work: Some(
11685 proto::cancel_language_server_work::Work::LanguageServerWork(
11686 proto::cancel_language_server_work::LanguageServerWork {
11687 language_server_id: server_id.to_proto(),
11688 token: token_to_cancel.map(|token| token.to_proto()),
11689 },
11690 ),
11691 ),
11692 });
11693 cx.background_spawn(request).detach_and_log_err(cx);
11694 }
11695 }
11696
11697 fn register_supplementary_language_server(
11698 &mut self,
11699 id: LanguageServerId,
11700 name: LanguageServerName,
11701 server: Arc<LanguageServer>,
11702 cx: &mut Context<Self>,
11703 ) {
11704 if let Some(local) = self.as_local_mut() {
11705 local
11706 .supplementary_language_servers
11707 .insert(id, (name.clone(), server));
11708 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11709 }
11710 }
11711
11712 fn unregister_supplementary_language_server(
11713 &mut self,
11714 id: LanguageServerId,
11715 cx: &mut Context<Self>,
11716 ) {
11717 if let Some(local) = self.as_local_mut() {
11718 local.supplementary_language_servers.remove(&id);
11719 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11720 }
11721 }
11722
11723 pub(crate) fn supplementary_language_servers(
11724 &self,
11725 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11726 self.as_local().into_iter().flat_map(|local| {
11727 local
11728 .supplementary_language_servers
11729 .iter()
11730 .map(|(id, (name, _))| (*id, name.clone()))
11731 })
11732 }
11733
11734 pub fn language_server_adapter_for_id(
11735 &self,
11736 id: LanguageServerId,
11737 ) -> Option<Arc<CachedLspAdapter>> {
11738 self.as_local()
11739 .and_then(|local| local.language_servers.get(&id))
11740 .and_then(|language_server_state| match language_server_state {
11741 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11742 _ => None,
11743 })
11744 }
11745
11746 pub(super) fn update_local_worktree_language_servers(
11747 &mut self,
11748 worktree_handle: &Entity<Worktree>,
11749 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11750 cx: &mut Context<Self>,
11751 ) {
11752 if changes.is_empty() {
11753 return;
11754 }
11755
11756 let Some(local) = self.as_local() else { return };
11757
11758 local.prettier_store.update(cx, |prettier_store, cx| {
11759 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11760 });
11761
11762 let worktree_id = worktree_handle.read(cx).id();
11763 let mut language_server_ids = local
11764 .language_server_ids
11765 .iter()
11766 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11767 .collect::<Vec<_>>();
11768 language_server_ids.sort();
11769 language_server_ids.dedup();
11770
11771 // let abs_path = worktree_handle.read(cx).abs_path();
11772 for server_id in &language_server_ids {
11773 if let Some(LanguageServerState::Running { server, .. }) =
11774 local.language_servers.get(server_id)
11775 && let Some(watched_paths) = local
11776 .language_server_watched_paths
11777 .get(server_id)
11778 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11779 {
11780 let params = lsp::DidChangeWatchedFilesParams {
11781 changes: changes
11782 .iter()
11783 .filter_map(|(path, _, change)| {
11784 if !watched_paths.is_match(path.as_std_path()) {
11785 return None;
11786 }
11787 let typ = match change {
11788 PathChange::Loaded => return None,
11789 PathChange::Added => lsp::FileChangeType::CREATED,
11790 PathChange::Removed => lsp::FileChangeType::DELETED,
11791 PathChange::Updated => lsp::FileChangeType::CHANGED,
11792 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11793 };
11794 let uri = lsp::Uri::from_file_path(
11795 worktree_handle.read(cx).absolutize(&path),
11796 )
11797 .ok()?;
11798 Some(lsp::FileEvent { uri, typ })
11799 })
11800 .collect(),
11801 };
11802 if !params.changes.is_empty() {
11803 server
11804 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11805 .ok();
11806 }
11807 }
11808 }
11809 for (path, _, _) in changes {
11810 if let Some(file_name) = path.file_name()
11811 && local.watched_manifest_filenames.contains(file_name)
11812 {
11813 self.request_workspace_config_refresh();
11814 break;
11815 }
11816 }
11817 }
11818
11819 pub fn wait_for_remote_buffer(
11820 &mut self,
11821 id: BufferId,
11822 cx: &mut Context<Self>,
11823 ) -> Task<Result<Entity<Buffer>>> {
11824 self.buffer_store.update(cx, |buffer_store, cx| {
11825 buffer_store.wait_for_remote_buffer(id, cx)
11826 })
11827 }
11828
11829 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11830 let mut result = proto::Symbol {
11831 language_server_name: symbol.language_server_name.0.to_string(),
11832 source_worktree_id: symbol.source_worktree_id.to_proto(),
11833 language_server_id: symbol.source_language_server_id.to_proto(),
11834 name: symbol.name.clone(),
11835 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11836 start: Some(proto::PointUtf16 {
11837 row: symbol.range.start.0.row,
11838 column: symbol.range.start.0.column,
11839 }),
11840 end: Some(proto::PointUtf16 {
11841 row: symbol.range.end.0.row,
11842 column: symbol.range.end.0.column,
11843 }),
11844 worktree_id: Default::default(),
11845 path: Default::default(),
11846 signature: Default::default(),
11847 };
11848 match &symbol.path {
11849 SymbolLocation::InProject(path) => {
11850 result.worktree_id = path.worktree_id.to_proto();
11851 result.path = path.path.to_proto();
11852 }
11853 SymbolLocation::OutsideProject {
11854 abs_path,
11855 signature,
11856 } => {
11857 result.path = abs_path.to_string_lossy().into_owned();
11858 result.signature = signature.to_vec();
11859 }
11860 }
11861 result
11862 }
11863
11864 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11865 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11866 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11867 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11868
11869 let path = if serialized_symbol.signature.is_empty() {
11870 SymbolLocation::InProject(ProjectPath {
11871 worktree_id,
11872 path: RelPath::from_proto(&serialized_symbol.path)
11873 .context("invalid symbol path")?,
11874 })
11875 } else {
11876 SymbolLocation::OutsideProject {
11877 abs_path: Path::new(&serialized_symbol.path).into(),
11878 signature: serialized_symbol
11879 .signature
11880 .try_into()
11881 .map_err(|_| anyhow!("invalid signature"))?,
11882 }
11883 };
11884
11885 let start = serialized_symbol.start.context("invalid start")?;
11886 let end = serialized_symbol.end.context("invalid end")?;
11887 Ok(CoreSymbol {
11888 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11889 source_worktree_id,
11890 source_language_server_id: LanguageServerId::from_proto(
11891 serialized_symbol.language_server_id,
11892 ),
11893 path,
11894 name: serialized_symbol.name,
11895 range: Unclipped(PointUtf16::new(start.row, start.column))
11896 ..Unclipped(PointUtf16::new(end.row, end.column)),
11897 kind,
11898 })
11899 }
11900
11901 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11902 let mut serialized_completion = proto::Completion {
11903 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11904 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11905 new_text: completion.new_text.clone(),
11906 ..proto::Completion::default()
11907 };
11908 match &completion.source {
11909 CompletionSource::Lsp {
11910 insert_range,
11911 server_id,
11912 lsp_completion,
11913 lsp_defaults,
11914 resolved,
11915 } => {
11916 let (old_insert_start, old_insert_end) = insert_range
11917 .as_ref()
11918 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11919 .unzip();
11920
11921 serialized_completion.old_insert_start = old_insert_start;
11922 serialized_completion.old_insert_end = old_insert_end;
11923 serialized_completion.source = proto::completion::Source::Lsp as i32;
11924 serialized_completion.server_id = server_id.0 as u64;
11925 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11926 serialized_completion.lsp_defaults = lsp_defaults
11927 .as_deref()
11928 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11929 serialized_completion.resolved = *resolved;
11930 }
11931 CompletionSource::BufferWord {
11932 word_range,
11933 resolved,
11934 } => {
11935 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11936 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11937 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11938 serialized_completion.resolved = *resolved;
11939 }
11940 CompletionSource::Custom => {
11941 serialized_completion.source = proto::completion::Source::Custom as i32;
11942 serialized_completion.resolved = true;
11943 }
11944 CompletionSource::Dap { sort_text } => {
11945 serialized_completion.source = proto::completion::Source::Dap as i32;
11946 serialized_completion.sort_text = Some(sort_text.clone());
11947 }
11948 }
11949
11950 serialized_completion
11951 }
11952
11953 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11954 let old_replace_start = completion
11955 .old_replace_start
11956 .and_then(deserialize_anchor)
11957 .context("invalid old start")?;
11958 let old_replace_end = completion
11959 .old_replace_end
11960 .and_then(deserialize_anchor)
11961 .context("invalid old end")?;
11962 let insert_range = {
11963 match completion.old_insert_start.zip(completion.old_insert_end) {
11964 Some((start, end)) => {
11965 let start = deserialize_anchor(start).context("invalid insert old start")?;
11966 let end = deserialize_anchor(end).context("invalid insert old end")?;
11967 Some(start..end)
11968 }
11969 None => None,
11970 }
11971 };
11972 Ok(CoreCompletion {
11973 replace_range: old_replace_start..old_replace_end,
11974 new_text: completion.new_text,
11975 source: match proto::completion::Source::from_i32(completion.source) {
11976 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11977 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11978 insert_range,
11979 server_id: LanguageServerId::from_proto(completion.server_id),
11980 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11981 lsp_defaults: completion
11982 .lsp_defaults
11983 .as_deref()
11984 .map(serde_json::from_slice)
11985 .transpose()?,
11986 resolved: completion.resolved,
11987 },
11988 Some(proto::completion::Source::BufferWord) => {
11989 let word_range = completion
11990 .buffer_word_start
11991 .and_then(deserialize_anchor)
11992 .context("invalid buffer word start")?
11993 ..completion
11994 .buffer_word_end
11995 .and_then(deserialize_anchor)
11996 .context("invalid buffer word end")?;
11997 CompletionSource::BufferWord {
11998 word_range,
11999 resolved: completion.resolved,
12000 }
12001 }
12002 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12003 sort_text: completion
12004 .sort_text
12005 .context("expected sort text to exist")?,
12006 },
12007 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12008 },
12009 })
12010 }
12011
12012 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12013 let (kind, lsp_action) = match &action.lsp_action {
12014 LspAction::Action(code_action) => (
12015 proto::code_action::Kind::Action as i32,
12016 serde_json::to_vec(code_action).unwrap(),
12017 ),
12018 LspAction::Command(command) => (
12019 proto::code_action::Kind::Command as i32,
12020 serde_json::to_vec(command).unwrap(),
12021 ),
12022 LspAction::CodeLens(code_lens) => (
12023 proto::code_action::Kind::CodeLens as i32,
12024 serde_json::to_vec(code_lens).unwrap(),
12025 ),
12026 };
12027
12028 proto::CodeAction {
12029 server_id: action.server_id.0 as u64,
12030 start: Some(serialize_anchor(&action.range.start)),
12031 end: Some(serialize_anchor(&action.range.end)),
12032 lsp_action,
12033 kind,
12034 resolved: action.resolved,
12035 }
12036 }
12037
12038 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12039 let start = action
12040 .start
12041 .and_then(deserialize_anchor)
12042 .context("invalid start")?;
12043 let end = action
12044 .end
12045 .and_then(deserialize_anchor)
12046 .context("invalid end")?;
12047 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12048 Some(proto::code_action::Kind::Action) => {
12049 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12050 }
12051 Some(proto::code_action::Kind::Command) => {
12052 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12053 }
12054 Some(proto::code_action::Kind::CodeLens) => {
12055 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12056 }
12057 None => anyhow::bail!("Unknown action kind {}", action.kind),
12058 };
12059 Ok(CodeAction {
12060 server_id: LanguageServerId(action.server_id as usize),
12061 range: start..end,
12062 resolved: action.resolved,
12063 lsp_action,
12064 })
12065 }
12066
12067 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12068 match &formatting_result {
12069 Ok(_) => self.last_formatting_failure = None,
12070 Err(error) => {
12071 let error_string = format!("{error:#}");
12072 log::error!("Formatting failed: {error_string}");
12073 self.last_formatting_failure
12074 .replace(error_string.lines().join(" "));
12075 }
12076 }
12077 }
12078
12079 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12080 self.lsp_server_capabilities.remove(&for_server);
12081 for lsp_data in self.lsp_data.values_mut() {
12082 lsp_data.remove_server_data(for_server);
12083 }
12084 if let Some(local) = self.as_local_mut() {
12085 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12086 local
12087 .workspace_pull_diagnostics_result_ids
12088 .remove(&for_server);
12089 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12090 buffer_servers.remove(&for_server);
12091 }
12092 }
12093 }
12094
12095 pub fn result_id_for_buffer_pull(
12096 &self,
12097 server_id: LanguageServerId,
12098 buffer_id: BufferId,
12099 registration_id: &Option<SharedString>,
12100 cx: &App,
12101 ) -> Option<SharedString> {
12102 let abs_path = self
12103 .buffer_store
12104 .read(cx)
12105 .get(buffer_id)
12106 .and_then(|b| File::from_dyn(b.read(cx).file()))
12107 .map(|f| f.abs_path(cx))?;
12108 self.as_local()?
12109 .buffer_pull_diagnostics_result_ids
12110 .get(&server_id)?
12111 .get(registration_id)?
12112 .get(&abs_path)?
12113 .clone()
12114 }
12115
12116 /// Gets all result_ids for a workspace diagnostics pull request.
12117 /// First, it tries to find buffer's result_id retrieved via the diagnostics pull; if it fails, it falls back to the workspace disagnostics pull result_id.
12118 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12119 pub fn result_ids_for_workspace_refresh(
12120 &self,
12121 server_id: LanguageServerId,
12122 registration_id: &Option<SharedString>,
12123 ) -> HashMap<PathBuf, SharedString> {
12124 let Some(local) = self.as_local() else {
12125 return HashMap::default();
12126 };
12127 local
12128 .workspace_pull_diagnostics_result_ids
12129 .get(&server_id)
12130 .into_iter()
12131 .filter_map(|diagnostics| diagnostics.get(registration_id))
12132 .flatten()
12133 .filter_map(|(abs_path, result_id)| {
12134 let result_id = local
12135 .buffer_pull_diagnostics_result_ids
12136 .get(&server_id)
12137 .and_then(|buffer_ids_result_ids| {
12138 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12139 })
12140 .cloned()
12141 .flatten()
12142 .or_else(|| result_id.clone())?;
12143 Some((abs_path.clone(), result_id))
12144 })
12145 .collect()
12146 }
12147
12148 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12149 if let Some(LanguageServerState::Running {
12150 workspace_diagnostics_refresh_tasks,
12151 ..
12152 }) = self
12153 .as_local_mut()
12154 .and_then(|local| local.language_servers.get_mut(&server_id))
12155 {
12156 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12157 diagnostics.refresh_tx.try_send(()).ok();
12158 }
12159 }
12160 }
12161
12162 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12163 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12164 return;
12165 };
12166 let Some(local) = self.as_local_mut() else {
12167 return;
12168 };
12169
12170 for server_id in buffer.update(cx, |buffer, cx| {
12171 local.language_server_ids_for_buffer(buffer, cx)
12172 }) {
12173 if let Some(LanguageServerState::Running {
12174 workspace_diagnostics_refresh_tasks,
12175 ..
12176 }) = local.language_servers.get_mut(&server_id)
12177 {
12178 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12179 diagnostics.refresh_tx.try_send(()).ok();
12180 }
12181 }
12182 }
12183 }
12184
12185 fn apply_workspace_diagnostic_report(
12186 &mut self,
12187 server_id: LanguageServerId,
12188 report: lsp::WorkspaceDiagnosticReportResult,
12189 registration_id: Option<SharedString>,
12190 cx: &mut Context<Self>,
12191 ) {
12192 let mut workspace_diagnostics =
12193 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12194 report,
12195 server_id,
12196 registration_id,
12197 );
12198 workspace_diagnostics.retain(|d| match &d.diagnostics {
12199 LspPullDiagnostics::Response {
12200 server_id,
12201 registration_id,
12202 ..
12203 } => self.diagnostic_registration_exists(*server_id, registration_id),
12204 LspPullDiagnostics::Default => false,
12205 });
12206 let mut unchanged_buffers = HashMap::default();
12207 let workspace_diagnostics_updates = workspace_diagnostics
12208 .into_iter()
12209 .filter_map(
12210 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12211 LspPullDiagnostics::Response {
12212 server_id,
12213 uri,
12214 diagnostics,
12215 registration_id,
12216 } => Some((
12217 server_id,
12218 uri,
12219 diagnostics,
12220 workspace_diagnostics.version,
12221 registration_id,
12222 )),
12223 LspPullDiagnostics::Default => None,
12224 },
12225 )
12226 .fold(
12227 HashMap::default(),
12228 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12229 let (result_id, diagnostics) = match diagnostics {
12230 PulledDiagnostics::Unchanged { result_id } => {
12231 unchanged_buffers
12232 .entry(new_registration_id.clone())
12233 .or_insert_with(HashSet::default)
12234 .insert(uri.clone());
12235 (Some(result_id), Vec::new())
12236 }
12237 PulledDiagnostics::Changed {
12238 result_id,
12239 diagnostics,
12240 } => (result_id, diagnostics),
12241 };
12242 let disk_based_sources = Cow::Owned(
12243 self.language_server_adapter_for_id(server_id)
12244 .as_ref()
12245 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12246 .unwrap_or(&[])
12247 .to_vec(),
12248 );
12249
12250 let Some(abs_path) = uri.to_file_path().ok() else {
12251 return acc;
12252 };
12253 let Some((worktree, relative_path)) =
12254 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12255 else {
12256 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12257 return acc;
12258 };
12259 let worktree_id = worktree.read(cx).id();
12260 let project_path = ProjectPath {
12261 worktree_id,
12262 path: relative_path,
12263 };
12264 if let Some(local_lsp_store) = self.as_local_mut() {
12265 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12266 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12267 }
12268 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12269 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12270 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12271 acc.entry(server_id)
12272 .or_insert_with(HashMap::default)
12273 .entry(new_registration_id.clone())
12274 .or_insert_with(Vec::new)
12275 .push(DocumentDiagnosticsUpdate {
12276 server_id,
12277 diagnostics: lsp::PublishDiagnosticsParams {
12278 uri,
12279 diagnostics,
12280 version,
12281 },
12282 result_id,
12283 disk_based_sources,
12284 registration_id: new_registration_id,
12285 });
12286 }
12287 acc
12288 },
12289 );
12290
12291 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12292 for (registration_id, diagnostic_updates) in diagnostic_updates {
12293 self.merge_lsp_diagnostics(
12294 DiagnosticSourceKind::Pulled,
12295 diagnostic_updates,
12296 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12297 DiagnosticSourceKind::Pulled => {
12298 old_diagnostic.registration_id != registration_id
12299 || unchanged_buffers
12300 .get(&old_diagnostic.registration_id)
12301 .is_some_and(|unchanged_buffers| {
12302 unchanged_buffers.contains(&document_uri)
12303 })
12304 }
12305 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12306 },
12307 cx,
12308 )
12309 .log_err();
12310 }
12311 }
12312 }
12313
12314 fn register_server_capabilities(
12315 &mut self,
12316 server_id: LanguageServerId,
12317 params: lsp::RegistrationParams,
12318 cx: &mut Context<Self>,
12319 ) -> anyhow::Result<()> {
12320 let server = self
12321 .language_server_for_id(server_id)
12322 .with_context(|| format!("no server {server_id} found"))?;
12323 for reg in params.registrations {
12324 match reg.method.as_str() {
12325 "workspace/didChangeWatchedFiles" => {
12326 if let Some(options) = reg.register_options {
12327 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12328 let caps = serde_json::from_value(options)?;
12329 local_lsp_store
12330 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12331 true
12332 } else {
12333 false
12334 };
12335 if notify {
12336 notify_server_capabilities_updated(&server, cx);
12337 }
12338 }
12339 }
12340 "workspace/didChangeConfiguration" => {
12341 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12342 }
12343 "workspace/didChangeWorkspaceFolders" => {
12344 // In this case register options is an empty object, we can ignore it
12345 let caps = lsp::WorkspaceFoldersServerCapabilities {
12346 supported: Some(true),
12347 change_notifications: Some(OneOf::Right(reg.id)),
12348 };
12349 server.update_capabilities(|capabilities| {
12350 capabilities
12351 .workspace
12352 .get_or_insert_default()
12353 .workspace_folders = Some(caps);
12354 });
12355 notify_server_capabilities_updated(&server, cx);
12356 }
12357 "workspace/symbol" => {
12358 let options = parse_register_capabilities(reg)?;
12359 server.update_capabilities(|capabilities| {
12360 capabilities.workspace_symbol_provider = Some(options);
12361 });
12362 notify_server_capabilities_updated(&server, cx);
12363 }
12364 "workspace/fileOperations" => {
12365 if let Some(options) = reg.register_options {
12366 let caps = serde_json::from_value(options)?;
12367 server.update_capabilities(|capabilities| {
12368 capabilities
12369 .workspace
12370 .get_or_insert_default()
12371 .file_operations = Some(caps);
12372 });
12373 notify_server_capabilities_updated(&server, cx);
12374 }
12375 }
12376 "workspace/executeCommand" => {
12377 if let Some(options) = reg.register_options {
12378 let options = serde_json::from_value(options)?;
12379 server.update_capabilities(|capabilities| {
12380 capabilities.execute_command_provider = Some(options);
12381 });
12382 notify_server_capabilities_updated(&server, cx);
12383 }
12384 }
12385 "textDocument/rangeFormatting" => {
12386 let options = parse_register_capabilities(reg)?;
12387 server.update_capabilities(|capabilities| {
12388 capabilities.document_range_formatting_provider = Some(options);
12389 });
12390 notify_server_capabilities_updated(&server, cx);
12391 }
12392 "textDocument/onTypeFormatting" => {
12393 if let Some(options) = reg
12394 .register_options
12395 .map(serde_json::from_value)
12396 .transpose()?
12397 {
12398 server.update_capabilities(|capabilities| {
12399 capabilities.document_on_type_formatting_provider = Some(options);
12400 });
12401 notify_server_capabilities_updated(&server, cx);
12402 }
12403 }
12404 "textDocument/formatting" => {
12405 let options = parse_register_capabilities(reg)?;
12406 server.update_capabilities(|capabilities| {
12407 capabilities.document_formatting_provider = Some(options);
12408 });
12409 notify_server_capabilities_updated(&server, cx);
12410 }
12411 "textDocument/rename" => {
12412 let options = parse_register_capabilities(reg)?;
12413 server.update_capabilities(|capabilities| {
12414 capabilities.rename_provider = Some(options);
12415 });
12416 notify_server_capabilities_updated(&server, cx);
12417 }
12418 "textDocument/inlayHint" => {
12419 let options = parse_register_capabilities(reg)?;
12420 server.update_capabilities(|capabilities| {
12421 capabilities.inlay_hint_provider = Some(options);
12422 });
12423 notify_server_capabilities_updated(&server, cx);
12424 }
12425 "textDocument/documentSymbol" => {
12426 let options = parse_register_capabilities(reg)?;
12427 server.update_capabilities(|capabilities| {
12428 capabilities.document_symbol_provider = Some(options);
12429 });
12430 notify_server_capabilities_updated(&server, cx);
12431 }
12432 "textDocument/codeAction" => {
12433 let options = parse_register_capabilities(reg)?;
12434 let provider = match options {
12435 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12436 OneOf::Right(caps) => caps,
12437 };
12438 server.update_capabilities(|capabilities| {
12439 capabilities.code_action_provider = Some(provider);
12440 });
12441 notify_server_capabilities_updated(&server, cx);
12442 }
12443 "textDocument/definition" => {
12444 let options = parse_register_capabilities(reg)?;
12445 server.update_capabilities(|capabilities| {
12446 capabilities.definition_provider = Some(options);
12447 });
12448 notify_server_capabilities_updated(&server, cx);
12449 }
12450 "textDocument/completion" => {
12451 if let Some(caps) = reg
12452 .register_options
12453 .map(serde_json::from_value::<CompletionOptions>)
12454 .transpose()?
12455 {
12456 server.update_capabilities(|capabilities| {
12457 capabilities.completion_provider = Some(caps.clone());
12458 });
12459
12460 if let Some(local) = self.as_local() {
12461 let mut buffers_with_language_server = Vec::new();
12462 for handle in self.buffer_store.read(cx).buffers() {
12463 let buffer_id = handle.read(cx).remote_id();
12464 if local
12465 .buffers_opened_in_servers
12466 .get(&buffer_id)
12467 .filter(|s| s.contains(&server_id))
12468 .is_some()
12469 {
12470 buffers_with_language_server.push(handle);
12471 }
12472 }
12473 let triggers = caps
12474 .trigger_characters
12475 .unwrap_or_default()
12476 .into_iter()
12477 .collect::<BTreeSet<_>>();
12478 for handle in buffers_with_language_server {
12479 let triggers = triggers.clone();
12480 let _ = handle.update(cx, move |buffer, cx| {
12481 buffer.set_completion_triggers(server_id, triggers, cx);
12482 });
12483 }
12484 }
12485 notify_server_capabilities_updated(&server, cx);
12486 }
12487 }
12488 "textDocument/hover" => {
12489 let options = parse_register_capabilities(reg)?;
12490 let provider = match options {
12491 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12492 OneOf::Right(caps) => caps,
12493 };
12494 server.update_capabilities(|capabilities| {
12495 capabilities.hover_provider = Some(provider);
12496 });
12497 notify_server_capabilities_updated(&server, cx);
12498 }
12499 "textDocument/signatureHelp" => {
12500 if let Some(caps) = reg
12501 .register_options
12502 .map(serde_json::from_value)
12503 .transpose()?
12504 {
12505 server.update_capabilities(|capabilities| {
12506 capabilities.signature_help_provider = Some(caps);
12507 });
12508 notify_server_capabilities_updated(&server, cx);
12509 }
12510 }
12511 "textDocument/didChange" => {
12512 if let Some(sync_kind) = reg
12513 .register_options
12514 .and_then(|opts| opts.get("syncKind").cloned())
12515 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12516 .transpose()?
12517 {
12518 server.update_capabilities(|capabilities| {
12519 let mut sync_options =
12520 Self::take_text_document_sync_options(capabilities);
12521 sync_options.change = Some(sync_kind);
12522 capabilities.text_document_sync =
12523 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12524 });
12525 notify_server_capabilities_updated(&server, cx);
12526 }
12527 }
12528 "textDocument/didSave" => {
12529 if let Some(include_text) = reg
12530 .register_options
12531 .map(|opts| {
12532 let transpose = opts
12533 .get("includeText")
12534 .cloned()
12535 .map(serde_json::from_value::<Option<bool>>)
12536 .transpose();
12537 match transpose {
12538 Ok(value) => Ok(value.flatten()),
12539 Err(e) => Err(e),
12540 }
12541 })
12542 .transpose()?
12543 {
12544 server.update_capabilities(|capabilities| {
12545 let mut sync_options =
12546 Self::take_text_document_sync_options(capabilities);
12547 sync_options.save =
12548 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12549 include_text,
12550 }));
12551 capabilities.text_document_sync =
12552 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12553 });
12554 notify_server_capabilities_updated(&server, cx);
12555 }
12556 }
12557 "textDocument/codeLens" => {
12558 if let Some(caps) = reg
12559 .register_options
12560 .map(serde_json::from_value)
12561 .transpose()?
12562 {
12563 server.update_capabilities(|capabilities| {
12564 capabilities.code_lens_provider = Some(caps);
12565 });
12566 notify_server_capabilities_updated(&server, cx);
12567 }
12568 }
12569 "textDocument/diagnostic" => {
12570 if let Some(caps) = reg
12571 .register_options
12572 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12573 .transpose()?
12574 {
12575 let local = self
12576 .as_local_mut()
12577 .context("Expected LSP Store to be local")?;
12578 let state = local
12579 .language_servers
12580 .get_mut(&server_id)
12581 .context("Could not obtain Language Servers state")?;
12582 local
12583 .language_server_dynamic_registrations
12584 .entry(server_id)
12585 .or_default()
12586 .diagnostics
12587 .insert(Some(reg.id.clone()), caps.clone());
12588
12589 let supports_workspace_diagnostics =
12590 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12591 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12592 diagnostic_options.workspace_diagnostics
12593 }
12594 DiagnosticServerCapabilities::RegistrationOptions(
12595 diagnostic_registration_options,
12596 ) => {
12597 diagnostic_registration_options
12598 .diagnostic_options
12599 .workspace_diagnostics
12600 }
12601 };
12602
12603 if supports_workspace_diagnostics(&caps) {
12604 if let LanguageServerState::Running {
12605 workspace_diagnostics_refresh_tasks,
12606 ..
12607 } = state
12608 && let Some(task) = lsp_workspace_diagnostics_refresh(
12609 Some(reg.id.clone()),
12610 caps.clone(),
12611 server.clone(),
12612 cx,
12613 )
12614 {
12615 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12616 }
12617 }
12618
12619 server.update_capabilities(|capabilities| {
12620 capabilities.diagnostic_provider = Some(caps);
12621 });
12622
12623 notify_server_capabilities_updated(&server, cx);
12624
12625 let buffers_to_pull: Vec<_> = self
12626 .as_local()
12627 .into_iter()
12628 .flat_map(|local| {
12629 self.buffer_store.read(cx).buffers().filter(|buffer| {
12630 let buffer_id = buffer.read(cx).remote_id();
12631 local
12632 .buffers_opened_in_servers
12633 .get(&buffer_id)
12634 .is_some_and(|servers| servers.contains(&server_id))
12635 })
12636 })
12637 .collect();
12638 for buffer in buffers_to_pull {
12639 self.pull_diagnostics_for_buffer(buffer, cx).detach();
12640 }
12641 }
12642 }
12643 "textDocument/documentColor" => {
12644 let options = parse_register_capabilities(reg)?;
12645 let provider = match options {
12646 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12647 OneOf::Right(caps) => caps,
12648 };
12649 server.update_capabilities(|capabilities| {
12650 capabilities.color_provider = Some(provider);
12651 });
12652 notify_server_capabilities_updated(&server, cx);
12653 }
12654 _ => log::warn!("unhandled capability registration: {reg:?}"),
12655 }
12656 }
12657
12658 Ok(())
12659 }
12660
12661 fn unregister_server_capabilities(
12662 &mut self,
12663 server_id: LanguageServerId,
12664 params: lsp::UnregistrationParams,
12665 cx: &mut Context<Self>,
12666 ) -> anyhow::Result<()> {
12667 let server = self
12668 .language_server_for_id(server_id)
12669 .with_context(|| format!("no server {server_id} found"))?;
12670 for unreg in params.unregisterations.iter() {
12671 match unreg.method.as_str() {
12672 "workspace/didChangeWatchedFiles" => {
12673 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12674 local_lsp_store
12675 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12676 true
12677 } else {
12678 false
12679 };
12680 if notify {
12681 notify_server_capabilities_updated(&server, cx);
12682 }
12683 }
12684 "workspace/didChangeConfiguration" => {
12685 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12686 }
12687 "workspace/didChangeWorkspaceFolders" => {
12688 server.update_capabilities(|capabilities| {
12689 capabilities
12690 .workspace
12691 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12692 workspace_folders: None,
12693 file_operations: None,
12694 })
12695 .workspace_folders = None;
12696 });
12697 notify_server_capabilities_updated(&server, cx);
12698 }
12699 "workspace/symbol" => {
12700 server.update_capabilities(|capabilities| {
12701 capabilities.workspace_symbol_provider = None
12702 });
12703 notify_server_capabilities_updated(&server, cx);
12704 }
12705 "workspace/fileOperations" => {
12706 server.update_capabilities(|capabilities| {
12707 capabilities
12708 .workspace
12709 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12710 workspace_folders: None,
12711 file_operations: None,
12712 })
12713 .file_operations = None;
12714 });
12715 notify_server_capabilities_updated(&server, cx);
12716 }
12717 "workspace/executeCommand" => {
12718 server.update_capabilities(|capabilities| {
12719 capabilities.execute_command_provider = None;
12720 });
12721 notify_server_capabilities_updated(&server, cx);
12722 }
12723 "textDocument/rangeFormatting" => {
12724 server.update_capabilities(|capabilities| {
12725 capabilities.document_range_formatting_provider = None
12726 });
12727 notify_server_capabilities_updated(&server, cx);
12728 }
12729 "textDocument/onTypeFormatting" => {
12730 server.update_capabilities(|capabilities| {
12731 capabilities.document_on_type_formatting_provider = None;
12732 });
12733 notify_server_capabilities_updated(&server, cx);
12734 }
12735 "textDocument/formatting" => {
12736 server.update_capabilities(|capabilities| {
12737 capabilities.document_formatting_provider = None;
12738 });
12739 notify_server_capabilities_updated(&server, cx);
12740 }
12741 "textDocument/rename" => {
12742 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12743 notify_server_capabilities_updated(&server, cx);
12744 }
12745 "textDocument/codeAction" => {
12746 server.update_capabilities(|capabilities| {
12747 capabilities.code_action_provider = None;
12748 });
12749 notify_server_capabilities_updated(&server, cx);
12750 }
12751 "textDocument/definition" => {
12752 server.update_capabilities(|capabilities| {
12753 capabilities.definition_provider = None;
12754 });
12755 notify_server_capabilities_updated(&server, cx);
12756 }
12757 "textDocument/completion" => {
12758 server.update_capabilities(|capabilities| {
12759 capabilities.completion_provider = None;
12760 });
12761 notify_server_capabilities_updated(&server, cx);
12762 }
12763 "textDocument/hover" => {
12764 server.update_capabilities(|capabilities| {
12765 capabilities.hover_provider = None;
12766 });
12767 notify_server_capabilities_updated(&server, cx);
12768 }
12769 "textDocument/signatureHelp" => {
12770 server.update_capabilities(|capabilities| {
12771 capabilities.signature_help_provider = None;
12772 });
12773 notify_server_capabilities_updated(&server, cx);
12774 }
12775 "textDocument/didChange" => {
12776 server.update_capabilities(|capabilities| {
12777 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12778 sync_options.change = None;
12779 capabilities.text_document_sync =
12780 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12781 });
12782 notify_server_capabilities_updated(&server, cx);
12783 }
12784 "textDocument/didSave" => {
12785 server.update_capabilities(|capabilities| {
12786 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12787 sync_options.save = None;
12788 capabilities.text_document_sync =
12789 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12790 });
12791 notify_server_capabilities_updated(&server, cx);
12792 }
12793 "textDocument/codeLens" => {
12794 server.update_capabilities(|capabilities| {
12795 capabilities.code_lens_provider = None;
12796 });
12797 notify_server_capabilities_updated(&server, cx);
12798 }
12799 "textDocument/diagnostic" => {
12800 let local = self
12801 .as_local_mut()
12802 .context("Expected LSP Store to be local")?;
12803
12804 let state = local
12805 .language_servers
12806 .get_mut(&server_id)
12807 .context("Could not obtain Language Servers state")?;
12808 let registrations = local
12809 .language_server_dynamic_registrations
12810 .get_mut(&server_id)
12811 .with_context(|| {
12812 format!("Expected dynamic registration to exist for server {server_id}")
12813 })?;
12814 registrations.diagnostics
12815 .remove(&Some(unreg.id.clone()))
12816 .with_context(|| format!(
12817 "Attempted to unregister non-existent diagnostic registration with ID {}",
12818 unreg.id)
12819 )?;
12820 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12821
12822 if let LanguageServerState::Running {
12823 workspace_diagnostics_refresh_tasks,
12824 ..
12825 } = state
12826 {
12827 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12828 }
12829
12830 self.clear_unregistered_diagnostics(
12831 server_id,
12832 SharedString::from(unreg.id.clone()),
12833 cx,
12834 )?;
12835
12836 if removed_last_diagnostic_provider {
12837 server.update_capabilities(|capabilities| {
12838 debug_assert!(capabilities.diagnostic_provider.is_some());
12839 capabilities.diagnostic_provider = None;
12840 });
12841 }
12842
12843 notify_server_capabilities_updated(&server, cx);
12844 }
12845 "textDocument/documentColor" => {
12846 server.update_capabilities(|capabilities| {
12847 capabilities.color_provider = None;
12848 });
12849 notify_server_capabilities_updated(&server, cx);
12850 }
12851 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12852 }
12853 }
12854
12855 Ok(())
12856 }
12857
12858 fn clear_unregistered_diagnostics(
12859 &mut self,
12860 server_id: LanguageServerId,
12861 cleared_registration_id: SharedString,
12862 cx: &mut Context<Self>,
12863 ) -> anyhow::Result<()> {
12864 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12865
12866 self.buffer_store.update(cx, |buffer_store, cx| {
12867 for buffer_handle in buffer_store.buffers() {
12868 let buffer = buffer_handle.read(cx);
12869 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12870 let Some(abs_path) = abs_path else {
12871 continue;
12872 };
12873 affected_abs_paths.insert(abs_path);
12874 }
12875 });
12876
12877 let local = self.as_local().context("Expected LSP Store to be local")?;
12878 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12879 let Some(worktree) = self
12880 .worktree_store
12881 .read(cx)
12882 .worktree_for_id(*worktree_id, cx)
12883 else {
12884 continue;
12885 };
12886
12887 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12888 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12889 let has_matching_registration =
12890 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12891 entry.diagnostic.registration_id.as_ref()
12892 == Some(&cleared_registration_id)
12893 });
12894 if has_matching_registration {
12895 let abs_path = worktree.read(cx).absolutize(rel_path);
12896 affected_abs_paths.insert(abs_path);
12897 }
12898 }
12899 }
12900 }
12901
12902 if affected_abs_paths.is_empty() {
12903 return Ok(());
12904 }
12905
12906 // Send a fake diagnostic update which clears the state for the registration ID
12907 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12908 affected_abs_paths
12909 .into_iter()
12910 .map(|abs_path| DocumentDiagnosticsUpdate {
12911 diagnostics: DocumentDiagnostics {
12912 diagnostics: Vec::new(),
12913 document_abs_path: abs_path,
12914 version: None,
12915 },
12916 result_id: None,
12917 registration_id: Some(cleared_registration_id.clone()),
12918 server_id,
12919 disk_based_sources: Cow::Borrowed(&[]),
12920 })
12921 .collect();
12922
12923 let merge_registration_id = cleared_registration_id.clone();
12924 self.merge_diagnostic_entries(
12925 clears,
12926 move |_, diagnostic, _| {
12927 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12928 diagnostic.registration_id != Some(merge_registration_id.clone())
12929 } else {
12930 true
12931 }
12932 },
12933 cx,
12934 )?;
12935
12936 Ok(())
12937 }
12938
12939 async fn deduplicate_range_based_lsp_requests<T>(
12940 lsp_store: &Entity<Self>,
12941 server_id: Option<LanguageServerId>,
12942 lsp_request_id: LspRequestId,
12943 proto_request: &T::ProtoRequest,
12944 range: Range<Anchor>,
12945 cx: &mut AsyncApp,
12946 ) -> Result<()>
12947 where
12948 T: LspCommand,
12949 T::ProtoRequest: proto::LspRequestMessage,
12950 {
12951 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12952 let version = deserialize_version(proto_request.buffer_version());
12953 let buffer = lsp_store.update(cx, |this, cx| {
12954 this.buffer_store.read(cx).get_existing(buffer_id)
12955 })??;
12956 buffer
12957 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12958 .await?;
12959 lsp_store.update(cx, |lsp_store, cx| {
12960 let buffer_snapshot = buffer.read(cx).snapshot();
12961 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12962 let chunks_queried_for = lsp_data
12963 .inlay_hints
12964 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12965 .collect::<Vec<_>>();
12966 match chunks_queried_for.as_slice() {
12967 &[chunk] => {
12968 let key = LspKey {
12969 request_type: TypeId::of::<T>(),
12970 server_queried: server_id,
12971 };
12972 let previous_request = lsp_data
12973 .chunk_lsp_requests
12974 .entry(key)
12975 .or_default()
12976 .insert(chunk, lsp_request_id);
12977 if let Some((previous_request, running_requests)) =
12978 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12979 {
12980 running_requests.remove(&previous_request);
12981 }
12982 }
12983 _ambiguous_chunks => {
12984 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12985 // there, a buffer version-based check will be performed and outdated requests discarded.
12986 }
12987 }
12988 anyhow::Ok(())
12989 })??;
12990
12991 Ok(())
12992 }
12993
12994 async fn query_lsp_locally<T>(
12995 lsp_store: Entity<Self>,
12996 for_server_id: Option<LanguageServerId>,
12997 sender_id: proto::PeerId,
12998 lsp_request_id: LspRequestId,
12999 proto_request: T::ProtoRequest,
13000 position: Option<Anchor>,
13001 cx: &mut AsyncApp,
13002 ) -> Result<()>
13003 where
13004 T: LspCommand + Clone,
13005 T::ProtoRequest: proto::LspRequestMessage,
13006 <T::ProtoRequest as proto::RequestMessage>::Response:
13007 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13008 {
13009 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13010 let version = deserialize_version(proto_request.buffer_version());
13011 let buffer = lsp_store.update(cx, |this, cx| {
13012 this.buffer_store.read(cx).get_existing(buffer_id)
13013 })??;
13014 buffer
13015 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
13016 .await?;
13017 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
13018 let request =
13019 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13020 let key = LspKey {
13021 request_type: TypeId::of::<T>(),
13022 server_queried: for_server_id,
13023 };
13024 lsp_store.update(cx, |lsp_store, cx| {
13025 let request_task = match for_server_id {
13026 Some(server_id) => {
13027 let server_task = lsp_store.request_lsp(
13028 buffer.clone(),
13029 LanguageServerToQuery::Other(server_id),
13030 request.clone(),
13031 cx,
13032 );
13033 cx.background_spawn(async move {
13034 let mut responses = Vec::new();
13035 match server_task.await {
13036 Ok(response) => responses.push((server_id, response)),
13037 // rust-analyzer likes to error with this when its still loading up
13038 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13039 Err(e) => log::error!(
13040 "Error handling response for request {request:?}: {e:#}"
13041 ),
13042 }
13043 responses
13044 })
13045 }
13046 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13047 };
13048 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13049 if T::ProtoRequest::stop_previous_requests() {
13050 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13051 lsp_requests.clear();
13052 }
13053 }
13054 lsp_data.lsp_requests.entry(key).or_default().insert(
13055 lsp_request_id,
13056 cx.spawn(async move |lsp_store, cx| {
13057 let response = request_task.await;
13058 lsp_store
13059 .update(cx, |lsp_store, cx| {
13060 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13061 {
13062 let response = response
13063 .into_iter()
13064 .map(|(server_id, response)| {
13065 (
13066 server_id.to_proto(),
13067 T::response_to_proto(
13068 response,
13069 lsp_store,
13070 sender_id,
13071 &buffer_version,
13072 cx,
13073 )
13074 .into(),
13075 )
13076 })
13077 .collect::<HashMap<_, _>>();
13078 match client.send_lsp_response::<T::ProtoRequest>(
13079 project_id,
13080 lsp_request_id,
13081 response,
13082 ) {
13083 Ok(()) => {}
13084 Err(e) => {
13085 log::error!("Failed to send LSP response: {e:#}",)
13086 }
13087 }
13088 }
13089 })
13090 .ok();
13091 }),
13092 );
13093 })?;
13094 Ok(())
13095 }
13096
13097 fn take_text_document_sync_options(
13098 capabilities: &mut lsp::ServerCapabilities,
13099 ) -> lsp::TextDocumentSyncOptions {
13100 match capabilities.text_document_sync.take() {
13101 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13102 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13103 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13104 sync_options.change = Some(sync_kind);
13105 sync_options
13106 }
13107 None => lsp::TextDocumentSyncOptions::default(),
13108 }
13109 }
13110
13111 #[cfg(any(test, feature = "test-support"))]
13112 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13113 Some(
13114 self.lsp_data
13115 .get_mut(&buffer_id)?
13116 .code_lens
13117 .take()?
13118 .update
13119 .take()?
13120 .1,
13121 )
13122 }
13123
13124 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13125 self.downstream_client.clone()
13126 }
13127
13128 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13129 self.worktree_store.clone()
13130 }
13131
13132 /// Gets what's stored in the LSP data for the given buffer.
13133 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13134 self.lsp_data.get_mut(&buffer_id)
13135 }
13136
13137 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13138 /// new [`BufferLspData`] will be created to replace the previous state.
13139 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13140 let (buffer_id, buffer_version) =
13141 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13142 let lsp_data = self
13143 .lsp_data
13144 .entry(buffer_id)
13145 .or_insert_with(|| BufferLspData::new(buffer, cx));
13146 if buffer_version.changed_since(&lsp_data.buffer_version) {
13147 *lsp_data = BufferLspData::new(buffer, cx);
13148 }
13149 lsp_data
13150 }
13151}
13152
13153// Registration with registerOptions as null, should fallback to true.
13154// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13155fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13156 reg: lsp::Registration,
13157) -> Result<OneOf<bool, T>> {
13158 Ok(match reg.register_options {
13159 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13160 None => OneOf::Left(true),
13161 })
13162}
13163
13164fn subscribe_to_binary_statuses(
13165 languages: &Arc<LanguageRegistry>,
13166 cx: &mut Context<'_, LspStore>,
13167) -> Task<()> {
13168 let mut server_statuses = languages.language_server_binary_statuses();
13169 cx.spawn(async move |lsp_store, cx| {
13170 while let Some((server_name, binary_status)) = server_statuses.next().await {
13171 if lsp_store
13172 .update(cx, |_, cx| {
13173 let mut message = None;
13174 let binary_status = match binary_status {
13175 BinaryStatus::None => proto::ServerBinaryStatus::None,
13176 BinaryStatus::CheckingForUpdate => {
13177 proto::ServerBinaryStatus::CheckingForUpdate
13178 }
13179 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13180 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13181 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13182 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13183 BinaryStatus::Failed { error } => {
13184 message = Some(error);
13185 proto::ServerBinaryStatus::Failed
13186 }
13187 };
13188 cx.emit(LspStoreEvent::LanguageServerUpdate {
13189 // Binary updates are about the binary that might not have any language server id at that point.
13190 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13191 language_server_id: LanguageServerId(0),
13192 name: Some(server_name),
13193 message: proto::update_language_server::Variant::StatusUpdate(
13194 proto::StatusUpdate {
13195 message,
13196 status: Some(proto::status_update::Status::Binary(
13197 binary_status as i32,
13198 )),
13199 },
13200 ),
13201 });
13202 })
13203 .is_err()
13204 {
13205 break;
13206 }
13207 }
13208 })
13209}
13210
13211fn lsp_workspace_diagnostics_refresh(
13212 registration_id: Option<String>,
13213 options: DiagnosticServerCapabilities,
13214 server: Arc<LanguageServer>,
13215 cx: &mut Context<'_, LspStore>,
13216) -> Option<WorkspaceRefreshTask> {
13217 let identifier = workspace_diagnostic_identifier(&options)?;
13218 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13219
13220 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13221 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13222 refresh_tx.try_send(()).ok();
13223
13224 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13225 let mut attempts = 0;
13226 let max_attempts = 50;
13227 let mut requests = 0;
13228
13229 loop {
13230 let Some(()) = refresh_rx.recv().await else {
13231 return;
13232 };
13233
13234 'request: loop {
13235 requests += 1;
13236 if attempts > max_attempts {
13237 log::error!(
13238 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13239 );
13240 return;
13241 }
13242 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13243 cx.background_executor()
13244 .timer(Duration::from_millis(backoff_millis))
13245 .await;
13246 attempts += 1;
13247
13248 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13249 lsp_store
13250 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13251 .into_iter()
13252 .filter_map(|(abs_path, result_id)| {
13253 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13254 Some(lsp::PreviousResultId {
13255 uri,
13256 value: result_id.to_string(),
13257 })
13258 })
13259 .collect()
13260 }) else {
13261 return;
13262 };
13263
13264 let token = if let Some(registration_id) = ®istration_id {
13265 format!(
13266 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13267 server.server_id(),
13268 )
13269 } else {
13270 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13271 };
13272
13273 progress_rx.try_recv().ok();
13274 let timer =
13275 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13276 let progress = pin!(progress_rx.recv().fuse());
13277 let response_result = server
13278 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13279 lsp::WorkspaceDiagnosticParams {
13280 previous_result_ids,
13281 identifier: identifier.clone(),
13282 work_done_progress_params: Default::default(),
13283 partial_result_params: lsp::PartialResultParams {
13284 partial_result_token: Some(lsp::ProgressToken::String(token)),
13285 },
13286 },
13287 select(timer, progress).then(|either| match either {
13288 Either::Left((message, ..)) => ready(message).left_future(),
13289 Either::Right(..) => pending::<String>().right_future(),
13290 }),
13291 )
13292 .await;
13293
13294 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13295 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13296 match response_result {
13297 ConnectionResult::Timeout => {
13298 log::error!("Timeout during workspace diagnostics pull");
13299 continue 'request;
13300 }
13301 ConnectionResult::ConnectionReset => {
13302 log::error!("Server closed a workspace diagnostics pull request");
13303 continue 'request;
13304 }
13305 ConnectionResult::Result(Err(e)) => {
13306 log::error!("Error during workspace diagnostics pull: {e:#}");
13307 break 'request;
13308 }
13309 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13310 attempts = 0;
13311 if lsp_store
13312 .update(cx, |lsp_store, cx| {
13313 lsp_store.apply_workspace_diagnostic_report(
13314 server.server_id(),
13315 pulled_diagnostics,
13316 registration_id_shared.clone(),
13317 cx,
13318 )
13319 })
13320 .is_err()
13321 {
13322 return;
13323 }
13324 break 'request;
13325 }
13326 }
13327 }
13328 }
13329 });
13330
13331 Some(WorkspaceRefreshTask {
13332 refresh_tx,
13333 progress_tx,
13334 task: workspace_query_language_server,
13335 })
13336}
13337
13338fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13339 match &options {
13340 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13341 diagnostic_options.identifier.clone()
13342 }
13343 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13344 let diagnostic_options = ®istration_options.diagnostic_options;
13345 diagnostic_options.identifier.clone()
13346 }
13347 }
13348}
13349
13350fn workspace_diagnostic_identifier(
13351 options: &DiagnosticServerCapabilities,
13352) -> Option<Option<String>> {
13353 match &options {
13354 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13355 if !diagnostic_options.workspace_diagnostics {
13356 return None;
13357 }
13358 Some(diagnostic_options.identifier.clone())
13359 }
13360 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13361 let diagnostic_options = ®istration_options.diagnostic_options;
13362 if !diagnostic_options.workspace_diagnostics {
13363 return None;
13364 }
13365 Some(diagnostic_options.identifier.clone())
13366 }
13367 }
13368}
13369
13370fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13371 let CompletionSource::BufferWord {
13372 word_range,
13373 resolved,
13374 } = &mut completion.source
13375 else {
13376 return;
13377 };
13378 if *resolved {
13379 return;
13380 }
13381
13382 if completion.new_text
13383 != snapshot
13384 .text_for_range(word_range.clone())
13385 .collect::<String>()
13386 {
13387 return;
13388 }
13389
13390 let mut offset = 0;
13391 for chunk in snapshot.chunks(word_range.clone(), true) {
13392 let end_offset = offset + chunk.text.len();
13393 if let Some(highlight_id) = chunk.syntax_highlight_id {
13394 completion
13395 .label
13396 .runs
13397 .push((offset..end_offset, highlight_id));
13398 }
13399 offset = end_offset;
13400 }
13401 *resolved = true;
13402}
13403
13404impl EventEmitter<LspStoreEvent> for LspStore {}
13405
13406fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13407 hover
13408 .contents
13409 .retain(|hover_block| !hover_block.text.trim().is_empty());
13410 if hover.contents.is_empty() {
13411 None
13412 } else {
13413 Some(hover)
13414 }
13415}
13416
13417async fn populate_labels_for_completions(
13418 new_completions: Vec<CoreCompletion>,
13419 language: Option<Arc<Language>>,
13420 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13421) -> Vec<Completion> {
13422 let lsp_completions = new_completions
13423 .iter()
13424 .filter_map(|new_completion| {
13425 new_completion
13426 .source
13427 .lsp_completion(true)
13428 .map(|lsp_completion| lsp_completion.into_owned())
13429 })
13430 .collect::<Vec<_>>();
13431
13432 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13433 lsp_adapter
13434 .labels_for_completions(&lsp_completions, language)
13435 .await
13436 .log_err()
13437 .unwrap_or_default()
13438 } else {
13439 Vec::new()
13440 }
13441 .into_iter()
13442 .fuse();
13443
13444 let mut completions = Vec::new();
13445 for completion in new_completions {
13446 match completion.source.lsp_completion(true) {
13447 Some(lsp_completion) => {
13448 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13449
13450 let mut label = labels.next().flatten().unwrap_or_else(|| {
13451 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13452 });
13453 ensure_uniform_list_compatible_label(&mut label);
13454 completions.push(Completion {
13455 label,
13456 documentation,
13457 replace_range: completion.replace_range,
13458 new_text: completion.new_text,
13459 insert_text_mode: lsp_completion.insert_text_mode,
13460 source: completion.source,
13461 icon_path: None,
13462 confirm: None,
13463 match_start: None,
13464 snippet_deduplication_key: None,
13465 });
13466 }
13467 None => {
13468 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13469 ensure_uniform_list_compatible_label(&mut label);
13470 completions.push(Completion {
13471 label,
13472 documentation: None,
13473 replace_range: completion.replace_range,
13474 new_text: completion.new_text,
13475 source: completion.source,
13476 insert_text_mode: None,
13477 icon_path: None,
13478 confirm: None,
13479 match_start: None,
13480 snippet_deduplication_key: None,
13481 });
13482 }
13483 }
13484 }
13485 completions
13486}
13487
13488#[derive(Debug)]
13489pub enum LanguageServerToQuery {
13490 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13491 FirstCapable,
13492 /// Query a specific language server.
13493 Other(LanguageServerId),
13494}
13495
13496#[derive(Default)]
13497struct RenamePathsWatchedForServer {
13498 did_rename: Vec<RenameActionPredicate>,
13499 will_rename: Vec<RenameActionPredicate>,
13500}
13501
13502impl RenamePathsWatchedForServer {
13503 fn with_did_rename_patterns(
13504 mut self,
13505 did_rename: Option<&FileOperationRegistrationOptions>,
13506 ) -> Self {
13507 if let Some(did_rename) = did_rename {
13508 self.did_rename = did_rename
13509 .filters
13510 .iter()
13511 .filter_map(|filter| filter.try_into().log_err())
13512 .collect();
13513 }
13514 self
13515 }
13516 fn with_will_rename_patterns(
13517 mut self,
13518 will_rename: Option<&FileOperationRegistrationOptions>,
13519 ) -> Self {
13520 if let Some(will_rename) = will_rename {
13521 self.will_rename = will_rename
13522 .filters
13523 .iter()
13524 .filter_map(|filter| filter.try_into().log_err())
13525 .collect();
13526 }
13527 self
13528 }
13529
13530 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13531 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13532 }
13533 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13534 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13535 }
13536}
13537
13538impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13539 type Error = globset::Error;
13540 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13541 Ok(Self {
13542 kind: ops.pattern.matches.clone(),
13543 glob: GlobBuilder::new(&ops.pattern.glob)
13544 .case_insensitive(
13545 ops.pattern
13546 .options
13547 .as_ref()
13548 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13549 )
13550 .build()?
13551 .compile_matcher(),
13552 })
13553 }
13554}
13555struct RenameActionPredicate {
13556 glob: GlobMatcher,
13557 kind: Option<FileOperationPatternKind>,
13558}
13559
13560impl RenameActionPredicate {
13561 // Returns true if language server should be notified
13562 fn eval(&self, path: &str, is_dir: bool) -> bool {
13563 self.kind.as_ref().is_none_or(|kind| {
13564 let expected_kind = if is_dir {
13565 FileOperationPatternKind::Folder
13566 } else {
13567 FileOperationPatternKind::File
13568 };
13569 kind == &expected_kind
13570 }) && self.glob.is_match(path)
13571 }
13572}
13573
13574#[derive(Default)]
13575struct LanguageServerWatchedPaths {
13576 worktree_paths: HashMap<WorktreeId, GlobSet>,
13577 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13578}
13579
13580#[derive(Default)]
13581struct LanguageServerWatchedPathsBuilder {
13582 worktree_paths: HashMap<WorktreeId, GlobSet>,
13583 abs_paths: HashMap<Arc<Path>, GlobSet>,
13584}
13585
13586impl LanguageServerWatchedPathsBuilder {
13587 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13588 self.worktree_paths.insert(worktree_id, glob_set);
13589 }
13590 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13591 self.abs_paths.insert(path, glob_set);
13592 }
13593 fn build(
13594 self,
13595 fs: Arc<dyn Fs>,
13596 language_server_id: LanguageServerId,
13597 cx: &mut Context<LspStore>,
13598 ) -> LanguageServerWatchedPaths {
13599 let lsp_store = cx.weak_entity();
13600
13601 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13602 let abs_paths = self
13603 .abs_paths
13604 .into_iter()
13605 .map(|(abs_path, globset)| {
13606 let task = cx.spawn({
13607 let abs_path = abs_path.clone();
13608 let fs = fs.clone();
13609
13610 let lsp_store = lsp_store.clone();
13611 async move |_, cx| {
13612 maybe!(async move {
13613 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13614 while let Some(update) = push_updates.0.next().await {
13615 let action = lsp_store
13616 .update(cx, |this, _| {
13617 let Some(local) = this.as_local() else {
13618 return ControlFlow::Break(());
13619 };
13620 let Some(watcher) = local
13621 .language_server_watched_paths
13622 .get(&language_server_id)
13623 else {
13624 return ControlFlow::Break(());
13625 };
13626 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13627 "Watched abs path is not registered with a watcher",
13628 );
13629 let matching_entries = update
13630 .into_iter()
13631 .filter(|event| globs.is_match(&event.path))
13632 .collect::<Vec<_>>();
13633 this.lsp_notify_abs_paths_changed(
13634 language_server_id,
13635 matching_entries,
13636 );
13637 ControlFlow::Continue(())
13638 })
13639 .ok()?;
13640
13641 if action.is_break() {
13642 break;
13643 }
13644 }
13645 Some(())
13646 })
13647 .await;
13648 }
13649 });
13650 (abs_path, (globset, task))
13651 })
13652 .collect();
13653 LanguageServerWatchedPaths {
13654 worktree_paths: self.worktree_paths,
13655 abs_paths,
13656 }
13657 }
13658}
13659
13660struct LspBufferSnapshot {
13661 version: i32,
13662 snapshot: TextBufferSnapshot,
13663}
13664
13665/// A prompt requested by LSP server.
13666#[derive(Clone, Debug)]
13667pub struct LanguageServerPromptRequest {
13668 pub level: PromptLevel,
13669 pub message: String,
13670 pub actions: Vec<MessageActionItem>,
13671 pub lsp_name: String,
13672 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13673}
13674
13675impl LanguageServerPromptRequest {
13676 pub async fn respond(self, index: usize) -> Option<()> {
13677 if let Some(response) = self.actions.into_iter().nth(index) {
13678 self.response_channel.send(response).await.ok()
13679 } else {
13680 None
13681 }
13682 }
13683}
13684impl PartialEq for LanguageServerPromptRequest {
13685 fn eq(&self, other: &Self) -> bool {
13686 self.message == other.message && self.actions == other.actions
13687 }
13688}
13689
13690#[derive(Clone, Debug, PartialEq)]
13691pub enum LanguageServerLogType {
13692 Log(MessageType),
13693 Trace { verbose_info: Option<String> },
13694 Rpc { received: bool },
13695}
13696
13697impl LanguageServerLogType {
13698 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13699 match self {
13700 Self::Log(log_type) => {
13701 use proto::log_message::LogLevel;
13702 let level = match *log_type {
13703 MessageType::ERROR => LogLevel::Error,
13704 MessageType::WARNING => LogLevel::Warning,
13705 MessageType::INFO => LogLevel::Info,
13706 MessageType::LOG => LogLevel::Log,
13707 other => {
13708 log::warn!("Unknown lsp log message type: {other:?}");
13709 LogLevel::Log
13710 }
13711 };
13712 proto::language_server_log::LogType::Log(proto::LogMessage {
13713 level: level as i32,
13714 })
13715 }
13716 Self::Trace { verbose_info } => {
13717 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13718 verbose_info: verbose_info.to_owned(),
13719 })
13720 }
13721 Self::Rpc { received } => {
13722 let kind = if *received {
13723 proto::rpc_message::Kind::Received
13724 } else {
13725 proto::rpc_message::Kind::Sent
13726 };
13727 let kind = kind as i32;
13728 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13729 }
13730 }
13731 }
13732
13733 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13734 use proto::log_message::LogLevel;
13735 use proto::rpc_message;
13736 match log_type {
13737 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13738 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13739 LogLevel::Error => MessageType::ERROR,
13740 LogLevel::Warning => MessageType::WARNING,
13741 LogLevel::Info => MessageType::INFO,
13742 LogLevel::Log => MessageType::LOG,
13743 },
13744 ),
13745 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13746 verbose_info: trace_message.verbose_info,
13747 },
13748 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13749 received: match rpc_message::Kind::from_i32(message.kind)
13750 .unwrap_or(rpc_message::Kind::Received)
13751 {
13752 rpc_message::Kind::Received => true,
13753 rpc_message::Kind::Sent => false,
13754 },
13755 },
13756 }
13757 }
13758}
13759
13760pub struct WorkspaceRefreshTask {
13761 refresh_tx: mpsc::Sender<()>,
13762 progress_tx: mpsc::Sender<()>,
13763 #[allow(dead_code)]
13764 task: Task<()>,
13765}
13766
13767pub enum LanguageServerState {
13768 Starting {
13769 startup: Task<Option<Arc<LanguageServer>>>,
13770 /// List of language servers that will be added to the workspace once it's initialization completes.
13771 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13772 },
13773
13774 Running {
13775 adapter: Arc<CachedLspAdapter>,
13776 server: Arc<LanguageServer>,
13777 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13778 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13779 },
13780}
13781
13782impl LanguageServerState {
13783 fn add_workspace_folder(&self, uri: Uri) {
13784 match self {
13785 LanguageServerState::Starting {
13786 pending_workspace_folders,
13787 ..
13788 } => {
13789 pending_workspace_folders.lock().insert(uri);
13790 }
13791 LanguageServerState::Running { server, .. } => {
13792 server.add_workspace_folder(uri);
13793 }
13794 }
13795 }
13796 fn _remove_workspace_folder(&self, uri: Uri) {
13797 match self {
13798 LanguageServerState::Starting {
13799 pending_workspace_folders,
13800 ..
13801 } => {
13802 pending_workspace_folders.lock().remove(&uri);
13803 }
13804 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13805 }
13806 }
13807}
13808
13809impl std::fmt::Debug for LanguageServerState {
13810 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13811 match self {
13812 LanguageServerState::Starting { .. } => {
13813 f.debug_struct("LanguageServerState::Starting").finish()
13814 }
13815 LanguageServerState::Running { .. } => {
13816 f.debug_struct("LanguageServerState::Running").finish()
13817 }
13818 }
13819 }
13820}
13821
13822#[derive(Clone, Debug, Serialize)]
13823pub struct LanguageServerProgress {
13824 pub is_disk_based_diagnostics_progress: bool,
13825 pub is_cancellable: bool,
13826 pub title: Option<String>,
13827 pub message: Option<String>,
13828 pub percentage: Option<usize>,
13829 #[serde(skip_serializing)]
13830 pub last_update_at: Instant,
13831}
13832
13833#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13834pub struct DiagnosticSummary {
13835 pub error_count: usize,
13836 pub warning_count: usize,
13837}
13838
13839impl DiagnosticSummary {
13840 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13841 let mut this = Self {
13842 error_count: 0,
13843 warning_count: 0,
13844 };
13845
13846 for entry in diagnostics {
13847 if entry.diagnostic.is_primary {
13848 match entry.diagnostic.severity {
13849 DiagnosticSeverity::ERROR => this.error_count += 1,
13850 DiagnosticSeverity::WARNING => this.warning_count += 1,
13851 _ => {}
13852 }
13853 }
13854 }
13855
13856 this
13857 }
13858
13859 pub fn is_empty(&self) -> bool {
13860 self.error_count == 0 && self.warning_count == 0
13861 }
13862
13863 pub fn to_proto(
13864 self,
13865 language_server_id: LanguageServerId,
13866 path: &RelPath,
13867 ) -> proto::DiagnosticSummary {
13868 proto::DiagnosticSummary {
13869 path: path.to_proto(),
13870 language_server_id: language_server_id.0 as u64,
13871 error_count: self.error_count as u32,
13872 warning_count: self.warning_count as u32,
13873 }
13874 }
13875}
13876
13877#[derive(Clone, Debug)]
13878pub enum CompletionDocumentation {
13879 /// There is no documentation for this completion.
13880 Undocumented,
13881 /// A single line of documentation.
13882 SingleLine(SharedString),
13883 /// Multiple lines of plain text documentation.
13884 MultiLinePlainText(SharedString),
13885 /// Markdown documentation.
13886 MultiLineMarkdown(SharedString),
13887 /// Both single line and multiple lines of plain text documentation.
13888 SingleLineAndMultiLinePlainText {
13889 single_line: SharedString,
13890 plain_text: Option<SharedString>,
13891 },
13892}
13893
13894impl CompletionDocumentation {
13895 #[cfg(any(test, feature = "test-support"))]
13896 pub fn text(&self) -> SharedString {
13897 match self {
13898 CompletionDocumentation::Undocumented => "".into(),
13899 CompletionDocumentation::SingleLine(s) => s.clone(),
13900 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13901 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13902 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13903 single_line.clone()
13904 }
13905 }
13906 }
13907}
13908
13909impl From<lsp::Documentation> for CompletionDocumentation {
13910 fn from(docs: lsp::Documentation) -> Self {
13911 match docs {
13912 lsp::Documentation::String(text) => {
13913 if text.lines().count() <= 1 {
13914 CompletionDocumentation::SingleLine(text.into())
13915 } else {
13916 CompletionDocumentation::MultiLinePlainText(text.into())
13917 }
13918 }
13919
13920 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13921 lsp::MarkupKind::PlainText => {
13922 if value.lines().count() <= 1 {
13923 CompletionDocumentation::SingleLine(value.into())
13924 } else {
13925 CompletionDocumentation::MultiLinePlainText(value.into())
13926 }
13927 }
13928
13929 lsp::MarkupKind::Markdown => {
13930 CompletionDocumentation::MultiLineMarkdown(value.into())
13931 }
13932 },
13933 }
13934 }
13935}
13936
13937pub enum ResolvedHint {
13938 Resolved(InlayHint),
13939 Resolving(Shared<Task<()>>),
13940}
13941
13942fn glob_literal_prefix(glob: &Path) -> PathBuf {
13943 glob.components()
13944 .take_while(|component| match component {
13945 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13946 _ => true,
13947 })
13948 .collect()
13949}
13950
13951pub struct SshLspAdapter {
13952 name: LanguageServerName,
13953 binary: LanguageServerBinary,
13954 initialization_options: Option<String>,
13955 code_action_kinds: Option<Vec<CodeActionKind>>,
13956}
13957
13958impl SshLspAdapter {
13959 pub fn new(
13960 name: LanguageServerName,
13961 binary: LanguageServerBinary,
13962 initialization_options: Option<String>,
13963 code_action_kinds: Option<String>,
13964 ) -> Self {
13965 Self {
13966 name,
13967 binary,
13968 initialization_options,
13969 code_action_kinds: code_action_kinds
13970 .as_ref()
13971 .and_then(|c| serde_json::from_str(c).ok()),
13972 }
13973 }
13974}
13975
13976impl LspInstaller for SshLspAdapter {
13977 type BinaryVersion = ();
13978 async fn check_if_user_installed(
13979 &self,
13980 _: &dyn LspAdapterDelegate,
13981 _: Option<Toolchain>,
13982 _: &AsyncApp,
13983 ) -> Option<LanguageServerBinary> {
13984 Some(self.binary.clone())
13985 }
13986
13987 async fn cached_server_binary(
13988 &self,
13989 _: PathBuf,
13990 _: &dyn LspAdapterDelegate,
13991 ) -> Option<LanguageServerBinary> {
13992 None
13993 }
13994
13995 async fn fetch_latest_server_version(
13996 &self,
13997 _: &dyn LspAdapterDelegate,
13998 _: bool,
13999 _: &mut AsyncApp,
14000 ) -> Result<()> {
14001 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14002 }
14003
14004 async fn fetch_server_binary(
14005 &self,
14006 _: (),
14007 _: PathBuf,
14008 _: &dyn LspAdapterDelegate,
14009 ) -> Result<LanguageServerBinary> {
14010 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14011 }
14012}
14013
14014#[async_trait(?Send)]
14015impl LspAdapter for SshLspAdapter {
14016 fn name(&self) -> LanguageServerName {
14017 self.name.clone()
14018 }
14019
14020 async fn initialization_options(
14021 self: Arc<Self>,
14022 _: &Arc<dyn LspAdapterDelegate>,
14023 ) -> Result<Option<serde_json::Value>> {
14024 let Some(options) = &self.initialization_options else {
14025 return Ok(None);
14026 };
14027 let result = serde_json::from_str(options)?;
14028 Ok(result)
14029 }
14030
14031 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14032 self.code_action_kinds.clone()
14033 }
14034}
14035
14036pub fn language_server_settings<'a>(
14037 delegate: &'a dyn LspAdapterDelegate,
14038 language: &LanguageServerName,
14039 cx: &'a App,
14040) -> Option<&'a LspSettings> {
14041 language_server_settings_for(
14042 SettingsLocation {
14043 worktree_id: delegate.worktree_id(),
14044 path: RelPath::empty(),
14045 },
14046 language,
14047 cx,
14048 )
14049}
14050
14051pub fn language_server_settings_for<'a>(
14052 location: SettingsLocation<'a>,
14053 language: &LanguageServerName,
14054 cx: &'a App,
14055) -> Option<&'a LspSettings> {
14056 ProjectSettings::get(Some(location), cx).lsp.get(language)
14057}
14058
14059pub struct LocalLspAdapterDelegate {
14060 lsp_store: WeakEntity<LspStore>,
14061 worktree: worktree::Snapshot,
14062 fs: Arc<dyn Fs>,
14063 http_client: Arc<dyn HttpClient>,
14064 language_registry: Arc<LanguageRegistry>,
14065 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14066}
14067
14068impl LocalLspAdapterDelegate {
14069 pub fn new(
14070 language_registry: Arc<LanguageRegistry>,
14071 environment: &Entity<ProjectEnvironment>,
14072 lsp_store: WeakEntity<LspStore>,
14073 worktree: &Entity<Worktree>,
14074 http_client: Arc<dyn HttpClient>,
14075 fs: Arc<dyn Fs>,
14076 cx: &mut App,
14077 ) -> Arc<Self> {
14078 let load_shell_env_task =
14079 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14080
14081 Arc::new(Self {
14082 lsp_store,
14083 worktree: worktree.read(cx).snapshot(),
14084 fs,
14085 http_client,
14086 language_registry,
14087 load_shell_env_task,
14088 })
14089 }
14090
14091 fn from_local_lsp(
14092 local: &LocalLspStore,
14093 worktree: &Entity<Worktree>,
14094 cx: &mut App,
14095 ) -> Arc<Self> {
14096 Self::new(
14097 local.languages.clone(),
14098 &local.environment,
14099 local.weak.clone(),
14100 worktree,
14101 local.http_client.clone(),
14102 local.fs.clone(),
14103 cx,
14104 )
14105 }
14106}
14107
14108#[async_trait]
14109impl LspAdapterDelegate for LocalLspAdapterDelegate {
14110 fn show_notification(&self, message: &str, cx: &mut App) {
14111 self.lsp_store
14112 .update(cx, |_, cx| {
14113 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14114 })
14115 .ok();
14116 }
14117
14118 fn http_client(&self) -> Arc<dyn HttpClient> {
14119 self.http_client.clone()
14120 }
14121
14122 fn worktree_id(&self) -> WorktreeId {
14123 self.worktree.id()
14124 }
14125
14126 fn worktree_root_path(&self) -> &Path {
14127 self.worktree.abs_path().as_ref()
14128 }
14129
14130 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14131 self.worktree.resolve_executable_path(path)
14132 }
14133
14134 async fn shell_env(&self) -> HashMap<String, String> {
14135 let task = self.load_shell_env_task.clone();
14136 task.await.unwrap_or_default()
14137 }
14138
14139 async fn npm_package_installed_version(
14140 &self,
14141 package_name: &str,
14142 ) -> Result<Option<(PathBuf, String)>> {
14143 let local_package_directory = self.worktree_root_path();
14144 let node_modules_directory = local_package_directory.join("node_modules");
14145
14146 if let Some(version) =
14147 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14148 {
14149 return Ok(Some((node_modules_directory, version)));
14150 }
14151 let Some(npm) = self.which("npm".as_ref()).await else {
14152 log::warn!(
14153 "Failed to find npm executable for {:?}",
14154 local_package_directory
14155 );
14156 return Ok(None);
14157 };
14158
14159 let env = self.shell_env().await;
14160 let output = util::command::new_smol_command(&npm)
14161 .args(["root", "-g"])
14162 .envs(env)
14163 .current_dir(local_package_directory)
14164 .output()
14165 .await?;
14166 let global_node_modules =
14167 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14168
14169 if let Some(version) =
14170 read_package_installed_version(global_node_modules.clone(), package_name).await?
14171 {
14172 return Ok(Some((global_node_modules, version)));
14173 }
14174 return Ok(None);
14175 }
14176
14177 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14178 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14179 if self.fs.is_file(&worktree_abs_path).await {
14180 worktree_abs_path.pop();
14181 }
14182
14183 let env = self.shell_env().await;
14184
14185 let shell_path = env.get("PATH").cloned();
14186
14187 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14188 }
14189
14190 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14191 let mut working_dir = self.worktree_root_path().to_path_buf();
14192 if self.fs.is_file(&working_dir).await {
14193 working_dir.pop();
14194 }
14195 let output = util::command::new_smol_command(&command.path)
14196 .args(command.arguments)
14197 .envs(command.env.clone().unwrap_or_default())
14198 .current_dir(working_dir)
14199 .output()
14200 .await?;
14201
14202 anyhow::ensure!(
14203 output.status.success(),
14204 "{}, stdout: {:?}, stderr: {:?}",
14205 output.status,
14206 String::from_utf8_lossy(&output.stdout),
14207 String::from_utf8_lossy(&output.stderr)
14208 );
14209 Ok(())
14210 }
14211
14212 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14213 self.language_registry
14214 .update_lsp_binary_status(server_name, status);
14215 }
14216
14217 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14218 self.language_registry
14219 .all_lsp_adapters()
14220 .into_iter()
14221 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14222 .collect()
14223 }
14224
14225 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14226 let dir = self.language_registry.language_server_download_dir(name)?;
14227
14228 if !dir.exists() {
14229 smol::fs::create_dir_all(&dir)
14230 .await
14231 .context("failed to create container directory")
14232 .log_err()?;
14233 }
14234
14235 Some(dir)
14236 }
14237
14238 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14239 let entry = self
14240 .worktree
14241 .entry_for_path(path)
14242 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14243 let abs_path = self.worktree.absolutize(&entry.path);
14244 self.fs.load(&abs_path).await
14245 }
14246}
14247
14248async fn populate_labels_for_symbols(
14249 symbols: Vec<CoreSymbol>,
14250 language_registry: &Arc<LanguageRegistry>,
14251 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14252 output: &mut Vec<Symbol>,
14253) {
14254 #[allow(clippy::mutable_key_type)]
14255 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14256
14257 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14258 for symbol in symbols {
14259 let Some(file_name) = symbol.path.file_name() else {
14260 continue;
14261 };
14262 let language = language_registry
14263 .load_language_for_file_path(Path::new(file_name))
14264 .await
14265 .ok()
14266 .or_else(|| {
14267 unknown_paths.insert(file_name.into());
14268 None
14269 });
14270 symbols_by_language
14271 .entry(language)
14272 .or_default()
14273 .push(symbol);
14274 }
14275
14276 for unknown_path in unknown_paths {
14277 log::info!("no language found for symbol in file {unknown_path:?}");
14278 }
14279
14280 let mut label_params = Vec::new();
14281 for (language, mut symbols) in symbols_by_language {
14282 label_params.clear();
14283 label_params.extend(
14284 symbols
14285 .iter_mut()
14286 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14287 );
14288
14289 let mut labels = Vec::new();
14290 if let Some(language) = language {
14291 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14292 language_registry
14293 .lsp_adapters(&language.name())
14294 .first()
14295 .cloned()
14296 });
14297 if let Some(lsp_adapter) = lsp_adapter {
14298 labels = lsp_adapter
14299 .labels_for_symbols(&label_params, &language)
14300 .await
14301 .log_err()
14302 .unwrap_or_default();
14303 }
14304 }
14305
14306 for ((symbol, (name, _)), label) in symbols
14307 .into_iter()
14308 .zip(label_params.drain(..))
14309 .zip(labels.into_iter().chain(iter::repeat(None)))
14310 {
14311 output.push(Symbol {
14312 language_server_name: symbol.language_server_name,
14313 source_worktree_id: symbol.source_worktree_id,
14314 source_language_server_id: symbol.source_language_server_id,
14315 path: symbol.path,
14316 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14317 name,
14318 kind: symbol.kind,
14319 range: symbol.range,
14320 });
14321 }
14322 }
14323}
14324
14325fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14326 match server.capabilities().text_document_sync.as_ref()? {
14327 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14328 // Server wants didSave but didn't specify includeText.
14329 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14330 // Server doesn't want didSave at all.
14331 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14332 // Server provided SaveOptions.
14333 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14334 Some(save_options.include_text.unwrap_or(false))
14335 }
14336 },
14337 // We do not have any save info. Kind affects didChange only.
14338 lsp::TextDocumentSyncCapability::Kind(_) => None,
14339 }
14340}
14341
14342/// Completion items are displayed in a `UniformList`.
14343/// Usually, those items are single-line strings, but in LSP responses,
14344/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14345/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14346/// 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,
14347/// breaking the completions menu presentation.
14348///
14349/// 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.
14350fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14351 let mut new_text = String::with_capacity(label.text.len());
14352 let mut offset_map = vec![0; label.text.len() + 1];
14353 let mut last_char_was_space = false;
14354 let mut new_idx = 0;
14355 let chars = label.text.char_indices().fuse();
14356 let mut newlines_removed = false;
14357
14358 for (idx, c) in chars {
14359 offset_map[idx] = new_idx;
14360
14361 match c {
14362 '\n' if last_char_was_space => {
14363 newlines_removed = true;
14364 }
14365 '\t' | ' ' if last_char_was_space => {}
14366 '\n' if !last_char_was_space => {
14367 new_text.push(' ');
14368 new_idx += 1;
14369 last_char_was_space = true;
14370 newlines_removed = true;
14371 }
14372 ' ' | '\t' => {
14373 new_text.push(' ');
14374 new_idx += 1;
14375 last_char_was_space = true;
14376 }
14377 _ => {
14378 new_text.push(c);
14379 new_idx += c.len_utf8();
14380 last_char_was_space = false;
14381 }
14382 }
14383 }
14384 offset_map[label.text.len()] = new_idx;
14385
14386 // Only modify the label if newlines were removed.
14387 if !newlines_removed {
14388 return;
14389 }
14390
14391 let last_index = new_idx;
14392 let mut run_ranges_errors = Vec::new();
14393 label.runs.retain_mut(|(range, _)| {
14394 match offset_map.get(range.start) {
14395 Some(&start) => range.start = start,
14396 None => {
14397 run_ranges_errors.push(range.clone());
14398 return false;
14399 }
14400 }
14401
14402 match offset_map.get(range.end) {
14403 Some(&end) => range.end = end,
14404 None => {
14405 run_ranges_errors.push(range.clone());
14406 range.end = last_index;
14407 }
14408 }
14409 true
14410 });
14411 if !run_ranges_errors.is_empty() {
14412 log::error!(
14413 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14414 label.text
14415 );
14416 }
14417
14418 let mut wrong_filter_range = None;
14419 if label.filter_range == (0..label.text.len()) {
14420 label.filter_range = 0..new_text.len();
14421 } else {
14422 let mut original_filter_range = Some(label.filter_range.clone());
14423 match offset_map.get(label.filter_range.start) {
14424 Some(&start) => label.filter_range.start = start,
14425 None => {
14426 wrong_filter_range = original_filter_range.take();
14427 label.filter_range.start = last_index;
14428 }
14429 }
14430
14431 match offset_map.get(label.filter_range.end) {
14432 Some(&end) => label.filter_range.end = end,
14433 None => {
14434 wrong_filter_range = original_filter_range.take();
14435 label.filter_range.end = last_index;
14436 }
14437 }
14438 }
14439 if let Some(wrong_filter_range) = wrong_filter_range {
14440 log::error!(
14441 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14442 label.text
14443 );
14444 }
14445
14446 label.text = new_text;
14447}
14448
14449#[cfg(test)]
14450mod tests {
14451 use language::HighlightId;
14452
14453 use super::*;
14454
14455 #[test]
14456 fn test_glob_literal_prefix() {
14457 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14458 assert_eq!(
14459 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14460 Path::new("node_modules")
14461 );
14462 assert_eq!(
14463 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14464 Path::new("foo")
14465 );
14466 assert_eq!(
14467 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14468 Path::new("foo/bar/baz.js")
14469 );
14470
14471 #[cfg(target_os = "windows")]
14472 {
14473 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14474 assert_eq!(
14475 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14476 Path::new("node_modules")
14477 );
14478 assert_eq!(
14479 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14480 Path::new("foo")
14481 );
14482 assert_eq!(
14483 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14484 Path::new("foo/bar/baz.js")
14485 );
14486 }
14487 }
14488
14489 #[test]
14490 fn test_multi_len_chars_normalization() {
14491 let mut label = CodeLabel::new(
14492 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14493 0..6,
14494 vec![(0..6, HighlightId(1))],
14495 );
14496 ensure_uniform_list_compatible_label(&mut label);
14497 assert_eq!(
14498 label,
14499 CodeLabel::new(
14500 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14501 0..6,
14502 vec![(0..6, HighlightId(1))],
14503 )
14504 );
14505 }
14506}