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 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(worktree_id, cx)
392 });
393 if can_trust {
394 self.restricted_worktrees_tasks.remove(&worktree_id);
395 None
396 } else {
397 match self.restricted_worktrees_tasks.entry(worktree_id) {
398 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
399 hash_map::Entry::Vacant(v) => {
400 let (tx, rx) = smol::channel::bounded::<()>(1);
401 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, _| {
402 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
403 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
404 tx.send_blocking(()).ok();
405 }
406 }
407 });
408 v.insert((subscription, rx.clone()));
409 Some(rx)
410 }
411 }
412 }
413 });
414 let update_binary_status = untrusted_worktree_task.is_none();
415
416 let binary = self.get_language_server_binary(
417 worktree_abs_path.clone(),
418 adapter.clone(),
419 settings,
420 toolchain.clone(),
421 delegate.clone(),
422 true,
423 untrusted_worktree_task,
424 cx,
425 );
426 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
427
428 let pending_server = cx.spawn({
429 let adapter = adapter.clone();
430 let server_name = adapter.name.clone();
431 let stderr_capture = stderr_capture.clone();
432 #[cfg(any(test, feature = "test-support"))]
433 let lsp_store = self.weak.clone();
434 let pending_workspace_folders = pending_workspace_folders.clone();
435 async move |cx| {
436 let binary = binary.await?;
437 #[cfg(any(test, feature = "test-support"))]
438 if let Some(server) = lsp_store
439 .update(&mut cx.clone(), |this, cx| {
440 this.languages.create_fake_language_server(
441 server_id,
442 &server_name,
443 binary.clone(),
444 &mut cx.to_async(),
445 )
446 })
447 .ok()
448 .flatten()
449 {
450 return Ok(server);
451 }
452
453 let code_action_kinds = adapter.code_action_kinds();
454 lsp::LanguageServer::new(
455 stderr_capture,
456 server_id,
457 server_name,
458 binary,
459 &worktree_abs_path,
460 code_action_kinds,
461 Some(pending_workspace_folders),
462 cx,
463 )
464 }
465 });
466
467 let startup = {
468 let server_name = adapter.name.0.clone();
469 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
470 let key = key.clone();
471 let adapter = adapter.clone();
472 let lsp_store = self.weak.clone();
473 let pending_workspace_folders = pending_workspace_folders.clone();
474
475 let pull_diagnostics = ProjectSettings::get_global(cx)
476 .diagnostics
477 .lsp_pull_diagnostics
478 .enabled;
479 cx.spawn(async move |cx| {
480 let result = async {
481 let language_server = pending_server.await?;
482
483 let workspace_config = Self::workspace_configuration_for_adapter(
484 adapter.adapter.clone(),
485 &delegate,
486 toolchain,
487 None,
488 cx,
489 )
490 .await?;
491
492 let mut initialization_options = Self::initialization_options_for_adapter(
493 adapter.adapter.clone(),
494 &delegate,
495 )
496 .await?;
497
498 match (&mut initialization_options, override_options) {
499 (Some(initialization_options), Some(override_options)) => {
500 merge_json_value_into(override_options, initialization_options);
501 }
502 (None, override_options) => initialization_options = override_options,
503 _ => {}
504 }
505
506 let initialization_params = cx.update(|cx| {
507 let mut params =
508 language_server.default_initialize_params(pull_diagnostics, cx);
509 params.initialization_options = initialization_options;
510 adapter.adapter.prepare_initialize_params(params, cx)
511 })??;
512
513 Self::setup_lsp_messages(
514 lsp_store.clone(),
515 &language_server,
516 delegate.clone(),
517 adapter.clone(),
518 );
519
520 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
521 settings: workspace_config,
522 };
523 let language_server = cx
524 .update(|cx| {
525 language_server.initialize(
526 initialization_params,
527 Arc::new(did_change_configuration_params.clone()),
528 cx,
529 )
530 })?
531 .await
532 .inspect_err(|_| {
533 if let Some(lsp_store) = lsp_store.upgrade() {
534 lsp_store
535 .update(cx, |lsp_store, cx| {
536 lsp_store.cleanup_lsp_data(server_id);
537 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
538 })
539 .ok();
540 }
541 })?;
542
543 language_server.notify::<lsp::notification::DidChangeConfiguration>(
544 did_change_configuration_params,
545 )?;
546
547 anyhow::Ok(language_server)
548 }
549 .await;
550
551 match result {
552 Ok(server) => {
553 lsp_store
554 .update(cx, |lsp_store, cx| {
555 lsp_store.insert_newly_running_language_server(
556 adapter,
557 server.clone(),
558 server_id,
559 key,
560 pending_workspace_folders,
561 cx,
562 );
563 })
564 .ok();
565 stderr_capture.lock().take();
566 Some(server)
567 }
568
569 Err(err) => {
570 let log = stderr_capture.lock().take().unwrap_or_default();
571 delegate.update_status(
572 adapter.name(),
573 BinaryStatus::Failed {
574 error: if log.is_empty() {
575 format!("{err:#}")
576 } else {
577 format!("{err:#}\n-- stderr --\n{log}")
578 },
579 },
580 );
581 log::error!(
582 "Failed to start language server {server_name:?}: {}",
583 redact_command(&format!("{err:?}"))
584 );
585 if !log.is_empty() {
586 log::error!("server stderr: {}", redact_command(&log));
587 }
588 None
589 }
590 }
591 })
592 };
593 let state = LanguageServerState::Starting {
594 startup,
595 pending_workspace_folders,
596 };
597
598 if update_binary_status {
599 self.languages
600 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
601 }
602
603 self.language_servers.insert(server_id, state);
604 self.language_server_ids
605 .entry(key)
606 .or_insert(UnifiedLanguageServer {
607 id: server_id,
608 project_roots: Default::default(),
609 });
610 server_id
611 }
612
613 fn get_language_server_binary(
614 &self,
615 worktree_abs_path: Arc<Path>,
616 adapter: Arc<CachedLspAdapter>,
617 settings: Arc<LspSettings>,
618 toolchain: Option<Toolchain>,
619 delegate: Arc<dyn LspAdapterDelegate>,
620 allow_binary_download: bool,
621 untrusted_worktree_task: Option<Receiver<()>>,
622 cx: &mut App,
623 ) -> Task<Result<LanguageServerBinary>> {
624 if let Some(settings) = &settings.binary
625 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
626 {
627 let settings = settings.clone();
628 let languages = self.languages.clone();
629 return cx.background_spawn(async move {
630 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
631 log::info!(
632 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
633 adapter.name(),
634 );
635 untrusted_worktree_task.recv().await.ok();
636 log::info!(
637 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
638 adapter.name(),
639 );
640 languages
641 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
642 }
643 let mut env = delegate.shell_env().await;
644 env.extend(settings.env.unwrap_or_default());
645
646 Ok(LanguageServerBinary {
647 path: delegate.resolve_executable_path(path),
648 env: Some(env),
649 arguments: settings
650 .arguments
651 .unwrap_or_default()
652 .iter()
653 .map(Into::into)
654 .collect(),
655 })
656 });
657 }
658 let lsp_binary_options = LanguageServerBinaryOptions {
659 allow_path_lookup: !settings
660 .binary
661 .as_ref()
662 .and_then(|b| b.ignore_system_version)
663 .unwrap_or_default(),
664 allow_binary_download,
665 pre_release: settings
666 .fetch
667 .as_ref()
668 .and_then(|f| f.pre_release)
669 .unwrap_or(false),
670 };
671
672 cx.spawn(async move |cx| {
673 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
674 log::info!(
675 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
676 adapter.name(),
677 );
678 untrusted_worktree_task.recv().await.ok();
679 log::info!(
680 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
681 adapter.name(),
682 );
683 }
684
685 let (existing_binary, maybe_download_binary) = adapter
686 .clone()
687 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
688 .await
689 .await;
690
691 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
692
693 let mut binary = match (existing_binary, maybe_download_binary) {
694 (binary, None) => binary?,
695 (Err(_), Some(downloader)) => downloader.await?,
696 (Ok(existing_binary), Some(downloader)) => {
697 let mut download_timeout = cx
698 .background_executor()
699 .timer(SERVER_DOWNLOAD_TIMEOUT)
700 .fuse();
701 let mut downloader = downloader.fuse();
702 futures::select! {
703 _ = download_timeout => {
704 // Return existing binary and kick the existing work to the background.
705 cx.spawn(async move |_| downloader.await).detach();
706 Ok(existing_binary)
707 },
708 downloaded_or_existing_binary = downloader => {
709 // If download fails, this results in the existing binary.
710 downloaded_or_existing_binary
711 }
712 }?
713 }
714 };
715 let mut shell_env = delegate.shell_env().await;
716
717 shell_env.extend(binary.env.unwrap_or_default());
718
719 if let Some(settings) = settings.binary.as_ref() {
720 if let Some(arguments) = &settings.arguments {
721 binary.arguments = arguments.iter().map(Into::into).collect();
722 }
723 if let Some(env) = &settings.env {
724 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
725 }
726 }
727
728 binary.env = Some(shell_env);
729 Ok(binary)
730 })
731 }
732
733 fn setup_lsp_messages(
734 lsp_store: WeakEntity<LspStore>,
735 language_server: &LanguageServer,
736 delegate: Arc<dyn LspAdapterDelegate>,
737 adapter: Arc<CachedLspAdapter>,
738 ) {
739 let name = language_server.name();
740 let server_id = language_server.server_id();
741 language_server
742 .on_notification::<lsp::notification::PublishDiagnostics, _>({
743 let adapter = adapter.clone();
744 let this = lsp_store.clone();
745 move |mut params, cx| {
746 let adapter = adapter.clone();
747 if let Some(this) = this.upgrade() {
748 this.update(cx, |this, cx| {
749 {
750 let buffer = params
751 .uri
752 .to_file_path()
753 .map(|file_path| this.get_buffer(&file_path, cx))
754 .ok()
755 .flatten();
756 adapter.process_diagnostics(&mut params, server_id, buffer);
757 }
758
759 this.merge_lsp_diagnostics(
760 DiagnosticSourceKind::Pushed,
761 vec![DocumentDiagnosticsUpdate {
762 server_id,
763 diagnostics: params,
764 result_id: None,
765 disk_based_sources: Cow::Borrowed(
766 &adapter.disk_based_diagnostic_sources,
767 ),
768 registration_id: None,
769 }],
770 |_, diagnostic, cx| match diagnostic.source_kind {
771 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
772 adapter.retain_old_diagnostic(diagnostic, cx)
773 }
774 DiagnosticSourceKind::Pulled => true,
775 },
776 cx,
777 )
778 .log_err();
779 })
780 .ok();
781 }
782 }
783 })
784 .detach();
785 language_server
786 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
787 let adapter = adapter.adapter.clone();
788 let delegate = delegate.clone();
789 let this = lsp_store.clone();
790 move |params, cx| {
791 let adapter = adapter.clone();
792 let delegate = delegate.clone();
793 let this = this.clone();
794 let mut cx = cx.clone();
795 async move {
796 let toolchain_for_id = this
797 .update(&mut cx, |this, _| {
798 this.as_local()?.language_server_ids.iter().find_map(
799 |(seed, value)| {
800 (value.id == server_id).then(|| seed.toolchain.clone())
801 },
802 )
803 })?
804 .context("Expected the LSP store to be in a local mode")?;
805
806 let mut scope_uri_to_workspace_config = BTreeMap::new();
807 for item in ¶ms.items {
808 let scope_uri = item.scope_uri.clone();
809 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
810 scope_uri_to_workspace_config.entry(scope_uri.clone())
811 else {
812 // We've already queried workspace configuration of this URI.
813 continue;
814 };
815 let workspace_config = Self::workspace_configuration_for_adapter(
816 adapter.clone(),
817 &delegate,
818 toolchain_for_id.clone(),
819 scope_uri,
820 &mut cx,
821 )
822 .await?;
823 new_scope_uri.insert(workspace_config);
824 }
825
826 Ok(params
827 .items
828 .into_iter()
829 .filter_map(|item| {
830 let workspace_config =
831 scope_uri_to_workspace_config.get(&item.scope_uri)?;
832 if let Some(section) = &item.section {
833 Some(
834 workspace_config
835 .get(section)
836 .cloned()
837 .unwrap_or(serde_json::Value::Null),
838 )
839 } else {
840 Some(workspace_config.clone())
841 }
842 })
843 .collect())
844 }
845 }
846 })
847 .detach();
848
849 language_server
850 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
851 let this = lsp_store.clone();
852 move |_, cx| {
853 let this = this.clone();
854 let cx = cx.clone();
855 async move {
856 let Some(server) =
857 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
858 else {
859 return Ok(None);
860 };
861 let root = server.workspace_folders();
862 Ok(Some(
863 root.into_iter()
864 .map(|uri| WorkspaceFolder {
865 uri,
866 name: Default::default(),
867 })
868 .collect(),
869 ))
870 }
871 }
872 })
873 .detach();
874 // Even though we don't have handling for these requests, respond to them to
875 // avoid stalling any language server like `gopls` which waits for a response
876 // to these requests when initializing.
877 language_server
878 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
879 let this = lsp_store.clone();
880 move |params, cx| {
881 let this = this.clone();
882 let mut cx = cx.clone();
883 async move {
884 this.update(&mut cx, |this, _| {
885 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
886 {
887 status
888 .progress_tokens
889 .insert(ProgressToken::from_lsp(params.token));
890 }
891 })?;
892
893 Ok(())
894 }
895 }
896 })
897 .detach();
898
899 language_server
900 .on_request::<lsp::request::RegisterCapability, _, _>({
901 let lsp_store = lsp_store.clone();
902 move |params, cx| {
903 let lsp_store = lsp_store.clone();
904 let mut cx = cx.clone();
905 async move {
906 lsp_store
907 .update(&mut cx, |lsp_store, cx| {
908 if lsp_store.as_local().is_some() {
909 match lsp_store
910 .register_server_capabilities(server_id, params, cx)
911 {
912 Ok(()) => {}
913 Err(e) => {
914 log::error!(
915 "Failed to register server capabilities: {e:#}"
916 );
917 }
918 };
919 }
920 })
921 .ok();
922 Ok(())
923 }
924 }
925 })
926 .detach();
927
928 language_server
929 .on_request::<lsp::request::UnregisterCapability, _, _>({
930 let lsp_store = lsp_store.clone();
931 move |params, cx| {
932 let lsp_store = lsp_store.clone();
933 let mut cx = cx.clone();
934 async move {
935 lsp_store
936 .update(&mut cx, |lsp_store, cx| {
937 if lsp_store.as_local().is_some() {
938 match lsp_store
939 .unregister_server_capabilities(server_id, params, cx)
940 {
941 Ok(()) => {}
942 Err(e) => {
943 log::error!(
944 "Failed to unregister server capabilities: {e:#}"
945 );
946 }
947 }
948 }
949 })
950 .ok();
951 Ok(())
952 }
953 }
954 })
955 .detach();
956
957 language_server
958 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
959 let this = lsp_store.clone();
960 move |params, cx| {
961 let mut cx = cx.clone();
962 let this = this.clone();
963 async move {
964 LocalLspStore::on_lsp_workspace_edit(
965 this.clone(),
966 params,
967 server_id,
968 &mut cx,
969 )
970 .await
971 }
972 }
973 })
974 .detach();
975
976 language_server
977 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
978 let lsp_store = lsp_store.clone();
979 let request_id = Arc::new(AtomicUsize::new(0));
980 move |(), cx| {
981 let lsp_store = lsp_store.clone();
982 let request_id = request_id.clone();
983 let mut cx = cx.clone();
984 async move {
985 lsp_store
986 .update(&mut cx, |lsp_store, cx| {
987 let request_id =
988 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
989 cx.emit(LspStoreEvent::RefreshInlayHints {
990 server_id,
991 request_id,
992 });
993 lsp_store
994 .downstream_client
995 .as_ref()
996 .map(|(client, project_id)| {
997 client.send(proto::RefreshInlayHints {
998 project_id: *project_id,
999 server_id: server_id.to_proto(),
1000 request_id: request_id.map(|id| id as u64),
1001 })
1002 })
1003 })?
1004 .transpose()?;
1005 Ok(())
1006 }
1007 }
1008 })
1009 .detach();
1010
1011 language_server
1012 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1013 let this = lsp_store.clone();
1014 move |(), cx| {
1015 let this = this.clone();
1016 let mut cx = cx.clone();
1017 async move {
1018 this.update(&mut cx, |this, cx| {
1019 cx.emit(LspStoreEvent::RefreshCodeLens);
1020 this.downstream_client.as_ref().map(|(client, project_id)| {
1021 client.send(proto::RefreshCodeLens {
1022 project_id: *project_id,
1023 })
1024 })
1025 })?
1026 .transpose()?;
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1035 let this = lsp_store.clone();
1036 move |(), cx| {
1037 let this = this.clone();
1038 let mut cx = cx.clone();
1039 async move {
1040 this.update(&mut cx, |lsp_store, _| {
1041 lsp_store.pull_workspace_diagnostics(server_id);
1042 lsp_store
1043 .downstream_client
1044 .as_ref()
1045 .map(|(client, project_id)| {
1046 client.send(proto::PullWorkspaceDiagnostics {
1047 project_id: *project_id,
1048 server_id: server_id.to_proto(),
1049 })
1050 })
1051 })?
1052 .transpose()?;
1053 Ok(())
1054 }
1055 }
1056 })
1057 .detach();
1058
1059 language_server
1060 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1061 let this = lsp_store.clone();
1062 let name = name.to_string();
1063 let adapter = adapter.clone();
1064 move |params, cx| {
1065 let this = this.clone();
1066 let name = name.to_string();
1067 let adapter = adapter.clone();
1068 let mut cx = cx.clone();
1069 async move {
1070 let actions = params.actions.unwrap_or_default();
1071 let message = params.message.clone();
1072 let (tx, rx) = smol::channel::bounded(1);
1073 let request = LanguageServerPromptRequest {
1074 level: match params.typ {
1075 lsp::MessageType::ERROR => PromptLevel::Critical,
1076 lsp::MessageType::WARNING => PromptLevel::Warning,
1077 _ => PromptLevel::Info,
1078 },
1079 message: params.message,
1080 actions,
1081 response_channel: tx,
1082 lsp_name: name.clone(),
1083 };
1084
1085 let did_update = this
1086 .update(&mut cx, |_, cx| {
1087 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1088 })
1089 .is_ok();
1090 if did_update {
1091 let response = rx.recv().await.ok();
1092 if let Some(ref selected_action) = response {
1093 let context = language::PromptResponseContext {
1094 message,
1095 selected_action: selected_action.clone(),
1096 };
1097 adapter.process_prompt_response(&context, &mut cx)
1098 }
1099
1100 Ok(response)
1101 } else {
1102 Ok(None)
1103 }
1104 }
1105 }
1106 })
1107 .detach();
1108 language_server
1109 .on_notification::<lsp::notification::ShowMessage, _>({
1110 let this = lsp_store.clone();
1111 let name = name.to_string();
1112 move |params, cx| {
1113 let this = this.clone();
1114 let name = name.to_string();
1115 let mut cx = cx.clone();
1116
1117 let (tx, _) = smol::channel::bounded(1);
1118 let request = LanguageServerPromptRequest {
1119 level: match params.typ {
1120 lsp::MessageType::ERROR => PromptLevel::Critical,
1121 lsp::MessageType::WARNING => PromptLevel::Warning,
1122 _ => PromptLevel::Info,
1123 },
1124 message: params.message,
1125 actions: vec![],
1126 response_channel: tx,
1127 lsp_name: name,
1128 };
1129
1130 let _ = this.update(&mut cx, |_, cx| {
1131 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1132 });
1133 }
1134 })
1135 .detach();
1136
1137 let disk_based_diagnostics_progress_token =
1138 adapter.disk_based_diagnostics_progress_token.clone();
1139
1140 language_server
1141 .on_notification::<lsp::notification::Progress, _>({
1142 let this = lsp_store.clone();
1143 move |params, cx| {
1144 if let Some(this) = this.upgrade() {
1145 this.update(cx, |this, cx| {
1146 this.on_lsp_progress(
1147 params,
1148 server_id,
1149 disk_based_diagnostics_progress_token.clone(),
1150 cx,
1151 );
1152 })
1153 .ok();
1154 }
1155 }
1156 })
1157 .detach();
1158
1159 language_server
1160 .on_notification::<lsp::notification::LogMessage, _>({
1161 let this = lsp_store.clone();
1162 move |params, cx| {
1163 if let Some(this) = this.upgrade() {
1164 this.update(cx, |_, cx| {
1165 cx.emit(LspStoreEvent::LanguageServerLog(
1166 server_id,
1167 LanguageServerLogType::Log(params.typ),
1168 params.message,
1169 ));
1170 })
1171 .ok();
1172 }
1173 }
1174 })
1175 .detach();
1176
1177 language_server
1178 .on_notification::<lsp::notification::LogTrace, _>({
1179 let this = lsp_store.clone();
1180 move |params, cx| {
1181 let mut cx = cx.clone();
1182 if let Some(this) = this.upgrade() {
1183 this.update(&mut cx, |_, cx| {
1184 cx.emit(LspStoreEvent::LanguageServerLog(
1185 server_id,
1186 LanguageServerLogType::Trace {
1187 verbose_info: params.verbose,
1188 },
1189 params.message,
1190 ));
1191 })
1192 .ok();
1193 }
1194 }
1195 })
1196 .detach();
1197
1198 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1199 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1200 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1201 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1202 }
1203
1204 fn shutdown_language_servers_on_quit(
1205 &mut self,
1206 _: &mut Context<LspStore>,
1207 ) -> impl Future<Output = ()> + use<> {
1208 let shutdown_futures = self
1209 .language_servers
1210 .drain()
1211 .map(|(_, server_state)| Self::shutdown_server(server_state))
1212 .collect::<Vec<_>>();
1213
1214 async move {
1215 join_all(shutdown_futures).await;
1216 }
1217 }
1218
1219 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1220 match server_state {
1221 LanguageServerState::Running { server, .. } => {
1222 if let Some(shutdown) = server.shutdown() {
1223 shutdown.await;
1224 }
1225 }
1226 LanguageServerState::Starting { startup, .. } => {
1227 if let Some(server) = startup.await
1228 && let Some(shutdown) = server.shutdown()
1229 {
1230 shutdown.await;
1231 }
1232 }
1233 }
1234 Ok(())
1235 }
1236
1237 fn language_servers_for_worktree(
1238 &self,
1239 worktree_id: WorktreeId,
1240 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1241 self.language_server_ids
1242 .iter()
1243 .filter_map(move |(seed, state)| {
1244 if seed.worktree_id != worktree_id {
1245 return None;
1246 }
1247
1248 if let Some(LanguageServerState::Running { server, .. }) =
1249 self.language_servers.get(&state.id)
1250 {
1251 Some(server)
1252 } else {
1253 None
1254 }
1255 })
1256 }
1257
1258 fn language_server_ids_for_project_path(
1259 &self,
1260 project_path: ProjectPath,
1261 language: &Language,
1262 cx: &mut App,
1263 ) -> Vec<LanguageServerId> {
1264 let Some(worktree) = self
1265 .worktree_store
1266 .read(cx)
1267 .worktree_for_id(project_path.worktree_id, cx)
1268 else {
1269 return Vec::new();
1270 };
1271 let delegate: Arc<dyn ManifestDelegate> =
1272 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1273
1274 self.lsp_tree
1275 .get(
1276 project_path,
1277 language.name(),
1278 language.manifest(),
1279 &delegate,
1280 cx,
1281 )
1282 .collect::<Vec<_>>()
1283 }
1284
1285 fn language_server_ids_for_buffer(
1286 &self,
1287 buffer: &Buffer,
1288 cx: &mut App,
1289 ) -> Vec<LanguageServerId> {
1290 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1291 let worktree_id = file.worktree_id(cx);
1292
1293 let path: Arc<RelPath> = file
1294 .path()
1295 .parent()
1296 .map(Arc::from)
1297 .unwrap_or_else(|| file.path().clone());
1298 let worktree_path = ProjectPath { worktree_id, path };
1299 self.language_server_ids_for_project_path(worktree_path, language, cx)
1300 } else {
1301 Vec::new()
1302 }
1303 }
1304
1305 fn language_servers_for_buffer<'a>(
1306 &'a self,
1307 buffer: &'a Buffer,
1308 cx: &'a mut App,
1309 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1310 self.language_server_ids_for_buffer(buffer, cx)
1311 .into_iter()
1312 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1313 LanguageServerState::Running {
1314 adapter, server, ..
1315 } => Some((adapter, server)),
1316 _ => None,
1317 })
1318 }
1319
1320 async fn execute_code_action_kind_locally(
1321 lsp_store: WeakEntity<LspStore>,
1322 mut buffers: Vec<Entity<Buffer>>,
1323 kind: CodeActionKind,
1324 push_to_history: bool,
1325 cx: &mut AsyncApp,
1326 ) -> anyhow::Result<ProjectTransaction> {
1327 // Do not allow multiple concurrent code actions requests for the
1328 // same buffer.
1329 lsp_store.update(cx, |this, cx| {
1330 let this = this.as_local_mut().unwrap();
1331 buffers.retain(|buffer| {
1332 this.buffers_being_formatted
1333 .insert(buffer.read(cx).remote_id())
1334 });
1335 })?;
1336 let _cleanup = defer({
1337 let this = lsp_store.clone();
1338 let mut cx = cx.clone();
1339 let buffers = &buffers;
1340 move || {
1341 this.update(&mut cx, |this, cx| {
1342 let this = this.as_local_mut().unwrap();
1343 for buffer in buffers {
1344 this.buffers_being_formatted
1345 .remove(&buffer.read(cx).remote_id());
1346 }
1347 })
1348 .ok();
1349 }
1350 });
1351 let mut project_transaction = ProjectTransaction::default();
1352
1353 for buffer in &buffers {
1354 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1355 buffer.update(cx, |buffer, cx| {
1356 lsp_store
1357 .as_local()
1358 .unwrap()
1359 .language_servers_for_buffer(buffer, cx)
1360 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1361 .collect::<Vec<_>>()
1362 })
1363 })?;
1364 for (_, language_server) in adapters_and_servers.iter() {
1365 let actions = Self::get_server_code_actions_from_action_kinds(
1366 &lsp_store,
1367 language_server.server_id(),
1368 vec![kind.clone()],
1369 buffer,
1370 cx,
1371 )
1372 .await?;
1373 Self::execute_code_actions_on_server(
1374 &lsp_store,
1375 language_server,
1376 actions,
1377 push_to_history,
1378 &mut project_transaction,
1379 cx,
1380 )
1381 .await?;
1382 }
1383 }
1384 Ok(project_transaction)
1385 }
1386
1387 async fn format_locally(
1388 lsp_store: WeakEntity<LspStore>,
1389 mut buffers: Vec<FormattableBuffer>,
1390 push_to_history: bool,
1391 trigger: FormatTrigger,
1392 logger: zlog::Logger,
1393 cx: &mut AsyncApp,
1394 ) -> anyhow::Result<ProjectTransaction> {
1395 // Do not allow multiple concurrent formatting requests for the
1396 // same buffer.
1397 lsp_store.update(cx, |this, cx| {
1398 let this = this.as_local_mut().unwrap();
1399 buffers.retain(|buffer| {
1400 this.buffers_being_formatted
1401 .insert(buffer.handle.read(cx).remote_id())
1402 });
1403 })?;
1404
1405 let _cleanup = defer({
1406 let this = lsp_store.clone();
1407 let mut cx = cx.clone();
1408 let buffers = &buffers;
1409 move || {
1410 this.update(&mut cx, |this, cx| {
1411 let this = this.as_local_mut().unwrap();
1412 for buffer in buffers {
1413 this.buffers_being_formatted
1414 .remove(&buffer.handle.read(cx).remote_id());
1415 }
1416 })
1417 .ok();
1418 }
1419 });
1420
1421 let mut project_transaction = ProjectTransaction::default();
1422
1423 for buffer in &buffers {
1424 zlog::debug!(
1425 logger =>
1426 "formatting buffer '{:?}'",
1427 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1428 );
1429 // Create an empty transaction to hold all of the formatting edits.
1430 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1431 // ensure no transactions created while formatting are
1432 // grouped with the previous transaction in the history
1433 // based on the transaction group interval
1434 buffer.finalize_last_transaction();
1435 buffer
1436 .start_transaction()
1437 .context("transaction already open")?;
1438 buffer.end_transaction(cx);
1439 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1440 buffer.finalize_last_transaction();
1441 anyhow::Ok(transaction_id)
1442 })??;
1443
1444 let result = Self::format_buffer_locally(
1445 lsp_store.clone(),
1446 buffer,
1447 formatting_transaction_id,
1448 trigger,
1449 logger,
1450 cx,
1451 )
1452 .await;
1453
1454 buffer.handle.update(cx, |buffer, cx| {
1455 let Some(formatting_transaction) =
1456 buffer.get_transaction(formatting_transaction_id).cloned()
1457 else {
1458 zlog::warn!(logger => "no formatting transaction");
1459 return;
1460 };
1461 if formatting_transaction.edit_ids.is_empty() {
1462 zlog::debug!(logger => "no changes made while formatting");
1463 buffer.forget_transaction(formatting_transaction_id);
1464 return;
1465 }
1466 if !push_to_history {
1467 zlog::trace!(logger => "forgetting format transaction");
1468 buffer.forget_transaction(formatting_transaction.id);
1469 }
1470 project_transaction
1471 .0
1472 .insert(cx.entity(), formatting_transaction);
1473 })?;
1474
1475 result?;
1476 }
1477
1478 Ok(project_transaction)
1479 }
1480
1481 async fn format_buffer_locally(
1482 lsp_store: WeakEntity<LspStore>,
1483 buffer: &FormattableBuffer,
1484 formatting_transaction_id: clock::Lamport,
1485 trigger: FormatTrigger,
1486 logger: zlog::Logger,
1487 cx: &mut AsyncApp,
1488 ) -> Result<()> {
1489 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1490 buffer.handle.update(cx, |buffer, cx| {
1491 let adapters_and_servers = lsp_store
1492 .as_local()
1493 .unwrap()
1494 .language_servers_for_buffer(buffer, cx)
1495 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1496 .collect::<Vec<_>>();
1497 let settings =
1498 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1499 .into_owned();
1500 (adapters_and_servers, settings)
1501 })
1502 })?;
1503
1504 /// Apply edits to the buffer that will become part of the formatting transaction.
1505 /// Fails if the buffer has been edited since the start of that transaction.
1506 fn extend_formatting_transaction(
1507 buffer: &FormattableBuffer,
1508 formatting_transaction_id: text::TransactionId,
1509 cx: &mut AsyncApp,
1510 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1511 ) -> anyhow::Result<()> {
1512 buffer.handle.update(cx, |buffer, cx| {
1513 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1514 if last_transaction_id != Some(formatting_transaction_id) {
1515 anyhow::bail!("Buffer edited while formatting. Aborting")
1516 }
1517 buffer.start_transaction();
1518 operation(buffer, cx);
1519 if let Some(transaction_id) = buffer.end_transaction(cx) {
1520 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1521 }
1522 Ok(())
1523 })?
1524 }
1525
1526 // handle whitespace formatting
1527 if settings.remove_trailing_whitespace_on_save {
1528 zlog::trace!(logger => "removing trailing whitespace");
1529 let diff = buffer
1530 .handle
1531 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1532 .await;
1533 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1534 buffer.apply_diff(diff, cx);
1535 })?;
1536 }
1537
1538 if settings.ensure_final_newline_on_save {
1539 zlog::trace!(logger => "ensuring final newline");
1540 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1541 buffer.ensure_final_newline(cx);
1542 })?;
1543 }
1544
1545 // Formatter for `code_actions_on_format` that runs before
1546 // the rest of the formatters
1547 let mut code_actions_on_format_formatters = None;
1548 let should_run_code_actions_on_format = !matches!(
1549 (trigger, &settings.format_on_save),
1550 (FormatTrigger::Save, &FormatOnSave::Off)
1551 );
1552 if should_run_code_actions_on_format {
1553 let have_code_actions_to_run_on_format = settings
1554 .code_actions_on_format
1555 .values()
1556 .any(|enabled| *enabled);
1557 if have_code_actions_to_run_on_format {
1558 zlog::trace!(logger => "going to run code actions on format");
1559 code_actions_on_format_formatters = Some(
1560 settings
1561 .code_actions_on_format
1562 .iter()
1563 .filter_map(|(action, enabled)| enabled.then_some(action))
1564 .cloned()
1565 .map(Formatter::CodeAction)
1566 .collect::<Vec<_>>(),
1567 );
1568 }
1569 }
1570
1571 let formatters = match (trigger, &settings.format_on_save) {
1572 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1573 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1574 settings.formatter.as_ref()
1575 }
1576 };
1577
1578 let formatters = code_actions_on_format_formatters
1579 .iter()
1580 .flatten()
1581 .chain(formatters);
1582
1583 for formatter in formatters {
1584 let formatter = if formatter == &Formatter::Auto {
1585 if settings.prettier.allowed {
1586 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1587 &Formatter::Prettier
1588 } else {
1589 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1590 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1591 }
1592 } else {
1593 formatter
1594 };
1595 match formatter {
1596 Formatter::Auto => unreachable!("Auto resolved above"),
1597 Formatter::Prettier => {
1598 let logger = zlog::scoped!(logger => "prettier");
1599 zlog::trace!(logger => "formatting");
1600 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1601
1602 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1603 lsp_store.prettier_store().unwrap().downgrade()
1604 })?;
1605 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1606 .await
1607 .transpose()?;
1608 let Some(diff) = diff else {
1609 zlog::trace!(logger => "No changes");
1610 continue;
1611 };
1612
1613 extend_formatting_transaction(
1614 buffer,
1615 formatting_transaction_id,
1616 cx,
1617 |buffer, cx| {
1618 buffer.apply_diff(diff, cx);
1619 },
1620 )?;
1621 }
1622 Formatter::External { command, arguments } => {
1623 let logger = zlog::scoped!(logger => "command");
1624 zlog::trace!(logger => "formatting");
1625 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1626
1627 let diff = Self::format_via_external_command(
1628 buffer,
1629 command.as_ref(),
1630 arguments.as_deref(),
1631 cx,
1632 )
1633 .await
1634 .with_context(|| {
1635 format!("Failed to format buffer via external command: {}", command)
1636 })?;
1637 let Some(diff) = diff else {
1638 zlog::trace!(logger => "No changes");
1639 continue;
1640 };
1641
1642 extend_formatting_transaction(
1643 buffer,
1644 formatting_transaction_id,
1645 cx,
1646 |buffer, cx| {
1647 buffer.apply_diff(diff, cx);
1648 },
1649 )?;
1650 }
1651 Formatter::LanguageServer(specifier) => {
1652 let logger = zlog::scoped!(logger => "language-server");
1653 zlog::trace!(logger => "formatting");
1654 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1655
1656 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1657 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1658 continue;
1659 };
1660
1661 let language_server = match specifier {
1662 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1663 adapters_and_servers.iter().find_map(|(adapter, server)| {
1664 if adapter.name.0.as_ref() == name {
1665 Some(server.clone())
1666 } else {
1667 None
1668 }
1669 })
1670 }
1671 settings::LanguageServerFormatterSpecifier::Current => {
1672 adapters_and_servers.first().map(|e| e.1.clone())
1673 }
1674 };
1675
1676 let Some(language_server) = language_server else {
1677 log::debug!(
1678 "No language server found to format buffer '{:?}'. Skipping",
1679 buffer_path_abs.as_path().to_string_lossy()
1680 );
1681 continue;
1682 };
1683
1684 zlog::trace!(
1685 logger =>
1686 "Formatting buffer '{:?}' using language server '{:?}'",
1687 buffer_path_abs.as_path().to_string_lossy(),
1688 language_server.name()
1689 );
1690
1691 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1692 zlog::trace!(logger => "formatting ranges");
1693 Self::format_ranges_via_lsp(
1694 &lsp_store,
1695 &buffer.handle,
1696 ranges,
1697 buffer_path_abs,
1698 &language_server,
1699 &settings,
1700 cx,
1701 )
1702 .await
1703 .context("Failed to format ranges via language server")?
1704 } else {
1705 zlog::trace!(logger => "formatting full");
1706 Self::format_via_lsp(
1707 &lsp_store,
1708 &buffer.handle,
1709 buffer_path_abs,
1710 &language_server,
1711 &settings,
1712 cx,
1713 )
1714 .await
1715 .context("failed to format via language server")?
1716 };
1717
1718 if edits.is_empty() {
1719 zlog::trace!(logger => "No changes");
1720 continue;
1721 }
1722 extend_formatting_transaction(
1723 buffer,
1724 formatting_transaction_id,
1725 cx,
1726 |buffer, cx| {
1727 buffer.edit(edits, None, cx);
1728 },
1729 )?;
1730 }
1731 Formatter::CodeAction(code_action_name) => {
1732 let logger = zlog::scoped!(logger => "code-actions");
1733 zlog::trace!(logger => "formatting");
1734 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1735
1736 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1737 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1738 continue;
1739 };
1740
1741 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1742 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1743
1744 let mut actions_and_servers = Vec::new();
1745
1746 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1747 let actions_result = Self::get_server_code_actions_from_action_kinds(
1748 &lsp_store,
1749 language_server.server_id(),
1750 vec![code_action_kind.clone()],
1751 &buffer.handle,
1752 cx,
1753 )
1754 .await
1755 .with_context(|| {
1756 format!(
1757 "Failed to resolve code action {:?} with language server {}",
1758 code_action_kind,
1759 language_server.name()
1760 )
1761 });
1762 let Ok(actions) = actions_result else {
1763 // note: it may be better to set result to the error and break formatters here
1764 // but for now we try to execute the actions that we can resolve and skip the rest
1765 zlog::error!(
1766 logger =>
1767 "Failed to resolve code action {:?} with language server {}",
1768 code_action_kind,
1769 language_server.name()
1770 );
1771 continue;
1772 };
1773 for action in actions {
1774 actions_and_servers.push((action, index));
1775 }
1776 }
1777
1778 if actions_and_servers.is_empty() {
1779 zlog::warn!(logger => "No code actions were resolved, continuing");
1780 continue;
1781 }
1782
1783 'actions: for (mut action, server_index) in actions_and_servers {
1784 let server = &adapters_and_servers[server_index].1;
1785
1786 let describe_code_action = |action: &CodeAction| {
1787 format!(
1788 "code action '{}' with title \"{}\" on server {}",
1789 action
1790 .lsp_action
1791 .action_kind()
1792 .unwrap_or("unknown".into())
1793 .as_str(),
1794 action.lsp_action.title(),
1795 server.name(),
1796 )
1797 };
1798
1799 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1800
1801 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1802 zlog::error!(
1803 logger =>
1804 "Failed to resolve {}. Error: {}",
1805 describe_code_action(&action),
1806 err
1807 );
1808 continue;
1809 }
1810
1811 if let Some(edit) = action.lsp_action.edit().cloned() {
1812 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1813 // but filters out and logs warnings for code actions that require unreasonably
1814 // difficult handling on our part, such as:
1815 // - applying edits that call commands
1816 // which can result in arbitrary workspace edits being sent from the server that
1817 // have no way of being tied back to the command that initiated them (i.e. we
1818 // can't know which edits are part of the format request, or if the server is done sending
1819 // actions in response to the command)
1820 // - actions that create/delete/modify/rename files other than the one we are formatting
1821 // as we then would need to handle such changes correctly in the local history as well
1822 // as the remote history through the ProjectTransaction
1823 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1824 // Supporting these actions is not impossible, but not supported as of yet.
1825 if edit.changes.is_none() && edit.document_changes.is_none() {
1826 zlog::trace!(
1827 logger =>
1828 "No changes for code action. Skipping {}",
1829 describe_code_action(&action),
1830 );
1831 continue;
1832 }
1833
1834 let mut operations = Vec::new();
1835 if let Some(document_changes) = edit.document_changes {
1836 match document_changes {
1837 lsp::DocumentChanges::Edits(edits) => operations.extend(
1838 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1839 ),
1840 lsp::DocumentChanges::Operations(ops) => operations = ops,
1841 }
1842 } else if let Some(changes) = edit.changes {
1843 operations.extend(changes.into_iter().map(|(uri, edits)| {
1844 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1845 text_document:
1846 lsp::OptionalVersionedTextDocumentIdentifier {
1847 uri,
1848 version: None,
1849 },
1850 edits: edits.into_iter().map(Edit::Plain).collect(),
1851 })
1852 }));
1853 }
1854
1855 let mut edits = Vec::with_capacity(operations.len());
1856
1857 if operations.is_empty() {
1858 zlog::trace!(
1859 logger =>
1860 "No changes for code action. Skipping {}",
1861 describe_code_action(&action),
1862 );
1863 continue;
1864 }
1865 for operation in operations {
1866 let op = match operation {
1867 lsp::DocumentChangeOperation::Edit(op) => op,
1868 lsp::DocumentChangeOperation::Op(_) => {
1869 zlog::warn!(
1870 logger =>
1871 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1872 describe_code_action(&action),
1873 );
1874 continue 'actions;
1875 }
1876 };
1877 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1878 zlog::warn!(
1879 logger =>
1880 "Failed to convert URI '{:?}' to file path. Skipping {}",
1881 &op.text_document.uri,
1882 describe_code_action(&action),
1883 );
1884 continue 'actions;
1885 };
1886 if &file_path != buffer_path_abs {
1887 zlog::warn!(
1888 logger =>
1889 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1890 file_path,
1891 buffer_path_abs,
1892 describe_code_action(&action),
1893 );
1894 continue 'actions;
1895 }
1896
1897 let mut lsp_edits = Vec::new();
1898 for edit in op.edits {
1899 match edit {
1900 Edit::Plain(edit) => {
1901 if !lsp_edits.contains(&edit) {
1902 lsp_edits.push(edit);
1903 }
1904 }
1905 Edit::Annotated(edit) => {
1906 if !lsp_edits.contains(&edit.text_edit) {
1907 lsp_edits.push(edit.text_edit);
1908 }
1909 }
1910 Edit::Snippet(_) => {
1911 zlog::warn!(
1912 logger =>
1913 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1914 describe_code_action(&action),
1915 );
1916 continue 'actions;
1917 }
1918 }
1919 }
1920 let edits_result = lsp_store
1921 .update(cx, |lsp_store, cx| {
1922 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1923 &buffer.handle,
1924 lsp_edits,
1925 server.server_id(),
1926 op.text_document.version,
1927 cx,
1928 )
1929 })?
1930 .await;
1931 let Ok(resolved_edits) = edits_result else {
1932 zlog::warn!(
1933 logger =>
1934 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1935 buffer_path_abs.as_path(),
1936 describe_code_action(&action),
1937 );
1938 continue 'actions;
1939 };
1940 edits.extend(resolved_edits);
1941 }
1942
1943 if edits.is_empty() {
1944 zlog::warn!(logger => "No edits resolved from LSP");
1945 continue;
1946 }
1947
1948 extend_formatting_transaction(
1949 buffer,
1950 formatting_transaction_id,
1951 cx,
1952 |buffer, cx| {
1953 zlog::info!(
1954 "Applying edits {edits:?}. Content: {:?}",
1955 buffer.text()
1956 );
1957 buffer.edit(edits, None, cx);
1958 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1959 },
1960 )?;
1961 }
1962
1963 if let Some(command) = action.lsp_action.command() {
1964 zlog::warn!(
1965 logger =>
1966 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1967 &command.command,
1968 );
1969
1970 // bail early if command is invalid
1971 let server_capabilities = server.capabilities();
1972 let available_commands = server_capabilities
1973 .execute_command_provider
1974 .as_ref()
1975 .map(|options| options.commands.as_slice())
1976 .unwrap_or_default();
1977 if !available_commands.contains(&command.command) {
1978 zlog::warn!(
1979 logger =>
1980 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1981 command.command,
1982 server.name(),
1983 );
1984 continue;
1985 }
1986
1987 // noop so we just ensure buffer hasn't been edited since resolving code actions
1988 extend_formatting_transaction(
1989 buffer,
1990 formatting_transaction_id,
1991 cx,
1992 |_, _| {},
1993 )?;
1994 zlog::info!(logger => "Executing command {}", &command.command);
1995
1996 lsp_store.update(cx, |this, _| {
1997 this.as_local_mut()
1998 .unwrap()
1999 .last_workspace_edits_by_language_server
2000 .remove(&server.server_id());
2001 })?;
2002
2003 let execute_command_result = server
2004 .request::<lsp::request::ExecuteCommand>(
2005 lsp::ExecuteCommandParams {
2006 command: command.command.clone(),
2007 arguments: command.arguments.clone().unwrap_or_default(),
2008 ..Default::default()
2009 },
2010 )
2011 .await
2012 .into_response();
2013
2014 if execute_command_result.is_err() {
2015 zlog::error!(
2016 logger =>
2017 "Failed to execute command '{}' as part of {}",
2018 &command.command,
2019 describe_code_action(&action),
2020 );
2021 continue 'actions;
2022 }
2023
2024 let mut project_transaction_command =
2025 lsp_store.update(cx, |this, _| {
2026 this.as_local_mut()
2027 .unwrap()
2028 .last_workspace_edits_by_language_server
2029 .remove(&server.server_id())
2030 .unwrap_or_default()
2031 })?;
2032
2033 if let Some(transaction) =
2034 project_transaction_command.0.remove(&buffer.handle)
2035 {
2036 zlog::trace!(
2037 logger =>
2038 "Successfully captured {} edits that resulted from command {}",
2039 transaction.edit_ids.len(),
2040 &command.command,
2041 );
2042 let transaction_id_project_transaction = transaction.id;
2043 buffer.handle.update(cx, |buffer, _| {
2044 // it may have been removed from history if push_to_history was
2045 // false in deserialize_workspace_edit. If so push it so we
2046 // can merge it with the format transaction
2047 // and pop the combined transaction off the history stack
2048 // later if push_to_history is false
2049 if buffer.get_transaction(transaction.id).is_none() {
2050 buffer.push_transaction(transaction, Instant::now());
2051 }
2052 buffer.merge_transactions(
2053 transaction_id_project_transaction,
2054 formatting_transaction_id,
2055 );
2056 })?;
2057 }
2058
2059 if !project_transaction_command.0.is_empty() {
2060 let mut extra_buffers = String::new();
2061 for buffer in project_transaction_command.0.keys() {
2062 buffer
2063 .read_with(cx, |b, cx| {
2064 if let Some(path) = b.project_path(cx) {
2065 if !extra_buffers.is_empty() {
2066 extra_buffers.push_str(", ");
2067 }
2068 extra_buffers.push_str(path.path.as_unix_str());
2069 }
2070 })
2071 .ok();
2072 }
2073 zlog::warn!(
2074 logger =>
2075 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2076 &command.command,
2077 extra_buffers,
2078 );
2079 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2080 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2081 // add it so it's included, and merge it into the format transaction when its created later
2082 }
2083 }
2084 }
2085 }
2086 }
2087 }
2088
2089 Ok(())
2090 }
2091
2092 pub async fn format_ranges_via_lsp(
2093 this: &WeakEntity<LspStore>,
2094 buffer_handle: &Entity<Buffer>,
2095 ranges: &[Range<Anchor>],
2096 abs_path: &Path,
2097 language_server: &Arc<LanguageServer>,
2098 settings: &LanguageSettings,
2099 cx: &mut AsyncApp,
2100 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2101 let capabilities = &language_server.capabilities();
2102 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2103 if range_formatting_provider == Some(&OneOf::Left(false)) {
2104 anyhow::bail!(
2105 "{} language server does not support range formatting",
2106 language_server.name()
2107 );
2108 }
2109
2110 let uri = file_path_to_lsp_url(abs_path)?;
2111 let text_document = lsp::TextDocumentIdentifier::new(uri);
2112
2113 let lsp_edits = {
2114 let mut lsp_ranges = Vec::new();
2115 this.update(cx, |_this, cx| {
2116 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2117 // not have been sent to the language server. This seems like a fairly systemic
2118 // issue, though, the resolution probably is not specific to formatting.
2119 //
2120 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2121 // LSP.
2122 let snapshot = buffer_handle.read(cx).snapshot();
2123 for range in ranges {
2124 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2125 }
2126 anyhow::Ok(())
2127 })??;
2128
2129 let mut edits = None;
2130 for range in lsp_ranges {
2131 if let Some(mut edit) = language_server
2132 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2133 text_document: text_document.clone(),
2134 range,
2135 options: lsp_command::lsp_formatting_options(settings),
2136 work_done_progress_params: Default::default(),
2137 })
2138 .await
2139 .into_response()?
2140 {
2141 edits.get_or_insert_with(Vec::new).append(&mut edit);
2142 }
2143 }
2144 edits
2145 };
2146
2147 if let Some(lsp_edits) = lsp_edits {
2148 this.update(cx, |this, cx| {
2149 this.as_local_mut().unwrap().edits_from_lsp(
2150 buffer_handle,
2151 lsp_edits,
2152 language_server.server_id(),
2153 None,
2154 cx,
2155 )
2156 })?
2157 .await
2158 } else {
2159 Ok(Vec::with_capacity(0))
2160 }
2161 }
2162
2163 async fn format_via_lsp(
2164 this: &WeakEntity<LspStore>,
2165 buffer: &Entity<Buffer>,
2166 abs_path: &Path,
2167 language_server: &Arc<LanguageServer>,
2168 settings: &LanguageSettings,
2169 cx: &mut AsyncApp,
2170 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2171 let logger = zlog::scoped!("lsp_format");
2172 zlog::debug!(logger => "Formatting via LSP");
2173
2174 let uri = file_path_to_lsp_url(abs_path)?;
2175 let text_document = lsp::TextDocumentIdentifier::new(uri);
2176 let capabilities = &language_server.capabilities();
2177
2178 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2179 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2180
2181 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2182 let _timer = zlog::time!(logger => "format-full");
2183 language_server
2184 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2185 text_document,
2186 options: lsp_command::lsp_formatting_options(settings),
2187 work_done_progress_params: Default::default(),
2188 })
2189 .await
2190 .into_response()?
2191 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2192 let _timer = zlog::time!(logger => "format-range");
2193 let buffer_start = lsp::Position::new(0, 0);
2194 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2195 language_server
2196 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2197 text_document: text_document.clone(),
2198 range: lsp::Range::new(buffer_start, buffer_end),
2199 options: lsp_command::lsp_formatting_options(settings),
2200 work_done_progress_params: Default::default(),
2201 })
2202 .await
2203 .into_response()?
2204 } else {
2205 None
2206 };
2207
2208 if let Some(lsp_edits) = lsp_edits {
2209 this.update(cx, |this, cx| {
2210 this.as_local_mut().unwrap().edits_from_lsp(
2211 buffer,
2212 lsp_edits,
2213 language_server.server_id(),
2214 None,
2215 cx,
2216 )
2217 })?
2218 .await
2219 } else {
2220 Ok(Vec::with_capacity(0))
2221 }
2222 }
2223
2224 async fn format_via_external_command(
2225 buffer: &FormattableBuffer,
2226 command: &str,
2227 arguments: Option<&[String]>,
2228 cx: &mut AsyncApp,
2229 ) -> Result<Option<Diff>> {
2230 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2231 let file = File::from_dyn(buffer.file())?;
2232 let worktree = file.worktree.read(cx);
2233 let mut worktree_path = worktree.abs_path().to_path_buf();
2234 if worktree.root_entry()?.is_file() {
2235 worktree_path.pop();
2236 }
2237 Some(worktree_path)
2238 })?;
2239
2240 let mut child = util::command::new_smol_command(command);
2241
2242 if let Some(buffer_env) = buffer.env.as_ref() {
2243 child.envs(buffer_env);
2244 }
2245
2246 if let Some(working_dir_path) = working_dir_path {
2247 child.current_dir(working_dir_path);
2248 }
2249
2250 if let Some(arguments) = arguments {
2251 child.args(arguments.iter().map(|arg| {
2252 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2253 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2254 } else {
2255 arg.replace("{buffer_path}", "Untitled")
2256 }
2257 }));
2258 }
2259
2260 let mut child = child
2261 .stdin(smol::process::Stdio::piped())
2262 .stdout(smol::process::Stdio::piped())
2263 .stderr(smol::process::Stdio::piped())
2264 .spawn()?;
2265
2266 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2267 let text = buffer
2268 .handle
2269 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2270 for chunk in text.chunks() {
2271 stdin.write_all(chunk.as_bytes()).await?;
2272 }
2273 stdin.flush().await?;
2274
2275 let output = child.output().await?;
2276 anyhow::ensure!(
2277 output.status.success(),
2278 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2279 output.status.code(),
2280 String::from_utf8_lossy(&output.stdout),
2281 String::from_utf8_lossy(&output.stderr),
2282 );
2283
2284 let stdout = String::from_utf8(output.stdout)?;
2285 Ok(Some(
2286 buffer
2287 .handle
2288 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2289 .await,
2290 ))
2291 }
2292
2293 async fn try_resolve_code_action(
2294 lang_server: &LanguageServer,
2295 action: &mut CodeAction,
2296 ) -> anyhow::Result<()> {
2297 match &mut action.lsp_action {
2298 LspAction::Action(lsp_action) => {
2299 if !action.resolved
2300 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2301 && lsp_action.data.is_some()
2302 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2303 {
2304 **lsp_action = lang_server
2305 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2306 .await
2307 .into_response()?;
2308 }
2309 }
2310 LspAction::CodeLens(lens) => {
2311 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2312 *lens = lang_server
2313 .request::<lsp::request::CodeLensResolve>(lens.clone())
2314 .await
2315 .into_response()?;
2316 }
2317 }
2318 LspAction::Command(_) => {}
2319 }
2320
2321 action.resolved = true;
2322 anyhow::Ok(())
2323 }
2324
2325 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2326 let buffer = buffer_handle.read(cx);
2327
2328 let file = buffer.file().cloned();
2329
2330 let Some(file) = File::from_dyn(file.as_ref()) else {
2331 return;
2332 };
2333 if !file.is_local() {
2334 return;
2335 }
2336 let path = ProjectPath::from_file(file, cx);
2337 let worktree_id = file.worktree_id(cx);
2338 let language = buffer.language().cloned();
2339
2340 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2341 for (server_id, diagnostics) in
2342 diagnostics.get(file.path()).cloned().unwrap_or_default()
2343 {
2344 self.update_buffer_diagnostics(
2345 buffer_handle,
2346 server_id,
2347 None,
2348 None,
2349 None,
2350 Vec::new(),
2351 diagnostics,
2352 cx,
2353 )
2354 .log_err();
2355 }
2356 }
2357 let Some(language) = language else {
2358 return;
2359 };
2360 let Some(snapshot) = self
2361 .worktree_store
2362 .read(cx)
2363 .worktree_for_id(worktree_id, cx)
2364 .map(|worktree| worktree.read(cx).snapshot())
2365 else {
2366 return;
2367 };
2368 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2369
2370 for server_id in
2371 self.lsp_tree
2372 .get(path, language.name(), language.manifest(), &delegate, cx)
2373 {
2374 let server = self
2375 .language_servers
2376 .get(&server_id)
2377 .and_then(|server_state| {
2378 if let LanguageServerState::Running { server, .. } = server_state {
2379 Some(server.clone())
2380 } else {
2381 None
2382 }
2383 });
2384 let server = match server {
2385 Some(server) => server,
2386 None => continue,
2387 };
2388
2389 buffer_handle.update(cx, |buffer, cx| {
2390 buffer.set_completion_triggers(
2391 server.server_id(),
2392 server
2393 .capabilities()
2394 .completion_provider
2395 .as_ref()
2396 .and_then(|provider| {
2397 provider
2398 .trigger_characters
2399 .as_ref()
2400 .map(|characters| characters.iter().cloned().collect())
2401 })
2402 .unwrap_or_default(),
2403 cx,
2404 );
2405 });
2406 }
2407 }
2408
2409 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2410 buffer.update(cx, |buffer, cx| {
2411 let Some(language) = buffer.language() else {
2412 return;
2413 };
2414 let path = ProjectPath {
2415 worktree_id: old_file.worktree_id(cx),
2416 path: old_file.path.clone(),
2417 };
2418 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2419 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2420 buffer.set_completion_triggers(server_id, Default::default(), cx);
2421 }
2422 });
2423 }
2424
2425 fn update_buffer_diagnostics(
2426 &mut self,
2427 buffer: &Entity<Buffer>,
2428 server_id: LanguageServerId,
2429 registration_id: Option<Option<SharedString>>,
2430 result_id: Option<SharedString>,
2431 version: Option<i32>,
2432 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2433 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2434 cx: &mut Context<LspStore>,
2435 ) -> Result<()> {
2436 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2437 Ordering::Equal
2438 .then_with(|| b.is_primary.cmp(&a.is_primary))
2439 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2440 .then_with(|| a.severity.cmp(&b.severity))
2441 .then_with(|| a.message.cmp(&b.message))
2442 }
2443
2444 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2445 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2446 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2447
2448 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2449 Ordering::Equal
2450 .then_with(|| a.range.start.cmp(&b.range.start))
2451 .then_with(|| b.range.end.cmp(&a.range.end))
2452 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2453 });
2454
2455 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2456
2457 let edits_since_save = std::cell::LazyCell::new(|| {
2458 let saved_version = buffer.read(cx).saved_version();
2459 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2460 });
2461
2462 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2463
2464 for (new_diagnostic, entry) in diagnostics {
2465 let start;
2466 let end;
2467 if new_diagnostic && entry.diagnostic.is_disk_based {
2468 // Some diagnostics are based on files on disk instead of buffers'
2469 // current contents. Adjust these diagnostics' ranges to reflect
2470 // any unsaved edits.
2471 // Do not alter the reused ones though, as their coordinates were stored as anchors
2472 // and were properly adjusted on reuse.
2473 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2474 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2475 } else {
2476 start = entry.range.start;
2477 end = entry.range.end;
2478 }
2479
2480 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2481 ..snapshot.clip_point_utf16(end, Bias::Right);
2482
2483 // Expand empty ranges by one codepoint
2484 if range.start == range.end {
2485 // This will be go to the next boundary when being clipped
2486 range.end.column += 1;
2487 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2488 if range.start == range.end && range.end.column > 0 {
2489 range.start.column -= 1;
2490 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2491 }
2492 }
2493
2494 sanitized_diagnostics.push(DiagnosticEntry {
2495 range,
2496 diagnostic: entry.diagnostic,
2497 });
2498 }
2499 drop(edits_since_save);
2500
2501 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2502 buffer.update(cx, |buffer, cx| {
2503 if let Some(registration_id) = registration_id {
2504 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2505 self.buffer_pull_diagnostics_result_ids
2506 .entry(server_id)
2507 .or_default()
2508 .entry(registration_id)
2509 .or_default()
2510 .insert(abs_path, result_id);
2511 }
2512 }
2513
2514 buffer.update_diagnostics(server_id, set, cx)
2515 });
2516
2517 Ok(())
2518 }
2519
2520 fn register_language_server_for_invisible_worktree(
2521 &mut self,
2522 worktree: &Entity<Worktree>,
2523 language_server_id: LanguageServerId,
2524 cx: &mut App,
2525 ) {
2526 let worktree = worktree.read(cx);
2527 let worktree_id = worktree.id();
2528 debug_assert!(!worktree.is_visible());
2529 let Some(mut origin_seed) = self
2530 .language_server_ids
2531 .iter()
2532 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2533 else {
2534 return;
2535 };
2536 origin_seed.worktree_id = worktree_id;
2537 self.language_server_ids
2538 .entry(origin_seed)
2539 .or_insert_with(|| UnifiedLanguageServer {
2540 id: language_server_id,
2541 project_roots: Default::default(),
2542 });
2543 }
2544
2545 fn register_buffer_with_language_servers(
2546 &mut self,
2547 buffer_handle: &Entity<Buffer>,
2548 only_register_servers: HashSet<LanguageServerSelector>,
2549 cx: &mut Context<LspStore>,
2550 ) {
2551 let buffer = buffer_handle.read(cx);
2552 let buffer_id = buffer.remote_id();
2553
2554 let Some(file) = File::from_dyn(buffer.file()) else {
2555 return;
2556 };
2557 if !file.is_local() {
2558 return;
2559 }
2560
2561 let abs_path = file.abs_path(cx);
2562 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2563 return;
2564 };
2565 let initial_snapshot = buffer.text_snapshot();
2566 let worktree_id = file.worktree_id(cx);
2567
2568 let Some(language) = buffer.language().cloned() else {
2569 return;
2570 };
2571 let path: Arc<RelPath> = file
2572 .path()
2573 .parent()
2574 .map(Arc::from)
2575 .unwrap_or_else(|| file.path().clone());
2576 let Some(worktree) = self
2577 .worktree_store
2578 .read(cx)
2579 .worktree_for_id(worktree_id, cx)
2580 else {
2581 return;
2582 };
2583 let language_name = language.name();
2584 let (reused, delegate, servers) = self
2585 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2586 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2587 .unwrap_or_else(|| {
2588 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2589 let delegate: Arc<dyn ManifestDelegate> =
2590 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2591
2592 let servers = self
2593 .lsp_tree
2594 .walk(
2595 ProjectPath { worktree_id, path },
2596 language.name(),
2597 language.manifest(),
2598 &delegate,
2599 cx,
2600 )
2601 .collect::<Vec<_>>();
2602 (false, lsp_delegate, servers)
2603 });
2604 let servers_and_adapters = servers
2605 .into_iter()
2606 .filter_map(|server_node| {
2607 if reused && server_node.server_id().is_none() {
2608 return None;
2609 }
2610 if !only_register_servers.is_empty() {
2611 if let Some(server_id) = server_node.server_id()
2612 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2613 {
2614 return None;
2615 }
2616 if let Some(name) = server_node.name()
2617 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2618 {
2619 return None;
2620 }
2621 }
2622
2623 let server_id = server_node.server_id_or_init(|disposition| {
2624 let path = &disposition.path;
2625
2626 {
2627 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2628
2629 let server_id = self.get_or_insert_language_server(
2630 &worktree,
2631 delegate.clone(),
2632 disposition,
2633 &language_name,
2634 cx,
2635 );
2636
2637 if let Some(state) = self.language_servers.get(&server_id)
2638 && let Ok(uri) = uri
2639 {
2640 state.add_workspace_folder(uri);
2641 };
2642 server_id
2643 }
2644 })?;
2645 let server_state = self.language_servers.get(&server_id)?;
2646 if let LanguageServerState::Running {
2647 server, adapter, ..
2648 } = server_state
2649 {
2650 Some((server.clone(), adapter.clone()))
2651 } else {
2652 None
2653 }
2654 })
2655 .collect::<Vec<_>>();
2656 for (server, adapter) in servers_and_adapters {
2657 buffer_handle.update(cx, |buffer, cx| {
2658 buffer.set_completion_triggers(
2659 server.server_id(),
2660 server
2661 .capabilities()
2662 .completion_provider
2663 .as_ref()
2664 .and_then(|provider| {
2665 provider
2666 .trigger_characters
2667 .as_ref()
2668 .map(|characters| characters.iter().cloned().collect())
2669 })
2670 .unwrap_or_default(),
2671 cx,
2672 );
2673 });
2674
2675 let snapshot = LspBufferSnapshot {
2676 version: 0,
2677 snapshot: initial_snapshot.clone(),
2678 };
2679
2680 let mut registered = false;
2681 self.buffer_snapshots
2682 .entry(buffer_id)
2683 .or_default()
2684 .entry(server.server_id())
2685 .or_insert_with(|| {
2686 registered = true;
2687 server.register_buffer(
2688 uri.clone(),
2689 adapter.language_id(&language.name()),
2690 0,
2691 initial_snapshot.text(),
2692 );
2693
2694 vec![snapshot]
2695 });
2696
2697 self.buffers_opened_in_servers
2698 .entry(buffer_id)
2699 .or_default()
2700 .insert(server.server_id());
2701 if registered {
2702 cx.emit(LspStoreEvent::LanguageServerUpdate {
2703 language_server_id: server.server_id(),
2704 name: None,
2705 message: proto::update_language_server::Variant::RegisteredForBuffer(
2706 proto::RegisteredForBuffer {
2707 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2708 buffer_id: buffer_id.to_proto(),
2709 },
2710 ),
2711 });
2712 }
2713 }
2714 }
2715
2716 fn reuse_existing_language_server<'lang_name>(
2717 &self,
2718 server_tree: &LanguageServerTree,
2719 worktree: &Entity<Worktree>,
2720 language_name: &'lang_name LanguageName,
2721 cx: &mut App,
2722 ) -> Option<(
2723 Arc<LocalLspAdapterDelegate>,
2724 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2725 )> {
2726 if worktree.read(cx).is_visible() {
2727 return None;
2728 }
2729
2730 let worktree_store = self.worktree_store.read(cx);
2731 let servers = server_tree
2732 .instances
2733 .iter()
2734 .filter(|(worktree_id, _)| {
2735 worktree_store
2736 .worktree_for_id(**worktree_id, cx)
2737 .is_some_and(|worktree| worktree.read(cx).is_visible())
2738 })
2739 .flat_map(|(worktree_id, servers)| {
2740 servers
2741 .roots
2742 .iter()
2743 .flat_map(|(_, language_servers)| language_servers)
2744 .map(move |(_, (server_node, server_languages))| {
2745 (worktree_id, server_node, server_languages)
2746 })
2747 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2748 .map(|(worktree_id, server_node, _)| {
2749 (
2750 *worktree_id,
2751 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2752 )
2753 })
2754 })
2755 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2756 acc.entry(worktree_id)
2757 .or_insert_with(Vec::new)
2758 .push(server_node);
2759 acc
2760 })
2761 .into_values()
2762 .max_by_key(|servers| servers.len())?;
2763
2764 let worktree_id = worktree.read(cx).id();
2765 let apply = move |tree: &mut LanguageServerTree| {
2766 for server_node in &servers {
2767 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2768 }
2769 servers
2770 };
2771
2772 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2773 Some((delegate, apply))
2774 }
2775
2776 pub(crate) fn unregister_old_buffer_from_language_servers(
2777 &mut self,
2778 buffer: &Entity<Buffer>,
2779 old_file: &File,
2780 cx: &mut App,
2781 ) {
2782 let old_path = match old_file.as_local() {
2783 Some(local) => local.abs_path(cx),
2784 None => return,
2785 };
2786
2787 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2788 debug_panic!("{old_path:?} is not parseable as an URI");
2789 return;
2790 };
2791 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2792 }
2793
2794 pub(crate) fn unregister_buffer_from_language_servers(
2795 &mut self,
2796 buffer: &Entity<Buffer>,
2797 file_url: &lsp::Uri,
2798 cx: &mut App,
2799 ) {
2800 buffer.update(cx, |buffer, cx| {
2801 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2802
2803 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2804 if snapshots
2805 .as_mut()
2806 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2807 {
2808 language_server.unregister_buffer(file_url.clone());
2809 }
2810 }
2811 });
2812 }
2813
2814 fn buffer_snapshot_for_lsp_version(
2815 &mut self,
2816 buffer: &Entity<Buffer>,
2817 server_id: LanguageServerId,
2818 version: Option<i32>,
2819 cx: &App,
2820 ) -> Result<TextBufferSnapshot> {
2821 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2822
2823 if let Some(version) = version {
2824 let buffer_id = buffer.read(cx).remote_id();
2825 let snapshots = if let Some(snapshots) = self
2826 .buffer_snapshots
2827 .get_mut(&buffer_id)
2828 .and_then(|m| m.get_mut(&server_id))
2829 {
2830 snapshots
2831 } else if version == 0 {
2832 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2833 // We detect this case and treat it as if the version was `None`.
2834 return Ok(buffer.read(cx).text_snapshot());
2835 } else {
2836 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2837 };
2838
2839 let found_snapshot = snapshots
2840 .binary_search_by_key(&version, |e| e.version)
2841 .map(|ix| snapshots[ix].snapshot.clone())
2842 .map_err(|_| {
2843 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2844 })?;
2845
2846 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2847 Ok(found_snapshot)
2848 } else {
2849 Ok((buffer.read(cx)).text_snapshot())
2850 }
2851 }
2852
2853 async fn get_server_code_actions_from_action_kinds(
2854 lsp_store: &WeakEntity<LspStore>,
2855 language_server_id: LanguageServerId,
2856 code_action_kinds: Vec<lsp::CodeActionKind>,
2857 buffer: &Entity<Buffer>,
2858 cx: &mut AsyncApp,
2859 ) -> Result<Vec<CodeAction>> {
2860 let actions = lsp_store
2861 .update(cx, move |this, cx| {
2862 let request = GetCodeActions {
2863 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2864 kinds: Some(code_action_kinds),
2865 };
2866 let server = LanguageServerToQuery::Other(language_server_id);
2867 this.request_lsp(buffer.clone(), server, request, cx)
2868 })?
2869 .await?;
2870 Ok(actions)
2871 }
2872
2873 pub async fn execute_code_actions_on_server(
2874 lsp_store: &WeakEntity<LspStore>,
2875 language_server: &Arc<LanguageServer>,
2876
2877 actions: Vec<CodeAction>,
2878 push_to_history: bool,
2879 project_transaction: &mut ProjectTransaction,
2880 cx: &mut AsyncApp,
2881 ) -> anyhow::Result<()> {
2882 for mut action in actions {
2883 Self::try_resolve_code_action(language_server, &mut action)
2884 .await
2885 .context("resolving a formatting code action")?;
2886
2887 if let Some(edit) = action.lsp_action.edit() {
2888 if edit.changes.is_none() && edit.document_changes.is_none() {
2889 continue;
2890 }
2891
2892 let new = Self::deserialize_workspace_edit(
2893 lsp_store.upgrade().context("project dropped")?,
2894 edit.clone(),
2895 push_to_history,
2896 language_server.clone(),
2897 cx,
2898 )
2899 .await?;
2900 project_transaction.0.extend(new.0);
2901 }
2902
2903 if let Some(command) = action.lsp_action.command() {
2904 let server_capabilities = language_server.capabilities();
2905 let available_commands = server_capabilities
2906 .execute_command_provider
2907 .as_ref()
2908 .map(|options| options.commands.as_slice())
2909 .unwrap_or_default();
2910 if available_commands.contains(&command.command) {
2911 lsp_store.update(cx, |lsp_store, _| {
2912 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2913 mode.last_workspace_edits_by_language_server
2914 .remove(&language_server.server_id());
2915 }
2916 })?;
2917
2918 language_server
2919 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2920 command: command.command.clone(),
2921 arguments: command.arguments.clone().unwrap_or_default(),
2922 ..Default::default()
2923 })
2924 .await
2925 .into_response()
2926 .context("execute command")?;
2927
2928 lsp_store.update(cx, |this, _| {
2929 if let LspStoreMode::Local(mode) = &mut this.mode {
2930 project_transaction.0.extend(
2931 mode.last_workspace_edits_by_language_server
2932 .remove(&language_server.server_id())
2933 .unwrap_or_default()
2934 .0,
2935 )
2936 }
2937 })?;
2938 } else {
2939 log::warn!(
2940 "Cannot execute a command {} not listed in the language server capabilities",
2941 command.command
2942 )
2943 }
2944 }
2945 }
2946 Ok(())
2947 }
2948
2949 pub async fn deserialize_text_edits(
2950 this: Entity<LspStore>,
2951 buffer_to_edit: Entity<Buffer>,
2952 edits: Vec<lsp::TextEdit>,
2953 push_to_history: bool,
2954 _: Arc<CachedLspAdapter>,
2955 language_server: Arc<LanguageServer>,
2956 cx: &mut AsyncApp,
2957 ) -> Result<Option<Transaction>> {
2958 let edits = this
2959 .update(cx, |this, cx| {
2960 this.as_local_mut().unwrap().edits_from_lsp(
2961 &buffer_to_edit,
2962 edits,
2963 language_server.server_id(),
2964 None,
2965 cx,
2966 )
2967 })?
2968 .await?;
2969
2970 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2971 buffer.finalize_last_transaction();
2972 buffer.start_transaction();
2973 for (range, text) in edits {
2974 buffer.edit([(range, text)], None, cx);
2975 }
2976
2977 if buffer.end_transaction(cx).is_some() {
2978 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2979 if !push_to_history {
2980 buffer.forget_transaction(transaction.id);
2981 }
2982 Some(transaction)
2983 } else {
2984 None
2985 }
2986 })?;
2987
2988 Ok(transaction)
2989 }
2990
2991 #[allow(clippy::type_complexity)]
2992 pub(crate) fn edits_from_lsp(
2993 &mut self,
2994 buffer: &Entity<Buffer>,
2995 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2996 server_id: LanguageServerId,
2997 version: Option<i32>,
2998 cx: &mut Context<LspStore>,
2999 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3000 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3001 cx.background_spawn(async move {
3002 let snapshot = snapshot?;
3003 let mut lsp_edits = lsp_edits
3004 .into_iter()
3005 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3006 .collect::<Vec<_>>();
3007
3008 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3009
3010 let mut lsp_edits = lsp_edits.into_iter().peekable();
3011 let mut edits = Vec::new();
3012 while let Some((range, mut new_text)) = lsp_edits.next() {
3013 // Clip invalid ranges provided by the language server.
3014 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3015 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3016
3017 // Combine any LSP edits that are adjacent.
3018 //
3019 // Also, combine LSP edits that are separated from each other by only
3020 // a newline. This is important because for some code actions,
3021 // Rust-analyzer rewrites the entire buffer via a series of edits that
3022 // are separated by unchanged newline characters.
3023 //
3024 // In order for the diffing logic below to work properly, any edits that
3025 // cancel each other out must be combined into one.
3026 while let Some((next_range, next_text)) = lsp_edits.peek() {
3027 if next_range.start.0 > range.end {
3028 if next_range.start.0.row > range.end.row + 1
3029 || next_range.start.0.column > 0
3030 || snapshot.clip_point_utf16(
3031 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3032 Bias::Left,
3033 ) > range.end
3034 {
3035 break;
3036 }
3037 new_text.push('\n');
3038 }
3039 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3040 new_text.push_str(next_text);
3041 lsp_edits.next();
3042 }
3043
3044 // For multiline edits, perform a diff of the old and new text so that
3045 // we can identify the changes more precisely, preserving the locations
3046 // of any anchors positioned in the unchanged regions.
3047 if range.end.row > range.start.row {
3048 let offset = range.start.to_offset(&snapshot);
3049 let old_text = snapshot.text_for_range(range).collect::<String>();
3050 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3051 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3052 (
3053 snapshot.anchor_after(offset + range.start)
3054 ..snapshot.anchor_before(offset + range.end),
3055 replacement,
3056 )
3057 }));
3058 } else if range.end == range.start {
3059 let anchor = snapshot.anchor_after(range.start);
3060 edits.push((anchor..anchor, new_text.into()));
3061 } else {
3062 let edit_start = snapshot.anchor_after(range.start);
3063 let edit_end = snapshot.anchor_before(range.end);
3064 edits.push((edit_start..edit_end, new_text.into()));
3065 }
3066 }
3067
3068 Ok(edits)
3069 })
3070 }
3071
3072 pub(crate) async fn deserialize_workspace_edit(
3073 this: Entity<LspStore>,
3074 edit: lsp::WorkspaceEdit,
3075 push_to_history: bool,
3076 language_server: Arc<LanguageServer>,
3077 cx: &mut AsyncApp,
3078 ) -> Result<ProjectTransaction> {
3079 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3080
3081 let mut operations = Vec::new();
3082 if let Some(document_changes) = edit.document_changes {
3083 match document_changes {
3084 lsp::DocumentChanges::Edits(edits) => {
3085 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3086 }
3087 lsp::DocumentChanges::Operations(ops) => operations = ops,
3088 }
3089 } else if let Some(changes) = edit.changes {
3090 operations.extend(changes.into_iter().map(|(uri, edits)| {
3091 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3092 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3093 uri,
3094 version: None,
3095 },
3096 edits: edits.into_iter().map(Edit::Plain).collect(),
3097 })
3098 }));
3099 }
3100
3101 let mut project_transaction = ProjectTransaction::default();
3102 for operation in operations {
3103 match operation {
3104 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3105 let abs_path = op
3106 .uri
3107 .to_file_path()
3108 .map_err(|()| anyhow!("can't convert URI to path"))?;
3109
3110 if let Some(parent_path) = abs_path.parent() {
3111 fs.create_dir(parent_path).await?;
3112 }
3113 if abs_path.ends_with("/") {
3114 fs.create_dir(&abs_path).await?;
3115 } else {
3116 fs.create_file(
3117 &abs_path,
3118 op.options
3119 .map(|options| fs::CreateOptions {
3120 overwrite: options.overwrite.unwrap_or(false),
3121 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3122 })
3123 .unwrap_or_default(),
3124 )
3125 .await?;
3126 }
3127 }
3128
3129 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3130 let source_abs_path = op
3131 .old_uri
3132 .to_file_path()
3133 .map_err(|()| anyhow!("can't convert URI to path"))?;
3134 let target_abs_path = op
3135 .new_uri
3136 .to_file_path()
3137 .map_err(|()| anyhow!("can't convert URI to path"))?;
3138
3139 let options = fs::RenameOptions {
3140 overwrite: op
3141 .options
3142 .as_ref()
3143 .and_then(|options| options.overwrite)
3144 .unwrap_or(false),
3145 ignore_if_exists: op
3146 .options
3147 .as_ref()
3148 .and_then(|options| options.ignore_if_exists)
3149 .unwrap_or(false),
3150 create_parents: true,
3151 };
3152
3153 fs.rename(&source_abs_path, &target_abs_path, options)
3154 .await?;
3155 }
3156
3157 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3158 let abs_path = op
3159 .uri
3160 .to_file_path()
3161 .map_err(|()| anyhow!("can't convert URI to path"))?;
3162 let options = op
3163 .options
3164 .map(|options| fs::RemoveOptions {
3165 recursive: options.recursive.unwrap_or(false),
3166 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3167 })
3168 .unwrap_or_default();
3169 if abs_path.ends_with("/") {
3170 fs.remove_dir(&abs_path, options).await?;
3171 } else {
3172 fs.remove_file(&abs_path, options).await?;
3173 }
3174 }
3175
3176 lsp::DocumentChangeOperation::Edit(op) => {
3177 let buffer_to_edit = this
3178 .update(cx, |this, cx| {
3179 this.open_local_buffer_via_lsp(
3180 op.text_document.uri.clone(),
3181 language_server.server_id(),
3182 cx,
3183 )
3184 })?
3185 .await?;
3186
3187 let edits = this
3188 .update(cx, |this, cx| {
3189 let path = buffer_to_edit.read(cx).project_path(cx);
3190 let active_entry = this.active_entry;
3191 let is_active_entry = path.is_some_and(|project_path| {
3192 this.worktree_store
3193 .read(cx)
3194 .entry_for_path(&project_path, cx)
3195 .is_some_and(|entry| Some(entry.id) == active_entry)
3196 });
3197 let local = this.as_local_mut().unwrap();
3198
3199 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3200 for edit in op.edits {
3201 match edit {
3202 Edit::Plain(edit) => {
3203 if !edits.contains(&edit) {
3204 edits.push(edit)
3205 }
3206 }
3207 Edit::Annotated(edit) => {
3208 if !edits.contains(&edit.text_edit) {
3209 edits.push(edit.text_edit)
3210 }
3211 }
3212 Edit::Snippet(edit) => {
3213 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3214 else {
3215 continue;
3216 };
3217
3218 if is_active_entry {
3219 snippet_edits.push((edit.range, snippet));
3220 } else {
3221 // Since this buffer is not focused, apply a normal edit.
3222 let new_edit = TextEdit {
3223 range: edit.range,
3224 new_text: snippet.text,
3225 };
3226 if !edits.contains(&new_edit) {
3227 edits.push(new_edit);
3228 }
3229 }
3230 }
3231 }
3232 }
3233 if !snippet_edits.is_empty() {
3234 let buffer_id = buffer_to_edit.read(cx).remote_id();
3235 let version = if let Some(buffer_version) = op.text_document.version
3236 {
3237 local
3238 .buffer_snapshot_for_lsp_version(
3239 &buffer_to_edit,
3240 language_server.server_id(),
3241 Some(buffer_version),
3242 cx,
3243 )
3244 .ok()
3245 .map(|snapshot| snapshot.version)
3246 } else {
3247 Some(buffer_to_edit.read(cx).saved_version().clone())
3248 };
3249
3250 let most_recent_edit =
3251 version.and_then(|version| version.most_recent());
3252 // Check if the edit that triggered that edit has been made by this participant.
3253
3254 if let Some(most_recent_edit) = most_recent_edit {
3255 cx.emit(LspStoreEvent::SnippetEdit {
3256 buffer_id,
3257 edits: snippet_edits,
3258 most_recent_edit,
3259 });
3260 }
3261 }
3262
3263 local.edits_from_lsp(
3264 &buffer_to_edit,
3265 edits,
3266 language_server.server_id(),
3267 op.text_document.version,
3268 cx,
3269 )
3270 })?
3271 .await?;
3272
3273 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3274 buffer.finalize_last_transaction();
3275 buffer.start_transaction();
3276 for (range, text) in edits {
3277 buffer.edit([(range, text)], None, cx);
3278 }
3279
3280 buffer.end_transaction(cx).and_then(|transaction_id| {
3281 if push_to_history {
3282 buffer.finalize_last_transaction();
3283 buffer.get_transaction(transaction_id).cloned()
3284 } else {
3285 buffer.forget_transaction(transaction_id)
3286 }
3287 })
3288 })?;
3289 if let Some(transaction) = transaction {
3290 project_transaction.0.insert(buffer_to_edit, transaction);
3291 }
3292 }
3293 }
3294 }
3295
3296 Ok(project_transaction)
3297 }
3298
3299 async fn on_lsp_workspace_edit(
3300 this: WeakEntity<LspStore>,
3301 params: lsp::ApplyWorkspaceEditParams,
3302 server_id: LanguageServerId,
3303 cx: &mut AsyncApp,
3304 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3305 let this = this.upgrade().context("project project closed")?;
3306 let language_server = this
3307 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3308 .context("language server not found")?;
3309 let transaction = Self::deserialize_workspace_edit(
3310 this.clone(),
3311 params.edit,
3312 true,
3313 language_server.clone(),
3314 cx,
3315 )
3316 .await
3317 .log_err();
3318 this.update(cx, |this, cx| {
3319 if let Some(transaction) = transaction {
3320 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3321
3322 this.as_local_mut()
3323 .unwrap()
3324 .last_workspace_edits_by_language_server
3325 .insert(server_id, transaction);
3326 }
3327 })?;
3328 Ok(lsp::ApplyWorkspaceEditResponse {
3329 applied: true,
3330 failed_change: None,
3331 failure_reason: None,
3332 })
3333 }
3334
3335 fn remove_worktree(
3336 &mut self,
3337 id_to_remove: WorktreeId,
3338 cx: &mut Context<LspStore>,
3339 ) -> Vec<LanguageServerId> {
3340 self.restricted_worktrees_tasks.remove(&id_to_remove);
3341 self.diagnostics.remove(&id_to_remove);
3342 self.prettier_store.update(cx, |prettier_store, cx| {
3343 prettier_store.remove_worktree(id_to_remove, cx);
3344 });
3345
3346 let mut servers_to_remove = BTreeSet::default();
3347 let mut servers_to_preserve = HashSet::default();
3348 for (seed, state) in &self.language_server_ids {
3349 if seed.worktree_id == id_to_remove {
3350 servers_to_remove.insert(state.id);
3351 } else {
3352 servers_to_preserve.insert(state.id);
3353 }
3354 }
3355 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3356 self.language_server_ids
3357 .retain(|_, state| !servers_to_remove.contains(&state.id));
3358 for server_id_to_remove in &servers_to_remove {
3359 self.language_server_watched_paths
3360 .remove(server_id_to_remove);
3361 self.language_server_paths_watched_for_rename
3362 .remove(server_id_to_remove);
3363 self.last_workspace_edits_by_language_server
3364 .remove(server_id_to_remove);
3365 self.language_servers.remove(server_id_to_remove);
3366 self.buffer_pull_diagnostics_result_ids
3367 .remove(server_id_to_remove);
3368 self.workspace_pull_diagnostics_result_ids
3369 .remove(server_id_to_remove);
3370 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3371 buffer_servers.remove(server_id_to_remove);
3372 }
3373 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3374 }
3375 servers_to_remove.into_iter().collect()
3376 }
3377
3378 fn rebuild_watched_paths_inner<'a>(
3379 &'a self,
3380 language_server_id: LanguageServerId,
3381 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3382 cx: &mut Context<LspStore>,
3383 ) -> LanguageServerWatchedPathsBuilder {
3384 let worktrees = self
3385 .worktree_store
3386 .read(cx)
3387 .worktrees()
3388 .filter_map(|worktree| {
3389 self.language_servers_for_worktree(worktree.read(cx).id())
3390 .find(|server| server.server_id() == language_server_id)
3391 .map(|_| worktree)
3392 })
3393 .collect::<Vec<_>>();
3394
3395 let mut worktree_globs = HashMap::default();
3396 let mut abs_globs = HashMap::default();
3397 log::trace!(
3398 "Processing new watcher paths for language server with id {}",
3399 language_server_id
3400 );
3401
3402 for watcher in watchers {
3403 if let Some((worktree, literal_prefix, pattern)) =
3404 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3405 {
3406 worktree.update(cx, |worktree, _| {
3407 if let Some((tree, glob)) =
3408 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3409 {
3410 tree.add_path_prefix_to_scan(literal_prefix);
3411 worktree_globs
3412 .entry(tree.id())
3413 .or_insert_with(GlobSetBuilder::new)
3414 .add(glob);
3415 }
3416 });
3417 } else {
3418 let (path, pattern) = match &watcher.glob_pattern {
3419 lsp::GlobPattern::String(s) => {
3420 let watcher_path = SanitizedPath::new(s);
3421 let path = glob_literal_prefix(watcher_path.as_path());
3422 let pattern = watcher_path
3423 .as_path()
3424 .strip_prefix(&path)
3425 .map(|p| p.to_string_lossy().into_owned())
3426 .unwrap_or_else(|e| {
3427 debug_panic!(
3428 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3429 s,
3430 path.display(),
3431 e
3432 );
3433 watcher_path.as_path().to_string_lossy().into_owned()
3434 });
3435 (path, pattern)
3436 }
3437 lsp::GlobPattern::Relative(rp) => {
3438 let Ok(mut base_uri) = match &rp.base_uri {
3439 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3440 lsp::OneOf::Right(base_uri) => base_uri,
3441 }
3442 .to_file_path() else {
3443 continue;
3444 };
3445
3446 let path = glob_literal_prefix(Path::new(&rp.pattern));
3447 let pattern = Path::new(&rp.pattern)
3448 .strip_prefix(&path)
3449 .map(|p| p.to_string_lossy().into_owned())
3450 .unwrap_or_else(|e| {
3451 debug_panic!(
3452 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3453 rp.pattern,
3454 path.display(),
3455 e
3456 );
3457 rp.pattern.clone()
3458 });
3459 base_uri.push(path);
3460 (base_uri, pattern)
3461 }
3462 };
3463
3464 if let Some(glob) = Glob::new(&pattern).log_err() {
3465 if !path
3466 .components()
3467 .any(|c| matches!(c, path::Component::Normal(_)))
3468 {
3469 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3470 // rather than adding a new watcher for `/`.
3471 for worktree in &worktrees {
3472 worktree_globs
3473 .entry(worktree.read(cx).id())
3474 .or_insert_with(GlobSetBuilder::new)
3475 .add(glob.clone());
3476 }
3477 } else {
3478 abs_globs
3479 .entry(path.into())
3480 .or_insert_with(GlobSetBuilder::new)
3481 .add(glob);
3482 }
3483 }
3484 }
3485 }
3486
3487 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3488 for (worktree_id, builder) in worktree_globs {
3489 if let Ok(globset) = builder.build() {
3490 watch_builder.watch_worktree(worktree_id, globset);
3491 }
3492 }
3493 for (abs_path, builder) in abs_globs {
3494 if let Ok(globset) = builder.build() {
3495 watch_builder.watch_abs_path(abs_path, globset);
3496 }
3497 }
3498 watch_builder
3499 }
3500
3501 fn worktree_and_path_for_file_watcher(
3502 worktrees: &[Entity<Worktree>],
3503 watcher: &FileSystemWatcher,
3504 cx: &App,
3505 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3506 worktrees.iter().find_map(|worktree| {
3507 let tree = worktree.read(cx);
3508 let worktree_root_path = tree.abs_path();
3509 let path_style = tree.path_style();
3510 match &watcher.glob_pattern {
3511 lsp::GlobPattern::String(s) => {
3512 let watcher_path = SanitizedPath::new(s);
3513 let relative = watcher_path
3514 .as_path()
3515 .strip_prefix(&worktree_root_path)
3516 .ok()?;
3517 let literal_prefix = glob_literal_prefix(relative);
3518 Some((
3519 worktree.clone(),
3520 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3521 relative.to_string_lossy().into_owned(),
3522 ))
3523 }
3524 lsp::GlobPattern::Relative(rp) => {
3525 let base_uri = match &rp.base_uri {
3526 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3527 lsp::OneOf::Right(base_uri) => base_uri,
3528 }
3529 .to_file_path()
3530 .ok()?;
3531 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3532 let mut literal_prefix = relative.to_owned();
3533 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3534 Some((
3535 worktree.clone(),
3536 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3537 rp.pattern.clone(),
3538 ))
3539 }
3540 }
3541 })
3542 }
3543
3544 fn rebuild_watched_paths(
3545 &mut self,
3546 language_server_id: LanguageServerId,
3547 cx: &mut Context<LspStore>,
3548 ) {
3549 let Some(registrations) = self
3550 .language_server_dynamic_registrations
3551 .get(&language_server_id)
3552 else {
3553 return;
3554 };
3555
3556 let watch_builder = self.rebuild_watched_paths_inner(
3557 language_server_id,
3558 registrations.did_change_watched_files.values().flatten(),
3559 cx,
3560 );
3561 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3562 self.language_server_watched_paths
3563 .insert(language_server_id, watcher);
3564
3565 cx.notify();
3566 }
3567
3568 fn on_lsp_did_change_watched_files(
3569 &mut self,
3570 language_server_id: LanguageServerId,
3571 registration_id: &str,
3572 params: DidChangeWatchedFilesRegistrationOptions,
3573 cx: &mut Context<LspStore>,
3574 ) {
3575 let registrations = self
3576 .language_server_dynamic_registrations
3577 .entry(language_server_id)
3578 .or_default();
3579
3580 registrations
3581 .did_change_watched_files
3582 .insert(registration_id.to_string(), params.watchers);
3583
3584 self.rebuild_watched_paths(language_server_id, cx);
3585 }
3586
3587 fn on_lsp_unregister_did_change_watched_files(
3588 &mut self,
3589 language_server_id: LanguageServerId,
3590 registration_id: &str,
3591 cx: &mut Context<LspStore>,
3592 ) {
3593 let registrations = self
3594 .language_server_dynamic_registrations
3595 .entry(language_server_id)
3596 .or_default();
3597
3598 if registrations
3599 .did_change_watched_files
3600 .remove(registration_id)
3601 .is_some()
3602 {
3603 log::info!(
3604 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3605 language_server_id,
3606 registration_id
3607 );
3608 } else {
3609 log::warn!(
3610 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3611 language_server_id,
3612 registration_id
3613 );
3614 }
3615
3616 self.rebuild_watched_paths(language_server_id, cx);
3617 }
3618
3619 async fn initialization_options_for_adapter(
3620 adapter: Arc<dyn LspAdapter>,
3621 delegate: &Arc<dyn LspAdapterDelegate>,
3622 ) -> Result<Option<serde_json::Value>> {
3623 let Some(mut initialization_config) =
3624 adapter.clone().initialization_options(delegate).await?
3625 else {
3626 return Ok(None);
3627 };
3628
3629 for other_adapter in delegate.registered_lsp_adapters() {
3630 if other_adapter.name() == adapter.name() {
3631 continue;
3632 }
3633 if let Ok(Some(target_config)) = other_adapter
3634 .clone()
3635 .additional_initialization_options(adapter.name(), delegate)
3636 .await
3637 {
3638 merge_json_value_into(target_config.clone(), &mut initialization_config);
3639 }
3640 }
3641
3642 Ok(Some(initialization_config))
3643 }
3644
3645 async fn workspace_configuration_for_adapter(
3646 adapter: Arc<dyn LspAdapter>,
3647 delegate: &Arc<dyn LspAdapterDelegate>,
3648 toolchain: Option<Toolchain>,
3649 requested_uri: Option<Uri>,
3650 cx: &mut AsyncApp,
3651 ) -> Result<serde_json::Value> {
3652 let mut workspace_config = adapter
3653 .clone()
3654 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3655 .await?;
3656
3657 for other_adapter in delegate.registered_lsp_adapters() {
3658 if other_adapter.name() == adapter.name() {
3659 continue;
3660 }
3661 if let Ok(Some(target_config)) = other_adapter
3662 .clone()
3663 .additional_workspace_configuration(adapter.name(), delegate, cx)
3664 .await
3665 {
3666 merge_json_value_into(target_config.clone(), &mut workspace_config);
3667 }
3668 }
3669
3670 Ok(workspace_config)
3671 }
3672
3673 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3674 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3675 Some(server.clone())
3676 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3677 Some(Arc::clone(server))
3678 } else {
3679 None
3680 }
3681 }
3682}
3683
3684fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3685 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3686 cx.emit(LspStoreEvent::LanguageServerUpdate {
3687 language_server_id: server.server_id(),
3688 name: Some(server.name()),
3689 message: proto::update_language_server::Variant::MetadataUpdated(
3690 proto::ServerMetadataUpdated {
3691 capabilities: Some(capabilities),
3692 binary: Some(proto::LanguageServerBinaryInfo {
3693 path: server.binary().path.to_string_lossy().into_owned(),
3694 arguments: server
3695 .binary()
3696 .arguments
3697 .iter()
3698 .map(|arg| arg.to_string_lossy().into_owned())
3699 .collect(),
3700 }),
3701 configuration: serde_json::to_string(server.configuration()).ok(),
3702 workspace_folders: server
3703 .workspace_folders()
3704 .iter()
3705 .map(|uri| uri.to_string())
3706 .collect(),
3707 },
3708 ),
3709 });
3710 }
3711}
3712
3713#[derive(Debug)]
3714pub struct FormattableBuffer {
3715 handle: Entity<Buffer>,
3716 abs_path: Option<PathBuf>,
3717 env: Option<HashMap<String, String>>,
3718 ranges: Option<Vec<Range<Anchor>>>,
3719}
3720
3721pub struct RemoteLspStore {
3722 upstream_client: Option<AnyProtoClient>,
3723 upstream_project_id: u64,
3724}
3725
3726pub(crate) enum LspStoreMode {
3727 Local(LocalLspStore), // ssh host and collab host
3728 Remote(RemoteLspStore), // collab guest
3729}
3730
3731impl LspStoreMode {
3732 fn is_local(&self) -> bool {
3733 matches!(self, LspStoreMode::Local(_))
3734 }
3735}
3736
3737pub struct LspStore {
3738 mode: LspStoreMode,
3739 last_formatting_failure: Option<String>,
3740 downstream_client: Option<(AnyProtoClient, u64)>,
3741 nonce: u128,
3742 buffer_store: Entity<BufferStore>,
3743 worktree_store: Entity<WorktreeStore>,
3744 pub languages: Arc<LanguageRegistry>,
3745 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3746 active_entry: Option<ProjectEntryId>,
3747 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3748 _maintain_buffer_languages: Task<()>,
3749 diagnostic_summaries:
3750 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3751 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3752 lsp_data: HashMap<BufferId, BufferLspData>,
3753 next_hint_id: Arc<AtomicUsize>,
3754}
3755
3756#[derive(Debug)]
3757pub struct BufferLspData {
3758 buffer_version: Global,
3759 document_colors: Option<DocumentColorData>,
3760 code_lens: Option<CodeLensData>,
3761 inlay_hints: BufferInlayHints,
3762 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3763 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3764}
3765
3766#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3767struct LspKey {
3768 request_type: TypeId,
3769 server_queried: Option<LanguageServerId>,
3770}
3771
3772impl BufferLspData {
3773 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3774 Self {
3775 buffer_version: buffer.read(cx).version(),
3776 document_colors: None,
3777 code_lens: None,
3778 inlay_hints: BufferInlayHints::new(buffer, cx),
3779 lsp_requests: HashMap::default(),
3780 chunk_lsp_requests: HashMap::default(),
3781 }
3782 }
3783
3784 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3785 if let Some(document_colors) = &mut self.document_colors {
3786 document_colors.colors.remove(&for_server);
3787 document_colors.cache_version += 1;
3788 }
3789
3790 if let Some(code_lens) = &mut self.code_lens {
3791 code_lens.lens.remove(&for_server);
3792 }
3793
3794 self.inlay_hints.remove_server_data(for_server);
3795 }
3796
3797 #[cfg(any(test, feature = "test-support"))]
3798 pub fn inlay_hints(&self) -> &BufferInlayHints {
3799 &self.inlay_hints
3800 }
3801}
3802
3803#[derive(Debug, Default, Clone)]
3804pub struct DocumentColors {
3805 pub colors: HashSet<DocumentColor>,
3806 pub cache_version: Option<usize>,
3807}
3808
3809type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3810type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3811
3812#[derive(Debug, Default)]
3813struct DocumentColorData {
3814 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3815 cache_version: usize,
3816 colors_update: Option<(Global, DocumentColorTask)>,
3817}
3818
3819#[derive(Debug, Default)]
3820struct CodeLensData {
3821 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3822 update: Option<(Global, CodeLensTask)>,
3823}
3824
3825#[derive(Debug)]
3826pub enum LspStoreEvent {
3827 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3828 LanguageServerRemoved(LanguageServerId),
3829 LanguageServerUpdate {
3830 language_server_id: LanguageServerId,
3831 name: Option<LanguageServerName>,
3832 message: proto::update_language_server::Variant,
3833 },
3834 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3835 LanguageServerPrompt(LanguageServerPromptRequest),
3836 LanguageDetected {
3837 buffer: Entity<Buffer>,
3838 new_language: Option<Arc<Language>>,
3839 },
3840 Notification(String),
3841 RefreshInlayHints {
3842 server_id: LanguageServerId,
3843 request_id: Option<usize>,
3844 },
3845 RefreshCodeLens,
3846 DiagnosticsUpdated {
3847 server_id: LanguageServerId,
3848 paths: Vec<ProjectPath>,
3849 },
3850 DiskBasedDiagnosticsStarted {
3851 language_server_id: LanguageServerId,
3852 },
3853 DiskBasedDiagnosticsFinished {
3854 language_server_id: LanguageServerId,
3855 },
3856 SnippetEdit {
3857 buffer_id: BufferId,
3858 edits: Vec<(lsp::Range, Snippet)>,
3859 most_recent_edit: clock::Lamport,
3860 },
3861 WorkspaceEditApplied(ProjectTransaction),
3862}
3863
3864#[derive(Clone, Debug, Serialize)]
3865pub struct LanguageServerStatus {
3866 pub name: LanguageServerName,
3867 pub server_version: Option<SharedString>,
3868 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3869 pub has_pending_diagnostic_updates: bool,
3870 pub progress_tokens: HashSet<ProgressToken>,
3871 pub worktree: Option<WorktreeId>,
3872 pub binary: Option<LanguageServerBinary>,
3873 pub configuration: Option<Value>,
3874 pub workspace_folders: BTreeSet<Uri>,
3875}
3876
3877#[derive(Clone, Debug)]
3878struct CoreSymbol {
3879 pub language_server_name: LanguageServerName,
3880 pub source_worktree_id: WorktreeId,
3881 pub source_language_server_id: LanguageServerId,
3882 pub path: SymbolLocation,
3883 pub name: String,
3884 pub kind: lsp::SymbolKind,
3885 pub range: Range<Unclipped<PointUtf16>>,
3886}
3887
3888#[derive(Clone, Debug, PartialEq, Eq)]
3889pub enum SymbolLocation {
3890 InProject(ProjectPath),
3891 OutsideProject {
3892 abs_path: Arc<Path>,
3893 signature: [u8; 32],
3894 },
3895}
3896
3897impl SymbolLocation {
3898 fn file_name(&self) -> Option<&str> {
3899 match self {
3900 Self::InProject(path) => path.path.file_name(),
3901 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3902 }
3903 }
3904}
3905
3906impl LspStore {
3907 pub fn init(client: &AnyProtoClient) {
3908 client.add_entity_request_handler(Self::handle_lsp_query);
3909 client.add_entity_message_handler(Self::handle_lsp_query_response);
3910 client.add_entity_request_handler(Self::handle_restart_language_servers);
3911 client.add_entity_request_handler(Self::handle_stop_language_servers);
3912 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3913 client.add_entity_message_handler(Self::handle_start_language_server);
3914 client.add_entity_message_handler(Self::handle_update_language_server);
3915 client.add_entity_message_handler(Self::handle_language_server_log);
3916 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3917 client.add_entity_request_handler(Self::handle_format_buffers);
3918 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3919 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3920 client.add_entity_request_handler(Self::handle_apply_code_action);
3921 client.add_entity_request_handler(Self::handle_get_project_symbols);
3922 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3923 client.add_entity_request_handler(Self::handle_get_color_presentation);
3924 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3925 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3926 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3927 client.add_entity_request_handler(Self::handle_on_type_formatting);
3928 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3929 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3930 client.add_entity_request_handler(Self::handle_rename_project_entry);
3931 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3932 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3933 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3934 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3935 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3936 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3937 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3938
3939 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3940 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3941 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3942 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3943 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3944 client.add_entity_request_handler(
3945 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3946 );
3947 client.add_entity_request_handler(
3948 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3949 );
3950 client.add_entity_request_handler(
3951 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3952 );
3953 }
3954
3955 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3956 match &self.mode {
3957 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3958 _ => None,
3959 }
3960 }
3961
3962 pub fn as_local(&self) -> Option<&LocalLspStore> {
3963 match &self.mode {
3964 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3965 _ => None,
3966 }
3967 }
3968
3969 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3970 match &mut self.mode {
3971 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3972 _ => None,
3973 }
3974 }
3975
3976 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3977 match &self.mode {
3978 LspStoreMode::Remote(RemoteLspStore {
3979 upstream_client: Some(upstream_client),
3980 upstream_project_id,
3981 ..
3982 }) => Some((upstream_client.clone(), *upstream_project_id)),
3983
3984 LspStoreMode::Remote(RemoteLspStore {
3985 upstream_client: None,
3986 ..
3987 }) => None,
3988 LspStoreMode::Local(_) => None,
3989 }
3990 }
3991
3992 pub fn new_local(
3993 buffer_store: Entity<BufferStore>,
3994 worktree_store: Entity<WorktreeStore>,
3995 prettier_store: Entity<PrettierStore>,
3996 toolchain_store: Entity<LocalToolchainStore>,
3997 environment: Entity<ProjectEnvironment>,
3998 manifest_tree: Entity<ManifestTree>,
3999 languages: Arc<LanguageRegistry>,
4000 http_client: Arc<dyn HttpClient>,
4001 fs: Arc<dyn Fs>,
4002 cx: &mut Context<Self>,
4003 ) -> Self {
4004 let yarn = YarnPathStore::new(fs.clone(), cx);
4005 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4006 .detach();
4007 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4008 .detach();
4009 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4010 .detach();
4011 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4012 .detach();
4013 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4014 .detach();
4015 subscribe_to_binary_statuses(&languages, cx).detach();
4016
4017 let _maintain_workspace_config = {
4018 let (sender, receiver) = watch::channel();
4019 (Self::maintain_workspace_config(receiver, cx), sender)
4020 };
4021
4022 Self {
4023 mode: LspStoreMode::Local(LocalLspStore {
4024 weak: cx.weak_entity(),
4025 worktree_store: worktree_store.clone(),
4026
4027 supplementary_language_servers: Default::default(),
4028 languages: languages.clone(),
4029 language_server_ids: Default::default(),
4030 language_servers: Default::default(),
4031 last_workspace_edits_by_language_server: Default::default(),
4032 language_server_watched_paths: Default::default(),
4033 language_server_paths_watched_for_rename: Default::default(),
4034 language_server_dynamic_registrations: Default::default(),
4035 buffers_being_formatted: Default::default(),
4036 buffer_snapshots: Default::default(),
4037 prettier_store,
4038 environment,
4039 http_client,
4040 fs,
4041 yarn,
4042 next_diagnostic_group_id: Default::default(),
4043 diagnostics: Default::default(),
4044 _subscription: cx.on_app_quit(|this, cx| {
4045 this.as_local_mut()
4046 .unwrap()
4047 .shutdown_language_servers_on_quit(cx)
4048 }),
4049 lsp_tree: LanguageServerTree::new(
4050 manifest_tree,
4051 languages.clone(),
4052 toolchain_store.clone(),
4053 ),
4054 toolchain_store,
4055 registered_buffers: HashMap::default(),
4056 buffers_opened_in_servers: HashMap::default(),
4057 buffer_pull_diagnostics_result_ids: HashMap::default(),
4058 workspace_pull_diagnostics_result_ids: HashMap::default(),
4059 restricted_worktrees_tasks: HashMap::default(),
4060 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4061 .manifest_file_names(),
4062 }),
4063 last_formatting_failure: None,
4064 downstream_client: None,
4065 buffer_store,
4066 worktree_store,
4067 languages: languages.clone(),
4068 language_server_statuses: Default::default(),
4069 nonce: StdRng::from_os_rng().random(),
4070 diagnostic_summaries: HashMap::default(),
4071 lsp_server_capabilities: HashMap::default(),
4072 lsp_data: HashMap::default(),
4073 next_hint_id: Arc::default(),
4074 active_entry: None,
4075 _maintain_workspace_config,
4076 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4077 }
4078 }
4079
4080 fn send_lsp_proto_request<R: LspCommand>(
4081 &self,
4082 buffer: Entity<Buffer>,
4083 client: AnyProtoClient,
4084 upstream_project_id: u64,
4085 request: R,
4086 cx: &mut Context<LspStore>,
4087 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4088 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4089 return Task::ready(Ok(R::Response::default()));
4090 }
4091 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4092 cx.spawn(async move |this, cx| {
4093 let response = client.request(message).await?;
4094 let this = this.upgrade().context("project dropped")?;
4095 request
4096 .response_from_proto(response, this, buffer, cx.clone())
4097 .await
4098 })
4099 }
4100
4101 pub(super) fn new_remote(
4102 buffer_store: Entity<BufferStore>,
4103 worktree_store: Entity<WorktreeStore>,
4104 languages: Arc<LanguageRegistry>,
4105 upstream_client: AnyProtoClient,
4106 project_id: u64,
4107 cx: &mut Context<Self>,
4108 ) -> Self {
4109 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4110 .detach();
4111 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4112 .detach();
4113 subscribe_to_binary_statuses(&languages, cx).detach();
4114 let _maintain_workspace_config = {
4115 let (sender, receiver) = watch::channel();
4116 (Self::maintain_workspace_config(receiver, cx), sender)
4117 };
4118 Self {
4119 mode: LspStoreMode::Remote(RemoteLspStore {
4120 upstream_client: Some(upstream_client),
4121 upstream_project_id: project_id,
4122 }),
4123 downstream_client: None,
4124 last_formatting_failure: None,
4125 buffer_store,
4126 worktree_store,
4127 languages: languages.clone(),
4128 language_server_statuses: Default::default(),
4129 nonce: StdRng::from_os_rng().random(),
4130 diagnostic_summaries: HashMap::default(),
4131 lsp_server_capabilities: HashMap::default(),
4132 next_hint_id: Arc::default(),
4133 lsp_data: HashMap::default(),
4134 active_entry: None,
4135
4136 _maintain_workspace_config,
4137 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4138 }
4139 }
4140
4141 fn on_buffer_store_event(
4142 &mut self,
4143 _: Entity<BufferStore>,
4144 event: &BufferStoreEvent,
4145 cx: &mut Context<Self>,
4146 ) {
4147 match event {
4148 BufferStoreEvent::BufferAdded(buffer) => {
4149 self.on_buffer_added(buffer, cx).log_err();
4150 }
4151 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4152 let buffer_id = buffer.read(cx).remote_id();
4153 if let Some(local) = self.as_local_mut()
4154 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4155 {
4156 local.reset_buffer(buffer, old_file, cx);
4157
4158 if local.registered_buffers.contains_key(&buffer_id) {
4159 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4160 }
4161 }
4162
4163 self.detect_language_for_buffer(buffer, cx);
4164 if let Some(local) = self.as_local_mut() {
4165 local.initialize_buffer(buffer, cx);
4166 if local.registered_buffers.contains_key(&buffer_id) {
4167 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4168 }
4169 }
4170 }
4171 _ => {}
4172 }
4173 }
4174
4175 fn on_worktree_store_event(
4176 &mut self,
4177 _: Entity<WorktreeStore>,
4178 event: &WorktreeStoreEvent,
4179 cx: &mut Context<Self>,
4180 ) {
4181 match event {
4182 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4183 if !worktree.read(cx).is_local() {
4184 return;
4185 }
4186 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4187 worktree::Event::UpdatedEntries(changes) => {
4188 this.update_local_worktree_language_servers(&worktree, changes, cx);
4189 }
4190 worktree::Event::UpdatedGitRepositories(_)
4191 | worktree::Event::DeletedEntry(_) => {}
4192 })
4193 .detach()
4194 }
4195 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4196 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4197 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4198 }
4199 WorktreeStoreEvent::WorktreeReleased(..)
4200 | WorktreeStoreEvent::WorktreeOrderChanged
4201 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4202 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4203 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4204 }
4205 }
4206
4207 fn on_prettier_store_event(
4208 &mut self,
4209 _: Entity<PrettierStore>,
4210 event: &PrettierStoreEvent,
4211 cx: &mut Context<Self>,
4212 ) {
4213 match event {
4214 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4215 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4216 }
4217 PrettierStoreEvent::LanguageServerAdded {
4218 new_server_id,
4219 name,
4220 prettier_server,
4221 } => {
4222 self.register_supplementary_language_server(
4223 *new_server_id,
4224 name.clone(),
4225 prettier_server.clone(),
4226 cx,
4227 );
4228 }
4229 }
4230 }
4231
4232 fn on_toolchain_store_event(
4233 &mut self,
4234 _: Entity<LocalToolchainStore>,
4235 event: &ToolchainStoreEvent,
4236 _: &mut Context<Self>,
4237 ) {
4238 if let ToolchainStoreEvent::ToolchainActivated = event {
4239 self.request_workspace_config_refresh()
4240 }
4241 }
4242
4243 fn request_workspace_config_refresh(&mut self) {
4244 *self._maintain_workspace_config.1.borrow_mut() = ();
4245 }
4246
4247 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4248 self.as_local().map(|local| local.prettier_store.clone())
4249 }
4250
4251 fn on_buffer_event(
4252 &mut self,
4253 buffer: Entity<Buffer>,
4254 event: &language::BufferEvent,
4255 cx: &mut Context<Self>,
4256 ) {
4257 match event {
4258 language::BufferEvent::Edited => {
4259 self.on_buffer_edited(buffer, cx);
4260 }
4261
4262 language::BufferEvent::Saved => {
4263 self.on_buffer_saved(buffer, cx);
4264 }
4265
4266 _ => {}
4267 }
4268 }
4269
4270 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4271 buffer
4272 .read(cx)
4273 .set_language_registry(self.languages.clone());
4274
4275 cx.subscribe(buffer, |this, buffer, event, cx| {
4276 this.on_buffer_event(buffer, event, cx);
4277 })
4278 .detach();
4279
4280 self.detect_language_for_buffer(buffer, cx);
4281 if let Some(local) = self.as_local_mut() {
4282 local.initialize_buffer(buffer, cx);
4283 }
4284
4285 Ok(())
4286 }
4287
4288 pub(crate) fn register_buffer_with_language_servers(
4289 &mut self,
4290 buffer: &Entity<Buffer>,
4291 only_register_servers: HashSet<LanguageServerSelector>,
4292 ignore_refcounts: bool,
4293 cx: &mut Context<Self>,
4294 ) -> OpenLspBufferHandle {
4295 let buffer_id = buffer.read(cx).remote_id();
4296 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4297 if let Some(local) = self.as_local_mut() {
4298 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4299 if !ignore_refcounts {
4300 *refcount += 1;
4301 }
4302
4303 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4304 // When a new unnamed buffer is created and saved, we will start loading it's language. Once the language is loaded, we go over all "language-less" buffers and try to fit that new language
4305 // with them. However, we do that only for the buffers that we think are open in at least one editor; thus, we need to keep tab of unnamed buffers as well, even though they're not actually registered with any language
4306 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4307 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4308 return handle;
4309 };
4310 if !file.is_local() {
4311 return handle;
4312 }
4313
4314 if ignore_refcounts || *refcount == 1 {
4315 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4316 }
4317 if !ignore_refcounts {
4318 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4319 let refcount = {
4320 let local = lsp_store.as_local_mut().unwrap();
4321 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4322 debug_panic!("bad refcounting");
4323 return;
4324 };
4325
4326 *refcount -= 1;
4327 *refcount
4328 };
4329 if refcount == 0 {
4330 lsp_store.lsp_data.remove(&buffer_id);
4331 let local = lsp_store.as_local_mut().unwrap();
4332 local.registered_buffers.remove(&buffer_id);
4333
4334 local.buffers_opened_in_servers.remove(&buffer_id);
4335 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4336 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4337
4338 let buffer_abs_path = file.abs_path(cx);
4339 for (_, buffer_pull_diagnostics_result_ids) in
4340 &mut local.buffer_pull_diagnostics_result_ids
4341 {
4342 buffer_pull_diagnostics_result_ids.retain(
4343 |_, buffer_result_ids| {
4344 buffer_result_ids.remove(&buffer_abs_path);
4345 !buffer_result_ids.is_empty()
4346 },
4347 );
4348 }
4349
4350 let diagnostic_updates = local
4351 .language_servers
4352 .keys()
4353 .cloned()
4354 .map(|server_id| DocumentDiagnosticsUpdate {
4355 diagnostics: DocumentDiagnostics {
4356 document_abs_path: buffer_abs_path.clone(),
4357 version: None,
4358 diagnostics: Vec::new(),
4359 },
4360 result_id: None,
4361 registration_id: None,
4362 server_id: server_id,
4363 disk_based_sources: Cow::Borrowed(&[]),
4364 })
4365 .collect::<Vec<_>>();
4366
4367 lsp_store
4368 .merge_diagnostic_entries(
4369 diagnostic_updates,
4370 |_, diagnostic, _| {
4371 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4372 },
4373 cx,
4374 )
4375 .context("Clearing diagnostics for the closed buffer")
4376 .log_err();
4377 }
4378 }
4379 })
4380 .detach();
4381 }
4382 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4383 let buffer_id = buffer.read(cx).remote_id().to_proto();
4384 cx.background_spawn(async move {
4385 upstream_client
4386 .request(proto::RegisterBufferWithLanguageServers {
4387 project_id: upstream_project_id,
4388 buffer_id,
4389 only_servers: only_register_servers
4390 .into_iter()
4391 .map(|selector| {
4392 let selector = match selector {
4393 LanguageServerSelector::Id(language_server_id) => {
4394 proto::language_server_selector::Selector::ServerId(
4395 language_server_id.to_proto(),
4396 )
4397 }
4398 LanguageServerSelector::Name(language_server_name) => {
4399 proto::language_server_selector::Selector::Name(
4400 language_server_name.to_string(),
4401 )
4402 }
4403 };
4404 proto::LanguageServerSelector {
4405 selector: Some(selector),
4406 }
4407 })
4408 .collect(),
4409 })
4410 .await
4411 })
4412 .detach();
4413 } else {
4414 // Our remote connection got closed
4415 }
4416 handle
4417 }
4418
4419 fn maintain_buffer_languages(
4420 languages: Arc<LanguageRegistry>,
4421 cx: &mut Context<Self>,
4422 ) -> Task<()> {
4423 let mut subscription = languages.subscribe();
4424 let mut prev_reload_count = languages.reload_count();
4425 cx.spawn(async move |this, cx| {
4426 while let Some(()) = subscription.next().await {
4427 if let Some(this) = this.upgrade() {
4428 // If the language registry has been reloaded, then remove and
4429 // re-assign the languages on all open buffers.
4430 let reload_count = languages.reload_count();
4431 if reload_count > prev_reload_count {
4432 prev_reload_count = reload_count;
4433 this.update(cx, |this, cx| {
4434 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4435 for buffer in buffer_store.buffers() {
4436 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4437 {
4438 buffer.update(cx, |buffer, cx| {
4439 buffer.set_language_async(None, cx)
4440 });
4441 if let Some(local) = this.as_local_mut() {
4442 local.reset_buffer(&buffer, &f, cx);
4443
4444 if local
4445 .registered_buffers
4446 .contains_key(&buffer.read(cx).remote_id())
4447 && let Some(file_url) =
4448 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4449 {
4450 local.unregister_buffer_from_language_servers(
4451 &buffer, &file_url, cx,
4452 );
4453 }
4454 }
4455 }
4456 }
4457 });
4458 })
4459 .ok();
4460 }
4461
4462 this.update(cx, |this, cx| {
4463 let mut plain_text_buffers = Vec::new();
4464 let mut buffers_with_unknown_injections = Vec::new();
4465 for handle in this.buffer_store.read(cx).buffers() {
4466 let buffer = handle.read(cx);
4467 if buffer.language().is_none()
4468 || buffer.language() == Some(&*language::PLAIN_TEXT)
4469 {
4470 plain_text_buffers.push(handle);
4471 } else if buffer.contains_unknown_injections() {
4472 buffers_with_unknown_injections.push(handle);
4473 }
4474 }
4475
4476 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4477 // and reused later in the invisible worktrees.
4478 plain_text_buffers.sort_by_key(|buffer| {
4479 Reverse(
4480 File::from_dyn(buffer.read(cx).file())
4481 .map(|file| file.worktree.read(cx).is_visible()),
4482 )
4483 });
4484
4485 for buffer in plain_text_buffers {
4486 this.detect_language_for_buffer(&buffer, cx);
4487 if let Some(local) = this.as_local_mut() {
4488 local.initialize_buffer(&buffer, cx);
4489 if local
4490 .registered_buffers
4491 .contains_key(&buffer.read(cx).remote_id())
4492 {
4493 local.register_buffer_with_language_servers(
4494 &buffer,
4495 HashSet::default(),
4496 cx,
4497 );
4498 }
4499 }
4500 }
4501
4502 for buffer in buffers_with_unknown_injections {
4503 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4504 }
4505 })
4506 .ok();
4507 }
4508 }
4509 })
4510 }
4511
4512 fn detect_language_for_buffer(
4513 &mut self,
4514 buffer_handle: &Entity<Buffer>,
4515 cx: &mut Context<Self>,
4516 ) -> Option<language::AvailableLanguage> {
4517 // If the buffer has a language, set it and start the language server if we haven't already.
4518 let buffer = buffer_handle.read(cx);
4519 let file = buffer.file()?;
4520
4521 let content = buffer.as_rope();
4522 let available_language = self.languages.language_for_file(file, Some(content), cx);
4523 if let Some(available_language) = &available_language {
4524 if let Some(Ok(Ok(new_language))) = self
4525 .languages
4526 .load_language(available_language)
4527 .now_or_never()
4528 {
4529 self.set_language_for_buffer(buffer_handle, new_language, cx);
4530 }
4531 } else {
4532 cx.emit(LspStoreEvent::LanguageDetected {
4533 buffer: buffer_handle.clone(),
4534 new_language: None,
4535 });
4536 }
4537
4538 available_language
4539 }
4540
4541 pub(crate) fn set_language_for_buffer(
4542 &mut self,
4543 buffer_entity: &Entity<Buffer>,
4544 new_language: Arc<Language>,
4545 cx: &mut Context<Self>,
4546 ) {
4547 let buffer = buffer_entity.read(cx);
4548 let buffer_file = buffer.file().cloned();
4549 let buffer_id = buffer.remote_id();
4550 if let Some(local_store) = self.as_local_mut()
4551 && local_store.registered_buffers.contains_key(&buffer_id)
4552 && let Some(abs_path) =
4553 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4554 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4555 {
4556 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4557 }
4558 buffer_entity.update(cx, |buffer, cx| {
4559 if buffer
4560 .language()
4561 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4562 {
4563 buffer.set_language_async(Some(new_language.clone()), cx);
4564 }
4565 });
4566
4567 let settings =
4568 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4569 let buffer_file = File::from_dyn(buffer_file.as_ref());
4570
4571 let worktree_id = if let Some(file) = buffer_file {
4572 let worktree = file.worktree.clone();
4573
4574 if let Some(local) = self.as_local_mut()
4575 && local.registered_buffers.contains_key(&buffer_id)
4576 {
4577 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4578 }
4579 Some(worktree.read(cx).id())
4580 } else {
4581 None
4582 };
4583
4584 if settings.prettier.allowed
4585 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4586 {
4587 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4588 if let Some(prettier_store) = prettier_store {
4589 prettier_store.update(cx, |prettier_store, cx| {
4590 prettier_store.install_default_prettier(
4591 worktree_id,
4592 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4593 cx,
4594 )
4595 })
4596 }
4597 }
4598
4599 cx.emit(LspStoreEvent::LanguageDetected {
4600 buffer: buffer_entity.clone(),
4601 new_language: Some(new_language),
4602 })
4603 }
4604
4605 pub fn buffer_store(&self) -> Entity<BufferStore> {
4606 self.buffer_store.clone()
4607 }
4608
4609 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4610 self.active_entry = active_entry;
4611 }
4612
4613 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4614 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4615 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4616 {
4617 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4618 summaries
4619 .iter()
4620 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4621 });
4622 if let Some(summary) = summaries.next() {
4623 client
4624 .send(proto::UpdateDiagnosticSummary {
4625 project_id: downstream_project_id,
4626 worktree_id: worktree.id().to_proto(),
4627 summary: Some(summary),
4628 more_summaries: summaries.collect(),
4629 })
4630 .log_err();
4631 }
4632 }
4633 }
4634
4635 fn is_capable_for_proto_request<R>(
4636 &self,
4637 buffer: &Entity<Buffer>,
4638 request: &R,
4639 cx: &App,
4640 ) -> bool
4641 where
4642 R: LspCommand,
4643 {
4644 self.check_if_capable_for_proto_request(
4645 buffer,
4646 |capabilities| {
4647 request.check_capabilities(AdapterServerCapabilities {
4648 server_capabilities: capabilities.clone(),
4649 code_action_kinds: None,
4650 })
4651 },
4652 cx,
4653 )
4654 }
4655
4656 fn check_if_capable_for_proto_request<F>(
4657 &self,
4658 buffer: &Entity<Buffer>,
4659 check: F,
4660 cx: &App,
4661 ) -> bool
4662 where
4663 F: FnMut(&lsp::ServerCapabilities) -> bool,
4664 {
4665 let Some(language) = buffer.read(cx).language().cloned() else {
4666 return false;
4667 };
4668 let relevant_language_servers = self
4669 .languages
4670 .lsp_adapters(&language.name())
4671 .into_iter()
4672 .map(|lsp_adapter| lsp_adapter.name())
4673 .collect::<HashSet<_>>();
4674 self.language_server_statuses
4675 .iter()
4676 .filter_map(|(server_id, server_status)| {
4677 relevant_language_servers
4678 .contains(&server_status.name)
4679 .then_some(server_id)
4680 })
4681 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4682 .any(check)
4683 }
4684
4685 fn all_capable_for_proto_request<F>(
4686 &self,
4687 buffer: &Entity<Buffer>,
4688 mut check: F,
4689 cx: &App,
4690 ) -> Vec<lsp::LanguageServerId>
4691 where
4692 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4693 {
4694 let Some(language) = buffer.read(cx).language().cloned() else {
4695 return Vec::default();
4696 };
4697 let relevant_language_servers = self
4698 .languages
4699 .lsp_adapters(&language.name())
4700 .into_iter()
4701 .map(|lsp_adapter| lsp_adapter.name())
4702 .collect::<HashSet<_>>();
4703 self.language_server_statuses
4704 .iter()
4705 .filter_map(|(server_id, server_status)| {
4706 relevant_language_servers
4707 .contains(&server_status.name)
4708 .then_some((server_id, &server_status.name))
4709 })
4710 .filter_map(|(server_id, server_name)| {
4711 self.lsp_server_capabilities
4712 .get(server_id)
4713 .map(|c| (server_id, server_name, c))
4714 })
4715 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4716 .map(|(server_id, _, _)| *server_id)
4717 .collect()
4718 }
4719
4720 pub fn request_lsp<R>(
4721 &mut self,
4722 buffer: Entity<Buffer>,
4723 server: LanguageServerToQuery,
4724 request: R,
4725 cx: &mut Context<Self>,
4726 ) -> Task<Result<R::Response>>
4727 where
4728 R: LspCommand,
4729 <R::LspRequest as lsp::request::Request>::Result: Send,
4730 <R::LspRequest as lsp::request::Request>::Params: Send,
4731 {
4732 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4733 return self.send_lsp_proto_request(
4734 buffer,
4735 upstream_client,
4736 upstream_project_id,
4737 request,
4738 cx,
4739 );
4740 }
4741
4742 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4743 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4744 local
4745 .language_servers_for_buffer(buffer, cx)
4746 .find(|(_, server)| {
4747 request.check_capabilities(server.adapter_server_capabilities())
4748 })
4749 .map(|(_, server)| server.clone())
4750 }),
4751 LanguageServerToQuery::Other(id) => self
4752 .language_server_for_local_buffer(buffer, id, cx)
4753 .and_then(|(_, server)| {
4754 request
4755 .check_capabilities(server.adapter_server_capabilities())
4756 .then(|| Arc::clone(server))
4757 }),
4758 }) else {
4759 return Task::ready(Ok(Default::default()));
4760 };
4761
4762 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4763
4764 let Some(file) = file else {
4765 return Task::ready(Ok(Default::default()));
4766 };
4767
4768 let lsp_params = match request.to_lsp_params_or_response(
4769 &file.abs_path(cx),
4770 buffer.read(cx),
4771 &language_server,
4772 cx,
4773 ) {
4774 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4775 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4776 Err(err) => {
4777 let message = format!(
4778 "{} via {} failed: {}",
4779 request.display_name(),
4780 language_server.name(),
4781 err
4782 );
4783 // rust-analyzer likes to error with this when its still loading up
4784 if !message.ends_with("content modified") {
4785 log::warn!("{message}");
4786 }
4787 return Task::ready(Err(anyhow!(message)));
4788 }
4789 };
4790
4791 let status = request.status();
4792 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4793 return Task::ready(Ok(Default::default()));
4794 }
4795 cx.spawn(async move |this, cx| {
4796 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4797
4798 let id = lsp_request.id();
4799 let _cleanup = if status.is_some() {
4800 cx.update(|cx| {
4801 this.update(cx, |this, cx| {
4802 this.on_lsp_work_start(
4803 language_server.server_id(),
4804 ProgressToken::Number(id),
4805 LanguageServerProgress {
4806 is_disk_based_diagnostics_progress: false,
4807 is_cancellable: false,
4808 title: None,
4809 message: status.clone(),
4810 percentage: None,
4811 last_update_at: cx.background_executor().now(),
4812 },
4813 cx,
4814 );
4815 })
4816 })
4817 .log_err();
4818
4819 Some(defer(|| {
4820 cx.update(|cx| {
4821 this.update(cx, |this, cx| {
4822 this.on_lsp_work_end(
4823 language_server.server_id(),
4824 ProgressToken::Number(id),
4825 cx,
4826 );
4827 })
4828 })
4829 .log_err();
4830 }))
4831 } else {
4832 None
4833 };
4834
4835 let result = lsp_request.await.into_response();
4836
4837 let response = result.map_err(|err| {
4838 let message = format!(
4839 "{} via {} failed: {}",
4840 request.display_name(),
4841 language_server.name(),
4842 err
4843 );
4844 // rust-analyzer likes to error with this when its still loading up
4845 if !message.ends_with("content modified") {
4846 log::warn!("{message}");
4847 }
4848 anyhow::anyhow!(message)
4849 })?;
4850
4851 request
4852 .response_from_lsp(
4853 response,
4854 this.upgrade().context("no app context")?,
4855 buffer,
4856 language_server.server_id(),
4857 cx.clone(),
4858 )
4859 .await
4860 })
4861 }
4862
4863 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4864 let mut language_formatters_to_check = Vec::new();
4865 for buffer in self.buffer_store.read(cx).buffers() {
4866 let buffer = buffer.read(cx);
4867 let buffer_file = File::from_dyn(buffer.file());
4868 let buffer_language = buffer.language();
4869 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4870 if buffer_language.is_some() {
4871 language_formatters_to_check.push((
4872 buffer_file.map(|f| f.worktree_id(cx)),
4873 settings.into_owned(),
4874 ));
4875 }
4876 }
4877
4878 self.request_workspace_config_refresh();
4879
4880 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4881 prettier_store.update(cx, |prettier_store, cx| {
4882 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4883 })
4884 }
4885
4886 cx.notify();
4887 }
4888
4889 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4890 let buffer_store = self.buffer_store.clone();
4891 let Some(local) = self.as_local_mut() else {
4892 return;
4893 };
4894 let mut adapters = BTreeMap::default();
4895 let get_adapter = {
4896 let languages = local.languages.clone();
4897 let environment = local.environment.clone();
4898 let weak = local.weak.clone();
4899 let worktree_store = local.worktree_store.clone();
4900 let http_client = local.http_client.clone();
4901 let fs = local.fs.clone();
4902 move |worktree_id, cx: &mut App| {
4903 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4904 Some(LocalLspAdapterDelegate::new(
4905 languages.clone(),
4906 &environment,
4907 weak.clone(),
4908 &worktree,
4909 http_client.clone(),
4910 fs.clone(),
4911 cx,
4912 ))
4913 }
4914 };
4915
4916 let mut messages_to_report = Vec::new();
4917 let (new_tree, to_stop) = {
4918 let mut rebase = local.lsp_tree.rebase();
4919 let buffers = buffer_store
4920 .read(cx)
4921 .buffers()
4922 .filter_map(|buffer| {
4923 let raw_buffer = buffer.read(cx);
4924 if !local
4925 .registered_buffers
4926 .contains_key(&raw_buffer.remote_id())
4927 {
4928 return None;
4929 }
4930 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4931 let language = raw_buffer.language().cloned()?;
4932 Some((file, language, raw_buffer.remote_id()))
4933 })
4934 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4935 for (file, language, buffer_id) in buffers {
4936 let worktree_id = file.worktree_id(cx);
4937 let Some(worktree) = local
4938 .worktree_store
4939 .read(cx)
4940 .worktree_for_id(worktree_id, cx)
4941 else {
4942 continue;
4943 };
4944
4945 if let Some((_, apply)) = local.reuse_existing_language_server(
4946 rebase.server_tree(),
4947 &worktree,
4948 &language.name(),
4949 cx,
4950 ) {
4951 (apply)(rebase.server_tree());
4952 } else if let Some(lsp_delegate) = adapters
4953 .entry(worktree_id)
4954 .or_insert_with(|| get_adapter(worktree_id, cx))
4955 .clone()
4956 {
4957 let delegate =
4958 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4959 let path = file
4960 .path()
4961 .parent()
4962 .map(Arc::from)
4963 .unwrap_or_else(|| file.path().clone());
4964 let worktree_path = ProjectPath { worktree_id, path };
4965 let abs_path = file.abs_path(cx);
4966 let nodes = rebase
4967 .walk(
4968 worktree_path,
4969 language.name(),
4970 language.manifest(),
4971 delegate.clone(),
4972 cx,
4973 )
4974 .collect::<Vec<_>>();
4975 for node in nodes {
4976 let server_id = node.server_id_or_init(|disposition| {
4977 let path = &disposition.path;
4978 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4979 let key = LanguageServerSeed {
4980 worktree_id,
4981 name: disposition.server_name.clone(),
4982 settings: disposition.settings.clone(),
4983 toolchain: local.toolchain_store.read(cx).active_toolchain(
4984 path.worktree_id,
4985 &path.path,
4986 language.name(),
4987 ),
4988 };
4989 local.language_server_ids.remove(&key);
4990
4991 let server_id = local.get_or_insert_language_server(
4992 &worktree,
4993 lsp_delegate.clone(),
4994 disposition,
4995 &language.name(),
4996 cx,
4997 );
4998 if let Some(state) = local.language_servers.get(&server_id)
4999 && let Ok(uri) = uri
5000 {
5001 state.add_workspace_folder(uri);
5002 };
5003 server_id
5004 });
5005
5006 if let Some(language_server_id) = server_id {
5007 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5008 language_server_id,
5009 name: node.name(),
5010 message:
5011 proto::update_language_server::Variant::RegisteredForBuffer(
5012 proto::RegisteredForBuffer {
5013 buffer_abs_path: abs_path
5014 .to_string_lossy()
5015 .into_owned(),
5016 buffer_id: buffer_id.to_proto(),
5017 },
5018 ),
5019 });
5020 }
5021 }
5022 } else {
5023 continue;
5024 }
5025 }
5026 rebase.finish()
5027 };
5028 for message in messages_to_report {
5029 cx.emit(message);
5030 }
5031 local.lsp_tree = new_tree;
5032 for (id, _) in to_stop {
5033 self.stop_local_language_server(id, cx).detach();
5034 }
5035 }
5036
5037 pub fn apply_code_action(
5038 &self,
5039 buffer_handle: Entity<Buffer>,
5040 mut action: CodeAction,
5041 push_to_history: bool,
5042 cx: &mut Context<Self>,
5043 ) -> Task<Result<ProjectTransaction>> {
5044 if let Some((upstream_client, project_id)) = self.upstream_client() {
5045 let request = proto::ApplyCodeAction {
5046 project_id,
5047 buffer_id: buffer_handle.read(cx).remote_id().into(),
5048 action: Some(Self::serialize_code_action(&action)),
5049 };
5050 let buffer_store = self.buffer_store();
5051 cx.spawn(async move |_, cx| {
5052 let response = upstream_client
5053 .request(request)
5054 .await?
5055 .transaction
5056 .context("missing transaction")?;
5057
5058 buffer_store
5059 .update(cx, |buffer_store, cx| {
5060 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5061 })?
5062 .await
5063 })
5064 } else if self.mode.is_local() {
5065 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5066 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5067 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5068 }) else {
5069 return Task::ready(Ok(ProjectTransaction::default()));
5070 };
5071 cx.spawn(async move |this, cx| {
5072 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5073 .await
5074 .context("resolving a code action")?;
5075 if let Some(edit) = action.lsp_action.edit()
5076 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5077 return LocalLspStore::deserialize_workspace_edit(
5078 this.upgrade().context("no app present")?,
5079 edit.clone(),
5080 push_to_history,
5081
5082 lang_server.clone(),
5083 cx,
5084 )
5085 .await;
5086 }
5087
5088 if let Some(command) = action.lsp_action.command() {
5089 let server_capabilities = lang_server.capabilities();
5090 let available_commands = server_capabilities
5091 .execute_command_provider
5092 .as_ref()
5093 .map(|options| options.commands.as_slice())
5094 .unwrap_or_default();
5095 if available_commands.contains(&command.command) {
5096 this.update(cx, |this, _| {
5097 this.as_local_mut()
5098 .unwrap()
5099 .last_workspace_edits_by_language_server
5100 .remove(&lang_server.server_id());
5101 })?;
5102
5103 let _result = lang_server
5104 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5105 command: command.command.clone(),
5106 arguments: command.arguments.clone().unwrap_or_default(),
5107 ..lsp::ExecuteCommandParams::default()
5108 })
5109 .await.into_response()
5110 .context("execute command")?;
5111
5112 return this.update(cx, |this, _| {
5113 this.as_local_mut()
5114 .unwrap()
5115 .last_workspace_edits_by_language_server
5116 .remove(&lang_server.server_id())
5117 .unwrap_or_default()
5118 });
5119 } else {
5120 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5121 }
5122 }
5123
5124 Ok(ProjectTransaction::default())
5125 })
5126 } else {
5127 Task::ready(Err(anyhow!("no upstream client and not local")))
5128 }
5129 }
5130
5131 pub fn apply_code_action_kind(
5132 &mut self,
5133 buffers: HashSet<Entity<Buffer>>,
5134 kind: CodeActionKind,
5135 push_to_history: bool,
5136 cx: &mut Context<Self>,
5137 ) -> Task<anyhow::Result<ProjectTransaction>> {
5138 if self.as_local().is_some() {
5139 cx.spawn(async move |lsp_store, cx| {
5140 let buffers = buffers.into_iter().collect::<Vec<_>>();
5141 let result = LocalLspStore::execute_code_action_kind_locally(
5142 lsp_store.clone(),
5143 buffers,
5144 kind,
5145 push_to_history,
5146 cx,
5147 )
5148 .await;
5149 lsp_store.update(cx, |lsp_store, _| {
5150 lsp_store.update_last_formatting_failure(&result);
5151 })?;
5152 result
5153 })
5154 } else if let Some((client, project_id)) = self.upstream_client() {
5155 let buffer_store = self.buffer_store();
5156 cx.spawn(async move |lsp_store, cx| {
5157 let result = client
5158 .request(proto::ApplyCodeActionKind {
5159 project_id,
5160 kind: kind.as_str().to_owned(),
5161 buffer_ids: buffers
5162 .iter()
5163 .map(|buffer| {
5164 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5165 })
5166 .collect::<Result<_>>()?,
5167 })
5168 .await
5169 .and_then(|result| result.transaction.context("missing transaction"));
5170 lsp_store.update(cx, |lsp_store, _| {
5171 lsp_store.update_last_formatting_failure(&result);
5172 })?;
5173
5174 let transaction_response = result?;
5175 buffer_store
5176 .update(cx, |buffer_store, cx| {
5177 buffer_store.deserialize_project_transaction(
5178 transaction_response,
5179 push_to_history,
5180 cx,
5181 )
5182 })?
5183 .await
5184 })
5185 } else {
5186 Task::ready(Ok(ProjectTransaction::default()))
5187 }
5188 }
5189
5190 pub fn resolved_hint(
5191 &mut self,
5192 buffer_id: BufferId,
5193 id: InlayId,
5194 cx: &mut Context<Self>,
5195 ) -> Option<ResolvedHint> {
5196 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5197
5198 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5199 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5200 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5201 let (server_id, resolve_data) = match &hint.resolve_state {
5202 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5203 ResolveState::Resolving => {
5204 return Some(ResolvedHint::Resolving(
5205 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5206 ));
5207 }
5208 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5209 };
5210
5211 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5212 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5213 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5214 id,
5215 cx.spawn(async move |lsp_store, cx| {
5216 let resolved_hint = resolve_task.await;
5217 lsp_store
5218 .update(cx, |lsp_store, _| {
5219 if let Some(old_inlay_hint) = lsp_store
5220 .lsp_data
5221 .get_mut(&buffer_id)
5222 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5223 {
5224 match resolved_hint {
5225 Ok(resolved_hint) => {
5226 *old_inlay_hint = resolved_hint;
5227 }
5228 Err(e) => {
5229 old_inlay_hint.resolve_state =
5230 ResolveState::CanResolve(server_id, resolve_data);
5231 log::error!("Inlay hint resolve failed: {e:#}");
5232 }
5233 }
5234 }
5235 })
5236 .ok();
5237 })
5238 .shared(),
5239 );
5240 debug_assert!(
5241 previous_task.is_none(),
5242 "Did not change hint's resolve state after spawning its resolve"
5243 );
5244 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5245 None
5246 }
5247
5248 fn resolve_inlay_hint(
5249 &self,
5250 mut hint: InlayHint,
5251 buffer: Entity<Buffer>,
5252 server_id: LanguageServerId,
5253 cx: &mut Context<Self>,
5254 ) -> Task<anyhow::Result<InlayHint>> {
5255 if let Some((upstream_client, project_id)) = self.upstream_client() {
5256 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5257 {
5258 hint.resolve_state = ResolveState::Resolved;
5259 return Task::ready(Ok(hint));
5260 }
5261 let request = proto::ResolveInlayHint {
5262 project_id,
5263 buffer_id: buffer.read(cx).remote_id().into(),
5264 language_server_id: server_id.0 as u64,
5265 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5266 };
5267 cx.background_spawn(async move {
5268 let response = upstream_client
5269 .request(request)
5270 .await
5271 .context("inlay hints proto request")?;
5272 match response.hint {
5273 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5274 .context("inlay hints proto resolve response conversion"),
5275 None => Ok(hint),
5276 }
5277 })
5278 } else {
5279 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5280 self.language_server_for_local_buffer(buffer, server_id, cx)
5281 .map(|(_, server)| server.clone())
5282 }) else {
5283 return Task::ready(Ok(hint));
5284 };
5285 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5286 return Task::ready(Ok(hint));
5287 }
5288 let buffer_snapshot = buffer.read(cx).snapshot();
5289 cx.spawn(async move |_, cx| {
5290 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5291 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5292 );
5293 let resolved_hint = resolve_task
5294 .await
5295 .into_response()
5296 .context("inlay hint resolve LSP request")?;
5297 let resolved_hint = InlayHints::lsp_to_project_hint(
5298 resolved_hint,
5299 &buffer,
5300 server_id,
5301 ResolveState::Resolved,
5302 false,
5303 cx,
5304 )
5305 .await?;
5306 Ok(resolved_hint)
5307 })
5308 }
5309 }
5310
5311 pub fn resolve_color_presentation(
5312 &mut self,
5313 mut color: DocumentColor,
5314 buffer: Entity<Buffer>,
5315 server_id: LanguageServerId,
5316 cx: &mut Context<Self>,
5317 ) -> Task<Result<DocumentColor>> {
5318 if color.resolved {
5319 return Task::ready(Ok(color));
5320 }
5321
5322 if let Some((upstream_client, project_id)) = self.upstream_client() {
5323 let start = color.lsp_range.start;
5324 let end = color.lsp_range.end;
5325 let request = proto::GetColorPresentation {
5326 project_id,
5327 server_id: server_id.to_proto(),
5328 buffer_id: buffer.read(cx).remote_id().into(),
5329 color: Some(proto::ColorInformation {
5330 red: color.color.red,
5331 green: color.color.green,
5332 blue: color.color.blue,
5333 alpha: color.color.alpha,
5334 lsp_range_start: Some(proto::PointUtf16 {
5335 row: start.line,
5336 column: start.character,
5337 }),
5338 lsp_range_end: Some(proto::PointUtf16 {
5339 row: end.line,
5340 column: end.character,
5341 }),
5342 }),
5343 };
5344 cx.background_spawn(async move {
5345 let response = upstream_client
5346 .request(request)
5347 .await
5348 .context("color presentation proto request")?;
5349 color.resolved = true;
5350 color.color_presentations = response
5351 .presentations
5352 .into_iter()
5353 .map(|presentation| ColorPresentation {
5354 label: SharedString::from(presentation.label),
5355 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5356 additional_text_edits: presentation
5357 .additional_text_edits
5358 .into_iter()
5359 .filter_map(deserialize_lsp_edit)
5360 .collect(),
5361 })
5362 .collect();
5363 Ok(color)
5364 })
5365 } else {
5366 let path = match buffer
5367 .update(cx, |buffer, cx| {
5368 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5369 })
5370 .context("buffer with the missing path")
5371 {
5372 Ok(path) => path,
5373 Err(e) => return Task::ready(Err(e)),
5374 };
5375 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5376 self.language_server_for_local_buffer(buffer, server_id, cx)
5377 .map(|(_, server)| server.clone())
5378 }) else {
5379 return Task::ready(Ok(color));
5380 };
5381 cx.background_spawn(async move {
5382 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5383 lsp::ColorPresentationParams {
5384 text_document: make_text_document_identifier(&path)?,
5385 color: color.color,
5386 range: color.lsp_range,
5387 work_done_progress_params: Default::default(),
5388 partial_result_params: Default::default(),
5389 },
5390 );
5391 color.color_presentations = resolve_task
5392 .await
5393 .into_response()
5394 .context("color presentation resolve LSP request")?
5395 .into_iter()
5396 .map(|presentation| ColorPresentation {
5397 label: SharedString::from(presentation.label),
5398 text_edit: presentation.text_edit,
5399 additional_text_edits: presentation
5400 .additional_text_edits
5401 .unwrap_or_default(),
5402 })
5403 .collect();
5404 color.resolved = true;
5405 Ok(color)
5406 })
5407 }
5408 }
5409
5410 pub(crate) fn linked_edits(
5411 &mut self,
5412 buffer: &Entity<Buffer>,
5413 position: Anchor,
5414 cx: &mut Context<Self>,
5415 ) -> Task<Result<Vec<Range<Anchor>>>> {
5416 let snapshot = buffer.read(cx).snapshot();
5417 let scope = snapshot.language_scope_at(position);
5418 let Some(server_id) = self
5419 .as_local()
5420 .and_then(|local| {
5421 buffer.update(cx, |buffer, cx| {
5422 local
5423 .language_servers_for_buffer(buffer, cx)
5424 .filter(|(_, server)| {
5425 LinkedEditingRange::check_server_capabilities(server.capabilities())
5426 })
5427 .filter(|(adapter, _)| {
5428 scope
5429 .as_ref()
5430 .map(|scope| scope.language_allowed(&adapter.name))
5431 .unwrap_or(true)
5432 })
5433 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5434 .next()
5435 })
5436 })
5437 .or_else(|| {
5438 self.upstream_client()
5439 .is_some()
5440 .then_some(LanguageServerToQuery::FirstCapable)
5441 })
5442 .filter(|_| {
5443 maybe!({
5444 let language = buffer.read(cx).language_at(position)?;
5445 Some(
5446 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5447 .linked_edits,
5448 )
5449 }) == Some(true)
5450 })
5451 else {
5452 return Task::ready(Ok(Vec::new()));
5453 };
5454
5455 self.request_lsp(
5456 buffer.clone(),
5457 server_id,
5458 LinkedEditingRange { position },
5459 cx,
5460 )
5461 }
5462
5463 fn apply_on_type_formatting(
5464 &mut self,
5465 buffer: Entity<Buffer>,
5466 position: Anchor,
5467 trigger: String,
5468 cx: &mut Context<Self>,
5469 ) -> Task<Result<Option<Transaction>>> {
5470 if let Some((client, project_id)) = self.upstream_client() {
5471 if !self.check_if_capable_for_proto_request(
5472 &buffer,
5473 |capabilities| {
5474 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5475 },
5476 cx,
5477 ) {
5478 return Task::ready(Ok(None));
5479 }
5480 let request = proto::OnTypeFormatting {
5481 project_id,
5482 buffer_id: buffer.read(cx).remote_id().into(),
5483 position: Some(serialize_anchor(&position)),
5484 trigger,
5485 version: serialize_version(&buffer.read(cx).version()),
5486 };
5487 cx.background_spawn(async move {
5488 client
5489 .request(request)
5490 .await?
5491 .transaction
5492 .map(language::proto::deserialize_transaction)
5493 .transpose()
5494 })
5495 } else if let Some(local) = self.as_local_mut() {
5496 let buffer_id = buffer.read(cx).remote_id();
5497 local.buffers_being_formatted.insert(buffer_id);
5498 cx.spawn(async move |this, cx| {
5499 let _cleanup = defer({
5500 let this = this.clone();
5501 let mut cx = cx.clone();
5502 move || {
5503 this.update(&mut cx, |this, _| {
5504 if let Some(local) = this.as_local_mut() {
5505 local.buffers_being_formatted.remove(&buffer_id);
5506 }
5507 })
5508 .ok();
5509 }
5510 });
5511
5512 buffer
5513 .update(cx, |buffer, _| {
5514 buffer.wait_for_edits(Some(position.timestamp))
5515 })?
5516 .await?;
5517 this.update(cx, |this, cx| {
5518 let position = position.to_point_utf16(buffer.read(cx));
5519 this.on_type_format(buffer, position, trigger, false, cx)
5520 })?
5521 .await
5522 })
5523 } else {
5524 Task::ready(Err(anyhow!("No upstream client or local language server")))
5525 }
5526 }
5527
5528 pub fn on_type_format<T: ToPointUtf16>(
5529 &mut self,
5530 buffer: Entity<Buffer>,
5531 position: T,
5532 trigger: String,
5533 push_to_history: bool,
5534 cx: &mut Context<Self>,
5535 ) -> Task<Result<Option<Transaction>>> {
5536 let position = position.to_point_utf16(buffer.read(cx));
5537 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5538 }
5539
5540 fn on_type_format_impl(
5541 &mut self,
5542 buffer: Entity<Buffer>,
5543 position: PointUtf16,
5544 trigger: String,
5545 push_to_history: bool,
5546 cx: &mut Context<Self>,
5547 ) -> Task<Result<Option<Transaction>>> {
5548 let options = buffer.update(cx, |buffer, cx| {
5549 lsp_command::lsp_formatting_options(
5550 language_settings(
5551 buffer.language_at(position).map(|l| l.name()),
5552 buffer.file(),
5553 cx,
5554 )
5555 .as_ref(),
5556 )
5557 });
5558
5559 cx.spawn(async move |this, cx| {
5560 if let Some(waiter) =
5561 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5562 {
5563 waiter.await?;
5564 }
5565 cx.update(|cx| {
5566 this.update(cx, |this, cx| {
5567 this.request_lsp(
5568 buffer.clone(),
5569 LanguageServerToQuery::FirstCapable,
5570 OnTypeFormatting {
5571 position,
5572 trigger,
5573 options,
5574 push_to_history,
5575 },
5576 cx,
5577 )
5578 })
5579 })??
5580 .await
5581 })
5582 }
5583
5584 pub fn definitions(
5585 &mut self,
5586 buffer: &Entity<Buffer>,
5587 position: PointUtf16,
5588 cx: &mut Context<Self>,
5589 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5590 if let Some((upstream_client, project_id)) = self.upstream_client() {
5591 let request = GetDefinitions { position };
5592 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5593 return Task::ready(Ok(None));
5594 }
5595 let request_task = upstream_client.request_lsp(
5596 project_id,
5597 None,
5598 LSP_REQUEST_TIMEOUT,
5599 cx.background_executor().clone(),
5600 request.to_proto(project_id, buffer.read(cx)),
5601 );
5602 let buffer = buffer.clone();
5603 cx.spawn(async move |weak_lsp_store, cx| {
5604 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5605 return Ok(None);
5606 };
5607 let Some(responses) = request_task.await? else {
5608 return Ok(None);
5609 };
5610 let actions = join_all(responses.payload.into_iter().map(|response| {
5611 GetDefinitions { position }.response_from_proto(
5612 response.response,
5613 lsp_store.clone(),
5614 buffer.clone(),
5615 cx.clone(),
5616 )
5617 }))
5618 .await;
5619
5620 Ok(Some(
5621 actions
5622 .into_iter()
5623 .collect::<Result<Vec<Vec<_>>>>()?
5624 .into_iter()
5625 .flatten()
5626 .dedup()
5627 .collect(),
5628 ))
5629 })
5630 } else {
5631 let definitions_task = self.request_multiple_lsp_locally(
5632 buffer,
5633 Some(position),
5634 GetDefinitions { position },
5635 cx,
5636 );
5637 cx.background_spawn(async move {
5638 Ok(Some(
5639 definitions_task
5640 .await
5641 .into_iter()
5642 .flat_map(|(_, definitions)| definitions)
5643 .dedup()
5644 .collect(),
5645 ))
5646 })
5647 }
5648 }
5649
5650 pub fn declarations(
5651 &mut self,
5652 buffer: &Entity<Buffer>,
5653 position: PointUtf16,
5654 cx: &mut Context<Self>,
5655 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5656 if let Some((upstream_client, project_id)) = self.upstream_client() {
5657 let request = GetDeclarations { position };
5658 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5659 return Task::ready(Ok(None));
5660 }
5661 let request_task = upstream_client.request_lsp(
5662 project_id,
5663 None,
5664 LSP_REQUEST_TIMEOUT,
5665 cx.background_executor().clone(),
5666 request.to_proto(project_id, buffer.read(cx)),
5667 );
5668 let buffer = buffer.clone();
5669 cx.spawn(async move |weak_lsp_store, cx| {
5670 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5671 return Ok(None);
5672 };
5673 let Some(responses) = request_task.await? else {
5674 return Ok(None);
5675 };
5676 let actions = join_all(responses.payload.into_iter().map(|response| {
5677 GetDeclarations { position }.response_from_proto(
5678 response.response,
5679 lsp_store.clone(),
5680 buffer.clone(),
5681 cx.clone(),
5682 )
5683 }))
5684 .await;
5685
5686 Ok(Some(
5687 actions
5688 .into_iter()
5689 .collect::<Result<Vec<Vec<_>>>>()?
5690 .into_iter()
5691 .flatten()
5692 .dedup()
5693 .collect(),
5694 ))
5695 })
5696 } else {
5697 let declarations_task = self.request_multiple_lsp_locally(
5698 buffer,
5699 Some(position),
5700 GetDeclarations { position },
5701 cx,
5702 );
5703 cx.background_spawn(async move {
5704 Ok(Some(
5705 declarations_task
5706 .await
5707 .into_iter()
5708 .flat_map(|(_, declarations)| declarations)
5709 .dedup()
5710 .collect(),
5711 ))
5712 })
5713 }
5714 }
5715
5716 pub fn type_definitions(
5717 &mut self,
5718 buffer: &Entity<Buffer>,
5719 position: PointUtf16,
5720 cx: &mut Context<Self>,
5721 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5722 if let Some((upstream_client, project_id)) = self.upstream_client() {
5723 let request = GetTypeDefinitions { position };
5724 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5725 return Task::ready(Ok(None));
5726 }
5727 let request_task = upstream_client.request_lsp(
5728 project_id,
5729 None,
5730 LSP_REQUEST_TIMEOUT,
5731 cx.background_executor().clone(),
5732 request.to_proto(project_id, buffer.read(cx)),
5733 );
5734 let buffer = buffer.clone();
5735 cx.spawn(async move |weak_lsp_store, cx| {
5736 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5737 return Ok(None);
5738 };
5739 let Some(responses) = request_task.await? else {
5740 return Ok(None);
5741 };
5742 let actions = join_all(responses.payload.into_iter().map(|response| {
5743 GetTypeDefinitions { position }.response_from_proto(
5744 response.response,
5745 lsp_store.clone(),
5746 buffer.clone(),
5747 cx.clone(),
5748 )
5749 }))
5750 .await;
5751
5752 Ok(Some(
5753 actions
5754 .into_iter()
5755 .collect::<Result<Vec<Vec<_>>>>()?
5756 .into_iter()
5757 .flatten()
5758 .dedup()
5759 .collect(),
5760 ))
5761 })
5762 } else {
5763 let type_definitions_task = self.request_multiple_lsp_locally(
5764 buffer,
5765 Some(position),
5766 GetTypeDefinitions { position },
5767 cx,
5768 );
5769 cx.background_spawn(async move {
5770 Ok(Some(
5771 type_definitions_task
5772 .await
5773 .into_iter()
5774 .flat_map(|(_, type_definitions)| type_definitions)
5775 .dedup()
5776 .collect(),
5777 ))
5778 })
5779 }
5780 }
5781
5782 pub fn implementations(
5783 &mut self,
5784 buffer: &Entity<Buffer>,
5785 position: PointUtf16,
5786 cx: &mut Context<Self>,
5787 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5788 if let Some((upstream_client, project_id)) = self.upstream_client() {
5789 let request = GetImplementations { position };
5790 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5791 return Task::ready(Ok(None));
5792 }
5793 let request_task = upstream_client.request_lsp(
5794 project_id,
5795 None,
5796 LSP_REQUEST_TIMEOUT,
5797 cx.background_executor().clone(),
5798 request.to_proto(project_id, buffer.read(cx)),
5799 );
5800 let buffer = buffer.clone();
5801 cx.spawn(async move |weak_lsp_store, cx| {
5802 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5803 return Ok(None);
5804 };
5805 let Some(responses) = request_task.await? else {
5806 return Ok(None);
5807 };
5808 let actions = join_all(responses.payload.into_iter().map(|response| {
5809 GetImplementations { position }.response_from_proto(
5810 response.response,
5811 lsp_store.clone(),
5812 buffer.clone(),
5813 cx.clone(),
5814 )
5815 }))
5816 .await;
5817
5818 Ok(Some(
5819 actions
5820 .into_iter()
5821 .collect::<Result<Vec<Vec<_>>>>()?
5822 .into_iter()
5823 .flatten()
5824 .dedup()
5825 .collect(),
5826 ))
5827 })
5828 } else {
5829 let implementations_task = self.request_multiple_lsp_locally(
5830 buffer,
5831 Some(position),
5832 GetImplementations { position },
5833 cx,
5834 );
5835 cx.background_spawn(async move {
5836 Ok(Some(
5837 implementations_task
5838 .await
5839 .into_iter()
5840 .flat_map(|(_, implementations)| implementations)
5841 .dedup()
5842 .collect(),
5843 ))
5844 })
5845 }
5846 }
5847
5848 pub fn references(
5849 &mut self,
5850 buffer: &Entity<Buffer>,
5851 position: PointUtf16,
5852 cx: &mut Context<Self>,
5853 ) -> Task<Result<Option<Vec<Location>>>> {
5854 if let Some((upstream_client, project_id)) = self.upstream_client() {
5855 let request = GetReferences { position };
5856 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5857 return Task::ready(Ok(None));
5858 }
5859
5860 let request_task = upstream_client.request_lsp(
5861 project_id,
5862 None,
5863 LSP_REQUEST_TIMEOUT,
5864 cx.background_executor().clone(),
5865 request.to_proto(project_id, buffer.read(cx)),
5866 );
5867 let buffer = buffer.clone();
5868 cx.spawn(async move |weak_lsp_store, cx| {
5869 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5870 return Ok(None);
5871 };
5872 let Some(responses) = request_task.await? else {
5873 return Ok(None);
5874 };
5875
5876 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5877 GetReferences { position }.response_from_proto(
5878 lsp_response.response,
5879 lsp_store.clone(),
5880 buffer.clone(),
5881 cx.clone(),
5882 )
5883 }))
5884 .await
5885 .into_iter()
5886 .collect::<Result<Vec<Vec<_>>>>()?
5887 .into_iter()
5888 .flatten()
5889 .dedup()
5890 .collect();
5891 Ok(Some(locations))
5892 })
5893 } else {
5894 let references_task = self.request_multiple_lsp_locally(
5895 buffer,
5896 Some(position),
5897 GetReferences { position },
5898 cx,
5899 );
5900 cx.background_spawn(async move {
5901 Ok(Some(
5902 references_task
5903 .await
5904 .into_iter()
5905 .flat_map(|(_, references)| references)
5906 .dedup()
5907 .collect(),
5908 ))
5909 })
5910 }
5911 }
5912
5913 pub fn code_actions(
5914 &mut self,
5915 buffer: &Entity<Buffer>,
5916 range: Range<Anchor>,
5917 kinds: Option<Vec<CodeActionKind>>,
5918 cx: &mut Context<Self>,
5919 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5920 if let Some((upstream_client, project_id)) = self.upstream_client() {
5921 let request = GetCodeActions {
5922 range: range.clone(),
5923 kinds: kinds.clone(),
5924 };
5925 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5926 return Task::ready(Ok(None));
5927 }
5928 let request_task = upstream_client.request_lsp(
5929 project_id,
5930 None,
5931 LSP_REQUEST_TIMEOUT,
5932 cx.background_executor().clone(),
5933 request.to_proto(project_id, buffer.read(cx)),
5934 );
5935 let buffer = buffer.clone();
5936 cx.spawn(async move |weak_lsp_store, cx| {
5937 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5938 return Ok(None);
5939 };
5940 let Some(responses) = request_task.await? else {
5941 return Ok(None);
5942 };
5943 let actions = join_all(responses.payload.into_iter().map(|response| {
5944 GetCodeActions {
5945 range: range.clone(),
5946 kinds: kinds.clone(),
5947 }
5948 .response_from_proto(
5949 response.response,
5950 lsp_store.clone(),
5951 buffer.clone(),
5952 cx.clone(),
5953 )
5954 }))
5955 .await;
5956
5957 Ok(Some(
5958 actions
5959 .into_iter()
5960 .collect::<Result<Vec<Vec<_>>>>()?
5961 .into_iter()
5962 .flatten()
5963 .collect(),
5964 ))
5965 })
5966 } else {
5967 let all_actions_task = self.request_multiple_lsp_locally(
5968 buffer,
5969 Some(range.start),
5970 GetCodeActions { range, kinds },
5971 cx,
5972 );
5973 cx.background_spawn(async move {
5974 Ok(Some(
5975 all_actions_task
5976 .await
5977 .into_iter()
5978 .flat_map(|(_, actions)| actions)
5979 .collect(),
5980 ))
5981 })
5982 }
5983 }
5984
5985 pub fn code_lens_actions(
5986 &mut self,
5987 buffer: &Entity<Buffer>,
5988 cx: &mut Context<Self>,
5989 ) -> CodeLensTask {
5990 let version_queried_for = buffer.read(cx).version();
5991 let buffer_id = buffer.read(cx).remote_id();
5992 let existing_servers = self.as_local().map(|local| {
5993 local
5994 .buffers_opened_in_servers
5995 .get(&buffer_id)
5996 .cloned()
5997 .unwrap_or_default()
5998 });
5999
6000 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6001 if let Some(cached_lens) = &lsp_data.code_lens {
6002 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6003 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6004 existing_servers != cached_lens.lens.keys().copied().collect()
6005 });
6006 if !has_different_servers {
6007 return Task::ready(Ok(Some(
6008 cached_lens.lens.values().flatten().cloned().collect(),
6009 )))
6010 .shared();
6011 }
6012 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6013 if !version_queried_for.changed_since(updating_for) {
6014 return running_update.clone();
6015 }
6016 }
6017 }
6018 }
6019
6020 let lens_lsp_data = self
6021 .latest_lsp_data(buffer, cx)
6022 .code_lens
6023 .get_or_insert_default();
6024 let buffer = buffer.clone();
6025 let query_version_queried_for = version_queried_for.clone();
6026 let new_task = cx
6027 .spawn(async move |lsp_store, cx| {
6028 cx.background_executor()
6029 .timer(Duration::from_millis(30))
6030 .await;
6031 let fetched_lens = lsp_store
6032 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6033 .map_err(Arc::new)?
6034 .await
6035 .context("fetching code lens")
6036 .map_err(Arc::new);
6037 let fetched_lens = match fetched_lens {
6038 Ok(fetched_lens) => fetched_lens,
6039 Err(e) => {
6040 lsp_store
6041 .update(cx, |lsp_store, _| {
6042 if let Some(lens_lsp_data) = lsp_store
6043 .lsp_data
6044 .get_mut(&buffer_id)
6045 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6046 {
6047 lens_lsp_data.update = None;
6048 }
6049 })
6050 .ok();
6051 return Err(e);
6052 }
6053 };
6054
6055 lsp_store
6056 .update(cx, |lsp_store, _| {
6057 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6058 let code_lens = lsp_data.code_lens.as_mut()?;
6059 if let Some(fetched_lens) = fetched_lens {
6060 if lsp_data.buffer_version == query_version_queried_for {
6061 code_lens.lens.extend(fetched_lens);
6062 } else if !lsp_data
6063 .buffer_version
6064 .changed_since(&query_version_queried_for)
6065 {
6066 lsp_data.buffer_version = query_version_queried_for;
6067 code_lens.lens = fetched_lens;
6068 }
6069 }
6070 code_lens.update = None;
6071 Some(code_lens.lens.values().flatten().cloned().collect())
6072 })
6073 .map_err(Arc::new)
6074 })
6075 .shared();
6076 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6077 new_task
6078 }
6079
6080 fn fetch_code_lens(
6081 &mut self,
6082 buffer: &Entity<Buffer>,
6083 cx: &mut Context<Self>,
6084 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6085 if let Some((upstream_client, project_id)) = self.upstream_client() {
6086 let request = GetCodeLens;
6087 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6088 return Task::ready(Ok(None));
6089 }
6090 let request_task = upstream_client.request_lsp(
6091 project_id,
6092 None,
6093 LSP_REQUEST_TIMEOUT,
6094 cx.background_executor().clone(),
6095 request.to_proto(project_id, buffer.read(cx)),
6096 );
6097 let buffer = buffer.clone();
6098 cx.spawn(async move |weak_lsp_store, cx| {
6099 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6100 return Ok(None);
6101 };
6102 let Some(responses) = request_task.await? else {
6103 return Ok(None);
6104 };
6105
6106 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6107 let lsp_store = lsp_store.clone();
6108 let buffer = buffer.clone();
6109 let cx = cx.clone();
6110 async move {
6111 (
6112 LanguageServerId::from_proto(response.server_id),
6113 GetCodeLens
6114 .response_from_proto(response.response, lsp_store, buffer, cx)
6115 .await,
6116 )
6117 }
6118 }))
6119 .await;
6120
6121 let mut has_errors = false;
6122 let code_lens_actions = code_lens_actions
6123 .into_iter()
6124 .filter_map(|(server_id, code_lens)| match code_lens {
6125 Ok(code_lens) => Some((server_id, code_lens)),
6126 Err(e) => {
6127 has_errors = true;
6128 log::error!("{e:#}");
6129 None
6130 }
6131 })
6132 .collect::<HashMap<_, _>>();
6133 anyhow::ensure!(
6134 !has_errors || !code_lens_actions.is_empty(),
6135 "Failed to fetch code lens"
6136 );
6137 Ok(Some(code_lens_actions))
6138 })
6139 } else {
6140 let code_lens_actions_task =
6141 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6142 cx.background_spawn(async move {
6143 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6144 })
6145 }
6146 }
6147
6148 #[inline(never)]
6149 pub fn completions(
6150 &self,
6151 buffer: &Entity<Buffer>,
6152 position: PointUtf16,
6153 context: CompletionContext,
6154 cx: &mut Context<Self>,
6155 ) -> Task<Result<Vec<CompletionResponse>>> {
6156 let language_registry = self.languages.clone();
6157
6158 if let Some((upstream_client, project_id)) = self.upstream_client() {
6159 let snapshot = buffer.read(cx).snapshot();
6160 let offset = position.to_offset(&snapshot);
6161 let scope = snapshot.language_scope_at(offset);
6162 let capable_lsps = self.all_capable_for_proto_request(
6163 buffer,
6164 |server_name, capabilities| {
6165 capabilities.completion_provider.is_some()
6166 && scope
6167 .as_ref()
6168 .map(|scope| scope.language_allowed(server_name))
6169 .unwrap_or(true)
6170 },
6171 cx,
6172 );
6173 if capable_lsps.is_empty() {
6174 return Task::ready(Ok(Vec::new()));
6175 }
6176
6177 let language = buffer.read(cx).language().cloned();
6178
6179 // In the future, we should provide project guests with the names of LSP adapters,
6180 // so that they can use the correct LSP adapter when computing labels. For now,
6181 // guests just use the first LSP adapter associated with the buffer's language.
6182 let lsp_adapter = language.as_ref().and_then(|language| {
6183 language_registry
6184 .lsp_adapters(&language.name())
6185 .first()
6186 .cloned()
6187 });
6188
6189 let buffer = buffer.clone();
6190
6191 cx.spawn(async move |this, cx| {
6192 let requests = join_all(
6193 capable_lsps
6194 .into_iter()
6195 .map(|id| {
6196 let request = GetCompletions {
6197 position,
6198 context: context.clone(),
6199 server_id: Some(id),
6200 };
6201 let buffer = buffer.clone();
6202 let language = language.clone();
6203 let lsp_adapter = lsp_adapter.clone();
6204 let upstream_client = upstream_client.clone();
6205 let response = this
6206 .update(cx, |this, cx| {
6207 this.send_lsp_proto_request(
6208 buffer,
6209 upstream_client,
6210 project_id,
6211 request,
6212 cx,
6213 )
6214 })
6215 .log_err();
6216 async move {
6217 let response = response?.await.log_err()?;
6218
6219 let completions = populate_labels_for_completions(
6220 response.completions,
6221 language,
6222 lsp_adapter,
6223 )
6224 .await;
6225
6226 Some(CompletionResponse {
6227 completions,
6228 display_options: CompletionDisplayOptions::default(),
6229 is_incomplete: response.is_incomplete,
6230 })
6231 }
6232 })
6233 .collect::<Vec<_>>(),
6234 );
6235 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6236 })
6237 } else if let Some(local) = self.as_local() {
6238 let snapshot = buffer.read(cx).snapshot();
6239 let offset = position.to_offset(&snapshot);
6240 let scope = snapshot.language_scope_at(offset);
6241 let language = snapshot.language().cloned();
6242 let completion_settings = language_settings(
6243 language.as_ref().map(|language| language.name()),
6244 buffer.read(cx).file(),
6245 cx,
6246 )
6247 .completions
6248 .clone();
6249 if !completion_settings.lsp {
6250 return Task::ready(Ok(Vec::new()));
6251 }
6252
6253 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6254 local
6255 .language_servers_for_buffer(buffer, cx)
6256 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6257 .filter(|(adapter, _)| {
6258 scope
6259 .as_ref()
6260 .map(|scope| scope.language_allowed(&adapter.name))
6261 .unwrap_or(true)
6262 })
6263 .map(|(_, server)| server.server_id())
6264 .collect()
6265 });
6266
6267 let buffer = buffer.clone();
6268 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6269 let lsp_timeout = if lsp_timeout > 0 {
6270 Some(Duration::from_millis(lsp_timeout))
6271 } else {
6272 None
6273 };
6274 cx.spawn(async move |this, cx| {
6275 let mut tasks = Vec::with_capacity(server_ids.len());
6276 this.update(cx, |lsp_store, cx| {
6277 for server_id in server_ids {
6278 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6279 let lsp_timeout = lsp_timeout
6280 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6281 let mut timeout = cx.background_spawn(async move {
6282 match lsp_timeout {
6283 Some(lsp_timeout) => {
6284 lsp_timeout.await;
6285 true
6286 },
6287 None => false,
6288 }
6289 }).fuse();
6290 let mut lsp_request = lsp_store.request_lsp(
6291 buffer.clone(),
6292 LanguageServerToQuery::Other(server_id),
6293 GetCompletions {
6294 position,
6295 context: context.clone(),
6296 server_id: Some(server_id),
6297 },
6298 cx,
6299 ).fuse();
6300 let new_task = cx.background_spawn(async move {
6301 select_biased! {
6302 response = lsp_request => anyhow::Ok(Some(response?)),
6303 timeout_happened = timeout => {
6304 if timeout_happened {
6305 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6306 Ok(None)
6307 } else {
6308 let completions = lsp_request.await?;
6309 Ok(Some(completions))
6310 }
6311 },
6312 }
6313 });
6314 tasks.push((lsp_adapter, new_task));
6315 }
6316 })?;
6317
6318 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6319 let completion_response = task.await.ok()??;
6320 let completions = populate_labels_for_completions(
6321 completion_response.completions,
6322 language.clone(),
6323 lsp_adapter,
6324 )
6325 .await;
6326 Some(CompletionResponse {
6327 completions,
6328 display_options: CompletionDisplayOptions::default(),
6329 is_incomplete: completion_response.is_incomplete,
6330 })
6331 });
6332
6333 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6334
6335 Ok(responses.into_iter().flatten().collect())
6336 })
6337 } else {
6338 Task::ready(Err(anyhow!("No upstream client or local language server")))
6339 }
6340 }
6341
6342 pub fn resolve_completions(
6343 &self,
6344 buffer: Entity<Buffer>,
6345 completion_indices: Vec<usize>,
6346 completions: Rc<RefCell<Box<[Completion]>>>,
6347 cx: &mut Context<Self>,
6348 ) -> Task<Result<bool>> {
6349 let client = self.upstream_client();
6350 let buffer_id = buffer.read(cx).remote_id();
6351 let buffer_snapshot = buffer.read(cx).snapshot();
6352
6353 if !self.check_if_capable_for_proto_request(
6354 &buffer,
6355 GetCompletions::can_resolve_completions,
6356 cx,
6357 ) {
6358 return Task::ready(Ok(false));
6359 }
6360 cx.spawn(async move |lsp_store, cx| {
6361 let mut did_resolve = false;
6362 if let Some((client, project_id)) = client {
6363 for completion_index in completion_indices {
6364 let server_id = {
6365 let completion = &completions.borrow()[completion_index];
6366 completion.source.server_id()
6367 };
6368 if let Some(server_id) = server_id {
6369 if Self::resolve_completion_remote(
6370 project_id,
6371 server_id,
6372 buffer_id,
6373 completions.clone(),
6374 completion_index,
6375 client.clone(),
6376 )
6377 .await
6378 .log_err()
6379 .is_some()
6380 {
6381 did_resolve = true;
6382 }
6383 } else {
6384 resolve_word_completion(
6385 &buffer_snapshot,
6386 &mut completions.borrow_mut()[completion_index],
6387 );
6388 }
6389 }
6390 } else {
6391 for completion_index in completion_indices {
6392 let server_id = {
6393 let completion = &completions.borrow()[completion_index];
6394 completion.source.server_id()
6395 };
6396 if let Some(server_id) = server_id {
6397 let server_and_adapter = lsp_store
6398 .read_with(cx, |lsp_store, _| {
6399 let server = lsp_store.language_server_for_id(server_id)?;
6400 let adapter =
6401 lsp_store.language_server_adapter_for_id(server.server_id())?;
6402 Some((server, adapter))
6403 })
6404 .ok()
6405 .flatten();
6406 let Some((server, adapter)) = server_and_adapter else {
6407 continue;
6408 };
6409
6410 let resolved = Self::resolve_completion_local(
6411 server,
6412 completions.clone(),
6413 completion_index,
6414 )
6415 .await
6416 .log_err()
6417 .is_some();
6418 if resolved {
6419 Self::regenerate_completion_labels(
6420 adapter,
6421 &buffer_snapshot,
6422 completions.clone(),
6423 completion_index,
6424 )
6425 .await
6426 .log_err();
6427 did_resolve = true;
6428 }
6429 } else {
6430 resolve_word_completion(
6431 &buffer_snapshot,
6432 &mut completions.borrow_mut()[completion_index],
6433 );
6434 }
6435 }
6436 }
6437
6438 Ok(did_resolve)
6439 })
6440 }
6441
6442 async fn resolve_completion_local(
6443 server: Arc<lsp::LanguageServer>,
6444 completions: Rc<RefCell<Box<[Completion]>>>,
6445 completion_index: usize,
6446 ) -> Result<()> {
6447 let server_id = server.server_id();
6448 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6449 return Ok(());
6450 }
6451
6452 let request = {
6453 let completion = &completions.borrow()[completion_index];
6454 match &completion.source {
6455 CompletionSource::Lsp {
6456 lsp_completion,
6457 resolved,
6458 server_id: completion_server_id,
6459 ..
6460 } => {
6461 if *resolved {
6462 return Ok(());
6463 }
6464 anyhow::ensure!(
6465 server_id == *completion_server_id,
6466 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6467 );
6468 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6469 }
6470 CompletionSource::BufferWord { .. }
6471 | CompletionSource::Dap { .. }
6472 | CompletionSource::Custom => {
6473 return Ok(());
6474 }
6475 }
6476 };
6477 let resolved_completion = request
6478 .await
6479 .into_response()
6480 .context("resolve completion")?;
6481
6482 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6483 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6484
6485 let mut completions = completions.borrow_mut();
6486 let completion = &mut completions[completion_index];
6487 if let CompletionSource::Lsp {
6488 lsp_completion,
6489 resolved,
6490 server_id: completion_server_id,
6491 ..
6492 } = &mut completion.source
6493 {
6494 if *resolved {
6495 return Ok(());
6496 }
6497 anyhow::ensure!(
6498 server_id == *completion_server_id,
6499 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6500 );
6501 **lsp_completion = resolved_completion;
6502 *resolved = true;
6503 }
6504 Ok(())
6505 }
6506
6507 async fn regenerate_completion_labels(
6508 adapter: Arc<CachedLspAdapter>,
6509 snapshot: &BufferSnapshot,
6510 completions: Rc<RefCell<Box<[Completion]>>>,
6511 completion_index: usize,
6512 ) -> Result<()> {
6513 let completion_item = completions.borrow()[completion_index]
6514 .source
6515 .lsp_completion(true)
6516 .map(Cow::into_owned);
6517 if let Some(lsp_documentation) = completion_item
6518 .as_ref()
6519 .and_then(|completion_item| completion_item.documentation.clone())
6520 {
6521 let mut completions = completions.borrow_mut();
6522 let completion = &mut completions[completion_index];
6523 completion.documentation = Some(lsp_documentation.into());
6524 } else {
6525 let mut completions = completions.borrow_mut();
6526 let completion = &mut completions[completion_index];
6527 completion.documentation = Some(CompletionDocumentation::Undocumented);
6528 }
6529
6530 let mut new_label = match completion_item {
6531 Some(completion_item) => {
6532 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6533 // So we have to update the label here anyway...
6534 let language = snapshot.language();
6535 match language {
6536 Some(language) => {
6537 adapter
6538 .labels_for_completions(
6539 std::slice::from_ref(&completion_item),
6540 language,
6541 )
6542 .await?
6543 }
6544 None => Vec::new(),
6545 }
6546 .pop()
6547 .flatten()
6548 .unwrap_or_else(|| {
6549 CodeLabel::fallback_for_completion(
6550 &completion_item,
6551 language.map(|language| language.as_ref()),
6552 )
6553 })
6554 }
6555 None => CodeLabel::plain(
6556 completions.borrow()[completion_index].new_text.clone(),
6557 None,
6558 ),
6559 };
6560 ensure_uniform_list_compatible_label(&mut new_label);
6561
6562 let mut completions = completions.borrow_mut();
6563 let completion = &mut completions[completion_index];
6564 if completion.label.filter_text() == new_label.filter_text() {
6565 completion.label = new_label;
6566 } else {
6567 log::error!(
6568 "Resolved completion changed display label from {} to {}. \
6569 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6570 completion.label.text(),
6571 new_label.text(),
6572 completion.label.filter_text(),
6573 new_label.filter_text()
6574 );
6575 }
6576
6577 Ok(())
6578 }
6579
6580 async fn resolve_completion_remote(
6581 project_id: u64,
6582 server_id: LanguageServerId,
6583 buffer_id: BufferId,
6584 completions: Rc<RefCell<Box<[Completion]>>>,
6585 completion_index: usize,
6586 client: AnyProtoClient,
6587 ) -> Result<()> {
6588 let lsp_completion = {
6589 let completion = &completions.borrow()[completion_index];
6590 match &completion.source {
6591 CompletionSource::Lsp {
6592 lsp_completion,
6593 resolved,
6594 server_id: completion_server_id,
6595 ..
6596 } => {
6597 anyhow::ensure!(
6598 server_id == *completion_server_id,
6599 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6600 );
6601 if *resolved {
6602 return Ok(());
6603 }
6604 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6605 }
6606 CompletionSource::Custom
6607 | CompletionSource::Dap { .. }
6608 | CompletionSource::BufferWord { .. } => {
6609 return Ok(());
6610 }
6611 }
6612 };
6613 let request = proto::ResolveCompletionDocumentation {
6614 project_id,
6615 language_server_id: server_id.0 as u64,
6616 lsp_completion,
6617 buffer_id: buffer_id.into(),
6618 };
6619
6620 let response = client
6621 .request(request)
6622 .await
6623 .context("completion documentation resolve proto request")?;
6624 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6625
6626 let documentation = if response.documentation.is_empty() {
6627 CompletionDocumentation::Undocumented
6628 } else if response.documentation_is_markdown {
6629 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6630 } else if response.documentation.lines().count() <= 1 {
6631 CompletionDocumentation::SingleLine(response.documentation.into())
6632 } else {
6633 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6634 };
6635
6636 let mut completions = completions.borrow_mut();
6637 let completion = &mut completions[completion_index];
6638 completion.documentation = Some(documentation);
6639 if let CompletionSource::Lsp {
6640 insert_range,
6641 lsp_completion,
6642 resolved,
6643 server_id: completion_server_id,
6644 lsp_defaults: _,
6645 } = &mut completion.source
6646 {
6647 let completion_insert_range = response
6648 .old_insert_start
6649 .and_then(deserialize_anchor)
6650 .zip(response.old_insert_end.and_then(deserialize_anchor));
6651 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6652
6653 if *resolved {
6654 return Ok(());
6655 }
6656 anyhow::ensure!(
6657 server_id == *completion_server_id,
6658 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6659 );
6660 **lsp_completion = resolved_lsp_completion;
6661 *resolved = true;
6662 }
6663
6664 let replace_range = response
6665 .old_replace_start
6666 .and_then(deserialize_anchor)
6667 .zip(response.old_replace_end.and_then(deserialize_anchor));
6668 if let Some((old_replace_start, old_replace_end)) = replace_range
6669 && !response.new_text.is_empty()
6670 {
6671 completion.new_text = response.new_text;
6672 completion.replace_range = old_replace_start..old_replace_end;
6673 }
6674
6675 Ok(())
6676 }
6677
6678 pub fn apply_additional_edits_for_completion(
6679 &self,
6680 buffer_handle: Entity<Buffer>,
6681 completions: Rc<RefCell<Box<[Completion]>>>,
6682 completion_index: usize,
6683 push_to_history: bool,
6684 cx: &mut Context<Self>,
6685 ) -> Task<Result<Option<Transaction>>> {
6686 if let Some((client, project_id)) = self.upstream_client() {
6687 let buffer = buffer_handle.read(cx);
6688 let buffer_id = buffer.remote_id();
6689 cx.spawn(async move |_, cx| {
6690 let request = {
6691 let completion = completions.borrow()[completion_index].clone();
6692 proto::ApplyCompletionAdditionalEdits {
6693 project_id,
6694 buffer_id: buffer_id.into(),
6695 completion: Some(Self::serialize_completion(&CoreCompletion {
6696 replace_range: completion.replace_range,
6697 new_text: completion.new_text,
6698 source: completion.source,
6699 })),
6700 }
6701 };
6702
6703 if let Some(transaction) = client.request(request).await?.transaction {
6704 let transaction = language::proto::deserialize_transaction(transaction)?;
6705 buffer_handle
6706 .update(cx, |buffer, _| {
6707 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6708 })?
6709 .await?;
6710 if push_to_history {
6711 buffer_handle.update(cx, |buffer, _| {
6712 buffer.push_transaction(transaction.clone(), Instant::now());
6713 buffer.finalize_last_transaction();
6714 })?;
6715 }
6716 Ok(Some(transaction))
6717 } else {
6718 Ok(None)
6719 }
6720 })
6721 } else {
6722 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6723 let completion = &completions.borrow()[completion_index];
6724 let server_id = completion.source.server_id()?;
6725 Some(
6726 self.language_server_for_local_buffer(buffer, server_id, cx)?
6727 .1
6728 .clone(),
6729 )
6730 }) else {
6731 return Task::ready(Ok(None));
6732 };
6733
6734 cx.spawn(async move |this, cx| {
6735 Self::resolve_completion_local(
6736 server.clone(),
6737 completions.clone(),
6738 completion_index,
6739 )
6740 .await
6741 .context("resolving completion")?;
6742 let completion = completions.borrow()[completion_index].clone();
6743 let additional_text_edits = completion
6744 .source
6745 .lsp_completion(true)
6746 .as_ref()
6747 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6748 if let Some(edits) = additional_text_edits {
6749 let edits = this
6750 .update(cx, |this, cx| {
6751 this.as_local_mut().unwrap().edits_from_lsp(
6752 &buffer_handle,
6753 edits,
6754 server.server_id(),
6755 None,
6756 cx,
6757 )
6758 })?
6759 .await?;
6760
6761 buffer_handle.update(cx, |buffer, cx| {
6762 buffer.finalize_last_transaction();
6763 buffer.start_transaction();
6764
6765 for (range, text) in edits {
6766 let primary = &completion.replace_range;
6767
6768 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6769 // and the primary completion is just an insertion (empty range), then this is likely
6770 // an auto-import scenario and should not be considered overlapping
6771 // https://github.com/zed-industries/zed/issues/26136
6772 let is_file_start_auto_import = {
6773 let snapshot = buffer.snapshot();
6774 let primary_start_point = primary.start.to_point(&snapshot);
6775 let range_start_point = range.start.to_point(&snapshot);
6776
6777 let result = primary_start_point.row == 0
6778 && primary_start_point.column == 0
6779 && range_start_point.row == 0
6780 && range_start_point.column == 0;
6781
6782 result
6783 };
6784
6785 let has_overlap = if is_file_start_auto_import {
6786 false
6787 } else {
6788 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6789 && primary.end.cmp(&range.start, buffer).is_ge();
6790 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6791 && range.end.cmp(&primary.end, buffer).is_ge();
6792 let result = start_within || end_within;
6793 result
6794 };
6795
6796 //Skip additional edits which overlap with the primary completion edit
6797 //https://github.com/zed-industries/zed/pull/1871
6798 if !has_overlap {
6799 buffer.edit([(range, text)], None, cx);
6800 }
6801 }
6802
6803 let transaction = if buffer.end_transaction(cx).is_some() {
6804 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6805 if !push_to_history {
6806 buffer.forget_transaction(transaction.id);
6807 }
6808 Some(transaction)
6809 } else {
6810 None
6811 };
6812 Ok(transaction)
6813 })?
6814 } else {
6815 Ok(None)
6816 }
6817 })
6818 }
6819 }
6820
6821 pub fn pull_diagnostics(
6822 &mut self,
6823 buffer: Entity<Buffer>,
6824 cx: &mut Context<Self>,
6825 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6826 let buffer_id = buffer.read(cx).remote_id();
6827
6828 if let Some((client, upstream_project_id)) = self.upstream_client() {
6829 let mut suitable_capabilities = None;
6830 // Are we capable for proto request?
6831 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6832 &buffer,
6833 |capabilities| {
6834 if let Some(caps) = &capabilities.diagnostic_provider {
6835 suitable_capabilities = Some(caps.clone());
6836 true
6837 } else {
6838 false
6839 }
6840 },
6841 cx,
6842 );
6843 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6844 let Some(dynamic_caps) = suitable_capabilities else {
6845 return Task::ready(Ok(None));
6846 };
6847 assert!(any_server_has_diagnostics_provider);
6848
6849 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6850 let request = GetDocumentDiagnostics {
6851 previous_result_id: None,
6852 identifier,
6853 registration_id: None,
6854 };
6855 let request_task = client.request_lsp(
6856 upstream_project_id,
6857 None,
6858 LSP_REQUEST_TIMEOUT,
6859 cx.background_executor().clone(),
6860 request.to_proto(upstream_project_id, buffer.read(cx)),
6861 );
6862 cx.background_spawn(async move {
6863 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6864 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6865 // Do not attempt to further process the dummy responses here.
6866 let _response = request_task.await?;
6867 Ok(None)
6868 })
6869 } else {
6870 let servers = buffer.update(cx, |buffer, cx| {
6871 self.running_language_servers_for_local_buffer(buffer, cx)
6872 .map(|(_, server)| server.clone())
6873 .collect::<Vec<_>>()
6874 });
6875
6876 let pull_diagnostics = servers
6877 .into_iter()
6878 .flat_map(|server| {
6879 let result = maybe!({
6880 let local = self.as_local()?;
6881 let server_id = server.server_id();
6882 let providers_with_identifiers = local
6883 .language_server_dynamic_registrations
6884 .get(&server_id)
6885 .into_iter()
6886 .flat_map(|registrations| registrations.diagnostics.clone())
6887 .collect::<Vec<_>>();
6888 Some(
6889 providers_with_identifiers
6890 .into_iter()
6891 .map(|(registration_id, dynamic_caps)| {
6892 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6893 let registration_id = registration_id.map(SharedString::from);
6894 let result_id = self.result_id_for_buffer_pull(
6895 server_id,
6896 buffer_id,
6897 ®istration_id,
6898 cx,
6899 );
6900 self.request_lsp(
6901 buffer.clone(),
6902 LanguageServerToQuery::Other(server_id),
6903 GetDocumentDiagnostics {
6904 previous_result_id: result_id,
6905 registration_id,
6906 identifier,
6907 },
6908 cx,
6909 )
6910 })
6911 .collect::<Vec<_>>(),
6912 )
6913 });
6914
6915 result.unwrap_or_default()
6916 })
6917 .collect::<Vec<_>>();
6918
6919 cx.background_spawn(async move {
6920 let mut responses = Vec::new();
6921 for diagnostics in join_all(pull_diagnostics).await {
6922 responses.extend(diagnostics?);
6923 }
6924 Ok(Some(responses))
6925 })
6926 }
6927 }
6928
6929 pub fn applicable_inlay_chunks(
6930 &mut self,
6931 buffer: &Entity<Buffer>,
6932 ranges: &[Range<text::Anchor>],
6933 cx: &mut Context<Self>,
6934 ) -> Vec<Range<BufferRow>> {
6935 let buffer_snapshot = buffer.read(cx).snapshot();
6936 let ranges = ranges
6937 .iter()
6938 .map(|range| range.to_point(&buffer_snapshot))
6939 .collect::<Vec<_>>();
6940
6941 self.latest_lsp_data(buffer, cx)
6942 .inlay_hints
6943 .applicable_chunks(ranges.as_slice())
6944 .map(|chunk| chunk.row_range())
6945 .collect()
6946 }
6947
6948 pub fn invalidate_inlay_hints<'a>(
6949 &'a mut self,
6950 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6951 ) {
6952 for buffer_id in for_buffers {
6953 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6954 lsp_data.inlay_hints.clear();
6955 }
6956 }
6957 }
6958
6959 pub fn inlay_hints(
6960 &mut self,
6961 invalidate: InvalidationStrategy,
6962 buffer: Entity<Buffer>,
6963 ranges: Vec<Range<text::Anchor>>,
6964 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6965 cx: &mut Context<Self>,
6966 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6967 let next_hint_id = self.next_hint_id.clone();
6968 let lsp_data = self.latest_lsp_data(&buffer, cx);
6969 let query_version = lsp_data.buffer_version.clone();
6970 let mut lsp_refresh_requested = false;
6971 let for_server = if let InvalidationStrategy::RefreshRequested {
6972 server_id,
6973 request_id,
6974 } = invalidate
6975 {
6976 let invalidated = lsp_data
6977 .inlay_hints
6978 .invalidate_for_server_refresh(server_id, request_id);
6979 lsp_refresh_requested = invalidated;
6980 Some(server_id)
6981 } else {
6982 None
6983 };
6984 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6985 let known_chunks = known_chunks
6986 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6987 .map(|(_, known_chunks)| known_chunks)
6988 .unwrap_or_default();
6989
6990 let buffer_snapshot = buffer.read(cx).snapshot();
6991 let ranges = ranges
6992 .iter()
6993 .map(|range| range.to_point(&buffer_snapshot))
6994 .collect::<Vec<_>>();
6995
6996 let mut hint_fetch_tasks = Vec::new();
6997 let mut cached_inlay_hints = None;
6998 let mut ranges_to_query = None;
6999 let applicable_chunks = existing_inlay_hints
7000 .applicable_chunks(ranges.as_slice())
7001 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7002 .collect::<Vec<_>>();
7003 if applicable_chunks.is_empty() {
7004 return HashMap::default();
7005 }
7006
7007 for row_chunk in applicable_chunks {
7008 match (
7009 existing_inlay_hints
7010 .cached_hints(&row_chunk)
7011 .filter(|_| !lsp_refresh_requested)
7012 .cloned(),
7013 existing_inlay_hints
7014 .fetched_hints(&row_chunk)
7015 .as_ref()
7016 .filter(|_| !lsp_refresh_requested)
7017 .cloned(),
7018 ) {
7019 (None, None) => {
7020 let chunk_range = row_chunk.anchor_range();
7021 ranges_to_query
7022 .get_or_insert_with(Vec::new)
7023 .push((row_chunk, chunk_range));
7024 }
7025 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7026 (Some(cached_hints), None) => {
7027 for (server_id, cached_hints) in cached_hints {
7028 if for_server.is_none_or(|for_server| for_server == server_id) {
7029 cached_inlay_hints
7030 .get_or_insert_with(HashMap::default)
7031 .entry(row_chunk.row_range())
7032 .or_insert_with(HashMap::default)
7033 .entry(server_id)
7034 .or_insert_with(Vec::new)
7035 .extend(cached_hints);
7036 }
7037 }
7038 }
7039 (Some(cached_hints), Some(fetched_hints)) => {
7040 hint_fetch_tasks.push((row_chunk, fetched_hints));
7041 for (server_id, cached_hints) in cached_hints {
7042 if for_server.is_none_or(|for_server| for_server == server_id) {
7043 cached_inlay_hints
7044 .get_or_insert_with(HashMap::default)
7045 .entry(row_chunk.row_range())
7046 .or_insert_with(HashMap::default)
7047 .entry(server_id)
7048 .or_insert_with(Vec::new)
7049 .extend(cached_hints);
7050 }
7051 }
7052 }
7053 }
7054 }
7055
7056 if hint_fetch_tasks.is_empty()
7057 && ranges_to_query
7058 .as_ref()
7059 .is_none_or(|ranges| ranges.is_empty())
7060 && let Some(cached_inlay_hints) = cached_inlay_hints
7061 {
7062 cached_inlay_hints
7063 .into_iter()
7064 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7065 .collect()
7066 } else {
7067 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7068 let next_hint_id = next_hint_id.clone();
7069 let buffer = buffer.clone();
7070 let query_version = query_version.clone();
7071 let new_inlay_hints = cx
7072 .spawn(async move |lsp_store, cx| {
7073 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7074 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7075 })?;
7076 new_fetch_task
7077 .await
7078 .and_then(|new_hints_by_server| {
7079 lsp_store.update(cx, |lsp_store, cx| {
7080 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7081 let update_cache = lsp_data.buffer_version == query_version;
7082 if new_hints_by_server.is_empty() {
7083 if update_cache {
7084 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7085 }
7086 HashMap::default()
7087 } else {
7088 new_hints_by_server
7089 .into_iter()
7090 .map(|(server_id, new_hints)| {
7091 let new_hints = new_hints
7092 .into_iter()
7093 .map(|new_hint| {
7094 (
7095 InlayId::Hint(next_hint_id.fetch_add(
7096 1,
7097 atomic::Ordering::AcqRel,
7098 )),
7099 new_hint,
7100 )
7101 })
7102 .collect::<Vec<_>>();
7103 if update_cache {
7104 lsp_data.inlay_hints.insert_new_hints(
7105 chunk,
7106 server_id,
7107 new_hints.clone(),
7108 );
7109 }
7110 (server_id, new_hints)
7111 })
7112 .collect()
7113 }
7114 })
7115 })
7116 .map_err(Arc::new)
7117 })
7118 .shared();
7119
7120 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7121 *fetch_task = Some(new_inlay_hints.clone());
7122 hint_fetch_tasks.push((chunk, new_inlay_hints));
7123 }
7124
7125 cached_inlay_hints
7126 .unwrap_or_default()
7127 .into_iter()
7128 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7129 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7130 (
7131 chunk.row_range(),
7132 cx.spawn(async move |_, _| {
7133 hints_fetch.await.map_err(|e| {
7134 if e.error_code() != ErrorCode::Internal {
7135 anyhow!(e.error_code())
7136 } else {
7137 anyhow!("{e:#}")
7138 }
7139 })
7140 }),
7141 )
7142 }))
7143 .collect()
7144 }
7145 }
7146
7147 fn fetch_inlay_hints(
7148 &mut self,
7149 for_server: Option<LanguageServerId>,
7150 buffer: &Entity<Buffer>,
7151 range: Range<Anchor>,
7152 cx: &mut Context<Self>,
7153 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7154 let request = InlayHints {
7155 range: range.clone(),
7156 };
7157 if let Some((upstream_client, project_id)) = self.upstream_client() {
7158 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7159 return Task::ready(Ok(HashMap::default()));
7160 }
7161 let request_task = upstream_client.request_lsp(
7162 project_id,
7163 for_server.map(|id| id.to_proto()),
7164 LSP_REQUEST_TIMEOUT,
7165 cx.background_executor().clone(),
7166 request.to_proto(project_id, buffer.read(cx)),
7167 );
7168 let buffer = buffer.clone();
7169 cx.spawn(async move |weak_lsp_store, cx| {
7170 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7171 return Ok(HashMap::default());
7172 };
7173 let Some(responses) = request_task.await? else {
7174 return Ok(HashMap::default());
7175 };
7176
7177 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7178 let lsp_store = lsp_store.clone();
7179 let buffer = buffer.clone();
7180 let cx = cx.clone();
7181 let request = request.clone();
7182 async move {
7183 (
7184 LanguageServerId::from_proto(response.server_id),
7185 request
7186 .response_from_proto(response.response, lsp_store, buffer, cx)
7187 .await,
7188 )
7189 }
7190 }))
7191 .await;
7192
7193 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7194 let mut has_errors = false;
7195 let inlay_hints = inlay_hints
7196 .into_iter()
7197 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7198 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7199 Err(e) => {
7200 has_errors = true;
7201 log::error!("{e:#}");
7202 None
7203 }
7204 })
7205 .map(|(server_id, mut new_hints)| {
7206 new_hints.retain(|hint| {
7207 hint.position.is_valid(&buffer_snapshot)
7208 && range.start.is_valid(&buffer_snapshot)
7209 && range.end.is_valid(&buffer_snapshot)
7210 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7211 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7212 });
7213 (server_id, new_hints)
7214 })
7215 .collect::<HashMap<_, _>>();
7216 anyhow::ensure!(
7217 !has_errors || !inlay_hints.is_empty(),
7218 "Failed to fetch inlay hints"
7219 );
7220 Ok(inlay_hints)
7221 })
7222 } else {
7223 let inlay_hints_task = match for_server {
7224 Some(server_id) => {
7225 let server_task = self.request_lsp(
7226 buffer.clone(),
7227 LanguageServerToQuery::Other(server_id),
7228 request,
7229 cx,
7230 );
7231 cx.background_spawn(async move {
7232 let mut responses = Vec::new();
7233 match server_task.await {
7234 Ok(response) => responses.push((server_id, response)),
7235 // rust-analyzer likes to error with this when its still loading up
7236 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7237 Err(e) => log::error!(
7238 "Error handling response for inlay hints request: {e:#}"
7239 ),
7240 }
7241 responses
7242 })
7243 }
7244 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7245 };
7246 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7247 cx.background_spawn(async move {
7248 Ok(inlay_hints_task
7249 .await
7250 .into_iter()
7251 .map(|(server_id, mut new_hints)| {
7252 new_hints.retain(|hint| {
7253 hint.position.is_valid(&buffer_snapshot)
7254 && range.start.is_valid(&buffer_snapshot)
7255 && range.end.is_valid(&buffer_snapshot)
7256 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7257 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7258 });
7259 (server_id, new_hints)
7260 })
7261 .collect())
7262 })
7263 }
7264 }
7265
7266 pub fn pull_diagnostics_for_buffer(
7267 &mut self,
7268 buffer: Entity<Buffer>,
7269 cx: &mut Context<Self>,
7270 ) -> Task<anyhow::Result<()>> {
7271 let diagnostics = self.pull_diagnostics(buffer, cx);
7272 cx.spawn(async move |lsp_store, cx| {
7273 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7274 return Ok(());
7275 };
7276 lsp_store.update(cx, |lsp_store, cx| {
7277 if lsp_store.as_local().is_none() {
7278 return;
7279 }
7280
7281 let mut unchanged_buffers = HashMap::default();
7282 let server_diagnostics_updates = diagnostics
7283 .into_iter()
7284 .filter_map(|diagnostics_set| match diagnostics_set {
7285 LspPullDiagnostics::Response {
7286 server_id,
7287 uri,
7288 diagnostics,
7289 registration_id,
7290 } => Some((server_id, uri, diagnostics, registration_id)),
7291 LspPullDiagnostics::Default => None,
7292 })
7293 .fold(
7294 HashMap::default(),
7295 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7296 let (result_id, diagnostics) = match diagnostics {
7297 PulledDiagnostics::Unchanged { result_id } => {
7298 unchanged_buffers
7299 .entry(new_registration_id.clone())
7300 .or_insert_with(HashSet::default)
7301 .insert(uri.clone());
7302 (Some(result_id), Vec::new())
7303 }
7304 PulledDiagnostics::Changed {
7305 result_id,
7306 diagnostics,
7307 } => (result_id, diagnostics),
7308 };
7309 let disk_based_sources = Cow::Owned(
7310 lsp_store
7311 .language_server_adapter_for_id(server_id)
7312 .as_ref()
7313 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7314 .unwrap_or(&[])
7315 .to_vec(),
7316 );
7317 acc.entry(server_id)
7318 .or_insert_with(HashMap::default)
7319 .entry(new_registration_id.clone())
7320 .or_insert_with(Vec::new)
7321 .push(DocumentDiagnosticsUpdate {
7322 server_id,
7323 diagnostics: lsp::PublishDiagnosticsParams {
7324 uri,
7325 diagnostics,
7326 version: None,
7327 },
7328 result_id,
7329 disk_based_sources,
7330 registration_id: new_registration_id,
7331 });
7332 acc
7333 },
7334 );
7335
7336 for diagnostic_updates in server_diagnostics_updates.into_values() {
7337 for (registration_id, diagnostic_updates) in diagnostic_updates {
7338 lsp_store
7339 .merge_lsp_diagnostics(
7340 DiagnosticSourceKind::Pulled,
7341 diagnostic_updates,
7342 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7343 DiagnosticSourceKind::Pulled => {
7344 old_diagnostic.registration_id != registration_id
7345 || unchanged_buffers
7346 .get(&old_diagnostic.registration_id)
7347 .is_some_and(|unchanged_buffers| {
7348 unchanged_buffers.contains(&document_uri)
7349 })
7350 }
7351 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7352 true
7353 }
7354 },
7355 cx,
7356 )
7357 .log_err();
7358 }
7359 }
7360 })
7361 })
7362 }
7363
7364 pub fn document_colors(
7365 &mut self,
7366 known_cache_version: Option<usize>,
7367 buffer: Entity<Buffer>,
7368 cx: &mut Context<Self>,
7369 ) -> Option<DocumentColorTask> {
7370 let version_queried_for = buffer.read(cx).version();
7371 let buffer_id = buffer.read(cx).remote_id();
7372
7373 let current_language_servers = self.as_local().map(|local| {
7374 local
7375 .buffers_opened_in_servers
7376 .get(&buffer_id)
7377 .cloned()
7378 .unwrap_or_default()
7379 });
7380
7381 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7382 if let Some(cached_colors) = &lsp_data.document_colors {
7383 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7384 let has_different_servers =
7385 current_language_servers.is_some_and(|current_language_servers| {
7386 current_language_servers
7387 != cached_colors.colors.keys().copied().collect()
7388 });
7389 if !has_different_servers {
7390 let cache_version = cached_colors.cache_version;
7391 if Some(cache_version) == known_cache_version {
7392 return None;
7393 } else {
7394 return Some(
7395 Task::ready(Ok(DocumentColors {
7396 colors: cached_colors
7397 .colors
7398 .values()
7399 .flatten()
7400 .cloned()
7401 .collect(),
7402 cache_version: Some(cache_version),
7403 }))
7404 .shared(),
7405 );
7406 }
7407 }
7408 }
7409 }
7410 }
7411
7412 let color_lsp_data = self
7413 .latest_lsp_data(&buffer, cx)
7414 .document_colors
7415 .get_or_insert_default();
7416 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7417 && !version_queried_for.changed_since(updating_for)
7418 {
7419 return Some(running_update.clone());
7420 }
7421 let buffer_version_queried_for = version_queried_for.clone();
7422 let new_task = cx
7423 .spawn(async move |lsp_store, cx| {
7424 cx.background_executor()
7425 .timer(Duration::from_millis(30))
7426 .await;
7427 let fetched_colors = lsp_store
7428 .update(cx, |lsp_store, cx| {
7429 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7430 })?
7431 .await
7432 .context("fetching document colors")
7433 .map_err(Arc::new);
7434 let fetched_colors = match fetched_colors {
7435 Ok(fetched_colors) => {
7436 if Some(true)
7437 == buffer
7438 .update(cx, |buffer, _| {
7439 buffer.version() != buffer_version_queried_for
7440 })
7441 .ok()
7442 {
7443 return Ok(DocumentColors::default());
7444 }
7445 fetched_colors
7446 }
7447 Err(e) => {
7448 lsp_store
7449 .update(cx, |lsp_store, _| {
7450 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7451 if let Some(document_colors) = &mut lsp_data.document_colors {
7452 document_colors.colors_update = None;
7453 }
7454 }
7455 })
7456 .ok();
7457 return Err(e);
7458 }
7459 };
7460
7461 lsp_store
7462 .update(cx, |lsp_store, cx| {
7463 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7464 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7465
7466 if let Some(fetched_colors) = fetched_colors {
7467 if lsp_data.buffer_version == buffer_version_queried_for {
7468 lsp_colors.colors.extend(fetched_colors);
7469 lsp_colors.cache_version += 1;
7470 } else if !lsp_data
7471 .buffer_version
7472 .changed_since(&buffer_version_queried_for)
7473 {
7474 lsp_data.buffer_version = buffer_version_queried_for;
7475 lsp_colors.colors = fetched_colors;
7476 lsp_colors.cache_version += 1;
7477 }
7478 }
7479 lsp_colors.colors_update = None;
7480 let colors = lsp_colors
7481 .colors
7482 .values()
7483 .flatten()
7484 .cloned()
7485 .collect::<HashSet<_>>();
7486 DocumentColors {
7487 colors,
7488 cache_version: Some(lsp_colors.cache_version),
7489 }
7490 })
7491 .map_err(Arc::new)
7492 })
7493 .shared();
7494 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7495 Some(new_task)
7496 }
7497
7498 fn fetch_document_colors_for_buffer(
7499 &mut self,
7500 buffer: &Entity<Buffer>,
7501 cx: &mut Context<Self>,
7502 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7503 if let Some((client, project_id)) = self.upstream_client() {
7504 let request = GetDocumentColor {};
7505 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7506 return Task::ready(Ok(None));
7507 }
7508
7509 let request_task = client.request_lsp(
7510 project_id,
7511 None,
7512 LSP_REQUEST_TIMEOUT,
7513 cx.background_executor().clone(),
7514 request.to_proto(project_id, buffer.read(cx)),
7515 );
7516 let buffer = buffer.clone();
7517 cx.spawn(async move |lsp_store, cx| {
7518 let Some(lsp_store) = lsp_store.upgrade() else {
7519 return Ok(None);
7520 };
7521 let colors = join_all(
7522 request_task
7523 .await
7524 .log_err()
7525 .flatten()
7526 .map(|response| response.payload)
7527 .unwrap_or_default()
7528 .into_iter()
7529 .map(|color_response| {
7530 let response = request.response_from_proto(
7531 color_response.response,
7532 lsp_store.clone(),
7533 buffer.clone(),
7534 cx.clone(),
7535 );
7536 async move {
7537 (
7538 LanguageServerId::from_proto(color_response.server_id),
7539 response.await.log_err().unwrap_or_default(),
7540 )
7541 }
7542 }),
7543 )
7544 .await
7545 .into_iter()
7546 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7547 acc.entry(server_id)
7548 .or_insert_with(HashSet::default)
7549 .extend(colors);
7550 acc
7551 });
7552 Ok(Some(colors))
7553 })
7554 } else {
7555 let document_colors_task =
7556 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7557 cx.background_spawn(async move {
7558 Ok(Some(
7559 document_colors_task
7560 .await
7561 .into_iter()
7562 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7563 acc.entry(server_id)
7564 .or_insert_with(HashSet::default)
7565 .extend(colors);
7566 acc
7567 })
7568 .into_iter()
7569 .collect(),
7570 ))
7571 })
7572 }
7573 }
7574
7575 pub fn signature_help<T: ToPointUtf16>(
7576 &mut self,
7577 buffer: &Entity<Buffer>,
7578 position: T,
7579 cx: &mut Context<Self>,
7580 ) -> Task<Option<Vec<SignatureHelp>>> {
7581 let position = position.to_point_utf16(buffer.read(cx));
7582
7583 if let Some((client, upstream_project_id)) = self.upstream_client() {
7584 let request = GetSignatureHelp { position };
7585 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7586 return Task::ready(None);
7587 }
7588 let request_task = client.request_lsp(
7589 upstream_project_id,
7590 None,
7591 LSP_REQUEST_TIMEOUT,
7592 cx.background_executor().clone(),
7593 request.to_proto(upstream_project_id, buffer.read(cx)),
7594 );
7595 let buffer = buffer.clone();
7596 cx.spawn(async move |weak_lsp_store, cx| {
7597 let lsp_store = weak_lsp_store.upgrade()?;
7598 let signatures = join_all(
7599 request_task
7600 .await
7601 .log_err()
7602 .flatten()
7603 .map(|response| response.payload)
7604 .unwrap_or_default()
7605 .into_iter()
7606 .map(|response| {
7607 let response = GetSignatureHelp { position }.response_from_proto(
7608 response.response,
7609 lsp_store.clone(),
7610 buffer.clone(),
7611 cx.clone(),
7612 );
7613 async move { response.await.log_err().flatten() }
7614 }),
7615 )
7616 .await
7617 .into_iter()
7618 .flatten()
7619 .collect();
7620 Some(signatures)
7621 })
7622 } else {
7623 let all_actions_task = self.request_multiple_lsp_locally(
7624 buffer,
7625 Some(position),
7626 GetSignatureHelp { position },
7627 cx,
7628 );
7629 cx.background_spawn(async move {
7630 Some(
7631 all_actions_task
7632 .await
7633 .into_iter()
7634 .flat_map(|(_, actions)| actions)
7635 .collect::<Vec<_>>(),
7636 )
7637 })
7638 }
7639 }
7640
7641 pub fn hover(
7642 &mut self,
7643 buffer: &Entity<Buffer>,
7644 position: PointUtf16,
7645 cx: &mut Context<Self>,
7646 ) -> Task<Option<Vec<Hover>>> {
7647 if let Some((client, upstream_project_id)) = self.upstream_client() {
7648 let request = GetHover { position };
7649 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7650 return Task::ready(None);
7651 }
7652 let request_task = client.request_lsp(
7653 upstream_project_id,
7654 None,
7655 LSP_REQUEST_TIMEOUT,
7656 cx.background_executor().clone(),
7657 request.to_proto(upstream_project_id, buffer.read(cx)),
7658 );
7659 let buffer = buffer.clone();
7660 cx.spawn(async move |weak_lsp_store, cx| {
7661 let lsp_store = weak_lsp_store.upgrade()?;
7662 let hovers = join_all(
7663 request_task
7664 .await
7665 .log_err()
7666 .flatten()
7667 .map(|response| response.payload)
7668 .unwrap_or_default()
7669 .into_iter()
7670 .map(|response| {
7671 let response = GetHover { position }.response_from_proto(
7672 response.response,
7673 lsp_store.clone(),
7674 buffer.clone(),
7675 cx.clone(),
7676 );
7677 async move {
7678 response
7679 .await
7680 .log_err()
7681 .flatten()
7682 .and_then(remove_empty_hover_blocks)
7683 }
7684 }),
7685 )
7686 .await
7687 .into_iter()
7688 .flatten()
7689 .collect();
7690 Some(hovers)
7691 })
7692 } else {
7693 let all_actions_task = self.request_multiple_lsp_locally(
7694 buffer,
7695 Some(position),
7696 GetHover { position },
7697 cx,
7698 );
7699 cx.background_spawn(async move {
7700 Some(
7701 all_actions_task
7702 .await
7703 .into_iter()
7704 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7705 .collect::<Vec<Hover>>(),
7706 )
7707 })
7708 }
7709 }
7710
7711 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7712 let language_registry = self.languages.clone();
7713
7714 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7715 let request = upstream_client.request(proto::GetProjectSymbols {
7716 project_id: *project_id,
7717 query: query.to_string(),
7718 });
7719 cx.foreground_executor().spawn(async move {
7720 let response = request.await?;
7721 let mut symbols = Vec::new();
7722 let core_symbols = response
7723 .symbols
7724 .into_iter()
7725 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7726 .collect::<Vec<_>>();
7727 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7728 .await;
7729 Ok(symbols)
7730 })
7731 } else if let Some(local) = self.as_local() {
7732 struct WorkspaceSymbolsResult {
7733 server_id: LanguageServerId,
7734 lsp_adapter: Arc<CachedLspAdapter>,
7735 worktree: WeakEntity<Worktree>,
7736 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7737 }
7738
7739 let mut requests = Vec::new();
7740 let mut requested_servers = BTreeSet::new();
7741 for (seed, state) in local.language_server_ids.iter() {
7742 let Some(worktree_handle) = self
7743 .worktree_store
7744 .read(cx)
7745 .worktree_for_id(seed.worktree_id, cx)
7746 else {
7747 continue;
7748 };
7749 let worktree = worktree_handle.read(cx);
7750 if !worktree.is_visible() {
7751 continue;
7752 }
7753
7754 if !requested_servers.insert(state.id) {
7755 continue;
7756 }
7757
7758 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7759 Some(LanguageServerState::Running {
7760 adapter, server, ..
7761 }) => (adapter.clone(), server),
7762
7763 _ => continue,
7764 };
7765 let supports_workspace_symbol_request =
7766 match server.capabilities().workspace_symbol_provider {
7767 Some(OneOf::Left(supported)) => supported,
7768 Some(OneOf::Right(_)) => true,
7769 None => false,
7770 };
7771 if !supports_workspace_symbol_request {
7772 continue;
7773 }
7774 let worktree_handle = worktree_handle.clone();
7775 let server_id = server.server_id();
7776 requests.push(
7777 server
7778 .request::<lsp::request::WorkspaceSymbolRequest>(
7779 lsp::WorkspaceSymbolParams {
7780 query: query.to_string(),
7781 ..Default::default()
7782 },
7783 )
7784 .map(move |response| {
7785 let lsp_symbols = response.into_response()
7786 .context("workspace symbols request")
7787 .log_err()
7788 .flatten()
7789 .map(|symbol_response| match symbol_response {
7790 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7791 flat_responses.into_iter().map(|lsp_symbol| {
7792 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7793 }).collect::<Vec<_>>()
7794 }
7795 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7796 nested_responses.into_iter().filter_map(|lsp_symbol| {
7797 let location = match lsp_symbol.location {
7798 OneOf::Left(location) => location,
7799 OneOf::Right(_) => {
7800 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7801 return None
7802 }
7803 };
7804 Some((lsp_symbol.name, lsp_symbol.kind, location))
7805 }).collect::<Vec<_>>()
7806 }
7807 }).unwrap_or_default();
7808
7809 WorkspaceSymbolsResult {
7810 server_id,
7811 lsp_adapter,
7812 worktree: worktree_handle.downgrade(),
7813 lsp_symbols,
7814 }
7815 }),
7816 );
7817 }
7818
7819 cx.spawn(async move |this, cx| {
7820 let responses = futures::future::join_all(requests).await;
7821 let this = match this.upgrade() {
7822 Some(this) => this,
7823 None => return Ok(Vec::new()),
7824 };
7825
7826 let mut symbols = Vec::new();
7827 for result in responses {
7828 let core_symbols = this.update(cx, |this, cx| {
7829 result
7830 .lsp_symbols
7831 .into_iter()
7832 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7833 let abs_path = symbol_location.uri.to_file_path().ok()?;
7834 let source_worktree = result.worktree.upgrade()?;
7835 let source_worktree_id = source_worktree.read(cx).id();
7836
7837 let path = if let Some((tree, rel_path)) =
7838 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7839 {
7840 let worktree_id = tree.read(cx).id();
7841 SymbolLocation::InProject(ProjectPath {
7842 worktree_id,
7843 path: rel_path,
7844 })
7845 } else {
7846 SymbolLocation::OutsideProject {
7847 signature: this.symbol_signature(&abs_path),
7848 abs_path: abs_path.into(),
7849 }
7850 };
7851
7852 Some(CoreSymbol {
7853 source_language_server_id: result.server_id,
7854 language_server_name: result.lsp_adapter.name.clone(),
7855 source_worktree_id,
7856 path,
7857 kind: symbol_kind,
7858 name: symbol_name,
7859 range: range_from_lsp(symbol_location.range),
7860 })
7861 })
7862 .collect()
7863 })?;
7864
7865 populate_labels_for_symbols(
7866 core_symbols,
7867 &language_registry,
7868 Some(result.lsp_adapter),
7869 &mut symbols,
7870 )
7871 .await;
7872 }
7873
7874 Ok(symbols)
7875 })
7876 } else {
7877 Task::ready(Err(anyhow!("No upstream client or local language server")))
7878 }
7879 }
7880
7881 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7882 let mut summary = DiagnosticSummary::default();
7883 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7884 summary.error_count += path_summary.error_count;
7885 summary.warning_count += path_summary.warning_count;
7886 }
7887 summary
7888 }
7889
7890 /// Returns the diagnostic summary for a specific project path.
7891 pub fn diagnostic_summary_for_path(
7892 &self,
7893 project_path: &ProjectPath,
7894 _: &App,
7895 ) -> DiagnosticSummary {
7896 if let Some(summaries) = self
7897 .diagnostic_summaries
7898 .get(&project_path.worktree_id)
7899 .and_then(|map| map.get(&project_path.path))
7900 {
7901 let (error_count, warning_count) = summaries.iter().fold(
7902 (0, 0),
7903 |(error_count, warning_count), (_language_server_id, summary)| {
7904 (
7905 error_count + summary.error_count,
7906 warning_count + summary.warning_count,
7907 )
7908 },
7909 );
7910
7911 DiagnosticSummary {
7912 error_count,
7913 warning_count,
7914 }
7915 } else {
7916 DiagnosticSummary::default()
7917 }
7918 }
7919
7920 pub fn diagnostic_summaries<'a>(
7921 &'a self,
7922 include_ignored: bool,
7923 cx: &'a App,
7924 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7925 self.worktree_store
7926 .read(cx)
7927 .visible_worktrees(cx)
7928 .filter_map(|worktree| {
7929 let worktree = worktree.read(cx);
7930 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7931 })
7932 .flat_map(move |(worktree, summaries)| {
7933 let worktree_id = worktree.id();
7934 summaries
7935 .iter()
7936 .filter(move |(path, _)| {
7937 include_ignored
7938 || worktree
7939 .entry_for_path(path.as_ref())
7940 .is_some_and(|entry| !entry.is_ignored)
7941 })
7942 .flat_map(move |(path, summaries)| {
7943 summaries.iter().map(move |(server_id, summary)| {
7944 (
7945 ProjectPath {
7946 worktree_id,
7947 path: path.clone(),
7948 },
7949 *server_id,
7950 *summary,
7951 )
7952 })
7953 })
7954 })
7955 }
7956
7957 pub fn on_buffer_edited(
7958 &mut self,
7959 buffer: Entity<Buffer>,
7960 cx: &mut Context<Self>,
7961 ) -> Option<()> {
7962 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7963 Some(
7964 self.as_local()?
7965 .language_servers_for_buffer(buffer, cx)
7966 .map(|i| i.1.clone())
7967 .collect(),
7968 )
7969 })?;
7970
7971 let buffer = buffer.read(cx);
7972 let file = File::from_dyn(buffer.file())?;
7973 let abs_path = file.as_local()?.abs_path(cx);
7974 let uri = lsp::Uri::from_file_path(&abs_path)
7975 .ok()
7976 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7977 .log_err()?;
7978 let next_snapshot = buffer.text_snapshot();
7979 for language_server in language_servers {
7980 let language_server = language_server.clone();
7981
7982 let buffer_snapshots = self
7983 .as_local_mut()?
7984 .buffer_snapshots
7985 .get_mut(&buffer.remote_id())
7986 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7987 let previous_snapshot = buffer_snapshots.last()?;
7988
7989 let build_incremental_change = || {
7990 buffer
7991 .edits_since::<Dimensions<PointUtf16, usize>>(
7992 previous_snapshot.snapshot.version(),
7993 )
7994 .map(|edit| {
7995 let edit_start = edit.new.start.0;
7996 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7997 let new_text = next_snapshot
7998 .text_for_range(edit.new.start.1..edit.new.end.1)
7999 .collect();
8000 lsp::TextDocumentContentChangeEvent {
8001 range: Some(lsp::Range::new(
8002 point_to_lsp(edit_start),
8003 point_to_lsp(edit_end),
8004 )),
8005 range_length: None,
8006 text: new_text,
8007 }
8008 })
8009 .collect()
8010 };
8011
8012 let document_sync_kind = language_server
8013 .capabilities()
8014 .text_document_sync
8015 .as_ref()
8016 .and_then(|sync| match sync {
8017 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8018 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8019 });
8020
8021 let content_changes: Vec<_> = match document_sync_kind {
8022 Some(lsp::TextDocumentSyncKind::FULL) => {
8023 vec![lsp::TextDocumentContentChangeEvent {
8024 range: None,
8025 range_length: None,
8026 text: next_snapshot.text(),
8027 }]
8028 }
8029 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8030 _ => {
8031 #[cfg(any(test, feature = "test-support"))]
8032 {
8033 build_incremental_change()
8034 }
8035
8036 #[cfg(not(any(test, feature = "test-support")))]
8037 {
8038 continue;
8039 }
8040 }
8041 };
8042
8043 let next_version = previous_snapshot.version + 1;
8044 buffer_snapshots.push(LspBufferSnapshot {
8045 version: next_version,
8046 snapshot: next_snapshot.clone(),
8047 });
8048
8049 language_server
8050 .notify::<lsp::notification::DidChangeTextDocument>(
8051 lsp::DidChangeTextDocumentParams {
8052 text_document: lsp::VersionedTextDocumentIdentifier::new(
8053 uri.clone(),
8054 next_version,
8055 ),
8056 content_changes,
8057 },
8058 )
8059 .ok();
8060 self.pull_workspace_diagnostics(language_server.server_id());
8061 }
8062
8063 None
8064 }
8065
8066 pub fn on_buffer_saved(
8067 &mut self,
8068 buffer: Entity<Buffer>,
8069 cx: &mut Context<Self>,
8070 ) -> Option<()> {
8071 let file = File::from_dyn(buffer.read(cx).file())?;
8072 let worktree_id = file.worktree_id(cx);
8073 let abs_path = file.as_local()?.abs_path(cx);
8074 let text_document = lsp::TextDocumentIdentifier {
8075 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8076 };
8077 let local = self.as_local()?;
8078
8079 for server in local.language_servers_for_worktree(worktree_id) {
8080 if let Some(include_text) = include_text(server.as_ref()) {
8081 let text = if include_text {
8082 Some(buffer.read(cx).text())
8083 } else {
8084 None
8085 };
8086 server
8087 .notify::<lsp::notification::DidSaveTextDocument>(
8088 lsp::DidSaveTextDocumentParams {
8089 text_document: text_document.clone(),
8090 text,
8091 },
8092 )
8093 .ok();
8094 }
8095 }
8096
8097 let language_servers = buffer.update(cx, |buffer, cx| {
8098 local.language_server_ids_for_buffer(buffer, cx)
8099 });
8100 for language_server_id in language_servers {
8101 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8102 }
8103
8104 None
8105 }
8106
8107 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8108 maybe!(async move {
8109 let mut refreshed_servers = HashSet::default();
8110 let servers = lsp_store
8111 .update(cx, |lsp_store, cx| {
8112 let local = lsp_store.as_local()?;
8113
8114 let servers = local
8115 .language_server_ids
8116 .iter()
8117 .filter_map(|(seed, state)| {
8118 let worktree = lsp_store
8119 .worktree_store
8120 .read(cx)
8121 .worktree_for_id(seed.worktree_id, cx);
8122 let delegate: Arc<dyn LspAdapterDelegate> =
8123 worktree.map(|worktree| {
8124 LocalLspAdapterDelegate::new(
8125 local.languages.clone(),
8126 &local.environment,
8127 cx.weak_entity(),
8128 &worktree,
8129 local.http_client.clone(),
8130 local.fs.clone(),
8131 cx,
8132 )
8133 })?;
8134 let server_id = state.id;
8135
8136 let states = local.language_servers.get(&server_id)?;
8137
8138 match states {
8139 LanguageServerState::Starting { .. } => None,
8140 LanguageServerState::Running {
8141 adapter, server, ..
8142 } => {
8143 let adapter = adapter.clone();
8144 let server = server.clone();
8145 refreshed_servers.insert(server.name());
8146 let toolchain = seed.toolchain.clone();
8147 Some(cx.spawn(async move |_, cx| {
8148 let settings =
8149 LocalLspStore::workspace_configuration_for_adapter(
8150 adapter.adapter.clone(),
8151 &delegate,
8152 toolchain,
8153 None,
8154 cx,
8155 )
8156 .await
8157 .ok()?;
8158 server
8159 .notify::<lsp::notification::DidChangeConfiguration>(
8160 lsp::DidChangeConfigurationParams { settings },
8161 )
8162 .ok()?;
8163 Some(())
8164 }))
8165 }
8166 }
8167 })
8168 .collect::<Vec<_>>();
8169
8170 Some(servers)
8171 })
8172 .ok()
8173 .flatten()?;
8174
8175 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8176 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8177 // to stop and unregister its language server wrapper.
8178 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8179 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8180 let _: Vec<Option<()>> = join_all(servers).await;
8181
8182 Some(())
8183 })
8184 .await;
8185 }
8186
8187 fn maintain_workspace_config(
8188 external_refresh_requests: watch::Receiver<()>,
8189 cx: &mut Context<Self>,
8190 ) -> Task<Result<()>> {
8191 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8192 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8193
8194 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8195 *settings_changed_tx.borrow_mut() = ();
8196 });
8197
8198 let mut joint_future =
8199 futures::stream::select(settings_changed_rx, external_refresh_requests);
8200 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8201 // - 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).
8202 // - 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.
8203 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8204 // - 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,
8205 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8206 cx.spawn(async move |this, cx| {
8207 while let Some(()) = joint_future.next().await {
8208 this.update(cx, |this, cx| {
8209 this.refresh_server_tree(cx);
8210 })
8211 .ok();
8212
8213 Self::refresh_workspace_configurations(&this, cx).await;
8214 }
8215
8216 drop(settings_observation);
8217 anyhow::Ok(())
8218 })
8219 }
8220
8221 pub fn running_language_servers_for_local_buffer<'a>(
8222 &'a self,
8223 buffer: &Buffer,
8224 cx: &mut App,
8225 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8226 let local = self.as_local();
8227 let language_server_ids = local
8228 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8229 .unwrap_or_default();
8230
8231 language_server_ids
8232 .into_iter()
8233 .filter_map(
8234 move |server_id| match local?.language_servers.get(&server_id)? {
8235 LanguageServerState::Running {
8236 adapter, server, ..
8237 } => Some((adapter, server)),
8238 _ => None,
8239 },
8240 )
8241 }
8242
8243 pub fn language_servers_for_local_buffer(
8244 &self,
8245 buffer: &Buffer,
8246 cx: &mut App,
8247 ) -> Vec<LanguageServerId> {
8248 let local = self.as_local();
8249 local
8250 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8251 .unwrap_or_default()
8252 }
8253
8254 pub fn language_server_for_local_buffer<'a>(
8255 &'a self,
8256 buffer: &'a Buffer,
8257 server_id: LanguageServerId,
8258 cx: &'a mut App,
8259 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8260 self.as_local()?
8261 .language_servers_for_buffer(buffer, cx)
8262 .find(|(_, s)| s.server_id() == server_id)
8263 }
8264
8265 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8266 self.diagnostic_summaries.remove(&id_to_remove);
8267 if let Some(local) = self.as_local_mut() {
8268 let to_remove = local.remove_worktree(id_to_remove, cx);
8269 for server in to_remove {
8270 self.language_server_statuses.remove(&server);
8271 }
8272 }
8273 }
8274
8275 pub fn shared(
8276 &mut self,
8277 project_id: u64,
8278 downstream_client: AnyProtoClient,
8279 _: &mut Context<Self>,
8280 ) {
8281 self.downstream_client = Some((downstream_client.clone(), project_id));
8282
8283 for (server_id, status) in &self.language_server_statuses {
8284 if let Some(server) = self.language_server_for_id(*server_id) {
8285 downstream_client
8286 .send(proto::StartLanguageServer {
8287 project_id,
8288 server: Some(proto::LanguageServer {
8289 id: server_id.to_proto(),
8290 name: status.name.to_string(),
8291 worktree_id: status.worktree.map(|id| id.to_proto()),
8292 }),
8293 capabilities: serde_json::to_string(&server.capabilities())
8294 .expect("serializing server LSP capabilities"),
8295 })
8296 .log_err();
8297 }
8298 }
8299 }
8300
8301 pub fn disconnected_from_host(&mut self) {
8302 self.downstream_client.take();
8303 }
8304
8305 pub fn disconnected_from_ssh_remote(&mut self) {
8306 if let LspStoreMode::Remote(RemoteLspStore {
8307 upstream_client, ..
8308 }) = &mut self.mode
8309 {
8310 upstream_client.take();
8311 }
8312 }
8313
8314 pub(crate) fn set_language_server_statuses_from_proto(
8315 &mut self,
8316 project: WeakEntity<Project>,
8317 language_servers: Vec<proto::LanguageServer>,
8318 server_capabilities: Vec<String>,
8319 cx: &mut Context<Self>,
8320 ) {
8321 let lsp_logs = cx
8322 .try_global::<GlobalLogStore>()
8323 .map(|lsp_store| lsp_store.0.clone());
8324
8325 self.language_server_statuses = language_servers
8326 .into_iter()
8327 .zip(server_capabilities)
8328 .map(|(server, server_capabilities)| {
8329 let server_id = LanguageServerId(server.id as usize);
8330 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8331 self.lsp_server_capabilities
8332 .insert(server_id, server_capabilities);
8333 }
8334
8335 let name = LanguageServerName::from_proto(server.name);
8336 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8337
8338 if let Some(lsp_logs) = &lsp_logs {
8339 lsp_logs.update(cx, |lsp_logs, cx| {
8340 lsp_logs.add_language_server(
8341 // Only remote clients get their language servers set from proto
8342 LanguageServerKind::Remote {
8343 project: project.clone(),
8344 },
8345 server_id,
8346 Some(name.clone()),
8347 worktree,
8348 None,
8349 cx,
8350 );
8351 });
8352 }
8353
8354 (
8355 server_id,
8356 LanguageServerStatus {
8357 name,
8358 server_version: None,
8359 pending_work: Default::default(),
8360 has_pending_diagnostic_updates: false,
8361 progress_tokens: Default::default(),
8362 worktree,
8363 binary: None,
8364 configuration: None,
8365 workspace_folders: BTreeSet::new(),
8366 },
8367 )
8368 })
8369 .collect();
8370 }
8371
8372 #[cfg(test)]
8373 pub fn update_diagnostic_entries(
8374 &mut self,
8375 server_id: LanguageServerId,
8376 abs_path: PathBuf,
8377 result_id: Option<SharedString>,
8378 version: Option<i32>,
8379 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8380 cx: &mut Context<Self>,
8381 ) -> anyhow::Result<()> {
8382 self.merge_diagnostic_entries(
8383 vec![DocumentDiagnosticsUpdate {
8384 diagnostics: DocumentDiagnostics {
8385 diagnostics,
8386 document_abs_path: abs_path,
8387 version,
8388 },
8389 result_id,
8390 server_id,
8391 disk_based_sources: Cow::Borrowed(&[]),
8392 registration_id: None,
8393 }],
8394 |_, _, _| false,
8395 cx,
8396 )?;
8397 Ok(())
8398 }
8399
8400 pub fn merge_diagnostic_entries<'a>(
8401 &mut self,
8402 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8403 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8404 cx: &mut Context<Self>,
8405 ) -> anyhow::Result<()> {
8406 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8407 let mut updated_diagnostics_paths = HashMap::default();
8408 for mut update in diagnostic_updates {
8409 let abs_path = &update.diagnostics.document_abs_path;
8410 let server_id = update.server_id;
8411 let Some((worktree, relative_path)) =
8412 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8413 else {
8414 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8415 return Ok(());
8416 };
8417
8418 let worktree_id = worktree.read(cx).id();
8419 let project_path = ProjectPath {
8420 worktree_id,
8421 path: relative_path,
8422 };
8423
8424 let document_uri = lsp::Uri::from_file_path(abs_path)
8425 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8426 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8427 let snapshot = buffer_handle.read(cx).snapshot();
8428 let buffer = buffer_handle.read(cx);
8429 let reused_diagnostics = buffer
8430 .buffer_diagnostics(Some(server_id))
8431 .iter()
8432 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8433 .map(|v| {
8434 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8435 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8436 DiagnosticEntry {
8437 range: start..end,
8438 diagnostic: v.diagnostic.clone(),
8439 }
8440 })
8441 .collect::<Vec<_>>();
8442
8443 self.as_local_mut()
8444 .context("cannot merge diagnostics on a remote LspStore")?
8445 .update_buffer_diagnostics(
8446 &buffer_handle,
8447 server_id,
8448 Some(update.registration_id),
8449 update.result_id,
8450 update.diagnostics.version,
8451 update.diagnostics.diagnostics.clone(),
8452 reused_diagnostics.clone(),
8453 cx,
8454 )?;
8455
8456 update.diagnostics.diagnostics.extend(reused_diagnostics);
8457 } else if let Some(local) = self.as_local() {
8458 let reused_diagnostics = local
8459 .diagnostics
8460 .get(&worktree_id)
8461 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8462 .and_then(|diagnostics_by_server_id| {
8463 diagnostics_by_server_id
8464 .binary_search_by_key(&server_id, |e| e.0)
8465 .ok()
8466 .map(|ix| &diagnostics_by_server_id[ix].1)
8467 })
8468 .into_iter()
8469 .flatten()
8470 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8471
8472 update
8473 .diagnostics
8474 .diagnostics
8475 .extend(reused_diagnostics.cloned());
8476 }
8477
8478 let updated = worktree.update(cx, |worktree, cx| {
8479 self.update_worktree_diagnostics(
8480 worktree.id(),
8481 server_id,
8482 project_path.path.clone(),
8483 update.diagnostics.diagnostics,
8484 cx,
8485 )
8486 })?;
8487 match updated {
8488 ControlFlow::Continue(new_summary) => {
8489 if let Some((project_id, new_summary)) = new_summary {
8490 match &mut diagnostics_summary {
8491 Some(diagnostics_summary) => {
8492 diagnostics_summary
8493 .more_summaries
8494 .push(proto::DiagnosticSummary {
8495 path: project_path.path.as_ref().to_proto(),
8496 language_server_id: server_id.0 as u64,
8497 error_count: new_summary.error_count,
8498 warning_count: new_summary.warning_count,
8499 })
8500 }
8501 None => {
8502 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8503 project_id,
8504 worktree_id: worktree_id.to_proto(),
8505 summary: Some(proto::DiagnosticSummary {
8506 path: project_path.path.as_ref().to_proto(),
8507 language_server_id: server_id.0 as u64,
8508 error_count: new_summary.error_count,
8509 warning_count: new_summary.warning_count,
8510 }),
8511 more_summaries: Vec::new(),
8512 })
8513 }
8514 }
8515 }
8516 updated_diagnostics_paths
8517 .entry(server_id)
8518 .or_insert_with(Vec::new)
8519 .push(project_path);
8520 }
8521 ControlFlow::Break(()) => {}
8522 }
8523 }
8524
8525 if let Some((diagnostics_summary, (downstream_client, _))) =
8526 diagnostics_summary.zip(self.downstream_client.as_ref())
8527 {
8528 downstream_client.send(diagnostics_summary).log_err();
8529 }
8530 for (server_id, paths) in updated_diagnostics_paths {
8531 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8532 }
8533 Ok(())
8534 }
8535
8536 fn update_worktree_diagnostics(
8537 &mut self,
8538 worktree_id: WorktreeId,
8539 server_id: LanguageServerId,
8540 path_in_worktree: Arc<RelPath>,
8541 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8542 _: &mut Context<Worktree>,
8543 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8544 let local = match &mut self.mode {
8545 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8546 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8547 };
8548
8549 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8550 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8551 let summaries_by_server_id = summaries_for_tree
8552 .entry(path_in_worktree.clone())
8553 .or_default();
8554
8555 let old_summary = summaries_by_server_id
8556 .remove(&server_id)
8557 .unwrap_or_default();
8558
8559 let new_summary = DiagnosticSummary::new(&diagnostics);
8560 if diagnostics.is_empty() {
8561 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8562 {
8563 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8564 diagnostics_by_server_id.remove(ix);
8565 }
8566 if diagnostics_by_server_id.is_empty() {
8567 diagnostics_for_tree.remove(&path_in_worktree);
8568 }
8569 }
8570 } else {
8571 summaries_by_server_id.insert(server_id, new_summary);
8572 let diagnostics_by_server_id = diagnostics_for_tree
8573 .entry(path_in_worktree.clone())
8574 .or_default();
8575 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8576 Ok(ix) => {
8577 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8578 }
8579 Err(ix) => {
8580 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8581 }
8582 }
8583 }
8584
8585 if !old_summary.is_empty() || !new_summary.is_empty() {
8586 if let Some((_, project_id)) = &self.downstream_client {
8587 Ok(ControlFlow::Continue(Some((
8588 *project_id,
8589 proto::DiagnosticSummary {
8590 path: path_in_worktree.to_proto(),
8591 language_server_id: server_id.0 as u64,
8592 error_count: new_summary.error_count as u32,
8593 warning_count: new_summary.warning_count as u32,
8594 },
8595 ))))
8596 } else {
8597 Ok(ControlFlow::Continue(None))
8598 }
8599 } else {
8600 Ok(ControlFlow::Break(()))
8601 }
8602 }
8603
8604 pub fn open_buffer_for_symbol(
8605 &mut self,
8606 symbol: &Symbol,
8607 cx: &mut Context<Self>,
8608 ) -> Task<Result<Entity<Buffer>>> {
8609 if let Some((client, project_id)) = self.upstream_client() {
8610 let request = client.request(proto::OpenBufferForSymbol {
8611 project_id,
8612 symbol: Some(Self::serialize_symbol(symbol)),
8613 });
8614 cx.spawn(async move |this, cx| {
8615 let response = request.await?;
8616 let buffer_id = BufferId::new(response.buffer_id)?;
8617 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8618 .await
8619 })
8620 } else if let Some(local) = self.as_local() {
8621 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8622 seed.worktree_id == symbol.source_worktree_id
8623 && state.id == symbol.source_language_server_id
8624 && symbol.language_server_name == seed.name
8625 });
8626 if !is_valid {
8627 return Task::ready(Err(anyhow!(
8628 "language server for worktree and language not found"
8629 )));
8630 };
8631
8632 let symbol_abs_path = match &symbol.path {
8633 SymbolLocation::InProject(project_path) => self
8634 .worktree_store
8635 .read(cx)
8636 .absolutize(&project_path, cx)
8637 .context("no such worktree"),
8638 SymbolLocation::OutsideProject {
8639 abs_path,
8640 signature: _,
8641 } => Ok(abs_path.to_path_buf()),
8642 };
8643 let symbol_abs_path = match symbol_abs_path {
8644 Ok(abs_path) => abs_path,
8645 Err(err) => return Task::ready(Err(err)),
8646 };
8647 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8648 uri
8649 } else {
8650 return Task::ready(Err(anyhow!("invalid symbol path")));
8651 };
8652
8653 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8654 } else {
8655 Task::ready(Err(anyhow!("no upstream client or local store")))
8656 }
8657 }
8658
8659 pub(crate) fn open_local_buffer_via_lsp(
8660 &mut self,
8661 abs_path: lsp::Uri,
8662 language_server_id: LanguageServerId,
8663 cx: &mut Context<Self>,
8664 ) -> Task<Result<Entity<Buffer>>> {
8665 cx.spawn(async move |lsp_store, cx| {
8666 // Escape percent-encoded string.
8667 let current_scheme = abs_path.scheme().to_owned();
8668 // Uri is immutable, so we can't modify the scheme
8669
8670 let abs_path = abs_path
8671 .to_file_path()
8672 .map_err(|()| anyhow!("can't convert URI to path"))?;
8673 let p = abs_path.clone();
8674 let yarn_worktree = lsp_store
8675 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8676 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8677 cx.spawn(async move |this, cx| {
8678 let t = this
8679 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8680 .ok()?;
8681 t.await
8682 })
8683 }),
8684 None => Task::ready(None),
8685 })?
8686 .await;
8687 let (worktree_root_target, known_relative_path) =
8688 if let Some((zip_root, relative_path)) = yarn_worktree {
8689 (zip_root, Some(relative_path))
8690 } else {
8691 (Arc::<Path>::from(abs_path.as_path()), None)
8692 };
8693 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8694 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8695 worktree_store.find_worktree(&worktree_root_target, cx)
8696 })
8697 })?;
8698 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8699 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8700 (result.0, relative_path, None)
8701 } else {
8702 let worktree = lsp_store
8703 .update(cx, |lsp_store, cx| {
8704 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8705 worktree_store.create_worktree(&worktree_root_target, false, cx)
8706 })
8707 })?
8708 .await?;
8709 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8710 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8711 lsp_store
8712 .update(cx, |lsp_store, cx| {
8713 if let Some(local) = lsp_store.as_local_mut() {
8714 local.register_language_server_for_invisible_worktree(
8715 &worktree,
8716 language_server_id,
8717 cx,
8718 )
8719 }
8720 match lsp_store.language_server_statuses.get(&language_server_id) {
8721 Some(status) => status.worktree,
8722 None => None,
8723 }
8724 })
8725 .ok()
8726 .flatten()
8727 .zip(Some(worktree_root.clone()))
8728 } else {
8729 None
8730 };
8731 let relative_path = if let Some(known_path) = known_relative_path {
8732 known_path
8733 } else {
8734 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8735 .into_arc()
8736 };
8737 (worktree, relative_path, source_ws)
8738 };
8739 let project_path = ProjectPath {
8740 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8741 path: relative_path,
8742 };
8743 let buffer = lsp_store
8744 .update(cx, |lsp_store, cx| {
8745 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8746 buffer_store.open_buffer(project_path, cx)
8747 })
8748 })?
8749 .await?;
8750 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8751 if let Some((source_ws, worktree_root)) = source_ws {
8752 buffer.update(cx, |buffer, cx| {
8753 let settings = WorktreeSettings::get(
8754 Some(
8755 (&ProjectPath {
8756 worktree_id: source_ws,
8757 path: Arc::from(RelPath::empty()),
8758 })
8759 .into(),
8760 ),
8761 cx,
8762 );
8763 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8764 if is_read_only {
8765 buffer.set_capability(Capability::ReadOnly, cx);
8766 }
8767 })?;
8768 }
8769 Ok(buffer)
8770 })
8771 }
8772
8773 fn request_multiple_lsp_locally<P, R>(
8774 &mut self,
8775 buffer: &Entity<Buffer>,
8776 position: Option<P>,
8777 request: R,
8778 cx: &mut Context<Self>,
8779 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8780 where
8781 P: ToOffset,
8782 R: LspCommand + Clone,
8783 <R::LspRequest as lsp::request::Request>::Result: Send,
8784 <R::LspRequest as lsp::request::Request>::Params: Send,
8785 {
8786 let Some(local) = self.as_local() else {
8787 return Task::ready(Vec::new());
8788 };
8789
8790 let snapshot = buffer.read(cx).snapshot();
8791 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8792
8793 let server_ids = buffer.update(cx, |buffer, cx| {
8794 local
8795 .language_servers_for_buffer(buffer, cx)
8796 .filter(|(adapter, _)| {
8797 scope
8798 .as_ref()
8799 .map(|scope| scope.language_allowed(&adapter.name))
8800 .unwrap_or(true)
8801 })
8802 .map(|(_, server)| server.server_id())
8803 .filter(|server_id| {
8804 self.as_local().is_none_or(|local| {
8805 local
8806 .buffers_opened_in_servers
8807 .get(&snapshot.remote_id())
8808 .is_some_and(|servers| servers.contains(server_id))
8809 })
8810 })
8811 .collect::<Vec<_>>()
8812 });
8813
8814 let mut response_results = server_ids
8815 .into_iter()
8816 .map(|server_id| {
8817 let task = self.request_lsp(
8818 buffer.clone(),
8819 LanguageServerToQuery::Other(server_id),
8820 request.clone(),
8821 cx,
8822 );
8823 async move { (server_id, task.await) }
8824 })
8825 .collect::<FuturesUnordered<_>>();
8826
8827 cx.background_spawn(async move {
8828 let mut responses = Vec::with_capacity(response_results.len());
8829 while let Some((server_id, response_result)) = response_results.next().await {
8830 match response_result {
8831 Ok(response) => responses.push((server_id, response)),
8832 // rust-analyzer likes to error with this when its still loading up
8833 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8834 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8835 }
8836 }
8837 responses
8838 })
8839 }
8840
8841 async fn handle_lsp_get_completions(
8842 this: Entity<Self>,
8843 envelope: TypedEnvelope<proto::GetCompletions>,
8844 mut cx: AsyncApp,
8845 ) -> Result<proto::GetCompletionsResponse> {
8846 let sender_id = envelope.original_sender_id().unwrap_or_default();
8847
8848 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8849 let buffer_handle = this.update(&mut cx, |this, cx| {
8850 this.buffer_store.read(cx).get_existing(buffer_id)
8851 })??;
8852 let request = GetCompletions::from_proto(
8853 envelope.payload,
8854 this.clone(),
8855 buffer_handle.clone(),
8856 cx.clone(),
8857 )
8858 .await?;
8859
8860 let server_to_query = match request.server_id {
8861 Some(server_id) => LanguageServerToQuery::Other(server_id),
8862 None => LanguageServerToQuery::FirstCapable,
8863 };
8864
8865 let response = this
8866 .update(&mut cx, |this, cx| {
8867 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8868 })?
8869 .await?;
8870 this.update(&mut cx, |this, cx| {
8871 Ok(GetCompletions::response_to_proto(
8872 response,
8873 this,
8874 sender_id,
8875 &buffer_handle.read(cx).version(),
8876 cx,
8877 ))
8878 })?
8879 }
8880
8881 async fn handle_lsp_command<T: LspCommand>(
8882 this: Entity<Self>,
8883 envelope: TypedEnvelope<T::ProtoRequest>,
8884 mut cx: AsyncApp,
8885 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8886 where
8887 <T::LspRequest as lsp::request::Request>::Params: Send,
8888 <T::LspRequest as lsp::request::Request>::Result: Send,
8889 {
8890 let sender_id = envelope.original_sender_id().unwrap_or_default();
8891 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8892 let buffer_handle = this.update(&mut cx, |this, cx| {
8893 this.buffer_store.read(cx).get_existing(buffer_id)
8894 })??;
8895 let request = T::from_proto(
8896 envelope.payload,
8897 this.clone(),
8898 buffer_handle.clone(),
8899 cx.clone(),
8900 )
8901 .await?;
8902 let response = this
8903 .update(&mut cx, |this, cx| {
8904 this.request_lsp(
8905 buffer_handle.clone(),
8906 LanguageServerToQuery::FirstCapable,
8907 request,
8908 cx,
8909 )
8910 })?
8911 .await?;
8912 this.update(&mut cx, |this, cx| {
8913 Ok(T::response_to_proto(
8914 response,
8915 this,
8916 sender_id,
8917 &buffer_handle.read(cx).version(),
8918 cx,
8919 ))
8920 })?
8921 }
8922
8923 async fn handle_lsp_query(
8924 lsp_store: Entity<Self>,
8925 envelope: TypedEnvelope<proto::LspQuery>,
8926 mut cx: AsyncApp,
8927 ) -> Result<proto::Ack> {
8928 use proto::lsp_query::Request;
8929 let sender_id = envelope.original_sender_id().unwrap_or_default();
8930 let lsp_query = envelope.payload;
8931 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8932 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8933 match lsp_query.request.context("invalid LSP query request")? {
8934 Request::GetReferences(get_references) => {
8935 let position = get_references.position.clone().and_then(deserialize_anchor);
8936 Self::query_lsp_locally::<GetReferences>(
8937 lsp_store,
8938 server_id,
8939 sender_id,
8940 lsp_request_id,
8941 get_references,
8942 position,
8943 &mut cx,
8944 )
8945 .await?;
8946 }
8947 Request::GetDocumentColor(get_document_color) => {
8948 Self::query_lsp_locally::<GetDocumentColor>(
8949 lsp_store,
8950 server_id,
8951 sender_id,
8952 lsp_request_id,
8953 get_document_color,
8954 None,
8955 &mut cx,
8956 )
8957 .await?;
8958 }
8959 Request::GetHover(get_hover) => {
8960 let position = get_hover.position.clone().and_then(deserialize_anchor);
8961 Self::query_lsp_locally::<GetHover>(
8962 lsp_store,
8963 server_id,
8964 sender_id,
8965 lsp_request_id,
8966 get_hover,
8967 position,
8968 &mut cx,
8969 )
8970 .await?;
8971 }
8972 Request::GetCodeActions(get_code_actions) => {
8973 Self::query_lsp_locally::<GetCodeActions>(
8974 lsp_store,
8975 server_id,
8976 sender_id,
8977 lsp_request_id,
8978 get_code_actions,
8979 None,
8980 &mut cx,
8981 )
8982 .await?;
8983 }
8984 Request::GetSignatureHelp(get_signature_help) => {
8985 let position = get_signature_help
8986 .position
8987 .clone()
8988 .and_then(deserialize_anchor);
8989 Self::query_lsp_locally::<GetSignatureHelp>(
8990 lsp_store,
8991 server_id,
8992 sender_id,
8993 lsp_request_id,
8994 get_signature_help,
8995 position,
8996 &mut cx,
8997 )
8998 .await?;
8999 }
9000 Request::GetCodeLens(get_code_lens) => {
9001 Self::query_lsp_locally::<GetCodeLens>(
9002 lsp_store,
9003 server_id,
9004 sender_id,
9005 lsp_request_id,
9006 get_code_lens,
9007 None,
9008 &mut cx,
9009 )
9010 .await?;
9011 }
9012 Request::GetDefinition(get_definition) => {
9013 let position = get_definition.position.clone().and_then(deserialize_anchor);
9014 Self::query_lsp_locally::<GetDefinitions>(
9015 lsp_store,
9016 server_id,
9017 sender_id,
9018 lsp_request_id,
9019 get_definition,
9020 position,
9021 &mut cx,
9022 )
9023 .await?;
9024 }
9025 Request::GetDeclaration(get_declaration) => {
9026 let position = get_declaration
9027 .position
9028 .clone()
9029 .and_then(deserialize_anchor);
9030 Self::query_lsp_locally::<GetDeclarations>(
9031 lsp_store,
9032 server_id,
9033 sender_id,
9034 lsp_request_id,
9035 get_declaration,
9036 position,
9037 &mut cx,
9038 )
9039 .await?;
9040 }
9041 Request::GetTypeDefinition(get_type_definition) => {
9042 let position = get_type_definition
9043 .position
9044 .clone()
9045 .and_then(deserialize_anchor);
9046 Self::query_lsp_locally::<GetTypeDefinitions>(
9047 lsp_store,
9048 server_id,
9049 sender_id,
9050 lsp_request_id,
9051 get_type_definition,
9052 position,
9053 &mut cx,
9054 )
9055 .await?;
9056 }
9057 Request::GetImplementation(get_implementation) => {
9058 let position = get_implementation
9059 .position
9060 .clone()
9061 .and_then(deserialize_anchor);
9062 Self::query_lsp_locally::<GetImplementations>(
9063 lsp_store,
9064 server_id,
9065 sender_id,
9066 lsp_request_id,
9067 get_implementation,
9068 position,
9069 &mut cx,
9070 )
9071 .await?;
9072 }
9073 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9074 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9075 let version = deserialize_version(get_document_diagnostics.buffer_version());
9076 let buffer = lsp_store.update(&mut cx, |this, cx| {
9077 this.buffer_store.read(cx).get_existing(buffer_id)
9078 })??;
9079 buffer
9080 .update(&mut cx, |buffer, _| {
9081 buffer.wait_for_version(version.clone())
9082 })?
9083 .await?;
9084 lsp_store.update(&mut cx, |lsp_store, cx| {
9085 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9086 let key = LspKey {
9087 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9088 server_queried: server_id,
9089 };
9090 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9091 ) {
9092 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9093 lsp_requests.clear();
9094 };
9095 }
9096
9097 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9098 existing_queries.insert(
9099 lsp_request_id,
9100 cx.spawn(async move |lsp_store, cx| {
9101 let diagnostics_pull = lsp_store
9102 .update(cx, |lsp_store, cx| {
9103 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9104 })
9105 .ok();
9106 if let Some(diagnostics_pull) = diagnostics_pull {
9107 match diagnostics_pull.await {
9108 Ok(()) => {}
9109 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9110 };
9111 }
9112 }),
9113 );
9114 })?;
9115 }
9116 Request::InlayHints(inlay_hints) => {
9117 let query_start = inlay_hints
9118 .start
9119 .clone()
9120 .and_then(deserialize_anchor)
9121 .context("invalid inlay hints range start")?;
9122 let query_end = inlay_hints
9123 .end
9124 .clone()
9125 .and_then(deserialize_anchor)
9126 .context("invalid inlay hints range end")?;
9127 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9128 &lsp_store,
9129 server_id,
9130 lsp_request_id,
9131 &inlay_hints,
9132 query_start..query_end,
9133 &mut cx,
9134 )
9135 .await
9136 .context("preparing inlay hints request")?;
9137 Self::query_lsp_locally::<InlayHints>(
9138 lsp_store,
9139 server_id,
9140 sender_id,
9141 lsp_request_id,
9142 inlay_hints,
9143 None,
9144 &mut cx,
9145 )
9146 .await
9147 .context("querying for inlay hints")?
9148 }
9149 }
9150 Ok(proto::Ack {})
9151 }
9152
9153 async fn handle_lsp_query_response(
9154 lsp_store: Entity<Self>,
9155 envelope: TypedEnvelope<proto::LspQueryResponse>,
9156 cx: AsyncApp,
9157 ) -> Result<()> {
9158 lsp_store.read_with(&cx, |lsp_store, _| {
9159 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9160 upstream_client.handle_lsp_response(envelope.clone());
9161 }
9162 })?;
9163 Ok(())
9164 }
9165
9166 async fn handle_apply_code_action(
9167 this: Entity<Self>,
9168 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9169 mut cx: AsyncApp,
9170 ) -> Result<proto::ApplyCodeActionResponse> {
9171 let sender_id = envelope.original_sender_id().unwrap_or_default();
9172 let action =
9173 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9174 let apply_code_action = this.update(&mut cx, |this, cx| {
9175 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9176 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9177 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9178 })??;
9179
9180 let project_transaction = apply_code_action.await?;
9181 let project_transaction = this.update(&mut cx, |this, cx| {
9182 this.buffer_store.update(cx, |buffer_store, cx| {
9183 buffer_store.serialize_project_transaction_for_peer(
9184 project_transaction,
9185 sender_id,
9186 cx,
9187 )
9188 })
9189 })?;
9190 Ok(proto::ApplyCodeActionResponse {
9191 transaction: Some(project_transaction),
9192 })
9193 }
9194
9195 async fn handle_register_buffer_with_language_servers(
9196 this: Entity<Self>,
9197 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9198 mut cx: AsyncApp,
9199 ) -> Result<proto::Ack> {
9200 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9201 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9202 this.update(&mut cx, |this, cx| {
9203 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9204 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9205 project_id: upstream_project_id,
9206 buffer_id: buffer_id.to_proto(),
9207 only_servers: envelope.payload.only_servers,
9208 });
9209 }
9210
9211 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9212 anyhow::bail!("buffer is not open");
9213 };
9214
9215 let handle = this.register_buffer_with_language_servers(
9216 &buffer,
9217 envelope
9218 .payload
9219 .only_servers
9220 .into_iter()
9221 .filter_map(|selector| {
9222 Some(match selector.selector? {
9223 proto::language_server_selector::Selector::ServerId(server_id) => {
9224 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9225 }
9226 proto::language_server_selector::Selector::Name(name) => {
9227 LanguageServerSelector::Name(LanguageServerName(
9228 SharedString::from(name),
9229 ))
9230 }
9231 })
9232 })
9233 .collect(),
9234 false,
9235 cx,
9236 );
9237 this.buffer_store().update(cx, |buffer_store, _| {
9238 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9239 });
9240
9241 Ok(())
9242 })??;
9243 Ok(proto::Ack {})
9244 }
9245
9246 async fn handle_rename_project_entry(
9247 this: Entity<Self>,
9248 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9249 mut cx: AsyncApp,
9250 ) -> Result<proto::ProjectEntryResponse> {
9251 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9252 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9253 let new_path =
9254 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9255
9256 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9257 .update(&mut cx, |this, cx| {
9258 let (worktree, entry) = this
9259 .worktree_store
9260 .read(cx)
9261 .worktree_and_entry_for_id(entry_id, cx)?;
9262 let new_worktree = this
9263 .worktree_store
9264 .read(cx)
9265 .worktree_for_id(new_worktree_id, cx)?;
9266 Some((
9267 this.worktree_store.clone(),
9268 worktree,
9269 new_worktree,
9270 entry.clone(),
9271 ))
9272 })?
9273 .context("worktree not found")?;
9274 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9275 (worktree.absolutize(&old_entry.path), worktree.id())
9276 })?;
9277 let new_abs_path =
9278 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9279
9280 let _transaction = Self::will_rename_entry(
9281 this.downgrade(),
9282 old_worktree_id,
9283 &old_abs_path,
9284 &new_abs_path,
9285 old_entry.is_dir(),
9286 cx.clone(),
9287 )
9288 .await;
9289 let response = WorktreeStore::handle_rename_project_entry(
9290 worktree_store,
9291 envelope.payload,
9292 cx.clone(),
9293 )
9294 .await;
9295 this.read_with(&cx, |this, _| {
9296 this.did_rename_entry(
9297 old_worktree_id,
9298 &old_abs_path,
9299 &new_abs_path,
9300 old_entry.is_dir(),
9301 );
9302 })
9303 .ok();
9304 response
9305 }
9306
9307 async fn handle_update_diagnostic_summary(
9308 this: Entity<Self>,
9309 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9310 mut cx: AsyncApp,
9311 ) -> Result<()> {
9312 this.update(&mut cx, |lsp_store, cx| {
9313 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9314 let mut updated_diagnostics_paths = HashMap::default();
9315 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9316 for message_summary in envelope
9317 .payload
9318 .summary
9319 .into_iter()
9320 .chain(envelope.payload.more_summaries)
9321 {
9322 let project_path = ProjectPath {
9323 worktree_id,
9324 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9325 };
9326 let path = project_path.path.clone();
9327 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9328 let summary = DiagnosticSummary {
9329 error_count: message_summary.error_count as usize,
9330 warning_count: message_summary.warning_count as usize,
9331 };
9332
9333 if summary.is_empty() {
9334 if let Some(worktree_summaries) =
9335 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9336 && let Some(summaries) = worktree_summaries.get_mut(&path)
9337 {
9338 summaries.remove(&server_id);
9339 if summaries.is_empty() {
9340 worktree_summaries.remove(&path);
9341 }
9342 }
9343 } else {
9344 lsp_store
9345 .diagnostic_summaries
9346 .entry(worktree_id)
9347 .or_default()
9348 .entry(path)
9349 .or_default()
9350 .insert(server_id, summary);
9351 }
9352
9353 if let Some((_, project_id)) = &lsp_store.downstream_client {
9354 match &mut diagnostics_summary {
9355 Some(diagnostics_summary) => {
9356 diagnostics_summary
9357 .more_summaries
9358 .push(proto::DiagnosticSummary {
9359 path: project_path.path.as_ref().to_proto(),
9360 language_server_id: server_id.0 as u64,
9361 error_count: summary.error_count as u32,
9362 warning_count: summary.warning_count as u32,
9363 })
9364 }
9365 None => {
9366 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9367 project_id: *project_id,
9368 worktree_id: worktree_id.to_proto(),
9369 summary: Some(proto::DiagnosticSummary {
9370 path: project_path.path.as_ref().to_proto(),
9371 language_server_id: server_id.0 as u64,
9372 error_count: summary.error_count as u32,
9373 warning_count: summary.warning_count as u32,
9374 }),
9375 more_summaries: Vec::new(),
9376 })
9377 }
9378 }
9379 }
9380 updated_diagnostics_paths
9381 .entry(server_id)
9382 .or_insert_with(Vec::new)
9383 .push(project_path);
9384 }
9385
9386 if let Some((diagnostics_summary, (downstream_client, _))) =
9387 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9388 {
9389 downstream_client.send(diagnostics_summary).log_err();
9390 }
9391 for (server_id, paths) in updated_diagnostics_paths {
9392 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9393 }
9394 Ok(())
9395 })?
9396 }
9397
9398 async fn handle_start_language_server(
9399 lsp_store: Entity<Self>,
9400 envelope: TypedEnvelope<proto::StartLanguageServer>,
9401 mut cx: AsyncApp,
9402 ) -> Result<()> {
9403 let server = envelope.payload.server.context("invalid server")?;
9404 let server_capabilities =
9405 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9406 .with_context(|| {
9407 format!(
9408 "incorrect server capabilities {}",
9409 envelope.payload.capabilities
9410 )
9411 })?;
9412 lsp_store.update(&mut cx, |lsp_store, cx| {
9413 let server_id = LanguageServerId(server.id as usize);
9414 let server_name = LanguageServerName::from_proto(server.name.clone());
9415 lsp_store
9416 .lsp_server_capabilities
9417 .insert(server_id, server_capabilities);
9418 lsp_store.language_server_statuses.insert(
9419 server_id,
9420 LanguageServerStatus {
9421 name: server_name.clone(),
9422 server_version: None,
9423 pending_work: Default::default(),
9424 has_pending_diagnostic_updates: false,
9425 progress_tokens: Default::default(),
9426 worktree: server.worktree_id.map(WorktreeId::from_proto),
9427 binary: None,
9428 configuration: None,
9429 workspace_folders: BTreeSet::new(),
9430 },
9431 );
9432 cx.emit(LspStoreEvent::LanguageServerAdded(
9433 server_id,
9434 server_name,
9435 server.worktree_id.map(WorktreeId::from_proto),
9436 ));
9437 cx.notify();
9438 })?;
9439 Ok(())
9440 }
9441
9442 async fn handle_update_language_server(
9443 lsp_store: Entity<Self>,
9444 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9445 mut cx: AsyncApp,
9446 ) -> Result<()> {
9447 lsp_store.update(&mut cx, |lsp_store, cx| {
9448 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9449
9450 match envelope.payload.variant.context("invalid variant")? {
9451 proto::update_language_server::Variant::WorkStart(payload) => {
9452 lsp_store.on_lsp_work_start(
9453 language_server_id,
9454 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9455 .context("invalid progress token value")?,
9456 LanguageServerProgress {
9457 title: payload.title,
9458 is_disk_based_diagnostics_progress: false,
9459 is_cancellable: payload.is_cancellable.unwrap_or(false),
9460 message: payload.message,
9461 percentage: payload.percentage.map(|p| p as usize),
9462 last_update_at: cx.background_executor().now(),
9463 },
9464 cx,
9465 );
9466 }
9467 proto::update_language_server::Variant::WorkProgress(payload) => {
9468 lsp_store.on_lsp_work_progress(
9469 language_server_id,
9470 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9471 .context("invalid progress token value")?,
9472 LanguageServerProgress {
9473 title: None,
9474 is_disk_based_diagnostics_progress: false,
9475 is_cancellable: payload.is_cancellable.unwrap_or(false),
9476 message: payload.message,
9477 percentage: payload.percentage.map(|p| p as usize),
9478 last_update_at: cx.background_executor().now(),
9479 },
9480 cx,
9481 );
9482 }
9483
9484 proto::update_language_server::Variant::WorkEnd(payload) => {
9485 lsp_store.on_lsp_work_end(
9486 language_server_id,
9487 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9488 .context("invalid progress token value")?,
9489 cx,
9490 );
9491 }
9492
9493 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9494 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9495 }
9496
9497 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9498 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9499 }
9500
9501 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9502 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9503 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9504 cx.emit(LspStoreEvent::LanguageServerUpdate {
9505 language_server_id,
9506 name: envelope
9507 .payload
9508 .server_name
9509 .map(SharedString::new)
9510 .map(LanguageServerName),
9511 message: non_lsp,
9512 });
9513 }
9514 }
9515
9516 Ok(())
9517 })?
9518 }
9519
9520 async fn handle_language_server_log(
9521 this: Entity<Self>,
9522 envelope: TypedEnvelope<proto::LanguageServerLog>,
9523 mut cx: AsyncApp,
9524 ) -> Result<()> {
9525 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9526 let log_type = envelope
9527 .payload
9528 .log_type
9529 .map(LanguageServerLogType::from_proto)
9530 .context("invalid language server log type")?;
9531
9532 let message = envelope.payload.message;
9533
9534 this.update(&mut cx, |_, cx| {
9535 cx.emit(LspStoreEvent::LanguageServerLog(
9536 language_server_id,
9537 log_type,
9538 message,
9539 ));
9540 })
9541 }
9542
9543 async fn handle_lsp_ext_cancel_flycheck(
9544 lsp_store: Entity<Self>,
9545 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9546 cx: AsyncApp,
9547 ) -> Result<proto::Ack> {
9548 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9549 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9550 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9551 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9552 } else {
9553 None
9554 }
9555 })?;
9556 if let Some(task) = task {
9557 task.context("handling lsp ext cancel flycheck")?;
9558 }
9559
9560 Ok(proto::Ack {})
9561 }
9562
9563 async fn handle_lsp_ext_run_flycheck(
9564 lsp_store: Entity<Self>,
9565 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9566 mut cx: AsyncApp,
9567 ) -> Result<proto::Ack> {
9568 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9569 lsp_store.update(&mut cx, |lsp_store, cx| {
9570 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9571 let text_document = if envelope.payload.current_file_only {
9572 let buffer_id = envelope
9573 .payload
9574 .buffer_id
9575 .map(|id| BufferId::new(id))
9576 .transpose()?;
9577 buffer_id
9578 .and_then(|buffer_id| {
9579 lsp_store
9580 .buffer_store()
9581 .read(cx)
9582 .get(buffer_id)
9583 .and_then(|buffer| {
9584 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9585 })
9586 .map(|path| make_text_document_identifier(&path))
9587 })
9588 .transpose()?
9589 } else {
9590 None
9591 };
9592 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9593 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9594 )?;
9595 }
9596 anyhow::Ok(())
9597 })??;
9598
9599 Ok(proto::Ack {})
9600 }
9601
9602 async fn handle_lsp_ext_clear_flycheck(
9603 lsp_store: Entity<Self>,
9604 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9605 cx: AsyncApp,
9606 ) -> Result<proto::Ack> {
9607 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9608 lsp_store
9609 .read_with(&cx, |lsp_store, _| {
9610 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9611 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9612 } else {
9613 None
9614 }
9615 })
9616 .context("handling lsp ext clear flycheck")?;
9617
9618 Ok(proto::Ack {})
9619 }
9620
9621 pub fn disk_based_diagnostics_started(
9622 &mut self,
9623 language_server_id: LanguageServerId,
9624 cx: &mut Context<Self>,
9625 ) {
9626 if let Some(language_server_status) =
9627 self.language_server_statuses.get_mut(&language_server_id)
9628 {
9629 language_server_status.has_pending_diagnostic_updates = true;
9630 }
9631
9632 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9633 cx.emit(LspStoreEvent::LanguageServerUpdate {
9634 language_server_id,
9635 name: self
9636 .language_server_adapter_for_id(language_server_id)
9637 .map(|adapter| adapter.name()),
9638 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9639 Default::default(),
9640 ),
9641 })
9642 }
9643
9644 pub fn disk_based_diagnostics_finished(
9645 &mut self,
9646 language_server_id: LanguageServerId,
9647 cx: &mut Context<Self>,
9648 ) {
9649 if let Some(language_server_status) =
9650 self.language_server_statuses.get_mut(&language_server_id)
9651 {
9652 language_server_status.has_pending_diagnostic_updates = false;
9653 }
9654
9655 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9656 cx.emit(LspStoreEvent::LanguageServerUpdate {
9657 language_server_id,
9658 name: self
9659 .language_server_adapter_for_id(language_server_id)
9660 .map(|adapter| adapter.name()),
9661 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9662 Default::default(),
9663 ),
9664 })
9665 }
9666
9667 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9668 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9669 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9670 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9671 // the language server might take some time to publish diagnostics.
9672 fn simulate_disk_based_diagnostics_events_if_needed(
9673 &mut self,
9674 language_server_id: LanguageServerId,
9675 cx: &mut Context<Self>,
9676 ) {
9677 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9678
9679 let Some(LanguageServerState::Running {
9680 simulate_disk_based_diagnostics_completion,
9681 adapter,
9682 ..
9683 }) = self
9684 .as_local_mut()
9685 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9686 else {
9687 return;
9688 };
9689
9690 if adapter.disk_based_diagnostics_progress_token.is_some() {
9691 return;
9692 }
9693
9694 let prev_task =
9695 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9696 cx.background_executor()
9697 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9698 .await;
9699
9700 this.update(cx, |this, cx| {
9701 this.disk_based_diagnostics_finished(language_server_id, cx);
9702
9703 if let Some(LanguageServerState::Running {
9704 simulate_disk_based_diagnostics_completion,
9705 ..
9706 }) = this.as_local_mut().and_then(|local_store| {
9707 local_store.language_servers.get_mut(&language_server_id)
9708 }) {
9709 *simulate_disk_based_diagnostics_completion = None;
9710 }
9711 })
9712 .ok();
9713 }));
9714
9715 if prev_task.is_none() {
9716 self.disk_based_diagnostics_started(language_server_id, cx);
9717 }
9718 }
9719
9720 pub fn language_server_statuses(
9721 &self,
9722 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9723 self.language_server_statuses
9724 .iter()
9725 .map(|(key, value)| (*key, value))
9726 }
9727
9728 pub(super) fn did_rename_entry(
9729 &self,
9730 worktree_id: WorktreeId,
9731 old_path: &Path,
9732 new_path: &Path,
9733 is_dir: bool,
9734 ) {
9735 maybe!({
9736 let local_store = self.as_local()?;
9737
9738 let old_uri = lsp::Uri::from_file_path(old_path)
9739 .ok()
9740 .map(|uri| uri.to_string())?;
9741 let new_uri = lsp::Uri::from_file_path(new_path)
9742 .ok()
9743 .map(|uri| uri.to_string())?;
9744
9745 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9746 let Some(filter) = local_store
9747 .language_server_paths_watched_for_rename
9748 .get(&language_server.server_id())
9749 else {
9750 continue;
9751 };
9752
9753 if filter.should_send_did_rename(&old_uri, is_dir) {
9754 language_server
9755 .notify::<DidRenameFiles>(RenameFilesParams {
9756 files: vec![FileRename {
9757 old_uri: old_uri.clone(),
9758 new_uri: new_uri.clone(),
9759 }],
9760 })
9761 .ok();
9762 }
9763 }
9764 Some(())
9765 });
9766 }
9767
9768 pub(super) fn will_rename_entry(
9769 this: WeakEntity<Self>,
9770 worktree_id: WorktreeId,
9771 old_path: &Path,
9772 new_path: &Path,
9773 is_dir: bool,
9774 cx: AsyncApp,
9775 ) -> Task<ProjectTransaction> {
9776 let old_uri = lsp::Uri::from_file_path(old_path)
9777 .ok()
9778 .map(|uri| uri.to_string());
9779 let new_uri = lsp::Uri::from_file_path(new_path)
9780 .ok()
9781 .map(|uri| uri.to_string());
9782 cx.spawn(async move |cx| {
9783 let mut tasks = vec![];
9784 this.update(cx, |this, cx| {
9785 let local_store = this.as_local()?;
9786 let old_uri = old_uri?;
9787 let new_uri = new_uri?;
9788 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9789 let Some(filter) = local_store
9790 .language_server_paths_watched_for_rename
9791 .get(&language_server.server_id())
9792 else {
9793 continue;
9794 };
9795
9796 if filter.should_send_will_rename(&old_uri, is_dir) {
9797 let apply_edit = cx.spawn({
9798 let old_uri = old_uri.clone();
9799 let new_uri = new_uri.clone();
9800 let language_server = language_server.clone();
9801 async move |this, cx| {
9802 let edit = language_server
9803 .request::<WillRenameFiles>(RenameFilesParams {
9804 files: vec![FileRename { old_uri, new_uri }],
9805 })
9806 .await
9807 .into_response()
9808 .context("will rename files")
9809 .log_err()
9810 .flatten()?;
9811
9812 let transaction = LocalLspStore::deserialize_workspace_edit(
9813 this.upgrade()?,
9814 edit,
9815 false,
9816 language_server.clone(),
9817 cx,
9818 )
9819 .await
9820 .ok()?;
9821 Some(transaction)
9822 }
9823 });
9824 tasks.push(apply_edit);
9825 }
9826 }
9827 Some(())
9828 })
9829 .ok()
9830 .flatten();
9831 let mut merged_transaction = ProjectTransaction::default();
9832 for task in tasks {
9833 // Await on tasks sequentially so that the order of application of edits is deterministic
9834 // (at least with regards to the order of registration of language servers)
9835 if let Some(transaction) = task.await {
9836 for (buffer, buffer_transaction) in transaction.0 {
9837 merged_transaction.0.insert(buffer, buffer_transaction);
9838 }
9839 }
9840 }
9841 merged_transaction
9842 })
9843 }
9844
9845 fn lsp_notify_abs_paths_changed(
9846 &mut self,
9847 server_id: LanguageServerId,
9848 changes: Vec<PathEvent>,
9849 ) {
9850 maybe!({
9851 let server = self.language_server_for_id(server_id)?;
9852 let changes = changes
9853 .into_iter()
9854 .filter_map(|event| {
9855 let typ = match event.kind? {
9856 PathEventKind::Created => lsp::FileChangeType::CREATED,
9857 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9858 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9859 };
9860 Some(lsp::FileEvent {
9861 uri: file_path_to_lsp_url(&event.path).log_err()?,
9862 typ,
9863 })
9864 })
9865 .collect::<Vec<_>>();
9866 if !changes.is_empty() {
9867 server
9868 .notify::<lsp::notification::DidChangeWatchedFiles>(
9869 lsp::DidChangeWatchedFilesParams { changes },
9870 )
9871 .ok();
9872 }
9873 Some(())
9874 });
9875 }
9876
9877 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9878 self.as_local()?.language_server_for_id(id)
9879 }
9880
9881 fn on_lsp_progress(
9882 &mut self,
9883 progress_params: lsp::ProgressParams,
9884 language_server_id: LanguageServerId,
9885 disk_based_diagnostics_progress_token: Option<String>,
9886 cx: &mut Context<Self>,
9887 ) {
9888 match progress_params.value {
9889 lsp::ProgressParamsValue::WorkDone(progress) => {
9890 self.handle_work_done_progress(
9891 progress,
9892 language_server_id,
9893 disk_based_diagnostics_progress_token,
9894 ProgressToken::from_lsp(progress_params.token),
9895 cx,
9896 );
9897 }
9898 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9899 let registration_id = match progress_params.token {
9900 lsp::NumberOrString::Number(_) => None,
9901 lsp::NumberOrString::String(token) => token
9902 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9903 .map(|(_, id)| id.to_owned()),
9904 };
9905 if let Some(LanguageServerState::Running {
9906 workspace_diagnostics_refresh_tasks,
9907 ..
9908 }) = self
9909 .as_local_mut()
9910 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9911 && let Some(workspace_diagnostics) =
9912 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9913 {
9914 workspace_diagnostics.progress_tx.try_send(()).ok();
9915 self.apply_workspace_diagnostic_report(
9916 language_server_id,
9917 report,
9918 registration_id.map(SharedString::from),
9919 cx,
9920 )
9921 }
9922 }
9923 }
9924 }
9925
9926 fn handle_work_done_progress(
9927 &mut self,
9928 progress: lsp::WorkDoneProgress,
9929 language_server_id: LanguageServerId,
9930 disk_based_diagnostics_progress_token: Option<String>,
9931 token: ProgressToken,
9932 cx: &mut Context<Self>,
9933 ) {
9934 let language_server_status =
9935 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9936 status
9937 } else {
9938 return;
9939 };
9940
9941 if !language_server_status.progress_tokens.contains(&token) {
9942 return;
9943 }
9944
9945 let is_disk_based_diagnostics_progress =
9946 if let (Some(disk_based_token), ProgressToken::String(token)) =
9947 (&disk_based_diagnostics_progress_token, &token)
9948 {
9949 token.starts_with(disk_based_token)
9950 } else {
9951 false
9952 };
9953
9954 match progress {
9955 lsp::WorkDoneProgress::Begin(report) => {
9956 if is_disk_based_diagnostics_progress {
9957 self.disk_based_diagnostics_started(language_server_id, cx);
9958 }
9959 self.on_lsp_work_start(
9960 language_server_id,
9961 token.clone(),
9962 LanguageServerProgress {
9963 title: Some(report.title),
9964 is_disk_based_diagnostics_progress,
9965 is_cancellable: report.cancellable.unwrap_or(false),
9966 message: report.message.clone(),
9967 percentage: report.percentage.map(|p| p as usize),
9968 last_update_at: cx.background_executor().now(),
9969 },
9970 cx,
9971 );
9972 }
9973 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9974 language_server_id,
9975 token,
9976 LanguageServerProgress {
9977 title: None,
9978 is_disk_based_diagnostics_progress,
9979 is_cancellable: report.cancellable.unwrap_or(false),
9980 message: report.message,
9981 percentage: report.percentage.map(|p| p as usize),
9982 last_update_at: cx.background_executor().now(),
9983 },
9984 cx,
9985 ),
9986 lsp::WorkDoneProgress::End(_) => {
9987 language_server_status.progress_tokens.remove(&token);
9988 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9989 if is_disk_based_diagnostics_progress {
9990 self.disk_based_diagnostics_finished(language_server_id, cx);
9991 }
9992 }
9993 }
9994 }
9995
9996 fn on_lsp_work_start(
9997 &mut self,
9998 language_server_id: LanguageServerId,
9999 token: ProgressToken,
10000 progress: LanguageServerProgress,
10001 cx: &mut Context<Self>,
10002 ) {
10003 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10004 status.pending_work.insert(token.clone(), progress.clone());
10005 cx.notify();
10006 }
10007 cx.emit(LspStoreEvent::LanguageServerUpdate {
10008 language_server_id,
10009 name: self
10010 .language_server_adapter_for_id(language_server_id)
10011 .map(|adapter| adapter.name()),
10012 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10013 token: Some(token.to_proto()),
10014 title: progress.title,
10015 message: progress.message,
10016 percentage: progress.percentage.map(|p| p as u32),
10017 is_cancellable: Some(progress.is_cancellable),
10018 }),
10019 })
10020 }
10021
10022 fn on_lsp_work_progress(
10023 &mut self,
10024 language_server_id: LanguageServerId,
10025 token: ProgressToken,
10026 progress: LanguageServerProgress,
10027 cx: &mut Context<Self>,
10028 ) {
10029 let mut did_update = false;
10030 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10031 match status.pending_work.entry(token.clone()) {
10032 btree_map::Entry::Vacant(entry) => {
10033 entry.insert(progress.clone());
10034 did_update = true;
10035 }
10036 btree_map::Entry::Occupied(mut entry) => {
10037 let entry = entry.get_mut();
10038 if (progress.last_update_at - entry.last_update_at)
10039 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10040 {
10041 entry.last_update_at = progress.last_update_at;
10042 if progress.message.is_some() {
10043 entry.message = progress.message.clone();
10044 }
10045 if progress.percentage.is_some() {
10046 entry.percentage = progress.percentage;
10047 }
10048 if progress.is_cancellable != entry.is_cancellable {
10049 entry.is_cancellable = progress.is_cancellable;
10050 }
10051 did_update = true;
10052 }
10053 }
10054 }
10055 }
10056
10057 if did_update {
10058 cx.emit(LspStoreEvent::LanguageServerUpdate {
10059 language_server_id,
10060 name: self
10061 .language_server_adapter_for_id(language_server_id)
10062 .map(|adapter| adapter.name()),
10063 message: proto::update_language_server::Variant::WorkProgress(
10064 proto::LspWorkProgress {
10065 token: Some(token.to_proto()),
10066 message: progress.message,
10067 percentage: progress.percentage.map(|p| p as u32),
10068 is_cancellable: Some(progress.is_cancellable),
10069 },
10070 ),
10071 })
10072 }
10073 }
10074
10075 fn on_lsp_work_end(
10076 &mut self,
10077 language_server_id: LanguageServerId,
10078 token: ProgressToken,
10079 cx: &mut Context<Self>,
10080 ) {
10081 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10082 if let Some(work) = status.pending_work.remove(&token)
10083 && !work.is_disk_based_diagnostics_progress
10084 {
10085 cx.emit(LspStoreEvent::RefreshInlayHints {
10086 server_id: language_server_id,
10087 request_id: None,
10088 });
10089 }
10090 cx.notify();
10091 }
10092
10093 cx.emit(LspStoreEvent::LanguageServerUpdate {
10094 language_server_id,
10095 name: self
10096 .language_server_adapter_for_id(language_server_id)
10097 .map(|adapter| adapter.name()),
10098 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10099 token: Some(token.to_proto()),
10100 }),
10101 })
10102 }
10103
10104 pub async fn handle_resolve_completion_documentation(
10105 this: Entity<Self>,
10106 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10107 mut cx: AsyncApp,
10108 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10109 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10110
10111 let completion = this
10112 .read_with(&cx, |this, cx| {
10113 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10114 let server = this
10115 .language_server_for_id(id)
10116 .with_context(|| format!("No language server {id}"))?;
10117
10118 anyhow::Ok(cx.background_spawn(async move {
10119 let can_resolve = server
10120 .capabilities()
10121 .completion_provider
10122 .as_ref()
10123 .and_then(|options| options.resolve_provider)
10124 .unwrap_or(false);
10125 if can_resolve {
10126 server
10127 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10128 .await
10129 .into_response()
10130 .context("resolve completion item")
10131 } else {
10132 anyhow::Ok(lsp_completion)
10133 }
10134 }))
10135 })??
10136 .await?;
10137
10138 let mut documentation_is_markdown = false;
10139 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10140 let documentation = match completion.documentation {
10141 Some(lsp::Documentation::String(text)) => text,
10142
10143 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10144 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10145 value
10146 }
10147
10148 _ => String::new(),
10149 };
10150
10151 // If we have a new buffer_id, that means we're talking to a new client
10152 // and want to check for new text_edits in the completion too.
10153 let mut old_replace_start = None;
10154 let mut old_replace_end = None;
10155 let mut old_insert_start = None;
10156 let mut old_insert_end = None;
10157 let mut new_text = String::default();
10158 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10159 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10160 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10161 anyhow::Ok(buffer.read(cx).snapshot())
10162 })??;
10163
10164 if let Some(text_edit) = completion.text_edit.as_ref() {
10165 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10166
10167 if let Some(mut edit) = edit {
10168 LineEnding::normalize(&mut edit.new_text);
10169
10170 new_text = edit.new_text;
10171 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10172 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10173 if let Some(insert_range) = edit.insert_range {
10174 old_insert_start = Some(serialize_anchor(&insert_range.start));
10175 old_insert_end = Some(serialize_anchor(&insert_range.end));
10176 }
10177 }
10178 }
10179 }
10180
10181 Ok(proto::ResolveCompletionDocumentationResponse {
10182 documentation,
10183 documentation_is_markdown,
10184 old_replace_start,
10185 old_replace_end,
10186 new_text,
10187 lsp_completion,
10188 old_insert_start,
10189 old_insert_end,
10190 })
10191 }
10192
10193 async fn handle_on_type_formatting(
10194 this: Entity<Self>,
10195 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10196 mut cx: AsyncApp,
10197 ) -> Result<proto::OnTypeFormattingResponse> {
10198 let on_type_formatting = this.update(&mut cx, |this, cx| {
10199 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10200 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10201 let position = envelope
10202 .payload
10203 .position
10204 .and_then(deserialize_anchor)
10205 .context("invalid position")?;
10206 anyhow::Ok(this.apply_on_type_formatting(
10207 buffer,
10208 position,
10209 envelope.payload.trigger.clone(),
10210 cx,
10211 ))
10212 })??;
10213
10214 let transaction = on_type_formatting
10215 .await?
10216 .as_ref()
10217 .map(language::proto::serialize_transaction);
10218 Ok(proto::OnTypeFormattingResponse { transaction })
10219 }
10220
10221 async fn handle_refresh_inlay_hints(
10222 lsp_store: Entity<Self>,
10223 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10224 mut cx: AsyncApp,
10225 ) -> Result<proto::Ack> {
10226 lsp_store.update(&mut cx, |_, cx| {
10227 cx.emit(LspStoreEvent::RefreshInlayHints {
10228 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10229 request_id: envelope.payload.request_id.map(|id| id as usize),
10230 });
10231 })?;
10232 Ok(proto::Ack {})
10233 }
10234
10235 async fn handle_pull_workspace_diagnostics(
10236 lsp_store: Entity<Self>,
10237 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10238 mut cx: AsyncApp,
10239 ) -> Result<proto::Ack> {
10240 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10241 lsp_store.update(&mut cx, |lsp_store, _| {
10242 lsp_store.pull_workspace_diagnostics(server_id);
10243 })?;
10244 Ok(proto::Ack {})
10245 }
10246
10247 async fn handle_get_color_presentation(
10248 lsp_store: Entity<Self>,
10249 envelope: TypedEnvelope<proto::GetColorPresentation>,
10250 mut cx: AsyncApp,
10251 ) -> Result<proto::GetColorPresentationResponse> {
10252 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10253 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10254 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10255 })??;
10256
10257 let color = envelope
10258 .payload
10259 .color
10260 .context("invalid color resolve request")?;
10261 let start = color
10262 .lsp_range_start
10263 .context("invalid color resolve request")?;
10264 let end = color
10265 .lsp_range_end
10266 .context("invalid color resolve request")?;
10267
10268 let color = DocumentColor {
10269 lsp_range: lsp::Range {
10270 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10271 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10272 },
10273 color: lsp::Color {
10274 red: color.red,
10275 green: color.green,
10276 blue: color.blue,
10277 alpha: color.alpha,
10278 },
10279 resolved: false,
10280 color_presentations: Vec::new(),
10281 };
10282 let resolved_color = lsp_store
10283 .update(&mut cx, |lsp_store, cx| {
10284 lsp_store.resolve_color_presentation(
10285 color,
10286 buffer.clone(),
10287 LanguageServerId(envelope.payload.server_id as usize),
10288 cx,
10289 )
10290 })?
10291 .await
10292 .context("resolving color presentation")?;
10293
10294 Ok(proto::GetColorPresentationResponse {
10295 presentations: resolved_color
10296 .color_presentations
10297 .into_iter()
10298 .map(|presentation| proto::ColorPresentation {
10299 label: presentation.label.to_string(),
10300 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10301 additional_text_edits: presentation
10302 .additional_text_edits
10303 .into_iter()
10304 .map(serialize_lsp_edit)
10305 .collect(),
10306 })
10307 .collect(),
10308 })
10309 }
10310
10311 async fn handle_resolve_inlay_hint(
10312 lsp_store: Entity<Self>,
10313 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10314 mut cx: AsyncApp,
10315 ) -> Result<proto::ResolveInlayHintResponse> {
10316 let proto_hint = envelope
10317 .payload
10318 .hint
10319 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10320 let hint = InlayHints::proto_to_project_hint(proto_hint)
10321 .context("resolved proto inlay hint conversion")?;
10322 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10323 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10324 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10325 })??;
10326 let response_hint = lsp_store
10327 .update(&mut cx, |lsp_store, cx| {
10328 lsp_store.resolve_inlay_hint(
10329 hint,
10330 buffer,
10331 LanguageServerId(envelope.payload.language_server_id as usize),
10332 cx,
10333 )
10334 })?
10335 .await
10336 .context("inlay hints fetch")?;
10337 Ok(proto::ResolveInlayHintResponse {
10338 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10339 })
10340 }
10341
10342 async fn handle_refresh_code_lens(
10343 this: Entity<Self>,
10344 _: TypedEnvelope<proto::RefreshCodeLens>,
10345 mut cx: AsyncApp,
10346 ) -> Result<proto::Ack> {
10347 this.update(&mut cx, |_, cx| {
10348 cx.emit(LspStoreEvent::RefreshCodeLens);
10349 })?;
10350 Ok(proto::Ack {})
10351 }
10352
10353 async fn handle_open_buffer_for_symbol(
10354 this: Entity<Self>,
10355 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10356 mut cx: AsyncApp,
10357 ) -> Result<proto::OpenBufferForSymbolResponse> {
10358 let peer_id = envelope.original_sender_id().unwrap_or_default();
10359 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10360 let symbol = Self::deserialize_symbol(symbol)?;
10361 this.read_with(&cx, |this, _| {
10362 if let SymbolLocation::OutsideProject {
10363 abs_path,
10364 signature,
10365 } = &symbol.path
10366 {
10367 let new_signature = this.symbol_signature(&abs_path);
10368 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10369 }
10370 Ok(())
10371 })??;
10372 let buffer = this
10373 .update(&mut cx, |this, cx| {
10374 this.open_buffer_for_symbol(
10375 &Symbol {
10376 language_server_name: symbol.language_server_name,
10377 source_worktree_id: symbol.source_worktree_id,
10378 source_language_server_id: symbol.source_language_server_id,
10379 path: symbol.path,
10380 name: symbol.name,
10381 kind: symbol.kind,
10382 range: symbol.range,
10383 label: CodeLabel::default(),
10384 },
10385 cx,
10386 )
10387 })?
10388 .await?;
10389
10390 this.update(&mut cx, |this, cx| {
10391 let is_private = buffer
10392 .read(cx)
10393 .file()
10394 .map(|f| f.is_private())
10395 .unwrap_or_default();
10396 if is_private {
10397 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10398 } else {
10399 this.buffer_store
10400 .update(cx, |buffer_store, cx| {
10401 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10402 })
10403 .detach_and_log_err(cx);
10404 let buffer_id = buffer.read(cx).remote_id().to_proto();
10405 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10406 }
10407 })?
10408 }
10409
10410 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10411 let mut hasher = Sha256::new();
10412 hasher.update(abs_path.to_string_lossy().as_bytes());
10413 hasher.update(self.nonce.to_be_bytes());
10414 hasher.finalize().as_slice().try_into().unwrap()
10415 }
10416
10417 pub async fn handle_get_project_symbols(
10418 this: Entity<Self>,
10419 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10420 mut cx: AsyncApp,
10421 ) -> Result<proto::GetProjectSymbolsResponse> {
10422 let symbols = this
10423 .update(&mut cx, |this, cx| {
10424 this.symbols(&envelope.payload.query, cx)
10425 })?
10426 .await?;
10427
10428 Ok(proto::GetProjectSymbolsResponse {
10429 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10430 })
10431 }
10432
10433 pub async fn handle_restart_language_servers(
10434 this: Entity<Self>,
10435 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10436 mut cx: AsyncApp,
10437 ) -> Result<proto::Ack> {
10438 this.update(&mut cx, |lsp_store, cx| {
10439 let buffers =
10440 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10441 lsp_store.restart_language_servers_for_buffers(
10442 buffers,
10443 envelope
10444 .payload
10445 .only_servers
10446 .into_iter()
10447 .filter_map(|selector| {
10448 Some(match selector.selector? {
10449 proto::language_server_selector::Selector::ServerId(server_id) => {
10450 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10451 }
10452 proto::language_server_selector::Selector::Name(name) => {
10453 LanguageServerSelector::Name(LanguageServerName(
10454 SharedString::from(name),
10455 ))
10456 }
10457 })
10458 })
10459 .collect(),
10460 cx,
10461 );
10462 })?;
10463
10464 Ok(proto::Ack {})
10465 }
10466
10467 pub async fn handle_stop_language_servers(
10468 lsp_store: Entity<Self>,
10469 envelope: TypedEnvelope<proto::StopLanguageServers>,
10470 mut cx: AsyncApp,
10471 ) -> Result<proto::Ack> {
10472 lsp_store.update(&mut cx, |lsp_store, cx| {
10473 if envelope.payload.all
10474 && envelope.payload.also_servers.is_empty()
10475 && envelope.payload.buffer_ids.is_empty()
10476 {
10477 lsp_store.stop_all_language_servers(cx);
10478 } else {
10479 let buffers =
10480 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10481 lsp_store
10482 .stop_language_servers_for_buffers(
10483 buffers,
10484 envelope
10485 .payload
10486 .also_servers
10487 .into_iter()
10488 .filter_map(|selector| {
10489 Some(match selector.selector? {
10490 proto::language_server_selector::Selector::ServerId(
10491 server_id,
10492 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10493 server_id,
10494 )),
10495 proto::language_server_selector::Selector::Name(name) => {
10496 LanguageServerSelector::Name(LanguageServerName(
10497 SharedString::from(name),
10498 ))
10499 }
10500 })
10501 })
10502 .collect(),
10503 cx,
10504 )
10505 .detach_and_log_err(cx);
10506 }
10507 })?;
10508
10509 Ok(proto::Ack {})
10510 }
10511
10512 pub async fn handle_cancel_language_server_work(
10513 lsp_store: Entity<Self>,
10514 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10515 mut cx: AsyncApp,
10516 ) -> Result<proto::Ack> {
10517 lsp_store.update(&mut cx, |lsp_store, cx| {
10518 if let Some(work) = envelope.payload.work {
10519 match work {
10520 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10521 let buffers =
10522 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10523 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10524 }
10525 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10526 let server_id = LanguageServerId::from_proto(work.language_server_id);
10527 let token = work
10528 .token
10529 .map(|token| {
10530 ProgressToken::from_proto(token)
10531 .context("invalid work progress token")
10532 })
10533 .transpose()?;
10534 lsp_store.cancel_language_server_work(server_id, token, cx);
10535 }
10536 }
10537 }
10538 anyhow::Ok(())
10539 })??;
10540
10541 Ok(proto::Ack {})
10542 }
10543
10544 fn buffer_ids_to_buffers(
10545 &mut self,
10546 buffer_ids: impl Iterator<Item = u64>,
10547 cx: &mut Context<Self>,
10548 ) -> Vec<Entity<Buffer>> {
10549 buffer_ids
10550 .into_iter()
10551 .flat_map(|buffer_id| {
10552 self.buffer_store
10553 .read(cx)
10554 .get(BufferId::new(buffer_id).log_err()?)
10555 })
10556 .collect::<Vec<_>>()
10557 }
10558
10559 async fn handle_apply_additional_edits_for_completion(
10560 this: Entity<Self>,
10561 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10562 mut cx: AsyncApp,
10563 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10564 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10565 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10566 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10567 let completion = Self::deserialize_completion(
10568 envelope.payload.completion.context("invalid completion")?,
10569 )?;
10570 anyhow::Ok((buffer, completion))
10571 })??;
10572
10573 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10574 this.apply_additional_edits_for_completion(
10575 buffer,
10576 Rc::new(RefCell::new(Box::new([Completion {
10577 replace_range: completion.replace_range,
10578 new_text: completion.new_text,
10579 source: completion.source,
10580 documentation: None,
10581 label: CodeLabel::default(),
10582 match_start: None,
10583 snippet_deduplication_key: None,
10584 insert_text_mode: None,
10585 icon_path: None,
10586 confirm: None,
10587 }]))),
10588 0,
10589 false,
10590 cx,
10591 )
10592 })?;
10593
10594 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10595 transaction: apply_additional_edits
10596 .await?
10597 .as_ref()
10598 .map(language::proto::serialize_transaction),
10599 })
10600 }
10601
10602 pub fn last_formatting_failure(&self) -> Option<&str> {
10603 self.last_formatting_failure.as_deref()
10604 }
10605
10606 pub fn reset_last_formatting_failure(&mut self) {
10607 self.last_formatting_failure = None;
10608 }
10609
10610 pub fn environment_for_buffer(
10611 &self,
10612 buffer: &Entity<Buffer>,
10613 cx: &mut Context<Self>,
10614 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10615 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10616 environment.update(cx, |env, cx| {
10617 env.buffer_environment(buffer, &self.worktree_store, cx)
10618 })
10619 } else {
10620 Task::ready(None).shared()
10621 }
10622 }
10623
10624 pub fn format(
10625 &mut self,
10626 buffers: HashSet<Entity<Buffer>>,
10627 target: LspFormatTarget,
10628 push_to_history: bool,
10629 trigger: FormatTrigger,
10630 cx: &mut Context<Self>,
10631 ) -> Task<anyhow::Result<ProjectTransaction>> {
10632 let logger = zlog::scoped!("format");
10633 if self.as_local().is_some() {
10634 zlog::trace!(logger => "Formatting locally");
10635 let logger = zlog::scoped!(logger => "local");
10636 let buffers = buffers
10637 .into_iter()
10638 .map(|buffer_handle| {
10639 let buffer = buffer_handle.read(cx);
10640 let buffer_abs_path = File::from_dyn(buffer.file())
10641 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10642
10643 (buffer_handle, buffer_abs_path, buffer.remote_id())
10644 })
10645 .collect::<Vec<_>>();
10646
10647 cx.spawn(async move |lsp_store, cx| {
10648 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10649
10650 for (handle, abs_path, id) in buffers {
10651 let env = lsp_store
10652 .update(cx, |lsp_store, cx| {
10653 lsp_store.environment_for_buffer(&handle, cx)
10654 })?
10655 .await;
10656
10657 let ranges = match &target {
10658 LspFormatTarget::Buffers => None,
10659 LspFormatTarget::Ranges(ranges) => {
10660 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10661 }
10662 };
10663
10664 formattable_buffers.push(FormattableBuffer {
10665 handle,
10666 abs_path,
10667 env,
10668 ranges,
10669 });
10670 }
10671 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10672
10673 let format_timer = zlog::time!(logger => "Formatting buffers");
10674 let result = LocalLspStore::format_locally(
10675 lsp_store.clone(),
10676 formattable_buffers,
10677 push_to_history,
10678 trigger,
10679 logger,
10680 cx,
10681 )
10682 .await;
10683 format_timer.end();
10684
10685 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10686
10687 lsp_store.update(cx, |lsp_store, _| {
10688 lsp_store.update_last_formatting_failure(&result);
10689 })?;
10690
10691 result
10692 })
10693 } else if let Some((client, project_id)) = self.upstream_client() {
10694 zlog::trace!(logger => "Formatting remotely");
10695 let logger = zlog::scoped!(logger => "remote");
10696 // Don't support formatting ranges via remote
10697 match target {
10698 LspFormatTarget::Buffers => {}
10699 LspFormatTarget::Ranges(_) => {
10700 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10701 return Task::ready(Ok(ProjectTransaction::default()));
10702 }
10703 }
10704
10705 let buffer_store = self.buffer_store();
10706 cx.spawn(async move |lsp_store, cx| {
10707 zlog::trace!(logger => "Sending remote format request");
10708 let request_timer = zlog::time!(logger => "remote format request");
10709 let result = client
10710 .request(proto::FormatBuffers {
10711 project_id,
10712 trigger: trigger as i32,
10713 buffer_ids: buffers
10714 .iter()
10715 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10716 .collect::<Result<_>>()?,
10717 })
10718 .await
10719 .and_then(|result| result.transaction.context("missing transaction"));
10720 request_timer.end();
10721
10722 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10723
10724 lsp_store.update(cx, |lsp_store, _| {
10725 lsp_store.update_last_formatting_failure(&result);
10726 })?;
10727
10728 let transaction_response = result?;
10729 let _timer = zlog::time!(logger => "deserializing project transaction");
10730 buffer_store
10731 .update(cx, |buffer_store, cx| {
10732 buffer_store.deserialize_project_transaction(
10733 transaction_response,
10734 push_to_history,
10735 cx,
10736 )
10737 })?
10738 .await
10739 })
10740 } else {
10741 zlog::trace!(logger => "Not formatting");
10742 Task::ready(Ok(ProjectTransaction::default()))
10743 }
10744 }
10745
10746 async fn handle_format_buffers(
10747 this: Entity<Self>,
10748 envelope: TypedEnvelope<proto::FormatBuffers>,
10749 mut cx: AsyncApp,
10750 ) -> Result<proto::FormatBuffersResponse> {
10751 let sender_id = envelope.original_sender_id().unwrap_or_default();
10752 let format = this.update(&mut cx, |this, cx| {
10753 let mut buffers = HashSet::default();
10754 for buffer_id in &envelope.payload.buffer_ids {
10755 let buffer_id = BufferId::new(*buffer_id)?;
10756 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10757 }
10758 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10759 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10760 })??;
10761
10762 let project_transaction = format.await?;
10763 let project_transaction = this.update(&mut cx, |this, cx| {
10764 this.buffer_store.update(cx, |buffer_store, cx| {
10765 buffer_store.serialize_project_transaction_for_peer(
10766 project_transaction,
10767 sender_id,
10768 cx,
10769 )
10770 })
10771 })?;
10772 Ok(proto::FormatBuffersResponse {
10773 transaction: Some(project_transaction),
10774 })
10775 }
10776
10777 async fn handle_apply_code_action_kind(
10778 this: Entity<Self>,
10779 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10780 mut cx: AsyncApp,
10781 ) -> Result<proto::ApplyCodeActionKindResponse> {
10782 let sender_id = envelope.original_sender_id().unwrap_or_default();
10783 let format = this.update(&mut cx, |this, cx| {
10784 let mut buffers = HashSet::default();
10785 for buffer_id in &envelope.payload.buffer_ids {
10786 let buffer_id = BufferId::new(*buffer_id)?;
10787 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10788 }
10789 let kind = match envelope.payload.kind.as_str() {
10790 "" => CodeActionKind::EMPTY,
10791 "quickfix" => CodeActionKind::QUICKFIX,
10792 "refactor" => CodeActionKind::REFACTOR,
10793 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10794 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10795 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10796 "source" => CodeActionKind::SOURCE,
10797 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10798 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10799 _ => anyhow::bail!(
10800 "Invalid code action kind {}",
10801 envelope.payload.kind.as_str()
10802 ),
10803 };
10804 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10805 })??;
10806
10807 let project_transaction = format.await?;
10808 let project_transaction = this.update(&mut cx, |this, cx| {
10809 this.buffer_store.update(cx, |buffer_store, cx| {
10810 buffer_store.serialize_project_transaction_for_peer(
10811 project_transaction,
10812 sender_id,
10813 cx,
10814 )
10815 })
10816 })?;
10817 Ok(proto::ApplyCodeActionKindResponse {
10818 transaction: Some(project_transaction),
10819 })
10820 }
10821
10822 async fn shutdown_language_server(
10823 server_state: Option<LanguageServerState>,
10824 name: LanguageServerName,
10825 cx: &mut AsyncApp,
10826 ) {
10827 let server = match server_state {
10828 Some(LanguageServerState::Starting { startup, .. }) => {
10829 let mut timer = cx
10830 .background_executor()
10831 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10832 .fuse();
10833
10834 select! {
10835 server = startup.fuse() => server,
10836 () = timer => {
10837 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10838 None
10839 },
10840 }
10841 }
10842
10843 Some(LanguageServerState::Running { server, .. }) => Some(server),
10844
10845 None => None,
10846 };
10847
10848 if let Some(server) = server
10849 && let Some(shutdown) = server.shutdown()
10850 {
10851 shutdown.await;
10852 }
10853 }
10854
10855 // Returns a list of all of the worktrees which no longer have a language server and the root path
10856 // for the stopped server
10857 fn stop_local_language_server(
10858 &mut self,
10859 server_id: LanguageServerId,
10860 cx: &mut Context<Self>,
10861 ) -> Task<()> {
10862 let local = match &mut self.mode {
10863 LspStoreMode::Local(local) => local,
10864 _ => {
10865 return Task::ready(());
10866 }
10867 };
10868
10869 // Remove this server ID from all entries in the given worktree.
10870 local
10871 .language_server_ids
10872 .retain(|_, state| state.id != server_id);
10873 self.buffer_store.update(cx, |buffer_store, cx| {
10874 for buffer in buffer_store.buffers() {
10875 buffer.update(cx, |buffer, cx| {
10876 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10877 buffer.set_completion_triggers(server_id, Default::default(), cx);
10878 });
10879 }
10880 });
10881
10882 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10883 summaries.retain(|path, summaries_by_server_id| {
10884 if summaries_by_server_id.remove(&server_id).is_some() {
10885 if let Some((client, project_id)) = self.downstream_client.clone() {
10886 client
10887 .send(proto::UpdateDiagnosticSummary {
10888 project_id,
10889 worktree_id: worktree_id.to_proto(),
10890 summary: Some(proto::DiagnosticSummary {
10891 path: path.as_ref().to_proto(),
10892 language_server_id: server_id.0 as u64,
10893 error_count: 0,
10894 warning_count: 0,
10895 }),
10896 more_summaries: Vec::new(),
10897 })
10898 .log_err();
10899 }
10900 !summaries_by_server_id.is_empty()
10901 } else {
10902 true
10903 }
10904 });
10905 }
10906
10907 let local = self.as_local_mut().unwrap();
10908 for diagnostics in local.diagnostics.values_mut() {
10909 diagnostics.retain(|_, diagnostics_by_server_id| {
10910 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10911 diagnostics_by_server_id.remove(ix);
10912 !diagnostics_by_server_id.is_empty()
10913 } else {
10914 true
10915 }
10916 });
10917 }
10918 local.language_server_watched_paths.remove(&server_id);
10919
10920 let server_state = local.language_servers.remove(&server_id);
10921 self.cleanup_lsp_data(server_id);
10922 let name = self
10923 .language_server_statuses
10924 .remove(&server_id)
10925 .map(|status| status.name)
10926 .or_else(|| {
10927 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10928 Some(adapter.name())
10929 } else {
10930 None
10931 }
10932 });
10933
10934 if let Some(name) = name {
10935 log::info!("stopping language server {name}");
10936 self.languages
10937 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10938 cx.notify();
10939
10940 return cx.spawn(async move |lsp_store, cx| {
10941 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10942 lsp_store
10943 .update(cx, |lsp_store, cx| {
10944 lsp_store
10945 .languages
10946 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10947 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10948 cx.notify();
10949 })
10950 .ok();
10951 });
10952 }
10953
10954 if server_state.is_some() {
10955 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10956 }
10957 Task::ready(())
10958 }
10959
10960 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10961 if let Some((client, project_id)) = self.upstream_client() {
10962 let request = client.request(proto::StopLanguageServers {
10963 project_id,
10964 buffer_ids: Vec::new(),
10965 also_servers: Vec::new(),
10966 all: true,
10967 });
10968 cx.background_spawn(request).detach_and_log_err(cx);
10969 } else {
10970 let Some(local) = self.as_local_mut() else {
10971 return;
10972 };
10973 let language_servers_to_stop = local
10974 .language_server_ids
10975 .values()
10976 .map(|state| state.id)
10977 .collect();
10978 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10979 let tasks = language_servers_to_stop
10980 .into_iter()
10981 .map(|server| self.stop_local_language_server(server, cx))
10982 .collect::<Vec<_>>();
10983 cx.background_spawn(async move {
10984 futures::future::join_all(tasks).await;
10985 })
10986 .detach();
10987 }
10988 }
10989
10990 pub fn restart_language_servers_for_buffers(
10991 &mut self,
10992 buffers: Vec<Entity<Buffer>>,
10993 only_restart_servers: HashSet<LanguageServerSelector>,
10994 cx: &mut Context<Self>,
10995 ) {
10996 if let Some((client, project_id)) = self.upstream_client() {
10997 let request = client.request(proto::RestartLanguageServers {
10998 project_id,
10999 buffer_ids: buffers
11000 .into_iter()
11001 .map(|b| b.read(cx).remote_id().to_proto())
11002 .collect(),
11003 only_servers: only_restart_servers
11004 .into_iter()
11005 .map(|selector| {
11006 let selector = match selector {
11007 LanguageServerSelector::Id(language_server_id) => {
11008 proto::language_server_selector::Selector::ServerId(
11009 language_server_id.to_proto(),
11010 )
11011 }
11012 LanguageServerSelector::Name(language_server_name) => {
11013 proto::language_server_selector::Selector::Name(
11014 language_server_name.to_string(),
11015 )
11016 }
11017 };
11018 proto::LanguageServerSelector {
11019 selector: Some(selector),
11020 }
11021 })
11022 .collect(),
11023 all: false,
11024 });
11025 cx.background_spawn(request).detach_and_log_err(cx);
11026 } else {
11027 let stop_task = if only_restart_servers.is_empty() {
11028 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11029 } else {
11030 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11031 };
11032 cx.spawn(async move |lsp_store, cx| {
11033 stop_task.await;
11034 lsp_store
11035 .update(cx, |lsp_store, cx| {
11036 for buffer in buffers {
11037 lsp_store.register_buffer_with_language_servers(
11038 &buffer,
11039 only_restart_servers.clone(),
11040 true,
11041 cx,
11042 );
11043 }
11044 })
11045 .ok()
11046 })
11047 .detach();
11048 }
11049 }
11050
11051 pub fn stop_language_servers_for_buffers(
11052 &mut self,
11053 buffers: Vec<Entity<Buffer>>,
11054 also_stop_servers: HashSet<LanguageServerSelector>,
11055 cx: &mut Context<Self>,
11056 ) -> Task<Result<()>> {
11057 if let Some((client, project_id)) = self.upstream_client() {
11058 let request = client.request(proto::StopLanguageServers {
11059 project_id,
11060 buffer_ids: buffers
11061 .into_iter()
11062 .map(|b| b.read(cx).remote_id().to_proto())
11063 .collect(),
11064 also_servers: also_stop_servers
11065 .into_iter()
11066 .map(|selector| {
11067 let selector = match selector {
11068 LanguageServerSelector::Id(language_server_id) => {
11069 proto::language_server_selector::Selector::ServerId(
11070 language_server_id.to_proto(),
11071 )
11072 }
11073 LanguageServerSelector::Name(language_server_name) => {
11074 proto::language_server_selector::Selector::Name(
11075 language_server_name.to_string(),
11076 )
11077 }
11078 };
11079 proto::LanguageServerSelector {
11080 selector: Some(selector),
11081 }
11082 })
11083 .collect(),
11084 all: false,
11085 });
11086 cx.background_spawn(async move {
11087 let _ = request.await?;
11088 Ok(())
11089 })
11090 } else {
11091 let task =
11092 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11093 cx.background_spawn(async move {
11094 task.await;
11095 Ok(())
11096 })
11097 }
11098 }
11099
11100 fn stop_local_language_servers_for_buffers(
11101 &mut self,
11102 buffers: &[Entity<Buffer>],
11103 also_stop_servers: HashSet<LanguageServerSelector>,
11104 cx: &mut Context<Self>,
11105 ) -> Task<()> {
11106 let Some(local) = self.as_local_mut() else {
11107 return Task::ready(());
11108 };
11109 let mut language_server_names_to_stop = BTreeSet::default();
11110 let mut language_servers_to_stop = also_stop_servers
11111 .into_iter()
11112 .flat_map(|selector| match selector {
11113 LanguageServerSelector::Id(id) => Some(id),
11114 LanguageServerSelector::Name(name) => {
11115 language_server_names_to_stop.insert(name);
11116 None
11117 }
11118 })
11119 .collect::<BTreeSet<_>>();
11120
11121 let mut covered_worktrees = HashSet::default();
11122 for buffer in buffers {
11123 buffer.update(cx, |buffer, cx| {
11124 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11125 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11126 && covered_worktrees.insert(worktree_id)
11127 {
11128 language_server_names_to_stop.retain(|name| {
11129 let old_ids_count = language_servers_to_stop.len();
11130 let all_language_servers_with_this_name = local
11131 .language_server_ids
11132 .iter()
11133 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11134 language_servers_to_stop.extend(all_language_servers_with_this_name);
11135 old_ids_count == language_servers_to_stop.len()
11136 });
11137 }
11138 });
11139 }
11140 for name in language_server_names_to_stop {
11141 language_servers_to_stop.extend(
11142 local
11143 .language_server_ids
11144 .iter()
11145 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11146 );
11147 }
11148
11149 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11150 let tasks = language_servers_to_stop
11151 .into_iter()
11152 .map(|server| self.stop_local_language_server(server, cx))
11153 .collect::<Vec<_>>();
11154
11155 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11156 }
11157
11158 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11159 let (worktree, relative_path) =
11160 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11161
11162 let project_path = ProjectPath {
11163 worktree_id: worktree.read(cx).id(),
11164 path: relative_path,
11165 };
11166
11167 Some(
11168 self.buffer_store()
11169 .read(cx)
11170 .get_by_path(&project_path)?
11171 .read(cx),
11172 )
11173 }
11174
11175 #[cfg(any(test, feature = "test-support"))]
11176 pub fn update_diagnostics(
11177 &mut self,
11178 server_id: LanguageServerId,
11179 diagnostics: lsp::PublishDiagnosticsParams,
11180 result_id: Option<SharedString>,
11181 source_kind: DiagnosticSourceKind,
11182 disk_based_sources: &[String],
11183 cx: &mut Context<Self>,
11184 ) -> Result<()> {
11185 self.merge_lsp_diagnostics(
11186 source_kind,
11187 vec![DocumentDiagnosticsUpdate {
11188 diagnostics,
11189 result_id,
11190 server_id,
11191 disk_based_sources: Cow::Borrowed(disk_based_sources),
11192 registration_id: None,
11193 }],
11194 |_, _, _| false,
11195 cx,
11196 )
11197 }
11198
11199 pub fn merge_lsp_diagnostics(
11200 &mut self,
11201 source_kind: DiagnosticSourceKind,
11202 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11203 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11204 cx: &mut Context<Self>,
11205 ) -> Result<()> {
11206 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11207 let updates = lsp_diagnostics
11208 .into_iter()
11209 .filter_map(|update| {
11210 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11211 Some(DocumentDiagnosticsUpdate {
11212 diagnostics: self.lsp_to_document_diagnostics(
11213 abs_path,
11214 source_kind,
11215 update.server_id,
11216 update.diagnostics,
11217 &update.disk_based_sources,
11218 update.registration_id.clone(),
11219 ),
11220 result_id: update.result_id,
11221 server_id: update.server_id,
11222 disk_based_sources: update.disk_based_sources,
11223 registration_id: update.registration_id,
11224 })
11225 })
11226 .collect();
11227 self.merge_diagnostic_entries(updates, merge, cx)?;
11228 Ok(())
11229 }
11230
11231 fn lsp_to_document_diagnostics(
11232 &mut self,
11233 document_abs_path: PathBuf,
11234 source_kind: DiagnosticSourceKind,
11235 server_id: LanguageServerId,
11236 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11237 disk_based_sources: &[String],
11238 registration_id: Option<SharedString>,
11239 ) -> DocumentDiagnostics {
11240 let mut diagnostics = Vec::default();
11241 let mut primary_diagnostic_group_ids = HashMap::default();
11242 let mut sources_by_group_id = HashMap::default();
11243 let mut supporting_diagnostics = HashMap::default();
11244
11245 let adapter = self.language_server_adapter_for_id(server_id);
11246
11247 // Ensure that primary diagnostics are always the most severe
11248 lsp_diagnostics
11249 .diagnostics
11250 .sort_by_key(|item| item.severity);
11251
11252 for diagnostic in &lsp_diagnostics.diagnostics {
11253 let source = diagnostic.source.as_ref();
11254 let range = range_from_lsp(diagnostic.range);
11255 let is_supporting = diagnostic
11256 .related_information
11257 .as_ref()
11258 .is_some_and(|infos| {
11259 infos.iter().any(|info| {
11260 primary_diagnostic_group_ids.contains_key(&(
11261 source,
11262 diagnostic.code.clone(),
11263 range_from_lsp(info.location.range),
11264 ))
11265 })
11266 });
11267
11268 let is_unnecessary = diagnostic
11269 .tags
11270 .as_ref()
11271 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11272
11273 let underline = self
11274 .language_server_adapter_for_id(server_id)
11275 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11276
11277 if is_supporting {
11278 supporting_diagnostics.insert(
11279 (source, diagnostic.code.clone(), range),
11280 (diagnostic.severity, is_unnecessary),
11281 );
11282 } else {
11283 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11284 let is_disk_based =
11285 source.is_some_and(|source| disk_based_sources.contains(source));
11286
11287 sources_by_group_id.insert(group_id, source);
11288 primary_diagnostic_group_ids
11289 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11290
11291 diagnostics.push(DiagnosticEntry {
11292 range,
11293 diagnostic: Diagnostic {
11294 source: diagnostic.source.clone(),
11295 source_kind,
11296 code: diagnostic.code.clone(),
11297 code_description: diagnostic
11298 .code_description
11299 .as_ref()
11300 .and_then(|d| d.href.clone()),
11301 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11302 markdown: adapter.as_ref().and_then(|adapter| {
11303 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11304 }),
11305 message: diagnostic.message.trim().to_string(),
11306 group_id,
11307 is_primary: true,
11308 is_disk_based,
11309 is_unnecessary,
11310 underline,
11311 data: diagnostic.data.clone(),
11312 registration_id: registration_id.clone(),
11313 },
11314 });
11315 if let Some(infos) = &diagnostic.related_information {
11316 for info in infos {
11317 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11318 let range = range_from_lsp(info.location.range);
11319 diagnostics.push(DiagnosticEntry {
11320 range,
11321 diagnostic: Diagnostic {
11322 source: diagnostic.source.clone(),
11323 source_kind,
11324 code: diagnostic.code.clone(),
11325 code_description: diagnostic
11326 .code_description
11327 .as_ref()
11328 .and_then(|d| d.href.clone()),
11329 severity: DiagnosticSeverity::INFORMATION,
11330 markdown: adapter.as_ref().and_then(|adapter| {
11331 adapter.diagnostic_message_to_markdown(&info.message)
11332 }),
11333 message: info.message.trim().to_string(),
11334 group_id,
11335 is_primary: false,
11336 is_disk_based,
11337 is_unnecessary: false,
11338 underline,
11339 data: diagnostic.data.clone(),
11340 registration_id: registration_id.clone(),
11341 },
11342 });
11343 }
11344 }
11345 }
11346 }
11347 }
11348
11349 for entry in &mut diagnostics {
11350 let diagnostic = &mut entry.diagnostic;
11351 if !diagnostic.is_primary {
11352 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11353 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11354 source,
11355 diagnostic.code.clone(),
11356 entry.range.clone(),
11357 )) {
11358 if let Some(severity) = severity {
11359 diagnostic.severity = severity;
11360 }
11361 diagnostic.is_unnecessary = is_unnecessary;
11362 }
11363 }
11364 }
11365
11366 DocumentDiagnostics {
11367 diagnostics,
11368 document_abs_path,
11369 version: lsp_diagnostics.version,
11370 }
11371 }
11372
11373 fn insert_newly_running_language_server(
11374 &mut self,
11375 adapter: Arc<CachedLspAdapter>,
11376 language_server: Arc<LanguageServer>,
11377 server_id: LanguageServerId,
11378 key: LanguageServerSeed,
11379 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11380 cx: &mut Context<Self>,
11381 ) {
11382 let Some(local) = self.as_local_mut() else {
11383 return;
11384 };
11385 // If the language server for this key doesn't match the server id, don't store the
11386 // server. Which will cause it to be dropped, killing the process
11387 if local
11388 .language_server_ids
11389 .get(&key)
11390 .map(|state| state.id != server_id)
11391 .unwrap_or(false)
11392 {
11393 return;
11394 }
11395
11396 // Update language_servers collection with Running variant of LanguageServerState
11397 // indicating that the server is up and running and ready
11398 let workspace_folders = workspace_folders.lock().clone();
11399 language_server.set_workspace_folders(workspace_folders);
11400
11401 let workspace_diagnostics_refresh_tasks = language_server
11402 .capabilities()
11403 .diagnostic_provider
11404 .and_then(|provider| {
11405 local
11406 .language_server_dynamic_registrations
11407 .entry(server_id)
11408 .or_default()
11409 .diagnostics
11410 .entry(None)
11411 .or_insert(provider.clone());
11412 let workspace_refresher =
11413 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11414
11415 Some((None, workspace_refresher))
11416 })
11417 .into_iter()
11418 .collect();
11419 local.language_servers.insert(
11420 server_id,
11421 LanguageServerState::Running {
11422 workspace_diagnostics_refresh_tasks,
11423 adapter: adapter.clone(),
11424 server: language_server.clone(),
11425 simulate_disk_based_diagnostics_completion: None,
11426 },
11427 );
11428 local
11429 .languages
11430 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11431 if let Some(file_ops_caps) = language_server
11432 .capabilities()
11433 .workspace
11434 .as_ref()
11435 .and_then(|ws| ws.file_operations.as_ref())
11436 {
11437 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11438 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11439 if did_rename_caps.or(will_rename_caps).is_some() {
11440 let watcher = RenamePathsWatchedForServer::default()
11441 .with_did_rename_patterns(did_rename_caps)
11442 .with_will_rename_patterns(will_rename_caps);
11443 local
11444 .language_server_paths_watched_for_rename
11445 .insert(server_id, watcher);
11446 }
11447 }
11448
11449 self.language_server_statuses.insert(
11450 server_id,
11451 LanguageServerStatus {
11452 name: language_server.name(),
11453 server_version: language_server.version(),
11454 pending_work: Default::default(),
11455 has_pending_diagnostic_updates: false,
11456 progress_tokens: Default::default(),
11457 worktree: Some(key.worktree_id),
11458 binary: Some(language_server.binary().clone()),
11459 configuration: Some(language_server.configuration().clone()),
11460 workspace_folders: language_server.workspace_folders(),
11461 },
11462 );
11463
11464 cx.emit(LspStoreEvent::LanguageServerAdded(
11465 server_id,
11466 language_server.name(),
11467 Some(key.worktree_id),
11468 ));
11469
11470 let server_capabilities = language_server.capabilities();
11471 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11472 downstream_client
11473 .send(proto::StartLanguageServer {
11474 project_id: *project_id,
11475 server: Some(proto::LanguageServer {
11476 id: server_id.to_proto(),
11477 name: language_server.name().to_string(),
11478 worktree_id: Some(key.worktree_id.to_proto()),
11479 }),
11480 capabilities: serde_json::to_string(&server_capabilities)
11481 .expect("serializing server LSP capabilities"),
11482 })
11483 .log_err();
11484 }
11485 self.lsp_server_capabilities
11486 .insert(server_id, server_capabilities);
11487
11488 // Tell the language server about every open buffer in the worktree that matches the language.
11489 // Also check for buffers in worktrees that reused this server
11490 let mut worktrees_using_server = vec![key.worktree_id];
11491 if let Some(local) = self.as_local() {
11492 // Find all worktrees that have this server in their language server tree
11493 for (worktree_id, servers) in &local.lsp_tree.instances {
11494 if *worktree_id != key.worktree_id {
11495 for server_map in servers.roots.values() {
11496 if server_map
11497 .values()
11498 .any(|(node, _)| node.id() == Some(server_id))
11499 {
11500 worktrees_using_server.push(*worktree_id);
11501 }
11502 }
11503 }
11504 }
11505 }
11506
11507 let mut buffer_paths_registered = Vec::new();
11508 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11509 let mut lsp_adapters = HashMap::default();
11510 for buffer_handle in buffer_store.buffers() {
11511 let buffer = buffer_handle.read(cx);
11512 let file = match File::from_dyn(buffer.file()) {
11513 Some(file) => file,
11514 None => continue,
11515 };
11516 let language = match buffer.language() {
11517 Some(language) => language,
11518 None => continue,
11519 };
11520
11521 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11522 || !lsp_adapters
11523 .entry(language.name())
11524 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11525 .iter()
11526 .any(|a| a.name == key.name)
11527 {
11528 continue;
11529 }
11530 // didOpen
11531 let file = match file.as_local() {
11532 Some(file) => file,
11533 None => continue,
11534 };
11535
11536 let local = self.as_local_mut().unwrap();
11537
11538 let buffer_id = buffer.remote_id();
11539 if local.registered_buffers.contains_key(&buffer_id) {
11540 let versions = local
11541 .buffer_snapshots
11542 .entry(buffer_id)
11543 .or_default()
11544 .entry(server_id)
11545 .and_modify(|_| {
11546 assert!(
11547 false,
11548 "There should not be an existing snapshot for a newly inserted buffer"
11549 )
11550 })
11551 .or_insert_with(|| {
11552 vec![LspBufferSnapshot {
11553 version: 0,
11554 snapshot: buffer.text_snapshot(),
11555 }]
11556 });
11557
11558 let snapshot = versions.last().unwrap();
11559 let version = snapshot.version;
11560 let initial_snapshot = &snapshot.snapshot;
11561 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11562 language_server.register_buffer(
11563 uri,
11564 adapter.language_id(&language.name()),
11565 version,
11566 initial_snapshot.text(),
11567 );
11568 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11569 local
11570 .buffers_opened_in_servers
11571 .entry(buffer_id)
11572 .or_default()
11573 .insert(server_id);
11574 }
11575 buffer_handle.update(cx, |buffer, cx| {
11576 buffer.set_completion_triggers(
11577 server_id,
11578 language_server
11579 .capabilities()
11580 .completion_provider
11581 .as_ref()
11582 .and_then(|provider| {
11583 provider
11584 .trigger_characters
11585 .as_ref()
11586 .map(|characters| characters.iter().cloned().collect())
11587 })
11588 .unwrap_or_default(),
11589 cx,
11590 )
11591 });
11592 }
11593 });
11594
11595 for (buffer_id, abs_path) in buffer_paths_registered {
11596 cx.emit(LspStoreEvent::LanguageServerUpdate {
11597 language_server_id: server_id,
11598 name: Some(adapter.name()),
11599 message: proto::update_language_server::Variant::RegisteredForBuffer(
11600 proto::RegisteredForBuffer {
11601 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11602 buffer_id: buffer_id.to_proto(),
11603 },
11604 ),
11605 });
11606 }
11607
11608 cx.notify();
11609 }
11610
11611 pub fn language_servers_running_disk_based_diagnostics(
11612 &self,
11613 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11614 self.language_server_statuses
11615 .iter()
11616 .filter_map(|(id, status)| {
11617 if status.has_pending_diagnostic_updates {
11618 Some(*id)
11619 } else {
11620 None
11621 }
11622 })
11623 }
11624
11625 pub(crate) fn cancel_language_server_work_for_buffers(
11626 &mut self,
11627 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11628 cx: &mut Context<Self>,
11629 ) {
11630 if let Some((client, project_id)) = self.upstream_client() {
11631 let request = client.request(proto::CancelLanguageServerWork {
11632 project_id,
11633 work: Some(proto::cancel_language_server_work::Work::Buffers(
11634 proto::cancel_language_server_work::Buffers {
11635 buffer_ids: buffers
11636 .into_iter()
11637 .map(|b| b.read(cx).remote_id().to_proto())
11638 .collect(),
11639 },
11640 )),
11641 });
11642 cx.background_spawn(request).detach_and_log_err(cx);
11643 } else if let Some(local) = self.as_local() {
11644 let servers = buffers
11645 .into_iter()
11646 .flat_map(|buffer| {
11647 buffer.update(cx, |buffer, cx| {
11648 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11649 })
11650 })
11651 .collect::<HashSet<_>>();
11652 for server_id in servers {
11653 self.cancel_language_server_work(server_id, None, cx);
11654 }
11655 }
11656 }
11657
11658 pub(crate) fn cancel_language_server_work(
11659 &mut self,
11660 server_id: LanguageServerId,
11661 token_to_cancel: Option<ProgressToken>,
11662 cx: &mut Context<Self>,
11663 ) {
11664 if let Some(local) = self.as_local() {
11665 let status = self.language_server_statuses.get(&server_id);
11666 let server = local.language_servers.get(&server_id);
11667 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11668 {
11669 for (token, progress) in &status.pending_work {
11670 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11671 && token != token_to_cancel
11672 {
11673 continue;
11674 }
11675 if progress.is_cancellable {
11676 server
11677 .notify::<lsp::notification::WorkDoneProgressCancel>(
11678 WorkDoneProgressCancelParams {
11679 token: token.to_lsp(),
11680 },
11681 )
11682 .ok();
11683 }
11684 }
11685 }
11686 } else if let Some((client, project_id)) = self.upstream_client() {
11687 let request = client.request(proto::CancelLanguageServerWork {
11688 project_id,
11689 work: Some(
11690 proto::cancel_language_server_work::Work::LanguageServerWork(
11691 proto::cancel_language_server_work::LanguageServerWork {
11692 language_server_id: server_id.to_proto(),
11693 token: token_to_cancel.map(|token| token.to_proto()),
11694 },
11695 ),
11696 ),
11697 });
11698 cx.background_spawn(request).detach_and_log_err(cx);
11699 }
11700 }
11701
11702 fn register_supplementary_language_server(
11703 &mut self,
11704 id: LanguageServerId,
11705 name: LanguageServerName,
11706 server: Arc<LanguageServer>,
11707 cx: &mut Context<Self>,
11708 ) {
11709 if let Some(local) = self.as_local_mut() {
11710 local
11711 .supplementary_language_servers
11712 .insert(id, (name.clone(), server));
11713 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11714 }
11715 }
11716
11717 fn unregister_supplementary_language_server(
11718 &mut self,
11719 id: LanguageServerId,
11720 cx: &mut Context<Self>,
11721 ) {
11722 if let Some(local) = self.as_local_mut() {
11723 local.supplementary_language_servers.remove(&id);
11724 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11725 }
11726 }
11727
11728 pub(crate) fn supplementary_language_servers(
11729 &self,
11730 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11731 self.as_local().into_iter().flat_map(|local| {
11732 local
11733 .supplementary_language_servers
11734 .iter()
11735 .map(|(id, (name, _))| (*id, name.clone()))
11736 })
11737 }
11738
11739 pub fn language_server_adapter_for_id(
11740 &self,
11741 id: LanguageServerId,
11742 ) -> Option<Arc<CachedLspAdapter>> {
11743 self.as_local()
11744 .and_then(|local| local.language_servers.get(&id))
11745 .and_then(|language_server_state| match language_server_state {
11746 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11747 _ => None,
11748 })
11749 }
11750
11751 pub(super) fn update_local_worktree_language_servers(
11752 &mut self,
11753 worktree_handle: &Entity<Worktree>,
11754 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11755 cx: &mut Context<Self>,
11756 ) {
11757 if changes.is_empty() {
11758 return;
11759 }
11760
11761 let Some(local) = self.as_local() else { return };
11762
11763 local.prettier_store.update(cx, |prettier_store, cx| {
11764 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11765 });
11766
11767 let worktree_id = worktree_handle.read(cx).id();
11768 let mut language_server_ids = local
11769 .language_server_ids
11770 .iter()
11771 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11772 .collect::<Vec<_>>();
11773 language_server_ids.sort();
11774 language_server_ids.dedup();
11775
11776 // let abs_path = worktree_handle.read(cx).abs_path();
11777 for server_id in &language_server_ids {
11778 if let Some(LanguageServerState::Running { server, .. }) =
11779 local.language_servers.get(server_id)
11780 && let Some(watched_paths) = local
11781 .language_server_watched_paths
11782 .get(server_id)
11783 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11784 {
11785 let params = lsp::DidChangeWatchedFilesParams {
11786 changes: changes
11787 .iter()
11788 .filter_map(|(path, _, change)| {
11789 if !watched_paths.is_match(path.as_std_path()) {
11790 return None;
11791 }
11792 let typ = match change {
11793 PathChange::Loaded => return None,
11794 PathChange::Added => lsp::FileChangeType::CREATED,
11795 PathChange::Removed => lsp::FileChangeType::DELETED,
11796 PathChange::Updated => lsp::FileChangeType::CHANGED,
11797 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11798 };
11799 let uri = lsp::Uri::from_file_path(
11800 worktree_handle.read(cx).absolutize(&path),
11801 )
11802 .ok()?;
11803 Some(lsp::FileEvent { uri, typ })
11804 })
11805 .collect(),
11806 };
11807 if !params.changes.is_empty() {
11808 server
11809 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11810 .ok();
11811 }
11812 }
11813 }
11814 for (path, _, _) in changes {
11815 if let Some(file_name) = path.file_name()
11816 && local.watched_manifest_filenames.contains(file_name)
11817 {
11818 self.request_workspace_config_refresh();
11819 break;
11820 }
11821 }
11822 }
11823
11824 pub fn wait_for_remote_buffer(
11825 &mut self,
11826 id: BufferId,
11827 cx: &mut Context<Self>,
11828 ) -> Task<Result<Entity<Buffer>>> {
11829 self.buffer_store.update(cx, |buffer_store, cx| {
11830 buffer_store.wait_for_remote_buffer(id, cx)
11831 })
11832 }
11833
11834 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11835 let mut result = proto::Symbol {
11836 language_server_name: symbol.language_server_name.0.to_string(),
11837 source_worktree_id: symbol.source_worktree_id.to_proto(),
11838 language_server_id: symbol.source_language_server_id.to_proto(),
11839 name: symbol.name.clone(),
11840 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11841 start: Some(proto::PointUtf16 {
11842 row: symbol.range.start.0.row,
11843 column: symbol.range.start.0.column,
11844 }),
11845 end: Some(proto::PointUtf16 {
11846 row: symbol.range.end.0.row,
11847 column: symbol.range.end.0.column,
11848 }),
11849 worktree_id: Default::default(),
11850 path: Default::default(),
11851 signature: Default::default(),
11852 };
11853 match &symbol.path {
11854 SymbolLocation::InProject(path) => {
11855 result.worktree_id = path.worktree_id.to_proto();
11856 result.path = path.path.to_proto();
11857 }
11858 SymbolLocation::OutsideProject {
11859 abs_path,
11860 signature,
11861 } => {
11862 result.path = abs_path.to_string_lossy().into_owned();
11863 result.signature = signature.to_vec();
11864 }
11865 }
11866 result
11867 }
11868
11869 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11870 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11871 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11872 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11873
11874 let path = if serialized_symbol.signature.is_empty() {
11875 SymbolLocation::InProject(ProjectPath {
11876 worktree_id,
11877 path: RelPath::from_proto(&serialized_symbol.path)
11878 .context("invalid symbol path")?,
11879 })
11880 } else {
11881 SymbolLocation::OutsideProject {
11882 abs_path: Path::new(&serialized_symbol.path).into(),
11883 signature: serialized_symbol
11884 .signature
11885 .try_into()
11886 .map_err(|_| anyhow!("invalid signature"))?,
11887 }
11888 };
11889
11890 let start = serialized_symbol.start.context("invalid start")?;
11891 let end = serialized_symbol.end.context("invalid end")?;
11892 Ok(CoreSymbol {
11893 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11894 source_worktree_id,
11895 source_language_server_id: LanguageServerId::from_proto(
11896 serialized_symbol.language_server_id,
11897 ),
11898 path,
11899 name: serialized_symbol.name,
11900 range: Unclipped(PointUtf16::new(start.row, start.column))
11901 ..Unclipped(PointUtf16::new(end.row, end.column)),
11902 kind,
11903 })
11904 }
11905
11906 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11907 let mut serialized_completion = proto::Completion {
11908 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11909 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11910 new_text: completion.new_text.clone(),
11911 ..proto::Completion::default()
11912 };
11913 match &completion.source {
11914 CompletionSource::Lsp {
11915 insert_range,
11916 server_id,
11917 lsp_completion,
11918 lsp_defaults,
11919 resolved,
11920 } => {
11921 let (old_insert_start, old_insert_end) = insert_range
11922 .as_ref()
11923 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11924 .unzip();
11925
11926 serialized_completion.old_insert_start = old_insert_start;
11927 serialized_completion.old_insert_end = old_insert_end;
11928 serialized_completion.source = proto::completion::Source::Lsp as i32;
11929 serialized_completion.server_id = server_id.0 as u64;
11930 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11931 serialized_completion.lsp_defaults = lsp_defaults
11932 .as_deref()
11933 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11934 serialized_completion.resolved = *resolved;
11935 }
11936 CompletionSource::BufferWord {
11937 word_range,
11938 resolved,
11939 } => {
11940 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11941 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11942 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11943 serialized_completion.resolved = *resolved;
11944 }
11945 CompletionSource::Custom => {
11946 serialized_completion.source = proto::completion::Source::Custom as i32;
11947 serialized_completion.resolved = true;
11948 }
11949 CompletionSource::Dap { sort_text } => {
11950 serialized_completion.source = proto::completion::Source::Dap as i32;
11951 serialized_completion.sort_text = Some(sort_text.clone());
11952 }
11953 }
11954
11955 serialized_completion
11956 }
11957
11958 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11959 let old_replace_start = completion
11960 .old_replace_start
11961 .and_then(deserialize_anchor)
11962 .context("invalid old start")?;
11963 let old_replace_end = completion
11964 .old_replace_end
11965 .and_then(deserialize_anchor)
11966 .context("invalid old end")?;
11967 let insert_range = {
11968 match completion.old_insert_start.zip(completion.old_insert_end) {
11969 Some((start, end)) => {
11970 let start = deserialize_anchor(start).context("invalid insert old start")?;
11971 let end = deserialize_anchor(end).context("invalid insert old end")?;
11972 Some(start..end)
11973 }
11974 None => None,
11975 }
11976 };
11977 Ok(CoreCompletion {
11978 replace_range: old_replace_start..old_replace_end,
11979 new_text: completion.new_text,
11980 source: match proto::completion::Source::from_i32(completion.source) {
11981 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11982 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11983 insert_range,
11984 server_id: LanguageServerId::from_proto(completion.server_id),
11985 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11986 lsp_defaults: completion
11987 .lsp_defaults
11988 .as_deref()
11989 .map(serde_json::from_slice)
11990 .transpose()?,
11991 resolved: completion.resolved,
11992 },
11993 Some(proto::completion::Source::BufferWord) => {
11994 let word_range = completion
11995 .buffer_word_start
11996 .and_then(deserialize_anchor)
11997 .context("invalid buffer word start")?
11998 ..completion
11999 .buffer_word_end
12000 .and_then(deserialize_anchor)
12001 .context("invalid buffer word end")?;
12002 CompletionSource::BufferWord {
12003 word_range,
12004 resolved: completion.resolved,
12005 }
12006 }
12007 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12008 sort_text: completion
12009 .sort_text
12010 .context("expected sort text to exist")?,
12011 },
12012 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12013 },
12014 })
12015 }
12016
12017 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12018 let (kind, lsp_action) = match &action.lsp_action {
12019 LspAction::Action(code_action) => (
12020 proto::code_action::Kind::Action as i32,
12021 serde_json::to_vec(code_action).unwrap(),
12022 ),
12023 LspAction::Command(command) => (
12024 proto::code_action::Kind::Command as i32,
12025 serde_json::to_vec(command).unwrap(),
12026 ),
12027 LspAction::CodeLens(code_lens) => (
12028 proto::code_action::Kind::CodeLens as i32,
12029 serde_json::to_vec(code_lens).unwrap(),
12030 ),
12031 };
12032
12033 proto::CodeAction {
12034 server_id: action.server_id.0 as u64,
12035 start: Some(serialize_anchor(&action.range.start)),
12036 end: Some(serialize_anchor(&action.range.end)),
12037 lsp_action,
12038 kind,
12039 resolved: action.resolved,
12040 }
12041 }
12042
12043 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12044 let start = action
12045 .start
12046 .and_then(deserialize_anchor)
12047 .context("invalid start")?;
12048 let end = action
12049 .end
12050 .and_then(deserialize_anchor)
12051 .context("invalid end")?;
12052 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12053 Some(proto::code_action::Kind::Action) => {
12054 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12055 }
12056 Some(proto::code_action::Kind::Command) => {
12057 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12058 }
12059 Some(proto::code_action::Kind::CodeLens) => {
12060 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12061 }
12062 None => anyhow::bail!("Unknown action kind {}", action.kind),
12063 };
12064 Ok(CodeAction {
12065 server_id: LanguageServerId(action.server_id as usize),
12066 range: start..end,
12067 resolved: action.resolved,
12068 lsp_action,
12069 })
12070 }
12071
12072 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12073 match &formatting_result {
12074 Ok(_) => self.last_formatting_failure = None,
12075 Err(error) => {
12076 let error_string = format!("{error:#}");
12077 log::error!("Formatting failed: {error_string}");
12078 self.last_formatting_failure
12079 .replace(error_string.lines().join(" "));
12080 }
12081 }
12082 }
12083
12084 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12085 self.lsp_server_capabilities.remove(&for_server);
12086 for lsp_data in self.lsp_data.values_mut() {
12087 lsp_data.remove_server_data(for_server);
12088 }
12089 if let Some(local) = self.as_local_mut() {
12090 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12091 local
12092 .workspace_pull_diagnostics_result_ids
12093 .remove(&for_server);
12094 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12095 buffer_servers.remove(&for_server);
12096 }
12097 }
12098 }
12099
12100 pub fn result_id_for_buffer_pull(
12101 &self,
12102 server_id: LanguageServerId,
12103 buffer_id: BufferId,
12104 registration_id: &Option<SharedString>,
12105 cx: &App,
12106 ) -> Option<SharedString> {
12107 let abs_path = self
12108 .buffer_store
12109 .read(cx)
12110 .get(buffer_id)
12111 .and_then(|b| File::from_dyn(b.read(cx).file()))
12112 .map(|f| f.abs_path(cx))?;
12113 self.as_local()?
12114 .buffer_pull_diagnostics_result_ids
12115 .get(&server_id)?
12116 .get(registration_id)?
12117 .get(&abs_path)?
12118 .clone()
12119 }
12120
12121 /// Gets all result_ids for a workspace diagnostics pull request.
12122 /// 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.
12123 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12124 pub fn result_ids_for_workspace_refresh(
12125 &self,
12126 server_id: LanguageServerId,
12127 registration_id: &Option<SharedString>,
12128 ) -> HashMap<PathBuf, SharedString> {
12129 let Some(local) = self.as_local() else {
12130 return HashMap::default();
12131 };
12132 local
12133 .workspace_pull_diagnostics_result_ids
12134 .get(&server_id)
12135 .into_iter()
12136 .filter_map(|diagnostics| diagnostics.get(registration_id))
12137 .flatten()
12138 .filter_map(|(abs_path, result_id)| {
12139 let result_id = local
12140 .buffer_pull_diagnostics_result_ids
12141 .get(&server_id)
12142 .and_then(|buffer_ids_result_ids| {
12143 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12144 })
12145 .cloned()
12146 .flatten()
12147 .or_else(|| result_id.clone())?;
12148 Some((abs_path.clone(), result_id))
12149 })
12150 .collect()
12151 }
12152
12153 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12154 if let Some(LanguageServerState::Running {
12155 workspace_diagnostics_refresh_tasks,
12156 ..
12157 }) = self
12158 .as_local_mut()
12159 .and_then(|local| local.language_servers.get_mut(&server_id))
12160 {
12161 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12162 diagnostics.refresh_tx.try_send(()).ok();
12163 }
12164 }
12165 }
12166
12167 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12168 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12169 return;
12170 };
12171 let Some(local) = self.as_local_mut() else {
12172 return;
12173 };
12174
12175 for server_id in buffer.update(cx, |buffer, cx| {
12176 local.language_server_ids_for_buffer(buffer, cx)
12177 }) {
12178 if let Some(LanguageServerState::Running {
12179 workspace_diagnostics_refresh_tasks,
12180 ..
12181 }) = local.language_servers.get_mut(&server_id)
12182 {
12183 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12184 diagnostics.refresh_tx.try_send(()).ok();
12185 }
12186 }
12187 }
12188 }
12189
12190 fn apply_workspace_diagnostic_report(
12191 &mut self,
12192 server_id: LanguageServerId,
12193 report: lsp::WorkspaceDiagnosticReportResult,
12194 registration_id: Option<SharedString>,
12195 cx: &mut Context<Self>,
12196 ) {
12197 let workspace_diagnostics =
12198 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12199 report,
12200 server_id,
12201 registration_id,
12202 );
12203 let mut unchanged_buffers = HashMap::default();
12204 let workspace_diagnostics_updates = workspace_diagnostics
12205 .into_iter()
12206 .filter_map(
12207 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12208 LspPullDiagnostics::Response {
12209 server_id,
12210 uri,
12211 diagnostics,
12212 registration_id,
12213 } => Some((
12214 server_id,
12215 uri,
12216 diagnostics,
12217 workspace_diagnostics.version,
12218 registration_id,
12219 )),
12220 LspPullDiagnostics::Default => None,
12221 },
12222 )
12223 .fold(
12224 HashMap::default(),
12225 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12226 let (result_id, diagnostics) = match diagnostics {
12227 PulledDiagnostics::Unchanged { result_id } => {
12228 unchanged_buffers
12229 .entry(new_registration_id.clone())
12230 .or_insert_with(HashSet::default)
12231 .insert(uri.clone());
12232 (Some(result_id), Vec::new())
12233 }
12234 PulledDiagnostics::Changed {
12235 result_id,
12236 diagnostics,
12237 } => (result_id, diagnostics),
12238 };
12239 let disk_based_sources = Cow::Owned(
12240 self.language_server_adapter_for_id(server_id)
12241 .as_ref()
12242 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12243 .unwrap_or(&[])
12244 .to_vec(),
12245 );
12246
12247 let Some(abs_path) = uri.to_file_path().ok() else {
12248 return acc;
12249 };
12250 let Some((worktree, relative_path)) =
12251 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12252 else {
12253 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12254 return acc;
12255 };
12256 let worktree_id = worktree.read(cx).id();
12257 let project_path = ProjectPath {
12258 worktree_id,
12259 path: relative_path,
12260 };
12261 if let Some(local_lsp_store) = self.as_local_mut() {
12262 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12263 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12264 }
12265 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12266 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12267 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12268 acc.entry(server_id)
12269 .or_insert_with(HashMap::default)
12270 .entry(new_registration_id.clone())
12271 .or_insert_with(Vec::new)
12272 .push(DocumentDiagnosticsUpdate {
12273 server_id,
12274 diagnostics: lsp::PublishDiagnosticsParams {
12275 uri,
12276 diagnostics,
12277 version,
12278 },
12279 result_id,
12280 disk_based_sources,
12281 registration_id: new_registration_id,
12282 });
12283 }
12284 acc
12285 },
12286 );
12287
12288 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12289 for (registration_id, diagnostic_updates) in diagnostic_updates {
12290 self.merge_lsp_diagnostics(
12291 DiagnosticSourceKind::Pulled,
12292 diagnostic_updates,
12293 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12294 DiagnosticSourceKind::Pulled => {
12295 old_diagnostic.registration_id != registration_id
12296 || unchanged_buffers
12297 .get(&old_diagnostic.registration_id)
12298 .is_some_and(|unchanged_buffers| {
12299 unchanged_buffers.contains(&document_uri)
12300 })
12301 }
12302 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12303 },
12304 cx,
12305 )
12306 .log_err();
12307 }
12308 }
12309 }
12310
12311 fn register_server_capabilities(
12312 &mut self,
12313 server_id: LanguageServerId,
12314 params: lsp::RegistrationParams,
12315 cx: &mut Context<Self>,
12316 ) -> anyhow::Result<()> {
12317 let server = self
12318 .language_server_for_id(server_id)
12319 .with_context(|| format!("no server {server_id} found"))?;
12320 for reg in params.registrations {
12321 match reg.method.as_str() {
12322 "workspace/didChangeWatchedFiles" => {
12323 if let Some(options) = reg.register_options {
12324 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12325 let caps = serde_json::from_value(options)?;
12326 local_lsp_store
12327 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12328 true
12329 } else {
12330 false
12331 };
12332 if notify {
12333 notify_server_capabilities_updated(&server, cx);
12334 }
12335 }
12336 }
12337 "workspace/didChangeConfiguration" => {
12338 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12339 }
12340 "workspace/didChangeWorkspaceFolders" => {
12341 // In this case register options is an empty object, we can ignore it
12342 let caps = lsp::WorkspaceFoldersServerCapabilities {
12343 supported: Some(true),
12344 change_notifications: Some(OneOf::Right(reg.id)),
12345 };
12346 server.update_capabilities(|capabilities| {
12347 capabilities
12348 .workspace
12349 .get_or_insert_default()
12350 .workspace_folders = Some(caps);
12351 });
12352 notify_server_capabilities_updated(&server, cx);
12353 }
12354 "workspace/symbol" => {
12355 let options = parse_register_capabilities(reg)?;
12356 server.update_capabilities(|capabilities| {
12357 capabilities.workspace_symbol_provider = Some(options);
12358 });
12359 notify_server_capabilities_updated(&server, cx);
12360 }
12361 "workspace/fileOperations" => {
12362 if let Some(options) = reg.register_options {
12363 let caps = serde_json::from_value(options)?;
12364 server.update_capabilities(|capabilities| {
12365 capabilities
12366 .workspace
12367 .get_or_insert_default()
12368 .file_operations = Some(caps);
12369 });
12370 notify_server_capabilities_updated(&server, cx);
12371 }
12372 }
12373 "workspace/executeCommand" => {
12374 if let Some(options) = reg.register_options {
12375 let options = serde_json::from_value(options)?;
12376 server.update_capabilities(|capabilities| {
12377 capabilities.execute_command_provider = Some(options);
12378 });
12379 notify_server_capabilities_updated(&server, cx);
12380 }
12381 }
12382 "textDocument/rangeFormatting" => {
12383 let options = parse_register_capabilities(reg)?;
12384 server.update_capabilities(|capabilities| {
12385 capabilities.document_range_formatting_provider = Some(options);
12386 });
12387 notify_server_capabilities_updated(&server, cx);
12388 }
12389 "textDocument/onTypeFormatting" => {
12390 if let Some(options) = reg
12391 .register_options
12392 .map(serde_json::from_value)
12393 .transpose()?
12394 {
12395 server.update_capabilities(|capabilities| {
12396 capabilities.document_on_type_formatting_provider = Some(options);
12397 });
12398 notify_server_capabilities_updated(&server, cx);
12399 }
12400 }
12401 "textDocument/formatting" => {
12402 let options = parse_register_capabilities(reg)?;
12403 server.update_capabilities(|capabilities| {
12404 capabilities.document_formatting_provider = Some(options);
12405 });
12406 notify_server_capabilities_updated(&server, cx);
12407 }
12408 "textDocument/rename" => {
12409 let options = parse_register_capabilities(reg)?;
12410 server.update_capabilities(|capabilities| {
12411 capabilities.rename_provider = Some(options);
12412 });
12413 notify_server_capabilities_updated(&server, cx);
12414 }
12415 "textDocument/inlayHint" => {
12416 let options = parse_register_capabilities(reg)?;
12417 server.update_capabilities(|capabilities| {
12418 capabilities.inlay_hint_provider = Some(options);
12419 });
12420 notify_server_capabilities_updated(&server, cx);
12421 }
12422 "textDocument/documentSymbol" => {
12423 let options = parse_register_capabilities(reg)?;
12424 server.update_capabilities(|capabilities| {
12425 capabilities.document_symbol_provider = Some(options);
12426 });
12427 notify_server_capabilities_updated(&server, cx);
12428 }
12429 "textDocument/codeAction" => {
12430 let options = parse_register_capabilities(reg)?;
12431 let provider = match options {
12432 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12433 OneOf::Right(caps) => caps,
12434 };
12435 server.update_capabilities(|capabilities| {
12436 capabilities.code_action_provider = Some(provider);
12437 });
12438 notify_server_capabilities_updated(&server, cx);
12439 }
12440 "textDocument/definition" => {
12441 let options = parse_register_capabilities(reg)?;
12442 server.update_capabilities(|capabilities| {
12443 capabilities.definition_provider = Some(options);
12444 });
12445 notify_server_capabilities_updated(&server, cx);
12446 }
12447 "textDocument/completion" => {
12448 if let Some(caps) = reg
12449 .register_options
12450 .map(serde_json::from_value::<CompletionOptions>)
12451 .transpose()?
12452 {
12453 server.update_capabilities(|capabilities| {
12454 capabilities.completion_provider = Some(caps.clone());
12455 });
12456
12457 if let Some(local) = self.as_local() {
12458 let mut buffers_with_language_server = Vec::new();
12459 for handle in self.buffer_store.read(cx).buffers() {
12460 let buffer_id = handle.read(cx).remote_id();
12461 if local
12462 .buffers_opened_in_servers
12463 .get(&buffer_id)
12464 .filter(|s| s.contains(&server_id))
12465 .is_some()
12466 {
12467 buffers_with_language_server.push(handle);
12468 }
12469 }
12470 let triggers = caps
12471 .trigger_characters
12472 .unwrap_or_default()
12473 .into_iter()
12474 .collect::<BTreeSet<_>>();
12475 for handle in buffers_with_language_server {
12476 let triggers = triggers.clone();
12477 let _ = handle.update(cx, move |buffer, cx| {
12478 buffer.set_completion_triggers(server_id, triggers, cx);
12479 });
12480 }
12481 }
12482 notify_server_capabilities_updated(&server, cx);
12483 }
12484 }
12485 "textDocument/hover" => {
12486 let options = parse_register_capabilities(reg)?;
12487 let provider = match options {
12488 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12489 OneOf::Right(caps) => caps,
12490 };
12491 server.update_capabilities(|capabilities| {
12492 capabilities.hover_provider = Some(provider);
12493 });
12494 notify_server_capabilities_updated(&server, cx);
12495 }
12496 "textDocument/signatureHelp" => {
12497 if let Some(caps) = reg
12498 .register_options
12499 .map(serde_json::from_value)
12500 .transpose()?
12501 {
12502 server.update_capabilities(|capabilities| {
12503 capabilities.signature_help_provider = Some(caps);
12504 });
12505 notify_server_capabilities_updated(&server, cx);
12506 }
12507 }
12508 "textDocument/didChange" => {
12509 if let Some(sync_kind) = reg
12510 .register_options
12511 .and_then(|opts| opts.get("syncKind").cloned())
12512 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12513 .transpose()?
12514 {
12515 server.update_capabilities(|capabilities| {
12516 let mut sync_options =
12517 Self::take_text_document_sync_options(capabilities);
12518 sync_options.change = Some(sync_kind);
12519 capabilities.text_document_sync =
12520 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12521 });
12522 notify_server_capabilities_updated(&server, cx);
12523 }
12524 }
12525 "textDocument/didSave" => {
12526 if let Some(include_text) = reg
12527 .register_options
12528 .map(|opts| {
12529 let transpose = opts
12530 .get("includeText")
12531 .cloned()
12532 .map(serde_json::from_value::<Option<bool>>)
12533 .transpose();
12534 match transpose {
12535 Ok(value) => Ok(value.flatten()),
12536 Err(e) => Err(e),
12537 }
12538 })
12539 .transpose()?
12540 {
12541 server.update_capabilities(|capabilities| {
12542 let mut sync_options =
12543 Self::take_text_document_sync_options(capabilities);
12544 sync_options.save =
12545 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12546 include_text,
12547 }));
12548 capabilities.text_document_sync =
12549 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12550 });
12551 notify_server_capabilities_updated(&server, cx);
12552 }
12553 }
12554 "textDocument/codeLens" => {
12555 if let Some(caps) = reg
12556 .register_options
12557 .map(serde_json::from_value)
12558 .transpose()?
12559 {
12560 server.update_capabilities(|capabilities| {
12561 capabilities.code_lens_provider = Some(caps);
12562 });
12563 notify_server_capabilities_updated(&server, cx);
12564 }
12565 }
12566 "textDocument/diagnostic" => {
12567 if let Some(caps) = reg
12568 .register_options
12569 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12570 .transpose()?
12571 {
12572 let local = self
12573 .as_local_mut()
12574 .context("Expected LSP Store to be local")?;
12575 let state = local
12576 .language_servers
12577 .get_mut(&server_id)
12578 .context("Could not obtain Language Servers state")?;
12579 local
12580 .language_server_dynamic_registrations
12581 .entry(server_id)
12582 .or_default()
12583 .diagnostics
12584 .insert(Some(reg.id.clone()), caps.clone());
12585
12586 let supports_workspace_diagnostics =
12587 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12588 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12589 diagnostic_options.workspace_diagnostics
12590 }
12591 DiagnosticServerCapabilities::RegistrationOptions(
12592 diagnostic_registration_options,
12593 ) => {
12594 diagnostic_registration_options
12595 .diagnostic_options
12596 .workspace_diagnostics
12597 }
12598 };
12599
12600 if supports_workspace_diagnostics(&caps) {
12601 if let LanguageServerState::Running {
12602 workspace_diagnostics_refresh_tasks,
12603 ..
12604 } = state
12605 && let Some(task) = lsp_workspace_diagnostics_refresh(
12606 Some(reg.id.clone()),
12607 caps.clone(),
12608 server.clone(),
12609 cx,
12610 )
12611 {
12612 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12613 }
12614 }
12615
12616 server.update_capabilities(|capabilities| {
12617 capabilities.diagnostic_provider = Some(caps);
12618 });
12619
12620 notify_server_capabilities_updated(&server, cx);
12621 }
12622 }
12623 "textDocument/documentColor" => {
12624 let options = parse_register_capabilities(reg)?;
12625 let provider = match options {
12626 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12627 OneOf::Right(caps) => caps,
12628 };
12629 server.update_capabilities(|capabilities| {
12630 capabilities.color_provider = Some(provider);
12631 });
12632 notify_server_capabilities_updated(&server, cx);
12633 }
12634 _ => log::warn!("unhandled capability registration: {reg:?}"),
12635 }
12636 }
12637
12638 Ok(())
12639 }
12640
12641 fn unregister_server_capabilities(
12642 &mut self,
12643 server_id: LanguageServerId,
12644 params: lsp::UnregistrationParams,
12645 cx: &mut Context<Self>,
12646 ) -> anyhow::Result<()> {
12647 let server = self
12648 .language_server_for_id(server_id)
12649 .with_context(|| format!("no server {server_id} found"))?;
12650 for unreg in params.unregisterations.iter() {
12651 match unreg.method.as_str() {
12652 "workspace/didChangeWatchedFiles" => {
12653 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12654 local_lsp_store
12655 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12656 true
12657 } else {
12658 false
12659 };
12660 if notify {
12661 notify_server_capabilities_updated(&server, cx);
12662 }
12663 }
12664 "workspace/didChangeConfiguration" => {
12665 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12666 }
12667 "workspace/didChangeWorkspaceFolders" => {
12668 server.update_capabilities(|capabilities| {
12669 capabilities
12670 .workspace
12671 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12672 workspace_folders: None,
12673 file_operations: None,
12674 })
12675 .workspace_folders = None;
12676 });
12677 notify_server_capabilities_updated(&server, cx);
12678 }
12679 "workspace/symbol" => {
12680 server.update_capabilities(|capabilities| {
12681 capabilities.workspace_symbol_provider = None
12682 });
12683 notify_server_capabilities_updated(&server, cx);
12684 }
12685 "workspace/fileOperations" => {
12686 server.update_capabilities(|capabilities| {
12687 capabilities
12688 .workspace
12689 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12690 workspace_folders: None,
12691 file_operations: None,
12692 })
12693 .file_operations = None;
12694 });
12695 notify_server_capabilities_updated(&server, cx);
12696 }
12697 "workspace/executeCommand" => {
12698 server.update_capabilities(|capabilities| {
12699 capabilities.execute_command_provider = None;
12700 });
12701 notify_server_capabilities_updated(&server, cx);
12702 }
12703 "textDocument/rangeFormatting" => {
12704 server.update_capabilities(|capabilities| {
12705 capabilities.document_range_formatting_provider = None
12706 });
12707 notify_server_capabilities_updated(&server, cx);
12708 }
12709 "textDocument/onTypeFormatting" => {
12710 server.update_capabilities(|capabilities| {
12711 capabilities.document_on_type_formatting_provider = None;
12712 });
12713 notify_server_capabilities_updated(&server, cx);
12714 }
12715 "textDocument/formatting" => {
12716 server.update_capabilities(|capabilities| {
12717 capabilities.document_formatting_provider = None;
12718 });
12719 notify_server_capabilities_updated(&server, cx);
12720 }
12721 "textDocument/rename" => {
12722 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12723 notify_server_capabilities_updated(&server, cx);
12724 }
12725 "textDocument/codeAction" => {
12726 server.update_capabilities(|capabilities| {
12727 capabilities.code_action_provider = None;
12728 });
12729 notify_server_capabilities_updated(&server, cx);
12730 }
12731 "textDocument/definition" => {
12732 server.update_capabilities(|capabilities| {
12733 capabilities.definition_provider = None;
12734 });
12735 notify_server_capabilities_updated(&server, cx);
12736 }
12737 "textDocument/completion" => {
12738 server.update_capabilities(|capabilities| {
12739 capabilities.completion_provider = None;
12740 });
12741 notify_server_capabilities_updated(&server, cx);
12742 }
12743 "textDocument/hover" => {
12744 server.update_capabilities(|capabilities| {
12745 capabilities.hover_provider = None;
12746 });
12747 notify_server_capabilities_updated(&server, cx);
12748 }
12749 "textDocument/signatureHelp" => {
12750 server.update_capabilities(|capabilities| {
12751 capabilities.signature_help_provider = None;
12752 });
12753 notify_server_capabilities_updated(&server, cx);
12754 }
12755 "textDocument/didChange" => {
12756 server.update_capabilities(|capabilities| {
12757 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12758 sync_options.change = None;
12759 capabilities.text_document_sync =
12760 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12761 });
12762 notify_server_capabilities_updated(&server, cx);
12763 }
12764 "textDocument/didSave" => {
12765 server.update_capabilities(|capabilities| {
12766 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12767 sync_options.save = None;
12768 capabilities.text_document_sync =
12769 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12770 });
12771 notify_server_capabilities_updated(&server, cx);
12772 }
12773 "textDocument/codeLens" => {
12774 server.update_capabilities(|capabilities| {
12775 capabilities.code_lens_provider = None;
12776 });
12777 notify_server_capabilities_updated(&server, cx);
12778 }
12779 "textDocument/diagnostic" => {
12780 let local = self
12781 .as_local_mut()
12782 .context("Expected LSP Store to be local")?;
12783
12784 let state = local
12785 .language_servers
12786 .get_mut(&server_id)
12787 .context("Could not obtain Language Servers state")?;
12788 let registrations = local
12789 .language_server_dynamic_registrations
12790 .get_mut(&server_id)
12791 .with_context(|| {
12792 format!("Expected dynamic registration to exist for server {server_id}")
12793 })?;
12794 registrations.diagnostics
12795 .remove(&Some(unreg.id.clone()))
12796 .with_context(|| format!(
12797 "Attempted to unregister non-existent diagnostic registration with ID {}",
12798 unreg.id)
12799 )?;
12800 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12801
12802 if let LanguageServerState::Running {
12803 workspace_diagnostics_refresh_tasks,
12804 ..
12805 } = state
12806 {
12807 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12808 }
12809
12810 if removed_last_diagnostic_provider {
12811 server.update_capabilities(|capabilities| {
12812 debug_assert!(capabilities.diagnostic_provider.is_some());
12813 capabilities.diagnostic_provider = None;
12814 });
12815 }
12816
12817 notify_server_capabilities_updated(&server, cx);
12818 }
12819 "textDocument/documentColor" => {
12820 server.update_capabilities(|capabilities| {
12821 capabilities.color_provider = None;
12822 });
12823 notify_server_capabilities_updated(&server, cx);
12824 }
12825 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12826 }
12827 }
12828
12829 Ok(())
12830 }
12831
12832 async fn deduplicate_range_based_lsp_requests<T>(
12833 lsp_store: &Entity<Self>,
12834 server_id: Option<LanguageServerId>,
12835 lsp_request_id: LspRequestId,
12836 proto_request: &T::ProtoRequest,
12837 range: Range<Anchor>,
12838 cx: &mut AsyncApp,
12839 ) -> Result<()>
12840 where
12841 T: LspCommand,
12842 T::ProtoRequest: proto::LspRequestMessage,
12843 {
12844 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12845 let version = deserialize_version(proto_request.buffer_version());
12846 let buffer = lsp_store.update(cx, |this, cx| {
12847 this.buffer_store.read(cx).get_existing(buffer_id)
12848 })??;
12849 buffer
12850 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12851 .await?;
12852 lsp_store.update(cx, |lsp_store, cx| {
12853 let buffer_snapshot = buffer.read(cx).snapshot();
12854 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12855 let chunks_queried_for = lsp_data
12856 .inlay_hints
12857 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12858 .collect::<Vec<_>>();
12859 match chunks_queried_for.as_slice() {
12860 &[chunk] => {
12861 let key = LspKey {
12862 request_type: TypeId::of::<T>(),
12863 server_queried: server_id,
12864 };
12865 let previous_request = lsp_data
12866 .chunk_lsp_requests
12867 .entry(key)
12868 .or_default()
12869 .insert(chunk, lsp_request_id);
12870 if let Some((previous_request, running_requests)) =
12871 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12872 {
12873 running_requests.remove(&previous_request);
12874 }
12875 }
12876 _ambiguous_chunks => {
12877 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12878 // there, a buffer version-based check will be performed and outdated requests discarded.
12879 }
12880 }
12881 anyhow::Ok(())
12882 })??;
12883
12884 Ok(())
12885 }
12886
12887 async fn query_lsp_locally<T>(
12888 lsp_store: Entity<Self>,
12889 for_server_id: Option<LanguageServerId>,
12890 sender_id: proto::PeerId,
12891 lsp_request_id: LspRequestId,
12892 proto_request: T::ProtoRequest,
12893 position: Option<Anchor>,
12894 cx: &mut AsyncApp,
12895 ) -> Result<()>
12896 where
12897 T: LspCommand + Clone,
12898 T::ProtoRequest: proto::LspRequestMessage,
12899 <T::ProtoRequest as proto::RequestMessage>::Response:
12900 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12901 {
12902 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12903 let version = deserialize_version(proto_request.buffer_version());
12904 let buffer = lsp_store.update(cx, |this, cx| {
12905 this.buffer_store.read(cx).get_existing(buffer_id)
12906 })??;
12907 buffer
12908 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12909 .await?;
12910 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12911 let request =
12912 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12913 let key = LspKey {
12914 request_type: TypeId::of::<T>(),
12915 server_queried: for_server_id,
12916 };
12917 lsp_store.update(cx, |lsp_store, cx| {
12918 let request_task = match for_server_id {
12919 Some(server_id) => {
12920 let server_task = lsp_store.request_lsp(
12921 buffer.clone(),
12922 LanguageServerToQuery::Other(server_id),
12923 request.clone(),
12924 cx,
12925 );
12926 cx.background_spawn(async move {
12927 let mut responses = Vec::new();
12928 match server_task.await {
12929 Ok(response) => responses.push((server_id, response)),
12930 // rust-analyzer likes to error with this when its still loading up
12931 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12932 Err(e) => log::error!(
12933 "Error handling response for request {request:?}: {e:#}"
12934 ),
12935 }
12936 responses
12937 })
12938 }
12939 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12940 };
12941 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12942 if T::ProtoRequest::stop_previous_requests() {
12943 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12944 lsp_requests.clear();
12945 }
12946 }
12947 lsp_data.lsp_requests.entry(key).or_default().insert(
12948 lsp_request_id,
12949 cx.spawn(async move |lsp_store, cx| {
12950 let response = request_task.await;
12951 lsp_store
12952 .update(cx, |lsp_store, cx| {
12953 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12954 {
12955 let response = response
12956 .into_iter()
12957 .map(|(server_id, response)| {
12958 (
12959 server_id.to_proto(),
12960 T::response_to_proto(
12961 response,
12962 lsp_store,
12963 sender_id,
12964 &buffer_version,
12965 cx,
12966 )
12967 .into(),
12968 )
12969 })
12970 .collect::<HashMap<_, _>>();
12971 match client.send_lsp_response::<T::ProtoRequest>(
12972 project_id,
12973 lsp_request_id,
12974 response,
12975 ) {
12976 Ok(()) => {}
12977 Err(e) => {
12978 log::error!("Failed to send LSP response: {e:#}",)
12979 }
12980 }
12981 }
12982 })
12983 .ok();
12984 }),
12985 );
12986 })?;
12987 Ok(())
12988 }
12989
12990 fn take_text_document_sync_options(
12991 capabilities: &mut lsp::ServerCapabilities,
12992 ) -> lsp::TextDocumentSyncOptions {
12993 match capabilities.text_document_sync.take() {
12994 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12995 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12996 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12997 sync_options.change = Some(sync_kind);
12998 sync_options
12999 }
13000 None => lsp::TextDocumentSyncOptions::default(),
13001 }
13002 }
13003
13004 #[cfg(any(test, feature = "test-support"))]
13005 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13006 Some(
13007 self.lsp_data
13008 .get_mut(&buffer_id)?
13009 .code_lens
13010 .take()?
13011 .update
13012 .take()?
13013 .1,
13014 )
13015 }
13016
13017 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13018 self.downstream_client.clone()
13019 }
13020
13021 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13022 self.worktree_store.clone()
13023 }
13024
13025 /// Gets what's stored in the LSP data for the given buffer.
13026 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13027 self.lsp_data.get_mut(&buffer_id)
13028 }
13029
13030 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13031 /// new [`BufferLspData`] will be created to replace the previous state.
13032 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13033 let (buffer_id, buffer_version) =
13034 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13035 let lsp_data = self
13036 .lsp_data
13037 .entry(buffer_id)
13038 .or_insert_with(|| BufferLspData::new(buffer, cx));
13039 if buffer_version.changed_since(&lsp_data.buffer_version) {
13040 *lsp_data = BufferLspData::new(buffer, cx);
13041 }
13042 lsp_data
13043 }
13044}
13045
13046// Registration with registerOptions as null, should fallback to true.
13047// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13048fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13049 reg: lsp::Registration,
13050) -> Result<OneOf<bool, T>> {
13051 Ok(match reg.register_options {
13052 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13053 None => OneOf::Left(true),
13054 })
13055}
13056
13057fn subscribe_to_binary_statuses(
13058 languages: &Arc<LanguageRegistry>,
13059 cx: &mut Context<'_, LspStore>,
13060) -> Task<()> {
13061 let mut server_statuses = languages.language_server_binary_statuses();
13062 cx.spawn(async move |lsp_store, cx| {
13063 while let Some((server_name, binary_status)) = server_statuses.next().await {
13064 if lsp_store
13065 .update(cx, |_, cx| {
13066 let mut message = None;
13067 let binary_status = match binary_status {
13068 BinaryStatus::None => proto::ServerBinaryStatus::None,
13069 BinaryStatus::CheckingForUpdate => {
13070 proto::ServerBinaryStatus::CheckingForUpdate
13071 }
13072 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13073 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13074 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13075 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13076 BinaryStatus::Failed { error } => {
13077 message = Some(error);
13078 proto::ServerBinaryStatus::Failed
13079 }
13080 };
13081 cx.emit(LspStoreEvent::LanguageServerUpdate {
13082 // Binary updates are about the binary that might not have any language server id at that point.
13083 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13084 language_server_id: LanguageServerId(0),
13085 name: Some(server_name),
13086 message: proto::update_language_server::Variant::StatusUpdate(
13087 proto::StatusUpdate {
13088 message,
13089 status: Some(proto::status_update::Status::Binary(
13090 binary_status as i32,
13091 )),
13092 },
13093 ),
13094 });
13095 })
13096 .is_err()
13097 {
13098 break;
13099 }
13100 }
13101 })
13102}
13103
13104fn lsp_workspace_diagnostics_refresh(
13105 registration_id: Option<String>,
13106 options: DiagnosticServerCapabilities,
13107 server: Arc<LanguageServer>,
13108 cx: &mut Context<'_, LspStore>,
13109) -> Option<WorkspaceRefreshTask> {
13110 let identifier = workspace_diagnostic_identifier(&options)?;
13111 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13112
13113 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13114 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13115 refresh_tx.try_send(()).ok();
13116
13117 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13118 let mut attempts = 0;
13119 let max_attempts = 50;
13120 let mut requests = 0;
13121
13122 loop {
13123 let Some(()) = refresh_rx.recv().await else {
13124 return;
13125 };
13126
13127 'request: loop {
13128 requests += 1;
13129 if attempts > max_attempts {
13130 log::error!(
13131 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13132 );
13133 return;
13134 }
13135 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13136 cx.background_executor()
13137 .timer(Duration::from_millis(backoff_millis))
13138 .await;
13139 attempts += 1;
13140
13141 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13142 lsp_store
13143 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13144 .into_iter()
13145 .filter_map(|(abs_path, result_id)| {
13146 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13147 Some(lsp::PreviousResultId {
13148 uri,
13149 value: result_id.to_string(),
13150 })
13151 })
13152 .collect()
13153 }) else {
13154 return;
13155 };
13156
13157 let token = if let Some(registration_id) = ®istration_id {
13158 format!(
13159 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13160 server.server_id(),
13161 )
13162 } else {
13163 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13164 };
13165
13166 progress_rx.try_recv().ok();
13167 let timer =
13168 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13169 let progress = pin!(progress_rx.recv().fuse());
13170 let response_result = server
13171 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13172 lsp::WorkspaceDiagnosticParams {
13173 previous_result_ids,
13174 identifier: identifier.clone(),
13175 work_done_progress_params: Default::default(),
13176 partial_result_params: lsp::PartialResultParams {
13177 partial_result_token: Some(lsp::ProgressToken::String(token)),
13178 },
13179 },
13180 select(timer, progress).then(|either| match either {
13181 Either::Left((message, ..)) => ready(message).left_future(),
13182 Either::Right(..) => pending::<String>().right_future(),
13183 }),
13184 )
13185 .await;
13186
13187 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13188 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13189 match response_result {
13190 ConnectionResult::Timeout => {
13191 log::error!("Timeout during workspace diagnostics pull");
13192 continue 'request;
13193 }
13194 ConnectionResult::ConnectionReset => {
13195 log::error!("Server closed a workspace diagnostics pull request");
13196 continue 'request;
13197 }
13198 ConnectionResult::Result(Err(e)) => {
13199 log::error!("Error during workspace diagnostics pull: {e:#}");
13200 break 'request;
13201 }
13202 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13203 attempts = 0;
13204 if lsp_store
13205 .update(cx, |lsp_store, cx| {
13206 lsp_store.apply_workspace_diagnostic_report(
13207 server.server_id(),
13208 pulled_diagnostics,
13209 registration_id_shared.clone(),
13210 cx,
13211 )
13212 })
13213 .is_err()
13214 {
13215 return;
13216 }
13217 break 'request;
13218 }
13219 }
13220 }
13221 }
13222 });
13223
13224 Some(WorkspaceRefreshTask {
13225 refresh_tx,
13226 progress_tx,
13227 task: workspace_query_language_server,
13228 })
13229}
13230
13231fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13232 match &options {
13233 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13234 diagnostic_options.identifier.clone()
13235 }
13236 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13237 let diagnostic_options = ®istration_options.diagnostic_options;
13238 diagnostic_options.identifier.clone()
13239 }
13240 }
13241}
13242
13243fn workspace_diagnostic_identifier(
13244 options: &DiagnosticServerCapabilities,
13245) -> Option<Option<String>> {
13246 match &options {
13247 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13248 if !diagnostic_options.workspace_diagnostics {
13249 return None;
13250 }
13251 Some(diagnostic_options.identifier.clone())
13252 }
13253 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13254 let diagnostic_options = ®istration_options.diagnostic_options;
13255 if !diagnostic_options.workspace_diagnostics {
13256 return None;
13257 }
13258 Some(diagnostic_options.identifier.clone())
13259 }
13260 }
13261}
13262
13263fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13264 let CompletionSource::BufferWord {
13265 word_range,
13266 resolved,
13267 } = &mut completion.source
13268 else {
13269 return;
13270 };
13271 if *resolved {
13272 return;
13273 }
13274
13275 if completion.new_text
13276 != snapshot
13277 .text_for_range(word_range.clone())
13278 .collect::<String>()
13279 {
13280 return;
13281 }
13282
13283 let mut offset = 0;
13284 for chunk in snapshot.chunks(word_range.clone(), true) {
13285 let end_offset = offset + chunk.text.len();
13286 if let Some(highlight_id) = chunk.syntax_highlight_id {
13287 completion
13288 .label
13289 .runs
13290 .push((offset..end_offset, highlight_id));
13291 }
13292 offset = end_offset;
13293 }
13294 *resolved = true;
13295}
13296
13297impl EventEmitter<LspStoreEvent> for LspStore {}
13298
13299fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13300 hover
13301 .contents
13302 .retain(|hover_block| !hover_block.text.trim().is_empty());
13303 if hover.contents.is_empty() {
13304 None
13305 } else {
13306 Some(hover)
13307 }
13308}
13309
13310async fn populate_labels_for_completions(
13311 new_completions: Vec<CoreCompletion>,
13312 language: Option<Arc<Language>>,
13313 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13314) -> Vec<Completion> {
13315 let lsp_completions = new_completions
13316 .iter()
13317 .filter_map(|new_completion| {
13318 new_completion
13319 .source
13320 .lsp_completion(true)
13321 .map(|lsp_completion| lsp_completion.into_owned())
13322 })
13323 .collect::<Vec<_>>();
13324
13325 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13326 lsp_adapter
13327 .labels_for_completions(&lsp_completions, language)
13328 .await
13329 .log_err()
13330 .unwrap_or_default()
13331 } else {
13332 Vec::new()
13333 }
13334 .into_iter()
13335 .fuse();
13336
13337 let mut completions = Vec::new();
13338 for completion in new_completions {
13339 match completion.source.lsp_completion(true) {
13340 Some(lsp_completion) => {
13341 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13342
13343 let mut label = labels.next().flatten().unwrap_or_else(|| {
13344 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13345 });
13346 ensure_uniform_list_compatible_label(&mut label);
13347 completions.push(Completion {
13348 label,
13349 documentation,
13350 replace_range: completion.replace_range,
13351 new_text: completion.new_text,
13352 insert_text_mode: lsp_completion.insert_text_mode,
13353 source: completion.source,
13354 icon_path: None,
13355 confirm: None,
13356 match_start: None,
13357 snippet_deduplication_key: None,
13358 });
13359 }
13360 None => {
13361 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13362 ensure_uniform_list_compatible_label(&mut label);
13363 completions.push(Completion {
13364 label,
13365 documentation: None,
13366 replace_range: completion.replace_range,
13367 new_text: completion.new_text,
13368 source: completion.source,
13369 insert_text_mode: None,
13370 icon_path: None,
13371 confirm: None,
13372 match_start: None,
13373 snippet_deduplication_key: None,
13374 });
13375 }
13376 }
13377 }
13378 completions
13379}
13380
13381#[derive(Debug)]
13382pub enum LanguageServerToQuery {
13383 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13384 FirstCapable,
13385 /// Query a specific language server.
13386 Other(LanguageServerId),
13387}
13388
13389#[derive(Default)]
13390struct RenamePathsWatchedForServer {
13391 did_rename: Vec<RenameActionPredicate>,
13392 will_rename: Vec<RenameActionPredicate>,
13393}
13394
13395impl RenamePathsWatchedForServer {
13396 fn with_did_rename_patterns(
13397 mut self,
13398 did_rename: Option<&FileOperationRegistrationOptions>,
13399 ) -> Self {
13400 if let Some(did_rename) = did_rename {
13401 self.did_rename = did_rename
13402 .filters
13403 .iter()
13404 .filter_map(|filter| filter.try_into().log_err())
13405 .collect();
13406 }
13407 self
13408 }
13409 fn with_will_rename_patterns(
13410 mut self,
13411 will_rename: Option<&FileOperationRegistrationOptions>,
13412 ) -> Self {
13413 if let Some(will_rename) = will_rename {
13414 self.will_rename = will_rename
13415 .filters
13416 .iter()
13417 .filter_map(|filter| filter.try_into().log_err())
13418 .collect();
13419 }
13420 self
13421 }
13422
13423 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13424 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13425 }
13426 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13427 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13428 }
13429}
13430
13431impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13432 type Error = globset::Error;
13433 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13434 Ok(Self {
13435 kind: ops.pattern.matches.clone(),
13436 glob: GlobBuilder::new(&ops.pattern.glob)
13437 .case_insensitive(
13438 ops.pattern
13439 .options
13440 .as_ref()
13441 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13442 )
13443 .build()?
13444 .compile_matcher(),
13445 })
13446 }
13447}
13448struct RenameActionPredicate {
13449 glob: GlobMatcher,
13450 kind: Option<FileOperationPatternKind>,
13451}
13452
13453impl RenameActionPredicate {
13454 // Returns true if language server should be notified
13455 fn eval(&self, path: &str, is_dir: bool) -> bool {
13456 self.kind.as_ref().is_none_or(|kind| {
13457 let expected_kind = if is_dir {
13458 FileOperationPatternKind::Folder
13459 } else {
13460 FileOperationPatternKind::File
13461 };
13462 kind == &expected_kind
13463 }) && self.glob.is_match(path)
13464 }
13465}
13466
13467#[derive(Default)]
13468struct LanguageServerWatchedPaths {
13469 worktree_paths: HashMap<WorktreeId, GlobSet>,
13470 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13471}
13472
13473#[derive(Default)]
13474struct LanguageServerWatchedPathsBuilder {
13475 worktree_paths: HashMap<WorktreeId, GlobSet>,
13476 abs_paths: HashMap<Arc<Path>, GlobSet>,
13477}
13478
13479impl LanguageServerWatchedPathsBuilder {
13480 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13481 self.worktree_paths.insert(worktree_id, glob_set);
13482 }
13483 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13484 self.abs_paths.insert(path, glob_set);
13485 }
13486 fn build(
13487 self,
13488 fs: Arc<dyn Fs>,
13489 language_server_id: LanguageServerId,
13490 cx: &mut Context<LspStore>,
13491 ) -> LanguageServerWatchedPaths {
13492 let lsp_store = cx.weak_entity();
13493
13494 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13495 let abs_paths = self
13496 .abs_paths
13497 .into_iter()
13498 .map(|(abs_path, globset)| {
13499 let task = cx.spawn({
13500 let abs_path = abs_path.clone();
13501 let fs = fs.clone();
13502
13503 let lsp_store = lsp_store.clone();
13504 async move |_, cx| {
13505 maybe!(async move {
13506 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13507 while let Some(update) = push_updates.0.next().await {
13508 let action = lsp_store
13509 .update(cx, |this, _| {
13510 let Some(local) = this.as_local() else {
13511 return ControlFlow::Break(());
13512 };
13513 let Some(watcher) = local
13514 .language_server_watched_paths
13515 .get(&language_server_id)
13516 else {
13517 return ControlFlow::Break(());
13518 };
13519 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13520 "Watched abs path is not registered with a watcher",
13521 );
13522 let matching_entries = update
13523 .into_iter()
13524 .filter(|event| globs.is_match(&event.path))
13525 .collect::<Vec<_>>();
13526 this.lsp_notify_abs_paths_changed(
13527 language_server_id,
13528 matching_entries,
13529 );
13530 ControlFlow::Continue(())
13531 })
13532 .ok()?;
13533
13534 if action.is_break() {
13535 break;
13536 }
13537 }
13538 Some(())
13539 })
13540 .await;
13541 }
13542 });
13543 (abs_path, (globset, task))
13544 })
13545 .collect();
13546 LanguageServerWatchedPaths {
13547 worktree_paths: self.worktree_paths,
13548 abs_paths,
13549 }
13550 }
13551}
13552
13553struct LspBufferSnapshot {
13554 version: i32,
13555 snapshot: TextBufferSnapshot,
13556}
13557
13558/// A prompt requested by LSP server.
13559#[derive(Clone, Debug)]
13560pub struct LanguageServerPromptRequest {
13561 pub level: PromptLevel,
13562 pub message: String,
13563 pub actions: Vec<MessageActionItem>,
13564 pub lsp_name: String,
13565 pub(crate) response_channel: Sender<MessageActionItem>,
13566}
13567
13568impl LanguageServerPromptRequest {
13569 pub async fn respond(self, index: usize) -> Option<()> {
13570 if let Some(response) = self.actions.into_iter().nth(index) {
13571 self.response_channel.send(response).await.ok()
13572 } else {
13573 None
13574 }
13575 }
13576}
13577impl PartialEq for LanguageServerPromptRequest {
13578 fn eq(&self, other: &Self) -> bool {
13579 self.message == other.message && self.actions == other.actions
13580 }
13581}
13582
13583#[derive(Clone, Debug, PartialEq)]
13584pub enum LanguageServerLogType {
13585 Log(MessageType),
13586 Trace { verbose_info: Option<String> },
13587 Rpc { received: bool },
13588}
13589
13590impl LanguageServerLogType {
13591 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13592 match self {
13593 Self::Log(log_type) => {
13594 use proto::log_message::LogLevel;
13595 let level = match *log_type {
13596 MessageType::ERROR => LogLevel::Error,
13597 MessageType::WARNING => LogLevel::Warning,
13598 MessageType::INFO => LogLevel::Info,
13599 MessageType::LOG => LogLevel::Log,
13600 other => {
13601 log::warn!("Unknown lsp log message type: {other:?}");
13602 LogLevel::Log
13603 }
13604 };
13605 proto::language_server_log::LogType::Log(proto::LogMessage {
13606 level: level as i32,
13607 })
13608 }
13609 Self::Trace { verbose_info } => {
13610 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13611 verbose_info: verbose_info.to_owned(),
13612 })
13613 }
13614 Self::Rpc { received } => {
13615 let kind = if *received {
13616 proto::rpc_message::Kind::Received
13617 } else {
13618 proto::rpc_message::Kind::Sent
13619 };
13620 let kind = kind as i32;
13621 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13622 }
13623 }
13624 }
13625
13626 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13627 use proto::log_message::LogLevel;
13628 use proto::rpc_message;
13629 match log_type {
13630 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13631 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13632 LogLevel::Error => MessageType::ERROR,
13633 LogLevel::Warning => MessageType::WARNING,
13634 LogLevel::Info => MessageType::INFO,
13635 LogLevel::Log => MessageType::LOG,
13636 },
13637 ),
13638 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13639 verbose_info: trace_message.verbose_info,
13640 },
13641 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13642 received: match rpc_message::Kind::from_i32(message.kind)
13643 .unwrap_or(rpc_message::Kind::Received)
13644 {
13645 rpc_message::Kind::Received => true,
13646 rpc_message::Kind::Sent => false,
13647 },
13648 },
13649 }
13650 }
13651}
13652
13653pub struct WorkspaceRefreshTask {
13654 refresh_tx: mpsc::Sender<()>,
13655 progress_tx: mpsc::Sender<()>,
13656 #[allow(dead_code)]
13657 task: Task<()>,
13658}
13659
13660pub enum LanguageServerState {
13661 Starting {
13662 startup: Task<Option<Arc<LanguageServer>>>,
13663 /// List of language servers that will be added to the workspace once it's initialization completes.
13664 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13665 },
13666
13667 Running {
13668 adapter: Arc<CachedLspAdapter>,
13669 server: Arc<LanguageServer>,
13670 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13671 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13672 },
13673}
13674
13675impl LanguageServerState {
13676 fn add_workspace_folder(&self, uri: Uri) {
13677 match self {
13678 LanguageServerState::Starting {
13679 pending_workspace_folders,
13680 ..
13681 } => {
13682 pending_workspace_folders.lock().insert(uri);
13683 }
13684 LanguageServerState::Running { server, .. } => {
13685 server.add_workspace_folder(uri);
13686 }
13687 }
13688 }
13689 fn _remove_workspace_folder(&self, uri: Uri) {
13690 match self {
13691 LanguageServerState::Starting {
13692 pending_workspace_folders,
13693 ..
13694 } => {
13695 pending_workspace_folders.lock().remove(&uri);
13696 }
13697 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13698 }
13699 }
13700}
13701
13702impl std::fmt::Debug for LanguageServerState {
13703 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13704 match self {
13705 LanguageServerState::Starting { .. } => {
13706 f.debug_struct("LanguageServerState::Starting").finish()
13707 }
13708 LanguageServerState::Running { .. } => {
13709 f.debug_struct("LanguageServerState::Running").finish()
13710 }
13711 }
13712 }
13713}
13714
13715#[derive(Clone, Debug, Serialize)]
13716pub struct LanguageServerProgress {
13717 pub is_disk_based_diagnostics_progress: bool,
13718 pub is_cancellable: bool,
13719 pub title: Option<String>,
13720 pub message: Option<String>,
13721 pub percentage: Option<usize>,
13722 #[serde(skip_serializing)]
13723 pub last_update_at: Instant,
13724}
13725
13726#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13727pub struct DiagnosticSummary {
13728 pub error_count: usize,
13729 pub warning_count: usize,
13730}
13731
13732impl DiagnosticSummary {
13733 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13734 let mut this = Self {
13735 error_count: 0,
13736 warning_count: 0,
13737 };
13738
13739 for entry in diagnostics {
13740 if entry.diagnostic.is_primary {
13741 match entry.diagnostic.severity {
13742 DiagnosticSeverity::ERROR => this.error_count += 1,
13743 DiagnosticSeverity::WARNING => this.warning_count += 1,
13744 _ => {}
13745 }
13746 }
13747 }
13748
13749 this
13750 }
13751
13752 pub fn is_empty(&self) -> bool {
13753 self.error_count == 0 && self.warning_count == 0
13754 }
13755
13756 pub fn to_proto(
13757 self,
13758 language_server_id: LanguageServerId,
13759 path: &RelPath,
13760 ) -> proto::DiagnosticSummary {
13761 proto::DiagnosticSummary {
13762 path: path.to_proto(),
13763 language_server_id: language_server_id.0 as u64,
13764 error_count: self.error_count as u32,
13765 warning_count: self.warning_count as u32,
13766 }
13767 }
13768}
13769
13770#[derive(Clone, Debug)]
13771pub enum CompletionDocumentation {
13772 /// There is no documentation for this completion.
13773 Undocumented,
13774 /// A single line of documentation.
13775 SingleLine(SharedString),
13776 /// Multiple lines of plain text documentation.
13777 MultiLinePlainText(SharedString),
13778 /// Markdown documentation.
13779 MultiLineMarkdown(SharedString),
13780 /// Both single line and multiple lines of plain text documentation.
13781 SingleLineAndMultiLinePlainText {
13782 single_line: SharedString,
13783 plain_text: Option<SharedString>,
13784 },
13785}
13786
13787impl CompletionDocumentation {
13788 #[cfg(any(test, feature = "test-support"))]
13789 pub fn text(&self) -> SharedString {
13790 match self {
13791 CompletionDocumentation::Undocumented => "".into(),
13792 CompletionDocumentation::SingleLine(s) => s.clone(),
13793 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13794 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13795 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13796 single_line.clone()
13797 }
13798 }
13799 }
13800}
13801
13802impl From<lsp::Documentation> for CompletionDocumentation {
13803 fn from(docs: lsp::Documentation) -> Self {
13804 match docs {
13805 lsp::Documentation::String(text) => {
13806 if text.lines().count() <= 1 {
13807 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13808 } else {
13809 CompletionDocumentation::MultiLinePlainText(text.into())
13810 }
13811 }
13812
13813 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13814 lsp::MarkupKind::PlainText => {
13815 if value.lines().count() <= 1 {
13816 CompletionDocumentation::SingleLine(value.into())
13817 } else {
13818 CompletionDocumentation::MultiLinePlainText(value.into())
13819 }
13820 }
13821
13822 lsp::MarkupKind::Markdown => {
13823 CompletionDocumentation::MultiLineMarkdown(value.into())
13824 }
13825 },
13826 }
13827 }
13828}
13829
13830pub enum ResolvedHint {
13831 Resolved(InlayHint),
13832 Resolving(Shared<Task<()>>),
13833}
13834
13835fn glob_literal_prefix(glob: &Path) -> PathBuf {
13836 glob.components()
13837 .take_while(|component| match component {
13838 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13839 _ => true,
13840 })
13841 .collect()
13842}
13843
13844pub struct SshLspAdapter {
13845 name: LanguageServerName,
13846 binary: LanguageServerBinary,
13847 initialization_options: Option<String>,
13848 code_action_kinds: Option<Vec<CodeActionKind>>,
13849}
13850
13851impl SshLspAdapter {
13852 pub fn new(
13853 name: LanguageServerName,
13854 binary: LanguageServerBinary,
13855 initialization_options: Option<String>,
13856 code_action_kinds: Option<String>,
13857 ) -> Self {
13858 Self {
13859 name,
13860 binary,
13861 initialization_options,
13862 code_action_kinds: code_action_kinds
13863 .as_ref()
13864 .and_then(|c| serde_json::from_str(c).ok()),
13865 }
13866 }
13867}
13868
13869impl LspInstaller for SshLspAdapter {
13870 type BinaryVersion = ();
13871 async fn check_if_user_installed(
13872 &self,
13873 _: &dyn LspAdapterDelegate,
13874 _: Option<Toolchain>,
13875 _: &AsyncApp,
13876 ) -> Option<LanguageServerBinary> {
13877 Some(self.binary.clone())
13878 }
13879
13880 async fn cached_server_binary(
13881 &self,
13882 _: PathBuf,
13883 _: &dyn LspAdapterDelegate,
13884 ) -> Option<LanguageServerBinary> {
13885 None
13886 }
13887
13888 async fn fetch_latest_server_version(
13889 &self,
13890 _: &dyn LspAdapterDelegate,
13891 _: bool,
13892 _: &mut AsyncApp,
13893 ) -> Result<()> {
13894 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13895 }
13896
13897 async fn fetch_server_binary(
13898 &self,
13899 _: (),
13900 _: PathBuf,
13901 _: &dyn LspAdapterDelegate,
13902 ) -> Result<LanguageServerBinary> {
13903 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13904 }
13905}
13906
13907#[async_trait(?Send)]
13908impl LspAdapter for SshLspAdapter {
13909 fn name(&self) -> LanguageServerName {
13910 self.name.clone()
13911 }
13912
13913 async fn initialization_options(
13914 self: Arc<Self>,
13915 _: &Arc<dyn LspAdapterDelegate>,
13916 ) -> Result<Option<serde_json::Value>> {
13917 let Some(options) = &self.initialization_options else {
13918 return Ok(None);
13919 };
13920 let result = serde_json::from_str(options)?;
13921 Ok(result)
13922 }
13923
13924 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13925 self.code_action_kinds.clone()
13926 }
13927}
13928
13929pub fn language_server_settings<'a>(
13930 delegate: &'a dyn LspAdapterDelegate,
13931 language: &LanguageServerName,
13932 cx: &'a App,
13933) -> Option<&'a LspSettings> {
13934 language_server_settings_for(
13935 SettingsLocation {
13936 worktree_id: delegate.worktree_id(),
13937 path: RelPath::empty(),
13938 },
13939 language,
13940 cx,
13941 )
13942}
13943
13944pub fn language_server_settings_for<'a>(
13945 location: SettingsLocation<'a>,
13946 language: &LanguageServerName,
13947 cx: &'a App,
13948) -> Option<&'a LspSettings> {
13949 ProjectSettings::get(Some(location), cx).lsp.get(language)
13950}
13951
13952pub struct LocalLspAdapterDelegate {
13953 lsp_store: WeakEntity<LspStore>,
13954 worktree: worktree::Snapshot,
13955 fs: Arc<dyn Fs>,
13956 http_client: Arc<dyn HttpClient>,
13957 language_registry: Arc<LanguageRegistry>,
13958 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13959}
13960
13961impl LocalLspAdapterDelegate {
13962 pub fn new(
13963 language_registry: Arc<LanguageRegistry>,
13964 environment: &Entity<ProjectEnvironment>,
13965 lsp_store: WeakEntity<LspStore>,
13966 worktree: &Entity<Worktree>,
13967 http_client: Arc<dyn HttpClient>,
13968 fs: Arc<dyn Fs>,
13969 cx: &mut App,
13970 ) -> Arc<Self> {
13971 let load_shell_env_task =
13972 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13973
13974 Arc::new(Self {
13975 lsp_store,
13976 worktree: worktree.read(cx).snapshot(),
13977 fs,
13978 http_client,
13979 language_registry,
13980 load_shell_env_task,
13981 })
13982 }
13983
13984 fn from_local_lsp(
13985 local: &LocalLspStore,
13986 worktree: &Entity<Worktree>,
13987 cx: &mut App,
13988 ) -> Arc<Self> {
13989 Self::new(
13990 local.languages.clone(),
13991 &local.environment,
13992 local.weak.clone(),
13993 worktree,
13994 local.http_client.clone(),
13995 local.fs.clone(),
13996 cx,
13997 )
13998 }
13999}
14000
14001#[async_trait]
14002impl LspAdapterDelegate for LocalLspAdapterDelegate {
14003 fn show_notification(&self, message: &str, cx: &mut App) {
14004 self.lsp_store
14005 .update(cx, |_, cx| {
14006 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14007 })
14008 .ok();
14009 }
14010
14011 fn http_client(&self) -> Arc<dyn HttpClient> {
14012 self.http_client.clone()
14013 }
14014
14015 fn worktree_id(&self) -> WorktreeId {
14016 self.worktree.id()
14017 }
14018
14019 fn worktree_root_path(&self) -> &Path {
14020 self.worktree.abs_path().as_ref()
14021 }
14022
14023 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14024 self.worktree.resolve_executable_path(path)
14025 }
14026
14027 async fn shell_env(&self) -> HashMap<String, String> {
14028 let task = self.load_shell_env_task.clone();
14029 task.await.unwrap_or_default()
14030 }
14031
14032 async fn npm_package_installed_version(
14033 &self,
14034 package_name: &str,
14035 ) -> Result<Option<(PathBuf, Version)>> {
14036 let local_package_directory = self.worktree_root_path();
14037 let node_modules_directory = local_package_directory.join("node_modules");
14038
14039 if let Some(version) =
14040 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14041 {
14042 return Ok(Some((node_modules_directory, version)));
14043 }
14044 let Some(npm) = self.which("npm".as_ref()).await else {
14045 log::warn!(
14046 "Failed to find npm executable for {:?}",
14047 local_package_directory
14048 );
14049 return Ok(None);
14050 };
14051
14052 let env = self.shell_env().await;
14053 let output = util::command::new_smol_command(&npm)
14054 .args(["root", "-g"])
14055 .envs(env)
14056 .current_dir(local_package_directory)
14057 .output()
14058 .await?;
14059 let global_node_modules =
14060 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14061
14062 if let Some(version) =
14063 read_package_installed_version(global_node_modules.clone(), package_name).await?
14064 {
14065 return Ok(Some((global_node_modules, version)));
14066 }
14067 return Ok(None);
14068 }
14069
14070 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14071 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14072 if self.fs.is_file(&worktree_abs_path).await {
14073 worktree_abs_path.pop();
14074 }
14075
14076 let env = self.shell_env().await;
14077
14078 let shell_path = env.get("PATH").cloned();
14079
14080 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14081 }
14082
14083 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14084 let mut working_dir = self.worktree_root_path().to_path_buf();
14085 if self.fs.is_file(&working_dir).await {
14086 working_dir.pop();
14087 }
14088 let output = util::command::new_smol_command(&command.path)
14089 .args(command.arguments)
14090 .envs(command.env.clone().unwrap_or_default())
14091 .current_dir(working_dir)
14092 .output()
14093 .await?;
14094
14095 anyhow::ensure!(
14096 output.status.success(),
14097 "{}, stdout: {:?}, stderr: {:?}",
14098 output.status,
14099 String::from_utf8_lossy(&output.stdout),
14100 String::from_utf8_lossy(&output.stderr)
14101 );
14102 Ok(())
14103 }
14104
14105 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14106 self.language_registry
14107 .update_lsp_binary_status(server_name, status);
14108 }
14109
14110 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14111 self.language_registry
14112 .all_lsp_adapters()
14113 .into_iter()
14114 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14115 .collect()
14116 }
14117
14118 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14119 let dir = self.language_registry.language_server_download_dir(name)?;
14120
14121 if !dir.exists() {
14122 smol::fs::create_dir_all(&dir)
14123 .await
14124 .context("failed to create container directory")
14125 .log_err()?;
14126 }
14127
14128 Some(dir)
14129 }
14130
14131 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14132 let entry = self
14133 .worktree
14134 .entry_for_path(path)
14135 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14136 let abs_path = self.worktree.absolutize(&entry.path);
14137 self.fs.load(&abs_path).await
14138 }
14139}
14140
14141async fn populate_labels_for_symbols(
14142 symbols: Vec<CoreSymbol>,
14143 language_registry: &Arc<LanguageRegistry>,
14144 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14145 output: &mut Vec<Symbol>,
14146) {
14147 #[allow(clippy::mutable_key_type)]
14148 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14149
14150 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14151 for symbol in symbols {
14152 let Some(file_name) = symbol.path.file_name() else {
14153 continue;
14154 };
14155 let language = language_registry
14156 .load_language_for_file_path(Path::new(file_name))
14157 .await
14158 .ok()
14159 .or_else(|| {
14160 unknown_paths.insert(file_name.into());
14161 None
14162 });
14163 symbols_by_language
14164 .entry(language)
14165 .or_default()
14166 .push(symbol);
14167 }
14168
14169 for unknown_path in unknown_paths {
14170 log::info!("no language found for symbol in file {unknown_path:?}");
14171 }
14172
14173 let mut label_params = Vec::new();
14174 for (language, mut symbols) in symbols_by_language {
14175 label_params.clear();
14176 label_params.extend(
14177 symbols
14178 .iter_mut()
14179 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14180 );
14181
14182 let mut labels = Vec::new();
14183 if let Some(language) = language {
14184 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14185 language_registry
14186 .lsp_adapters(&language.name())
14187 .first()
14188 .cloned()
14189 });
14190 if let Some(lsp_adapter) = lsp_adapter {
14191 labels = lsp_adapter
14192 .labels_for_symbols(&label_params, &language)
14193 .await
14194 .log_err()
14195 .unwrap_or_default();
14196 }
14197 }
14198
14199 for ((symbol, (name, _)), label) in symbols
14200 .into_iter()
14201 .zip(label_params.drain(..))
14202 .zip(labels.into_iter().chain(iter::repeat(None)))
14203 {
14204 output.push(Symbol {
14205 language_server_name: symbol.language_server_name,
14206 source_worktree_id: symbol.source_worktree_id,
14207 source_language_server_id: symbol.source_language_server_id,
14208 path: symbol.path,
14209 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14210 name,
14211 kind: symbol.kind,
14212 range: symbol.range,
14213 });
14214 }
14215 }
14216}
14217
14218fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14219 match server.capabilities().text_document_sync.as_ref()? {
14220 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14221 // Server wants didSave but didn't specify includeText.
14222 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14223 // Server doesn't want didSave at all.
14224 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14225 // Server provided SaveOptions.
14226 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14227 Some(save_options.include_text.unwrap_or(false))
14228 }
14229 },
14230 // We do not have any save info. Kind affects didChange only.
14231 lsp::TextDocumentSyncCapability::Kind(_) => None,
14232 }
14233}
14234
14235/// Completion items are displayed in a `UniformList`.
14236/// Usually, those items are single-line strings, but in LSP responses,
14237/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14238/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14239/// 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,
14240/// breaking the completions menu presentation.
14241///
14242/// 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.
14243fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14244 let mut new_text = String::with_capacity(label.text.len());
14245 let mut offset_map = vec![0; label.text.len() + 1];
14246 let mut last_char_was_space = false;
14247 let mut new_idx = 0;
14248 let chars = label.text.char_indices().fuse();
14249 let mut newlines_removed = false;
14250
14251 for (idx, c) in chars {
14252 offset_map[idx] = new_idx;
14253
14254 match c {
14255 '\n' if last_char_was_space => {
14256 newlines_removed = true;
14257 }
14258 '\t' | ' ' if last_char_was_space => {}
14259 '\n' if !last_char_was_space => {
14260 new_text.push(' ');
14261 new_idx += 1;
14262 last_char_was_space = true;
14263 newlines_removed = true;
14264 }
14265 ' ' | '\t' => {
14266 new_text.push(' ');
14267 new_idx += 1;
14268 last_char_was_space = true;
14269 }
14270 _ => {
14271 new_text.push(c);
14272 new_idx += c.len_utf8();
14273 last_char_was_space = false;
14274 }
14275 }
14276 }
14277 offset_map[label.text.len()] = new_idx;
14278
14279 // Only modify the label if newlines were removed.
14280 if !newlines_removed {
14281 return;
14282 }
14283
14284 let last_index = new_idx;
14285 let mut run_ranges_errors = Vec::new();
14286 label.runs.retain_mut(|(range, _)| {
14287 match offset_map.get(range.start) {
14288 Some(&start) => range.start = start,
14289 None => {
14290 run_ranges_errors.push(range.clone());
14291 return false;
14292 }
14293 }
14294
14295 match offset_map.get(range.end) {
14296 Some(&end) => range.end = end,
14297 None => {
14298 run_ranges_errors.push(range.clone());
14299 range.end = last_index;
14300 }
14301 }
14302 true
14303 });
14304 if !run_ranges_errors.is_empty() {
14305 log::error!(
14306 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14307 label.text
14308 );
14309 }
14310
14311 let mut wrong_filter_range = None;
14312 if label.filter_range == (0..label.text.len()) {
14313 label.filter_range = 0..new_text.len();
14314 } else {
14315 let mut original_filter_range = Some(label.filter_range.clone());
14316 match offset_map.get(label.filter_range.start) {
14317 Some(&start) => label.filter_range.start = start,
14318 None => {
14319 wrong_filter_range = original_filter_range.take();
14320 label.filter_range.start = last_index;
14321 }
14322 }
14323
14324 match offset_map.get(label.filter_range.end) {
14325 Some(&end) => label.filter_range.end = end,
14326 None => {
14327 wrong_filter_range = original_filter_range.take();
14328 label.filter_range.end = last_index;
14329 }
14330 }
14331 }
14332 if let Some(wrong_filter_range) = wrong_filter_range {
14333 log::error!(
14334 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14335 label.text
14336 );
14337 }
14338
14339 label.text = new_text;
14340}
14341
14342#[cfg(test)]
14343mod tests {
14344 use language::HighlightId;
14345
14346 use super::*;
14347
14348 #[test]
14349 fn test_glob_literal_prefix() {
14350 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14351 assert_eq!(
14352 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14353 Path::new("node_modules")
14354 );
14355 assert_eq!(
14356 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14357 Path::new("foo")
14358 );
14359 assert_eq!(
14360 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14361 Path::new("foo/bar/baz.js")
14362 );
14363
14364 #[cfg(target_os = "windows")]
14365 {
14366 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14367 assert_eq!(
14368 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14369 Path::new("node_modules")
14370 );
14371 assert_eq!(
14372 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14373 Path::new("foo")
14374 );
14375 assert_eq!(
14376 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14377 Path::new("foo/bar/baz.js")
14378 );
14379 }
14380 }
14381
14382 #[test]
14383 fn test_multi_len_chars_normalization() {
14384 let mut label = CodeLabel::new(
14385 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14386 0..6,
14387 vec![(0..6, HighlightId(1))],
14388 );
14389 ensure_uniform_list_compatible_label(&mut label);
14390 assert_eq!(
14391 label,
14392 CodeLabel::new(
14393 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14394 0..6,
14395 vec![(0..6, HighlightId(1))],
14396 )
14397 );
14398 }
14399
14400 #[test]
14401 fn test_trailing_newline_in_completion_documentation() {
14402 let doc = lsp::Documentation::String(
14403 "Inappropriate argument value (of correct type).\n".to_string(),
14404 );
14405 let completion_doc: CompletionDocumentation = doc.into();
14406 assert!(
14407 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
14408 );
14409
14410 let doc = lsp::Documentation::String(" some value \n".to_string());
14411 let completion_doc: CompletionDocumentation = doc.into();
14412 assert!(matches!(
14413 completion_doc,
14414 CompletionDocumentation::SingleLine(s) if s == "some value"
14415 ));
14416 }
14417}