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.update(cx, |lsp_store, cx| {
535 lsp_store.cleanup_lsp_data(server_id);
536 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
537 });
538 }
539 })?;
540
541 language_server.notify::<lsp::notification::DidChangeConfiguration>(
542 did_change_configuration_params,
543 )?;
544
545 anyhow::Ok(language_server)
546 }
547 .await;
548
549 match result {
550 Ok(server) => {
551 lsp_store
552 .update(cx, |lsp_store, cx| {
553 lsp_store.insert_newly_running_language_server(
554 adapter,
555 server.clone(),
556 server_id,
557 key,
558 pending_workspace_folders,
559 cx,
560 );
561 })
562 .ok();
563 stderr_capture.lock().take();
564 Some(server)
565 }
566
567 Err(err) => {
568 let log = stderr_capture.lock().take().unwrap_or_default();
569 delegate.update_status(
570 adapter.name(),
571 BinaryStatus::Failed {
572 error: if log.is_empty() {
573 format!("{err:#}")
574 } else {
575 format!("{err:#}\n-- stderr --\n{log}")
576 },
577 },
578 );
579 log::error!(
580 "Failed to start language server {server_name:?}: {}",
581 redact_command(&format!("{err:?}"))
582 );
583 if !log.is_empty() {
584 log::error!("server stderr: {}", redact_command(&log));
585 }
586 None
587 }
588 }
589 })
590 };
591 let state = LanguageServerState::Starting {
592 startup,
593 pending_workspace_folders,
594 };
595
596 if update_binary_status {
597 self.languages
598 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
599 }
600
601 self.language_servers.insert(server_id, state);
602 self.language_server_ids
603 .entry(key)
604 .or_insert(UnifiedLanguageServer {
605 id: server_id,
606 project_roots: Default::default(),
607 });
608 server_id
609 }
610
611 fn get_language_server_binary(
612 &self,
613 worktree_abs_path: Arc<Path>,
614 adapter: Arc<CachedLspAdapter>,
615 settings: Arc<LspSettings>,
616 toolchain: Option<Toolchain>,
617 delegate: Arc<dyn LspAdapterDelegate>,
618 allow_binary_download: bool,
619 untrusted_worktree_task: Option<Receiver<()>>,
620 cx: &mut App,
621 ) -> Task<Result<LanguageServerBinary>> {
622 if let Some(settings) = &settings.binary
623 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
624 {
625 let settings = settings.clone();
626 let languages = self.languages.clone();
627 return cx.background_spawn(async move {
628 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
629 log::info!(
630 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
631 adapter.name(),
632 );
633 untrusted_worktree_task.recv().await.ok();
634 log::info!(
635 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
636 adapter.name(),
637 );
638 languages
639 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
640 }
641 let mut env = delegate.shell_env().await;
642 env.extend(settings.env.unwrap_or_default());
643
644 Ok(LanguageServerBinary {
645 path: delegate.resolve_executable_path(path),
646 env: Some(env),
647 arguments: settings
648 .arguments
649 .unwrap_or_default()
650 .iter()
651 .map(Into::into)
652 .collect(),
653 })
654 });
655 }
656 let lsp_binary_options = LanguageServerBinaryOptions {
657 allow_path_lookup: !settings
658 .binary
659 .as_ref()
660 .and_then(|b| b.ignore_system_version)
661 .unwrap_or_default(),
662 allow_binary_download,
663 pre_release: settings
664 .fetch
665 .as_ref()
666 .and_then(|f| f.pre_release)
667 .unwrap_or(false),
668 };
669
670 cx.spawn(async move |cx| {
671 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
672 log::info!(
673 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
674 adapter.name(),
675 );
676 untrusted_worktree_task.recv().await.ok();
677 log::info!(
678 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
679 adapter.name(),
680 );
681 }
682
683 let (existing_binary, maybe_download_binary) = adapter
684 .clone()
685 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
686 .await
687 .await;
688
689 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
690
691 let mut binary = match (existing_binary, maybe_download_binary) {
692 (binary, None) => binary?,
693 (Err(_), Some(downloader)) => downloader.await?,
694 (Ok(existing_binary), Some(downloader)) => {
695 let mut download_timeout = cx
696 .background_executor()
697 .timer(SERVER_DOWNLOAD_TIMEOUT)
698 .fuse();
699 let mut downloader = downloader.fuse();
700 futures::select! {
701 _ = download_timeout => {
702 // Return existing binary and kick the existing work to the background.
703 cx.spawn(async move |_| downloader.await).detach();
704 Ok(existing_binary)
705 },
706 downloaded_or_existing_binary = downloader => {
707 // If download fails, this results in the existing binary.
708 downloaded_or_existing_binary
709 }
710 }?
711 }
712 };
713 let mut shell_env = delegate.shell_env().await;
714
715 shell_env.extend(binary.env.unwrap_or_default());
716
717 if let Some(settings) = settings.binary.as_ref() {
718 if let Some(arguments) = &settings.arguments {
719 binary.arguments = arguments.iter().map(Into::into).collect();
720 }
721 if let Some(env) = &settings.env {
722 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
723 }
724 }
725
726 binary.env = Some(shell_env);
727 Ok(binary)
728 })
729 }
730
731 fn setup_lsp_messages(
732 lsp_store: WeakEntity<LspStore>,
733 language_server: &LanguageServer,
734 delegate: Arc<dyn LspAdapterDelegate>,
735 adapter: Arc<CachedLspAdapter>,
736 ) {
737 let name = language_server.name();
738 let server_id = language_server.server_id();
739 language_server
740 .on_notification::<lsp::notification::PublishDiagnostics, _>({
741 let adapter = adapter.clone();
742 let this = lsp_store.clone();
743 move |mut params, cx| {
744 let adapter = adapter.clone();
745 if let Some(this) = this.upgrade() {
746 this.update(cx, |this, cx| {
747 {
748 let buffer = params
749 .uri
750 .to_file_path()
751 .map(|file_path| this.get_buffer(&file_path, cx))
752 .ok()
753 .flatten();
754 adapter.process_diagnostics(&mut params, server_id, buffer);
755 }
756
757 this.merge_lsp_diagnostics(
758 DiagnosticSourceKind::Pushed,
759 vec![DocumentDiagnosticsUpdate {
760 server_id,
761 diagnostics: params,
762 result_id: None,
763 disk_based_sources: Cow::Borrowed(
764 &adapter.disk_based_diagnostic_sources,
765 ),
766 registration_id: None,
767 }],
768 |_, diagnostic, cx| match diagnostic.source_kind {
769 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
770 adapter.retain_old_diagnostic(diagnostic, cx)
771 }
772 DiagnosticSourceKind::Pulled => true,
773 },
774 cx,
775 )
776 .log_err();
777 });
778 }
779 }
780 })
781 .detach();
782 language_server
783 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
784 let adapter = adapter.adapter.clone();
785 let delegate = delegate.clone();
786 let this = lsp_store.clone();
787 move |params, cx| {
788 let adapter = adapter.clone();
789 let delegate = delegate.clone();
790 let this = this.clone();
791 let mut cx = cx.clone();
792 async move {
793 let toolchain_for_id = this
794 .update(&mut cx, |this, _| {
795 this.as_local()?.language_server_ids.iter().find_map(
796 |(seed, value)| {
797 (value.id == server_id).then(|| seed.toolchain.clone())
798 },
799 )
800 })?
801 .context("Expected the LSP store to be in a local mode")?;
802
803 let mut scope_uri_to_workspace_config = BTreeMap::new();
804 for item in ¶ms.items {
805 let scope_uri = item.scope_uri.clone();
806 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
807 scope_uri_to_workspace_config.entry(scope_uri.clone())
808 else {
809 // We've already queried workspace configuration of this URI.
810 continue;
811 };
812 let workspace_config = Self::workspace_configuration_for_adapter(
813 adapter.clone(),
814 &delegate,
815 toolchain_for_id.clone(),
816 scope_uri,
817 &mut cx,
818 )
819 .await?;
820 new_scope_uri.insert(workspace_config);
821 }
822
823 Ok(params
824 .items
825 .into_iter()
826 .filter_map(|item| {
827 let workspace_config =
828 scope_uri_to_workspace_config.get(&item.scope_uri)?;
829 if let Some(section) = &item.section {
830 Some(
831 workspace_config
832 .get(section)
833 .cloned()
834 .unwrap_or(serde_json::Value::Null),
835 )
836 } else {
837 Some(workspace_config.clone())
838 }
839 })
840 .collect())
841 }
842 }
843 })
844 .detach();
845
846 language_server
847 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
848 let this = lsp_store.clone();
849 move |_, cx| {
850 let this = this.clone();
851 let cx = cx.clone();
852 async move {
853 let Some(server) =
854 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
855 else {
856 return Ok(None);
857 };
858 let root = server.workspace_folders();
859 Ok(Some(
860 root.into_iter()
861 .map(|uri| WorkspaceFolder {
862 uri,
863 name: Default::default(),
864 })
865 .collect(),
866 ))
867 }
868 }
869 })
870 .detach();
871 // Even though we don't have handling for these requests, respond to them to
872 // avoid stalling any language server like `gopls` which waits for a response
873 // to these requests when initializing.
874 language_server
875 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
876 let this = lsp_store.clone();
877 move |params, cx| {
878 let this = this.clone();
879 let mut cx = cx.clone();
880 async move {
881 this.update(&mut cx, |this, _| {
882 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
883 {
884 status
885 .progress_tokens
886 .insert(ProgressToken::from_lsp(params.token));
887 }
888 })?;
889
890 Ok(())
891 }
892 }
893 })
894 .detach();
895
896 language_server
897 .on_request::<lsp::request::RegisterCapability, _, _>({
898 let lsp_store = lsp_store.clone();
899 move |params, cx| {
900 let lsp_store = lsp_store.clone();
901 let mut cx = cx.clone();
902 async move {
903 lsp_store
904 .update(&mut cx, |lsp_store, cx| {
905 if lsp_store.as_local().is_some() {
906 match lsp_store
907 .register_server_capabilities(server_id, params, cx)
908 {
909 Ok(()) => {}
910 Err(e) => {
911 log::error!(
912 "Failed to register server capabilities: {e:#}"
913 );
914 }
915 };
916 }
917 })
918 .ok();
919 Ok(())
920 }
921 }
922 })
923 .detach();
924
925 language_server
926 .on_request::<lsp::request::UnregisterCapability, _, _>({
927 let lsp_store = lsp_store.clone();
928 move |params, cx| {
929 let lsp_store = lsp_store.clone();
930 let mut cx = cx.clone();
931 async move {
932 lsp_store
933 .update(&mut cx, |lsp_store, cx| {
934 if lsp_store.as_local().is_some() {
935 match lsp_store
936 .unregister_server_capabilities(server_id, params, cx)
937 {
938 Ok(()) => {}
939 Err(e) => {
940 log::error!(
941 "Failed to unregister server capabilities: {e:#}"
942 );
943 }
944 }
945 }
946 })
947 .ok();
948 Ok(())
949 }
950 }
951 })
952 .detach();
953
954 language_server
955 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
956 let this = lsp_store.clone();
957 move |params, cx| {
958 let mut cx = cx.clone();
959 let this = this.clone();
960 async move {
961 LocalLspStore::on_lsp_workspace_edit(
962 this.clone(),
963 params,
964 server_id,
965 &mut cx,
966 )
967 .await
968 }
969 }
970 })
971 .detach();
972
973 language_server
974 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
975 let lsp_store = lsp_store.clone();
976 let request_id = Arc::new(AtomicUsize::new(0));
977 move |(), cx| {
978 let lsp_store = lsp_store.clone();
979 let request_id = request_id.clone();
980 let mut cx = cx.clone();
981 async move {
982 lsp_store
983 .update(&mut cx, |lsp_store, cx| {
984 let request_id =
985 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
986 cx.emit(LspStoreEvent::RefreshInlayHints {
987 server_id,
988 request_id,
989 });
990 lsp_store
991 .downstream_client
992 .as_ref()
993 .map(|(client, project_id)| {
994 client.send(proto::RefreshInlayHints {
995 project_id: *project_id,
996 server_id: server_id.to_proto(),
997 request_id: request_id.map(|id| id as u64),
998 })
999 })
1000 })?
1001 .transpose()?;
1002 Ok(())
1003 }
1004 }
1005 })
1006 .detach();
1007
1008 language_server
1009 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1010 let this = lsp_store.clone();
1011 move |(), cx| {
1012 let this = this.clone();
1013 let mut cx = cx.clone();
1014 async move {
1015 this.update(&mut cx, |this, cx| {
1016 cx.emit(LspStoreEvent::RefreshCodeLens);
1017 this.downstream_client.as_ref().map(|(client, project_id)| {
1018 client.send(proto::RefreshCodeLens {
1019 project_id: *project_id,
1020 })
1021 })
1022 })?
1023 .transpose()?;
1024 Ok(())
1025 }
1026 }
1027 })
1028 .detach();
1029
1030 language_server
1031 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1032 let this = lsp_store.clone();
1033 move |(), cx| {
1034 let this = this.clone();
1035 let mut cx = cx.clone();
1036 async move {
1037 this.update(&mut cx, |lsp_store, cx| {
1038 lsp_store.pull_workspace_diagnostics(server_id);
1039 lsp_store
1040 .downstream_client
1041 .as_ref()
1042 .map(|(client, project_id)| {
1043 client.send(proto::PullWorkspaceDiagnostics {
1044 project_id: *project_id,
1045 server_id: server_id.to_proto(),
1046 })
1047 })
1048 .transpose()?;
1049 anyhow::Ok(
1050 lsp_store.pull_document_diagnostics_for_server(server_id, cx),
1051 )
1052 })??
1053 .await;
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 }
1155 }
1156 })
1157 .detach();
1158
1159 language_server
1160 .on_notification::<lsp::notification::LogMessage, _>({
1161 let this = lsp_store.clone();
1162 move |params, cx| {
1163 if let Some(this) = this.upgrade() {
1164 this.update(cx, |_, cx| {
1165 cx.emit(LspStoreEvent::LanguageServerLog(
1166 server_id,
1167 LanguageServerLogType::Log(params.typ),
1168 params.message,
1169 ));
1170 });
1171 }
1172 }
1173 })
1174 .detach();
1175
1176 language_server
1177 .on_notification::<lsp::notification::LogTrace, _>({
1178 let this = lsp_store.clone();
1179 move |params, cx| {
1180 let mut cx = cx.clone();
1181 if let Some(this) = this.upgrade() {
1182 this.update(&mut cx, |_, cx| {
1183 cx.emit(LspStoreEvent::LanguageServerLog(
1184 server_id,
1185 LanguageServerLogType::Trace {
1186 verbose_info: params.verbose,
1187 },
1188 params.message,
1189 ));
1190 });
1191 }
1192 }
1193 })
1194 .detach();
1195
1196 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1197 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1198 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1199 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1200 }
1201
1202 fn shutdown_language_servers_on_quit(
1203 &mut self,
1204 _: &mut Context<LspStore>,
1205 ) -> impl Future<Output = ()> + use<> {
1206 let shutdown_futures = self
1207 .language_servers
1208 .drain()
1209 .map(|(_, server_state)| Self::shutdown_server(server_state))
1210 .collect::<Vec<_>>();
1211
1212 async move {
1213 join_all(shutdown_futures).await;
1214 }
1215 }
1216
1217 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1218 match server_state {
1219 LanguageServerState::Running { server, .. } => {
1220 if let Some(shutdown) = server.shutdown() {
1221 shutdown.await;
1222 }
1223 }
1224 LanguageServerState::Starting { startup, .. } => {
1225 if let Some(server) = startup.await
1226 && let Some(shutdown) = server.shutdown()
1227 {
1228 shutdown.await;
1229 }
1230 }
1231 }
1232 Ok(())
1233 }
1234
1235 fn language_servers_for_worktree(
1236 &self,
1237 worktree_id: WorktreeId,
1238 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1239 self.language_server_ids
1240 .iter()
1241 .filter_map(move |(seed, state)| {
1242 if seed.worktree_id != worktree_id {
1243 return None;
1244 }
1245
1246 if let Some(LanguageServerState::Running { server, .. }) =
1247 self.language_servers.get(&state.id)
1248 {
1249 Some(server)
1250 } else {
1251 None
1252 }
1253 })
1254 }
1255
1256 fn language_server_ids_for_project_path(
1257 &self,
1258 project_path: ProjectPath,
1259 language: &Language,
1260 cx: &mut App,
1261 ) -> Vec<LanguageServerId> {
1262 let Some(worktree) = self
1263 .worktree_store
1264 .read(cx)
1265 .worktree_for_id(project_path.worktree_id, cx)
1266 else {
1267 return Vec::new();
1268 };
1269 let delegate: Arc<dyn ManifestDelegate> =
1270 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1271
1272 self.lsp_tree
1273 .get(
1274 project_path,
1275 language.name(),
1276 language.manifest(),
1277 &delegate,
1278 cx,
1279 )
1280 .collect::<Vec<_>>()
1281 }
1282
1283 fn language_server_ids_for_buffer(
1284 &self,
1285 buffer: &Buffer,
1286 cx: &mut App,
1287 ) -> Vec<LanguageServerId> {
1288 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1289 let worktree_id = file.worktree_id(cx);
1290
1291 let path: Arc<RelPath> = file
1292 .path()
1293 .parent()
1294 .map(Arc::from)
1295 .unwrap_or_else(|| file.path().clone());
1296 let worktree_path = ProjectPath { worktree_id, path };
1297 self.language_server_ids_for_project_path(worktree_path, language, cx)
1298 } else {
1299 Vec::new()
1300 }
1301 }
1302
1303 fn language_servers_for_buffer<'a>(
1304 &'a self,
1305 buffer: &'a Buffer,
1306 cx: &'a mut App,
1307 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1308 self.language_server_ids_for_buffer(buffer, cx)
1309 .into_iter()
1310 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1311 LanguageServerState::Running {
1312 adapter, server, ..
1313 } => Some((adapter, server)),
1314 _ => None,
1315 })
1316 }
1317
1318 async fn execute_code_action_kind_locally(
1319 lsp_store: WeakEntity<LspStore>,
1320 mut buffers: Vec<Entity<Buffer>>,
1321 kind: CodeActionKind,
1322 push_to_history: bool,
1323 cx: &mut AsyncApp,
1324 ) -> anyhow::Result<ProjectTransaction> {
1325 // Do not allow multiple concurrent code actions requests for the
1326 // same buffer.
1327 lsp_store.update(cx, |this, cx| {
1328 let this = this.as_local_mut().unwrap();
1329 buffers.retain(|buffer| {
1330 this.buffers_being_formatted
1331 .insert(buffer.read(cx).remote_id())
1332 });
1333 })?;
1334 let _cleanup = defer({
1335 let this = lsp_store.clone();
1336 let mut cx = cx.clone();
1337 let buffers = &buffers;
1338 move || {
1339 this.update(&mut cx, |this, cx| {
1340 let this = this.as_local_mut().unwrap();
1341 for buffer in buffers {
1342 this.buffers_being_formatted
1343 .remove(&buffer.read(cx).remote_id());
1344 }
1345 })
1346 .ok();
1347 }
1348 });
1349 let mut project_transaction = ProjectTransaction::default();
1350
1351 for buffer in &buffers {
1352 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1353 buffer.update(cx, |buffer, cx| {
1354 lsp_store
1355 .as_local()
1356 .unwrap()
1357 .language_servers_for_buffer(buffer, cx)
1358 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1359 .collect::<Vec<_>>()
1360 })
1361 })?;
1362 for (_, language_server) in adapters_and_servers.iter() {
1363 let actions = Self::get_server_code_actions_from_action_kinds(
1364 &lsp_store,
1365 language_server.server_id(),
1366 vec![kind.clone()],
1367 buffer,
1368 cx,
1369 )
1370 .await?;
1371 Self::execute_code_actions_on_server(
1372 &lsp_store,
1373 language_server,
1374 actions,
1375 push_to_history,
1376 &mut project_transaction,
1377 cx,
1378 )
1379 .await?;
1380 }
1381 }
1382 Ok(project_transaction)
1383 }
1384
1385 async fn format_locally(
1386 lsp_store: WeakEntity<LspStore>,
1387 mut buffers: Vec<FormattableBuffer>,
1388 push_to_history: bool,
1389 trigger: FormatTrigger,
1390 logger: zlog::Logger,
1391 cx: &mut AsyncApp,
1392 ) -> anyhow::Result<ProjectTransaction> {
1393 // Do not allow multiple concurrent formatting requests for the
1394 // same buffer.
1395 lsp_store.update(cx, |this, cx| {
1396 let this = this.as_local_mut().unwrap();
1397 buffers.retain(|buffer| {
1398 this.buffers_being_formatted
1399 .insert(buffer.handle.read(cx).remote_id())
1400 });
1401 })?;
1402
1403 let _cleanup = defer({
1404 let this = lsp_store.clone();
1405 let mut cx = cx.clone();
1406 let buffers = &buffers;
1407 move || {
1408 this.update(&mut cx, |this, cx| {
1409 let this = this.as_local_mut().unwrap();
1410 for buffer in buffers {
1411 this.buffers_being_formatted
1412 .remove(&buffer.handle.read(cx).remote_id());
1413 }
1414 })
1415 .ok();
1416 }
1417 });
1418
1419 let mut project_transaction = ProjectTransaction::default();
1420
1421 for buffer in &buffers {
1422 zlog::debug!(
1423 logger =>
1424 "formatting buffer '{:?}'",
1425 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1426 );
1427 // Create an empty transaction to hold all of the formatting edits.
1428 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1429 // ensure no transactions created while formatting are
1430 // grouped with the previous transaction in the history
1431 // based on the transaction group interval
1432 buffer.finalize_last_transaction();
1433 buffer
1434 .start_transaction()
1435 .context("transaction already open")?;
1436 buffer.end_transaction(cx);
1437 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1438 buffer.finalize_last_transaction();
1439 anyhow::Ok(transaction_id)
1440 })?;
1441
1442 let result = Self::format_buffer_locally(
1443 lsp_store.clone(),
1444 buffer,
1445 formatting_transaction_id,
1446 trigger,
1447 logger,
1448 cx,
1449 )
1450 .await;
1451
1452 buffer.handle.update(cx, |buffer, cx| {
1453 let Some(formatting_transaction) =
1454 buffer.get_transaction(formatting_transaction_id).cloned()
1455 else {
1456 zlog::warn!(logger => "no formatting transaction");
1457 return;
1458 };
1459 if formatting_transaction.edit_ids.is_empty() {
1460 zlog::debug!(logger => "no changes made while formatting");
1461 buffer.forget_transaction(formatting_transaction_id);
1462 return;
1463 }
1464 if !push_to_history {
1465 zlog::trace!(logger => "forgetting format transaction");
1466 buffer.forget_transaction(formatting_transaction.id);
1467 }
1468 project_transaction
1469 .0
1470 .insert(cx.entity(), formatting_transaction);
1471 });
1472
1473 result?;
1474 }
1475
1476 Ok(project_transaction)
1477 }
1478
1479 async fn format_buffer_locally(
1480 lsp_store: WeakEntity<LspStore>,
1481 buffer: &FormattableBuffer,
1482 formatting_transaction_id: clock::Lamport,
1483 trigger: FormatTrigger,
1484 logger: zlog::Logger,
1485 cx: &mut AsyncApp,
1486 ) -> Result<()> {
1487 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1488 buffer.handle.update(cx, |buffer, cx| {
1489 let adapters_and_servers = lsp_store
1490 .as_local()
1491 .unwrap()
1492 .language_servers_for_buffer(buffer, cx)
1493 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1494 .collect::<Vec<_>>();
1495 let settings =
1496 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1497 .into_owned();
1498 (adapters_and_servers, settings)
1499 })
1500 })?;
1501
1502 /// Apply edits to the buffer that will become part of the formatting transaction.
1503 /// Fails if the buffer has been edited since the start of that transaction.
1504 fn extend_formatting_transaction(
1505 buffer: &FormattableBuffer,
1506 formatting_transaction_id: text::TransactionId,
1507 cx: &mut AsyncApp,
1508 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1509 ) -> anyhow::Result<()> {
1510 buffer.handle.update(cx, |buffer, cx| {
1511 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1512 if last_transaction_id != Some(formatting_transaction_id) {
1513 anyhow::bail!("Buffer edited while formatting. Aborting")
1514 }
1515 buffer.start_transaction();
1516 operation(buffer, cx);
1517 if let Some(transaction_id) = buffer.end_transaction(cx) {
1518 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1519 }
1520 Ok(())
1521 })
1522 }
1523
1524 // handle whitespace formatting
1525 if settings.remove_trailing_whitespace_on_save {
1526 zlog::trace!(logger => "removing trailing whitespace");
1527 let diff = buffer
1528 .handle
1529 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1530 .await;
1531 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1532 buffer.apply_diff(diff, cx);
1533 })?;
1534 }
1535
1536 if settings.ensure_final_newline_on_save {
1537 zlog::trace!(logger => "ensuring final newline");
1538 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1539 buffer.ensure_final_newline(cx);
1540 })?;
1541 }
1542
1543 // Formatter for `code_actions_on_format` that runs before
1544 // the rest of the formatters
1545 let mut code_actions_on_format_formatters = None;
1546 let should_run_code_actions_on_format = !matches!(
1547 (trigger, &settings.format_on_save),
1548 (FormatTrigger::Save, &FormatOnSave::Off)
1549 );
1550 if should_run_code_actions_on_format {
1551 let have_code_actions_to_run_on_format = settings
1552 .code_actions_on_format
1553 .values()
1554 .any(|enabled| *enabled);
1555 if have_code_actions_to_run_on_format {
1556 zlog::trace!(logger => "going to run code actions on format");
1557 code_actions_on_format_formatters = Some(
1558 settings
1559 .code_actions_on_format
1560 .iter()
1561 .filter_map(|(action, enabled)| enabled.then_some(action))
1562 .cloned()
1563 .map(Formatter::CodeAction)
1564 .collect::<Vec<_>>(),
1565 );
1566 }
1567 }
1568
1569 let formatters = match (trigger, &settings.format_on_save) {
1570 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1571 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1572 settings.formatter.as_ref()
1573 }
1574 };
1575
1576 let formatters = code_actions_on_format_formatters
1577 .iter()
1578 .flatten()
1579 .chain(formatters);
1580
1581 for formatter in formatters {
1582 let formatter = if formatter == &Formatter::Auto {
1583 if settings.prettier.allowed {
1584 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1585 &Formatter::Prettier
1586 } else {
1587 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1588 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1589 }
1590 } else {
1591 formatter
1592 };
1593 match formatter {
1594 Formatter::Auto => unreachable!("Auto resolved above"),
1595 Formatter::Prettier => {
1596 let logger = zlog::scoped!(logger => "prettier");
1597 zlog::trace!(logger => "formatting");
1598 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1599
1600 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1601 lsp_store.prettier_store().unwrap().downgrade()
1602 })?;
1603 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1604 .await
1605 .transpose()?;
1606 let Some(diff) = diff else {
1607 zlog::trace!(logger => "No changes");
1608 continue;
1609 };
1610
1611 extend_formatting_transaction(
1612 buffer,
1613 formatting_transaction_id,
1614 cx,
1615 |buffer, cx| {
1616 buffer.apply_diff(diff, cx);
1617 },
1618 )?;
1619 }
1620 Formatter::External { command, arguments } => {
1621 let logger = zlog::scoped!(logger => "command");
1622 zlog::trace!(logger => "formatting");
1623 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1624
1625 let diff = Self::format_via_external_command(
1626 buffer,
1627 command.as_ref(),
1628 arguments.as_deref(),
1629 cx,
1630 )
1631 .await
1632 .with_context(|| {
1633 format!("Failed to format buffer via external command: {}", command)
1634 })?;
1635 let Some(diff) = diff else {
1636 zlog::trace!(logger => "No changes");
1637 continue;
1638 };
1639
1640 extend_formatting_transaction(
1641 buffer,
1642 formatting_transaction_id,
1643 cx,
1644 |buffer, cx| {
1645 buffer.apply_diff(diff, cx);
1646 },
1647 )?;
1648 }
1649 Formatter::LanguageServer(specifier) => {
1650 let logger = zlog::scoped!(logger => "language-server");
1651 zlog::trace!(logger => "formatting");
1652 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1653
1654 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1655 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1656 continue;
1657 };
1658
1659 let language_server = match specifier {
1660 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1661 adapters_and_servers.iter().find_map(|(adapter, server)| {
1662 if adapter.name.0.as_ref() == name {
1663 Some(server.clone())
1664 } else {
1665 None
1666 }
1667 })
1668 }
1669 settings::LanguageServerFormatterSpecifier::Current => {
1670 adapters_and_servers.first().map(|e| e.1.clone())
1671 }
1672 };
1673
1674 let Some(language_server) = language_server else {
1675 log::debug!(
1676 "No language server found to format buffer '{:?}'. Skipping",
1677 buffer_path_abs.as_path().to_string_lossy()
1678 );
1679 continue;
1680 };
1681
1682 zlog::trace!(
1683 logger =>
1684 "Formatting buffer '{:?}' using language server '{:?}'",
1685 buffer_path_abs.as_path().to_string_lossy(),
1686 language_server.name()
1687 );
1688
1689 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1690 zlog::trace!(logger => "formatting ranges");
1691 Self::format_ranges_via_lsp(
1692 &lsp_store,
1693 &buffer.handle,
1694 ranges,
1695 buffer_path_abs,
1696 &language_server,
1697 &settings,
1698 cx,
1699 )
1700 .await
1701 .context("Failed to format ranges via language server")?
1702 } else {
1703 zlog::trace!(logger => "formatting full");
1704 Self::format_via_lsp(
1705 &lsp_store,
1706 &buffer.handle,
1707 buffer_path_abs,
1708 &language_server,
1709 &settings,
1710 cx,
1711 )
1712 .await
1713 .context("failed to format via language server")?
1714 };
1715
1716 if edits.is_empty() {
1717 zlog::trace!(logger => "No changes");
1718 continue;
1719 }
1720 extend_formatting_transaction(
1721 buffer,
1722 formatting_transaction_id,
1723 cx,
1724 |buffer, cx| {
1725 buffer.edit(edits, None, cx);
1726 },
1727 )?;
1728 }
1729 Formatter::CodeAction(code_action_name) => {
1730 let logger = zlog::scoped!(logger => "code-actions");
1731 zlog::trace!(logger => "formatting");
1732 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1733
1734 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1735 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1736 continue;
1737 };
1738
1739 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1740 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1741
1742 let mut actions_and_servers = Vec::new();
1743
1744 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1745 let actions_result = Self::get_server_code_actions_from_action_kinds(
1746 &lsp_store,
1747 language_server.server_id(),
1748 vec![code_action_kind.clone()],
1749 &buffer.handle,
1750 cx,
1751 )
1752 .await
1753 .with_context(|| {
1754 format!(
1755 "Failed to resolve code action {:?} with language server {}",
1756 code_action_kind,
1757 language_server.name()
1758 )
1759 });
1760 let Ok(actions) = actions_result else {
1761 // note: it may be better to set result to the error and break formatters here
1762 // but for now we try to execute the actions that we can resolve and skip the rest
1763 zlog::error!(
1764 logger =>
1765 "Failed to resolve code action {:?} with language server {}",
1766 code_action_kind,
1767 language_server.name()
1768 );
1769 continue;
1770 };
1771 for action in actions {
1772 actions_and_servers.push((action, index));
1773 }
1774 }
1775
1776 if actions_and_servers.is_empty() {
1777 zlog::warn!(logger => "No code actions were resolved, continuing");
1778 continue;
1779 }
1780
1781 'actions: for (mut action, server_index) in actions_and_servers {
1782 let server = &adapters_and_servers[server_index].1;
1783
1784 let describe_code_action = |action: &CodeAction| {
1785 format!(
1786 "code action '{}' with title \"{}\" on server {}",
1787 action
1788 .lsp_action
1789 .action_kind()
1790 .unwrap_or("unknown".into())
1791 .as_str(),
1792 action.lsp_action.title(),
1793 server.name(),
1794 )
1795 };
1796
1797 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1798
1799 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1800 zlog::error!(
1801 logger =>
1802 "Failed to resolve {}. Error: {}",
1803 describe_code_action(&action),
1804 err
1805 );
1806 continue;
1807 }
1808
1809 if let Some(edit) = action.lsp_action.edit().cloned() {
1810 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1811 // but filters out and logs warnings for code actions that require unreasonably
1812 // difficult handling on our part, such as:
1813 // - applying edits that call commands
1814 // which can result in arbitrary workspace edits being sent from the server that
1815 // have no way of being tied back to the command that initiated them (i.e. we
1816 // can't know which edits are part of the format request, or if the server is done sending
1817 // actions in response to the command)
1818 // - actions that create/delete/modify/rename files other than the one we are formatting
1819 // as we then would need to handle such changes correctly in the local history as well
1820 // as the remote history through the ProjectTransaction
1821 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1822 // Supporting these actions is not impossible, but not supported as of yet.
1823 if edit.changes.is_none() && edit.document_changes.is_none() {
1824 zlog::trace!(
1825 logger =>
1826 "No changes for code action. Skipping {}",
1827 describe_code_action(&action),
1828 );
1829 continue;
1830 }
1831
1832 let mut operations = Vec::new();
1833 if let Some(document_changes) = edit.document_changes {
1834 match document_changes {
1835 lsp::DocumentChanges::Edits(edits) => operations.extend(
1836 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1837 ),
1838 lsp::DocumentChanges::Operations(ops) => operations = ops,
1839 }
1840 } else if let Some(changes) = edit.changes {
1841 operations.extend(changes.into_iter().map(|(uri, edits)| {
1842 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1843 text_document:
1844 lsp::OptionalVersionedTextDocumentIdentifier {
1845 uri,
1846 version: None,
1847 },
1848 edits: edits.into_iter().map(Edit::Plain).collect(),
1849 })
1850 }));
1851 }
1852
1853 let mut edits = Vec::with_capacity(operations.len());
1854
1855 if operations.is_empty() {
1856 zlog::trace!(
1857 logger =>
1858 "No changes for code action. Skipping {}",
1859 describe_code_action(&action),
1860 );
1861 continue;
1862 }
1863 for operation in operations {
1864 let op = match operation {
1865 lsp::DocumentChangeOperation::Edit(op) => op,
1866 lsp::DocumentChangeOperation::Op(_) => {
1867 zlog::warn!(
1868 logger =>
1869 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1870 describe_code_action(&action),
1871 );
1872 continue 'actions;
1873 }
1874 };
1875 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1876 zlog::warn!(
1877 logger =>
1878 "Failed to convert URI '{:?}' to file path. Skipping {}",
1879 &op.text_document.uri,
1880 describe_code_action(&action),
1881 );
1882 continue 'actions;
1883 };
1884 if &file_path != buffer_path_abs {
1885 zlog::warn!(
1886 logger =>
1887 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1888 file_path,
1889 buffer_path_abs,
1890 describe_code_action(&action),
1891 );
1892 continue 'actions;
1893 }
1894
1895 let mut lsp_edits = Vec::new();
1896 for edit in op.edits {
1897 match edit {
1898 Edit::Plain(edit) => {
1899 if !lsp_edits.contains(&edit) {
1900 lsp_edits.push(edit);
1901 }
1902 }
1903 Edit::Annotated(edit) => {
1904 if !lsp_edits.contains(&edit.text_edit) {
1905 lsp_edits.push(edit.text_edit);
1906 }
1907 }
1908 Edit::Snippet(_) => {
1909 zlog::warn!(
1910 logger =>
1911 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1912 describe_code_action(&action),
1913 );
1914 continue 'actions;
1915 }
1916 }
1917 }
1918 let edits_result = lsp_store
1919 .update(cx, |lsp_store, cx| {
1920 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1921 &buffer.handle,
1922 lsp_edits,
1923 server.server_id(),
1924 op.text_document.version,
1925 cx,
1926 )
1927 })?
1928 .await;
1929 let Ok(resolved_edits) = edits_result else {
1930 zlog::warn!(
1931 logger =>
1932 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1933 buffer_path_abs.as_path(),
1934 describe_code_action(&action),
1935 );
1936 continue 'actions;
1937 };
1938 edits.extend(resolved_edits);
1939 }
1940
1941 if edits.is_empty() {
1942 zlog::warn!(logger => "No edits resolved from LSP");
1943 continue;
1944 }
1945
1946 extend_formatting_transaction(
1947 buffer,
1948 formatting_transaction_id,
1949 cx,
1950 |buffer, cx| {
1951 zlog::info!(
1952 "Applying edits {edits:?}. Content: {:?}",
1953 buffer.text()
1954 );
1955 buffer.edit(edits, None, cx);
1956 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1957 },
1958 )?;
1959 }
1960
1961 if let Some(command) = action.lsp_action.command() {
1962 zlog::warn!(
1963 logger =>
1964 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1965 &command.command,
1966 );
1967
1968 // bail early if command is invalid
1969 let server_capabilities = server.capabilities();
1970 let available_commands = server_capabilities
1971 .execute_command_provider
1972 .as_ref()
1973 .map(|options| options.commands.as_slice())
1974 .unwrap_or_default();
1975 if !available_commands.contains(&command.command) {
1976 zlog::warn!(
1977 logger =>
1978 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1979 command.command,
1980 server.name(),
1981 );
1982 continue;
1983 }
1984
1985 // noop so we just ensure buffer hasn't been edited since resolving code actions
1986 extend_formatting_transaction(
1987 buffer,
1988 formatting_transaction_id,
1989 cx,
1990 |_, _| {},
1991 )?;
1992 zlog::info!(logger => "Executing command {}", &command.command);
1993
1994 lsp_store.update(cx, |this, _| {
1995 this.as_local_mut()
1996 .unwrap()
1997 .last_workspace_edits_by_language_server
1998 .remove(&server.server_id());
1999 })?;
2000
2001 let execute_command_result = server
2002 .request::<lsp::request::ExecuteCommand>(
2003 lsp::ExecuteCommandParams {
2004 command: command.command.clone(),
2005 arguments: command.arguments.clone().unwrap_or_default(),
2006 ..Default::default()
2007 },
2008 )
2009 .await
2010 .into_response();
2011
2012 if execute_command_result.is_err() {
2013 zlog::error!(
2014 logger =>
2015 "Failed to execute command '{}' as part of {}",
2016 &command.command,
2017 describe_code_action(&action),
2018 );
2019 continue 'actions;
2020 }
2021
2022 let mut project_transaction_command =
2023 lsp_store.update(cx, |this, _| {
2024 this.as_local_mut()
2025 .unwrap()
2026 .last_workspace_edits_by_language_server
2027 .remove(&server.server_id())
2028 .unwrap_or_default()
2029 })?;
2030
2031 if let Some(transaction) =
2032 project_transaction_command.0.remove(&buffer.handle)
2033 {
2034 zlog::trace!(
2035 logger =>
2036 "Successfully captured {} edits that resulted from command {}",
2037 transaction.edit_ids.len(),
2038 &command.command,
2039 );
2040 let transaction_id_project_transaction = transaction.id;
2041 buffer.handle.update(cx, |buffer, _| {
2042 // it may have been removed from history if push_to_history was
2043 // false in deserialize_workspace_edit. If so push it so we
2044 // can merge it with the format transaction
2045 // and pop the combined transaction off the history stack
2046 // later if push_to_history is false
2047 if buffer.get_transaction(transaction.id).is_none() {
2048 buffer.push_transaction(transaction, Instant::now());
2049 }
2050 buffer.merge_transactions(
2051 transaction_id_project_transaction,
2052 formatting_transaction_id,
2053 );
2054 });
2055 }
2056
2057 if !project_transaction_command.0.is_empty() {
2058 let mut extra_buffers = String::new();
2059 for buffer in project_transaction_command.0.keys() {
2060 buffer.read_with(cx, |b, cx| {
2061 if let Some(path) = b.project_path(cx) {
2062 if !extra_buffers.is_empty() {
2063 extra_buffers.push_str(", ");
2064 }
2065 extra_buffers.push_str(path.path.as_unix_str());
2066 }
2067 });
2068 }
2069 zlog::warn!(
2070 logger =>
2071 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2072 &command.command,
2073 extra_buffers,
2074 );
2075 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2076 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2077 // add it so it's included, and merge it into the format transaction when its created later
2078 }
2079 }
2080 }
2081 }
2082 }
2083 }
2084
2085 Ok(())
2086 }
2087
2088 pub async fn format_ranges_via_lsp(
2089 this: &WeakEntity<LspStore>,
2090 buffer_handle: &Entity<Buffer>,
2091 ranges: &[Range<Anchor>],
2092 abs_path: &Path,
2093 language_server: &Arc<LanguageServer>,
2094 settings: &LanguageSettings,
2095 cx: &mut AsyncApp,
2096 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2097 let capabilities = &language_server.capabilities();
2098 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2099 if range_formatting_provider == Some(&OneOf::Left(false)) {
2100 anyhow::bail!(
2101 "{} language server does not support range formatting",
2102 language_server.name()
2103 );
2104 }
2105
2106 let uri = file_path_to_lsp_url(abs_path)?;
2107 let text_document = lsp::TextDocumentIdentifier::new(uri);
2108
2109 let lsp_edits = {
2110 let mut lsp_ranges = Vec::new();
2111 this.update(cx, |_this, cx| {
2112 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2113 // not have been sent to the language server. This seems like a fairly systemic
2114 // issue, though, the resolution probably is not specific to formatting.
2115 //
2116 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2117 // LSP.
2118 let snapshot = buffer_handle.read(cx).snapshot();
2119 for range in ranges {
2120 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2121 }
2122 anyhow::Ok(())
2123 })??;
2124
2125 let mut edits = None;
2126 for range in lsp_ranges {
2127 if let Some(mut edit) = language_server
2128 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2129 text_document: text_document.clone(),
2130 range,
2131 options: lsp_command::lsp_formatting_options(settings),
2132 work_done_progress_params: Default::default(),
2133 })
2134 .await
2135 .into_response()?
2136 {
2137 edits.get_or_insert_with(Vec::new).append(&mut edit);
2138 }
2139 }
2140 edits
2141 };
2142
2143 if let Some(lsp_edits) = lsp_edits {
2144 this.update(cx, |this, cx| {
2145 this.as_local_mut().unwrap().edits_from_lsp(
2146 buffer_handle,
2147 lsp_edits,
2148 language_server.server_id(),
2149 None,
2150 cx,
2151 )
2152 })?
2153 .await
2154 } else {
2155 Ok(Vec::with_capacity(0))
2156 }
2157 }
2158
2159 async fn format_via_lsp(
2160 this: &WeakEntity<LspStore>,
2161 buffer: &Entity<Buffer>,
2162 abs_path: &Path,
2163 language_server: &Arc<LanguageServer>,
2164 settings: &LanguageSettings,
2165 cx: &mut AsyncApp,
2166 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2167 let logger = zlog::scoped!("lsp_format");
2168 zlog::debug!(logger => "Formatting via LSP");
2169
2170 let uri = file_path_to_lsp_url(abs_path)?;
2171 let text_document = lsp::TextDocumentIdentifier::new(uri);
2172 let capabilities = &language_server.capabilities();
2173
2174 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2175 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2176
2177 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2178 let _timer = zlog::time!(logger => "format-full");
2179 language_server
2180 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2181 text_document,
2182 options: lsp_command::lsp_formatting_options(settings),
2183 work_done_progress_params: Default::default(),
2184 })
2185 .await
2186 .into_response()?
2187 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2188 let _timer = zlog::time!(logger => "format-range");
2189 let buffer_start = lsp::Position::new(0, 0);
2190 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2191 language_server
2192 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2193 text_document: text_document.clone(),
2194 range: lsp::Range::new(buffer_start, buffer_end),
2195 options: lsp_command::lsp_formatting_options(settings),
2196 work_done_progress_params: Default::default(),
2197 })
2198 .await
2199 .into_response()?
2200 } else {
2201 None
2202 };
2203
2204 if let Some(lsp_edits) = lsp_edits {
2205 this.update(cx, |this, cx| {
2206 this.as_local_mut().unwrap().edits_from_lsp(
2207 buffer,
2208 lsp_edits,
2209 language_server.server_id(),
2210 None,
2211 cx,
2212 )
2213 })?
2214 .await
2215 } else {
2216 Ok(Vec::with_capacity(0))
2217 }
2218 }
2219
2220 async fn format_via_external_command(
2221 buffer: &FormattableBuffer,
2222 command: &str,
2223 arguments: Option<&[String]>,
2224 cx: &mut AsyncApp,
2225 ) -> Result<Option<Diff>> {
2226 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2227 let file = File::from_dyn(buffer.file())?;
2228 let worktree = file.worktree.read(cx);
2229 let mut worktree_path = worktree.abs_path().to_path_buf();
2230 if worktree.root_entry()?.is_file() {
2231 worktree_path.pop();
2232 }
2233 Some(worktree_path)
2234 });
2235
2236 let mut child = util::command::new_smol_command(command);
2237
2238 if let Some(buffer_env) = buffer.env.as_ref() {
2239 child.envs(buffer_env);
2240 }
2241
2242 if let Some(working_dir_path) = working_dir_path {
2243 child.current_dir(working_dir_path);
2244 }
2245
2246 if let Some(arguments) = arguments {
2247 child.args(arguments.iter().map(|arg| {
2248 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2249 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2250 } else {
2251 arg.replace("{buffer_path}", "Untitled")
2252 }
2253 }));
2254 }
2255
2256 let mut child = child
2257 .stdin(smol::process::Stdio::piped())
2258 .stdout(smol::process::Stdio::piped())
2259 .stderr(smol::process::Stdio::piped())
2260 .spawn()?;
2261
2262 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2263 let text = buffer
2264 .handle
2265 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2266 for chunk in text.chunks() {
2267 stdin.write_all(chunk.as_bytes()).await?;
2268 }
2269 stdin.flush().await?;
2270
2271 let output = child.output().await?;
2272 anyhow::ensure!(
2273 output.status.success(),
2274 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2275 output.status.code(),
2276 String::from_utf8_lossy(&output.stdout),
2277 String::from_utf8_lossy(&output.stderr),
2278 );
2279
2280 let stdout = String::from_utf8(output.stdout)?;
2281 Ok(Some(
2282 buffer
2283 .handle
2284 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2285 .await,
2286 ))
2287 }
2288
2289 async fn try_resolve_code_action(
2290 lang_server: &LanguageServer,
2291 action: &mut CodeAction,
2292 ) -> anyhow::Result<()> {
2293 match &mut action.lsp_action {
2294 LspAction::Action(lsp_action) => {
2295 if !action.resolved
2296 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2297 && lsp_action.data.is_some()
2298 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2299 {
2300 **lsp_action = lang_server
2301 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2302 .await
2303 .into_response()?;
2304 }
2305 }
2306 LspAction::CodeLens(lens) => {
2307 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2308 *lens = lang_server
2309 .request::<lsp::request::CodeLensResolve>(lens.clone())
2310 .await
2311 .into_response()?;
2312 }
2313 }
2314 LspAction::Command(_) => {}
2315 }
2316
2317 action.resolved = true;
2318 anyhow::Ok(())
2319 }
2320
2321 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2322 let buffer = buffer_handle.read(cx);
2323
2324 let file = buffer.file().cloned();
2325
2326 let Some(file) = File::from_dyn(file.as_ref()) else {
2327 return;
2328 };
2329 if !file.is_local() {
2330 return;
2331 }
2332 let path = ProjectPath::from_file(file, cx);
2333 let worktree_id = file.worktree_id(cx);
2334 let language = buffer.language().cloned();
2335
2336 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2337 for (server_id, diagnostics) in
2338 diagnostics.get(file.path()).cloned().unwrap_or_default()
2339 {
2340 self.update_buffer_diagnostics(
2341 buffer_handle,
2342 server_id,
2343 None,
2344 None,
2345 None,
2346 Vec::new(),
2347 diagnostics,
2348 cx,
2349 )
2350 .log_err();
2351 }
2352 }
2353 let Some(language) = language else {
2354 return;
2355 };
2356 let Some(snapshot) = self
2357 .worktree_store
2358 .read(cx)
2359 .worktree_for_id(worktree_id, cx)
2360 .map(|worktree| worktree.read(cx).snapshot())
2361 else {
2362 return;
2363 };
2364 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2365
2366 for server_id in
2367 self.lsp_tree
2368 .get(path, language.name(), language.manifest(), &delegate, cx)
2369 {
2370 let server = self
2371 .language_servers
2372 .get(&server_id)
2373 .and_then(|server_state| {
2374 if let LanguageServerState::Running { server, .. } = server_state {
2375 Some(server.clone())
2376 } else {
2377 None
2378 }
2379 });
2380 let server = match server {
2381 Some(server) => server,
2382 None => continue,
2383 };
2384
2385 buffer_handle.update(cx, |buffer, cx| {
2386 buffer.set_completion_triggers(
2387 server.server_id(),
2388 server
2389 .capabilities()
2390 .completion_provider
2391 .as_ref()
2392 .and_then(|provider| {
2393 provider
2394 .trigger_characters
2395 .as_ref()
2396 .map(|characters| characters.iter().cloned().collect())
2397 })
2398 .unwrap_or_default(),
2399 cx,
2400 );
2401 });
2402 }
2403 }
2404
2405 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2406 buffer.update(cx, |buffer, cx| {
2407 let Some(language) = buffer.language() else {
2408 return;
2409 };
2410 let path = ProjectPath {
2411 worktree_id: old_file.worktree_id(cx),
2412 path: old_file.path.clone(),
2413 };
2414 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2415 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2416 buffer.set_completion_triggers(server_id, Default::default(), cx);
2417 }
2418 });
2419 }
2420
2421 fn update_buffer_diagnostics(
2422 &mut self,
2423 buffer: &Entity<Buffer>,
2424 server_id: LanguageServerId,
2425 registration_id: Option<Option<SharedString>>,
2426 result_id: Option<SharedString>,
2427 version: Option<i32>,
2428 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2429 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2430 cx: &mut Context<LspStore>,
2431 ) -> Result<()> {
2432 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2433 Ordering::Equal
2434 .then_with(|| b.is_primary.cmp(&a.is_primary))
2435 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2436 .then_with(|| a.severity.cmp(&b.severity))
2437 .then_with(|| a.message.cmp(&b.message))
2438 }
2439
2440 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2441 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2442 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2443
2444 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2445 Ordering::Equal
2446 .then_with(|| a.range.start.cmp(&b.range.start))
2447 .then_with(|| b.range.end.cmp(&a.range.end))
2448 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2449 });
2450
2451 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2452
2453 let edits_since_save = std::cell::LazyCell::new(|| {
2454 let saved_version = buffer.read(cx).saved_version();
2455 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2456 });
2457
2458 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2459
2460 for (new_diagnostic, entry) in diagnostics {
2461 let start;
2462 let end;
2463 if new_diagnostic && entry.diagnostic.is_disk_based {
2464 // Some diagnostics are based on files on disk instead of buffers'
2465 // current contents. Adjust these diagnostics' ranges to reflect
2466 // any unsaved edits.
2467 // Do not alter the reused ones though, as their coordinates were stored as anchors
2468 // and were properly adjusted on reuse.
2469 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2470 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2471 } else {
2472 start = entry.range.start;
2473 end = entry.range.end;
2474 }
2475
2476 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2477 ..snapshot.clip_point_utf16(end, Bias::Right);
2478
2479 // Expand empty ranges by one codepoint
2480 if range.start == range.end {
2481 // This will be go to the next boundary when being clipped
2482 range.end.column += 1;
2483 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2484 if range.start == range.end && range.end.column > 0 {
2485 range.start.column -= 1;
2486 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2487 }
2488 }
2489
2490 sanitized_diagnostics.push(DiagnosticEntry {
2491 range,
2492 diagnostic: entry.diagnostic,
2493 });
2494 }
2495 drop(edits_since_save);
2496
2497 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2498 buffer.update(cx, |buffer, cx| {
2499 if let Some(registration_id) = registration_id {
2500 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2501 self.buffer_pull_diagnostics_result_ids
2502 .entry(server_id)
2503 .or_default()
2504 .entry(registration_id)
2505 .or_default()
2506 .insert(abs_path, result_id);
2507 }
2508 }
2509
2510 buffer.update_diagnostics(server_id, set, cx)
2511 });
2512
2513 Ok(())
2514 }
2515
2516 fn register_language_server_for_invisible_worktree(
2517 &mut self,
2518 worktree: &Entity<Worktree>,
2519 language_server_id: LanguageServerId,
2520 cx: &mut App,
2521 ) {
2522 let worktree = worktree.read(cx);
2523 let worktree_id = worktree.id();
2524 debug_assert!(!worktree.is_visible());
2525 let Some(mut origin_seed) = self
2526 .language_server_ids
2527 .iter()
2528 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2529 else {
2530 return;
2531 };
2532 origin_seed.worktree_id = worktree_id;
2533 self.language_server_ids
2534 .entry(origin_seed)
2535 .or_insert_with(|| UnifiedLanguageServer {
2536 id: language_server_id,
2537 project_roots: Default::default(),
2538 });
2539 }
2540
2541 fn register_buffer_with_language_servers(
2542 &mut self,
2543 buffer_handle: &Entity<Buffer>,
2544 only_register_servers: HashSet<LanguageServerSelector>,
2545 cx: &mut Context<LspStore>,
2546 ) {
2547 let buffer = buffer_handle.read(cx);
2548 let buffer_id = buffer.remote_id();
2549
2550 let Some(file) = File::from_dyn(buffer.file()) else {
2551 return;
2552 };
2553 if !file.is_local() {
2554 return;
2555 }
2556
2557 let abs_path = file.abs_path(cx);
2558 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2559 return;
2560 };
2561 let initial_snapshot = buffer.text_snapshot();
2562 let worktree_id = file.worktree_id(cx);
2563
2564 let Some(language) = buffer.language().cloned() else {
2565 return;
2566 };
2567 let path: Arc<RelPath> = file
2568 .path()
2569 .parent()
2570 .map(Arc::from)
2571 .unwrap_or_else(|| file.path().clone());
2572 let Some(worktree) = self
2573 .worktree_store
2574 .read(cx)
2575 .worktree_for_id(worktree_id, cx)
2576 else {
2577 return;
2578 };
2579 let language_name = language.name();
2580 let (reused, delegate, servers) = self
2581 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2582 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2583 .unwrap_or_else(|| {
2584 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2585 let delegate: Arc<dyn ManifestDelegate> =
2586 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2587
2588 let servers = self
2589 .lsp_tree
2590 .walk(
2591 ProjectPath { worktree_id, path },
2592 language.name(),
2593 language.manifest(),
2594 &delegate,
2595 cx,
2596 )
2597 .collect::<Vec<_>>();
2598 (false, lsp_delegate, servers)
2599 });
2600 let servers_and_adapters = servers
2601 .into_iter()
2602 .filter_map(|server_node| {
2603 if reused && server_node.server_id().is_none() {
2604 return None;
2605 }
2606 if !only_register_servers.is_empty() {
2607 if let Some(server_id) = server_node.server_id()
2608 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2609 {
2610 return None;
2611 }
2612 if let Some(name) = server_node.name()
2613 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2614 {
2615 return None;
2616 }
2617 }
2618
2619 let server_id = server_node.server_id_or_init(|disposition| {
2620 let path = &disposition.path;
2621
2622 {
2623 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2624
2625 let server_id = self.get_or_insert_language_server(
2626 &worktree,
2627 delegate.clone(),
2628 disposition,
2629 &language_name,
2630 cx,
2631 );
2632
2633 if let Some(state) = self.language_servers.get(&server_id)
2634 && let Ok(uri) = uri
2635 {
2636 state.add_workspace_folder(uri);
2637 };
2638 server_id
2639 }
2640 })?;
2641 let server_state = self.language_servers.get(&server_id)?;
2642 if let LanguageServerState::Running {
2643 server, adapter, ..
2644 } = server_state
2645 {
2646 Some((server.clone(), adapter.clone()))
2647 } else {
2648 None
2649 }
2650 })
2651 .collect::<Vec<_>>();
2652 for (server, adapter) in servers_and_adapters {
2653 buffer_handle.update(cx, |buffer, cx| {
2654 buffer.set_completion_triggers(
2655 server.server_id(),
2656 server
2657 .capabilities()
2658 .completion_provider
2659 .as_ref()
2660 .and_then(|provider| {
2661 provider
2662 .trigger_characters
2663 .as_ref()
2664 .map(|characters| characters.iter().cloned().collect())
2665 })
2666 .unwrap_or_default(),
2667 cx,
2668 );
2669 });
2670
2671 let snapshot = LspBufferSnapshot {
2672 version: 0,
2673 snapshot: initial_snapshot.clone(),
2674 };
2675
2676 let mut registered = false;
2677 self.buffer_snapshots
2678 .entry(buffer_id)
2679 .or_default()
2680 .entry(server.server_id())
2681 .or_insert_with(|| {
2682 registered = true;
2683 server.register_buffer(
2684 uri.clone(),
2685 adapter.language_id(&language.name()),
2686 0,
2687 initial_snapshot.text(),
2688 );
2689
2690 vec![snapshot]
2691 });
2692
2693 self.buffers_opened_in_servers
2694 .entry(buffer_id)
2695 .or_default()
2696 .insert(server.server_id());
2697 if registered {
2698 cx.emit(LspStoreEvent::LanguageServerUpdate {
2699 language_server_id: server.server_id(),
2700 name: None,
2701 message: proto::update_language_server::Variant::RegisteredForBuffer(
2702 proto::RegisteredForBuffer {
2703 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2704 buffer_id: buffer_id.to_proto(),
2705 },
2706 ),
2707 });
2708 }
2709 }
2710 }
2711
2712 fn reuse_existing_language_server<'lang_name>(
2713 &self,
2714 server_tree: &LanguageServerTree,
2715 worktree: &Entity<Worktree>,
2716 language_name: &'lang_name LanguageName,
2717 cx: &mut App,
2718 ) -> Option<(
2719 Arc<LocalLspAdapterDelegate>,
2720 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2721 )> {
2722 if worktree.read(cx).is_visible() {
2723 return None;
2724 }
2725
2726 let worktree_store = self.worktree_store.read(cx);
2727 let servers = server_tree
2728 .instances
2729 .iter()
2730 .filter(|(worktree_id, _)| {
2731 worktree_store
2732 .worktree_for_id(**worktree_id, cx)
2733 .is_some_and(|worktree| worktree.read(cx).is_visible())
2734 })
2735 .flat_map(|(worktree_id, servers)| {
2736 servers
2737 .roots
2738 .iter()
2739 .flat_map(|(_, language_servers)| language_servers)
2740 .map(move |(_, (server_node, server_languages))| {
2741 (worktree_id, server_node, server_languages)
2742 })
2743 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2744 .map(|(worktree_id, server_node, _)| {
2745 (
2746 *worktree_id,
2747 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2748 )
2749 })
2750 })
2751 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2752 acc.entry(worktree_id)
2753 .or_insert_with(Vec::new)
2754 .push(server_node);
2755 acc
2756 })
2757 .into_values()
2758 .max_by_key(|servers| servers.len())?;
2759
2760 let worktree_id = worktree.read(cx).id();
2761 let apply = move |tree: &mut LanguageServerTree| {
2762 for server_node in &servers {
2763 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2764 }
2765 servers
2766 };
2767
2768 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2769 Some((delegate, apply))
2770 }
2771
2772 pub(crate) fn unregister_old_buffer_from_language_servers(
2773 &mut self,
2774 buffer: &Entity<Buffer>,
2775 old_file: &File,
2776 cx: &mut App,
2777 ) {
2778 let old_path = match old_file.as_local() {
2779 Some(local) => local.abs_path(cx),
2780 None => return,
2781 };
2782
2783 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2784 debug_panic!("{old_path:?} is not parseable as an URI");
2785 return;
2786 };
2787 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2788 }
2789
2790 pub(crate) fn unregister_buffer_from_language_servers(
2791 &mut self,
2792 buffer: &Entity<Buffer>,
2793 file_url: &lsp::Uri,
2794 cx: &mut App,
2795 ) {
2796 buffer.update(cx, |buffer, cx| {
2797 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2798
2799 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2800 if snapshots
2801 .as_mut()
2802 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2803 {
2804 language_server.unregister_buffer(file_url.clone());
2805 }
2806 }
2807 });
2808 }
2809
2810 fn buffer_snapshot_for_lsp_version(
2811 &mut self,
2812 buffer: &Entity<Buffer>,
2813 server_id: LanguageServerId,
2814 version: Option<i32>,
2815 cx: &App,
2816 ) -> Result<TextBufferSnapshot> {
2817 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2818
2819 if let Some(version) = version {
2820 let buffer_id = buffer.read(cx).remote_id();
2821 let snapshots = if let Some(snapshots) = self
2822 .buffer_snapshots
2823 .get_mut(&buffer_id)
2824 .and_then(|m| m.get_mut(&server_id))
2825 {
2826 snapshots
2827 } else if version == 0 {
2828 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2829 // We detect this case and treat it as if the version was `None`.
2830 return Ok(buffer.read(cx).text_snapshot());
2831 } else {
2832 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2833 };
2834
2835 let found_snapshot = snapshots
2836 .binary_search_by_key(&version, |e| e.version)
2837 .map(|ix| snapshots[ix].snapshot.clone())
2838 .map_err(|_| {
2839 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2840 })?;
2841
2842 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2843 Ok(found_snapshot)
2844 } else {
2845 Ok((buffer.read(cx)).text_snapshot())
2846 }
2847 }
2848
2849 async fn get_server_code_actions_from_action_kinds(
2850 lsp_store: &WeakEntity<LspStore>,
2851 language_server_id: LanguageServerId,
2852 code_action_kinds: Vec<lsp::CodeActionKind>,
2853 buffer: &Entity<Buffer>,
2854 cx: &mut AsyncApp,
2855 ) -> Result<Vec<CodeAction>> {
2856 let actions = lsp_store
2857 .update(cx, move |this, cx| {
2858 let request = GetCodeActions {
2859 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2860 kinds: Some(code_action_kinds),
2861 };
2862 let server = LanguageServerToQuery::Other(language_server_id);
2863 this.request_lsp(buffer.clone(), server, request, cx)
2864 })?
2865 .await?;
2866 Ok(actions)
2867 }
2868
2869 pub async fn execute_code_actions_on_server(
2870 lsp_store: &WeakEntity<LspStore>,
2871 language_server: &Arc<LanguageServer>,
2872
2873 actions: Vec<CodeAction>,
2874 push_to_history: bool,
2875 project_transaction: &mut ProjectTransaction,
2876 cx: &mut AsyncApp,
2877 ) -> anyhow::Result<()> {
2878 for mut action in actions {
2879 Self::try_resolve_code_action(language_server, &mut action)
2880 .await
2881 .context("resolving a formatting code action")?;
2882
2883 if let Some(edit) = action.lsp_action.edit() {
2884 if edit.changes.is_none() && edit.document_changes.is_none() {
2885 continue;
2886 }
2887
2888 let new = Self::deserialize_workspace_edit(
2889 lsp_store.upgrade().context("project dropped")?,
2890 edit.clone(),
2891 push_to_history,
2892 language_server.clone(),
2893 cx,
2894 )
2895 .await?;
2896 project_transaction.0.extend(new.0);
2897 }
2898
2899 if let Some(command) = action.lsp_action.command() {
2900 let server_capabilities = language_server.capabilities();
2901 let available_commands = server_capabilities
2902 .execute_command_provider
2903 .as_ref()
2904 .map(|options| options.commands.as_slice())
2905 .unwrap_or_default();
2906 if available_commands.contains(&command.command) {
2907 lsp_store.update(cx, |lsp_store, _| {
2908 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2909 mode.last_workspace_edits_by_language_server
2910 .remove(&language_server.server_id());
2911 }
2912 })?;
2913
2914 language_server
2915 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2916 command: command.command.clone(),
2917 arguments: command.arguments.clone().unwrap_or_default(),
2918 ..Default::default()
2919 })
2920 .await
2921 .into_response()
2922 .context("execute command")?;
2923
2924 lsp_store.update(cx, |this, _| {
2925 if let LspStoreMode::Local(mode) = &mut this.mode {
2926 project_transaction.0.extend(
2927 mode.last_workspace_edits_by_language_server
2928 .remove(&language_server.server_id())
2929 .unwrap_or_default()
2930 .0,
2931 )
2932 }
2933 })?;
2934 } else {
2935 log::warn!(
2936 "Cannot execute a command {} not listed in the language server capabilities",
2937 command.command
2938 )
2939 }
2940 }
2941 }
2942 Ok(())
2943 }
2944
2945 pub async fn deserialize_text_edits(
2946 this: Entity<LspStore>,
2947 buffer_to_edit: Entity<Buffer>,
2948 edits: Vec<lsp::TextEdit>,
2949 push_to_history: bool,
2950 _: Arc<CachedLspAdapter>,
2951 language_server: Arc<LanguageServer>,
2952 cx: &mut AsyncApp,
2953 ) -> Result<Option<Transaction>> {
2954 let edits = this
2955 .update(cx, |this, cx| {
2956 this.as_local_mut().unwrap().edits_from_lsp(
2957 &buffer_to_edit,
2958 edits,
2959 language_server.server_id(),
2960 None,
2961 cx,
2962 )
2963 })
2964 .await?;
2965
2966 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2967 buffer.finalize_last_transaction();
2968 buffer.start_transaction();
2969 for (range, text) in edits {
2970 buffer.edit([(range, text)], None, cx);
2971 }
2972
2973 if buffer.end_transaction(cx).is_some() {
2974 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2975 if !push_to_history {
2976 buffer.forget_transaction(transaction.id);
2977 }
2978 Some(transaction)
2979 } else {
2980 None
2981 }
2982 });
2983
2984 Ok(transaction)
2985 }
2986
2987 #[allow(clippy::type_complexity)]
2988 pub(crate) fn edits_from_lsp(
2989 &mut self,
2990 buffer: &Entity<Buffer>,
2991 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2992 server_id: LanguageServerId,
2993 version: Option<i32>,
2994 cx: &mut Context<LspStore>,
2995 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2996 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2997 cx.background_spawn(async move {
2998 let snapshot = snapshot?;
2999 let mut lsp_edits = lsp_edits
3000 .into_iter()
3001 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3002 .collect::<Vec<_>>();
3003
3004 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3005
3006 let mut lsp_edits = lsp_edits.into_iter().peekable();
3007 let mut edits = Vec::new();
3008 while let Some((range, mut new_text)) = lsp_edits.next() {
3009 // Clip invalid ranges provided by the language server.
3010 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3011 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3012
3013 // Combine any LSP edits that are adjacent.
3014 //
3015 // Also, combine LSP edits that are separated from each other by only
3016 // a newline. This is important because for some code actions,
3017 // Rust-analyzer rewrites the entire buffer via a series of edits that
3018 // are separated by unchanged newline characters.
3019 //
3020 // In order for the diffing logic below to work properly, any edits that
3021 // cancel each other out must be combined into one.
3022 while let Some((next_range, next_text)) = lsp_edits.peek() {
3023 if next_range.start.0 > range.end {
3024 if next_range.start.0.row > range.end.row + 1
3025 || next_range.start.0.column > 0
3026 || snapshot.clip_point_utf16(
3027 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3028 Bias::Left,
3029 ) > range.end
3030 {
3031 break;
3032 }
3033 new_text.push('\n');
3034 }
3035 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3036 new_text.push_str(next_text);
3037 lsp_edits.next();
3038 }
3039
3040 // For multiline edits, perform a diff of the old and new text so that
3041 // we can identify the changes more precisely, preserving the locations
3042 // of any anchors positioned in the unchanged regions.
3043 if range.end.row > range.start.row {
3044 let offset = range.start.to_offset(&snapshot);
3045 let old_text = snapshot.text_for_range(range).collect::<String>();
3046 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3047 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3048 (
3049 snapshot.anchor_after(offset + range.start)
3050 ..snapshot.anchor_before(offset + range.end),
3051 replacement,
3052 )
3053 }));
3054 } else if range.end == range.start {
3055 let anchor = snapshot.anchor_after(range.start);
3056 edits.push((anchor..anchor, new_text.into()));
3057 } else {
3058 let edit_start = snapshot.anchor_after(range.start);
3059 let edit_end = snapshot.anchor_before(range.end);
3060 edits.push((edit_start..edit_end, new_text.into()));
3061 }
3062 }
3063
3064 Ok(edits)
3065 })
3066 }
3067
3068 pub(crate) async fn deserialize_workspace_edit(
3069 this: Entity<LspStore>,
3070 edit: lsp::WorkspaceEdit,
3071 push_to_history: bool,
3072 language_server: Arc<LanguageServer>,
3073 cx: &mut AsyncApp,
3074 ) -> Result<ProjectTransaction> {
3075 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3076
3077 let mut operations = Vec::new();
3078 if let Some(document_changes) = edit.document_changes {
3079 match document_changes {
3080 lsp::DocumentChanges::Edits(edits) => {
3081 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3082 }
3083 lsp::DocumentChanges::Operations(ops) => operations = ops,
3084 }
3085 } else if let Some(changes) = edit.changes {
3086 operations.extend(changes.into_iter().map(|(uri, edits)| {
3087 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3088 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3089 uri,
3090 version: None,
3091 },
3092 edits: edits.into_iter().map(Edit::Plain).collect(),
3093 })
3094 }));
3095 }
3096
3097 let mut project_transaction = ProjectTransaction::default();
3098 for operation in operations {
3099 match operation {
3100 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3101 let abs_path = op
3102 .uri
3103 .to_file_path()
3104 .map_err(|()| anyhow!("can't convert URI to path"))?;
3105
3106 if let Some(parent_path) = abs_path.parent() {
3107 fs.create_dir(parent_path).await?;
3108 }
3109 if abs_path.ends_with("/") {
3110 fs.create_dir(&abs_path).await?;
3111 } else {
3112 fs.create_file(
3113 &abs_path,
3114 op.options
3115 .map(|options| fs::CreateOptions {
3116 overwrite: options.overwrite.unwrap_or(false),
3117 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3118 })
3119 .unwrap_or_default(),
3120 )
3121 .await?;
3122 }
3123 }
3124
3125 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3126 let source_abs_path = op
3127 .old_uri
3128 .to_file_path()
3129 .map_err(|()| anyhow!("can't convert URI to path"))?;
3130 let target_abs_path = op
3131 .new_uri
3132 .to_file_path()
3133 .map_err(|()| anyhow!("can't convert URI to path"))?;
3134
3135 let options = fs::RenameOptions {
3136 overwrite: op
3137 .options
3138 .as_ref()
3139 .and_then(|options| options.overwrite)
3140 .unwrap_or(false),
3141 ignore_if_exists: op
3142 .options
3143 .as_ref()
3144 .and_then(|options| options.ignore_if_exists)
3145 .unwrap_or(false),
3146 create_parents: true,
3147 };
3148
3149 fs.rename(&source_abs_path, &target_abs_path, options)
3150 .await?;
3151 }
3152
3153 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3154 let abs_path = op
3155 .uri
3156 .to_file_path()
3157 .map_err(|()| anyhow!("can't convert URI to path"))?;
3158 let options = op
3159 .options
3160 .map(|options| fs::RemoveOptions {
3161 recursive: options.recursive.unwrap_or(false),
3162 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3163 })
3164 .unwrap_or_default();
3165 if abs_path.ends_with("/") {
3166 fs.remove_dir(&abs_path, options).await?;
3167 } else {
3168 fs.remove_file(&abs_path, options).await?;
3169 }
3170 }
3171
3172 lsp::DocumentChangeOperation::Edit(op) => {
3173 let buffer_to_edit = this
3174 .update(cx, |this, cx| {
3175 this.open_local_buffer_via_lsp(
3176 op.text_document.uri.clone(),
3177 language_server.server_id(),
3178 cx,
3179 )
3180 })
3181 .await?;
3182
3183 let edits = this
3184 .update(cx, |this, cx| {
3185 let path = buffer_to_edit.read(cx).project_path(cx);
3186 let active_entry = this.active_entry;
3187 let is_active_entry = path.is_some_and(|project_path| {
3188 this.worktree_store
3189 .read(cx)
3190 .entry_for_path(&project_path, cx)
3191 .is_some_and(|entry| Some(entry.id) == active_entry)
3192 });
3193 let local = this.as_local_mut().unwrap();
3194
3195 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3196 for edit in op.edits {
3197 match edit {
3198 Edit::Plain(edit) => {
3199 if !edits.contains(&edit) {
3200 edits.push(edit)
3201 }
3202 }
3203 Edit::Annotated(edit) => {
3204 if !edits.contains(&edit.text_edit) {
3205 edits.push(edit.text_edit)
3206 }
3207 }
3208 Edit::Snippet(edit) => {
3209 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3210 else {
3211 continue;
3212 };
3213
3214 if is_active_entry {
3215 snippet_edits.push((edit.range, snippet));
3216 } else {
3217 // Since this buffer is not focused, apply a normal edit.
3218 let new_edit = TextEdit {
3219 range: edit.range,
3220 new_text: snippet.text,
3221 };
3222 if !edits.contains(&new_edit) {
3223 edits.push(new_edit);
3224 }
3225 }
3226 }
3227 }
3228 }
3229 if !snippet_edits.is_empty() {
3230 let buffer_id = buffer_to_edit.read(cx).remote_id();
3231 let version = if let Some(buffer_version) = op.text_document.version
3232 {
3233 local
3234 .buffer_snapshot_for_lsp_version(
3235 &buffer_to_edit,
3236 language_server.server_id(),
3237 Some(buffer_version),
3238 cx,
3239 )
3240 .ok()
3241 .map(|snapshot| snapshot.version)
3242 } else {
3243 Some(buffer_to_edit.read(cx).saved_version().clone())
3244 };
3245
3246 let most_recent_edit =
3247 version.and_then(|version| version.most_recent());
3248 // Check if the edit that triggered that edit has been made by this participant.
3249
3250 if let Some(most_recent_edit) = most_recent_edit {
3251 cx.emit(LspStoreEvent::SnippetEdit {
3252 buffer_id,
3253 edits: snippet_edits,
3254 most_recent_edit,
3255 });
3256 }
3257 }
3258
3259 local.edits_from_lsp(
3260 &buffer_to_edit,
3261 edits,
3262 language_server.server_id(),
3263 op.text_document.version,
3264 cx,
3265 )
3266 })
3267 .await?;
3268
3269 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3270 buffer.finalize_last_transaction();
3271 buffer.start_transaction();
3272 for (range, text) in edits {
3273 buffer.edit([(range, text)], None, cx);
3274 }
3275
3276 buffer.end_transaction(cx).and_then(|transaction_id| {
3277 if push_to_history {
3278 buffer.finalize_last_transaction();
3279 buffer.get_transaction(transaction_id).cloned()
3280 } else {
3281 buffer.forget_transaction(transaction_id)
3282 }
3283 })
3284 });
3285 if let Some(transaction) = transaction {
3286 project_transaction.0.insert(buffer_to_edit, transaction);
3287 }
3288 }
3289 }
3290 }
3291
3292 Ok(project_transaction)
3293 }
3294
3295 async fn on_lsp_workspace_edit(
3296 this: WeakEntity<LspStore>,
3297 params: lsp::ApplyWorkspaceEditParams,
3298 server_id: LanguageServerId,
3299 cx: &mut AsyncApp,
3300 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3301 let this = this.upgrade().context("project project closed")?;
3302 let language_server = this
3303 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3304 .context("language server not found")?;
3305 let transaction = Self::deserialize_workspace_edit(
3306 this.clone(),
3307 params.edit,
3308 true,
3309 language_server.clone(),
3310 cx,
3311 )
3312 .await
3313 .log_err();
3314 this.update(cx, |this, cx| {
3315 if let Some(transaction) = transaction {
3316 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3317
3318 this.as_local_mut()
3319 .unwrap()
3320 .last_workspace_edits_by_language_server
3321 .insert(server_id, transaction);
3322 }
3323 });
3324 Ok(lsp::ApplyWorkspaceEditResponse {
3325 applied: true,
3326 failed_change: None,
3327 failure_reason: None,
3328 })
3329 }
3330
3331 fn remove_worktree(
3332 &mut self,
3333 id_to_remove: WorktreeId,
3334 cx: &mut Context<LspStore>,
3335 ) -> Vec<LanguageServerId> {
3336 self.restricted_worktrees_tasks.remove(&id_to_remove);
3337 self.diagnostics.remove(&id_to_remove);
3338 self.prettier_store.update(cx, |prettier_store, cx| {
3339 prettier_store.remove_worktree(id_to_remove, cx);
3340 });
3341
3342 let mut servers_to_remove = BTreeSet::default();
3343 let mut servers_to_preserve = HashSet::default();
3344 for (seed, state) in &self.language_server_ids {
3345 if seed.worktree_id == id_to_remove {
3346 servers_to_remove.insert(state.id);
3347 } else {
3348 servers_to_preserve.insert(state.id);
3349 }
3350 }
3351 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3352 self.language_server_ids
3353 .retain(|_, state| !servers_to_remove.contains(&state.id));
3354 for server_id_to_remove in &servers_to_remove {
3355 self.language_server_watched_paths
3356 .remove(server_id_to_remove);
3357 self.language_server_paths_watched_for_rename
3358 .remove(server_id_to_remove);
3359 self.last_workspace_edits_by_language_server
3360 .remove(server_id_to_remove);
3361 self.language_servers.remove(server_id_to_remove);
3362 self.buffer_pull_diagnostics_result_ids
3363 .remove(server_id_to_remove);
3364 self.workspace_pull_diagnostics_result_ids
3365 .remove(server_id_to_remove);
3366 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3367 buffer_servers.remove(server_id_to_remove);
3368 }
3369 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3370 }
3371 servers_to_remove.into_iter().collect()
3372 }
3373
3374 fn rebuild_watched_paths_inner<'a>(
3375 &'a self,
3376 language_server_id: LanguageServerId,
3377 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3378 cx: &mut Context<LspStore>,
3379 ) -> LanguageServerWatchedPathsBuilder {
3380 let worktrees = self
3381 .worktree_store
3382 .read(cx)
3383 .worktrees()
3384 .filter_map(|worktree| {
3385 self.language_servers_for_worktree(worktree.read(cx).id())
3386 .find(|server| server.server_id() == language_server_id)
3387 .map(|_| worktree)
3388 })
3389 .collect::<Vec<_>>();
3390
3391 let mut worktree_globs = HashMap::default();
3392 let mut abs_globs = HashMap::default();
3393 log::trace!(
3394 "Processing new watcher paths for language server with id {}",
3395 language_server_id
3396 );
3397
3398 for watcher in watchers {
3399 if let Some((worktree, literal_prefix, pattern)) =
3400 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3401 {
3402 worktree.update(cx, |worktree, _| {
3403 if let Some((tree, glob)) =
3404 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3405 {
3406 tree.add_path_prefix_to_scan(literal_prefix);
3407 worktree_globs
3408 .entry(tree.id())
3409 .or_insert_with(GlobSetBuilder::new)
3410 .add(glob);
3411 }
3412 });
3413 } else {
3414 let (path, pattern) = match &watcher.glob_pattern {
3415 lsp::GlobPattern::String(s) => {
3416 let watcher_path = SanitizedPath::new(s);
3417 let path = glob_literal_prefix(watcher_path.as_path());
3418 let pattern = watcher_path
3419 .as_path()
3420 .strip_prefix(&path)
3421 .map(|p| p.to_string_lossy().into_owned())
3422 .unwrap_or_else(|e| {
3423 debug_panic!(
3424 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3425 s,
3426 path.display(),
3427 e
3428 );
3429 watcher_path.as_path().to_string_lossy().into_owned()
3430 });
3431 (path, pattern)
3432 }
3433 lsp::GlobPattern::Relative(rp) => {
3434 let Ok(mut base_uri) = match &rp.base_uri {
3435 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3436 lsp::OneOf::Right(base_uri) => base_uri,
3437 }
3438 .to_file_path() else {
3439 continue;
3440 };
3441
3442 let path = glob_literal_prefix(Path::new(&rp.pattern));
3443 let pattern = Path::new(&rp.pattern)
3444 .strip_prefix(&path)
3445 .map(|p| p.to_string_lossy().into_owned())
3446 .unwrap_or_else(|e| {
3447 debug_panic!(
3448 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3449 rp.pattern,
3450 path.display(),
3451 e
3452 );
3453 rp.pattern.clone()
3454 });
3455 base_uri.push(path);
3456 (base_uri, pattern)
3457 }
3458 };
3459
3460 if let Some(glob) = Glob::new(&pattern).log_err() {
3461 if !path
3462 .components()
3463 .any(|c| matches!(c, path::Component::Normal(_)))
3464 {
3465 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3466 // rather than adding a new watcher for `/`.
3467 for worktree in &worktrees {
3468 worktree_globs
3469 .entry(worktree.read(cx).id())
3470 .or_insert_with(GlobSetBuilder::new)
3471 .add(glob.clone());
3472 }
3473 } else {
3474 abs_globs
3475 .entry(path.into())
3476 .or_insert_with(GlobSetBuilder::new)
3477 .add(glob);
3478 }
3479 }
3480 }
3481 }
3482
3483 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3484 for (worktree_id, builder) in worktree_globs {
3485 if let Ok(globset) = builder.build() {
3486 watch_builder.watch_worktree(worktree_id, globset);
3487 }
3488 }
3489 for (abs_path, builder) in abs_globs {
3490 if let Ok(globset) = builder.build() {
3491 watch_builder.watch_abs_path(abs_path, globset);
3492 }
3493 }
3494 watch_builder
3495 }
3496
3497 fn worktree_and_path_for_file_watcher(
3498 worktrees: &[Entity<Worktree>],
3499 watcher: &FileSystemWatcher,
3500 cx: &App,
3501 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3502 worktrees.iter().find_map(|worktree| {
3503 let tree = worktree.read(cx);
3504 let worktree_root_path = tree.abs_path();
3505 let path_style = tree.path_style();
3506 match &watcher.glob_pattern {
3507 lsp::GlobPattern::String(s) => {
3508 let watcher_path = SanitizedPath::new(s);
3509 let relative = watcher_path
3510 .as_path()
3511 .strip_prefix(&worktree_root_path)
3512 .ok()?;
3513 let literal_prefix = glob_literal_prefix(relative);
3514 Some((
3515 worktree.clone(),
3516 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3517 relative.to_string_lossy().into_owned(),
3518 ))
3519 }
3520 lsp::GlobPattern::Relative(rp) => {
3521 let base_uri = match &rp.base_uri {
3522 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3523 lsp::OneOf::Right(base_uri) => base_uri,
3524 }
3525 .to_file_path()
3526 .ok()?;
3527 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3528 let mut literal_prefix = relative.to_owned();
3529 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3530 Some((
3531 worktree.clone(),
3532 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3533 rp.pattern.clone(),
3534 ))
3535 }
3536 }
3537 })
3538 }
3539
3540 fn rebuild_watched_paths(
3541 &mut self,
3542 language_server_id: LanguageServerId,
3543 cx: &mut Context<LspStore>,
3544 ) {
3545 let Some(registrations) = self
3546 .language_server_dynamic_registrations
3547 .get(&language_server_id)
3548 else {
3549 return;
3550 };
3551
3552 let watch_builder = self.rebuild_watched_paths_inner(
3553 language_server_id,
3554 registrations.did_change_watched_files.values().flatten(),
3555 cx,
3556 );
3557 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3558 self.language_server_watched_paths
3559 .insert(language_server_id, watcher);
3560
3561 cx.notify();
3562 }
3563
3564 fn on_lsp_did_change_watched_files(
3565 &mut self,
3566 language_server_id: LanguageServerId,
3567 registration_id: &str,
3568 params: DidChangeWatchedFilesRegistrationOptions,
3569 cx: &mut Context<LspStore>,
3570 ) {
3571 let registrations = self
3572 .language_server_dynamic_registrations
3573 .entry(language_server_id)
3574 .or_default();
3575
3576 registrations
3577 .did_change_watched_files
3578 .insert(registration_id.to_string(), params.watchers);
3579
3580 self.rebuild_watched_paths(language_server_id, cx);
3581 }
3582
3583 fn on_lsp_unregister_did_change_watched_files(
3584 &mut self,
3585 language_server_id: LanguageServerId,
3586 registration_id: &str,
3587 cx: &mut Context<LspStore>,
3588 ) {
3589 let registrations = self
3590 .language_server_dynamic_registrations
3591 .entry(language_server_id)
3592 .or_default();
3593
3594 if registrations
3595 .did_change_watched_files
3596 .remove(registration_id)
3597 .is_some()
3598 {
3599 log::info!(
3600 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3601 language_server_id,
3602 registration_id
3603 );
3604 } else {
3605 log::warn!(
3606 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3607 language_server_id,
3608 registration_id
3609 );
3610 }
3611
3612 self.rebuild_watched_paths(language_server_id, cx);
3613 }
3614
3615 async fn initialization_options_for_adapter(
3616 adapter: Arc<dyn LspAdapter>,
3617 delegate: &Arc<dyn LspAdapterDelegate>,
3618 ) -> Result<Option<serde_json::Value>> {
3619 let Some(mut initialization_config) =
3620 adapter.clone().initialization_options(delegate).await?
3621 else {
3622 return Ok(None);
3623 };
3624
3625 for other_adapter in delegate.registered_lsp_adapters() {
3626 if other_adapter.name() == adapter.name() {
3627 continue;
3628 }
3629 if let Ok(Some(target_config)) = other_adapter
3630 .clone()
3631 .additional_initialization_options(adapter.name(), delegate)
3632 .await
3633 {
3634 merge_json_value_into(target_config.clone(), &mut initialization_config);
3635 }
3636 }
3637
3638 Ok(Some(initialization_config))
3639 }
3640
3641 async fn workspace_configuration_for_adapter(
3642 adapter: Arc<dyn LspAdapter>,
3643 delegate: &Arc<dyn LspAdapterDelegate>,
3644 toolchain: Option<Toolchain>,
3645 requested_uri: Option<Uri>,
3646 cx: &mut AsyncApp,
3647 ) -> Result<serde_json::Value> {
3648 let mut workspace_config = adapter
3649 .clone()
3650 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3651 .await?;
3652
3653 for other_adapter in delegate.registered_lsp_adapters() {
3654 if other_adapter.name() == adapter.name() {
3655 continue;
3656 }
3657 if let Ok(Some(target_config)) = other_adapter
3658 .clone()
3659 .additional_workspace_configuration(adapter.name(), delegate, cx)
3660 .await
3661 {
3662 merge_json_value_into(target_config.clone(), &mut workspace_config);
3663 }
3664 }
3665
3666 Ok(workspace_config)
3667 }
3668
3669 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3670 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3671 Some(server.clone())
3672 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3673 Some(Arc::clone(server))
3674 } else {
3675 None
3676 }
3677 }
3678}
3679
3680fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3681 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3682 cx.emit(LspStoreEvent::LanguageServerUpdate {
3683 language_server_id: server.server_id(),
3684 name: Some(server.name()),
3685 message: proto::update_language_server::Variant::MetadataUpdated(
3686 proto::ServerMetadataUpdated {
3687 capabilities: Some(capabilities),
3688 binary: Some(proto::LanguageServerBinaryInfo {
3689 path: server.binary().path.to_string_lossy().into_owned(),
3690 arguments: server
3691 .binary()
3692 .arguments
3693 .iter()
3694 .map(|arg| arg.to_string_lossy().into_owned())
3695 .collect(),
3696 }),
3697 configuration: serde_json::to_string(server.configuration()).ok(),
3698 workspace_folders: server
3699 .workspace_folders()
3700 .iter()
3701 .map(|uri| uri.to_string())
3702 .collect(),
3703 },
3704 ),
3705 });
3706 }
3707}
3708
3709#[derive(Debug)]
3710pub struct FormattableBuffer {
3711 handle: Entity<Buffer>,
3712 abs_path: Option<PathBuf>,
3713 env: Option<HashMap<String, String>>,
3714 ranges: Option<Vec<Range<Anchor>>>,
3715}
3716
3717pub struct RemoteLspStore {
3718 upstream_client: Option<AnyProtoClient>,
3719 upstream_project_id: u64,
3720}
3721
3722pub(crate) enum LspStoreMode {
3723 Local(LocalLspStore), // ssh host and collab host
3724 Remote(RemoteLspStore), // collab guest
3725}
3726
3727impl LspStoreMode {
3728 fn is_local(&self) -> bool {
3729 matches!(self, LspStoreMode::Local(_))
3730 }
3731}
3732
3733pub struct LspStore {
3734 mode: LspStoreMode,
3735 last_formatting_failure: Option<String>,
3736 downstream_client: Option<(AnyProtoClient, u64)>,
3737 nonce: u128,
3738 buffer_store: Entity<BufferStore>,
3739 worktree_store: Entity<WorktreeStore>,
3740 pub languages: Arc<LanguageRegistry>,
3741 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3742 active_entry: Option<ProjectEntryId>,
3743 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3744 _maintain_buffer_languages: Task<()>,
3745 diagnostic_summaries:
3746 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3747 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3748 lsp_data: HashMap<BufferId, BufferLspData>,
3749 next_hint_id: Arc<AtomicUsize>,
3750}
3751
3752#[derive(Debug)]
3753pub struct BufferLspData {
3754 buffer_version: Global,
3755 document_colors: Option<DocumentColorData>,
3756 code_lens: Option<CodeLensData>,
3757 inlay_hints: BufferInlayHints,
3758 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3759 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3760}
3761
3762#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3763struct LspKey {
3764 request_type: TypeId,
3765 server_queried: Option<LanguageServerId>,
3766}
3767
3768impl BufferLspData {
3769 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3770 Self {
3771 buffer_version: buffer.read(cx).version(),
3772 document_colors: None,
3773 code_lens: None,
3774 inlay_hints: BufferInlayHints::new(buffer, cx),
3775 lsp_requests: HashMap::default(),
3776 chunk_lsp_requests: HashMap::default(),
3777 }
3778 }
3779
3780 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3781 if let Some(document_colors) = &mut self.document_colors {
3782 document_colors.colors.remove(&for_server);
3783 document_colors.cache_version += 1;
3784 }
3785
3786 if let Some(code_lens) = &mut self.code_lens {
3787 code_lens.lens.remove(&for_server);
3788 }
3789
3790 self.inlay_hints.remove_server_data(for_server);
3791 }
3792
3793 #[cfg(any(test, feature = "test-support"))]
3794 pub fn inlay_hints(&self) -> &BufferInlayHints {
3795 &self.inlay_hints
3796 }
3797}
3798
3799#[derive(Debug, Default, Clone)]
3800pub struct DocumentColors {
3801 pub colors: HashSet<DocumentColor>,
3802 pub cache_version: Option<usize>,
3803}
3804
3805type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3806type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3807
3808#[derive(Debug, Default)]
3809struct DocumentColorData {
3810 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3811 cache_version: usize,
3812 colors_update: Option<(Global, DocumentColorTask)>,
3813}
3814
3815#[derive(Debug, Default)]
3816struct CodeLensData {
3817 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3818 update: Option<(Global, CodeLensTask)>,
3819}
3820
3821#[derive(Debug)]
3822pub enum LspStoreEvent {
3823 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3824 LanguageServerRemoved(LanguageServerId),
3825 LanguageServerUpdate {
3826 language_server_id: LanguageServerId,
3827 name: Option<LanguageServerName>,
3828 message: proto::update_language_server::Variant,
3829 },
3830 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3831 LanguageServerPrompt(LanguageServerPromptRequest),
3832 LanguageDetected {
3833 buffer: Entity<Buffer>,
3834 new_language: Option<Arc<Language>>,
3835 },
3836 Notification(String),
3837 RefreshInlayHints {
3838 server_id: LanguageServerId,
3839 request_id: Option<usize>,
3840 },
3841 RefreshCodeLens,
3842 DiagnosticsUpdated {
3843 server_id: LanguageServerId,
3844 paths: Vec<ProjectPath>,
3845 },
3846 DiskBasedDiagnosticsStarted {
3847 language_server_id: LanguageServerId,
3848 },
3849 DiskBasedDiagnosticsFinished {
3850 language_server_id: LanguageServerId,
3851 },
3852 SnippetEdit {
3853 buffer_id: BufferId,
3854 edits: Vec<(lsp::Range, Snippet)>,
3855 most_recent_edit: clock::Lamport,
3856 },
3857 WorkspaceEditApplied(ProjectTransaction),
3858}
3859
3860#[derive(Clone, Debug, Serialize)]
3861pub struct LanguageServerStatus {
3862 pub name: LanguageServerName,
3863 pub server_version: Option<SharedString>,
3864 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3865 pub has_pending_diagnostic_updates: bool,
3866 pub progress_tokens: HashSet<ProgressToken>,
3867 pub worktree: Option<WorktreeId>,
3868 pub binary: Option<LanguageServerBinary>,
3869 pub configuration: Option<Value>,
3870 pub workspace_folders: BTreeSet<Uri>,
3871}
3872
3873#[derive(Clone, Debug)]
3874struct CoreSymbol {
3875 pub language_server_name: LanguageServerName,
3876 pub source_worktree_id: WorktreeId,
3877 pub source_language_server_id: LanguageServerId,
3878 pub path: SymbolLocation,
3879 pub name: String,
3880 pub kind: lsp::SymbolKind,
3881 pub range: Range<Unclipped<PointUtf16>>,
3882}
3883
3884#[derive(Clone, Debug, PartialEq, Eq)]
3885pub enum SymbolLocation {
3886 InProject(ProjectPath),
3887 OutsideProject {
3888 abs_path: Arc<Path>,
3889 signature: [u8; 32],
3890 },
3891}
3892
3893impl SymbolLocation {
3894 fn file_name(&self) -> Option<&str> {
3895 match self {
3896 Self::InProject(path) => path.path.file_name(),
3897 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3898 }
3899 }
3900}
3901
3902impl LspStore {
3903 pub fn init(client: &AnyProtoClient) {
3904 client.add_entity_request_handler(Self::handle_lsp_query);
3905 client.add_entity_message_handler(Self::handle_lsp_query_response);
3906 client.add_entity_request_handler(Self::handle_restart_language_servers);
3907 client.add_entity_request_handler(Self::handle_stop_language_servers);
3908 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3909 client.add_entity_message_handler(Self::handle_start_language_server);
3910 client.add_entity_message_handler(Self::handle_update_language_server);
3911 client.add_entity_message_handler(Self::handle_language_server_log);
3912 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3913 client.add_entity_request_handler(Self::handle_format_buffers);
3914 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3915 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3916 client.add_entity_request_handler(Self::handle_apply_code_action);
3917 client.add_entity_request_handler(Self::handle_get_project_symbols);
3918 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3919 client.add_entity_request_handler(Self::handle_get_color_presentation);
3920 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3921 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3922 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3923 client.add_entity_request_handler(Self::handle_on_type_formatting);
3924 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3925 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3926 client.add_entity_request_handler(Self::handle_rename_project_entry);
3927 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3928 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3929 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3930 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3931 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3932 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3933 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3934
3935 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3936 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3937 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3938 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3939 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3940 client.add_entity_request_handler(
3941 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3942 );
3943 client.add_entity_request_handler(
3944 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3945 );
3946 client.add_entity_request_handler(
3947 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3948 );
3949 }
3950
3951 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3952 match &self.mode {
3953 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3954 _ => None,
3955 }
3956 }
3957
3958 pub fn as_local(&self) -> Option<&LocalLspStore> {
3959 match &self.mode {
3960 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3961 _ => None,
3962 }
3963 }
3964
3965 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3966 match &mut self.mode {
3967 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3968 _ => None,
3969 }
3970 }
3971
3972 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3973 match &self.mode {
3974 LspStoreMode::Remote(RemoteLspStore {
3975 upstream_client: Some(upstream_client),
3976 upstream_project_id,
3977 ..
3978 }) => Some((upstream_client.clone(), *upstream_project_id)),
3979
3980 LspStoreMode::Remote(RemoteLspStore {
3981 upstream_client: None,
3982 ..
3983 }) => None,
3984 LspStoreMode::Local(_) => None,
3985 }
3986 }
3987
3988 pub fn new_local(
3989 buffer_store: Entity<BufferStore>,
3990 worktree_store: Entity<WorktreeStore>,
3991 prettier_store: Entity<PrettierStore>,
3992 toolchain_store: Entity<LocalToolchainStore>,
3993 environment: Entity<ProjectEnvironment>,
3994 manifest_tree: Entity<ManifestTree>,
3995 languages: Arc<LanguageRegistry>,
3996 http_client: Arc<dyn HttpClient>,
3997 fs: Arc<dyn Fs>,
3998 cx: &mut Context<Self>,
3999 ) -> Self {
4000 let yarn = YarnPathStore::new(fs.clone(), cx);
4001 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4002 .detach();
4003 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4004 .detach();
4005 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4006 .detach();
4007 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4008 .detach();
4009 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4010 .detach();
4011 subscribe_to_binary_statuses(&languages, cx).detach();
4012
4013 let _maintain_workspace_config = {
4014 let (sender, receiver) = watch::channel();
4015 (Self::maintain_workspace_config(receiver, cx), sender)
4016 };
4017
4018 Self {
4019 mode: LspStoreMode::Local(LocalLspStore {
4020 weak: cx.weak_entity(),
4021 worktree_store: worktree_store.clone(),
4022
4023 supplementary_language_servers: Default::default(),
4024 languages: languages.clone(),
4025 language_server_ids: Default::default(),
4026 language_servers: Default::default(),
4027 last_workspace_edits_by_language_server: Default::default(),
4028 language_server_watched_paths: Default::default(),
4029 language_server_paths_watched_for_rename: Default::default(),
4030 language_server_dynamic_registrations: Default::default(),
4031 buffers_being_formatted: Default::default(),
4032 buffer_snapshots: Default::default(),
4033 prettier_store,
4034 environment,
4035 http_client,
4036 fs,
4037 yarn,
4038 next_diagnostic_group_id: Default::default(),
4039 diagnostics: Default::default(),
4040 _subscription: cx.on_app_quit(|this, cx| {
4041 this.as_local_mut()
4042 .unwrap()
4043 .shutdown_language_servers_on_quit(cx)
4044 }),
4045 lsp_tree: LanguageServerTree::new(
4046 manifest_tree,
4047 languages.clone(),
4048 toolchain_store.clone(),
4049 ),
4050 toolchain_store,
4051 registered_buffers: HashMap::default(),
4052 buffers_opened_in_servers: HashMap::default(),
4053 buffer_pull_diagnostics_result_ids: HashMap::default(),
4054 workspace_pull_diagnostics_result_ids: HashMap::default(),
4055 restricted_worktrees_tasks: HashMap::default(),
4056 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4057 .manifest_file_names(),
4058 }),
4059 last_formatting_failure: None,
4060 downstream_client: None,
4061 buffer_store,
4062 worktree_store,
4063 languages: languages.clone(),
4064 language_server_statuses: Default::default(),
4065 nonce: StdRng::from_os_rng().random(),
4066 diagnostic_summaries: HashMap::default(),
4067 lsp_server_capabilities: HashMap::default(),
4068 lsp_data: HashMap::default(),
4069 next_hint_id: Arc::default(),
4070 active_entry: None,
4071 _maintain_workspace_config,
4072 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4073 }
4074 }
4075
4076 fn send_lsp_proto_request<R: LspCommand>(
4077 &self,
4078 buffer: Entity<Buffer>,
4079 client: AnyProtoClient,
4080 upstream_project_id: u64,
4081 request: R,
4082 cx: &mut Context<LspStore>,
4083 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4084 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4085 return Task::ready(Ok(R::Response::default()));
4086 }
4087 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4088 cx.spawn(async move |this, cx| {
4089 let response = client.request(message).await?;
4090 let this = this.upgrade().context("project dropped")?;
4091 request
4092 .response_from_proto(response, this, buffer, cx.clone())
4093 .await
4094 })
4095 }
4096
4097 pub(super) fn new_remote(
4098 buffer_store: Entity<BufferStore>,
4099 worktree_store: Entity<WorktreeStore>,
4100 languages: Arc<LanguageRegistry>,
4101 upstream_client: AnyProtoClient,
4102 project_id: u64,
4103 cx: &mut Context<Self>,
4104 ) -> Self {
4105 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4106 .detach();
4107 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4108 .detach();
4109 subscribe_to_binary_statuses(&languages, cx).detach();
4110 let _maintain_workspace_config = {
4111 let (sender, receiver) = watch::channel();
4112 (Self::maintain_workspace_config(receiver, cx), sender)
4113 };
4114 Self {
4115 mode: LspStoreMode::Remote(RemoteLspStore {
4116 upstream_client: Some(upstream_client),
4117 upstream_project_id: project_id,
4118 }),
4119 downstream_client: None,
4120 last_formatting_failure: None,
4121 buffer_store,
4122 worktree_store,
4123 languages: languages.clone(),
4124 language_server_statuses: Default::default(),
4125 nonce: StdRng::from_os_rng().random(),
4126 diagnostic_summaries: HashMap::default(),
4127 lsp_server_capabilities: HashMap::default(),
4128 next_hint_id: Arc::default(),
4129 lsp_data: HashMap::default(),
4130 active_entry: None,
4131
4132 _maintain_workspace_config,
4133 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4134 }
4135 }
4136
4137 fn on_buffer_store_event(
4138 &mut self,
4139 _: Entity<BufferStore>,
4140 event: &BufferStoreEvent,
4141 cx: &mut Context<Self>,
4142 ) {
4143 match event {
4144 BufferStoreEvent::BufferAdded(buffer) => {
4145 self.on_buffer_added(buffer, cx).log_err();
4146 }
4147 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4148 let buffer_id = buffer.read(cx).remote_id();
4149 if let Some(local) = self.as_local_mut()
4150 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4151 {
4152 local.reset_buffer(buffer, old_file, cx);
4153
4154 if local.registered_buffers.contains_key(&buffer_id) {
4155 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4156 }
4157 }
4158
4159 self.detect_language_for_buffer(buffer, cx);
4160 if let Some(local) = self.as_local_mut() {
4161 local.initialize_buffer(buffer, cx);
4162 if local.registered_buffers.contains_key(&buffer_id) {
4163 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4164 }
4165 }
4166 }
4167 _ => {}
4168 }
4169 }
4170
4171 fn on_worktree_store_event(
4172 &mut self,
4173 _: Entity<WorktreeStore>,
4174 event: &WorktreeStoreEvent,
4175 cx: &mut Context<Self>,
4176 ) {
4177 match event {
4178 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4179 if !worktree.read(cx).is_local() {
4180 return;
4181 }
4182 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4183 worktree::Event::UpdatedEntries(changes) => {
4184 this.update_local_worktree_language_servers(&worktree, changes, cx);
4185 }
4186 worktree::Event::UpdatedGitRepositories(_)
4187 | worktree::Event::DeletedEntry(_) => {}
4188 })
4189 .detach()
4190 }
4191 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4192 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4193 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4194 }
4195 WorktreeStoreEvent::WorktreeReleased(..)
4196 | WorktreeStoreEvent::WorktreeOrderChanged
4197 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4198 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4199 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4200 }
4201 }
4202
4203 fn on_prettier_store_event(
4204 &mut self,
4205 _: Entity<PrettierStore>,
4206 event: &PrettierStoreEvent,
4207 cx: &mut Context<Self>,
4208 ) {
4209 match event {
4210 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4211 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4212 }
4213 PrettierStoreEvent::LanguageServerAdded {
4214 new_server_id,
4215 name,
4216 prettier_server,
4217 } => {
4218 self.register_supplementary_language_server(
4219 *new_server_id,
4220 name.clone(),
4221 prettier_server.clone(),
4222 cx,
4223 );
4224 }
4225 }
4226 }
4227
4228 fn on_toolchain_store_event(
4229 &mut self,
4230 _: Entity<LocalToolchainStore>,
4231 event: &ToolchainStoreEvent,
4232 _: &mut Context<Self>,
4233 ) {
4234 if let ToolchainStoreEvent::ToolchainActivated = event {
4235 self.request_workspace_config_refresh()
4236 }
4237 }
4238
4239 fn request_workspace_config_refresh(&mut self) {
4240 *self._maintain_workspace_config.1.borrow_mut() = ();
4241 }
4242
4243 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4244 self.as_local().map(|local| local.prettier_store.clone())
4245 }
4246
4247 fn on_buffer_event(
4248 &mut self,
4249 buffer: Entity<Buffer>,
4250 event: &language::BufferEvent,
4251 cx: &mut Context<Self>,
4252 ) {
4253 match event {
4254 language::BufferEvent::Edited => {
4255 self.on_buffer_edited(buffer, cx);
4256 }
4257
4258 language::BufferEvent::Saved => {
4259 self.on_buffer_saved(buffer, cx);
4260 }
4261
4262 _ => {}
4263 }
4264 }
4265
4266 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4267 buffer
4268 .read(cx)
4269 .set_language_registry(self.languages.clone());
4270
4271 cx.subscribe(buffer, |this, buffer, event, cx| {
4272 this.on_buffer_event(buffer, event, cx);
4273 })
4274 .detach();
4275
4276 self.detect_language_for_buffer(buffer, cx);
4277 if let Some(local) = self.as_local_mut() {
4278 local.initialize_buffer(buffer, cx);
4279 }
4280
4281 Ok(())
4282 }
4283
4284 pub(crate) fn register_buffer_with_language_servers(
4285 &mut self,
4286 buffer: &Entity<Buffer>,
4287 only_register_servers: HashSet<LanguageServerSelector>,
4288 ignore_refcounts: bool,
4289 cx: &mut Context<Self>,
4290 ) -> OpenLspBufferHandle {
4291 let buffer_id = buffer.read(cx).remote_id();
4292 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4293 if let Some(local) = self.as_local_mut() {
4294 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4295 if !ignore_refcounts {
4296 *refcount += 1;
4297 }
4298
4299 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4300 // 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
4301 // 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
4302 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4303 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4304 return handle;
4305 };
4306 if !file.is_local() {
4307 return handle;
4308 }
4309
4310 if ignore_refcounts || *refcount == 1 {
4311 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4312 }
4313 if !ignore_refcounts {
4314 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4315 let refcount = {
4316 let local = lsp_store.as_local_mut().unwrap();
4317 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4318 debug_panic!("bad refcounting");
4319 return;
4320 };
4321
4322 *refcount -= 1;
4323 *refcount
4324 };
4325 if refcount == 0 {
4326 lsp_store.lsp_data.remove(&buffer_id);
4327 let local = lsp_store.as_local_mut().unwrap();
4328 local.registered_buffers.remove(&buffer_id);
4329
4330 local.buffers_opened_in_servers.remove(&buffer_id);
4331 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4332 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4333
4334 let buffer_abs_path = file.abs_path(cx);
4335 for (_, buffer_pull_diagnostics_result_ids) in
4336 &mut local.buffer_pull_diagnostics_result_ids
4337 {
4338 buffer_pull_diagnostics_result_ids.retain(
4339 |_, buffer_result_ids| {
4340 buffer_result_ids.remove(&buffer_abs_path);
4341 !buffer_result_ids.is_empty()
4342 },
4343 );
4344 }
4345
4346 let diagnostic_updates = local
4347 .language_servers
4348 .keys()
4349 .cloned()
4350 .map(|server_id| DocumentDiagnosticsUpdate {
4351 diagnostics: DocumentDiagnostics {
4352 document_abs_path: buffer_abs_path.clone(),
4353 version: None,
4354 diagnostics: Vec::new(),
4355 },
4356 result_id: None,
4357 registration_id: None,
4358 server_id: server_id,
4359 disk_based_sources: Cow::Borrowed(&[]),
4360 })
4361 .collect::<Vec<_>>();
4362
4363 lsp_store
4364 .merge_diagnostic_entries(
4365 diagnostic_updates,
4366 |_, diagnostic, _| {
4367 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4368 },
4369 cx,
4370 )
4371 .context("Clearing diagnostics for the closed buffer")
4372 .log_err();
4373 }
4374 }
4375 })
4376 .detach();
4377 }
4378 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4379 let buffer_id = buffer.read(cx).remote_id().to_proto();
4380 cx.background_spawn(async move {
4381 upstream_client
4382 .request(proto::RegisterBufferWithLanguageServers {
4383 project_id: upstream_project_id,
4384 buffer_id,
4385 only_servers: only_register_servers
4386 .into_iter()
4387 .map(|selector| {
4388 let selector = match selector {
4389 LanguageServerSelector::Id(language_server_id) => {
4390 proto::language_server_selector::Selector::ServerId(
4391 language_server_id.to_proto(),
4392 )
4393 }
4394 LanguageServerSelector::Name(language_server_name) => {
4395 proto::language_server_selector::Selector::Name(
4396 language_server_name.to_string(),
4397 )
4398 }
4399 };
4400 proto::LanguageServerSelector {
4401 selector: Some(selector),
4402 }
4403 })
4404 .collect(),
4405 })
4406 .await
4407 })
4408 .detach();
4409 } else {
4410 // Our remote connection got closed
4411 }
4412 handle
4413 }
4414
4415 fn maintain_buffer_languages(
4416 languages: Arc<LanguageRegistry>,
4417 cx: &mut Context<Self>,
4418 ) -> Task<()> {
4419 let mut subscription = languages.subscribe();
4420 let mut prev_reload_count = languages.reload_count();
4421 cx.spawn(async move |this, cx| {
4422 while let Some(()) = subscription.next().await {
4423 if let Some(this) = this.upgrade() {
4424 // If the language registry has been reloaded, then remove and
4425 // re-assign the languages on all open buffers.
4426 let reload_count = languages.reload_count();
4427 if reload_count > prev_reload_count {
4428 prev_reload_count = reload_count;
4429 this.update(cx, |this, cx| {
4430 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4431 for buffer in buffer_store.buffers() {
4432 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4433 {
4434 buffer.update(cx, |buffer, cx| {
4435 buffer.set_language_async(None, cx)
4436 });
4437 if let Some(local) = this.as_local_mut() {
4438 local.reset_buffer(&buffer, &f, cx);
4439
4440 if local
4441 .registered_buffers
4442 .contains_key(&buffer.read(cx).remote_id())
4443 && let Some(file_url) =
4444 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4445 {
4446 local.unregister_buffer_from_language_servers(
4447 &buffer, &file_url, cx,
4448 );
4449 }
4450 }
4451 }
4452 }
4453 });
4454 });
4455 }
4456
4457 this.update(cx, |this, cx| {
4458 let mut plain_text_buffers = Vec::new();
4459 let mut buffers_with_unknown_injections = Vec::new();
4460 for handle in this.buffer_store.read(cx).buffers() {
4461 let buffer = handle.read(cx);
4462 if buffer.language().is_none()
4463 || buffer.language() == Some(&*language::PLAIN_TEXT)
4464 {
4465 plain_text_buffers.push(handle);
4466 } else if buffer.contains_unknown_injections() {
4467 buffers_with_unknown_injections.push(handle);
4468 }
4469 }
4470
4471 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4472 // and reused later in the invisible worktrees.
4473 plain_text_buffers.sort_by_key(|buffer| {
4474 Reverse(
4475 File::from_dyn(buffer.read(cx).file())
4476 .map(|file| file.worktree.read(cx).is_visible()),
4477 )
4478 });
4479
4480 for buffer in plain_text_buffers {
4481 this.detect_language_for_buffer(&buffer, cx);
4482 if let Some(local) = this.as_local_mut() {
4483 local.initialize_buffer(&buffer, cx);
4484 if local
4485 .registered_buffers
4486 .contains_key(&buffer.read(cx).remote_id())
4487 {
4488 local.register_buffer_with_language_servers(
4489 &buffer,
4490 HashSet::default(),
4491 cx,
4492 );
4493 }
4494 }
4495 }
4496
4497 for buffer in buffers_with_unknown_injections {
4498 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4499 }
4500 });
4501 }
4502 }
4503 })
4504 }
4505
4506 fn detect_language_for_buffer(
4507 &mut self,
4508 buffer_handle: &Entity<Buffer>,
4509 cx: &mut Context<Self>,
4510 ) -> Option<language::AvailableLanguage> {
4511 // If the buffer has a language, set it and start the language server if we haven't already.
4512 let buffer = buffer_handle.read(cx);
4513 let file = buffer.file()?;
4514
4515 let content = buffer.as_rope();
4516 let available_language = self.languages.language_for_file(file, Some(content), cx);
4517 if let Some(available_language) = &available_language {
4518 if let Some(Ok(Ok(new_language))) = self
4519 .languages
4520 .load_language(available_language)
4521 .now_or_never()
4522 {
4523 self.set_language_for_buffer(buffer_handle, new_language, cx);
4524 }
4525 } else {
4526 cx.emit(LspStoreEvent::LanguageDetected {
4527 buffer: buffer_handle.clone(),
4528 new_language: None,
4529 });
4530 }
4531
4532 available_language
4533 }
4534
4535 pub(crate) fn set_language_for_buffer(
4536 &mut self,
4537 buffer_entity: &Entity<Buffer>,
4538 new_language: Arc<Language>,
4539 cx: &mut Context<Self>,
4540 ) {
4541 let buffer = buffer_entity.read(cx);
4542 let buffer_file = buffer.file().cloned();
4543 let buffer_id = buffer.remote_id();
4544 if let Some(local_store) = self.as_local_mut()
4545 && local_store.registered_buffers.contains_key(&buffer_id)
4546 && let Some(abs_path) =
4547 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4548 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4549 {
4550 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4551 }
4552 buffer_entity.update(cx, |buffer, cx| {
4553 if buffer
4554 .language()
4555 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4556 {
4557 buffer.set_language_async(Some(new_language.clone()), cx);
4558 }
4559 });
4560
4561 let settings =
4562 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4563 let buffer_file = File::from_dyn(buffer_file.as_ref());
4564
4565 let worktree_id = if let Some(file) = buffer_file {
4566 let worktree = file.worktree.clone();
4567
4568 if let Some(local) = self.as_local_mut()
4569 && local.registered_buffers.contains_key(&buffer_id)
4570 {
4571 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4572 }
4573 Some(worktree.read(cx).id())
4574 } else {
4575 None
4576 };
4577
4578 if settings.prettier.allowed
4579 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4580 {
4581 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4582 if let Some(prettier_store) = prettier_store {
4583 prettier_store.update(cx, |prettier_store, cx| {
4584 prettier_store.install_default_prettier(
4585 worktree_id,
4586 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4587 cx,
4588 )
4589 })
4590 }
4591 }
4592
4593 cx.emit(LspStoreEvent::LanguageDetected {
4594 buffer: buffer_entity.clone(),
4595 new_language: Some(new_language),
4596 })
4597 }
4598
4599 pub fn buffer_store(&self) -> Entity<BufferStore> {
4600 self.buffer_store.clone()
4601 }
4602
4603 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4604 self.active_entry = active_entry;
4605 }
4606
4607 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4608 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4609 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4610 {
4611 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4612 summaries
4613 .iter()
4614 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4615 });
4616 if let Some(summary) = summaries.next() {
4617 client
4618 .send(proto::UpdateDiagnosticSummary {
4619 project_id: downstream_project_id,
4620 worktree_id: worktree.id().to_proto(),
4621 summary: Some(summary),
4622 more_summaries: summaries.collect(),
4623 })
4624 .log_err();
4625 }
4626 }
4627 }
4628
4629 fn is_capable_for_proto_request<R>(
4630 &self,
4631 buffer: &Entity<Buffer>,
4632 request: &R,
4633 cx: &App,
4634 ) -> bool
4635 where
4636 R: LspCommand,
4637 {
4638 self.check_if_capable_for_proto_request(
4639 buffer,
4640 |capabilities| {
4641 request.check_capabilities(AdapterServerCapabilities {
4642 server_capabilities: capabilities.clone(),
4643 code_action_kinds: None,
4644 })
4645 },
4646 cx,
4647 )
4648 }
4649
4650 fn check_if_capable_for_proto_request<F>(
4651 &self,
4652 buffer: &Entity<Buffer>,
4653 check: F,
4654 cx: &App,
4655 ) -> bool
4656 where
4657 F: FnMut(&lsp::ServerCapabilities) -> bool,
4658 {
4659 let Some(language) = buffer.read(cx).language().cloned() else {
4660 return false;
4661 };
4662 let registered_language_servers = self
4663 .languages
4664 .lsp_adapters(&language.name())
4665 .into_iter()
4666 .map(|lsp_adapter| lsp_adapter.name())
4667 .collect::<HashSet<_>>();
4668 self.language_server_statuses
4669 .iter()
4670 .filter_map(|(server_id, server_status)| {
4671 // Include servers that are either registered for this language OR
4672 // available to be loaded (for SSH remote mode where adapters like
4673 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4674 // but only loaded on the server side)
4675 let is_relevant = registered_language_servers.contains(&server_status.name)
4676 || self.languages.is_lsp_adapter_available(&server_status.name);
4677 is_relevant.then_some(server_id)
4678 })
4679 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4680 .any(check)
4681 }
4682
4683 fn all_capable_for_proto_request<F>(
4684 &self,
4685 buffer: &Entity<Buffer>,
4686 mut check: F,
4687 cx: &App,
4688 ) -> Vec<lsp::LanguageServerId>
4689 where
4690 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4691 {
4692 let Some(language) = buffer.read(cx).language().cloned() else {
4693 return Vec::default();
4694 };
4695 let registered_language_servers = self
4696 .languages
4697 .lsp_adapters(&language.name())
4698 .into_iter()
4699 .map(|lsp_adapter| lsp_adapter.name())
4700 .collect::<HashSet<_>>();
4701 self.language_server_statuses
4702 .iter()
4703 .filter_map(|(server_id, server_status)| {
4704 // Include servers that are either registered for this language OR
4705 // available to be loaded (for SSH remote mode where adapters like
4706 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4707 // but only loaded on the server side)
4708 let is_relevant = registered_language_servers.contains(&server_status.name)
4709 || self.languages.is_lsp_adapter_available(&server_status.name);
4710 is_relevant.then_some((server_id, &server_status.name))
4711 })
4712 .filter_map(|(server_id, server_name)| {
4713 self.lsp_server_capabilities
4714 .get(server_id)
4715 .map(|c| (server_id, server_name, c))
4716 })
4717 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4718 .map(|(server_id, _, _)| *server_id)
4719 .collect()
4720 }
4721
4722 pub fn request_lsp<R>(
4723 &mut self,
4724 buffer: Entity<Buffer>,
4725 server: LanguageServerToQuery,
4726 request: R,
4727 cx: &mut Context<Self>,
4728 ) -> Task<Result<R::Response>>
4729 where
4730 R: LspCommand,
4731 <R::LspRequest as lsp::request::Request>::Result: Send,
4732 <R::LspRequest as lsp::request::Request>::Params: Send,
4733 {
4734 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4735 return self.send_lsp_proto_request(
4736 buffer,
4737 upstream_client,
4738 upstream_project_id,
4739 request,
4740 cx,
4741 );
4742 }
4743
4744 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4745 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4746 local
4747 .language_servers_for_buffer(buffer, cx)
4748 .find(|(_, server)| {
4749 request.check_capabilities(server.adapter_server_capabilities())
4750 })
4751 .map(|(_, server)| server.clone())
4752 }),
4753 LanguageServerToQuery::Other(id) => self
4754 .language_server_for_local_buffer(buffer, id, cx)
4755 .and_then(|(_, server)| {
4756 request
4757 .check_capabilities(server.adapter_server_capabilities())
4758 .then(|| Arc::clone(server))
4759 }),
4760 }) else {
4761 return Task::ready(Ok(Default::default()));
4762 };
4763
4764 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4765
4766 let Some(file) = file else {
4767 return Task::ready(Ok(Default::default()));
4768 };
4769
4770 let lsp_params = match request.to_lsp_params_or_response(
4771 &file.abs_path(cx),
4772 buffer.read(cx),
4773 &language_server,
4774 cx,
4775 ) {
4776 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4777 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4778 Err(err) => {
4779 let message = format!(
4780 "{} via {} failed: {}",
4781 request.display_name(),
4782 language_server.name(),
4783 err
4784 );
4785 // rust-analyzer likes to error with this when its still loading up
4786 if !message.ends_with("content modified") {
4787 log::warn!("{message}");
4788 }
4789 return Task::ready(Err(anyhow!(message)));
4790 }
4791 };
4792
4793 let status = request.status();
4794 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4795 return Task::ready(Ok(Default::default()));
4796 }
4797 cx.spawn(async move |this, cx| {
4798 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4799
4800 let id = lsp_request.id();
4801 let _cleanup = if status.is_some() {
4802 cx.update(|cx| {
4803 this.update(cx, |this, cx| {
4804 this.on_lsp_work_start(
4805 language_server.server_id(),
4806 ProgressToken::Number(id),
4807 LanguageServerProgress {
4808 is_disk_based_diagnostics_progress: false,
4809 is_cancellable: false,
4810 title: None,
4811 message: status.clone(),
4812 percentage: None,
4813 last_update_at: cx.background_executor().now(),
4814 },
4815 cx,
4816 );
4817 })
4818 })
4819 .log_err();
4820
4821 Some(defer(|| {
4822 cx.update(|cx| {
4823 this.update(cx, |this, cx| {
4824 this.on_lsp_work_end(
4825 language_server.server_id(),
4826 ProgressToken::Number(id),
4827 cx,
4828 );
4829 })
4830 })
4831 .log_err();
4832 }))
4833 } else {
4834 None
4835 };
4836
4837 let result = lsp_request.await.into_response();
4838
4839 let response = result.map_err(|err| {
4840 let message = format!(
4841 "{} via {} failed: {}",
4842 request.display_name(),
4843 language_server.name(),
4844 err
4845 );
4846 // rust-analyzer likes to error with this when its still loading up
4847 if !message.ends_with("content modified") {
4848 log::warn!("{message}");
4849 }
4850 anyhow::anyhow!(message)
4851 })?;
4852
4853 request
4854 .response_from_lsp(
4855 response,
4856 this.upgrade().context("no app context")?,
4857 buffer,
4858 language_server.server_id(),
4859 cx.clone(),
4860 )
4861 .await
4862 })
4863 }
4864
4865 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4866 let mut language_formatters_to_check = Vec::new();
4867 for buffer in self.buffer_store.read(cx).buffers() {
4868 let buffer = buffer.read(cx);
4869 let buffer_file = File::from_dyn(buffer.file());
4870 let buffer_language = buffer.language();
4871 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4872 if buffer_language.is_some() {
4873 language_formatters_to_check.push((
4874 buffer_file.map(|f| f.worktree_id(cx)),
4875 settings.into_owned(),
4876 ));
4877 }
4878 }
4879
4880 self.request_workspace_config_refresh();
4881
4882 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4883 prettier_store.update(cx, |prettier_store, cx| {
4884 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4885 })
4886 }
4887
4888 cx.notify();
4889 }
4890
4891 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4892 let buffer_store = self.buffer_store.clone();
4893 let Some(local) = self.as_local_mut() else {
4894 return;
4895 };
4896 let mut adapters = BTreeMap::default();
4897 let get_adapter = {
4898 let languages = local.languages.clone();
4899 let environment = local.environment.clone();
4900 let weak = local.weak.clone();
4901 let worktree_store = local.worktree_store.clone();
4902 let http_client = local.http_client.clone();
4903 let fs = local.fs.clone();
4904 move |worktree_id, cx: &mut App| {
4905 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4906 Some(LocalLspAdapterDelegate::new(
4907 languages.clone(),
4908 &environment,
4909 weak.clone(),
4910 &worktree,
4911 http_client.clone(),
4912 fs.clone(),
4913 cx,
4914 ))
4915 }
4916 };
4917
4918 let mut messages_to_report = Vec::new();
4919 let (new_tree, to_stop) = {
4920 let mut rebase = local.lsp_tree.rebase();
4921 let buffers = buffer_store
4922 .read(cx)
4923 .buffers()
4924 .filter_map(|buffer| {
4925 let raw_buffer = buffer.read(cx);
4926 if !local
4927 .registered_buffers
4928 .contains_key(&raw_buffer.remote_id())
4929 {
4930 return None;
4931 }
4932 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4933 let language = raw_buffer.language().cloned()?;
4934 Some((file, language, raw_buffer.remote_id()))
4935 })
4936 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4937 for (file, language, buffer_id) in buffers {
4938 let worktree_id = file.worktree_id(cx);
4939 let Some(worktree) = local
4940 .worktree_store
4941 .read(cx)
4942 .worktree_for_id(worktree_id, cx)
4943 else {
4944 continue;
4945 };
4946
4947 if let Some((_, apply)) = local.reuse_existing_language_server(
4948 rebase.server_tree(),
4949 &worktree,
4950 &language.name(),
4951 cx,
4952 ) {
4953 (apply)(rebase.server_tree());
4954 } else if let Some(lsp_delegate) = adapters
4955 .entry(worktree_id)
4956 .or_insert_with(|| get_adapter(worktree_id, cx))
4957 .clone()
4958 {
4959 let delegate =
4960 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4961 let path = file
4962 .path()
4963 .parent()
4964 .map(Arc::from)
4965 .unwrap_or_else(|| file.path().clone());
4966 let worktree_path = ProjectPath { worktree_id, path };
4967 let abs_path = file.abs_path(cx);
4968 let nodes = rebase
4969 .walk(
4970 worktree_path,
4971 language.name(),
4972 language.manifest(),
4973 delegate.clone(),
4974 cx,
4975 )
4976 .collect::<Vec<_>>();
4977 for node in nodes {
4978 let server_id = node.server_id_or_init(|disposition| {
4979 let path = &disposition.path;
4980 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4981 let key = LanguageServerSeed {
4982 worktree_id,
4983 name: disposition.server_name.clone(),
4984 settings: disposition.settings.clone(),
4985 toolchain: local.toolchain_store.read(cx).active_toolchain(
4986 path.worktree_id,
4987 &path.path,
4988 language.name(),
4989 ),
4990 };
4991 local.language_server_ids.remove(&key);
4992
4993 let server_id = local.get_or_insert_language_server(
4994 &worktree,
4995 lsp_delegate.clone(),
4996 disposition,
4997 &language.name(),
4998 cx,
4999 );
5000 if let Some(state) = local.language_servers.get(&server_id)
5001 && let Ok(uri) = uri
5002 {
5003 state.add_workspace_folder(uri);
5004 };
5005 server_id
5006 });
5007
5008 if let Some(language_server_id) = server_id {
5009 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5010 language_server_id,
5011 name: node.name(),
5012 message:
5013 proto::update_language_server::Variant::RegisteredForBuffer(
5014 proto::RegisteredForBuffer {
5015 buffer_abs_path: abs_path
5016 .to_string_lossy()
5017 .into_owned(),
5018 buffer_id: buffer_id.to_proto(),
5019 },
5020 ),
5021 });
5022 }
5023 }
5024 } else {
5025 continue;
5026 }
5027 }
5028 rebase.finish()
5029 };
5030 for message in messages_to_report {
5031 cx.emit(message);
5032 }
5033 local.lsp_tree = new_tree;
5034 for (id, _) in to_stop {
5035 self.stop_local_language_server(id, cx).detach();
5036 }
5037 }
5038
5039 pub fn apply_code_action(
5040 &self,
5041 buffer_handle: Entity<Buffer>,
5042 mut action: CodeAction,
5043 push_to_history: bool,
5044 cx: &mut Context<Self>,
5045 ) -> Task<Result<ProjectTransaction>> {
5046 if let Some((upstream_client, project_id)) = self.upstream_client() {
5047 let request = proto::ApplyCodeAction {
5048 project_id,
5049 buffer_id: buffer_handle.read(cx).remote_id().into(),
5050 action: Some(Self::serialize_code_action(&action)),
5051 };
5052 let buffer_store = self.buffer_store();
5053 cx.spawn(async move |_, cx| {
5054 let response = upstream_client
5055 .request(request)
5056 .await?
5057 .transaction
5058 .context("missing transaction")?;
5059
5060 buffer_store
5061 .update(cx, |buffer_store, cx| {
5062 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5063 })
5064 .await
5065 })
5066 } else if self.mode.is_local() {
5067 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5068 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5069 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5070 }) else {
5071 return Task::ready(Ok(ProjectTransaction::default()));
5072 };
5073 cx.spawn(async move |this, cx| {
5074 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5075 .await
5076 .context("resolving a code action")?;
5077 if let Some(edit) = action.lsp_action.edit()
5078 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5079 return LocalLspStore::deserialize_workspace_edit(
5080 this.upgrade().context("no app present")?,
5081 edit.clone(),
5082 push_to_history,
5083
5084 lang_server.clone(),
5085 cx,
5086 )
5087 .await;
5088 }
5089
5090 if let Some(command) = action.lsp_action.command() {
5091 let server_capabilities = lang_server.capabilities();
5092 let available_commands = server_capabilities
5093 .execute_command_provider
5094 .as_ref()
5095 .map(|options| options.commands.as_slice())
5096 .unwrap_or_default();
5097 if available_commands.contains(&command.command) {
5098 this.update(cx, |this, _| {
5099 this.as_local_mut()
5100 .unwrap()
5101 .last_workspace_edits_by_language_server
5102 .remove(&lang_server.server_id());
5103 })?;
5104
5105 let _result = lang_server
5106 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5107 command: command.command.clone(),
5108 arguments: command.arguments.clone().unwrap_or_default(),
5109 ..lsp::ExecuteCommandParams::default()
5110 })
5111 .await.into_response()
5112 .context("execute command")?;
5113
5114 return this.update(cx, |this, _| {
5115 this.as_local_mut()
5116 .unwrap()
5117 .last_workspace_edits_by_language_server
5118 .remove(&lang_server.server_id())
5119 .unwrap_or_default()
5120 });
5121 } else {
5122 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5123 }
5124 }
5125
5126 Ok(ProjectTransaction::default())
5127 })
5128 } else {
5129 Task::ready(Err(anyhow!("no upstream client and not local")))
5130 }
5131 }
5132
5133 pub fn apply_code_action_kind(
5134 &mut self,
5135 buffers: HashSet<Entity<Buffer>>,
5136 kind: CodeActionKind,
5137 push_to_history: bool,
5138 cx: &mut Context<Self>,
5139 ) -> Task<anyhow::Result<ProjectTransaction>> {
5140 if self.as_local().is_some() {
5141 cx.spawn(async move |lsp_store, cx| {
5142 let buffers = buffers.into_iter().collect::<Vec<_>>();
5143 let result = LocalLspStore::execute_code_action_kind_locally(
5144 lsp_store.clone(),
5145 buffers,
5146 kind,
5147 push_to_history,
5148 cx,
5149 )
5150 .await;
5151 lsp_store.update(cx, |lsp_store, _| {
5152 lsp_store.update_last_formatting_failure(&result);
5153 })?;
5154 result
5155 })
5156 } else if let Some((client, project_id)) = self.upstream_client() {
5157 let buffer_store = self.buffer_store();
5158 cx.spawn(async move |lsp_store, cx| {
5159 let result = client
5160 .request(proto::ApplyCodeActionKind {
5161 project_id,
5162 kind: kind.as_str().to_owned(),
5163 buffer_ids: buffers
5164 .iter()
5165 .map(|buffer| {
5166 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5167 })
5168 .collect(),
5169 })
5170 .await
5171 .and_then(|result| result.transaction.context("missing transaction"));
5172 lsp_store.update(cx, |lsp_store, _| {
5173 lsp_store.update_last_formatting_failure(&result);
5174 })?;
5175
5176 let transaction_response = result?;
5177 buffer_store
5178 .update(cx, |buffer_store, cx| {
5179 buffer_store.deserialize_project_transaction(
5180 transaction_response,
5181 push_to_history,
5182 cx,
5183 )
5184 })
5185 .await
5186 })
5187 } else {
5188 Task::ready(Ok(ProjectTransaction::default()))
5189 }
5190 }
5191
5192 pub fn resolved_hint(
5193 &mut self,
5194 buffer_id: BufferId,
5195 id: InlayId,
5196 cx: &mut Context<Self>,
5197 ) -> Option<ResolvedHint> {
5198 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5199
5200 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5201 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5202 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5203 let (server_id, resolve_data) = match &hint.resolve_state {
5204 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5205 ResolveState::Resolving => {
5206 return Some(ResolvedHint::Resolving(
5207 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5208 ));
5209 }
5210 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5211 };
5212
5213 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5214 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5215 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5216 id,
5217 cx.spawn(async move |lsp_store, cx| {
5218 let resolved_hint = resolve_task.await;
5219 lsp_store
5220 .update(cx, |lsp_store, _| {
5221 if let Some(old_inlay_hint) = lsp_store
5222 .lsp_data
5223 .get_mut(&buffer_id)
5224 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5225 {
5226 match resolved_hint {
5227 Ok(resolved_hint) => {
5228 *old_inlay_hint = resolved_hint;
5229 }
5230 Err(e) => {
5231 old_inlay_hint.resolve_state =
5232 ResolveState::CanResolve(server_id, resolve_data);
5233 log::error!("Inlay hint resolve failed: {e:#}");
5234 }
5235 }
5236 }
5237 })
5238 .ok();
5239 })
5240 .shared(),
5241 );
5242 debug_assert!(
5243 previous_task.is_none(),
5244 "Did not change hint's resolve state after spawning its resolve"
5245 );
5246 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5247 None
5248 }
5249
5250 fn resolve_inlay_hint(
5251 &self,
5252 mut hint: InlayHint,
5253 buffer: Entity<Buffer>,
5254 server_id: LanguageServerId,
5255 cx: &mut Context<Self>,
5256 ) -> Task<anyhow::Result<InlayHint>> {
5257 if let Some((upstream_client, project_id)) = self.upstream_client() {
5258 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5259 {
5260 hint.resolve_state = ResolveState::Resolved;
5261 return Task::ready(Ok(hint));
5262 }
5263 let request = proto::ResolveInlayHint {
5264 project_id,
5265 buffer_id: buffer.read(cx).remote_id().into(),
5266 language_server_id: server_id.0 as u64,
5267 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5268 };
5269 cx.background_spawn(async move {
5270 let response = upstream_client
5271 .request(request)
5272 .await
5273 .context("inlay hints proto request")?;
5274 match response.hint {
5275 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5276 .context("inlay hints proto resolve response conversion"),
5277 None => Ok(hint),
5278 }
5279 })
5280 } else {
5281 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5282 self.language_server_for_local_buffer(buffer, server_id, cx)
5283 .map(|(_, server)| server.clone())
5284 }) else {
5285 return Task::ready(Ok(hint));
5286 };
5287 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5288 return Task::ready(Ok(hint));
5289 }
5290 let buffer_snapshot = buffer.read(cx).snapshot();
5291 cx.spawn(async move |_, cx| {
5292 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5293 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5294 );
5295 let resolved_hint = resolve_task
5296 .await
5297 .into_response()
5298 .context("inlay hint resolve LSP request")?;
5299 let resolved_hint = InlayHints::lsp_to_project_hint(
5300 resolved_hint,
5301 &buffer,
5302 server_id,
5303 ResolveState::Resolved,
5304 false,
5305 cx,
5306 )
5307 .await?;
5308 Ok(resolved_hint)
5309 })
5310 }
5311 }
5312
5313 pub fn resolve_color_presentation(
5314 &mut self,
5315 mut color: DocumentColor,
5316 buffer: Entity<Buffer>,
5317 server_id: LanguageServerId,
5318 cx: &mut Context<Self>,
5319 ) -> Task<Result<DocumentColor>> {
5320 if color.resolved {
5321 return Task::ready(Ok(color));
5322 }
5323
5324 if let Some((upstream_client, project_id)) = self.upstream_client() {
5325 let start = color.lsp_range.start;
5326 let end = color.lsp_range.end;
5327 let request = proto::GetColorPresentation {
5328 project_id,
5329 server_id: server_id.to_proto(),
5330 buffer_id: buffer.read(cx).remote_id().into(),
5331 color: Some(proto::ColorInformation {
5332 red: color.color.red,
5333 green: color.color.green,
5334 blue: color.color.blue,
5335 alpha: color.color.alpha,
5336 lsp_range_start: Some(proto::PointUtf16 {
5337 row: start.line,
5338 column: start.character,
5339 }),
5340 lsp_range_end: Some(proto::PointUtf16 {
5341 row: end.line,
5342 column: end.character,
5343 }),
5344 }),
5345 };
5346 cx.background_spawn(async move {
5347 let response = upstream_client
5348 .request(request)
5349 .await
5350 .context("color presentation proto request")?;
5351 color.resolved = true;
5352 color.color_presentations = response
5353 .presentations
5354 .into_iter()
5355 .map(|presentation| ColorPresentation {
5356 label: SharedString::from(presentation.label),
5357 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5358 additional_text_edits: presentation
5359 .additional_text_edits
5360 .into_iter()
5361 .filter_map(deserialize_lsp_edit)
5362 .collect(),
5363 })
5364 .collect();
5365 Ok(color)
5366 })
5367 } else {
5368 let path = match buffer
5369 .update(cx, |buffer, cx| {
5370 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5371 })
5372 .context("buffer with the missing path")
5373 {
5374 Ok(path) => path,
5375 Err(e) => return Task::ready(Err(e)),
5376 };
5377 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5378 self.language_server_for_local_buffer(buffer, server_id, cx)
5379 .map(|(_, server)| server.clone())
5380 }) else {
5381 return Task::ready(Ok(color));
5382 };
5383 cx.background_spawn(async move {
5384 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5385 lsp::ColorPresentationParams {
5386 text_document: make_text_document_identifier(&path)?,
5387 color: color.color,
5388 range: color.lsp_range,
5389 work_done_progress_params: Default::default(),
5390 partial_result_params: Default::default(),
5391 },
5392 );
5393 color.color_presentations = resolve_task
5394 .await
5395 .into_response()
5396 .context("color presentation resolve LSP request")?
5397 .into_iter()
5398 .map(|presentation| ColorPresentation {
5399 label: SharedString::from(presentation.label),
5400 text_edit: presentation.text_edit,
5401 additional_text_edits: presentation
5402 .additional_text_edits
5403 .unwrap_or_default(),
5404 })
5405 .collect();
5406 color.resolved = true;
5407 Ok(color)
5408 })
5409 }
5410 }
5411
5412 pub(crate) fn linked_edits(
5413 &mut self,
5414 buffer: &Entity<Buffer>,
5415 position: Anchor,
5416 cx: &mut Context<Self>,
5417 ) -> Task<Result<Vec<Range<Anchor>>>> {
5418 let snapshot = buffer.read(cx).snapshot();
5419 let scope = snapshot.language_scope_at(position);
5420 let Some(server_id) = self
5421 .as_local()
5422 .and_then(|local| {
5423 buffer.update(cx, |buffer, cx| {
5424 local
5425 .language_servers_for_buffer(buffer, cx)
5426 .filter(|(_, server)| {
5427 LinkedEditingRange::check_server_capabilities(server.capabilities())
5428 })
5429 .filter(|(adapter, _)| {
5430 scope
5431 .as_ref()
5432 .map(|scope| scope.language_allowed(&adapter.name))
5433 .unwrap_or(true)
5434 })
5435 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5436 .next()
5437 })
5438 })
5439 .or_else(|| {
5440 self.upstream_client()
5441 .is_some()
5442 .then_some(LanguageServerToQuery::FirstCapable)
5443 })
5444 .filter(|_| {
5445 maybe!({
5446 let language = buffer.read(cx).language_at(position)?;
5447 Some(
5448 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5449 .linked_edits,
5450 )
5451 }) == Some(true)
5452 })
5453 else {
5454 return Task::ready(Ok(Vec::new()));
5455 };
5456
5457 self.request_lsp(
5458 buffer.clone(),
5459 server_id,
5460 LinkedEditingRange { position },
5461 cx,
5462 )
5463 }
5464
5465 fn apply_on_type_formatting(
5466 &mut self,
5467 buffer: Entity<Buffer>,
5468 position: Anchor,
5469 trigger: String,
5470 cx: &mut Context<Self>,
5471 ) -> Task<Result<Option<Transaction>>> {
5472 if let Some((client, project_id)) = self.upstream_client() {
5473 if !self.check_if_capable_for_proto_request(
5474 &buffer,
5475 |capabilities| {
5476 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5477 },
5478 cx,
5479 ) {
5480 return Task::ready(Ok(None));
5481 }
5482 let request = proto::OnTypeFormatting {
5483 project_id,
5484 buffer_id: buffer.read(cx).remote_id().into(),
5485 position: Some(serialize_anchor(&position)),
5486 trigger,
5487 version: serialize_version(&buffer.read(cx).version()),
5488 };
5489 cx.background_spawn(async move {
5490 client
5491 .request(request)
5492 .await?
5493 .transaction
5494 .map(language::proto::deserialize_transaction)
5495 .transpose()
5496 })
5497 } else if let Some(local) = self.as_local_mut() {
5498 let buffer_id = buffer.read(cx).remote_id();
5499 local.buffers_being_formatted.insert(buffer_id);
5500 cx.spawn(async move |this, cx| {
5501 let _cleanup = defer({
5502 let this = this.clone();
5503 let mut cx = cx.clone();
5504 move || {
5505 this.update(&mut cx, |this, _| {
5506 if let Some(local) = this.as_local_mut() {
5507 local.buffers_being_formatted.remove(&buffer_id);
5508 }
5509 })
5510 .ok();
5511 }
5512 });
5513
5514 buffer
5515 .update(cx, |buffer, _| {
5516 buffer.wait_for_edits(Some(position.timestamp))
5517 })
5518 .await?;
5519 this.update(cx, |this, cx| {
5520 let position = position.to_point_utf16(buffer.read(cx));
5521 this.on_type_format(buffer, position, trigger, false, cx)
5522 })?
5523 .await
5524 })
5525 } else {
5526 Task::ready(Err(anyhow!("No upstream client or local language server")))
5527 }
5528 }
5529
5530 pub fn on_type_format<T: ToPointUtf16>(
5531 &mut self,
5532 buffer: Entity<Buffer>,
5533 position: T,
5534 trigger: String,
5535 push_to_history: bool,
5536 cx: &mut Context<Self>,
5537 ) -> Task<Result<Option<Transaction>>> {
5538 let position = position.to_point_utf16(buffer.read(cx));
5539 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5540 }
5541
5542 fn on_type_format_impl(
5543 &mut self,
5544 buffer: Entity<Buffer>,
5545 position: PointUtf16,
5546 trigger: String,
5547 push_to_history: bool,
5548 cx: &mut Context<Self>,
5549 ) -> Task<Result<Option<Transaction>>> {
5550 let options = buffer.update(cx, |buffer, cx| {
5551 lsp_command::lsp_formatting_options(
5552 language_settings(
5553 buffer.language_at(position).map(|l| l.name()),
5554 buffer.file(),
5555 cx,
5556 )
5557 .as_ref(),
5558 )
5559 });
5560
5561 cx.spawn(async move |this, cx| {
5562 if let Some(waiter) =
5563 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5564 {
5565 waiter.await?;
5566 }
5567 cx.update(|cx| {
5568 this.update(cx, |this, cx| {
5569 this.request_lsp(
5570 buffer.clone(),
5571 LanguageServerToQuery::FirstCapable,
5572 OnTypeFormatting {
5573 position,
5574 trigger,
5575 options,
5576 push_to_history,
5577 },
5578 cx,
5579 )
5580 })
5581 })?
5582 .await
5583 })
5584 }
5585
5586 pub fn definitions(
5587 &mut self,
5588 buffer: &Entity<Buffer>,
5589 position: PointUtf16,
5590 cx: &mut Context<Self>,
5591 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5592 if let Some((upstream_client, project_id)) = self.upstream_client() {
5593 let request = GetDefinitions { position };
5594 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5595 return Task::ready(Ok(None));
5596 }
5597 let request_task = upstream_client.request_lsp(
5598 project_id,
5599 None,
5600 LSP_REQUEST_TIMEOUT,
5601 cx.background_executor().clone(),
5602 request.to_proto(project_id, buffer.read(cx)),
5603 );
5604 let buffer = buffer.clone();
5605 cx.spawn(async move |weak_lsp_store, cx| {
5606 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5607 return Ok(None);
5608 };
5609 let Some(responses) = request_task.await? else {
5610 return Ok(None);
5611 };
5612 let actions = join_all(responses.payload.into_iter().map(|response| {
5613 GetDefinitions { position }.response_from_proto(
5614 response.response,
5615 lsp_store.clone(),
5616 buffer.clone(),
5617 cx.clone(),
5618 )
5619 }))
5620 .await;
5621
5622 Ok(Some(
5623 actions
5624 .into_iter()
5625 .collect::<Result<Vec<Vec<_>>>>()?
5626 .into_iter()
5627 .flatten()
5628 .dedup()
5629 .collect(),
5630 ))
5631 })
5632 } else {
5633 let definitions_task = self.request_multiple_lsp_locally(
5634 buffer,
5635 Some(position),
5636 GetDefinitions { position },
5637 cx,
5638 );
5639 cx.background_spawn(async move {
5640 Ok(Some(
5641 definitions_task
5642 .await
5643 .into_iter()
5644 .flat_map(|(_, definitions)| definitions)
5645 .dedup()
5646 .collect(),
5647 ))
5648 })
5649 }
5650 }
5651
5652 pub fn declarations(
5653 &mut self,
5654 buffer: &Entity<Buffer>,
5655 position: PointUtf16,
5656 cx: &mut Context<Self>,
5657 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5658 if let Some((upstream_client, project_id)) = self.upstream_client() {
5659 let request = GetDeclarations { position };
5660 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5661 return Task::ready(Ok(None));
5662 }
5663 let request_task = upstream_client.request_lsp(
5664 project_id,
5665 None,
5666 LSP_REQUEST_TIMEOUT,
5667 cx.background_executor().clone(),
5668 request.to_proto(project_id, buffer.read(cx)),
5669 );
5670 let buffer = buffer.clone();
5671 cx.spawn(async move |weak_lsp_store, cx| {
5672 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5673 return Ok(None);
5674 };
5675 let Some(responses) = request_task.await? else {
5676 return Ok(None);
5677 };
5678 let actions = join_all(responses.payload.into_iter().map(|response| {
5679 GetDeclarations { position }.response_from_proto(
5680 response.response,
5681 lsp_store.clone(),
5682 buffer.clone(),
5683 cx.clone(),
5684 )
5685 }))
5686 .await;
5687
5688 Ok(Some(
5689 actions
5690 .into_iter()
5691 .collect::<Result<Vec<Vec<_>>>>()?
5692 .into_iter()
5693 .flatten()
5694 .dedup()
5695 .collect(),
5696 ))
5697 })
5698 } else {
5699 let declarations_task = self.request_multiple_lsp_locally(
5700 buffer,
5701 Some(position),
5702 GetDeclarations { position },
5703 cx,
5704 );
5705 cx.background_spawn(async move {
5706 Ok(Some(
5707 declarations_task
5708 .await
5709 .into_iter()
5710 .flat_map(|(_, declarations)| declarations)
5711 .dedup()
5712 .collect(),
5713 ))
5714 })
5715 }
5716 }
5717
5718 pub fn type_definitions(
5719 &mut self,
5720 buffer: &Entity<Buffer>,
5721 position: PointUtf16,
5722 cx: &mut Context<Self>,
5723 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5724 if let Some((upstream_client, project_id)) = self.upstream_client() {
5725 let request = GetTypeDefinitions { position };
5726 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5727 return Task::ready(Ok(None));
5728 }
5729 let request_task = upstream_client.request_lsp(
5730 project_id,
5731 None,
5732 LSP_REQUEST_TIMEOUT,
5733 cx.background_executor().clone(),
5734 request.to_proto(project_id, buffer.read(cx)),
5735 );
5736 let buffer = buffer.clone();
5737 cx.spawn(async move |weak_lsp_store, cx| {
5738 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5739 return Ok(None);
5740 };
5741 let Some(responses) = request_task.await? else {
5742 return Ok(None);
5743 };
5744 let actions = join_all(responses.payload.into_iter().map(|response| {
5745 GetTypeDefinitions { position }.response_from_proto(
5746 response.response,
5747 lsp_store.clone(),
5748 buffer.clone(),
5749 cx.clone(),
5750 )
5751 }))
5752 .await;
5753
5754 Ok(Some(
5755 actions
5756 .into_iter()
5757 .collect::<Result<Vec<Vec<_>>>>()?
5758 .into_iter()
5759 .flatten()
5760 .dedup()
5761 .collect(),
5762 ))
5763 })
5764 } else {
5765 let type_definitions_task = self.request_multiple_lsp_locally(
5766 buffer,
5767 Some(position),
5768 GetTypeDefinitions { position },
5769 cx,
5770 );
5771 cx.background_spawn(async move {
5772 Ok(Some(
5773 type_definitions_task
5774 .await
5775 .into_iter()
5776 .flat_map(|(_, type_definitions)| type_definitions)
5777 .dedup()
5778 .collect(),
5779 ))
5780 })
5781 }
5782 }
5783
5784 pub fn implementations(
5785 &mut self,
5786 buffer: &Entity<Buffer>,
5787 position: PointUtf16,
5788 cx: &mut Context<Self>,
5789 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5790 if let Some((upstream_client, project_id)) = self.upstream_client() {
5791 let request = GetImplementations { position };
5792 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5793 return Task::ready(Ok(None));
5794 }
5795 let request_task = upstream_client.request_lsp(
5796 project_id,
5797 None,
5798 LSP_REQUEST_TIMEOUT,
5799 cx.background_executor().clone(),
5800 request.to_proto(project_id, buffer.read(cx)),
5801 );
5802 let buffer = buffer.clone();
5803 cx.spawn(async move |weak_lsp_store, cx| {
5804 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5805 return Ok(None);
5806 };
5807 let Some(responses) = request_task.await? else {
5808 return Ok(None);
5809 };
5810 let actions = join_all(responses.payload.into_iter().map(|response| {
5811 GetImplementations { position }.response_from_proto(
5812 response.response,
5813 lsp_store.clone(),
5814 buffer.clone(),
5815 cx.clone(),
5816 )
5817 }))
5818 .await;
5819
5820 Ok(Some(
5821 actions
5822 .into_iter()
5823 .collect::<Result<Vec<Vec<_>>>>()?
5824 .into_iter()
5825 .flatten()
5826 .dedup()
5827 .collect(),
5828 ))
5829 })
5830 } else {
5831 let implementations_task = self.request_multiple_lsp_locally(
5832 buffer,
5833 Some(position),
5834 GetImplementations { position },
5835 cx,
5836 );
5837 cx.background_spawn(async move {
5838 Ok(Some(
5839 implementations_task
5840 .await
5841 .into_iter()
5842 .flat_map(|(_, implementations)| implementations)
5843 .dedup()
5844 .collect(),
5845 ))
5846 })
5847 }
5848 }
5849
5850 pub fn references(
5851 &mut self,
5852 buffer: &Entity<Buffer>,
5853 position: PointUtf16,
5854 cx: &mut Context<Self>,
5855 ) -> Task<Result<Option<Vec<Location>>>> {
5856 if let Some((upstream_client, project_id)) = self.upstream_client() {
5857 let request = GetReferences { position };
5858 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5859 return Task::ready(Ok(None));
5860 }
5861
5862 let request_task = upstream_client.request_lsp(
5863 project_id,
5864 None,
5865 LSP_REQUEST_TIMEOUT,
5866 cx.background_executor().clone(),
5867 request.to_proto(project_id, buffer.read(cx)),
5868 );
5869 let buffer = buffer.clone();
5870 cx.spawn(async move |weak_lsp_store, cx| {
5871 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5872 return Ok(None);
5873 };
5874 let Some(responses) = request_task.await? else {
5875 return Ok(None);
5876 };
5877
5878 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5879 GetReferences { position }.response_from_proto(
5880 lsp_response.response,
5881 lsp_store.clone(),
5882 buffer.clone(),
5883 cx.clone(),
5884 )
5885 }))
5886 .await
5887 .into_iter()
5888 .collect::<Result<Vec<Vec<_>>>>()?
5889 .into_iter()
5890 .flatten()
5891 .dedup()
5892 .collect();
5893 Ok(Some(locations))
5894 })
5895 } else {
5896 let references_task = self.request_multiple_lsp_locally(
5897 buffer,
5898 Some(position),
5899 GetReferences { position },
5900 cx,
5901 );
5902 cx.background_spawn(async move {
5903 Ok(Some(
5904 references_task
5905 .await
5906 .into_iter()
5907 .flat_map(|(_, references)| references)
5908 .dedup()
5909 .collect(),
5910 ))
5911 })
5912 }
5913 }
5914
5915 pub fn code_actions(
5916 &mut self,
5917 buffer: &Entity<Buffer>,
5918 range: Range<Anchor>,
5919 kinds: Option<Vec<CodeActionKind>>,
5920 cx: &mut Context<Self>,
5921 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5922 if let Some((upstream_client, project_id)) = self.upstream_client() {
5923 let request = GetCodeActions {
5924 range: range.clone(),
5925 kinds: kinds.clone(),
5926 };
5927 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5928 return Task::ready(Ok(None));
5929 }
5930 let request_task = upstream_client.request_lsp(
5931 project_id,
5932 None,
5933 LSP_REQUEST_TIMEOUT,
5934 cx.background_executor().clone(),
5935 request.to_proto(project_id, buffer.read(cx)),
5936 );
5937 let buffer = buffer.clone();
5938 cx.spawn(async move |weak_lsp_store, cx| {
5939 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5940 return Ok(None);
5941 };
5942 let Some(responses) = request_task.await? else {
5943 return Ok(None);
5944 };
5945 let actions = join_all(responses.payload.into_iter().map(|response| {
5946 GetCodeActions {
5947 range: range.clone(),
5948 kinds: kinds.clone(),
5949 }
5950 .response_from_proto(
5951 response.response,
5952 lsp_store.clone(),
5953 buffer.clone(),
5954 cx.clone(),
5955 )
5956 }))
5957 .await;
5958
5959 Ok(Some(
5960 actions
5961 .into_iter()
5962 .collect::<Result<Vec<Vec<_>>>>()?
5963 .into_iter()
5964 .flatten()
5965 .collect(),
5966 ))
5967 })
5968 } else {
5969 let all_actions_task = self.request_multiple_lsp_locally(
5970 buffer,
5971 Some(range.start),
5972 GetCodeActions { range, kinds },
5973 cx,
5974 );
5975 cx.background_spawn(async move {
5976 Ok(Some(
5977 all_actions_task
5978 .await
5979 .into_iter()
5980 .flat_map(|(_, actions)| actions)
5981 .collect(),
5982 ))
5983 })
5984 }
5985 }
5986
5987 pub fn code_lens_actions(
5988 &mut self,
5989 buffer: &Entity<Buffer>,
5990 cx: &mut Context<Self>,
5991 ) -> CodeLensTask {
5992 let version_queried_for = buffer.read(cx).version();
5993 let buffer_id = buffer.read(cx).remote_id();
5994 let existing_servers = self.as_local().map(|local| {
5995 local
5996 .buffers_opened_in_servers
5997 .get(&buffer_id)
5998 .cloned()
5999 .unwrap_or_default()
6000 });
6001
6002 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6003 if let Some(cached_lens) = &lsp_data.code_lens {
6004 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6005 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6006 existing_servers != cached_lens.lens.keys().copied().collect()
6007 });
6008 if !has_different_servers {
6009 return Task::ready(Ok(Some(
6010 cached_lens.lens.values().flatten().cloned().collect(),
6011 )))
6012 .shared();
6013 }
6014 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6015 if !version_queried_for.changed_since(updating_for) {
6016 return running_update.clone();
6017 }
6018 }
6019 }
6020 }
6021
6022 let lens_lsp_data = self
6023 .latest_lsp_data(buffer, cx)
6024 .code_lens
6025 .get_or_insert_default();
6026 let buffer = buffer.clone();
6027 let query_version_queried_for = version_queried_for.clone();
6028 let new_task = cx
6029 .spawn(async move |lsp_store, cx| {
6030 cx.background_executor()
6031 .timer(Duration::from_millis(30))
6032 .await;
6033 let fetched_lens = lsp_store
6034 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6035 .map_err(Arc::new)?
6036 .await
6037 .context("fetching code lens")
6038 .map_err(Arc::new);
6039 let fetched_lens = match fetched_lens {
6040 Ok(fetched_lens) => fetched_lens,
6041 Err(e) => {
6042 lsp_store
6043 .update(cx, |lsp_store, _| {
6044 if let Some(lens_lsp_data) = lsp_store
6045 .lsp_data
6046 .get_mut(&buffer_id)
6047 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6048 {
6049 lens_lsp_data.update = None;
6050 }
6051 })
6052 .ok();
6053 return Err(e);
6054 }
6055 };
6056
6057 lsp_store
6058 .update(cx, |lsp_store, _| {
6059 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6060 let code_lens = lsp_data.code_lens.as_mut()?;
6061 if let Some(fetched_lens) = fetched_lens {
6062 if lsp_data.buffer_version == query_version_queried_for {
6063 code_lens.lens.extend(fetched_lens);
6064 } else if !lsp_data
6065 .buffer_version
6066 .changed_since(&query_version_queried_for)
6067 {
6068 lsp_data.buffer_version = query_version_queried_for;
6069 code_lens.lens = fetched_lens;
6070 }
6071 }
6072 code_lens.update = None;
6073 Some(code_lens.lens.values().flatten().cloned().collect())
6074 })
6075 .map_err(Arc::new)
6076 })
6077 .shared();
6078 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6079 new_task
6080 }
6081
6082 fn fetch_code_lens(
6083 &mut self,
6084 buffer: &Entity<Buffer>,
6085 cx: &mut Context<Self>,
6086 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6087 if let Some((upstream_client, project_id)) = self.upstream_client() {
6088 let request = GetCodeLens;
6089 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6090 return Task::ready(Ok(None));
6091 }
6092 let request_task = upstream_client.request_lsp(
6093 project_id,
6094 None,
6095 LSP_REQUEST_TIMEOUT,
6096 cx.background_executor().clone(),
6097 request.to_proto(project_id, buffer.read(cx)),
6098 );
6099 let buffer = buffer.clone();
6100 cx.spawn(async move |weak_lsp_store, cx| {
6101 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6102 return Ok(None);
6103 };
6104 let Some(responses) = request_task.await? else {
6105 return Ok(None);
6106 };
6107
6108 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6109 let lsp_store = lsp_store.clone();
6110 let buffer = buffer.clone();
6111 let cx = cx.clone();
6112 async move {
6113 (
6114 LanguageServerId::from_proto(response.server_id),
6115 GetCodeLens
6116 .response_from_proto(response.response, lsp_store, buffer, cx)
6117 .await,
6118 )
6119 }
6120 }))
6121 .await;
6122
6123 let mut has_errors = false;
6124 let code_lens_actions = code_lens_actions
6125 .into_iter()
6126 .filter_map(|(server_id, code_lens)| match code_lens {
6127 Ok(code_lens) => Some((server_id, code_lens)),
6128 Err(e) => {
6129 has_errors = true;
6130 log::error!("{e:#}");
6131 None
6132 }
6133 })
6134 .collect::<HashMap<_, _>>();
6135 anyhow::ensure!(
6136 !has_errors || !code_lens_actions.is_empty(),
6137 "Failed to fetch code lens"
6138 );
6139 Ok(Some(code_lens_actions))
6140 })
6141 } else {
6142 let code_lens_actions_task =
6143 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6144 cx.background_spawn(async move {
6145 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6146 })
6147 }
6148 }
6149
6150 #[inline(never)]
6151 pub fn completions(
6152 &self,
6153 buffer: &Entity<Buffer>,
6154 position: PointUtf16,
6155 context: CompletionContext,
6156 cx: &mut Context<Self>,
6157 ) -> Task<Result<Vec<CompletionResponse>>> {
6158 let language_registry = self.languages.clone();
6159
6160 if let Some((upstream_client, project_id)) = self.upstream_client() {
6161 let snapshot = buffer.read(cx).snapshot();
6162 let offset = position.to_offset(&snapshot);
6163 let scope = snapshot.language_scope_at(offset);
6164 let capable_lsps = self.all_capable_for_proto_request(
6165 buffer,
6166 |server_name, capabilities| {
6167 capabilities.completion_provider.is_some()
6168 && scope
6169 .as_ref()
6170 .map(|scope| scope.language_allowed(server_name))
6171 .unwrap_or(true)
6172 },
6173 cx,
6174 );
6175 if capable_lsps.is_empty() {
6176 return Task::ready(Ok(Vec::new()));
6177 }
6178
6179 let language = buffer.read(cx).language().cloned();
6180
6181 // In the future, we should provide project guests with the names of LSP adapters,
6182 // so that they can use the correct LSP adapter when computing labels. For now,
6183 // guests just use the first LSP adapter associated with the buffer's language.
6184 let lsp_adapter = language.as_ref().and_then(|language| {
6185 language_registry
6186 .lsp_adapters(&language.name())
6187 .first()
6188 .cloned()
6189 });
6190
6191 let buffer = buffer.clone();
6192
6193 cx.spawn(async move |this, cx| {
6194 let requests = join_all(
6195 capable_lsps
6196 .into_iter()
6197 .map(|id| {
6198 let request = GetCompletions {
6199 position,
6200 context: context.clone(),
6201 server_id: Some(id),
6202 };
6203 let buffer = buffer.clone();
6204 let language = language.clone();
6205 let lsp_adapter = lsp_adapter.clone();
6206 let upstream_client = upstream_client.clone();
6207 let response = this
6208 .update(cx, |this, cx| {
6209 this.send_lsp_proto_request(
6210 buffer,
6211 upstream_client,
6212 project_id,
6213 request,
6214 cx,
6215 )
6216 })
6217 .log_err();
6218 async move {
6219 let response = response?.await.log_err()?;
6220
6221 let completions = populate_labels_for_completions(
6222 response.completions,
6223 language,
6224 lsp_adapter,
6225 )
6226 .await;
6227
6228 Some(CompletionResponse {
6229 completions,
6230 display_options: CompletionDisplayOptions::default(),
6231 is_incomplete: response.is_incomplete,
6232 })
6233 }
6234 })
6235 .collect::<Vec<_>>(),
6236 );
6237 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6238 })
6239 } else if let Some(local) = self.as_local() {
6240 let snapshot = buffer.read(cx).snapshot();
6241 let offset = position.to_offset(&snapshot);
6242 let scope = snapshot.language_scope_at(offset);
6243 let language = snapshot.language().cloned();
6244 let completion_settings = language_settings(
6245 language.as_ref().map(|language| language.name()),
6246 buffer.read(cx).file(),
6247 cx,
6248 )
6249 .completions
6250 .clone();
6251 if !completion_settings.lsp {
6252 return Task::ready(Ok(Vec::new()));
6253 }
6254
6255 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6256 local
6257 .language_servers_for_buffer(buffer, cx)
6258 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6259 .filter(|(adapter, _)| {
6260 scope
6261 .as_ref()
6262 .map(|scope| scope.language_allowed(&adapter.name))
6263 .unwrap_or(true)
6264 })
6265 .map(|(_, server)| server.server_id())
6266 .collect()
6267 });
6268
6269 let buffer = buffer.clone();
6270 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6271 let lsp_timeout = if lsp_timeout > 0 {
6272 Some(Duration::from_millis(lsp_timeout))
6273 } else {
6274 None
6275 };
6276 cx.spawn(async move |this, cx| {
6277 let mut tasks = Vec::with_capacity(server_ids.len());
6278 this.update(cx, |lsp_store, cx| {
6279 for server_id in server_ids {
6280 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6281 let lsp_timeout = lsp_timeout
6282 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6283 let mut timeout = cx.background_spawn(async move {
6284 match lsp_timeout {
6285 Some(lsp_timeout) => {
6286 lsp_timeout.await;
6287 true
6288 },
6289 None => false,
6290 }
6291 }).fuse();
6292 let mut lsp_request = lsp_store.request_lsp(
6293 buffer.clone(),
6294 LanguageServerToQuery::Other(server_id),
6295 GetCompletions {
6296 position,
6297 context: context.clone(),
6298 server_id: Some(server_id),
6299 },
6300 cx,
6301 ).fuse();
6302 let new_task = cx.background_spawn(async move {
6303 select_biased! {
6304 response = lsp_request => anyhow::Ok(Some(response?)),
6305 timeout_happened = timeout => {
6306 if timeout_happened {
6307 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6308 Ok(None)
6309 } else {
6310 let completions = lsp_request.await?;
6311 Ok(Some(completions))
6312 }
6313 },
6314 }
6315 });
6316 tasks.push((lsp_adapter, new_task));
6317 }
6318 })?;
6319
6320 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6321 let completion_response = task.await.ok()??;
6322 let completions = populate_labels_for_completions(
6323 completion_response.completions,
6324 language.clone(),
6325 lsp_adapter,
6326 )
6327 .await;
6328 Some(CompletionResponse {
6329 completions,
6330 display_options: CompletionDisplayOptions::default(),
6331 is_incomplete: completion_response.is_incomplete,
6332 })
6333 });
6334
6335 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6336
6337 Ok(responses.into_iter().flatten().collect())
6338 })
6339 } else {
6340 Task::ready(Err(anyhow!("No upstream client or local language server")))
6341 }
6342 }
6343
6344 pub fn resolve_completions(
6345 &self,
6346 buffer: Entity<Buffer>,
6347 completion_indices: Vec<usize>,
6348 completions: Rc<RefCell<Box<[Completion]>>>,
6349 cx: &mut Context<Self>,
6350 ) -> Task<Result<bool>> {
6351 let client = self.upstream_client();
6352 let buffer_id = buffer.read(cx).remote_id();
6353 let buffer_snapshot = buffer.read(cx).snapshot();
6354
6355 if !self.check_if_capable_for_proto_request(
6356 &buffer,
6357 GetCompletions::can_resolve_completions,
6358 cx,
6359 ) {
6360 return Task::ready(Ok(false));
6361 }
6362 cx.spawn(async move |lsp_store, cx| {
6363 let mut did_resolve = false;
6364 if let Some((client, project_id)) = client {
6365 for completion_index in completion_indices {
6366 let server_id = {
6367 let completion = &completions.borrow()[completion_index];
6368 completion.source.server_id()
6369 };
6370 if let Some(server_id) = server_id {
6371 if Self::resolve_completion_remote(
6372 project_id,
6373 server_id,
6374 buffer_id,
6375 completions.clone(),
6376 completion_index,
6377 client.clone(),
6378 )
6379 .await
6380 .log_err()
6381 .is_some()
6382 {
6383 did_resolve = true;
6384 }
6385 } else {
6386 resolve_word_completion(
6387 &buffer_snapshot,
6388 &mut completions.borrow_mut()[completion_index],
6389 );
6390 }
6391 }
6392 } else {
6393 for completion_index in completion_indices {
6394 let server_id = {
6395 let completion = &completions.borrow()[completion_index];
6396 completion.source.server_id()
6397 };
6398 if let Some(server_id) = server_id {
6399 let server_and_adapter = lsp_store
6400 .read_with(cx, |lsp_store, _| {
6401 let server = lsp_store.language_server_for_id(server_id)?;
6402 let adapter =
6403 lsp_store.language_server_adapter_for_id(server.server_id())?;
6404 Some((server, adapter))
6405 })
6406 .ok()
6407 .flatten();
6408 let Some((server, adapter)) = server_and_adapter else {
6409 continue;
6410 };
6411
6412 let resolved = Self::resolve_completion_local(
6413 server,
6414 completions.clone(),
6415 completion_index,
6416 )
6417 .await
6418 .log_err()
6419 .is_some();
6420 if resolved {
6421 Self::regenerate_completion_labels(
6422 adapter,
6423 &buffer_snapshot,
6424 completions.clone(),
6425 completion_index,
6426 )
6427 .await
6428 .log_err();
6429 did_resolve = true;
6430 }
6431 } else {
6432 resolve_word_completion(
6433 &buffer_snapshot,
6434 &mut completions.borrow_mut()[completion_index],
6435 );
6436 }
6437 }
6438 }
6439
6440 Ok(did_resolve)
6441 })
6442 }
6443
6444 async fn resolve_completion_local(
6445 server: Arc<lsp::LanguageServer>,
6446 completions: Rc<RefCell<Box<[Completion]>>>,
6447 completion_index: usize,
6448 ) -> Result<()> {
6449 let server_id = server.server_id();
6450 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6451 return Ok(());
6452 }
6453
6454 let request = {
6455 let completion = &completions.borrow()[completion_index];
6456 match &completion.source {
6457 CompletionSource::Lsp {
6458 lsp_completion,
6459 resolved,
6460 server_id: completion_server_id,
6461 ..
6462 } => {
6463 if *resolved {
6464 return Ok(());
6465 }
6466 anyhow::ensure!(
6467 server_id == *completion_server_id,
6468 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6469 );
6470 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6471 }
6472 CompletionSource::BufferWord { .. }
6473 | CompletionSource::Dap { .. }
6474 | CompletionSource::Custom => {
6475 return Ok(());
6476 }
6477 }
6478 };
6479 let resolved_completion = request
6480 .await
6481 .into_response()
6482 .context("resolve completion")?;
6483
6484 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6485 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6486
6487 let mut completions = completions.borrow_mut();
6488 let completion = &mut completions[completion_index];
6489 if let CompletionSource::Lsp {
6490 lsp_completion,
6491 resolved,
6492 server_id: completion_server_id,
6493 ..
6494 } = &mut completion.source
6495 {
6496 if *resolved {
6497 return Ok(());
6498 }
6499 anyhow::ensure!(
6500 server_id == *completion_server_id,
6501 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6502 );
6503 **lsp_completion = resolved_completion;
6504 *resolved = true;
6505 }
6506 Ok(())
6507 }
6508
6509 async fn regenerate_completion_labels(
6510 adapter: Arc<CachedLspAdapter>,
6511 snapshot: &BufferSnapshot,
6512 completions: Rc<RefCell<Box<[Completion]>>>,
6513 completion_index: usize,
6514 ) -> Result<()> {
6515 let completion_item = completions.borrow()[completion_index]
6516 .source
6517 .lsp_completion(true)
6518 .map(Cow::into_owned);
6519 if let Some(lsp_documentation) = completion_item
6520 .as_ref()
6521 .and_then(|completion_item| completion_item.documentation.clone())
6522 {
6523 let mut completions = completions.borrow_mut();
6524 let completion = &mut completions[completion_index];
6525 completion.documentation = Some(lsp_documentation.into());
6526 } else {
6527 let mut completions = completions.borrow_mut();
6528 let completion = &mut completions[completion_index];
6529 completion.documentation = Some(CompletionDocumentation::Undocumented);
6530 }
6531
6532 let mut new_label = match completion_item {
6533 Some(completion_item) => {
6534 // Some language servers always return `detail` lazily via resolve, regardless of
6535 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6536 // See: https://github.com/yioneko/vtsls/issues/213
6537 let language = snapshot.language();
6538 match language {
6539 Some(language) => {
6540 adapter
6541 .labels_for_completions(
6542 std::slice::from_ref(&completion_item),
6543 language,
6544 )
6545 .await?
6546 }
6547 None => Vec::new(),
6548 }
6549 .pop()
6550 .flatten()
6551 .unwrap_or_else(|| {
6552 CodeLabel::fallback_for_completion(
6553 &completion_item,
6554 language.map(|language| language.as_ref()),
6555 )
6556 })
6557 }
6558 None => CodeLabel::plain(
6559 completions.borrow()[completion_index].new_text.clone(),
6560 None,
6561 ),
6562 };
6563 ensure_uniform_list_compatible_label(&mut new_label);
6564
6565 let mut completions = completions.borrow_mut();
6566 let completion = &mut completions[completion_index];
6567 if completion.label.filter_text() == new_label.filter_text() {
6568 completion.label = new_label;
6569 } else {
6570 log::error!(
6571 "Resolved completion changed display label from {} to {}. \
6572 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6573 completion.label.text(),
6574 new_label.text(),
6575 completion.label.filter_text(),
6576 new_label.filter_text()
6577 );
6578 }
6579
6580 Ok(())
6581 }
6582
6583 async fn resolve_completion_remote(
6584 project_id: u64,
6585 server_id: LanguageServerId,
6586 buffer_id: BufferId,
6587 completions: Rc<RefCell<Box<[Completion]>>>,
6588 completion_index: usize,
6589 client: AnyProtoClient,
6590 ) -> Result<()> {
6591 let lsp_completion = {
6592 let completion = &completions.borrow()[completion_index];
6593 match &completion.source {
6594 CompletionSource::Lsp {
6595 lsp_completion,
6596 resolved,
6597 server_id: completion_server_id,
6598 ..
6599 } => {
6600 anyhow::ensure!(
6601 server_id == *completion_server_id,
6602 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6603 );
6604 if *resolved {
6605 return Ok(());
6606 }
6607 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6608 }
6609 CompletionSource::Custom
6610 | CompletionSource::Dap { .. }
6611 | CompletionSource::BufferWord { .. } => {
6612 return Ok(());
6613 }
6614 }
6615 };
6616 let request = proto::ResolveCompletionDocumentation {
6617 project_id,
6618 language_server_id: server_id.0 as u64,
6619 lsp_completion,
6620 buffer_id: buffer_id.into(),
6621 };
6622
6623 let response = client
6624 .request(request)
6625 .await
6626 .context("completion documentation resolve proto request")?;
6627 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6628
6629 let documentation = if response.documentation.is_empty() {
6630 CompletionDocumentation::Undocumented
6631 } else if response.documentation_is_markdown {
6632 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6633 } else if response.documentation.lines().count() <= 1 {
6634 CompletionDocumentation::SingleLine(response.documentation.into())
6635 } else {
6636 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6637 };
6638
6639 let mut completions = completions.borrow_mut();
6640 let completion = &mut completions[completion_index];
6641 completion.documentation = Some(documentation);
6642 if let CompletionSource::Lsp {
6643 insert_range,
6644 lsp_completion,
6645 resolved,
6646 server_id: completion_server_id,
6647 lsp_defaults: _,
6648 } = &mut completion.source
6649 {
6650 let completion_insert_range = response
6651 .old_insert_start
6652 .and_then(deserialize_anchor)
6653 .zip(response.old_insert_end.and_then(deserialize_anchor));
6654 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6655
6656 if *resolved {
6657 return Ok(());
6658 }
6659 anyhow::ensure!(
6660 server_id == *completion_server_id,
6661 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6662 );
6663 **lsp_completion = resolved_lsp_completion;
6664 *resolved = true;
6665 }
6666
6667 let replace_range = response
6668 .old_replace_start
6669 .and_then(deserialize_anchor)
6670 .zip(response.old_replace_end.and_then(deserialize_anchor));
6671 if let Some((old_replace_start, old_replace_end)) = replace_range
6672 && !response.new_text.is_empty()
6673 {
6674 completion.new_text = response.new_text;
6675 completion.replace_range = old_replace_start..old_replace_end;
6676 }
6677
6678 Ok(())
6679 }
6680
6681 pub fn apply_additional_edits_for_completion(
6682 &self,
6683 buffer_handle: Entity<Buffer>,
6684 completions: Rc<RefCell<Box<[Completion]>>>,
6685 completion_index: usize,
6686 push_to_history: bool,
6687 cx: &mut Context<Self>,
6688 ) -> Task<Result<Option<Transaction>>> {
6689 if let Some((client, project_id)) = self.upstream_client() {
6690 let buffer = buffer_handle.read(cx);
6691 let buffer_id = buffer.remote_id();
6692 cx.spawn(async move |_, cx| {
6693 let request = {
6694 let completion = completions.borrow()[completion_index].clone();
6695 proto::ApplyCompletionAdditionalEdits {
6696 project_id,
6697 buffer_id: buffer_id.into(),
6698 completion: Some(Self::serialize_completion(&CoreCompletion {
6699 replace_range: completion.replace_range,
6700 new_text: completion.new_text,
6701 source: completion.source,
6702 })),
6703 }
6704 };
6705
6706 if let Some(transaction) = client.request(request).await?.transaction {
6707 let transaction = language::proto::deserialize_transaction(transaction)?;
6708 buffer_handle
6709 .update(cx, |buffer, _| {
6710 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6711 })
6712 .await?;
6713 if push_to_history {
6714 buffer_handle.update(cx, |buffer, _| {
6715 buffer.push_transaction(transaction.clone(), Instant::now());
6716 buffer.finalize_last_transaction();
6717 });
6718 }
6719 Ok(Some(transaction))
6720 } else {
6721 Ok(None)
6722 }
6723 })
6724 } else {
6725 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6726 let completion = &completions.borrow()[completion_index];
6727 let server_id = completion.source.server_id()?;
6728 Some(
6729 self.language_server_for_local_buffer(buffer, server_id, cx)?
6730 .1
6731 .clone(),
6732 )
6733 }) else {
6734 return Task::ready(Ok(None));
6735 };
6736
6737 cx.spawn(async move |this, cx| {
6738 Self::resolve_completion_local(
6739 server.clone(),
6740 completions.clone(),
6741 completion_index,
6742 )
6743 .await
6744 .context("resolving completion")?;
6745 let completion = completions.borrow()[completion_index].clone();
6746 let additional_text_edits = completion
6747 .source
6748 .lsp_completion(true)
6749 .as_ref()
6750 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6751 if let Some(edits) = additional_text_edits {
6752 let edits = this
6753 .update(cx, |this, cx| {
6754 this.as_local_mut().unwrap().edits_from_lsp(
6755 &buffer_handle,
6756 edits,
6757 server.server_id(),
6758 None,
6759 cx,
6760 )
6761 })?
6762 .await?;
6763
6764 buffer_handle.update(cx, |buffer, cx| {
6765 buffer.finalize_last_transaction();
6766 buffer.start_transaction();
6767
6768 for (range, text) in edits {
6769 let primary = &completion.replace_range;
6770
6771 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6772 // and the primary completion is just an insertion (empty range), then this is likely
6773 // an auto-import scenario and should not be considered overlapping
6774 // https://github.com/zed-industries/zed/issues/26136
6775 let is_file_start_auto_import = {
6776 let snapshot = buffer.snapshot();
6777 let primary_start_point = primary.start.to_point(&snapshot);
6778 let range_start_point = range.start.to_point(&snapshot);
6779
6780 let result = primary_start_point.row == 0
6781 && primary_start_point.column == 0
6782 && range_start_point.row == 0
6783 && range_start_point.column == 0;
6784
6785 result
6786 };
6787
6788 let has_overlap = if is_file_start_auto_import {
6789 false
6790 } else {
6791 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6792 && primary.end.cmp(&range.start, buffer).is_ge();
6793 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6794 && range.end.cmp(&primary.end, buffer).is_ge();
6795 let result = start_within || end_within;
6796 result
6797 };
6798
6799 //Skip additional edits which overlap with the primary completion edit
6800 //https://github.com/zed-industries/zed/pull/1871
6801 if !has_overlap {
6802 buffer.edit([(range, text)], None, cx);
6803 }
6804 }
6805
6806 let transaction = if buffer.end_transaction(cx).is_some() {
6807 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6808 if !push_to_history {
6809 buffer.forget_transaction(transaction.id);
6810 }
6811 Some(transaction)
6812 } else {
6813 None
6814 };
6815 Ok(transaction)
6816 })
6817 } else {
6818 Ok(None)
6819 }
6820 })
6821 }
6822 }
6823
6824 pub fn pull_diagnostics(
6825 &mut self,
6826 buffer: Entity<Buffer>,
6827 cx: &mut Context<Self>,
6828 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6829 let buffer_id = buffer.read(cx).remote_id();
6830
6831 if let Some((client, upstream_project_id)) = self.upstream_client() {
6832 let mut suitable_capabilities = None;
6833 // Are we capable for proto request?
6834 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6835 &buffer,
6836 |capabilities| {
6837 if let Some(caps) = &capabilities.diagnostic_provider {
6838 suitable_capabilities = Some(caps.clone());
6839 true
6840 } else {
6841 false
6842 }
6843 },
6844 cx,
6845 );
6846 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6847 let Some(dynamic_caps) = suitable_capabilities else {
6848 return Task::ready(Ok(None));
6849 };
6850 assert!(any_server_has_diagnostics_provider);
6851
6852 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6853 let request = GetDocumentDiagnostics {
6854 previous_result_id: None,
6855 identifier,
6856 registration_id: None,
6857 };
6858 let request_task = client.request_lsp(
6859 upstream_project_id,
6860 None,
6861 LSP_REQUEST_TIMEOUT,
6862 cx.background_executor().clone(),
6863 request.to_proto(upstream_project_id, buffer.read(cx)),
6864 );
6865 cx.background_spawn(async move {
6866 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6867 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6868 // Do not attempt to further process the dummy responses here.
6869 let _response = request_task.await?;
6870 Ok(None)
6871 })
6872 } else {
6873 let servers = buffer.update(cx, |buffer, cx| {
6874 self.running_language_servers_for_local_buffer(buffer, cx)
6875 .map(|(_, server)| server.clone())
6876 .collect::<Vec<_>>()
6877 });
6878
6879 let pull_diagnostics = servers
6880 .into_iter()
6881 .flat_map(|server| {
6882 let result = maybe!({
6883 let local = self.as_local()?;
6884 let server_id = server.server_id();
6885 let providers_with_identifiers = local
6886 .language_server_dynamic_registrations
6887 .get(&server_id)
6888 .into_iter()
6889 .flat_map(|registrations| registrations.diagnostics.clone())
6890 .collect::<Vec<_>>();
6891 Some(
6892 providers_with_identifiers
6893 .into_iter()
6894 .map(|(registration_id, dynamic_caps)| {
6895 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6896 let registration_id = registration_id.map(SharedString::from);
6897 let result_id = self.result_id_for_buffer_pull(
6898 server_id,
6899 buffer_id,
6900 ®istration_id,
6901 cx,
6902 );
6903 self.request_lsp(
6904 buffer.clone(),
6905 LanguageServerToQuery::Other(server_id),
6906 GetDocumentDiagnostics {
6907 previous_result_id: result_id,
6908 registration_id,
6909 identifier,
6910 },
6911 cx,
6912 )
6913 })
6914 .collect::<Vec<_>>(),
6915 )
6916 });
6917
6918 result.unwrap_or_default()
6919 })
6920 .collect::<Vec<_>>();
6921
6922 cx.background_spawn(async move {
6923 let mut responses = Vec::new();
6924 for diagnostics in join_all(pull_diagnostics).await {
6925 responses.extend(diagnostics?);
6926 }
6927 Ok(Some(responses))
6928 })
6929 }
6930 }
6931
6932 pub fn applicable_inlay_chunks(
6933 &mut self,
6934 buffer: &Entity<Buffer>,
6935 ranges: &[Range<text::Anchor>],
6936 cx: &mut Context<Self>,
6937 ) -> Vec<Range<BufferRow>> {
6938 let buffer_snapshot = buffer.read(cx).snapshot();
6939 let ranges = ranges
6940 .iter()
6941 .map(|range| range.to_point(&buffer_snapshot))
6942 .collect::<Vec<_>>();
6943
6944 self.latest_lsp_data(buffer, cx)
6945 .inlay_hints
6946 .applicable_chunks(ranges.as_slice())
6947 .map(|chunk| chunk.row_range())
6948 .collect()
6949 }
6950
6951 pub fn invalidate_inlay_hints<'a>(
6952 &'a mut self,
6953 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6954 ) {
6955 for buffer_id in for_buffers {
6956 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6957 lsp_data.inlay_hints.clear();
6958 }
6959 }
6960 }
6961
6962 pub fn inlay_hints(
6963 &mut self,
6964 invalidate: InvalidationStrategy,
6965 buffer: Entity<Buffer>,
6966 ranges: Vec<Range<text::Anchor>>,
6967 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6968 cx: &mut Context<Self>,
6969 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6970 let next_hint_id = self.next_hint_id.clone();
6971 let lsp_data = self.latest_lsp_data(&buffer, cx);
6972 let query_version = lsp_data.buffer_version.clone();
6973 let mut lsp_refresh_requested = false;
6974 let for_server = if let InvalidationStrategy::RefreshRequested {
6975 server_id,
6976 request_id,
6977 } = invalidate
6978 {
6979 let invalidated = lsp_data
6980 .inlay_hints
6981 .invalidate_for_server_refresh(server_id, request_id);
6982 lsp_refresh_requested = invalidated;
6983 Some(server_id)
6984 } else {
6985 None
6986 };
6987 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6988 let known_chunks = known_chunks
6989 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6990 .map(|(_, known_chunks)| known_chunks)
6991 .unwrap_or_default();
6992
6993 let buffer_snapshot = buffer.read(cx).snapshot();
6994 let ranges = ranges
6995 .iter()
6996 .map(|range| range.to_point(&buffer_snapshot))
6997 .collect::<Vec<_>>();
6998
6999 let mut hint_fetch_tasks = Vec::new();
7000 let mut cached_inlay_hints = None;
7001 let mut ranges_to_query = None;
7002 let applicable_chunks = existing_inlay_hints
7003 .applicable_chunks(ranges.as_slice())
7004 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7005 .collect::<Vec<_>>();
7006 if applicable_chunks.is_empty() {
7007 return HashMap::default();
7008 }
7009
7010 for row_chunk in applicable_chunks {
7011 match (
7012 existing_inlay_hints
7013 .cached_hints(&row_chunk)
7014 .filter(|_| !lsp_refresh_requested)
7015 .cloned(),
7016 existing_inlay_hints
7017 .fetched_hints(&row_chunk)
7018 .as_ref()
7019 .filter(|_| !lsp_refresh_requested)
7020 .cloned(),
7021 ) {
7022 (None, None) => {
7023 let chunk_range = row_chunk.anchor_range();
7024 ranges_to_query
7025 .get_or_insert_with(Vec::new)
7026 .push((row_chunk, chunk_range));
7027 }
7028 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7029 (Some(cached_hints), None) => {
7030 for (server_id, cached_hints) in cached_hints {
7031 if for_server.is_none_or(|for_server| for_server == server_id) {
7032 cached_inlay_hints
7033 .get_or_insert_with(HashMap::default)
7034 .entry(row_chunk.row_range())
7035 .or_insert_with(HashMap::default)
7036 .entry(server_id)
7037 .or_insert_with(Vec::new)
7038 .extend(cached_hints);
7039 }
7040 }
7041 }
7042 (Some(cached_hints), Some(fetched_hints)) => {
7043 hint_fetch_tasks.push((row_chunk, fetched_hints));
7044 for (server_id, cached_hints) in cached_hints {
7045 if for_server.is_none_or(|for_server| for_server == server_id) {
7046 cached_inlay_hints
7047 .get_or_insert_with(HashMap::default)
7048 .entry(row_chunk.row_range())
7049 .or_insert_with(HashMap::default)
7050 .entry(server_id)
7051 .or_insert_with(Vec::new)
7052 .extend(cached_hints);
7053 }
7054 }
7055 }
7056 }
7057 }
7058
7059 if hint_fetch_tasks.is_empty()
7060 && ranges_to_query
7061 .as_ref()
7062 .is_none_or(|ranges| ranges.is_empty())
7063 && let Some(cached_inlay_hints) = cached_inlay_hints
7064 {
7065 cached_inlay_hints
7066 .into_iter()
7067 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7068 .collect()
7069 } else {
7070 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7071 let next_hint_id = next_hint_id.clone();
7072 let buffer = buffer.clone();
7073 let query_version = query_version.clone();
7074 let new_inlay_hints = cx
7075 .spawn(async move |lsp_store, cx| {
7076 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7077 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7078 })?;
7079 new_fetch_task
7080 .await
7081 .and_then(|new_hints_by_server| {
7082 lsp_store.update(cx, |lsp_store, cx| {
7083 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7084 let update_cache = lsp_data.buffer_version == query_version;
7085 if new_hints_by_server.is_empty() {
7086 if update_cache {
7087 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7088 }
7089 HashMap::default()
7090 } else {
7091 new_hints_by_server
7092 .into_iter()
7093 .map(|(server_id, new_hints)| {
7094 let new_hints = new_hints
7095 .into_iter()
7096 .map(|new_hint| {
7097 (
7098 InlayId::Hint(next_hint_id.fetch_add(
7099 1,
7100 atomic::Ordering::AcqRel,
7101 )),
7102 new_hint,
7103 )
7104 })
7105 .collect::<Vec<_>>();
7106 if update_cache {
7107 lsp_data.inlay_hints.insert_new_hints(
7108 chunk,
7109 server_id,
7110 new_hints.clone(),
7111 );
7112 }
7113 (server_id, new_hints)
7114 })
7115 .collect()
7116 }
7117 })
7118 })
7119 .map_err(Arc::new)
7120 })
7121 .shared();
7122
7123 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7124 *fetch_task = Some(new_inlay_hints.clone());
7125 hint_fetch_tasks.push((chunk, new_inlay_hints));
7126 }
7127
7128 cached_inlay_hints
7129 .unwrap_or_default()
7130 .into_iter()
7131 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7132 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7133 (
7134 chunk.row_range(),
7135 cx.spawn(async move |_, _| {
7136 hints_fetch.await.map_err(|e| {
7137 if e.error_code() != ErrorCode::Internal {
7138 anyhow!(e.error_code())
7139 } else {
7140 anyhow!("{e:#}")
7141 }
7142 })
7143 }),
7144 )
7145 }))
7146 .collect()
7147 }
7148 }
7149
7150 fn fetch_inlay_hints(
7151 &mut self,
7152 for_server: Option<LanguageServerId>,
7153 buffer: &Entity<Buffer>,
7154 range: Range<Anchor>,
7155 cx: &mut Context<Self>,
7156 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7157 let request = InlayHints {
7158 range: range.clone(),
7159 };
7160 if let Some((upstream_client, project_id)) = self.upstream_client() {
7161 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7162 return Task::ready(Ok(HashMap::default()));
7163 }
7164 let request_task = upstream_client.request_lsp(
7165 project_id,
7166 for_server.map(|id| id.to_proto()),
7167 LSP_REQUEST_TIMEOUT,
7168 cx.background_executor().clone(),
7169 request.to_proto(project_id, buffer.read(cx)),
7170 );
7171 let buffer = buffer.clone();
7172 cx.spawn(async move |weak_lsp_store, cx| {
7173 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7174 return Ok(HashMap::default());
7175 };
7176 let Some(responses) = request_task.await? else {
7177 return Ok(HashMap::default());
7178 };
7179
7180 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7181 let lsp_store = lsp_store.clone();
7182 let buffer = buffer.clone();
7183 let cx = cx.clone();
7184 let request = request.clone();
7185 async move {
7186 (
7187 LanguageServerId::from_proto(response.server_id),
7188 request
7189 .response_from_proto(response.response, lsp_store, buffer, cx)
7190 .await,
7191 )
7192 }
7193 }))
7194 .await;
7195
7196 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7197 let mut has_errors = false;
7198 let inlay_hints = inlay_hints
7199 .into_iter()
7200 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7201 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7202 Err(e) => {
7203 has_errors = true;
7204 log::error!("{e:#}");
7205 None
7206 }
7207 })
7208 .map(|(server_id, mut new_hints)| {
7209 new_hints.retain(|hint| {
7210 hint.position.is_valid(&buffer_snapshot)
7211 && range.start.is_valid(&buffer_snapshot)
7212 && range.end.is_valid(&buffer_snapshot)
7213 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7214 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7215 });
7216 (server_id, new_hints)
7217 })
7218 .collect::<HashMap<_, _>>();
7219 anyhow::ensure!(
7220 !has_errors || !inlay_hints.is_empty(),
7221 "Failed to fetch inlay hints"
7222 );
7223 Ok(inlay_hints)
7224 })
7225 } else {
7226 let inlay_hints_task = match for_server {
7227 Some(server_id) => {
7228 let server_task = self.request_lsp(
7229 buffer.clone(),
7230 LanguageServerToQuery::Other(server_id),
7231 request,
7232 cx,
7233 );
7234 cx.background_spawn(async move {
7235 let mut responses = Vec::new();
7236 match server_task.await {
7237 Ok(response) => responses.push((server_id, response)),
7238 // rust-analyzer likes to error with this when its still loading up
7239 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7240 Err(e) => log::error!(
7241 "Error handling response for inlay hints request: {e:#}"
7242 ),
7243 }
7244 responses
7245 })
7246 }
7247 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7248 };
7249 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7250 cx.background_spawn(async move {
7251 Ok(inlay_hints_task
7252 .await
7253 .into_iter()
7254 .map(|(server_id, mut new_hints)| {
7255 new_hints.retain(|hint| {
7256 hint.position.is_valid(&buffer_snapshot)
7257 && range.start.is_valid(&buffer_snapshot)
7258 && range.end.is_valid(&buffer_snapshot)
7259 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7260 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7261 });
7262 (server_id, new_hints)
7263 })
7264 .collect())
7265 })
7266 }
7267 }
7268
7269 fn diagnostic_registration_exists(
7270 &self,
7271 server_id: LanguageServerId,
7272 registration_id: &Option<SharedString>,
7273 ) -> bool {
7274 let Some(local) = self.as_local() else {
7275 return false;
7276 };
7277 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7278 else {
7279 return false;
7280 };
7281 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7282 registrations.diagnostics.contains_key(®istration_key)
7283 }
7284
7285 pub fn pull_diagnostics_for_buffer(
7286 &mut self,
7287 buffer: Entity<Buffer>,
7288 cx: &mut Context<Self>,
7289 ) -> Task<anyhow::Result<()>> {
7290 let diagnostics = self.pull_diagnostics(buffer, cx);
7291 cx.spawn(async move |lsp_store, cx| {
7292 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7293 return Ok(());
7294 };
7295 lsp_store.update(cx, |lsp_store, cx| {
7296 if lsp_store.as_local().is_none() {
7297 return;
7298 }
7299
7300 let mut unchanged_buffers = HashMap::default();
7301 let server_diagnostics_updates = diagnostics
7302 .into_iter()
7303 .filter_map(|diagnostics_set| match diagnostics_set {
7304 LspPullDiagnostics::Response {
7305 server_id,
7306 uri,
7307 diagnostics,
7308 registration_id,
7309 } => Some((server_id, uri, diagnostics, registration_id)),
7310 LspPullDiagnostics::Default => None,
7311 })
7312 .filter(|(server_id, _, _, registration_id)| {
7313 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7314 })
7315 .fold(
7316 HashMap::default(),
7317 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7318 let (result_id, diagnostics) = match diagnostics {
7319 PulledDiagnostics::Unchanged { result_id } => {
7320 unchanged_buffers
7321 .entry(new_registration_id.clone())
7322 .or_insert_with(HashSet::default)
7323 .insert(uri.clone());
7324 (Some(result_id), Vec::new())
7325 }
7326 PulledDiagnostics::Changed {
7327 result_id,
7328 diagnostics,
7329 } => (result_id, diagnostics),
7330 };
7331 let disk_based_sources = Cow::Owned(
7332 lsp_store
7333 .language_server_adapter_for_id(server_id)
7334 .as_ref()
7335 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7336 .unwrap_or(&[])
7337 .to_vec(),
7338 );
7339 acc.entry(server_id)
7340 .or_insert_with(HashMap::default)
7341 .entry(new_registration_id.clone())
7342 .or_insert_with(Vec::new)
7343 .push(DocumentDiagnosticsUpdate {
7344 server_id,
7345 diagnostics: lsp::PublishDiagnosticsParams {
7346 uri,
7347 diagnostics,
7348 version: None,
7349 },
7350 result_id,
7351 disk_based_sources,
7352 registration_id: new_registration_id,
7353 });
7354 acc
7355 },
7356 );
7357
7358 for diagnostic_updates in server_diagnostics_updates.into_values() {
7359 for (registration_id, diagnostic_updates) in diagnostic_updates {
7360 lsp_store
7361 .merge_lsp_diagnostics(
7362 DiagnosticSourceKind::Pulled,
7363 diagnostic_updates,
7364 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7365 DiagnosticSourceKind::Pulled => {
7366 old_diagnostic.registration_id != registration_id
7367 || unchanged_buffers
7368 .get(&old_diagnostic.registration_id)
7369 .is_some_and(|unchanged_buffers| {
7370 unchanged_buffers.contains(&document_uri)
7371 })
7372 }
7373 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7374 true
7375 }
7376 },
7377 cx,
7378 )
7379 .log_err();
7380 }
7381 }
7382 })
7383 })
7384 }
7385
7386 pub fn document_colors(
7387 &mut self,
7388 known_cache_version: Option<usize>,
7389 buffer: Entity<Buffer>,
7390 cx: &mut Context<Self>,
7391 ) -> Option<DocumentColorTask> {
7392 let version_queried_for = buffer.read(cx).version();
7393 let buffer_id = buffer.read(cx).remote_id();
7394
7395 let current_language_servers = self.as_local().map(|local| {
7396 local
7397 .buffers_opened_in_servers
7398 .get(&buffer_id)
7399 .cloned()
7400 .unwrap_or_default()
7401 });
7402
7403 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7404 if let Some(cached_colors) = &lsp_data.document_colors {
7405 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7406 let has_different_servers =
7407 current_language_servers.is_some_and(|current_language_servers| {
7408 current_language_servers
7409 != cached_colors.colors.keys().copied().collect()
7410 });
7411 if !has_different_servers {
7412 let cache_version = cached_colors.cache_version;
7413 if Some(cache_version) == known_cache_version {
7414 return None;
7415 } else {
7416 return Some(
7417 Task::ready(Ok(DocumentColors {
7418 colors: cached_colors
7419 .colors
7420 .values()
7421 .flatten()
7422 .cloned()
7423 .collect(),
7424 cache_version: Some(cache_version),
7425 }))
7426 .shared(),
7427 );
7428 }
7429 }
7430 }
7431 }
7432 }
7433
7434 let color_lsp_data = self
7435 .latest_lsp_data(&buffer, cx)
7436 .document_colors
7437 .get_or_insert_default();
7438 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7439 && !version_queried_for.changed_since(updating_for)
7440 {
7441 return Some(running_update.clone());
7442 }
7443 let buffer_version_queried_for = version_queried_for.clone();
7444 let new_task = cx
7445 .spawn(async move |lsp_store, cx| {
7446 cx.background_executor()
7447 .timer(Duration::from_millis(30))
7448 .await;
7449 let fetched_colors = lsp_store
7450 .update(cx, |lsp_store, cx| {
7451 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7452 })?
7453 .await
7454 .context("fetching document colors")
7455 .map_err(Arc::new);
7456 let fetched_colors = match fetched_colors {
7457 Ok(fetched_colors) => {
7458 if buffer.update(cx, |buffer, _| {
7459 buffer.version() != buffer_version_queried_for
7460 }) {
7461 return Ok(DocumentColors::default());
7462 }
7463 fetched_colors
7464 }
7465 Err(e) => {
7466 lsp_store
7467 .update(cx, |lsp_store, _| {
7468 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7469 if let Some(document_colors) = &mut lsp_data.document_colors {
7470 document_colors.colors_update = None;
7471 }
7472 }
7473 })
7474 .ok();
7475 return Err(e);
7476 }
7477 };
7478
7479 lsp_store
7480 .update(cx, |lsp_store, cx| {
7481 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7482 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7483
7484 if let Some(fetched_colors) = fetched_colors {
7485 if lsp_data.buffer_version == buffer_version_queried_for {
7486 lsp_colors.colors.extend(fetched_colors);
7487 lsp_colors.cache_version += 1;
7488 } else if !lsp_data
7489 .buffer_version
7490 .changed_since(&buffer_version_queried_for)
7491 {
7492 lsp_data.buffer_version = buffer_version_queried_for;
7493 lsp_colors.colors = fetched_colors;
7494 lsp_colors.cache_version += 1;
7495 }
7496 }
7497 lsp_colors.colors_update = None;
7498 let colors = lsp_colors
7499 .colors
7500 .values()
7501 .flatten()
7502 .cloned()
7503 .collect::<HashSet<_>>();
7504 DocumentColors {
7505 colors,
7506 cache_version: Some(lsp_colors.cache_version),
7507 }
7508 })
7509 .map_err(Arc::new)
7510 })
7511 .shared();
7512 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7513 Some(new_task)
7514 }
7515
7516 fn fetch_document_colors_for_buffer(
7517 &mut self,
7518 buffer: &Entity<Buffer>,
7519 cx: &mut Context<Self>,
7520 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7521 if let Some((client, project_id)) = self.upstream_client() {
7522 let request = GetDocumentColor {};
7523 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7524 return Task::ready(Ok(None));
7525 }
7526
7527 let request_task = client.request_lsp(
7528 project_id,
7529 None,
7530 LSP_REQUEST_TIMEOUT,
7531 cx.background_executor().clone(),
7532 request.to_proto(project_id, buffer.read(cx)),
7533 );
7534 let buffer = buffer.clone();
7535 cx.spawn(async move |lsp_store, cx| {
7536 let Some(lsp_store) = lsp_store.upgrade() else {
7537 return Ok(None);
7538 };
7539 let colors = join_all(
7540 request_task
7541 .await
7542 .log_err()
7543 .flatten()
7544 .map(|response| response.payload)
7545 .unwrap_or_default()
7546 .into_iter()
7547 .map(|color_response| {
7548 let response = request.response_from_proto(
7549 color_response.response,
7550 lsp_store.clone(),
7551 buffer.clone(),
7552 cx.clone(),
7553 );
7554 async move {
7555 (
7556 LanguageServerId::from_proto(color_response.server_id),
7557 response.await.log_err().unwrap_or_default(),
7558 )
7559 }
7560 }),
7561 )
7562 .await
7563 .into_iter()
7564 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7565 acc.entry(server_id)
7566 .or_insert_with(HashSet::default)
7567 .extend(colors);
7568 acc
7569 });
7570 Ok(Some(colors))
7571 })
7572 } else {
7573 let document_colors_task =
7574 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7575 cx.background_spawn(async move {
7576 Ok(Some(
7577 document_colors_task
7578 .await
7579 .into_iter()
7580 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7581 acc.entry(server_id)
7582 .or_insert_with(HashSet::default)
7583 .extend(colors);
7584 acc
7585 })
7586 .into_iter()
7587 .collect(),
7588 ))
7589 })
7590 }
7591 }
7592
7593 pub fn signature_help<T: ToPointUtf16>(
7594 &mut self,
7595 buffer: &Entity<Buffer>,
7596 position: T,
7597 cx: &mut Context<Self>,
7598 ) -> Task<Option<Vec<SignatureHelp>>> {
7599 let position = position.to_point_utf16(buffer.read(cx));
7600
7601 if let Some((client, upstream_project_id)) = self.upstream_client() {
7602 let request = GetSignatureHelp { position };
7603 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7604 return Task::ready(None);
7605 }
7606 let request_task = client.request_lsp(
7607 upstream_project_id,
7608 None,
7609 LSP_REQUEST_TIMEOUT,
7610 cx.background_executor().clone(),
7611 request.to_proto(upstream_project_id, buffer.read(cx)),
7612 );
7613 let buffer = buffer.clone();
7614 cx.spawn(async move |weak_lsp_store, cx| {
7615 let lsp_store = weak_lsp_store.upgrade()?;
7616 let signatures = join_all(
7617 request_task
7618 .await
7619 .log_err()
7620 .flatten()
7621 .map(|response| response.payload)
7622 .unwrap_or_default()
7623 .into_iter()
7624 .map(|response| {
7625 let response = GetSignatureHelp { position }.response_from_proto(
7626 response.response,
7627 lsp_store.clone(),
7628 buffer.clone(),
7629 cx.clone(),
7630 );
7631 async move { response.await.log_err().flatten() }
7632 }),
7633 )
7634 .await
7635 .into_iter()
7636 .flatten()
7637 .collect();
7638 Some(signatures)
7639 })
7640 } else {
7641 let all_actions_task = self.request_multiple_lsp_locally(
7642 buffer,
7643 Some(position),
7644 GetSignatureHelp { position },
7645 cx,
7646 );
7647 cx.background_spawn(async move {
7648 Some(
7649 all_actions_task
7650 .await
7651 .into_iter()
7652 .flat_map(|(_, actions)| actions)
7653 .collect::<Vec<_>>(),
7654 )
7655 })
7656 }
7657 }
7658
7659 pub fn hover(
7660 &mut self,
7661 buffer: &Entity<Buffer>,
7662 position: PointUtf16,
7663 cx: &mut Context<Self>,
7664 ) -> Task<Option<Vec<Hover>>> {
7665 if let Some((client, upstream_project_id)) = self.upstream_client() {
7666 let request = GetHover { position };
7667 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7668 return Task::ready(None);
7669 }
7670 let request_task = client.request_lsp(
7671 upstream_project_id,
7672 None,
7673 LSP_REQUEST_TIMEOUT,
7674 cx.background_executor().clone(),
7675 request.to_proto(upstream_project_id, buffer.read(cx)),
7676 );
7677 let buffer = buffer.clone();
7678 cx.spawn(async move |weak_lsp_store, cx| {
7679 let lsp_store = weak_lsp_store.upgrade()?;
7680 let hovers = join_all(
7681 request_task
7682 .await
7683 .log_err()
7684 .flatten()
7685 .map(|response| response.payload)
7686 .unwrap_or_default()
7687 .into_iter()
7688 .map(|response| {
7689 let response = GetHover { position }.response_from_proto(
7690 response.response,
7691 lsp_store.clone(),
7692 buffer.clone(),
7693 cx.clone(),
7694 );
7695 async move {
7696 response
7697 .await
7698 .log_err()
7699 .flatten()
7700 .and_then(remove_empty_hover_blocks)
7701 }
7702 }),
7703 )
7704 .await
7705 .into_iter()
7706 .flatten()
7707 .collect();
7708 Some(hovers)
7709 })
7710 } else {
7711 let all_actions_task = self.request_multiple_lsp_locally(
7712 buffer,
7713 Some(position),
7714 GetHover { position },
7715 cx,
7716 );
7717 cx.background_spawn(async move {
7718 Some(
7719 all_actions_task
7720 .await
7721 .into_iter()
7722 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7723 .collect::<Vec<Hover>>(),
7724 )
7725 })
7726 }
7727 }
7728
7729 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7730 let language_registry = self.languages.clone();
7731
7732 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7733 let request = upstream_client.request(proto::GetProjectSymbols {
7734 project_id: *project_id,
7735 query: query.to_string(),
7736 });
7737 cx.foreground_executor().spawn(async move {
7738 let response = request.await?;
7739 let mut symbols = Vec::new();
7740 let core_symbols = response
7741 .symbols
7742 .into_iter()
7743 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7744 .collect::<Vec<_>>();
7745 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7746 .await;
7747 Ok(symbols)
7748 })
7749 } else if let Some(local) = self.as_local() {
7750 struct WorkspaceSymbolsResult {
7751 server_id: LanguageServerId,
7752 lsp_adapter: Arc<CachedLspAdapter>,
7753 worktree: WeakEntity<Worktree>,
7754 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7755 }
7756
7757 let mut requests = Vec::new();
7758 let mut requested_servers = BTreeSet::new();
7759 for (seed, state) in local.language_server_ids.iter() {
7760 let Some(worktree_handle) = self
7761 .worktree_store
7762 .read(cx)
7763 .worktree_for_id(seed.worktree_id, cx)
7764 else {
7765 continue;
7766 };
7767 let worktree = worktree_handle.read(cx);
7768 if !worktree.is_visible() {
7769 continue;
7770 }
7771
7772 if !requested_servers.insert(state.id) {
7773 continue;
7774 }
7775
7776 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7777 Some(LanguageServerState::Running {
7778 adapter, server, ..
7779 }) => (adapter.clone(), server),
7780
7781 _ => continue,
7782 };
7783 let supports_workspace_symbol_request =
7784 match server.capabilities().workspace_symbol_provider {
7785 Some(OneOf::Left(supported)) => supported,
7786 Some(OneOf::Right(_)) => true,
7787 None => false,
7788 };
7789 if !supports_workspace_symbol_request {
7790 continue;
7791 }
7792 let worktree_handle = worktree_handle.clone();
7793 let server_id = server.server_id();
7794 requests.push(
7795 server
7796 .request::<lsp::request::WorkspaceSymbolRequest>(
7797 lsp::WorkspaceSymbolParams {
7798 query: query.to_string(),
7799 ..Default::default()
7800 },
7801 )
7802 .map(move |response| {
7803 let lsp_symbols = response.into_response()
7804 .context("workspace symbols request")
7805 .log_err()
7806 .flatten()
7807 .map(|symbol_response| match symbol_response {
7808 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7809 flat_responses.into_iter().map(|lsp_symbol| {
7810 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7811 }).collect::<Vec<_>>()
7812 }
7813 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7814 nested_responses.into_iter().filter_map(|lsp_symbol| {
7815 let location = match lsp_symbol.location {
7816 OneOf::Left(location) => location,
7817 OneOf::Right(_) => {
7818 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7819 return None
7820 }
7821 };
7822 Some((lsp_symbol.name, lsp_symbol.kind, location))
7823 }).collect::<Vec<_>>()
7824 }
7825 }).unwrap_or_default();
7826
7827 WorkspaceSymbolsResult {
7828 server_id,
7829 lsp_adapter,
7830 worktree: worktree_handle.downgrade(),
7831 lsp_symbols,
7832 }
7833 }),
7834 );
7835 }
7836
7837 cx.spawn(async move |this, cx| {
7838 let responses = futures::future::join_all(requests).await;
7839 let this = match this.upgrade() {
7840 Some(this) => this,
7841 None => return Ok(Vec::new()),
7842 };
7843
7844 let mut symbols = Vec::new();
7845 for result in responses {
7846 let core_symbols = this.update(cx, |this, cx| {
7847 result
7848 .lsp_symbols
7849 .into_iter()
7850 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7851 let abs_path = symbol_location.uri.to_file_path().ok()?;
7852 let source_worktree = result.worktree.upgrade()?;
7853 let source_worktree_id = source_worktree.read(cx).id();
7854
7855 let path = if let Some((tree, rel_path)) =
7856 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7857 {
7858 let worktree_id = tree.read(cx).id();
7859 SymbolLocation::InProject(ProjectPath {
7860 worktree_id,
7861 path: rel_path,
7862 })
7863 } else {
7864 SymbolLocation::OutsideProject {
7865 signature: this.symbol_signature(&abs_path),
7866 abs_path: abs_path.into(),
7867 }
7868 };
7869
7870 Some(CoreSymbol {
7871 source_language_server_id: result.server_id,
7872 language_server_name: result.lsp_adapter.name.clone(),
7873 source_worktree_id,
7874 path,
7875 kind: symbol_kind,
7876 name: symbol_name,
7877 range: range_from_lsp(symbol_location.range),
7878 })
7879 })
7880 .collect::<Vec<_>>()
7881 });
7882
7883 populate_labels_for_symbols(
7884 core_symbols,
7885 &language_registry,
7886 Some(result.lsp_adapter),
7887 &mut symbols,
7888 )
7889 .await;
7890 }
7891
7892 Ok(symbols)
7893 })
7894 } else {
7895 Task::ready(Err(anyhow!("No upstream client or local language server")))
7896 }
7897 }
7898
7899 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7900 let mut summary = DiagnosticSummary::default();
7901 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7902 summary.error_count += path_summary.error_count;
7903 summary.warning_count += path_summary.warning_count;
7904 }
7905 summary
7906 }
7907
7908 /// Returns the diagnostic summary for a specific project path.
7909 pub fn diagnostic_summary_for_path(
7910 &self,
7911 project_path: &ProjectPath,
7912 _: &App,
7913 ) -> DiagnosticSummary {
7914 if let Some(summaries) = self
7915 .diagnostic_summaries
7916 .get(&project_path.worktree_id)
7917 .and_then(|map| map.get(&project_path.path))
7918 {
7919 let (error_count, warning_count) = summaries.iter().fold(
7920 (0, 0),
7921 |(error_count, warning_count), (_language_server_id, summary)| {
7922 (
7923 error_count + summary.error_count,
7924 warning_count + summary.warning_count,
7925 )
7926 },
7927 );
7928
7929 DiagnosticSummary {
7930 error_count,
7931 warning_count,
7932 }
7933 } else {
7934 DiagnosticSummary::default()
7935 }
7936 }
7937
7938 pub fn diagnostic_summaries<'a>(
7939 &'a self,
7940 include_ignored: bool,
7941 cx: &'a App,
7942 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7943 self.worktree_store
7944 .read(cx)
7945 .visible_worktrees(cx)
7946 .filter_map(|worktree| {
7947 let worktree = worktree.read(cx);
7948 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7949 })
7950 .flat_map(move |(worktree, summaries)| {
7951 let worktree_id = worktree.id();
7952 summaries
7953 .iter()
7954 .filter(move |(path, _)| {
7955 include_ignored
7956 || worktree
7957 .entry_for_path(path.as_ref())
7958 .is_some_and(|entry| !entry.is_ignored)
7959 })
7960 .flat_map(move |(path, summaries)| {
7961 summaries.iter().map(move |(server_id, summary)| {
7962 (
7963 ProjectPath {
7964 worktree_id,
7965 path: path.clone(),
7966 },
7967 *server_id,
7968 *summary,
7969 )
7970 })
7971 })
7972 })
7973 }
7974
7975 pub fn on_buffer_edited(
7976 &mut self,
7977 buffer: Entity<Buffer>,
7978 cx: &mut Context<Self>,
7979 ) -> Option<()> {
7980 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7981 Some(
7982 self.as_local()?
7983 .language_servers_for_buffer(buffer, cx)
7984 .map(|i| i.1.clone())
7985 .collect(),
7986 )
7987 })?;
7988
7989 let buffer = buffer.read(cx);
7990 let file = File::from_dyn(buffer.file())?;
7991 let abs_path = file.as_local()?.abs_path(cx);
7992 let uri = lsp::Uri::from_file_path(&abs_path)
7993 .ok()
7994 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7995 .log_err()?;
7996 let next_snapshot = buffer.text_snapshot();
7997 for language_server in language_servers {
7998 let language_server = language_server.clone();
7999
8000 let buffer_snapshots = self
8001 .as_local_mut()?
8002 .buffer_snapshots
8003 .get_mut(&buffer.remote_id())
8004 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8005 let previous_snapshot = buffer_snapshots.last()?;
8006
8007 let build_incremental_change = || {
8008 buffer
8009 .edits_since::<Dimensions<PointUtf16, usize>>(
8010 previous_snapshot.snapshot.version(),
8011 )
8012 .map(|edit| {
8013 let edit_start = edit.new.start.0;
8014 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8015 let new_text = next_snapshot
8016 .text_for_range(edit.new.start.1..edit.new.end.1)
8017 .collect();
8018 lsp::TextDocumentContentChangeEvent {
8019 range: Some(lsp::Range::new(
8020 point_to_lsp(edit_start),
8021 point_to_lsp(edit_end),
8022 )),
8023 range_length: None,
8024 text: new_text,
8025 }
8026 })
8027 .collect()
8028 };
8029
8030 let document_sync_kind = language_server
8031 .capabilities()
8032 .text_document_sync
8033 .as_ref()
8034 .and_then(|sync| match sync {
8035 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8036 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8037 });
8038
8039 let content_changes: Vec<_> = match document_sync_kind {
8040 Some(lsp::TextDocumentSyncKind::FULL) => {
8041 vec![lsp::TextDocumentContentChangeEvent {
8042 range: None,
8043 range_length: None,
8044 text: next_snapshot.text(),
8045 }]
8046 }
8047 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8048 _ => {
8049 #[cfg(any(test, feature = "test-support"))]
8050 {
8051 build_incremental_change()
8052 }
8053
8054 #[cfg(not(any(test, feature = "test-support")))]
8055 {
8056 continue;
8057 }
8058 }
8059 };
8060
8061 let next_version = previous_snapshot.version + 1;
8062 buffer_snapshots.push(LspBufferSnapshot {
8063 version: next_version,
8064 snapshot: next_snapshot.clone(),
8065 });
8066
8067 language_server
8068 .notify::<lsp::notification::DidChangeTextDocument>(
8069 lsp::DidChangeTextDocumentParams {
8070 text_document: lsp::VersionedTextDocumentIdentifier::new(
8071 uri.clone(),
8072 next_version,
8073 ),
8074 content_changes,
8075 },
8076 )
8077 .ok();
8078 self.pull_workspace_diagnostics(language_server.server_id());
8079 }
8080
8081 None
8082 }
8083
8084 pub fn on_buffer_saved(
8085 &mut self,
8086 buffer: Entity<Buffer>,
8087 cx: &mut Context<Self>,
8088 ) -> Option<()> {
8089 let file = File::from_dyn(buffer.read(cx).file())?;
8090 let worktree_id = file.worktree_id(cx);
8091 let abs_path = file.as_local()?.abs_path(cx);
8092 let text_document = lsp::TextDocumentIdentifier {
8093 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8094 };
8095 let local = self.as_local()?;
8096
8097 for server in local.language_servers_for_worktree(worktree_id) {
8098 if let Some(include_text) = include_text(server.as_ref()) {
8099 let text = if include_text {
8100 Some(buffer.read(cx).text())
8101 } else {
8102 None
8103 };
8104 server
8105 .notify::<lsp::notification::DidSaveTextDocument>(
8106 lsp::DidSaveTextDocumentParams {
8107 text_document: text_document.clone(),
8108 text,
8109 },
8110 )
8111 .ok();
8112 }
8113 }
8114
8115 let language_servers = buffer.update(cx, |buffer, cx| {
8116 local.language_server_ids_for_buffer(buffer, cx)
8117 });
8118 for language_server_id in language_servers {
8119 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8120 }
8121
8122 None
8123 }
8124
8125 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8126 maybe!(async move {
8127 let mut refreshed_servers = HashSet::default();
8128 let servers = lsp_store
8129 .update(cx, |lsp_store, cx| {
8130 let local = lsp_store.as_local()?;
8131
8132 let servers = local
8133 .language_server_ids
8134 .iter()
8135 .filter_map(|(seed, state)| {
8136 let worktree = lsp_store
8137 .worktree_store
8138 .read(cx)
8139 .worktree_for_id(seed.worktree_id, cx);
8140 let delegate: Arc<dyn LspAdapterDelegate> =
8141 worktree.map(|worktree| {
8142 LocalLspAdapterDelegate::new(
8143 local.languages.clone(),
8144 &local.environment,
8145 cx.weak_entity(),
8146 &worktree,
8147 local.http_client.clone(),
8148 local.fs.clone(),
8149 cx,
8150 )
8151 })?;
8152 let server_id = state.id;
8153
8154 let states = local.language_servers.get(&server_id)?;
8155
8156 match states {
8157 LanguageServerState::Starting { .. } => None,
8158 LanguageServerState::Running {
8159 adapter, server, ..
8160 } => {
8161 let adapter = adapter.clone();
8162 let server = server.clone();
8163 refreshed_servers.insert(server.name());
8164 let toolchain = seed.toolchain.clone();
8165 Some(cx.spawn(async move |_, cx| {
8166 let settings =
8167 LocalLspStore::workspace_configuration_for_adapter(
8168 adapter.adapter.clone(),
8169 &delegate,
8170 toolchain,
8171 None,
8172 cx,
8173 )
8174 .await
8175 .ok()?;
8176 server
8177 .notify::<lsp::notification::DidChangeConfiguration>(
8178 lsp::DidChangeConfigurationParams { settings },
8179 )
8180 .ok()?;
8181 Some(())
8182 }))
8183 }
8184 }
8185 })
8186 .collect::<Vec<_>>();
8187
8188 Some(servers)
8189 })
8190 .ok()
8191 .flatten()?;
8192
8193 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8194 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8195 // to stop and unregister its language server wrapper.
8196 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8197 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8198 let _: Vec<Option<()>> = join_all(servers).await;
8199
8200 Some(())
8201 })
8202 .await;
8203 }
8204
8205 fn maintain_workspace_config(
8206 external_refresh_requests: watch::Receiver<()>,
8207 cx: &mut Context<Self>,
8208 ) -> Task<Result<()>> {
8209 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8210 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8211
8212 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8213 *settings_changed_tx.borrow_mut() = ();
8214 });
8215
8216 let mut joint_future =
8217 futures::stream::select(settings_changed_rx, external_refresh_requests);
8218 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8219 // - 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).
8220 // - 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.
8221 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8222 // - 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,
8223 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8224 cx.spawn(async move |this, cx| {
8225 while let Some(()) = joint_future.next().await {
8226 this.update(cx, |this, cx| {
8227 this.refresh_server_tree(cx);
8228 })
8229 .ok();
8230
8231 Self::refresh_workspace_configurations(&this, cx).await;
8232 }
8233
8234 drop(settings_observation);
8235 anyhow::Ok(())
8236 })
8237 }
8238
8239 pub fn running_language_servers_for_local_buffer<'a>(
8240 &'a self,
8241 buffer: &Buffer,
8242 cx: &mut App,
8243 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8244 let local = self.as_local();
8245 let language_server_ids = local
8246 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8247 .unwrap_or_default();
8248
8249 language_server_ids
8250 .into_iter()
8251 .filter_map(
8252 move |server_id| match local?.language_servers.get(&server_id)? {
8253 LanguageServerState::Running {
8254 adapter, server, ..
8255 } => Some((adapter, server)),
8256 _ => None,
8257 },
8258 )
8259 }
8260
8261 pub fn language_servers_for_local_buffer(
8262 &self,
8263 buffer: &Buffer,
8264 cx: &mut App,
8265 ) -> Vec<LanguageServerId> {
8266 let local = self.as_local();
8267 local
8268 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8269 .unwrap_or_default()
8270 }
8271
8272 pub fn language_server_for_local_buffer<'a>(
8273 &'a self,
8274 buffer: &'a Buffer,
8275 server_id: LanguageServerId,
8276 cx: &'a mut App,
8277 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8278 self.as_local()?
8279 .language_servers_for_buffer(buffer, cx)
8280 .find(|(_, s)| s.server_id() == server_id)
8281 }
8282
8283 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8284 self.diagnostic_summaries.remove(&id_to_remove);
8285 if let Some(local) = self.as_local_mut() {
8286 let to_remove = local.remove_worktree(id_to_remove, cx);
8287 for server in to_remove {
8288 self.language_server_statuses.remove(&server);
8289 }
8290 }
8291 }
8292
8293 pub fn shared(
8294 &mut self,
8295 project_id: u64,
8296 downstream_client: AnyProtoClient,
8297 _: &mut Context<Self>,
8298 ) {
8299 self.downstream_client = Some((downstream_client.clone(), project_id));
8300
8301 for (server_id, status) in &self.language_server_statuses {
8302 if let Some(server) = self.language_server_for_id(*server_id) {
8303 downstream_client
8304 .send(proto::StartLanguageServer {
8305 project_id,
8306 server: Some(proto::LanguageServer {
8307 id: server_id.to_proto(),
8308 name: status.name.to_string(),
8309 worktree_id: status.worktree.map(|id| id.to_proto()),
8310 }),
8311 capabilities: serde_json::to_string(&server.capabilities())
8312 .expect("serializing server LSP capabilities"),
8313 })
8314 .log_err();
8315 }
8316 }
8317 }
8318
8319 pub fn disconnected_from_host(&mut self) {
8320 self.downstream_client.take();
8321 }
8322
8323 pub fn disconnected_from_ssh_remote(&mut self) {
8324 if let LspStoreMode::Remote(RemoteLspStore {
8325 upstream_client, ..
8326 }) = &mut self.mode
8327 {
8328 upstream_client.take();
8329 }
8330 }
8331
8332 pub(crate) fn set_language_server_statuses_from_proto(
8333 &mut self,
8334 project: WeakEntity<Project>,
8335 language_servers: Vec<proto::LanguageServer>,
8336 server_capabilities: Vec<String>,
8337 cx: &mut Context<Self>,
8338 ) {
8339 let lsp_logs = cx
8340 .try_global::<GlobalLogStore>()
8341 .map(|lsp_store| lsp_store.0.clone());
8342
8343 self.language_server_statuses = language_servers
8344 .into_iter()
8345 .zip(server_capabilities)
8346 .map(|(server, server_capabilities)| {
8347 let server_id = LanguageServerId(server.id as usize);
8348 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8349 self.lsp_server_capabilities
8350 .insert(server_id, server_capabilities);
8351 }
8352
8353 let name = LanguageServerName::from_proto(server.name);
8354 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8355
8356 if let Some(lsp_logs) = &lsp_logs {
8357 lsp_logs.update(cx, |lsp_logs, cx| {
8358 lsp_logs.add_language_server(
8359 // Only remote clients get their language servers set from proto
8360 LanguageServerKind::Remote {
8361 project: project.clone(),
8362 },
8363 server_id,
8364 Some(name.clone()),
8365 worktree,
8366 None,
8367 cx,
8368 );
8369 });
8370 }
8371
8372 (
8373 server_id,
8374 LanguageServerStatus {
8375 name,
8376 server_version: None,
8377 pending_work: Default::default(),
8378 has_pending_diagnostic_updates: false,
8379 progress_tokens: Default::default(),
8380 worktree,
8381 binary: None,
8382 configuration: None,
8383 workspace_folders: BTreeSet::new(),
8384 },
8385 )
8386 })
8387 .collect();
8388 }
8389
8390 #[cfg(test)]
8391 pub fn update_diagnostic_entries(
8392 &mut self,
8393 server_id: LanguageServerId,
8394 abs_path: PathBuf,
8395 result_id: Option<SharedString>,
8396 version: Option<i32>,
8397 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8398 cx: &mut Context<Self>,
8399 ) -> anyhow::Result<()> {
8400 self.merge_diagnostic_entries(
8401 vec![DocumentDiagnosticsUpdate {
8402 diagnostics: DocumentDiagnostics {
8403 diagnostics,
8404 document_abs_path: abs_path,
8405 version,
8406 },
8407 result_id,
8408 server_id,
8409 disk_based_sources: Cow::Borrowed(&[]),
8410 registration_id: None,
8411 }],
8412 |_, _, _| false,
8413 cx,
8414 )?;
8415 Ok(())
8416 }
8417
8418 pub fn merge_diagnostic_entries<'a>(
8419 &mut self,
8420 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8421 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8422 cx: &mut Context<Self>,
8423 ) -> anyhow::Result<()> {
8424 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8425 let mut updated_diagnostics_paths = HashMap::default();
8426 for mut update in diagnostic_updates {
8427 let abs_path = &update.diagnostics.document_abs_path;
8428 let server_id = update.server_id;
8429 let Some((worktree, relative_path)) =
8430 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8431 else {
8432 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8433 return Ok(());
8434 };
8435
8436 let worktree_id = worktree.read(cx).id();
8437 let project_path = ProjectPath {
8438 worktree_id,
8439 path: relative_path,
8440 };
8441
8442 let document_uri = lsp::Uri::from_file_path(abs_path)
8443 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8444 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8445 let snapshot = buffer_handle.read(cx).snapshot();
8446 let buffer = buffer_handle.read(cx);
8447 let reused_diagnostics = buffer
8448 .buffer_diagnostics(Some(server_id))
8449 .iter()
8450 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8451 .map(|v| {
8452 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8453 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8454 DiagnosticEntry {
8455 range: start..end,
8456 diagnostic: v.diagnostic.clone(),
8457 }
8458 })
8459 .collect::<Vec<_>>();
8460
8461 self.as_local_mut()
8462 .context("cannot merge diagnostics on a remote LspStore")?
8463 .update_buffer_diagnostics(
8464 &buffer_handle,
8465 server_id,
8466 Some(update.registration_id),
8467 update.result_id,
8468 update.diagnostics.version,
8469 update.diagnostics.diagnostics.clone(),
8470 reused_diagnostics.clone(),
8471 cx,
8472 )?;
8473
8474 update.diagnostics.diagnostics.extend(reused_diagnostics);
8475 } else if let Some(local) = self.as_local() {
8476 let reused_diagnostics = local
8477 .diagnostics
8478 .get(&worktree_id)
8479 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8480 .and_then(|diagnostics_by_server_id| {
8481 diagnostics_by_server_id
8482 .binary_search_by_key(&server_id, |e| e.0)
8483 .ok()
8484 .map(|ix| &diagnostics_by_server_id[ix].1)
8485 })
8486 .into_iter()
8487 .flatten()
8488 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8489
8490 update
8491 .diagnostics
8492 .diagnostics
8493 .extend(reused_diagnostics.cloned());
8494 }
8495
8496 let updated = worktree.update(cx, |worktree, cx| {
8497 self.update_worktree_diagnostics(
8498 worktree.id(),
8499 server_id,
8500 project_path.path.clone(),
8501 update.diagnostics.diagnostics,
8502 cx,
8503 )
8504 })?;
8505 match updated {
8506 ControlFlow::Continue(new_summary) => {
8507 if let Some((project_id, new_summary)) = new_summary {
8508 match &mut diagnostics_summary {
8509 Some(diagnostics_summary) => {
8510 diagnostics_summary
8511 .more_summaries
8512 .push(proto::DiagnosticSummary {
8513 path: project_path.path.as_ref().to_proto(),
8514 language_server_id: server_id.0 as u64,
8515 error_count: new_summary.error_count,
8516 warning_count: new_summary.warning_count,
8517 })
8518 }
8519 None => {
8520 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8521 project_id,
8522 worktree_id: worktree_id.to_proto(),
8523 summary: Some(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 more_summaries: Vec::new(),
8530 })
8531 }
8532 }
8533 }
8534 updated_diagnostics_paths
8535 .entry(server_id)
8536 .or_insert_with(Vec::new)
8537 .push(project_path);
8538 }
8539 ControlFlow::Break(()) => {}
8540 }
8541 }
8542
8543 if let Some((diagnostics_summary, (downstream_client, _))) =
8544 diagnostics_summary.zip(self.downstream_client.as_ref())
8545 {
8546 downstream_client.send(diagnostics_summary).log_err();
8547 }
8548 for (server_id, paths) in updated_diagnostics_paths {
8549 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8550 }
8551 Ok(())
8552 }
8553
8554 fn update_worktree_diagnostics(
8555 &mut self,
8556 worktree_id: WorktreeId,
8557 server_id: LanguageServerId,
8558 path_in_worktree: Arc<RelPath>,
8559 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8560 _: &mut Context<Worktree>,
8561 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8562 let local = match &mut self.mode {
8563 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8564 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8565 };
8566
8567 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8568 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8569 let summaries_by_server_id = summaries_for_tree
8570 .entry(path_in_worktree.clone())
8571 .or_default();
8572
8573 let old_summary = summaries_by_server_id
8574 .remove(&server_id)
8575 .unwrap_or_default();
8576
8577 let new_summary = DiagnosticSummary::new(&diagnostics);
8578 if diagnostics.is_empty() {
8579 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8580 {
8581 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8582 diagnostics_by_server_id.remove(ix);
8583 }
8584 if diagnostics_by_server_id.is_empty() {
8585 diagnostics_for_tree.remove(&path_in_worktree);
8586 }
8587 }
8588 } else {
8589 summaries_by_server_id.insert(server_id, new_summary);
8590 let diagnostics_by_server_id = diagnostics_for_tree
8591 .entry(path_in_worktree.clone())
8592 .or_default();
8593 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8594 Ok(ix) => {
8595 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8596 }
8597 Err(ix) => {
8598 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8599 }
8600 }
8601 }
8602
8603 if !old_summary.is_empty() || !new_summary.is_empty() {
8604 if let Some((_, project_id)) = &self.downstream_client {
8605 Ok(ControlFlow::Continue(Some((
8606 *project_id,
8607 proto::DiagnosticSummary {
8608 path: path_in_worktree.to_proto(),
8609 language_server_id: server_id.0 as u64,
8610 error_count: new_summary.error_count as u32,
8611 warning_count: new_summary.warning_count as u32,
8612 },
8613 ))))
8614 } else {
8615 Ok(ControlFlow::Continue(None))
8616 }
8617 } else {
8618 Ok(ControlFlow::Break(()))
8619 }
8620 }
8621
8622 pub fn open_buffer_for_symbol(
8623 &mut self,
8624 symbol: &Symbol,
8625 cx: &mut Context<Self>,
8626 ) -> Task<Result<Entity<Buffer>>> {
8627 if let Some((client, project_id)) = self.upstream_client() {
8628 let request = client.request(proto::OpenBufferForSymbol {
8629 project_id,
8630 symbol: Some(Self::serialize_symbol(symbol)),
8631 });
8632 cx.spawn(async move |this, cx| {
8633 let response = request.await?;
8634 let buffer_id = BufferId::new(response.buffer_id)?;
8635 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8636 .await
8637 })
8638 } else if let Some(local) = self.as_local() {
8639 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8640 seed.worktree_id == symbol.source_worktree_id
8641 && state.id == symbol.source_language_server_id
8642 && symbol.language_server_name == seed.name
8643 });
8644 if !is_valid {
8645 return Task::ready(Err(anyhow!(
8646 "language server for worktree and language not found"
8647 )));
8648 };
8649
8650 let symbol_abs_path = match &symbol.path {
8651 SymbolLocation::InProject(project_path) => self
8652 .worktree_store
8653 .read(cx)
8654 .absolutize(&project_path, cx)
8655 .context("no such worktree"),
8656 SymbolLocation::OutsideProject {
8657 abs_path,
8658 signature: _,
8659 } => Ok(abs_path.to_path_buf()),
8660 };
8661 let symbol_abs_path = match symbol_abs_path {
8662 Ok(abs_path) => abs_path,
8663 Err(err) => return Task::ready(Err(err)),
8664 };
8665 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8666 uri
8667 } else {
8668 return Task::ready(Err(anyhow!("invalid symbol path")));
8669 };
8670
8671 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8672 } else {
8673 Task::ready(Err(anyhow!("no upstream client or local store")))
8674 }
8675 }
8676
8677 pub(crate) fn open_local_buffer_via_lsp(
8678 &mut self,
8679 abs_path: lsp::Uri,
8680 language_server_id: LanguageServerId,
8681 cx: &mut Context<Self>,
8682 ) -> Task<Result<Entity<Buffer>>> {
8683 cx.spawn(async move |lsp_store, cx| {
8684 // Escape percent-encoded string.
8685 let current_scheme = abs_path.scheme().to_owned();
8686 // Uri is immutable, so we can't modify the scheme
8687
8688 let abs_path = abs_path
8689 .to_file_path()
8690 .map_err(|()| anyhow!("can't convert URI to path"))?;
8691 let p = abs_path.clone();
8692 let yarn_worktree = lsp_store
8693 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8694 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8695 cx.spawn(async move |this, cx| {
8696 let t = this
8697 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8698 .ok()?;
8699 t.await
8700 })
8701 }),
8702 None => Task::ready(None),
8703 })?
8704 .await;
8705 let (worktree_root_target, known_relative_path) =
8706 if let Some((zip_root, relative_path)) = yarn_worktree {
8707 (zip_root, Some(relative_path))
8708 } else {
8709 (Arc::<Path>::from(abs_path.as_path()), None)
8710 };
8711 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8712 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8713 worktree_store.find_worktree(&worktree_root_target, cx)
8714 })
8715 })?;
8716 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8717 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8718 (result.0, relative_path, None)
8719 } else {
8720 let worktree = lsp_store
8721 .update(cx, |lsp_store, cx| {
8722 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8723 worktree_store.create_worktree(&worktree_root_target, false, cx)
8724 })
8725 })?
8726 .await?;
8727 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8728 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8729 lsp_store
8730 .update(cx, |lsp_store, cx| {
8731 if let Some(local) = lsp_store.as_local_mut() {
8732 local.register_language_server_for_invisible_worktree(
8733 &worktree,
8734 language_server_id,
8735 cx,
8736 )
8737 }
8738 match lsp_store.language_server_statuses.get(&language_server_id) {
8739 Some(status) => status.worktree,
8740 None => None,
8741 }
8742 })
8743 .ok()
8744 .flatten()
8745 .zip(Some(worktree_root.clone()))
8746 } else {
8747 None
8748 };
8749 let relative_path = if let Some(known_path) = known_relative_path {
8750 known_path
8751 } else {
8752 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8753 .into_arc()
8754 };
8755 (worktree, relative_path, source_ws)
8756 };
8757 let project_path = ProjectPath {
8758 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8759 path: relative_path,
8760 };
8761 let buffer = lsp_store
8762 .update(cx, |lsp_store, cx| {
8763 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8764 buffer_store.open_buffer(project_path, cx)
8765 })
8766 })?
8767 .await?;
8768 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8769 if let Some((source_ws, worktree_root)) = source_ws {
8770 buffer.update(cx, |buffer, cx| {
8771 let settings = WorktreeSettings::get(
8772 Some(
8773 (&ProjectPath {
8774 worktree_id: source_ws,
8775 path: Arc::from(RelPath::empty()),
8776 })
8777 .into(),
8778 ),
8779 cx,
8780 );
8781 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8782 if is_read_only {
8783 buffer.set_capability(Capability::ReadOnly, cx);
8784 }
8785 });
8786 }
8787 Ok(buffer)
8788 })
8789 }
8790
8791 fn request_multiple_lsp_locally<P, R>(
8792 &mut self,
8793 buffer: &Entity<Buffer>,
8794 position: Option<P>,
8795 request: R,
8796 cx: &mut Context<Self>,
8797 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8798 where
8799 P: ToOffset,
8800 R: LspCommand + Clone,
8801 <R::LspRequest as lsp::request::Request>::Result: Send,
8802 <R::LspRequest as lsp::request::Request>::Params: Send,
8803 {
8804 let Some(local) = self.as_local() else {
8805 return Task::ready(Vec::new());
8806 };
8807
8808 let snapshot = buffer.read(cx).snapshot();
8809 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8810
8811 let server_ids = buffer.update(cx, |buffer, cx| {
8812 local
8813 .language_servers_for_buffer(buffer, cx)
8814 .filter(|(adapter, _)| {
8815 scope
8816 .as_ref()
8817 .map(|scope| scope.language_allowed(&adapter.name))
8818 .unwrap_or(true)
8819 })
8820 .map(|(_, server)| server.server_id())
8821 .filter(|server_id| {
8822 self.as_local().is_none_or(|local| {
8823 local
8824 .buffers_opened_in_servers
8825 .get(&snapshot.remote_id())
8826 .is_some_and(|servers| servers.contains(server_id))
8827 })
8828 })
8829 .collect::<Vec<_>>()
8830 });
8831
8832 let mut response_results = server_ids
8833 .into_iter()
8834 .map(|server_id| {
8835 let task = self.request_lsp(
8836 buffer.clone(),
8837 LanguageServerToQuery::Other(server_id),
8838 request.clone(),
8839 cx,
8840 );
8841 async move { (server_id, task.await) }
8842 })
8843 .collect::<FuturesUnordered<_>>();
8844
8845 cx.background_spawn(async move {
8846 let mut responses = Vec::with_capacity(response_results.len());
8847 while let Some((server_id, response_result)) = response_results.next().await {
8848 match response_result {
8849 Ok(response) => responses.push((server_id, response)),
8850 // rust-analyzer likes to error with this when its still loading up
8851 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8852 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8853 }
8854 }
8855 responses
8856 })
8857 }
8858
8859 async fn handle_lsp_get_completions(
8860 this: Entity<Self>,
8861 envelope: TypedEnvelope<proto::GetCompletions>,
8862 mut cx: AsyncApp,
8863 ) -> Result<proto::GetCompletionsResponse> {
8864 let sender_id = envelope.original_sender_id().unwrap_or_default();
8865
8866 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8867 let buffer_handle = this.update(&mut cx, |this, cx| {
8868 this.buffer_store.read(cx).get_existing(buffer_id)
8869 })?;
8870 let request = GetCompletions::from_proto(
8871 envelope.payload,
8872 this.clone(),
8873 buffer_handle.clone(),
8874 cx.clone(),
8875 )
8876 .await?;
8877
8878 let server_to_query = match request.server_id {
8879 Some(server_id) => LanguageServerToQuery::Other(server_id),
8880 None => LanguageServerToQuery::FirstCapable,
8881 };
8882
8883 let response = this
8884 .update(&mut cx, |this, cx| {
8885 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8886 })
8887 .await?;
8888 this.update(&mut cx, |this, cx| {
8889 Ok(GetCompletions::response_to_proto(
8890 response,
8891 this,
8892 sender_id,
8893 &buffer_handle.read(cx).version(),
8894 cx,
8895 ))
8896 })
8897 }
8898
8899 async fn handle_lsp_command<T: LspCommand>(
8900 this: Entity<Self>,
8901 envelope: TypedEnvelope<T::ProtoRequest>,
8902 mut cx: AsyncApp,
8903 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8904 where
8905 <T::LspRequest as lsp::request::Request>::Params: Send,
8906 <T::LspRequest as lsp::request::Request>::Result: Send,
8907 {
8908 let sender_id = envelope.original_sender_id().unwrap_or_default();
8909 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8910 let buffer_handle = this.update(&mut cx, |this, cx| {
8911 this.buffer_store.read(cx).get_existing(buffer_id)
8912 })?;
8913 let request = T::from_proto(
8914 envelope.payload,
8915 this.clone(),
8916 buffer_handle.clone(),
8917 cx.clone(),
8918 )
8919 .await?;
8920 let response = this
8921 .update(&mut cx, |this, cx| {
8922 this.request_lsp(
8923 buffer_handle.clone(),
8924 LanguageServerToQuery::FirstCapable,
8925 request,
8926 cx,
8927 )
8928 })
8929 .await?;
8930 this.update(&mut cx, |this, cx| {
8931 Ok(T::response_to_proto(
8932 response,
8933 this,
8934 sender_id,
8935 &buffer_handle.read(cx).version(),
8936 cx,
8937 ))
8938 })
8939 }
8940
8941 async fn handle_lsp_query(
8942 lsp_store: Entity<Self>,
8943 envelope: TypedEnvelope<proto::LspQuery>,
8944 mut cx: AsyncApp,
8945 ) -> Result<proto::Ack> {
8946 use proto::lsp_query::Request;
8947 let sender_id = envelope.original_sender_id().unwrap_or_default();
8948 let lsp_query = envelope.payload;
8949 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8950 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8951 match lsp_query.request.context("invalid LSP query request")? {
8952 Request::GetReferences(get_references) => {
8953 let position = get_references.position.clone().and_then(deserialize_anchor);
8954 Self::query_lsp_locally::<GetReferences>(
8955 lsp_store,
8956 server_id,
8957 sender_id,
8958 lsp_request_id,
8959 get_references,
8960 position,
8961 &mut cx,
8962 )
8963 .await?;
8964 }
8965 Request::GetDocumentColor(get_document_color) => {
8966 Self::query_lsp_locally::<GetDocumentColor>(
8967 lsp_store,
8968 server_id,
8969 sender_id,
8970 lsp_request_id,
8971 get_document_color,
8972 None,
8973 &mut cx,
8974 )
8975 .await?;
8976 }
8977 Request::GetHover(get_hover) => {
8978 let position = get_hover.position.clone().and_then(deserialize_anchor);
8979 Self::query_lsp_locally::<GetHover>(
8980 lsp_store,
8981 server_id,
8982 sender_id,
8983 lsp_request_id,
8984 get_hover,
8985 position,
8986 &mut cx,
8987 )
8988 .await?;
8989 }
8990 Request::GetCodeActions(get_code_actions) => {
8991 Self::query_lsp_locally::<GetCodeActions>(
8992 lsp_store,
8993 server_id,
8994 sender_id,
8995 lsp_request_id,
8996 get_code_actions,
8997 None,
8998 &mut cx,
8999 )
9000 .await?;
9001 }
9002 Request::GetSignatureHelp(get_signature_help) => {
9003 let position = get_signature_help
9004 .position
9005 .clone()
9006 .and_then(deserialize_anchor);
9007 Self::query_lsp_locally::<GetSignatureHelp>(
9008 lsp_store,
9009 server_id,
9010 sender_id,
9011 lsp_request_id,
9012 get_signature_help,
9013 position,
9014 &mut cx,
9015 )
9016 .await?;
9017 }
9018 Request::GetCodeLens(get_code_lens) => {
9019 Self::query_lsp_locally::<GetCodeLens>(
9020 lsp_store,
9021 server_id,
9022 sender_id,
9023 lsp_request_id,
9024 get_code_lens,
9025 None,
9026 &mut cx,
9027 )
9028 .await?;
9029 }
9030 Request::GetDefinition(get_definition) => {
9031 let position = get_definition.position.clone().and_then(deserialize_anchor);
9032 Self::query_lsp_locally::<GetDefinitions>(
9033 lsp_store,
9034 server_id,
9035 sender_id,
9036 lsp_request_id,
9037 get_definition,
9038 position,
9039 &mut cx,
9040 )
9041 .await?;
9042 }
9043 Request::GetDeclaration(get_declaration) => {
9044 let position = get_declaration
9045 .position
9046 .clone()
9047 .and_then(deserialize_anchor);
9048 Self::query_lsp_locally::<GetDeclarations>(
9049 lsp_store,
9050 server_id,
9051 sender_id,
9052 lsp_request_id,
9053 get_declaration,
9054 position,
9055 &mut cx,
9056 )
9057 .await?;
9058 }
9059 Request::GetTypeDefinition(get_type_definition) => {
9060 let position = get_type_definition
9061 .position
9062 .clone()
9063 .and_then(deserialize_anchor);
9064 Self::query_lsp_locally::<GetTypeDefinitions>(
9065 lsp_store,
9066 server_id,
9067 sender_id,
9068 lsp_request_id,
9069 get_type_definition,
9070 position,
9071 &mut cx,
9072 )
9073 .await?;
9074 }
9075 Request::GetImplementation(get_implementation) => {
9076 let position = get_implementation
9077 .position
9078 .clone()
9079 .and_then(deserialize_anchor);
9080 Self::query_lsp_locally::<GetImplementations>(
9081 lsp_store,
9082 server_id,
9083 sender_id,
9084 lsp_request_id,
9085 get_implementation,
9086 position,
9087 &mut cx,
9088 )
9089 .await?;
9090 }
9091 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9092 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9093 let version = deserialize_version(get_document_diagnostics.buffer_version());
9094 let buffer = lsp_store.update(&mut cx, |this, cx| {
9095 this.buffer_store.read(cx).get_existing(buffer_id)
9096 })?;
9097 buffer
9098 .update(&mut cx, |buffer, _| {
9099 buffer.wait_for_version(version.clone())
9100 })
9101 .await?;
9102 lsp_store.update(&mut cx, |lsp_store, cx| {
9103 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9104 let key = LspKey {
9105 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9106 server_queried: server_id,
9107 };
9108 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9109 ) {
9110 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9111 lsp_requests.clear();
9112 };
9113 }
9114
9115 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9116 existing_queries.insert(
9117 lsp_request_id,
9118 cx.spawn(async move |lsp_store, cx| {
9119 let diagnostics_pull = lsp_store.update(cx, |lsp_store, cx| {
9120 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9121 });
9122 if let Ok(diagnostics_pull) = diagnostics_pull {
9123 match diagnostics_pull.await {
9124 Ok(()) => {}
9125 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9126 };
9127 }
9128 }),
9129 );
9130 });
9131 }
9132 Request::InlayHints(inlay_hints) => {
9133 let query_start = inlay_hints
9134 .start
9135 .clone()
9136 .and_then(deserialize_anchor)
9137 .context("invalid inlay hints range start")?;
9138 let query_end = inlay_hints
9139 .end
9140 .clone()
9141 .and_then(deserialize_anchor)
9142 .context("invalid inlay hints range end")?;
9143 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9144 &lsp_store,
9145 server_id,
9146 lsp_request_id,
9147 &inlay_hints,
9148 query_start..query_end,
9149 &mut cx,
9150 )
9151 .await
9152 .context("preparing inlay hints request")?;
9153 Self::query_lsp_locally::<InlayHints>(
9154 lsp_store,
9155 server_id,
9156 sender_id,
9157 lsp_request_id,
9158 inlay_hints,
9159 None,
9160 &mut cx,
9161 )
9162 .await
9163 .context("querying for inlay hints")?
9164 }
9165 }
9166 Ok(proto::Ack {})
9167 }
9168
9169 async fn handle_lsp_query_response(
9170 lsp_store: Entity<Self>,
9171 envelope: TypedEnvelope<proto::LspQueryResponse>,
9172 cx: AsyncApp,
9173 ) -> Result<()> {
9174 lsp_store.read_with(&cx, |lsp_store, _| {
9175 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9176 upstream_client.handle_lsp_response(envelope.clone());
9177 }
9178 });
9179 Ok(())
9180 }
9181
9182 async fn handle_apply_code_action(
9183 this: Entity<Self>,
9184 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9185 mut cx: AsyncApp,
9186 ) -> Result<proto::ApplyCodeActionResponse> {
9187 let sender_id = envelope.original_sender_id().unwrap_or_default();
9188 let action =
9189 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9190 let apply_code_action = this.update(&mut cx, |this, cx| {
9191 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9192 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9193 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9194 })?;
9195
9196 let project_transaction = apply_code_action.await?;
9197 let project_transaction = this.update(&mut cx, |this, cx| {
9198 this.buffer_store.update(cx, |buffer_store, cx| {
9199 buffer_store.serialize_project_transaction_for_peer(
9200 project_transaction,
9201 sender_id,
9202 cx,
9203 )
9204 })
9205 });
9206 Ok(proto::ApplyCodeActionResponse {
9207 transaction: Some(project_transaction),
9208 })
9209 }
9210
9211 async fn handle_register_buffer_with_language_servers(
9212 this: Entity<Self>,
9213 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9214 mut cx: AsyncApp,
9215 ) -> Result<proto::Ack> {
9216 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9217 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9218 this.update(&mut cx, |this, cx| {
9219 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9220 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9221 project_id: upstream_project_id,
9222 buffer_id: buffer_id.to_proto(),
9223 only_servers: envelope.payload.only_servers,
9224 });
9225 }
9226
9227 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9228 anyhow::bail!("buffer is not open");
9229 };
9230
9231 let handle = this.register_buffer_with_language_servers(
9232 &buffer,
9233 envelope
9234 .payload
9235 .only_servers
9236 .into_iter()
9237 .filter_map(|selector| {
9238 Some(match selector.selector? {
9239 proto::language_server_selector::Selector::ServerId(server_id) => {
9240 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9241 }
9242 proto::language_server_selector::Selector::Name(name) => {
9243 LanguageServerSelector::Name(LanguageServerName(
9244 SharedString::from(name),
9245 ))
9246 }
9247 })
9248 })
9249 .collect(),
9250 false,
9251 cx,
9252 );
9253 this.buffer_store().update(cx, |buffer_store, _| {
9254 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9255 });
9256
9257 Ok(())
9258 })?;
9259 Ok(proto::Ack {})
9260 }
9261
9262 async fn handle_rename_project_entry(
9263 this: Entity<Self>,
9264 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9265 mut cx: AsyncApp,
9266 ) -> Result<proto::ProjectEntryResponse> {
9267 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9268 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9269 let new_path =
9270 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9271
9272 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9273 .update(&mut cx, |this, cx| {
9274 let (worktree, entry) = this
9275 .worktree_store
9276 .read(cx)
9277 .worktree_and_entry_for_id(entry_id, cx)?;
9278 let new_worktree = this
9279 .worktree_store
9280 .read(cx)
9281 .worktree_for_id(new_worktree_id, cx)?;
9282 Some((
9283 this.worktree_store.clone(),
9284 worktree,
9285 new_worktree,
9286 entry.clone(),
9287 ))
9288 })
9289 .context("worktree not found")?;
9290 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9291 (worktree.absolutize(&old_entry.path), worktree.id())
9292 });
9293 let new_abs_path =
9294 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9295
9296 let _transaction = Self::will_rename_entry(
9297 this.downgrade(),
9298 old_worktree_id,
9299 &old_abs_path,
9300 &new_abs_path,
9301 old_entry.is_dir(),
9302 cx.clone(),
9303 )
9304 .await;
9305 let response = WorktreeStore::handle_rename_project_entry(
9306 worktree_store,
9307 envelope.payload,
9308 cx.clone(),
9309 )
9310 .await;
9311 this.read_with(&cx, |this, _| {
9312 this.did_rename_entry(
9313 old_worktree_id,
9314 &old_abs_path,
9315 &new_abs_path,
9316 old_entry.is_dir(),
9317 );
9318 });
9319 response
9320 }
9321
9322 async fn handle_update_diagnostic_summary(
9323 this: Entity<Self>,
9324 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9325 mut cx: AsyncApp,
9326 ) -> Result<()> {
9327 this.update(&mut cx, |lsp_store, cx| {
9328 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9329 let mut updated_diagnostics_paths = HashMap::default();
9330 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9331 for message_summary in envelope
9332 .payload
9333 .summary
9334 .into_iter()
9335 .chain(envelope.payload.more_summaries)
9336 {
9337 let project_path = ProjectPath {
9338 worktree_id,
9339 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9340 };
9341 let path = project_path.path.clone();
9342 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9343 let summary = DiagnosticSummary {
9344 error_count: message_summary.error_count as usize,
9345 warning_count: message_summary.warning_count as usize,
9346 };
9347
9348 if summary.is_empty() {
9349 if let Some(worktree_summaries) =
9350 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9351 && let Some(summaries) = worktree_summaries.get_mut(&path)
9352 {
9353 summaries.remove(&server_id);
9354 if summaries.is_empty() {
9355 worktree_summaries.remove(&path);
9356 }
9357 }
9358 } else {
9359 lsp_store
9360 .diagnostic_summaries
9361 .entry(worktree_id)
9362 .or_default()
9363 .entry(path)
9364 .or_default()
9365 .insert(server_id, summary);
9366 }
9367
9368 if let Some((_, project_id)) = &lsp_store.downstream_client {
9369 match &mut diagnostics_summary {
9370 Some(diagnostics_summary) => {
9371 diagnostics_summary
9372 .more_summaries
9373 .push(proto::DiagnosticSummary {
9374 path: project_path.path.as_ref().to_proto(),
9375 language_server_id: server_id.0 as u64,
9376 error_count: summary.error_count as u32,
9377 warning_count: summary.warning_count as u32,
9378 })
9379 }
9380 None => {
9381 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9382 project_id: *project_id,
9383 worktree_id: worktree_id.to_proto(),
9384 summary: Some(proto::DiagnosticSummary {
9385 path: project_path.path.as_ref().to_proto(),
9386 language_server_id: server_id.0 as u64,
9387 error_count: summary.error_count as u32,
9388 warning_count: summary.warning_count as u32,
9389 }),
9390 more_summaries: Vec::new(),
9391 })
9392 }
9393 }
9394 }
9395 updated_diagnostics_paths
9396 .entry(server_id)
9397 .or_insert_with(Vec::new)
9398 .push(project_path);
9399 }
9400
9401 if let Some((diagnostics_summary, (downstream_client, _))) =
9402 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9403 {
9404 downstream_client.send(diagnostics_summary).log_err();
9405 }
9406 for (server_id, paths) in updated_diagnostics_paths {
9407 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9408 }
9409 Ok(())
9410 })
9411 }
9412
9413 async fn handle_start_language_server(
9414 lsp_store: Entity<Self>,
9415 envelope: TypedEnvelope<proto::StartLanguageServer>,
9416 mut cx: AsyncApp,
9417 ) -> Result<()> {
9418 let server = envelope.payload.server.context("invalid server")?;
9419 let server_capabilities =
9420 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9421 .with_context(|| {
9422 format!(
9423 "incorrect server capabilities {}",
9424 envelope.payload.capabilities
9425 )
9426 })?;
9427 lsp_store.update(&mut cx, |lsp_store, cx| {
9428 let server_id = LanguageServerId(server.id as usize);
9429 let server_name = LanguageServerName::from_proto(server.name.clone());
9430 lsp_store
9431 .lsp_server_capabilities
9432 .insert(server_id, server_capabilities);
9433 lsp_store.language_server_statuses.insert(
9434 server_id,
9435 LanguageServerStatus {
9436 name: server_name.clone(),
9437 server_version: None,
9438 pending_work: Default::default(),
9439 has_pending_diagnostic_updates: false,
9440 progress_tokens: Default::default(),
9441 worktree: server.worktree_id.map(WorktreeId::from_proto),
9442 binary: None,
9443 configuration: None,
9444 workspace_folders: BTreeSet::new(),
9445 },
9446 );
9447 cx.emit(LspStoreEvent::LanguageServerAdded(
9448 server_id,
9449 server_name,
9450 server.worktree_id.map(WorktreeId::from_proto),
9451 ));
9452 cx.notify();
9453 });
9454 Ok(())
9455 }
9456
9457 async fn handle_update_language_server(
9458 lsp_store: Entity<Self>,
9459 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9460 mut cx: AsyncApp,
9461 ) -> Result<()> {
9462 lsp_store.update(&mut cx, |lsp_store, cx| {
9463 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9464
9465 match envelope.payload.variant.context("invalid variant")? {
9466 proto::update_language_server::Variant::WorkStart(payload) => {
9467 lsp_store.on_lsp_work_start(
9468 language_server_id,
9469 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9470 .context("invalid progress token value")?,
9471 LanguageServerProgress {
9472 title: payload.title,
9473 is_disk_based_diagnostics_progress: false,
9474 is_cancellable: payload.is_cancellable.unwrap_or(false),
9475 message: payload.message,
9476 percentage: payload.percentage.map(|p| p as usize),
9477 last_update_at: cx.background_executor().now(),
9478 },
9479 cx,
9480 );
9481 }
9482 proto::update_language_server::Variant::WorkProgress(payload) => {
9483 lsp_store.on_lsp_work_progress(
9484 language_server_id,
9485 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9486 .context("invalid progress token value")?,
9487 LanguageServerProgress {
9488 title: None,
9489 is_disk_based_diagnostics_progress: false,
9490 is_cancellable: payload.is_cancellable.unwrap_or(false),
9491 message: payload.message,
9492 percentage: payload.percentage.map(|p| p as usize),
9493 last_update_at: cx.background_executor().now(),
9494 },
9495 cx,
9496 );
9497 }
9498
9499 proto::update_language_server::Variant::WorkEnd(payload) => {
9500 lsp_store.on_lsp_work_end(
9501 language_server_id,
9502 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9503 .context("invalid progress token value")?,
9504 cx,
9505 );
9506 }
9507
9508 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9509 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9510 }
9511
9512 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9513 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9514 }
9515
9516 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9517 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9518 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9519 cx.emit(LspStoreEvent::LanguageServerUpdate {
9520 language_server_id,
9521 name: envelope
9522 .payload
9523 .server_name
9524 .map(SharedString::new)
9525 .map(LanguageServerName),
9526 message: non_lsp,
9527 });
9528 }
9529 }
9530
9531 Ok(())
9532 })
9533 }
9534
9535 async fn handle_language_server_log(
9536 this: Entity<Self>,
9537 envelope: TypedEnvelope<proto::LanguageServerLog>,
9538 mut cx: AsyncApp,
9539 ) -> Result<()> {
9540 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9541 let log_type = envelope
9542 .payload
9543 .log_type
9544 .map(LanguageServerLogType::from_proto)
9545 .context("invalid language server log type")?;
9546
9547 let message = envelope.payload.message;
9548
9549 this.update(&mut cx, |_, cx| {
9550 cx.emit(LspStoreEvent::LanguageServerLog(
9551 language_server_id,
9552 log_type,
9553 message,
9554 ));
9555 });
9556 Ok(())
9557 }
9558
9559 async fn handle_lsp_ext_cancel_flycheck(
9560 lsp_store: Entity<Self>,
9561 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9562 cx: AsyncApp,
9563 ) -> Result<proto::Ack> {
9564 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9565 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9566 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9567 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9568 } else {
9569 None
9570 }
9571 });
9572 if let Some(task) = task {
9573 task.context("handling lsp ext cancel flycheck")?;
9574 }
9575
9576 Ok(proto::Ack {})
9577 }
9578
9579 async fn handle_lsp_ext_run_flycheck(
9580 lsp_store: Entity<Self>,
9581 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9582 mut cx: AsyncApp,
9583 ) -> Result<proto::Ack> {
9584 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9585 lsp_store.update(&mut cx, |lsp_store, cx| {
9586 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9587 let text_document = if envelope.payload.current_file_only {
9588 let buffer_id = envelope
9589 .payload
9590 .buffer_id
9591 .map(|id| BufferId::new(id))
9592 .transpose()?;
9593 buffer_id
9594 .and_then(|buffer_id| {
9595 lsp_store
9596 .buffer_store()
9597 .read(cx)
9598 .get(buffer_id)
9599 .and_then(|buffer| {
9600 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9601 })
9602 .map(|path| make_text_document_identifier(&path))
9603 })
9604 .transpose()?
9605 } else {
9606 None
9607 };
9608 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9609 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9610 )?;
9611 }
9612 anyhow::Ok(())
9613 })?;
9614
9615 Ok(proto::Ack {})
9616 }
9617
9618 async fn handle_lsp_ext_clear_flycheck(
9619 lsp_store: Entity<Self>,
9620 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9621 cx: AsyncApp,
9622 ) -> Result<proto::Ack> {
9623 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9624 lsp_store.read_with(&cx, |lsp_store, _| {
9625 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9626 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9627 } else {
9628 None
9629 }
9630 });
9631
9632 Ok(proto::Ack {})
9633 }
9634
9635 pub fn disk_based_diagnostics_started(
9636 &mut self,
9637 language_server_id: LanguageServerId,
9638 cx: &mut Context<Self>,
9639 ) {
9640 if let Some(language_server_status) =
9641 self.language_server_statuses.get_mut(&language_server_id)
9642 {
9643 language_server_status.has_pending_diagnostic_updates = true;
9644 }
9645
9646 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9647 cx.emit(LspStoreEvent::LanguageServerUpdate {
9648 language_server_id,
9649 name: self
9650 .language_server_adapter_for_id(language_server_id)
9651 .map(|adapter| adapter.name()),
9652 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9653 Default::default(),
9654 ),
9655 })
9656 }
9657
9658 pub fn disk_based_diagnostics_finished(
9659 &mut self,
9660 language_server_id: LanguageServerId,
9661 cx: &mut Context<Self>,
9662 ) {
9663 if let Some(language_server_status) =
9664 self.language_server_statuses.get_mut(&language_server_id)
9665 {
9666 language_server_status.has_pending_diagnostic_updates = false;
9667 }
9668
9669 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9670 cx.emit(LspStoreEvent::LanguageServerUpdate {
9671 language_server_id,
9672 name: self
9673 .language_server_adapter_for_id(language_server_id)
9674 .map(|adapter| adapter.name()),
9675 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9676 Default::default(),
9677 ),
9678 })
9679 }
9680
9681 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9682 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9683 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9684 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9685 // the language server might take some time to publish diagnostics.
9686 fn simulate_disk_based_diagnostics_events_if_needed(
9687 &mut self,
9688 language_server_id: LanguageServerId,
9689 cx: &mut Context<Self>,
9690 ) {
9691 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9692
9693 let Some(LanguageServerState::Running {
9694 simulate_disk_based_diagnostics_completion,
9695 adapter,
9696 ..
9697 }) = self
9698 .as_local_mut()
9699 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9700 else {
9701 return;
9702 };
9703
9704 if adapter.disk_based_diagnostics_progress_token.is_some() {
9705 return;
9706 }
9707
9708 let prev_task =
9709 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9710 cx.background_executor()
9711 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9712 .await;
9713
9714 this.update(cx, |this, cx| {
9715 this.disk_based_diagnostics_finished(language_server_id, cx);
9716
9717 if let Some(LanguageServerState::Running {
9718 simulate_disk_based_diagnostics_completion,
9719 ..
9720 }) = this.as_local_mut().and_then(|local_store| {
9721 local_store.language_servers.get_mut(&language_server_id)
9722 }) {
9723 *simulate_disk_based_diagnostics_completion = None;
9724 }
9725 })
9726 .ok();
9727 }));
9728
9729 if prev_task.is_none() {
9730 self.disk_based_diagnostics_started(language_server_id, cx);
9731 }
9732 }
9733
9734 pub fn language_server_statuses(
9735 &self,
9736 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9737 self.language_server_statuses
9738 .iter()
9739 .map(|(key, value)| (*key, value))
9740 }
9741
9742 pub(super) fn did_rename_entry(
9743 &self,
9744 worktree_id: WorktreeId,
9745 old_path: &Path,
9746 new_path: &Path,
9747 is_dir: bool,
9748 ) {
9749 maybe!({
9750 let local_store = self.as_local()?;
9751
9752 let old_uri = lsp::Uri::from_file_path(old_path)
9753 .ok()
9754 .map(|uri| uri.to_string())?;
9755 let new_uri = lsp::Uri::from_file_path(new_path)
9756 .ok()
9757 .map(|uri| uri.to_string())?;
9758
9759 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9760 let Some(filter) = local_store
9761 .language_server_paths_watched_for_rename
9762 .get(&language_server.server_id())
9763 else {
9764 continue;
9765 };
9766
9767 if filter.should_send_did_rename(&old_uri, is_dir) {
9768 language_server
9769 .notify::<DidRenameFiles>(RenameFilesParams {
9770 files: vec![FileRename {
9771 old_uri: old_uri.clone(),
9772 new_uri: new_uri.clone(),
9773 }],
9774 })
9775 .ok();
9776 }
9777 }
9778 Some(())
9779 });
9780 }
9781
9782 pub(super) fn will_rename_entry(
9783 this: WeakEntity<Self>,
9784 worktree_id: WorktreeId,
9785 old_path: &Path,
9786 new_path: &Path,
9787 is_dir: bool,
9788 cx: AsyncApp,
9789 ) -> Task<ProjectTransaction> {
9790 let old_uri = lsp::Uri::from_file_path(old_path)
9791 .ok()
9792 .map(|uri| uri.to_string());
9793 let new_uri = lsp::Uri::from_file_path(new_path)
9794 .ok()
9795 .map(|uri| uri.to_string());
9796 cx.spawn(async move |cx| {
9797 let mut tasks = vec![];
9798 this.update(cx, |this, cx| {
9799 let local_store = this.as_local()?;
9800 let old_uri = old_uri?;
9801 let new_uri = new_uri?;
9802 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9803 let Some(filter) = local_store
9804 .language_server_paths_watched_for_rename
9805 .get(&language_server.server_id())
9806 else {
9807 continue;
9808 };
9809
9810 if filter.should_send_will_rename(&old_uri, is_dir) {
9811 let apply_edit = cx.spawn({
9812 let old_uri = old_uri.clone();
9813 let new_uri = new_uri.clone();
9814 let language_server = language_server.clone();
9815 async move |this, cx| {
9816 let edit = language_server
9817 .request::<WillRenameFiles>(RenameFilesParams {
9818 files: vec![FileRename { old_uri, new_uri }],
9819 })
9820 .await
9821 .into_response()
9822 .context("will rename files")
9823 .log_err()
9824 .flatten()?;
9825
9826 let transaction = LocalLspStore::deserialize_workspace_edit(
9827 this.upgrade()?,
9828 edit,
9829 false,
9830 language_server.clone(),
9831 cx,
9832 )
9833 .await
9834 .ok()?;
9835 Some(transaction)
9836 }
9837 });
9838 tasks.push(apply_edit);
9839 }
9840 }
9841 Some(())
9842 })
9843 .ok()
9844 .flatten();
9845 let mut merged_transaction = ProjectTransaction::default();
9846 for task in tasks {
9847 // Await on tasks sequentially so that the order of application of edits is deterministic
9848 // (at least with regards to the order of registration of language servers)
9849 if let Some(transaction) = task.await {
9850 for (buffer, buffer_transaction) in transaction.0 {
9851 merged_transaction.0.insert(buffer, buffer_transaction);
9852 }
9853 }
9854 }
9855 merged_transaction
9856 })
9857 }
9858
9859 fn lsp_notify_abs_paths_changed(
9860 &mut self,
9861 server_id: LanguageServerId,
9862 changes: Vec<PathEvent>,
9863 ) {
9864 maybe!({
9865 let server = self.language_server_for_id(server_id)?;
9866 let changes = changes
9867 .into_iter()
9868 .filter_map(|event| {
9869 let typ = match event.kind? {
9870 PathEventKind::Created => lsp::FileChangeType::CREATED,
9871 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9872 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9873 };
9874 Some(lsp::FileEvent {
9875 uri: file_path_to_lsp_url(&event.path).log_err()?,
9876 typ,
9877 })
9878 })
9879 .collect::<Vec<_>>();
9880 if !changes.is_empty() {
9881 server
9882 .notify::<lsp::notification::DidChangeWatchedFiles>(
9883 lsp::DidChangeWatchedFilesParams { changes },
9884 )
9885 .ok();
9886 }
9887 Some(())
9888 });
9889 }
9890
9891 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9892 self.as_local()?.language_server_for_id(id)
9893 }
9894
9895 fn on_lsp_progress(
9896 &mut self,
9897 progress_params: lsp::ProgressParams,
9898 language_server_id: LanguageServerId,
9899 disk_based_diagnostics_progress_token: Option<String>,
9900 cx: &mut Context<Self>,
9901 ) {
9902 match progress_params.value {
9903 lsp::ProgressParamsValue::WorkDone(progress) => {
9904 self.handle_work_done_progress(
9905 progress,
9906 language_server_id,
9907 disk_based_diagnostics_progress_token,
9908 ProgressToken::from_lsp(progress_params.token),
9909 cx,
9910 );
9911 }
9912 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9913 let registration_id = match progress_params.token {
9914 lsp::NumberOrString::Number(_) => None,
9915 lsp::NumberOrString::String(token) => token
9916 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9917 .map(|(_, id)| id.to_owned()),
9918 };
9919 if let Some(LanguageServerState::Running {
9920 workspace_diagnostics_refresh_tasks,
9921 ..
9922 }) = self
9923 .as_local_mut()
9924 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9925 && let Some(workspace_diagnostics) =
9926 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9927 {
9928 workspace_diagnostics.progress_tx.try_send(()).ok();
9929 self.apply_workspace_diagnostic_report(
9930 language_server_id,
9931 report,
9932 registration_id.map(SharedString::from),
9933 cx,
9934 )
9935 }
9936 }
9937 }
9938 }
9939
9940 fn handle_work_done_progress(
9941 &mut self,
9942 progress: lsp::WorkDoneProgress,
9943 language_server_id: LanguageServerId,
9944 disk_based_diagnostics_progress_token: Option<String>,
9945 token: ProgressToken,
9946 cx: &mut Context<Self>,
9947 ) {
9948 let language_server_status =
9949 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9950 status
9951 } else {
9952 return;
9953 };
9954
9955 if !language_server_status.progress_tokens.contains(&token) {
9956 return;
9957 }
9958
9959 let is_disk_based_diagnostics_progress =
9960 if let (Some(disk_based_token), ProgressToken::String(token)) =
9961 (&disk_based_diagnostics_progress_token, &token)
9962 {
9963 token.starts_with(disk_based_token)
9964 } else {
9965 false
9966 };
9967
9968 match progress {
9969 lsp::WorkDoneProgress::Begin(report) => {
9970 if is_disk_based_diagnostics_progress {
9971 self.disk_based_diagnostics_started(language_server_id, cx);
9972 }
9973 self.on_lsp_work_start(
9974 language_server_id,
9975 token.clone(),
9976 LanguageServerProgress {
9977 title: Some(report.title),
9978 is_disk_based_diagnostics_progress,
9979 is_cancellable: report.cancellable.unwrap_or(false),
9980 message: report.message.clone(),
9981 percentage: report.percentage.map(|p| p as usize),
9982 last_update_at: cx.background_executor().now(),
9983 },
9984 cx,
9985 );
9986 }
9987 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9988 language_server_id,
9989 token,
9990 LanguageServerProgress {
9991 title: None,
9992 is_disk_based_diagnostics_progress,
9993 is_cancellable: report.cancellable.unwrap_or(false),
9994 message: report.message,
9995 percentage: report.percentage.map(|p| p as usize),
9996 last_update_at: cx.background_executor().now(),
9997 },
9998 cx,
9999 ),
10000 lsp::WorkDoneProgress::End(_) => {
10001 language_server_status.progress_tokens.remove(&token);
10002 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10003 if is_disk_based_diagnostics_progress {
10004 self.disk_based_diagnostics_finished(language_server_id, cx);
10005 }
10006 }
10007 }
10008 }
10009
10010 fn on_lsp_work_start(
10011 &mut self,
10012 language_server_id: LanguageServerId,
10013 token: ProgressToken,
10014 progress: LanguageServerProgress,
10015 cx: &mut Context<Self>,
10016 ) {
10017 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10018 status.pending_work.insert(token.clone(), progress.clone());
10019 cx.notify();
10020 }
10021 cx.emit(LspStoreEvent::LanguageServerUpdate {
10022 language_server_id,
10023 name: self
10024 .language_server_adapter_for_id(language_server_id)
10025 .map(|adapter| adapter.name()),
10026 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10027 token: Some(token.to_proto()),
10028 title: progress.title,
10029 message: progress.message,
10030 percentage: progress.percentage.map(|p| p as u32),
10031 is_cancellable: Some(progress.is_cancellable),
10032 }),
10033 })
10034 }
10035
10036 fn on_lsp_work_progress(
10037 &mut self,
10038 language_server_id: LanguageServerId,
10039 token: ProgressToken,
10040 progress: LanguageServerProgress,
10041 cx: &mut Context<Self>,
10042 ) {
10043 let mut did_update = false;
10044 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10045 match status.pending_work.entry(token.clone()) {
10046 btree_map::Entry::Vacant(entry) => {
10047 entry.insert(progress.clone());
10048 did_update = true;
10049 }
10050 btree_map::Entry::Occupied(mut entry) => {
10051 let entry = entry.get_mut();
10052 if (progress.last_update_at - entry.last_update_at)
10053 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10054 {
10055 entry.last_update_at = progress.last_update_at;
10056 if progress.message.is_some() {
10057 entry.message = progress.message.clone();
10058 }
10059 if progress.percentage.is_some() {
10060 entry.percentage = progress.percentage;
10061 }
10062 if progress.is_cancellable != entry.is_cancellable {
10063 entry.is_cancellable = progress.is_cancellable;
10064 }
10065 did_update = true;
10066 }
10067 }
10068 }
10069 }
10070
10071 if did_update {
10072 cx.emit(LspStoreEvent::LanguageServerUpdate {
10073 language_server_id,
10074 name: self
10075 .language_server_adapter_for_id(language_server_id)
10076 .map(|adapter| adapter.name()),
10077 message: proto::update_language_server::Variant::WorkProgress(
10078 proto::LspWorkProgress {
10079 token: Some(token.to_proto()),
10080 message: progress.message,
10081 percentage: progress.percentage.map(|p| p as u32),
10082 is_cancellable: Some(progress.is_cancellable),
10083 },
10084 ),
10085 })
10086 }
10087 }
10088
10089 fn on_lsp_work_end(
10090 &mut self,
10091 language_server_id: LanguageServerId,
10092 token: ProgressToken,
10093 cx: &mut Context<Self>,
10094 ) {
10095 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10096 if let Some(work) = status.pending_work.remove(&token)
10097 && !work.is_disk_based_diagnostics_progress
10098 {
10099 cx.emit(LspStoreEvent::RefreshInlayHints {
10100 server_id: language_server_id,
10101 request_id: None,
10102 });
10103 }
10104 cx.notify();
10105 }
10106
10107 cx.emit(LspStoreEvent::LanguageServerUpdate {
10108 language_server_id,
10109 name: self
10110 .language_server_adapter_for_id(language_server_id)
10111 .map(|adapter| adapter.name()),
10112 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10113 token: Some(token.to_proto()),
10114 }),
10115 })
10116 }
10117
10118 pub async fn handle_resolve_completion_documentation(
10119 this: Entity<Self>,
10120 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10121 mut cx: AsyncApp,
10122 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10123 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10124
10125 let completion = this
10126 .read_with(&cx, |this, cx| {
10127 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10128 let server = this
10129 .language_server_for_id(id)
10130 .with_context(|| format!("No language server {id}"))?;
10131
10132 anyhow::Ok(cx.background_spawn(async move {
10133 let can_resolve = server
10134 .capabilities()
10135 .completion_provider
10136 .as_ref()
10137 .and_then(|options| options.resolve_provider)
10138 .unwrap_or(false);
10139 if can_resolve {
10140 server
10141 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10142 .await
10143 .into_response()
10144 .context("resolve completion item")
10145 } else {
10146 anyhow::Ok(lsp_completion)
10147 }
10148 }))
10149 })?
10150 .await?;
10151
10152 let mut documentation_is_markdown = false;
10153 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10154 let documentation = match completion.documentation {
10155 Some(lsp::Documentation::String(text)) => text,
10156
10157 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10158 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10159 value
10160 }
10161
10162 _ => String::new(),
10163 };
10164
10165 // If we have a new buffer_id, that means we're talking to a new client
10166 // and want to check for new text_edits in the completion too.
10167 let mut old_replace_start = None;
10168 let mut old_replace_end = None;
10169 let mut old_insert_start = None;
10170 let mut old_insert_end = None;
10171 let mut new_text = String::default();
10172 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10173 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10174 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10175 anyhow::Ok(buffer.read(cx).snapshot())
10176 })?;
10177
10178 if let Some(text_edit) = completion.text_edit.as_ref() {
10179 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10180
10181 if let Some(mut edit) = edit {
10182 LineEnding::normalize(&mut edit.new_text);
10183
10184 new_text = edit.new_text;
10185 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10186 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10187 if let Some(insert_range) = edit.insert_range {
10188 old_insert_start = Some(serialize_anchor(&insert_range.start));
10189 old_insert_end = Some(serialize_anchor(&insert_range.end));
10190 }
10191 }
10192 }
10193 }
10194
10195 Ok(proto::ResolveCompletionDocumentationResponse {
10196 documentation,
10197 documentation_is_markdown,
10198 old_replace_start,
10199 old_replace_end,
10200 new_text,
10201 lsp_completion,
10202 old_insert_start,
10203 old_insert_end,
10204 })
10205 }
10206
10207 async fn handle_on_type_formatting(
10208 this: Entity<Self>,
10209 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10210 mut cx: AsyncApp,
10211 ) -> Result<proto::OnTypeFormattingResponse> {
10212 let on_type_formatting = this.update(&mut cx, |this, cx| {
10213 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10214 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10215 let position = envelope
10216 .payload
10217 .position
10218 .and_then(deserialize_anchor)
10219 .context("invalid position")?;
10220 anyhow::Ok(this.apply_on_type_formatting(
10221 buffer,
10222 position,
10223 envelope.payload.trigger.clone(),
10224 cx,
10225 ))
10226 })?;
10227
10228 let transaction = on_type_formatting
10229 .await?
10230 .as_ref()
10231 .map(language::proto::serialize_transaction);
10232 Ok(proto::OnTypeFormattingResponse { transaction })
10233 }
10234
10235 async fn handle_refresh_inlay_hints(
10236 lsp_store: Entity<Self>,
10237 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10238 mut cx: AsyncApp,
10239 ) -> Result<proto::Ack> {
10240 lsp_store.update(&mut cx, |_, cx| {
10241 cx.emit(LspStoreEvent::RefreshInlayHints {
10242 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10243 request_id: envelope.payload.request_id.map(|id| id as usize),
10244 });
10245 });
10246 Ok(proto::Ack {})
10247 }
10248
10249 async fn handle_pull_workspace_diagnostics(
10250 lsp_store: Entity<Self>,
10251 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10252 mut cx: AsyncApp,
10253 ) -> Result<proto::Ack> {
10254 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10255 lsp_store.update(&mut cx, |lsp_store, _| {
10256 lsp_store.pull_workspace_diagnostics(server_id);
10257 });
10258 Ok(proto::Ack {})
10259 }
10260
10261 async fn handle_get_color_presentation(
10262 lsp_store: Entity<Self>,
10263 envelope: TypedEnvelope<proto::GetColorPresentation>,
10264 mut cx: AsyncApp,
10265 ) -> Result<proto::GetColorPresentationResponse> {
10266 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10267 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10268 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10269 })?;
10270
10271 let color = envelope
10272 .payload
10273 .color
10274 .context("invalid color resolve request")?;
10275 let start = color
10276 .lsp_range_start
10277 .context("invalid color resolve request")?;
10278 let end = color
10279 .lsp_range_end
10280 .context("invalid color resolve request")?;
10281
10282 let color = DocumentColor {
10283 lsp_range: lsp::Range {
10284 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10285 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10286 },
10287 color: lsp::Color {
10288 red: color.red,
10289 green: color.green,
10290 blue: color.blue,
10291 alpha: color.alpha,
10292 },
10293 resolved: false,
10294 color_presentations: Vec::new(),
10295 };
10296 let resolved_color = lsp_store
10297 .update(&mut cx, |lsp_store, cx| {
10298 lsp_store.resolve_color_presentation(
10299 color,
10300 buffer.clone(),
10301 LanguageServerId(envelope.payload.server_id as usize),
10302 cx,
10303 )
10304 })
10305 .await
10306 .context("resolving color presentation")?;
10307
10308 Ok(proto::GetColorPresentationResponse {
10309 presentations: resolved_color
10310 .color_presentations
10311 .into_iter()
10312 .map(|presentation| proto::ColorPresentation {
10313 label: presentation.label.to_string(),
10314 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10315 additional_text_edits: presentation
10316 .additional_text_edits
10317 .into_iter()
10318 .map(serialize_lsp_edit)
10319 .collect(),
10320 })
10321 .collect(),
10322 })
10323 }
10324
10325 async fn handle_resolve_inlay_hint(
10326 lsp_store: Entity<Self>,
10327 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10328 mut cx: AsyncApp,
10329 ) -> Result<proto::ResolveInlayHintResponse> {
10330 let proto_hint = envelope
10331 .payload
10332 .hint
10333 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10334 let hint = InlayHints::proto_to_project_hint(proto_hint)
10335 .context("resolved proto inlay hint conversion")?;
10336 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10337 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10338 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10339 })?;
10340 let response_hint = lsp_store
10341 .update(&mut cx, |lsp_store, cx| {
10342 lsp_store.resolve_inlay_hint(
10343 hint,
10344 buffer,
10345 LanguageServerId(envelope.payload.language_server_id as usize),
10346 cx,
10347 )
10348 })
10349 .await
10350 .context("inlay hints fetch")?;
10351 Ok(proto::ResolveInlayHintResponse {
10352 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10353 })
10354 }
10355
10356 async fn handle_refresh_code_lens(
10357 this: Entity<Self>,
10358 _: TypedEnvelope<proto::RefreshCodeLens>,
10359 mut cx: AsyncApp,
10360 ) -> Result<proto::Ack> {
10361 this.update(&mut cx, |_, cx| {
10362 cx.emit(LspStoreEvent::RefreshCodeLens);
10363 });
10364 Ok(proto::Ack {})
10365 }
10366
10367 async fn handle_open_buffer_for_symbol(
10368 this: Entity<Self>,
10369 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10370 mut cx: AsyncApp,
10371 ) -> Result<proto::OpenBufferForSymbolResponse> {
10372 let peer_id = envelope.original_sender_id().unwrap_or_default();
10373 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10374 let symbol = Self::deserialize_symbol(symbol)?;
10375 this.read_with(&cx, |this, _| {
10376 if let SymbolLocation::OutsideProject {
10377 abs_path,
10378 signature,
10379 } = &symbol.path
10380 {
10381 let new_signature = this.symbol_signature(&abs_path);
10382 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10383 }
10384 Ok(())
10385 })?;
10386 let buffer = this
10387 .update(&mut cx, |this, cx| {
10388 this.open_buffer_for_symbol(
10389 &Symbol {
10390 language_server_name: symbol.language_server_name,
10391 source_worktree_id: symbol.source_worktree_id,
10392 source_language_server_id: symbol.source_language_server_id,
10393 path: symbol.path,
10394 name: symbol.name,
10395 kind: symbol.kind,
10396 range: symbol.range,
10397 label: CodeLabel::default(),
10398 },
10399 cx,
10400 )
10401 })
10402 .await?;
10403
10404 this.update(&mut cx, |this, cx| {
10405 let is_private = buffer
10406 .read(cx)
10407 .file()
10408 .map(|f| f.is_private())
10409 .unwrap_or_default();
10410 if is_private {
10411 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10412 } else {
10413 this.buffer_store
10414 .update(cx, |buffer_store, cx| {
10415 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10416 })
10417 .detach_and_log_err(cx);
10418 let buffer_id = buffer.read(cx).remote_id().to_proto();
10419 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10420 }
10421 })
10422 }
10423
10424 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10425 let mut hasher = Sha256::new();
10426 hasher.update(abs_path.to_string_lossy().as_bytes());
10427 hasher.update(self.nonce.to_be_bytes());
10428 hasher.finalize().as_slice().try_into().unwrap()
10429 }
10430
10431 pub async fn handle_get_project_symbols(
10432 this: Entity<Self>,
10433 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10434 mut cx: AsyncApp,
10435 ) -> Result<proto::GetProjectSymbolsResponse> {
10436 let symbols = this
10437 .update(&mut cx, |this, cx| {
10438 this.symbols(&envelope.payload.query, cx)
10439 })
10440 .await?;
10441
10442 Ok(proto::GetProjectSymbolsResponse {
10443 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10444 })
10445 }
10446
10447 pub async fn handle_restart_language_servers(
10448 this: Entity<Self>,
10449 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10450 mut cx: AsyncApp,
10451 ) -> Result<proto::Ack> {
10452 this.update(&mut cx, |lsp_store, cx| {
10453 let buffers =
10454 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10455 lsp_store.restart_language_servers_for_buffers(
10456 buffers,
10457 envelope
10458 .payload
10459 .only_servers
10460 .into_iter()
10461 .filter_map(|selector| {
10462 Some(match selector.selector? {
10463 proto::language_server_selector::Selector::ServerId(server_id) => {
10464 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10465 }
10466 proto::language_server_selector::Selector::Name(name) => {
10467 LanguageServerSelector::Name(LanguageServerName(
10468 SharedString::from(name),
10469 ))
10470 }
10471 })
10472 })
10473 .collect(),
10474 cx,
10475 );
10476 });
10477
10478 Ok(proto::Ack {})
10479 }
10480
10481 pub async fn handle_stop_language_servers(
10482 lsp_store: Entity<Self>,
10483 envelope: TypedEnvelope<proto::StopLanguageServers>,
10484 mut cx: AsyncApp,
10485 ) -> Result<proto::Ack> {
10486 lsp_store.update(&mut cx, |lsp_store, cx| {
10487 if envelope.payload.all
10488 && envelope.payload.also_servers.is_empty()
10489 && envelope.payload.buffer_ids.is_empty()
10490 {
10491 lsp_store.stop_all_language_servers(cx);
10492 } else {
10493 let buffers =
10494 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10495 lsp_store
10496 .stop_language_servers_for_buffers(
10497 buffers,
10498 envelope
10499 .payload
10500 .also_servers
10501 .into_iter()
10502 .filter_map(|selector| {
10503 Some(match selector.selector? {
10504 proto::language_server_selector::Selector::ServerId(
10505 server_id,
10506 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10507 server_id,
10508 )),
10509 proto::language_server_selector::Selector::Name(name) => {
10510 LanguageServerSelector::Name(LanguageServerName(
10511 SharedString::from(name),
10512 ))
10513 }
10514 })
10515 })
10516 .collect(),
10517 cx,
10518 )
10519 .detach_and_log_err(cx);
10520 }
10521 });
10522
10523 Ok(proto::Ack {})
10524 }
10525
10526 pub async fn handle_cancel_language_server_work(
10527 lsp_store: Entity<Self>,
10528 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10529 mut cx: AsyncApp,
10530 ) -> Result<proto::Ack> {
10531 lsp_store.update(&mut cx, |lsp_store, cx| {
10532 if let Some(work) = envelope.payload.work {
10533 match work {
10534 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10535 let buffers =
10536 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10537 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10538 }
10539 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10540 let server_id = LanguageServerId::from_proto(work.language_server_id);
10541 let token = work
10542 .token
10543 .map(|token| {
10544 ProgressToken::from_proto(token)
10545 .context("invalid work progress token")
10546 })
10547 .transpose()?;
10548 lsp_store.cancel_language_server_work(server_id, token, cx);
10549 }
10550 }
10551 }
10552 anyhow::Ok(())
10553 })?;
10554
10555 Ok(proto::Ack {})
10556 }
10557
10558 fn buffer_ids_to_buffers(
10559 &mut self,
10560 buffer_ids: impl Iterator<Item = u64>,
10561 cx: &mut Context<Self>,
10562 ) -> Vec<Entity<Buffer>> {
10563 buffer_ids
10564 .into_iter()
10565 .flat_map(|buffer_id| {
10566 self.buffer_store
10567 .read(cx)
10568 .get(BufferId::new(buffer_id).log_err()?)
10569 })
10570 .collect::<Vec<_>>()
10571 }
10572
10573 async fn handle_apply_additional_edits_for_completion(
10574 this: Entity<Self>,
10575 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10576 mut cx: AsyncApp,
10577 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10578 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10579 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10580 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10581 let completion = Self::deserialize_completion(
10582 envelope.payload.completion.context("invalid completion")?,
10583 )?;
10584 anyhow::Ok((buffer, completion))
10585 })?;
10586
10587 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10588 this.apply_additional_edits_for_completion(
10589 buffer,
10590 Rc::new(RefCell::new(Box::new([Completion {
10591 replace_range: completion.replace_range,
10592 new_text: completion.new_text,
10593 source: completion.source,
10594 documentation: None,
10595 label: CodeLabel::default(),
10596 match_start: None,
10597 snippet_deduplication_key: None,
10598 insert_text_mode: None,
10599 icon_path: None,
10600 confirm: None,
10601 }]))),
10602 0,
10603 false,
10604 cx,
10605 )
10606 });
10607
10608 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10609 transaction: apply_additional_edits
10610 .await?
10611 .as_ref()
10612 .map(language::proto::serialize_transaction),
10613 })
10614 }
10615
10616 pub fn last_formatting_failure(&self) -> Option<&str> {
10617 self.last_formatting_failure.as_deref()
10618 }
10619
10620 pub fn reset_last_formatting_failure(&mut self) {
10621 self.last_formatting_failure = None;
10622 }
10623
10624 pub fn environment_for_buffer(
10625 &self,
10626 buffer: &Entity<Buffer>,
10627 cx: &mut Context<Self>,
10628 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10629 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10630 environment.update(cx, |env, cx| {
10631 env.buffer_environment(buffer, &self.worktree_store, cx)
10632 })
10633 } else {
10634 Task::ready(None).shared()
10635 }
10636 }
10637
10638 pub fn format(
10639 &mut self,
10640 buffers: HashSet<Entity<Buffer>>,
10641 target: LspFormatTarget,
10642 push_to_history: bool,
10643 trigger: FormatTrigger,
10644 cx: &mut Context<Self>,
10645 ) -> Task<anyhow::Result<ProjectTransaction>> {
10646 let logger = zlog::scoped!("format");
10647 if self.as_local().is_some() {
10648 zlog::trace!(logger => "Formatting locally");
10649 let logger = zlog::scoped!(logger => "local");
10650 let buffers = buffers
10651 .into_iter()
10652 .map(|buffer_handle| {
10653 let buffer = buffer_handle.read(cx);
10654 let buffer_abs_path = File::from_dyn(buffer.file())
10655 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10656
10657 (buffer_handle, buffer_abs_path, buffer.remote_id())
10658 })
10659 .collect::<Vec<_>>();
10660
10661 cx.spawn(async move |lsp_store, cx| {
10662 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10663
10664 for (handle, abs_path, id) in buffers {
10665 let env = lsp_store
10666 .update(cx, |lsp_store, cx| {
10667 lsp_store.environment_for_buffer(&handle, cx)
10668 })?
10669 .await;
10670
10671 let ranges = match &target {
10672 LspFormatTarget::Buffers => None,
10673 LspFormatTarget::Ranges(ranges) => {
10674 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10675 }
10676 };
10677
10678 formattable_buffers.push(FormattableBuffer {
10679 handle,
10680 abs_path,
10681 env,
10682 ranges,
10683 });
10684 }
10685 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10686
10687 let format_timer = zlog::time!(logger => "Formatting buffers");
10688 let result = LocalLspStore::format_locally(
10689 lsp_store.clone(),
10690 formattable_buffers,
10691 push_to_history,
10692 trigger,
10693 logger,
10694 cx,
10695 )
10696 .await;
10697 format_timer.end();
10698
10699 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10700
10701 lsp_store.update(cx, |lsp_store, _| {
10702 lsp_store.update_last_formatting_failure(&result);
10703 })?;
10704
10705 result
10706 })
10707 } else if let Some((client, project_id)) = self.upstream_client() {
10708 zlog::trace!(logger => "Formatting remotely");
10709 let logger = zlog::scoped!(logger => "remote");
10710 // Don't support formatting ranges via remote
10711 match target {
10712 LspFormatTarget::Buffers => {}
10713 LspFormatTarget::Ranges(_) => {
10714 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10715 return Task::ready(Ok(ProjectTransaction::default()));
10716 }
10717 }
10718
10719 let buffer_store = self.buffer_store();
10720 cx.spawn(async move |lsp_store, cx| {
10721 zlog::trace!(logger => "Sending remote format request");
10722 let request_timer = zlog::time!(logger => "remote format request");
10723 let result = client
10724 .request(proto::FormatBuffers {
10725 project_id,
10726 trigger: trigger as i32,
10727 buffer_ids: buffers
10728 .iter()
10729 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10730 .collect(),
10731 })
10732 .await
10733 .and_then(|result| result.transaction.context("missing transaction"));
10734 request_timer.end();
10735
10736 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10737
10738 lsp_store.update(cx, |lsp_store, _| {
10739 lsp_store.update_last_formatting_failure(&result);
10740 })?;
10741
10742 let transaction_response = result?;
10743 let _timer = zlog::time!(logger => "deserializing project transaction");
10744 buffer_store
10745 .update(cx, |buffer_store, cx| {
10746 buffer_store.deserialize_project_transaction(
10747 transaction_response,
10748 push_to_history,
10749 cx,
10750 )
10751 })
10752 .await
10753 })
10754 } else {
10755 zlog::trace!(logger => "Not formatting");
10756 Task::ready(Ok(ProjectTransaction::default()))
10757 }
10758 }
10759
10760 async fn handle_format_buffers(
10761 this: Entity<Self>,
10762 envelope: TypedEnvelope<proto::FormatBuffers>,
10763 mut cx: AsyncApp,
10764 ) -> Result<proto::FormatBuffersResponse> {
10765 let sender_id = envelope.original_sender_id().unwrap_or_default();
10766 let format = this.update(&mut cx, |this, cx| {
10767 let mut buffers = HashSet::default();
10768 for buffer_id in &envelope.payload.buffer_ids {
10769 let buffer_id = BufferId::new(*buffer_id)?;
10770 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10771 }
10772 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10773 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10774 })?;
10775
10776 let project_transaction = format.await?;
10777 let project_transaction = this.update(&mut cx, |this, cx| {
10778 this.buffer_store.update(cx, |buffer_store, cx| {
10779 buffer_store.serialize_project_transaction_for_peer(
10780 project_transaction,
10781 sender_id,
10782 cx,
10783 )
10784 })
10785 });
10786 Ok(proto::FormatBuffersResponse {
10787 transaction: Some(project_transaction),
10788 })
10789 }
10790
10791 async fn handle_apply_code_action_kind(
10792 this: Entity<Self>,
10793 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10794 mut cx: AsyncApp,
10795 ) -> Result<proto::ApplyCodeActionKindResponse> {
10796 let sender_id = envelope.original_sender_id().unwrap_or_default();
10797 let format = this.update(&mut cx, |this, cx| {
10798 let mut buffers = HashSet::default();
10799 for buffer_id in &envelope.payload.buffer_ids {
10800 let buffer_id = BufferId::new(*buffer_id)?;
10801 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10802 }
10803 let kind = match envelope.payload.kind.as_str() {
10804 "" => CodeActionKind::EMPTY,
10805 "quickfix" => CodeActionKind::QUICKFIX,
10806 "refactor" => CodeActionKind::REFACTOR,
10807 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10808 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10809 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10810 "source" => CodeActionKind::SOURCE,
10811 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10812 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10813 _ => anyhow::bail!(
10814 "Invalid code action kind {}",
10815 envelope.payload.kind.as_str()
10816 ),
10817 };
10818 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10819 })?;
10820
10821 let project_transaction = format.await?;
10822 let project_transaction = this.update(&mut cx, |this, cx| {
10823 this.buffer_store.update(cx, |buffer_store, cx| {
10824 buffer_store.serialize_project_transaction_for_peer(
10825 project_transaction,
10826 sender_id,
10827 cx,
10828 )
10829 })
10830 });
10831 Ok(proto::ApplyCodeActionKindResponse {
10832 transaction: Some(project_transaction),
10833 })
10834 }
10835
10836 async fn shutdown_language_server(
10837 server_state: Option<LanguageServerState>,
10838 name: LanguageServerName,
10839 cx: &mut AsyncApp,
10840 ) {
10841 let server = match server_state {
10842 Some(LanguageServerState::Starting { startup, .. }) => {
10843 let mut timer = cx
10844 .background_executor()
10845 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10846 .fuse();
10847
10848 select! {
10849 server = startup.fuse() => server,
10850 () = timer => {
10851 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10852 None
10853 },
10854 }
10855 }
10856
10857 Some(LanguageServerState::Running { server, .. }) => Some(server),
10858
10859 None => None,
10860 };
10861
10862 if let Some(server) = server
10863 && let Some(shutdown) = server.shutdown()
10864 {
10865 shutdown.await;
10866 }
10867 }
10868
10869 // Returns a list of all of the worktrees which no longer have a language server and the root path
10870 // for the stopped server
10871 fn stop_local_language_server(
10872 &mut self,
10873 server_id: LanguageServerId,
10874 cx: &mut Context<Self>,
10875 ) -> Task<()> {
10876 let local = match &mut self.mode {
10877 LspStoreMode::Local(local) => local,
10878 _ => {
10879 return Task::ready(());
10880 }
10881 };
10882
10883 // Remove this server ID from all entries in the given worktree.
10884 local
10885 .language_server_ids
10886 .retain(|_, state| state.id != server_id);
10887 self.buffer_store.update(cx, |buffer_store, cx| {
10888 for buffer in buffer_store.buffers() {
10889 buffer.update(cx, |buffer, cx| {
10890 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10891 buffer.set_completion_triggers(server_id, Default::default(), cx);
10892 });
10893 }
10894 });
10895
10896 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10897 summaries.retain(|path, summaries_by_server_id| {
10898 if summaries_by_server_id.remove(&server_id).is_some() {
10899 if let Some((client, project_id)) = self.downstream_client.clone() {
10900 client
10901 .send(proto::UpdateDiagnosticSummary {
10902 project_id,
10903 worktree_id: worktree_id.to_proto(),
10904 summary: Some(proto::DiagnosticSummary {
10905 path: path.as_ref().to_proto(),
10906 language_server_id: server_id.0 as u64,
10907 error_count: 0,
10908 warning_count: 0,
10909 }),
10910 more_summaries: Vec::new(),
10911 })
10912 .log_err();
10913 }
10914 !summaries_by_server_id.is_empty()
10915 } else {
10916 true
10917 }
10918 });
10919 }
10920
10921 let local = self.as_local_mut().unwrap();
10922 for diagnostics in local.diagnostics.values_mut() {
10923 diagnostics.retain(|_, diagnostics_by_server_id| {
10924 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10925 diagnostics_by_server_id.remove(ix);
10926 !diagnostics_by_server_id.is_empty()
10927 } else {
10928 true
10929 }
10930 });
10931 }
10932 local.language_server_watched_paths.remove(&server_id);
10933
10934 let server_state = local.language_servers.remove(&server_id);
10935 self.cleanup_lsp_data(server_id);
10936 let name = self
10937 .language_server_statuses
10938 .remove(&server_id)
10939 .map(|status| status.name)
10940 .or_else(|| {
10941 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10942 Some(adapter.name())
10943 } else {
10944 None
10945 }
10946 });
10947
10948 if let Some(name) = name {
10949 log::info!("stopping language server {name}");
10950 self.languages
10951 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10952 cx.notify();
10953
10954 return cx.spawn(async move |lsp_store, cx| {
10955 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10956 lsp_store
10957 .update(cx, |lsp_store, cx| {
10958 lsp_store
10959 .languages
10960 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10961 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10962 cx.notify();
10963 })
10964 .ok();
10965 });
10966 }
10967
10968 if server_state.is_some() {
10969 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10970 }
10971 Task::ready(())
10972 }
10973
10974 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10975 if let Some((client, project_id)) = self.upstream_client() {
10976 let request = client.request(proto::StopLanguageServers {
10977 project_id,
10978 buffer_ids: Vec::new(),
10979 also_servers: Vec::new(),
10980 all: true,
10981 });
10982 cx.background_spawn(request).detach_and_log_err(cx);
10983 } else {
10984 let Some(local) = self.as_local_mut() else {
10985 return;
10986 };
10987 let language_servers_to_stop = local
10988 .language_server_ids
10989 .values()
10990 .map(|state| state.id)
10991 .collect();
10992 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10993 let tasks = language_servers_to_stop
10994 .into_iter()
10995 .map(|server| self.stop_local_language_server(server, cx))
10996 .collect::<Vec<_>>();
10997 cx.background_spawn(async move {
10998 futures::future::join_all(tasks).await;
10999 })
11000 .detach();
11001 }
11002 }
11003
11004 pub fn restart_language_servers_for_buffers(
11005 &mut self,
11006 buffers: Vec<Entity<Buffer>>,
11007 only_restart_servers: HashSet<LanguageServerSelector>,
11008 cx: &mut Context<Self>,
11009 ) {
11010 if let Some((client, project_id)) = self.upstream_client() {
11011 let request = client.request(proto::RestartLanguageServers {
11012 project_id,
11013 buffer_ids: buffers
11014 .into_iter()
11015 .map(|b| b.read(cx).remote_id().to_proto())
11016 .collect(),
11017 only_servers: only_restart_servers
11018 .into_iter()
11019 .map(|selector| {
11020 let selector = match selector {
11021 LanguageServerSelector::Id(language_server_id) => {
11022 proto::language_server_selector::Selector::ServerId(
11023 language_server_id.to_proto(),
11024 )
11025 }
11026 LanguageServerSelector::Name(language_server_name) => {
11027 proto::language_server_selector::Selector::Name(
11028 language_server_name.to_string(),
11029 )
11030 }
11031 };
11032 proto::LanguageServerSelector {
11033 selector: Some(selector),
11034 }
11035 })
11036 .collect(),
11037 all: false,
11038 });
11039 cx.background_spawn(request).detach_and_log_err(cx);
11040 } else {
11041 let stop_task = if only_restart_servers.is_empty() {
11042 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11043 } else {
11044 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11045 };
11046 cx.spawn(async move |lsp_store, cx| {
11047 stop_task.await;
11048 lsp_store.update(cx, |lsp_store, cx| {
11049 for buffer in buffers {
11050 lsp_store.register_buffer_with_language_servers(
11051 &buffer,
11052 only_restart_servers.clone(),
11053 true,
11054 cx,
11055 );
11056 }
11057 })
11058 })
11059 .detach();
11060 }
11061 }
11062
11063 pub fn stop_language_servers_for_buffers(
11064 &mut self,
11065 buffers: Vec<Entity<Buffer>>,
11066 also_stop_servers: HashSet<LanguageServerSelector>,
11067 cx: &mut Context<Self>,
11068 ) -> Task<Result<()>> {
11069 if let Some((client, project_id)) = self.upstream_client() {
11070 let request = client.request(proto::StopLanguageServers {
11071 project_id,
11072 buffer_ids: buffers
11073 .into_iter()
11074 .map(|b| b.read(cx).remote_id().to_proto())
11075 .collect(),
11076 also_servers: also_stop_servers
11077 .into_iter()
11078 .map(|selector| {
11079 let selector = match selector {
11080 LanguageServerSelector::Id(language_server_id) => {
11081 proto::language_server_selector::Selector::ServerId(
11082 language_server_id.to_proto(),
11083 )
11084 }
11085 LanguageServerSelector::Name(language_server_name) => {
11086 proto::language_server_selector::Selector::Name(
11087 language_server_name.to_string(),
11088 )
11089 }
11090 };
11091 proto::LanguageServerSelector {
11092 selector: Some(selector),
11093 }
11094 })
11095 .collect(),
11096 all: false,
11097 });
11098 cx.background_spawn(async move {
11099 let _ = request.await?;
11100 Ok(())
11101 })
11102 } else {
11103 let task =
11104 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11105 cx.background_spawn(async move {
11106 task.await;
11107 Ok(())
11108 })
11109 }
11110 }
11111
11112 fn stop_local_language_servers_for_buffers(
11113 &mut self,
11114 buffers: &[Entity<Buffer>],
11115 also_stop_servers: HashSet<LanguageServerSelector>,
11116 cx: &mut Context<Self>,
11117 ) -> Task<()> {
11118 let Some(local) = self.as_local_mut() else {
11119 return Task::ready(());
11120 };
11121 let mut language_server_names_to_stop = BTreeSet::default();
11122 let mut language_servers_to_stop = also_stop_servers
11123 .into_iter()
11124 .flat_map(|selector| match selector {
11125 LanguageServerSelector::Id(id) => Some(id),
11126 LanguageServerSelector::Name(name) => {
11127 language_server_names_to_stop.insert(name);
11128 None
11129 }
11130 })
11131 .collect::<BTreeSet<_>>();
11132
11133 let mut covered_worktrees = HashSet::default();
11134 for buffer in buffers {
11135 buffer.update(cx, |buffer, cx| {
11136 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11137 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11138 && covered_worktrees.insert(worktree_id)
11139 {
11140 language_server_names_to_stop.retain(|name| {
11141 let old_ids_count = language_servers_to_stop.len();
11142 let all_language_servers_with_this_name = local
11143 .language_server_ids
11144 .iter()
11145 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11146 language_servers_to_stop.extend(all_language_servers_with_this_name);
11147 old_ids_count == language_servers_to_stop.len()
11148 });
11149 }
11150 });
11151 }
11152 for name in language_server_names_to_stop {
11153 language_servers_to_stop.extend(
11154 local
11155 .language_server_ids
11156 .iter()
11157 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11158 );
11159 }
11160
11161 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11162 let tasks = language_servers_to_stop
11163 .into_iter()
11164 .map(|server| self.stop_local_language_server(server, cx))
11165 .collect::<Vec<_>>();
11166
11167 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11168 }
11169
11170 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11171 let (worktree, relative_path) =
11172 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11173
11174 let project_path = ProjectPath {
11175 worktree_id: worktree.read(cx).id(),
11176 path: relative_path,
11177 };
11178
11179 Some(
11180 self.buffer_store()
11181 .read(cx)
11182 .get_by_path(&project_path)?
11183 .read(cx),
11184 )
11185 }
11186
11187 #[cfg(any(test, feature = "test-support"))]
11188 pub fn update_diagnostics(
11189 &mut self,
11190 server_id: LanguageServerId,
11191 diagnostics: lsp::PublishDiagnosticsParams,
11192 result_id: Option<SharedString>,
11193 source_kind: DiagnosticSourceKind,
11194 disk_based_sources: &[String],
11195 cx: &mut Context<Self>,
11196 ) -> Result<()> {
11197 self.merge_lsp_diagnostics(
11198 source_kind,
11199 vec![DocumentDiagnosticsUpdate {
11200 diagnostics,
11201 result_id,
11202 server_id,
11203 disk_based_sources: Cow::Borrowed(disk_based_sources),
11204 registration_id: None,
11205 }],
11206 |_, _, _| false,
11207 cx,
11208 )
11209 }
11210
11211 pub fn merge_lsp_diagnostics(
11212 &mut self,
11213 source_kind: DiagnosticSourceKind,
11214 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11215 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11216 cx: &mut Context<Self>,
11217 ) -> Result<()> {
11218 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11219 let updates = lsp_diagnostics
11220 .into_iter()
11221 .filter_map(|update| {
11222 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11223 Some(DocumentDiagnosticsUpdate {
11224 diagnostics: self.lsp_to_document_diagnostics(
11225 abs_path,
11226 source_kind,
11227 update.server_id,
11228 update.diagnostics,
11229 &update.disk_based_sources,
11230 update.registration_id.clone(),
11231 ),
11232 result_id: update.result_id,
11233 server_id: update.server_id,
11234 disk_based_sources: update.disk_based_sources,
11235 registration_id: update.registration_id,
11236 })
11237 })
11238 .collect();
11239 self.merge_diagnostic_entries(updates, merge, cx)?;
11240 Ok(())
11241 }
11242
11243 fn lsp_to_document_diagnostics(
11244 &mut self,
11245 document_abs_path: PathBuf,
11246 source_kind: DiagnosticSourceKind,
11247 server_id: LanguageServerId,
11248 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11249 disk_based_sources: &[String],
11250 registration_id: Option<SharedString>,
11251 ) -> DocumentDiagnostics {
11252 let mut diagnostics = Vec::default();
11253 let mut primary_diagnostic_group_ids = HashMap::default();
11254 let mut sources_by_group_id = HashMap::default();
11255 let mut supporting_diagnostics = HashMap::default();
11256
11257 let adapter = self.language_server_adapter_for_id(server_id);
11258
11259 // Ensure that primary diagnostics are always the most severe
11260 lsp_diagnostics
11261 .diagnostics
11262 .sort_by_key(|item| item.severity);
11263
11264 for diagnostic in &lsp_diagnostics.diagnostics {
11265 let source = diagnostic.source.as_ref();
11266 let range = range_from_lsp(diagnostic.range);
11267 let is_supporting = diagnostic
11268 .related_information
11269 .as_ref()
11270 .is_some_and(|infos| {
11271 infos.iter().any(|info| {
11272 primary_diagnostic_group_ids.contains_key(&(
11273 source,
11274 diagnostic.code.clone(),
11275 range_from_lsp(info.location.range),
11276 ))
11277 })
11278 });
11279
11280 let is_unnecessary = diagnostic
11281 .tags
11282 .as_ref()
11283 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11284
11285 let underline = self
11286 .language_server_adapter_for_id(server_id)
11287 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11288
11289 if is_supporting {
11290 supporting_diagnostics.insert(
11291 (source, diagnostic.code.clone(), range),
11292 (diagnostic.severity, is_unnecessary),
11293 );
11294 } else {
11295 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11296 let is_disk_based =
11297 source.is_some_and(|source| disk_based_sources.contains(source));
11298
11299 sources_by_group_id.insert(group_id, source);
11300 primary_diagnostic_group_ids
11301 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11302
11303 diagnostics.push(DiagnosticEntry {
11304 range,
11305 diagnostic: Diagnostic {
11306 source: diagnostic.source.clone(),
11307 source_kind,
11308 code: diagnostic.code.clone(),
11309 code_description: diagnostic
11310 .code_description
11311 .as_ref()
11312 .and_then(|d| d.href.clone()),
11313 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11314 markdown: adapter.as_ref().and_then(|adapter| {
11315 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11316 }),
11317 message: diagnostic.message.trim().to_string(),
11318 group_id,
11319 is_primary: true,
11320 is_disk_based,
11321 is_unnecessary,
11322 underline,
11323 data: diagnostic.data.clone(),
11324 registration_id: registration_id.clone(),
11325 },
11326 });
11327 if let Some(infos) = &diagnostic.related_information {
11328 for info in infos {
11329 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11330 let range = range_from_lsp(info.location.range);
11331 diagnostics.push(DiagnosticEntry {
11332 range,
11333 diagnostic: Diagnostic {
11334 source: diagnostic.source.clone(),
11335 source_kind,
11336 code: diagnostic.code.clone(),
11337 code_description: diagnostic
11338 .code_description
11339 .as_ref()
11340 .and_then(|d| d.href.clone()),
11341 severity: DiagnosticSeverity::INFORMATION,
11342 markdown: adapter.as_ref().and_then(|adapter| {
11343 adapter.diagnostic_message_to_markdown(&info.message)
11344 }),
11345 message: info.message.trim().to_string(),
11346 group_id,
11347 is_primary: false,
11348 is_disk_based,
11349 is_unnecessary: false,
11350 underline,
11351 data: diagnostic.data.clone(),
11352 registration_id: registration_id.clone(),
11353 },
11354 });
11355 }
11356 }
11357 }
11358 }
11359 }
11360
11361 for entry in &mut diagnostics {
11362 let diagnostic = &mut entry.diagnostic;
11363 if !diagnostic.is_primary {
11364 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11365 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11366 source,
11367 diagnostic.code.clone(),
11368 entry.range.clone(),
11369 )) {
11370 if let Some(severity) = severity {
11371 diagnostic.severity = severity;
11372 }
11373 diagnostic.is_unnecessary = is_unnecessary;
11374 }
11375 }
11376 }
11377
11378 DocumentDiagnostics {
11379 diagnostics,
11380 document_abs_path,
11381 version: lsp_diagnostics.version,
11382 }
11383 }
11384
11385 fn insert_newly_running_language_server(
11386 &mut self,
11387 adapter: Arc<CachedLspAdapter>,
11388 language_server: Arc<LanguageServer>,
11389 server_id: LanguageServerId,
11390 key: LanguageServerSeed,
11391 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11392 cx: &mut Context<Self>,
11393 ) {
11394 let Some(local) = self.as_local_mut() else {
11395 return;
11396 };
11397 // If the language server for this key doesn't match the server id, don't store the
11398 // server. Which will cause it to be dropped, killing the process
11399 if local
11400 .language_server_ids
11401 .get(&key)
11402 .map(|state| state.id != server_id)
11403 .unwrap_or(false)
11404 {
11405 return;
11406 }
11407
11408 // Update language_servers collection with Running variant of LanguageServerState
11409 // indicating that the server is up and running and ready
11410 let workspace_folders = workspace_folders.lock().clone();
11411 language_server.set_workspace_folders(workspace_folders);
11412
11413 let workspace_diagnostics_refresh_tasks = language_server
11414 .capabilities()
11415 .diagnostic_provider
11416 .and_then(|provider| {
11417 local
11418 .language_server_dynamic_registrations
11419 .entry(server_id)
11420 .or_default()
11421 .diagnostics
11422 .entry(None)
11423 .or_insert(provider.clone());
11424 let workspace_refresher =
11425 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11426
11427 Some((None, workspace_refresher))
11428 })
11429 .into_iter()
11430 .collect();
11431 local.language_servers.insert(
11432 server_id,
11433 LanguageServerState::Running {
11434 workspace_diagnostics_refresh_tasks,
11435 adapter: adapter.clone(),
11436 server: language_server.clone(),
11437 simulate_disk_based_diagnostics_completion: None,
11438 },
11439 );
11440 local
11441 .languages
11442 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11443 if let Some(file_ops_caps) = language_server
11444 .capabilities()
11445 .workspace
11446 .as_ref()
11447 .and_then(|ws| ws.file_operations.as_ref())
11448 {
11449 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11450 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11451 if did_rename_caps.or(will_rename_caps).is_some() {
11452 let watcher = RenamePathsWatchedForServer::default()
11453 .with_did_rename_patterns(did_rename_caps)
11454 .with_will_rename_patterns(will_rename_caps);
11455 local
11456 .language_server_paths_watched_for_rename
11457 .insert(server_id, watcher);
11458 }
11459 }
11460
11461 self.language_server_statuses.insert(
11462 server_id,
11463 LanguageServerStatus {
11464 name: language_server.name(),
11465 server_version: language_server.version(),
11466 pending_work: Default::default(),
11467 has_pending_diagnostic_updates: false,
11468 progress_tokens: Default::default(),
11469 worktree: Some(key.worktree_id),
11470 binary: Some(language_server.binary().clone()),
11471 configuration: Some(language_server.configuration().clone()),
11472 workspace_folders: language_server.workspace_folders(),
11473 },
11474 );
11475
11476 cx.emit(LspStoreEvent::LanguageServerAdded(
11477 server_id,
11478 language_server.name(),
11479 Some(key.worktree_id),
11480 ));
11481
11482 let server_capabilities = language_server.capabilities();
11483 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11484 downstream_client
11485 .send(proto::StartLanguageServer {
11486 project_id: *project_id,
11487 server: Some(proto::LanguageServer {
11488 id: server_id.to_proto(),
11489 name: language_server.name().to_string(),
11490 worktree_id: Some(key.worktree_id.to_proto()),
11491 }),
11492 capabilities: serde_json::to_string(&server_capabilities)
11493 .expect("serializing server LSP capabilities"),
11494 })
11495 .log_err();
11496 }
11497 self.lsp_server_capabilities
11498 .insert(server_id, server_capabilities);
11499
11500 // Tell the language server about every open buffer in the worktree that matches the language.
11501 // Also check for buffers in worktrees that reused this server
11502 let mut worktrees_using_server = vec![key.worktree_id];
11503 if let Some(local) = self.as_local() {
11504 // Find all worktrees that have this server in their language server tree
11505 for (worktree_id, servers) in &local.lsp_tree.instances {
11506 if *worktree_id != key.worktree_id {
11507 for server_map in servers.roots.values() {
11508 if server_map
11509 .values()
11510 .any(|(node, _)| node.id() == Some(server_id))
11511 {
11512 worktrees_using_server.push(*worktree_id);
11513 }
11514 }
11515 }
11516 }
11517 }
11518
11519 let mut buffer_paths_registered = Vec::new();
11520 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11521 let mut lsp_adapters = HashMap::default();
11522 for buffer_handle in buffer_store.buffers() {
11523 let buffer = buffer_handle.read(cx);
11524 let file = match File::from_dyn(buffer.file()) {
11525 Some(file) => file,
11526 None => continue,
11527 };
11528 let language = match buffer.language() {
11529 Some(language) => language,
11530 None => continue,
11531 };
11532
11533 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11534 || !lsp_adapters
11535 .entry(language.name())
11536 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11537 .iter()
11538 .any(|a| a.name == key.name)
11539 {
11540 continue;
11541 }
11542 // didOpen
11543 let file = match file.as_local() {
11544 Some(file) => file,
11545 None => continue,
11546 };
11547
11548 let local = self.as_local_mut().unwrap();
11549
11550 let buffer_id = buffer.remote_id();
11551 if local.registered_buffers.contains_key(&buffer_id) {
11552 let versions = local
11553 .buffer_snapshots
11554 .entry(buffer_id)
11555 .or_default()
11556 .entry(server_id)
11557 .and_modify(|_| {
11558 assert!(
11559 false,
11560 "There should not be an existing snapshot for a newly inserted buffer"
11561 )
11562 })
11563 .or_insert_with(|| {
11564 vec![LspBufferSnapshot {
11565 version: 0,
11566 snapshot: buffer.text_snapshot(),
11567 }]
11568 });
11569
11570 let snapshot = versions.last().unwrap();
11571 let version = snapshot.version;
11572 let initial_snapshot = &snapshot.snapshot;
11573 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11574 language_server.register_buffer(
11575 uri,
11576 adapter.language_id(&language.name()),
11577 version,
11578 initial_snapshot.text(),
11579 );
11580 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11581 local
11582 .buffers_opened_in_servers
11583 .entry(buffer_id)
11584 .or_default()
11585 .insert(server_id);
11586 }
11587 buffer_handle.update(cx, |buffer, cx| {
11588 buffer.set_completion_triggers(
11589 server_id,
11590 language_server
11591 .capabilities()
11592 .completion_provider
11593 .as_ref()
11594 .and_then(|provider| {
11595 provider
11596 .trigger_characters
11597 .as_ref()
11598 .map(|characters| characters.iter().cloned().collect())
11599 })
11600 .unwrap_or_default(),
11601 cx,
11602 )
11603 });
11604 }
11605 });
11606
11607 for (buffer_id, abs_path) in buffer_paths_registered {
11608 cx.emit(LspStoreEvent::LanguageServerUpdate {
11609 language_server_id: server_id,
11610 name: Some(adapter.name()),
11611 message: proto::update_language_server::Variant::RegisteredForBuffer(
11612 proto::RegisteredForBuffer {
11613 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11614 buffer_id: buffer_id.to_proto(),
11615 },
11616 ),
11617 });
11618 }
11619
11620 cx.notify();
11621 }
11622
11623 pub fn language_servers_running_disk_based_diagnostics(
11624 &self,
11625 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11626 self.language_server_statuses
11627 .iter()
11628 .filter_map(|(id, status)| {
11629 if status.has_pending_diagnostic_updates {
11630 Some(*id)
11631 } else {
11632 None
11633 }
11634 })
11635 }
11636
11637 pub(crate) fn cancel_language_server_work_for_buffers(
11638 &mut self,
11639 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11640 cx: &mut Context<Self>,
11641 ) {
11642 if let Some((client, project_id)) = self.upstream_client() {
11643 let request = client.request(proto::CancelLanguageServerWork {
11644 project_id,
11645 work: Some(proto::cancel_language_server_work::Work::Buffers(
11646 proto::cancel_language_server_work::Buffers {
11647 buffer_ids: buffers
11648 .into_iter()
11649 .map(|b| b.read(cx).remote_id().to_proto())
11650 .collect(),
11651 },
11652 )),
11653 });
11654 cx.background_spawn(request).detach_and_log_err(cx);
11655 } else if let Some(local) = self.as_local() {
11656 let servers = buffers
11657 .into_iter()
11658 .flat_map(|buffer| {
11659 buffer.update(cx, |buffer, cx| {
11660 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11661 })
11662 })
11663 .collect::<HashSet<_>>();
11664 for server_id in servers {
11665 self.cancel_language_server_work(server_id, None, cx);
11666 }
11667 }
11668 }
11669
11670 pub(crate) fn cancel_language_server_work(
11671 &mut self,
11672 server_id: LanguageServerId,
11673 token_to_cancel: Option<ProgressToken>,
11674 cx: &mut Context<Self>,
11675 ) {
11676 if let Some(local) = self.as_local() {
11677 let status = self.language_server_statuses.get(&server_id);
11678 let server = local.language_servers.get(&server_id);
11679 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11680 {
11681 for (token, progress) in &status.pending_work {
11682 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11683 && token != token_to_cancel
11684 {
11685 continue;
11686 }
11687 if progress.is_cancellable {
11688 server
11689 .notify::<lsp::notification::WorkDoneProgressCancel>(
11690 WorkDoneProgressCancelParams {
11691 token: token.to_lsp(),
11692 },
11693 )
11694 .ok();
11695 }
11696 }
11697 }
11698 } else if let Some((client, project_id)) = self.upstream_client() {
11699 let request = client.request(proto::CancelLanguageServerWork {
11700 project_id,
11701 work: Some(
11702 proto::cancel_language_server_work::Work::LanguageServerWork(
11703 proto::cancel_language_server_work::LanguageServerWork {
11704 language_server_id: server_id.to_proto(),
11705 token: token_to_cancel.map(|token| token.to_proto()),
11706 },
11707 ),
11708 ),
11709 });
11710 cx.background_spawn(request).detach_and_log_err(cx);
11711 }
11712 }
11713
11714 fn register_supplementary_language_server(
11715 &mut self,
11716 id: LanguageServerId,
11717 name: LanguageServerName,
11718 server: Arc<LanguageServer>,
11719 cx: &mut Context<Self>,
11720 ) {
11721 if let Some(local) = self.as_local_mut() {
11722 local
11723 .supplementary_language_servers
11724 .insert(id, (name.clone(), server));
11725 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11726 }
11727 }
11728
11729 fn unregister_supplementary_language_server(
11730 &mut self,
11731 id: LanguageServerId,
11732 cx: &mut Context<Self>,
11733 ) {
11734 if let Some(local) = self.as_local_mut() {
11735 local.supplementary_language_servers.remove(&id);
11736 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11737 }
11738 }
11739
11740 pub(crate) fn supplementary_language_servers(
11741 &self,
11742 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11743 self.as_local().into_iter().flat_map(|local| {
11744 local
11745 .supplementary_language_servers
11746 .iter()
11747 .map(|(id, (name, _))| (*id, name.clone()))
11748 })
11749 }
11750
11751 pub fn language_server_adapter_for_id(
11752 &self,
11753 id: LanguageServerId,
11754 ) -> Option<Arc<CachedLspAdapter>> {
11755 self.as_local()
11756 .and_then(|local| local.language_servers.get(&id))
11757 .and_then(|language_server_state| match language_server_state {
11758 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11759 _ => None,
11760 })
11761 }
11762
11763 pub(super) fn update_local_worktree_language_servers(
11764 &mut self,
11765 worktree_handle: &Entity<Worktree>,
11766 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11767 cx: &mut Context<Self>,
11768 ) {
11769 if changes.is_empty() {
11770 return;
11771 }
11772
11773 let Some(local) = self.as_local() else { return };
11774
11775 local.prettier_store.update(cx, |prettier_store, cx| {
11776 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11777 });
11778
11779 let worktree_id = worktree_handle.read(cx).id();
11780 let mut language_server_ids = local
11781 .language_server_ids
11782 .iter()
11783 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11784 .collect::<Vec<_>>();
11785 language_server_ids.sort();
11786 language_server_ids.dedup();
11787
11788 // let abs_path = worktree_handle.read(cx).abs_path();
11789 for server_id in &language_server_ids {
11790 if let Some(LanguageServerState::Running { server, .. }) =
11791 local.language_servers.get(server_id)
11792 && let Some(watched_paths) = local
11793 .language_server_watched_paths
11794 .get(server_id)
11795 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11796 {
11797 let params = lsp::DidChangeWatchedFilesParams {
11798 changes: changes
11799 .iter()
11800 .filter_map(|(path, _, change)| {
11801 if !watched_paths.is_match(path.as_std_path()) {
11802 return None;
11803 }
11804 let typ = match change {
11805 PathChange::Loaded => return None,
11806 PathChange::Added => lsp::FileChangeType::CREATED,
11807 PathChange::Removed => lsp::FileChangeType::DELETED,
11808 PathChange::Updated => lsp::FileChangeType::CHANGED,
11809 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11810 };
11811 let uri = lsp::Uri::from_file_path(
11812 worktree_handle.read(cx).absolutize(&path),
11813 )
11814 .ok()?;
11815 Some(lsp::FileEvent { uri, typ })
11816 })
11817 .collect(),
11818 };
11819 if !params.changes.is_empty() {
11820 server
11821 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11822 .ok();
11823 }
11824 }
11825 }
11826 for (path, _, _) in changes {
11827 if let Some(file_name) = path.file_name()
11828 && local.watched_manifest_filenames.contains(file_name)
11829 {
11830 self.request_workspace_config_refresh();
11831 break;
11832 }
11833 }
11834 }
11835
11836 pub fn wait_for_remote_buffer(
11837 &mut self,
11838 id: BufferId,
11839 cx: &mut Context<Self>,
11840 ) -> Task<Result<Entity<Buffer>>> {
11841 self.buffer_store.update(cx, |buffer_store, cx| {
11842 buffer_store.wait_for_remote_buffer(id, cx)
11843 })
11844 }
11845
11846 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11847 let mut result = proto::Symbol {
11848 language_server_name: symbol.language_server_name.0.to_string(),
11849 source_worktree_id: symbol.source_worktree_id.to_proto(),
11850 language_server_id: symbol.source_language_server_id.to_proto(),
11851 name: symbol.name.clone(),
11852 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11853 start: Some(proto::PointUtf16 {
11854 row: symbol.range.start.0.row,
11855 column: symbol.range.start.0.column,
11856 }),
11857 end: Some(proto::PointUtf16 {
11858 row: symbol.range.end.0.row,
11859 column: symbol.range.end.0.column,
11860 }),
11861 worktree_id: Default::default(),
11862 path: Default::default(),
11863 signature: Default::default(),
11864 };
11865 match &symbol.path {
11866 SymbolLocation::InProject(path) => {
11867 result.worktree_id = path.worktree_id.to_proto();
11868 result.path = path.path.to_proto();
11869 }
11870 SymbolLocation::OutsideProject {
11871 abs_path,
11872 signature,
11873 } => {
11874 result.path = abs_path.to_string_lossy().into_owned();
11875 result.signature = signature.to_vec();
11876 }
11877 }
11878 result
11879 }
11880
11881 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11882 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11883 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11884 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11885
11886 let path = if serialized_symbol.signature.is_empty() {
11887 SymbolLocation::InProject(ProjectPath {
11888 worktree_id,
11889 path: RelPath::from_proto(&serialized_symbol.path)
11890 .context("invalid symbol path")?,
11891 })
11892 } else {
11893 SymbolLocation::OutsideProject {
11894 abs_path: Path::new(&serialized_symbol.path).into(),
11895 signature: serialized_symbol
11896 .signature
11897 .try_into()
11898 .map_err(|_| anyhow!("invalid signature"))?,
11899 }
11900 };
11901
11902 let start = serialized_symbol.start.context("invalid start")?;
11903 let end = serialized_symbol.end.context("invalid end")?;
11904 Ok(CoreSymbol {
11905 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11906 source_worktree_id,
11907 source_language_server_id: LanguageServerId::from_proto(
11908 serialized_symbol.language_server_id,
11909 ),
11910 path,
11911 name: serialized_symbol.name,
11912 range: Unclipped(PointUtf16::new(start.row, start.column))
11913 ..Unclipped(PointUtf16::new(end.row, end.column)),
11914 kind,
11915 })
11916 }
11917
11918 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11919 let mut serialized_completion = proto::Completion {
11920 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11921 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11922 new_text: completion.new_text.clone(),
11923 ..proto::Completion::default()
11924 };
11925 match &completion.source {
11926 CompletionSource::Lsp {
11927 insert_range,
11928 server_id,
11929 lsp_completion,
11930 lsp_defaults,
11931 resolved,
11932 } => {
11933 let (old_insert_start, old_insert_end) = insert_range
11934 .as_ref()
11935 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11936 .unzip();
11937
11938 serialized_completion.old_insert_start = old_insert_start;
11939 serialized_completion.old_insert_end = old_insert_end;
11940 serialized_completion.source = proto::completion::Source::Lsp as i32;
11941 serialized_completion.server_id = server_id.0 as u64;
11942 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11943 serialized_completion.lsp_defaults = lsp_defaults
11944 .as_deref()
11945 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11946 serialized_completion.resolved = *resolved;
11947 }
11948 CompletionSource::BufferWord {
11949 word_range,
11950 resolved,
11951 } => {
11952 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11953 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11954 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11955 serialized_completion.resolved = *resolved;
11956 }
11957 CompletionSource::Custom => {
11958 serialized_completion.source = proto::completion::Source::Custom as i32;
11959 serialized_completion.resolved = true;
11960 }
11961 CompletionSource::Dap { sort_text } => {
11962 serialized_completion.source = proto::completion::Source::Dap as i32;
11963 serialized_completion.sort_text = Some(sort_text.clone());
11964 }
11965 }
11966
11967 serialized_completion
11968 }
11969
11970 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11971 let old_replace_start = completion
11972 .old_replace_start
11973 .and_then(deserialize_anchor)
11974 .context("invalid old start")?;
11975 let old_replace_end = completion
11976 .old_replace_end
11977 .and_then(deserialize_anchor)
11978 .context("invalid old end")?;
11979 let insert_range = {
11980 match completion.old_insert_start.zip(completion.old_insert_end) {
11981 Some((start, end)) => {
11982 let start = deserialize_anchor(start).context("invalid insert old start")?;
11983 let end = deserialize_anchor(end).context("invalid insert old end")?;
11984 Some(start..end)
11985 }
11986 None => None,
11987 }
11988 };
11989 Ok(CoreCompletion {
11990 replace_range: old_replace_start..old_replace_end,
11991 new_text: completion.new_text,
11992 source: match proto::completion::Source::from_i32(completion.source) {
11993 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11994 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11995 insert_range,
11996 server_id: LanguageServerId::from_proto(completion.server_id),
11997 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11998 lsp_defaults: completion
11999 .lsp_defaults
12000 .as_deref()
12001 .map(serde_json::from_slice)
12002 .transpose()?,
12003 resolved: completion.resolved,
12004 },
12005 Some(proto::completion::Source::BufferWord) => {
12006 let word_range = completion
12007 .buffer_word_start
12008 .and_then(deserialize_anchor)
12009 .context("invalid buffer word start")?
12010 ..completion
12011 .buffer_word_end
12012 .and_then(deserialize_anchor)
12013 .context("invalid buffer word end")?;
12014 CompletionSource::BufferWord {
12015 word_range,
12016 resolved: completion.resolved,
12017 }
12018 }
12019 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12020 sort_text: completion
12021 .sort_text
12022 .context("expected sort text to exist")?,
12023 },
12024 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12025 },
12026 })
12027 }
12028
12029 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12030 let (kind, lsp_action) = match &action.lsp_action {
12031 LspAction::Action(code_action) => (
12032 proto::code_action::Kind::Action as i32,
12033 serde_json::to_vec(code_action).unwrap(),
12034 ),
12035 LspAction::Command(command) => (
12036 proto::code_action::Kind::Command as i32,
12037 serde_json::to_vec(command).unwrap(),
12038 ),
12039 LspAction::CodeLens(code_lens) => (
12040 proto::code_action::Kind::CodeLens as i32,
12041 serde_json::to_vec(code_lens).unwrap(),
12042 ),
12043 };
12044
12045 proto::CodeAction {
12046 server_id: action.server_id.0 as u64,
12047 start: Some(serialize_anchor(&action.range.start)),
12048 end: Some(serialize_anchor(&action.range.end)),
12049 lsp_action,
12050 kind,
12051 resolved: action.resolved,
12052 }
12053 }
12054
12055 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12056 let start = action
12057 .start
12058 .and_then(deserialize_anchor)
12059 .context("invalid start")?;
12060 let end = action
12061 .end
12062 .and_then(deserialize_anchor)
12063 .context("invalid end")?;
12064 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12065 Some(proto::code_action::Kind::Action) => {
12066 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12067 }
12068 Some(proto::code_action::Kind::Command) => {
12069 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12070 }
12071 Some(proto::code_action::Kind::CodeLens) => {
12072 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12073 }
12074 None => anyhow::bail!("Unknown action kind {}", action.kind),
12075 };
12076 Ok(CodeAction {
12077 server_id: LanguageServerId(action.server_id as usize),
12078 range: start..end,
12079 resolved: action.resolved,
12080 lsp_action,
12081 })
12082 }
12083
12084 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12085 match &formatting_result {
12086 Ok(_) => self.last_formatting_failure = None,
12087 Err(error) => {
12088 let error_string = format!("{error:#}");
12089 log::error!("Formatting failed: {error_string}");
12090 self.last_formatting_failure
12091 .replace(error_string.lines().join(" "));
12092 }
12093 }
12094 }
12095
12096 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12097 self.lsp_server_capabilities.remove(&for_server);
12098 for lsp_data in self.lsp_data.values_mut() {
12099 lsp_data.remove_server_data(for_server);
12100 }
12101 if let Some(local) = self.as_local_mut() {
12102 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12103 local
12104 .workspace_pull_diagnostics_result_ids
12105 .remove(&for_server);
12106 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12107 buffer_servers.remove(&for_server);
12108 }
12109 }
12110 }
12111
12112 pub fn result_id_for_buffer_pull(
12113 &self,
12114 server_id: LanguageServerId,
12115 buffer_id: BufferId,
12116 registration_id: &Option<SharedString>,
12117 cx: &App,
12118 ) -> Option<SharedString> {
12119 let abs_path = self
12120 .buffer_store
12121 .read(cx)
12122 .get(buffer_id)
12123 .and_then(|b| File::from_dyn(b.read(cx).file()))
12124 .map(|f| f.abs_path(cx))?;
12125 self.as_local()?
12126 .buffer_pull_diagnostics_result_ids
12127 .get(&server_id)?
12128 .get(registration_id)?
12129 .get(&abs_path)?
12130 .clone()
12131 }
12132
12133 /// Gets all result_ids for a workspace diagnostics pull request.
12134 /// 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.
12135 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12136 pub fn result_ids_for_workspace_refresh(
12137 &self,
12138 server_id: LanguageServerId,
12139 registration_id: &Option<SharedString>,
12140 ) -> HashMap<PathBuf, SharedString> {
12141 let Some(local) = self.as_local() else {
12142 return HashMap::default();
12143 };
12144 local
12145 .workspace_pull_diagnostics_result_ids
12146 .get(&server_id)
12147 .into_iter()
12148 .filter_map(|diagnostics| diagnostics.get(registration_id))
12149 .flatten()
12150 .filter_map(|(abs_path, result_id)| {
12151 let result_id = local
12152 .buffer_pull_diagnostics_result_ids
12153 .get(&server_id)
12154 .and_then(|buffer_ids_result_ids| {
12155 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12156 })
12157 .cloned()
12158 .flatten()
12159 .or_else(|| result_id.clone())?;
12160 Some((abs_path.clone(), result_id))
12161 })
12162 .collect()
12163 }
12164
12165 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12166 if let Some(LanguageServerState::Running {
12167 workspace_diagnostics_refresh_tasks,
12168 ..
12169 }) = self
12170 .as_local_mut()
12171 .and_then(|local| local.language_servers.get_mut(&server_id))
12172 {
12173 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12174 diagnostics.refresh_tx.try_send(()).ok();
12175 }
12176 }
12177 }
12178
12179 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12180 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12181 /// which requires refreshing both workspace and document diagnostics.
12182 pub fn pull_document_diagnostics_for_server(
12183 &mut self,
12184 server_id: LanguageServerId,
12185 cx: &mut Context<Self>,
12186 ) -> Task<()> {
12187 let buffers_to_pull = self
12188 .as_local()
12189 .into_iter()
12190 .flat_map(|local| {
12191 self.buffer_store.read(cx).buffers().filter(|buffer| {
12192 let buffer_id = buffer.read(cx).remote_id();
12193 local
12194 .buffers_opened_in_servers
12195 .get(&buffer_id)
12196 .is_some_and(|servers| servers.contains(&server_id))
12197 })
12198 })
12199 .collect::<Vec<_>>();
12200
12201 let pulls = join_all(buffers_to_pull.into_iter().map(|buffer| {
12202 let buffer_path = buffer.read(cx).file().map(|f| f.full_path(cx));
12203 let pull_task = self.pull_diagnostics_for_buffer(buffer, cx);
12204 async move { (buffer_path, pull_task.await) }
12205 }));
12206 cx.background_spawn(async move {
12207 for (pull_task_path, pull_task_result) in pulls.await {
12208 if let Err(e) = pull_task_result {
12209 match pull_task_path {
12210 Some(path) => {
12211 log::error!("Failed to pull diagnostics for buffer {path:?}: {e:#}");
12212 }
12213 None => log::error!("Failed to pull diagnostics: {e:#}"),
12214 }
12215 }
12216 }
12217 })
12218 }
12219
12220 fn apply_workspace_diagnostic_report(
12221 &mut self,
12222 server_id: LanguageServerId,
12223 report: lsp::WorkspaceDiagnosticReportResult,
12224 registration_id: Option<SharedString>,
12225 cx: &mut Context<Self>,
12226 ) {
12227 let mut workspace_diagnostics =
12228 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12229 report,
12230 server_id,
12231 registration_id,
12232 );
12233 workspace_diagnostics.retain(|d| match &d.diagnostics {
12234 LspPullDiagnostics::Response {
12235 server_id,
12236 registration_id,
12237 ..
12238 } => self.diagnostic_registration_exists(*server_id, registration_id),
12239 LspPullDiagnostics::Default => false,
12240 });
12241 let mut unchanged_buffers = HashMap::default();
12242 let workspace_diagnostics_updates = workspace_diagnostics
12243 .into_iter()
12244 .filter_map(
12245 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12246 LspPullDiagnostics::Response {
12247 server_id,
12248 uri,
12249 diagnostics,
12250 registration_id,
12251 } => Some((
12252 server_id,
12253 uri,
12254 diagnostics,
12255 workspace_diagnostics.version,
12256 registration_id,
12257 )),
12258 LspPullDiagnostics::Default => None,
12259 },
12260 )
12261 .fold(
12262 HashMap::default(),
12263 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12264 let (result_id, diagnostics) = match diagnostics {
12265 PulledDiagnostics::Unchanged { result_id } => {
12266 unchanged_buffers
12267 .entry(new_registration_id.clone())
12268 .or_insert_with(HashSet::default)
12269 .insert(uri.clone());
12270 (Some(result_id), Vec::new())
12271 }
12272 PulledDiagnostics::Changed {
12273 result_id,
12274 diagnostics,
12275 } => (result_id, diagnostics),
12276 };
12277 let disk_based_sources = Cow::Owned(
12278 self.language_server_adapter_for_id(server_id)
12279 .as_ref()
12280 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12281 .unwrap_or(&[])
12282 .to_vec(),
12283 );
12284
12285 let Some(abs_path) = uri.to_file_path().ok() else {
12286 return acc;
12287 };
12288 let Some((worktree, relative_path)) =
12289 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12290 else {
12291 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12292 return acc;
12293 };
12294 let worktree_id = worktree.read(cx).id();
12295 let project_path = ProjectPath {
12296 worktree_id,
12297 path: relative_path,
12298 };
12299 if let Some(local_lsp_store) = self.as_local_mut() {
12300 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12301 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12302 }
12303 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12304 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12305 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12306 acc.entry(server_id)
12307 .or_insert_with(HashMap::default)
12308 .entry(new_registration_id.clone())
12309 .or_insert_with(Vec::new)
12310 .push(DocumentDiagnosticsUpdate {
12311 server_id,
12312 diagnostics: lsp::PublishDiagnosticsParams {
12313 uri,
12314 diagnostics,
12315 version,
12316 },
12317 result_id,
12318 disk_based_sources,
12319 registration_id: new_registration_id,
12320 });
12321 }
12322 acc
12323 },
12324 );
12325
12326 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12327 for (registration_id, diagnostic_updates) in diagnostic_updates {
12328 self.merge_lsp_diagnostics(
12329 DiagnosticSourceKind::Pulled,
12330 diagnostic_updates,
12331 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12332 DiagnosticSourceKind::Pulled => {
12333 old_diagnostic.registration_id != registration_id
12334 || unchanged_buffers
12335 .get(&old_diagnostic.registration_id)
12336 .is_some_and(|unchanged_buffers| {
12337 unchanged_buffers.contains(&document_uri)
12338 })
12339 }
12340 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12341 },
12342 cx,
12343 )
12344 .log_err();
12345 }
12346 }
12347 }
12348
12349 fn register_server_capabilities(
12350 &mut self,
12351 server_id: LanguageServerId,
12352 params: lsp::RegistrationParams,
12353 cx: &mut Context<Self>,
12354 ) -> anyhow::Result<()> {
12355 let server = self
12356 .language_server_for_id(server_id)
12357 .with_context(|| format!("no server {server_id} found"))?;
12358 for reg in params.registrations {
12359 match reg.method.as_str() {
12360 "workspace/didChangeWatchedFiles" => {
12361 if let Some(options) = reg.register_options {
12362 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12363 let caps = serde_json::from_value(options)?;
12364 local_lsp_store
12365 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12366 true
12367 } else {
12368 false
12369 };
12370 if notify {
12371 notify_server_capabilities_updated(&server, cx);
12372 }
12373 }
12374 }
12375 "workspace/didChangeConfiguration" => {
12376 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12377 }
12378 "workspace/didChangeWorkspaceFolders" => {
12379 // In this case register options is an empty object, we can ignore it
12380 let caps = lsp::WorkspaceFoldersServerCapabilities {
12381 supported: Some(true),
12382 change_notifications: Some(OneOf::Right(reg.id)),
12383 };
12384 server.update_capabilities(|capabilities| {
12385 capabilities
12386 .workspace
12387 .get_or_insert_default()
12388 .workspace_folders = Some(caps);
12389 });
12390 notify_server_capabilities_updated(&server, cx);
12391 }
12392 "workspace/symbol" => {
12393 let options = parse_register_capabilities(reg)?;
12394 server.update_capabilities(|capabilities| {
12395 capabilities.workspace_symbol_provider = Some(options);
12396 });
12397 notify_server_capabilities_updated(&server, cx);
12398 }
12399 "workspace/fileOperations" => {
12400 if let Some(options) = reg.register_options {
12401 let caps = serde_json::from_value(options)?;
12402 server.update_capabilities(|capabilities| {
12403 capabilities
12404 .workspace
12405 .get_or_insert_default()
12406 .file_operations = Some(caps);
12407 });
12408 notify_server_capabilities_updated(&server, cx);
12409 }
12410 }
12411 "workspace/executeCommand" => {
12412 if let Some(options) = reg.register_options {
12413 let options = serde_json::from_value(options)?;
12414 server.update_capabilities(|capabilities| {
12415 capabilities.execute_command_provider = Some(options);
12416 });
12417 notify_server_capabilities_updated(&server, cx);
12418 }
12419 }
12420 "textDocument/rangeFormatting" => {
12421 let options = parse_register_capabilities(reg)?;
12422 server.update_capabilities(|capabilities| {
12423 capabilities.document_range_formatting_provider = Some(options);
12424 });
12425 notify_server_capabilities_updated(&server, cx);
12426 }
12427 "textDocument/onTypeFormatting" => {
12428 if let Some(options) = reg
12429 .register_options
12430 .map(serde_json::from_value)
12431 .transpose()?
12432 {
12433 server.update_capabilities(|capabilities| {
12434 capabilities.document_on_type_formatting_provider = Some(options);
12435 });
12436 notify_server_capabilities_updated(&server, cx);
12437 }
12438 }
12439 "textDocument/formatting" => {
12440 let options = parse_register_capabilities(reg)?;
12441 server.update_capabilities(|capabilities| {
12442 capabilities.document_formatting_provider = Some(options);
12443 });
12444 notify_server_capabilities_updated(&server, cx);
12445 }
12446 "textDocument/rename" => {
12447 let options = parse_register_capabilities(reg)?;
12448 server.update_capabilities(|capabilities| {
12449 capabilities.rename_provider = Some(options);
12450 });
12451 notify_server_capabilities_updated(&server, cx);
12452 }
12453 "textDocument/inlayHint" => {
12454 let options = parse_register_capabilities(reg)?;
12455 server.update_capabilities(|capabilities| {
12456 capabilities.inlay_hint_provider = Some(options);
12457 });
12458 notify_server_capabilities_updated(&server, cx);
12459 }
12460 "textDocument/documentSymbol" => {
12461 let options = parse_register_capabilities(reg)?;
12462 server.update_capabilities(|capabilities| {
12463 capabilities.document_symbol_provider = Some(options);
12464 });
12465 notify_server_capabilities_updated(&server, cx);
12466 }
12467 "textDocument/codeAction" => {
12468 let options = parse_register_capabilities(reg)?;
12469 let provider = match options {
12470 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12471 OneOf::Right(caps) => caps,
12472 };
12473 server.update_capabilities(|capabilities| {
12474 capabilities.code_action_provider = Some(provider);
12475 });
12476 notify_server_capabilities_updated(&server, cx);
12477 }
12478 "textDocument/definition" => {
12479 let options = parse_register_capabilities(reg)?;
12480 server.update_capabilities(|capabilities| {
12481 capabilities.definition_provider = Some(options);
12482 });
12483 notify_server_capabilities_updated(&server, cx);
12484 }
12485 "textDocument/completion" => {
12486 if let Some(caps) = reg
12487 .register_options
12488 .map(serde_json::from_value::<CompletionOptions>)
12489 .transpose()?
12490 {
12491 server.update_capabilities(|capabilities| {
12492 capabilities.completion_provider = Some(caps.clone());
12493 });
12494
12495 if let Some(local) = self.as_local() {
12496 let mut buffers_with_language_server = Vec::new();
12497 for handle in self.buffer_store.read(cx).buffers() {
12498 let buffer_id = handle.read(cx).remote_id();
12499 if local
12500 .buffers_opened_in_servers
12501 .get(&buffer_id)
12502 .filter(|s| s.contains(&server_id))
12503 .is_some()
12504 {
12505 buffers_with_language_server.push(handle);
12506 }
12507 }
12508 let triggers = caps
12509 .trigger_characters
12510 .unwrap_or_default()
12511 .into_iter()
12512 .collect::<BTreeSet<_>>();
12513 for handle in buffers_with_language_server {
12514 let triggers = triggers.clone();
12515 let _ = handle.update(cx, move |buffer, cx| {
12516 buffer.set_completion_triggers(server_id, triggers, cx);
12517 });
12518 }
12519 }
12520 notify_server_capabilities_updated(&server, cx);
12521 }
12522 }
12523 "textDocument/hover" => {
12524 let options = parse_register_capabilities(reg)?;
12525 let provider = match options {
12526 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12527 OneOf::Right(caps) => caps,
12528 };
12529 server.update_capabilities(|capabilities| {
12530 capabilities.hover_provider = Some(provider);
12531 });
12532 notify_server_capabilities_updated(&server, cx);
12533 }
12534 "textDocument/signatureHelp" => {
12535 if let Some(caps) = reg
12536 .register_options
12537 .map(serde_json::from_value)
12538 .transpose()?
12539 {
12540 server.update_capabilities(|capabilities| {
12541 capabilities.signature_help_provider = Some(caps);
12542 });
12543 notify_server_capabilities_updated(&server, cx);
12544 }
12545 }
12546 "textDocument/didChange" => {
12547 if let Some(sync_kind) = reg
12548 .register_options
12549 .and_then(|opts| opts.get("syncKind").cloned())
12550 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12551 .transpose()?
12552 {
12553 server.update_capabilities(|capabilities| {
12554 let mut sync_options =
12555 Self::take_text_document_sync_options(capabilities);
12556 sync_options.change = Some(sync_kind);
12557 capabilities.text_document_sync =
12558 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12559 });
12560 notify_server_capabilities_updated(&server, cx);
12561 }
12562 }
12563 "textDocument/didSave" => {
12564 if let Some(include_text) = reg
12565 .register_options
12566 .map(|opts| {
12567 let transpose = opts
12568 .get("includeText")
12569 .cloned()
12570 .map(serde_json::from_value::<Option<bool>>)
12571 .transpose();
12572 match transpose {
12573 Ok(value) => Ok(value.flatten()),
12574 Err(e) => Err(e),
12575 }
12576 })
12577 .transpose()?
12578 {
12579 server.update_capabilities(|capabilities| {
12580 let mut sync_options =
12581 Self::take_text_document_sync_options(capabilities);
12582 sync_options.save =
12583 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12584 include_text,
12585 }));
12586 capabilities.text_document_sync =
12587 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12588 });
12589 notify_server_capabilities_updated(&server, cx);
12590 }
12591 }
12592 "textDocument/codeLens" => {
12593 if let Some(caps) = reg
12594 .register_options
12595 .map(serde_json::from_value)
12596 .transpose()?
12597 {
12598 server.update_capabilities(|capabilities| {
12599 capabilities.code_lens_provider = Some(caps);
12600 });
12601 notify_server_capabilities_updated(&server, cx);
12602 }
12603 }
12604 "textDocument/diagnostic" => {
12605 if let Some(caps) = reg
12606 .register_options
12607 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12608 .transpose()?
12609 {
12610 let local = self
12611 .as_local_mut()
12612 .context("Expected LSP Store to be local")?;
12613 let state = local
12614 .language_servers
12615 .get_mut(&server_id)
12616 .context("Could not obtain Language Servers state")?;
12617 local
12618 .language_server_dynamic_registrations
12619 .entry(server_id)
12620 .or_default()
12621 .diagnostics
12622 .insert(Some(reg.id.clone()), caps.clone());
12623
12624 let supports_workspace_diagnostics =
12625 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12626 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12627 diagnostic_options.workspace_diagnostics
12628 }
12629 DiagnosticServerCapabilities::RegistrationOptions(
12630 diagnostic_registration_options,
12631 ) => {
12632 diagnostic_registration_options
12633 .diagnostic_options
12634 .workspace_diagnostics
12635 }
12636 };
12637
12638 if supports_workspace_diagnostics(&caps) {
12639 if let LanguageServerState::Running {
12640 workspace_diagnostics_refresh_tasks,
12641 ..
12642 } = state
12643 && let Some(task) = lsp_workspace_diagnostics_refresh(
12644 Some(reg.id.clone()),
12645 caps.clone(),
12646 server.clone(),
12647 cx,
12648 )
12649 {
12650 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12651 }
12652 }
12653
12654 server.update_capabilities(|capabilities| {
12655 capabilities.diagnostic_provider = Some(caps);
12656 });
12657
12658 notify_server_capabilities_updated(&server, cx);
12659
12660 self.pull_document_diagnostics_for_server(server_id, cx)
12661 .detach();
12662 }
12663 }
12664 "textDocument/documentColor" => {
12665 let options = parse_register_capabilities(reg)?;
12666 let provider = match options {
12667 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12668 OneOf::Right(caps) => caps,
12669 };
12670 server.update_capabilities(|capabilities| {
12671 capabilities.color_provider = Some(provider);
12672 });
12673 notify_server_capabilities_updated(&server, cx);
12674 }
12675 _ => log::warn!("unhandled capability registration: {reg:?}"),
12676 }
12677 }
12678
12679 Ok(())
12680 }
12681
12682 fn unregister_server_capabilities(
12683 &mut self,
12684 server_id: LanguageServerId,
12685 params: lsp::UnregistrationParams,
12686 cx: &mut Context<Self>,
12687 ) -> anyhow::Result<()> {
12688 let server = self
12689 .language_server_for_id(server_id)
12690 .with_context(|| format!("no server {server_id} found"))?;
12691 for unreg in params.unregisterations.iter() {
12692 match unreg.method.as_str() {
12693 "workspace/didChangeWatchedFiles" => {
12694 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12695 local_lsp_store
12696 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12697 true
12698 } else {
12699 false
12700 };
12701 if notify {
12702 notify_server_capabilities_updated(&server, cx);
12703 }
12704 }
12705 "workspace/didChangeConfiguration" => {
12706 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12707 }
12708 "workspace/didChangeWorkspaceFolders" => {
12709 server.update_capabilities(|capabilities| {
12710 capabilities
12711 .workspace
12712 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12713 workspace_folders: None,
12714 file_operations: None,
12715 })
12716 .workspace_folders = None;
12717 });
12718 notify_server_capabilities_updated(&server, cx);
12719 }
12720 "workspace/symbol" => {
12721 server.update_capabilities(|capabilities| {
12722 capabilities.workspace_symbol_provider = None
12723 });
12724 notify_server_capabilities_updated(&server, cx);
12725 }
12726 "workspace/fileOperations" => {
12727 server.update_capabilities(|capabilities| {
12728 capabilities
12729 .workspace
12730 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12731 workspace_folders: None,
12732 file_operations: None,
12733 })
12734 .file_operations = None;
12735 });
12736 notify_server_capabilities_updated(&server, cx);
12737 }
12738 "workspace/executeCommand" => {
12739 server.update_capabilities(|capabilities| {
12740 capabilities.execute_command_provider = None;
12741 });
12742 notify_server_capabilities_updated(&server, cx);
12743 }
12744 "textDocument/rangeFormatting" => {
12745 server.update_capabilities(|capabilities| {
12746 capabilities.document_range_formatting_provider = None
12747 });
12748 notify_server_capabilities_updated(&server, cx);
12749 }
12750 "textDocument/onTypeFormatting" => {
12751 server.update_capabilities(|capabilities| {
12752 capabilities.document_on_type_formatting_provider = None;
12753 });
12754 notify_server_capabilities_updated(&server, cx);
12755 }
12756 "textDocument/formatting" => {
12757 server.update_capabilities(|capabilities| {
12758 capabilities.document_formatting_provider = None;
12759 });
12760 notify_server_capabilities_updated(&server, cx);
12761 }
12762 "textDocument/rename" => {
12763 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12764 notify_server_capabilities_updated(&server, cx);
12765 }
12766 "textDocument/codeAction" => {
12767 server.update_capabilities(|capabilities| {
12768 capabilities.code_action_provider = None;
12769 });
12770 notify_server_capabilities_updated(&server, cx);
12771 }
12772 "textDocument/definition" => {
12773 server.update_capabilities(|capabilities| {
12774 capabilities.definition_provider = None;
12775 });
12776 notify_server_capabilities_updated(&server, cx);
12777 }
12778 "textDocument/completion" => {
12779 server.update_capabilities(|capabilities| {
12780 capabilities.completion_provider = None;
12781 });
12782 notify_server_capabilities_updated(&server, cx);
12783 }
12784 "textDocument/hover" => {
12785 server.update_capabilities(|capabilities| {
12786 capabilities.hover_provider = None;
12787 });
12788 notify_server_capabilities_updated(&server, cx);
12789 }
12790 "textDocument/signatureHelp" => {
12791 server.update_capabilities(|capabilities| {
12792 capabilities.signature_help_provider = None;
12793 });
12794 notify_server_capabilities_updated(&server, cx);
12795 }
12796 "textDocument/didChange" => {
12797 server.update_capabilities(|capabilities| {
12798 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12799 sync_options.change = None;
12800 capabilities.text_document_sync =
12801 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12802 });
12803 notify_server_capabilities_updated(&server, cx);
12804 }
12805 "textDocument/didSave" => {
12806 server.update_capabilities(|capabilities| {
12807 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12808 sync_options.save = None;
12809 capabilities.text_document_sync =
12810 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12811 });
12812 notify_server_capabilities_updated(&server, cx);
12813 }
12814 "textDocument/codeLens" => {
12815 server.update_capabilities(|capabilities| {
12816 capabilities.code_lens_provider = None;
12817 });
12818 notify_server_capabilities_updated(&server, cx);
12819 }
12820 "textDocument/diagnostic" => {
12821 let local = self
12822 .as_local_mut()
12823 .context("Expected LSP Store to be local")?;
12824
12825 let state = local
12826 .language_servers
12827 .get_mut(&server_id)
12828 .context("Could not obtain Language Servers state")?;
12829 let registrations = local
12830 .language_server_dynamic_registrations
12831 .get_mut(&server_id)
12832 .with_context(|| {
12833 format!("Expected dynamic registration to exist for server {server_id}")
12834 })?;
12835 registrations.diagnostics
12836 .remove(&Some(unreg.id.clone()))
12837 .with_context(|| format!(
12838 "Attempted to unregister non-existent diagnostic registration with ID {}",
12839 unreg.id)
12840 )?;
12841 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12842
12843 if let LanguageServerState::Running {
12844 workspace_diagnostics_refresh_tasks,
12845 ..
12846 } = state
12847 {
12848 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12849 }
12850
12851 self.clear_unregistered_diagnostics(
12852 server_id,
12853 SharedString::from(unreg.id.clone()),
12854 cx,
12855 )?;
12856
12857 if removed_last_diagnostic_provider {
12858 server.update_capabilities(|capabilities| {
12859 debug_assert!(capabilities.diagnostic_provider.is_some());
12860 capabilities.diagnostic_provider = None;
12861 });
12862 }
12863
12864 notify_server_capabilities_updated(&server, cx);
12865 }
12866 "textDocument/documentColor" => {
12867 server.update_capabilities(|capabilities| {
12868 capabilities.color_provider = None;
12869 });
12870 notify_server_capabilities_updated(&server, cx);
12871 }
12872 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12873 }
12874 }
12875
12876 Ok(())
12877 }
12878
12879 fn clear_unregistered_diagnostics(
12880 &mut self,
12881 server_id: LanguageServerId,
12882 cleared_registration_id: SharedString,
12883 cx: &mut Context<Self>,
12884 ) -> anyhow::Result<()> {
12885 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12886
12887 self.buffer_store.update(cx, |buffer_store, cx| {
12888 for buffer_handle in buffer_store.buffers() {
12889 let buffer = buffer_handle.read(cx);
12890 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12891 let Some(abs_path) = abs_path else {
12892 continue;
12893 };
12894 affected_abs_paths.insert(abs_path);
12895 }
12896 });
12897
12898 let local = self.as_local().context("Expected LSP Store to be local")?;
12899 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12900 let Some(worktree) = self
12901 .worktree_store
12902 .read(cx)
12903 .worktree_for_id(*worktree_id, cx)
12904 else {
12905 continue;
12906 };
12907
12908 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12909 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12910 let has_matching_registration =
12911 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12912 entry.diagnostic.registration_id.as_ref()
12913 == Some(&cleared_registration_id)
12914 });
12915 if has_matching_registration {
12916 let abs_path = worktree.read(cx).absolutize(rel_path);
12917 affected_abs_paths.insert(abs_path);
12918 }
12919 }
12920 }
12921 }
12922
12923 if affected_abs_paths.is_empty() {
12924 return Ok(());
12925 }
12926
12927 // Send a fake diagnostic update which clears the state for the registration ID
12928 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12929 affected_abs_paths
12930 .into_iter()
12931 .map(|abs_path| DocumentDiagnosticsUpdate {
12932 diagnostics: DocumentDiagnostics {
12933 diagnostics: Vec::new(),
12934 document_abs_path: abs_path,
12935 version: None,
12936 },
12937 result_id: None,
12938 registration_id: Some(cleared_registration_id.clone()),
12939 server_id,
12940 disk_based_sources: Cow::Borrowed(&[]),
12941 })
12942 .collect();
12943
12944 let merge_registration_id = cleared_registration_id.clone();
12945 self.merge_diagnostic_entries(
12946 clears,
12947 move |_, diagnostic, _| {
12948 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12949 diagnostic.registration_id != Some(merge_registration_id.clone())
12950 } else {
12951 true
12952 }
12953 },
12954 cx,
12955 )?;
12956
12957 Ok(())
12958 }
12959
12960 async fn deduplicate_range_based_lsp_requests<T>(
12961 lsp_store: &Entity<Self>,
12962 server_id: Option<LanguageServerId>,
12963 lsp_request_id: LspRequestId,
12964 proto_request: &T::ProtoRequest,
12965 range: Range<Anchor>,
12966 cx: &mut AsyncApp,
12967 ) -> Result<()>
12968 where
12969 T: LspCommand,
12970 T::ProtoRequest: proto::LspRequestMessage,
12971 {
12972 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12973 let version = deserialize_version(proto_request.buffer_version());
12974 let buffer = lsp_store.update(cx, |this, cx| {
12975 this.buffer_store.read(cx).get_existing(buffer_id)
12976 })?;
12977 buffer
12978 .update(cx, |buffer, _| buffer.wait_for_version(version))
12979 .await?;
12980 lsp_store.update(cx, |lsp_store, cx| {
12981 let buffer_snapshot = buffer.read(cx).snapshot();
12982 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12983 let chunks_queried_for = lsp_data
12984 .inlay_hints
12985 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12986 .collect::<Vec<_>>();
12987 match chunks_queried_for.as_slice() {
12988 &[chunk] => {
12989 let key = LspKey {
12990 request_type: TypeId::of::<T>(),
12991 server_queried: server_id,
12992 };
12993 let previous_request = lsp_data
12994 .chunk_lsp_requests
12995 .entry(key)
12996 .or_default()
12997 .insert(chunk, lsp_request_id);
12998 if let Some((previous_request, running_requests)) =
12999 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13000 {
13001 running_requests.remove(&previous_request);
13002 }
13003 }
13004 _ambiguous_chunks => {
13005 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13006 // there, a buffer version-based check will be performed and outdated requests discarded.
13007 }
13008 }
13009 anyhow::Ok(())
13010 })?;
13011
13012 Ok(())
13013 }
13014
13015 async fn query_lsp_locally<T>(
13016 lsp_store: Entity<Self>,
13017 for_server_id: Option<LanguageServerId>,
13018 sender_id: proto::PeerId,
13019 lsp_request_id: LspRequestId,
13020 proto_request: T::ProtoRequest,
13021 position: Option<Anchor>,
13022 cx: &mut AsyncApp,
13023 ) -> Result<()>
13024 where
13025 T: LspCommand + Clone,
13026 T::ProtoRequest: proto::LspRequestMessage,
13027 <T::ProtoRequest as proto::RequestMessage>::Response:
13028 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13029 {
13030 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13031 let version = deserialize_version(proto_request.buffer_version());
13032 let buffer = lsp_store.update(cx, |this, cx| {
13033 this.buffer_store.read(cx).get_existing(buffer_id)
13034 })?;
13035 buffer
13036 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13037 .await?;
13038 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13039 let request =
13040 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13041 let key = LspKey {
13042 request_type: TypeId::of::<T>(),
13043 server_queried: for_server_id,
13044 };
13045 lsp_store.update(cx, |lsp_store, cx| {
13046 let request_task = match for_server_id {
13047 Some(server_id) => {
13048 let server_task = lsp_store.request_lsp(
13049 buffer.clone(),
13050 LanguageServerToQuery::Other(server_id),
13051 request.clone(),
13052 cx,
13053 );
13054 cx.background_spawn(async move {
13055 let mut responses = Vec::new();
13056 match server_task.await {
13057 Ok(response) => responses.push((server_id, response)),
13058 // rust-analyzer likes to error with this when its still loading up
13059 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13060 Err(e) => log::error!(
13061 "Error handling response for request {request:?}: {e:#}"
13062 ),
13063 }
13064 responses
13065 })
13066 }
13067 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13068 };
13069 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13070 if T::ProtoRequest::stop_previous_requests() {
13071 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13072 lsp_requests.clear();
13073 }
13074 }
13075 lsp_data.lsp_requests.entry(key).or_default().insert(
13076 lsp_request_id,
13077 cx.spawn(async move |lsp_store, cx| {
13078 let response = request_task.await;
13079 lsp_store
13080 .update(cx, |lsp_store, cx| {
13081 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13082 {
13083 let response = response
13084 .into_iter()
13085 .map(|(server_id, response)| {
13086 (
13087 server_id.to_proto(),
13088 T::response_to_proto(
13089 response,
13090 lsp_store,
13091 sender_id,
13092 &buffer_version,
13093 cx,
13094 )
13095 .into(),
13096 )
13097 })
13098 .collect::<HashMap<_, _>>();
13099 match client.send_lsp_response::<T::ProtoRequest>(
13100 project_id,
13101 lsp_request_id,
13102 response,
13103 ) {
13104 Ok(()) => {}
13105 Err(e) => {
13106 log::error!("Failed to send LSP response: {e:#}",)
13107 }
13108 }
13109 }
13110 })
13111 .ok();
13112 }),
13113 );
13114 });
13115 Ok(())
13116 }
13117
13118 fn take_text_document_sync_options(
13119 capabilities: &mut lsp::ServerCapabilities,
13120 ) -> lsp::TextDocumentSyncOptions {
13121 match capabilities.text_document_sync.take() {
13122 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13123 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13124 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13125 sync_options.change = Some(sync_kind);
13126 sync_options
13127 }
13128 None => lsp::TextDocumentSyncOptions::default(),
13129 }
13130 }
13131
13132 #[cfg(any(test, feature = "test-support"))]
13133 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13134 Some(
13135 self.lsp_data
13136 .get_mut(&buffer_id)?
13137 .code_lens
13138 .take()?
13139 .update
13140 .take()?
13141 .1,
13142 )
13143 }
13144
13145 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13146 self.downstream_client.clone()
13147 }
13148
13149 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13150 self.worktree_store.clone()
13151 }
13152
13153 /// Gets what's stored in the LSP data for the given buffer.
13154 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13155 self.lsp_data.get_mut(&buffer_id)
13156 }
13157
13158 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13159 /// new [`BufferLspData`] will be created to replace the previous state.
13160 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13161 let (buffer_id, buffer_version) =
13162 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13163 let lsp_data = self
13164 .lsp_data
13165 .entry(buffer_id)
13166 .or_insert_with(|| BufferLspData::new(buffer, cx));
13167 if buffer_version.changed_since(&lsp_data.buffer_version) {
13168 *lsp_data = BufferLspData::new(buffer, cx);
13169 }
13170 lsp_data
13171 }
13172}
13173
13174// Registration with registerOptions as null, should fallback to true.
13175// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13176fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13177 reg: lsp::Registration,
13178) -> Result<OneOf<bool, T>> {
13179 Ok(match reg.register_options {
13180 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13181 None => OneOf::Left(true),
13182 })
13183}
13184
13185fn subscribe_to_binary_statuses(
13186 languages: &Arc<LanguageRegistry>,
13187 cx: &mut Context<'_, LspStore>,
13188) -> Task<()> {
13189 let mut server_statuses = languages.language_server_binary_statuses();
13190 cx.spawn(async move |lsp_store, cx| {
13191 while let Some((server_name, binary_status)) = server_statuses.next().await {
13192 if lsp_store
13193 .update(cx, |_, cx| {
13194 let mut message = None;
13195 let binary_status = match binary_status {
13196 BinaryStatus::None => proto::ServerBinaryStatus::None,
13197 BinaryStatus::CheckingForUpdate => {
13198 proto::ServerBinaryStatus::CheckingForUpdate
13199 }
13200 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13201 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13202 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13203 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13204 BinaryStatus::Failed { error } => {
13205 message = Some(error);
13206 proto::ServerBinaryStatus::Failed
13207 }
13208 };
13209 cx.emit(LspStoreEvent::LanguageServerUpdate {
13210 // Binary updates are about the binary that might not have any language server id at that point.
13211 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13212 language_server_id: LanguageServerId(0),
13213 name: Some(server_name),
13214 message: proto::update_language_server::Variant::StatusUpdate(
13215 proto::StatusUpdate {
13216 message,
13217 status: Some(proto::status_update::Status::Binary(
13218 binary_status as i32,
13219 )),
13220 },
13221 ),
13222 });
13223 })
13224 .is_err()
13225 {
13226 break;
13227 }
13228 }
13229 })
13230}
13231
13232fn lsp_workspace_diagnostics_refresh(
13233 registration_id: Option<String>,
13234 options: DiagnosticServerCapabilities,
13235 server: Arc<LanguageServer>,
13236 cx: &mut Context<'_, LspStore>,
13237) -> Option<WorkspaceRefreshTask> {
13238 let identifier = workspace_diagnostic_identifier(&options)?;
13239 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13240
13241 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13242 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13243 refresh_tx.try_send(()).ok();
13244
13245 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13246 let mut attempts = 0;
13247 let max_attempts = 50;
13248 let mut requests = 0;
13249
13250 loop {
13251 let Some(()) = refresh_rx.recv().await else {
13252 return;
13253 };
13254
13255 'request: loop {
13256 requests += 1;
13257 if attempts > max_attempts {
13258 log::error!(
13259 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13260 );
13261 return;
13262 }
13263 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13264 cx.background_executor()
13265 .timer(Duration::from_millis(backoff_millis))
13266 .await;
13267 attempts += 1;
13268
13269 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13270 lsp_store
13271 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13272 .into_iter()
13273 .filter_map(|(abs_path, result_id)| {
13274 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13275 Some(lsp::PreviousResultId {
13276 uri,
13277 value: result_id.to_string(),
13278 })
13279 })
13280 .collect()
13281 }) else {
13282 return;
13283 };
13284
13285 let token = if let Some(registration_id) = ®istration_id {
13286 format!(
13287 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13288 server.server_id(),
13289 )
13290 } else {
13291 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13292 };
13293
13294 progress_rx.try_recv().ok();
13295 let timer =
13296 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13297 let progress = pin!(progress_rx.recv().fuse());
13298 let response_result = server
13299 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13300 lsp::WorkspaceDiagnosticParams {
13301 previous_result_ids,
13302 identifier: identifier.clone(),
13303 work_done_progress_params: Default::default(),
13304 partial_result_params: lsp::PartialResultParams {
13305 partial_result_token: Some(lsp::ProgressToken::String(token)),
13306 },
13307 },
13308 select(timer, progress).then(|either| match either {
13309 Either::Left((message, ..)) => ready(message).left_future(),
13310 Either::Right(..) => pending::<String>().right_future(),
13311 }),
13312 )
13313 .await;
13314
13315 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13316 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13317 match response_result {
13318 ConnectionResult::Timeout => {
13319 log::error!("Timeout during workspace diagnostics pull");
13320 continue 'request;
13321 }
13322 ConnectionResult::ConnectionReset => {
13323 log::error!("Server closed a workspace diagnostics pull request");
13324 continue 'request;
13325 }
13326 ConnectionResult::Result(Err(e)) => {
13327 log::error!("Error during workspace diagnostics pull: {e:#}");
13328 break 'request;
13329 }
13330 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13331 attempts = 0;
13332 if lsp_store
13333 .update(cx, |lsp_store, cx| {
13334 lsp_store.apply_workspace_diagnostic_report(
13335 server.server_id(),
13336 pulled_diagnostics,
13337 registration_id_shared.clone(),
13338 cx,
13339 )
13340 })
13341 .is_err()
13342 {
13343 return;
13344 }
13345 break 'request;
13346 }
13347 }
13348 }
13349 }
13350 });
13351
13352 Some(WorkspaceRefreshTask {
13353 refresh_tx,
13354 progress_tx,
13355 task: workspace_query_language_server,
13356 })
13357}
13358
13359fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13360 match &options {
13361 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13362 diagnostic_options.identifier.clone()
13363 }
13364 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13365 let diagnostic_options = ®istration_options.diagnostic_options;
13366 diagnostic_options.identifier.clone()
13367 }
13368 }
13369}
13370
13371fn workspace_diagnostic_identifier(
13372 options: &DiagnosticServerCapabilities,
13373) -> Option<Option<String>> {
13374 match &options {
13375 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13376 if !diagnostic_options.workspace_diagnostics {
13377 return None;
13378 }
13379 Some(diagnostic_options.identifier.clone())
13380 }
13381 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13382 let diagnostic_options = ®istration_options.diagnostic_options;
13383 if !diagnostic_options.workspace_diagnostics {
13384 return None;
13385 }
13386 Some(diagnostic_options.identifier.clone())
13387 }
13388 }
13389}
13390
13391fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13392 let CompletionSource::BufferWord {
13393 word_range,
13394 resolved,
13395 } = &mut completion.source
13396 else {
13397 return;
13398 };
13399 if *resolved {
13400 return;
13401 }
13402
13403 if completion.new_text
13404 != snapshot
13405 .text_for_range(word_range.clone())
13406 .collect::<String>()
13407 {
13408 return;
13409 }
13410
13411 let mut offset = 0;
13412 for chunk in snapshot.chunks(word_range.clone(), true) {
13413 let end_offset = offset + chunk.text.len();
13414 if let Some(highlight_id) = chunk.syntax_highlight_id {
13415 completion
13416 .label
13417 .runs
13418 .push((offset..end_offset, highlight_id));
13419 }
13420 offset = end_offset;
13421 }
13422 *resolved = true;
13423}
13424
13425impl EventEmitter<LspStoreEvent> for LspStore {}
13426
13427fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13428 hover
13429 .contents
13430 .retain(|hover_block| !hover_block.text.trim().is_empty());
13431 if hover.contents.is_empty() {
13432 None
13433 } else {
13434 Some(hover)
13435 }
13436}
13437
13438async fn populate_labels_for_completions(
13439 new_completions: Vec<CoreCompletion>,
13440 language: Option<Arc<Language>>,
13441 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13442) -> Vec<Completion> {
13443 let lsp_completions = new_completions
13444 .iter()
13445 .filter_map(|new_completion| {
13446 new_completion
13447 .source
13448 .lsp_completion(true)
13449 .map(|lsp_completion| lsp_completion.into_owned())
13450 })
13451 .collect::<Vec<_>>();
13452
13453 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13454 lsp_adapter
13455 .labels_for_completions(&lsp_completions, language)
13456 .await
13457 .log_err()
13458 .unwrap_or_default()
13459 } else {
13460 Vec::new()
13461 }
13462 .into_iter()
13463 .fuse();
13464
13465 let mut completions = Vec::new();
13466 for completion in new_completions {
13467 match completion.source.lsp_completion(true) {
13468 Some(lsp_completion) => {
13469 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13470
13471 let mut label = labels.next().flatten().unwrap_or_else(|| {
13472 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13473 });
13474 ensure_uniform_list_compatible_label(&mut label);
13475 completions.push(Completion {
13476 label,
13477 documentation,
13478 replace_range: completion.replace_range,
13479 new_text: completion.new_text,
13480 insert_text_mode: lsp_completion.insert_text_mode,
13481 source: completion.source,
13482 icon_path: None,
13483 confirm: None,
13484 match_start: None,
13485 snippet_deduplication_key: None,
13486 });
13487 }
13488 None => {
13489 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13490 ensure_uniform_list_compatible_label(&mut label);
13491 completions.push(Completion {
13492 label,
13493 documentation: None,
13494 replace_range: completion.replace_range,
13495 new_text: completion.new_text,
13496 source: completion.source,
13497 insert_text_mode: None,
13498 icon_path: None,
13499 confirm: None,
13500 match_start: None,
13501 snippet_deduplication_key: None,
13502 });
13503 }
13504 }
13505 }
13506 completions
13507}
13508
13509#[derive(Debug)]
13510pub enum LanguageServerToQuery {
13511 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13512 FirstCapable,
13513 /// Query a specific language server.
13514 Other(LanguageServerId),
13515}
13516
13517#[derive(Default)]
13518struct RenamePathsWatchedForServer {
13519 did_rename: Vec<RenameActionPredicate>,
13520 will_rename: Vec<RenameActionPredicate>,
13521}
13522
13523impl RenamePathsWatchedForServer {
13524 fn with_did_rename_patterns(
13525 mut self,
13526 did_rename: Option<&FileOperationRegistrationOptions>,
13527 ) -> Self {
13528 if let Some(did_rename) = did_rename {
13529 self.did_rename = did_rename
13530 .filters
13531 .iter()
13532 .filter_map(|filter| filter.try_into().log_err())
13533 .collect();
13534 }
13535 self
13536 }
13537 fn with_will_rename_patterns(
13538 mut self,
13539 will_rename: Option<&FileOperationRegistrationOptions>,
13540 ) -> Self {
13541 if let Some(will_rename) = will_rename {
13542 self.will_rename = will_rename
13543 .filters
13544 .iter()
13545 .filter_map(|filter| filter.try_into().log_err())
13546 .collect();
13547 }
13548 self
13549 }
13550
13551 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13552 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13553 }
13554 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13555 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13556 }
13557}
13558
13559impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13560 type Error = globset::Error;
13561 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13562 Ok(Self {
13563 kind: ops.pattern.matches.clone(),
13564 glob: GlobBuilder::new(&ops.pattern.glob)
13565 .case_insensitive(
13566 ops.pattern
13567 .options
13568 .as_ref()
13569 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13570 )
13571 .build()?
13572 .compile_matcher(),
13573 })
13574 }
13575}
13576struct RenameActionPredicate {
13577 glob: GlobMatcher,
13578 kind: Option<FileOperationPatternKind>,
13579}
13580
13581impl RenameActionPredicate {
13582 // Returns true if language server should be notified
13583 fn eval(&self, path: &str, is_dir: bool) -> bool {
13584 self.kind.as_ref().is_none_or(|kind| {
13585 let expected_kind = if is_dir {
13586 FileOperationPatternKind::Folder
13587 } else {
13588 FileOperationPatternKind::File
13589 };
13590 kind == &expected_kind
13591 }) && self.glob.is_match(path)
13592 }
13593}
13594
13595#[derive(Default)]
13596struct LanguageServerWatchedPaths {
13597 worktree_paths: HashMap<WorktreeId, GlobSet>,
13598 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13599}
13600
13601#[derive(Default)]
13602struct LanguageServerWatchedPathsBuilder {
13603 worktree_paths: HashMap<WorktreeId, GlobSet>,
13604 abs_paths: HashMap<Arc<Path>, GlobSet>,
13605}
13606
13607impl LanguageServerWatchedPathsBuilder {
13608 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13609 self.worktree_paths.insert(worktree_id, glob_set);
13610 }
13611 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13612 self.abs_paths.insert(path, glob_set);
13613 }
13614 fn build(
13615 self,
13616 fs: Arc<dyn Fs>,
13617 language_server_id: LanguageServerId,
13618 cx: &mut Context<LspStore>,
13619 ) -> LanguageServerWatchedPaths {
13620 let lsp_store = cx.weak_entity();
13621
13622 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13623 let abs_paths = self
13624 .abs_paths
13625 .into_iter()
13626 .map(|(abs_path, globset)| {
13627 let task = cx.spawn({
13628 let abs_path = abs_path.clone();
13629 let fs = fs.clone();
13630
13631 let lsp_store = lsp_store.clone();
13632 async move |_, cx| {
13633 maybe!(async move {
13634 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13635 while let Some(update) = push_updates.0.next().await {
13636 let action = lsp_store
13637 .update(cx, |this, _| {
13638 let Some(local) = this.as_local() else {
13639 return ControlFlow::Break(());
13640 };
13641 let Some(watcher) = local
13642 .language_server_watched_paths
13643 .get(&language_server_id)
13644 else {
13645 return ControlFlow::Break(());
13646 };
13647 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13648 "Watched abs path is not registered with a watcher",
13649 );
13650 let matching_entries = update
13651 .into_iter()
13652 .filter(|event| globs.is_match(&event.path))
13653 .collect::<Vec<_>>();
13654 this.lsp_notify_abs_paths_changed(
13655 language_server_id,
13656 matching_entries,
13657 );
13658 ControlFlow::Continue(())
13659 })
13660 .ok()?;
13661
13662 if action.is_break() {
13663 break;
13664 }
13665 }
13666 Some(())
13667 })
13668 .await;
13669 }
13670 });
13671 (abs_path, (globset, task))
13672 })
13673 .collect();
13674 LanguageServerWatchedPaths {
13675 worktree_paths: self.worktree_paths,
13676 abs_paths,
13677 }
13678 }
13679}
13680
13681struct LspBufferSnapshot {
13682 version: i32,
13683 snapshot: TextBufferSnapshot,
13684}
13685
13686/// A prompt requested by LSP server.
13687#[derive(Clone, Debug)]
13688pub struct LanguageServerPromptRequest {
13689 pub level: PromptLevel,
13690 pub message: String,
13691 pub actions: Vec<MessageActionItem>,
13692 pub lsp_name: String,
13693 pub(crate) response_channel: Sender<MessageActionItem>,
13694}
13695
13696impl LanguageServerPromptRequest {
13697 pub async fn respond(self, index: usize) -> Option<()> {
13698 if let Some(response) = self.actions.into_iter().nth(index) {
13699 self.response_channel.send(response).await.ok()
13700 } else {
13701 None
13702 }
13703 }
13704}
13705impl PartialEq for LanguageServerPromptRequest {
13706 fn eq(&self, other: &Self) -> bool {
13707 self.message == other.message && self.actions == other.actions
13708 }
13709}
13710
13711#[derive(Clone, Debug, PartialEq)]
13712pub enum LanguageServerLogType {
13713 Log(MessageType),
13714 Trace { verbose_info: Option<String> },
13715 Rpc { received: bool },
13716}
13717
13718impl LanguageServerLogType {
13719 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13720 match self {
13721 Self::Log(log_type) => {
13722 use proto::log_message::LogLevel;
13723 let level = match *log_type {
13724 MessageType::ERROR => LogLevel::Error,
13725 MessageType::WARNING => LogLevel::Warning,
13726 MessageType::INFO => LogLevel::Info,
13727 MessageType::LOG => LogLevel::Log,
13728 other => {
13729 log::warn!("Unknown lsp log message type: {other:?}");
13730 LogLevel::Log
13731 }
13732 };
13733 proto::language_server_log::LogType::Log(proto::LogMessage {
13734 level: level as i32,
13735 })
13736 }
13737 Self::Trace { verbose_info } => {
13738 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13739 verbose_info: verbose_info.to_owned(),
13740 })
13741 }
13742 Self::Rpc { received } => {
13743 let kind = if *received {
13744 proto::rpc_message::Kind::Received
13745 } else {
13746 proto::rpc_message::Kind::Sent
13747 };
13748 let kind = kind as i32;
13749 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13750 }
13751 }
13752 }
13753
13754 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13755 use proto::log_message::LogLevel;
13756 use proto::rpc_message;
13757 match log_type {
13758 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13759 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13760 LogLevel::Error => MessageType::ERROR,
13761 LogLevel::Warning => MessageType::WARNING,
13762 LogLevel::Info => MessageType::INFO,
13763 LogLevel::Log => MessageType::LOG,
13764 },
13765 ),
13766 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13767 verbose_info: trace_message.verbose_info,
13768 },
13769 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13770 received: match rpc_message::Kind::from_i32(message.kind)
13771 .unwrap_or(rpc_message::Kind::Received)
13772 {
13773 rpc_message::Kind::Received => true,
13774 rpc_message::Kind::Sent => false,
13775 },
13776 },
13777 }
13778 }
13779}
13780
13781pub struct WorkspaceRefreshTask {
13782 refresh_tx: mpsc::Sender<()>,
13783 progress_tx: mpsc::Sender<()>,
13784 #[allow(dead_code)]
13785 task: Task<()>,
13786}
13787
13788pub enum LanguageServerState {
13789 Starting {
13790 startup: Task<Option<Arc<LanguageServer>>>,
13791 /// List of language servers that will be added to the workspace once it's initialization completes.
13792 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13793 },
13794
13795 Running {
13796 adapter: Arc<CachedLspAdapter>,
13797 server: Arc<LanguageServer>,
13798 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13799 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13800 },
13801}
13802
13803impl LanguageServerState {
13804 fn add_workspace_folder(&self, uri: Uri) {
13805 match self {
13806 LanguageServerState::Starting {
13807 pending_workspace_folders,
13808 ..
13809 } => {
13810 pending_workspace_folders.lock().insert(uri);
13811 }
13812 LanguageServerState::Running { server, .. } => {
13813 server.add_workspace_folder(uri);
13814 }
13815 }
13816 }
13817 fn _remove_workspace_folder(&self, uri: Uri) {
13818 match self {
13819 LanguageServerState::Starting {
13820 pending_workspace_folders,
13821 ..
13822 } => {
13823 pending_workspace_folders.lock().remove(&uri);
13824 }
13825 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13826 }
13827 }
13828}
13829
13830impl std::fmt::Debug for LanguageServerState {
13831 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13832 match self {
13833 LanguageServerState::Starting { .. } => {
13834 f.debug_struct("LanguageServerState::Starting").finish()
13835 }
13836 LanguageServerState::Running { .. } => {
13837 f.debug_struct("LanguageServerState::Running").finish()
13838 }
13839 }
13840 }
13841}
13842
13843#[derive(Clone, Debug, Serialize)]
13844pub struct LanguageServerProgress {
13845 pub is_disk_based_diagnostics_progress: bool,
13846 pub is_cancellable: bool,
13847 pub title: Option<String>,
13848 pub message: Option<String>,
13849 pub percentage: Option<usize>,
13850 #[serde(skip_serializing)]
13851 pub last_update_at: Instant,
13852}
13853
13854#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13855pub struct DiagnosticSummary {
13856 pub error_count: usize,
13857 pub warning_count: usize,
13858}
13859
13860impl DiagnosticSummary {
13861 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13862 let mut this = Self {
13863 error_count: 0,
13864 warning_count: 0,
13865 };
13866
13867 for entry in diagnostics {
13868 if entry.diagnostic.is_primary {
13869 match entry.diagnostic.severity {
13870 DiagnosticSeverity::ERROR => this.error_count += 1,
13871 DiagnosticSeverity::WARNING => this.warning_count += 1,
13872 _ => {}
13873 }
13874 }
13875 }
13876
13877 this
13878 }
13879
13880 pub fn is_empty(&self) -> bool {
13881 self.error_count == 0 && self.warning_count == 0
13882 }
13883
13884 pub fn to_proto(
13885 self,
13886 language_server_id: LanguageServerId,
13887 path: &RelPath,
13888 ) -> proto::DiagnosticSummary {
13889 proto::DiagnosticSummary {
13890 path: path.to_proto(),
13891 language_server_id: language_server_id.0 as u64,
13892 error_count: self.error_count as u32,
13893 warning_count: self.warning_count as u32,
13894 }
13895 }
13896}
13897
13898#[derive(Clone, Debug)]
13899pub enum CompletionDocumentation {
13900 /// There is no documentation for this completion.
13901 Undocumented,
13902 /// A single line of documentation.
13903 SingleLine(SharedString),
13904 /// Multiple lines of plain text documentation.
13905 MultiLinePlainText(SharedString),
13906 /// Markdown documentation.
13907 MultiLineMarkdown(SharedString),
13908 /// Both single line and multiple lines of plain text documentation.
13909 SingleLineAndMultiLinePlainText {
13910 single_line: SharedString,
13911 plain_text: Option<SharedString>,
13912 },
13913}
13914
13915impl CompletionDocumentation {
13916 #[cfg(any(test, feature = "test-support"))]
13917 pub fn text(&self) -> SharedString {
13918 match self {
13919 CompletionDocumentation::Undocumented => "".into(),
13920 CompletionDocumentation::SingleLine(s) => s.clone(),
13921 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13922 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13923 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13924 single_line.clone()
13925 }
13926 }
13927 }
13928}
13929
13930impl From<lsp::Documentation> for CompletionDocumentation {
13931 fn from(docs: lsp::Documentation) -> Self {
13932 match docs {
13933 lsp::Documentation::String(text) => {
13934 if text.lines().count() <= 1 {
13935 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13936 } else {
13937 CompletionDocumentation::MultiLinePlainText(text.into())
13938 }
13939 }
13940
13941 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13942 lsp::MarkupKind::PlainText => {
13943 if value.lines().count() <= 1 {
13944 CompletionDocumentation::SingleLine(value.into())
13945 } else {
13946 CompletionDocumentation::MultiLinePlainText(value.into())
13947 }
13948 }
13949
13950 lsp::MarkupKind::Markdown => {
13951 CompletionDocumentation::MultiLineMarkdown(value.into())
13952 }
13953 },
13954 }
13955 }
13956}
13957
13958pub enum ResolvedHint {
13959 Resolved(InlayHint),
13960 Resolving(Shared<Task<()>>),
13961}
13962
13963fn glob_literal_prefix(glob: &Path) -> PathBuf {
13964 glob.components()
13965 .take_while(|component| match component {
13966 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13967 _ => true,
13968 })
13969 .collect()
13970}
13971
13972pub struct SshLspAdapter {
13973 name: LanguageServerName,
13974 binary: LanguageServerBinary,
13975 initialization_options: Option<String>,
13976 code_action_kinds: Option<Vec<CodeActionKind>>,
13977}
13978
13979impl SshLspAdapter {
13980 pub fn new(
13981 name: LanguageServerName,
13982 binary: LanguageServerBinary,
13983 initialization_options: Option<String>,
13984 code_action_kinds: Option<String>,
13985 ) -> Self {
13986 Self {
13987 name,
13988 binary,
13989 initialization_options,
13990 code_action_kinds: code_action_kinds
13991 .as_ref()
13992 .and_then(|c| serde_json::from_str(c).ok()),
13993 }
13994 }
13995}
13996
13997impl LspInstaller for SshLspAdapter {
13998 type BinaryVersion = ();
13999 async fn check_if_user_installed(
14000 &self,
14001 _: &dyn LspAdapterDelegate,
14002 _: Option<Toolchain>,
14003 _: &AsyncApp,
14004 ) -> Option<LanguageServerBinary> {
14005 Some(self.binary.clone())
14006 }
14007
14008 async fn cached_server_binary(
14009 &self,
14010 _: PathBuf,
14011 _: &dyn LspAdapterDelegate,
14012 ) -> Option<LanguageServerBinary> {
14013 None
14014 }
14015
14016 async fn fetch_latest_server_version(
14017 &self,
14018 _: &dyn LspAdapterDelegate,
14019 _: bool,
14020 _: &mut AsyncApp,
14021 ) -> Result<()> {
14022 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14023 }
14024
14025 async fn fetch_server_binary(
14026 &self,
14027 _: (),
14028 _: PathBuf,
14029 _: &dyn LspAdapterDelegate,
14030 ) -> Result<LanguageServerBinary> {
14031 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14032 }
14033}
14034
14035#[async_trait(?Send)]
14036impl LspAdapter for SshLspAdapter {
14037 fn name(&self) -> LanguageServerName {
14038 self.name.clone()
14039 }
14040
14041 async fn initialization_options(
14042 self: Arc<Self>,
14043 _: &Arc<dyn LspAdapterDelegate>,
14044 ) -> Result<Option<serde_json::Value>> {
14045 let Some(options) = &self.initialization_options else {
14046 return Ok(None);
14047 };
14048 let result = serde_json::from_str(options)?;
14049 Ok(result)
14050 }
14051
14052 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14053 self.code_action_kinds.clone()
14054 }
14055}
14056
14057pub fn language_server_settings<'a>(
14058 delegate: &'a dyn LspAdapterDelegate,
14059 language: &LanguageServerName,
14060 cx: &'a App,
14061) -> Option<&'a LspSettings> {
14062 language_server_settings_for(
14063 SettingsLocation {
14064 worktree_id: delegate.worktree_id(),
14065 path: RelPath::empty(),
14066 },
14067 language,
14068 cx,
14069 )
14070}
14071
14072pub fn language_server_settings_for<'a>(
14073 location: SettingsLocation<'a>,
14074 language: &LanguageServerName,
14075 cx: &'a App,
14076) -> Option<&'a LspSettings> {
14077 ProjectSettings::get(Some(location), cx).lsp.get(language)
14078}
14079
14080pub struct LocalLspAdapterDelegate {
14081 lsp_store: WeakEntity<LspStore>,
14082 worktree: worktree::Snapshot,
14083 fs: Arc<dyn Fs>,
14084 http_client: Arc<dyn HttpClient>,
14085 language_registry: Arc<LanguageRegistry>,
14086 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14087}
14088
14089impl LocalLspAdapterDelegate {
14090 pub fn new(
14091 language_registry: Arc<LanguageRegistry>,
14092 environment: &Entity<ProjectEnvironment>,
14093 lsp_store: WeakEntity<LspStore>,
14094 worktree: &Entity<Worktree>,
14095 http_client: Arc<dyn HttpClient>,
14096 fs: Arc<dyn Fs>,
14097 cx: &mut App,
14098 ) -> Arc<Self> {
14099 let load_shell_env_task =
14100 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14101
14102 Arc::new(Self {
14103 lsp_store,
14104 worktree: worktree.read(cx).snapshot(),
14105 fs,
14106 http_client,
14107 language_registry,
14108 load_shell_env_task,
14109 })
14110 }
14111
14112 pub fn from_local_lsp(
14113 local: &LocalLspStore,
14114 worktree: &Entity<Worktree>,
14115 cx: &mut App,
14116 ) -> Arc<Self> {
14117 Self::new(
14118 local.languages.clone(),
14119 &local.environment,
14120 local.weak.clone(),
14121 worktree,
14122 local.http_client.clone(),
14123 local.fs.clone(),
14124 cx,
14125 )
14126 }
14127}
14128
14129#[async_trait]
14130impl LspAdapterDelegate for LocalLspAdapterDelegate {
14131 fn show_notification(&self, message: &str, cx: &mut App) {
14132 self.lsp_store
14133 .update(cx, |_, cx| {
14134 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14135 })
14136 .ok();
14137 }
14138
14139 fn http_client(&self) -> Arc<dyn HttpClient> {
14140 self.http_client.clone()
14141 }
14142
14143 fn worktree_id(&self) -> WorktreeId {
14144 self.worktree.id()
14145 }
14146
14147 fn worktree_root_path(&self) -> &Path {
14148 self.worktree.abs_path().as_ref()
14149 }
14150
14151 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14152 self.worktree.resolve_executable_path(path)
14153 }
14154
14155 async fn shell_env(&self) -> HashMap<String, String> {
14156 let task = self.load_shell_env_task.clone();
14157 task.await.unwrap_or_default()
14158 }
14159
14160 async fn npm_package_installed_version(
14161 &self,
14162 package_name: &str,
14163 ) -> Result<Option<(PathBuf, Version)>> {
14164 let local_package_directory = self.worktree_root_path();
14165 let node_modules_directory = local_package_directory.join("node_modules");
14166
14167 if let Some(version) =
14168 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14169 {
14170 return Ok(Some((node_modules_directory, version)));
14171 }
14172 let Some(npm) = self.which("npm".as_ref()).await else {
14173 log::warn!(
14174 "Failed to find npm executable for {:?}",
14175 local_package_directory
14176 );
14177 return Ok(None);
14178 };
14179
14180 let env = self.shell_env().await;
14181 let output = util::command::new_smol_command(&npm)
14182 .args(["root", "-g"])
14183 .envs(env)
14184 .current_dir(local_package_directory)
14185 .output()
14186 .await?;
14187 let global_node_modules =
14188 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14189
14190 if let Some(version) =
14191 read_package_installed_version(global_node_modules.clone(), package_name).await?
14192 {
14193 return Ok(Some((global_node_modules, version)));
14194 }
14195 return Ok(None);
14196 }
14197
14198 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14199 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14200 if self.fs.is_file(&worktree_abs_path).await {
14201 worktree_abs_path.pop();
14202 }
14203
14204 let env = self.shell_env().await;
14205
14206 let shell_path = env.get("PATH").cloned();
14207
14208 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14209 }
14210
14211 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14212 let mut working_dir = self.worktree_root_path().to_path_buf();
14213 if self.fs.is_file(&working_dir).await {
14214 working_dir.pop();
14215 }
14216 let output = util::command::new_smol_command(&command.path)
14217 .args(command.arguments)
14218 .envs(command.env.clone().unwrap_or_default())
14219 .current_dir(working_dir)
14220 .output()
14221 .await?;
14222
14223 anyhow::ensure!(
14224 output.status.success(),
14225 "{}, stdout: {:?}, stderr: {:?}",
14226 output.status,
14227 String::from_utf8_lossy(&output.stdout),
14228 String::from_utf8_lossy(&output.stderr)
14229 );
14230 Ok(())
14231 }
14232
14233 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14234 self.language_registry
14235 .update_lsp_binary_status(server_name, status);
14236 }
14237
14238 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14239 self.language_registry
14240 .all_lsp_adapters()
14241 .into_iter()
14242 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14243 .collect()
14244 }
14245
14246 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14247 let dir = self.language_registry.language_server_download_dir(name)?;
14248
14249 if !dir.exists() {
14250 smol::fs::create_dir_all(&dir)
14251 .await
14252 .context("failed to create container directory")
14253 .log_err()?;
14254 }
14255
14256 Some(dir)
14257 }
14258
14259 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14260 let entry = self
14261 .worktree
14262 .entry_for_path(path)
14263 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14264 let abs_path = self.worktree.absolutize(&entry.path);
14265 self.fs.load(&abs_path).await
14266 }
14267}
14268
14269async fn populate_labels_for_symbols(
14270 symbols: Vec<CoreSymbol>,
14271 language_registry: &Arc<LanguageRegistry>,
14272 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14273 output: &mut Vec<Symbol>,
14274) {
14275 #[allow(clippy::mutable_key_type)]
14276 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14277
14278 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14279 for symbol in symbols {
14280 let Some(file_name) = symbol.path.file_name() else {
14281 continue;
14282 };
14283 let language = language_registry
14284 .load_language_for_file_path(Path::new(file_name))
14285 .await
14286 .ok()
14287 .or_else(|| {
14288 unknown_paths.insert(file_name.into());
14289 None
14290 });
14291 symbols_by_language
14292 .entry(language)
14293 .or_default()
14294 .push(symbol);
14295 }
14296
14297 for unknown_path in unknown_paths {
14298 log::info!("no language found for symbol in file {unknown_path:?}");
14299 }
14300
14301 let mut label_params = Vec::new();
14302 for (language, mut symbols) in symbols_by_language {
14303 label_params.clear();
14304 label_params.extend(
14305 symbols
14306 .iter_mut()
14307 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14308 );
14309
14310 let mut labels = Vec::new();
14311 if let Some(language) = language {
14312 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14313 language_registry
14314 .lsp_adapters(&language.name())
14315 .first()
14316 .cloned()
14317 });
14318 if let Some(lsp_adapter) = lsp_adapter {
14319 labels = lsp_adapter
14320 .labels_for_symbols(&label_params, &language)
14321 .await
14322 .log_err()
14323 .unwrap_or_default();
14324 }
14325 }
14326
14327 for ((symbol, (name, _)), label) in symbols
14328 .into_iter()
14329 .zip(label_params.drain(..))
14330 .zip(labels.into_iter().chain(iter::repeat(None)))
14331 {
14332 output.push(Symbol {
14333 language_server_name: symbol.language_server_name,
14334 source_worktree_id: symbol.source_worktree_id,
14335 source_language_server_id: symbol.source_language_server_id,
14336 path: symbol.path,
14337 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14338 name,
14339 kind: symbol.kind,
14340 range: symbol.range,
14341 });
14342 }
14343 }
14344}
14345
14346fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14347 match server.capabilities().text_document_sync.as_ref()? {
14348 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14349 // Server wants didSave but didn't specify includeText.
14350 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14351 // Server doesn't want didSave at all.
14352 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14353 // Server provided SaveOptions.
14354 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14355 Some(save_options.include_text.unwrap_or(false))
14356 }
14357 },
14358 // We do not have any save info. Kind affects didChange only.
14359 lsp::TextDocumentSyncCapability::Kind(_) => None,
14360 }
14361}
14362
14363/// Completion items are displayed in a `UniformList`.
14364/// Usually, those items are single-line strings, but in LSP responses,
14365/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14366/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14367/// 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,
14368/// breaking the completions menu presentation.
14369///
14370/// 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.
14371fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14372 let mut new_text = String::with_capacity(label.text.len());
14373 let mut offset_map = vec![0; label.text.len() + 1];
14374 let mut last_char_was_space = false;
14375 let mut new_idx = 0;
14376 let chars = label.text.char_indices().fuse();
14377 let mut newlines_removed = false;
14378
14379 for (idx, c) in chars {
14380 offset_map[idx] = new_idx;
14381
14382 match c {
14383 '\n' if last_char_was_space => {
14384 newlines_removed = true;
14385 }
14386 '\t' | ' ' if last_char_was_space => {}
14387 '\n' if !last_char_was_space => {
14388 new_text.push(' ');
14389 new_idx += 1;
14390 last_char_was_space = true;
14391 newlines_removed = true;
14392 }
14393 ' ' | '\t' => {
14394 new_text.push(' ');
14395 new_idx += 1;
14396 last_char_was_space = true;
14397 }
14398 _ => {
14399 new_text.push(c);
14400 new_idx += c.len_utf8();
14401 last_char_was_space = false;
14402 }
14403 }
14404 }
14405 offset_map[label.text.len()] = new_idx;
14406
14407 // Only modify the label if newlines were removed.
14408 if !newlines_removed {
14409 return;
14410 }
14411
14412 let last_index = new_idx;
14413 let mut run_ranges_errors = Vec::new();
14414 label.runs.retain_mut(|(range, _)| {
14415 match offset_map.get(range.start) {
14416 Some(&start) => range.start = start,
14417 None => {
14418 run_ranges_errors.push(range.clone());
14419 return false;
14420 }
14421 }
14422
14423 match offset_map.get(range.end) {
14424 Some(&end) => range.end = end,
14425 None => {
14426 run_ranges_errors.push(range.clone());
14427 range.end = last_index;
14428 }
14429 }
14430 true
14431 });
14432 if !run_ranges_errors.is_empty() {
14433 log::error!(
14434 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14435 label.text
14436 );
14437 }
14438
14439 let mut wrong_filter_range = None;
14440 if label.filter_range == (0..label.text.len()) {
14441 label.filter_range = 0..new_text.len();
14442 } else {
14443 let mut original_filter_range = Some(label.filter_range.clone());
14444 match offset_map.get(label.filter_range.start) {
14445 Some(&start) => label.filter_range.start = start,
14446 None => {
14447 wrong_filter_range = original_filter_range.take();
14448 label.filter_range.start = last_index;
14449 }
14450 }
14451
14452 match offset_map.get(label.filter_range.end) {
14453 Some(&end) => label.filter_range.end = end,
14454 None => {
14455 wrong_filter_range = original_filter_range.take();
14456 label.filter_range.end = last_index;
14457 }
14458 }
14459 }
14460 if let Some(wrong_filter_range) = wrong_filter_range {
14461 log::error!(
14462 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14463 label.text
14464 );
14465 }
14466
14467 label.text = new_text;
14468}
14469
14470#[cfg(test)]
14471mod tests {
14472 use language::HighlightId;
14473
14474 use super::*;
14475
14476 #[test]
14477 fn test_glob_literal_prefix() {
14478 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14479 assert_eq!(
14480 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14481 Path::new("node_modules")
14482 );
14483 assert_eq!(
14484 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14485 Path::new("foo")
14486 );
14487 assert_eq!(
14488 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14489 Path::new("foo/bar/baz.js")
14490 );
14491
14492 #[cfg(target_os = "windows")]
14493 {
14494 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14495 assert_eq!(
14496 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14497 Path::new("node_modules")
14498 );
14499 assert_eq!(
14500 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14501 Path::new("foo")
14502 );
14503 assert_eq!(
14504 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14505 Path::new("foo/bar/baz.js")
14506 );
14507 }
14508 }
14509
14510 #[test]
14511 fn test_multi_len_chars_normalization() {
14512 let mut label = CodeLabel::new(
14513 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14514 0..6,
14515 vec![(0..6, HighlightId(1))],
14516 );
14517 ensure_uniform_list_compatible_label(&mut label);
14518 assert_eq!(
14519 label,
14520 CodeLabel::new(
14521 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14522 0..6,
14523 vec![(0..6, HighlightId(1))],
14524 )
14525 );
14526 }
14527
14528 #[test]
14529 fn test_trailing_newline_in_completion_documentation() {
14530 let doc = lsp::Documentation::String(
14531 "Inappropriate argument value (of correct type).\n".to_string(),
14532 );
14533 let completion_doc: CompletionDocumentation = doc.into();
14534 assert!(
14535 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
14536 );
14537
14538 let doc = lsp::Documentation::String(" some value \n".to_string());
14539 let completion_doc: CompletionDocumentation = doc.into();
14540 assert!(matches!(
14541 completion_doc,
14542 CompletionDocumentation::SingleLine(s) if s == "some value"
14543 ));
14544 }
14545}