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