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, Capability, CodeLabel,
65 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
66 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
67 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
68 Toolchain, 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 semver::Version;
97use serde::Serialize;
98use serde_json::Value;
99use settings::{Settings, SettingsLocation, SettingsStore};
100use sha2::{Digest, Sha256};
101use smol::channel::{Receiver, Sender};
102use snippet::Snippet;
103use std::{
104 any::TypeId,
105 borrow::Cow,
106 cell::RefCell,
107 cmp::{Ordering, Reverse},
108 collections::hash_map,
109 convert::TryInto,
110 ffi::OsStr,
111 future::ready,
112 iter, mem,
113 ops::{ControlFlow, Range},
114 path::{self, Path, PathBuf},
115 pin::pin,
116 rc::Rc,
117 sync::{
118 Arc,
119 atomic::{self, AtomicUsize},
120 },
121 time::{Duration, Instant},
122 vec,
123};
124use sum_tree::Dimensions;
125use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
126
127use util::{
128 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
129 paths::{PathStyle, SanitizedPath},
130 post_inc,
131 redact::redact_command,
132 rel_path::RelPath,
133};
134
135pub use fs::*;
136pub use language::Location;
137pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
138#[cfg(any(test, feature = "test-support"))]
139pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
140pub use worktree::{
141 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
142 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
143};
144
145const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
146pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
147const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
148const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
149
150#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
151pub enum ProgressToken {
152 Number(i32),
153 String(SharedString),
154}
155
156impl std::fmt::Display for ProgressToken {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 match self {
159 Self::Number(number) => write!(f, "{number}"),
160 Self::String(string) => write!(f, "{string}"),
161 }
162 }
163}
164
165impl ProgressToken {
166 fn from_lsp(value: lsp::NumberOrString) -> Self {
167 match value {
168 lsp::NumberOrString::Number(number) => Self::Number(number),
169 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
170 }
171 }
172
173 fn to_lsp(&self) -> lsp::NumberOrString {
174 match self {
175 Self::Number(number) => lsp::NumberOrString::Number(*number),
176 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
177 }
178 }
179
180 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
181 Some(match value.value? {
182 proto::progress_token::Value::Number(number) => Self::Number(number),
183 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
184 })
185 }
186
187 fn to_proto(&self) -> proto::ProgressToken {
188 proto::ProgressToken {
189 value: Some(match self {
190 Self::Number(number) => proto::progress_token::Value::Number(*number),
191 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
192 }),
193 }
194 }
195}
196
197#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198pub enum FormatTrigger {
199 Save,
200 Manual,
201}
202
203pub enum LspFormatTarget {
204 Buffers,
205 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
206}
207
208#[derive(Clone, PartialEq, Eq, Hash)]
209pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
210
211struct OpenLspBuffer(Entity<Buffer>);
212
213impl FormatTrigger {
214 fn from_proto(value: i32) -> FormatTrigger {
215 match value {
216 0 => FormatTrigger::Save,
217 1 => FormatTrigger::Manual,
218 _ => FormatTrigger::Save,
219 }
220 }
221}
222
223#[derive(Clone)]
224struct UnifiedLanguageServer {
225 id: LanguageServerId,
226 project_roots: HashSet<Arc<RelPath>>,
227}
228
229#[derive(Clone, Debug, Hash, PartialEq, Eq)]
230struct LanguageServerSeed {
231 worktree_id: WorktreeId,
232 name: LanguageServerName,
233 toolchain: Option<Toolchain>,
234 settings: Arc<LspSettings>,
235}
236
237#[derive(Debug)]
238pub struct DocumentDiagnosticsUpdate<'a, D> {
239 pub diagnostics: D,
240 pub result_id: Option<SharedString>,
241 pub registration_id: Option<SharedString>,
242 pub server_id: LanguageServerId,
243 pub disk_based_sources: Cow<'a, [String]>,
244}
245
246pub struct DocumentDiagnostics {
247 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
248 document_abs_path: PathBuf,
249 version: Option<i32>,
250}
251
252#[derive(Default, Debug)]
253struct DynamicRegistrations {
254 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
255 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
256}
257
258pub struct LocalLspStore {
259 weak: WeakEntity<LspStore>,
260 pub worktree_store: Entity<WorktreeStore>,
261 toolchain_store: Entity<LocalToolchainStore>,
262 http_client: Arc<dyn HttpClient>,
263 environment: Entity<ProjectEnvironment>,
264 fs: Arc<dyn Fs>,
265 languages: Arc<LanguageRegistry>,
266 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
267 yarn: Entity<YarnPathStore>,
268 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
269 buffers_being_formatted: HashSet<BufferId>,
270 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
271 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
272 watched_manifest_filenames: HashSet<ManifestName>,
273 language_server_paths_watched_for_rename:
274 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
275 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
276 supplementary_language_servers:
277 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
278 prettier_store: Entity<PrettierStore>,
279 next_diagnostic_group_id: usize,
280 diagnostics: HashMap<
281 WorktreeId,
282 HashMap<
283 Arc<RelPath>,
284 Vec<(
285 LanguageServerId,
286 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
287 )>,
288 >,
289 >,
290 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
291 _subscription: gpui::Subscription,
292 lsp_tree: LanguageServerTree,
293 registered_buffers: HashMap<BufferId, usize>,
294 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
295 buffer_pull_diagnostics_result_ids: HashMap<
296 LanguageServerId,
297 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
298 >,
299 workspace_pull_diagnostics_result_ids: HashMap<
300 LanguageServerId,
301 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
302 >,
303 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, Receiver<()>)>,
304}
305
306impl LocalLspStore {
307 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
308 pub fn running_language_server_for_id(
309 &self,
310 id: LanguageServerId,
311 ) -> Option<&Arc<LanguageServer>> {
312 let language_server_state = self.language_servers.get(&id)?;
313
314 match language_server_state {
315 LanguageServerState::Running { server, .. } => Some(server),
316 LanguageServerState::Starting { .. } => None,
317 }
318 }
319
320 fn get_or_insert_language_server(
321 &mut self,
322 worktree_handle: &Entity<Worktree>,
323 delegate: Arc<LocalLspAdapterDelegate>,
324 disposition: &Arc<LaunchDisposition>,
325 language_name: &LanguageName,
326 cx: &mut App,
327 ) -> LanguageServerId {
328 let key = LanguageServerSeed {
329 worktree_id: worktree_handle.read(cx).id(),
330 name: disposition.server_name.clone(),
331 settings: disposition.settings.clone(),
332 toolchain: disposition.toolchain.clone(),
333 };
334 if let Some(state) = self.language_server_ids.get_mut(&key) {
335 state.project_roots.insert(disposition.path.path.clone());
336 state.id
337 } else {
338 let adapter = self
339 .languages
340 .lsp_adapters(language_name)
341 .into_iter()
342 .find(|adapter| adapter.name() == disposition.server_name)
343 .expect("To find LSP adapter");
344 let new_language_server_id = self.start_language_server(
345 worktree_handle,
346 delegate,
347 adapter,
348 disposition.settings.clone(),
349 key.clone(),
350 cx,
351 );
352 if let Some(state) = self.language_server_ids.get_mut(&key) {
353 state.project_roots.insert(disposition.path.path.clone());
354 } else {
355 debug_assert!(
356 false,
357 "Expected `start_language_server` to ensure that `key` exists in a map"
358 );
359 }
360 new_language_server_id
361 }
362 }
363
364 fn start_language_server(
365 &mut self,
366 worktree_handle: &Entity<Worktree>,
367 delegate: Arc<LocalLspAdapterDelegate>,
368 adapter: Arc<CachedLspAdapter>,
369 settings: Arc<LspSettings>,
370 key: LanguageServerSeed,
371 cx: &mut App,
372 ) -> LanguageServerId {
373 let worktree = worktree_handle.read(cx);
374
375 let worktree_id = worktree.id();
376 let worktree_abs_path = worktree.abs_path();
377 let toolchain = key.toolchain.clone();
378 let override_options = settings.initialization_options.clone();
379
380 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
381
382 let server_id = self.languages.next_language_server_id();
383 log::trace!(
384 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
385 adapter.name.0
386 );
387
388 let untrusted_worktree_task =
389 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
390 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
391 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
392 });
393 if can_trust {
394 self.restricted_worktrees_tasks.remove(&worktree_id);
395 None
396 } else {
397 match self.restricted_worktrees_tasks.entry(worktree_id) {
398 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
399 hash_map::Entry::Vacant(v) => {
400 let (tx, rx) = smol::channel::bounded::<()>(1);
401 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, _| {
402 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
403 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
404 tx.send_blocking(()).ok();
405 }
406 }
407 });
408 v.insert((subscription, rx.clone()));
409 Some(rx)
410 }
411 }
412 }
413 });
414 let update_binary_status = untrusted_worktree_task.is_none();
415
416 let binary = self.get_language_server_binary(
417 worktree_abs_path.clone(),
418 adapter.clone(),
419 settings,
420 toolchain.clone(),
421 delegate.clone(),
422 true,
423 untrusted_worktree_task,
424 cx,
425 );
426 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
427
428 let pending_server = cx.spawn({
429 let adapter = adapter.clone();
430 let server_name = adapter.name.clone();
431 let stderr_capture = stderr_capture.clone();
432 #[cfg(any(test, feature = "test-support"))]
433 let lsp_store = self.weak.clone();
434 let pending_workspace_folders = pending_workspace_folders.clone();
435 async move |cx| {
436 let binary = binary.await?;
437 #[cfg(any(test, feature = "test-support"))]
438 if let Some(server) = lsp_store
439 .update(&mut cx.clone(), |this, cx| {
440 this.languages.create_fake_language_server(
441 server_id,
442 &server_name,
443 binary.clone(),
444 &mut cx.to_async(),
445 )
446 })
447 .ok()
448 .flatten()
449 {
450 return Ok(server);
451 }
452
453 let code_action_kinds = adapter.code_action_kinds();
454 lsp::LanguageServer::new(
455 stderr_capture,
456 server_id,
457 server_name,
458 binary,
459 &worktree_abs_path,
460 code_action_kinds,
461 Some(pending_workspace_folders),
462 cx,
463 )
464 }
465 });
466
467 let startup = {
468 let server_name = adapter.name.0.clone();
469 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
470 let key = key.clone();
471 let adapter = adapter.clone();
472 let lsp_store = self.weak.clone();
473 let pending_workspace_folders = pending_workspace_folders.clone();
474
475 let pull_diagnostics = ProjectSettings::get_global(cx)
476 .diagnostics
477 .lsp_pull_diagnostics
478 .enabled;
479 cx.spawn(async move |cx| {
480 let result = async {
481 let language_server = pending_server.await?;
482
483 let workspace_config = Self::workspace_configuration_for_adapter(
484 adapter.adapter.clone(),
485 &delegate,
486 toolchain,
487 None,
488 cx,
489 )
490 .await?;
491
492 let mut initialization_options = Self::initialization_options_for_adapter(
493 adapter.adapter.clone(),
494 &delegate,
495 )
496 .await?;
497
498 match (&mut initialization_options, override_options) {
499 (Some(initialization_options), Some(override_options)) => {
500 merge_json_value_into(override_options, initialization_options);
501 }
502 (None, override_options) => initialization_options = override_options,
503 _ => {}
504 }
505
506 let initialization_params = cx.update(|cx| {
507 let mut params =
508 language_server.default_initialize_params(pull_diagnostics, cx);
509 params.initialization_options = initialization_options;
510 adapter.adapter.prepare_initialize_params(params, cx)
511 })??;
512
513 Self::setup_lsp_messages(
514 lsp_store.clone(),
515 &language_server,
516 delegate.clone(),
517 adapter.clone(),
518 );
519
520 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
521 settings: workspace_config,
522 };
523 let language_server = cx
524 .update(|cx| {
525 language_server.initialize(
526 initialization_params,
527 Arc::new(did_change_configuration_params.clone()),
528 cx,
529 )
530 })?
531 .await
532 .inspect_err(|_| {
533 if let Some(lsp_store) = lsp_store.upgrade() {
534 lsp_store
535 .update(cx, |lsp_store, cx| {
536 lsp_store.cleanup_lsp_data(server_id);
537 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
538 })
539 .ok();
540 }
541 })?;
542
543 language_server.notify::<lsp::notification::DidChangeConfiguration>(
544 did_change_configuration_params,
545 )?;
546
547 anyhow::Ok(language_server)
548 }
549 .await;
550
551 match result {
552 Ok(server) => {
553 lsp_store
554 .update(cx, |lsp_store, cx| {
555 lsp_store.insert_newly_running_language_server(
556 adapter,
557 server.clone(),
558 server_id,
559 key,
560 pending_workspace_folders,
561 cx,
562 );
563 })
564 .ok();
565 stderr_capture.lock().take();
566 Some(server)
567 }
568
569 Err(err) => {
570 let log = stderr_capture.lock().take().unwrap_or_default();
571 delegate.update_status(
572 adapter.name(),
573 BinaryStatus::Failed {
574 error: if log.is_empty() {
575 format!("{err:#}")
576 } else {
577 format!("{err:#}\n-- stderr --\n{log}")
578 },
579 },
580 );
581 log::error!(
582 "Failed to start language server {server_name:?}: {}",
583 redact_command(&format!("{err:?}"))
584 );
585 if !log.is_empty() {
586 log::error!("server stderr: {}", redact_command(&log));
587 }
588 None
589 }
590 }
591 })
592 };
593 let state = LanguageServerState::Starting {
594 startup,
595 pending_workspace_folders,
596 };
597
598 if update_binary_status {
599 self.languages
600 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
601 }
602
603 self.language_servers.insert(server_id, state);
604 self.language_server_ids
605 .entry(key)
606 .or_insert(UnifiedLanguageServer {
607 id: server_id,
608 project_roots: Default::default(),
609 });
610 server_id
611 }
612
613 fn get_language_server_binary(
614 &self,
615 worktree_abs_path: Arc<Path>,
616 adapter: Arc<CachedLspAdapter>,
617 settings: Arc<LspSettings>,
618 toolchain: Option<Toolchain>,
619 delegate: Arc<dyn LspAdapterDelegate>,
620 allow_binary_download: bool,
621 untrusted_worktree_task: Option<Receiver<()>>,
622 cx: &mut App,
623 ) -> Task<Result<LanguageServerBinary>> {
624 if let Some(settings) = &settings.binary
625 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
626 {
627 let settings = settings.clone();
628 let languages = self.languages.clone();
629 return cx.background_spawn(async move {
630 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
631 log::info!(
632 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
633 adapter.name(),
634 );
635 untrusted_worktree_task.recv().await.ok();
636 log::info!(
637 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
638 adapter.name(),
639 );
640 languages
641 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
642 }
643 let mut env = delegate.shell_env().await;
644 env.extend(settings.env.unwrap_or_default());
645
646 Ok(LanguageServerBinary {
647 path: delegate.resolve_executable_path(path),
648 env: Some(env),
649 arguments: settings
650 .arguments
651 .unwrap_or_default()
652 .iter()
653 .map(Into::into)
654 .collect(),
655 })
656 });
657 }
658 let lsp_binary_options = LanguageServerBinaryOptions {
659 allow_path_lookup: !settings
660 .binary
661 .as_ref()
662 .and_then(|b| b.ignore_system_version)
663 .unwrap_or_default(),
664 allow_binary_download,
665 pre_release: settings
666 .fetch
667 .as_ref()
668 .and_then(|f| f.pre_release)
669 .unwrap_or(false),
670 };
671
672 cx.spawn(async move |cx| {
673 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
674 log::info!(
675 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
676 adapter.name(),
677 );
678 untrusted_worktree_task.recv().await.ok();
679 log::info!(
680 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
681 adapter.name(),
682 );
683 }
684
685 let (existing_binary, maybe_download_binary) = adapter
686 .clone()
687 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
688 .await
689 .await;
690
691 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
692
693 let mut binary = match (existing_binary, maybe_download_binary) {
694 (binary, None) => binary?,
695 (Err(_), Some(downloader)) => downloader.await?,
696 (Ok(existing_binary), Some(downloader)) => {
697 let mut download_timeout = cx
698 .background_executor()
699 .timer(SERVER_DOWNLOAD_TIMEOUT)
700 .fuse();
701 let mut downloader = downloader.fuse();
702 futures::select! {
703 _ = download_timeout => {
704 // Return existing binary and kick the existing work to the background.
705 cx.spawn(async move |_| downloader.await).detach();
706 Ok(existing_binary)
707 },
708 downloaded_or_existing_binary = downloader => {
709 // If download fails, this results in the existing binary.
710 downloaded_or_existing_binary
711 }
712 }?
713 }
714 };
715 let mut shell_env = delegate.shell_env().await;
716
717 shell_env.extend(binary.env.unwrap_or_default());
718
719 if let Some(settings) = settings.binary.as_ref() {
720 if let Some(arguments) = &settings.arguments {
721 binary.arguments = arguments.iter().map(Into::into).collect();
722 }
723 if let Some(env) = &settings.env {
724 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
725 }
726 }
727
728 binary.env = Some(shell_env);
729 Ok(binary)
730 })
731 }
732
733 fn setup_lsp_messages(
734 lsp_store: WeakEntity<LspStore>,
735 language_server: &LanguageServer,
736 delegate: Arc<dyn LspAdapterDelegate>,
737 adapter: Arc<CachedLspAdapter>,
738 ) {
739 let name = language_server.name();
740 let server_id = language_server.server_id();
741 language_server
742 .on_notification::<lsp::notification::PublishDiagnostics, _>({
743 let adapter = adapter.clone();
744 let this = lsp_store.clone();
745 move |mut params, cx| {
746 let adapter = adapter.clone();
747 if let Some(this) = this.upgrade() {
748 this.update(cx, |this, cx| {
749 {
750 let buffer = params
751 .uri
752 .to_file_path()
753 .map(|file_path| this.get_buffer(&file_path, cx))
754 .ok()
755 .flatten();
756 adapter.process_diagnostics(&mut params, server_id, buffer);
757 }
758
759 this.merge_lsp_diagnostics(
760 DiagnosticSourceKind::Pushed,
761 vec![DocumentDiagnosticsUpdate {
762 server_id,
763 diagnostics: params,
764 result_id: None,
765 disk_based_sources: Cow::Borrowed(
766 &adapter.disk_based_diagnostic_sources,
767 ),
768 registration_id: None,
769 }],
770 |_, diagnostic, cx| match diagnostic.source_kind {
771 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
772 adapter.retain_old_diagnostic(diagnostic, cx)
773 }
774 DiagnosticSourceKind::Pulled => true,
775 },
776 cx,
777 )
778 .log_err();
779 })
780 .ok();
781 }
782 }
783 })
784 .detach();
785 language_server
786 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
787 let adapter = adapter.adapter.clone();
788 let delegate = delegate.clone();
789 let this = lsp_store.clone();
790 move |params, cx| {
791 let adapter = adapter.clone();
792 let delegate = delegate.clone();
793 let this = this.clone();
794 let mut cx = cx.clone();
795 async move {
796 let toolchain_for_id = this
797 .update(&mut cx, |this, _| {
798 this.as_local()?.language_server_ids.iter().find_map(
799 |(seed, value)| {
800 (value.id == server_id).then(|| seed.toolchain.clone())
801 },
802 )
803 })?
804 .context("Expected the LSP store to be in a local mode")?;
805
806 let mut scope_uri_to_workspace_config = BTreeMap::new();
807 for item in ¶ms.items {
808 let scope_uri = item.scope_uri.clone();
809 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
810 scope_uri_to_workspace_config.entry(scope_uri.clone())
811 else {
812 // We've already queried workspace configuration of this URI.
813 continue;
814 };
815 let workspace_config = Self::workspace_configuration_for_adapter(
816 adapter.clone(),
817 &delegate,
818 toolchain_for_id.clone(),
819 scope_uri,
820 &mut cx,
821 )
822 .await?;
823 new_scope_uri.insert(workspace_config);
824 }
825
826 Ok(params
827 .items
828 .into_iter()
829 .filter_map(|item| {
830 let workspace_config =
831 scope_uri_to_workspace_config.get(&item.scope_uri)?;
832 if let Some(section) = &item.section {
833 Some(
834 workspace_config
835 .get(section)
836 .cloned()
837 .unwrap_or(serde_json::Value::Null),
838 )
839 } else {
840 Some(workspace_config.clone())
841 }
842 })
843 .collect())
844 }
845 }
846 })
847 .detach();
848
849 language_server
850 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
851 let this = lsp_store.clone();
852 move |_, cx| {
853 let this = this.clone();
854 let cx = cx.clone();
855 async move {
856 let Some(server) =
857 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
858 else {
859 return Ok(None);
860 };
861 let root = server.workspace_folders();
862 Ok(Some(
863 root.into_iter()
864 .map(|uri| WorkspaceFolder {
865 uri,
866 name: Default::default(),
867 })
868 .collect(),
869 ))
870 }
871 }
872 })
873 .detach();
874 // Even though we don't have handling for these requests, respond to them to
875 // avoid stalling any language server like `gopls` which waits for a response
876 // to these requests when initializing.
877 language_server
878 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
879 let this = lsp_store.clone();
880 move |params, cx| {
881 let this = this.clone();
882 let mut cx = cx.clone();
883 async move {
884 this.update(&mut cx, |this, _| {
885 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
886 {
887 status
888 .progress_tokens
889 .insert(ProgressToken::from_lsp(params.token));
890 }
891 })?;
892
893 Ok(())
894 }
895 }
896 })
897 .detach();
898
899 language_server
900 .on_request::<lsp::request::RegisterCapability, _, _>({
901 let lsp_store = lsp_store.clone();
902 move |params, cx| {
903 let lsp_store = lsp_store.clone();
904 let mut cx = cx.clone();
905 async move {
906 lsp_store
907 .update(&mut cx, |lsp_store, cx| {
908 if lsp_store.as_local().is_some() {
909 match lsp_store
910 .register_server_capabilities(server_id, params, cx)
911 {
912 Ok(()) => {}
913 Err(e) => {
914 log::error!(
915 "Failed to register server capabilities: {e:#}"
916 );
917 }
918 };
919 }
920 })
921 .ok();
922 Ok(())
923 }
924 }
925 })
926 .detach();
927
928 language_server
929 .on_request::<lsp::request::UnregisterCapability, _, _>({
930 let lsp_store = lsp_store.clone();
931 move |params, cx| {
932 let lsp_store = lsp_store.clone();
933 let mut cx = cx.clone();
934 async move {
935 lsp_store
936 .update(&mut cx, |lsp_store, cx| {
937 if lsp_store.as_local().is_some() {
938 match lsp_store
939 .unregister_server_capabilities(server_id, params, cx)
940 {
941 Ok(()) => {}
942 Err(e) => {
943 log::error!(
944 "Failed to unregister server capabilities: {e:#}"
945 );
946 }
947 }
948 }
949 })
950 .ok();
951 Ok(())
952 }
953 }
954 })
955 .detach();
956
957 language_server
958 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
959 let this = lsp_store.clone();
960 move |params, cx| {
961 let mut cx = cx.clone();
962 let this = this.clone();
963 async move {
964 LocalLspStore::on_lsp_workspace_edit(
965 this.clone(),
966 params,
967 server_id,
968 &mut cx,
969 )
970 .await
971 }
972 }
973 })
974 .detach();
975
976 language_server
977 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
978 let lsp_store = lsp_store.clone();
979 let request_id = Arc::new(AtomicUsize::new(0));
980 move |(), cx| {
981 let lsp_store = lsp_store.clone();
982 let request_id = request_id.clone();
983 let mut cx = cx.clone();
984 async move {
985 lsp_store
986 .update(&mut cx, |lsp_store, cx| {
987 let request_id =
988 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
989 cx.emit(LspStoreEvent::RefreshInlayHints {
990 server_id,
991 request_id,
992 });
993 lsp_store
994 .downstream_client
995 .as_ref()
996 .map(|(client, project_id)| {
997 client.send(proto::RefreshInlayHints {
998 project_id: *project_id,
999 server_id: server_id.to_proto(),
1000 request_id: request_id.map(|id| id as u64),
1001 })
1002 })
1003 })?
1004 .transpose()?;
1005 Ok(())
1006 }
1007 }
1008 })
1009 .detach();
1010
1011 language_server
1012 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1013 let this = lsp_store.clone();
1014 move |(), cx| {
1015 let this = this.clone();
1016 let mut cx = cx.clone();
1017 async move {
1018 this.update(&mut cx, |this, cx| {
1019 cx.emit(LspStoreEvent::RefreshCodeLens);
1020 this.downstream_client.as_ref().map(|(client, project_id)| {
1021 client.send(proto::RefreshCodeLens {
1022 project_id: *project_id,
1023 })
1024 })
1025 })?
1026 .transpose()?;
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1035 let this = lsp_store.clone();
1036 move |(), cx| {
1037 let this = this.clone();
1038 let mut cx = cx.clone();
1039 async move {
1040 this.update(&mut cx, |lsp_store, _| {
1041 lsp_store.pull_workspace_diagnostics(server_id);
1042 lsp_store
1043 .downstream_client
1044 .as_ref()
1045 .map(|(client, project_id)| {
1046 client.send(proto::PullWorkspaceDiagnostics {
1047 project_id: *project_id,
1048 server_id: server_id.to_proto(),
1049 })
1050 })
1051 })?
1052 .transpose()?;
1053 Ok(())
1054 }
1055 }
1056 })
1057 .detach();
1058
1059 language_server
1060 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1061 let this = lsp_store.clone();
1062 let name = name.to_string();
1063 let adapter = adapter.clone();
1064 move |params, cx| {
1065 let this = this.clone();
1066 let name = name.to_string();
1067 let adapter = adapter.clone();
1068 let mut cx = cx.clone();
1069 async move {
1070 let actions = params.actions.unwrap_or_default();
1071 let message = params.message.clone();
1072 let (tx, rx) = smol::channel::bounded(1);
1073 let request = LanguageServerPromptRequest {
1074 level: match params.typ {
1075 lsp::MessageType::ERROR => PromptLevel::Critical,
1076 lsp::MessageType::WARNING => PromptLevel::Warning,
1077 _ => PromptLevel::Info,
1078 },
1079 message: params.message,
1080 actions,
1081 response_channel: tx,
1082 lsp_name: name.clone(),
1083 };
1084
1085 let did_update = this
1086 .update(&mut cx, |_, cx| {
1087 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1088 })
1089 .is_ok();
1090 if did_update {
1091 let response = rx.recv().await.ok();
1092 if let Some(ref selected_action) = response {
1093 let context = language::PromptResponseContext {
1094 message,
1095 selected_action: selected_action.clone(),
1096 };
1097 adapter.process_prompt_response(&context, &mut cx)
1098 }
1099
1100 Ok(response)
1101 } else {
1102 Ok(None)
1103 }
1104 }
1105 }
1106 })
1107 .detach();
1108 language_server
1109 .on_notification::<lsp::notification::ShowMessage, _>({
1110 let this = lsp_store.clone();
1111 let name = name.to_string();
1112 move |params, cx| {
1113 let this = this.clone();
1114 let name = name.to_string();
1115 let mut cx = cx.clone();
1116
1117 let (tx, _) = smol::channel::bounded(1);
1118 let request = LanguageServerPromptRequest {
1119 level: match params.typ {
1120 lsp::MessageType::ERROR => PromptLevel::Critical,
1121 lsp::MessageType::WARNING => PromptLevel::Warning,
1122 _ => PromptLevel::Info,
1123 },
1124 message: params.message,
1125 actions: vec![],
1126 response_channel: tx,
1127 lsp_name: name,
1128 };
1129
1130 let _ = this.update(&mut cx, |_, cx| {
1131 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1132 });
1133 }
1134 })
1135 .detach();
1136
1137 let disk_based_diagnostics_progress_token =
1138 adapter.disk_based_diagnostics_progress_token.clone();
1139
1140 language_server
1141 .on_notification::<lsp::notification::Progress, _>({
1142 let this = lsp_store.clone();
1143 move |params, cx| {
1144 if let Some(this) = this.upgrade() {
1145 this.update(cx, |this, cx| {
1146 this.on_lsp_progress(
1147 params,
1148 server_id,
1149 disk_based_diagnostics_progress_token.clone(),
1150 cx,
1151 );
1152 })
1153 .ok();
1154 }
1155 }
1156 })
1157 .detach();
1158
1159 language_server
1160 .on_notification::<lsp::notification::LogMessage, _>({
1161 let this = lsp_store.clone();
1162 move |params, cx| {
1163 if let Some(this) = this.upgrade() {
1164 this.update(cx, |_, cx| {
1165 cx.emit(LspStoreEvent::LanguageServerLog(
1166 server_id,
1167 LanguageServerLogType::Log(params.typ),
1168 params.message,
1169 ));
1170 })
1171 .ok();
1172 }
1173 }
1174 })
1175 .detach();
1176
1177 language_server
1178 .on_notification::<lsp::notification::LogTrace, _>({
1179 let this = lsp_store.clone();
1180 move |params, cx| {
1181 let mut cx = cx.clone();
1182 if let Some(this) = this.upgrade() {
1183 this.update(&mut cx, |_, cx| {
1184 cx.emit(LspStoreEvent::LanguageServerLog(
1185 server_id,
1186 LanguageServerLogType::Trace {
1187 verbose_info: params.verbose,
1188 },
1189 params.message,
1190 ));
1191 })
1192 .ok();
1193 }
1194 }
1195 })
1196 .detach();
1197
1198 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1199 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1200 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1201 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1202 }
1203
1204 fn shutdown_language_servers_on_quit(
1205 &mut self,
1206 _: &mut Context<LspStore>,
1207 ) -> impl Future<Output = ()> + use<> {
1208 let shutdown_futures = self
1209 .language_servers
1210 .drain()
1211 .map(|(_, server_state)| Self::shutdown_server(server_state))
1212 .collect::<Vec<_>>();
1213
1214 async move {
1215 join_all(shutdown_futures).await;
1216 }
1217 }
1218
1219 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1220 match server_state {
1221 LanguageServerState::Running { server, .. } => {
1222 if let Some(shutdown) = server.shutdown() {
1223 shutdown.await;
1224 }
1225 }
1226 LanguageServerState::Starting { startup, .. } => {
1227 if let Some(server) = startup.await
1228 && let Some(shutdown) = server.shutdown()
1229 {
1230 shutdown.await;
1231 }
1232 }
1233 }
1234 Ok(())
1235 }
1236
1237 fn language_servers_for_worktree(
1238 &self,
1239 worktree_id: WorktreeId,
1240 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1241 self.language_server_ids
1242 .iter()
1243 .filter_map(move |(seed, state)| {
1244 if seed.worktree_id != worktree_id {
1245 return None;
1246 }
1247
1248 if let Some(LanguageServerState::Running { server, .. }) =
1249 self.language_servers.get(&state.id)
1250 {
1251 Some(server)
1252 } else {
1253 None
1254 }
1255 })
1256 }
1257
1258 fn language_server_ids_for_project_path(
1259 &self,
1260 project_path: ProjectPath,
1261 language: &Language,
1262 cx: &mut App,
1263 ) -> Vec<LanguageServerId> {
1264 let Some(worktree) = self
1265 .worktree_store
1266 .read(cx)
1267 .worktree_for_id(project_path.worktree_id, cx)
1268 else {
1269 return Vec::new();
1270 };
1271 let delegate: Arc<dyn ManifestDelegate> =
1272 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1273
1274 self.lsp_tree
1275 .get(
1276 project_path,
1277 language.name(),
1278 language.manifest(),
1279 &delegate,
1280 cx,
1281 )
1282 .collect::<Vec<_>>()
1283 }
1284
1285 fn language_server_ids_for_buffer(
1286 &self,
1287 buffer: &Buffer,
1288 cx: &mut App,
1289 ) -> Vec<LanguageServerId> {
1290 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1291 let worktree_id = file.worktree_id(cx);
1292
1293 let path: Arc<RelPath> = file
1294 .path()
1295 .parent()
1296 .map(Arc::from)
1297 .unwrap_or_else(|| file.path().clone());
1298 let worktree_path = ProjectPath { worktree_id, path };
1299 self.language_server_ids_for_project_path(worktree_path, language, cx)
1300 } else {
1301 Vec::new()
1302 }
1303 }
1304
1305 fn language_servers_for_buffer<'a>(
1306 &'a self,
1307 buffer: &'a Buffer,
1308 cx: &'a mut App,
1309 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1310 self.language_server_ids_for_buffer(buffer, cx)
1311 .into_iter()
1312 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1313 LanguageServerState::Running {
1314 adapter, server, ..
1315 } => Some((adapter, server)),
1316 _ => None,
1317 })
1318 }
1319
1320 async fn execute_code_action_kind_locally(
1321 lsp_store: WeakEntity<LspStore>,
1322 mut buffers: Vec<Entity<Buffer>>,
1323 kind: CodeActionKind,
1324 push_to_history: bool,
1325 cx: &mut AsyncApp,
1326 ) -> anyhow::Result<ProjectTransaction> {
1327 // Do not allow multiple concurrent code actions requests for the
1328 // same buffer.
1329 lsp_store.update(cx, |this, cx| {
1330 let this = this.as_local_mut().unwrap();
1331 buffers.retain(|buffer| {
1332 this.buffers_being_formatted
1333 .insert(buffer.read(cx).remote_id())
1334 });
1335 })?;
1336 let _cleanup = defer({
1337 let this = lsp_store.clone();
1338 let mut cx = cx.clone();
1339 let buffers = &buffers;
1340 move || {
1341 this.update(&mut cx, |this, cx| {
1342 let this = this.as_local_mut().unwrap();
1343 for buffer in buffers {
1344 this.buffers_being_formatted
1345 .remove(&buffer.read(cx).remote_id());
1346 }
1347 })
1348 .ok();
1349 }
1350 });
1351 let mut project_transaction = ProjectTransaction::default();
1352
1353 for buffer in &buffers {
1354 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1355 buffer.update(cx, |buffer, cx| {
1356 lsp_store
1357 .as_local()
1358 .unwrap()
1359 .language_servers_for_buffer(buffer, cx)
1360 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1361 .collect::<Vec<_>>()
1362 })
1363 })?;
1364 for (_, language_server) in adapters_and_servers.iter() {
1365 let actions = Self::get_server_code_actions_from_action_kinds(
1366 &lsp_store,
1367 language_server.server_id(),
1368 vec![kind.clone()],
1369 buffer,
1370 cx,
1371 )
1372 .await?;
1373 Self::execute_code_actions_on_server(
1374 &lsp_store,
1375 language_server,
1376 actions,
1377 push_to_history,
1378 &mut project_transaction,
1379 cx,
1380 )
1381 .await?;
1382 }
1383 }
1384 Ok(project_transaction)
1385 }
1386
1387 async fn format_locally(
1388 lsp_store: WeakEntity<LspStore>,
1389 mut buffers: Vec<FormattableBuffer>,
1390 push_to_history: bool,
1391 trigger: FormatTrigger,
1392 logger: zlog::Logger,
1393 cx: &mut AsyncApp,
1394 ) -> anyhow::Result<ProjectTransaction> {
1395 // Do not allow multiple concurrent formatting requests for the
1396 // same buffer.
1397 lsp_store.update(cx, |this, cx| {
1398 let this = this.as_local_mut().unwrap();
1399 buffers.retain(|buffer| {
1400 this.buffers_being_formatted
1401 .insert(buffer.handle.read(cx).remote_id())
1402 });
1403 })?;
1404
1405 let _cleanup = defer({
1406 let this = lsp_store.clone();
1407 let mut cx = cx.clone();
1408 let buffers = &buffers;
1409 move || {
1410 this.update(&mut cx, |this, cx| {
1411 let this = this.as_local_mut().unwrap();
1412 for buffer in buffers {
1413 this.buffers_being_formatted
1414 .remove(&buffer.handle.read(cx).remote_id());
1415 }
1416 })
1417 .ok();
1418 }
1419 });
1420
1421 let mut project_transaction = ProjectTransaction::default();
1422
1423 for buffer in &buffers {
1424 zlog::debug!(
1425 logger =>
1426 "formatting buffer '{:?}'",
1427 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1428 );
1429 // Create an empty transaction to hold all of the formatting edits.
1430 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1431 // ensure no transactions created while formatting are
1432 // grouped with the previous transaction in the history
1433 // based on the transaction group interval
1434 buffer.finalize_last_transaction();
1435 buffer
1436 .start_transaction()
1437 .context("transaction already open")?;
1438 buffer.end_transaction(cx);
1439 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1440 buffer.finalize_last_transaction();
1441 anyhow::Ok(transaction_id)
1442 })??;
1443
1444 let result = Self::format_buffer_locally(
1445 lsp_store.clone(),
1446 buffer,
1447 formatting_transaction_id,
1448 trigger,
1449 logger,
1450 cx,
1451 )
1452 .await;
1453
1454 buffer.handle.update(cx, |buffer, cx| {
1455 let Some(formatting_transaction) =
1456 buffer.get_transaction(formatting_transaction_id).cloned()
1457 else {
1458 zlog::warn!(logger => "no formatting transaction");
1459 return;
1460 };
1461 if formatting_transaction.edit_ids.is_empty() {
1462 zlog::debug!(logger => "no changes made while formatting");
1463 buffer.forget_transaction(formatting_transaction_id);
1464 return;
1465 }
1466 if !push_to_history {
1467 zlog::trace!(logger => "forgetting format transaction");
1468 buffer.forget_transaction(formatting_transaction.id);
1469 }
1470 project_transaction
1471 .0
1472 .insert(cx.entity(), formatting_transaction);
1473 })?;
1474
1475 result?;
1476 }
1477
1478 Ok(project_transaction)
1479 }
1480
1481 async fn format_buffer_locally(
1482 lsp_store: WeakEntity<LspStore>,
1483 buffer: &FormattableBuffer,
1484 formatting_transaction_id: clock::Lamport,
1485 trigger: FormatTrigger,
1486 logger: zlog::Logger,
1487 cx: &mut AsyncApp,
1488 ) -> Result<()> {
1489 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1490 buffer.handle.update(cx, |buffer, cx| {
1491 let adapters_and_servers = lsp_store
1492 .as_local()
1493 .unwrap()
1494 .language_servers_for_buffer(buffer, cx)
1495 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1496 .collect::<Vec<_>>();
1497 let settings =
1498 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1499 .into_owned();
1500 (adapters_and_servers, settings)
1501 })
1502 })?;
1503
1504 /// Apply edits to the buffer that will become part of the formatting transaction.
1505 /// Fails if the buffer has been edited since the start of that transaction.
1506 fn extend_formatting_transaction(
1507 buffer: &FormattableBuffer,
1508 formatting_transaction_id: text::TransactionId,
1509 cx: &mut AsyncApp,
1510 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1511 ) -> anyhow::Result<()> {
1512 buffer.handle.update(cx, |buffer, cx| {
1513 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1514 if last_transaction_id != Some(formatting_transaction_id) {
1515 anyhow::bail!("Buffer edited while formatting. Aborting")
1516 }
1517 buffer.start_transaction();
1518 operation(buffer, cx);
1519 if let Some(transaction_id) = buffer.end_transaction(cx) {
1520 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1521 }
1522 Ok(())
1523 })?
1524 }
1525
1526 // handle whitespace formatting
1527 if settings.remove_trailing_whitespace_on_save {
1528 zlog::trace!(logger => "removing trailing whitespace");
1529 let diff = buffer
1530 .handle
1531 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1532 .await;
1533 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1534 buffer.apply_diff(diff, cx);
1535 })?;
1536 }
1537
1538 if settings.ensure_final_newline_on_save {
1539 zlog::trace!(logger => "ensuring final newline");
1540 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1541 buffer.ensure_final_newline(cx);
1542 })?;
1543 }
1544
1545 // Formatter for `code_actions_on_format` that runs before
1546 // the rest of the formatters
1547 let mut code_actions_on_format_formatters = None;
1548 let should_run_code_actions_on_format = !matches!(
1549 (trigger, &settings.format_on_save),
1550 (FormatTrigger::Save, &FormatOnSave::Off)
1551 );
1552 if should_run_code_actions_on_format {
1553 let have_code_actions_to_run_on_format = settings
1554 .code_actions_on_format
1555 .values()
1556 .any(|enabled| *enabled);
1557 if have_code_actions_to_run_on_format {
1558 zlog::trace!(logger => "going to run code actions on format");
1559 code_actions_on_format_formatters = Some(
1560 settings
1561 .code_actions_on_format
1562 .iter()
1563 .filter_map(|(action, enabled)| enabled.then_some(action))
1564 .cloned()
1565 .map(Formatter::CodeAction)
1566 .collect::<Vec<_>>(),
1567 );
1568 }
1569 }
1570
1571 let formatters = match (trigger, &settings.format_on_save) {
1572 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1573 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1574 settings.formatter.as_ref()
1575 }
1576 };
1577
1578 let formatters = code_actions_on_format_formatters
1579 .iter()
1580 .flatten()
1581 .chain(formatters);
1582
1583 for formatter in formatters {
1584 let formatter = if formatter == &Formatter::Auto {
1585 if settings.prettier.allowed {
1586 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1587 &Formatter::Prettier
1588 } else {
1589 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1590 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1591 }
1592 } else {
1593 formatter
1594 };
1595 match formatter {
1596 Formatter::Auto => unreachable!("Auto resolved above"),
1597 Formatter::Prettier => {
1598 let logger = zlog::scoped!(logger => "prettier");
1599 zlog::trace!(logger => "formatting");
1600 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1601
1602 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1603 lsp_store.prettier_store().unwrap().downgrade()
1604 })?;
1605 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1606 .await
1607 .transpose()?;
1608 let Some(diff) = diff else {
1609 zlog::trace!(logger => "No changes");
1610 continue;
1611 };
1612
1613 extend_formatting_transaction(
1614 buffer,
1615 formatting_transaction_id,
1616 cx,
1617 |buffer, cx| {
1618 buffer.apply_diff(diff, cx);
1619 },
1620 )?;
1621 }
1622 Formatter::External { command, arguments } => {
1623 let logger = zlog::scoped!(logger => "command");
1624 zlog::trace!(logger => "formatting");
1625 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1626
1627 let diff = Self::format_via_external_command(
1628 buffer,
1629 command.as_ref(),
1630 arguments.as_deref(),
1631 cx,
1632 )
1633 .await
1634 .with_context(|| {
1635 format!("Failed to format buffer via external command: {}", command)
1636 })?;
1637 let Some(diff) = diff else {
1638 zlog::trace!(logger => "No changes");
1639 continue;
1640 };
1641
1642 extend_formatting_transaction(
1643 buffer,
1644 formatting_transaction_id,
1645 cx,
1646 |buffer, cx| {
1647 buffer.apply_diff(diff, cx);
1648 },
1649 )?;
1650 }
1651 Formatter::LanguageServer(specifier) => {
1652 let logger = zlog::scoped!(logger => "language-server");
1653 zlog::trace!(logger => "formatting");
1654 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1655
1656 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1657 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1658 continue;
1659 };
1660
1661 let language_server = match specifier {
1662 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1663 adapters_and_servers.iter().find_map(|(adapter, server)| {
1664 if adapter.name.0.as_ref() == name {
1665 Some(server.clone())
1666 } else {
1667 None
1668 }
1669 })
1670 }
1671 settings::LanguageServerFormatterSpecifier::Current => {
1672 adapters_and_servers.first().map(|e| e.1.clone())
1673 }
1674 };
1675
1676 let Some(language_server) = language_server else {
1677 log::debug!(
1678 "No language server found to format buffer '{:?}'. Skipping",
1679 buffer_path_abs.as_path().to_string_lossy()
1680 );
1681 continue;
1682 };
1683
1684 zlog::trace!(
1685 logger =>
1686 "Formatting buffer '{:?}' using language server '{:?}'",
1687 buffer_path_abs.as_path().to_string_lossy(),
1688 language_server.name()
1689 );
1690
1691 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1692 zlog::trace!(logger => "formatting ranges");
1693 Self::format_ranges_via_lsp(
1694 &lsp_store,
1695 &buffer.handle,
1696 ranges,
1697 buffer_path_abs,
1698 &language_server,
1699 &settings,
1700 cx,
1701 )
1702 .await
1703 .context("Failed to format ranges via language server")?
1704 } else {
1705 zlog::trace!(logger => "formatting full");
1706 Self::format_via_lsp(
1707 &lsp_store,
1708 &buffer.handle,
1709 buffer_path_abs,
1710 &language_server,
1711 &settings,
1712 cx,
1713 )
1714 .await
1715 .context("failed to format via language server")?
1716 };
1717
1718 if edits.is_empty() {
1719 zlog::trace!(logger => "No changes");
1720 continue;
1721 }
1722 extend_formatting_transaction(
1723 buffer,
1724 formatting_transaction_id,
1725 cx,
1726 |buffer, cx| {
1727 buffer.edit(edits, None, cx);
1728 },
1729 )?;
1730 }
1731 Formatter::CodeAction(code_action_name) => {
1732 let logger = zlog::scoped!(logger => "code-actions");
1733 zlog::trace!(logger => "formatting");
1734 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1735
1736 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1737 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1738 continue;
1739 };
1740
1741 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1742 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1743
1744 let mut actions_and_servers = Vec::new();
1745
1746 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1747 let actions_result = Self::get_server_code_actions_from_action_kinds(
1748 &lsp_store,
1749 language_server.server_id(),
1750 vec![code_action_kind.clone()],
1751 &buffer.handle,
1752 cx,
1753 )
1754 .await
1755 .with_context(|| {
1756 format!(
1757 "Failed to resolve code action {:?} with language server {}",
1758 code_action_kind,
1759 language_server.name()
1760 )
1761 });
1762 let Ok(actions) = actions_result else {
1763 // note: it may be better to set result to the error and break formatters here
1764 // but for now we try to execute the actions that we can resolve and skip the rest
1765 zlog::error!(
1766 logger =>
1767 "Failed to resolve code action {:?} with language server {}",
1768 code_action_kind,
1769 language_server.name()
1770 );
1771 continue;
1772 };
1773 for action in actions {
1774 actions_and_servers.push((action, index));
1775 }
1776 }
1777
1778 if actions_and_servers.is_empty() {
1779 zlog::warn!(logger => "No code actions were resolved, continuing");
1780 continue;
1781 }
1782
1783 'actions: for (mut action, server_index) in actions_and_servers {
1784 let server = &adapters_and_servers[server_index].1;
1785
1786 let describe_code_action = |action: &CodeAction| {
1787 format!(
1788 "code action '{}' with title \"{}\" on server {}",
1789 action
1790 .lsp_action
1791 .action_kind()
1792 .unwrap_or("unknown".into())
1793 .as_str(),
1794 action.lsp_action.title(),
1795 server.name(),
1796 )
1797 };
1798
1799 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1800
1801 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1802 zlog::error!(
1803 logger =>
1804 "Failed to resolve {}. Error: {}",
1805 describe_code_action(&action),
1806 err
1807 );
1808 continue;
1809 }
1810
1811 if let Some(edit) = action.lsp_action.edit().cloned() {
1812 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1813 // but filters out and logs warnings for code actions that require unreasonably
1814 // difficult handling on our part, such as:
1815 // - applying edits that call commands
1816 // which can result in arbitrary workspace edits being sent from the server that
1817 // have no way of being tied back to the command that initiated them (i.e. we
1818 // can't know which edits are part of the format request, or if the server is done sending
1819 // actions in response to the command)
1820 // - actions that create/delete/modify/rename files other than the one we are formatting
1821 // as we then would need to handle such changes correctly in the local history as well
1822 // as the remote history through the ProjectTransaction
1823 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1824 // Supporting these actions is not impossible, but not supported as of yet.
1825 if edit.changes.is_none() && edit.document_changes.is_none() {
1826 zlog::trace!(
1827 logger =>
1828 "No changes for code action. Skipping {}",
1829 describe_code_action(&action),
1830 );
1831 continue;
1832 }
1833
1834 let mut operations = Vec::new();
1835 if let Some(document_changes) = edit.document_changes {
1836 match document_changes {
1837 lsp::DocumentChanges::Edits(edits) => operations.extend(
1838 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1839 ),
1840 lsp::DocumentChanges::Operations(ops) => operations = ops,
1841 }
1842 } else if let Some(changes) = edit.changes {
1843 operations.extend(changes.into_iter().map(|(uri, edits)| {
1844 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1845 text_document:
1846 lsp::OptionalVersionedTextDocumentIdentifier {
1847 uri,
1848 version: None,
1849 },
1850 edits: edits.into_iter().map(Edit::Plain).collect(),
1851 })
1852 }));
1853 }
1854
1855 let mut edits = Vec::with_capacity(operations.len());
1856
1857 if operations.is_empty() {
1858 zlog::trace!(
1859 logger =>
1860 "No changes for code action. Skipping {}",
1861 describe_code_action(&action),
1862 );
1863 continue;
1864 }
1865 for operation in operations {
1866 let op = match operation {
1867 lsp::DocumentChangeOperation::Edit(op) => op,
1868 lsp::DocumentChangeOperation::Op(_) => {
1869 zlog::warn!(
1870 logger =>
1871 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1872 describe_code_action(&action),
1873 );
1874 continue 'actions;
1875 }
1876 };
1877 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1878 zlog::warn!(
1879 logger =>
1880 "Failed to convert URI '{:?}' to file path. Skipping {}",
1881 &op.text_document.uri,
1882 describe_code_action(&action),
1883 );
1884 continue 'actions;
1885 };
1886 if &file_path != buffer_path_abs {
1887 zlog::warn!(
1888 logger =>
1889 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1890 file_path,
1891 buffer_path_abs,
1892 describe_code_action(&action),
1893 );
1894 continue 'actions;
1895 }
1896
1897 let mut lsp_edits = Vec::new();
1898 for edit in op.edits {
1899 match edit {
1900 Edit::Plain(edit) => {
1901 if !lsp_edits.contains(&edit) {
1902 lsp_edits.push(edit);
1903 }
1904 }
1905 Edit::Annotated(edit) => {
1906 if !lsp_edits.contains(&edit.text_edit) {
1907 lsp_edits.push(edit.text_edit);
1908 }
1909 }
1910 Edit::Snippet(_) => {
1911 zlog::warn!(
1912 logger =>
1913 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1914 describe_code_action(&action),
1915 );
1916 continue 'actions;
1917 }
1918 }
1919 }
1920 let edits_result = lsp_store
1921 .update(cx, |lsp_store, cx| {
1922 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1923 &buffer.handle,
1924 lsp_edits,
1925 server.server_id(),
1926 op.text_document.version,
1927 cx,
1928 )
1929 })?
1930 .await;
1931 let Ok(resolved_edits) = edits_result else {
1932 zlog::warn!(
1933 logger =>
1934 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1935 buffer_path_abs.as_path(),
1936 describe_code_action(&action),
1937 );
1938 continue 'actions;
1939 };
1940 edits.extend(resolved_edits);
1941 }
1942
1943 if edits.is_empty() {
1944 zlog::warn!(logger => "No edits resolved from LSP");
1945 continue;
1946 }
1947
1948 extend_formatting_transaction(
1949 buffer,
1950 formatting_transaction_id,
1951 cx,
1952 |buffer, cx| {
1953 zlog::info!(
1954 "Applying edits {edits:?}. Content: {:?}",
1955 buffer.text()
1956 );
1957 buffer.edit(edits, None, cx);
1958 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1959 },
1960 )?;
1961 }
1962
1963 if let Some(command) = action.lsp_action.command() {
1964 zlog::warn!(
1965 logger =>
1966 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1967 &command.command,
1968 );
1969
1970 // bail early if command is invalid
1971 let server_capabilities = server.capabilities();
1972 let available_commands = server_capabilities
1973 .execute_command_provider
1974 .as_ref()
1975 .map(|options| options.commands.as_slice())
1976 .unwrap_or_default();
1977 if !available_commands.contains(&command.command) {
1978 zlog::warn!(
1979 logger =>
1980 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1981 command.command,
1982 server.name(),
1983 );
1984 continue;
1985 }
1986
1987 // noop so we just ensure buffer hasn't been edited since resolving code actions
1988 extend_formatting_transaction(
1989 buffer,
1990 formatting_transaction_id,
1991 cx,
1992 |_, _| {},
1993 )?;
1994 zlog::info!(logger => "Executing command {}", &command.command);
1995
1996 lsp_store.update(cx, |this, _| {
1997 this.as_local_mut()
1998 .unwrap()
1999 .last_workspace_edits_by_language_server
2000 .remove(&server.server_id());
2001 })?;
2002
2003 let execute_command_result = server
2004 .request::<lsp::request::ExecuteCommand>(
2005 lsp::ExecuteCommandParams {
2006 command: command.command.clone(),
2007 arguments: command.arguments.clone().unwrap_or_default(),
2008 ..Default::default()
2009 },
2010 )
2011 .await
2012 .into_response();
2013
2014 if execute_command_result.is_err() {
2015 zlog::error!(
2016 logger =>
2017 "Failed to execute command '{}' as part of {}",
2018 &command.command,
2019 describe_code_action(&action),
2020 );
2021 continue 'actions;
2022 }
2023
2024 let mut project_transaction_command =
2025 lsp_store.update(cx, |this, _| {
2026 this.as_local_mut()
2027 .unwrap()
2028 .last_workspace_edits_by_language_server
2029 .remove(&server.server_id())
2030 .unwrap_or_default()
2031 })?;
2032
2033 if let Some(transaction) =
2034 project_transaction_command.0.remove(&buffer.handle)
2035 {
2036 zlog::trace!(
2037 logger =>
2038 "Successfully captured {} edits that resulted from command {}",
2039 transaction.edit_ids.len(),
2040 &command.command,
2041 );
2042 let transaction_id_project_transaction = transaction.id;
2043 buffer.handle.update(cx, |buffer, _| {
2044 // it may have been removed from history if push_to_history was
2045 // false in deserialize_workspace_edit. If so push it so we
2046 // can merge it with the format transaction
2047 // and pop the combined transaction off the history stack
2048 // later if push_to_history is false
2049 if buffer.get_transaction(transaction.id).is_none() {
2050 buffer.push_transaction(transaction, Instant::now());
2051 }
2052 buffer.merge_transactions(
2053 transaction_id_project_transaction,
2054 formatting_transaction_id,
2055 );
2056 })?;
2057 }
2058
2059 if !project_transaction_command.0.is_empty() {
2060 let mut extra_buffers = String::new();
2061 for buffer in project_transaction_command.0.keys() {
2062 buffer
2063 .read_with(cx, |b, cx| {
2064 if let Some(path) = b.project_path(cx) {
2065 if !extra_buffers.is_empty() {
2066 extra_buffers.push_str(", ");
2067 }
2068 extra_buffers.push_str(path.path.as_unix_str());
2069 }
2070 })
2071 .ok();
2072 }
2073 zlog::warn!(
2074 logger =>
2075 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2076 &command.command,
2077 extra_buffers,
2078 );
2079 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2080 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2081 // add it so it's included, and merge it into the format transaction when its created later
2082 }
2083 }
2084 }
2085 }
2086 }
2087 }
2088
2089 Ok(())
2090 }
2091
2092 pub async fn format_ranges_via_lsp(
2093 this: &WeakEntity<LspStore>,
2094 buffer_handle: &Entity<Buffer>,
2095 ranges: &[Range<Anchor>],
2096 abs_path: &Path,
2097 language_server: &Arc<LanguageServer>,
2098 settings: &LanguageSettings,
2099 cx: &mut AsyncApp,
2100 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2101 let capabilities = &language_server.capabilities();
2102 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2103 if range_formatting_provider == Some(&OneOf::Left(false)) {
2104 anyhow::bail!(
2105 "{} language server does not support range formatting",
2106 language_server.name()
2107 );
2108 }
2109
2110 let uri = file_path_to_lsp_url(abs_path)?;
2111 let text_document = lsp::TextDocumentIdentifier::new(uri);
2112
2113 let lsp_edits = {
2114 let mut lsp_ranges = Vec::new();
2115 this.update(cx, |_this, cx| {
2116 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2117 // not have been sent to the language server. This seems like a fairly systemic
2118 // issue, though, the resolution probably is not specific to formatting.
2119 //
2120 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2121 // LSP.
2122 let snapshot = buffer_handle.read(cx).snapshot();
2123 for range in ranges {
2124 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2125 }
2126 anyhow::Ok(())
2127 })??;
2128
2129 let mut edits = None;
2130 for range in lsp_ranges {
2131 if let Some(mut edit) = language_server
2132 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2133 text_document: text_document.clone(),
2134 range,
2135 options: lsp_command::lsp_formatting_options(settings),
2136 work_done_progress_params: Default::default(),
2137 })
2138 .await
2139 .into_response()?
2140 {
2141 edits.get_or_insert_with(Vec::new).append(&mut edit);
2142 }
2143 }
2144 edits
2145 };
2146
2147 if let Some(lsp_edits) = lsp_edits {
2148 this.update(cx, |this, cx| {
2149 this.as_local_mut().unwrap().edits_from_lsp(
2150 buffer_handle,
2151 lsp_edits,
2152 language_server.server_id(),
2153 None,
2154 cx,
2155 )
2156 })?
2157 .await
2158 } else {
2159 Ok(Vec::with_capacity(0))
2160 }
2161 }
2162
2163 async fn format_via_lsp(
2164 this: &WeakEntity<LspStore>,
2165 buffer: &Entity<Buffer>,
2166 abs_path: &Path,
2167 language_server: &Arc<LanguageServer>,
2168 settings: &LanguageSettings,
2169 cx: &mut AsyncApp,
2170 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2171 let logger = zlog::scoped!("lsp_format");
2172 zlog::debug!(logger => "Formatting via LSP");
2173
2174 let uri = file_path_to_lsp_url(abs_path)?;
2175 let text_document = lsp::TextDocumentIdentifier::new(uri);
2176 let capabilities = &language_server.capabilities();
2177
2178 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2179 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2180
2181 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2182 let _timer = zlog::time!(logger => "format-full");
2183 language_server
2184 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2185 text_document,
2186 options: lsp_command::lsp_formatting_options(settings),
2187 work_done_progress_params: Default::default(),
2188 })
2189 .await
2190 .into_response()?
2191 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2192 let _timer = zlog::time!(logger => "format-range");
2193 let buffer_start = lsp::Position::new(0, 0);
2194 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2195 language_server
2196 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2197 text_document: text_document.clone(),
2198 range: lsp::Range::new(buffer_start, buffer_end),
2199 options: lsp_command::lsp_formatting_options(settings),
2200 work_done_progress_params: Default::default(),
2201 })
2202 .await
2203 .into_response()?
2204 } else {
2205 None
2206 };
2207
2208 if let Some(lsp_edits) = lsp_edits {
2209 this.update(cx, |this, cx| {
2210 this.as_local_mut().unwrap().edits_from_lsp(
2211 buffer,
2212 lsp_edits,
2213 language_server.server_id(),
2214 None,
2215 cx,
2216 )
2217 })?
2218 .await
2219 } else {
2220 Ok(Vec::with_capacity(0))
2221 }
2222 }
2223
2224 async fn format_via_external_command(
2225 buffer: &FormattableBuffer,
2226 command: &str,
2227 arguments: Option<&[String]>,
2228 cx: &mut AsyncApp,
2229 ) -> Result<Option<Diff>> {
2230 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2231 let file = File::from_dyn(buffer.file())?;
2232 let worktree = file.worktree.read(cx);
2233 let mut worktree_path = worktree.abs_path().to_path_buf();
2234 if worktree.root_entry()?.is_file() {
2235 worktree_path.pop();
2236 }
2237 Some(worktree_path)
2238 })?;
2239
2240 let mut child = util::command::new_smol_command(command);
2241
2242 if let Some(buffer_env) = buffer.env.as_ref() {
2243 child.envs(buffer_env);
2244 }
2245
2246 if let Some(working_dir_path) = working_dir_path {
2247 child.current_dir(working_dir_path);
2248 }
2249
2250 if let Some(arguments) = arguments {
2251 child.args(arguments.iter().map(|arg| {
2252 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2253 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2254 } else {
2255 arg.replace("{buffer_path}", "Untitled")
2256 }
2257 }));
2258 }
2259
2260 let mut child = child
2261 .stdin(smol::process::Stdio::piped())
2262 .stdout(smol::process::Stdio::piped())
2263 .stderr(smol::process::Stdio::piped())
2264 .spawn()?;
2265
2266 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2267 let text = buffer
2268 .handle
2269 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2270 for chunk in text.chunks() {
2271 stdin.write_all(chunk.as_bytes()).await?;
2272 }
2273 stdin.flush().await?;
2274
2275 let output = child.output().await?;
2276 anyhow::ensure!(
2277 output.status.success(),
2278 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2279 output.status.code(),
2280 String::from_utf8_lossy(&output.stdout),
2281 String::from_utf8_lossy(&output.stderr),
2282 );
2283
2284 let stdout = String::from_utf8(output.stdout)?;
2285 Ok(Some(
2286 buffer
2287 .handle
2288 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2289 .await,
2290 ))
2291 }
2292
2293 async fn try_resolve_code_action(
2294 lang_server: &LanguageServer,
2295 action: &mut CodeAction,
2296 ) -> anyhow::Result<()> {
2297 match &mut action.lsp_action {
2298 LspAction::Action(lsp_action) => {
2299 if !action.resolved
2300 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2301 && lsp_action.data.is_some()
2302 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2303 {
2304 **lsp_action = lang_server
2305 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2306 .await
2307 .into_response()?;
2308 }
2309 }
2310 LspAction::CodeLens(lens) => {
2311 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2312 *lens = lang_server
2313 .request::<lsp::request::CodeLensResolve>(lens.clone())
2314 .await
2315 .into_response()?;
2316 }
2317 }
2318 LspAction::Command(_) => {}
2319 }
2320
2321 action.resolved = true;
2322 anyhow::Ok(())
2323 }
2324
2325 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2326 let buffer = buffer_handle.read(cx);
2327
2328 let file = buffer.file().cloned();
2329
2330 let Some(file) = File::from_dyn(file.as_ref()) else {
2331 return;
2332 };
2333 if !file.is_local() {
2334 return;
2335 }
2336 let path = ProjectPath::from_file(file, cx);
2337 let worktree_id = file.worktree_id(cx);
2338 let language = buffer.language().cloned();
2339
2340 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2341 for (server_id, diagnostics) in
2342 diagnostics.get(file.path()).cloned().unwrap_or_default()
2343 {
2344 self.update_buffer_diagnostics(
2345 buffer_handle,
2346 server_id,
2347 None,
2348 None,
2349 None,
2350 Vec::new(),
2351 diagnostics,
2352 cx,
2353 )
2354 .log_err();
2355 }
2356 }
2357 let Some(language) = language else {
2358 return;
2359 };
2360 let Some(snapshot) = self
2361 .worktree_store
2362 .read(cx)
2363 .worktree_for_id(worktree_id, cx)
2364 .map(|worktree| worktree.read(cx).snapshot())
2365 else {
2366 return;
2367 };
2368 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2369
2370 for server_id in
2371 self.lsp_tree
2372 .get(path, language.name(), language.manifest(), &delegate, cx)
2373 {
2374 let server = self
2375 .language_servers
2376 .get(&server_id)
2377 .and_then(|server_state| {
2378 if let LanguageServerState::Running { server, .. } = server_state {
2379 Some(server.clone())
2380 } else {
2381 None
2382 }
2383 });
2384 let server = match server {
2385 Some(server) => server,
2386 None => continue,
2387 };
2388
2389 buffer_handle.update(cx, |buffer, cx| {
2390 buffer.set_completion_triggers(
2391 server.server_id(),
2392 server
2393 .capabilities()
2394 .completion_provider
2395 .as_ref()
2396 .and_then(|provider| {
2397 provider
2398 .trigger_characters
2399 .as_ref()
2400 .map(|characters| characters.iter().cloned().collect())
2401 })
2402 .unwrap_or_default(),
2403 cx,
2404 );
2405 });
2406 }
2407 }
2408
2409 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2410 buffer.update(cx, |buffer, cx| {
2411 let Some(language) = buffer.language() else {
2412 return;
2413 };
2414 let path = ProjectPath {
2415 worktree_id: old_file.worktree_id(cx),
2416 path: old_file.path.clone(),
2417 };
2418 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2419 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2420 buffer.set_completion_triggers(server_id, Default::default(), cx);
2421 }
2422 });
2423 }
2424
2425 fn update_buffer_diagnostics(
2426 &mut self,
2427 buffer: &Entity<Buffer>,
2428 server_id: LanguageServerId,
2429 registration_id: Option<Option<SharedString>>,
2430 result_id: Option<SharedString>,
2431 version: Option<i32>,
2432 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2433 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2434 cx: &mut Context<LspStore>,
2435 ) -> Result<()> {
2436 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2437 Ordering::Equal
2438 .then_with(|| b.is_primary.cmp(&a.is_primary))
2439 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2440 .then_with(|| a.severity.cmp(&b.severity))
2441 .then_with(|| a.message.cmp(&b.message))
2442 }
2443
2444 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2445 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2446 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2447
2448 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2449 Ordering::Equal
2450 .then_with(|| a.range.start.cmp(&b.range.start))
2451 .then_with(|| b.range.end.cmp(&a.range.end))
2452 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2453 });
2454
2455 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2456
2457 let edits_since_save = std::cell::LazyCell::new(|| {
2458 let saved_version = buffer.read(cx).saved_version();
2459 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2460 });
2461
2462 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2463
2464 for (new_diagnostic, entry) in diagnostics {
2465 let start;
2466 let end;
2467 if new_diagnostic && entry.diagnostic.is_disk_based {
2468 // Some diagnostics are based on files on disk instead of buffers'
2469 // current contents. Adjust these diagnostics' ranges to reflect
2470 // any unsaved edits.
2471 // Do not alter the reused ones though, as their coordinates were stored as anchors
2472 // and were properly adjusted on reuse.
2473 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2474 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2475 } else {
2476 start = entry.range.start;
2477 end = entry.range.end;
2478 }
2479
2480 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2481 ..snapshot.clip_point_utf16(end, Bias::Right);
2482
2483 // Expand empty ranges by one codepoint
2484 if range.start == range.end {
2485 // This will be go to the next boundary when being clipped
2486 range.end.column += 1;
2487 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2488 if range.start == range.end && range.end.column > 0 {
2489 range.start.column -= 1;
2490 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2491 }
2492 }
2493
2494 sanitized_diagnostics.push(DiagnosticEntry {
2495 range,
2496 diagnostic: entry.diagnostic,
2497 });
2498 }
2499 drop(edits_since_save);
2500
2501 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2502 buffer.update(cx, |buffer, cx| {
2503 if let Some(registration_id) = registration_id {
2504 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2505 self.buffer_pull_diagnostics_result_ids
2506 .entry(server_id)
2507 .or_default()
2508 .entry(registration_id)
2509 .or_default()
2510 .insert(abs_path, result_id);
2511 }
2512 }
2513
2514 buffer.update_diagnostics(server_id, set, cx)
2515 });
2516
2517 Ok(())
2518 }
2519
2520 fn register_language_server_for_invisible_worktree(
2521 &mut self,
2522 worktree: &Entity<Worktree>,
2523 language_server_id: LanguageServerId,
2524 cx: &mut App,
2525 ) {
2526 let worktree = worktree.read(cx);
2527 let worktree_id = worktree.id();
2528 debug_assert!(!worktree.is_visible());
2529 let Some(mut origin_seed) = self
2530 .language_server_ids
2531 .iter()
2532 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2533 else {
2534 return;
2535 };
2536 origin_seed.worktree_id = worktree_id;
2537 self.language_server_ids
2538 .entry(origin_seed)
2539 .or_insert_with(|| UnifiedLanguageServer {
2540 id: language_server_id,
2541 project_roots: Default::default(),
2542 });
2543 }
2544
2545 fn register_buffer_with_language_servers(
2546 &mut self,
2547 buffer_handle: &Entity<Buffer>,
2548 only_register_servers: HashSet<LanguageServerSelector>,
2549 cx: &mut Context<LspStore>,
2550 ) {
2551 let buffer = buffer_handle.read(cx);
2552 let buffer_id = buffer.remote_id();
2553
2554 let Some(file) = File::from_dyn(buffer.file()) else {
2555 return;
2556 };
2557 if !file.is_local() {
2558 return;
2559 }
2560
2561 let abs_path = file.abs_path(cx);
2562 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2563 return;
2564 };
2565 let initial_snapshot = buffer.text_snapshot();
2566 let worktree_id = file.worktree_id(cx);
2567
2568 let Some(language) = buffer.language().cloned() else {
2569 return;
2570 };
2571 let path: Arc<RelPath> = file
2572 .path()
2573 .parent()
2574 .map(Arc::from)
2575 .unwrap_or_else(|| file.path().clone());
2576 let Some(worktree) = self
2577 .worktree_store
2578 .read(cx)
2579 .worktree_for_id(worktree_id, cx)
2580 else {
2581 return;
2582 };
2583 let language_name = language.name();
2584 let (reused, delegate, servers) = self
2585 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2586 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2587 .unwrap_or_else(|| {
2588 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2589 let delegate: Arc<dyn ManifestDelegate> =
2590 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2591
2592 let servers = self
2593 .lsp_tree
2594 .walk(
2595 ProjectPath { worktree_id, path },
2596 language.name(),
2597 language.manifest(),
2598 &delegate,
2599 cx,
2600 )
2601 .collect::<Vec<_>>();
2602 (false, lsp_delegate, servers)
2603 });
2604 let servers_and_adapters = servers
2605 .into_iter()
2606 .filter_map(|server_node| {
2607 if reused && server_node.server_id().is_none() {
2608 return None;
2609 }
2610 if !only_register_servers.is_empty() {
2611 if let Some(server_id) = server_node.server_id()
2612 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2613 {
2614 return None;
2615 }
2616 if let Some(name) = server_node.name()
2617 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2618 {
2619 return None;
2620 }
2621 }
2622
2623 let server_id = server_node.server_id_or_init(|disposition| {
2624 let path = &disposition.path;
2625
2626 {
2627 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2628
2629 let server_id = self.get_or_insert_language_server(
2630 &worktree,
2631 delegate.clone(),
2632 disposition,
2633 &language_name,
2634 cx,
2635 );
2636
2637 if let Some(state) = self.language_servers.get(&server_id)
2638 && let Ok(uri) = uri
2639 {
2640 state.add_workspace_folder(uri);
2641 };
2642 server_id
2643 }
2644 })?;
2645 let server_state = self.language_servers.get(&server_id)?;
2646 if let LanguageServerState::Running {
2647 server, adapter, ..
2648 } = server_state
2649 {
2650 Some((server.clone(), adapter.clone()))
2651 } else {
2652 None
2653 }
2654 })
2655 .collect::<Vec<_>>();
2656 for (server, adapter) in servers_and_adapters {
2657 buffer_handle.update(cx, |buffer, cx| {
2658 buffer.set_completion_triggers(
2659 server.server_id(),
2660 server
2661 .capabilities()
2662 .completion_provider
2663 .as_ref()
2664 .and_then(|provider| {
2665 provider
2666 .trigger_characters
2667 .as_ref()
2668 .map(|characters| characters.iter().cloned().collect())
2669 })
2670 .unwrap_or_default(),
2671 cx,
2672 );
2673 });
2674
2675 let snapshot = LspBufferSnapshot {
2676 version: 0,
2677 snapshot: initial_snapshot.clone(),
2678 };
2679
2680 let mut registered = false;
2681 self.buffer_snapshots
2682 .entry(buffer_id)
2683 .or_default()
2684 .entry(server.server_id())
2685 .or_insert_with(|| {
2686 registered = true;
2687 server.register_buffer(
2688 uri.clone(),
2689 adapter.language_id(&language.name()),
2690 0,
2691 initial_snapshot.text(),
2692 );
2693
2694 vec![snapshot]
2695 });
2696
2697 self.buffers_opened_in_servers
2698 .entry(buffer_id)
2699 .or_default()
2700 .insert(server.server_id());
2701 if registered {
2702 cx.emit(LspStoreEvent::LanguageServerUpdate {
2703 language_server_id: server.server_id(),
2704 name: None,
2705 message: proto::update_language_server::Variant::RegisteredForBuffer(
2706 proto::RegisteredForBuffer {
2707 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2708 buffer_id: buffer_id.to_proto(),
2709 },
2710 ),
2711 });
2712 }
2713 }
2714 }
2715
2716 fn reuse_existing_language_server<'lang_name>(
2717 &self,
2718 server_tree: &LanguageServerTree,
2719 worktree: &Entity<Worktree>,
2720 language_name: &'lang_name LanguageName,
2721 cx: &mut App,
2722 ) -> Option<(
2723 Arc<LocalLspAdapterDelegate>,
2724 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2725 )> {
2726 if worktree.read(cx).is_visible() {
2727 return None;
2728 }
2729
2730 let worktree_store = self.worktree_store.read(cx);
2731 let servers = server_tree
2732 .instances
2733 .iter()
2734 .filter(|(worktree_id, _)| {
2735 worktree_store
2736 .worktree_for_id(**worktree_id, cx)
2737 .is_some_and(|worktree| worktree.read(cx).is_visible())
2738 })
2739 .flat_map(|(worktree_id, servers)| {
2740 servers
2741 .roots
2742 .iter()
2743 .flat_map(|(_, language_servers)| language_servers)
2744 .map(move |(_, (server_node, server_languages))| {
2745 (worktree_id, server_node, server_languages)
2746 })
2747 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2748 .map(|(worktree_id, server_node, _)| {
2749 (
2750 *worktree_id,
2751 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2752 )
2753 })
2754 })
2755 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2756 acc.entry(worktree_id)
2757 .or_insert_with(Vec::new)
2758 .push(server_node);
2759 acc
2760 })
2761 .into_values()
2762 .max_by_key(|servers| servers.len())?;
2763
2764 let worktree_id = worktree.read(cx).id();
2765 let apply = move |tree: &mut LanguageServerTree| {
2766 for server_node in &servers {
2767 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2768 }
2769 servers
2770 };
2771
2772 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2773 Some((delegate, apply))
2774 }
2775
2776 pub(crate) fn unregister_old_buffer_from_language_servers(
2777 &mut self,
2778 buffer: &Entity<Buffer>,
2779 old_file: &File,
2780 cx: &mut App,
2781 ) {
2782 let old_path = match old_file.as_local() {
2783 Some(local) => local.abs_path(cx),
2784 None => return,
2785 };
2786
2787 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2788 debug_panic!("{old_path:?} is not parseable as an URI");
2789 return;
2790 };
2791 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2792 }
2793
2794 pub(crate) fn unregister_buffer_from_language_servers(
2795 &mut self,
2796 buffer: &Entity<Buffer>,
2797 file_url: &lsp::Uri,
2798 cx: &mut App,
2799 ) {
2800 buffer.update(cx, |buffer, cx| {
2801 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2802
2803 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2804 if snapshots
2805 .as_mut()
2806 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2807 {
2808 language_server.unregister_buffer(file_url.clone());
2809 }
2810 }
2811 });
2812 }
2813
2814 fn buffer_snapshot_for_lsp_version(
2815 &mut self,
2816 buffer: &Entity<Buffer>,
2817 server_id: LanguageServerId,
2818 version: Option<i32>,
2819 cx: &App,
2820 ) -> Result<TextBufferSnapshot> {
2821 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2822
2823 if let Some(version) = version {
2824 let buffer_id = buffer.read(cx).remote_id();
2825 let snapshots = if let Some(snapshots) = self
2826 .buffer_snapshots
2827 .get_mut(&buffer_id)
2828 .and_then(|m| m.get_mut(&server_id))
2829 {
2830 snapshots
2831 } else if version == 0 {
2832 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2833 // We detect this case and treat it as if the version was `None`.
2834 return Ok(buffer.read(cx).text_snapshot());
2835 } else {
2836 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2837 };
2838
2839 let found_snapshot = snapshots
2840 .binary_search_by_key(&version, |e| e.version)
2841 .map(|ix| snapshots[ix].snapshot.clone())
2842 .map_err(|_| {
2843 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2844 })?;
2845
2846 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2847 Ok(found_snapshot)
2848 } else {
2849 Ok((buffer.read(cx)).text_snapshot())
2850 }
2851 }
2852
2853 async fn get_server_code_actions_from_action_kinds(
2854 lsp_store: &WeakEntity<LspStore>,
2855 language_server_id: LanguageServerId,
2856 code_action_kinds: Vec<lsp::CodeActionKind>,
2857 buffer: &Entity<Buffer>,
2858 cx: &mut AsyncApp,
2859 ) -> Result<Vec<CodeAction>> {
2860 let actions = lsp_store
2861 .update(cx, move |this, cx| {
2862 let request = GetCodeActions {
2863 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2864 kinds: Some(code_action_kinds),
2865 };
2866 let server = LanguageServerToQuery::Other(language_server_id);
2867 this.request_lsp(buffer.clone(), server, request, cx)
2868 })?
2869 .await?;
2870 Ok(actions)
2871 }
2872
2873 pub async fn execute_code_actions_on_server(
2874 lsp_store: &WeakEntity<LspStore>,
2875 language_server: &Arc<LanguageServer>,
2876
2877 actions: Vec<CodeAction>,
2878 push_to_history: bool,
2879 project_transaction: &mut ProjectTransaction,
2880 cx: &mut AsyncApp,
2881 ) -> anyhow::Result<()> {
2882 for mut action in actions {
2883 Self::try_resolve_code_action(language_server, &mut action)
2884 .await
2885 .context("resolving a formatting code action")?;
2886
2887 if let Some(edit) = action.lsp_action.edit() {
2888 if edit.changes.is_none() && edit.document_changes.is_none() {
2889 continue;
2890 }
2891
2892 let new = Self::deserialize_workspace_edit(
2893 lsp_store.upgrade().context("project dropped")?,
2894 edit.clone(),
2895 push_to_history,
2896 language_server.clone(),
2897 cx,
2898 )
2899 .await?;
2900 project_transaction.0.extend(new.0);
2901 }
2902
2903 if let Some(command) = action.lsp_action.command() {
2904 let server_capabilities = language_server.capabilities();
2905 let available_commands = server_capabilities
2906 .execute_command_provider
2907 .as_ref()
2908 .map(|options| options.commands.as_slice())
2909 .unwrap_or_default();
2910 if available_commands.contains(&command.command) {
2911 lsp_store.update(cx, |lsp_store, _| {
2912 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2913 mode.last_workspace_edits_by_language_server
2914 .remove(&language_server.server_id());
2915 }
2916 })?;
2917
2918 language_server
2919 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2920 command: command.command.clone(),
2921 arguments: command.arguments.clone().unwrap_or_default(),
2922 ..Default::default()
2923 })
2924 .await
2925 .into_response()
2926 .context("execute command")?;
2927
2928 lsp_store.update(cx, |this, _| {
2929 if let LspStoreMode::Local(mode) = &mut this.mode {
2930 project_transaction.0.extend(
2931 mode.last_workspace_edits_by_language_server
2932 .remove(&language_server.server_id())
2933 .unwrap_or_default()
2934 .0,
2935 )
2936 }
2937 })?;
2938 } else {
2939 log::warn!(
2940 "Cannot execute a command {} not listed in the language server capabilities",
2941 command.command
2942 )
2943 }
2944 }
2945 }
2946 Ok(())
2947 }
2948
2949 pub async fn deserialize_text_edits(
2950 this: Entity<LspStore>,
2951 buffer_to_edit: Entity<Buffer>,
2952 edits: Vec<lsp::TextEdit>,
2953 push_to_history: bool,
2954 _: Arc<CachedLspAdapter>,
2955 language_server: Arc<LanguageServer>,
2956 cx: &mut AsyncApp,
2957 ) -> Result<Option<Transaction>> {
2958 let edits = this
2959 .update(cx, |this, cx| {
2960 this.as_local_mut().unwrap().edits_from_lsp(
2961 &buffer_to_edit,
2962 edits,
2963 language_server.server_id(),
2964 None,
2965 cx,
2966 )
2967 })?
2968 .await?;
2969
2970 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2971 buffer.finalize_last_transaction();
2972 buffer.start_transaction();
2973 for (range, text) in edits {
2974 buffer.edit([(range, text)], None, cx);
2975 }
2976
2977 if buffer.end_transaction(cx).is_some() {
2978 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2979 if !push_to_history {
2980 buffer.forget_transaction(transaction.id);
2981 }
2982 Some(transaction)
2983 } else {
2984 None
2985 }
2986 })?;
2987
2988 Ok(transaction)
2989 }
2990
2991 #[allow(clippy::type_complexity)]
2992 pub(crate) fn edits_from_lsp(
2993 &mut self,
2994 buffer: &Entity<Buffer>,
2995 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2996 server_id: LanguageServerId,
2997 version: Option<i32>,
2998 cx: &mut Context<LspStore>,
2999 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3000 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3001 cx.background_spawn(async move {
3002 let snapshot = snapshot?;
3003 let mut lsp_edits = lsp_edits
3004 .into_iter()
3005 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3006 .collect::<Vec<_>>();
3007
3008 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3009
3010 let mut lsp_edits = lsp_edits.into_iter().peekable();
3011 let mut edits = Vec::new();
3012 while let Some((range, mut new_text)) = lsp_edits.next() {
3013 // Clip invalid ranges provided by the language server.
3014 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3015 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3016
3017 // Combine any LSP edits that are adjacent.
3018 //
3019 // Also, combine LSP edits that are separated from each other by only
3020 // a newline. This is important because for some code actions,
3021 // Rust-analyzer rewrites the entire buffer via a series of edits that
3022 // are separated by unchanged newline characters.
3023 //
3024 // In order for the diffing logic below to work properly, any edits that
3025 // cancel each other out must be combined into one.
3026 while let Some((next_range, next_text)) = lsp_edits.peek() {
3027 if next_range.start.0 > range.end {
3028 if next_range.start.0.row > range.end.row + 1
3029 || next_range.start.0.column > 0
3030 || snapshot.clip_point_utf16(
3031 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3032 Bias::Left,
3033 ) > range.end
3034 {
3035 break;
3036 }
3037 new_text.push('\n');
3038 }
3039 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3040 new_text.push_str(next_text);
3041 lsp_edits.next();
3042 }
3043
3044 // For multiline edits, perform a diff of the old and new text so that
3045 // we can identify the changes more precisely, preserving the locations
3046 // of any anchors positioned in the unchanged regions.
3047 if range.end.row > range.start.row {
3048 let offset = range.start.to_offset(&snapshot);
3049 let old_text = snapshot.text_for_range(range).collect::<String>();
3050 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3051 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3052 (
3053 snapshot.anchor_after(offset + range.start)
3054 ..snapshot.anchor_before(offset + range.end),
3055 replacement,
3056 )
3057 }));
3058 } else if range.end == range.start {
3059 let anchor = snapshot.anchor_after(range.start);
3060 edits.push((anchor..anchor, new_text.into()));
3061 } else {
3062 let edit_start = snapshot.anchor_after(range.start);
3063 let edit_end = snapshot.anchor_before(range.end);
3064 edits.push((edit_start..edit_end, new_text.into()));
3065 }
3066 }
3067
3068 Ok(edits)
3069 })
3070 }
3071
3072 pub(crate) async fn deserialize_workspace_edit(
3073 this: Entity<LspStore>,
3074 edit: lsp::WorkspaceEdit,
3075 push_to_history: bool,
3076 language_server: Arc<LanguageServer>,
3077 cx: &mut AsyncApp,
3078 ) -> Result<ProjectTransaction> {
3079 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3080
3081 let mut operations = Vec::new();
3082 if let Some(document_changes) = edit.document_changes {
3083 match document_changes {
3084 lsp::DocumentChanges::Edits(edits) => {
3085 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3086 }
3087 lsp::DocumentChanges::Operations(ops) => operations = ops,
3088 }
3089 } else if let Some(changes) = edit.changes {
3090 operations.extend(changes.into_iter().map(|(uri, edits)| {
3091 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3092 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3093 uri,
3094 version: None,
3095 },
3096 edits: edits.into_iter().map(Edit::Plain).collect(),
3097 })
3098 }));
3099 }
3100
3101 let mut project_transaction = ProjectTransaction::default();
3102 for operation in operations {
3103 match operation {
3104 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3105 let abs_path = op
3106 .uri
3107 .to_file_path()
3108 .map_err(|()| anyhow!("can't convert URI to path"))?;
3109
3110 if let Some(parent_path) = abs_path.parent() {
3111 fs.create_dir(parent_path).await?;
3112 }
3113 if abs_path.ends_with("/") {
3114 fs.create_dir(&abs_path).await?;
3115 } else {
3116 fs.create_file(
3117 &abs_path,
3118 op.options
3119 .map(|options| fs::CreateOptions {
3120 overwrite: options.overwrite.unwrap_or(false),
3121 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3122 })
3123 .unwrap_or_default(),
3124 )
3125 .await?;
3126 }
3127 }
3128
3129 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3130 let source_abs_path = op
3131 .old_uri
3132 .to_file_path()
3133 .map_err(|()| anyhow!("can't convert URI to path"))?;
3134 let target_abs_path = op
3135 .new_uri
3136 .to_file_path()
3137 .map_err(|()| anyhow!("can't convert URI to path"))?;
3138
3139 let options = fs::RenameOptions {
3140 overwrite: op
3141 .options
3142 .as_ref()
3143 .and_then(|options| options.overwrite)
3144 .unwrap_or(false),
3145 ignore_if_exists: op
3146 .options
3147 .as_ref()
3148 .and_then(|options| options.ignore_if_exists)
3149 .unwrap_or(false),
3150 create_parents: true,
3151 };
3152
3153 fs.rename(&source_abs_path, &target_abs_path, options)
3154 .await?;
3155 }
3156
3157 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3158 let abs_path = op
3159 .uri
3160 .to_file_path()
3161 .map_err(|()| anyhow!("can't convert URI to path"))?;
3162 let options = op
3163 .options
3164 .map(|options| fs::RemoveOptions {
3165 recursive: options.recursive.unwrap_or(false),
3166 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3167 })
3168 .unwrap_or_default();
3169 if abs_path.ends_with("/") {
3170 fs.remove_dir(&abs_path, options).await?;
3171 } else {
3172 fs.remove_file(&abs_path, options).await?;
3173 }
3174 }
3175
3176 lsp::DocumentChangeOperation::Edit(op) => {
3177 let buffer_to_edit = this
3178 .update(cx, |this, cx| {
3179 this.open_local_buffer_via_lsp(
3180 op.text_document.uri.clone(),
3181 language_server.server_id(),
3182 cx,
3183 )
3184 })?
3185 .await?;
3186
3187 let edits = this
3188 .update(cx, |this, cx| {
3189 let path = buffer_to_edit.read(cx).project_path(cx);
3190 let active_entry = this.active_entry;
3191 let is_active_entry = path.is_some_and(|project_path| {
3192 this.worktree_store
3193 .read(cx)
3194 .entry_for_path(&project_path, cx)
3195 .is_some_and(|entry| Some(entry.id) == active_entry)
3196 });
3197 let local = this.as_local_mut().unwrap();
3198
3199 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3200 for edit in op.edits {
3201 match edit {
3202 Edit::Plain(edit) => {
3203 if !edits.contains(&edit) {
3204 edits.push(edit)
3205 }
3206 }
3207 Edit::Annotated(edit) => {
3208 if !edits.contains(&edit.text_edit) {
3209 edits.push(edit.text_edit)
3210 }
3211 }
3212 Edit::Snippet(edit) => {
3213 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3214 else {
3215 continue;
3216 };
3217
3218 if is_active_entry {
3219 snippet_edits.push((edit.range, snippet));
3220 } else {
3221 // Since this buffer is not focused, apply a normal edit.
3222 let new_edit = TextEdit {
3223 range: edit.range,
3224 new_text: snippet.text,
3225 };
3226 if !edits.contains(&new_edit) {
3227 edits.push(new_edit);
3228 }
3229 }
3230 }
3231 }
3232 }
3233 if !snippet_edits.is_empty() {
3234 let buffer_id = buffer_to_edit.read(cx).remote_id();
3235 let version = if let Some(buffer_version) = op.text_document.version
3236 {
3237 local
3238 .buffer_snapshot_for_lsp_version(
3239 &buffer_to_edit,
3240 language_server.server_id(),
3241 Some(buffer_version),
3242 cx,
3243 )
3244 .ok()
3245 .map(|snapshot| snapshot.version)
3246 } else {
3247 Some(buffer_to_edit.read(cx).saved_version().clone())
3248 };
3249
3250 let most_recent_edit =
3251 version.and_then(|version| version.most_recent());
3252 // Check if the edit that triggered that edit has been made by this participant.
3253
3254 if let Some(most_recent_edit) = most_recent_edit {
3255 cx.emit(LspStoreEvent::SnippetEdit {
3256 buffer_id,
3257 edits: snippet_edits,
3258 most_recent_edit,
3259 });
3260 }
3261 }
3262
3263 local.edits_from_lsp(
3264 &buffer_to_edit,
3265 edits,
3266 language_server.server_id(),
3267 op.text_document.version,
3268 cx,
3269 )
3270 })?
3271 .await?;
3272
3273 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3274 buffer.finalize_last_transaction();
3275 buffer.start_transaction();
3276 for (range, text) in edits {
3277 buffer.edit([(range, text)], None, cx);
3278 }
3279
3280 buffer.end_transaction(cx).and_then(|transaction_id| {
3281 if push_to_history {
3282 buffer.finalize_last_transaction();
3283 buffer.get_transaction(transaction_id).cloned()
3284 } else {
3285 buffer.forget_transaction(transaction_id)
3286 }
3287 })
3288 })?;
3289 if let Some(transaction) = transaction {
3290 project_transaction.0.insert(buffer_to_edit, transaction);
3291 }
3292 }
3293 }
3294 }
3295
3296 Ok(project_transaction)
3297 }
3298
3299 async fn on_lsp_workspace_edit(
3300 this: WeakEntity<LspStore>,
3301 params: lsp::ApplyWorkspaceEditParams,
3302 server_id: LanguageServerId,
3303 cx: &mut AsyncApp,
3304 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3305 let this = this.upgrade().context("project project closed")?;
3306 let language_server = this
3307 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3308 .context("language server not found")?;
3309 let transaction = Self::deserialize_workspace_edit(
3310 this.clone(),
3311 params.edit,
3312 true,
3313 language_server.clone(),
3314 cx,
3315 )
3316 .await
3317 .log_err();
3318 this.update(cx, |this, cx| {
3319 if let Some(transaction) = transaction {
3320 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3321
3322 this.as_local_mut()
3323 .unwrap()
3324 .last_workspace_edits_by_language_server
3325 .insert(server_id, transaction);
3326 }
3327 })?;
3328 Ok(lsp::ApplyWorkspaceEditResponse {
3329 applied: true,
3330 failed_change: None,
3331 failure_reason: None,
3332 })
3333 }
3334
3335 fn remove_worktree(
3336 &mut self,
3337 id_to_remove: WorktreeId,
3338 cx: &mut Context<LspStore>,
3339 ) -> Vec<LanguageServerId> {
3340 self.restricted_worktrees_tasks.remove(&id_to_remove);
3341 self.diagnostics.remove(&id_to_remove);
3342 self.prettier_store.update(cx, |prettier_store, cx| {
3343 prettier_store.remove_worktree(id_to_remove, cx);
3344 });
3345
3346 let mut servers_to_remove = BTreeSet::default();
3347 let mut servers_to_preserve = HashSet::default();
3348 for (seed, state) in &self.language_server_ids {
3349 if seed.worktree_id == id_to_remove {
3350 servers_to_remove.insert(state.id);
3351 } else {
3352 servers_to_preserve.insert(state.id);
3353 }
3354 }
3355 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3356 self.language_server_ids
3357 .retain(|_, state| !servers_to_remove.contains(&state.id));
3358 for server_id_to_remove in &servers_to_remove {
3359 self.language_server_watched_paths
3360 .remove(server_id_to_remove);
3361 self.language_server_paths_watched_for_rename
3362 .remove(server_id_to_remove);
3363 self.last_workspace_edits_by_language_server
3364 .remove(server_id_to_remove);
3365 self.language_servers.remove(server_id_to_remove);
3366 self.buffer_pull_diagnostics_result_ids
3367 .remove(server_id_to_remove);
3368 self.workspace_pull_diagnostics_result_ids
3369 .remove(server_id_to_remove);
3370 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3371 buffer_servers.remove(server_id_to_remove);
3372 }
3373 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3374 }
3375 servers_to_remove.into_iter().collect()
3376 }
3377
3378 fn rebuild_watched_paths_inner<'a>(
3379 &'a self,
3380 language_server_id: LanguageServerId,
3381 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3382 cx: &mut Context<LspStore>,
3383 ) -> LanguageServerWatchedPathsBuilder {
3384 let worktrees = self
3385 .worktree_store
3386 .read(cx)
3387 .worktrees()
3388 .filter_map(|worktree| {
3389 self.language_servers_for_worktree(worktree.read(cx).id())
3390 .find(|server| server.server_id() == language_server_id)
3391 .map(|_| worktree)
3392 })
3393 .collect::<Vec<_>>();
3394
3395 let mut worktree_globs = HashMap::default();
3396 let mut abs_globs = HashMap::default();
3397 log::trace!(
3398 "Processing new watcher paths for language server with id {}",
3399 language_server_id
3400 );
3401
3402 for watcher in watchers {
3403 if let Some((worktree, literal_prefix, pattern)) =
3404 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3405 {
3406 worktree.update(cx, |worktree, _| {
3407 if let Some((tree, glob)) =
3408 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3409 {
3410 tree.add_path_prefix_to_scan(literal_prefix);
3411 worktree_globs
3412 .entry(tree.id())
3413 .or_insert_with(GlobSetBuilder::new)
3414 .add(glob);
3415 }
3416 });
3417 } else {
3418 let (path, pattern) = match &watcher.glob_pattern {
3419 lsp::GlobPattern::String(s) => {
3420 let watcher_path = SanitizedPath::new(s);
3421 let path = glob_literal_prefix(watcher_path.as_path());
3422 let pattern = watcher_path
3423 .as_path()
3424 .strip_prefix(&path)
3425 .map(|p| p.to_string_lossy().into_owned())
3426 .unwrap_or_else(|e| {
3427 debug_panic!(
3428 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3429 s,
3430 path.display(),
3431 e
3432 );
3433 watcher_path.as_path().to_string_lossy().into_owned()
3434 });
3435 (path, pattern)
3436 }
3437 lsp::GlobPattern::Relative(rp) => {
3438 let Ok(mut base_uri) = match &rp.base_uri {
3439 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3440 lsp::OneOf::Right(base_uri) => base_uri,
3441 }
3442 .to_file_path() else {
3443 continue;
3444 };
3445
3446 let path = glob_literal_prefix(Path::new(&rp.pattern));
3447 let pattern = Path::new(&rp.pattern)
3448 .strip_prefix(&path)
3449 .map(|p| p.to_string_lossy().into_owned())
3450 .unwrap_or_else(|e| {
3451 debug_panic!(
3452 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3453 rp.pattern,
3454 path.display(),
3455 e
3456 );
3457 rp.pattern.clone()
3458 });
3459 base_uri.push(path);
3460 (base_uri, pattern)
3461 }
3462 };
3463
3464 if let Some(glob) = Glob::new(&pattern).log_err() {
3465 if !path
3466 .components()
3467 .any(|c| matches!(c, path::Component::Normal(_)))
3468 {
3469 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3470 // rather than adding a new watcher for `/`.
3471 for worktree in &worktrees {
3472 worktree_globs
3473 .entry(worktree.read(cx).id())
3474 .or_insert_with(GlobSetBuilder::new)
3475 .add(glob.clone());
3476 }
3477 } else {
3478 abs_globs
3479 .entry(path.into())
3480 .or_insert_with(GlobSetBuilder::new)
3481 .add(glob);
3482 }
3483 }
3484 }
3485 }
3486
3487 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3488 for (worktree_id, builder) in worktree_globs {
3489 if let Ok(globset) = builder.build() {
3490 watch_builder.watch_worktree(worktree_id, globset);
3491 }
3492 }
3493 for (abs_path, builder) in abs_globs {
3494 if let Ok(globset) = builder.build() {
3495 watch_builder.watch_abs_path(abs_path, globset);
3496 }
3497 }
3498 watch_builder
3499 }
3500
3501 fn worktree_and_path_for_file_watcher(
3502 worktrees: &[Entity<Worktree>],
3503 watcher: &FileSystemWatcher,
3504 cx: &App,
3505 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3506 worktrees.iter().find_map(|worktree| {
3507 let tree = worktree.read(cx);
3508 let worktree_root_path = tree.abs_path();
3509 let path_style = tree.path_style();
3510 match &watcher.glob_pattern {
3511 lsp::GlobPattern::String(s) => {
3512 let watcher_path = SanitizedPath::new(s);
3513 let relative = watcher_path
3514 .as_path()
3515 .strip_prefix(&worktree_root_path)
3516 .ok()?;
3517 let literal_prefix = glob_literal_prefix(relative);
3518 Some((
3519 worktree.clone(),
3520 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3521 relative.to_string_lossy().into_owned(),
3522 ))
3523 }
3524 lsp::GlobPattern::Relative(rp) => {
3525 let base_uri = match &rp.base_uri {
3526 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3527 lsp::OneOf::Right(base_uri) => base_uri,
3528 }
3529 .to_file_path()
3530 .ok()?;
3531 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3532 let mut literal_prefix = relative.to_owned();
3533 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3534 Some((
3535 worktree.clone(),
3536 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3537 rp.pattern.clone(),
3538 ))
3539 }
3540 }
3541 })
3542 }
3543
3544 fn rebuild_watched_paths(
3545 &mut self,
3546 language_server_id: LanguageServerId,
3547 cx: &mut Context<LspStore>,
3548 ) {
3549 let Some(registrations) = self
3550 .language_server_dynamic_registrations
3551 .get(&language_server_id)
3552 else {
3553 return;
3554 };
3555
3556 let watch_builder = self.rebuild_watched_paths_inner(
3557 language_server_id,
3558 registrations.did_change_watched_files.values().flatten(),
3559 cx,
3560 );
3561 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3562 self.language_server_watched_paths
3563 .insert(language_server_id, watcher);
3564
3565 cx.notify();
3566 }
3567
3568 fn on_lsp_did_change_watched_files(
3569 &mut self,
3570 language_server_id: LanguageServerId,
3571 registration_id: &str,
3572 params: DidChangeWatchedFilesRegistrationOptions,
3573 cx: &mut Context<LspStore>,
3574 ) {
3575 let registrations = self
3576 .language_server_dynamic_registrations
3577 .entry(language_server_id)
3578 .or_default();
3579
3580 registrations
3581 .did_change_watched_files
3582 .insert(registration_id.to_string(), params.watchers);
3583
3584 self.rebuild_watched_paths(language_server_id, cx);
3585 }
3586
3587 fn on_lsp_unregister_did_change_watched_files(
3588 &mut self,
3589 language_server_id: LanguageServerId,
3590 registration_id: &str,
3591 cx: &mut Context<LspStore>,
3592 ) {
3593 let registrations = self
3594 .language_server_dynamic_registrations
3595 .entry(language_server_id)
3596 .or_default();
3597
3598 if registrations
3599 .did_change_watched_files
3600 .remove(registration_id)
3601 .is_some()
3602 {
3603 log::info!(
3604 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3605 language_server_id,
3606 registration_id
3607 );
3608 } else {
3609 log::warn!(
3610 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3611 language_server_id,
3612 registration_id
3613 );
3614 }
3615
3616 self.rebuild_watched_paths(language_server_id, cx);
3617 }
3618
3619 async fn initialization_options_for_adapter(
3620 adapter: Arc<dyn LspAdapter>,
3621 delegate: &Arc<dyn LspAdapterDelegate>,
3622 ) -> Result<Option<serde_json::Value>> {
3623 let Some(mut initialization_config) =
3624 adapter.clone().initialization_options(delegate).await?
3625 else {
3626 return Ok(None);
3627 };
3628
3629 for other_adapter in delegate.registered_lsp_adapters() {
3630 if other_adapter.name() == adapter.name() {
3631 continue;
3632 }
3633 if let Ok(Some(target_config)) = other_adapter
3634 .clone()
3635 .additional_initialization_options(adapter.name(), delegate)
3636 .await
3637 {
3638 merge_json_value_into(target_config.clone(), &mut initialization_config);
3639 }
3640 }
3641
3642 Ok(Some(initialization_config))
3643 }
3644
3645 async fn workspace_configuration_for_adapter(
3646 adapter: Arc<dyn LspAdapter>,
3647 delegate: &Arc<dyn LspAdapterDelegate>,
3648 toolchain: Option<Toolchain>,
3649 requested_uri: Option<Uri>,
3650 cx: &mut AsyncApp,
3651 ) -> Result<serde_json::Value> {
3652 let mut workspace_config = adapter
3653 .clone()
3654 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3655 .await?;
3656
3657 for other_adapter in delegate.registered_lsp_adapters() {
3658 if other_adapter.name() == adapter.name() {
3659 continue;
3660 }
3661 if let Ok(Some(target_config)) = other_adapter
3662 .clone()
3663 .additional_workspace_configuration(adapter.name(), delegate, cx)
3664 .await
3665 {
3666 merge_json_value_into(target_config.clone(), &mut workspace_config);
3667 }
3668 }
3669
3670 Ok(workspace_config)
3671 }
3672
3673 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3674 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3675 Some(server.clone())
3676 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3677 Some(Arc::clone(server))
3678 } else {
3679 None
3680 }
3681 }
3682}
3683
3684fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3685 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3686 cx.emit(LspStoreEvent::LanguageServerUpdate {
3687 language_server_id: server.server_id(),
3688 name: Some(server.name()),
3689 message: proto::update_language_server::Variant::MetadataUpdated(
3690 proto::ServerMetadataUpdated {
3691 capabilities: Some(capabilities),
3692 binary: Some(proto::LanguageServerBinaryInfo {
3693 path: server.binary().path.to_string_lossy().into_owned(),
3694 arguments: server
3695 .binary()
3696 .arguments
3697 .iter()
3698 .map(|arg| arg.to_string_lossy().into_owned())
3699 .collect(),
3700 }),
3701 configuration: serde_json::to_string(server.configuration()).ok(),
3702 workspace_folders: server
3703 .workspace_folders()
3704 .iter()
3705 .map(|uri| uri.to_string())
3706 .collect(),
3707 },
3708 ),
3709 });
3710 }
3711}
3712
3713#[derive(Debug)]
3714pub struct FormattableBuffer {
3715 handle: Entity<Buffer>,
3716 abs_path: Option<PathBuf>,
3717 env: Option<HashMap<String, String>>,
3718 ranges: Option<Vec<Range<Anchor>>>,
3719}
3720
3721pub struct RemoteLspStore {
3722 upstream_client: Option<AnyProtoClient>,
3723 upstream_project_id: u64,
3724}
3725
3726pub(crate) enum LspStoreMode {
3727 Local(LocalLspStore), // ssh host and collab host
3728 Remote(RemoteLspStore), // collab guest
3729}
3730
3731impl LspStoreMode {
3732 fn is_local(&self) -> bool {
3733 matches!(self, LspStoreMode::Local(_))
3734 }
3735}
3736
3737pub struct LspStore {
3738 mode: LspStoreMode,
3739 last_formatting_failure: Option<String>,
3740 downstream_client: Option<(AnyProtoClient, u64)>,
3741 nonce: u128,
3742 buffer_store: Entity<BufferStore>,
3743 worktree_store: Entity<WorktreeStore>,
3744 pub languages: Arc<LanguageRegistry>,
3745 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3746 active_entry: Option<ProjectEntryId>,
3747 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3748 _maintain_buffer_languages: Task<()>,
3749 diagnostic_summaries:
3750 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3751 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3752 lsp_data: HashMap<BufferId, BufferLspData>,
3753 next_hint_id: Arc<AtomicUsize>,
3754}
3755
3756#[derive(Debug)]
3757pub struct BufferLspData {
3758 buffer_version: Global,
3759 document_colors: Option<DocumentColorData>,
3760 code_lens: Option<CodeLensData>,
3761 inlay_hints: BufferInlayHints,
3762 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3763 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3764}
3765
3766#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3767struct LspKey {
3768 request_type: TypeId,
3769 server_queried: Option<LanguageServerId>,
3770}
3771
3772impl BufferLspData {
3773 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3774 Self {
3775 buffer_version: buffer.read(cx).version(),
3776 document_colors: None,
3777 code_lens: None,
3778 inlay_hints: BufferInlayHints::new(buffer, cx),
3779 lsp_requests: HashMap::default(),
3780 chunk_lsp_requests: HashMap::default(),
3781 }
3782 }
3783
3784 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3785 if let Some(document_colors) = &mut self.document_colors {
3786 document_colors.colors.remove(&for_server);
3787 document_colors.cache_version += 1;
3788 }
3789
3790 if let Some(code_lens) = &mut self.code_lens {
3791 code_lens.lens.remove(&for_server);
3792 }
3793
3794 self.inlay_hints.remove_server_data(for_server);
3795 }
3796
3797 #[cfg(any(test, feature = "test-support"))]
3798 pub fn inlay_hints(&self) -> &BufferInlayHints {
3799 &self.inlay_hints
3800 }
3801}
3802
3803#[derive(Debug, Default, Clone)]
3804pub struct DocumentColors {
3805 pub colors: HashSet<DocumentColor>,
3806 pub cache_version: Option<usize>,
3807}
3808
3809type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3810type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3811
3812#[derive(Debug, Default)]
3813struct DocumentColorData {
3814 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3815 cache_version: usize,
3816 colors_update: Option<(Global, DocumentColorTask)>,
3817}
3818
3819#[derive(Debug, Default)]
3820struct CodeLensData {
3821 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3822 update: Option<(Global, CodeLensTask)>,
3823}
3824
3825#[derive(Debug)]
3826pub enum LspStoreEvent {
3827 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3828 LanguageServerRemoved(LanguageServerId),
3829 LanguageServerUpdate {
3830 language_server_id: LanguageServerId,
3831 name: Option<LanguageServerName>,
3832 message: proto::update_language_server::Variant,
3833 },
3834 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3835 LanguageServerPrompt(LanguageServerPromptRequest),
3836 LanguageDetected {
3837 buffer: Entity<Buffer>,
3838 new_language: Option<Arc<Language>>,
3839 },
3840 Notification(String),
3841 RefreshInlayHints {
3842 server_id: LanguageServerId,
3843 request_id: Option<usize>,
3844 },
3845 RefreshCodeLens,
3846 DiagnosticsUpdated {
3847 server_id: LanguageServerId,
3848 paths: Vec<ProjectPath>,
3849 },
3850 DiskBasedDiagnosticsStarted {
3851 language_server_id: LanguageServerId,
3852 },
3853 DiskBasedDiagnosticsFinished {
3854 language_server_id: LanguageServerId,
3855 },
3856 SnippetEdit {
3857 buffer_id: BufferId,
3858 edits: Vec<(lsp::Range, Snippet)>,
3859 most_recent_edit: clock::Lamport,
3860 },
3861 WorkspaceEditApplied(ProjectTransaction),
3862}
3863
3864#[derive(Clone, Debug, Serialize)]
3865pub struct LanguageServerStatus {
3866 pub name: LanguageServerName,
3867 pub server_version: Option<SharedString>,
3868 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3869 pub has_pending_diagnostic_updates: bool,
3870 pub progress_tokens: HashSet<ProgressToken>,
3871 pub worktree: Option<WorktreeId>,
3872 pub binary: Option<LanguageServerBinary>,
3873 pub configuration: Option<Value>,
3874 pub workspace_folders: BTreeSet<Uri>,
3875}
3876
3877#[derive(Clone, Debug)]
3878struct CoreSymbol {
3879 pub language_server_name: LanguageServerName,
3880 pub source_worktree_id: WorktreeId,
3881 pub source_language_server_id: LanguageServerId,
3882 pub path: SymbolLocation,
3883 pub name: String,
3884 pub kind: lsp::SymbolKind,
3885 pub range: Range<Unclipped<PointUtf16>>,
3886}
3887
3888#[derive(Clone, Debug, PartialEq, Eq)]
3889pub enum SymbolLocation {
3890 InProject(ProjectPath),
3891 OutsideProject {
3892 abs_path: Arc<Path>,
3893 signature: [u8; 32],
3894 },
3895}
3896
3897impl SymbolLocation {
3898 fn file_name(&self) -> Option<&str> {
3899 match self {
3900 Self::InProject(path) => path.path.file_name(),
3901 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3902 }
3903 }
3904}
3905
3906impl LspStore {
3907 pub fn init(client: &AnyProtoClient) {
3908 client.add_entity_request_handler(Self::handle_lsp_query);
3909 client.add_entity_message_handler(Self::handle_lsp_query_response);
3910 client.add_entity_request_handler(Self::handle_restart_language_servers);
3911 client.add_entity_request_handler(Self::handle_stop_language_servers);
3912 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3913 client.add_entity_message_handler(Self::handle_start_language_server);
3914 client.add_entity_message_handler(Self::handle_update_language_server);
3915 client.add_entity_message_handler(Self::handle_language_server_log);
3916 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3917 client.add_entity_request_handler(Self::handle_format_buffers);
3918 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3919 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3920 client.add_entity_request_handler(Self::handle_apply_code_action);
3921 client.add_entity_request_handler(Self::handle_get_project_symbols);
3922 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3923 client.add_entity_request_handler(Self::handle_get_color_presentation);
3924 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3925 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3926 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3927 client.add_entity_request_handler(Self::handle_on_type_formatting);
3928 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3929 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3930 client.add_entity_request_handler(Self::handle_rename_project_entry);
3931 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3932 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3933 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3934 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3935 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3936 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3937 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3938
3939 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3940 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3941 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3942 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3943 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3944 client.add_entity_request_handler(
3945 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3946 );
3947 client.add_entity_request_handler(
3948 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3949 );
3950 client.add_entity_request_handler(
3951 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3952 );
3953 }
3954
3955 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3956 match &self.mode {
3957 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3958 _ => None,
3959 }
3960 }
3961
3962 pub fn as_local(&self) -> Option<&LocalLspStore> {
3963 match &self.mode {
3964 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3965 _ => None,
3966 }
3967 }
3968
3969 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3970 match &mut self.mode {
3971 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3972 _ => None,
3973 }
3974 }
3975
3976 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3977 match &self.mode {
3978 LspStoreMode::Remote(RemoteLspStore {
3979 upstream_client: Some(upstream_client),
3980 upstream_project_id,
3981 ..
3982 }) => Some((upstream_client.clone(), *upstream_project_id)),
3983
3984 LspStoreMode::Remote(RemoteLspStore {
3985 upstream_client: None,
3986 ..
3987 }) => None,
3988 LspStoreMode::Local(_) => None,
3989 }
3990 }
3991
3992 pub fn new_local(
3993 buffer_store: Entity<BufferStore>,
3994 worktree_store: Entity<WorktreeStore>,
3995 prettier_store: Entity<PrettierStore>,
3996 toolchain_store: Entity<LocalToolchainStore>,
3997 environment: Entity<ProjectEnvironment>,
3998 manifest_tree: Entity<ManifestTree>,
3999 languages: Arc<LanguageRegistry>,
4000 http_client: Arc<dyn HttpClient>,
4001 fs: Arc<dyn Fs>,
4002 cx: &mut Context<Self>,
4003 ) -> Self {
4004 let yarn = YarnPathStore::new(fs.clone(), cx);
4005 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4006 .detach();
4007 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4008 .detach();
4009 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4010 .detach();
4011 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4012 .detach();
4013 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4014 .detach();
4015 subscribe_to_binary_statuses(&languages, cx).detach();
4016
4017 let _maintain_workspace_config = {
4018 let (sender, receiver) = watch::channel();
4019 (Self::maintain_workspace_config(receiver, cx), sender)
4020 };
4021
4022 Self {
4023 mode: LspStoreMode::Local(LocalLspStore {
4024 weak: cx.weak_entity(),
4025 worktree_store: worktree_store.clone(),
4026
4027 supplementary_language_servers: Default::default(),
4028 languages: languages.clone(),
4029 language_server_ids: Default::default(),
4030 language_servers: Default::default(),
4031 last_workspace_edits_by_language_server: Default::default(),
4032 language_server_watched_paths: Default::default(),
4033 language_server_paths_watched_for_rename: Default::default(),
4034 language_server_dynamic_registrations: Default::default(),
4035 buffers_being_formatted: Default::default(),
4036 buffer_snapshots: Default::default(),
4037 prettier_store,
4038 environment,
4039 http_client,
4040 fs,
4041 yarn,
4042 next_diagnostic_group_id: Default::default(),
4043 diagnostics: Default::default(),
4044 _subscription: cx.on_app_quit(|this, cx| {
4045 this.as_local_mut()
4046 .unwrap()
4047 .shutdown_language_servers_on_quit(cx)
4048 }),
4049 lsp_tree: LanguageServerTree::new(
4050 manifest_tree,
4051 languages.clone(),
4052 toolchain_store.clone(),
4053 ),
4054 toolchain_store,
4055 registered_buffers: HashMap::default(),
4056 buffers_opened_in_servers: HashMap::default(),
4057 buffer_pull_diagnostics_result_ids: HashMap::default(),
4058 workspace_pull_diagnostics_result_ids: HashMap::default(),
4059 restricted_worktrees_tasks: HashMap::default(),
4060 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4061 .manifest_file_names(),
4062 }),
4063 last_formatting_failure: None,
4064 downstream_client: None,
4065 buffer_store,
4066 worktree_store,
4067 languages: languages.clone(),
4068 language_server_statuses: Default::default(),
4069 nonce: StdRng::from_os_rng().random(),
4070 diagnostic_summaries: HashMap::default(),
4071 lsp_server_capabilities: HashMap::default(),
4072 lsp_data: HashMap::default(),
4073 next_hint_id: Arc::default(),
4074 active_entry: None,
4075 _maintain_workspace_config,
4076 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4077 }
4078 }
4079
4080 fn send_lsp_proto_request<R: LspCommand>(
4081 &self,
4082 buffer: Entity<Buffer>,
4083 client: AnyProtoClient,
4084 upstream_project_id: u64,
4085 request: R,
4086 cx: &mut Context<LspStore>,
4087 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4088 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4089 return Task::ready(Ok(R::Response::default()));
4090 }
4091 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4092 cx.spawn(async move |this, cx| {
4093 let response = client.request(message).await?;
4094 let this = this.upgrade().context("project dropped")?;
4095 request
4096 .response_from_proto(response, this, buffer, cx.clone())
4097 .await
4098 })
4099 }
4100
4101 pub(super) fn new_remote(
4102 buffer_store: Entity<BufferStore>,
4103 worktree_store: Entity<WorktreeStore>,
4104 languages: Arc<LanguageRegistry>,
4105 upstream_client: AnyProtoClient,
4106 project_id: u64,
4107 cx: &mut Context<Self>,
4108 ) -> Self {
4109 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4110 .detach();
4111 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4112 .detach();
4113 subscribe_to_binary_statuses(&languages, cx).detach();
4114 let _maintain_workspace_config = {
4115 let (sender, receiver) = watch::channel();
4116 (Self::maintain_workspace_config(receiver, cx), sender)
4117 };
4118 Self {
4119 mode: LspStoreMode::Remote(RemoteLspStore {
4120 upstream_client: Some(upstream_client),
4121 upstream_project_id: project_id,
4122 }),
4123 downstream_client: None,
4124 last_formatting_failure: None,
4125 buffer_store,
4126 worktree_store,
4127 languages: languages.clone(),
4128 language_server_statuses: Default::default(),
4129 nonce: StdRng::from_os_rng().random(),
4130 diagnostic_summaries: HashMap::default(),
4131 lsp_server_capabilities: HashMap::default(),
4132 next_hint_id: Arc::default(),
4133 lsp_data: HashMap::default(),
4134 active_entry: None,
4135
4136 _maintain_workspace_config,
4137 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4138 }
4139 }
4140
4141 fn on_buffer_store_event(
4142 &mut self,
4143 _: Entity<BufferStore>,
4144 event: &BufferStoreEvent,
4145 cx: &mut Context<Self>,
4146 ) {
4147 match event {
4148 BufferStoreEvent::BufferAdded(buffer) => {
4149 self.on_buffer_added(buffer, cx).log_err();
4150 }
4151 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4152 let buffer_id = buffer.read(cx).remote_id();
4153 if let Some(local) = self.as_local_mut()
4154 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4155 {
4156 local.reset_buffer(buffer, old_file, cx);
4157
4158 if local.registered_buffers.contains_key(&buffer_id) {
4159 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4160 }
4161 }
4162
4163 self.detect_language_for_buffer(buffer, cx);
4164 if let Some(local) = self.as_local_mut() {
4165 local.initialize_buffer(buffer, cx);
4166 if local.registered_buffers.contains_key(&buffer_id) {
4167 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4168 }
4169 }
4170 }
4171 _ => {}
4172 }
4173 }
4174
4175 fn on_worktree_store_event(
4176 &mut self,
4177 _: Entity<WorktreeStore>,
4178 event: &WorktreeStoreEvent,
4179 cx: &mut Context<Self>,
4180 ) {
4181 match event {
4182 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4183 if !worktree.read(cx).is_local() {
4184 return;
4185 }
4186 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4187 worktree::Event::UpdatedEntries(changes) => {
4188 this.update_local_worktree_language_servers(&worktree, changes, cx);
4189 }
4190 worktree::Event::UpdatedGitRepositories(_)
4191 | worktree::Event::DeletedEntry(_) => {}
4192 })
4193 .detach()
4194 }
4195 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4196 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4197 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4198 }
4199 WorktreeStoreEvent::WorktreeReleased(..)
4200 | WorktreeStoreEvent::WorktreeOrderChanged
4201 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4202 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4203 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4204 }
4205 }
4206
4207 fn on_prettier_store_event(
4208 &mut self,
4209 _: Entity<PrettierStore>,
4210 event: &PrettierStoreEvent,
4211 cx: &mut Context<Self>,
4212 ) {
4213 match event {
4214 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4215 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4216 }
4217 PrettierStoreEvent::LanguageServerAdded {
4218 new_server_id,
4219 name,
4220 prettier_server,
4221 } => {
4222 self.register_supplementary_language_server(
4223 *new_server_id,
4224 name.clone(),
4225 prettier_server.clone(),
4226 cx,
4227 );
4228 }
4229 }
4230 }
4231
4232 fn on_toolchain_store_event(
4233 &mut self,
4234 _: Entity<LocalToolchainStore>,
4235 event: &ToolchainStoreEvent,
4236 _: &mut Context<Self>,
4237 ) {
4238 if let ToolchainStoreEvent::ToolchainActivated = event {
4239 self.request_workspace_config_refresh()
4240 }
4241 }
4242
4243 fn request_workspace_config_refresh(&mut self) {
4244 *self._maintain_workspace_config.1.borrow_mut() = ();
4245 }
4246
4247 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4248 self.as_local().map(|local| local.prettier_store.clone())
4249 }
4250
4251 fn on_buffer_event(
4252 &mut self,
4253 buffer: Entity<Buffer>,
4254 event: &language::BufferEvent,
4255 cx: &mut Context<Self>,
4256 ) {
4257 match event {
4258 language::BufferEvent::Edited => {
4259 self.on_buffer_edited(buffer, cx);
4260 }
4261
4262 language::BufferEvent::Saved => {
4263 self.on_buffer_saved(buffer, cx);
4264 }
4265
4266 _ => {}
4267 }
4268 }
4269
4270 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4271 buffer
4272 .read(cx)
4273 .set_language_registry(self.languages.clone());
4274
4275 cx.subscribe(buffer, |this, buffer, event, cx| {
4276 this.on_buffer_event(buffer, event, cx);
4277 })
4278 .detach();
4279
4280 self.detect_language_for_buffer(buffer, cx);
4281 if let Some(local) = self.as_local_mut() {
4282 local.initialize_buffer(buffer, cx);
4283 }
4284
4285 Ok(())
4286 }
4287
4288 pub(crate) fn register_buffer_with_language_servers(
4289 &mut self,
4290 buffer: &Entity<Buffer>,
4291 only_register_servers: HashSet<LanguageServerSelector>,
4292 ignore_refcounts: bool,
4293 cx: &mut Context<Self>,
4294 ) -> OpenLspBufferHandle {
4295 let buffer_id = buffer.read(cx).remote_id();
4296 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4297 if let Some(local) = self.as_local_mut() {
4298 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4299 if !ignore_refcounts {
4300 *refcount += 1;
4301 }
4302
4303 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4304 // 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
4305 // 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
4306 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4307 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4308 return handle;
4309 };
4310 if !file.is_local() {
4311 return handle;
4312 }
4313
4314 if ignore_refcounts || *refcount == 1 {
4315 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4316 }
4317 if !ignore_refcounts {
4318 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4319 let refcount = {
4320 let local = lsp_store.as_local_mut().unwrap();
4321 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4322 debug_panic!("bad refcounting");
4323 return;
4324 };
4325
4326 *refcount -= 1;
4327 *refcount
4328 };
4329 if refcount == 0 {
4330 lsp_store.lsp_data.remove(&buffer_id);
4331 let local = lsp_store.as_local_mut().unwrap();
4332 local.registered_buffers.remove(&buffer_id);
4333
4334 local.buffers_opened_in_servers.remove(&buffer_id);
4335 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4336 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4337
4338 let buffer_abs_path = file.abs_path(cx);
4339 for (_, buffer_pull_diagnostics_result_ids) in
4340 &mut local.buffer_pull_diagnostics_result_ids
4341 {
4342 buffer_pull_diagnostics_result_ids.retain(
4343 |_, buffer_result_ids| {
4344 buffer_result_ids.remove(&buffer_abs_path);
4345 !buffer_result_ids.is_empty()
4346 },
4347 );
4348 }
4349
4350 let diagnostic_updates = local
4351 .language_servers
4352 .keys()
4353 .cloned()
4354 .map(|server_id| DocumentDiagnosticsUpdate {
4355 diagnostics: DocumentDiagnostics {
4356 document_abs_path: buffer_abs_path.clone(),
4357 version: None,
4358 diagnostics: Vec::new(),
4359 },
4360 result_id: None,
4361 registration_id: None,
4362 server_id: server_id,
4363 disk_based_sources: Cow::Borrowed(&[]),
4364 })
4365 .collect::<Vec<_>>();
4366
4367 lsp_store
4368 .merge_diagnostic_entries(
4369 diagnostic_updates,
4370 |_, diagnostic, _| {
4371 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4372 },
4373 cx,
4374 )
4375 .context("Clearing diagnostics for the closed buffer")
4376 .log_err();
4377 }
4378 }
4379 })
4380 .detach();
4381 }
4382 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4383 let buffer_id = buffer.read(cx).remote_id().to_proto();
4384 cx.background_spawn(async move {
4385 upstream_client
4386 .request(proto::RegisterBufferWithLanguageServers {
4387 project_id: upstream_project_id,
4388 buffer_id,
4389 only_servers: only_register_servers
4390 .into_iter()
4391 .map(|selector| {
4392 let selector = match selector {
4393 LanguageServerSelector::Id(language_server_id) => {
4394 proto::language_server_selector::Selector::ServerId(
4395 language_server_id.to_proto(),
4396 )
4397 }
4398 LanguageServerSelector::Name(language_server_name) => {
4399 proto::language_server_selector::Selector::Name(
4400 language_server_name.to_string(),
4401 )
4402 }
4403 };
4404 proto::LanguageServerSelector {
4405 selector: Some(selector),
4406 }
4407 })
4408 .collect(),
4409 })
4410 .await
4411 })
4412 .detach();
4413 } else {
4414 // Our remote connection got closed
4415 }
4416 handle
4417 }
4418
4419 fn maintain_buffer_languages(
4420 languages: Arc<LanguageRegistry>,
4421 cx: &mut Context<Self>,
4422 ) -> Task<()> {
4423 let mut subscription = languages.subscribe();
4424 let mut prev_reload_count = languages.reload_count();
4425 cx.spawn(async move |this, cx| {
4426 while let Some(()) = subscription.next().await {
4427 if let Some(this) = this.upgrade() {
4428 // If the language registry has been reloaded, then remove and
4429 // re-assign the languages on all open buffers.
4430 let reload_count = languages.reload_count();
4431 if reload_count > prev_reload_count {
4432 prev_reload_count = reload_count;
4433 this.update(cx, |this, cx| {
4434 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4435 for buffer in buffer_store.buffers() {
4436 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4437 {
4438 buffer.update(cx, |buffer, cx| {
4439 buffer.set_language_async(None, cx)
4440 });
4441 if let Some(local) = this.as_local_mut() {
4442 local.reset_buffer(&buffer, &f, cx);
4443
4444 if local
4445 .registered_buffers
4446 .contains_key(&buffer.read(cx).remote_id())
4447 && let Some(file_url) =
4448 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4449 {
4450 local.unregister_buffer_from_language_servers(
4451 &buffer, &file_url, cx,
4452 );
4453 }
4454 }
4455 }
4456 }
4457 });
4458 })
4459 .ok();
4460 }
4461
4462 this.update(cx, |this, cx| {
4463 let mut plain_text_buffers = Vec::new();
4464 let mut buffers_with_unknown_injections = Vec::new();
4465 for handle in this.buffer_store.read(cx).buffers() {
4466 let buffer = handle.read(cx);
4467 if buffer.language().is_none()
4468 || buffer.language() == Some(&*language::PLAIN_TEXT)
4469 {
4470 plain_text_buffers.push(handle);
4471 } else if buffer.contains_unknown_injections() {
4472 buffers_with_unknown_injections.push(handle);
4473 }
4474 }
4475
4476 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4477 // and reused later in the invisible worktrees.
4478 plain_text_buffers.sort_by_key(|buffer| {
4479 Reverse(
4480 File::from_dyn(buffer.read(cx).file())
4481 .map(|file| file.worktree.read(cx).is_visible()),
4482 )
4483 });
4484
4485 for buffer in plain_text_buffers {
4486 this.detect_language_for_buffer(&buffer, cx);
4487 if let Some(local) = this.as_local_mut() {
4488 local.initialize_buffer(&buffer, cx);
4489 if local
4490 .registered_buffers
4491 .contains_key(&buffer.read(cx).remote_id())
4492 {
4493 local.register_buffer_with_language_servers(
4494 &buffer,
4495 HashSet::default(),
4496 cx,
4497 );
4498 }
4499 }
4500 }
4501
4502 for buffer in buffers_with_unknown_injections {
4503 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4504 }
4505 })
4506 .ok();
4507 }
4508 }
4509 })
4510 }
4511
4512 fn detect_language_for_buffer(
4513 &mut self,
4514 buffer_handle: &Entity<Buffer>,
4515 cx: &mut Context<Self>,
4516 ) -> Option<language::AvailableLanguage> {
4517 // If the buffer has a language, set it and start the language server if we haven't already.
4518 let buffer = buffer_handle.read(cx);
4519 let file = buffer.file()?;
4520
4521 let content = buffer.as_rope();
4522 let available_language = self.languages.language_for_file(file, Some(content), cx);
4523 if let Some(available_language) = &available_language {
4524 if let Some(Ok(Ok(new_language))) = self
4525 .languages
4526 .load_language(available_language)
4527 .now_or_never()
4528 {
4529 self.set_language_for_buffer(buffer_handle, new_language, cx);
4530 }
4531 } else {
4532 cx.emit(LspStoreEvent::LanguageDetected {
4533 buffer: buffer_handle.clone(),
4534 new_language: None,
4535 });
4536 }
4537
4538 available_language
4539 }
4540
4541 pub(crate) fn set_language_for_buffer(
4542 &mut self,
4543 buffer_entity: &Entity<Buffer>,
4544 new_language: Arc<Language>,
4545 cx: &mut Context<Self>,
4546 ) {
4547 let buffer = buffer_entity.read(cx);
4548 let buffer_file = buffer.file().cloned();
4549 let buffer_id = buffer.remote_id();
4550 if let Some(local_store) = self.as_local_mut()
4551 && local_store.registered_buffers.contains_key(&buffer_id)
4552 && let Some(abs_path) =
4553 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4554 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4555 {
4556 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4557 }
4558 buffer_entity.update(cx, |buffer, cx| {
4559 if buffer
4560 .language()
4561 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4562 {
4563 buffer.set_language_async(Some(new_language.clone()), cx);
4564 }
4565 });
4566
4567 let settings =
4568 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4569 let buffer_file = File::from_dyn(buffer_file.as_ref());
4570
4571 let worktree_id = if let Some(file) = buffer_file {
4572 let worktree = file.worktree.clone();
4573
4574 if let Some(local) = self.as_local_mut()
4575 && local.registered_buffers.contains_key(&buffer_id)
4576 {
4577 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4578 }
4579 Some(worktree.read(cx).id())
4580 } else {
4581 None
4582 };
4583
4584 if settings.prettier.allowed
4585 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4586 {
4587 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4588 if let Some(prettier_store) = prettier_store {
4589 prettier_store.update(cx, |prettier_store, cx| {
4590 prettier_store.install_default_prettier(
4591 worktree_id,
4592 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4593 cx,
4594 )
4595 })
4596 }
4597 }
4598
4599 cx.emit(LspStoreEvent::LanguageDetected {
4600 buffer: buffer_entity.clone(),
4601 new_language: Some(new_language),
4602 })
4603 }
4604
4605 pub fn buffer_store(&self) -> Entity<BufferStore> {
4606 self.buffer_store.clone()
4607 }
4608
4609 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4610 self.active_entry = active_entry;
4611 }
4612
4613 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4614 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4615 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4616 {
4617 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4618 summaries
4619 .iter()
4620 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4621 });
4622 if let Some(summary) = summaries.next() {
4623 client
4624 .send(proto::UpdateDiagnosticSummary {
4625 project_id: downstream_project_id,
4626 worktree_id: worktree.id().to_proto(),
4627 summary: Some(summary),
4628 more_summaries: summaries.collect(),
4629 })
4630 .log_err();
4631 }
4632 }
4633 }
4634
4635 fn is_capable_for_proto_request<R>(
4636 &self,
4637 buffer: &Entity<Buffer>,
4638 request: &R,
4639 cx: &App,
4640 ) -> bool
4641 where
4642 R: LspCommand,
4643 {
4644 self.check_if_capable_for_proto_request(
4645 buffer,
4646 |capabilities| {
4647 request.check_capabilities(AdapterServerCapabilities {
4648 server_capabilities: capabilities.clone(),
4649 code_action_kinds: None,
4650 })
4651 },
4652 cx,
4653 )
4654 }
4655
4656 fn check_if_capable_for_proto_request<F>(
4657 &self,
4658 buffer: &Entity<Buffer>,
4659 check: F,
4660 cx: &App,
4661 ) -> bool
4662 where
4663 F: FnMut(&lsp::ServerCapabilities) -> bool,
4664 {
4665 let Some(language) = buffer.read(cx).language().cloned() else {
4666 return false;
4667 };
4668 let registered_language_servers = self
4669 .languages
4670 .lsp_adapters(&language.name())
4671 .into_iter()
4672 .map(|lsp_adapter| lsp_adapter.name())
4673 .collect::<HashSet<_>>();
4674 self.language_server_statuses
4675 .iter()
4676 .filter_map(|(server_id, server_status)| {
4677 // Include servers that are either registered for this language OR
4678 // available to be loaded (for SSH remote mode where adapters like
4679 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4680 // but only loaded on the server side)
4681 let is_relevant = registered_language_servers.contains(&server_status.name)
4682 || self.languages.is_lsp_adapter_available(&server_status.name);
4683 is_relevant.then_some(server_id)
4684 })
4685 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4686 .any(check)
4687 }
4688
4689 fn all_capable_for_proto_request<F>(
4690 &self,
4691 buffer: &Entity<Buffer>,
4692 mut check: F,
4693 cx: &App,
4694 ) -> Vec<lsp::LanguageServerId>
4695 where
4696 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4697 {
4698 let Some(language) = buffer.read(cx).language().cloned() else {
4699 return Vec::default();
4700 };
4701 let registered_language_servers = self
4702 .languages
4703 .lsp_adapters(&language.name())
4704 .into_iter()
4705 .map(|lsp_adapter| lsp_adapter.name())
4706 .collect::<HashSet<_>>();
4707 self.language_server_statuses
4708 .iter()
4709 .filter_map(|(server_id, server_status)| {
4710 // Include servers that are either registered for this language OR
4711 // available to be loaded (for SSH remote mode where adapters like
4712 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4713 // but only loaded on the server side)
4714 let is_relevant = registered_language_servers.contains(&server_status.name)
4715 || self.languages.is_lsp_adapter_available(&server_status.name);
4716 is_relevant.then_some((server_id, &server_status.name))
4717 })
4718 .filter_map(|(server_id, server_name)| {
4719 self.lsp_server_capabilities
4720 .get(server_id)
4721 .map(|c| (server_id, server_name, c))
4722 })
4723 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4724 .map(|(server_id, _, _)| *server_id)
4725 .collect()
4726 }
4727
4728 pub fn request_lsp<R>(
4729 &mut self,
4730 buffer: Entity<Buffer>,
4731 server: LanguageServerToQuery,
4732 request: R,
4733 cx: &mut Context<Self>,
4734 ) -> Task<Result<R::Response>>
4735 where
4736 R: LspCommand,
4737 <R::LspRequest as lsp::request::Request>::Result: Send,
4738 <R::LspRequest as lsp::request::Request>::Params: Send,
4739 {
4740 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4741 return self.send_lsp_proto_request(
4742 buffer,
4743 upstream_client,
4744 upstream_project_id,
4745 request,
4746 cx,
4747 );
4748 }
4749
4750 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4751 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4752 local
4753 .language_servers_for_buffer(buffer, cx)
4754 .find(|(_, server)| {
4755 request.check_capabilities(server.adapter_server_capabilities())
4756 })
4757 .map(|(_, server)| server.clone())
4758 }),
4759 LanguageServerToQuery::Other(id) => self
4760 .language_server_for_local_buffer(buffer, id, cx)
4761 .and_then(|(_, server)| {
4762 request
4763 .check_capabilities(server.adapter_server_capabilities())
4764 .then(|| Arc::clone(server))
4765 }),
4766 }) else {
4767 return Task::ready(Ok(Default::default()));
4768 };
4769
4770 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4771
4772 let Some(file) = file else {
4773 return Task::ready(Ok(Default::default()));
4774 };
4775
4776 let lsp_params = match request.to_lsp_params_or_response(
4777 &file.abs_path(cx),
4778 buffer.read(cx),
4779 &language_server,
4780 cx,
4781 ) {
4782 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4783 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4784 Err(err) => {
4785 let message = format!(
4786 "{} via {} failed: {}",
4787 request.display_name(),
4788 language_server.name(),
4789 err
4790 );
4791 // rust-analyzer likes to error with this when its still loading up
4792 if !message.ends_with("content modified") {
4793 log::warn!("{message}");
4794 }
4795 return Task::ready(Err(anyhow!(message)));
4796 }
4797 };
4798
4799 let status = request.status();
4800 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4801 return Task::ready(Ok(Default::default()));
4802 }
4803 cx.spawn(async move |this, cx| {
4804 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4805
4806 let id = lsp_request.id();
4807 let _cleanup = if status.is_some() {
4808 cx.update(|cx| {
4809 this.update(cx, |this, cx| {
4810 this.on_lsp_work_start(
4811 language_server.server_id(),
4812 ProgressToken::Number(id),
4813 LanguageServerProgress {
4814 is_disk_based_diagnostics_progress: false,
4815 is_cancellable: false,
4816 title: None,
4817 message: status.clone(),
4818 percentage: None,
4819 last_update_at: cx.background_executor().now(),
4820 },
4821 cx,
4822 );
4823 })
4824 })
4825 .log_err();
4826
4827 Some(defer(|| {
4828 cx.update(|cx| {
4829 this.update(cx, |this, cx| {
4830 this.on_lsp_work_end(
4831 language_server.server_id(),
4832 ProgressToken::Number(id),
4833 cx,
4834 );
4835 })
4836 })
4837 .log_err();
4838 }))
4839 } else {
4840 None
4841 };
4842
4843 let result = lsp_request.await.into_response();
4844
4845 let response = result.map_err(|err| {
4846 let message = format!(
4847 "{} via {} failed: {}",
4848 request.display_name(),
4849 language_server.name(),
4850 err
4851 );
4852 // rust-analyzer likes to error with this when its still loading up
4853 if !message.ends_with("content modified") {
4854 log::warn!("{message}");
4855 }
4856 anyhow::anyhow!(message)
4857 })?;
4858
4859 request
4860 .response_from_lsp(
4861 response,
4862 this.upgrade().context("no app context")?,
4863 buffer,
4864 language_server.server_id(),
4865 cx.clone(),
4866 )
4867 .await
4868 })
4869 }
4870
4871 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4872 let mut language_formatters_to_check = Vec::new();
4873 for buffer in self.buffer_store.read(cx).buffers() {
4874 let buffer = buffer.read(cx);
4875 let buffer_file = File::from_dyn(buffer.file());
4876 let buffer_language = buffer.language();
4877 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4878 if buffer_language.is_some() {
4879 language_formatters_to_check.push((
4880 buffer_file.map(|f| f.worktree_id(cx)),
4881 settings.into_owned(),
4882 ));
4883 }
4884 }
4885
4886 self.request_workspace_config_refresh();
4887
4888 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4889 prettier_store.update(cx, |prettier_store, cx| {
4890 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4891 })
4892 }
4893
4894 cx.notify();
4895 }
4896
4897 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4898 let buffer_store = self.buffer_store.clone();
4899 let Some(local) = self.as_local_mut() else {
4900 return;
4901 };
4902 let mut adapters = BTreeMap::default();
4903 let get_adapter = {
4904 let languages = local.languages.clone();
4905 let environment = local.environment.clone();
4906 let weak = local.weak.clone();
4907 let worktree_store = local.worktree_store.clone();
4908 let http_client = local.http_client.clone();
4909 let fs = local.fs.clone();
4910 move |worktree_id, cx: &mut App| {
4911 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4912 Some(LocalLspAdapterDelegate::new(
4913 languages.clone(),
4914 &environment,
4915 weak.clone(),
4916 &worktree,
4917 http_client.clone(),
4918 fs.clone(),
4919 cx,
4920 ))
4921 }
4922 };
4923
4924 let mut messages_to_report = Vec::new();
4925 let (new_tree, to_stop) = {
4926 let mut rebase = local.lsp_tree.rebase();
4927 let buffers = buffer_store
4928 .read(cx)
4929 .buffers()
4930 .filter_map(|buffer| {
4931 let raw_buffer = buffer.read(cx);
4932 if !local
4933 .registered_buffers
4934 .contains_key(&raw_buffer.remote_id())
4935 {
4936 return None;
4937 }
4938 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4939 let language = raw_buffer.language().cloned()?;
4940 Some((file, language, raw_buffer.remote_id()))
4941 })
4942 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4943 for (file, language, buffer_id) in buffers {
4944 let worktree_id = file.worktree_id(cx);
4945 let Some(worktree) = local
4946 .worktree_store
4947 .read(cx)
4948 .worktree_for_id(worktree_id, cx)
4949 else {
4950 continue;
4951 };
4952
4953 if let Some((_, apply)) = local.reuse_existing_language_server(
4954 rebase.server_tree(),
4955 &worktree,
4956 &language.name(),
4957 cx,
4958 ) {
4959 (apply)(rebase.server_tree());
4960 } else if let Some(lsp_delegate) = adapters
4961 .entry(worktree_id)
4962 .or_insert_with(|| get_adapter(worktree_id, cx))
4963 .clone()
4964 {
4965 let delegate =
4966 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4967 let path = file
4968 .path()
4969 .parent()
4970 .map(Arc::from)
4971 .unwrap_or_else(|| file.path().clone());
4972 let worktree_path = ProjectPath { worktree_id, path };
4973 let abs_path = file.abs_path(cx);
4974 let nodes = rebase
4975 .walk(
4976 worktree_path,
4977 language.name(),
4978 language.manifest(),
4979 delegate.clone(),
4980 cx,
4981 )
4982 .collect::<Vec<_>>();
4983 for node in nodes {
4984 let server_id = node.server_id_or_init(|disposition| {
4985 let path = &disposition.path;
4986 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4987 let key = LanguageServerSeed {
4988 worktree_id,
4989 name: disposition.server_name.clone(),
4990 settings: disposition.settings.clone(),
4991 toolchain: local.toolchain_store.read(cx).active_toolchain(
4992 path.worktree_id,
4993 &path.path,
4994 language.name(),
4995 ),
4996 };
4997 local.language_server_ids.remove(&key);
4998
4999 let server_id = local.get_or_insert_language_server(
5000 &worktree,
5001 lsp_delegate.clone(),
5002 disposition,
5003 &language.name(),
5004 cx,
5005 );
5006 if let Some(state) = local.language_servers.get(&server_id)
5007 && let Ok(uri) = uri
5008 {
5009 state.add_workspace_folder(uri);
5010 };
5011 server_id
5012 });
5013
5014 if let Some(language_server_id) = server_id {
5015 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5016 language_server_id,
5017 name: node.name(),
5018 message:
5019 proto::update_language_server::Variant::RegisteredForBuffer(
5020 proto::RegisteredForBuffer {
5021 buffer_abs_path: abs_path
5022 .to_string_lossy()
5023 .into_owned(),
5024 buffer_id: buffer_id.to_proto(),
5025 },
5026 ),
5027 });
5028 }
5029 }
5030 } else {
5031 continue;
5032 }
5033 }
5034 rebase.finish()
5035 };
5036 for message in messages_to_report {
5037 cx.emit(message);
5038 }
5039 local.lsp_tree = new_tree;
5040 for (id, _) in to_stop {
5041 self.stop_local_language_server(id, cx).detach();
5042 }
5043 }
5044
5045 pub fn apply_code_action(
5046 &self,
5047 buffer_handle: Entity<Buffer>,
5048 mut action: CodeAction,
5049 push_to_history: bool,
5050 cx: &mut Context<Self>,
5051 ) -> Task<Result<ProjectTransaction>> {
5052 if let Some((upstream_client, project_id)) = self.upstream_client() {
5053 let request = proto::ApplyCodeAction {
5054 project_id,
5055 buffer_id: buffer_handle.read(cx).remote_id().into(),
5056 action: Some(Self::serialize_code_action(&action)),
5057 };
5058 let buffer_store = self.buffer_store();
5059 cx.spawn(async move |_, cx| {
5060 let response = upstream_client
5061 .request(request)
5062 .await?
5063 .transaction
5064 .context("missing transaction")?;
5065
5066 buffer_store
5067 .update(cx, |buffer_store, cx| {
5068 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5069 })?
5070 .await
5071 })
5072 } else if self.mode.is_local() {
5073 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5074 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5075 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5076 }) else {
5077 return Task::ready(Ok(ProjectTransaction::default()));
5078 };
5079 cx.spawn(async move |this, cx| {
5080 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5081 .await
5082 .context("resolving a code action")?;
5083 if let Some(edit) = action.lsp_action.edit()
5084 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5085 return LocalLspStore::deserialize_workspace_edit(
5086 this.upgrade().context("no app present")?,
5087 edit.clone(),
5088 push_to_history,
5089
5090 lang_server.clone(),
5091 cx,
5092 )
5093 .await;
5094 }
5095
5096 if let Some(command) = action.lsp_action.command() {
5097 let server_capabilities = lang_server.capabilities();
5098 let available_commands = server_capabilities
5099 .execute_command_provider
5100 .as_ref()
5101 .map(|options| options.commands.as_slice())
5102 .unwrap_or_default();
5103 if available_commands.contains(&command.command) {
5104 this.update(cx, |this, _| {
5105 this.as_local_mut()
5106 .unwrap()
5107 .last_workspace_edits_by_language_server
5108 .remove(&lang_server.server_id());
5109 })?;
5110
5111 let _result = lang_server
5112 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5113 command: command.command.clone(),
5114 arguments: command.arguments.clone().unwrap_or_default(),
5115 ..lsp::ExecuteCommandParams::default()
5116 })
5117 .await.into_response()
5118 .context("execute command")?;
5119
5120 return this.update(cx, |this, _| {
5121 this.as_local_mut()
5122 .unwrap()
5123 .last_workspace_edits_by_language_server
5124 .remove(&lang_server.server_id())
5125 .unwrap_or_default()
5126 });
5127 } else {
5128 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5129 }
5130 }
5131
5132 Ok(ProjectTransaction::default())
5133 })
5134 } else {
5135 Task::ready(Err(anyhow!("no upstream client and not local")))
5136 }
5137 }
5138
5139 pub fn apply_code_action_kind(
5140 &mut self,
5141 buffers: HashSet<Entity<Buffer>>,
5142 kind: CodeActionKind,
5143 push_to_history: bool,
5144 cx: &mut Context<Self>,
5145 ) -> Task<anyhow::Result<ProjectTransaction>> {
5146 if self.as_local().is_some() {
5147 cx.spawn(async move |lsp_store, cx| {
5148 let buffers = buffers.into_iter().collect::<Vec<_>>();
5149 let result = LocalLspStore::execute_code_action_kind_locally(
5150 lsp_store.clone(),
5151 buffers,
5152 kind,
5153 push_to_history,
5154 cx,
5155 )
5156 .await;
5157 lsp_store.update(cx, |lsp_store, _| {
5158 lsp_store.update_last_formatting_failure(&result);
5159 })?;
5160 result
5161 })
5162 } else if let Some((client, project_id)) = self.upstream_client() {
5163 let buffer_store = self.buffer_store();
5164 cx.spawn(async move |lsp_store, cx| {
5165 let result = client
5166 .request(proto::ApplyCodeActionKind {
5167 project_id,
5168 kind: kind.as_str().to_owned(),
5169 buffer_ids: buffers
5170 .iter()
5171 .map(|buffer| {
5172 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5173 })
5174 .collect::<Result<_>>()?,
5175 })
5176 .await
5177 .and_then(|result| result.transaction.context("missing transaction"));
5178 lsp_store.update(cx, |lsp_store, _| {
5179 lsp_store.update_last_formatting_failure(&result);
5180 })?;
5181
5182 let transaction_response = result?;
5183 buffer_store
5184 .update(cx, |buffer_store, cx| {
5185 buffer_store.deserialize_project_transaction(
5186 transaction_response,
5187 push_to_history,
5188 cx,
5189 )
5190 })?
5191 .await
5192 })
5193 } else {
5194 Task::ready(Ok(ProjectTransaction::default()))
5195 }
5196 }
5197
5198 pub fn resolved_hint(
5199 &mut self,
5200 buffer_id: BufferId,
5201 id: InlayId,
5202 cx: &mut Context<Self>,
5203 ) -> Option<ResolvedHint> {
5204 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5205
5206 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5207 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5208 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5209 let (server_id, resolve_data) = match &hint.resolve_state {
5210 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5211 ResolveState::Resolving => {
5212 return Some(ResolvedHint::Resolving(
5213 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5214 ));
5215 }
5216 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5217 };
5218
5219 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5220 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5221 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5222 id,
5223 cx.spawn(async move |lsp_store, cx| {
5224 let resolved_hint = resolve_task.await;
5225 lsp_store
5226 .update(cx, |lsp_store, _| {
5227 if let Some(old_inlay_hint) = lsp_store
5228 .lsp_data
5229 .get_mut(&buffer_id)
5230 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5231 {
5232 match resolved_hint {
5233 Ok(resolved_hint) => {
5234 *old_inlay_hint = resolved_hint;
5235 }
5236 Err(e) => {
5237 old_inlay_hint.resolve_state =
5238 ResolveState::CanResolve(server_id, resolve_data);
5239 log::error!("Inlay hint resolve failed: {e:#}");
5240 }
5241 }
5242 }
5243 })
5244 .ok();
5245 })
5246 .shared(),
5247 );
5248 debug_assert!(
5249 previous_task.is_none(),
5250 "Did not change hint's resolve state after spawning its resolve"
5251 );
5252 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5253 None
5254 }
5255
5256 fn resolve_inlay_hint(
5257 &self,
5258 mut hint: InlayHint,
5259 buffer: Entity<Buffer>,
5260 server_id: LanguageServerId,
5261 cx: &mut Context<Self>,
5262 ) -> Task<anyhow::Result<InlayHint>> {
5263 if let Some((upstream_client, project_id)) = self.upstream_client() {
5264 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5265 {
5266 hint.resolve_state = ResolveState::Resolved;
5267 return Task::ready(Ok(hint));
5268 }
5269 let request = proto::ResolveInlayHint {
5270 project_id,
5271 buffer_id: buffer.read(cx).remote_id().into(),
5272 language_server_id: server_id.0 as u64,
5273 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5274 };
5275 cx.background_spawn(async move {
5276 let response = upstream_client
5277 .request(request)
5278 .await
5279 .context("inlay hints proto request")?;
5280 match response.hint {
5281 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5282 .context("inlay hints proto resolve response conversion"),
5283 None => Ok(hint),
5284 }
5285 })
5286 } else {
5287 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5288 self.language_server_for_local_buffer(buffer, server_id, cx)
5289 .map(|(_, server)| server.clone())
5290 }) else {
5291 return Task::ready(Ok(hint));
5292 };
5293 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5294 return Task::ready(Ok(hint));
5295 }
5296 let buffer_snapshot = buffer.read(cx).snapshot();
5297 cx.spawn(async move |_, cx| {
5298 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5299 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5300 );
5301 let resolved_hint = resolve_task
5302 .await
5303 .into_response()
5304 .context("inlay hint resolve LSP request")?;
5305 let resolved_hint = InlayHints::lsp_to_project_hint(
5306 resolved_hint,
5307 &buffer,
5308 server_id,
5309 ResolveState::Resolved,
5310 false,
5311 cx,
5312 )
5313 .await?;
5314 Ok(resolved_hint)
5315 })
5316 }
5317 }
5318
5319 pub fn resolve_color_presentation(
5320 &mut self,
5321 mut color: DocumentColor,
5322 buffer: Entity<Buffer>,
5323 server_id: LanguageServerId,
5324 cx: &mut Context<Self>,
5325 ) -> Task<Result<DocumentColor>> {
5326 if color.resolved {
5327 return Task::ready(Ok(color));
5328 }
5329
5330 if let Some((upstream_client, project_id)) = self.upstream_client() {
5331 let start = color.lsp_range.start;
5332 let end = color.lsp_range.end;
5333 let request = proto::GetColorPresentation {
5334 project_id,
5335 server_id: server_id.to_proto(),
5336 buffer_id: buffer.read(cx).remote_id().into(),
5337 color: Some(proto::ColorInformation {
5338 red: color.color.red,
5339 green: color.color.green,
5340 blue: color.color.blue,
5341 alpha: color.color.alpha,
5342 lsp_range_start: Some(proto::PointUtf16 {
5343 row: start.line,
5344 column: start.character,
5345 }),
5346 lsp_range_end: Some(proto::PointUtf16 {
5347 row: end.line,
5348 column: end.character,
5349 }),
5350 }),
5351 };
5352 cx.background_spawn(async move {
5353 let response = upstream_client
5354 .request(request)
5355 .await
5356 .context("color presentation proto request")?;
5357 color.resolved = true;
5358 color.color_presentations = response
5359 .presentations
5360 .into_iter()
5361 .map(|presentation| ColorPresentation {
5362 label: SharedString::from(presentation.label),
5363 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5364 additional_text_edits: presentation
5365 .additional_text_edits
5366 .into_iter()
5367 .filter_map(deserialize_lsp_edit)
5368 .collect(),
5369 })
5370 .collect();
5371 Ok(color)
5372 })
5373 } else {
5374 let path = match buffer
5375 .update(cx, |buffer, cx| {
5376 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5377 })
5378 .context("buffer with the missing path")
5379 {
5380 Ok(path) => path,
5381 Err(e) => return Task::ready(Err(e)),
5382 };
5383 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5384 self.language_server_for_local_buffer(buffer, server_id, cx)
5385 .map(|(_, server)| server.clone())
5386 }) else {
5387 return Task::ready(Ok(color));
5388 };
5389 cx.background_spawn(async move {
5390 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5391 lsp::ColorPresentationParams {
5392 text_document: make_text_document_identifier(&path)?,
5393 color: color.color,
5394 range: color.lsp_range,
5395 work_done_progress_params: Default::default(),
5396 partial_result_params: Default::default(),
5397 },
5398 );
5399 color.color_presentations = resolve_task
5400 .await
5401 .into_response()
5402 .context("color presentation resolve LSP request")?
5403 .into_iter()
5404 .map(|presentation| ColorPresentation {
5405 label: SharedString::from(presentation.label),
5406 text_edit: presentation.text_edit,
5407 additional_text_edits: presentation
5408 .additional_text_edits
5409 .unwrap_or_default(),
5410 })
5411 .collect();
5412 color.resolved = true;
5413 Ok(color)
5414 })
5415 }
5416 }
5417
5418 pub(crate) fn linked_edits(
5419 &mut self,
5420 buffer: &Entity<Buffer>,
5421 position: Anchor,
5422 cx: &mut Context<Self>,
5423 ) -> Task<Result<Vec<Range<Anchor>>>> {
5424 let snapshot = buffer.read(cx).snapshot();
5425 let scope = snapshot.language_scope_at(position);
5426 let Some(server_id) = self
5427 .as_local()
5428 .and_then(|local| {
5429 buffer.update(cx, |buffer, cx| {
5430 local
5431 .language_servers_for_buffer(buffer, cx)
5432 .filter(|(_, server)| {
5433 LinkedEditingRange::check_server_capabilities(server.capabilities())
5434 })
5435 .filter(|(adapter, _)| {
5436 scope
5437 .as_ref()
5438 .map(|scope| scope.language_allowed(&adapter.name))
5439 .unwrap_or(true)
5440 })
5441 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5442 .next()
5443 })
5444 })
5445 .or_else(|| {
5446 self.upstream_client()
5447 .is_some()
5448 .then_some(LanguageServerToQuery::FirstCapable)
5449 })
5450 .filter(|_| {
5451 maybe!({
5452 let language = buffer.read(cx).language_at(position)?;
5453 Some(
5454 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5455 .linked_edits,
5456 )
5457 }) == Some(true)
5458 })
5459 else {
5460 return Task::ready(Ok(Vec::new()));
5461 };
5462
5463 self.request_lsp(
5464 buffer.clone(),
5465 server_id,
5466 LinkedEditingRange { position },
5467 cx,
5468 )
5469 }
5470
5471 fn apply_on_type_formatting(
5472 &mut self,
5473 buffer: Entity<Buffer>,
5474 position: Anchor,
5475 trigger: String,
5476 cx: &mut Context<Self>,
5477 ) -> Task<Result<Option<Transaction>>> {
5478 if let Some((client, project_id)) = self.upstream_client() {
5479 if !self.check_if_capable_for_proto_request(
5480 &buffer,
5481 |capabilities| {
5482 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5483 },
5484 cx,
5485 ) {
5486 return Task::ready(Ok(None));
5487 }
5488 let request = proto::OnTypeFormatting {
5489 project_id,
5490 buffer_id: buffer.read(cx).remote_id().into(),
5491 position: Some(serialize_anchor(&position)),
5492 trigger,
5493 version: serialize_version(&buffer.read(cx).version()),
5494 };
5495 cx.background_spawn(async move {
5496 client
5497 .request(request)
5498 .await?
5499 .transaction
5500 .map(language::proto::deserialize_transaction)
5501 .transpose()
5502 })
5503 } else if let Some(local) = self.as_local_mut() {
5504 let buffer_id = buffer.read(cx).remote_id();
5505 local.buffers_being_formatted.insert(buffer_id);
5506 cx.spawn(async move |this, cx| {
5507 let _cleanup = defer({
5508 let this = this.clone();
5509 let mut cx = cx.clone();
5510 move || {
5511 this.update(&mut cx, |this, _| {
5512 if let Some(local) = this.as_local_mut() {
5513 local.buffers_being_formatted.remove(&buffer_id);
5514 }
5515 })
5516 .ok();
5517 }
5518 });
5519
5520 buffer
5521 .update(cx, |buffer, _| {
5522 buffer.wait_for_edits(Some(position.timestamp))
5523 })?
5524 .await?;
5525 this.update(cx, |this, cx| {
5526 let position = position.to_point_utf16(buffer.read(cx));
5527 this.on_type_format(buffer, position, trigger, false, cx)
5528 })?
5529 .await
5530 })
5531 } else {
5532 Task::ready(Err(anyhow!("No upstream client or local language server")))
5533 }
5534 }
5535
5536 pub fn on_type_format<T: ToPointUtf16>(
5537 &mut self,
5538 buffer: Entity<Buffer>,
5539 position: T,
5540 trigger: String,
5541 push_to_history: bool,
5542 cx: &mut Context<Self>,
5543 ) -> Task<Result<Option<Transaction>>> {
5544 let position = position.to_point_utf16(buffer.read(cx));
5545 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5546 }
5547
5548 fn on_type_format_impl(
5549 &mut self,
5550 buffer: Entity<Buffer>,
5551 position: PointUtf16,
5552 trigger: String,
5553 push_to_history: bool,
5554 cx: &mut Context<Self>,
5555 ) -> Task<Result<Option<Transaction>>> {
5556 let options = buffer.update(cx, |buffer, cx| {
5557 lsp_command::lsp_formatting_options(
5558 language_settings(
5559 buffer.language_at(position).map(|l| l.name()),
5560 buffer.file(),
5561 cx,
5562 )
5563 .as_ref(),
5564 )
5565 });
5566
5567 cx.spawn(async move |this, cx| {
5568 if let Some(waiter) =
5569 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5570 {
5571 waiter.await?;
5572 }
5573 cx.update(|cx| {
5574 this.update(cx, |this, cx| {
5575 this.request_lsp(
5576 buffer.clone(),
5577 LanguageServerToQuery::FirstCapable,
5578 OnTypeFormatting {
5579 position,
5580 trigger,
5581 options,
5582 push_to_history,
5583 },
5584 cx,
5585 )
5586 })
5587 })??
5588 .await
5589 })
5590 }
5591
5592 pub fn definitions(
5593 &mut self,
5594 buffer: &Entity<Buffer>,
5595 position: PointUtf16,
5596 cx: &mut Context<Self>,
5597 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5598 if let Some((upstream_client, project_id)) = self.upstream_client() {
5599 let request = GetDefinitions { position };
5600 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5601 return Task::ready(Ok(None));
5602 }
5603 let request_task = upstream_client.request_lsp(
5604 project_id,
5605 None,
5606 LSP_REQUEST_TIMEOUT,
5607 cx.background_executor().clone(),
5608 request.to_proto(project_id, buffer.read(cx)),
5609 );
5610 let buffer = buffer.clone();
5611 cx.spawn(async move |weak_lsp_store, cx| {
5612 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5613 return Ok(None);
5614 };
5615 let Some(responses) = request_task.await? else {
5616 return Ok(None);
5617 };
5618 let actions = join_all(responses.payload.into_iter().map(|response| {
5619 GetDefinitions { position }.response_from_proto(
5620 response.response,
5621 lsp_store.clone(),
5622 buffer.clone(),
5623 cx.clone(),
5624 )
5625 }))
5626 .await;
5627
5628 Ok(Some(
5629 actions
5630 .into_iter()
5631 .collect::<Result<Vec<Vec<_>>>>()?
5632 .into_iter()
5633 .flatten()
5634 .dedup()
5635 .collect(),
5636 ))
5637 })
5638 } else {
5639 let definitions_task = self.request_multiple_lsp_locally(
5640 buffer,
5641 Some(position),
5642 GetDefinitions { position },
5643 cx,
5644 );
5645 cx.background_spawn(async move {
5646 Ok(Some(
5647 definitions_task
5648 .await
5649 .into_iter()
5650 .flat_map(|(_, definitions)| definitions)
5651 .dedup()
5652 .collect(),
5653 ))
5654 })
5655 }
5656 }
5657
5658 pub fn declarations(
5659 &mut self,
5660 buffer: &Entity<Buffer>,
5661 position: PointUtf16,
5662 cx: &mut Context<Self>,
5663 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5664 if let Some((upstream_client, project_id)) = self.upstream_client() {
5665 let request = GetDeclarations { position };
5666 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5667 return Task::ready(Ok(None));
5668 }
5669 let request_task = upstream_client.request_lsp(
5670 project_id,
5671 None,
5672 LSP_REQUEST_TIMEOUT,
5673 cx.background_executor().clone(),
5674 request.to_proto(project_id, buffer.read(cx)),
5675 );
5676 let buffer = buffer.clone();
5677 cx.spawn(async move |weak_lsp_store, cx| {
5678 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5679 return Ok(None);
5680 };
5681 let Some(responses) = request_task.await? else {
5682 return Ok(None);
5683 };
5684 let actions = join_all(responses.payload.into_iter().map(|response| {
5685 GetDeclarations { position }.response_from_proto(
5686 response.response,
5687 lsp_store.clone(),
5688 buffer.clone(),
5689 cx.clone(),
5690 )
5691 }))
5692 .await;
5693
5694 Ok(Some(
5695 actions
5696 .into_iter()
5697 .collect::<Result<Vec<Vec<_>>>>()?
5698 .into_iter()
5699 .flatten()
5700 .dedup()
5701 .collect(),
5702 ))
5703 })
5704 } else {
5705 let declarations_task = self.request_multiple_lsp_locally(
5706 buffer,
5707 Some(position),
5708 GetDeclarations { position },
5709 cx,
5710 );
5711 cx.background_spawn(async move {
5712 Ok(Some(
5713 declarations_task
5714 .await
5715 .into_iter()
5716 .flat_map(|(_, declarations)| declarations)
5717 .dedup()
5718 .collect(),
5719 ))
5720 })
5721 }
5722 }
5723
5724 pub fn type_definitions(
5725 &mut self,
5726 buffer: &Entity<Buffer>,
5727 position: PointUtf16,
5728 cx: &mut Context<Self>,
5729 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5730 if let Some((upstream_client, project_id)) = self.upstream_client() {
5731 let request = GetTypeDefinitions { position };
5732 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5733 return Task::ready(Ok(None));
5734 }
5735 let request_task = upstream_client.request_lsp(
5736 project_id,
5737 None,
5738 LSP_REQUEST_TIMEOUT,
5739 cx.background_executor().clone(),
5740 request.to_proto(project_id, buffer.read(cx)),
5741 );
5742 let buffer = buffer.clone();
5743 cx.spawn(async move |weak_lsp_store, cx| {
5744 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5745 return Ok(None);
5746 };
5747 let Some(responses) = request_task.await? else {
5748 return Ok(None);
5749 };
5750 let actions = join_all(responses.payload.into_iter().map(|response| {
5751 GetTypeDefinitions { position }.response_from_proto(
5752 response.response,
5753 lsp_store.clone(),
5754 buffer.clone(),
5755 cx.clone(),
5756 )
5757 }))
5758 .await;
5759
5760 Ok(Some(
5761 actions
5762 .into_iter()
5763 .collect::<Result<Vec<Vec<_>>>>()?
5764 .into_iter()
5765 .flatten()
5766 .dedup()
5767 .collect(),
5768 ))
5769 })
5770 } else {
5771 let type_definitions_task = self.request_multiple_lsp_locally(
5772 buffer,
5773 Some(position),
5774 GetTypeDefinitions { position },
5775 cx,
5776 );
5777 cx.background_spawn(async move {
5778 Ok(Some(
5779 type_definitions_task
5780 .await
5781 .into_iter()
5782 .flat_map(|(_, type_definitions)| type_definitions)
5783 .dedup()
5784 .collect(),
5785 ))
5786 })
5787 }
5788 }
5789
5790 pub fn implementations(
5791 &mut self,
5792 buffer: &Entity<Buffer>,
5793 position: PointUtf16,
5794 cx: &mut Context<Self>,
5795 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5796 if let Some((upstream_client, project_id)) = self.upstream_client() {
5797 let request = GetImplementations { position };
5798 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5799 return Task::ready(Ok(None));
5800 }
5801 let request_task = upstream_client.request_lsp(
5802 project_id,
5803 None,
5804 LSP_REQUEST_TIMEOUT,
5805 cx.background_executor().clone(),
5806 request.to_proto(project_id, buffer.read(cx)),
5807 );
5808 let buffer = buffer.clone();
5809 cx.spawn(async move |weak_lsp_store, cx| {
5810 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5811 return Ok(None);
5812 };
5813 let Some(responses) = request_task.await? else {
5814 return Ok(None);
5815 };
5816 let actions = join_all(responses.payload.into_iter().map(|response| {
5817 GetImplementations { position }.response_from_proto(
5818 response.response,
5819 lsp_store.clone(),
5820 buffer.clone(),
5821 cx.clone(),
5822 )
5823 }))
5824 .await;
5825
5826 Ok(Some(
5827 actions
5828 .into_iter()
5829 .collect::<Result<Vec<Vec<_>>>>()?
5830 .into_iter()
5831 .flatten()
5832 .dedup()
5833 .collect(),
5834 ))
5835 })
5836 } else {
5837 let implementations_task = self.request_multiple_lsp_locally(
5838 buffer,
5839 Some(position),
5840 GetImplementations { position },
5841 cx,
5842 );
5843 cx.background_spawn(async move {
5844 Ok(Some(
5845 implementations_task
5846 .await
5847 .into_iter()
5848 .flat_map(|(_, implementations)| implementations)
5849 .dedup()
5850 .collect(),
5851 ))
5852 })
5853 }
5854 }
5855
5856 pub fn references(
5857 &mut self,
5858 buffer: &Entity<Buffer>,
5859 position: PointUtf16,
5860 cx: &mut Context<Self>,
5861 ) -> Task<Result<Option<Vec<Location>>>> {
5862 if let Some((upstream_client, project_id)) = self.upstream_client() {
5863 let request = GetReferences { position };
5864 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5865 return Task::ready(Ok(None));
5866 }
5867
5868 let request_task = upstream_client.request_lsp(
5869 project_id,
5870 None,
5871 LSP_REQUEST_TIMEOUT,
5872 cx.background_executor().clone(),
5873 request.to_proto(project_id, buffer.read(cx)),
5874 );
5875 let buffer = buffer.clone();
5876 cx.spawn(async move |weak_lsp_store, cx| {
5877 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5878 return Ok(None);
5879 };
5880 let Some(responses) = request_task.await? else {
5881 return Ok(None);
5882 };
5883
5884 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5885 GetReferences { position }.response_from_proto(
5886 lsp_response.response,
5887 lsp_store.clone(),
5888 buffer.clone(),
5889 cx.clone(),
5890 )
5891 }))
5892 .await
5893 .into_iter()
5894 .collect::<Result<Vec<Vec<_>>>>()?
5895 .into_iter()
5896 .flatten()
5897 .dedup()
5898 .collect();
5899 Ok(Some(locations))
5900 })
5901 } else {
5902 let references_task = self.request_multiple_lsp_locally(
5903 buffer,
5904 Some(position),
5905 GetReferences { position },
5906 cx,
5907 );
5908 cx.background_spawn(async move {
5909 Ok(Some(
5910 references_task
5911 .await
5912 .into_iter()
5913 .flat_map(|(_, references)| references)
5914 .dedup()
5915 .collect(),
5916 ))
5917 })
5918 }
5919 }
5920
5921 pub fn code_actions(
5922 &mut self,
5923 buffer: &Entity<Buffer>,
5924 range: Range<Anchor>,
5925 kinds: Option<Vec<CodeActionKind>>,
5926 cx: &mut Context<Self>,
5927 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5928 if let Some((upstream_client, project_id)) = self.upstream_client() {
5929 let request = GetCodeActions {
5930 range: range.clone(),
5931 kinds: kinds.clone(),
5932 };
5933 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5934 return Task::ready(Ok(None));
5935 }
5936 let request_task = upstream_client.request_lsp(
5937 project_id,
5938 None,
5939 LSP_REQUEST_TIMEOUT,
5940 cx.background_executor().clone(),
5941 request.to_proto(project_id, buffer.read(cx)),
5942 );
5943 let buffer = buffer.clone();
5944 cx.spawn(async move |weak_lsp_store, cx| {
5945 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5946 return Ok(None);
5947 };
5948 let Some(responses) = request_task.await? else {
5949 return Ok(None);
5950 };
5951 let actions = join_all(responses.payload.into_iter().map(|response| {
5952 GetCodeActions {
5953 range: range.clone(),
5954 kinds: kinds.clone(),
5955 }
5956 .response_from_proto(
5957 response.response,
5958 lsp_store.clone(),
5959 buffer.clone(),
5960 cx.clone(),
5961 )
5962 }))
5963 .await;
5964
5965 Ok(Some(
5966 actions
5967 .into_iter()
5968 .collect::<Result<Vec<Vec<_>>>>()?
5969 .into_iter()
5970 .flatten()
5971 .collect(),
5972 ))
5973 })
5974 } else {
5975 let all_actions_task = self.request_multiple_lsp_locally(
5976 buffer,
5977 Some(range.start),
5978 GetCodeActions { range, kinds },
5979 cx,
5980 );
5981 cx.background_spawn(async move {
5982 Ok(Some(
5983 all_actions_task
5984 .await
5985 .into_iter()
5986 .flat_map(|(_, actions)| actions)
5987 .collect(),
5988 ))
5989 })
5990 }
5991 }
5992
5993 pub fn code_lens_actions(
5994 &mut self,
5995 buffer: &Entity<Buffer>,
5996 cx: &mut Context<Self>,
5997 ) -> CodeLensTask {
5998 let version_queried_for = buffer.read(cx).version();
5999 let buffer_id = buffer.read(cx).remote_id();
6000 let existing_servers = self.as_local().map(|local| {
6001 local
6002 .buffers_opened_in_servers
6003 .get(&buffer_id)
6004 .cloned()
6005 .unwrap_or_default()
6006 });
6007
6008 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6009 if let Some(cached_lens) = &lsp_data.code_lens {
6010 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6011 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6012 existing_servers != cached_lens.lens.keys().copied().collect()
6013 });
6014 if !has_different_servers {
6015 return Task::ready(Ok(Some(
6016 cached_lens.lens.values().flatten().cloned().collect(),
6017 )))
6018 .shared();
6019 }
6020 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6021 if !version_queried_for.changed_since(updating_for) {
6022 return running_update.clone();
6023 }
6024 }
6025 }
6026 }
6027
6028 let lens_lsp_data = self
6029 .latest_lsp_data(buffer, cx)
6030 .code_lens
6031 .get_or_insert_default();
6032 let buffer = buffer.clone();
6033 let query_version_queried_for = version_queried_for.clone();
6034 let new_task = cx
6035 .spawn(async move |lsp_store, cx| {
6036 cx.background_executor()
6037 .timer(Duration::from_millis(30))
6038 .await;
6039 let fetched_lens = lsp_store
6040 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6041 .map_err(Arc::new)?
6042 .await
6043 .context("fetching code lens")
6044 .map_err(Arc::new);
6045 let fetched_lens = match fetched_lens {
6046 Ok(fetched_lens) => fetched_lens,
6047 Err(e) => {
6048 lsp_store
6049 .update(cx, |lsp_store, _| {
6050 if let Some(lens_lsp_data) = lsp_store
6051 .lsp_data
6052 .get_mut(&buffer_id)
6053 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6054 {
6055 lens_lsp_data.update = None;
6056 }
6057 })
6058 .ok();
6059 return Err(e);
6060 }
6061 };
6062
6063 lsp_store
6064 .update(cx, |lsp_store, _| {
6065 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6066 let code_lens = lsp_data.code_lens.as_mut()?;
6067 if let Some(fetched_lens) = fetched_lens {
6068 if lsp_data.buffer_version == query_version_queried_for {
6069 code_lens.lens.extend(fetched_lens);
6070 } else if !lsp_data
6071 .buffer_version
6072 .changed_since(&query_version_queried_for)
6073 {
6074 lsp_data.buffer_version = query_version_queried_for;
6075 code_lens.lens = fetched_lens;
6076 }
6077 }
6078 code_lens.update = None;
6079 Some(code_lens.lens.values().flatten().cloned().collect())
6080 })
6081 .map_err(Arc::new)
6082 })
6083 .shared();
6084 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6085 new_task
6086 }
6087
6088 fn fetch_code_lens(
6089 &mut self,
6090 buffer: &Entity<Buffer>,
6091 cx: &mut Context<Self>,
6092 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6093 if let Some((upstream_client, project_id)) = self.upstream_client() {
6094 let request = GetCodeLens;
6095 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6096 return Task::ready(Ok(None));
6097 }
6098 let request_task = upstream_client.request_lsp(
6099 project_id,
6100 None,
6101 LSP_REQUEST_TIMEOUT,
6102 cx.background_executor().clone(),
6103 request.to_proto(project_id, buffer.read(cx)),
6104 );
6105 let buffer = buffer.clone();
6106 cx.spawn(async move |weak_lsp_store, cx| {
6107 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6108 return Ok(None);
6109 };
6110 let Some(responses) = request_task.await? else {
6111 return Ok(None);
6112 };
6113
6114 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6115 let lsp_store = lsp_store.clone();
6116 let buffer = buffer.clone();
6117 let cx = cx.clone();
6118 async move {
6119 (
6120 LanguageServerId::from_proto(response.server_id),
6121 GetCodeLens
6122 .response_from_proto(response.response, lsp_store, buffer, cx)
6123 .await,
6124 )
6125 }
6126 }))
6127 .await;
6128
6129 let mut has_errors = false;
6130 let code_lens_actions = code_lens_actions
6131 .into_iter()
6132 .filter_map(|(server_id, code_lens)| match code_lens {
6133 Ok(code_lens) => Some((server_id, code_lens)),
6134 Err(e) => {
6135 has_errors = true;
6136 log::error!("{e:#}");
6137 None
6138 }
6139 })
6140 .collect::<HashMap<_, _>>();
6141 anyhow::ensure!(
6142 !has_errors || !code_lens_actions.is_empty(),
6143 "Failed to fetch code lens"
6144 );
6145 Ok(Some(code_lens_actions))
6146 })
6147 } else {
6148 let code_lens_actions_task =
6149 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6150 cx.background_spawn(async move {
6151 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6152 })
6153 }
6154 }
6155
6156 #[inline(never)]
6157 pub fn completions(
6158 &self,
6159 buffer: &Entity<Buffer>,
6160 position: PointUtf16,
6161 context: CompletionContext,
6162 cx: &mut Context<Self>,
6163 ) -> Task<Result<Vec<CompletionResponse>>> {
6164 let language_registry = self.languages.clone();
6165
6166 if let Some((upstream_client, project_id)) = self.upstream_client() {
6167 let snapshot = buffer.read(cx).snapshot();
6168 let offset = position.to_offset(&snapshot);
6169 let scope = snapshot.language_scope_at(offset);
6170 let capable_lsps = self.all_capable_for_proto_request(
6171 buffer,
6172 |server_name, capabilities| {
6173 capabilities.completion_provider.is_some()
6174 && scope
6175 .as_ref()
6176 .map(|scope| scope.language_allowed(server_name))
6177 .unwrap_or(true)
6178 },
6179 cx,
6180 );
6181 if capable_lsps.is_empty() {
6182 return Task::ready(Ok(Vec::new()));
6183 }
6184
6185 let language = buffer.read(cx).language().cloned();
6186
6187 // In the future, we should provide project guests with the names of LSP adapters,
6188 // so that they can use the correct LSP adapter when computing labels. For now,
6189 // guests just use the first LSP adapter associated with the buffer's language.
6190 let lsp_adapter = language.as_ref().and_then(|language| {
6191 language_registry
6192 .lsp_adapters(&language.name())
6193 .first()
6194 .cloned()
6195 });
6196
6197 let buffer = buffer.clone();
6198
6199 cx.spawn(async move |this, cx| {
6200 let requests = join_all(
6201 capable_lsps
6202 .into_iter()
6203 .map(|id| {
6204 let request = GetCompletions {
6205 position,
6206 context: context.clone(),
6207 server_id: Some(id),
6208 };
6209 let buffer = buffer.clone();
6210 let language = language.clone();
6211 let lsp_adapter = lsp_adapter.clone();
6212 let upstream_client = upstream_client.clone();
6213 let response = this
6214 .update(cx, |this, cx| {
6215 this.send_lsp_proto_request(
6216 buffer,
6217 upstream_client,
6218 project_id,
6219 request,
6220 cx,
6221 )
6222 })
6223 .log_err();
6224 async move {
6225 let response = response?.await.log_err()?;
6226
6227 let completions = populate_labels_for_completions(
6228 response.completions,
6229 language,
6230 lsp_adapter,
6231 )
6232 .await;
6233
6234 Some(CompletionResponse {
6235 completions,
6236 display_options: CompletionDisplayOptions::default(),
6237 is_incomplete: response.is_incomplete,
6238 })
6239 }
6240 })
6241 .collect::<Vec<_>>(),
6242 );
6243 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6244 })
6245 } else if let Some(local) = self.as_local() {
6246 let snapshot = buffer.read(cx).snapshot();
6247 let offset = position.to_offset(&snapshot);
6248 let scope = snapshot.language_scope_at(offset);
6249 let language = snapshot.language().cloned();
6250 let completion_settings = language_settings(
6251 language.as_ref().map(|language| language.name()),
6252 buffer.read(cx).file(),
6253 cx,
6254 )
6255 .completions
6256 .clone();
6257 if !completion_settings.lsp {
6258 return Task::ready(Ok(Vec::new()));
6259 }
6260
6261 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6262 local
6263 .language_servers_for_buffer(buffer, cx)
6264 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6265 .filter(|(adapter, _)| {
6266 scope
6267 .as_ref()
6268 .map(|scope| scope.language_allowed(&adapter.name))
6269 .unwrap_or(true)
6270 })
6271 .map(|(_, server)| server.server_id())
6272 .collect()
6273 });
6274
6275 let buffer = buffer.clone();
6276 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6277 let lsp_timeout = if lsp_timeout > 0 {
6278 Some(Duration::from_millis(lsp_timeout))
6279 } else {
6280 None
6281 };
6282 cx.spawn(async move |this, cx| {
6283 let mut tasks = Vec::with_capacity(server_ids.len());
6284 this.update(cx, |lsp_store, cx| {
6285 for server_id in server_ids {
6286 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6287 let lsp_timeout = lsp_timeout
6288 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6289 let mut timeout = cx.background_spawn(async move {
6290 match lsp_timeout {
6291 Some(lsp_timeout) => {
6292 lsp_timeout.await;
6293 true
6294 },
6295 None => false,
6296 }
6297 }).fuse();
6298 let mut lsp_request = lsp_store.request_lsp(
6299 buffer.clone(),
6300 LanguageServerToQuery::Other(server_id),
6301 GetCompletions {
6302 position,
6303 context: context.clone(),
6304 server_id: Some(server_id),
6305 },
6306 cx,
6307 ).fuse();
6308 let new_task = cx.background_spawn(async move {
6309 select_biased! {
6310 response = lsp_request => anyhow::Ok(Some(response?)),
6311 timeout_happened = timeout => {
6312 if timeout_happened {
6313 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6314 Ok(None)
6315 } else {
6316 let completions = lsp_request.await?;
6317 Ok(Some(completions))
6318 }
6319 },
6320 }
6321 });
6322 tasks.push((lsp_adapter, new_task));
6323 }
6324 })?;
6325
6326 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6327 let completion_response = task.await.ok()??;
6328 let completions = populate_labels_for_completions(
6329 completion_response.completions,
6330 language.clone(),
6331 lsp_adapter,
6332 )
6333 .await;
6334 Some(CompletionResponse {
6335 completions,
6336 display_options: CompletionDisplayOptions::default(),
6337 is_incomplete: completion_response.is_incomplete,
6338 })
6339 });
6340
6341 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6342
6343 Ok(responses.into_iter().flatten().collect())
6344 })
6345 } else {
6346 Task::ready(Err(anyhow!("No upstream client or local language server")))
6347 }
6348 }
6349
6350 pub fn resolve_completions(
6351 &self,
6352 buffer: Entity<Buffer>,
6353 completion_indices: Vec<usize>,
6354 completions: Rc<RefCell<Box<[Completion]>>>,
6355 cx: &mut Context<Self>,
6356 ) -> Task<Result<bool>> {
6357 let client = self.upstream_client();
6358 let buffer_id = buffer.read(cx).remote_id();
6359 let buffer_snapshot = buffer.read(cx).snapshot();
6360
6361 if !self.check_if_capable_for_proto_request(
6362 &buffer,
6363 GetCompletions::can_resolve_completions,
6364 cx,
6365 ) {
6366 return Task::ready(Ok(false));
6367 }
6368 cx.spawn(async move |lsp_store, cx| {
6369 let mut did_resolve = false;
6370 if let Some((client, project_id)) = client {
6371 for completion_index in completion_indices {
6372 let server_id = {
6373 let completion = &completions.borrow()[completion_index];
6374 completion.source.server_id()
6375 };
6376 if let Some(server_id) = server_id {
6377 if Self::resolve_completion_remote(
6378 project_id,
6379 server_id,
6380 buffer_id,
6381 completions.clone(),
6382 completion_index,
6383 client.clone(),
6384 )
6385 .await
6386 .log_err()
6387 .is_some()
6388 {
6389 did_resolve = true;
6390 }
6391 } else {
6392 resolve_word_completion(
6393 &buffer_snapshot,
6394 &mut completions.borrow_mut()[completion_index],
6395 );
6396 }
6397 }
6398 } else {
6399 for completion_index in completion_indices {
6400 let server_id = {
6401 let completion = &completions.borrow()[completion_index];
6402 completion.source.server_id()
6403 };
6404 if let Some(server_id) = server_id {
6405 let server_and_adapter = lsp_store
6406 .read_with(cx, |lsp_store, _| {
6407 let server = lsp_store.language_server_for_id(server_id)?;
6408 let adapter =
6409 lsp_store.language_server_adapter_for_id(server.server_id())?;
6410 Some((server, adapter))
6411 })
6412 .ok()
6413 .flatten();
6414 let Some((server, adapter)) = server_and_adapter else {
6415 continue;
6416 };
6417
6418 let resolved = Self::resolve_completion_local(
6419 server,
6420 completions.clone(),
6421 completion_index,
6422 )
6423 .await
6424 .log_err()
6425 .is_some();
6426 if resolved {
6427 Self::regenerate_completion_labels(
6428 adapter,
6429 &buffer_snapshot,
6430 completions.clone(),
6431 completion_index,
6432 )
6433 .await
6434 .log_err();
6435 did_resolve = true;
6436 }
6437 } else {
6438 resolve_word_completion(
6439 &buffer_snapshot,
6440 &mut completions.borrow_mut()[completion_index],
6441 );
6442 }
6443 }
6444 }
6445
6446 Ok(did_resolve)
6447 })
6448 }
6449
6450 async fn resolve_completion_local(
6451 server: Arc<lsp::LanguageServer>,
6452 completions: Rc<RefCell<Box<[Completion]>>>,
6453 completion_index: usize,
6454 ) -> Result<()> {
6455 let server_id = server.server_id();
6456 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6457 return Ok(());
6458 }
6459
6460 let request = {
6461 let completion = &completions.borrow()[completion_index];
6462 match &completion.source {
6463 CompletionSource::Lsp {
6464 lsp_completion,
6465 resolved,
6466 server_id: completion_server_id,
6467 ..
6468 } => {
6469 if *resolved {
6470 return Ok(());
6471 }
6472 anyhow::ensure!(
6473 server_id == *completion_server_id,
6474 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6475 );
6476 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6477 }
6478 CompletionSource::BufferWord { .. }
6479 | CompletionSource::Dap { .. }
6480 | CompletionSource::Custom => {
6481 return Ok(());
6482 }
6483 }
6484 };
6485 let resolved_completion = request
6486 .await
6487 .into_response()
6488 .context("resolve completion")?;
6489
6490 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6491 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6492
6493 let mut completions = completions.borrow_mut();
6494 let completion = &mut completions[completion_index];
6495 if let CompletionSource::Lsp {
6496 lsp_completion,
6497 resolved,
6498 server_id: completion_server_id,
6499 ..
6500 } = &mut completion.source
6501 {
6502 if *resolved {
6503 return Ok(());
6504 }
6505 anyhow::ensure!(
6506 server_id == *completion_server_id,
6507 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6508 );
6509 **lsp_completion = resolved_completion;
6510 *resolved = true;
6511 }
6512 Ok(())
6513 }
6514
6515 async fn regenerate_completion_labels(
6516 adapter: Arc<CachedLspAdapter>,
6517 snapshot: &BufferSnapshot,
6518 completions: Rc<RefCell<Box<[Completion]>>>,
6519 completion_index: usize,
6520 ) -> Result<()> {
6521 let completion_item = completions.borrow()[completion_index]
6522 .source
6523 .lsp_completion(true)
6524 .map(Cow::into_owned);
6525 if let Some(lsp_documentation) = completion_item
6526 .as_ref()
6527 .and_then(|completion_item| completion_item.documentation.clone())
6528 {
6529 let mut completions = completions.borrow_mut();
6530 let completion = &mut completions[completion_index];
6531 completion.documentation = Some(lsp_documentation.into());
6532 } else {
6533 let mut completions = completions.borrow_mut();
6534 let completion = &mut completions[completion_index];
6535 completion.documentation = Some(CompletionDocumentation::Undocumented);
6536 }
6537
6538 let mut new_label = match completion_item {
6539 Some(completion_item) => {
6540 // Some language servers always return `detail` lazily via resolve, regardless of
6541 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6542 // See: https://github.com/yioneko/vtsls/issues/213
6543 let language = snapshot.language();
6544 match language {
6545 Some(language) => {
6546 adapter
6547 .labels_for_completions(
6548 std::slice::from_ref(&completion_item),
6549 language,
6550 )
6551 .await?
6552 }
6553 None => Vec::new(),
6554 }
6555 .pop()
6556 .flatten()
6557 .unwrap_or_else(|| {
6558 CodeLabel::fallback_for_completion(
6559 &completion_item,
6560 language.map(|language| language.as_ref()),
6561 )
6562 })
6563 }
6564 None => CodeLabel::plain(
6565 completions.borrow()[completion_index].new_text.clone(),
6566 None,
6567 ),
6568 };
6569 ensure_uniform_list_compatible_label(&mut new_label);
6570
6571 let mut completions = completions.borrow_mut();
6572 let completion = &mut completions[completion_index];
6573 if completion.label.filter_text() == new_label.filter_text() {
6574 completion.label = new_label;
6575 } else {
6576 log::error!(
6577 "Resolved completion changed display label from {} to {}. \
6578 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6579 completion.label.text(),
6580 new_label.text(),
6581 completion.label.filter_text(),
6582 new_label.filter_text()
6583 );
6584 }
6585
6586 Ok(())
6587 }
6588
6589 async fn resolve_completion_remote(
6590 project_id: u64,
6591 server_id: LanguageServerId,
6592 buffer_id: BufferId,
6593 completions: Rc<RefCell<Box<[Completion]>>>,
6594 completion_index: usize,
6595 client: AnyProtoClient,
6596 ) -> Result<()> {
6597 let lsp_completion = {
6598 let completion = &completions.borrow()[completion_index];
6599 match &completion.source {
6600 CompletionSource::Lsp {
6601 lsp_completion,
6602 resolved,
6603 server_id: completion_server_id,
6604 ..
6605 } => {
6606 anyhow::ensure!(
6607 server_id == *completion_server_id,
6608 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6609 );
6610 if *resolved {
6611 return Ok(());
6612 }
6613 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6614 }
6615 CompletionSource::Custom
6616 | CompletionSource::Dap { .. }
6617 | CompletionSource::BufferWord { .. } => {
6618 return Ok(());
6619 }
6620 }
6621 };
6622 let request = proto::ResolveCompletionDocumentation {
6623 project_id,
6624 language_server_id: server_id.0 as u64,
6625 lsp_completion,
6626 buffer_id: buffer_id.into(),
6627 };
6628
6629 let response = client
6630 .request(request)
6631 .await
6632 .context("completion documentation resolve proto request")?;
6633 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6634
6635 let documentation = if response.documentation.is_empty() {
6636 CompletionDocumentation::Undocumented
6637 } else if response.documentation_is_markdown {
6638 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6639 } else if response.documentation.lines().count() <= 1 {
6640 CompletionDocumentation::SingleLine(response.documentation.into())
6641 } else {
6642 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6643 };
6644
6645 let mut completions = completions.borrow_mut();
6646 let completion = &mut completions[completion_index];
6647 completion.documentation = Some(documentation);
6648 if let CompletionSource::Lsp {
6649 insert_range,
6650 lsp_completion,
6651 resolved,
6652 server_id: completion_server_id,
6653 lsp_defaults: _,
6654 } = &mut completion.source
6655 {
6656 let completion_insert_range = response
6657 .old_insert_start
6658 .and_then(deserialize_anchor)
6659 .zip(response.old_insert_end.and_then(deserialize_anchor));
6660 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6661
6662 if *resolved {
6663 return Ok(());
6664 }
6665 anyhow::ensure!(
6666 server_id == *completion_server_id,
6667 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6668 );
6669 **lsp_completion = resolved_lsp_completion;
6670 *resolved = true;
6671 }
6672
6673 let replace_range = response
6674 .old_replace_start
6675 .and_then(deserialize_anchor)
6676 .zip(response.old_replace_end.and_then(deserialize_anchor));
6677 if let Some((old_replace_start, old_replace_end)) = replace_range
6678 && !response.new_text.is_empty()
6679 {
6680 completion.new_text = response.new_text;
6681 completion.replace_range = old_replace_start..old_replace_end;
6682 }
6683
6684 Ok(())
6685 }
6686
6687 pub fn apply_additional_edits_for_completion(
6688 &self,
6689 buffer_handle: Entity<Buffer>,
6690 completions: Rc<RefCell<Box<[Completion]>>>,
6691 completion_index: usize,
6692 push_to_history: bool,
6693 cx: &mut Context<Self>,
6694 ) -> Task<Result<Option<Transaction>>> {
6695 if let Some((client, project_id)) = self.upstream_client() {
6696 let buffer = buffer_handle.read(cx);
6697 let buffer_id = buffer.remote_id();
6698 cx.spawn(async move |_, cx| {
6699 let request = {
6700 let completion = completions.borrow()[completion_index].clone();
6701 proto::ApplyCompletionAdditionalEdits {
6702 project_id,
6703 buffer_id: buffer_id.into(),
6704 completion: Some(Self::serialize_completion(&CoreCompletion {
6705 replace_range: completion.replace_range,
6706 new_text: completion.new_text,
6707 source: completion.source,
6708 })),
6709 }
6710 };
6711
6712 if let Some(transaction) = client.request(request).await?.transaction {
6713 let transaction = language::proto::deserialize_transaction(transaction)?;
6714 buffer_handle
6715 .update(cx, |buffer, _| {
6716 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6717 })?
6718 .await?;
6719 if push_to_history {
6720 buffer_handle.update(cx, |buffer, _| {
6721 buffer.push_transaction(transaction.clone(), Instant::now());
6722 buffer.finalize_last_transaction();
6723 })?;
6724 }
6725 Ok(Some(transaction))
6726 } else {
6727 Ok(None)
6728 }
6729 })
6730 } else {
6731 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6732 let completion = &completions.borrow()[completion_index];
6733 let server_id = completion.source.server_id()?;
6734 Some(
6735 self.language_server_for_local_buffer(buffer, server_id, cx)?
6736 .1
6737 .clone(),
6738 )
6739 }) else {
6740 return Task::ready(Ok(None));
6741 };
6742
6743 cx.spawn(async move |this, cx| {
6744 Self::resolve_completion_local(
6745 server.clone(),
6746 completions.clone(),
6747 completion_index,
6748 )
6749 .await
6750 .context("resolving completion")?;
6751 let completion = completions.borrow()[completion_index].clone();
6752 let additional_text_edits = completion
6753 .source
6754 .lsp_completion(true)
6755 .as_ref()
6756 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6757 if let Some(edits) = additional_text_edits {
6758 let edits = this
6759 .update(cx, |this, cx| {
6760 this.as_local_mut().unwrap().edits_from_lsp(
6761 &buffer_handle,
6762 edits,
6763 server.server_id(),
6764 None,
6765 cx,
6766 )
6767 })?
6768 .await?;
6769
6770 buffer_handle.update(cx, |buffer, cx| {
6771 buffer.finalize_last_transaction();
6772 buffer.start_transaction();
6773
6774 for (range, text) in edits {
6775 let primary = &completion.replace_range;
6776
6777 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6778 // and the primary completion is just an insertion (empty range), then this is likely
6779 // an auto-import scenario and should not be considered overlapping
6780 // https://github.com/zed-industries/zed/issues/26136
6781 let is_file_start_auto_import = {
6782 let snapshot = buffer.snapshot();
6783 let primary_start_point = primary.start.to_point(&snapshot);
6784 let range_start_point = range.start.to_point(&snapshot);
6785
6786 let result = primary_start_point.row == 0
6787 && primary_start_point.column == 0
6788 && range_start_point.row == 0
6789 && range_start_point.column == 0;
6790
6791 result
6792 };
6793
6794 let has_overlap = if is_file_start_auto_import {
6795 false
6796 } else {
6797 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6798 && primary.end.cmp(&range.start, buffer).is_ge();
6799 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6800 && range.end.cmp(&primary.end, buffer).is_ge();
6801 let result = start_within || end_within;
6802 result
6803 };
6804
6805 //Skip additional edits which overlap with the primary completion edit
6806 //https://github.com/zed-industries/zed/pull/1871
6807 if !has_overlap {
6808 buffer.edit([(range, text)], None, cx);
6809 }
6810 }
6811
6812 let transaction = if buffer.end_transaction(cx).is_some() {
6813 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6814 if !push_to_history {
6815 buffer.forget_transaction(transaction.id);
6816 }
6817 Some(transaction)
6818 } else {
6819 None
6820 };
6821 Ok(transaction)
6822 })?
6823 } else {
6824 Ok(None)
6825 }
6826 })
6827 }
6828 }
6829
6830 pub fn pull_diagnostics(
6831 &mut self,
6832 buffer: Entity<Buffer>,
6833 cx: &mut Context<Self>,
6834 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6835 let buffer_id = buffer.read(cx).remote_id();
6836
6837 if let Some((client, upstream_project_id)) = self.upstream_client() {
6838 let mut suitable_capabilities = None;
6839 // Are we capable for proto request?
6840 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6841 &buffer,
6842 |capabilities| {
6843 if let Some(caps) = &capabilities.diagnostic_provider {
6844 suitable_capabilities = Some(caps.clone());
6845 true
6846 } else {
6847 false
6848 }
6849 },
6850 cx,
6851 );
6852 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6853 let Some(dynamic_caps) = suitable_capabilities else {
6854 return Task::ready(Ok(None));
6855 };
6856 assert!(any_server_has_diagnostics_provider);
6857
6858 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6859 let request = GetDocumentDiagnostics {
6860 previous_result_id: None,
6861 identifier,
6862 registration_id: None,
6863 };
6864 let request_task = client.request_lsp(
6865 upstream_project_id,
6866 None,
6867 LSP_REQUEST_TIMEOUT,
6868 cx.background_executor().clone(),
6869 request.to_proto(upstream_project_id, buffer.read(cx)),
6870 );
6871 cx.background_spawn(async move {
6872 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6873 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6874 // Do not attempt to further process the dummy responses here.
6875 let _response = request_task.await?;
6876 Ok(None)
6877 })
6878 } else {
6879 let servers = buffer.update(cx, |buffer, cx| {
6880 self.running_language_servers_for_local_buffer(buffer, cx)
6881 .map(|(_, server)| server.clone())
6882 .collect::<Vec<_>>()
6883 });
6884
6885 let pull_diagnostics = servers
6886 .into_iter()
6887 .flat_map(|server| {
6888 let result = maybe!({
6889 let local = self.as_local()?;
6890 let server_id = server.server_id();
6891 let providers_with_identifiers = local
6892 .language_server_dynamic_registrations
6893 .get(&server_id)
6894 .into_iter()
6895 .flat_map(|registrations| registrations.diagnostics.clone())
6896 .collect::<Vec<_>>();
6897 Some(
6898 providers_with_identifiers
6899 .into_iter()
6900 .map(|(registration_id, dynamic_caps)| {
6901 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6902 let registration_id = registration_id.map(SharedString::from);
6903 let result_id = self.result_id_for_buffer_pull(
6904 server_id,
6905 buffer_id,
6906 ®istration_id,
6907 cx,
6908 );
6909 self.request_lsp(
6910 buffer.clone(),
6911 LanguageServerToQuery::Other(server_id),
6912 GetDocumentDiagnostics {
6913 previous_result_id: result_id,
6914 registration_id,
6915 identifier,
6916 },
6917 cx,
6918 )
6919 })
6920 .collect::<Vec<_>>(),
6921 )
6922 });
6923
6924 result.unwrap_or_default()
6925 })
6926 .collect::<Vec<_>>();
6927
6928 cx.background_spawn(async move {
6929 let mut responses = Vec::new();
6930 for diagnostics in join_all(pull_diagnostics).await {
6931 responses.extend(diagnostics?);
6932 }
6933 Ok(Some(responses))
6934 })
6935 }
6936 }
6937
6938 pub fn applicable_inlay_chunks(
6939 &mut self,
6940 buffer: &Entity<Buffer>,
6941 ranges: &[Range<text::Anchor>],
6942 cx: &mut Context<Self>,
6943 ) -> Vec<Range<BufferRow>> {
6944 let buffer_snapshot = buffer.read(cx).snapshot();
6945 let ranges = ranges
6946 .iter()
6947 .map(|range| range.to_point(&buffer_snapshot))
6948 .collect::<Vec<_>>();
6949
6950 self.latest_lsp_data(buffer, cx)
6951 .inlay_hints
6952 .applicable_chunks(ranges.as_slice())
6953 .map(|chunk| chunk.row_range())
6954 .collect()
6955 }
6956
6957 pub fn invalidate_inlay_hints<'a>(
6958 &'a mut self,
6959 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6960 ) {
6961 for buffer_id in for_buffers {
6962 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6963 lsp_data.inlay_hints.clear();
6964 }
6965 }
6966 }
6967
6968 pub fn inlay_hints(
6969 &mut self,
6970 invalidate: InvalidationStrategy,
6971 buffer: Entity<Buffer>,
6972 ranges: Vec<Range<text::Anchor>>,
6973 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6974 cx: &mut Context<Self>,
6975 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6976 let next_hint_id = self.next_hint_id.clone();
6977 let lsp_data = self.latest_lsp_data(&buffer, cx);
6978 let query_version = lsp_data.buffer_version.clone();
6979 let mut lsp_refresh_requested = false;
6980 let for_server = if let InvalidationStrategy::RefreshRequested {
6981 server_id,
6982 request_id,
6983 } = invalidate
6984 {
6985 let invalidated = lsp_data
6986 .inlay_hints
6987 .invalidate_for_server_refresh(server_id, request_id);
6988 lsp_refresh_requested = invalidated;
6989 Some(server_id)
6990 } else {
6991 None
6992 };
6993 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6994 let known_chunks = known_chunks
6995 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6996 .map(|(_, known_chunks)| known_chunks)
6997 .unwrap_or_default();
6998
6999 let buffer_snapshot = buffer.read(cx).snapshot();
7000 let ranges = ranges
7001 .iter()
7002 .map(|range| range.to_point(&buffer_snapshot))
7003 .collect::<Vec<_>>();
7004
7005 let mut hint_fetch_tasks = Vec::new();
7006 let mut cached_inlay_hints = None;
7007 let mut ranges_to_query = None;
7008 let applicable_chunks = existing_inlay_hints
7009 .applicable_chunks(ranges.as_slice())
7010 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7011 .collect::<Vec<_>>();
7012 if applicable_chunks.is_empty() {
7013 return HashMap::default();
7014 }
7015
7016 for row_chunk in applicable_chunks {
7017 match (
7018 existing_inlay_hints
7019 .cached_hints(&row_chunk)
7020 .filter(|_| !lsp_refresh_requested)
7021 .cloned(),
7022 existing_inlay_hints
7023 .fetched_hints(&row_chunk)
7024 .as_ref()
7025 .filter(|_| !lsp_refresh_requested)
7026 .cloned(),
7027 ) {
7028 (None, None) => {
7029 let chunk_range = row_chunk.anchor_range();
7030 ranges_to_query
7031 .get_or_insert_with(Vec::new)
7032 .push((row_chunk, chunk_range));
7033 }
7034 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7035 (Some(cached_hints), None) => {
7036 for (server_id, cached_hints) in cached_hints {
7037 if for_server.is_none_or(|for_server| for_server == server_id) {
7038 cached_inlay_hints
7039 .get_or_insert_with(HashMap::default)
7040 .entry(row_chunk.row_range())
7041 .or_insert_with(HashMap::default)
7042 .entry(server_id)
7043 .or_insert_with(Vec::new)
7044 .extend(cached_hints);
7045 }
7046 }
7047 }
7048 (Some(cached_hints), Some(fetched_hints)) => {
7049 hint_fetch_tasks.push((row_chunk, fetched_hints));
7050 for (server_id, cached_hints) in cached_hints {
7051 if for_server.is_none_or(|for_server| for_server == server_id) {
7052 cached_inlay_hints
7053 .get_or_insert_with(HashMap::default)
7054 .entry(row_chunk.row_range())
7055 .or_insert_with(HashMap::default)
7056 .entry(server_id)
7057 .or_insert_with(Vec::new)
7058 .extend(cached_hints);
7059 }
7060 }
7061 }
7062 }
7063 }
7064
7065 if hint_fetch_tasks.is_empty()
7066 && ranges_to_query
7067 .as_ref()
7068 .is_none_or(|ranges| ranges.is_empty())
7069 && let Some(cached_inlay_hints) = cached_inlay_hints
7070 {
7071 cached_inlay_hints
7072 .into_iter()
7073 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7074 .collect()
7075 } else {
7076 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7077 let next_hint_id = next_hint_id.clone();
7078 let buffer = buffer.clone();
7079 let query_version = query_version.clone();
7080 let new_inlay_hints = cx
7081 .spawn(async move |lsp_store, cx| {
7082 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7083 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7084 })?;
7085 new_fetch_task
7086 .await
7087 .and_then(|new_hints_by_server| {
7088 lsp_store.update(cx, |lsp_store, cx| {
7089 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7090 let update_cache = lsp_data.buffer_version == query_version;
7091 if new_hints_by_server.is_empty() {
7092 if update_cache {
7093 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7094 }
7095 HashMap::default()
7096 } else {
7097 new_hints_by_server
7098 .into_iter()
7099 .map(|(server_id, new_hints)| {
7100 let new_hints = new_hints
7101 .into_iter()
7102 .map(|new_hint| {
7103 (
7104 InlayId::Hint(next_hint_id.fetch_add(
7105 1,
7106 atomic::Ordering::AcqRel,
7107 )),
7108 new_hint,
7109 )
7110 })
7111 .collect::<Vec<_>>();
7112 if update_cache {
7113 lsp_data.inlay_hints.insert_new_hints(
7114 chunk,
7115 server_id,
7116 new_hints.clone(),
7117 );
7118 }
7119 (server_id, new_hints)
7120 })
7121 .collect()
7122 }
7123 })
7124 })
7125 .map_err(Arc::new)
7126 })
7127 .shared();
7128
7129 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7130 *fetch_task = Some(new_inlay_hints.clone());
7131 hint_fetch_tasks.push((chunk, new_inlay_hints));
7132 }
7133
7134 cached_inlay_hints
7135 .unwrap_or_default()
7136 .into_iter()
7137 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7138 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7139 (
7140 chunk.row_range(),
7141 cx.spawn(async move |_, _| {
7142 hints_fetch.await.map_err(|e| {
7143 if e.error_code() != ErrorCode::Internal {
7144 anyhow!(e.error_code())
7145 } else {
7146 anyhow!("{e:#}")
7147 }
7148 })
7149 }),
7150 )
7151 }))
7152 .collect()
7153 }
7154 }
7155
7156 fn fetch_inlay_hints(
7157 &mut self,
7158 for_server: Option<LanguageServerId>,
7159 buffer: &Entity<Buffer>,
7160 range: Range<Anchor>,
7161 cx: &mut Context<Self>,
7162 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7163 let request = InlayHints {
7164 range: range.clone(),
7165 };
7166 if let Some((upstream_client, project_id)) = self.upstream_client() {
7167 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7168 return Task::ready(Ok(HashMap::default()));
7169 }
7170 let request_task = upstream_client.request_lsp(
7171 project_id,
7172 for_server.map(|id| id.to_proto()),
7173 LSP_REQUEST_TIMEOUT,
7174 cx.background_executor().clone(),
7175 request.to_proto(project_id, buffer.read(cx)),
7176 );
7177 let buffer = buffer.clone();
7178 cx.spawn(async move |weak_lsp_store, cx| {
7179 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7180 return Ok(HashMap::default());
7181 };
7182 let Some(responses) = request_task.await? else {
7183 return Ok(HashMap::default());
7184 };
7185
7186 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7187 let lsp_store = lsp_store.clone();
7188 let buffer = buffer.clone();
7189 let cx = cx.clone();
7190 let request = request.clone();
7191 async move {
7192 (
7193 LanguageServerId::from_proto(response.server_id),
7194 request
7195 .response_from_proto(response.response, lsp_store, buffer, cx)
7196 .await,
7197 )
7198 }
7199 }))
7200 .await;
7201
7202 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7203 let mut has_errors = false;
7204 let inlay_hints = inlay_hints
7205 .into_iter()
7206 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7207 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7208 Err(e) => {
7209 has_errors = true;
7210 log::error!("{e:#}");
7211 None
7212 }
7213 })
7214 .map(|(server_id, mut new_hints)| {
7215 new_hints.retain(|hint| {
7216 hint.position.is_valid(&buffer_snapshot)
7217 && range.start.is_valid(&buffer_snapshot)
7218 && range.end.is_valid(&buffer_snapshot)
7219 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7220 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7221 });
7222 (server_id, new_hints)
7223 })
7224 .collect::<HashMap<_, _>>();
7225 anyhow::ensure!(
7226 !has_errors || !inlay_hints.is_empty(),
7227 "Failed to fetch inlay hints"
7228 );
7229 Ok(inlay_hints)
7230 })
7231 } else {
7232 let inlay_hints_task = match for_server {
7233 Some(server_id) => {
7234 let server_task = self.request_lsp(
7235 buffer.clone(),
7236 LanguageServerToQuery::Other(server_id),
7237 request,
7238 cx,
7239 );
7240 cx.background_spawn(async move {
7241 let mut responses = Vec::new();
7242 match server_task.await {
7243 Ok(response) => responses.push((server_id, response)),
7244 // rust-analyzer likes to error with this when its still loading up
7245 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7246 Err(e) => log::error!(
7247 "Error handling response for inlay hints request: {e:#}"
7248 ),
7249 }
7250 responses
7251 })
7252 }
7253 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7254 };
7255 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7256 cx.background_spawn(async move {
7257 Ok(inlay_hints_task
7258 .await
7259 .into_iter()
7260 .map(|(server_id, mut new_hints)| {
7261 new_hints.retain(|hint| {
7262 hint.position.is_valid(&buffer_snapshot)
7263 && range.start.is_valid(&buffer_snapshot)
7264 && range.end.is_valid(&buffer_snapshot)
7265 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7266 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7267 });
7268 (server_id, new_hints)
7269 })
7270 .collect())
7271 })
7272 }
7273 }
7274
7275 fn diagnostic_registration_exists(
7276 &self,
7277 server_id: LanguageServerId,
7278 registration_id: &Option<SharedString>,
7279 ) -> bool {
7280 let Some(local) = self.as_local() else {
7281 return false;
7282 };
7283 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7284 else {
7285 return false;
7286 };
7287 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7288 registrations.diagnostics.contains_key(®istration_key)
7289 }
7290
7291 pub fn pull_diagnostics_for_buffer(
7292 &mut self,
7293 buffer: Entity<Buffer>,
7294 cx: &mut Context<Self>,
7295 ) -> Task<anyhow::Result<()>> {
7296 let diagnostics = self.pull_diagnostics(buffer, cx);
7297 cx.spawn(async move |lsp_store, cx| {
7298 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7299 return Ok(());
7300 };
7301 lsp_store.update(cx, |lsp_store, cx| {
7302 if lsp_store.as_local().is_none() {
7303 return;
7304 }
7305
7306 let mut unchanged_buffers = HashMap::default();
7307 let server_diagnostics_updates = diagnostics
7308 .into_iter()
7309 .filter_map(|diagnostics_set| match diagnostics_set {
7310 LspPullDiagnostics::Response {
7311 server_id,
7312 uri,
7313 diagnostics,
7314 registration_id,
7315 } => Some((server_id, uri, diagnostics, registration_id)),
7316 LspPullDiagnostics::Default => None,
7317 })
7318 .filter(|(server_id, _, _, registration_id)| {
7319 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7320 })
7321 .fold(
7322 HashMap::default(),
7323 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7324 let (result_id, diagnostics) = match diagnostics {
7325 PulledDiagnostics::Unchanged { result_id } => {
7326 unchanged_buffers
7327 .entry(new_registration_id.clone())
7328 .or_insert_with(HashSet::default)
7329 .insert(uri.clone());
7330 (Some(result_id), Vec::new())
7331 }
7332 PulledDiagnostics::Changed {
7333 result_id,
7334 diagnostics,
7335 } => (result_id, diagnostics),
7336 };
7337 let disk_based_sources = Cow::Owned(
7338 lsp_store
7339 .language_server_adapter_for_id(server_id)
7340 .as_ref()
7341 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7342 .unwrap_or(&[])
7343 .to_vec(),
7344 );
7345 acc.entry(server_id)
7346 .or_insert_with(HashMap::default)
7347 .entry(new_registration_id.clone())
7348 .or_insert_with(Vec::new)
7349 .push(DocumentDiagnosticsUpdate {
7350 server_id,
7351 diagnostics: lsp::PublishDiagnosticsParams {
7352 uri,
7353 diagnostics,
7354 version: None,
7355 },
7356 result_id,
7357 disk_based_sources,
7358 registration_id: new_registration_id,
7359 });
7360 acc
7361 },
7362 );
7363
7364 for diagnostic_updates in server_diagnostics_updates.into_values() {
7365 for (registration_id, diagnostic_updates) in diagnostic_updates {
7366 lsp_store
7367 .merge_lsp_diagnostics(
7368 DiagnosticSourceKind::Pulled,
7369 diagnostic_updates,
7370 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7371 DiagnosticSourceKind::Pulled => {
7372 old_diagnostic.registration_id != registration_id
7373 || unchanged_buffers
7374 .get(&old_diagnostic.registration_id)
7375 .is_some_and(|unchanged_buffers| {
7376 unchanged_buffers.contains(&document_uri)
7377 })
7378 }
7379 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7380 true
7381 }
7382 },
7383 cx,
7384 )
7385 .log_err();
7386 }
7387 }
7388 })
7389 })
7390 }
7391
7392 pub fn document_colors(
7393 &mut self,
7394 known_cache_version: Option<usize>,
7395 buffer: Entity<Buffer>,
7396 cx: &mut Context<Self>,
7397 ) -> Option<DocumentColorTask> {
7398 let version_queried_for = buffer.read(cx).version();
7399 let buffer_id = buffer.read(cx).remote_id();
7400
7401 let current_language_servers = self.as_local().map(|local| {
7402 local
7403 .buffers_opened_in_servers
7404 .get(&buffer_id)
7405 .cloned()
7406 .unwrap_or_default()
7407 });
7408
7409 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7410 if let Some(cached_colors) = &lsp_data.document_colors {
7411 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7412 let has_different_servers =
7413 current_language_servers.is_some_and(|current_language_servers| {
7414 current_language_servers
7415 != cached_colors.colors.keys().copied().collect()
7416 });
7417 if !has_different_servers {
7418 let cache_version = cached_colors.cache_version;
7419 if Some(cache_version) == known_cache_version {
7420 return None;
7421 } else {
7422 return Some(
7423 Task::ready(Ok(DocumentColors {
7424 colors: cached_colors
7425 .colors
7426 .values()
7427 .flatten()
7428 .cloned()
7429 .collect(),
7430 cache_version: Some(cache_version),
7431 }))
7432 .shared(),
7433 );
7434 }
7435 }
7436 }
7437 }
7438 }
7439
7440 let color_lsp_data = self
7441 .latest_lsp_data(&buffer, cx)
7442 .document_colors
7443 .get_or_insert_default();
7444 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7445 && !version_queried_for.changed_since(updating_for)
7446 {
7447 return Some(running_update.clone());
7448 }
7449 let buffer_version_queried_for = version_queried_for.clone();
7450 let new_task = cx
7451 .spawn(async move |lsp_store, cx| {
7452 cx.background_executor()
7453 .timer(Duration::from_millis(30))
7454 .await;
7455 let fetched_colors = lsp_store
7456 .update(cx, |lsp_store, cx| {
7457 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7458 })?
7459 .await
7460 .context("fetching document colors")
7461 .map_err(Arc::new);
7462 let fetched_colors = match fetched_colors {
7463 Ok(fetched_colors) => {
7464 if Some(true)
7465 == buffer
7466 .update(cx, |buffer, _| {
7467 buffer.version() != buffer_version_queried_for
7468 })
7469 .ok()
7470 {
7471 return Ok(DocumentColors::default());
7472 }
7473 fetched_colors
7474 }
7475 Err(e) => {
7476 lsp_store
7477 .update(cx, |lsp_store, _| {
7478 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7479 if let Some(document_colors) = &mut lsp_data.document_colors {
7480 document_colors.colors_update = None;
7481 }
7482 }
7483 })
7484 .ok();
7485 return Err(e);
7486 }
7487 };
7488
7489 lsp_store
7490 .update(cx, |lsp_store, cx| {
7491 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7492 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7493
7494 if let Some(fetched_colors) = fetched_colors {
7495 if lsp_data.buffer_version == buffer_version_queried_for {
7496 lsp_colors.colors.extend(fetched_colors);
7497 lsp_colors.cache_version += 1;
7498 } else if !lsp_data
7499 .buffer_version
7500 .changed_since(&buffer_version_queried_for)
7501 {
7502 lsp_data.buffer_version = buffer_version_queried_for;
7503 lsp_colors.colors = fetched_colors;
7504 lsp_colors.cache_version += 1;
7505 }
7506 }
7507 lsp_colors.colors_update = None;
7508 let colors = lsp_colors
7509 .colors
7510 .values()
7511 .flatten()
7512 .cloned()
7513 .collect::<HashSet<_>>();
7514 DocumentColors {
7515 colors,
7516 cache_version: Some(lsp_colors.cache_version),
7517 }
7518 })
7519 .map_err(Arc::new)
7520 })
7521 .shared();
7522 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7523 Some(new_task)
7524 }
7525
7526 fn fetch_document_colors_for_buffer(
7527 &mut self,
7528 buffer: &Entity<Buffer>,
7529 cx: &mut Context<Self>,
7530 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7531 if let Some((client, project_id)) = self.upstream_client() {
7532 let request = GetDocumentColor {};
7533 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7534 return Task::ready(Ok(None));
7535 }
7536
7537 let request_task = client.request_lsp(
7538 project_id,
7539 None,
7540 LSP_REQUEST_TIMEOUT,
7541 cx.background_executor().clone(),
7542 request.to_proto(project_id, buffer.read(cx)),
7543 );
7544 let buffer = buffer.clone();
7545 cx.spawn(async move |lsp_store, cx| {
7546 let Some(lsp_store) = lsp_store.upgrade() else {
7547 return Ok(None);
7548 };
7549 let colors = join_all(
7550 request_task
7551 .await
7552 .log_err()
7553 .flatten()
7554 .map(|response| response.payload)
7555 .unwrap_or_default()
7556 .into_iter()
7557 .map(|color_response| {
7558 let response = request.response_from_proto(
7559 color_response.response,
7560 lsp_store.clone(),
7561 buffer.clone(),
7562 cx.clone(),
7563 );
7564 async move {
7565 (
7566 LanguageServerId::from_proto(color_response.server_id),
7567 response.await.log_err().unwrap_or_default(),
7568 )
7569 }
7570 }),
7571 )
7572 .await
7573 .into_iter()
7574 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7575 acc.entry(server_id)
7576 .or_insert_with(HashSet::default)
7577 .extend(colors);
7578 acc
7579 });
7580 Ok(Some(colors))
7581 })
7582 } else {
7583 let document_colors_task =
7584 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7585 cx.background_spawn(async move {
7586 Ok(Some(
7587 document_colors_task
7588 .await
7589 .into_iter()
7590 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7591 acc.entry(server_id)
7592 .or_insert_with(HashSet::default)
7593 .extend(colors);
7594 acc
7595 })
7596 .into_iter()
7597 .collect(),
7598 ))
7599 })
7600 }
7601 }
7602
7603 pub fn signature_help<T: ToPointUtf16>(
7604 &mut self,
7605 buffer: &Entity<Buffer>,
7606 position: T,
7607 cx: &mut Context<Self>,
7608 ) -> Task<Option<Vec<SignatureHelp>>> {
7609 let position = position.to_point_utf16(buffer.read(cx));
7610
7611 if let Some((client, upstream_project_id)) = self.upstream_client() {
7612 let request = GetSignatureHelp { position };
7613 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7614 return Task::ready(None);
7615 }
7616 let request_task = client.request_lsp(
7617 upstream_project_id,
7618 None,
7619 LSP_REQUEST_TIMEOUT,
7620 cx.background_executor().clone(),
7621 request.to_proto(upstream_project_id, buffer.read(cx)),
7622 );
7623 let buffer = buffer.clone();
7624 cx.spawn(async move |weak_lsp_store, cx| {
7625 let lsp_store = weak_lsp_store.upgrade()?;
7626 let signatures = join_all(
7627 request_task
7628 .await
7629 .log_err()
7630 .flatten()
7631 .map(|response| response.payload)
7632 .unwrap_or_default()
7633 .into_iter()
7634 .map(|response| {
7635 let response = GetSignatureHelp { position }.response_from_proto(
7636 response.response,
7637 lsp_store.clone(),
7638 buffer.clone(),
7639 cx.clone(),
7640 );
7641 async move { response.await.log_err().flatten() }
7642 }),
7643 )
7644 .await
7645 .into_iter()
7646 .flatten()
7647 .collect();
7648 Some(signatures)
7649 })
7650 } else {
7651 let all_actions_task = self.request_multiple_lsp_locally(
7652 buffer,
7653 Some(position),
7654 GetSignatureHelp { position },
7655 cx,
7656 );
7657 cx.background_spawn(async move {
7658 Some(
7659 all_actions_task
7660 .await
7661 .into_iter()
7662 .flat_map(|(_, actions)| actions)
7663 .collect::<Vec<_>>(),
7664 )
7665 })
7666 }
7667 }
7668
7669 pub fn hover(
7670 &mut self,
7671 buffer: &Entity<Buffer>,
7672 position: PointUtf16,
7673 cx: &mut Context<Self>,
7674 ) -> Task<Option<Vec<Hover>>> {
7675 if let Some((client, upstream_project_id)) = self.upstream_client() {
7676 let request = GetHover { position };
7677 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7678 return Task::ready(None);
7679 }
7680 let request_task = client.request_lsp(
7681 upstream_project_id,
7682 None,
7683 LSP_REQUEST_TIMEOUT,
7684 cx.background_executor().clone(),
7685 request.to_proto(upstream_project_id, buffer.read(cx)),
7686 );
7687 let buffer = buffer.clone();
7688 cx.spawn(async move |weak_lsp_store, cx| {
7689 let lsp_store = weak_lsp_store.upgrade()?;
7690 let hovers = join_all(
7691 request_task
7692 .await
7693 .log_err()
7694 .flatten()
7695 .map(|response| response.payload)
7696 .unwrap_or_default()
7697 .into_iter()
7698 .map(|response| {
7699 let response = GetHover { position }.response_from_proto(
7700 response.response,
7701 lsp_store.clone(),
7702 buffer.clone(),
7703 cx.clone(),
7704 );
7705 async move {
7706 response
7707 .await
7708 .log_err()
7709 .flatten()
7710 .and_then(remove_empty_hover_blocks)
7711 }
7712 }),
7713 )
7714 .await
7715 .into_iter()
7716 .flatten()
7717 .collect();
7718 Some(hovers)
7719 })
7720 } else {
7721 let all_actions_task = self.request_multiple_lsp_locally(
7722 buffer,
7723 Some(position),
7724 GetHover { position },
7725 cx,
7726 );
7727 cx.background_spawn(async move {
7728 Some(
7729 all_actions_task
7730 .await
7731 .into_iter()
7732 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7733 .collect::<Vec<Hover>>(),
7734 )
7735 })
7736 }
7737 }
7738
7739 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7740 let language_registry = self.languages.clone();
7741
7742 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7743 let request = upstream_client.request(proto::GetProjectSymbols {
7744 project_id: *project_id,
7745 query: query.to_string(),
7746 });
7747 cx.foreground_executor().spawn(async move {
7748 let response = request.await?;
7749 let mut symbols = Vec::new();
7750 let core_symbols = response
7751 .symbols
7752 .into_iter()
7753 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7754 .collect::<Vec<_>>();
7755 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7756 .await;
7757 Ok(symbols)
7758 })
7759 } else if let Some(local) = self.as_local() {
7760 struct WorkspaceSymbolsResult {
7761 server_id: LanguageServerId,
7762 lsp_adapter: Arc<CachedLspAdapter>,
7763 worktree: WeakEntity<Worktree>,
7764 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7765 }
7766
7767 let mut requests = Vec::new();
7768 let mut requested_servers = BTreeSet::new();
7769 for (seed, state) in local.language_server_ids.iter() {
7770 let Some(worktree_handle) = self
7771 .worktree_store
7772 .read(cx)
7773 .worktree_for_id(seed.worktree_id, cx)
7774 else {
7775 continue;
7776 };
7777 let worktree = worktree_handle.read(cx);
7778 if !worktree.is_visible() {
7779 continue;
7780 }
7781
7782 if !requested_servers.insert(state.id) {
7783 continue;
7784 }
7785
7786 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7787 Some(LanguageServerState::Running {
7788 adapter, server, ..
7789 }) => (adapter.clone(), server),
7790
7791 _ => continue,
7792 };
7793 let supports_workspace_symbol_request =
7794 match server.capabilities().workspace_symbol_provider {
7795 Some(OneOf::Left(supported)) => supported,
7796 Some(OneOf::Right(_)) => true,
7797 None => false,
7798 };
7799 if !supports_workspace_symbol_request {
7800 continue;
7801 }
7802 let worktree_handle = worktree_handle.clone();
7803 let server_id = server.server_id();
7804 requests.push(
7805 server
7806 .request::<lsp::request::WorkspaceSymbolRequest>(
7807 lsp::WorkspaceSymbolParams {
7808 query: query.to_string(),
7809 ..Default::default()
7810 },
7811 )
7812 .map(move |response| {
7813 let lsp_symbols = response.into_response()
7814 .context("workspace symbols request")
7815 .log_err()
7816 .flatten()
7817 .map(|symbol_response| match symbol_response {
7818 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7819 flat_responses.into_iter().map(|lsp_symbol| {
7820 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7821 }).collect::<Vec<_>>()
7822 }
7823 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7824 nested_responses.into_iter().filter_map(|lsp_symbol| {
7825 let location = match lsp_symbol.location {
7826 OneOf::Left(location) => location,
7827 OneOf::Right(_) => {
7828 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7829 return None
7830 }
7831 };
7832 Some((lsp_symbol.name, lsp_symbol.kind, location))
7833 }).collect::<Vec<_>>()
7834 }
7835 }).unwrap_or_default();
7836
7837 WorkspaceSymbolsResult {
7838 server_id,
7839 lsp_adapter,
7840 worktree: worktree_handle.downgrade(),
7841 lsp_symbols,
7842 }
7843 }),
7844 );
7845 }
7846
7847 cx.spawn(async move |this, cx| {
7848 let responses = futures::future::join_all(requests).await;
7849 let this = match this.upgrade() {
7850 Some(this) => this,
7851 None => return Ok(Vec::new()),
7852 };
7853
7854 let mut symbols = Vec::new();
7855 for result in responses {
7856 let core_symbols = this.update(cx, |this, cx| {
7857 result
7858 .lsp_symbols
7859 .into_iter()
7860 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7861 let abs_path = symbol_location.uri.to_file_path().ok()?;
7862 let source_worktree = result.worktree.upgrade()?;
7863 let source_worktree_id = source_worktree.read(cx).id();
7864
7865 let path = if let Some((tree, rel_path)) =
7866 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7867 {
7868 let worktree_id = tree.read(cx).id();
7869 SymbolLocation::InProject(ProjectPath {
7870 worktree_id,
7871 path: rel_path,
7872 })
7873 } else {
7874 SymbolLocation::OutsideProject {
7875 signature: this.symbol_signature(&abs_path),
7876 abs_path: abs_path.into(),
7877 }
7878 };
7879
7880 Some(CoreSymbol {
7881 source_language_server_id: result.server_id,
7882 language_server_name: result.lsp_adapter.name.clone(),
7883 source_worktree_id,
7884 path,
7885 kind: symbol_kind,
7886 name: symbol_name,
7887 range: range_from_lsp(symbol_location.range),
7888 })
7889 })
7890 .collect()
7891 })?;
7892
7893 populate_labels_for_symbols(
7894 core_symbols,
7895 &language_registry,
7896 Some(result.lsp_adapter),
7897 &mut symbols,
7898 )
7899 .await;
7900 }
7901
7902 Ok(symbols)
7903 })
7904 } else {
7905 Task::ready(Err(anyhow!("No upstream client or local language server")))
7906 }
7907 }
7908
7909 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7910 let mut summary = DiagnosticSummary::default();
7911 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7912 summary.error_count += path_summary.error_count;
7913 summary.warning_count += path_summary.warning_count;
7914 }
7915 summary
7916 }
7917
7918 /// Returns the diagnostic summary for a specific project path.
7919 pub fn diagnostic_summary_for_path(
7920 &self,
7921 project_path: &ProjectPath,
7922 _: &App,
7923 ) -> DiagnosticSummary {
7924 if let Some(summaries) = self
7925 .diagnostic_summaries
7926 .get(&project_path.worktree_id)
7927 .and_then(|map| map.get(&project_path.path))
7928 {
7929 let (error_count, warning_count) = summaries.iter().fold(
7930 (0, 0),
7931 |(error_count, warning_count), (_language_server_id, summary)| {
7932 (
7933 error_count + summary.error_count,
7934 warning_count + summary.warning_count,
7935 )
7936 },
7937 );
7938
7939 DiagnosticSummary {
7940 error_count,
7941 warning_count,
7942 }
7943 } else {
7944 DiagnosticSummary::default()
7945 }
7946 }
7947
7948 pub fn diagnostic_summaries<'a>(
7949 &'a self,
7950 include_ignored: bool,
7951 cx: &'a App,
7952 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7953 self.worktree_store
7954 .read(cx)
7955 .visible_worktrees(cx)
7956 .filter_map(|worktree| {
7957 let worktree = worktree.read(cx);
7958 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7959 })
7960 .flat_map(move |(worktree, summaries)| {
7961 let worktree_id = worktree.id();
7962 summaries
7963 .iter()
7964 .filter(move |(path, _)| {
7965 include_ignored
7966 || worktree
7967 .entry_for_path(path.as_ref())
7968 .is_some_and(|entry| !entry.is_ignored)
7969 })
7970 .flat_map(move |(path, summaries)| {
7971 summaries.iter().map(move |(server_id, summary)| {
7972 (
7973 ProjectPath {
7974 worktree_id,
7975 path: path.clone(),
7976 },
7977 *server_id,
7978 *summary,
7979 )
7980 })
7981 })
7982 })
7983 }
7984
7985 pub fn on_buffer_edited(
7986 &mut self,
7987 buffer: Entity<Buffer>,
7988 cx: &mut Context<Self>,
7989 ) -> Option<()> {
7990 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7991 Some(
7992 self.as_local()?
7993 .language_servers_for_buffer(buffer, cx)
7994 .map(|i| i.1.clone())
7995 .collect(),
7996 )
7997 })?;
7998
7999 let buffer = buffer.read(cx);
8000 let file = File::from_dyn(buffer.file())?;
8001 let abs_path = file.as_local()?.abs_path(cx);
8002 let uri = lsp::Uri::from_file_path(&abs_path)
8003 .ok()
8004 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8005 .log_err()?;
8006 let next_snapshot = buffer.text_snapshot();
8007 for language_server in language_servers {
8008 let language_server = language_server.clone();
8009
8010 let buffer_snapshots = self
8011 .as_local_mut()?
8012 .buffer_snapshots
8013 .get_mut(&buffer.remote_id())
8014 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8015 let previous_snapshot = buffer_snapshots.last()?;
8016
8017 let build_incremental_change = || {
8018 buffer
8019 .edits_since::<Dimensions<PointUtf16, usize>>(
8020 previous_snapshot.snapshot.version(),
8021 )
8022 .map(|edit| {
8023 let edit_start = edit.new.start.0;
8024 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8025 let new_text = next_snapshot
8026 .text_for_range(edit.new.start.1..edit.new.end.1)
8027 .collect();
8028 lsp::TextDocumentContentChangeEvent {
8029 range: Some(lsp::Range::new(
8030 point_to_lsp(edit_start),
8031 point_to_lsp(edit_end),
8032 )),
8033 range_length: None,
8034 text: new_text,
8035 }
8036 })
8037 .collect()
8038 };
8039
8040 let document_sync_kind = language_server
8041 .capabilities()
8042 .text_document_sync
8043 .as_ref()
8044 .and_then(|sync| match sync {
8045 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8046 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8047 });
8048
8049 let content_changes: Vec<_> = match document_sync_kind {
8050 Some(lsp::TextDocumentSyncKind::FULL) => {
8051 vec![lsp::TextDocumentContentChangeEvent {
8052 range: None,
8053 range_length: None,
8054 text: next_snapshot.text(),
8055 }]
8056 }
8057 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8058 _ => {
8059 #[cfg(any(test, feature = "test-support"))]
8060 {
8061 build_incremental_change()
8062 }
8063
8064 #[cfg(not(any(test, feature = "test-support")))]
8065 {
8066 continue;
8067 }
8068 }
8069 };
8070
8071 let next_version = previous_snapshot.version + 1;
8072 buffer_snapshots.push(LspBufferSnapshot {
8073 version: next_version,
8074 snapshot: next_snapshot.clone(),
8075 });
8076
8077 language_server
8078 .notify::<lsp::notification::DidChangeTextDocument>(
8079 lsp::DidChangeTextDocumentParams {
8080 text_document: lsp::VersionedTextDocumentIdentifier::new(
8081 uri.clone(),
8082 next_version,
8083 ),
8084 content_changes,
8085 },
8086 )
8087 .ok();
8088 self.pull_workspace_diagnostics(language_server.server_id());
8089 }
8090
8091 None
8092 }
8093
8094 pub fn on_buffer_saved(
8095 &mut self,
8096 buffer: Entity<Buffer>,
8097 cx: &mut Context<Self>,
8098 ) -> Option<()> {
8099 let file = File::from_dyn(buffer.read(cx).file())?;
8100 let worktree_id = file.worktree_id(cx);
8101 let abs_path = file.as_local()?.abs_path(cx);
8102 let text_document = lsp::TextDocumentIdentifier {
8103 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8104 };
8105 let local = self.as_local()?;
8106
8107 for server in local.language_servers_for_worktree(worktree_id) {
8108 if let Some(include_text) = include_text(server.as_ref()) {
8109 let text = if include_text {
8110 Some(buffer.read(cx).text())
8111 } else {
8112 None
8113 };
8114 server
8115 .notify::<lsp::notification::DidSaveTextDocument>(
8116 lsp::DidSaveTextDocumentParams {
8117 text_document: text_document.clone(),
8118 text,
8119 },
8120 )
8121 .ok();
8122 }
8123 }
8124
8125 let language_servers = buffer.update(cx, |buffer, cx| {
8126 local.language_server_ids_for_buffer(buffer, cx)
8127 });
8128 for language_server_id in language_servers {
8129 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8130 }
8131
8132 None
8133 }
8134
8135 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8136 maybe!(async move {
8137 let mut refreshed_servers = HashSet::default();
8138 let servers = lsp_store
8139 .update(cx, |lsp_store, cx| {
8140 let local = lsp_store.as_local()?;
8141
8142 let servers = local
8143 .language_server_ids
8144 .iter()
8145 .filter_map(|(seed, state)| {
8146 let worktree = lsp_store
8147 .worktree_store
8148 .read(cx)
8149 .worktree_for_id(seed.worktree_id, cx);
8150 let delegate: Arc<dyn LspAdapterDelegate> =
8151 worktree.map(|worktree| {
8152 LocalLspAdapterDelegate::new(
8153 local.languages.clone(),
8154 &local.environment,
8155 cx.weak_entity(),
8156 &worktree,
8157 local.http_client.clone(),
8158 local.fs.clone(),
8159 cx,
8160 )
8161 })?;
8162 let server_id = state.id;
8163
8164 let states = local.language_servers.get(&server_id)?;
8165
8166 match states {
8167 LanguageServerState::Starting { .. } => None,
8168 LanguageServerState::Running {
8169 adapter, server, ..
8170 } => {
8171 let adapter = adapter.clone();
8172 let server = server.clone();
8173 refreshed_servers.insert(server.name());
8174 let toolchain = seed.toolchain.clone();
8175 Some(cx.spawn(async move |_, cx| {
8176 let settings =
8177 LocalLspStore::workspace_configuration_for_adapter(
8178 adapter.adapter.clone(),
8179 &delegate,
8180 toolchain,
8181 None,
8182 cx,
8183 )
8184 .await
8185 .ok()?;
8186 server
8187 .notify::<lsp::notification::DidChangeConfiguration>(
8188 lsp::DidChangeConfigurationParams { settings },
8189 )
8190 .ok()?;
8191 Some(())
8192 }))
8193 }
8194 }
8195 })
8196 .collect::<Vec<_>>();
8197
8198 Some(servers)
8199 })
8200 .ok()
8201 .flatten()?;
8202
8203 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8204 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8205 // to stop and unregister its language server wrapper.
8206 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8207 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8208 let _: Vec<Option<()>> = join_all(servers).await;
8209
8210 Some(())
8211 })
8212 .await;
8213 }
8214
8215 fn maintain_workspace_config(
8216 external_refresh_requests: watch::Receiver<()>,
8217 cx: &mut Context<Self>,
8218 ) -> Task<Result<()>> {
8219 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8220 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8221
8222 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8223 *settings_changed_tx.borrow_mut() = ();
8224 });
8225
8226 let mut joint_future =
8227 futures::stream::select(settings_changed_rx, external_refresh_requests);
8228 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8229 // - 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).
8230 // - 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.
8231 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8232 // - 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,
8233 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8234 cx.spawn(async move |this, cx| {
8235 while let Some(()) = joint_future.next().await {
8236 this.update(cx, |this, cx| {
8237 this.refresh_server_tree(cx);
8238 })
8239 .ok();
8240
8241 Self::refresh_workspace_configurations(&this, cx).await;
8242 }
8243
8244 drop(settings_observation);
8245 anyhow::Ok(())
8246 })
8247 }
8248
8249 pub fn running_language_servers_for_local_buffer<'a>(
8250 &'a self,
8251 buffer: &Buffer,
8252 cx: &mut App,
8253 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8254 let local = self.as_local();
8255 let language_server_ids = local
8256 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8257 .unwrap_or_default();
8258
8259 language_server_ids
8260 .into_iter()
8261 .filter_map(
8262 move |server_id| match local?.language_servers.get(&server_id)? {
8263 LanguageServerState::Running {
8264 adapter, server, ..
8265 } => Some((adapter, server)),
8266 _ => None,
8267 },
8268 )
8269 }
8270
8271 pub fn language_servers_for_local_buffer(
8272 &self,
8273 buffer: &Buffer,
8274 cx: &mut App,
8275 ) -> Vec<LanguageServerId> {
8276 let local = self.as_local();
8277 local
8278 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8279 .unwrap_or_default()
8280 }
8281
8282 pub fn language_server_for_local_buffer<'a>(
8283 &'a self,
8284 buffer: &'a Buffer,
8285 server_id: LanguageServerId,
8286 cx: &'a mut App,
8287 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8288 self.as_local()?
8289 .language_servers_for_buffer(buffer, cx)
8290 .find(|(_, s)| s.server_id() == server_id)
8291 }
8292
8293 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8294 self.diagnostic_summaries.remove(&id_to_remove);
8295 if let Some(local) = self.as_local_mut() {
8296 let to_remove = local.remove_worktree(id_to_remove, cx);
8297 for server in to_remove {
8298 self.language_server_statuses.remove(&server);
8299 }
8300 }
8301 }
8302
8303 pub fn shared(
8304 &mut self,
8305 project_id: u64,
8306 downstream_client: AnyProtoClient,
8307 _: &mut Context<Self>,
8308 ) {
8309 self.downstream_client = Some((downstream_client.clone(), project_id));
8310
8311 for (server_id, status) in &self.language_server_statuses {
8312 if let Some(server) = self.language_server_for_id(*server_id) {
8313 downstream_client
8314 .send(proto::StartLanguageServer {
8315 project_id,
8316 server: Some(proto::LanguageServer {
8317 id: server_id.to_proto(),
8318 name: status.name.to_string(),
8319 worktree_id: status.worktree.map(|id| id.to_proto()),
8320 }),
8321 capabilities: serde_json::to_string(&server.capabilities())
8322 .expect("serializing server LSP capabilities"),
8323 })
8324 .log_err();
8325 }
8326 }
8327 }
8328
8329 pub fn disconnected_from_host(&mut self) {
8330 self.downstream_client.take();
8331 }
8332
8333 pub fn disconnected_from_ssh_remote(&mut self) {
8334 if let LspStoreMode::Remote(RemoteLspStore {
8335 upstream_client, ..
8336 }) = &mut self.mode
8337 {
8338 upstream_client.take();
8339 }
8340 }
8341
8342 pub(crate) fn set_language_server_statuses_from_proto(
8343 &mut self,
8344 project: WeakEntity<Project>,
8345 language_servers: Vec<proto::LanguageServer>,
8346 server_capabilities: Vec<String>,
8347 cx: &mut Context<Self>,
8348 ) {
8349 let lsp_logs = cx
8350 .try_global::<GlobalLogStore>()
8351 .map(|lsp_store| lsp_store.0.clone());
8352
8353 self.language_server_statuses = language_servers
8354 .into_iter()
8355 .zip(server_capabilities)
8356 .map(|(server, server_capabilities)| {
8357 let server_id = LanguageServerId(server.id as usize);
8358 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8359 self.lsp_server_capabilities
8360 .insert(server_id, server_capabilities);
8361 }
8362
8363 let name = LanguageServerName::from_proto(server.name);
8364 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8365
8366 if let Some(lsp_logs) = &lsp_logs {
8367 lsp_logs.update(cx, |lsp_logs, cx| {
8368 lsp_logs.add_language_server(
8369 // Only remote clients get their language servers set from proto
8370 LanguageServerKind::Remote {
8371 project: project.clone(),
8372 },
8373 server_id,
8374 Some(name.clone()),
8375 worktree,
8376 None,
8377 cx,
8378 );
8379 });
8380 }
8381
8382 (
8383 server_id,
8384 LanguageServerStatus {
8385 name,
8386 server_version: None,
8387 pending_work: Default::default(),
8388 has_pending_diagnostic_updates: false,
8389 progress_tokens: Default::default(),
8390 worktree,
8391 binary: None,
8392 configuration: None,
8393 workspace_folders: BTreeSet::new(),
8394 },
8395 )
8396 })
8397 .collect();
8398 }
8399
8400 #[cfg(test)]
8401 pub fn update_diagnostic_entries(
8402 &mut self,
8403 server_id: LanguageServerId,
8404 abs_path: PathBuf,
8405 result_id: Option<SharedString>,
8406 version: Option<i32>,
8407 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8408 cx: &mut Context<Self>,
8409 ) -> anyhow::Result<()> {
8410 self.merge_diagnostic_entries(
8411 vec![DocumentDiagnosticsUpdate {
8412 diagnostics: DocumentDiagnostics {
8413 diagnostics,
8414 document_abs_path: abs_path,
8415 version,
8416 },
8417 result_id,
8418 server_id,
8419 disk_based_sources: Cow::Borrowed(&[]),
8420 registration_id: None,
8421 }],
8422 |_, _, _| false,
8423 cx,
8424 )?;
8425 Ok(())
8426 }
8427
8428 pub fn merge_diagnostic_entries<'a>(
8429 &mut self,
8430 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8431 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8432 cx: &mut Context<Self>,
8433 ) -> anyhow::Result<()> {
8434 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8435 let mut updated_diagnostics_paths = HashMap::default();
8436 for mut update in diagnostic_updates {
8437 let abs_path = &update.diagnostics.document_abs_path;
8438 let server_id = update.server_id;
8439 let Some((worktree, relative_path)) =
8440 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8441 else {
8442 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8443 return Ok(());
8444 };
8445
8446 let worktree_id = worktree.read(cx).id();
8447 let project_path = ProjectPath {
8448 worktree_id,
8449 path: relative_path,
8450 };
8451
8452 let document_uri = lsp::Uri::from_file_path(abs_path)
8453 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8454 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8455 let snapshot = buffer_handle.read(cx).snapshot();
8456 let buffer = buffer_handle.read(cx);
8457 let reused_diagnostics = buffer
8458 .buffer_diagnostics(Some(server_id))
8459 .iter()
8460 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8461 .map(|v| {
8462 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8463 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8464 DiagnosticEntry {
8465 range: start..end,
8466 diagnostic: v.diagnostic.clone(),
8467 }
8468 })
8469 .collect::<Vec<_>>();
8470
8471 self.as_local_mut()
8472 .context("cannot merge diagnostics on a remote LspStore")?
8473 .update_buffer_diagnostics(
8474 &buffer_handle,
8475 server_id,
8476 Some(update.registration_id),
8477 update.result_id,
8478 update.diagnostics.version,
8479 update.diagnostics.diagnostics.clone(),
8480 reused_diagnostics.clone(),
8481 cx,
8482 )?;
8483
8484 update.diagnostics.diagnostics.extend(reused_diagnostics);
8485 } else if let Some(local) = self.as_local() {
8486 let reused_diagnostics = local
8487 .diagnostics
8488 .get(&worktree_id)
8489 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8490 .and_then(|diagnostics_by_server_id| {
8491 diagnostics_by_server_id
8492 .binary_search_by_key(&server_id, |e| e.0)
8493 .ok()
8494 .map(|ix| &diagnostics_by_server_id[ix].1)
8495 })
8496 .into_iter()
8497 .flatten()
8498 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8499
8500 update
8501 .diagnostics
8502 .diagnostics
8503 .extend(reused_diagnostics.cloned());
8504 }
8505
8506 let updated = worktree.update(cx, |worktree, cx| {
8507 self.update_worktree_diagnostics(
8508 worktree.id(),
8509 server_id,
8510 project_path.path.clone(),
8511 update.diagnostics.diagnostics,
8512 cx,
8513 )
8514 })?;
8515 match updated {
8516 ControlFlow::Continue(new_summary) => {
8517 if let Some((project_id, new_summary)) = new_summary {
8518 match &mut diagnostics_summary {
8519 Some(diagnostics_summary) => {
8520 diagnostics_summary
8521 .more_summaries
8522 .push(proto::DiagnosticSummary {
8523 path: project_path.path.as_ref().to_proto(),
8524 language_server_id: server_id.0 as u64,
8525 error_count: new_summary.error_count,
8526 warning_count: new_summary.warning_count,
8527 })
8528 }
8529 None => {
8530 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8531 project_id,
8532 worktree_id: worktree_id.to_proto(),
8533 summary: Some(proto::DiagnosticSummary {
8534 path: project_path.path.as_ref().to_proto(),
8535 language_server_id: server_id.0 as u64,
8536 error_count: new_summary.error_count,
8537 warning_count: new_summary.warning_count,
8538 }),
8539 more_summaries: Vec::new(),
8540 })
8541 }
8542 }
8543 }
8544 updated_diagnostics_paths
8545 .entry(server_id)
8546 .or_insert_with(Vec::new)
8547 .push(project_path);
8548 }
8549 ControlFlow::Break(()) => {}
8550 }
8551 }
8552
8553 if let Some((diagnostics_summary, (downstream_client, _))) =
8554 diagnostics_summary.zip(self.downstream_client.as_ref())
8555 {
8556 downstream_client.send(diagnostics_summary).log_err();
8557 }
8558 for (server_id, paths) in updated_diagnostics_paths {
8559 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8560 }
8561 Ok(())
8562 }
8563
8564 fn update_worktree_diagnostics(
8565 &mut self,
8566 worktree_id: WorktreeId,
8567 server_id: LanguageServerId,
8568 path_in_worktree: Arc<RelPath>,
8569 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8570 _: &mut Context<Worktree>,
8571 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8572 let local = match &mut self.mode {
8573 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8574 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8575 };
8576
8577 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8578 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8579 let summaries_by_server_id = summaries_for_tree
8580 .entry(path_in_worktree.clone())
8581 .or_default();
8582
8583 let old_summary = summaries_by_server_id
8584 .remove(&server_id)
8585 .unwrap_or_default();
8586
8587 let new_summary = DiagnosticSummary::new(&diagnostics);
8588 if diagnostics.is_empty() {
8589 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8590 {
8591 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8592 diagnostics_by_server_id.remove(ix);
8593 }
8594 if diagnostics_by_server_id.is_empty() {
8595 diagnostics_for_tree.remove(&path_in_worktree);
8596 }
8597 }
8598 } else {
8599 summaries_by_server_id.insert(server_id, new_summary);
8600 let diagnostics_by_server_id = diagnostics_for_tree
8601 .entry(path_in_worktree.clone())
8602 .or_default();
8603 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8604 Ok(ix) => {
8605 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8606 }
8607 Err(ix) => {
8608 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8609 }
8610 }
8611 }
8612
8613 if !old_summary.is_empty() || !new_summary.is_empty() {
8614 if let Some((_, project_id)) = &self.downstream_client {
8615 Ok(ControlFlow::Continue(Some((
8616 *project_id,
8617 proto::DiagnosticSummary {
8618 path: path_in_worktree.to_proto(),
8619 language_server_id: server_id.0 as u64,
8620 error_count: new_summary.error_count as u32,
8621 warning_count: new_summary.warning_count as u32,
8622 },
8623 ))))
8624 } else {
8625 Ok(ControlFlow::Continue(None))
8626 }
8627 } else {
8628 Ok(ControlFlow::Break(()))
8629 }
8630 }
8631
8632 pub fn open_buffer_for_symbol(
8633 &mut self,
8634 symbol: &Symbol,
8635 cx: &mut Context<Self>,
8636 ) -> Task<Result<Entity<Buffer>>> {
8637 if let Some((client, project_id)) = self.upstream_client() {
8638 let request = client.request(proto::OpenBufferForSymbol {
8639 project_id,
8640 symbol: Some(Self::serialize_symbol(symbol)),
8641 });
8642 cx.spawn(async move |this, cx| {
8643 let response = request.await?;
8644 let buffer_id = BufferId::new(response.buffer_id)?;
8645 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8646 .await
8647 })
8648 } else if let Some(local) = self.as_local() {
8649 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8650 seed.worktree_id == symbol.source_worktree_id
8651 && state.id == symbol.source_language_server_id
8652 && symbol.language_server_name == seed.name
8653 });
8654 if !is_valid {
8655 return Task::ready(Err(anyhow!(
8656 "language server for worktree and language not found"
8657 )));
8658 };
8659
8660 let symbol_abs_path = match &symbol.path {
8661 SymbolLocation::InProject(project_path) => self
8662 .worktree_store
8663 .read(cx)
8664 .absolutize(&project_path, cx)
8665 .context("no such worktree"),
8666 SymbolLocation::OutsideProject {
8667 abs_path,
8668 signature: _,
8669 } => Ok(abs_path.to_path_buf()),
8670 };
8671 let symbol_abs_path = match symbol_abs_path {
8672 Ok(abs_path) => abs_path,
8673 Err(err) => return Task::ready(Err(err)),
8674 };
8675 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8676 uri
8677 } else {
8678 return Task::ready(Err(anyhow!("invalid symbol path")));
8679 };
8680
8681 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8682 } else {
8683 Task::ready(Err(anyhow!("no upstream client or local store")))
8684 }
8685 }
8686
8687 pub(crate) fn open_local_buffer_via_lsp(
8688 &mut self,
8689 abs_path: lsp::Uri,
8690 language_server_id: LanguageServerId,
8691 cx: &mut Context<Self>,
8692 ) -> Task<Result<Entity<Buffer>>> {
8693 cx.spawn(async move |lsp_store, cx| {
8694 // Escape percent-encoded string.
8695 let current_scheme = abs_path.scheme().to_owned();
8696 // Uri is immutable, so we can't modify the scheme
8697
8698 let abs_path = abs_path
8699 .to_file_path()
8700 .map_err(|()| anyhow!("can't convert URI to path"))?;
8701 let p = abs_path.clone();
8702 let yarn_worktree = lsp_store
8703 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8704 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8705 cx.spawn(async move |this, cx| {
8706 let t = this
8707 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8708 .ok()?;
8709 t.await
8710 })
8711 }),
8712 None => Task::ready(None),
8713 })?
8714 .await;
8715 let (worktree_root_target, known_relative_path) =
8716 if let Some((zip_root, relative_path)) = yarn_worktree {
8717 (zip_root, Some(relative_path))
8718 } else {
8719 (Arc::<Path>::from(abs_path.as_path()), None)
8720 };
8721 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8722 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8723 worktree_store.find_worktree(&worktree_root_target, cx)
8724 })
8725 })?;
8726 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8727 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8728 (result.0, relative_path, None)
8729 } else {
8730 let worktree = lsp_store
8731 .update(cx, |lsp_store, cx| {
8732 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8733 worktree_store.create_worktree(&worktree_root_target, false, cx)
8734 })
8735 })?
8736 .await?;
8737 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8738 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8739 lsp_store
8740 .update(cx, |lsp_store, cx| {
8741 if let Some(local) = lsp_store.as_local_mut() {
8742 local.register_language_server_for_invisible_worktree(
8743 &worktree,
8744 language_server_id,
8745 cx,
8746 )
8747 }
8748 match lsp_store.language_server_statuses.get(&language_server_id) {
8749 Some(status) => status.worktree,
8750 None => None,
8751 }
8752 })
8753 .ok()
8754 .flatten()
8755 .zip(Some(worktree_root.clone()))
8756 } else {
8757 None
8758 };
8759 let relative_path = if let Some(known_path) = known_relative_path {
8760 known_path
8761 } else {
8762 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8763 .into_arc()
8764 };
8765 (worktree, relative_path, source_ws)
8766 };
8767 let project_path = ProjectPath {
8768 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8769 path: relative_path,
8770 };
8771 let buffer = lsp_store
8772 .update(cx, |lsp_store, cx| {
8773 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8774 buffer_store.open_buffer(project_path, cx)
8775 })
8776 })?
8777 .await?;
8778 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8779 if let Some((source_ws, worktree_root)) = source_ws {
8780 buffer.update(cx, |buffer, cx| {
8781 let settings = WorktreeSettings::get(
8782 Some(
8783 (&ProjectPath {
8784 worktree_id: source_ws,
8785 path: Arc::from(RelPath::empty()),
8786 })
8787 .into(),
8788 ),
8789 cx,
8790 );
8791 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8792 if is_read_only {
8793 buffer.set_capability(Capability::ReadOnly, cx);
8794 }
8795 })?;
8796 }
8797 Ok(buffer)
8798 })
8799 }
8800
8801 fn request_multiple_lsp_locally<P, R>(
8802 &mut self,
8803 buffer: &Entity<Buffer>,
8804 position: Option<P>,
8805 request: R,
8806 cx: &mut Context<Self>,
8807 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8808 where
8809 P: ToOffset,
8810 R: LspCommand + Clone,
8811 <R::LspRequest as lsp::request::Request>::Result: Send,
8812 <R::LspRequest as lsp::request::Request>::Params: Send,
8813 {
8814 let Some(local) = self.as_local() else {
8815 return Task::ready(Vec::new());
8816 };
8817
8818 let snapshot = buffer.read(cx).snapshot();
8819 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8820
8821 let server_ids = buffer.update(cx, |buffer, cx| {
8822 local
8823 .language_servers_for_buffer(buffer, cx)
8824 .filter(|(adapter, _)| {
8825 scope
8826 .as_ref()
8827 .map(|scope| scope.language_allowed(&adapter.name))
8828 .unwrap_or(true)
8829 })
8830 .map(|(_, server)| server.server_id())
8831 .filter(|server_id| {
8832 self.as_local().is_none_or(|local| {
8833 local
8834 .buffers_opened_in_servers
8835 .get(&snapshot.remote_id())
8836 .is_some_and(|servers| servers.contains(server_id))
8837 })
8838 })
8839 .collect::<Vec<_>>()
8840 });
8841
8842 let mut response_results = server_ids
8843 .into_iter()
8844 .map(|server_id| {
8845 let task = self.request_lsp(
8846 buffer.clone(),
8847 LanguageServerToQuery::Other(server_id),
8848 request.clone(),
8849 cx,
8850 );
8851 async move { (server_id, task.await) }
8852 })
8853 .collect::<FuturesUnordered<_>>();
8854
8855 cx.background_spawn(async move {
8856 let mut responses = Vec::with_capacity(response_results.len());
8857 while let Some((server_id, response_result)) = response_results.next().await {
8858 match response_result {
8859 Ok(response) => responses.push((server_id, response)),
8860 // rust-analyzer likes to error with this when its still loading up
8861 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8862 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8863 }
8864 }
8865 responses
8866 })
8867 }
8868
8869 async fn handle_lsp_get_completions(
8870 this: Entity<Self>,
8871 envelope: TypedEnvelope<proto::GetCompletions>,
8872 mut cx: AsyncApp,
8873 ) -> Result<proto::GetCompletionsResponse> {
8874 let sender_id = envelope.original_sender_id().unwrap_or_default();
8875
8876 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8877 let buffer_handle = this.update(&mut cx, |this, cx| {
8878 this.buffer_store.read(cx).get_existing(buffer_id)
8879 })??;
8880 let request = GetCompletions::from_proto(
8881 envelope.payload,
8882 this.clone(),
8883 buffer_handle.clone(),
8884 cx.clone(),
8885 )
8886 .await?;
8887
8888 let server_to_query = match request.server_id {
8889 Some(server_id) => LanguageServerToQuery::Other(server_id),
8890 None => LanguageServerToQuery::FirstCapable,
8891 };
8892
8893 let response = this
8894 .update(&mut cx, |this, cx| {
8895 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8896 })?
8897 .await?;
8898 this.update(&mut cx, |this, cx| {
8899 Ok(GetCompletions::response_to_proto(
8900 response,
8901 this,
8902 sender_id,
8903 &buffer_handle.read(cx).version(),
8904 cx,
8905 ))
8906 })?
8907 }
8908
8909 async fn handle_lsp_command<T: LspCommand>(
8910 this: Entity<Self>,
8911 envelope: TypedEnvelope<T::ProtoRequest>,
8912 mut cx: AsyncApp,
8913 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8914 where
8915 <T::LspRequest as lsp::request::Request>::Params: Send,
8916 <T::LspRequest as lsp::request::Request>::Result: Send,
8917 {
8918 let sender_id = envelope.original_sender_id().unwrap_or_default();
8919 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8920 let buffer_handle = this.update(&mut cx, |this, cx| {
8921 this.buffer_store.read(cx).get_existing(buffer_id)
8922 })??;
8923 let request = T::from_proto(
8924 envelope.payload,
8925 this.clone(),
8926 buffer_handle.clone(),
8927 cx.clone(),
8928 )
8929 .await?;
8930 let response = this
8931 .update(&mut cx, |this, cx| {
8932 this.request_lsp(
8933 buffer_handle.clone(),
8934 LanguageServerToQuery::FirstCapable,
8935 request,
8936 cx,
8937 )
8938 })?
8939 .await?;
8940 this.update(&mut cx, |this, cx| {
8941 Ok(T::response_to_proto(
8942 response,
8943 this,
8944 sender_id,
8945 &buffer_handle.read(cx).version(),
8946 cx,
8947 ))
8948 })?
8949 }
8950
8951 async fn handle_lsp_query(
8952 lsp_store: Entity<Self>,
8953 envelope: TypedEnvelope<proto::LspQuery>,
8954 mut cx: AsyncApp,
8955 ) -> Result<proto::Ack> {
8956 use proto::lsp_query::Request;
8957 let sender_id = envelope.original_sender_id().unwrap_or_default();
8958 let lsp_query = envelope.payload;
8959 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8960 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8961 match lsp_query.request.context("invalid LSP query request")? {
8962 Request::GetReferences(get_references) => {
8963 let position = get_references.position.clone().and_then(deserialize_anchor);
8964 Self::query_lsp_locally::<GetReferences>(
8965 lsp_store,
8966 server_id,
8967 sender_id,
8968 lsp_request_id,
8969 get_references,
8970 position,
8971 &mut cx,
8972 )
8973 .await?;
8974 }
8975 Request::GetDocumentColor(get_document_color) => {
8976 Self::query_lsp_locally::<GetDocumentColor>(
8977 lsp_store,
8978 server_id,
8979 sender_id,
8980 lsp_request_id,
8981 get_document_color,
8982 None,
8983 &mut cx,
8984 )
8985 .await?;
8986 }
8987 Request::GetHover(get_hover) => {
8988 let position = get_hover.position.clone().and_then(deserialize_anchor);
8989 Self::query_lsp_locally::<GetHover>(
8990 lsp_store,
8991 server_id,
8992 sender_id,
8993 lsp_request_id,
8994 get_hover,
8995 position,
8996 &mut cx,
8997 )
8998 .await?;
8999 }
9000 Request::GetCodeActions(get_code_actions) => {
9001 Self::query_lsp_locally::<GetCodeActions>(
9002 lsp_store,
9003 server_id,
9004 sender_id,
9005 lsp_request_id,
9006 get_code_actions,
9007 None,
9008 &mut cx,
9009 )
9010 .await?;
9011 }
9012 Request::GetSignatureHelp(get_signature_help) => {
9013 let position = get_signature_help
9014 .position
9015 .clone()
9016 .and_then(deserialize_anchor);
9017 Self::query_lsp_locally::<GetSignatureHelp>(
9018 lsp_store,
9019 server_id,
9020 sender_id,
9021 lsp_request_id,
9022 get_signature_help,
9023 position,
9024 &mut cx,
9025 )
9026 .await?;
9027 }
9028 Request::GetCodeLens(get_code_lens) => {
9029 Self::query_lsp_locally::<GetCodeLens>(
9030 lsp_store,
9031 server_id,
9032 sender_id,
9033 lsp_request_id,
9034 get_code_lens,
9035 None,
9036 &mut cx,
9037 )
9038 .await?;
9039 }
9040 Request::GetDefinition(get_definition) => {
9041 let position = get_definition.position.clone().and_then(deserialize_anchor);
9042 Self::query_lsp_locally::<GetDefinitions>(
9043 lsp_store,
9044 server_id,
9045 sender_id,
9046 lsp_request_id,
9047 get_definition,
9048 position,
9049 &mut cx,
9050 )
9051 .await?;
9052 }
9053 Request::GetDeclaration(get_declaration) => {
9054 let position = get_declaration
9055 .position
9056 .clone()
9057 .and_then(deserialize_anchor);
9058 Self::query_lsp_locally::<GetDeclarations>(
9059 lsp_store,
9060 server_id,
9061 sender_id,
9062 lsp_request_id,
9063 get_declaration,
9064 position,
9065 &mut cx,
9066 )
9067 .await?;
9068 }
9069 Request::GetTypeDefinition(get_type_definition) => {
9070 let position = get_type_definition
9071 .position
9072 .clone()
9073 .and_then(deserialize_anchor);
9074 Self::query_lsp_locally::<GetTypeDefinitions>(
9075 lsp_store,
9076 server_id,
9077 sender_id,
9078 lsp_request_id,
9079 get_type_definition,
9080 position,
9081 &mut cx,
9082 )
9083 .await?;
9084 }
9085 Request::GetImplementation(get_implementation) => {
9086 let position = get_implementation
9087 .position
9088 .clone()
9089 .and_then(deserialize_anchor);
9090 Self::query_lsp_locally::<GetImplementations>(
9091 lsp_store,
9092 server_id,
9093 sender_id,
9094 lsp_request_id,
9095 get_implementation,
9096 position,
9097 &mut cx,
9098 )
9099 .await?;
9100 }
9101 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9102 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9103 let version = deserialize_version(get_document_diagnostics.buffer_version());
9104 let buffer = lsp_store.update(&mut cx, |this, cx| {
9105 this.buffer_store.read(cx).get_existing(buffer_id)
9106 })??;
9107 buffer
9108 .update(&mut cx, |buffer, _| {
9109 buffer.wait_for_version(version.clone())
9110 })?
9111 .await?;
9112 lsp_store.update(&mut cx, |lsp_store, cx| {
9113 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9114 let key = LspKey {
9115 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9116 server_queried: server_id,
9117 };
9118 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9119 ) {
9120 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9121 lsp_requests.clear();
9122 };
9123 }
9124
9125 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9126 existing_queries.insert(
9127 lsp_request_id,
9128 cx.spawn(async move |lsp_store, cx| {
9129 let diagnostics_pull = lsp_store
9130 .update(cx, |lsp_store, cx| {
9131 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9132 })
9133 .ok();
9134 if let Some(diagnostics_pull) = diagnostics_pull {
9135 match diagnostics_pull.await {
9136 Ok(()) => {}
9137 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9138 };
9139 }
9140 }),
9141 );
9142 })?;
9143 }
9144 Request::InlayHints(inlay_hints) => {
9145 let query_start = inlay_hints
9146 .start
9147 .clone()
9148 .and_then(deserialize_anchor)
9149 .context("invalid inlay hints range start")?;
9150 let query_end = inlay_hints
9151 .end
9152 .clone()
9153 .and_then(deserialize_anchor)
9154 .context("invalid inlay hints range end")?;
9155 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9156 &lsp_store,
9157 server_id,
9158 lsp_request_id,
9159 &inlay_hints,
9160 query_start..query_end,
9161 &mut cx,
9162 )
9163 .await
9164 .context("preparing inlay hints request")?;
9165 Self::query_lsp_locally::<InlayHints>(
9166 lsp_store,
9167 server_id,
9168 sender_id,
9169 lsp_request_id,
9170 inlay_hints,
9171 None,
9172 &mut cx,
9173 )
9174 .await
9175 .context("querying for inlay hints")?
9176 }
9177 }
9178 Ok(proto::Ack {})
9179 }
9180
9181 async fn handle_lsp_query_response(
9182 lsp_store: Entity<Self>,
9183 envelope: TypedEnvelope<proto::LspQueryResponse>,
9184 cx: AsyncApp,
9185 ) -> Result<()> {
9186 lsp_store.read_with(&cx, |lsp_store, _| {
9187 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9188 upstream_client.handle_lsp_response(envelope.clone());
9189 }
9190 })?;
9191 Ok(())
9192 }
9193
9194 async fn handle_apply_code_action(
9195 this: Entity<Self>,
9196 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9197 mut cx: AsyncApp,
9198 ) -> Result<proto::ApplyCodeActionResponse> {
9199 let sender_id = envelope.original_sender_id().unwrap_or_default();
9200 let action =
9201 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9202 let apply_code_action = this.update(&mut cx, |this, cx| {
9203 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9204 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9205 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9206 })??;
9207
9208 let project_transaction = apply_code_action.await?;
9209 let project_transaction = this.update(&mut cx, |this, cx| {
9210 this.buffer_store.update(cx, |buffer_store, cx| {
9211 buffer_store.serialize_project_transaction_for_peer(
9212 project_transaction,
9213 sender_id,
9214 cx,
9215 )
9216 })
9217 })?;
9218 Ok(proto::ApplyCodeActionResponse {
9219 transaction: Some(project_transaction),
9220 })
9221 }
9222
9223 async fn handle_register_buffer_with_language_servers(
9224 this: Entity<Self>,
9225 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9226 mut cx: AsyncApp,
9227 ) -> Result<proto::Ack> {
9228 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9229 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9230 this.update(&mut cx, |this, cx| {
9231 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9232 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9233 project_id: upstream_project_id,
9234 buffer_id: buffer_id.to_proto(),
9235 only_servers: envelope.payload.only_servers,
9236 });
9237 }
9238
9239 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9240 anyhow::bail!("buffer is not open");
9241 };
9242
9243 let handle = this.register_buffer_with_language_servers(
9244 &buffer,
9245 envelope
9246 .payload
9247 .only_servers
9248 .into_iter()
9249 .filter_map(|selector| {
9250 Some(match selector.selector? {
9251 proto::language_server_selector::Selector::ServerId(server_id) => {
9252 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9253 }
9254 proto::language_server_selector::Selector::Name(name) => {
9255 LanguageServerSelector::Name(LanguageServerName(
9256 SharedString::from(name),
9257 ))
9258 }
9259 })
9260 })
9261 .collect(),
9262 false,
9263 cx,
9264 );
9265 this.buffer_store().update(cx, |buffer_store, _| {
9266 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9267 });
9268
9269 Ok(())
9270 })??;
9271 Ok(proto::Ack {})
9272 }
9273
9274 async fn handle_rename_project_entry(
9275 this: Entity<Self>,
9276 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9277 mut cx: AsyncApp,
9278 ) -> Result<proto::ProjectEntryResponse> {
9279 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9280 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9281 let new_path =
9282 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9283
9284 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9285 .update(&mut cx, |this, cx| {
9286 let (worktree, entry) = this
9287 .worktree_store
9288 .read(cx)
9289 .worktree_and_entry_for_id(entry_id, cx)?;
9290 let new_worktree = this
9291 .worktree_store
9292 .read(cx)
9293 .worktree_for_id(new_worktree_id, cx)?;
9294 Some((
9295 this.worktree_store.clone(),
9296 worktree,
9297 new_worktree,
9298 entry.clone(),
9299 ))
9300 })?
9301 .context("worktree not found")?;
9302 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9303 (worktree.absolutize(&old_entry.path), worktree.id())
9304 })?;
9305 let new_abs_path =
9306 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9307
9308 let _transaction = Self::will_rename_entry(
9309 this.downgrade(),
9310 old_worktree_id,
9311 &old_abs_path,
9312 &new_abs_path,
9313 old_entry.is_dir(),
9314 cx.clone(),
9315 )
9316 .await;
9317 let response = WorktreeStore::handle_rename_project_entry(
9318 worktree_store,
9319 envelope.payload,
9320 cx.clone(),
9321 )
9322 .await;
9323 this.read_with(&cx, |this, _| {
9324 this.did_rename_entry(
9325 old_worktree_id,
9326 &old_abs_path,
9327 &new_abs_path,
9328 old_entry.is_dir(),
9329 );
9330 })
9331 .ok();
9332 response
9333 }
9334
9335 async fn handle_update_diagnostic_summary(
9336 this: Entity<Self>,
9337 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9338 mut cx: AsyncApp,
9339 ) -> Result<()> {
9340 this.update(&mut cx, |lsp_store, cx| {
9341 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9342 let mut updated_diagnostics_paths = HashMap::default();
9343 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9344 for message_summary in envelope
9345 .payload
9346 .summary
9347 .into_iter()
9348 .chain(envelope.payload.more_summaries)
9349 {
9350 let project_path = ProjectPath {
9351 worktree_id,
9352 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9353 };
9354 let path = project_path.path.clone();
9355 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9356 let summary = DiagnosticSummary {
9357 error_count: message_summary.error_count as usize,
9358 warning_count: message_summary.warning_count as usize,
9359 };
9360
9361 if summary.is_empty() {
9362 if let Some(worktree_summaries) =
9363 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9364 && let Some(summaries) = worktree_summaries.get_mut(&path)
9365 {
9366 summaries.remove(&server_id);
9367 if summaries.is_empty() {
9368 worktree_summaries.remove(&path);
9369 }
9370 }
9371 } else {
9372 lsp_store
9373 .diagnostic_summaries
9374 .entry(worktree_id)
9375 .or_default()
9376 .entry(path)
9377 .or_default()
9378 .insert(server_id, summary);
9379 }
9380
9381 if let Some((_, project_id)) = &lsp_store.downstream_client {
9382 match &mut diagnostics_summary {
9383 Some(diagnostics_summary) => {
9384 diagnostics_summary
9385 .more_summaries
9386 .push(proto::DiagnosticSummary {
9387 path: project_path.path.as_ref().to_proto(),
9388 language_server_id: server_id.0 as u64,
9389 error_count: summary.error_count as u32,
9390 warning_count: summary.warning_count as u32,
9391 })
9392 }
9393 None => {
9394 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9395 project_id: *project_id,
9396 worktree_id: worktree_id.to_proto(),
9397 summary: Some(proto::DiagnosticSummary {
9398 path: project_path.path.as_ref().to_proto(),
9399 language_server_id: server_id.0 as u64,
9400 error_count: summary.error_count as u32,
9401 warning_count: summary.warning_count as u32,
9402 }),
9403 more_summaries: Vec::new(),
9404 })
9405 }
9406 }
9407 }
9408 updated_diagnostics_paths
9409 .entry(server_id)
9410 .or_insert_with(Vec::new)
9411 .push(project_path);
9412 }
9413
9414 if let Some((diagnostics_summary, (downstream_client, _))) =
9415 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9416 {
9417 downstream_client.send(diagnostics_summary).log_err();
9418 }
9419 for (server_id, paths) in updated_diagnostics_paths {
9420 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9421 }
9422 Ok(())
9423 })?
9424 }
9425
9426 async fn handle_start_language_server(
9427 lsp_store: Entity<Self>,
9428 envelope: TypedEnvelope<proto::StartLanguageServer>,
9429 mut cx: AsyncApp,
9430 ) -> Result<()> {
9431 let server = envelope.payload.server.context("invalid server")?;
9432 let server_capabilities =
9433 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9434 .with_context(|| {
9435 format!(
9436 "incorrect server capabilities {}",
9437 envelope.payload.capabilities
9438 )
9439 })?;
9440 lsp_store.update(&mut cx, |lsp_store, cx| {
9441 let server_id = LanguageServerId(server.id as usize);
9442 let server_name = LanguageServerName::from_proto(server.name.clone());
9443 lsp_store
9444 .lsp_server_capabilities
9445 .insert(server_id, server_capabilities);
9446 lsp_store.language_server_statuses.insert(
9447 server_id,
9448 LanguageServerStatus {
9449 name: server_name.clone(),
9450 server_version: None,
9451 pending_work: Default::default(),
9452 has_pending_diagnostic_updates: false,
9453 progress_tokens: Default::default(),
9454 worktree: server.worktree_id.map(WorktreeId::from_proto),
9455 binary: None,
9456 configuration: None,
9457 workspace_folders: BTreeSet::new(),
9458 },
9459 );
9460 cx.emit(LspStoreEvent::LanguageServerAdded(
9461 server_id,
9462 server_name,
9463 server.worktree_id.map(WorktreeId::from_proto),
9464 ));
9465 cx.notify();
9466 })?;
9467 Ok(())
9468 }
9469
9470 async fn handle_update_language_server(
9471 lsp_store: Entity<Self>,
9472 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9473 mut cx: AsyncApp,
9474 ) -> Result<()> {
9475 lsp_store.update(&mut cx, |lsp_store, cx| {
9476 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9477
9478 match envelope.payload.variant.context("invalid variant")? {
9479 proto::update_language_server::Variant::WorkStart(payload) => {
9480 lsp_store.on_lsp_work_start(
9481 language_server_id,
9482 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9483 .context("invalid progress token value")?,
9484 LanguageServerProgress {
9485 title: payload.title,
9486 is_disk_based_diagnostics_progress: false,
9487 is_cancellable: payload.is_cancellable.unwrap_or(false),
9488 message: payload.message,
9489 percentage: payload.percentage.map(|p| p as usize),
9490 last_update_at: cx.background_executor().now(),
9491 },
9492 cx,
9493 );
9494 }
9495 proto::update_language_server::Variant::WorkProgress(payload) => {
9496 lsp_store.on_lsp_work_progress(
9497 language_server_id,
9498 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9499 .context("invalid progress token value")?,
9500 LanguageServerProgress {
9501 title: None,
9502 is_disk_based_diagnostics_progress: false,
9503 is_cancellable: payload.is_cancellable.unwrap_or(false),
9504 message: payload.message,
9505 percentage: payload.percentage.map(|p| p as usize),
9506 last_update_at: cx.background_executor().now(),
9507 },
9508 cx,
9509 );
9510 }
9511
9512 proto::update_language_server::Variant::WorkEnd(payload) => {
9513 lsp_store.on_lsp_work_end(
9514 language_server_id,
9515 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9516 .context("invalid progress token value")?,
9517 cx,
9518 );
9519 }
9520
9521 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9522 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9523 }
9524
9525 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9526 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9527 }
9528
9529 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9530 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9531 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9532 cx.emit(LspStoreEvent::LanguageServerUpdate {
9533 language_server_id,
9534 name: envelope
9535 .payload
9536 .server_name
9537 .map(SharedString::new)
9538 .map(LanguageServerName),
9539 message: non_lsp,
9540 });
9541 }
9542 }
9543
9544 Ok(())
9545 })?
9546 }
9547
9548 async fn handle_language_server_log(
9549 this: Entity<Self>,
9550 envelope: TypedEnvelope<proto::LanguageServerLog>,
9551 mut cx: AsyncApp,
9552 ) -> Result<()> {
9553 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9554 let log_type = envelope
9555 .payload
9556 .log_type
9557 .map(LanguageServerLogType::from_proto)
9558 .context("invalid language server log type")?;
9559
9560 let message = envelope.payload.message;
9561
9562 this.update(&mut cx, |_, cx| {
9563 cx.emit(LspStoreEvent::LanguageServerLog(
9564 language_server_id,
9565 log_type,
9566 message,
9567 ));
9568 })
9569 }
9570
9571 async fn handle_lsp_ext_cancel_flycheck(
9572 lsp_store: Entity<Self>,
9573 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9574 cx: AsyncApp,
9575 ) -> Result<proto::Ack> {
9576 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9577 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9578 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9579 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9580 } else {
9581 None
9582 }
9583 })?;
9584 if let Some(task) = task {
9585 task.context("handling lsp ext cancel flycheck")?;
9586 }
9587
9588 Ok(proto::Ack {})
9589 }
9590
9591 async fn handle_lsp_ext_run_flycheck(
9592 lsp_store: Entity<Self>,
9593 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9594 mut cx: AsyncApp,
9595 ) -> Result<proto::Ack> {
9596 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9597 lsp_store.update(&mut cx, |lsp_store, cx| {
9598 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9599 let text_document = if envelope.payload.current_file_only {
9600 let buffer_id = envelope
9601 .payload
9602 .buffer_id
9603 .map(|id| BufferId::new(id))
9604 .transpose()?;
9605 buffer_id
9606 .and_then(|buffer_id| {
9607 lsp_store
9608 .buffer_store()
9609 .read(cx)
9610 .get(buffer_id)
9611 .and_then(|buffer| {
9612 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9613 })
9614 .map(|path| make_text_document_identifier(&path))
9615 })
9616 .transpose()?
9617 } else {
9618 None
9619 };
9620 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9621 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9622 )?;
9623 }
9624 anyhow::Ok(())
9625 })??;
9626
9627 Ok(proto::Ack {})
9628 }
9629
9630 async fn handle_lsp_ext_clear_flycheck(
9631 lsp_store: Entity<Self>,
9632 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9633 cx: AsyncApp,
9634 ) -> Result<proto::Ack> {
9635 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9636 lsp_store
9637 .read_with(&cx, |lsp_store, _| {
9638 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9639 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9640 } else {
9641 None
9642 }
9643 })
9644 .context("handling lsp ext clear flycheck")?;
9645
9646 Ok(proto::Ack {})
9647 }
9648
9649 pub fn disk_based_diagnostics_started(
9650 &mut self,
9651 language_server_id: LanguageServerId,
9652 cx: &mut Context<Self>,
9653 ) {
9654 if let Some(language_server_status) =
9655 self.language_server_statuses.get_mut(&language_server_id)
9656 {
9657 language_server_status.has_pending_diagnostic_updates = true;
9658 }
9659
9660 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9661 cx.emit(LspStoreEvent::LanguageServerUpdate {
9662 language_server_id,
9663 name: self
9664 .language_server_adapter_for_id(language_server_id)
9665 .map(|adapter| adapter.name()),
9666 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9667 Default::default(),
9668 ),
9669 })
9670 }
9671
9672 pub fn disk_based_diagnostics_finished(
9673 &mut self,
9674 language_server_id: LanguageServerId,
9675 cx: &mut Context<Self>,
9676 ) {
9677 if let Some(language_server_status) =
9678 self.language_server_statuses.get_mut(&language_server_id)
9679 {
9680 language_server_status.has_pending_diagnostic_updates = false;
9681 }
9682
9683 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9684 cx.emit(LspStoreEvent::LanguageServerUpdate {
9685 language_server_id,
9686 name: self
9687 .language_server_adapter_for_id(language_server_id)
9688 .map(|adapter| adapter.name()),
9689 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9690 Default::default(),
9691 ),
9692 })
9693 }
9694
9695 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9696 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9697 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9698 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9699 // the language server might take some time to publish diagnostics.
9700 fn simulate_disk_based_diagnostics_events_if_needed(
9701 &mut self,
9702 language_server_id: LanguageServerId,
9703 cx: &mut Context<Self>,
9704 ) {
9705 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9706
9707 let Some(LanguageServerState::Running {
9708 simulate_disk_based_diagnostics_completion,
9709 adapter,
9710 ..
9711 }) = self
9712 .as_local_mut()
9713 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9714 else {
9715 return;
9716 };
9717
9718 if adapter.disk_based_diagnostics_progress_token.is_some() {
9719 return;
9720 }
9721
9722 let prev_task =
9723 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9724 cx.background_executor()
9725 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9726 .await;
9727
9728 this.update(cx, |this, cx| {
9729 this.disk_based_diagnostics_finished(language_server_id, cx);
9730
9731 if let Some(LanguageServerState::Running {
9732 simulate_disk_based_diagnostics_completion,
9733 ..
9734 }) = this.as_local_mut().and_then(|local_store| {
9735 local_store.language_servers.get_mut(&language_server_id)
9736 }) {
9737 *simulate_disk_based_diagnostics_completion = None;
9738 }
9739 })
9740 .ok();
9741 }));
9742
9743 if prev_task.is_none() {
9744 self.disk_based_diagnostics_started(language_server_id, cx);
9745 }
9746 }
9747
9748 pub fn language_server_statuses(
9749 &self,
9750 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9751 self.language_server_statuses
9752 .iter()
9753 .map(|(key, value)| (*key, value))
9754 }
9755
9756 pub(super) fn did_rename_entry(
9757 &self,
9758 worktree_id: WorktreeId,
9759 old_path: &Path,
9760 new_path: &Path,
9761 is_dir: bool,
9762 ) {
9763 maybe!({
9764 let local_store = self.as_local()?;
9765
9766 let old_uri = lsp::Uri::from_file_path(old_path)
9767 .ok()
9768 .map(|uri| uri.to_string())?;
9769 let new_uri = lsp::Uri::from_file_path(new_path)
9770 .ok()
9771 .map(|uri| uri.to_string())?;
9772
9773 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9774 let Some(filter) = local_store
9775 .language_server_paths_watched_for_rename
9776 .get(&language_server.server_id())
9777 else {
9778 continue;
9779 };
9780
9781 if filter.should_send_did_rename(&old_uri, is_dir) {
9782 language_server
9783 .notify::<DidRenameFiles>(RenameFilesParams {
9784 files: vec![FileRename {
9785 old_uri: old_uri.clone(),
9786 new_uri: new_uri.clone(),
9787 }],
9788 })
9789 .ok();
9790 }
9791 }
9792 Some(())
9793 });
9794 }
9795
9796 pub(super) fn will_rename_entry(
9797 this: WeakEntity<Self>,
9798 worktree_id: WorktreeId,
9799 old_path: &Path,
9800 new_path: &Path,
9801 is_dir: bool,
9802 cx: AsyncApp,
9803 ) -> Task<ProjectTransaction> {
9804 let old_uri = lsp::Uri::from_file_path(old_path)
9805 .ok()
9806 .map(|uri| uri.to_string());
9807 let new_uri = lsp::Uri::from_file_path(new_path)
9808 .ok()
9809 .map(|uri| uri.to_string());
9810 cx.spawn(async move |cx| {
9811 let mut tasks = vec![];
9812 this.update(cx, |this, cx| {
9813 let local_store = this.as_local()?;
9814 let old_uri = old_uri?;
9815 let new_uri = new_uri?;
9816 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9817 let Some(filter) = local_store
9818 .language_server_paths_watched_for_rename
9819 .get(&language_server.server_id())
9820 else {
9821 continue;
9822 };
9823
9824 if filter.should_send_will_rename(&old_uri, is_dir) {
9825 let apply_edit = cx.spawn({
9826 let old_uri = old_uri.clone();
9827 let new_uri = new_uri.clone();
9828 let language_server = language_server.clone();
9829 async move |this, cx| {
9830 let edit = language_server
9831 .request::<WillRenameFiles>(RenameFilesParams {
9832 files: vec![FileRename { old_uri, new_uri }],
9833 })
9834 .await
9835 .into_response()
9836 .context("will rename files")
9837 .log_err()
9838 .flatten()?;
9839
9840 let transaction = LocalLspStore::deserialize_workspace_edit(
9841 this.upgrade()?,
9842 edit,
9843 false,
9844 language_server.clone(),
9845 cx,
9846 )
9847 .await
9848 .ok()?;
9849 Some(transaction)
9850 }
9851 });
9852 tasks.push(apply_edit);
9853 }
9854 }
9855 Some(())
9856 })
9857 .ok()
9858 .flatten();
9859 let mut merged_transaction = ProjectTransaction::default();
9860 for task in tasks {
9861 // Await on tasks sequentially so that the order of application of edits is deterministic
9862 // (at least with regards to the order of registration of language servers)
9863 if let Some(transaction) = task.await {
9864 for (buffer, buffer_transaction) in transaction.0 {
9865 merged_transaction.0.insert(buffer, buffer_transaction);
9866 }
9867 }
9868 }
9869 merged_transaction
9870 })
9871 }
9872
9873 fn lsp_notify_abs_paths_changed(
9874 &mut self,
9875 server_id: LanguageServerId,
9876 changes: Vec<PathEvent>,
9877 ) {
9878 maybe!({
9879 let server = self.language_server_for_id(server_id)?;
9880 let changes = changes
9881 .into_iter()
9882 .filter_map(|event| {
9883 let typ = match event.kind? {
9884 PathEventKind::Created => lsp::FileChangeType::CREATED,
9885 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9886 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9887 };
9888 Some(lsp::FileEvent {
9889 uri: file_path_to_lsp_url(&event.path).log_err()?,
9890 typ,
9891 })
9892 })
9893 .collect::<Vec<_>>();
9894 if !changes.is_empty() {
9895 server
9896 .notify::<lsp::notification::DidChangeWatchedFiles>(
9897 lsp::DidChangeWatchedFilesParams { changes },
9898 )
9899 .ok();
9900 }
9901 Some(())
9902 });
9903 }
9904
9905 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9906 self.as_local()?.language_server_for_id(id)
9907 }
9908
9909 fn on_lsp_progress(
9910 &mut self,
9911 progress_params: lsp::ProgressParams,
9912 language_server_id: LanguageServerId,
9913 disk_based_diagnostics_progress_token: Option<String>,
9914 cx: &mut Context<Self>,
9915 ) {
9916 match progress_params.value {
9917 lsp::ProgressParamsValue::WorkDone(progress) => {
9918 self.handle_work_done_progress(
9919 progress,
9920 language_server_id,
9921 disk_based_diagnostics_progress_token,
9922 ProgressToken::from_lsp(progress_params.token),
9923 cx,
9924 );
9925 }
9926 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9927 let registration_id = match progress_params.token {
9928 lsp::NumberOrString::Number(_) => None,
9929 lsp::NumberOrString::String(token) => token
9930 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9931 .map(|(_, id)| id.to_owned()),
9932 };
9933 if let Some(LanguageServerState::Running {
9934 workspace_diagnostics_refresh_tasks,
9935 ..
9936 }) = self
9937 .as_local_mut()
9938 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9939 && let Some(workspace_diagnostics) =
9940 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9941 {
9942 workspace_diagnostics.progress_tx.try_send(()).ok();
9943 self.apply_workspace_diagnostic_report(
9944 language_server_id,
9945 report,
9946 registration_id.map(SharedString::from),
9947 cx,
9948 )
9949 }
9950 }
9951 }
9952 }
9953
9954 fn handle_work_done_progress(
9955 &mut self,
9956 progress: lsp::WorkDoneProgress,
9957 language_server_id: LanguageServerId,
9958 disk_based_diagnostics_progress_token: Option<String>,
9959 token: ProgressToken,
9960 cx: &mut Context<Self>,
9961 ) {
9962 let language_server_status =
9963 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9964 status
9965 } else {
9966 return;
9967 };
9968
9969 if !language_server_status.progress_tokens.contains(&token) {
9970 return;
9971 }
9972
9973 let is_disk_based_diagnostics_progress =
9974 if let (Some(disk_based_token), ProgressToken::String(token)) =
9975 (&disk_based_diagnostics_progress_token, &token)
9976 {
9977 token.starts_with(disk_based_token)
9978 } else {
9979 false
9980 };
9981
9982 match progress {
9983 lsp::WorkDoneProgress::Begin(report) => {
9984 if is_disk_based_diagnostics_progress {
9985 self.disk_based_diagnostics_started(language_server_id, cx);
9986 }
9987 self.on_lsp_work_start(
9988 language_server_id,
9989 token.clone(),
9990 LanguageServerProgress {
9991 title: Some(report.title),
9992 is_disk_based_diagnostics_progress,
9993 is_cancellable: report.cancellable.unwrap_or(false),
9994 message: report.message.clone(),
9995 percentage: report.percentage.map(|p| p as usize),
9996 last_update_at: cx.background_executor().now(),
9997 },
9998 cx,
9999 );
10000 }
10001 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10002 language_server_id,
10003 token,
10004 LanguageServerProgress {
10005 title: None,
10006 is_disk_based_diagnostics_progress,
10007 is_cancellable: report.cancellable.unwrap_or(false),
10008 message: report.message,
10009 percentage: report.percentage.map(|p| p as usize),
10010 last_update_at: cx.background_executor().now(),
10011 },
10012 cx,
10013 ),
10014 lsp::WorkDoneProgress::End(_) => {
10015 language_server_status.progress_tokens.remove(&token);
10016 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10017 if is_disk_based_diagnostics_progress {
10018 self.disk_based_diagnostics_finished(language_server_id, cx);
10019 }
10020 }
10021 }
10022 }
10023
10024 fn on_lsp_work_start(
10025 &mut self,
10026 language_server_id: LanguageServerId,
10027 token: ProgressToken,
10028 progress: LanguageServerProgress,
10029 cx: &mut Context<Self>,
10030 ) {
10031 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10032 status.pending_work.insert(token.clone(), progress.clone());
10033 cx.notify();
10034 }
10035 cx.emit(LspStoreEvent::LanguageServerUpdate {
10036 language_server_id,
10037 name: self
10038 .language_server_adapter_for_id(language_server_id)
10039 .map(|adapter| adapter.name()),
10040 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10041 token: Some(token.to_proto()),
10042 title: progress.title,
10043 message: progress.message,
10044 percentage: progress.percentage.map(|p| p as u32),
10045 is_cancellable: Some(progress.is_cancellable),
10046 }),
10047 })
10048 }
10049
10050 fn on_lsp_work_progress(
10051 &mut self,
10052 language_server_id: LanguageServerId,
10053 token: ProgressToken,
10054 progress: LanguageServerProgress,
10055 cx: &mut Context<Self>,
10056 ) {
10057 let mut did_update = false;
10058 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10059 match status.pending_work.entry(token.clone()) {
10060 btree_map::Entry::Vacant(entry) => {
10061 entry.insert(progress.clone());
10062 did_update = true;
10063 }
10064 btree_map::Entry::Occupied(mut entry) => {
10065 let entry = entry.get_mut();
10066 if (progress.last_update_at - entry.last_update_at)
10067 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10068 {
10069 entry.last_update_at = progress.last_update_at;
10070 if progress.message.is_some() {
10071 entry.message = progress.message.clone();
10072 }
10073 if progress.percentage.is_some() {
10074 entry.percentage = progress.percentage;
10075 }
10076 if progress.is_cancellable != entry.is_cancellable {
10077 entry.is_cancellable = progress.is_cancellable;
10078 }
10079 did_update = true;
10080 }
10081 }
10082 }
10083 }
10084
10085 if did_update {
10086 cx.emit(LspStoreEvent::LanguageServerUpdate {
10087 language_server_id,
10088 name: self
10089 .language_server_adapter_for_id(language_server_id)
10090 .map(|adapter| adapter.name()),
10091 message: proto::update_language_server::Variant::WorkProgress(
10092 proto::LspWorkProgress {
10093 token: Some(token.to_proto()),
10094 message: progress.message,
10095 percentage: progress.percentage.map(|p| p as u32),
10096 is_cancellable: Some(progress.is_cancellable),
10097 },
10098 ),
10099 })
10100 }
10101 }
10102
10103 fn on_lsp_work_end(
10104 &mut self,
10105 language_server_id: LanguageServerId,
10106 token: ProgressToken,
10107 cx: &mut Context<Self>,
10108 ) {
10109 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10110 if let Some(work) = status.pending_work.remove(&token)
10111 && !work.is_disk_based_diagnostics_progress
10112 {
10113 cx.emit(LspStoreEvent::RefreshInlayHints {
10114 server_id: language_server_id,
10115 request_id: None,
10116 });
10117 }
10118 cx.notify();
10119 }
10120
10121 cx.emit(LspStoreEvent::LanguageServerUpdate {
10122 language_server_id,
10123 name: self
10124 .language_server_adapter_for_id(language_server_id)
10125 .map(|adapter| adapter.name()),
10126 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10127 token: Some(token.to_proto()),
10128 }),
10129 })
10130 }
10131
10132 pub async fn handle_resolve_completion_documentation(
10133 this: Entity<Self>,
10134 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10135 mut cx: AsyncApp,
10136 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10137 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10138
10139 let completion = this
10140 .read_with(&cx, |this, cx| {
10141 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10142 let server = this
10143 .language_server_for_id(id)
10144 .with_context(|| format!("No language server {id}"))?;
10145
10146 anyhow::Ok(cx.background_spawn(async move {
10147 let can_resolve = server
10148 .capabilities()
10149 .completion_provider
10150 .as_ref()
10151 .and_then(|options| options.resolve_provider)
10152 .unwrap_or(false);
10153 if can_resolve {
10154 server
10155 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10156 .await
10157 .into_response()
10158 .context("resolve completion item")
10159 } else {
10160 anyhow::Ok(lsp_completion)
10161 }
10162 }))
10163 })??
10164 .await?;
10165
10166 let mut documentation_is_markdown = false;
10167 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10168 let documentation = match completion.documentation {
10169 Some(lsp::Documentation::String(text)) => text,
10170
10171 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10172 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10173 value
10174 }
10175
10176 _ => String::new(),
10177 };
10178
10179 // If we have a new buffer_id, that means we're talking to a new client
10180 // and want to check for new text_edits in the completion too.
10181 let mut old_replace_start = None;
10182 let mut old_replace_end = None;
10183 let mut old_insert_start = None;
10184 let mut old_insert_end = None;
10185 let mut new_text = String::default();
10186 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10187 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10188 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10189 anyhow::Ok(buffer.read(cx).snapshot())
10190 })??;
10191
10192 if let Some(text_edit) = completion.text_edit.as_ref() {
10193 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10194
10195 if let Some(mut edit) = edit {
10196 LineEnding::normalize(&mut edit.new_text);
10197
10198 new_text = edit.new_text;
10199 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10200 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10201 if let Some(insert_range) = edit.insert_range {
10202 old_insert_start = Some(serialize_anchor(&insert_range.start));
10203 old_insert_end = Some(serialize_anchor(&insert_range.end));
10204 }
10205 }
10206 }
10207 }
10208
10209 Ok(proto::ResolveCompletionDocumentationResponse {
10210 documentation,
10211 documentation_is_markdown,
10212 old_replace_start,
10213 old_replace_end,
10214 new_text,
10215 lsp_completion,
10216 old_insert_start,
10217 old_insert_end,
10218 })
10219 }
10220
10221 async fn handle_on_type_formatting(
10222 this: Entity<Self>,
10223 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10224 mut cx: AsyncApp,
10225 ) -> Result<proto::OnTypeFormattingResponse> {
10226 let on_type_formatting = this.update(&mut cx, |this, cx| {
10227 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10228 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10229 let position = envelope
10230 .payload
10231 .position
10232 .and_then(deserialize_anchor)
10233 .context("invalid position")?;
10234 anyhow::Ok(this.apply_on_type_formatting(
10235 buffer,
10236 position,
10237 envelope.payload.trigger.clone(),
10238 cx,
10239 ))
10240 })??;
10241
10242 let transaction = on_type_formatting
10243 .await?
10244 .as_ref()
10245 .map(language::proto::serialize_transaction);
10246 Ok(proto::OnTypeFormattingResponse { transaction })
10247 }
10248
10249 async fn handle_refresh_inlay_hints(
10250 lsp_store: Entity<Self>,
10251 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10252 mut cx: AsyncApp,
10253 ) -> Result<proto::Ack> {
10254 lsp_store.update(&mut cx, |_, cx| {
10255 cx.emit(LspStoreEvent::RefreshInlayHints {
10256 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10257 request_id: envelope.payload.request_id.map(|id| id as usize),
10258 });
10259 })?;
10260 Ok(proto::Ack {})
10261 }
10262
10263 async fn handle_pull_workspace_diagnostics(
10264 lsp_store: Entity<Self>,
10265 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10266 mut cx: AsyncApp,
10267 ) -> Result<proto::Ack> {
10268 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10269 lsp_store.update(&mut cx, |lsp_store, _| {
10270 lsp_store.pull_workspace_diagnostics(server_id);
10271 })?;
10272 Ok(proto::Ack {})
10273 }
10274
10275 async fn handle_get_color_presentation(
10276 lsp_store: Entity<Self>,
10277 envelope: TypedEnvelope<proto::GetColorPresentation>,
10278 mut cx: AsyncApp,
10279 ) -> Result<proto::GetColorPresentationResponse> {
10280 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10281 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10282 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10283 })??;
10284
10285 let color = envelope
10286 .payload
10287 .color
10288 .context("invalid color resolve request")?;
10289 let start = color
10290 .lsp_range_start
10291 .context("invalid color resolve request")?;
10292 let end = color
10293 .lsp_range_end
10294 .context("invalid color resolve request")?;
10295
10296 let color = DocumentColor {
10297 lsp_range: lsp::Range {
10298 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10299 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10300 },
10301 color: lsp::Color {
10302 red: color.red,
10303 green: color.green,
10304 blue: color.blue,
10305 alpha: color.alpha,
10306 },
10307 resolved: false,
10308 color_presentations: Vec::new(),
10309 };
10310 let resolved_color = lsp_store
10311 .update(&mut cx, |lsp_store, cx| {
10312 lsp_store.resolve_color_presentation(
10313 color,
10314 buffer.clone(),
10315 LanguageServerId(envelope.payload.server_id as usize),
10316 cx,
10317 )
10318 })?
10319 .await
10320 .context("resolving color presentation")?;
10321
10322 Ok(proto::GetColorPresentationResponse {
10323 presentations: resolved_color
10324 .color_presentations
10325 .into_iter()
10326 .map(|presentation| proto::ColorPresentation {
10327 label: presentation.label.to_string(),
10328 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10329 additional_text_edits: presentation
10330 .additional_text_edits
10331 .into_iter()
10332 .map(serialize_lsp_edit)
10333 .collect(),
10334 })
10335 .collect(),
10336 })
10337 }
10338
10339 async fn handle_resolve_inlay_hint(
10340 lsp_store: Entity<Self>,
10341 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10342 mut cx: AsyncApp,
10343 ) -> Result<proto::ResolveInlayHintResponse> {
10344 let proto_hint = envelope
10345 .payload
10346 .hint
10347 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10348 let hint = InlayHints::proto_to_project_hint(proto_hint)
10349 .context("resolved proto inlay hint conversion")?;
10350 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10351 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10352 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10353 })??;
10354 let response_hint = lsp_store
10355 .update(&mut cx, |lsp_store, cx| {
10356 lsp_store.resolve_inlay_hint(
10357 hint,
10358 buffer,
10359 LanguageServerId(envelope.payload.language_server_id as usize),
10360 cx,
10361 )
10362 })?
10363 .await
10364 .context("inlay hints fetch")?;
10365 Ok(proto::ResolveInlayHintResponse {
10366 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10367 })
10368 }
10369
10370 async fn handle_refresh_code_lens(
10371 this: Entity<Self>,
10372 _: TypedEnvelope<proto::RefreshCodeLens>,
10373 mut cx: AsyncApp,
10374 ) -> Result<proto::Ack> {
10375 this.update(&mut cx, |_, cx| {
10376 cx.emit(LspStoreEvent::RefreshCodeLens);
10377 })?;
10378 Ok(proto::Ack {})
10379 }
10380
10381 async fn handle_open_buffer_for_symbol(
10382 this: Entity<Self>,
10383 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10384 mut cx: AsyncApp,
10385 ) -> Result<proto::OpenBufferForSymbolResponse> {
10386 let peer_id = envelope.original_sender_id().unwrap_or_default();
10387 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10388 let symbol = Self::deserialize_symbol(symbol)?;
10389 this.read_with(&cx, |this, _| {
10390 if let SymbolLocation::OutsideProject {
10391 abs_path,
10392 signature,
10393 } = &symbol.path
10394 {
10395 let new_signature = this.symbol_signature(&abs_path);
10396 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10397 }
10398 Ok(())
10399 })??;
10400 let buffer = this
10401 .update(&mut cx, |this, cx| {
10402 this.open_buffer_for_symbol(
10403 &Symbol {
10404 language_server_name: symbol.language_server_name,
10405 source_worktree_id: symbol.source_worktree_id,
10406 source_language_server_id: symbol.source_language_server_id,
10407 path: symbol.path,
10408 name: symbol.name,
10409 kind: symbol.kind,
10410 range: symbol.range,
10411 label: CodeLabel::default(),
10412 },
10413 cx,
10414 )
10415 })?
10416 .await?;
10417
10418 this.update(&mut cx, |this, cx| {
10419 let is_private = buffer
10420 .read(cx)
10421 .file()
10422 .map(|f| f.is_private())
10423 .unwrap_or_default();
10424 if is_private {
10425 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10426 } else {
10427 this.buffer_store
10428 .update(cx, |buffer_store, cx| {
10429 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10430 })
10431 .detach_and_log_err(cx);
10432 let buffer_id = buffer.read(cx).remote_id().to_proto();
10433 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10434 }
10435 })?
10436 }
10437
10438 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10439 let mut hasher = Sha256::new();
10440 hasher.update(abs_path.to_string_lossy().as_bytes());
10441 hasher.update(self.nonce.to_be_bytes());
10442 hasher.finalize().as_slice().try_into().unwrap()
10443 }
10444
10445 pub async fn handle_get_project_symbols(
10446 this: Entity<Self>,
10447 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10448 mut cx: AsyncApp,
10449 ) -> Result<proto::GetProjectSymbolsResponse> {
10450 let symbols = this
10451 .update(&mut cx, |this, cx| {
10452 this.symbols(&envelope.payload.query, cx)
10453 })?
10454 .await?;
10455
10456 Ok(proto::GetProjectSymbolsResponse {
10457 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10458 })
10459 }
10460
10461 pub async fn handle_restart_language_servers(
10462 this: Entity<Self>,
10463 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10464 mut cx: AsyncApp,
10465 ) -> Result<proto::Ack> {
10466 this.update(&mut cx, |lsp_store, cx| {
10467 let buffers =
10468 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10469 lsp_store.restart_language_servers_for_buffers(
10470 buffers,
10471 envelope
10472 .payload
10473 .only_servers
10474 .into_iter()
10475 .filter_map(|selector| {
10476 Some(match selector.selector? {
10477 proto::language_server_selector::Selector::ServerId(server_id) => {
10478 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10479 }
10480 proto::language_server_selector::Selector::Name(name) => {
10481 LanguageServerSelector::Name(LanguageServerName(
10482 SharedString::from(name),
10483 ))
10484 }
10485 })
10486 })
10487 .collect(),
10488 cx,
10489 );
10490 })?;
10491
10492 Ok(proto::Ack {})
10493 }
10494
10495 pub async fn handle_stop_language_servers(
10496 lsp_store: Entity<Self>,
10497 envelope: TypedEnvelope<proto::StopLanguageServers>,
10498 mut cx: AsyncApp,
10499 ) -> Result<proto::Ack> {
10500 lsp_store.update(&mut cx, |lsp_store, cx| {
10501 if envelope.payload.all
10502 && envelope.payload.also_servers.is_empty()
10503 && envelope.payload.buffer_ids.is_empty()
10504 {
10505 lsp_store.stop_all_language_servers(cx);
10506 } else {
10507 let buffers =
10508 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10509 lsp_store
10510 .stop_language_servers_for_buffers(
10511 buffers,
10512 envelope
10513 .payload
10514 .also_servers
10515 .into_iter()
10516 .filter_map(|selector| {
10517 Some(match selector.selector? {
10518 proto::language_server_selector::Selector::ServerId(
10519 server_id,
10520 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10521 server_id,
10522 )),
10523 proto::language_server_selector::Selector::Name(name) => {
10524 LanguageServerSelector::Name(LanguageServerName(
10525 SharedString::from(name),
10526 ))
10527 }
10528 })
10529 })
10530 .collect(),
10531 cx,
10532 )
10533 .detach_and_log_err(cx);
10534 }
10535 })?;
10536
10537 Ok(proto::Ack {})
10538 }
10539
10540 pub async fn handle_cancel_language_server_work(
10541 lsp_store: Entity<Self>,
10542 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10543 mut cx: AsyncApp,
10544 ) -> Result<proto::Ack> {
10545 lsp_store.update(&mut cx, |lsp_store, cx| {
10546 if let Some(work) = envelope.payload.work {
10547 match work {
10548 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10549 let buffers =
10550 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10551 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10552 }
10553 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10554 let server_id = LanguageServerId::from_proto(work.language_server_id);
10555 let token = work
10556 .token
10557 .map(|token| {
10558 ProgressToken::from_proto(token)
10559 .context("invalid work progress token")
10560 })
10561 .transpose()?;
10562 lsp_store.cancel_language_server_work(server_id, token, cx);
10563 }
10564 }
10565 }
10566 anyhow::Ok(())
10567 })??;
10568
10569 Ok(proto::Ack {})
10570 }
10571
10572 fn buffer_ids_to_buffers(
10573 &mut self,
10574 buffer_ids: impl Iterator<Item = u64>,
10575 cx: &mut Context<Self>,
10576 ) -> Vec<Entity<Buffer>> {
10577 buffer_ids
10578 .into_iter()
10579 .flat_map(|buffer_id| {
10580 self.buffer_store
10581 .read(cx)
10582 .get(BufferId::new(buffer_id).log_err()?)
10583 })
10584 .collect::<Vec<_>>()
10585 }
10586
10587 async fn handle_apply_additional_edits_for_completion(
10588 this: Entity<Self>,
10589 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10590 mut cx: AsyncApp,
10591 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10592 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10593 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10594 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10595 let completion = Self::deserialize_completion(
10596 envelope.payload.completion.context("invalid completion")?,
10597 )?;
10598 anyhow::Ok((buffer, completion))
10599 })??;
10600
10601 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10602 this.apply_additional_edits_for_completion(
10603 buffer,
10604 Rc::new(RefCell::new(Box::new([Completion {
10605 replace_range: completion.replace_range,
10606 new_text: completion.new_text,
10607 source: completion.source,
10608 documentation: None,
10609 label: CodeLabel::default(),
10610 match_start: None,
10611 snippet_deduplication_key: None,
10612 insert_text_mode: None,
10613 icon_path: None,
10614 confirm: None,
10615 }]))),
10616 0,
10617 false,
10618 cx,
10619 )
10620 })?;
10621
10622 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10623 transaction: apply_additional_edits
10624 .await?
10625 .as_ref()
10626 .map(language::proto::serialize_transaction),
10627 })
10628 }
10629
10630 pub fn last_formatting_failure(&self) -> Option<&str> {
10631 self.last_formatting_failure.as_deref()
10632 }
10633
10634 pub fn reset_last_formatting_failure(&mut self) {
10635 self.last_formatting_failure = None;
10636 }
10637
10638 pub fn environment_for_buffer(
10639 &self,
10640 buffer: &Entity<Buffer>,
10641 cx: &mut Context<Self>,
10642 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10643 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10644 environment.update(cx, |env, cx| {
10645 env.buffer_environment(buffer, &self.worktree_store, cx)
10646 })
10647 } else {
10648 Task::ready(None).shared()
10649 }
10650 }
10651
10652 pub fn format(
10653 &mut self,
10654 buffers: HashSet<Entity<Buffer>>,
10655 target: LspFormatTarget,
10656 push_to_history: bool,
10657 trigger: FormatTrigger,
10658 cx: &mut Context<Self>,
10659 ) -> Task<anyhow::Result<ProjectTransaction>> {
10660 let logger = zlog::scoped!("format");
10661 if self.as_local().is_some() {
10662 zlog::trace!(logger => "Formatting locally");
10663 let logger = zlog::scoped!(logger => "local");
10664 let buffers = buffers
10665 .into_iter()
10666 .map(|buffer_handle| {
10667 let buffer = buffer_handle.read(cx);
10668 let buffer_abs_path = File::from_dyn(buffer.file())
10669 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10670
10671 (buffer_handle, buffer_abs_path, buffer.remote_id())
10672 })
10673 .collect::<Vec<_>>();
10674
10675 cx.spawn(async move |lsp_store, cx| {
10676 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10677
10678 for (handle, abs_path, id) in buffers {
10679 let env = lsp_store
10680 .update(cx, |lsp_store, cx| {
10681 lsp_store.environment_for_buffer(&handle, cx)
10682 })?
10683 .await;
10684
10685 let ranges = match &target {
10686 LspFormatTarget::Buffers => None,
10687 LspFormatTarget::Ranges(ranges) => {
10688 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10689 }
10690 };
10691
10692 formattable_buffers.push(FormattableBuffer {
10693 handle,
10694 abs_path,
10695 env,
10696 ranges,
10697 });
10698 }
10699 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10700
10701 let format_timer = zlog::time!(logger => "Formatting buffers");
10702 let result = LocalLspStore::format_locally(
10703 lsp_store.clone(),
10704 formattable_buffers,
10705 push_to_history,
10706 trigger,
10707 logger,
10708 cx,
10709 )
10710 .await;
10711 format_timer.end();
10712
10713 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10714
10715 lsp_store.update(cx, |lsp_store, _| {
10716 lsp_store.update_last_formatting_failure(&result);
10717 })?;
10718
10719 result
10720 })
10721 } else if let Some((client, project_id)) = self.upstream_client() {
10722 zlog::trace!(logger => "Formatting remotely");
10723 let logger = zlog::scoped!(logger => "remote");
10724 // Don't support formatting ranges via remote
10725 match target {
10726 LspFormatTarget::Buffers => {}
10727 LspFormatTarget::Ranges(_) => {
10728 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10729 return Task::ready(Ok(ProjectTransaction::default()));
10730 }
10731 }
10732
10733 let buffer_store = self.buffer_store();
10734 cx.spawn(async move |lsp_store, cx| {
10735 zlog::trace!(logger => "Sending remote format request");
10736 let request_timer = zlog::time!(logger => "remote format request");
10737 let result = client
10738 .request(proto::FormatBuffers {
10739 project_id,
10740 trigger: trigger as i32,
10741 buffer_ids: buffers
10742 .iter()
10743 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10744 .collect::<Result<_>>()?,
10745 })
10746 .await
10747 .and_then(|result| result.transaction.context("missing transaction"));
10748 request_timer.end();
10749
10750 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10751
10752 lsp_store.update(cx, |lsp_store, _| {
10753 lsp_store.update_last_formatting_failure(&result);
10754 })?;
10755
10756 let transaction_response = result?;
10757 let _timer = zlog::time!(logger => "deserializing project transaction");
10758 buffer_store
10759 .update(cx, |buffer_store, cx| {
10760 buffer_store.deserialize_project_transaction(
10761 transaction_response,
10762 push_to_history,
10763 cx,
10764 )
10765 })?
10766 .await
10767 })
10768 } else {
10769 zlog::trace!(logger => "Not formatting");
10770 Task::ready(Ok(ProjectTransaction::default()))
10771 }
10772 }
10773
10774 async fn handle_format_buffers(
10775 this: Entity<Self>,
10776 envelope: TypedEnvelope<proto::FormatBuffers>,
10777 mut cx: AsyncApp,
10778 ) -> Result<proto::FormatBuffersResponse> {
10779 let sender_id = envelope.original_sender_id().unwrap_or_default();
10780 let format = this.update(&mut cx, |this, cx| {
10781 let mut buffers = HashSet::default();
10782 for buffer_id in &envelope.payload.buffer_ids {
10783 let buffer_id = BufferId::new(*buffer_id)?;
10784 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10785 }
10786 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10787 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10788 })??;
10789
10790 let project_transaction = format.await?;
10791 let project_transaction = this.update(&mut cx, |this, cx| {
10792 this.buffer_store.update(cx, |buffer_store, cx| {
10793 buffer_store.serialize_project_transaction_for_peer(
10794 project_transaction,
10795 sender_id,
10796 cx,
10797 )
10798 })
10799 })?;
10800 Ok(proto::FormatBuffersResponse {
10801 transaction: Some(project_transaction),
10802 })
10803 }
10804
10805 async fn handle_apply_code_action_kind(
10806 this: Entity<Self>,
10807 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10808 mut cx: AsyncApp,
10809 ) -> Result<proto::ApplyCodeActionKindResponse> {
10810 let sender_id = envelope.original_sender_id().unwrap_or_default();
10811 let format = this.update(&mut cx, |this, cx| {
10812 let mut buffers = HashSet::default();
10813 for buffer_id in &envelope.payload.buffer_ids {
10814 let buffer_id = BufferId::new(*buffer_id)?;
10815 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10816 }
10817 let kind = match envelope.payload.kind.as_str() {
10818 "" => CodeActionKind::EMPTY,
10819 "quickfix" => CodeActionKind::QUICKFIX,
10820 "refactor" => CodeActionKind::REFACTOR,
10821 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10822 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10823 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10824 "source" => CodeActionKind::SOURCE,
10825 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10826 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10827 _ => anyhow::bail!(
10828 "Invalid code action kind {}",
10829 envelope.payload.kind.as_str()
10830 ),
10831 };
10832 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10833 })??;
10834
10835 let project_transaction = format.await?;
10836 let project_transaction = this.update(&mut cx, |this, cx| {
10837 this.buffer_store.update(cx, |buffer_store, cx| {
10838 buffer_store.serialize_project_transaction_for_peer(
10839 project_transaction,
10840 sender_id,
10841 cx,
10842 )
10843 })
10844 })?;
10845 Ok(proto::ApplyCodeActionKindResponse {
10846 transaction: Some(project_transaction),
10847 })
10848 }
10849
10850 async fn shutdown_language_server(
10851 server_state: Option<LanguageServerState>,
10852 name: LanguageServerName,
10853 cx: &mut AsyncApp,
10854 ) {
10855 let server = match server_state {
10856 Some(LanguageServerState::Starting { startup, .. }) => {
10857 let mut timer = cx
10858 .background_executor()
10859 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10860 .fuse();
10861
10862 select! {
10863 server = startup.fuse() => server,
10864 () = timer => {
10865 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10866 None
10867 },
10868 }
10869 }
10870
10871 Some(LanguageServerState::Running { server, .. }) => Some(server),
10872
10873 None => None,
10874 };
10875
10876 if let Some(server) = server
10877 && let Some(shutdown) = server.shutdown()
10878 {
10879 shutdown.await;
10880 }
10881 }
10882
10883 // Returns a list of all of the worktrees which no longer have a language server and the root path
10884 // for the stopped server
10885 fn stop_local_language_server(
10886 &mut self,
10887 server_id: LanguageServerId,
10888 cx: &mut Context<Self>,
10889 ) -> Task<()> {
10890 let local = match &mut self.mode {
10891 LspStoreMode::Local(local) => local,
10892 _ => {
10893 return Task::ready(());
10894 }
10895 };
10896
10897 // Remove this server ID from all entries in the given worktree.
10898 local
10899 .language_server_ids
10900 .retain(|_, state| state.id != server_id);
10901 self.buffer_store.update(cx, |buffer_store, cx| {
10902 for buffer in buffer_store.buffers() {
10903 buffer.update(cx, |buffer, cx| {
10904 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10905 buffer.set_completion_triggers(server_id, Default::default(), cx);
10906 });
10907 }
10908 });
10909
10910 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10911 summaries.retain(|path, summaries_by_server_id| {
10912 if summaries_by_server_id.remove(&server_id).is_some() {
10913 if let Some((client, project_id)) = self.downstream_client.clone() {
10914 client
10915 .send(proto::UpdateDiagnosticSummary {
10916 project_id,
10917 worktree_id: worktree_id.to_proto(),
10918 summary: Some(proto::DiagnosticSummary {
10919 path: path.as_ref().to_proto(),
10920 language_server_id: server_id.0 as u64,
10921 error_count: 0,
10922 warning_count: 0,
10923 }),
10924 more_summaries: Vec::new(),
10925 })
10926 .log_err();
10927 }
10928 !summaries_by_server_id.is_empty()
10929 } else {
10930 true
10931 }
10932 });
10933 }
10934
10935 let local = self.as_local_mut().unwrap();
10936 for diagnostics in local.diagnostics.values_mut() {
10937 diagnostics.retain(|_, diagnostics_by_server_id| {
10938 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10939 diagnostics_by_server_id.remove(ix);
10940 !diagnostics_by_server_id.is_empty()
10941 } else {
10942 true
10943 }
10944 });
10945 }
10946 local.language_server_watched_paths.remove(&server_id);
10947
10948 let server_state = local.language_servers.remove(&server_id);
10949 self.cleanup_lsp_data(server_id);
10950 let name = self
10951 .language_server_statuses
10952 .remove(&server_id)
10953 .map(|status| status.name)
10954 .or_else(|| {
10955 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10956 Some(adapter.name())
10957 } else {
10958 None
10959 }
10960 });
10961
10962 if let Some(name) = name {
10963 log::info!("stopping language server {name}");
10964 self.languages
10965 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10966 cx.notify();
10967
10968 return cx.spawn(async move |lsp_store, cx| {
10969 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10970 lsp_store
10971 .update(cx, |lsp_store, cx| {
10972 lsp_store
10973 .languages
10974 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10975 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10976 cx.notify();
10977 })
10978 .ok();
10979 });
10980 }
10981
10982 if server_state.is_some() {
10983 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10984 }
10985 Task::ready(())
10986 }
10987
10988 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10989 if let Some((client, project_id)) = self.upstream_client() {
10990 let request = client.request(proto::StopLanguageServers {
10991 project_id,
10992 buffer_ids: Vec::new(),
10993 also_servers: Vec::new(),
10994 all: true,
10995 });
10996 cx.background_spawn(request).detach_and_log_err(cx);
10997 } else {
10998 let Some(local) = self.as_local_mut() else {
10999 return;
11000 };
11001 let language_servers_to_stop = local
11002 .language_server_ids
11003 .values()
11004 .map(|state| state.id)
11005 .collect();
11006 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11007 let tasks = language_servers_to_stop
11008 .into_iter()
11009 .map(|server| self.stop_local_language_server(server, cx))
11010 .collect::<Vec<_>>();
11011 cx.background_spawn(async move {
11012 futures::future::join_all(tasks).await;
11013 })
11014 .detach();
11015 }
11016 }
11017
11018 pub fn restart_language_servers_for_buffers(
11019 &mut self,
11020 buffers: Vec<Entity<Buffer>>,
11021 only_restart_servers: HashSet<LanguageServerSelector>,
11022 cx: &mut Context<Self>,
11023 ) {
11024 if let Some((client, project_id)) = self.upstream_client() {
11025 let request = client.request(proto::RestartLanguageServers {
11026 project_id,
11027 buffer_ids: buffers
11028 .into_iter()
11029 .map(|b| b.read(cx).remote_id().to_proto())
11030 .collect(),
11031 only_servers: only_restart_servers
11032 .into_iter()
11033 .map(|selector| {
11034 let selector = match selector {
11035 LanguageServerSelector::Id(language_server_id) => {
11036 proto::language_server_selector::Selector::ServerId(
11037 language_server_id.to_proto(),
11038 )
11039 }
11040 LanguageServerSelector::Name(language_server_name) => {
11041 proto::language_server_selector::Selector::Name(
11042 language_server_name.to_string(),
11043 )
11044 }
11045 };
11046 proto::LanguageServerSelector {
11047 selector: Some(selector),
11048 }
11049 })
11050 .collect(),
11051 all: false,
11052 });
11053 cx.background_spawn(request).detach_and_log_err(cx);
11054 } else {
11055 let stop_task = if only_restart_servers.is_empty() {
11056 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11057 } else {
11058 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11059 };
11060 cx.spawn(async move |lsp_store, cx| {
11061 stop_task.await;
11062 lsp_store
11063 .update(cx, |lsp_store, cx| {
11064 for buffer in buffers {
11065 lsp_store.register_buffer_with_language_servers(
11066 &buffer,
11067 only_restart_servers.clone(),
11068 true,
11069 cx,
11070 );
11071 }
11072 })
11073 .ok()
11074 })
11075 .detach();
11076 }
11077 }
11078
11079 pub fn stop_language_servers_for_buffers(
11080 &mut self,
11081 buffers: Vec<Entity<Buffer>>,
11082 also_stop_servers: HashSet<LanguageServerSelector>,
11083 cx: &mut Context<Self>,
11084 ) -> Task<Result<()>> {
11085 if let Some((client, project_id)) = self.upstream_client() {
11086 let request = client.request(proto::StopLanguageServers {
11087 project_id,
11088 buffer_ids: buffers
11089 .into_iter()
11090 .map(|b| b.read(cx).remote_id().to_proto())
11091 .collect(),
11092 also_servers: also_stop_servers
11093 .into_iter()
11094 .map(|selector| {
11095 let selector = match selector {
11096 LanguageServerSelector::Id(language_server_id) => {
11097 proto::language_server_selector::Selector::ServerId(
11098 language_server_id.to_proto(),
11099 )
11100 }
11101 LanguageServerSelector::Name(language_server_name) => {
11102 proto::language_server_selector::Selector::Name(
11103 language_server_name.to_string(),
11104 )
11105 }
11106 };
11107 proto::LanguageServerSelector {
11108 selector: Some(selector),
11109 }
11110 })
11111 .collect(),
11112 all: false,
11113 });
11114 cx.background_spawn(async move {
11115 let _ = request.await?;
11116 Ok(())
11117 })
11118 } else {
11119 let task =
11120 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11121 cx.background_spawn(async move {
11122 task.await;
11123 Ok(())
11124 })
11125 }
11126 }
11127
11128 fn stop_local_language_servers_for_buffers(
11129 &mut self,
11130 buffers: &[Entity<Buffer>],
11131 also_stop_servers: HashSet<LanguageServerSelector>,
11132 cx: &mut Context<Self>,
11133 ) -> Task<()> {
11134 let Some(local) = self.as_local_mut() else {
11135 return Task::ready(());
11136 };
11137 let mut language_server_names_to_stop = BTreeSet::default();
11138 let mut language_servers_to_stop = also_stop_servers
11139 .into_iter()
11140 .flat_map(|selector| match selector {
11141 LanguageServerSelector::Id(id) => Some(id),
11142 LanguageServerSelector::Name(name) => {
11143 language_server_names_to_stop.insert(name);
11144 None
11145 }
11146 })
11147 .collect::<BTreeSet<_>>();
11148
11149 let mut covered_worktrees = HashSet::default();
11150 for buffer in buffers {
11151 buffer.update(cx, |buffer, cx| {
11152 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11153 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11154 && covered_worktrees.insert(worktree_id)
11155 {
11156 language_server_names_to_stop.retain(|name| {
11157 let old_ids_count = language_servers_to_stop.len();
11158 let all_language_servers_with_this_name = local
11159 .language_server_ids
11160 .iter()
11161 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11162 language_servers_to_stop.extend(all_language_servers_with_this_name);
11163 old_ids_count == language_servers_to_stop.len()
11164 });
11165 }
11166 });
11167 }
11168 for name in language_server_names_to_stop {
11169 language_servers_to_stop.extend(
11170 local
11171 .language_server_ids
11172 .iter()
11173 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11174 );
11175 }
11176
11177 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11178 let tasks = language_servers_to_stop
11179 .into_iter()
11180 .map(|server| self.stop_local_language_server(server, cx))
11181 .collect::<Vec<_>>();
11182
11183 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11184 }
11185
11186 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11187 let (worktree, relative_path) =
11188 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11189
11190 let project_path = ProjectPath {
11191 worktree_id: worktree.read(cx).id(),
11192 path: relative_path,
11193 };
11194
11195 Some(
11196 self.buffer_store()
11197 .read(cx)
11198 .get_by_path(&project_path)?
11199 .read(cx),
11200 )
11201 }
11202
11203 #[cfg(any(test, feature = "test-support"))]
11204 pub fn update_diagnostics(
11205 &mut self,
11206 server_id: LanguageServerId,
11207 diagnostics: lsp::PublishDiagnosticsParams,
11208 result_id: Option<SharedString>,
11209 source_kind: DiagnosticSourceKind,
11210 disk_based_sources: &[String],
11211 cx: &mut Context<Self>,
11212 ) -> Result<()> {
11213 self.merge_lsp_diagnostics(
11214 source_kind,
11215 vec![DocumentDiagnosticsUpdate {
11216 diagnostics,
11217 result_id,
11218 server_id,
11219 disk_based_sources: Cow::Borrowed(disk_based_sources),
11220 registration_id: None,
11221 }],
11222 |_, _, _| false,
11223 cx,
11224 )
11225 }
11226
11227 pub fn merge_lsp_diagnostics(
11228 &mut self,
11229 source_kind: DiagnosticSourceKind,
11230 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11231 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11232 cx: &mut Context<Self>,
11233 ) -> Result<()> {
11234 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11235 let updates = lsp_diagnostics
11236 .into_iter()
11237 .filter_map(|update| {
11238 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11239 Some(DocumentDiagnosticsUpdate {
11240 diagnostics: self.lsp_to_document_diagnostics(
11241 abs_path,
11242 source_kind,
11243 update.server_id,
11244 update.diagnostics,
11245 &update.disk_based_sources,
11246 update.registration_id.clone(),
11247 ),
11248 result_id: update.result_id,
11249 server_id: update.server_id,
11250 disk_based_sources: update.disk_based_sources,
11251 registration_id: update.registration_id,
11252 })
11253 })
11254 .collect();
11255 self.merge_diagnostic_entries(updates, merge, cx)?;
11256 Ok(())
11257 }
11258
11259 fn lsp_to_document_diagnostics(
11260 &mut self,
11261 document_abs_path: PathBuf,
11262 source_kind: DiagnosticSourceKind,
11263 server_id: LanguageServerId,
11264 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11265 disk_based_sources: &[String],
11266 registration_id: Option<SharedString>,
11267 ) -> DocumentDiagnostics {
11268 let mut diagnostics = Vec::default();
11269 let mut primary_diagnostic_group_ids = HashMap::default();
11270 let mut sources_by_group_id = HashMap::default();
11271 let mut supporting_diagnostics = HashMap::default();
11272
11273 let adapter = self.language_server_adapter_for_id(server_id);
11274
11275 // Ensure that primary diagnostics are always the most severe
11276 lsp_diagnostics
11277 .diagnostics
11278 .sort_by_key(|item| item.severity);
11279
11280 for diagnostic in &lsp_diagnostics.diagnostics {
11281 let source = diagnostic.source.as_ref();
11282 let range = range_from_lsp(diagnostic.range);
11283 let is_supporting = diagnostic
11284 .related_information
11285 .as_ref()
11286 .is_some_and(|infos| {
11287 infos.iter().any(|info| {
11288 primary_diagnostic_group_ids.contains_key(&(
11289 source,
11290 diagnostic.code.clone(),
11291 range_from_lsp(info.location.range),
11292 ))
11293 })
11294 });
11295
11296 let is_unnecessary = diagnostic
11297 .tags
11298 .as_ref()
11299 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11300
11301 let underline = self
11302 .language_server_adapter_for_id(server_id)
11303 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11304
11305 if is_supporting {
11306 supporting_diagnostics.insert(
11307 (source, diagnostic.code.clone(), range),
11308 (diagnostic.severity, is_unnecessary),
11309 );
11310 } else {
11311 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11312 let is_disk_based =
11313 source.is_some_and(|source| disk_based_sources.contains(source));
11314
11315 sources_by_group_id.insert(group_id, source);
11316 primary_diagnostic_group_ids
11317 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11318
11319 diagnostics.push(DiagnosticEntry {
11320 range,
11321 diagnostic: Diagnostic {
11322 source: diagnostic.source.clone(),
11323 source_kind,
11324 code: diagnostic.code.clone(),
11325 code_description: diagnostic
11326 .code_description
11327 .as_ref()
11328 .and_then(|d| d.href.clone()),
11329 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11330 markdown: adapter.as_ref().and_then(|adapter| {
11331 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11332 }),
11333 message: diagnostic.message.trim().to_string(),
11334 group_id,
11335 is_primary: true,
11336 is_disk_based,
11337 is_unnecessary,
11338 underline,
11339 data: diagnostic.data.clone(),
11340 registration_id: registration_id.clone(),
11341 },
11342 });
11343 if let Some(infos) = &diagnostic.related_information {
11344 for info in infos {
11345 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11346 let range = range_from_lsp(info.location.range);
11347 diagnostics.push(DiagnosticEntry {
11348 range,
11349 diagnostic: Diagnostic {
11350 source: diagnostic.source.clone(),
11351 source_kind,
11352 code: diagnostic.code.clone(),
11353 code_description: diagnostic
11354 .code_description
11355 .as_ref()
11356 .and_then(|d| d.href.clone()),
11357 severity: DiagnosticSeverity::INFORMATION,
11358 markdown: adapter.as_ref().and_then(|adapter| {
11359 adapter.diagnostic_message_to_markdown(&info.message)
11360 }),
11361 message: info.message.trim().to_string(),
11362 group_id,
11363 is_primary: false,
11364 is_disk_based,
11365 is_unnecessary: false,
11366 underline,
11367 data: diagnostic.data.clone(),
11368 registration_id: registration_id.clone(),
11369 },
11370 });
11371 }
11372 }
11373 }
11374 }
11375 }
11376
11377 for entry in &mut diagnostics {
11378 let diagnostic = &mut entry.diagnostic;
11379 if !diagnostic.is_primary {
11380 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11381 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11382 source,
11383 diagnostic.code.clone(),
11384 entry.range.clone(),
11385 )) {
11386 if let Some(severity) = severity {
11387 diagnostic.severity = severity;
11388 }
11389 diagnostic.is_unnecessary = is_unnecessary;
11390 }
11391 }
11392 }
11393
11394 DocumentDiagnostics {
11395 diagnostics,
11396 document_abs_path,
11397 version: lsp_diagnostics.version,
11398 }
11399 }
11400
11401 fn insert_newly_running_language_server(
11402 &mut self,
11403 adapter: Arc<CachedLspAdapter>,
11404 language_server: Arc<LanguageServer>,
11405 server_id: LanguageServerId,
11406 key: LanguageServerSeed,
11407 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11408 cx: &mut Context<Self>,
11409 ) {
11410 let Some(local) = self.as_local_mut() else {
11411 return;
11412 };
11413 // If the language server for this key doesn't match the server id, don't store the
11414 // server. Which will cause it to be dropped, killing the process
11415 if local
11416 .language_server_ids
11417 .get(&key)
11418 .map(|state| state.id != server_id)
11419 .unwrap_or(false)
11420 {
11421 return;
11422 }
11423
11424 // Update language_servers collection with Running variant of LanguageServerState
11425 // indicating that the server is up and running and ready
11426 let workspace_folders = workspace_folders.lock().clone();
11427 language_server.set_workspace_folders(workspace_folders);
11428
11429 let workspace_diagnostics_refresh_tasks = language_server
11430 .capabilities()
11431 .diagnostic_provider
11432 .and_then(|provider| {
11433 local
11434 .language_server_dynamic_registrations
11435 .entry(server_id)
11436 .or_default()
11437 .diagnostics
11438 .entry(None)
11439 .or_insert(provider.clone());
11440 let workspace_refresher =
11441 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11442
11443 Some((None, workspace_refresher))
11444 })
11445 .into_iter()
11446 .collect();
11447 local.language_servers.insert(
11448 server_id,
11449 LanguageServerState::Running {
11450 workspace_diagnostics_refresh_tasks,
11451 adapter: adapter.clone(),
11452 server: language_server.clone(),
11453 simulate_disk_based_diagnostics_completion: None,
11454 },
11455 );
11456 local
11457 .languages
11458 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11459 if let Some(file_ops_caps) = language_server
11460 .capabilities()
11461 .workspace
11462 .as_ref()
11463 .and_then(|ws| ws.file_operations.as_ref())
11464 {
11465 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11466 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11467 if did_rename_caps.or(will_rename_caps).is_some() {
11468 let watcher = RenamePathsWatchedForServer::default()
11469 .with_did_rename_patterns(did_rename_caps)
11470 .with_will_rename_patterns(will_rename_caps);
11471 local
11472 .language_server_paths_watched_for_rename
11473 .insert(server_id, watcher);
11474 }
11475 }
11476
11477 self.language_server_statuses.insert(
11478 server_id,
11479 LanguageServerStatus {
11480 name: language_server.name(),
11481 server_version: language_server.version(),
11482 pending_work: Default::default(),
11483 has_pending_diagnostic_updates: false,
11484 progress_tokens: Default::default(),
11485 worktree: Some(key.worktree_id),
11486 binary: Some(language_server.binary().clone()),
11487 configuration: Some(language_server.configuration().clone()),
11488 workspace_folders: language_server.workspace_folders(),
11489 },
11490 );
11491
11492 cx.emit(LspStoreEvent::LanguageServerAdded(
11493 server_id,
11494 language_server.name(),
11495 Some(key.worktree_id),
11496 ));
11497
11498 let server_capabilities = language_server.capabilities();
11499 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11500 downstream_client
11501 .send(proto::StartLanguageServer {
11502 project_id: *project_id,
11503 server: Some(proto::LanguageServer {
11504 id: server_id.to_proto(),
11505 name: language_server.name().to_string(),
11506 worktree_id: Some(key.worktree_id.to_proto()),
11507 }),
11508 capabilities: serde_json::to_string(&server_capabilities)
11509 .expect("serializing server LSP capabilities"),
11510 })
11511 .log_err();
11512 }
11513 self.lsp_server_capabilities
11514 .insert(server_id, server_capabilities);
11515
11516 // Tell the language server about every open buffer in the worktree that matches the language.
11517 // Also check for buffers in worktrees that reused this server
11518 let mut worktrees_using_server = vec![key.worktree_id];
11519 if let Some(local) = self.as_local() {
11520 // Find all worktrees that have this server in their language server tree
11521 for (worktree_id, servers) in &local.lsp_tree.instances {
11522 if *worktree_id != key.worktree_id {
11523 for server_map in servers.roots.values() {
11524 if server_map
11525 .values()
11526 .any(|(node, _)| node.id() == Some(server_id))
11527 {
11528 worktrees_using_server.push(*worktree_id);
11529 }
11530 }
11531 }
11532 }
11533 }
11534
11535 let mut buffer_paths_registered = Vec::new();
11536 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11537 let mut lsp_adapters = HashMap::default();
11538 for buffer_handle in buffer_store.buffers() {
11539 let buffer = buffer_handle.read(cx);
11540 let file = match File::from_dyn(buffer.file()) {
11541 Some(file) => file,
11542 None => continue,
11543 };
11544 let language = match buffer.language() {
11545 Some(language) => language,
11546 None => continue,
11547 };
11548
11549 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11550 || !lsp_adapters
11551 .entry(language.name())
11552 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11553 .iter()
11554 .any(|a| a.name == key.name)
11555 {
11556 continue;
11557 }
11558 // didOpen
11559 let file = match file.as_local() {
11560 Some(file) => file,
11561 None => continue,
11562 };
11563
11564 let local = self.as_local_mut().unwrap();
11565
11566 let buffer_id = buffer.remote_id();
11567 if local.registered_buffers.contains_key(&buffer_id) {
11568 let versions = local
11569 .buffer_snapshots
11570 .entry(buffer_id)
11571 .or_default()
11572 .entry(server_id)
11573 .and_modify(|_| {
11574 assert!(
11575 false,
11576 "There should not be an existing snapshot for a newly inserted buffer"
11577 )
11578 })
11579 .or_insert_with(|| {
11580 vec![LspBufferSnapshot {
11581 version: 0,
11582 snapshot: buffer.text_snapshot(),
11583 }]
11584 });
11585
11586 let snapshot = versions.last().unwrap();
11587 let version = snapshot.version;
11588 let initial_snapshot = &snapshot.snapshot;
11589 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11590 language_server.register_buffer(
11591 uri,
11592 adapter.language_id(&language.name()),
11593 version,
11594 initial_snapshot.text(),
11595 );
11596 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11597 local
11598 .buffers_opened_in_servers
11599 .entry(buffer_id)
11600 .or_default()
11601 .insert(server_id);
11602 }
11603 buffer_handle.update(cx, |buffer, cx| {
11604 buffer.set_completion_triggers(
11605 server_id,
11606 language_server
11607 .capabilities()
11608 .completion_provider
11609 .as_ref()
11610 .and_then(|provider| {
11611 provider
11612 .trigger_characters
11613 .as_ref()
11614 .map(|characters| characters.iter().cloned().collect())
11615 })
11616 .unwrap_or_default(),
11617 cx,
11618 )
11619 });
11620 }
11621 });
11622
11623 for (buffer_id, abs_path) in buffer_paths_registered {
11624 cx.emit(LspStoreEvent::LanguageServerUpdate {
11625 language_server_id: server_id,
11626 name: Some(adapter.name()),
11627 message: proto::update_language_server::Variant::RegisteredForBuffer(
11628 proto::RegisteredForBuffer {
11629 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11630 buffer_id: buffer_id.to_proto(),
11631 },
11632 ),
11633 });
11634 }
11635
11636 cx.notify();
11637 }
11638
11639 pub fn language_servers_running_disk_based_diagnostics(
11640 &self,
11641 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11642 self.language_server_statuses
11643 .iter()
11644 .filter_map(|(id, status)| {
11645 if status.has_pending_diagnostic_updates {
11646 Some(*id)
11647 } else {
11648 None
11649 }
11650 })
11651 }
11652
11653 pub(crate) fn cancel_language_server_work_for_buffers(
11654 &mut self,
11655 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11656 cx: &mut Context<Self>,
11657 ) {
11658 if let Some((client, project_id)) = self.upstream_client() {
11659 let request = client.request(proto::CancelLanguageServerWork {
11660 project_id,
11661 work: Some(proto::cancel_language_server_work::Work::Buffers(
11662 proto::cancel_language_server_work::Buffers {
11663 buffer_ids: buffers
11664 .into_iter()
11665 .map(|b| b.read(cx).remote_id().to_proto())
11666 .collect(),
11667 },
11668 )),
11669 });
11670 cx.background_spawn(request).detach_and_log_err(cx);
11671 } else if let Some(local) = self.as_local() {
11672 let servers = buffers
11673 .into_iter()
11674 .flat_map(|buffer| {
11675 buffer.update(cx, |buffer, cx| {
11676 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11677 })
11678 })
11679 .collect::<HashSet<_>>();
11680 for server_id in servers {
11681 self.cancel_language_server_work(server_id, None, cx);
11682 }
11683 }
11684 }
11685
11686 pub(crate) fn cancel_language_server_work(
11687 &mut self,
11688 server_id: LanguageServerId,
11689 token_to_cancel: Option<ProgressToken>,
11690 cx: &mut Context<Self>,
11691 ) {
11692 if let Some(local) = self.as_local() {
11693 let status = self.language_server_statuses.get(&server_id);
11694 let server = local.language_servers.get(&server_id);
11695 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11696 {
11697 for (token, progress) in &status.pending_work {
11698 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11699 && token != token_to_cancel
11700 {
11701 continue;
11702 }
11703 if progress.is_cancellable {
11704 server
11705 .notify::<lsp::notification::WorkDoneProgressCancel>(
11706 WorkDoneProgressCancelParams {
11707 token: token.to_lsp(),
11708 },
11709 )
11710 .ok();
11711 }
11712 }
11713 }
11714 } else if let Some((client, project_id)) = self.upstream_client() {
11715 let request = client.request(proto::CancelLanguageServerWork {
11716 project_id,
11717 work: Some(
11718 proto::cancel_language_server_work::Work::LanguageServerWork(
11719 proto::cancel_language_server_work::LanguageServerWork {
11720 language_server_id: server_id.to_proto(),
11721 token: token_to_cancel.map(|token| token.to_proto()),
11722 },
11723 ),
11724 ),
11725 });
11726 cx.background_spawn(request).detach_and_log_err(cx);
11727 }
11728 }
11729
11730 fn register_supplementary_language_server(
11731 &mut self,
11732 id: LanguageServerId,
11733 name: LanguageServerName,
11734 server: Arc<LanguageServer>,
11735 cx: &mut Context<Self>,
11736 ) {
11737 if let Some(local) = self.as_local_mut() {
11738 local
11739 .supplementary_language_servers
11740 .insert(id, (name.clone(), server));
11741 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11742 }
11743 }
11744
11745 fn unregister_supplementary_language_server(
11746 &mut self,
11747 id: LanguageServerId,
11748 cx: &mut Context<Self>,
11749 ) {
11750 if let Some(local) = self.as_local_mut() {
11751 local.supplementary_language_servers.remove(&id);
11752 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11753 }
11754 }
11755
11756 pub(crate) fn supplementary_language_servers(
11757 &self,
11758 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11759 self.as_local().into_iter().flat_map(|local| {
11760 local
11761 .supplementary_language_servers
11762 .iter()
11763 .map(|(id, (name, _))| (*id, name.clone()))
11764 })
11765 }
11766
11767 pub fn language_server_adapter_for_id(
11768 &self,
11769 id: LanguageServerId,
11770 ) -> Option<Arc<CachedLspAdapter>> {
11771 self.as_local()
11772 .and_then(|local| local.language_servers.get(&id))
11773 .and_then(|language_server_state| match language_server_state {
11774 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11775 _ => None,
11776 })
11777 }
11778
11779 pub(super) fn update_local_worktree_language_servers(
11780 &mut self,
11781 worktree_handle: &Entity<Worktree>,
11782 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11783 cx: &mut Context<Self>,
11784 ) {
11785 if changes.is_empty() {
11786 return;
11787 }
11788
11789 let Some(local) = self.as_local() else { return };
11790
11791 local.prettier_store.update(cx, |prettier_store, cx| {
11792 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11793 });
11794
11795 let worktree_id = worktree_handle.read(cx).id();
11796 let mut language_server_ids = local
11797 .language_server_ids
11798 .iter()
11799 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11800 .collect::<Vec<_>>();
11801 language_server_ids.sort();
11802 language_server_ids.dedup();
11803
11804 // let abs_path = worktree_handle.read(cx).abs_path();
11805 for server_id in &language_server_ids {
11806 if let Some(LanguageServerState::Running { server, .. }) =
11807 local.language_servers.get(server_id)
11808 && let Some(watched_paths) = local
11809 .language_server_watched_paths
11810 .get(server_id)
11811 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11812 {
11813 let params = lsp::DidChangeWatchedFilesParams {
11814 changes: changes
11815 .iter()
11816 .filter_map(|(path, _, change)| {
11817 if !watched_paths.is_match(path.as_std_path()) {
11818 return None;
11819 }
11820 let typ = match change {
11821 PathChange::Loaded => return None,
11822 PathChange::Added => lsp::FileChangeType::CREATED,
11823 PathChange::Removed => lsp::FileChangeType::DELETED,
11824 PathChange::Updated => lsp::FileChangeType::CHANGED,
11825 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11826 };
11827 let uri = lsp::Uri::from_file_path(
11828 worktree_handle.read(cx).absolutize(&path),
11829 )
11830 .ok()?;
11831 Some(lsp::FileEvent { uri, typ })
11832 })
11833 .collect(),
11834 };
11835 if !params.changes.is_empty() {
11836 server
11837 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11838 .ok();
11839 }
11840 }
11841 }
11842 for (path, _, _) in changes {
11843 if let Some(file_name) = path.file_name()
11844 && local.watched_manifest_filenames.contains(file_name)
11845 {
11846 self.request_workspace_config_refresh();
11847 break;
11848 }
11849 }
11850 }
11851
11852 pub fn wait_for_remote_buffer(
11853 &mut self,
11854 id: BufferId,
11855 cx: &mut Context<Self>,
11856 ) -> Task<Result<Entity<Buffer>>> {
11857 self.buffer_store.update(cx, |buffer_store, cx| {
11858 buffer_store.wait_for_remote_buffer(id, cx)
11859 })
11860 }
11861
11862 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11863 let mut result = proto::Symbol {
11864 language_server_name: symbol.language_server_name.0.to_string(),
11865 source_worktree_id: symbol.source_worktree_id.to_proto(),
11866 language_server_id: symbol.source_language_server_id.to_proto(),
11867 name: symbol.name.clone(),
11868 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11869 start: Some(proto::PointUtf16 {
11870 row: symbol.range.start.0.row,
11871 column: symbol.range.start.0.column,
11872 }),
11873 end: Some(proto::PointUtf16 {
11874 row: symbol.range.end.0.row,
11875 column: symbol.range.end.0.column,
11876 }),
11877 worktree_id: Default::default(),
11878 path: Default::default(),
11879 signature: Default::default(),
11880 };
11881 match &symbol.path {
11882 SymbolLocation::InProject(path) => {
11883 result.worktree_id = path.worktree_id.to_proto();
11884 result.path = path.path.to_proto();
11885 }
11886 SymbolLocation::OutsideProject {
11887 abs_path,
11888 signature,
11889 } => {
11890 result.path = abs_path.to_string_lossy().into_owned();
11891 result.signature = signature.to_vec();
11892 }
11893 }
11894 result
11895 }
11896
11897 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11898 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11899 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11900 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11901
11902 let path = if serialized_symbol.signature.is_empty() {
11903 SymbolLocation::InProject(ProjectPath {
11904 worktree_id,
11905 path: RelPath::from_proto(&serialized_symbol.path)
11906 .context("invalid symbol path")?,
11907 })
11908 } else {
11909 SymbolLocation::OutsideProject {
11910 abs_path: Path::new(&serialized_symbol.path).into(),
11911 signature: serialized_symbol
11912 .signature
11913 .try_into()
11914 .map_err(|_| anyhow!("invalid signature"))?,
11915 }
11916 };
11917
11918 let start = serialized_symbol.start.context("invalid start")?;
11919 let end = serialized_symbol.end.context("invalid end")?;
11920 Ok(CoreSymbol {
11921 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11922 source_worktree_id,
11923 source_language_server_id: LanguageServerId::from_proto(
11924 serialized_symbol.language_server_id,
11925 ),
11926 path,
11927 name: serialized_symbol.name,
11928 range: Unclipped(PointUtf16::new(start.row, start.column))
11929 ..Unclipped(PointUtf16::new(end.row, end.column)),
11930 kind,
11931 })
11932 }
11933
11934 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11935 let mut serialized_completion = proto::Completion {
11936 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11937 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11938 new_text: completion.new_text.clone(),
11939 ..proto::Completion::default()
11940 };
11941 match &completion.source {
11942 CompletionSource::Lsp {
11943 insert_range,
11944 server_id,
11945 lsp_completion,
11946 lsp_defaults,
11947 resolved,
11948 } => {
11949 let (old_insert_start, old_insert_end) = insert_range
11950 .as_ref()
11951 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11952 .unzip();
11953
11954 serialized_completion.old_insert_start = old_insert_start;
11955 serialized_completion.old_insert_end = old_insert_end;
11956 serialized_completion.source = proto::completion::Source::Lsp as i32;
11957 serialized_completion.server_id = server_id.0 as u64;
11958 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11959 serialized_completion.lsp_defaults = lsp_defaults
11960 .as_deref()
11961 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11962 serialized_completion.resolved = *resolved;
11963 }
11964 CompletionSource::BufferWord {
11965 word_range,
11966 resolved,
11967 } => {
11968 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11969 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11970 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11971 serialized_completion.resolved = *resolved;
11972 }
11973 CompletionSource::Custom => {
11974 serialized_completion.source = proto::completion::Source::Custom as i32;
11975 serialized_completion.resolved = true;
11976 }
11977 CompletionSource::Dap { sort_text } => {
11978 serialized_completion.source = proto::completion::Source::Dap as i32;
11979 serialized_completion.sort_text = Some(sort_text.clone());
11980 }
11981 }
11982
11983 serialized_completion
11984 }
11985
11986 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11987 let old_replace_start = completion
11988 .old_replace_start
11989 .and_then(deserialize_anchor)
11990 .context("invalid old start")?;
11991 let old_replace_end = completion
11992 .old_replace_end
11993 .and_then(deserialize_anchor)
11994 .context("invalid old end")?;
11995 let insert_range = {
11996 match completion.old_insert_start.zip(completion.old_insert_end) {
11997 Some((start, end)) => {
11998 let start = deserialize_anchor(start).context("invalid insert old start")?;
11999 let end = deserialize_anchor(end).context("invalid insert old end")?;
12000 Some(start..end)
12001 }
12002 None => None,
12003 }
12004 };
12005 Ok(CoreCompletion {
12006 replace_range: old_replace_start..old_replace_end,
12007 new_text: completion.new_text,
12008 source: match proto::completion::Source::from_i32(completion.source) {
12009 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12010 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12011 insert_range,
12012 server_id: LanguageServerId::from_proto(completion.server_id),
12013 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12014 lsp_defaults: completion
12015 .lsp_defaults
12016 .as_deref()
12017 .map(serde_json::from_slice)
12018 .transpose()?,
12019 resolved: completion.resolved,
12020 },
12021 Some(proto::completion::Source::BufferWord) => {
12022 let word_range = completion
12023 .buffer_word_start
12024 .and_then(deserialize_anchor)
12025 .context("invalid buffer word start")?
12026 ..completion
12027 .buffer_word_end
12028 .and_then(deserialize_anchor)
12029 .context("invalid buffer word end")?;
12030 CompletionSource::BufferWord {
12031 word_range,
12032 resolved: completion.resolved,
12033 }
12034 }
12035 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12036 sort_text: completion
12037 .sort_text
12038 .context("expected sort text to exist")?,
12039 },
12040 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12041 },
12042 })
12043 }
12044
12045 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12046 let (kind, lsp_action) = match &action.lsp_action {
12047 LspAction::Action(code_action) => (
12048 proto::code_action::Kind::Action as i32,
12049 serde_json::to_vec(code_action).unwrap(),
12050 ),
12051 LspAction::Command(command) => (
12052 proto::code_action::Kind::Command as i32,
12053 serde_json::to_vec(command).unwrap(),
12054 ),
12055 LspAction::CodeLens(code_lens) => (
12056 proto::code_action::Kind::CodeLens as i32,
12057 serde_json::to_vec(code_lens).unwrap(),
12058 ),
12059 };
12060
12061 proto::CodeAction {
12062 server_id: action.server_id.0 as u64,
12063 start: Some(serialize_anchor(&action.range.start)),
12064 end: Some(serialize_anchor(&action.range.end)),
12065 lsp_action,
12066 kind,
12067 resolved: action.resolved,
12068 }
12069 }
12070
12071 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12072 let start = action
12073 .start
12074 .and_then(deserialize_anchor)
12075 .context("invalid start")?;
12076 let end = action
12077 .end
12078 .and_then(deserialize_anchor)
12079 .context("invalid end")?;
12080 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12081 Some(proto::code_action::Kind::Action) => {
12082 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12083 }
12084 Some(proto::code_action::Kind::Command) => {
12085 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12086 }
12087 Some(proto::code_action::Kind::CodeLens) => {
12088 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12089 }
12090 None => anyhow::bail!("Unknown action kind {}", action.kind),
12091 };
12092 Ok(CodeAction {
12093 server_id: LanguageServerId(action.server_id as usize),
12094 range: start..end,
12095 resolved: action.resolved,
12096 lsp_action,
12097 })
12098 }
12099
12100 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12101 match &formatting_result {
12102 Ok(_) => self.last_formatting_failure = None,
12103 Err(error) => {
12104 let error_string = format!("{error:#}");
12105 log::error!("Formatting failed: {error_string}");
12106 self.last_formatting_failure
12107 .replace(error_string.lines().join(" "));
12108 }
12109 }
12110 }
12111
12112 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12113 self.lsp_server_capabilities.remove(&for_server);
12114 for lsp_data in self.lsp_data.values_mut() {
12115 lsp_data.remove_server_data(for_server);
12116 }
12117 if let Some(local) = self.as_local_mut() {
12118 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12119 local
12120 .workspace_pull_diagnostics_result_ids
12121 .remove(&for_server);
12122 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12123 buffer_servers.remove(&for_server);
12124 }
12125 }
12126 }
12127
12128 pub fn result_id_for_buffer_pull(
12129 &self,
12130 server_id: LanguageServerId,
12131 buffer_id: BufferId,
12132 registration_id: &Option<SharedString>,
12133 cx: &App,
12134 ) -> Option<SharedString> {
12135 let abs_path = self
12136 .buffer_store
12137 .read(cx)
12138 .get(buffer_id)
12139 .and_then(|b| File::from_dyn(b.read(cx).file()))
12140 .map(|f| f.abs_path(cx))?;
12141 self.as_local()?
12142 .buffer_pull_diagnostics_result_ids
12143 .get(&server_id)?
12144 .get(registration_id)?
12145 .get(&abs_path)?
12146 .clone()
12147 }
12148
12149 /// Gets all result_ids for a workspace diagnostics pull request.
12150 /// 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.
12151 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12152 pub fn result_ids_for_workspace_refresh(
12153 &self,
12154 server_id: LanguageServerId,
12155 registration_id: &Option<SharedString>,
12156 ) -> HashMap<PathBuf, SharedString> {
12157 let Some(local) = self.as_local() else {
12158 return HashMap::default();
12159 };
12160 local
12161 .workspace_pull_diagnostics_result_ids
12162 .get(&server_id)
12163 .into_iter()
12164 .filter_map(|diagnostics| diagnostics.get(registration_id))
12165 .flatten()
12166 .filter_map(|(abs_path, result_id)| {
12167 let result_id = local
12168 .buffer_pull_diagnostics_result_ids
12169 .get(&server_id)
12170 .and_then(|buffer_ids_result_ids| {
12171 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12172 })
12173 .cloned()
12174 .flatten()
12175 .or_else(|| result_id.clone())?;
12176 Some((abs_path.clone(), result_id))
12177 })
12178 .collect()
12179 }
12180
12181 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12182 if let Some(LanguageServerState::Running {
12183 workspace_diagnostics_refresh_tasks,
12184 ..
12185 }) = self
12186 .as_local_mut()
12187 .and_then(|local| local.language_servers.get_mut(&server_id))
12188 {
12189 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12190 diagnostics.refresh_tx.try_send(()).ok();
12191 }
12192 }
12193 }
12194
12195 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12196 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12197 return;
12198 };
12199 let Some(local) = self.as_local_mut() else {
12200 return;
12201 };
12202
12203 for server_id in buffer.update(cx, |buffer, cx| {
12204 local.language_server_ids_for_buffer(buffer, cx)
12205 }) {
12206 if let Some(LanguageServerState::Running {
12207 workspace_diagnostics_refresh_tasks,
12208 ..
12209 }) = local.language_servers.get_mut(&server_id)
12210 {
12211 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12212 diagnostics.refresh_tx.try_send(()).ok();
12213 }
12214 }
12215 }
12216 }
12217
12218 fn apply_workspace_diagnostic_report(
12219 &mut self,
12220 server_id: LanguageServerId,
12221 report: lsp::WorkspaceDiagnosticReportResult,
12222 registration_id: Option<SharedString>,
12223 cx: &mut Context<Self>,
12224 ) {
12225 let mut workspace_diagnostics =
12226 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12227 report,
12228 server_id,
12229 registration_id,
12230 );
12231 workspace_diagnostics.retain(|d| match &d.diagnostics {
12232 LspPullDiagnostics::Response {
12233 server_id,
12234 registration_id,
12235 ..
12236 } => self.diagnostic_registration_exists(*server_id, registration_id),
12237 LspPullDiagnostics::Default => false,
12238 });
12239 let mut unchanged_buffers = HashMap::default();
12240 let workspace_diagnostics_updates = workspace_diagnostics
12241 .into_iter()
12242 .filter_map(
12243 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12244 LspPullDiagnostics::Response {
12245 server_id,
12246 uri,
12247 diagnostics,
12248 registration_id,
12249 } => Some((
12250 server_id,
12251 uri,
12252 diagnostics,
12253 workspace_diagnostics.version,
12254 registration_id,
12255 )),
12256 LspPullDiagnostics::Default => None,
12257 },
12258 )
12259 .fold(
12260 HashMap::default(),
12261 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12262 let (result_id, diagnostics) = match diagnostics {
12263 PulledDiagnostics::Unchanged { result_id } => {
12264 unchanged_buffers
12265 .entry(new_registration_id.clone())
12266 .or_insert_with(HashSet::default)
12267 .insert(uri.clone());
12268 (Some(result_id), Vec::new())
12269 }
12270 PulledDiagnostics::Changed {
12271 result_id,
12272 diagnostics,
12273 } => (result_id, diagnostics),
12274 };
12275 let disk_based_sources = Cow::Owned(
12276 self.language_server_adapter_for_id(server_id)
12277 .as_ref()
12278 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12279 .unwrap_or(&[])
12280 .to_vec(),
12281 );
12282
12283 let Some(abs_path) = uri.to_file_path().ok() else {
12284 return acc;
12285 };
12286 let Some((worktree, relative_path)) =
12287 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12288 else {
12289 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12290 return acc;
12291 };
12292 let worktree_id = worktree.read(cx).id();
12293 let project_path = ProjectPath {
12294 worktree_id,
12295 path: relative_path,
12296 };
12297 if let Some(local_lsp_store) = self.as_local_mut() {
12298 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12299 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12300 }
12301 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12302 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12303 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12304 acc.entry(server_id)
12305 .or_insert_with(HashMap::default)
12306 .entry(new_registration_id.clone())
12307 .or_insert_with(Vec::new)
12308 .push(DocumentDiagnosticsUpdate {
12309 server_id,
12310 diagnostics: lsp::PublishDiagnosticsParams {
12311 uri,
12312 diagnostics,
12313 version,
12314 },
12315 result_id,
12316 disk_based_sources,
12317 registration_id: new_registration_id,
12318 });
12319 }
12320 acc
12321 },
12322 );
12323
12324 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12325 for (registration_id, diagnostic_updates) in diagnostic_updates {
12326 self.merge_lsp_diagnostics(
12327 DiagnosticSourceKind::Pulled,
12328 diagnostic_updates,
12329 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12330 DiagnosticSourceKind::Pulled => {
12331 old_diagnostic.registration_id != registration_id
12332 || unchanged_buffers
12333 .get(&old_diagnostic.registration_id)
12334 .is_some_and(|unchanged_buffers| {
12335 unchanged_buffers.contains(&document_uri)
12336 })
12337 }
12338 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12339 },
12340 cx,
12341 )
12342 .log_err();
12343 }
12344 }
12345 }
12346
12347 fn register_server_capabilities(
12348 &mut self,
12349 server_id: LanguageServerId,
12350 params: lsp::RegistrationParams,
12351 cx: &mut Context<Self>,
12352 ) -> anyhow::Result<()> {
12353 let server = self
12354 .language_server_for_id(server_id)
12355 .with_context(|| format!("no server {server_id} found"))?;
12356 for reg in params.registrations {
12357 match reg.method.as_str() {
12358 "workspace/didChangeWatchedFiles" => {
12359 if let Some(options) = reg.register_options {
12360 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12361 let caps = serde_json::from_value(options)?;
12362 local_lsp_store
12363 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12364 true
12365 } else {
12366 false
12367 };
12368 if notify {
12369 notify_server_capabilities_updated(&server, cx);
12370 }
12371 }
12372 }
12373 "workspace/didChangeConfiguration" => {
12374 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12375 }
12376 "workspace/didChangeWorkspaceFolders" => {
12377 // In this case register options is an empty object, we can ignore it
12378 let caps = lsp::WorkspaceFoldersServerCapabilities {
12379 supported: Some(true),
12380 change_notifications: Some(OneOf::Right(reg.id)),
12381 };
12382 server.update_capabilities(|capabilities| {
12383 capabilities
12384 .workspace
12385 .get_or_insert_default()
12386 .workspace_folders = Some(caps);
12387 });
12388 notify_server_capabilities_updated(&server, cx);
12389 }
12390 "workspace/symbol" => {
12391 let options = parse_register_capabilities(reg)?;
12392 server.update_capabilities(|capabilities| {
12393 capabilities.workspace_symbol_provider = Some(options);
12394 });
12395 notify_server_capabilities_updated(&server, cx);
12396 }
12397 "workspace/fileOperations" => {
12398 if let Some(options) = reg.register_options {
12399 let caps = serde_json::from_value(options)?;
12400 server.update_capabilities(|capabilities| {
12401 capabilities
12402 .workspace
12403 .get_or_insert_default()
12404 .file_operations = Some(caps);
12405 });
12406 notify_server_capabilities_updated(&server, cx);
12407 }
12408 }
12409 "workspace/executeCommand" => {
12410 if let Some(options) = reg.register_options {
12411 let options = serde_json::from_value(options)?;
12412 server.update_capabilities(|capabilities| {
12413 capabilities.execute_command_provider = Some(options);
12414 });
12415 notify_server_capabilities_updated(&server, cx);
12416 }
12417 }
12418 "textDocument/rangeFormatting" => {
12419 let options = parse_register_capabilities(reg)?;
12420 server.update_capabilities(|capabilities| {
12421 capabilities.document_range_formatting_provider = Some(options);
12422 });
12423 notify_server_capabilities_updated(&server, cx);
12424 }
12425 "textDocument/onTypeFormatting" => {
12426 if let Some(options) = reg
12427 .register_options
12428 .map(serde_json::from_value)
12429 .transpose()?
12430 {
12431 server.update_capabilities(|capabilities| {
12432 capabilities.document_on_type_formatting_provider = Some(options);
12433 });
12434 notify_server_capabilities_updated(&server, cx);
12435 }
12436 }
12437 "textDocument/formatting" => {
12438 let options = parse_register_capabilities(reg)?;
12439 server.update_capabilities(|capabilities| {
12440 capabilities.document_formatting_provider = Some(options);
12441 });
12442 notify_server_capabilities_updated(&server, cx);
12443 }
12444 "textDocument/rename" => {
12445 let options = parse_register_capabilities(reg)?;
12446 server.update_capabilities(|capabilities| {
12447 capabilities.rename_provider = Some(options);
12448 });
12449 notify_server_capabilities_updated(&server, cx);
12450 }
12451 "textDocument/inlayHint" => {
12452 let options = parse_register_capabilities(reg)?;
12453 server.update_capabilities(|capabilities| {
12454 capabilities.inlay_hint_provider = Some(options);
12455 });
12456 notify_server_capabilities_updated(&server, cx);
12457 }
12458 "textDocument/documentSymbol" => {
12459 let options = parse_register_capabilities(reg)?;
12460 server.update_capabilities(|capabilities| {
12461 capabilities.document_symbol_provider = Some(options);
12462 });
12463 notify_server_capabilities_updated(&server, cx);
12464 }
12465 "textDocument/codeAction" => {
12466 let options = parse_register_capabilities(reg)?;
12467 let provider = match options {
12468 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12469 OneOf::Right(caps) => caps,
12470 };
12471 server.update_capabilities(|capabilities| {
12472 capabilities.code_action_provider = Some(provider);
12473 });
12474 notify_server_capabilities_updated(&server, cx);
12475 }
12476 "textDocument/definition" => {
12477 let options = parse_register_capabilities(reg)?;
12478 server.update_capabilities(|capabilities| {
12479 capabilities.definition_provider = Some(options);
12480 });
12481 notify_server_capabilities_updated(&server, cx);
12482 }
12483 "textDocument/completion" => {
12484 if let Some(caps) = reg
12485 .register_options
12486 .map(serde_json::from_value::<CompletionOptions>)
12487 .transpose()?
12488 {
12489 server.update_capabilities(|capabilities| {
12490 capabilities.completion_provider = Some(caps.clone());
12491 });
12492
12493 if let Some(local) = self.as_local() {
12494 let mut buffers_with_language_server = Vec::new();
12495 for handle in self.buffer_store.read(cx).buffers() {
12496 let buffer_id = handle.read(cx).remote_id();
12497 if local
12498 .buffers_opened_in_servers
12499 .get(&buffer_id)
12500 .filter(|s| s.contains(&server_id))
12501 .is_some()
12502 {
12503 buffers_with_language_server.push(handle);
12504 }
12505 }
12506 let triggers = caps
12507 .trigger_characters
12508 .unwrap_or_default()
12509 .into_iter()
12510 .collect::<BTreeSet<_>>();
12511 for handle in buffers_with_language_server {
12512 let triggers = triggers.clone();
12513 let _ = handle.update(cx, move |buffer, cx| {
12514 buffer.set_completion_triggers(server_id, triggers, cx);
12515 });
12516 }
12517 }
12518 notify_server_capabilities_updated(&server, cx);
12519 }
12520 }
12521 "textDocument/hover" => {
12522 let options = parse_register_capabilities(reg)?;
12523 let provider = match options {
12524 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12525 OneOf::Right(caps) => caps,
12526 };
12527 server.update_capabilities(|capabilities| {
12528 capabilities.hover_provider = Some(provider);
12529 });
12530 notify_server_capabilities_updated(&server, cx);
12531 }
12532 "textDocument/signatureHelp" => {
12533 if let Some(caps) = reg
12534 .register_options
12535 .map(serde_json::from_value)
12536 .transpose()?
12537 {
12538 server.update_capabilities(|capabilities| {
12539 capabilities.signature_help_provider = Some(caps);
12540 });
12541 notify_server_capabilities_updated(&server, cx);
12542 }
12543 }
12544 "textDocument/didChange" => {
12545 if let Some(sync_kind) = reg
12546 .register_options
12547 .and_then(|opts| opts.get("syncKind").cloned())
12548 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12549 .transpose()?
12550 {
12551 server.update_capabilities(|capabilities| {
12552 let mut sync_options =
12553 Self::take_text_document_sync_options(capabilities);
12554 sync_options.change = Some(sync_kind);
12555 capabilities.text_document_sync =
12556 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12557 });
12558 notify_server_capabilities_updated(&server, cx);
12559 }
12560 }
12561 "textDocument/didSave" => {
12562 if let Some(include_text) = reg
12563 .register_options
12564 .map(|opts| {
12565 let transpose = opts
12566 .get("includeText")
12567 .cloned()
12568 .map(serde_json::from_value::<Option<bool>>)
12569 .transpose();
12570 match transpose {
12571 Ok(value) => Ok(value.flatten()),
12572 Err(e) => Err(e),
12573 }
12574 })
12575 .transpose()?
12576 {
12577 server.update_capabilities(|capabilities| {
12578 let mut sync_options =
12579 Self::take_text_document_sync_options(capabilities);
12580 sync_options.save =
12581 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12582 include_text,
12583 }));
12584 capabilities.text_document_sync =
12585 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12586 });
12587 notify_server_capabilities_updated(&server, cx);
12588 }
12589 }
12590 "textDocument/codeLens" => {
12591 if let Some(caps) = reg
12592 .register_options
12593 .map(serde_json::from_value)
12594 .transpose()?
12595 {
12596 server.update_capabilities(|capabilities| {
12597 capabilities.code_lens_provider = Some(caps);
12598 });
12599 notify_server_capabilities_updated(&server, cx);
12600 }
12601 }
12602 "textDocument/diagnostic" => {
12603 if let Some(caps) = reg
12604 .register_options
12605 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12606 .transpose()?
12607 {
12608 let local = self
12609 .as_local_mut()
12610 .context("Expected LSP Store to be local")?;
12611 let state = local
12612 .language_servers
12613 .get_mut(&server_id)
12614 .context("Could not obtain Language Servers state")?;
12615 local
12616 .language_server_dynamic_registrations
12617 .entry(server_id)
12618 .or_default()
12619 .diagnostics
12620 .insert(Some(reg.id.clone()), caps.clone());
12621
12622 let supports_workspace_diagnostics =
12623 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12624 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12625 diagnostic_options.workspace_diagnostics
12626 }
12627 DiagnosticServerCapabilities::RegistrationOptions(
12628 diagnostic_registration_options,
12629 ) => {
12630 diagnostic_registration_options
12631 .diagnostic_options
12632 .workspace_diagnostics
12633 }
12634 };
12635
12636 if supports_workspace_diagnostics(&caps) {
12637 if let LanguageServerState::Running {
12638 workspace_diagnostics_refresh_tasks,
12639 ..
12640 } = state
12641 && let Some(task) = lsp_workspace_diagnostics_refresh(
12642 Some(reg.id.clone()),
12643 caps.clone(),
12644 server.clone(),
12645 cx,
12646 )
12647 {
12648 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12649 }
12650 }
12651
12652 server.update_capabilities(|capabilities| {
12653 capabilities.diagnostic_provider = Some(caps);
12654 });
12655
12656 notify_server_capabilities_updated(&server, cx);
12657
12658 let buffers_to_pull: Vec<_> = self
12659 .as_local()
12660 .into_iter()
12661 .flat_map(|local| {
12662 self.buffer_store.read(cx).buffers().filter(|buffer| {
12663 let buffer_id = buffer.read(cx).remote_id();
12664 local
12665 .buffers_opened_in_servers
12666 .get(&buffer_id)
12667 .is_some_and(|servers| servers.contains(&server_id))
12668 })
12669 })
12670 .collect();
12671 for buffer in buffers_to_pull {
12672 self.pull_diagnostics_for_buffer(buffer, cx).detach();
12673 }
12674 }
12675 }
12676 "textDocument/documentColor" => {
12677 let options = parse_register_capabilities(reg)?;
12678 let provider = match options {
12679 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12680 OneOf::Right(caps) => caps,
12681 };
12682 server.update_capabilities(|capabilities| {
12683 capabilities.color_provider = Some(provider);
12684 });
12685 notify_server_capabilities_updated(&server, cx);
12686 }
12687 _ => log::warn!("unhandled capability registration: {reg:?}"),
12688 }
12689 }
12690
12691 Ok(())
12692 }
12693
12694 fn unregister_server_capabilities(
12695 &mut self,
12696 server_id: LanguageServerId,
12697 params: lsp::UnregistrationParams,
12698 cx: &mut Context<Self>,
12699 ) -> anyhow::Result<()> {
12700 let server = self
12701 .language_server_for_id(server_id)
12702 .with_context(|| format!("no server {server_id} found"))?;
12703 for unreg in params.unregisterations.iter() {
12704 match unreg.method.as_str() {
12705 "workspace/didChangeWatchedFiles" => {
12706 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12707 local_lsp_store
12708 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12709 true
12710 } else {
12711 false
12712 };
12713 if notify {
12714 notify_server_capabilities_updated(&server, cx);
12715 }
12716 }
12717 "workspace/didChangeConfiguration" => {
12718 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12719 }
12720 "workspace/didChangeWorkspaceFolders" => {
12721 server.update_capabilities(|capabilities| {
12722 capabilities
12723 .workspace
12724 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12725 workspace_folders: None,
12726 file_operations: None,
12727 })
12728 .workspace_folders = None;
12729 });
12730 notify_server_capabilities_updated(&server, cx);
12731 }
12732 "workspace/symbol" => {
12733 server.update_capabilities(|capabilities| {
12734 capabilities.workspace_symbol_provider = None
12735 });
12736 notify_server_capabilities_updated(&server, cx);
12737 }
12738 "workspace/fileOperations" => {
12739 server.update_capabilities(|capabilities| {
12740 capabilities
12741 .workspace
12742 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12743 workspace_folders: None,
12744 file_operations: None,
12745 })
12746 .file_operations = None;
12747 });
12748 notify_server_capabilities_updated(&server, cx);
12749 }
12750 "workspace/executeCommand" => {
12751 server.update_capabilities(|capabilities| {
12752 capabilities.execute_command_provider = None;
12753 });
12754 notify_server_capabilities_updated(&server, cx);
12755 }
12756 "textDocument/rangeFormatting" => {
12757 server.update_capabilities(|capabilities| {
12758 capabilities.document_range_formatting_provider = None
12759 });
12760 notify_server_capabilities_updated(&server, cx);
12761 }
12762 "textDocument/onTypeFormatting" => {
12763 server.update_capabilities(|capabilities| {
12764 capabilities.document_on_type_formatting_provider = None;
12765 });
12766 notify_server_capabilities_updated(&server, cx);
12767 }
12768 "textDocument/formatting" => {
12769 server.update_capabilities(|capabilities| {
12770 capabilities.document_formatting_provider = None;
12771 });
12772 notify_server_capabilities_updated(&server, cx);
12773 }
12774 "textDocument/rename" => {
12775 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12776 notify_server_capabilities_updated(&server, cx);
12777 }
12778 "textDocument/codeAction" => {
12779 server.update_capabilities(|capabilities| {
12780 capabilities.code_action_provider = None;
12781 });
12782 notify_server_capabilities_updated(&server, cx);
12783 }
12784 "textDocument/definition" => {
12785 server.update_capabilities(|capabilities| {
12786 capabilities.definition_provider = None;
12787 });
12788 notify_server_capabilities_updated(&server, cx);
12789 }
12790 "textDocument/completion" => {
12791 server.update_capabilities(|capabilities| {
12792 capabilities.completion_provider = None;
12793 });
12794 notify_server_capabilities_updated(&server, cx);
12795 }
12796 "textDocument/hover" => {
12797 server.update_capabilities(|capabilities| {
12798 capabilities.hover_provider = None;
12799 });
12800 notify_server_capabilities_updated(&server, cx);
12801 }
12802 "textDocument/signatureHelp" => {
12803 server.update_capabilities(|capabilities| {
12804 capabilities.signature_help_provider = None;
12805 });
12806 notify_server_capabilities_updated(&server, cx);
12807 }
12808 "textDocument/didChange" => {
12809 server.update_capabilities(|capabilities| {
12810 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12811 sync_options.change = None;
12812 capabilities.text_document_sync =
12813 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12814 });
12815 notify_server_capabilities_updated(&server, cx);
12816 }
12817 "textDocument/didSave" => {
12818 server.update_capabilities(|capabilities| {
12819 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12820 sync_options.save = None;
12821 capabilities.text_document_sync =
12822 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12823 });
12824 notify_server_capabilities_updated(&server, cx);
12825 }
12826 "textDocument/codeLens" => {
12827 server.update_capabilities(|capabilities| {
12828 capabilities.code_lens_provider = None;
12829 });
12830 notify_server_capabilities_updated(&server, cx);
12831 }
12832 "textDocument/diagnostic" => {
12833 let local = self
12834 .as_local_mut()
12835 .context("Expected LSP Store to be local")?;
12836
12837 let state = local
12838 .language_servers
12839 .get_mut(&server_id)
12840 .context("Could not obtain Language Servers state")?;
12841 let registrations = local
12842 .language_server_dynamic_registrations
12843 .get_mut(&server_id)
12844 .with_context(|| {
12845 format!("Expected dynamic registration to exist for server {server_id}")
12846 })?;
12847 registrations.diagnostics
12848 .remove(&Some(unreg.id.clone()))
12849 .with_context(|| format!(
12850 "Attempted to unregister non-existent diagnostic registration with ID {}",
12851 unreg.id)
12852 )?;
12853 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12854
12855 if let LanguageServerState::Running {
12856 workspace_diagnostics_refresh_tasks,
12857 ..
12858 } = state
12859 {
12860 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12861 }
12862
12863 self.clear_unregistered_diagnostics(
12864 server_id,
12865 SharedString::from(unreg.id.clone()),
12866 cx,
12867 )?;
12868
12869 if removed_last_diagnostic_provider {
12870 server.update_capabilities(|capabilities| {
12871 debug_assert!(capabilities.diagnostic_provider.is_some());
12872 capabilities.diagnostic_provider = None;
12873 });
12874 }
12875
12876 notify_server_capabilities_updated(&server, cx);
12877 }
12878 "textDocument/documentColor" => {
12879 server.update_capabilities(|capabilities| {
12880 capabilities.color_provider = None;
12881 });
12882 notify_server_capabilities_updated(&server, cx);
12883 }
12884 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12885 }
12886 }
12887
12888 Ok(())
12889 }
12890
12891 fn clear_unregistered_diagnostics(
12892 &mut self,
12893 server_id: LanguageServerId,
12894 cleared_registration_id: SharedString,
12895 cx: &mut Context<Self>,
12896 ) -> anyhow::Result<()> {
12897 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12898
12899 self.buffer_store.update(cx, |buffer_store, cx| {
12900 for buffer_handle in buffer_store.buffers() {
12901 let buffer = buffer_handle.read(cx);
12902 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12903 let Some(abs_path) = abs_path else {
12904 continue;
12905 };
12906 affected_abs_paths.insert(abs_path);
12907 }
12908 });
12909
12910 let local = self.as_local().context("Expected LSP Store to be local")?;
12911 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12912 let Some(worktree) = self
12913 .worktree_store
12914 .read(cx)
12915 .worktree_for_id(*worktree_id, cx)
12916 else {
12917 continue;
12918 };
12919
12920 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12921 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12922 let has_matching_registration =
12923 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12924 entry.diagnostic.registration_id.as_ref()
12925 == Some(&cleared_registration_id)
12926 });
12927 if has_matching_registration {
12928 let abs_path = worktree.read(cx).absolutize(rel_path);
12929 affected_abs_paths.insert(abs_path);
12930 }
12931 }
12932 }
12933 }
12934
12935 if affected_abs_paths.is_empty() {
12936 return Ok(());
12937 }
12938
12939 // Send a fake diagnostic update which clears the state for the registration ID
12940 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12941 affected_abs_paths
12942 .into_iter()
12943 .map(|abs_path| DocumentDiagnosticsUpdate {
12944 diagnostics: DocumentDiagnostics {
12945 diagnostics: Vec::new(),
12946 document_abs_path: abs_path,
12947 version: None,
12948 },
12949 result_id: None,
12950 registration_id: Some(cleared_registration_id.clone()),
12951 server_id,
12952 disk_based_sources: Cow::Borrowed(&[]),
12953 })
12954 .collect();
12955
12956 let merge_registration_id = cleared_registration_id.clone();
12957 self.merge_diagnostic_entries(
12958 clears,
12959 move |_, diagnostic, _| {
12960 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12961 diagnostic.registration_id != Some(merge_registration_id.clone())
12962 } else {
12963 true
12964 }
12965 },
12966 cx,
12967 )?;
12968
12969 Ok(())
12970 }
12971
12972 async fn deduplicate_range_based_lsp_requests<T>(
12973 lsp_store: &Entity<Self>,
12974 server_id: Option<LanguageServerId>,
12975 lsp_request_id: LspRequestId,
12976 proto_request: &T::ProtoRequest,
12977 range: Range<Anchor>,
12978 cx: &mut AsyncApp,
12979 ) -> Result<()>
12980 where
12981 T: LspCommand,
12982 T::ProtoRequest: proto::LspRequestMessage,
12983 {
12984 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12985 let version = deserialize_version(proto_request.buffer_version());
12986 let buffer = lsp_store.update(cx, |this, cx| {
12987 this.buffer_store.read(cx).get_existing(buffer_id)
12988 })??;
12989 buffer
12990 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12991 .await?;
12992 lsp_store.update(cx, |lsp_store, cx| {
12993 let buffer_snapshot = buffer.read(cx).snapshot();
12994 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12995 let chunks_queried_for = lsp_data
12996 .inlay_hints
12997 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12998 .collect::<Vec<_>>();
12999 match chunks_queried_for.as_slice() {
13000 &[chunk] => {
13001 let key = LspKey {
13002 request_type: TypeId::of::<T>(),
13003 server_queried: server_id,
13004 };
13005 let previous_request = lsp_data
13006 .chunk_lsp_requests
13007 .entry(key)
13008 .or_default()
13009 .insert(chunk, lsp_request_id);
13010 if let Some((previous_request, running_requests)) =
13011 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13012 {
13013 running_requests.remove(&previous_request);
13014 }
13015 }
13016 _ambiguous_chunks => {
13017 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13018 // there, a buffer version-based check will be performed and outdated requests discarded.
13019 }
13020 }
13021 anyhow::Ok(())
13022 })??;
13023
13024 Ok(())
13025 }
13026
13027 async fn query_lsp_locally<T>(
13028 lsp_store: Entity<Self>,
13029 for_server_id: Option<LanguageServerId>,
13030 sender_id: proto::PeerId,
13031 lsp_request_id: LspRequestId,
13032 proto_request: T::ProtoRequest,
13033 position: Option<Anchor>,
13034 cx: &mut AsyncApp,
13035 ) -> Result<()>
13036 where
13037 T: LspCommand + Clone,
13038 T::ProtoRequest: proto::LspRequestMessage,
13039 <T::ProtoRequest as proto::RequestMessage>::Response:
13040 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13041 {
13042 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13043 let version = deserialize_version(proto_request.buffer_version());
13044 let buffer = lsp_store.update(cx, |this, cx| {
13045 this.buffer_store.read(cx).get_existing(buffer_id)
13046 })??;
13047 buffer
13048 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
13049 .await?;
13050 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
13051 let request =
13052 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13053 let key = LspKey {
13054 request_type: TypeId::of::<T>(),
13055 server_queried: for_server_id,
13056 };
13057 lsp_store.update(cx, |lsp_store, cx| {
13058 let request_task = match for_server_id {
13059 Some(server_id) => {
13060 let server_task = lsp_store.request_lsp(
13061 buffer.clone(),
13062 LanguageServerToQuery::Other(server_id),
13063 request.clone(),
13064 cx,
13065 );
13066 cx.background_spawn(async move {
13067 let mut responses = Vec::new();
13068 match server_task.await {
13069 Ok(response) => responses.push((server_id, response)),
13070 // rust-analyzer likes to error with this when its still loading up
13071 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13072 Err(e) => log::error!(
13073 "Error handling response for request {request:?}: {e:#}"
13074 ),
13075 }
13076 responses
13077 })
13078 }
13079 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13080 };
13081 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13082 if T::ProtoRequest::stop_previous_requests() {
13083 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13084 lsp_requests.clear();
13085 }
13086 }
13087 lsp_data.lsp_requests.entry(key).or_default().insert(
13088 lsp_request_id,
13089 cx.spawn(async move |lsp_store, cx| {
13090 let response = request_task.await;
13091 lsp_store
13092 .update(cx, |lsp_store, cx| {
13093 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13094 {
13095 let response = response
13096 .into_iter()
13097 .map(|(server_id, response)| {
13098 (
13099 server_id.to_proto(),
13100 T::response_to_proto(
13101 response,
13102 lsp_store,
13103 sender_id,
13104 &buffer_version,
13105 cx,
13106 )
13107 .into(),
13108 )
13109 })
13110 .collect::<HashMap<_, _>>();
13111 match client.send_lsp_response::<T::ProtoRequest>(
13112 project_id,
13113 lsp_request_id,
13114 response,
13115 ) {
13116 Ok(()) => {}
13117 Err(e) => {
13118 log::error!("Failed to send LSP response: {e:#}",)
13119 }
13120 }
13121 }
13122 })
13123 .ok();
13124 }),
13125 );
13126 })?;
13127 Ok(())
13128 }
13129
13130 fn take_text_document_sync_options(
13131 capabilities: &mut lsp::ServerCapabilities,
13132 ) -> lsp::TextDocumentSyncOptions {
13133 match capabilities.text_document_sync.take() {
13134 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13135 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13136 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13137 sync_options.change = Some(sync_kind);
13138 sync_options
13139 }
13140 None => lsp::TextDocumentSyncOptions::default(),
13141 }
13142 }
13143
13144 #[cfg(any(test, feature = "test-support"))]
13145 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13146 Some(
13147 self.lsp_data
13148 .get_mut(&buffer_id)?
13149 .code_lens
13150 .take()?
13151 .update
13152 .take()?
13153 .1,
13154 )
13155 }
13156
13157 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13158 self.downstream_client.clone()
13159 }
13160
13161 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13162 self.worktree_store.clone()
13163 }
13164
13165 /// Gets what's stored in the LSP data for the given buffer.
13166 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13167 self.lsp_data.get_mut(&buffer_id)
13168 }
13169
13170 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13171 /// new [`BufferLspData`] will be created to replace the previous state.
13172 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13173 let (buffer_id, buffer_version) =
13174 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13175 let lsp_data = self
13176 .lsp_data
13177 .entry(buffer_id)
13178 .or_insert_with(|| BufferLspData::new(buffer, cx));
13179 if buffer_version.changed_since(&lsp_data.buffer_version) {
13180 *lsp_data = BufferLspData::new(buffer, cx);
13181 }
13182 lsp_data
13183 }
13184}
13185
13186// Registration with registerOptions as null, should fallback to true.
13187// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13188fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13189 reg: lsp::Registration,
13190) -> Result<OneOf<bool, T>> {
13191 Ok(match reg.register_options {
13192 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13193 None => OneOf::Left(true),
13194 })
13195}
13196
13197fn subscribe_to_binary_statuses(
13198 languages: &Arc<LanguageRegistry>,
13199 cx: &mut Context<'_, LspStore>,
13200) -> Task<()> {
13201 let mut server_statuses = languages.language_server_binary_statuses();
13202 cx.spawn(async move |lsp_store, cx| {
13203 while let Some((server_name, binary_status)) = server_statuses.next().await {
13204 if lsp_store
13205 .update(cx, |_, cx| {
13206 let mut message = None;
13207 let binary_status = match binary_status {
13208 BinaryStatus::None => proto::ServerBinaryStatus::None,
13209 BinaryStatus::CheckingForUpdate => {
13210 proto::ServerBinaryStatus::CheckingForUpdate
13211 }
13212 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13213 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13214 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13215 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13216 BinaryStatus::Failed { error } => {
13217 message = Some(error);
13218 proto::ServerBinaryStatus::Failed
13219 }
13220 };
13221 cx.emit(LspStoreEvent::LanguageServerUpdate {
13222 // Binary updates are about the binary that might not have any language server id at that point.
13223 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13224 language_server_id: LanguageServerId(0),
13225 name: Some(server_name),
13226 message: proto::update_language_server::Variant::StatusUpdate(
13227 proto::StatusUpdate {
13228 message,
13229 status: Some(proto::status_update::Status::Binary(
13230 binary_status as i32,
13231 )),
13232 },
13233 ),
13234 });
13235 })
13236 .is_err()
13237 {
13238 break;
13239 }
13240 }
13241 })
13242}
13243
13244fn lsp_workspace_diagnostics_refresh(
13245 registration_id: Option<String>,
13246 options: DiagnosticServerCapabilities,
13247 server: Arc<LanguageServer>,
13248 cx: &mut Context<'_, LspStore>,
13249) -> Option<WorkspaceRefreshTask> {
13250 let identifier = workspace_diagnostic_identifier(&options)?;
13251 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13252
13253 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13254 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13255 refresh_tx.try_send(()).ok();
13256
13257 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13258 let mut attempts = 0;
13259 let max_attempts = 50;
13260 let mut requests = 0;
13261
13262 loop {
13263 let Some(()) = refresh_rx.recv().await else {
13264 return;
13265 };
13266
13267 'request: loop {
13268 requests += 1;
13269 if attempts > max_attempts {
13270 log::error!(
13271 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13272 );
13273 return;
13274 }
13275 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13276 cx.background_executor()
13277 .timer(Duration::from_millis(backoff_millis))
13278 .await;
13279 attempts += 1;
13280
13281 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13282 lsp_store
13283 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13284 .into_iter()
13285 .filter_map(|(abs_path, result_id)| {
13286 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13287 Some(lsp::PreviousResultId {
13288 uri,
13289 value: result_id.to_string(),
13290 })
13291 })
13292 .collect()
13293 }) else {
13294 return;
13295 };
13296
13297 let token = if let Some(registration_id) = ®istration_id {
13298 format!(
13299 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13300 server.server_id(),
13301 )
13302 } else {
13303 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13304 };
13305
13306 progress_rx.try_recv().ok();
13307 let timer =
13308 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13309 let progress = pin!(progress_rx.recv().fuse());
13310 let response_result = server
13311 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13312 lsp::WorkspaceDiagnosticParams {
13313 previous_result_ids,
13314 identifier: identifier.clone(),
13315 work_done_progress_params: Default::default(),
13316 partial_result_params: lsp::PartialResultParams {
13317 partial_result_token: Some(lsp::ProgressToken::String(token)),
13318 },
13319 },
13320 select(timer, progress).then(|either| match either {
13321 Either::Left((message, ..)) => ready(message).left_future(),
13322 Either::Right(..) => pending::<String>().right_future(),
13323 }),
13324 )
13325 .await;
13326
13327 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13328 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13329 match response_result {
13330 ConnectionResult::Timeout => {
13331 log::error!("Timeout during workspace diagnostics pull");
13332 continue 'request;
13333 }
13334 ConnectionResult::ConnectionReset => {
13335 log::error!("Server closed a workspace diagnostics pull request");
13336 continue 'request;
13337 }
13338 ConnectionResult::Result(Err(e)) => {
13339 log::error!("Error during workspace diagnostics pull: {e:#}");
13340 break 'request;
13341 }
13342 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13343 attempts = 0;
13344 if lsp_store
13345 .update(cx, |lsp_store, cx| {
13346 lsp_store.apply_workspace_diagnostic_report(
13347 server.server_id(),
13348 pulled_diagnostics,
13349 registration_id_shared.clone(),
13350 cx,
13351 )
13352 })
13353 .is_err()
13354 {
13355 return;
13356 }
13357 break 'request;
13358 }
13359 }
13360 }
13361 }
13362 });
13363
13364 Some(WorkspaceRefreshTask {
13365 refresh_tx,
13366 progress_tx,
13367 task: workspace_query_language_server,
13368 })
13369}
13370
13371fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13372 match &options {
13373 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13374 diagnostic_options.identifier.clone()
13375 }
13376 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13377 let diagnostic_options = ®istration_options.diagnostic_options;
13378 diagnostic_options.identifier.clone()
13379 }
13380 }
13381}
13382
13383fn workspace_diagnostic_identifier(
13384 options: &DiagnosticServerCapabilities,
13385) -> Option<Option<String>> {
13386 match &options {
13387 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13388 if !diagnostic_options.workspace_diagnostics {
13389 return None;
13390 }
13391 Some(diagnostic_options.identifier.clone())
13392 }
13393 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13394 let diagnostic_options = ®istration_options.diagnostic_options;
13395 if !diagnostic_options.workspace_diagnostics {
13396 return None;
13397 }
13398 Some(diagnostic_options.identifier.clone())
13399 }
13400 }
13401}
13402
13403fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13404 let CompletionSource::BufferWord {
13405 word_range,
13406 resolved,
13407 } = &mut completion.source
13408 else {
13409 return;
13410 };
13411 if *resolved {
13412 return;
13413 }
13414
13415 if completion.new_text
13416 != snapshot
13417 .text_for_range(word_range.clone())
13418 .collect::<String>()
13419 {
13420 return;
13421 }
13422
13423 let mut offset = 0;
13424 for chunk in snapshot.chunks(word_range.clone(), true) {
13425 let end_offset = offset + chunk.text.len();
13426 if let Some(highlight_id) = chunk.syntax_highlight_id {
13427 completion
13428 .label
13429 .runs
13430 .push((offset..end_offset, highlight_id));
13431 }
13432 offset = end_offset;
13433 }
13434 *resolved = true;
13435}
13436
13437impl EventEmitter<LspStoreEvent> for LspStore {}
13438
13439fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13440 hover
13441 .contents
13442 .retain(|hover_block| !hover_block.text.trim().is_empty());
13443 if hover.contents.is_empty() {
13444 None
13445 } else {
13446 Some(hover)
13447 }
13448}
13449
13450async fn populate_labels_for_completions(
13451 new_completions: Vec<CoreCompletion>,
13452 language: Option<Arc<Language>>,
13453 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13454) -> Vec<Completion> {
13455 let lsp_completions = new_completions
13456 .iter()
13457 .filter_map(|new_completion| {
13458 new_completion
13459 .source
13460 .lsp_completion(true)
13461 .map(|lsp_completion| lsp_completion.into_owned())
13462 })
13463 .collect::<Vec<_>>();
13464
13465 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13466 lsp_adapter
13467 .labels_for_completions(&lsp_completions, language)
13468 .await
13469 .log_err()
13470 .unwrap_or_default()
13471 } else {
13472 Vec::new()
13473 }
13474 .into_iter()
13475 .fuse();
13476
13477 let mut completions = Vec::new();
13478 for completion in new_completions {
13479 match completion.source.lsp_completion(true) {
13480 Some(lsp_completion) => {
13481 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13482
13483 let mut label = labels.next().flatten().unwrap_or_else(|| {
13484 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13485 });
13486 ensure_uniform_list_compatible_label(&mut label);
13487 completions.push(Completion {
13488 label,
13489 documentation,
13490 replace_range: completion.replace_range,
13491 new_text: completion.new_text,
13492 insert_text_mode: lsp_completion.insert_text_mode,
13493 source: completion.source,
13494 icon_path: None,
13495 confirm: None,
13496 match_start: None,
13497 snippet_deduplication_key: None,
13498 });
13499 }
13500 None => {
13501 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13502 ensure_uniform_list_compatible_label(&mut label);
13503 completions.push(Completion {
13504 label,
13505 documentation: None,
13506 replace_range: completion.replace_range,
13507 new_text: completion.new_text,
13508 source: completion.source,
13509 insert_text_mode: None,
13510 icon_path: None,
13511 confirm: None,
13512 match_start: None,
13513 snippet_deduplication_key: None,
13514 });
13515 }
13516 }
13517 }
13518 completions
13519}
13520
13521#[derive(Debug)]
13522pub enum LanguageServerToQuery {
13523 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13524 FirstCapable,
13525 /// Query a specific language server.
13526 Other(LanguageServerId),
13527}
13528
13529#[derive(Default)]
13530struct RenamePathsWatchedForServer {
13531 did_rename: Vec<RenameActionPredicate>,
13532 will_rename: Vec<RenameActionPredicate>,
13533}
13534
13535impl RenamePathsWatchedForServer {
13536 fn with_did_rename_patterns(
13537 mut self,
13538 did_rename: Option<&FileOperationRegistrationOptions>,
13539 ) -> Self {
13540 if let Some(did_rename) = did_rename {
13541 self.did_rename = did_rename
13542 .filters
13543 .iter()
13544 .filter_map(|filter| filter.try_into().log_err())
13545 .collect();
13546 }
13547 self
13548 }
13549 fn with_will_rename_patterns(
13550 mut self,
13551 will_rename: Option<&FileOperationRegistrationOptions>,
13552 ) -> Self {
13553 if let Some(will_rename) = will_rename {
13554 self.will_rename = will_rename
13555 .filters
13556 .iter()
13557 .filter_map(|filter| filter.try_into().log_err())
13558 .collect();
13559 }
13560 self
13561 }
13562
13563 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13564 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13565 }
13566 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13567 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13568 }
13569}
13570
13571impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13572 type Error = globset::Error;
13573 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13574 Ok(Self {
13575 kind: ops.pattern.matches.clone(),
13576 glob: GlobBuilder::new(&ops.pattern.glob)
13577 .case_insensitive(
13578 ops.pattern
13579 .options
13580 .as_ref()
13581 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13582 )
13583 .build()?
13584 .compile_matcher(),
13585 })
13586 }
13587}
13588struct RenameActionPredicate {
13589 glob: GlobMatcher,
13590 kind: Option<FileOperationPatternKind>,
13591}
13592
13593impl RenameActionPredicate {
13594 // Returns true if language server should be notified
13595 fn eval(&self, path: &str, is_dir: bool) -> bool {
13596 self.kind.as_ref().is_none_or(|kind| {
13597 let expected_kind = if is_dir {
13598 FileOperationPatternKind::Folder
13599 } else {
13600 FileOperationPatternKind::File
13601 };
13602 kind == &expected_kind
13603 }) && self.glob.is_match(path)
13604 }
13605}
13606
13607#[derive(Default)]
13608struct LanguageServerWatchedPaths {
13609 worktree_paths: HashMap<WorktreeId, GlobSet>,
13610 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13611}
13612
13613#[derive(Default)]
13614struct LanguageServerWatchedPathsBuilder {
13615 worktree_paths: HashMap<WorktreeId, GlobSet>,
13616 abs_paths: HashMap<Arc<Path>, GlobSet>,
13617}
13618
13619impl LanguageServerWatchedPathsBuilder {
13620 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13621 self.worktree_paths.insert(worktree_id, glob_set);
13622 }
13623 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13624 self.abs_paths.insert(path, glob_set);
13625 }
13626 fn build(
13627 self,
13628 fs: Arc<dyn Fs>,
13629 language_server_id: LanguageServerId,
13630 cx: &mut Context<LspStore>,
13631 ) -> LanguageServerWatchedPaths {
13632 let lsp_store = cx.weak_entity();
13633
13634 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13635 let abs_paths = self
13636 .abs_paths
13637 .into_iter()
13638 .map(|(abs_path, globset)| {
13639 let task = cx.spawn({
13640 let abs_path = abs_path.clone();
13641 let fs = fs.clone();
13642
13643 let lsp_store = lsp_store.clone();
13644 async move |_, cx| {
13645 maybe!(async move {
13646 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13647 while let Some(update) = push_updates.0.next().await {
13648 let action = lsp_store
13649 .update(cx, |this, _| {
13650 let Some(local) = this.as_local() else {
13651 return ControlFlow::Break(());
13652 };
13653 let Some(watcher) = local
13654 .language_server_watched_paths
13655 .get(&language_server_id)
13656 else {
13657 return ControlFlow::Break(());
13658 };
13659 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13660 "Watched abs path is not registered with a watcher",
13661 );
13662 let matching_entries = update
13663 .into_iter()
13664 .filter(|event| globs.is_match(&event.path))
13665 .collect::<Vec<_>>();
13666 this.lsp_notify_abs_paths_changed(
13667 language_server_id,
13668 matching_entries,
13669 );
13670 ControlFlow::Continue(())
13671 })
13672 .ok()?;
13673
13674 if action.is_break() {
13675 break;
13676 }
13677 }
13678 Some(())
13679 })
13680 .await;
13681 }
13682 });
13683 (abs_path, (globset, task))
13684 })
13685 .collect();
13686 LanguageServerWatchedPaths {
13687 worktree_paths: self.worktree_paths,
13688 abs_paths,
13689 }
13690 }
13691}
13692
13693struct LspBufferSnapshot {
13694 version: i32,
13695 snapshot: TextBufferSnapshot,
13696}
13697
13698/// A prompt requested by LSP server.
13699#[derive(Clone, Debug)]
13700pub struct LanguageServerPromptRequest {
13701 pub level: PromptLevel,
13702 pub message: String,
13703 pub actions: Vec<MessageActionItem>,
13704 pub lsp_name: String,
13705 pub(crate) response_channel: Sender<MessageActionItem>,
13706}
13707
13708impl LanguageServerPromptRequest {
13709 pub async fn respond(self, index: usize) -> Option<()> {
13710 if let Some(response) = self.actions.into_iter().nth(index) {
13711 self.response_channel.send(response).await.ok()
13712 } else {
13713 None
13714 }
13715 }
13716}
13717impl PartialEq for LanguageServerPromptRequest {
13718 fn eq(&self, other: &Self) -> bool {
13719 self.message == other.message && self.actions == other.actions
13720 }
13721}
13722
13723#[derive(Clone, Debug, PartialEq)]
13724pub enum LanguageServerLogType {
13725 Log(MessageType),
13726 Trace { verbose_info: Option<String> },
13727 Rpc { received: bool },
13728}
13729
13730impl LanguageServerLogType {
13731 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13732 match self {
13733 Self::Log(log_type) => {
13734 use proto::log_message::LogLevel;
13735 let level = match *log_type {
13736 MessageType::ERROR => LogLevel::Error,
13737 MessageType::WARNING => LogLevel::Warning,
13738 MessageType::INFO => LogLevel::Info,
13739 MessageType::LOG => LogLevel::Log,
13740 other => {
13741 log::warn!("Unknown lsp log message type: {other:?}");
13742 LogLevel::Log
13743 }
13744 };
13745 proto::language_server_log::LogType::Log(proto::LogMessage {
13746 level: level as i32,
13747 })
13748 }
13749 Self::Trace { verbose_info } => {
13750 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13751 verbose_info: verbose_info.to_owned(),
13752 })
13753 }
13754 Self::Rpc { received } => {
13755 let kind = if *received {
13756 proto::rpc_message::Kind::Received
13757 } else {
13758 proto::rpc_message::Kind::Sent
13759 };
13760 let kind = kind as i32;
13761 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13762 }
13763 }
13764 }
13765
13766 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13767 use proto::log_message::LogLevel;
13768 use proto::rpc_message;
13769 match log_type {
13770 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13771 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13772 LogLevel::Error => MessageType::ERROR,
13773 LogLevel::Warning => MessageType::WARNING,
13774 LogLevel::Info => MessageType::INFO,
13775 LogLevel::Log => MessageType::LOG,
13776 },
13777 ),
13778 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13779 verbose_info: trace_message.verbose_info,
13780 },
13781 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13782 received: match rpc_message::Kind::from_i32(message.kind)
13783 .unwrap_or(rpc_message::Kind::Received)
13784 {
13785 rpc_message::Kind::Received => true,
13786 rpc_message::Kind::Sent => false,
13787 },
13788 },
13789 }
13790 }
13791}
13792
13793pub struct WorkspaceRefreshTask {
13794 refresh_tx: mpsc::Sender<()>,
13795 progress_tx: mpsc::Sender<()>,
13796 #[allow(dead_code)]
13797 task: Task<()>,
13798}
13799
13800pub enum LanguageServerState {
13801 Starting {
13802 startup: Task<Option<Arc<LanguageServer>>>,
13803 /// List of language servers that will be added to the workspace once it's initialization completes.
13804 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13805 },
13806
13807 Running {
13808 adapter: Arc<CachedLspAdapter>,
13809 server: Arc<LanguageServer>,
13810 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13811 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13812 },
13813}
13814
13815impl LanguageServerState {
13816 fn add_workspace_folder(&self, uri: Uri) {
13817 match self {
13818 LanguageServerState::Starting {
13819 pending_workspace_folders,
13820 ..
13821 } => {
13822 pending_workspace_folders.lock().insert(uri);
13823 }
13824 LanguageServerState::Running { server, .. } => {
13825 server.add_workspace_folder(uri);
13826 }
13827 }
13828 }
13829 fn _remove_workspace_folder(&self, uri: Uri) {
13830 match self {
13831 LanguageServerState::Starting {
13832 pending_workspace_folders,
13833 ..
13834 } => {
13835 pending_workspace_folders.lock().remove(&uri);
13836 }
13837 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13838 }
13839 }
13840}
13841
13842impl std::fmt::Debug for LanguageServerState {
13843 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13844 match self {
13845 LanguageServerState::Starting { .. } => {
13846 f.debug_struct("LanguageServerState::Starting").finish()
13847 }
13848 LanguageServerState::Running { .. } => {
13849 f.debug_struct("LanguageServerState::Running").finish()
13850 }
13851 }
13852 }
13853}
13854
13855#[derive(Clone, Debug, Serialize)]
13856pub struct LanguageServerProgress {
13857 pub is_disk_based_diagnostics_progress: bool,
13858 pub is_cancellable: bool,
13859 pub title: Option<String>,
13860 pub message: Option<String>,
13861 pub percentage: Option<usize>,
13862 #[serde(skip_serializing)]
13863 pub last_update_at: Instant,
13864}
13865
13866#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13867pub struct DiagnosticSummary {
13868 pub error_count: usize,
13869 pub warning_count: usize,
13870}
13871
13872impl DiagnosticSummary {
13873 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13874 let mut this = Self {
13875 error_count: 0,
13876 warning_count: 0,
13877 };
13878
13879 for entry in diagnostics {
13880 if entry.diagnostic.is_primary {
13881 match entry.diagnostic.severity {
13882 DiagnosticSeverity::ERROR => this.error_count += 1,
13883 DiagnosticSeverity::WARNING => this.warning_count += 1,
13884 _ => {}
13885 }
13886 }
13887 }
13888
13889 this
13890 }
13891
13892 pub fn is_empty(&self) -> bool {
13893 self.error_count == 0 && self.warning_count == 0
13894 }
13895
13896 pub fn to_proto(
13897 self,
13898 language_server_id: LanguageServerId,
13899 path: &RelPath,
13900 ) -> proto::DiagnosticSummary {
13901 proto::DiagnosticSummary {
13902 path: path.to_proto(),
13903 language_server_id: language_server_id.0 as u64,
13904 error_count: self.error_count as u32,
13905 warning_count: self.warning_count as u32,
13906 }
13907 }
13908}
13909
13910#[derive(Clone, Debug)]
13911pub enum CompletionDocumentation {
13912 /// There is no documentation for this completion.
13913 Undocumented,
13914 /// A single line of documentation.
13915 SingleLine(SharedString),
13916 /// Multiple lines of plain text documentation.
13917 MultiLinePlainText(SharedString),
13918 /// Markdown documentation.
13919 MultiLineMarkdown(SharedString),
13920 /// Both single line and multiple lines of plain text documentation.
13921 SingleLineAndMultiLinePlainText {
13922 single_line: SharedString,
13923 plain_text: Option<SharedString>,
13924 },
13925}
13926
13927impl CompletionDocumentation {
13928 #[cfg(any(test, feature = "test-support"))]
13929 pub fn text(&self) -> SharedString {
13930 match self {
13931 CompletionDocumentation::Undocumented => "".into(),
13932 CompletionDocumentation::SingleLine(s) => s.clone(),
13933 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13934 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13935 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13936 single_line.clone()
13937 }
13938 }
13939 }
13940}
13941
13942impl From<lsp::Documentation> for CompletionDocumentation {
13943 fn from(docs: lsp::Documentation) -> Self {
13944 match docs {
13945 lsp::Documentation::String(text) => {
13946 if text.lines().count() <= 1 {
13947 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13948 } else {
13949 CompletionDocumentation::MultiLinePlainText(text.into())
13950 }
13951 }
13952
13953 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13954 lsp::MarkupKind::PlainText => {
13955 if value.lines().count() <= 1 {
13956 CompletionDocumentation::SingleLine(value.into())
13957 } else {
13958 CompletionDocumentation::MultiLinePlainText(value.into())
13959 }
13960 }
13961
13962 lsp::MarkupKind::Markdown => {
13963 CompletionDocumentation::MultiLineMarkdown(value.into())
13964 }
13965 },
13966 }
13967 }
13968}
13969
13970pub enum ResolvedHint {
13971 Resolved(InlayHint),
13972 Resolving(Shared<Task<()>>),
13973}
13974
13975fn glob_literal_prefix(glob: &Path) -> PathBuf {
13976 glob.components()
13977 .take_while(|component| match component {
13978 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13979 _ => true,
13980 })
13981 .collect()
13982}
13983
13984pub struct SshLspAdapter {
13985 name: LanguageServerName,
13986 binary: LanguageServerBinary,
13987 initialization_options: Option<String>,
13988 code_action_kinds: Option<Vec<CodeActionKind>>,
13989}
13990
13991impl SshLspAdapter {
13992 pub fn new(
13993 name: LanguageServerName,
13994 binary: LanguageServerBinary,
13995 initialization_options: Option<String>,
13996 code_action_kinds: Option<String>,
13997 ) -> Self {
13998 Self {
13999 name,
14000 binary,
14001 initialization_options,
14002 code_action_kinds: code_action_kinds
14003 .as_ref()
14004 .and_then(|c| serde_json::from_str(c).ok()),
14005 }
14006 }
14007}
14008
14009impl LspInstaller for SshLspAdapter {
14010 type BinaryVersion = ();
14011 async fn check_if_user_installed(
14012 &self,
14013 _: &dyn LspAdapterDelegate,
14014 _: Option<Toolchain>,
14015 _: &AsyncApp,
14016 ) -> Option<LanguageServerBinary> {
14017 Some(self.binary.clone())
14018 }
14019
14020 async fn cached_server_binary(
14021 &self,
14022 _: PathBuf,
14023 _: &dyn LspAdapterDelegate,
14024 ) -> Option<LanguageServerBinary> {
14025 None
14026 }
14027
14028 async fn fetch_latest_server_version(
14029 &self,
14030 _: &dyn LspAdapterDelegate,
14031 _: bool,
14032 _: &mut AsyncApp,
14033 ) -> Result<()> {
14034 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14035 }
14036
14037 async fn fetch_server_binary(
14038 &self,
14039 _: (),
14040 _: PathBuf,
14041 _: &dyn LspAdapterDelegate,
14042 ) -> Result<LanguageServerBinary> {
14043 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14044 }
14045}
14046
14047#[async_trait(?Send)]
14048impl LspAdapter for SshLspAdapter {
14049 fn name(&self) -> LanguageServerName {
14050 self.name.clone()
14051 }
14052
14053 async fn initialization_options(
14054 self: Arc<Self>,
14055 _: &Arc<dyn LspAdapterDelegate>,
14056 ) -> Result<Option<serde_json::Value>> {
14057 let Some(options) = &self.initialization_options else {
14058 return Ok(None);
14059 };
14060 let result = serde_json::from_str(options)?;
14061 Ok(result)
14062 }
14063
14064 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14065 self.code_action_kinds.clone()
14066 }
14067}
14068
14069pub fn language_server_settings<'a>(
14070 delegate: &'a dyn LspAdapterDelegate,
14071 language: &LanguageServerName,
14072 cx: &'a App,
14073) -> Option<&'a LspSettings> {
14074 language_server_settings_for(
14075 SettingsLocation {
14076 worktree_id: delegate.worktree_id(),
14077 path: RelPath::empty(),
14078 },
14079 language,
14080 cx,
14081 )
14082}
14083
14084pub fn language_server_settings_for<'a>(
14085 location: SettingsLocation<'a>,
14086 language: &LanguageServerName,
14087 cx: &'a App,
14088) -> Option<&'a LspSettings> {
14089 ProjectSettings::get(Some(location), cx).lsp.get(language)
14090}
14091
14092pub struct LocalLspAdapterDelegate {
14093 lsp_store: WeakEntity<LspStore>,
14094 worktree: worktree::Snapshot,
14095 fs: Arc<dyn Fs>,
14096 http_client: Arc<dyn HttpClient>,
14097 language_registry: Arc<LanguageRegistry>,
14098 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14099}
14100
14101impl LocalLspAdapterDelegate {
14102 pub fn new(
14103 language_registry: Arc<LanguageRegistry>,
14104 environment: &Entity<ProjectEnvironment>,
14105 lsp_store: WeakEntity<LspStore>,
14106 worktree: &Entity<Worktree>,
14107 http_client: Arc<dyn HttpClient>,
14108 fs: Arc<dyn Fs>,
14109 cx: &mut App,
14110 ) -> Arc<Self> {
14111 let load_shell_env_task =
14112 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14113
14114 Arc::new(Self {
14115 lsp_store,
14116 worktree: worktree.read(cx).snapshot(),
14117 fs,
14118 http_client,
14119 language_registry,
14120 load_shell_env_task,
14121 })
14122 }
14123
14124 pub fn from_local_lsp(
14125 local: &LocalLspStore,
14126 worktree: &Entity<Worktree>,
14127 cx: &mut App,
14128 ) -> Arc<Self> {
14129 Self::new(
14130 local.languages.clone(),
14131 &local.environment,
14132 local.weak.clone(),
14133 worktree,
14134 local.http_client.clone(),
14135 local.fs.clone(),
14136 cx,
14137 )
14138 }
14139}
14140
14141#[async_trait]
14142impl LspAdapterDelegate for LocalLspAdapterDelegate {
14143 fn show_notification(&self, message: &str, cx: &mut App) {
14144 self.lsp_store
14145 .update(cx, |_, cx| {
14146 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14147 })
14148 .ok();
14149 }
14150
14151 fn http_client(&self) -> Arc<dyn HttpClient> {
14152 self.http_client.clone()
14153 }
14154
14155 fn worktree_id(&self) -> WorktreeId {
14156 self.worktree.id()
14157 }
14158
14159 fn worktree_root_path(&self) -> &Path {
14160 self.worktree.abs_path().as_ref()
14161 }
14162
14163 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14164 self.worktree.resolve_executable_path(path)
14165 }
14166
14167 async fn shell_env(&self) -> HashMap<String, String> {
14168 let task = self.load_shell_env_task.clone();
14169 task.await.unwrap_or_default()
14170 }
14171
14172 async fn npm_package_installed_version(
14173 &self,
14174 package_name: &str,
14175 ) -> Result<Option<(PathBuf, Version)>> {
14176 let local_package_directory = self.worktree_root_path();
14177 let node_modules_directory = local_package_directory.join("node_modules");
14178
14179 if let Some(version) =
14180 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14181 {
14182 return Ok(Some((node_modules_directory, version)));
14183 }
14184 let Some(npm) = self.which("npm".as_ref()).await else {
14185 log::warn!(
14186 "Failed to find npm executable for {:?}",
14187 local_package_directory
14188 );
14189 return Ok(None);
14190 };
14191
14192 let env = self.shell_env().await;
14193 let output = util::command::new_smol_command(&npm)
14194 .args(["root", "-g"])
14195 .envs(env)
14196 .current_dir(local_package_directory)
14197 .output()
14198 .await?;
14199 let global_node_modules =
14200 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14201
14202 if let Some(version) =
14203 read_package_installed_version(global_node_modules.clone(), package_name).await?
14204 {
14205 return Ok(Some((global_node_modules, version)));
14206 }
14207 return Ok(None);
14208 }
14209
14210 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14211 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14212 if self.fs.is_file(&worktree_abs_path).await {
14213 worktree_abs_path.pop();
14214 }
14215
14216 let env = self.shell_env().await;
14217
14218 let shell_path = env.get("PATH").cloned();
14219
14220 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14221 }
14222
14223 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14224 let mut working_dir = self.worktree_root_path().to_path_buf();
14225 if self.fs.is_file(&working_dir).await {
14226 working_dir.pop();
14227 }
14228 let output = util::command::new_smol_command(&command.path)
14229 .args(command.arguments)
14230 .envs(command.env.clone().unwrap_or_default())
14231 .current_dir(working_dir)
14232 .output()
14233 .await?;
14234
14235 anyhow::ensure!(
14236 output.status.success(),
14237 "{}, stdout: {:?}, stderr: {:?}",
14238 output.status,
14239 String::from_utf8_lossy(&output.stdout),
14240 String::from_utf8_lossy(&output.stderr)
14241 );
14242 Ok(())
14243 }
14244
14245 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14246 self.language_registry
14247 .update_lsp_binary_status(server_name, status);
14248 }
14249
14250 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14251 self.language_registry
14252 .all_lsp_adapters()
14253 .into_iter()
14254 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14255 .collect()
14256 }
14257
14258 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14259 let dir = self.language_registry.language_server_download_dir(name)?;
14260
14261 if !dir.exists() {
14262 smol::fs::create_dir_all(&dir)
14263 .await
14264 .context("failed to create container directory")
14265 .log_err()?;
14266 }
14267
14268 Some(dir)
14269 }
14270
14271 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14272 let entry = self
14273 .worktree
14274 .entry_for_path(path)
14275 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14276 let abs_path = self.worktree.absolutize(&entry.path);
14277 self.fs.load(&abs_path).await
14278 }
14279}
14280
14281async fn populate_labels_for_symbols(
14282 symbols: Vec<CoreSymbol>,
14283 language_registry: &Arc<LanguageRegistry>,
14284 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14285 output: &mut Vec<Symbol>,
14286) {
14287 #[allow(clippy::mutable_key_type)]
14288 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14289
14290 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14291 for symbol in symbols {
14292 let Some(file_name) = symbol.path.file_name() else {
14293 continue;
14294 };
14295 let language = language_registry
14296 .load_language_for_file_path(Path::new(file_name))
14297 .await
14298 .ok()
14299 .or_else(|| {
14300 unknown_paths.insert(file_name.into());
14301 None
14302 });
14303 symbols_by_language
14304 .entry(language)
14305 .or_default()
14306 .push(symbol);
14307 }
14308
14309 for unknown_path in unknown_paths {
14310 log::info!("no language found for symbol in file {unknown_path:?}");
14311 }
14312
14313 let mut label_params = Vec::new();
14314 for (language, mut symbols) in symbols_by_language {
14315 label_params.clear();
14316 label_params.extend(
14317 symbols
14318 .iter_mut()
14319 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14320 );
14321
14322 let mut labels = Vec::new();
14323 if let Some(language) = language {
14324 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14325 language_registry
14326 .lsp_adapters(&language.name())
14327 .first()
14328 .cloned()
14329 });
14330 if let Some(lsp_adapter) = lsp_adapter {
14331 labels = lsp_adapter
14332 .labels_for_symbols(&label_params, &language)
14333 .await
14334 .log_err()
14335 .unwrap_or_default();
14336 }
14337 }
14338
14339 for ((symbol, (name, _)), label) in symbols
14340 .into_iter()
14341 .zip(label_params.drain(..))
14342 .zip(labels.into_iter().chain(iter::repeat(None)))
14343 {
14344 output.push(Symbol {
14345 language_server_name: symbol.language_server_name,
14346 source_worktree_id: symbol.source_worktree_id,
14347 source_language_server_id: symbol.source_language_server_id,
14348 path: symbol.path,
14349 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14350 name,
14351 kind: symbol.kind,
14352 range: symbol.range,
14353 });
14354 }
14355 }
14356}
14357
14358fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14359 match server.capabilities().text_document_sync.as_ref()? {
14360 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14361 // Server wants didSave but didn't specify includeText.
14362 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14363 // Server doesn't want didSave at all.
14364 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14365 // Server provided SaveOptions.
14366 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14367 Some(save_options.include_text.unwrap_or(false))
14368 }
14369 },
14370 // We do not have any save info. Kind affects didChange only.
14371 lsp::TextDocumentSyncCapability::Kind(_) => None,
14372 }
14373}
14374
14375/// Completion items are displayed in a `UniformList`.
14376/// Usually, those items are single-line strings, but in LSP responses,
14377/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14378/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14379/// 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,
14380/// breaking the completions menu presentation.
14381///
14382/// 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.
14383fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14384 let mut new_text = String::with_capacity(label.text.len());
14385 let mut offset_map = vec![0; label.text.len() + 1];
14386 let mut last_char_was_space = false;
14387 let mut new_idx = 0;
14388 let chars = label.text.char_indices().fuse();
14389 let mut newlines_removed = false;
14390
14391 for (idx, c) in chars {
14392 offset_map[idx] = new_idx;
14393
14394 match c {
14395 '\n' if last_char_was_space => {
14396 newlines_removed = true;
14397 }
14398 '\t' | ' ' if last_char_was_space => {}
14399 '\n' if !last_char_was_space => {
14400 new_text.push(' ');
14401 new_idx += 1;
14402 last_char_was_space = true;
14403 newlines_removed = true;
14404 }
14405 ' ' | '\t' => {
14406 new_text.push(' ');
14407 new_idx += 1;
14408 last_char_was_space = true;
14409 }
14410 _ => {
14411 new_text.push(c);
14412 new_idx += c.len_utf8();
14413 last_char_was_space = false;
14414 }
14415 }
14416 }
14417 offset_map[label.text.len()] = new_idx;
14418
14419 // Only modify the label if newlines were removed.
14420 if !newlines_removed {
14421 return;
14422 }
14423
14424 let last_index = new_idx;
14425 let mut run_ranges_errors = Vec::new();
14426 label.runs.retain_mut(|(range, _)| {
14427 match offset_map.get(range.start) {
14428 Some(&start) => range.start = start,
14429 None => {
14430 run_ranges_errors.push(range.clone());
14431 return false;
14432 }
14433 }
14434
14435 match offset_map.get(range.end) {
14436 Some(&end) => range.end = end,
14437 None => {
14438 run_ranges_errors.push(range.clone());
14439 range.end = last_index;
14440 }
14441 }
14442 true
14443 });
14444 if !run_ranges_errors.is_empty() {
14445 log::error!(
14446 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14447 label.text
14448 );
14449 }
14450
14451 let mut wrong_filter_range = None;
14452 if label.filter_range == (0..label.text.len()) {
14453 label.filter_range = 0..new_text.len();
14454 } else {
14455 let mut original_filter_range = Some(label.filter_range.clone());
14456 match offset_map.get(label.filter_range.start) {
14457 Some(&start) => label.filter_range.start = start,
14458 None => {
14459 wrong_filter_range = original_filter_range.take();
14460 label.filter_range.start = last_index;
14461 }
14462 }
14463
14464 match offset_map.get(label.filter_range.end) {
14465 Some(&end) => label.filter_range.end = end,
14466 None => {
14467 wrong_filter_range = original_filter_range.take();
14468 label.filter_range.end = last_index;
14469 }
14470 }
14471 }
14472 if let Some(wrong_filter_range) = wrong_filter_range {
14473 log::error!(
14474 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14475 label.text
14476 );
14477 }
14478
14479 label.text = new_text;
14480}
14481
14482#[cfg(test)]
14483mod tests {
14484 use language::HighlightId;
14485
14486 use super::*;
14487
14488 #[test]
14489 fn test_glob_literal_prefix() {
14490 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14491 assert_eq!(
14492 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14493 Path::new("node_modules")
14494 );
14495 assert_eq!(
14496 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14497 Path::new("foo")
14498 );
14499 assert_eq!(
14500 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14501 Path::new("foo/bar/baz.js")
14502 );
14503
14504 #[cfg(target_os = "windows")]
14505 {
14506 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14507 assert_eq!(
14508 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14509 Path::new("node_modules")
14510 );
14511 assert_eq!(
14512 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14513 Path::new("foo")
14514 );
14515 assert_eq!(
14516 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14517 Path::new("foo/bar/baz.js")
14518 );
14519 }
14520 }
14521
14522 #[test]
14523 fn test_multi_len_chars_normalization() {
14524 let mut label = CodeLabel::new(
14525 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14526 0..6,
14527 vec![(0..6, HighlightId(1))],
14528 );
14529 ensure_uniform_list_compatible_label(&mut label);
14530 assert_eq!(
14531 label,
14532 CodeLabel::new(
14533 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14534 0..6,
14535 vec![(0..6, HighlightId(1))],
14536 )
14537 );
14538 }
14539
14540 #[test]
14541 fn test_trailing_newline_in_completion_documentation() {
14542 let doc = lsp::Documentation::String(
14543 "Inappropriate argument value (of correct type).\n".to_string(),
14544 );
14545 let completion_doc: CompletionDocumentation = doc.into();
14546 assert!(
14547 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
14548 );
14549
14550 let doc = lsp::Documentation::String(" some value \n".to_string());
14551 let completion_doc: CompletionDocumentation = doc.into();
14552 assert!(matches!(
14553 completion_doc,
14554 CompletionDocumentation::SingleLine(s) if s == "some value"
14555 ));
14556 }
14557}