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::{BinarySettings, 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_anchor_range, deserialize_lsp_edit, deserialize_version,
73 serialize_anchor, serialize_anchor_range, 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 snippet::Snippet;
102use std::{
103 any::TypeId,
104 borrow::Cow,
105 cell::RefCell,
106 cmp::{Ordering, Reverse},
107 collections::{VecDeque, hash_map},
108 convert::TryInto,
109 ffi::OsStr,
110 future::ready,
111 iter, mem,
112 ops::{ControlFlow, Range},
113 path::{self, Path, PathBuf},
114 pin::pin,
115 rc::Rc,
116 sync::{
117 Arc,
118 atomic::{self, AtomicUsize},
119 },
120 time::{Duration, Instant},
121 vec,
122};
123use sum_tree::Dimensions;
124use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
125
126use util::{
127 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
128 paths::{PathStyle, SanitizedPath, UrlExt},
129 post_inc,
130 redact::redact_command,
131 rel_path::RelPath,
132};
133
134pub use fs::*;
135pub use language::Location;
136pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
137#[cfg(any(test, feature = "test-support"))]
138pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
139pub use worktree::{
140 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
141 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
142};
143
144const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
145pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
146const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
147const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
148static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
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/// Settings that affect language server identity.
230///
231/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
232/// updated via `workspace/didChangeConfiguration` without restarting the server.
233#[derive(Clone, Debug, Hash, PartialEq, Eq)]
234struct LanguageServerSeedSettings {
235 binary: Option<BinarySettings>,
236 initialization_options: Option<serde_json::Value>,
237}
238
239#[derive(Clone, Debug, Hash, PartialEq, Eq)]
240struct LanguageServerSeed {
241 worktree_id: WorktreeId,
242 name: LanguageServerName,
243 toolchain: Option<Toolchain>,
244 settings: LanguageServerSeedSettings,
245}
246
247#[derive(Debug)]
248pub struct DocumentDiagnosticsUpdate<'a, D> {
249 pub diagnostics: D,
250 pub result_id: Option<SharedString>,
251 pub registration_id: Option<SharedString>,
252 pub server_id: LanguageServerId,
253 pub disk_based_sources: Cow<'a, [String]>,
254}
255
256pub struct DocumentDiagnostics {
257 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
258 document_abs_path: PathBuf,
259 version: Option<i32>,
260}
261
262#[derive(Default, Debug)]
263struct DynamicRegistrations {
264 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
265 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
266}
267
268pub struct LocalLspStore {
269 weak: WeakEntity<LspStore>,
270 pub worktree_store: Entity<WorktreeStore>,
271 toolchain_store: Entity<LocalToolchainStore>,
272 http_client: Arc<dyn HttpClient>,
273 environment: Entity<ProjectEnvironment>,
274 fs: Arc<dyn Fs>,
275 languages: Arc<LanguageRegistry>,
276 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
277 yarn: Entity<YarnPathStore>,
278 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
279 buffers_being_formatted: HashSet<BufferId>,
280 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
281 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
282 watched_manifest_filenames: HashSet<ManifestName>,
283 language_server_paths_watched_for_rename:
284 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
285 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
286 supplementary_language_servers:
287 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
288 prettier_store: Entity<PrettierStore>,
289 next_diagnostic_group_id: usize,
290 diagnostics: HashMap<
291 WorktreeId,
292 HashMap<
293 Arc<RelPath>,
294 Vec<(
295 LanguageServerId,
296 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
297 )>,
298 >,
299 >,
300 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
301 _subscription: gpui::Subscription,
302 lsp_tree: LanguageServerTree,
303 registered_buffers: HashMap<BufferId, usize>,
304 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
305 buffer_pull_diagnostics_result_ids: HashMap<
306 LanguageServerId,
307 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
308 >,
309 workspace_pull_diagnostics_result_ids: HashMap<
310 LanguageServerId,
311 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
312 >,
313 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
314
315 buffers_to_refresh_hash_set: HashSet<BufferId>,
316 buffers_to_refresh_queue: VecDeque<BufferId>,
317 _background_diagnostics_worker: Shared<Task<()>>,
318}
319
320impl LocalLspStore {
321 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
322 pub fn running_language_server_for_id(
323 &self,
324 id: LanguageServerId,
325 ) -> Option<&Arc<LanguageServer>> {
326 let language_server_state = self.language_servers.get(&id)?;
327
328 match language_server_state {
329 LanguageServerState::Running { server, .. } => Some(server),
330 LanguageServerState::Starting { .. } => None,
331 }
332 }
333
334 fn get_or_insert_language_server(
335 &mut self,
336 worktree_handle: &Entity<Worktree>,
337 delegate: Arc<LocalLspAdapterDelegate>,
338 disposition: &Arc<LaunchDisposition>,
339 language_name: &LanguageName,
340 cx: &mut App,
341 ) -> LanguageServerId {
342 let key = LanguageServerSeed {
343 worktree_id: worktree_handle.read(cx).id(),
344 name: disposition.server_name.clone(),
345 settings: LanguageServerSeedSettings {
346 binary: disposition.settings.binary.clone(),
347 initialization_options: disposition.settings.initialization_options.clone(),
348 },
349 toolchain: disposition.toolchain.clone(),
350 };
351 if let Some(state) = self.language_server_ids.get_mut(&key) {
352 state.project_roots.insert(disposition.path.path.clone());
353 state.id
354 } else {
355 let adapter = self
356 .languages
357 .lsp_adapters(language_name)
358 .into_iter()
359 .find(|adapter| adapter.name() == disposition.server_name)
360 .expect("To find LSP adapter");
361 let new_language_server_id = self.start_language_server(
362 worktree_handle,
363 delegate,
364 adapter,
365 disposition.settings.clone(),
366 key.clone(),
367 cx,
368 );
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 } else {
372 debug_assert!(
373 false,
374 "Expected `start_language_server` to ensure that `key` exists in a map"
375 );
376 }
377 new_language_server_id
378 }
379 }
380
381 fn start_language_server(
382 &mut self,
383 worktree_handle: &Entity<Worktree>,
384 delegate: Arc<LocalLspAdapterDelegate>,
385 adapter: Arc<CachedLspAdapter>,
386 settings: Arc<LspSettings>,
387 key: LanguageServerSeed,
388 cx: &mut App,
389 ) -> LanguageServerId {
390 let worktree = worktree_handle.read(cx);
391
392 let worktree_id = worktree.id();
393 let worktree_abs_path = worktree.abs_path();
394 let toolchain = key.toolchain.clone();
395 let override_options = settings.initialization_options.clone();
396
397 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
398
399 let server_id = self.languages.next_language_server_id();
400 log::trace!(
401 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
402 adapter.name.0
403 );
404
405 let wait_until_worktree_trust =
406 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
407 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
408 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
409 });
410 if can_trust {
411 self.restricted_worktrees_tasks.remove(&worktree_id);
412 None
413 } else {
414 match self.restricted_worktrees_tasks.entry(worktree_id) {
415 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
416 hash_map::Entry::Vacant(v) => {
417 let (mut tx, rx) = watch::channel::<bool>();
418 let lsp_store = self.weak.clone();
419 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
420 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
421 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
422 tx.blocking_send(true).ok();
423 lsp_store
424 .update(cx, |lsp_store, _| {
425 if let Some(local_lsp_store) =
426 lsp_store.as_local_mut()
427 {
428 local_lsp_store
429 .restricted_worktrees_tasks
430 .remove(&worktree_id);
431 }
432 })
433 .ok();
434 }
435 }
436 });
437 v.insert((subscription, rx.clone()));
438 Some(rx)
439 }
440 }
441 }
442 });
443 let update_binary_status = wait_until_worktree_trust.is_none();
444
445 let binary = self.get_language_server_binary(
446 worktree_abs_path.clone(),
447 adapter.clone(),
448 settings,
449 toolchain.clone(),
450 delegate.clone(),
451 true,
452 wait_until_worktree_trust,
453 cx,
454 );
455 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
456
457 let pending_server = cx.spawn({
458 let adapter = adapter.clone();
459 let server_name = adapter.name.clone();
460 let stderr_capture = stderr_capture.clone();
461 #[cfg(any(test, feature = "test-support"))]
462 let lsp_store = self.weak.clone();
463 let pending_workspace_folders = pending_workspace_folders.clone();
464 async move |cx| {
465 let binary = binary.await?;
466 #[cfg(any(test, feature = "test-support"))]
467 if let Some(server) = lsp_store
468 .update(&mut cx.clone(), |this, cx| {
469 this.languages.create_fake_language_server(
470 server_id,
471 &server_name,
472 binary.clone(),
473 &mut cx.to_async(),
474 )
475 })
476 .ok()
477 .flatten()
478 {
479 return Ok(server);
480 }
481
482 let code_action_kinds = adapter.code_action_kinds();
483 lsp::LanguageServer::new(
484 stderr_capture,
485 server_id,
486 server_name,
487 binary,
488 &worktree_abs_path,
489 code_action_kinds,
490 Some(pending_workspace_folders),
491 cx,
492 )
493 }
494 });
495
496 let startup = {
497 let server_name = adapter.name.0.clone();
498 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
499 let key = key.clone();
500 let adapter = adapter.clone();
501 let lsp_store = self.weak.clone();
502 let pending_workspace_folders = pending_workspace_folders.clone();
503
504 let pull_diagnostics = ProjectSettings::get_global(cx)
505 .diagnostics
506 .lsp_pull_diagnostics
507 .enabled;
508 cx.spawn(async move |cx| {
509 let result = async {
510 let language_server = pending_server.await?;
511
512 let workspace_config = Self::workspace_configuration_for_adapter(
513 adapter.adapter.clone(),
514 &delegate,
515 toolchain,
516 None,
517 cx,
518 )
519 .await?;
520
521 let mut initialization_options = Self::initialization_options_for_adapter(
522 adapter.adapter.clone(),
523 &delegate,
524 )
525 .await?;
526
527 match (&mut initialization_options, override_options) {
528 (Some(initialization_options), Some(override_options)) => {
529 merge_json_value_into(override_options, initialization_options);
530 }
531 (None, override_options) => initialization_options = override_options,
532 _ => {}
533 }
534
535 let initialization_params = cx.update(|cx| {
536 let mut params =
537 language_server.default_initialize_params(pull_diagnostics, cx);
538 params.initialization_options = initialization_options;
539 adapter.adapter.prepare_initialize_params(params, cx)
540 })?;
541
542 Self::setup_lsp_messages(
543 lsp_store.clone(),
544 &language_server,
545 delegate.clone(),
546 adapter.clone(),
547 );
548
549 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
550 settings: workspace_config,
551 };
552 let language_server = cx
553 .update(|cx| {
554 language_server.initialize(
555 initialization_params,
556 Arc::new(did_change_configuration_params.clone()),
557 cx,
558 )
559 })
560 .await
561 .inspect_err(|_| {
562 if let Some(lsp_store) = lsp_store.upgrade() {
563 lsp_store.update(cx, |lsp_store, cx| {
564 lsp_store.cleanup_lsp_data(server_id);
565 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
566 });
567 }
568 })?;
569
570 language_server.notify::<lsp::notification::DidChangeConfiguration>(
571 did_change_configuration_params,
572 )?;
573
574 anyhow::Ok(language_server)
575 }
576 .await;
577
578 match result {
579 Ok(server) => {
580 lsp_store
581 .update(cx, |lsp_store, cx| {
582 lsp_store.insert_newly_running_language_server(
583 adapter,
584 server.clone(),
585 server_id,
586 key,
587 pending_workspace_folders,
588 cx,
589 );
590 })
591 .ok();
592 stderr_capture.lock().take();
593 Some(server)
594 }
595
596 Err(err) => {
597 let log = stderr_capture.lock().take().unwrap_or_default();
598 delegate.update_status(
599 adapter.name(),
600 BinaryStatus::Failed {
601 error: if log.is_empty() {
602 format!("{err:#}")
603 } else {
604 format!("{err:#}\n-- stderr --\n{log}")
605 },
606 },
607 );
608 log::error!(
609 "Failed to start language server {server_name:?}: {}",
610 redact_command(&format!("{err:?}"))
611 );
612 if !log.is_empty() {
613 log::error!("server stderr: {}", redact_command(&log));
614 }
615 None
616 }
617 }
618 })
619 };
620 let state = LanguageServerState::Starting {
621 startup,
622 pending_workspace_folders,
623 };
624
625 if update_binary_status {
626 self.languages
627 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
628 }
629
630 self.language_servers.insert(server_id, state);
631 self.language_server_ids
632 .entry(key)
633 .or_insert(UnifiedLanguageServer {
634 id: server_id,
635 project_roots: Default::default(),
636 });
637 server_id
638 }
639
640 fn get_language_server_binary(
641 &self,
642 worktree_abs_path: Arc<Path>,
643 adapter: Arc<CachedLspAdapter>,
644 settings: Arc<LspSettings>,
645 toolchain: Option<Toolchain>,
646 delegate: Arc<dyn LspAdapterDelegate>,
647 allow_binary_download: bool,
648 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
649 cx: &mut App,
650 ) -> Task<Result<LanguageServerBinary>> {
651 if let Some(settings) = &settings.binary
652 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
653 {
654 let settings = settings.clone();
655 let languages = self.languages.clone();
656 return cx.background_spawn(async move {
657 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
658 let already_trusted = *wait_until_worktree_trust.borrow();
659 if !already_trusted {
660 log::info!(
661 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
662 adapter.name(),
663 );
664 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
665 if worktree_trusted {
666 break;
667 }
668 }
669 log::info!(
670 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
671 adapter.name(),
672 );
673 }
674 languages
675 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
676 }
677 let mut env = delegate.shell_env().await;
678 env.extend(settings.env.unwrap_or_default());
679
680 Ok(LanguageServerBinary {
681 path: delegate.resolve_executable_path(path),
682 env: Some(env),
683 arguments: settings
684 .arguments
685 .unwrap_or_default()
686 .iter()
687 .map(Into::into)
688 .collect(),
689 })
690 });
691 }
692 let lsp_binary_options = LanguageServerBinaryOptions {
693 allow_path_lookup: !settings
694 .binary
695 .as_ref()
696 .and_then(|b| b.ignore_system_version)
697 .unwrap_or_default(),
698 allow_binary_download,
699 pre_release: settings
700 .fetch
701 .as_ref()
702 .and_then(|f| f.pre_release)
703 .unwrap_or(false),
704 };
705
706 cx.spawn(async move |cx| {
707 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
708 let already_trusted = *wait_until_worktree_trust.borrow();
709 if !already_trusted {
710 log::info!(
711 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
712 adapter.name(),
713 );
714 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
715 if worktree_trusted {
716 break;
717 }
718 }
719 log::info!(
720 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
721 adapter.name(),
722 );
723 }
724 }
725
726 let (existing_binary, maybe_download_binary) = adapter
727 .clone()
728 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
729 .await
730 .await;
731
732 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
733
734 let mut binary = match (existing_binary, maybe_download_binary) {
735 (binary, None) => binary?,
736 (Err(_), Some(downloader)) => downloader.await?,
737 (Ok(existing_binary), Some(downloader)) => {
738 let mut download_timeout = cx
739 .background_executor()
740 .timer(SERVER_DOWNLOAD_TIMEOUT)
741 .fuse();
742 let mut downloader = downloader.fuse();
743 futures::select! {
744 _ = download_timeout => {
745 // Return existing binary and kick the existing work to the background.
746 cx.spawn(async move |_| downloader.await).detach();
747 Ok(existing_binary)
748 },
749 downloaded_or_existing_binary = downloader => {
750 // If download fails, this results in the existing binary.
751 downloaded_or_existing_binary
752 }
753 }?
754 }
755 };
756 let mut shell_env = delegate.shell_env().await;
757
758 shell_env.extend(binary.env.unwrap_or_default());
759
760 if let Some(settings) = settings.binary.as_ref() {
761 if let Some(arguments) = &settings.arguments {
762 binary.arguments = arguments.iter().map(Into::into).collect();
763 }
764 if let Some(env) = &settings.env {
765 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
766 }
767 }
768
769 binary.env = Some(shell_env);
770 Ok(binary)
771 })
772 }
773
774 fn setup_lsp_messages(
775 lsp_store: WeakEntity<LspStore>,
776 language_server: &LanguageServer,
777 delegate: Arc<dyn LspAdapterDelegate>,
778 adapter: Arc<CachedLspAdapter>,
779 ) {
780 let name = language_server.name();
781 let server_id = language_server.server_id();
782 language_server
783 .on_notification::<lsp::notification::PublishDiagnostics, _>({
784 let adapter = adapter.clone();
785 let this = lsp_store.clone();
786 move |mut params, cx| {
787 let adapter = adapter.clone();
788 if let Some(this) = this.upgrade() {
789 this.update(cx, |this, cx| {
790 {
791 let buffer = params
792 .uri
793 .to_file_path()
794 .map(|file_path| this.get_buffer(&file_path, cx))
795 .ok()
796 .flatten();
797 adapter.process_diagnostics(&mut params, server_id, buffer);
798 }
799
800 this.merge_lsp_diagnostics(
801 DiagnosticSourceKind::Pushed,
802 vec![DocumentDiagnosticsUpdate {
803 server_id,
804 diagnostics: params,
805 result_id: None,
806 disk_based_sources: Cow::Borrowed(
807 &adapter.disk_based_diagnostic_sources,
808 ),
809 registration_id: None,
810 }],
811 |_, diagnostic, cx| match diagnostic.source_kind {
812 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
813 adapter.retain_old_diagnostic(diagnostic, cx)
814 }
815 DiagnosticSourceKind::Pulled => true,
816 },
817 cx,
818 )
819 .log_err();
820 });
821 }
822 }
823 })
824 .detach();
825 language_server
826 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
827 let adapter = adapter.adapter.clone();
828 let delegate = delegate.clone();
829 let this = lsp_store.clone();
830 move |params, cx| {
831 let adapter = adapter.clone();
832 let delegate = delegate.clone();
833 let this = this.clone();
834 let mut cx = cx.clone();
835 async move {
836 let toolchain_for_id = this
837 .update(&mut cx, |this, _| {
838 this.as_local()?.language_server_ids.iter().find_map(
839 |(seed, value)| {
840 (value.id == server_id).then(|| seed.toolchain.clone())
841 },
842 )
843 })?
844 .context("Expected the LSP store to be in a local mode")?;
845
846 let mut scope_uri_to_workspace_config = BTreeMap::new();
847 for item in ¶ms.items {
848 let scope_uri = item.scope_uri.clone();
849 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
850 scope_uri_to_workspace_config.entry(scope_uri.clone())
851 else {
852 // We've already queried workspace configuration of this URI.
853 continue;
854 };
855 let workspace_config = Self::workspace_configuration_for_adapter(
856 adapter.clone(),
857 &delegate,
858 toolchain_for_id.clone(),
859 scope_uri,
860 &mut cx,
861 )
862 .await?;
863 new_scope_uri.insert(workspace_config);
864 }
865
866 Ok(params
867 .items
868 .into_iter()
869 .filter_map(|item| {
870 let workspace_config =
871 scope_uri_to_workspace_config.get(&item.scope_uri)?;
872 if let Some(section) = &item.section {
873 Some(
874 workspace_config
875 .get(section)
876 .cloned()
877 .unwrap_or(serde_json::Value::Null),
878 )
879 } else {
880 Some(workspace_config.clone())
881 }
882 })
883 .collect())
884 }
885 }
886 })
887 .detach();
888
889 language_server
890 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
891 let this = lsp_store.clone();
892 move |_, cx| {
893 let this = this.clone();
894 let cx = cx.clone();
895 async move {
896 let Some(server) =
897 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
898 else {
899 return Ok(None);
900 };
901 let root = server.workspace_folders();
902 Ok(Some(
903 root.into_iter()
904 .map(|uri| WorkspaceFolder {
905 uri,
906 name: Default::default(),
907 })
908 .collect(),
909 ))
910 }
911 }
912 })
913 .detach();
914 // Even though we don't have handling for these requests, respond to them to
915 // avoid stalling any language server like `gopls` which waits for a response
916 // to these requests when initializing.
917 language_server
918 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
919 let this = lsp_store.clone();
920 move |params, cx| {
921 let this = this.clone();
922 let mut cx = cx.clone();
923 async move {
924 this.update(&mut cx, |this, _| {
925 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
926 {
927 status
928 .progress_tokens
929 .insert(ProgressToken::from_lsp(params.token));
930 }
931 })?;
932
933 Ok(())
934 }
935 }
936 })
937 .detach();
938
939 language_server
940 .on_request::<lsp::request::RegisterCapability, _, _>({
941 let lsp_store = lsp_store.clone();
942 move |params, cx| {
943 let lsp_store = lsp_store.clone();
944 let mut cx = cx.clone();
945 async move {
946 lsp_store
947 .update(&mut cx, |lsp_store, cx| {
948 if lsp_store.as_local().is_some() {
949 match lsp_store
950 .register_server_capabilities(server_id, params, cx)
951 {
952 Ok(()) => {}
953 Err(e) => {
954 log::error!(
955 "Failed to register server capabilities: {e:#}"
956 );
957 }
958 };
959 }
960 })
961 .ok();
962 Ok(())
963 }
964 }
965 })
966 .detach();
967
968 language_server
969 .on_request::<lsp::request::UnregisterCapability, _, _>({
970 let lsp_store = lsp_store.clone();
971 move |params, cx| {
972 let lsp_store = lsp_store.clone();
973 let mut cx = cx.clone();
974 async move {
975 lsp_store
976 .update(&mut cx, |lsp_store, cx| {
977 if lsp_store.as_local().is_some() {
978 match lsp_store
979 .unregister_server_capabilities(server_id, params, cx)
980 {
981 Ok(()) => {}
982 Err(e) => {
983 log::error!(
984 "Failed to unregister server capabilities: {e:#}"
985 );
986 }
987 }
988 }
989 })
990 .ok();
991 Ok(())
992 }
993 }
994 })
995 .detach();
996
997 language_server
998 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
999 let this = lsp_store.clone();
1000 move |params, cx| {
1001 let mut cx = cx.clone();
1002 let this = this.clone();
1003 async move {
1004 LocalLspStore::on_lsp_workspace_edit(
1005 this.clone(),
1006 params,
1007 server_id,
1008 &mut cx,
1009 )
1010 .await
1011 }
1012 }
1013 })
1014 .detach();
1015
1016 language_server
1017 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1018 let lsp_store = lsp_store.clone();
1019 let request_id = Arc::new(AtomicUsize::new(0));
1020 move |(), cx| {
1021 let lsp_store = lsp_store.clone();
1022 let request_id = request_id.clone();
1023 let mut cx = cx.clone();
1024 async move {
1025 lsp_store
1026 .update(&mut cx, |lsp_store, cx| {
1027 let request_id =
1028 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1029 cx.emit(LspStoreEvent::RefreshInlayHints {
1030 server_id,
1031 request_id,
1032 });
1033 lsp_store
1034 .downstream_client
1035 .as_ref()
1036 .map(|(client, project_id)| {
1037 client.send(proto::RefreshInlayHints {
1038 project_id: *project_id,
1039 server_id: server_id.to_proto(),
1040 request_id: request_id.map(|id| id as u64),
1041 })
1042 })
1043 })?
1044 .transpose()?;
1045 Ok(())
1046 }
1047 }
1048 })
1049 .detach();
1050
1051 language_server
1052 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1053 let this = lsp_store.clone();
1054 move |(), cx| {
1055 let this = this.clone();
1056 let mut cx = cx.clone();
1057 async move {
1058 this.update(&mut cx, |this, cx| {
1059 cx.emit(LspStoreEvent::RefreshCodeLens);
1060 this.downstream_client.as_ref().map(|(client, project_id)| {
1061 client.send(proto::RefreshCodeLens {
1062 project_id: *project_id,
1063 })
1064 })
1065 })?
1066 .transpose()?;
1067 Ok(())
1068 }
1069 }
1070 })
1071 .detach();
1072
1073 language_server
1074 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1075 let this = lsp_store.clone();
1076 move |(), cx| {
1077 let this = this.clone();
1078 let mut cx = cx.clone();
1079 async move {
1080 this.update(&mut cx, |lsp_store, cx| {
1081 lsp_store.pull_workspace_diagnostics(server_id);
1082 lsp_store
1083 .downstream_client
1084 .as_ref()
1085 .map(|(client, project_id)| {
1086 client.send(proto::PullWorkspaceDiagnostics {
1087 project_id: *project_id,
1088 server_id: server_id.to_proto(),
1089 })
1090 })
1091 .transpose()?;
1092 anyhow::Ok(
1093 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1094 )
1095 })??
1096 .await;
1097 Ok(())
1098 }
1099 }
1100 })
1101 .detach();
1102
1103 language_server
1104 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1105 let this = lsp_store.clone();
1106 let name = name.to_string();
1107 let adapter = adapter.clone();
1108 move |params, cx| {
1109 let this = this.clone();
1110 let name = name.to_string();
1111 let adapter = adapter.clone();
1112 let mut cx = cx.clone();
1113 async move {
1114 let actions = params.actions.unwrap_or_default();
1115 let message = params.message.clone();
1116 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1117 let level = match params.typ {
1118 lsp::MessageType::ERROR => PromptLevel::Critical,
1119 lsp::MessageType::WARNING => PromptLevel::Warning,
1120 _ => PromptLevel::Info,
1121 };
1122 let request = LanguageServerPromptRequest::new(
1123 level,
1124 params.message,
1125 actions,
1126 name.clone(),
1127 tx,
1128 );
1129
1130 let did_update = this
1131 .update(&mut cx, |_, cx| {
1132 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1133 })
1134 .is_ok();
1135 if did_update {
1136 let response = rx.recv().await.ok();
1137 if let Some(ref selected_action) = response {
1138 let context = language::PromptResponseContext {
1139 message,
1140 selected_action: selected_action.clone(),
1141 };
1142 adapter.process_prompt_response(&context, &mut cx)
1143 }
1144
1145 Ok(response)
1146 } else {
1147 Ok(None)
1148 }
1149 }
1150 }
1151 })
1152 .detach();
1153 language_server
1154 .on_notification::<lsp::notification::ShowMessage, _>({
1155 let this = lsp_store.clone();
1156 let name = name.to_string();
1157 move |params, cx| {
1158 let this = this.clone();
1159 let name = name.to_string();
1160 let mut cx = cx.clone();
1161
1162 let (tx, _) = smol::channel::bounded(1);
1163 let level = match params.typ {
1164 lsp::MessageType::ERROR => PromptLevel::Critical,
1165 lsp::MessageType::WARNING => PromptLevel::Warning,
1166 _ => PromptLevel::Info,
1167 };
1168 let request =
1169 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1170
1171 let _ = this.update(&mut cx, |_, cx| {
1172 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1173 });
1174 }
1175 })
1176 .detach();
1177
1178 let disk_based_diagnostics_progress_token =
1179 adapter.disk_based_diagnostics_progress_token.clone();
1180
1181 language_server
1182 .on_notification::<lsp::notification::Progress, _>({
1183 let this = lsp_store.clone();
1184 move |params, cx| {
1185 if let Some(this) = this.upgrade() {
1186 this.update(cx, |this, cx| {
1187 this.on_lsp_progress(
1188 params,
1189 server_id,
1190 disk_based_diagnostics_progress_token.clone(),
1191 cx,
1192 );
1193 });
1194 }
1195 }
1196 })
1197 .detach();
1198
1199 language_server
1200 .on_notification::<lsp::notification::LogMessage, _>({
1201 let this = lsp_store.clone();
1202 move |params, cx| {
1203 if let Some(this) = this.upgrade() {
1204 this.update(cx, |_, cx| {
1205 cx.emit(LspStoreEvent::LanguageServerLog(
1206 server_id,
1207 LanguageServerLogType::Log(params.typ),
1208 params.message,
1209 ));
1210 });
1211 }
1212 }
1213 })
1214 .detach();
1215
1216 language_server
1217 .on_notification::<lsp::notification::LogTrace, _>({
1218 let this = lsp_store.clone();
1219 move |params, cx| {
1220 let mut cx = cx.clone();
1221 if let Some(this) = this.upgrade() {
1222 this.update(&mut cx, |_, cx| {
1223 cx.emit(LspStoreEvent::LanguageServerLog(
1224 server_id,
1225 LanguageServerLogType::Trace {
1226 verbose_info: params.verbose,
1227 },
1228 params.message,
1229 ));
1230 });
1231 }
1232 }
1233 })
1234 .detach();
1235
1236 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1237 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1238 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1239 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1240 }
1241
1242 fn shutdown_language_servers_on_quit(
1243 &mut self,
1244 _: &mut Context<LspStore>,
1245 ) -> impl Future<Output = ()> + use<> {
1246 let shutdown_futures = self
1247 .language_servers
1248 .drain()
1249 .map(|(_, server_state)| Self::shutdown_server(server_state))
1250 .collect::<Vec<_>>();
1251
1252 async move {
1253 join_all(shutdown_futures).await;
1254 }
1255 }
1256
1257 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1258 match server_state {
1259 LanguageServerState::Running { server, .. } => {
1260 if let Some(shutdown) = server.shutdown() {
1261 shutdown.await;
1262 }
1263 }
1264 LanguageServerState::Starting { startup, .. } => {
1265 if let Some(server) = startup.await
1266 && let Some(shutdown) = server.shutdown()
1267 {
1268 shutdown.await;
1269 }
1270 }
1271 }
1272 Ok(())
1273 }
1274
1275 fn language_servers_for_worktree(
1276 &self,
1277 worktree_id: WorktreeId,
1278 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1279 self.language_server_ids
1280 .iter()
1281 .filter_map(move |(seed, state)| {
1282 if seed.worktree_id != worktree_id {
1283 return None;
1284 }
1285
1286 if let Some(LanguageServerState::Running { server, .. }) =
1287 self.language_servers.get(&state.id)
1288 {
1289 Some(server)
1290 } else {
1291 None
1292 }
1293 })
1294 }
1295
1296 fn language_server_ids_for_project_path(
1297 &self,
1298 project_path: ProjectPath,
1299 language: &Language,
1300 cx: &mut App,
1301 ) -> Vec<LanguageServerId> {
1302 let Some(worktree) = self
1303 .worktree_store
1304 .read(cx)
1305 .worktree_for_id(project_path.worktree_id, cx)
1306 else {
1307 return Vec::new();
1308 };
1309 let delegate: Arc<dyn ManifestDelegate> =
1310 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1311
1312 self.lsp_tree
1313 .get(
1314 project_path,
1315 language.name(),
1316 language.manifest(),
1317 &delegate,
1318 cx,
1319 )
1320 .collect::<Vec<_>>()
1321 }
1322
1323 fn language_server_ids_for_buffer(
1324 &self,
1325 buffer: &Buffer,
1326 cx: &mut App,
1327 ) -> Vec<LanguageServerId> {
1328 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1329 let worktree_id = file.worktree_id(cx);
1330
1331 let path: Arc<RelPath> = file
1332 .path()
1333 .parent()
1334 .map(Arc::from)
1335 .unwrap_or_else(|| file.path().clone());
1336 let worktree_path = ProjectPath { worktree_id, path };
1337 self.language_server_ids_for_project_path(worktree_path, language, cx)
1338 } else {
1339 Vec::new()
1340 }
1341 }
1342
1343 fn language_servers_for_buffer<'a>(
1344 &'a self,
1345 buffer: &'a Buffer,
1346 cx: &'a mut App,
1347 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1348 self.language_server_ids_for_buffer(buffer, cx)
1349 .into_iter()
1350 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1351 LanguageServerState::Running {
1352 adapter, server, ..
1353 } => Some((adapter, server)),
1354 _ => None,
1355 })
1356 }
1357
1358 async fn execute_code_action_kind_locally(
1359 lsp_store: WeakEntity<LspStore>,
1360 mut buffers: Vec<Entity<Buffer>>,
1361 kind: CodeActionKind,
1362 push_to_history: bool,
1363 cx: &mut AsyncApp,
1364 ) -> anyhow::Result<ProjectTransaction> {
1365 // Do not allow multiple concurrent code actions requests for the
1366 // same buffer.
1367 lsp_store.update(cx, |this, cx| {
1368 let this = this.as_local_mut().unwrap();
1369 buffers.retain(|buffer| {
1370 this.buffers_being_formatted
1371 .insert(buffer.read(cx).remote_id())
1372 });
1373 })?;
1374 let _cleanup = defer({
1375 let this = lsp_store.clone();
1376 let mut cx = cx.clone();
1377 let buffers = &buffers;
1378 move || {
1379 this.update(&mut cx, |this, cx| {
1380 let this = this.as_local_mut().unwrap();
1381 for buffer in buffers {
1382 this.buffers_being_formatted
1383 .remove(&buffer.read(cx).remote_id());
1384 }
1385 })
1386 .ok();
1387 }
1388 });
1389 let mut project_transaction = ProjectTransaction::default();
1390
1391 for buffer in &buffers {
1392 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1393 buffer.update(cx, |buffer, cx| {
1394 lsp_store
1395 .as_local()
1396 .unwrap()
1397 .language_servers_for_buffer(buffer, cx)
1398 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1399 .collect::<Vec<_>>()
1400 })
1401 })?;
1402 for (_, language_server) in adapters_and_servers.iter() {
1403 let actions = Self::get_server_code_actions_from_action_kinds(
1404 &lsp_store,
1405 language_server.server_id(),
1406 vec![kind.clone()],
1407 buffer,
1408 cx,
1409 )
1410 .await?;
1411 Self::execute_code_actions_on_server(
1412 &lsp_store,
1413 language_server,
1414 actions,
1415 push_to_history,
1416 &mut project_transaction,
1417 cx,
1418 )
1419 .await?;
1420 }
1421 }
1422 Ok(project_transaction)
1423 }
1424
1425 async fn format_locally(
1426 lsp_store: WeakEntity<LspStore>,
1427 mut buffers: Vec<FormattableBuffer>,
1428 push_to_history: bool,
1429 trigger: FormatTrigger,
1430 logger: zlog::Logger,
1431 cx: &mut AsyncApp,
1432 ) -> anyhow::Result<ProjectTransaction> {
1433 // Do not allow multiple concurrent formatting requests for the
1434 // same buffer.
1435 lsp_store.update(cx, |this, cx| {
1436 let this = this.as_local_mut().unwrap();
1437 buffers.retain(|buffer| {
1438 this.buffers_being_formatted
1439 .insert(buffer.handle.read(cx).remote_id())
1440 });
1441 })?;
1442
1443 let _cleanup = defer({
1444 let this = lsp_store.clone();
1445 let mut cx = cx.clone();
1446 let buffers = &buffers;
1447 move || {
1448 this.update(&mut cx, |this, cx| {
1449 let this = this.as_local_mut().unwrap();
1450 for buffer in buffers {
1451 this.buffers_being_formatted
1452 .remove(&buffer.handle.read(cx).remote_id());
1453 }
1454 })
1455 .ok();
1456 }
1457 });
1458
1459 let mut project_transaction = ProjectTransaction::default();
1460
1461 for buffer in &buffers {
1462 zlog::debug!(
1463 logger =>
1464 "formatting buffer '{:?}'",
1465 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1466 );
1467 // Create an empty transaction to hold all of the formatting edits.
1468 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1469 // ensure no transactions created while formatting are
1470 // grouped with the previous transaction in the history
1471 // based on the transaction group interval
1472 buffer.finalize_last_transaction();
1473 buffer
1474 .start_transaction()
1475 .context("transaction already open")?;
1476 buffer.end_transaction(cx);
1477 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1478 buffer.finalize_last_transaction();
1479 anyhow::Ok(transaction_id)
1480 })?;
1481
1482 let result = Self::format_buffer_locally(
1483 lsp_store.clone(),
1484 buffer,
1485 formatting_transaction_id,
1486 trigger,
1487 logger,
1488 cx,
1489 )
1490 .await;
1491
1492 buffer.handle.update(cx, |buffer, cx| {
1493 let Some(formatting_transaction) =
1494 buffer.get_transaction(formatting_transaction_id).cloned()
1495 else {
1496 zlog::warn!(logger => "no formatting transaction");
1497 return;
1498 };
1499 if formatting_transaction.edit_ids.is_empty() {
1500 zlog::debug!(logger => "no changes made while formatting");
1501 buffer.forget_transaction(formatting_transaction_id);
1502 return;
1503 }
1504 if !push_to_history {
1505 zlog::trace!(logger => "forgetting format transaction");
1506 buffer.forget_transaction(formatting_transaction.id);
1507 }
1508 project_transaction
1509 .0
1510 .insert(cx.entity(), formatting_transaction);
1511 });
1512
1513 result?;
1514 }
1515
1516 Ok(project_transaction)
1517 }
1518
1519 async fn format_buffer_locally(
1520 lsp_store: WeakEntity<LspStore>,
1521 buffer: &FormattableBuffer,
1522 formatting_transaction_id: clock::Lamport,
1523 trigger: FormatTrigger,
1524 logger: zlog::Logger,
1525 cx: &mut AsyncApp,
1526 ) -> Result<()> {
1527 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1528 buffer.handle.update(cx, |buffer, cx| {
1529 let adapters_and_servers = lsp_store
1530 .as_local()
1531 .unwrap()
1532 .language_servers_for_buffer(buffer, cx)
1533 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1534 .collect::<Vec<_>>();
1535 let settings =
1536 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1537 .into_owned();
1538 (adapters_and_servers, settings)
1539 })
1540 })?;
1541
1542 /// Apply edits to the buffer that will become part of the formatting transaction.
1543 /// Fails if the buffer has been edited since the start of that transaction.
1544 fn extend_formatting_transaction(
1545 buffer: &FormattableBuffer,
1546 formatting_transaction_id: text::TransactionId,
1547 cx: &mut AsyncApp,
1548 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1549 ) -> anyhow::Result<()> {
1550 buffer.handle.update(cx, |buffer, cx| {
1551 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1552 if last_transaction_id != Some(formatting_transaction_id) {
1553 anyhow::bail!("Buffer edited while formatting. Aborting")
1554 }
1555 buffer.start_transaction();
1556 operation(buffer, cx);
1557 if let Some(transaction_id) = buffer.end_transaction(cx) {
1558 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1559 }
1560 Ok(())
1561 })
1562 }
1563
1564 // handle whitespace formatting
1565 if settings.remove_trailing_whitespace_on_save {
1566 zlog::trace!(logger => "removing trailing whitespace");
1567 let diff = buffer
1568 .handle
1569 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1570 .await;
1571 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1572 buffer.apply_diff(diff, cx);
1573 })?;
1574 }
1575
1576 if settings.ensure_final_newline_on_save {
1577 zlog::trace!(logger => "ensuring final newline");
1578 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1579 buffer.ensure_final_newline(cx);
1580 })?;
1581 }
1582
1583 // Formatter for `code_actions_on_format` that runs before
1584 // the rest of the formatters
1585 let mut code_actions_on_format_formatters = None;
1586 let should_run_code_actions_on_format = !matches!(
1587 (trigger, &settings.format_on_save),
1588 (FormatTrigger::Save, &FormatOnSave::Off)
1589 );
1590 if should_run_code_actions_on_format {
1591 let have_code_actions_to_run_on_format = settings
1592 .code_actions_on_format
1593 .values()
1594 .any(|enabled| *enabled);
1595 if have_code_actions_to_run_on_format {
1596 zlog::trace!(logger => "going to run code actions on format");
1597 code_actions_on_format_formatters = Some(
1598 settings
1599 .code_actions_on_format
1600 .iter()
1601 .filter_map(|(action, enabled)| enabled.then_some(action))
1602 .cloned()
1603 .map(Formatter::CodeAction)
1604 .collect::<Vec<_>>(),
1605 );
1606 }
1607 }
1608
1609 let formatters = match (trigger, &settings.format_on_save) {
1610 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1611 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1612 settings.formatter.as_ref()
1613 }
1614 };
1615
1616 let formatters = code_actions_on_format_formatters
1617 .iter()
1618 .flatten()
1619 .chain(formatters);
1620
1621 for formatter in formatters {
1622 let formatter = if formatter == &Formatter::Auto {
1623 if settings.prettier.allowed {
1624 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1625 &Formatter::Prettier
1626 } else {
1627 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1628 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1629 }
1630 } else {
1631 formatter
1632 };
1633 match formatter {
1634 Formatter::Auto => unreachable!("Auto resolved above"),
1635 Formatter::Prettier => {
1636 let logger = zlog::scoped!(logger => "prettier");
1637 zlog::trace!(logger => "formatting");
1638 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1639
1640 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1641 lsp_store.prettier_store().unwrap().downgrade()
1642 })?;
1643 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1644 .await
1645 .transpose()?;
1646 let Some(diff) = diff else {
1647 zlog::trace!(logger => "No changes");
1648 continue;
1649 };
1650
1651 extend_formatting_transaction(
1652 buffer,
1653 formatting_transaction_id,
1654 cx,
1655 |buffer, cx| {
1656 buffer.apply_diff(diff, cx);
1657 },
1658 )?;
1659 }
1660 Formatter::External { command, arguments } => {
1661 let logger = zlog::scoped!(logger => "command");
1662 zlog::trace!(logger => "formatting");
1663 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1664
1665 let diff = Self::format_via_external_command(
1666 buffer,
1667 &command,
1668 arguments.as_deref(),
1669 cx,
1670 )
1671 .await
1672 .with_context(|| {
1673 format!("Failed to format buffer via external command: {}", command)
1674 })?;
1675 let Some(diff) = diff else {
1676 zlog::trace!(logger => "No changes");
1677 continue;
1678 };
1679
1680 extend_formatting_transaction(
1681 buffer,
1682 formatting_transaction_id,
1683 cx,
1684 |buffer, cx| {
1685 buffer.apply_diff(diff, cx);
1686 },
1687 )?;
1688 }
1689 Formatter::LanguageServer(specifier) => {
1690 let logger = zlog::scoped!(logger => "language-server");
1691 zlog::trace!(logger => "formatting");
1692 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1693
1694 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1695 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1696 continue;
1697 };
1698
1699 let language_server = match specifier {
1700 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1701 adapters_and_servers.iter().find_map(|(adapter, server)| {
1702 if adapter.name.0.as_ref() == name {
1703 Some(server.clone())
1704 } else {
1705 None
1706 }
1707 })
1708 }
1709 settings::LanguageServerFormatterSpecifier::Current => {
1710 adapters_and_servers.first().map(|e| e.1.clone())
1711 }
1712 };
1713
1714 let Some(language_server) = language_server else {
1715 log::debug!(
1716 "No language server found to format buffer '{:?}'. Skipping",
1717 buffer_path_abs.as_path().to_string_lossy()
1718 );
1719 continue;
1720 };
1721
1722 zlog::trace!(
1723 logger =>
1724 "Formatting buffer '{:?}' using language server '{:?}'",
1725 buffer_path_abs.as_path().to_string_lossy(),
1726 language_server.name()
1727 );
1728
1729 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1730 zlog::trace!(logger => "formatting ranges");
1731 Self::format_ranges_via_lsp(
1732 &lsp_store,
1733 &buffer.handle,
1734 ranges,
1735 buffer_path_abs,
1736 &language_server,
1737 &settings,
1738 cx,
1739 )
1740 .await
1741 .context("Failed to format ranges via language server")?
1742 } else {
1743 zlog::trace!(logger => "formatting full");
1744 Self::format_via_lsp(
1745 &lsp_store,
1746 &buffer.handle,
1747 buffer_path_abs,
1748 &language_server,
1749 &settings,
1750 cx,
1751 )
1752 .await
1753 .context("failed to format via language server")?
1754 };
1755
1756 if edits.is_empty() {
1757 zlog::trace!(logger => "No changes");
1758 continue;
1759 }
1760 extend_formatting_transaction(
1761 buffer,
1762 formatting_transaction_id,
1763 cx,
1764 |buffer, cx| {
1765 buffer.edit(edits, None, cx);
1766 },
1767 )?;
1768 }
1769 Formatter::CodeAction(code_action_name) => {
1770 let logger = zlog::scoped!(logger => "code-actions");
1771 zlog::trace!(logger => "formatting");
1772 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1773
1774 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1775 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1776 continue;
1777 };
1778
1779 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1780 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1781
1782 let mut actions_and_servers = Vec::new();
1783
1784 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1785 let actions_result = Self::get_server_code_actions_from_action_kinds(
1786 &lsp_store,
1787 language_server.server_id(),
1788 vec![code_action_kind.clone()],
1789 &buffer.handle,
1790 cx,
1791 )
1792 .await
1793 .with_context(|| {
1794 format!(
1795 "Failed to resolve code action {:?} with language server {}",
1796 code_action_kind,
1797 language_server.name()
1798 )
1799 });
1800 let Ok(actions) = actions_result else {
1801 // note: it may be better to set result to the error and break formatters here
1802 // but for now we try to execute the actions that we can resolve and skip the rest
1803 zlog::error!(
1804 logger =>
1805 "Failed to resolve code action {:?} with language server {}",
1806 code_action_kind,
1807 language_server.name()
1808 );
1809 continue;
1810 };
1811 for action in actions {
1812 actions_and_servers.push((action, index));
1813 }
1814 }
1815
1816 if actions_and_servers.is_empty() {
1817 zlog::warn!(logger => "No code actions were resolved, continuing");
1818 continue;
1819 }
1820
1821 'actions: for (mut action, server_index) in actions_and_servers {
1822 let server = &adapters_and_servers[server_index].1;
1823
1824 let describe_code_action = |action: &CodeAction| {
1825 format!(
1826 "code action '{}' with title \"{}\" on server {}",
1827 action
1828 .lsp_action
1829 .action_kind()
1830 .unwrap_or("unknown".into())
1831 .as_str(),
1832 action.lsp_action.title(),
1833 server.name(),
1834 )
1835 };
1836
1837 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1838
1839 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1840 zlog::error!(
1841 logger =>
1842 "Failed to resolve {}. Error: {}",
1843 describe_code_action(&action),
1844 err
1845 );
1846 continue;
1847 }
1848
1849 if let Some(edit) = action.lsp_action.edit().cloned() {
1850 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1851 // but filters out and logs warnings for code actions that require unreasonably
1852 // difficult handling on our part, such as:
1853 // - applying edits that call commands
1854 // which can result in arbitrary workspace edits being sent from the server that
1855 // have no way of being tied back to the command that initiated them (i.e. we
1856 // can't know which edits are part of the format request, or if the server is done sending
1857 // actions in response to the command)
1858 // - actions that create/delete/modify/rename files other than the one we are formatting
1859 // as we then would need to handle such changes correctly in the local history as well
1860 // as the remote history through the ProjectTransaction
1861 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1862 // Supporting these actions is not impossible, but not supported as of yet.
1863 if edit.changes.is_none() && edit.document_changes.is_none() {
1864 zlog::trace!(
1865 logger =>
1866 "No changes for code action. Skipping {}",
1867 describe_code_action(&action),
1868 );
1869 continue;
1870 }
1871
1872 let mut operations = Vec::new();
1873 if let Some(document_changes) = edit.document_changes {
1874 match document_changes {
1875 lsp::DocumentChanges::Edits(edits) => operations.extend(
1876 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1877 ),
1878 lsp::DocumentChanges::Operations(ops) => operations = ops,
1879 }
1880 } else if let Some(changes) = edit.changes {
1881 operations.extend(changes.into_iter().map(|(uri, edits)| {
1882 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1883 text_document:
1884 lsp::OptionalVersionedTextDocumentIdentifier {
1885 uri,
1886 version: None,
1887 },
1888 edits: edits.into_iter().map(Edit::Plain).collect(),
1889 })
1890 }));
1891 }
1892
1893 let mut edits = Vec::with_capacity(operations.len());
1894
1895 if operations.is_empty() {
1896 zlog::trace!(
1897 logger =>
1898 "No changes for code action. Skipping {}",
1899 describe_code_action(&action),
1900 );
1901 continue;
1902 }
1903 for operation in operations {
1904 let op = match operation {
1905 lsp::DocumentChangeOperation::Edit(op) => op,
1906 lsp::DocumentChangeOperation::Op(_) => {
1907 zlog::warn!(
1908 logger =>
1909 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1910 describe_code_action(&action),
1911 );
1912 continue 'actions;
1913 }
1914 };
1915 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1916 zlog::warn!(
1917 logger =>
1918 "Failed to convert URI '{:?}' to file path. Skipping {}",
1919 &op.text_document.uri,
1920 describe_code_action(&action),
1921 );
1922 continue 'actions;
1923 };
1924 if &file_path != buffer_path_abs {
1925 zlog::warn!(
1926 logger =>
1927 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1928 file_path,
1929 buffer_path_abs,
1930 describe_code_action(&action),
1931 );
1932 continue 'actions;
1933 }
1934
1935 let mut lsp_edits = Vec::new();
1936 for edit in op.edits {
1937 match edit {
1938 Edit::Plain(edit) => {
1939 if !lsp_edits.contains(&edit) {
1940 lsp_edits.push(edit);
1941 }
1942 }
1943 Edit::Annotated(edit) => {
1944 if !lsp_edits.contains(&edit.text_edit) {
1945 lsp_edits.push(edit.text_edit);
1946 }
1947 }
1948 Edit::Snippet(_) => {
1949 zlog::warn!(
1950 logger =>
1951 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1952 describe_code_action(&action),
1953 );
1954 continue 'actions;
1955 }
1956 }
1957 }
1958 let edits_result = lsp_store
1959 .update(cx, |lsp_store, cx| {
1960 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1961 &buffer.handle,
1962 lsp_edits,
1963 server.server_id(),
1964 op.text_document.version,
1965 cx,
1966 )
1967 })?
1968 .await;
1969 let Ok(resolved_edits) = edits_result else {
1970 zlog::warn!(
1971 logger =>
1972 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1973 buffer_path_abs.as_path(),
1974 describe_code_action(&action),
1975 );
1976 continue 'actions;
1977 };
1978 edits.extend(resolved_edits);
1979 }
1980
1981 if edits.is_empty() {
1982 zlog::warn!(logger => "No edits resolved from LSP");
1983 continue;
1984 }
1985
1986 extend_formatting_transaction(
1987 buffer,
1988 formatting_transaction_id,
1989 cx,
1990 |buffer, cx| {
1991 zlog::info!(
1992 "Applying edits {edits:?}. Content: {:?}",
1993 buffer.text()
1994 );
1995 buffer.edit(edits, None, cx);
1996 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1997 },
1998 )?;
1999 }
2000
2001 if let Some(command) = action.lsp_action.command() {
2002 zlog::warn!(
2003 logger =>
2004 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2005 &command.command,
2006 );
2007
2008 // bail early if command is invalid
2009 let server_capabilities = server.capabilities();
2010 let available_commands = server_capabilities
2011 .execute_command_provider
2012 .as_ref()
2013 .map(|options| options.commands.as_slice())
2014 .unwrap_or_default();
2015 if !available_commands.contains(&command.command) {
2016 zlog::warn!(
2017 logger =>
2018 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2019 command.command,
2020 server.name(),
2021 );
2022 continue;
2023 }
2024
2025 // noop so we just ensure buffer hasn't been edited since resolving code actions
2026 extend_formatting_transaction(
2027 buffer,
2028 formatting_transaction_id,
2029 cx,
2030 |_, _| {},
2031 )?;
2032 zlog::info!(logger => "Executing command {}", &command.command);
2033
2034 lsp_store.update(cx, |this, _| {
2035 this.as_local_mut()
2036 .unwrap()
2037 .last_workspace_edits_by_language_server
2038 .remove(&server.server_id());
2039 })?;
2040
2041 let execute_command_result = server
2042 .request::<lsp::request::ExecuteCommand>(
2043 lsp::ExecuteCommandParams {
2044 command: command.command.clone(),
2045 arguments: command.arguments.clone().unwrap_or_default(),
2046 ..Default::default()
2047 },
2048 )
2049 .await
2050 .into_response();
2051
2052 if execute_command_result.is_err() {
2053 zlog::error!(
2054 logger =>
2055 "Failed to execute command '{}' as part of {}",
2056 &command.command,
2057 describe_code_action(&action),
2058 );
2059 continue 'actions;
2060 }
2061
2062 let mut project_transaction_command =
2063 lsp_store.update(cx, |this, _| {
2064 this.as_local_mut()
2065 .unwrap()
2066 .last_workspace_edits_by_language_server
2067 .remove(&server.server_id())
2068 .unwrap_or_default()
2069 })?;
2070
2071 if let Some(transaction) =
2072 project_transaction_command.0.remove(&buffer.handle)
2073 {
2074 zlog::trace!(
2075 logger =>
2076 "Successfully captured {} edits that resulted from command {}",
2077 transaction.edit_ids.len(),
2078 &command.command,
2079 );
2080 let transaction_id_project_transaction = transaction.id;
2081 buffer.handle.update(cx, |buffer, _| {
2082 // it may have been removed from history if push_to_history was
2083 // false in deserialize_workspace_edit. If so push it so we
2084 // can merge it with the format transaction
2085 // and pop the combined transaction off the history stack
2086 // later if push_to_history is false
2087 if buffer.get_transaction(transaction.id).is_none() {
2088 buffer.push_transaction(transaction, Instant::now());
2089 }
2090 buffer.merge_transactions(
2091 transaction_id_project_transaction,
2092 formatting_transaction_id,
2093 );
2094 });
2095 }
2096
2097 if !project_transaction_command.0.is_empty() {
2098 let mut extra_buffers = String::new();
2099 for buffer in project_transaction_command.0.keys() {
2100 buffer.read_with(cx, |b, cx| {
2101 if let Some(path) = b.project_path(cx) {
2102 if !extra_buffers.is_empty() {
2103 extra_buffers.push_str(", ");
2104 }
2105 extra_buffers.push_str(path.path.as_unix_str());
2106 }
2107 });
2108 }
2109 zlog::warn!(
2110 logger =>
2111 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2112 &command.command,
2113 extra_buffers,
2114 );
2115 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2116 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2117 // add it so it's included, and merge it into the format transaction when its created later
2118 }
2119 }
2120 }
2121 }
2122 }
2123 }
2124
2125 Ok(())
2126 }
2127
2128 pub async fn format_ranges_via_lsp(
2129 this: &WeakEntity<LspStore>,
2130 buffer_handle: &Entity<Buffer>,
2131 ranges: &[Range<Anchor>],
2132 abs_path: &Path,
2133 language_server: &Arc<LanguageServer>,
2134 settings: &LanguageSettings,
2135 cx: &mut AsyncApp,
2136 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2137 let capabilities = &language_server.capabilities();
2138 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2139 if range_formatting_provider == Some(&OneOf::Left(false)) {
2140 anyhow::bail!(
2141 "{} language server does not support range formatting",
2142 language_server.name()
2143 );
2144 }
2145
2146 let uri = file_path_to_lsp_url(abs_path)?;
2147 let text_document = lsp::TextDocumentIdentifier::new(uri);
2148
2149 let lsp_edits = {
2150 let mut lsp_ranges = Vec::new();
2151 this.update(cx, |_this, cx| {
2152 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2153 // not have been sent to the language server. This seems like a fairly systemic
2154 // issue, though, the resolution probably is not specific to formatting.
2155 //
2156 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2157 // LSP.
2158 let snapshot = buffer_handle.read(cx).snapshot();
2159 for range in ranges {
2160 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2161 }
2162 anyhow::Ok(())
2163 })??;
2164
2165 let mut edits = None;
2166 for range in lsp_ranges {
2167 if let Some(mut edit) = language_server
2168 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2169 text_document: text_document.clone(),
2170 range,
2171 options: lsp_command::lsp_formatting_options(settings),
2172 work_done_progress_params: Default::default(),
2173 })
2174 .await
2175 .into_response()?
2176 {
2177 edits.get_or_insert_with(Vec::new).append(&mut edit);
2178 }
2179 }
2180 edits
2181 };
2182
2183 if let Some(lsp_edits) = lsp_edits {
2184 this.update(cx, |this, cx| {
2185 this.as_local_mut().unwrap().edits_from_lsp(
2186 buffer_handle,
2187 lsp_edits,
2188 language_server.server_id(),
2189 None,
2190 cx,
2191 )
2192 })?
2193 .await
2194 } else {
2195 Ok(Vec::with_capacity(0))
2196 }
2197 }
2198
2199 async fn format_via_lsp(
2200 this: &WeakEntity<LspStore>,
2201 buffer: &Entity<Buffer>,
2202 abs_path: &Path,
2203 language_server: &Arc<LanguageServer>,
2204 settings: &LanguageSettings,
2205 cx: &mut AsyncApp,
2206 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2207 let logger = zlog::scoped!("lsp_format");
2208 zlog::debug!(logger => "Formatting via LSP");
2209
2210 let uri = file_path_to_lsp_url(abs_path)?;
2211 let text_document = lsp::TextDocumentIdentifier::new(uri);
2212 let capabilities = &language_server.capabilities();
2213
2214 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2215 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2216
2217 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2218 let _timer = zlog::time!(logger => "format-full");
2219 language_server
2220 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2221 text_document,
2222 options: lsp_command::lsp_formatting_options(settings),
2223 work_done_progress_params: Default::default(),
2224 })
2225 .await
2226 .into_response()?
2227 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2228 let _timer = zlog::time!(logger => "format-range");
2229 let buffer_start = lsp::Position::new(0, 0);
2230 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2231 language_server
2232 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2233 text_document: text_document.clone(),
2234 range: lsp::Range::new(buffer_start, buffer_end),
2235 options: lsp_command::lsp_formatting_options(settings),
2236 work_done_progress_params: Default::default(),
2237 })
2238 .await
2239 .into_response()?
2240 } else {
2241 None
2242 };
2243
2244 if let Some(lsp_edits) = lsp_edits {
2245 this.update(cx, |this, cx| {
2246 this.as_local_mut().unwrap().edits_from_lsp(
2247 buffer,
2248 lsp_edits,
2249 language_server.server_id(),
2250 None,
2251 cx,
2252 )
2253 })?
2254 .await
2255 } else {
2256 Ok(Vec::with_capacity(0))
2257 }
2258 }
2259
2260 async fn format_via_external_command(
2261 buffer: &FormattableBuffer,
2262 command: &str,
2263 arguments: Option<&[String]>,
2264 cx: &mut AsyncApp,
2265 ) -> Result<Option<Diff>> {
2266 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2267 let file = File::from_dyn(buffer.file())?;
2268 let worktree = file.worktree.read(cx);
2269 let mut worktree_path = worktree.abs_path().to_path_buf();
2270 if worktree.root_entry()?.is_file() {
2271 worktree_path.pop();
2272 }
2273 Some(worktree_path)
2274 });
2275
2276 let mut child = util::command::new_smol_command(command);
2277
2278 if let Some(buffer_env) = buffer.env.as_ref() {
2279 child.envs(buffer_env);
2280 }
2281
2282 if let Some(working_dir_path) = working_dir_path {
2283 child.current_dir(working_dir_path);
2284 }
2285
2286 if let Some(arguments) = arguments {
2287 child.args(arguments.iter().map(|arg| {
2288 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2289 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2290 } else {
2291 arg.replace("{buffer_path}", "Untitled")
2292 }
2293 }));
2294 }
2295
2296 let mut child = child
2297 .stdin(smol::process::Stdio::piped())
2298 .stdout(smol::process::Stdio::piped())
2299 .stderr(smol::process::Stdio::piped())
2300 .spawn()?;
2301
2302 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2303 let text = buffer
2304 .handle
2305 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2306 for chunk in text.chunks() {
2307 stdin.write_all(chunk.as_bytes()).await?;
2308 }
2309 stdin.flush().await?;
2310
2311 let output = child.output().await?;
2312 anyhow::ensure!(
2313 output.status.success(),
2314 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2315 output.status.code(),
2316 String::from_utf8_lossy(&output.stdout),
2317 String::from_utf8_lossy(&output.stderr),
2318 );
2319
2320 let stdout = String::from_utf8(output.stdout)?;
2321 Ok(Some(
2322 buffer
2323 .handle
2324 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2325 .await,
2326 ))
2327 }
2328
2329 async fn try_resolve_code_action(
2330 lang_server: &LanguageServer,
2331 action: &mut CodeAction,
2332 ) -> anyhow::Result<()> {
2333 match &mut action.lsp_action {
2334 LspAction::Action(lsp_action) => {
2335 if !action.resolved
2336 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2337 && lsp_action.data.is_some()
2338 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2339 {
2340 **lsp_action = lang_server
2341 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2342 .await
2343 .into_response()?;
2344 }
2345 }
2346 LspAction::CodeLens(lens) => {
2347 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2348 *lens = lang_server
2349 .request::<lsp::request::CodeLensResolve>(lens.clone())
2350 .await
2351 .into_response()?;
2352 }
2353 }
2354 LspAction::Command(_) => {}
2355 }
2356
2357 action.resolved = true;
2358 anyhow::Ok(())
2359 }
2360
2361 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2362 let buffer = buffer_handle.read(cx);
2363
2364 let file = buffer.file().cloned();
2365
2366 let Some(file) = File::from_dyn(file.as_ref()) else {
2367 return;
2368 };
2369 if !file.is_local() {
2370 return;
2371 }
2372 let path = ProjectPath::from_file(file, cx);
2373 let worktree_id = file.worktree_id(cx);
2374 let language = buffer.language().cloned();
2375
2376 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2377 for (server_id, diagnostics) in
2378 diagnostics.get(file.path()).cloned().unwrap_or_default()
2379 {
2380 self.update_buffer_diagnostics(
2381 buffer_handle,
2382 server_id,
2383 None,
2384 None,
2385 None,
2386 Vec::new(),
2387 diagnostics,
2388 cx,
2389 )
2390 .log_err();
2391 }
2392 }
2393 let Some(language) = language else {
2394 return;
2395 };
2396 let Some(snapshot) = self
2397 .worktree_store
2398 .read(cx)
2399 .worktree_for_id(worktree_id, cx)
2400 .map(|worktree| worktree.read(cx).snapshot())
2401 else {
2402 return;
2403 };
2404 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2405
2406 for server_id in
2407 self.lsp_tree
2408 .get(path, language.name(), language.manifest(), &delegate, cx)
2409 {
2410 let server = self
2411 .language_servers
2412 .get(&server_id)
2413 .and_then(|server_state| {
2414 if let LanguageServerState::Running { server, .. } = server_state {
2415 Some(server.clone())
2416 } else {
2417 None
2418 }
2419 });
2420 let server = match server {
2421 Some(server) => server,
2422 None => continue,
2423 };
2424
2425 buffer_handle.update(cx, |buffer, cx| {
2426 buffer.set_completion_triggers(
2427 server.server_id(),
2428 server
2429 .capabilities()
2430 .completion_provider
2431 .as_ref()
2432 .and_then(|provider| {
2433 provider
2434 .trigger_characters
2435 .as_ref()
2436 .map(|characters| characters.iter().cloned().collect())
2437 })
2438 .unwrap_or_default(),
2439 cx,
2440 );
2441 });
2442 }
2443 }
2444
2445 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2446 buffer.update(cx, |buffer, cx| {
2447 let Some(language) = buffer.language() else {
2448 return;
2449 };
2450 let path = ProjectPath {
2451 worktree_id: old_file.worktree_id(cx),
2452 path: old_file.path.clone(),
2453 };
2454 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2455 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2456 buffer.set_completion_triggers(server_id, Default::default(), cx);
2457 }
2458 });
2459 }
2460
2461 fn update_buffer_diagnostics(
2462 &mut self,
2463 buffer: &Entity<Buffer>,
2464 server_id: LanguageServerId,
2465 registration_id: Option<Option<SharedString>>,
2466 result_id: Option<SharedString>,
2467 version: Option<i32>,
2468 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2469 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2470 cx: &mut Context<LspStore>,
2471 ) -> Result<()> {
2472 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2473 Ordering::Equal
2474 .then_with(|| b.is_primary.cmp(&a.is_primary))
2475 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2476 .then_with(|| a.severity.cmp(&b.severity))
2477 .then_with(|| a.message.cmp(&b.message))
2478 }
2479
2480 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2481 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2482 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2483
2484 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2485 Ordering::Equal
2486 .then_with(|| a.range.start.cmp(&b.range.start))
2487 .then_with(|| b.range.end.cmp(&a.range.end))
2488 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2489 });
2490
2491 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2492
2493 let edits_since_save = std::cell::LazyCell::new(|| {
2494 let saved_version = buffer.read(cx).saved_version();
2495 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2496 });
2497
2498 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2499
2500 for (new_diagnostic, entry) in diagnostics {
2501 let start;
2502 let end;
2503 if new_diagnostic && entry.diagnostic.is_disk_based {
2504 // Some diagnostics are based on files on disk instead of buffers'
2505 // current contents. Adjust these diagnostics' ranges to reflect
2506 // any unsaved edits.
2507 // Do not alter the reused ones though, as their coordinates were stored as anchors
2508 // and were properly adjusted on reuse.
2509 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2510 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2511 } else {
2512 start = entry.range.start;
2513 end = entry.range.end;
2514 }
2515
2516 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2517 ..snapshot.clip_point_utf16(end, Bias::Right);
2518
2519 // Expand empty ranges by one codepoint
2520 if range.start == range.end {
2521 // This will be go to the next boundary when being clipped
2522 range.end.column += 1;
2523 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2524 if range.start == range.end && range.end.column > 0 {
2525 range.start.column -= 1;
2526 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2527 }
2528 }
2529
2530 sanitized_diagnostics.push(DiagnosticEntry {
2531 range,
2532 diagnostic: entry.diagnostic,
2533 });
2534 }
2535 drop(edits_since_save);
2536
2537 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2538 buffer.update(cx, |buffer, cx| {
2539 if let Some(registration_id) = registration_id {
2540 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2541 self.buffer_pull_diagnostics_result_ids
2542 .entry(server_id)
2543 .or_default()
2544 .entry(registration_id)
2545 .or_default()
2546 .insert(abs_path, result_id);
2547 }
2548 }
2549
2550 buffer.update_diagnostics(server_id, set, cx)
2551 });
2552
2553 Ok(())
2554 }
2555
2556 fn register_language_server_for_invisible_worktree(
2557 &mut self,
2558 worktree: &Entity<Worktree>,
2559 language_server_id: LanguageServerId,
2560 cx: &mut App,
2561 ) {
2562 let worktree = worktree.read(cx);
2563 let worktree_id = worktree.id();
2564 debug_assert!(!worktree.is_visible());
2565 let Some(mut origin_seed) = self
2566 .language_server_ids
2567 .iter()
2568 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2569 else {
2570 return;
2571 };
2572 origin_seed.worktree_id = worktree_id;
2573 self.language_server_ids
2574 .entry(origin_seed)
2575 .or_insert_with(|| UnifiedLanguageServer {
2576 id: language_server_id,
2577 project_roots: Default::default(),
2578 });
2579 }
2580
2581 fn register_buffer_with_language_servers(
2582 &mut self,
2583 buffer_handle: &Entity<Buffer>,
2584 only_register_servers: HashSet<LanguageServerSelector>,
2585 cx: &mut Context<LspStore>,
2586 ) {
2587 let buffer = buffer_handle.read(cx);
2588 let buffer_id = buffer.remote_id();
2589
2590 let Some(file) = File::from_dyn(buffer.file()) else {
2591 return;
2592 };
2593 if !file.is_local() {
2594 return;
2595 }
2596
2597 let abs_path = file.abs_path(cx);
2598 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2599 return;
2600 };
2601 let initial_snapshot = buffer.text_snapshot();
2602 let worktree_id = file.worktree_id(cx);
2603
2604 let Some(language) = buffer.language().cloned() else {
2605 return;
2606 };
2607 let path: Arc<RelPath> = file
2608 .path()
2609 .parent()
2610 .map(Arc::from)
2611 .unwrap_or_else(|| file.path().clone());
2612 let Some(worktree) = self
2613 .worktree_store
2614 .read(cx)
2615 .worktree_for_id(worktree_id, cx)
2616 else {
2617 return;
2618 };
2619 let language_name = language.name();
2620 let (reused, delegate, servers) = self
2621 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2622 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2623 .unwrap_or_else(|| {
2624 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2625 let delegate: Arc<dyn ManifestDelegate> =
2626 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2627
2628 let servers = self
2629 .lsp_tree
2630 .walk(
2631 ProjectPath { worktree_id, path },
2632 language.name(),
2633 language.manifest(),
2634 &delegate,
2635 cx,
2636 )
2637 .collect::<Vec<_>>();
2638 (false, lsp_delegate, servers)
2639 });
2640 let servers_and_adapters = servers
2641 .into_iter()
2642 .filter_map(|server_node| {
2643 if reused && server_node.server_id().is_none() {
2644 return None;
2645 }
2646 if !only_register_servers.is_empty() {
2647 if let Some(server_id) = server_node.server_id()
2648 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2649 {
2650 return None;
2651 }
2652 if let Some(name) = server_node.name()
2653 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2654 {
2655 return None;
2656 }
2657 }
2658
2659 let server_id = server_node.server_id_or_init(|disposition| {
2660 let path = &disposition.path;
2661
2662 {
2663 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2664
2665 let server_id = self.get_or_insert_language_server(
2666 &worktree,
2667 delegate.clone(),
2668 disposition,
2669 &language_name,
2670 cx,
2671 );
2672
2673 if let Some(state) = self.language_servers.get(&server_id)
2674 && let Ok(uri) = uri
2675 {
2676 state.add_workspace_folder(uri);
2677 };
2678 server_id
2679 }
2680 })?;
2681 let server_state = self.language_servers.get(&server_id)?;
2682 if let LanguageServerState::Running {
2683 server, adapter, ..
2684 } = server_state
2685 {
2686 Some((server.clone(), adapter.clone()))
2687 } else {
2688 None
2689 }
2690 })
2691 .collect::<Vec<_>>();
2692 for (server, adapter) in servers_and_adapters {
2693 buffer_handle.update(cx, |buffer, cx| {
2694 buffer.set_completion_triggers(
2695 server.server_id(),
2696 server
2697 .capabilities()
2698 .completion_provider
2699 .as_ref()
2700 .and_then(|provider| {
2701 provider
2702 .trigger_characters
2703 .as_ref()
2704 .map(|characters| characters.iter().cloned().collect())
2705 })
2706 .unwrap_or_default(),
2707 cx,
2708 );
2709 });
2710
2711 let snapshot = LspBufferSnapshot {
2712 version: 0,
2713 snapshot: initial_snapshot.clone(),
2714 };
2715
2716 let mut registered = false;
2717 self.buffer_snapshots
2718 .entry(buffer_id)
2719 .or_default()
2720 .entry(server.server_id())
2721 .or_insert_with(|| {
2722 registered = true;
2723 server.register_buffer(
2724 uri.clone(),
2725 adapter.language_id(&language.name()),
2726 0,
2727 initial_snapshot.text(),
2728 );
2729
2730 vec![snapshot]
2731 });
2732
2733 self.buffers_opened_in_servers
2734 .entry(buffer_id)
2735 .or_default()
2736 .insert(server.server_id());
2737 if registered {
2738 cx.emit(LspStoreEvent::LanguageServerUpdate {
2739 language_server_id: server.server_id(),
2740 name: None,
2741 message: proto::update_language_server::Variant::RegisteredForBuffer(
2742 proto::RegisteredForBuffer {
2743 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2744 buffer_id: buffer_id.to_proto(),
2745 },
2746 ),
2747 });
2748 }
2749 }
2750 }
2751
2752 fn reuse_existing_language_server<'lang_name>(
2753 &self,
2754 server_tree: &LanguageServerTree,
2755 worktree: &Entity<Worktree>,
2756 language_name: &'lang_name LanguageName,
2757 cx: &mut App,
2758 ) -> Option<(
2759 Arc<LocalLspAdapterDelegate>,
2760 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2761 )> {
2762 if worktree.read(cx).is_visible() {
2763 return None;
2764 }
2765
2766 let worktree_store = self.worktree_store.read(cx);
2767 let servers = server_tree
2768 .instances
2769 .iter()
2770 .filter(|(worktree_id, _)| {
2771 worktree_store
2772 .worktree_for_id(**worktree_id, cx)
2773 .is_some_and(|worktree| worktree.read(cx).is_visible())
2774 })
2775 .flat_map(|(worktree_id, servers)| {
2776 servers
2777 .roots
2778 .iter()
2779 .flat_map(|(_, language_servers)| language_servers)
2780 .map(move |(_, (server_node, server_languages))| {
2781 (worktree_id, server_node, server_languages)
2782 })
2783 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2784 .map(|(worktree_id, server_node, _)| {
2785 (
2786 *worktree_id,
2787 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2788 )
2789 })
2790 })
2791 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2792 acc.entry(worktree_id)
2793 .or_insert_with(Vec::new)
2794 .push(server_node);
2795 acc
2796 })
2797 .into_values()
2798 .max_by_key(|servers| servers.len())?;
2799
2800 let worktree_id = worktree.read(cx).id();
2801 let apply = move |tree: &mut LanguageServerTree| {
2802 for server_node in &servers {
2803 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2804 }
2805 servers
2806 };
2807
2808 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2809 Some((delegate, apply))
2810 }
2811
2812 pub(crate) fn unregister_old_buffer_from_language_servers(
2813 &mut self,
2814 buffer: &Entity<Buffer>,
2815 old_file: &File,
2816 cx: &mut App,
2817 ) {
2818 let old_path = match old_file.as_local() {
2819 Some(local) => local.abs_path(cx),
2820 None => return,
2821 };
2822
2823 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2824 debug_panic!("{old_path:?} is not parseable as an URI");
2825 return;
2826 };
2827 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2828 }
2829
2830 pub(crate) fn unregister_buffer_from_language_servers(
2831 &mut self,
2832 buffer: &Entity<Buffer>,
2833 file_url: &lsp::Uri,
2834 cx: &mut App,
2835 ) {
2836 buffer.update(cx, |buffer, cx| {
2837 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2838
2839 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2840 if snapshots
2841 .as_mut()
2842 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2843 {
2844 language_server.unregister_buffer(file_url.clone());
2845 }
2846 }
2847 });
2848 }
2849
2850 fn buffer_snapshot_for_lsp_version(
2851 &mut self,
2852 buffer: &Entity<Buffer>,
2853 server_id: LanguageServerId,
2854 version: Option<i32>,
2855 cx: &App,
2856 ) -> Result<TextBufferSnapshot> {
2857 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2858
2859 if let Some(version) = version {
2860 let buffer_id = buffer.read(cx).remote_id();
2861 let snapshots = if let Some(snapshots) = self
2862 .buffer_snapshots
2863 .get_mut(&buffer_id)
2864 .and_then(|m| m.get_mut(&server_id))
2865 {
2866 snapshots
2867 } else if version == 0 {
2868 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2869 // We detect this case and treat it as if the version was `None`.
2870 return Ok(buffer.read(cx).text_snapshot());
2871 } else {
2872 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2873 };
2874
2875 let found_snapshot = snapshots
2876 .binary_search_by_key(&version, |e| e.version)
2877 .map(|ix| snapshots[ix].snapshot.clone())
2878 .map_err(|_| {
2879 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2880 })?;
2881
2882 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2883 Ok(found_snapshot)
2884 } else {
2885 Ok((buffer.read(cx)).text_snapshot())
2886 }
2887 }
2888
2889 async fn get_server_code_actions_from_action_kinds(
2890 lsp_store: &WeakEntity<LspStore>,
2891 language_server_id: LanguageServerId,
2892 code_action_kinds: Vec<lsp::CodeActionKind>,
2893 buffer: &Entity<Buffer>,
2894 cx: &mut AsyncApp,
2895 ) -> Result<Vec<CodeAction>> {
2896 let actions = lsp_store
2897 .update(cx, move |this, cx| {
2898 let request = GetCodeActions {
2899 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2900 kinds: Some(code_action_kinds),
2901 };
2902 let server = LanguageServerToQuery::Other(language_server_id);
2903 this.request_lsp(buffer.clone(), server, request, cx)
2904 })?
2905 .await?;
2906 Ok(actions)
2907 }
2908
2909 pub async fn execute_code_actions_on_server(
2910 lsp_store: &WeakEntity<LspStore>,
2911 language_server: &Arc<LanguageServer>,
2912
2913 actions: Vec<CodeAction>,
2914 push_to_history: bool,
2915 project_transaction: &mut ProjectTransaction,
2916 cx: &mut AsyncApp,
2917 ) -> anyhow::Result<()> {
2918 for mut action in actions {
2919 Self::try_resolve_code_action(language_server, &mut action)
2920 .await
2921 .context("resolving a formatting code action")?;
2922
2923 if let Some(edit) = action.lsp_action.edit() {
2924 if edit.changes.is_none() && edit.document_changes.is_none() {
2925 continue;
2926 }
2927
2928 let new = Self::deserialize_workspace_edit(
2929 lsp_store.upgrade().context("project dropped")?,
2930 edit.clone(),
2931 push_to_history,
2932 language_server.clone(),
2933 cx,
2934 )
2935 .await?;
2936 project_transaction.0.extend(new.0);
2937 }
2938
2939 if let Some(command) = action.lsp_action.command() {
2940 let server_capabilities = language_server.capabilities();
2941 let available_commands = server_capabilities
2942 .execute_command_provider
2943 .as_ref()
2944 .map(|options| options.commands.as_slice())
2945 .unwrap_or_default();
2946 if available_commands.contains(&command.command) {
2947 lsp_store.update(cx, |lsp_store, _| {
2948 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2949 mode.last_workspace_edits_by_language_server
2950 .remove(&language_server.server_id());
2951 }
2952 })?;
2953
2954 language_server
2955 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2956 command: command.command.clone(),
2957 arguments: command.arguments.clone().unwrap_or_default(),
2958 ..Default::default()
2959 })
2960 .await
2961 .into_response()
2962 .context("execute command")?;
2963
2964 lsp_store.update(cx, |this, _| {
2965 if let LspStoreMode::Local(mode) = &mut this.mode {
2966 project_transaction.0.extend(
2967 mode.last_workspace_edits_by_language_server
2968 .remove(&language_server.server_id())
2969 .unwrap_or_default()
2970 .0,
2971 )
2972 }
2973 })?;
2974 } else {
2975 log::warn!(
2976 "Cannot execute a command {} not listed in the language server capabilities",
2977 command.command
2978 )
2979 }
2980 }
2981 }
2982 Ok(())
2983 }
2984
2985 pub async fn deserialize_text_edits(
2986 this: Entity<LspStore>,
2987 buffer_to_edit: Entity<Buffer>,
2988 edits: Vec<lsp::TextEdit>,
2989 push_to_history: bool,
2990 _: Arc<CachedLspAdapter>,
2991 language_server: Arc<LanguageServer>,
2992 cx: &mut AsyncApp,
2993 ) -> Result<Option<Transaction>> {
2994 let edits = this
2995 .update(cx, |this, cx| {
2996 this.as_local_mut().unwrap().edits_from_lsp(
2997 &buffer_to_edit,
2998 edits,
2999 language_server.server_id(),
3000 None,
3001 cx,
3002 )
3003 })
3004 .await?;
3005
3006 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3007 buffer.finalize_last_transaction();
3008 buffer.start_transaction();
3009 for (range, text) in edits {
3010 buffer.edit([(range, text)], None, cx);
3011 }
3012
3013 if buffer.end_transaction(cx).is_some() {
3014 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3015 if !push_to_history {
3016 buffer.forget_transaction(transaction.id);
3017 }
3018 Some(transaction)
3019 } else {
3020 None
3021 }
3022 });
3023
3024 Ok(transaction)
3025 }
3026
3027 #[allow(clippy::type_complexity)]
3028 pub fn edits_from_lsp(
3029 &mut self,
3030 buffer: &Entity<Buffer>,
3031 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3032 server_id: LanguageServerId,
3033 version: Option<i32>,
3034 cx: &mut Context<LspStore>,
3035 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3036 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3037 cx.background_spawn(async move {
3038 let snapshot = snapshot?;
3039 let mut lsp_edits = lsp_edits
3040 .into_iter()
3041 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3042 .collect::<Vec<_>>();
3043
3044 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3045
3046 let mut lsp_edits = lsp_edits.into_iter().peekable();
3047 let mut edits = Vec::new();
3048 while let Some((range, mut new_text)) = lsp_edits.next() {
3049 // Clip invalid ranges provided by the language server.
3050 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3051 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3052
3053 // Combine any LSP edits that are adjacent.
3054 //
3055 // Also, combine LSP edits that are separated from each other by only
3056 // a newline. This is important because for some code actions,
3057 // Rust-analyzer rewrites the entire buffer via a series of edits that
3058 // are separated by unchanged newline characters.
3059 //
3060 // In order for the diffing logic below to work properly, any edits that
3061 // cancel each other out must be combined into one.
3062 while let Some((next_range, next_text)) = lsp_edits.peek() {
3063 if next_range.start.0 > range.end {
3064 if next_range.start.0.row > range.end.row + 1
3065 || next_range.start.0.column > 0
3066 || snapshot.clip_point_utf16(
3067 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3068 Bias::Left,
3069 ) > range.end
3070 {
3071 break;
3072 }
3073 new_text.push('\n');
3074 }
3075 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3076 new_text.push_str(next_text);
3077 lsp_edits.next();
3078 }
3079
3080 // For multiline edits, perform a diff of the old and new text so that
3081 // we can identify the changes more precisely, preserving the locations
3082 // of any anchors positioned in the unchanged regions.
3083 if range.end.row > range.start.row {
3084 let offset = range.start.to_offset(&snapshot);
3085 let old_text = snapshot.text_for_range(range).collect::<String>();
3086 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3087 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3088 (
3089 snapshot.anchor_after(offset + range.start)
3090 ..snapshot.anchor_before(offset + range.end),
3091 replacement,
3092 )
3093 }));
3094 } else if range.end == range.start {
3095 let anchor = snapshot.anchor_after(range.start);
3096 edits.push((anchor..anchor, new_text.into()));
3097 } else {
3098 let edit_start = snapshot.anchor_after(range.start);
3099 let edit_end = snapshot.anchor_before(range.end);
3100 edits.push((edit_start..edit_end, new_text.into()));
3101 }
3102 }
3103
3104 Ok(edits)
3105 })
3106 }
3107
3108 pub(crate) async fn deserialize_workspace_edit(
3109 this: Entity<LspStore>,
3110 edit: lsp::WorkspaceEdit,
3111 push_to_history: bool,
3112 language_server: Arc<LanguageServer>,
3113 cx: &mut AsyncApp,
3114 ) -> Result<ProjectTransaction> {
3115 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3116
3117 let mut operations = Vec::new();
3118 if let Some(document_changes) = edit.document_changes {
3119 match document_changes {
3120 lsp::DocumentChanges::Edits(edits) => {
3121 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3122 }
3123 lsp::DocumentChanges::Operations(ops) => operations = ops,
3124 }
3125 } else if let Some(changes) = edit.changes {
3126 operations.extend(changes.into_iter().map(|(uri, edits)| {
3127 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3128 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3129 uri,
3130 version: None,
3131 },
3132 edits: edits.into_iter().map(Edit::Plain).collect(),
3133 })
3134 }));
3135 }
3136
3137 let mut project_transaction = ProjectTransaction::default();
3138 for operation in operations {
3139 match operation {
3140 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3141 let abs_path = op
3142 .uri
3143 .to_file_path()
3144 .map_err(|()| anyhow!("can't convert URI to path"))?;
3145
3146 if let Some(parent_path) = abs_path.parent() {
3147 fs.create_dir(parent_path).await?;
3148 }
3149 if abs_path.ends_with("/") {
3150 fs.create_dir(&abs_path).await?;
3151 } else {
3152 fs.create_file(
3153 &abs_path,
3154 op.options
3155 .map(|options| fs::CreateOptions {
3156 overwrite: options.overwrite.unwrap_or(false),
3157 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3158 })
3159 .unwrap_or_default(),
3160 )
3161 .await?;
3162 }
3163 }
3164
3165 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3166 let source_abs_path = op
3167 .old_uri
3168 .to_file_path()
3169 .map_err(|()| anyhow!("can't convert URI to path"))?;
3170 let target_abs_path = op
3171 .new_uri
3172 .to_file_path()
3173 .map_err(|()| anyhow!("can't convert URI to path"))?;
3174
3175 let options = fs::RenameOptions {
3176 overwrite: op
3177 .options
3178 .as_ref()
3179 .and_then(|options| options.overwrite)
3180 .unwrap_or(false),
3181 ignore_if_exists: op
3182 .options
3183 .as_ref()
3184 .and_then(|options| options.ignore_if_exists)
3185 .unwrap_or(false),
3186 create_parents: true,
3187 };
3188
3189 fs.rename(&source_abs_path, &target_abs_path, options)
3190 .await?;
3191 }
3192
3193 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3194 let abs_path = op
3195 .uri
3196 .to_file_path()
3197 .map_err(|()| anyhow!("can't convert URI to path"))?;
3198 let options = op
3199 .options
3200 .map(|options| fs::RemoveOptions {
3201 recursive: options.recursive.unwrap_or(false),
3202 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3203 })
3204 .unwrap_or_default();
3205 if abs_path.ends_with("/") {
3206 fs.remove_dir(&abs_path, options).await?;
3207 } else {
3208 fs.remove_file(&abs_path, options).await?;
3209 }
3210 }
3211
3212 lsp::DocumentChangeOperation::Edit(op) => {
3213 let buffer_to_edit = this
3214 .update(cx, |this, cx| {
3215 this.open_local_buffer_via_lsp(
3216 op.text_document.uri.clone(),
3217 language_server.server_id(),
3218 cx,
3219 )
3220 })
3221 .await?;
3222
3223 let edits = this
3224 .update(cx, |this, cx| {
3225 let path = buffer_to_edit.read(cx).project_path(cx);
3226 let active_entry = this.active_entry;
3227 let is_active_entry = path.is_some_and(|project_path| {
3228 this.worktree_store
3229 .read(cx)
3230 .entry_for_path(&project_path, cx)
3231 .is_some_and(|entry| Some(entry.id) == active_entry)
3232 });
3233 let local = this.as_local_mut().unwrap();
3234
3235 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3236 for edit in op.edits {
3237 match edit {
3238 Edit::Plain(edit) => {
3239 if !edits.contains(&edit) {
3240 edits.push(edit)
3241 }
3242 }
3243 Edit::Annotated(edit) => {
3244 if !edits.contains(&edit.text_edit) {
3245 edits.push(edit.text_edit)
3246 }
3247 }
3248 Edit::Snippet(edit) => {
3249 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3250 else {
3251 continue;
3252 };
3253
3254 if is_active_entry {
3255 snippet_edits.push((edit.range, snippet));
3256 } else {
3257 // Since this buffer is not focused, apply a normal edit.
3258 let new_edit = TextEdit {
3259 range: edit.range,
3260 new_text: snippet.text,
3261 };
3262 if !edits.contains(&new_edit) {
3263 edits.push(new_edit);
3264 }
3265 }
3266 }
3267 }
3268 }
3269 if !snippet_edits.is_empty() {
3270 let buffer_id = buffer_to_edit.read(cx).remote_id();
3271 let version = if let Some(buffer_version) = op.text_document.version
3272 {
3273 local
3274 .buffer_snapshot_for_lsp_version(
3275 &buffer_to_edit,
3276 language_server.server_id(),
3277 Some(buffer_version),
3278 cx,
3279 )
3280 .ok()
3281 .map(|snapshot| snapshot.version)
3282 } else {
3283 Some(buffer_to_edit.read(cx).saved_version().clone())
3284 };
3285
3286 let most_recent_edit =
3287 version.and_then(|version| version.most_recent());
3288 // Check if the edit that triggered that edit has been made by this participant.
3289
3290 if let Some(most_recent_edit) = most_recent_edit {
3291 cx.emit(LspStoreEvent::SnippetEdit {
3292 buffer_id,
3293 edits: snippet_edits,
3294 most_recent_edit,
3295 });
3296 }
3297 }
3298
3299 local.edits_from_lsp(
3300 &buffer_to_edit,
3301 edits,
3302 language_server.server_id(),
3303 op.text_document.version,
3304 cx,
3305 )
3306 })
3307 .await?;
3308
3309 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3310 buffer.finalize_last_transaction();
3311 buffer.start_transaction();
3312 for (range, text) in edits {
3313 buffer.edit([(range, text)], None, cx);
3314 }
3315
3316 buffer.end_transaction(cx).and_then(|transaction_id| {
3317 if push_to_history {
3318 buffer.finalize_last_transaction();
3319 buffer.get_transaction(transaction_id).cloned()
3320 } else {
3321 buffer.forget_transaction(transaction_id)
3322 }
3323 })
3324 });
3325 if let Some(transaction) = transaction {
3326 project_transaction.0.insert(buffer_to_edit, transaction);
3327 }
3328 }
3329 }
3330 }
3331
3332 Ok(project_transaction)
3333 }
3334
3335 async fn on_lsp_workspace_edit(
3336 this: WeakEntity<LspStore>,
3337 params: lsp::ApplyWorkspaceEditParams,
3338 server_id: LanguageServerId,
3339 cx: &mut AsyncApp,
3340 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3341 let this = this.upgrade().context("project project closed")?;
3342 let language_server = this
3343 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3344 .context("language server not found")?;
3345 let transaction = Self::deserialize_workspace_edit(
3346 this.clone(),
3347 params.edit,
3348 true,
3349 language_server.clone(),
3350 cx,
3351 )
3352 .await
3353 .log_err();
3354 this.update(cx, |this, cx| {
3355 if let Some(transaction) = transaction {
3356 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3357
3358 this.as_local_mut()
3359 .unwrap()
3360 .last_workspace_edits_by_language_server
3361 .insert(server_id, transaction);
3362 }
3363 });
3364 Ok(lsp::ApplyWorkspaceEditResponse {
3365 applied: true,
3366 failed_change: None,
3367 failure_reason: None,
3368 })
3369 }
3370
3371 fn remove_worktree(
3372 &mut self,
3373 id_to_remove: WorktreeId,
3374 cx: &mut Context<LspStore>,
3375 ) -> Vec<LanguageServerId> {
3376 self.restricted_worktrees_tasks.remove(&id_to_remove);
3377 self.diagnostics.remove(&id_to_remove);
3378 self.prettier_store.update(cx, |prettier_store, cx| {
3379 prettier_store.remove_worktree(id_to_remove, cx);
3380 });
3381
3382 let mut servers_to_remove = BTreeSet::default();
3383 let mut servers_to_preserve = HashSet::default();
3384 for (seed, state) in &self.language_server_ids {
3385 if seed.worktree_id == id_to_remove {
3386 servers_to_remove.insert(state.id);
3387 } else {
3388 servers_to_preserve.insert(state.id);
3389 }
3390 }
3391 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3392 self.language_server_ids
3393 .retain(|_, state| !servers_to_remove.contains(&state.id));
3394 for server_id_to_remove in &servers_to_remove {
3395 self.language_server_watched_paths
3396 .remove(server_id_to_remove);
3397 self.language_server_paths_watched_for_rename
3398 .remove(server_id_to_remove);
3399 self.last_workspace_edits_by_language_server
3400 .remove(server_id_to_remove);
3401 self.language_servers.remove(server_id_to_remove);
3402 self.buffer_pull_diagnostics_result_ids
3403 .remove(server_id_to_remove);
3404 self.workspace_pull_diagnostics_result_ids
3405 .remove(server_id_to_remove);
3406 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3407 buffer_servers.remove(server_id_to_remove);
3408 }
3409 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3410 }
3411 servers_to_remove.into_iter().collect()
3412 }
3413
3414 fn rebuild_watched_paths_inner<'a>(
3415 &'a self,
3416 language_server_id: LanguageServerId,
3417 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3418 cx: &mut Context<LspStore>,
3419 ) -> LanguageServerWatchedPathsBuilder {
3420 let worktrees = self
3421 .worktree_store
3422 .read(cx)
3423 .worktrees()
3424 .filter_map(|worktree| {
3425 self.language_servers_for_worktree(worktree.read(cx).id())
3426 .find(|server| server.server_id() == language_server_id)
3427 .map(|_| worktree)
3428 })
3429 .collect::<Vec<_>>();
3430
3431 let mut worktree_globs = HashMap::default();
3432 let mut abs_globs = HashMap::default();
3433 log::trace!(
3434 "Processing new watcher paths for language server with id {}",
3435 language_server_id
3436 );
3437
3438 for watcher in watchers {
3439 if let Some((worktree, literal_prefix, pattern)) =
3440 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3441 {
3442 worktree.update(cx, |worktree, _| {
3443 if let Some((tree, glob)) =
3444 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3445 {
3446 tree.add_path_prefix_to_scan(literal_prefix);
3447 worktree_globs
3448 .entry(tree.id())
3449 .or_insert_with(GlobSetBuilder::new)
3450 .add(glob);
3451 }
3452 });
3453 } else {
3454 let (path, pattern) = match &watcher.glob_pattern {
3455 lsp::GlobPattern::String(s) => {
3456 let watcher_path = SanitizedPath::new(s);
3457 let path = glob_literal_prefix(watcher_path.as_path());
3458 let pattern = watcher_path
3459 .as_path()
3460 .strip_prefix(&path)
3461 .map(|p| p.to_string_lossy().into_owned())
3462 .unwrap_or_else(|e| {
3463 debug_panic!(
3464 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3465 s,
3466 path.display(),
3467 e
3468 );
3469 watcher_path.as_path().to_string_lossy().into_owned()
3470 });
3471 (path, pattern)
3472 }
3473 lsp::GlobPattern::Relative(rp) => {
3474 let Ok(mut base_uri) = match &rp.base_uri {
3475 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3476 lsp::OneOf::Right(base_uri) => base_uri,
3477 }
3478 .to_file_path() else {
3479 continue;
3480 };
3481
3482 let path = glob_literal_prefix(Path::new(&rp.pattern));
3483 let pattern = Path::new(&rp.pattern)
3484 .strip_prefix(&path)
3485 .map(|p| p.to_string_lossy().into_owned())
3486 .unwrap_or_else(|e| {
3487 debug_panic!(
3488 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3489 rp.pattern,
3490 path.display(),
3491 e
3492 );
3493 rp.pattern.clone()
3494 });
3495 base_uri.push(path);
3496 (base_uri, pattern)
3497 }
3498 };
3499
3500 if let Some(glob) = Glob::new(&pattern).log_err() {
3501 if !path
3502 .components()
3503 .any(|c| matches!(c, path::Component::Normal(_)))
3504 {
3505 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3506 // rather than adding a new watcher for `/`.
3507 for worktree in &worktrees {
3508 worktree_globs
3509 .entry(worktree.read(cx).id())
3510 .or_insert_with(GlobSetBuilder::new)
3511 .add(glob.clone());
3512 }
3513 } else {
3514 abs_globs
3515 .entry(path.into())
3516 .or_insert_with(GlobSetBuilder::new)
3517 .add(glob);
3518 }
3519 }
3520 }
3521 }
3522
3523 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3524 for (worktree_id, builder) in worktree_globs {
3525 if let Ok(globset) = builder.build() {
3526 watch_builder.watch_worktree(worktree_id, globset);
3527 }
3528 }
3529 for (abs_path, builder) in abs_globs {
3530 if let Ok(globset) = builder.build() {
3531 watch_builder.watch_abs_path(abs_path, globset);
3532 }
3533 }
3534 watch_builder
3535 }
3536
3537 fn worktree_and_path_for_file_watcher(
3538 worktrees: &[Entity<Worktree>],
3539 watcher: &FileSystemWatcher,
3540 cx: &App,
3541 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3542 worktrees.iter().find_map(|worktree| {
3543 let tree = worktree.read(cx);
3544 let worktree_root_path = tree.abs_path();
3545 let path_style = tree.path_style();
3546 match &watcher.glob_pattern {
3547 lsp::GlobPattern::String(s) => {
3548 let watcher_path = SanitizedPath::new(s);
3549 let relative = watcher_path
3550 .as_path()
3551 .strip_prefix(&worktree_root_path)
3552 .ok()?;
3553 let literal_prefix = glob_literal_prefix(relative);
3554 Some((
3555 worktree.clone(),
3556 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3557 relative.to_string_lossy().into_owned(),
3558 ))
3559 }
3560 lsp::GlobPattern::Relative(rp) => {
3561 let base_uri = match &rp.base_uri {
3562 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3563 lsp::OneOf::Right(base_uri) => base_uri,
3564 }
3565 .to_file_path()
3566 .ok()?;
3567 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3568 let mut literal_prefix = relative.to_owned();
3569 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3570 Some((
3571 worktree.clone(),
3572 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3573 rp.pattern.clone(),
3574 ))
3575 }
3576 }
3577 })
3578 }
3579
3580 fn rebuild_watched_paths(
3581 &mut self,
3582 language_server_id: LanguageServerId,
3583 cx: &mut Context<LspStore>,
3584 ) {
3585 let Some(registrations) = self
3586 .language_server_dynamic_registrations
3587 .get(&language_server_id)
3588 else {
3589 return;
3590 };
3591
3592 let watch_builder = self.rebuild_watched_paths_inner(
3593 language_server_id,
3594 registrations.did_change_watched_files.values().flatten(),
3595 cx,
3596 );
3597 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3598 self.language_server_watched_paths
3599 .insert(language_server_id, watcher);
3600
3601 cx.notify();
3602 }
3603
3604 fn on_lsp_did_change_watched_files(
3605 &mut self,
3606 language_server_id: LanguageServerId,
3607 registration_id: &str,
3608 params: DidChangeWatchedFilesRegistrationOptions,
3609 cx: &mut Context<LspStore>,
3610 ) {
3611 let registrations = self
3612 .language_server_dynamic_registrations
3613 .entry(language_server_id)
3614 .or_default();
3615
3616 registrations
3617 .did_change_watched_files
3618 .insert(registration_id.to_string(), params.watchers);
3619
3620 self.rebuild_watched_paths(language_server_id, cx);
3621 }
3622
3623 fn on_lsp_unregister_did_change_watched_files(
3624 &mut self,
3625 language_server_id: LanguageServerId,
3626 registration_id: &str,
3627 cx: &mut Context<LspStore>,
3628 ) {
3629 let registrations = self
3630 .language_server_dynamic_registrations
3631 .entry(language_server_id)
3632 .or_default();
3633
3634 if registrations
3635 .did_change_watched_files
3636 .remove(registration_id)
3637 .is_some()
3638 {
3639 log::info!(
3640 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3641 language_server_id,
3642 registration_id
3643 );
3644 } else {
3645 log::warn!(
3646 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3647 language_server_id,
3648 registration_id
3649 );
3650 }
3651
3652 self.rebuild_watched_paths(language_server_id, cx);
3653 }
3654
3655 async fn initialization_options_for_adapter(
3656 adapter: Arc<dyn LspAdapter>,
3657 delegate: &Arc<dyn LspAdapterDelegate>,
3658 ) -> Result<Option<serde_json::Value>> {
3659 let Some(mut initialization_config) =
3660 adapter.clone().initialization_options(delegate).await?
3661 else {
3662 return Ok(None);
3663 };
3664
3665 for other_adapter in delegate.registered_lsp_adapters() {
3666 if other_adapter.name() == adapter.name() {
3667 continue;
3668 }
3669 if let Ok(Some(target_config)) = other_adapter
3670 .clone()
3671 .additional_initialization_options(adapter.name(), delegate)
3672 .await
3673 {
3674 merge_json_value_into(target_config.clone(), &mut initialization_config);
3675 }
3676 }
3677
3678 Ok(Some(initialization_config))
3679 }
3680
3681 async fn workspace_configuration_for_adapter(
3682 adapter: Arc<dyn LspAdapter>,
3683 delegate: &Arc<dyn LspAdapterDelegate>,
3684 toolchain: Option<Toolchain>,
3685 requested_uri: Option<Uri>,
3686 cx: &mut AsyncApp,
3687 ) -> Result<serde_json::Value> {
3688 let mut workspace_config = adapter
3689 .clone()
3690 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3691 .await?;
3692
3693 for other_adapter in delegate.registered_lsp_adapters() {
3694 if other_adapter.name() == adapter.name() {
3695 continue;
3696 }
3697 if let Ok(Some(target_config)) = other_adapter
3698 .clone()
3699 .additional_workspace_configuration(adapter.name(), delegate, cx)
3700 .await
3701 {
3702 merge_json_value_into(target_config.clone(), &mut workspace_config);
3703 }
3704 }
3705
3706 Ok(workspace_config)
3707 }
3708
3709 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3710 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3711 Some(server.clone())
3712 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3713 Some(Arc::clone(server))
3714 } else {
3715 None
3716 }
3717 }
3718}
3719
3720fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3721 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3722 cx.emit(LspStoreEvent::LanguageServerUpdate {
3723 language_server_id: server.server_id(),
3724 name: Some(server.name()),
3725 message: proto::update_language_server::Variant::MetadataUpdated(
3726 proto::ServerMetadataUpdated {
3727 capabilities: Some(capabilities),
3728 binary: Some(proto::LanguageServerBinaryInfo {
3729 path: server.binary().path.to_string_lossy().into_owned(),
3730 arguments: server
3731 .binary()
3732 .arguments
3733 .iter()
3734 .map(|arg| arg.to_string_lossy().into_owned())
3735 .collect(),
3736 }),
3737 configuration: serde_json::to_string(server.configuration()).ok(),
3738 workspace_folders: server
3739 .workspace_folders()
3740 .iter()
3741 .map(|uri| uri.to_string())
3742 .collect(),
3743 },
3744 ),
3745 });
3746 }
3747}
3748
3749#[derive(Debug)]
3750pub struct FormattableBuffer {
3751 handle: Entity<Buffer>,
3752 abs_path: Option<PathBuf>,
3753 env: Option<HashMap<String, String>>,
3754 ranges: Option<Vec<Range<Anchor>>>,
3755}
3756
3757pub struct RemoteLspStore {
3758 upstream_client: Option<AnyProtoClient>,
3759 upstream_project_id: u64,
3760}
3761
3762pub(crate) enum LspStoreMode {
3763 Local(LocalLspStore), // ssh host and collab host
3764 Remote(RemoteLspStore), // collab guest
3765}
3766
3767impl LspStoreMode {
3768 fn is_local(&self) -> bool {
3769 matches!(self, LspStoreMode::Local(_))
3770 }
3771}
3772
3773pub struct LspStore {
3774 mode: LspStoreMode,
3775 last_formatting_failure: Option<String>,
3776 downstream_client: Option<(AnyProtoClient, u64)>,
3777 nonce: u128,
3778 buffer_store: Entity<BufferStore>,
3779 worktree_store: Entity<WorktreeStore>,
3780 pub languages: Arc<LanguageRegistry>,
3781 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3782 active_entry: Option<ProjectEntryId>,
3783 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3784 _maintain_buffer_languages: Task<()>,
3785 diagnostic_summaries:
3786 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3787 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3788 lsp_data: HashMap<BufferId, BufferLspData>,
3789 next_hint_id: Arc<AtomicUsize>,
3790}
3791
3792#[derive(Debug)]
3793pub struct BufferLspData {
3794 buffer_version: Global,
3795 document_colors: Option<DocumentColorData>,
3796 code_lens: Option<CodeLensData>,
3797 inlay_hints: BufferInlayHints,
3798 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3799 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3800}
3801
3802#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3803struct LspKey {
3804 request_type: TypeId,
3805 server_queried: Option<LanguageServerId>,
3806}
3807
3808impl BufferLspData {
3809 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3810 Self {
3811 buffer_version: buffer.read(cx).version(),
3812 document_colors: None,
3813 code_lens: None,
3814 inlay_hints: BufferInlayHints::new(buffer, cx),
3815 lsp_requests: HashMap::default(),
3816 chunk_lsp_requests: HashMap::default(),
3817 }
3818 }
3819
3820 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3821 if let Some(document_colors) = &mut self.document_colors {
3822 document_colors.colors.remove(&for_server);
3823 document_colors.cache_version += 1;
3824 }
3825
3826 if let Some(code_lens) = &mut self.code_lens {
3827 code_lens.lens.remove(&for_server);
3828 }
3829
3830 self.inlay_hints.remove_server_data(for_server);
3831 }
3832
3833 #[cfg(any(test, feature = "test-support"))]
3834 pub fn inlay_hints(&self) -> &BufferInlayHints {
3835 &self.inlay_hints
3836 }
3837}
3838
3839#[derive(Debug, Default, Clone)]
3840pub struct DocumentColors {
3841 pub colors: HashSet<DocumentColor>,
3842 pub cache_version: Option<usize>,
3843}
3844
3845type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3846type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3847
3848#[derive(Debug, Default)]
3849struct DocumentColorData {
3850 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3851 cache_version: usize,
3852 colors_update: Option<(Global, DocumentColorTask)>,
3853}
3854
3855#[derive(Debug, Default)]
3856struct CodeLensData {
3857 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3858 update: Option<(Global, CodeLensTask)>,
3859}
3860
3861#[derive(Debug)]
3862pub enum LspStoreEvent {
3863 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3864 LanguageServerRemoved(LanguageServerId),
3865 LanguageServerUpdate {
3866 language_server_id: LanguageServerId,
3867 name: Option<LanguageServerName>,
3868 message: proto::update_language_server::Variant,
3869 },
3870 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3871 LanguageServerPrompt(LanguageServerPromptRequest),
3872 LanguageDetected {
3873 buffer: Entity<Buffer>,
3874 new_language: Option<Arc<Language>>,
3875 },
3876 Notification(String),
3877 RefreshInlayHints {
3878 server_id: LanguageServerId,
3879 request_id: Option<usize>,
3880 },
3881 RefreshCodeLens,
3882 DiagnosticsUpdated {
3883 server_id: LanguageServerId,
3884 paths: Vec<ProjectPath>,
3885 },
3886 DiskBasedDiagnosticsStarted {
3887 language_server_id: LanguageServerId,
3888 },
3889 DiskBasedDiagnosticsFinished {
3890 language_server_id: LanguageServerId,
3891 },
3892 SnippetEdit {
3893 buffer_id: BufferId,
3894 edits: Vec<(lsp::Range, Snippet)>,
3895 most_recent_edit: clock::Lamport,
3896 },
3897 WorkspaceEditApplied(ProjectTransaction),
3898}
3899
3900#[derive(Clone, Debug, Serialize)]
3901pub struct LanguageServerStatus {
3902 pub name: LanguageServerName,
3903 pub server_version: Option<SharedString>,
3904 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3905 pub has_pending_diagnostic_updates: bool,
3906 pub progress_tokens: HashSet<ProgressToken>,
3907 pub worktree: Option<WorktreeId>,
3908 pub binary: Option<LanguageServerBinary>,
3909 pub configuration: Option<Value>,
3910 pub workspace_folders: BTreeSet<Uri>,
3911 pub process_id: Option<u32>,
3912}
3913
3914#[derive(Clone, Debug)]
3915struct CoreSymbol {
3916 pub language_server_name: LanguageServerName,
3917 pub source_worktree_id: WorktreeId,
3918 pub source_language_server_id: LanguageServerId,
3919 pub path: SymbolLocation,
3920 pub name: String,
3921 pub kind: lsp::SymbolKind,
3922 pub range: Range<Unclipped<PointUtf16>>,
3923}
3924
3925#[derive(Clone, Debug, PartialEq, Eq)]
3926pub enum SymbolLocation {
3927 InProject(ProjectPath),
3928 OutsideProject {
3929 abs_path: Arc<Path>,
3930 signature: [u8; 32],
3931 },
3932}
3933
3934impl SymbolLocation {
3935 fn file_name(&self) -> Option<&str> {
3936 match self {
3937 Self::InProject(path) => path.path.file_name(),
3938 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3939 }
3940 }
3941}
3942
3943impl LspStore {
3944 pub fn init(client: &AnyProtoClient) {
3945 client.add_entity_request_handler(Self::handle_lsp_query);
3946 client.add_entity_message_handler(Self::handle_lsp_query_response);
3947 client.add_entity_request_handler(Self::handle_restart_language_servers);
3948 client.add_entity_request_handler(Self::handle_stop_language_servers);
3949 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3950 client.add_entity_message_handler(Self::handle_start_language_server);
3951 client.add_entity_message_handler(Self::handle_update_language_server);
3952 client.add_entity_message_handler(Self::handle_language_server_log);
3953 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3954 client.add_entity_request_handler(Self::handle_format_buffers);
3955 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3956 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3957 client.add_entity_request_handler(Self::handle_apply_code_action);
3958 client.add_entity_request_handler(Self::handle_get_project_symbols);
3959 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3960 client.add_entity_request_handler(Self::handle_get_color_presentation);
3961 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3962 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3963 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3964 client.add_entity_request_handler(Self::handle_on_type_formatting);
3965 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3966 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3967 client.add_entity_request_handler(Self::handle_rename_project_entry);
3968 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3969 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3970 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3971 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3972 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3973 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3974 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3975
3976 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3977 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3978 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3979 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3980 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3981 client.add_entity_request_handler(
3982 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3983 );
3984 client.add_entity_request_handler(
3985 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3986 );
3987 client.add_entity_request_handler(
3988 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3989 );
3990 }
3991
3992 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3993 match &self.mode {
3994 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3995 _ => None,
3996 }
3997 }
3998
3999 pub fn as_local(&self) -> Option<&LocalLspStore> {
4000 match &self.mode {
4001 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4002 _ => None,
4003 }
4004 }
4005
4006 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4007 match &mut self.mode {
4008 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4009 _ => None,
4010 }
4011 }
4012
4013 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4014 match &self.mode {
4015 LspStoreMode::Remote(RemoteLspStore {
4016 upstream_client: Some(upstream_client),
4017 upstream_project_id,
4018 ..
4019 }) => Some((upstream_client.clone(), *upstream_project_id)),
4020
4021 LspStoreMode::Remote(RemoteLspStore {
4022 upstream_client: None,
4023 ..
4024 }) => None,
4025 LspStoreMode::Local(_) => None,
4026 }
4027 }
4028
4029 pub fn new_local(
4030 buffer_store: Entity<BufferStore>,
4031 worktree_store: Entity<WorktreeStore>,
4032 prettier_store: Entity<PrettierStore>,
4033 toolchain_store: Entity<LocalToolchainStore>,
4034 environment: Entity<ProjectEnvironment>,
4035 manifest_tree: Entity<ManifestTree>,
4036 languages: Arc<LanguageRegistry>,
4037 http_client: Arc<dyn HttpClient>,
4038 fs: Arc<dyn Fs>,
4039 cx: &mut Context<Self>,
4040 ) -> Self {
4041 let yarn = YarnPathStore::new(fs.clone(), cx);
4042 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4043 .detach();
4044 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4045 .detach();
4046 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4047 .detach();
4048 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4049 .detach();
4050 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4051 .detach();
4052 subscribe_to_binary_statuses(&languages, cx).detach();
4053
4054 let _maintain_workspace_config = {
4055 let (sender, receiver) = watch::channel();
4056 (Self::maintain_workspace_config(receiver, cx), sender)
4057 };
4058
4059 Self {
4060 mode: LspStoreMode::Local(LocalLspStore {
4061 weak: cx.weak_entity(),
4062 worktree_store: worktree_store.clone(),
4063
4064 supplementary_language_servers: Default::default(),
4065 languages: languages.clone(),
4066 language_server_ids: Default::default(),
4067 language_servers: Default::default(),
4068 last_workspace_edits_by_language_server: Default::default(),
4069 language_server_watched_paths: Default::default(),
4070 language_server_paths_watched_for_rename: Default::default(),
4071 language_server_dynamic_registrations: Default::default(),
4072 buffers_being_formatted: Default::default(),
4073 buffers_to_refresh_hash_set: HashSet::default(),
4074 buffers_to_refresh_queue: VecDeque::new(),
4075 _background_diagnostics_worker: Task::ready(()).shared(),
4076 buffer_snapshots: Default::default(),
4077 prettier_store,
4078 environment,
4079 http_client,
4080 fs,
4081 yarn,
4082 next_diagnostic_group_id: Default::default(),
4083 diagnostics: Default::default(),
4084 _subscription: cx.on_app_quit(|this, cx| {
4085 this.as_local_mut()
4086 .unwrap()
4087 .shutdown_language_servers_on_quit(cx)
4088 }),
4089 lsp_tree: LanguageServerTree::new(
4090 manifest_tree,
4091 languages.clone(),
4092 toolchain_store.clone(),
4093 ),
4094 toolchain_store,
4095 registered_buffers: HashMap::default(),
4096 buffers_opened_in_servers: HashMap::default(),
4097 buffer_pull_diagnostics_result_ids: HashMap::default(),
4098 workspace_pull_diagnostics_result_ids: HashMap::default(),
4099 restricted_worktrees_tasks: HashMap::default(),
4100 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4101 .manifest_file_names(),
4102 }),
4103 last_formatting_failure: None,
4104 downstream_client: None,
4105 buffer_store,
4106 worktree_store,
4107 languages: languages.clone(),
4108 language_server_statuses: Default::default(),
4109 nonce: StdRng::from_os_rng().random(),
4110 diagnostic_summaries: HashMap::default(),
4111 lsp_server_capabilities: HashMap::default(),
4112 lsp_data: HashMap::default(),
4113 next_hint_id: Arc::default(),
4114 active_entry: None,
4115 _maintain_workspace_config,
4116 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4117 }
4118 }
4119
4120 fn send_lsp_proto_request<R: LspCommand>(
4121 &self,
4122 buffer: Entity<Buffer>,
4123 client: AnyProtoClient,
4124 upstream_project_id: u64,
4125 request: R,
4126 cx: &mut Context<LspStore>,
4127 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4128 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4129 return Task::ready(Ok(R::Response::default()));
4130 }
4131 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4132 cx.spawn(async move |this, cx| {
4133 let response = client.request(message).await?;
4134 let this = this.upgrade().context("project dropped")?;
4135 request
4136 .response_from_proto(response, this, buffer, cx.clone())
4137 .await
4138 })
4139 }
4140
4141 pub(super) fn new_remote(
4142 buffer_store: Entity<BufferStore>,
4143 worktree_store: Entity<WorktreeStore>,
4144 languages: Arc<LanguageRegistry>,
4145 upstream_client: AnyProtoClient,
4146 project_id: u64,
4147 cx: &mut Context<Self>,
4148 ) -> Self {
4149 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4150 .detach();
4151 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4152 .detach();
4153 subscribe_to_binary_statuses(&languages, cx).detach();
4154 let _maintain_workspace_config = {
4155 let (sender, receiver) = watch::channel();
4156 (Self::maintain_workspace_config(receiver, cx), sender)
4157 };
4158 Self {
4159 mode: LspStoreMode::Remote(RemoteLspStore {
4160 upstream_client: Some(upstream_client),
4161 upstream_project_id: project_id,
4162 }),
4163 downstream_client: None,
4164 last_formatting_failure: None,
4165 buffer_store,
4166 worktree_store,
4167 languages: languages.clone(),
4168 language_server_statuses: Default::default(),
4169 nonce: StdRng::from_os_rng().random(),
4170 diagnostic_summaries: HashMap::default(),
4171 lsp_server_capabilities: HashMap::default(),
4172 next_hint_id: Arc::default(),
4173 lsp_data: HashMap::default(),
4174 active_entry: None,
4175
4176 _maintain_workspace_config,
4177 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4178 }
4179 }
4180
4181 fn on_buffer_store_event(
4182 &mut self,
4183 _: Entity<BufferStore>,
4184 event: &BufferStoreEvent,
4185 cx: &mut Context<Self>,
4186 ) {
4187 match event {
4188 BufferStoreEvent::BufferAdded(buffer) => {
4189 self.on_buffer_added(buffer, cx).log_err();
4190 }
4191 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4192 let buffer_id = buffer.read(cx).remote_id();
4193 if let Some(local) = self.as_local_mut()
4194 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4195 {
4196 local.reset_buffer(buffer, old_file, cx);
4197
4198 if local.registered_buffers.contains_key(&buffer_id) {
4199 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4200 }
4201 }
4202
4203 self.detect_language_for_buffer(buffer, cx);
4204 if let Some(local) = self.as_local_mut() {
4205 local.initialize_buffer(buffer, cx);
4206 if local.registered_buffers.contains_key(&buffer_id) {
4207 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4208 }
4209 }
4210 }
4211 _ => {}
4212 }
4213 }
4214
4215 fn on_worktree_store_event(
4216 &mut self,
4217 _: Entity<WorktreeStore>,
4218 event: &WorktreeStoreEvent,
4219 cx: &mut Context<Self>,
4220 ) {
4221 match event {
4222 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4223 if !worktree.read(cx).is_local() {
4224 return;
4225 }
4226 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4227 worktree::Event::UpdatedEntries(changes) => {
4228 this.update_local_worktree_language_servers(&worktree, changes, cx);
4229 }
4230 worktree::Event::UpdatedGitRepositories(_)
4231 | worktree::Event::DeletedEntry(_) => {}
4232 })
4233 .detach()
4234 }
4235 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4236 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4237 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4238 }
4239 WorktreeStoreEvent::WorktreeReleased(..)
4240 | WorktreeStoreEvent::WorktreeOrderChanged
4241 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4242 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4243 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4244 }
4245 }
4246
4247 fn on_prettier_store_event(
4248 &mut self,
4249 _: Entity<PrettierStore>,
4250 event: &PrettierStoreEvent,
4251 cx: &mut Context<Self>,
4252 ) {
4253 match event {
4254 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4255 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4256 }
4257 PrettierStoreEvent::LanguageServerAdded {
4258 new_server_id,
4259 name,
4260 prettier_server,
4261 } => {
4262 self.register_supplementary_language_server(
4263 *new_server_id,
4264 name.clone(),
4265 prettier_server.clone(),
4266 cx,
4267 );
4268 }
4269 }
4270 }
4271
4272 fn on_toolchain_store_event(
4273 &mut self,
4274 _: Entity<LocalToolchainStore>,
4275 event: &ToolchainStoreEvent,
4276 _: &mut Context<Self>,
4277 ) {
4278 if let ToolchainStoreEvent::ToolchainActivated = event {
4279 self.request_workspace_config_refresh()
4280 }
4281 }
4282
4283 fn request_workspace_config_refresh(&mut self) {
4284 *self._maintain_workspace_config.1.borrow_mut() = ();
4285 }
4286
4287 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4288 self.as_local().map(|local| local.prettier_store.clone())
4289 }
4290
4291 fn on_buffer_event(
4292 &mut self,
4293 buffer: Entity<Buffer>,
4294 event: &language::BufferEvent,
4295 cx: &mut Context<Self>,
4296 ) {
4297 match event {
4298 language::BufferEvent::Edited => {
4299 self.on_buffer_edited(buffer, cx);
4300 }
4301
4302 language::BufferEvent::Saved => {
4303 self.on_buffer_saved(buffer, cx);
4304 }
4305
4306 _ => {}
4307 }
4308 }
4309
4310 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4311 buffer
4312 .read(cx)
4313 .set_language_registry(self.languages.clone());
4314
4315 cx.subscribe(buffer, |this, buffer, event, cx| {
4316 this.on_buffer_event(buffer, event, cx);
4317 })
4318 .detach();
4319
4320 self.detect_language_for_buffer(buffer, cx);
4321 if let Some(local) = self.as_local_mut() {
4322 local.initialize_buffer(buffer, cx);
4323 }
4324
4325 Ok(())
4326 }
4327
4328 pub fn refresh_background_diagnostics_for_buffers(
4329 &mut self,
4330 buffers: HashSet<BufferId>,
4331 cx: &mut Context<Self>,
4332 ) -> Shared<Task<()>> {
4333 let Some(local) = self.as_local_mut() else {
4334 return Task::ready(()).shared();
4335 };
4336 for buffer in buffers {
4337 if local.buffers_to_refresh_hash_set.insert(buffer) {
4338 local.buffers_to_refresh_queue.push_back(buffer);
4339 if local.buffers_to_refresh_queue.len() == 1 {
4340 local._background_diagnostics_worker =
4341 Self::background_diagnostics_worker(cx).shared();
4342 }
4343 }
4344 }
4345
4346 local._background_diagnostics_worker.clone()
4347 }
4348
4349 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4350 let buffer_store = self.buffer_store.clone();
4351 let local = self.as_local_mut()?;
4352 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4353 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4354 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4355 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4356 }
4357 }
4358 None
4359 }
4360
4361 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4362 cx.spawn(async move |this, cx| {
4363 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4364 task.await.log_err();
4365 }
4366 })
4367 }
4368
4369 pub(crate) fn register_buffer_with_language_servers(
4370 &mut self,
4371 buffer: &Entity<Buffer>,
4372 only_register_servers: HashSet<LanguageServerSelector>,
4373 ignore_refcounts: bool,
4374 cx: &mut Context<Self>,
4375 ) -> OpenLspBufferHandle {
4376 let buffer_id = buffer.read(cx).remote_id();
4377 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4378 if let Some(local) = self.as_local_mut() {
4379 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4380 if !ignore_refcounts {
4381 *refcount += 1;
4382 }
4383
4384 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4385 // 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
4386 // 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
4387 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4388 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4389 return handle;
4390 };
4391 if !file.is_local() {
4392 return handle;
4393 }
4394
4395 if ignore_refcounts || *refcount == 1 {
4396 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4397 }
4398 if !ignore_refcounts {
4399 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4400 let refcount = {
4401 let local = lsp_store.as_local_mut().unwrap();
4402 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4403 debug_panic!("bad refcounting");
4404 return;
4405 };
4406
4407 *refcount -= 1;
4408 *refcount
4409 };
4410 if refcount == 0 {
4411 lsp_store.lsp_data.remove(&buffer_id);
4412 let local = lsp_store.as_local_mut().unwrap();
4413 local.registered_buffers.remove(&buffer_id);
4414
4415 local.buffers_opened_in_servers.remove(&buffer_id);
4416 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4417 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4418
4419 let buffer_abs_path = file.abs_path(cx);
4420 for (_, buffer_pull_diagnostics_result_ids) in
4421 &mut local.buffer_pull_diagnostics_result_ids
4422 {
4423 buffer_pull_diagnostics_result_ids.retain(
4424 |_, buffer_result_ids| {
4425 buffer_result_ids.remove(&buffer_abs_path);
4426 !buffer_result_ids.is_empty()
4427 },
4428 );
4429 }
4430
4431 let diagnostic_updates = local
4432 .language_servers
4433 .keys()
4434 .cloned()
4435 .map(|server_id| DocumentDiagnosticsUpdate {
4436 diagnostics: DocumentDiagnostics {
4437 document_abs_path: buffer_abs_path.clone(),
4438 version: None,
4439 diagnostics: Vec::new(),
4440 },
4441 result_id: None,
4442 registration_id: None,
4443 server_id: server_id,
4444 disk_based_sources: Cow::Borrowed(&[]),
4445 })
4446 .collect::<Vec<_>>();
4447
4448 lsp_store
4449 .merge_diagnostic_entries(
4450 diagnostic_updates,
4451 |_, diagnostic, _| {
4452 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4453 },
4454 cx,
4455 )
4456 .context("Clearing diagnostics for the closed buffer")
4457 .log_err();
4458 }
4459 }
4460 })
4461 .detach();
4462 }
4463 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4464 let buffer_id = buffer.read(cx).remote_id().to_proto();
4465 cx.background_spawn(async move {
4466 upstream_client
4467 .request(proto::RegisterBufferWithLanguageServers {
4468 project_id: upstream_project_id,
4469 buffer_id,
4470 only_servers: only_register_servers
4471 .into_iter()
4472 .map(|selector| {
4473 let selector = match selector {
4474 LanguageServerSelector::Id(language_server_id) => {
4475 proto::language_server_selector::Selector::ServerId(
4476 language_server_id.to_proto(),
4477 )
4478 }
4479 LanguageServerSelector::Name(language_server_name) => {
4480 proto::language_server_selector::Selector::Name(
4481 language_server_name.to_string(),
4482 )
4483 }
4484 };
4485 proto::LanguageServerSelector {
4486 selector: Some(selector),
4487 }
4488 })
4489 .collect(),
4490 })
4491 .await
4492 })
4493 .detach();
4494 } else {
4495 // Our remote connection got closed
4496 }
4497 handle
4498 }
4499
4500 fn maintain_buffer_languages(
4501 languages: Arc<LanguageRegistry>,
4502 cx: &mut Context<Self>,
4503 ) -> Task<()> {
4504 let mut subscription = languages.subscribe();
4505 let mut prev_reload_count = languages.reload_count();
4506 cx.spawn(async move |this, cx| {
4507 while let Some(()) = subscription.next().await {
4508 if let Some(this) = this.upgrade() {
4509 // If the language registry has been reloaded, then remove and
4510 // re-assign the languages on all open buffers.
4511 let reload_count = languages.reload_count();
4512 if reload_count > prev_reload_count {
4513 prev_reload_count = reload_count;
4514 this.update(cx, |this, cx| {
4515 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4516 for buffer in buffer_store.buffers() {
4517 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4518 {
4519 buffer.update(cx, |buffer, cx| {
4520 buffer.set_language_async(None, cx)
4521 });
4522 if let Some(local) = this.as_local_mut() {
4523 local.reset_buffer(&buffer, &f, cx);
4524
4525 if local
4526 .registered_buffers
4527 .contains_key(&buffer.read(cx).remote_id())
4528 && let Some(file_url) =
4529 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4530 {
4531 local.unregister_buffer_from_language_servers(
4532 &buffer, &file_url, cx,
4533 );
4534 }
4535 }
4536 }
4537 }
4538 });
4539 });
4540 }
4541
4542 this.update(cx, |this, cx| {
4543 let mut plain_text_buffers = Vec::new();
4544 let mut buffers_with_unknown_injections = Vec::new();
4545 for handle in this.buffer_store.read(cx).buffers() {
4546 let buffer = handle.read(cx);
4547 if buffer.language().is_none()
4548 || buffer.language() == Some(&*language::PLAIN_TEXT)
4549 {
4550 plain_text_buffers.push(handle);
4551 } else if buffer.contains_unknown_injections() {
4552 buffers_with_unknown_injections.push(handle);
4553 }
4554 }
4555
4556 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4557 // and reused later in the invisible worktrees.
4558 plain_text_buffers.sort_by_key(|buffer| {
4559 Reverse(
4560 File::from_dyn(buffer.read(cx).file())
4561 .map(|file| file.worktree.read(cx).is_visible()),
4562 )
4563 });
4564
4565 for buffer in plain_text_buffers {
4566 this.detect_language_for_buffer(&buffer, cx);
4567 if let Some(local) = this.as_local_mut() {
4568 local.initialize_buffer(&buffer, cx);
4569 if local
4570 .registered_buffers
4571 .contains_key(&buffer.read(cx).remote_id())
4572 {
4573 local.register_buffer_with_language_servers(
4574 &buffer,
4575 HashSet::default(),
4576 cx,
4577 );
4578 }
4579 }
4580 }
4581
4582 for buffer in buffers_with_unknown_injections {
4583 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4584 }
4585 });
4586 }
4587 }
4588 })
4589 }
4590
4591 fn detect_language_for_buffer(
4592 &mut self,
4593 buffer_handle: &Entity<Buffer>,
4594 cx: &mut Context<Self>,
4595 ) -> Option<language::AvailableLanguage> {
4596 // If the buffer has a language, set it and start the language server if we haven't already.
4597 let buffer = buffer_handle.read(cx);
4598 let file = buffer.file()?;
4599
4600 let content = buffer.as_rope();
4601 let available_language = self.languages.language_for_file(file, Some(content), cx);
4602 if let Some(available_language) = &available_language {
4603 if let Some(Ok(Ok(new_language))) = self
4604 .languages
4605 .load_language(available_language)
4606 .now_or_never()
4607 {
4608 self.set_language_for_buffer(buffer_handle, new_language, cx);
4609 }
4610 } else {
4611 cx.emit(LspStoreEvent::LanguageDetected {
4612 buffer: buffer_handle.clone(),
4613 new_language: None,
4614 });
4615 }
4616
4617 available_language
4618 }
4619
4620 pub(crate) fn set_language_for_buffer(
4621 &mut self,
4622 buffer_entity: &Entity<Buffer>,
4623 new_language: Arc<Language>,
4624 cx: &mut Context<Self>,
4625 ) {
4626 let buffer = buffer_entity.read(cx);
4627 let buffer_file = buffer.file().cloned();
4628 let buffer_id = buffer.remote_id();
4629 if let Some(local_store) = self.as_local_mut()
4630 && local_store.registered_buffers.contains_key(&buffer_id)
4631 && let Some(abs_path) =
4632 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4633 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4634 {
4635 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4636 }
4637 buffer_entity.update(cx, |buffer, cx| {
4638 if buffer
4639 .language()
4640 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4641 {
4642 buffer.set_language_async(Some(new_language.clone()), cx);
4643 }
4644 });
4645
4646 let settings =
4647 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4648 let buffer_file = File::from_dyn(buffer_file.as_ref());
4649
4650 let worktree_id = if let Some(file) = buffer_file {
4651 let worktree = file.worktree.clone();
4652
4653 if let Some(local) = self.as_local_mut()
4654 && local.registered_buffers.contains_key(&buffer_id)
4655 {
4656 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4657 }
4658 Some(worktree.read(cx).id())
4659 } else {
4660 None
4661 };
4662
4663 if settings.prettier.allowed
4664 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4665 {
4666 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4667 if let Some(prettier_store) = prettier_store {
4668 prettier_store.update(cx, |prettier_store, cx| {
4669 prettier_store.install_default_prettier(
4670 worktree_id,
4671 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4672 cx,
4673 )
4674 })
4675 }
4676 }
4677
4678 cx.emit(LspStoreEvent::LanguageDetected {
4679 buffer: buffer_entity.clone(),
4680 new_language: Some(new_language),
4681 })
4682 }
4683
4684 pub fn buffer_store(&self) -> Entity<BufferStore> {
4685 self.buffer_store.clone()
4686 }
4687
4688 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4689 self.active_entry = active_entry;
4690 }
4691
4692 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4693 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4694 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4695 {
4696 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4697 summaries
4698 .iter()
4699 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4700 });
4701 if let Some(summary) = summaries.next() {
4702 client
4703 .send(proto::UpdateDiagnosticSummary {
4704 project_id: downstream_project_id,
4705 worktree_id: worktree.id().to_proto(),
4706 summary: Some(summary),
4707 more_summaries: summaries.collect(),
4708 })
4709 .log_err();
4710 }
4711 }
4712 }
4713
4714 fn is_capable_for_proto_request<R>(
4715 &self,
4716 buffer: &Entity<Buffer>,
4717 request: &R,
4718 cx: &App,
4719 ) -> bool
4720 where
4721 R: LspCommand,
4722 {
4723 self.check_if_capable_for_proto_request(
4724 buffer,
4725 |capabilities| {
4726 request.check_capabilities(AdapterServerCapabilities {
4727 server_capabilities: capabilities.clone(),
4728 code_action_kinds: None,
4729 })
4730 },
4731 cx,
4732 )
4733 }
4734
4735 fn check_if_capable_for_proto_request<F>(
4736 &self,
4737 buffer: &Entity<Buffer>,
4738 check: F,
4739 cx: &App,
4740 ) -> bool
4741 where
4742 F: FnMut(&lsp::ServerCapabilities) -> bool,
4743 {
4744 let Some(language) = buffer.read(cx).language().cloned() else {
4745 return false;
4746 };
4747 let registered_language_servers = self
4748 .languages
4749 .lsp_adapters(&language.name())
4750 .into_iter()
4751 .map(|lsp_adapter| lsp_adapter.name())
4752 .collect::<HashSet<_>>();
4753 self.language_server_statuses
4754 .iter()
4755 .filter_map(|(server_id, server_status)| {
4756 // Include servers that are either registered for this language OR
4757 // available to be loaded (for SSH remote mode where adapters like
4758 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4759 // but only loaded on the server side)
4760 let is_relevant = registered_language_servers.contains(&server_status.name)
4761 || self.languages.is_lsp_adapter_available(&server_status.name);
4762 is_relevant.then_some(server_id)
4763 })
4764 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4765 .any(check)
4766 }
4767
4768 fn all_capable_for_proto_request<F>(
4769 &self,
4770 buffer: &Entity<Buffer>,
4771 mut check: F,
4772 cx: &App,
4773 ) -> Vec<lsp::LanguageServerId>
4774 where
4775 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4776 {
4777 let Some(language) = buffer.read(cx).language().cloned() else {
4778 return Vec::default();
4779 };
4780 let registered_language_servers = self
4781 .languages
4782 .lsp_adapters(&language.name())
4783 .into_iter()
4784 .map(|lsp_adapter| lsp_adapter.name())
4785 .collect::<HashSet<_>>();
4786 self.language_server_statuses
4787 .iter()
4788 .filter_map(|(server_id, server_status)| {
4789 // Include servers that are either registered for this language OR
4790 // available to be loaded (for SSH remote mode where adapters like
4791 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4792 // but only loaded on the server side)
4793 let is_relevant = registered_language_servers.contains(&server_status.name)
4794 || self.languages.is_lsp_adapter_available(&server_status.name);
4795 is_relevant.then_some((server_id, &server_status.name))
4796 })
4797 .filter_map(|(server_id, server_name)| {
4798 self.lsp_server_capabilities
4799 .get(server_id)
4800 .map(|c| (server_id, server_name, c))
4801 })
4802 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4803 .map(|(server_id, _, _)| *server_id)
4804 .collect()
4805 }
4806
4807 pub fn request_lsp<R>(
4808 &mut self,
4809 buffer: Entity<Buffer>,
4810 server: LanguageServerToQuery,
4811 request: R,
4812 cx: &mut Context<Self>,
4813 ) -> Task<Result<R::Response>>
4814 where
4815 R: LspCommand,
4816 <R::LspRequest as lsp::request::Request>::Result: Send,
4817 <R::LspRequest as lsp::request::Request>::Params: Send,
4818 {
4819 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4820 return self.send_lsp_proto_request(
4821 buffer,
4822 upstream_client,
4823 upstream_project_id,
4824 request,
4825 cx,
4826 );
4827 }
4828
4829 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4830 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4831 local
4832 .language_servers_for_buffer(buffer, cx)
4833 .find(|(_, server)| {
4834 request.check_capabilities(server.adapter_server_capabilities())
4835 })
4836 .map(|(_, server)| server.clone())
4837 }),
4838 LanguageServerToQuery::Other(id) => self
4839 .language_server_for_local_buffer(buffer, id, cx)
4840 .and_then(|(_, server)| {
4841 request
4842 .check_capabilities(server.adapter_server_capabilities())
4843 .then(|| Arc::clone(server))
4844 }),
4845 }) else {
4846 return Task::ready(Ok(Default::default()));
4847 };
4848
4849 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4850
4851 let Some(file) = file else {
4852 return Task::ready(Ok(Default::default()));
4853 };
4854
4855 let lsp_params = match request.to_lsp_params_or_response(
4856 &file.abs_path(cx),
4857 buffer.read(cx),
4858 &language_server,
4859 cx,
4860 ) {
4861 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4862 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4863 Err(err) => {
4864 let message = format!(
4865 "{} via {} failed: {}",
4866 request.display_name(),
4867 language_server.name(),
4868 err
4869 );
4870 // rust-analyzer likes to error with this when its still loading up
4871 if !message.ends_with("content modified") {
4872 log::warn!("{message}");
4873 }
4874 return Task::ready(Err(anyhow!(message)));
4875 }
4876 };
4877
4878 let status = request.status();
4879 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4880 return Task::ready(Ok(Default::default()));
4881 }
4882 cx.spawn(async move |this, cx| {
4883 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4884
4885 let id = lsp_request.id();
4886 let _cleanup = if status.is_some() {
4887 cx.update(|cx| {
4888 this.update(cx, |this, cx| {
4889 this.on_lsp_work_start(
4890 language_server.server_id(),
4891 ProgressToken::Number(id),
4892 LanguageServerProgress {
4893 is_disk_based_diagnostics_progress: false,
4894 is_cancellable: false,
4895 title: None,
4896 message: status.clone(),
4897 percentage: None,
4898 last_update_at: cx.background_executor().now(),
4899 },
4900 cx,
4901 );
4902 })
4903 })
4904 .log_err();
4905
4906 Some(defer(|| {
4907 cx.update(|cx| {
4908 this.update(cx, |this, cx| {
4909 this.on_lsp_work_end(
4910 language_server.server_id(),
4911 ProgressToken::Number(id),
4912 cx,
4913 );
4914 })
4915 })
4916 .log_err();
4917 }))
4918 } else {
4919 None
4920 };
4921
4922 let result = lsp_request.await.into_response();
4923
4924 let response = result.map_err(|err| {
4925 let message = format!(
4926 "{} via {} failed: {}",
4927 request.display_name(),
4928 language_server.name(),
4929 err
4930 );
4931 // rust-analyzer likes to error with this when its still loading up
4932 if !message.ends_with("content modified") {
4933 log::warn!("{message}");
4934 }
4935 anyhow::anyhow!(message)
4936 })?;
4937
4938 request
4939 .response_from_lsp(
4940 response,
4941 this.upgrade().context("no app context")?,
4942 buffer,
4943 language_server.server_id(),
4944 cx.clone(),
4945 )
4946 .await
4947 })
4948 }
4949
4950 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4951 let mut language_formatters_to_check = Vec::new();
4952 for buffer in self.buffer_store.read(cx).buffers() {
4953 let buffer = buffer.read(cx);
4954 let buffer_file = File::from_dyn(buffer.file());
4955 let buffer_language = buffer.language();
4956 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4957 if buffer_language.is_some() {
4958 language_formatters_to_check.push((
4959 buffer_file.map(|f| f.worktree_id(cx)),
4960 settings.into_owned(),
4961 ));
4962 }
4963 }
4964
4965 self.request_workspace_config_refresh();
4966
4967 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4968 prettier_store.update(cx, |prettier_store, cx| {
4969 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4970 })
4971 }
4972
4973 cx.notify();
4974 }
4975
4976 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4977 let buffer_store = self.buffer_store.clone();
4978 let Some(local) = self.as_local_mut() else {
4979 return;
4980 };
4981 let mut adapters = BTreeMap::default();
4982 let get_adapter = {
4983 let languages = local.languages.clone();
4984 let environment = local.environment.clone();
4985 let weak = local.weak.clone();
4986 let worktree_store = local.worktree_store.clone();
4987 let http_client = local.http_client.clone();
4988 let fs = local.fs.clone();
4989 move |worktree_id, cx: &mut App| {
4990 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4991 Some(LocalLspAdapterDelegate::new(
4992 languages.clone(),
4993 &environment,
4994 weak.clone(),
4995 &worktree,
4996 http_client.clone(),
4997 fs.clone(),
4998 cx,
4999 ))
5000 }
5001 };
5002
5003 let mut messages_to_report = Vec::new();
5004 let (new_tree, to_stop) = {
5005 let mut rebase = local.lsp_tree.rebase();
5006 let buffers = buffer_store
5007 .read(cx)
5008 .buffers()
5009 .filter_map(|buffer| {
5010 let raw_buffer = buffer.read(cx);
5011 if !local
5012 .registered_buffers
5013 .contains_key(&raw_buffer.remote_id())
5014 {
5015 return None;
5016 }
5017 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5018 let language = raw_buffer.language().cloned()?;
5019 Some((file, language, raw_buffer.remote_id()))
5020 })
5021 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5022 for (file, language, buffer_id) in buffers {
5023 let worktree_id = file.worktree_id(cx);
5024 let Some(worktree) = local
5025 .worktree_store
5026 .read(cx)
5027 .worktree_for_id(worktree_id, cx)
5028 else {
5029 continue;
5030 };
5031
5032 if let Some((_, apply)) = local.reuse_existing_language_server(
5033 rebase.server_tree(),
5034 &worktree,
5035 &language.name(),
5036 cx,
5037 ) {
5038 (apply)(rebase.server_tree());
5039 } else if let Some(lsp_delegate) = adapters
5040 .entry(worktree_id)
5041 .or_insert_with(|| get_adapter(worktree_id, cx))
5042 .clone()
5043 {
5044 let delegate =
5045 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5046 let path = file
5047 .path()
5048 .parent()
5049 .map(Arc::from)
5050 .unwrap_or_else(|| file.path().clone());
5051 let worktree_path = ProjectPath { worktree_id, path };
5052 let abs_path = file.abs_path(cx);
5053 let nodes = rebase
5054 .walk(
5055 worktree_path,
5056 language.name(),
5057 language.manifest(),
5058 delegate.clone(),
5059 cx,
5060 )
5061 .collect::<Vec<_>>();
5062 for node in nodes {
5063 let server_id = node.server_id_or_init(|disposition| {
5064 let path = &disposition.path;
5065 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5066 let key = LanguageServerSeed {
5067 worktree_id,
5068 name: disposition.server_name.clone(),
5069 settings: LanguageServerSeedSettings {
5070 binary: disposition.settings.binary.clone(),
5071 initialization_options: disposition
5072 .settings
5073 .initialization_options
5074 .clone(),
5075 },
5076 toolchain: local.toolchain_store.read(cx).active_toolchain(
5077 path.worktree_id,
5078 &path.path,
5079 language.name(),
5080 ),
5081 };
5082 local.language_server_ids.remove(&key);
5083
5084 let server_id = local.get_or_insert_language_server(
5085 &worktree,
5086 lsp_delegate.clone(),
5087 disposition,
5088 &language.name(),
5089 cx,
5090 );
5091 if let Some(state) = local.language_servers.get(&server_id)
5092 && let Ok(uri) = uri
5093 {
5094 state.add_workspace_folder(uri);
5095 };
5096 server_id
5097 });
5098
5099 if let Some(language_server_id) = server_id {
5100 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5101 language_server_id,
5102 name: node.name(),
5103 message:
5104 proto::update_language_server::Variant::RegisteredForBuffer(
5105 proto::RegisteredForBuffer {
5106 buffer_abs_path: abs_path
5107 .to_string_lossy()
5108 .into_owned(),
5109 buffer_id: buffer_id.to_proto(),
5110 },
5111 ),
5112 });
5113 }
5114 }
5115 } else {
5116 continue;
5117 }
5118 }
5119 rebase.finish()
5120 };
5121 for message in messages_to_report {
5122 cx.emit(message);
5123 }
5124 local.lsp_tree = new_tree;
5125 for (id, _) in to_stop {
5126 self.stop_local_language_server(id, cx).detach();
5127 }
5128 }
5129
5130 pub fn apply_code_action(
5131 &self,
5132 buffer_handle: Entity<Buffer>,
5133 mut action: CodeAction,
5134 push_to_history: bool,
5135 cx: &mut Context<Self>,
5136 ) -> Task<Result<ProjectTransaction>> {
5137 if let Some((upstream_client, project_id)) = self.upstream_client() {
5138 let request = proto::ApplyCodeAction {
5139 project_id,
5140 buffer_id: buffer_handle.read(cx).remote_id().into(),
5141 action: Some(Self::serialize_code_action(&action)),
5142 };
5143 let buffer_store = self.buffer_store();
5144 cx.spawn(async move |_, cx| {
5145 let response = upstream_client
5146 .request(request)
5147 .await?
5148 .transaction
5149 .context("missing transaction")?;
5150
5151 buffer_store
5152 .update(cx, |buffer_store, cx| {
5153 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5154 })
5155 .await
5156 })
5157 } else if self.mode.is_local() {
5158 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5159 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5160 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5161 }) else {
5162 return Task::ready(Ok(ProjectTransaction::default()));
5163 };
5164 cx.spawn(async move |this, cx| {
5165 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5166 .await
5167 .context("resolving a code action")?;
5168 if let Some(edit) = action.lsp_action.edit()
5169 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5170 return LocalLspStore::deserialize_workspace_edit(
5171 this.upgrade().context("no app present")?,
5172 edit.clone(),
5173 push_to_history,
5174
5175 lang_server.clone(),
5176 cx,
5177 )
5178 .await;
5179 }
5180
5181 if let Some(command) = action.lsp_action.command() {
5182 let server_capabilities = lang_server.capabilities();
5183 let available_commands = server_capabilities
5184 .execute_command_provider
5185 .as_ref()
5186 .map(|options| options.commands.as_slice())
5187 .unwrap_or_default();
5188 if available_commands.contains(&command.command) {
5189 this.update(cx, |this, _| {
5190 this.as_local_mut()
5191 .unwrap()
5192 .last_workspace_edits_by_language_server
5193 .remove(&lang_server.server_id());
5194 })?;
5195
5196 let _result = lang_server
5197 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5198 command: command.command.clone(),
5199 arguments: command.arguments.clone().unwrap_or_default(),
5200 ..lsp::ExecuteCommandParams::default()
5201 })
5202 .await.into_response()
5203 .context("execute command")?;
5204
5205 return this.update(cx, |this, _| {
5206 this.as_local_mut()
5207 .unwrap()
5208 .last_workspace_edits_by_language_server
5209 .remove(&lang_server.server_id())
5210 .unwrap_or_default()
5211 });
5212 } else {
5213 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5214 }
5215 }
5216
5217 Ok(ProjectTransaction::default())
5218 })
5219 } else {
5220 Task::ready(Err(anyhow!("no upstream client and not local")))
5221 }
5222 }
5223
5224 pub fn apply_code_action_kind(
5225 &mut self,
5226 buffers: HashSet<Entity<Buffer>>,
5227 kind: CodeActionKind,
5228 push_to_history: bool,
5229 cx: &mut Context<Self>,
5230 ) -> Task<anyhow::Result<ProjectTransaction>> {
5231 if self.as_local().is_some() {
5232 cx.spawn(async move |lsp_store, cx| {
5233 let buffers = buffers.into_iter().collect::<Vec<_>>();
5234 let result = LocalLspStore::execute_code_action_kind_locally(
5235 lsp_store.clone(),
5236 buffers,
5237 kind,
5238 push_to_history,
5239 cx,
5240 )
5241 .await;
5242 lsp_store.update(cx, |lsp_store, _| {
5243 lsp_store.update_last_formatting_failure(&result);
5244 })?;
5245 result
5246 })
5247 } else if let Some((client, project_id)) = self.upstream_client() {
5248 let buffer_store = self.buffer_store();
5249 cx.spawn(async move |lsp_store, cx| {
5250 let result = client
5251 .request(proto::ApplyCodeActionKind {
5252 project_id,
5253 kind: kind.as_str().to_owned(),
5254 buffer_ids: buffers
5255 .iter()
5256 .map(|buffer| {
5257 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5258 })
5259 .collect(),
5260 })
5261 .await
5262 .and_then(|result| result.transaction.context("missing transaction"));
5263 lsp_store.update(cx, |lsp_store, _| {
5264 lsp_store.update_last_formatting_failure(&result);
5265 })?;
5266
5267 let transaction_response = result?;
5268 buffer_store
5269 .update(cx, |buffer_store, cx| {
5270 buffer_store.deserialize_project_transaction(
5271 transaction_response,
5272 push_to_history,
5273 cx,
5274 )
5275 })
5276 .await
5277 })
5278 } else {
5279 Task::ready(Ok(ProjectTransaction::default()))
5280 }
5281 }
5282
5283 pub fn resolved_hint(
5284 &mut self,
5285 buffer_id: BufferId,
5286 id: InlayId,
5287 cx: &mut Context<Self>,
5288 ) -> Option<ResolvedHint> {
5289 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5290
5291 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5292 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5293 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5294 let (server_id, resolve_data) = match &hint.resolve_state {
5295 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5296 ResolveState::Resolving => {
5297 return Some(ResolvedHint::Resolving(
5298 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5299 ));
5300 }
5301 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5302 };
5303
5304 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5305 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5306 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5307 id,
5308 cx.spawn(async move |lsp_store, cx| {
5309 let resolved_hint = resolve_task.await;
5310 lsp_store
5311 .update(cx, |lsp_store, _| {
5312 if let Some(old_inlay_hint) = lsp_store
5313 .lsp_data
5314 .get_mut(&buffer_id)
5315 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5316 {
5317 match resolved_hint {
5318 Ok(resolved_hint) => {
5319 *old_inlay_hint = resolved_hint;
5320 }
5321 Err(e) => {
5322 old_inlay_hint.resolve_state =
5323 ResolveState::CanResolve(server_id, resolve_data);
5324 log::error!("Inlay hint resolve failed: {e:#}");
5325 }
5326 }
5327 }
5328 })
5329 .ok();
5330 })
5331 .shared(),
5332 );
5333 debug_assert!(
5334 previous_task.is_none(),
5335 "Did not change hint's resolve state after spawning its resolve"
5336 );
5337 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5338 None
5339 }
5340
5341 fn resolve_inlay_hint(
5342 &self,
5343 mut hint: InlayHint,
5344 buffer: Entity<Buffer>,
5345 server_id: LanguageServerId,
5346 cx: &mut Context<Self>,
5347 ) -> Task<anyhow::Result<InlayHint>> {
5348 if let Some((upstream_client, project_id)) = self.upstream_client() {
5349 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5350 {
5351 hint.resolve_state = ResolveState::Resolved;
5352 return Task::ready(Ok(hint));
5353 }
5354 let request = proto::ResolveInlayHint {
5355 project_id,
5356 buffer_id: buffer.read(cx).remote_id().into(),
5357 language_server_id: server_id.0 as u64,
5358 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5359 };
5360 cx.background_spawn(async move {
5361 let response = upstream_client
5362 .request(request)
5363 .await
5364 .context("inlay hints proto request")?;
5365 match response.hint {
5366 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5367 .context("inlay hints proto resolve response conversion"),
5368 None => Ok(hint),
5369 }
5370 })
5371 } else {
5372 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5373 self.language_server_for_local_buffer(buffer, server_id, cx)
5374 .map(|(_, server)| server.clone())
5375 }) else {
5376 return Task::ready(Ok(hint));
5377 };
5378 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5379 return Task::ready(Ok(hint));
5380 }
5381 let buffer_snapshot = buffer.read(cx).snapshot();
5382 cx.spawn(async move |_, cx| {
5383 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5384 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5385 );
5386 let resolved_hint = resolve_task
5387 .await
5388 .into_response()
5389 .context("inlay hint resolve LSP request")?;
5390 let resolved_hint = InlayHints::lsp_to_project_hint(
5391 resolved_hint,
5392 &buffer,
5393 server_id,
5394 ResolveState::Resolved,
5395 false,
5396 cx,
5397 )
5398 .await?;
5399 Ok(resolved_hint)
5400 })
5401 }
5402 }
5403
5404 pub fn resolve_color_presentation(
5405 &mut self,
5406 mut color: DocumentColor,
5407 buffer: Entity<Buffer>,
5408 server_id: LanguageServerId,
5409 cx: &mut Context<Self>,
5410 ) -> Task<Result<DocumentColor>> {
5411 if color.resolved {
5412 return Task::ready(Ok(color));
5413 }
5414
5415 if let Some((upstream_client, project_id)) = self.upstream_client() {
5416 let start = color.lsp_range.start;
5417 let end = color.lsp_range.end;
5418 let request = proto::GetColorPresentation {
5419 project_id,
5420 server_id: server_id.to_proto(),
5421 buffer_id: buffer.read(cx).remote_id().into(),
5422 color: Some(proto::ColorInformation {
5423 red: color.color.red,
5424 green: color.color.green,
5425 blue: color.color.blue,
5426 alpha: color.color.alpha,
5427 lsp_range_start: Some(proto::PointUtf16 {
5428 row: start.line,
5429 column: start.character,
5430 }),
5431 lsp_range_end: Some(proto::PointUtf16 {
5432 row: end.line,
5433 column: end.character,
5434 }),
5435 }),
5436 };
5437 cx.background_spawn(async move {
5438 let response = upstream_client
5439 .request(request)
5440 .await
5441 .context("color presentation proto request")?;
5442 color.resolved = true;
5443 color.color_presentations = response
5444 .presentations
5445 .into_iter()
5446 .map(|presentation| ColorPresentation {
5447 label: SharedString::from(presentation.label),
5448 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5449 additional_text_edits: presentation
5450 .additional_text_edits
5451 .into_iter()
5452 .filter_map(deserialize_lsp_edit)
5453 .collect(),
5454 })
5455 .collect();
5456 Ok(color)
5457 })
5458 } else {
5459 let path = match buffer
5460 .update(cx, |buffer, cx| {
5461 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5462 })
5463 .context("buffer with the missing path")
5464 {
5465 Ok(path) => path,
5466 Err(e) => return Task::ready(Err(e)),
5467 };
5468 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5469 self.language_server_for_local_buffer(buffer, server_id, cx)
5470 .map(|(_, server)| server.clone())
5471 }) else {
5472 return Task::ready(Ok(color));
5473 };
5474 cx.background_spawn(async move {
5475 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5476 lsp::ColorPresentationParams {
5477 text_document: make_text_document_identifier(&path)?,
5478 color: color.color,
5479 range: color.lsp_range,
5480 work_done_progress_params: Default::default(),
5481 partial_result_params: Default::default(),
5482 },
5483 );
5484 color.color_presentations = resolve_task
5485 .await
5486 .into_response()
5487 .context("color presentation resolve LSP request")?
5488 .into_iter()
5489 .map(|presentation| ColorPresentation {
5490 label: SharedString::from(presentation.label),
5491 text_edit: presentation.text_edit,
5492 additional_text_edits: presentation
5493 .additional_text_edits
5494 .unwrap_or_default(),
5495 })
5496 .collect();
5497 color.resolved = true;
5498 Ok(color)
5499 })
5500 }
5501 }
5502
5503 pub(crate) fn linked_edits(
5504 &mut self,
5505 buffer: &Entity<Buffer>,
5506 position: Anchor,
5507 cx: &mut Context<Self>,
5508 ) -> Task<Result<Vec<Range<Anchor>>>> {
5509 let snapshot = buffer.read(cx).snapshot();
5510 let scope = snapshot.language_scope_at(position);
5511 let Some(server_id) = self
5512 .as_local()
5513 .and_then(|local| {
5514 buffer.update(cx, |buffer, cx| {
5515 local
5516 .language_servers_for_buffer(buffer, cx)
5517 .filter(|(_, server)| {
5518 LinkedEditingRange::check_server_capabilities(server.capabilities())
5519 })
5520 .filter(|(adapter, _)| {
5521 scope
5522 .as_ref()
5523 .map(|scope| scope.language_allowed(&adapter.name))
5524 .unwrap_or(true)
5525 })
5526 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5527 .next()
5528 })
5529 })
5530 .or_else(|| {
5531 self.upstream_client()
5532 .is_some()
5533 .then_some(LanguageServerToQuery::FirstCapable)
5534 })
5535 .filter(|_| {
5536 maybe!({
5537 let language = buffer.read(cx).language_at(position)?;
5538 Some(
5539 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5540 .linked_edits,
5541 )
5542 }) == Some(true)
5543 })
5544 else {
5545 return Task::ready(Ok(Vec::new()));
5546 };
5547
5548 self.request_lsp(
5549 buffer.clone(),
5550 server_id,
5551 LinkedEditingRange { position },
5552 cx,
5553 )
5554 }
5555
5556 fn apply_on_type_formatting(
5557 &mut self,
5558 buffer: Entity<Buffer>,
5559 position: Anchor,
5560 trigger: String,
5561 cx: &mut Context<Self>,
5562 ) -> Task<Result<Option<Transaction>>> {
5563 if let Some((client, project_id)) = self.upstream_client() {
5564 if !self.check_if_capable_for_proto_request(
5565 &buffer,
5566 |capabilities| {
5567 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5568 },
5569 cx,
5570 ) {
5571 return Task::ready(Ok(None));
5572 }
5573 let request = proto::OnTypeFormatting {
5574 project_id,
5575 buffer_id: buffer.read(cx).remote_id().into(),
5576 position: Some(serialize_anchor(&position)),
5577 trigger,
5578 version: serialize_version(&buffer.read(cx).version()),
5579 };
5580 cx.background_spawn(async move {
5581 client
5582 .request(request)
5583 .await?
5584 .transaction
5585 .map(language::proto::deserialize_transaction)
5586 .transpose()
5587 })
5588 } else if let Some(local) = self.as_local_mut() {
5589 let buffer_id = buffer.read(cx).remote_id();
5590 local.buffers_being_formatted.insert(buffer_id);
5591 cx.spawn(async move |this, cx| {
5592 let _cleanup = defer({
5593 let this = this.clone();
5594 let mut cx = cx.clone();
5595 move || {
5596 this.update(&mut cx, |this, _| {
5597 if let Some(local) = this.as_local_mut() {
5598 local.buffers_being_formatted.remove(&buffer_id);
5599 }
5600 })
5601 .ok();
5602 }
5603 });
5604
5605 buffer
5606 .update(cx, |buffer, _| {
5607 buffer.wait_for_edits(Some(position.timestamp))
5608 })
5609 .await?;
5610 this.update(cx, |this, cx| {
5611 let position = position.to_point_utf16(buffer.read(cx));
5612 this.on_type_format(buffer, position, trigger, false, cx)
5613 })?
5614 .await
5615 })
5616 } else {
5617 Task::ready(Err(anyhow!("No upstream client or local language server")))
5618 }
5619 }
5620
5621 pub fn on_type_format<T: ToPointUtf16>(
5622 &mut self,
5623 buffer: Entity<Buffer>,
5624 position: T,
5625 trigger: String,
5626 push_to_history: bool,
5627 cx: &mut Context<Self>,
5628 ) -> Task<Result<Option<Transaction>>> {
5629 let position = position.to_point_utf16(buffer.read(cx));
5630 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5631 }
5632
5633 fn on_type_format_impl(
5634 &mut self,
5635 buffer: Entity<Buffer>,
5636 position: PointUtf16,
5637 trigger: String,
5638 push_to_history: bool,
5639 cx: &mut Context<Self>,
5640 ) -> Task<Result<Option<Transaction>>> {
5641 let options = buffer.update(cx, |buffer, cx| {
5642 lsp_command::lsp_formatting_options(
5643 language_settings(
5644 buffer.language_at(position).map(|l| l.name()),
5645 buffer.file(),
5646 cx,
5647 )
5648 .as_ref(),
5649 )
5650 });
5651
5652 cx.spawn(async move |this, cx| {
5653 if let Some(waiter) =
5654 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5655 {
5656 waiter.await?;
5657 }
5658 cx.update(|cx| {
5659 this.update(cx, |this, cx| {
5660 this.request_lsp(
5661 buffer.clone(),
5662 LanguageServerToQuery::FirstCapable,
5663 OnTypeFormatting {
5664 position,
5665 trigger,
5666 options,
5667 push_to_history,
5668 },
5669 cx,
5670 )
5671 })
5672 })?
5673 .await
5674 })
5675 }
5676
5677 pub fn definitions(
5678 &mut self,
5679 buffer: &Entity<Buffer>,
5680 position: PointUtf16,
5681 cx: &mut Context<Self>,
5682 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5683 if let Some((upstream_client, project_id)) = self.upstream_client() {
5684 let request = GetDefinitions { position };
5685 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5686 return Task::ready(Ok(None));
5687 }
5688 let request_task = upstream_client.request_lsp(
5689 project_id,
5690 None,
5691 LSP_REQUEST_TIMEOUT,
5692 cx.background_executor().clone(),
5693 request.to_proto(project_id, buffer.read(cx)),
5694 );
5695 let buffer = buffer.clone();
5696 cx.spawn(async move |weak_lsp_store, cx| {
5697 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5698 return Ok(None);
5699 };
5700 let Some(responses) = request_task.await? else {
5701 return Ok(None);
5702 };
5703 let actions = join_all(responses.payload.into_iter().map(|response| {
5704 GetDefinitions { position }.response_from_proto(
5705 response.response,
5706 lsp_store.clone(),
5707 buffer.clone(),
5708 cx.clone(),
5709 )
5710 }))
5711 .await;
5712
5713 Ok(Some(
5714 actions
5715 .into_iter()
5716 .collect::<Result<Vec<Vec<_>>>>()?
5717 .into_iter()
5718 .flatten()
5719 .dedup()
5720 .collect(),
5721 ))
5722 })
5723 } else {
5724 let definitions_task = self.request_multiple_lsp_locally(
5725 buffer,
5726 Some(position),
5727 GetDefinitions { position },
5728 cx,
5729 );
5730 cx.background_spawn(async move {
5731 Ok(Some(
5732 definitions_task
5733 .await
5734 .into_iter()
5735 .flat_map(|(_, definitions)| definitions)
5736 .dedup()
5737 .collect(),
5738 ))
5739 })
5740 }
5741 }
5742
5743 pub fn declarations(
5744 &mut self,
5745 buffer: &Entity<Buffer>,
5746 position: PointUtf16,
5747 cx: &mut Context<Self>,
5748 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5749 if let Some((upstream_client, project_id)) = self.upstream_client() {
5750 let request = GetDeclarations { position };
5751 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5752 return Task::ready(Ok(None));
5753 }
5754 let request_task = upstream_client.request_lsp(
5755 project_id,
5756 None,
5757 LSP_REQUEST_TIMEOUT,
5758 cx.background_executor().clone(),
5759 request.to_proto(project_id, buffer.read(cx)),
5760 );
5761 let buffer = buffer.clone();
5762 cx.spawn(async move |weak_lsp_store, cx| {
5763 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5764 return Ok(None);
5765 };
5766 let Some(responses) = request_task.await? else {
5767 return Ok(None);
5768 };
5769 let actions = join_all(responses.payload.into_iter().map(|response| {
5770 GetDeclarations { position }.response_from_proto(
5771 response.response,
5772 lsp_store.clone(),
5773 buffer.clone(),
5774 cx.clone(),
5775 )
5776 }))
5777 .await;
5778
5779 Ok(Some(
5780 actions
5781 .into_iter()
5782 .collect::<Result<Vec<Vec<_>>>>()?
5783 .into_iter()
5784 .flatten()
5785 .dedup()
5786 .collect(),
5787 ))
5788 })
5789 } else {
5790 let declarations_task = self.request_multiple_lsp_locally(
5791 buffer,
5792 Some(position),
5793 GetDeclarations { position },
5794 cx,
5795 );
5796 cx.background_spawn(async move {
5797 Ok(Some(
5798 declarations_task
5799 .await
5800 .into_iter()
5801 .flat_map(|(_, declarations)| declarations)
5802 .dedup()
5803 .collect(),
5804 ))
5805 })
5806 }
5807 }
5808
5809 pub fn type_definitions(
5810 &mut self,
5811 buffer: &Entity<Buffer>,
5812 position: PointUtf16,
5813 cx: &mut Context<Self>,
5814 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5815 if let Some((upstream_client, project_id)) = self.upstream_client() {
5816 let request = GetTypeDefinitions { position };
5817 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5818 return Task::ready(Ok(None));
5819 }
5820 let request_task = upstream_client.request_lsp(
5821 project_id,
5822 None,
5823 LSP_REQUEST_TIMEOUT,
5824 cx.background_executor().clone(),
5825 request.to_proto(project_id, buffer.read(cx)),
5826 );
5827 let buffer = buffer.clone();
5828 cx.spawn(async move |weak_lsp_store, cx| {
5829 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5830 return Ok(None);
5831 };
5832 let Some(responses) = request_task.await? else {
5833 return Ok(None);
5834 };
5835 let actions = join_all(responses.payload.into_iter().map(|response| {
5836 GetTypeDefinitions { position }.response_from_proto(
5837 response.response,
5838 lsp_store.clone(),
5839 buffer.clone(),
5840 cx.clone(),
5841 )
5842 }))
5843 .await;
5844
5845 Ok(Some(
5846 actions
5847 .into_iter()
5848 .collect::<Result<Vec<Vec<_>>>>()?
5849 .into_iter()
5850 .flatten()
5851 .dedup()
5852 .collect(),
5853 ))
5854 })
5855 } else {
5856 let type_definitions_task = self.request_multiple_lsp_locally(
5857 buffer,
5858 Some(position),
5859 GetTypeDefinitions { position },
5860 cx,
5861 );
5862 cx.background_spawn(async move {
5863 Ok(Some(
5864 type_definitions_task
5865 .await
5866 .into_iter()
5867 .flat_map(|(_, type_definitions)| type_definitions)
5868 .dedup()
5869 .collect(),
5870 ))
5871 })
5872 }
5873 }
5874
5875 pub fn implementations(
5876 &mut self,
5877 buffer: &Entity<Buffer>,
5878 position: PointUtf16,
5879 cx: &mut Context<Self>,
5880 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5881 if let Some((upstream_client, project_id)) = self.upstream_client() {
5882 let request = GetImplementations { position };
5883 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5884 return Task::ready(Ok(None));
5885 }
5886 let request_task = upstream_client.request_lsp(
5887 project_id,
5888 None,
5889 LSP_REQUEST_TIMEOUT,
5890 cx.background_executor().clone(),
5891 request.to_proto(project_id, buffer.read(cx)),
5892 );
5893 let buffer = buffer.clone();
5894 cx.spawn(async move |weak_lsp_store, cx| {
5895 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5896 return Ok(None);
5897 };
5898 let Some(responses) = request_task.await? else {
5899 return Ok(None);
5900 };
5901 let actions = join_all(responses.payload.into_iter().map(|response| {
5902 GetImplementations { position }.response_from_proto(
5903 response.response,
5904 lsp_store.clone(),
5905 buffer.clone(),
5906 cx.clone(),
5907 )
5908 }))
5909 .await;
5910
5911 Ok(Some(
5912 actions
5913 .into_iter()
5914 .collect::<Result<Vec<Vec<_>>>>()?
5915 .into_iter()
5916 .flatten()
5917 .dedup()
5918 .collect(),
5919 ))
5920 })
5921 } else {
5922 let implementations_task = self.request_multiple_lsp_locally(
5923 buffer,
5924 Some(position),
5925 GetImplementations { position },
5926 cx,
5927 );
5928 cx.background_spawn(async move {
5929 Ok(Some(
5930 implementations_task
5931 .await
5932 .into_iter()
5933 .flat_map(|(_, implementations)| implementations)
5934 .dedup()
5935 .collect(),
5936 ))
5937 })
5938 }
5939 }
5940
5941 pub fn references(
5942 &mut self,
5943 buffer: &Entity<Buffer>,
5944 position: PointUtf16,
5945 cx: &mut Context<Self>,
5946 ) -> Task<Result<Option<Vec<Location>>>> {
5947 if let Some((upstream_client, project_id)) = self.upstream_client() {
5948 let request = GetReferences { position };
5949 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5950 return Task::ready(Ok(None));
5951 }
5952
5953 let request_task = upstream_client.request_lsp(
5954 project_id,
5955 None,
5956 LSP_REQUEST_TIMEOUT,
5957 cx.background_executor().clone(),
5958 request.to_proto(project_id, buffer.read(cx)),
5959 );
5960 let buffer = buffer.clone();
5961 cx.spawn(async move |weak_lsp_store, cx| {
5962 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5963 return Ok(None);
5964 };
5965 let Some(responses) = request_task.await? else {
5966 return Ok(None);
5967 };
5968
5969 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5970 GetReferences { position }.response_from_proto(
5971 lsp_response.response,
5972 lsp_store.clone(),
5973 buffer.clone(),
5974 cx.clone(),
5975 )
5976 }))
5977 .await
5978 .into_iter()
5979 .collect::<Result<Vec<Vec<_>>>>()?
5980 .into_iter()
5981 .flatten()
5982 .dedup()
5983 .collect();
5984 Ok(Some(locations))
5985 })
5986 } else {
5987 let references_task = self.request_multiple_lsp_locally(
5988 buffer,
5989 Some(position),
5990 GetReferences { position },
5991 cx,
5992 );
5993 cx.background_spawn(async move {
5994 Ok(Some(
5995 references_task
5996 .await
5997 .into_iter()
5998 .flat_map(|(_, references)| references)
5999 .dedup()
6000 .collect(),
6001 ))
6002 })
6003 }
6004 }
6005
6006 pub fn code_actions(
6007 &mut self,
6008 buffer: &Entity<Buffer>,
6009 range: Range<Anchor>,
6010 kinds: Option<Vec<CodeActionKind>>,
6011 cx: &mut Context<Self>,
6012 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6013 if let Some((upstream_client, project_id)) = self.upstream_client() {
6014 let request = GetCodeActions {
6015 range: range.clone(),
6016 kinds: kinds.clone(),
6017 };
6018 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6019 return Task::ready(Ok(None));
6020 }
6021 let request_task = upstream_client.request_lsp(
6022 project_id,
6023 None,
6024 LSP_REQUEST_TIMEOUT,
6025 cx.background_executor().clone(),
6026 request.to_proto(project_id, buffer.read(cx)),
6027 );
6028 let buffer = buffer.clone();
6029 cx.spawn(async move |weak_lsp_store, cx| {
6030 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6031 return Ok(None);
6032 };
6033 let Some(responses) = request_task.await? else {
6034 return Ok(None);
6035 };
6036 let actions = join_all(responses.payload.into_iter().map(|response| {
6037 GetCodeActions {
6038 range: range.clone(),
6039 kinds: kinds.clone(),
6040 }
6041 .response_from_proto(
6042 response.response,
6043 lsp_store.clone(),
6044 buffer.clone(),
6045 cx.clone(),
6046 )
6047 }))
6048 .await;
6049
6050 Ok(Some(
6051 actions
6052 .into_iter()
6053 .collect::<Result<Vec<Vec<_>>>>()?
6054 .into_iter()
6055 .flatten()
6056 .collect(),
6057 ))
6058 })
6059 } else {
6060 let all_actions_task = self.request_multiple_lsp_locally(
6061 buffer,
6062 Some(range.start),
6063 GetCodeActions { range, kinds },
6064 cx,
6065 );
6066 cx.background_spawn(async move {
6067 Ok(Some(
6068 all_actions_task
6069 .await
6070 .into_iter()
6071 .flat_map(|(_, actions)| actions)
6072 .collect(),
6073 ))
6074 })
6075 }
6076 }
6077
6078 pub fn code_lens_actions(
6079 &mut self,
6080 buffer: &Entity<Buffer>,
6081 cx: &mut Context<Self>,
6082 ) -> CodeLensTask {
6083 let version_queried_for = buffer.read(cx).version();
6084 let buffer_id = buffer.read(cx).remote_id();
6085 let existing_servers = self.as_local().map(|local| {
6086 local
6087 .buffers_opened_in_servers
6088 .get(&buffer_id)
6089 .cloned()
6090 .unwrap_or_default()
6091 });
6092
6093 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6094 if let Some(cached_lens) = &lsp_data.code_lens {
6095 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6096 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6097 existing_servers != cached_lens.lens.keys().copied().collect()
6098 });
6099 if !has_different_servers {
6100 return Task::ready(Ok(Some(
6101 cached_lens.lens.values().flatten().cloned().collect(),
6102 )))
6103 .shared();
6104 }
6105 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6106 if !version_queried_for.changed_since(updating_for) {
6107 return running_update.clone();
6108 }
6109 }
6110 }
6111 }
6112
6113 let lens_lsp_data = self
6114 .latest_lsp_data(buffer, cx)
6115 .code_lens
6116 .get_or_insert_default();
6117 let buffer = buffer.clone();
6118 let query_version_queried_for = version_queried_for.clone();
6119 let new_task = cx
6120 .spawn(async move |lsp_store, cx| {
6121 cx.background_executor()
6122 .timer(Duration::from_millis(30))
6123 .await;
6124 let fetched_lens = lsp_store
6125 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6126 .map_err(Arc::new)?
6127 .await
6128 .context("fetching code lens")
6129 .map_err(Arc::new);
6130 let fetched_lens = match fetched_lens {
6131 Ok(fetched_lens) => fetched_lens,
6132 Err(e) => {
6133 lsp_store
6134 .update(cx, |lsp_store, _| {
6135 if let Some(lens_lsp_data) = lsp_store
6136 .lsp_data
6137 .get_mut(&buffer_id)
6138 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6139 {
6140 lens_lsp_data.update = None;
6141 }
6142 })
6143 .ok();
6144 return Err(e);
6145 }
6146 };
6147
6148 lsp_store
6149 .update(cx, |lsp_store, _| {
6150 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6151 let code_lens = lsp_data.code_lens.as_mut()?;
6152 if let Some(fetched_lens) = fetched_lens {
6153 if lsp_data.buffer_version == query_version_queried_for {
6154 code_lens.lens.extend(fetched_lens);
6155 } else if !lsp_data
6156 .buffer_version
6157 .changed_since(&query_version_queried_for)
6158 {
6159 lsp_data.buffer_version = query_version_queried_for;
6160 code_lens.lens = fetched_lens;
6161 }
6162 }
6163 code_lens.update = None;
6164 Some(code_lens.lens.values().flatten().cloned().collect())
6165 })
6166 .map_err(Arc::new)
6167 })
6168 .shared();
6169 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6170 new_task
6171 }
6172
6173 fn fetch_code_lens(
6174 &mut self,
6175 buffer: &Entity<Buffer>,
6176 cx: &mut Context<Self>,
6177 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6178 if let Some((upstream_client, project_id)) = self.upstream_client() {
6179 let request = GetCodeLens;
6180 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6181 return Task::ready(Ok(None));
6182 }
6183 let request_task = upstream_client.request_lsp(
6184 project_id,
6185 None,
6186 LSP_REQUEST_TIMEOUT,
6187 cx.background_executor().clone(),
6188 request.to_proto(project_id, buffer.read(cx)),
6189 );
6190 let buffer = buffer.clone();
6191 cx.spawn(async move |weak_lsp_store, cx| {
6192 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6193 return Ok(None);
6194 };
6195 let Some(responses) = request_task.await? else {
6196 return Ok(None);
6197 };
6198
6199 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6200 let lsp_store = lsp_store.clone();
6201 let buffer = buffer.clone();
6202 let cx = cx.clone();
6203 async move {
6204 (
6205 LanguageServerId::from_proto(response.server_id),
6206 GetCodeLens
6207 .response_from_proto(response.response, lsp_store, buffer, cx)
6208 .await,
6209 )
6210 }
6211 }))
6212 .await;
6213
6214 let mut has_errors = false;
6215 let code_lens_actions = code_lens_actions
6216 .into_iter()
6217 .filter_map(|(server_id, code_lens)| match code_lens {
6218 Ok(code_lens) => Some((server_id, code_lens)),
6219 Err(e) => {
6220 has_errors = true;
6221 log::error!("{e:#}");
6222 None
6223 }
6224 })
6225 .collect::<HashMap<_, _>>();
6226 anyhow::ensure!(
6227 !has_errors || !code_lens_actions.is_empty(),
6228 "Failed to fetch code lens"
6229 );
6230 Ok(Some(code_lens_actions))
6231 })
6232 } else {
6233 let code_lens_actions_task =
6234 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6235 cx.background_spawn(async move {
6236 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6237 })
6238 }
6239 }
6240
6241 #[inline(never)]
6242 pub fn completions(
6243 &self,
6244 buffer: &Entity<Buffer>,
6245 position: PointUtf16,
6246 context: CompletionContext,
6247 cx: &mut Context<Self>,
6248 ) -> Task<Result<Vec<CompletionResponse>>> {
6249 let language_registry = self.languages.clone();
6250
6251 if let Some((upstream_client, project_id)) = self.upstream_client() {
6252 let snapshot = buffer.read(cx).snapshot();
6253 let offset = position.to_offset(&snapshot);
6254 let scope = snapshot.language_scope_at(offset);
6255 let capable_lsps = self.all_capable_for_proto_request(
6256 buffer,
6257 |server_name, capabilities| {
6258 capabilities.completion_provider.is_some()
6259 && scope
6260 .as_ref()
6261 .map(|scope| scope.language_allowed(server_name))
6262 .unwrap_or(true)
6263 },
6264 cx,
6265 );
6266 if capable_lsps.is_empty() {
6267 return Task::ready(Ok(Vec::new()));
6268 }
6269
6270 let language = buffer.read(cx).language().cloned();
6271
6272 // In the future, we should provide project guests with the names of LSP adapters,
6273 // so that they can use the correct LSP adapter when computing labels. For now,
6274 // guests just use the first LSP adapter associated with the buffer's language.
6275 let lsp_adapter = language.as_ref().and_then(|language| {
6276 language_registry
6277 .lsp_adapters(&language.name())
6278 .first()
6279 .cloned()
6280 });
6281
6282 let buffer = buffer.clone();
6283
6284 cx.spawn(async move |this, cx| {
6285 let requests = join_all(
6286 capable_lsps
6287 .into_iter()
6288 .map(|id| {
6289 let request = GetCompletions {
6290 position,
6291 context: context.clone(),
6292 server_id: Some(id),
6293 };
6294 let buffer = buffer.clone();
6295 let language = language.clone();
6296 let lsp_adapter = lsp_adapter.clone();
6297 let upstream_client = upstream_client.clone();
6298 let response = this
6299 .update(cx, |this, cx| {
6300 this.send_lsp_proto_request(
6301 buffer,
6302 upstream_client,
6303 project_id,
6304 request,
6305 cx,
6306 )
6307 })
6308 .log_err();
6309 async move {
6310 let response = response?.await.log_err()?;
6311
6312 let completions = populate_labels_for_completions(
6313 response.completions,
6314 language,
6315 lsp_adapter,
6316 )
6317 .await;
6318
6319 Some(CompletionResponse {
6320 completions,
6321 display_options: CompletionDisplayOptions::default(),
6322 is_incomplete: response.is_incomplete,
6323 })
6324 }
6325 })
6326 .collect::<Vec<_>>(),
6327 );
6328 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6329 })
6330 } else if let Some(local) = self.as_local() {
6331 let snapshot = buffer.read(cx).snapshot();
6332 let offset = position.to_offset(&snapshot);
6333 let scope = snapshot.language_scope_at(offset);
6334 let language = snapshot.language().cloned();
6335 let completion_settings = language_settings(
6336 language.as_ref().map(|language| language.name()),
6337 buffer.read(cx).file(),
6338 cx,
6339 )
6340 .completions
6341 .clone();
6342 if !completion_settings.lsp {
6343 return Task::ready(Ok(Vec::new()));
6344 }
6345
6346 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6347 local
6348 .language_servers_for_buffer(buffer, cx)
6349 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6350 .filter(|(adapter, _)| {
6351 scope
6352 .as_ref()
6353 .map(|scope| scope.language_allowed(&adapter.name))
6354 .unwrap_or(true)
6355 })
6356 .map(|(_, server)| server.server_id())
6357 .collect()
6358 });
6359
6360 let buffer = buffer.clone();
6361 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6362 let lsp_timeout = if lsp_timeout > 0 {
6363 Some(Duration::from_millis(lsp_timeout))
6364 } else {
6365 None
6366 };
6367 cx.spawn(async move |this, cx| {
6368 let mut tasks = Vec::with_capacity(server_ids.len());
6369 this.update(cx, |lsp_store, cx| {
6370 for server_id in server_ids {
6371 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6372 let lsp_timeout = lsp_timeout
6373 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6374 let mut timeout = cx.background_spawn(async move {
6375 match lsp_timeout {
6376 Some(lsp_timeout) => {
6377 lsp_timeout.await;
6378 true
6379 },
6380 None => false,
6381 }
6382 }).fuse();
6383 let mut lsp_request = lsp_store.request_lsp(
6384 buffer.clone(),
6385 LanguageServerToQuery::Other(server_id),
6386 GetCompletions {
6387 position,
6388 context: context.clone(),
6389 server_id: Some(server_id),
6390 },
6391 cx,
6392 ).fuse();
6393 let new_task = cx.background_spawn(async move {
6394 select_biased! {
6395 response = lsp_request => anyhow::Ok(Some(response?)),
6396 timeout_happened = timeout => {
6397 if timeout_happened {
6398 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6399 Ok(None)
6400 } else {
6401 let completions = lsp_request.await?;
6402 Ok(Some(completions))
6403 }
6404 },
6405 }
6406 });
6407 tasks.push((lsp_adapter, new_task));
6408 }
6409 })?;
6410
6411 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6412 let completion_response = task.await.ok()??;
6413 let completions = populate_labels_for_completions(
6414 completion_response.completions,
6415 language.clone(),
6416 lsp_adapter,
6417 )
6418 .await;
6419 Some(CompletionResponse {
6420 completions,
6421 display_options: CompletionDisplayOptions::default(),
6422 is_incomplete: completion_response.is_incomplete,
6423 })
6424 });
6425
6426 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6427
6428 Ok(responses.into_iter().flatten().collect())
6429 })
6430 } else {
6431 Task::ready(Err(anyhow!("No upstream client or local language server")))
6432 }
6433 }
6434
6435 pub fn resolve_completions(
6436 &self,
6437 buffer: Entity<Buffer>,
6438 completion_indices: Vec<usize>,
6439 completions: Rc<RefCell<Box<[Completion]>>>,
6440 cx: &mut Context<Self>,
6441 ) -> Task<Result<bool>> {
6442 let client = self.upstream_client();
6443 let buffer_id = buffer.read(cx).remote_id();
6444 let buffer_snapshot = buffer.read(cx).snapshot();
6445
6446 if !self.check_if_capable_for_proto_request(
6447 &buffer,
6448 GetCompletions::can_resolve_completions,
6449 cx,
6450 ) {
6451 return Task::ready(Ok(false));
6452 }
6453 cx.spawn(async move |lsp_store, cx| {
6454 let mut did_resolve = false;
6455 if let Some((client, project_id)) = client {
6456 for completion_index in completion_indices {
6457 let server_id = {
6458 let completion = &completions.borrow()[completion_index];
6459 completion.source.server_id()
6460 };
6461 if let Some(server_id) = server_id {
6462 if Self::resolve_completion_remote(
6463 project_id,
6464 server_id,
6465 buffer_id,
6466 completions.clone(),
6467 completion_index,
6468 client.clone(),
6469 )
6470 .await
6471 .log_err()
6472 .is_some()
6473 {
6474 did_resolve = true;
6475 }
6476 } else {
6477 resolve_word_completion(
6478 &buffer_snapshot,
6479 &mut completions.borrow_mut()[completion_index],
6480 );
6481 }
6482 }
6483 } else {
6484 for completion_index in completion_indices {
6485 let server_id = {
6486 let completion = &completions.borrow()[completion_index];
6487 completion.source.server_id()
6488 };
6489 if let Some(server_id) = server_id {
6490 let server_and_adapter = lsp_store
6491 .read_with(cx, |lsp_store, _| {
6492 let server = lsp_store.language_server_for_id(server_id)?;
6493 let adapter =
6494 lsp_store.language_server_adapter_for_id(server.server_id())?;
6495 Some((server, adapter))
6496 })
6497 .ok()
6498 .flatten();
6499 let Some((server, adapter)) = server_and_adapter else {
6500 continue;
6501 };
6502
6503 let resolved = Self::resolve_completion_local(
6504 server,
6505 completions.clone(),
6506 completion_index,
6507 )
6508 .await
6509 .log_err()
6510 .is_some();
6511 if resolved {
6512 Self::regenerate_completion_labels(
6513 adapter,
6514 &buffer_snapshot,
6515 completions.clone(),
6516 completion_index,
6517 )
6518 .await
6519 .log_err();
6520 did_resolve = true;
6521 }
6522 } else {
6523 resolve_word_completion(
6524 &buffer_snapshot,
6525 &mut completions.borrow_mut()[completion_index],
6526 );
6527 }
6528 }
6529 }
6530
6531 Ok(did_resolve)
6532 })
6533 }
6534
6535 async fn resolve_completion_local(
6536 server: Arc<lsp::LanguageServer>,
6537 completions: Rc<RefCell<Box<[Completion]>>>,
6538 completion_index: usize,
6539 ) -> Result<()> {
6540 let server_id = server.server_id();
6541 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6542 return Ok(());
6543 }
6544
6545 let request = {
6546 let completion = &completions.borrow()[completion_index];
6547 match &completion.source {
6548 CompletionSource::Lsp {
6549 lsp_completion,
6550 resolved,
6551 server_id: completion_server_id,
6552 ..
6553 } => {
6554 if *resolved {
6555 return Ok(());
6556 }
6557 anyhow::ensure!(
6558 server_id == *completion_server_id,
6559 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6560 );
6561 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6562 }
6563 CompletionSource::BufferWord { .. }
6564 | CompletionSource::Dap { .. }
6565 | CompletionSource::Custom => {
6566 return Ok(());
6567 }
6568 }
6569 };
6570 let resolved_completion = request
6571 .await
6572 .into_response()
6573 .context("resolve completion")?;
6574
6575 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6576 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6577
6578 let mut completions = completions.borrow_mut();
6579 let completion = &mut completions[completion_index];
6580 if let CompletionSource::Lsp {
6581 lsp_completion,
6582 resolved,
6583 server_id: completion_server_id,
6584 ..
6585 } = &mut completion.source
6586 {
6587 if *resolved {
6588 return Ok(());
6589 }
6590 anyhow::ensure!(
6591 server_id == *completion_server_id,
6592 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6593 );
6594 **lsp_completion = resolved_completion;
6595 *resolved = true;
6596 }
6597 Ok(())
6598 }
6599
6600 async fn regenerate_completion_labels(
6601 adapter: Arc<CachedLspAdapter>,
6602 snapshot: &BufferSnapshot,
6603 completions: Rc<RefCell<Box<[Completion]>>>,
6604 completion_index: usize,
6605 ) -> Result<()> {
6606 let completion_item = completions.borrow()[completion_index]
6607 .source
6608 .lsp_completion(true)
6609 .map(Cow::into_owned);
6610 if let Some(lsp_documentation) = completion_item
6611 .as_ref()
6612 .and_then(|completion_item| completion_item.documentation.clone())
6613 {
6614 let mut completions = completions.borrow_mut();
6615 let completion = &mut completions[completion_index];
6616 completion.documentation = Some(lsp_documentation.into());
6617 } else {
6618 let mut completions = completions.borrow_mut();
6619 let completion = &mut completions[completion_index];
6620 completion.documentation = Some(CompletionDocumentation::Undocumented);
6621 }
6622
6623 let mut new_label = match completion_item {
6624 Some(completion_item) => {
6625 // Some language servers always return `detail` lazily via resolve, regardless of
6626 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6627 // See: https://github.com/yioneko/vtsls/issues/213
6628 let language = snapshot.language();
6629 match language {
6630 Some(language) => {
6631 adapter
6632 .labels_for_completions(
6633 std::slice::from_ref(&completion_item),
6634 language,
6635 )
6636 .await?
6637 }
6638 None => Vec::new(),
6639 }
6640 .pop()
6641 .flatten()
6642 .unwrap_or_else(|| {
6643 CodeLabel::fallback_for_completion(
6644 &completion_item,
6645 language.map(|language| language.as_ref()),
6646 )
6647 })
6648 }
6649 None => CodeLabel::plain(
6650 completions.borrow()[completion_index].new_text.clone(),
6651 None,
6652 ),
6653 };
6654 ensure_uniform_list_compatible_label(&mut new_label);
6655
6656 let mut completions = completions.borrow_mut();
6657 let completion = &mut completions[completion_index];
6658 if completion.label.filter_text() == new_label.filter_text() {
6659 completion.label = new_label;
6660 } else {
6661 log::error!(
6662 "Resolved completion changed display label from {} to {}. \
6663 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6664 completion.label.text(),
6665 new_label.text(),
6666 completion.label.filter_text(),
6667 new_label.filter_text()
6668 );
6669 }
6670
6671 Ok(())
6672 }
6673
6674 async fn resolve_completion_remote(
6675 project_id: u64,
6676 server_id: LanguageServerId,
6677 buffer_id: BufferId,
6678 completions: Rc<RefCell<Box<[Completion]>>>,
6679 completion_index: usize,
6680 client: AnyProtoClient,
6681 ) -> Result<()> {
6682 let lsp_completion = {
6683 let completion = &completions.borrow()[completion_index];
6684 match &completion.source {
6685 CompletionSource::Lsp {
6686 lsp_completion,
6687 resolved,
6688 server_id: completion_server_id,
6689 ..
6690 } => {
6691 anyhow::ensure!(
6692 server_id == *completion_server_id,
6693 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6694 );
6695 if *resolved {
6696 return Ok(());
6697 }
6698 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6699 }
6700 CompletionSource::Custom
6701 | CompletionSource::Dap { .. }
6702 | CompletionSource::BufferWord { .. } => {
6703 return Ok(());
6704 }
6705 }
6706 };
6707 let request = proto::ResolveCompletionDocumentation {
6708 project_id,
6709 language_server_id: server_id.0 as u64,
6710 lsp_completion,
6711 buffer_id: buffer_id.into(),
6712 };
6713
6714 let response = client
6715 .request(request)
6716 .await
6717 .context("completion documentation resolve proto request")?;
6718 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6719
6720 let documentation = if response.documentation.is_empty() {
6721 CompletionDocumentation::Undocumented
6722 } else if response.documentation_is_markdown {
6723 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6724 } else if response.documentation.lines().count() <= 1 {
6725 CompletionDocumentation::SingleLine(response.documentation.into())
6726 } else {
6727 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6728 };
6729
6730 let mut completions = completions.borrow_mut();
6731 let completion = &mut completions[completion_index];
6732 completion.documentation = Some(documentation);
6733 if let CompletionSource::Lsp {
6734 insert_range,
6735 lsp_completion,
6736 resolved,
6737 server_id: completion_server_id,
6738 lsp_defaults: _,
6739 } = &mut completion.source
6740 {
6741 let completion_insert_range = response
6742 .old_insert_start
6743 .and_then(deserialize_anchor)
6744 .zip(response.old_insert_end.and_then(deserialize_anchor));
6745 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6746
6747 if *resolved {
6748 return Ok(());
6749 }
6750 anyhow::ensure!(
6751 server_id == *completion_server_id,
6752 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6753 );
6754 **lsp_completion = resolved_lsp_completion;
6755 *resolved = true;
6756 }
6757
6758 let replace_range = response
6759 .old_replace_start
6760 .and_then(deserialize_anchor)
6761 .zip(response.old_replace_end.and_then(deserialize_anchor));
6762 if let Some((old_replace_start, old_replace_end)) = replace_range
6763 && !response.new_text.is_empty()
6764 {
6765 completion.new_text = response.new_text;
6766 completion.replace_range = old_replace_start..old_replace_end;
6767 }
6768
6769 Ok(())
6770 }
6771
6772 pub fn apply_additional_edits_for_completion(
6773 &self,
6774 buffer_handle: Entity<Buffer>,
6775 completions: Rc<RefCell<Box<[Completion]>>>,
6776 completion_index: usize,
6777 push_to_history: bool,
6778 cx: &mut Context<Self>,
6779 ) -> Task<Result<Option<Transaction>>> {
6780 if let Some((client, project_id)) = self.upstream_client() {
6781 let buffer = buffer_handle.read(cx);
6782 let buffer_id = buffer.remote_id();
6783 cx.spawn(async move |_, cx| {
6784 let request = {
6785 let completion = completions.borrow()[completion_index].clone();
6786 proto::ApplyCompletionAdditionalEdits {
6787 project_id,
6788 buffer_id: buffer_id.into(),
6789 completion: Some(Self::serialize_completion(&CoreCompletion {
6790 replace_range: completion.replace_range,
6791 new_text: completion.new_text,
6792 source: completion.source,
6793 })),
6794 }
6795 };
6796
6797 if let Some(transaction) = client.request(request).await?.transaction {
6798 let transaction = language::proto::deserialize_transaction(transaction)?;
6799 buffer_handle
6800 .update(cx, |buffer, _| {
6801 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6802 })
6803 .await?;
6804 if push_to_history {
6805 buffer_handle.update(cx, |buffer, _| {
6806 buffer.push_transaction(transaction.clone(), Instant::now());
6807 buffer.finalize_last_transaction();
6808 });
6809 }
6810 Ok(Some(transaction))
6811 } else {
6812 Ok(None)
6813 }
6814 })
6815 } else {
6816 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6817 let completion = &completions.borrow()[completion_index];
6818 let server_id = completion.source.server_id()?;
6819 Some(
6820 self.language_server_for_local_buffer(buffer, server_id, cx)?
6821 .1
6822 .clone(),
6823 )
6824 }) else {
6825 return Task::ready(Ok(None));
6826 };
6827
6828 cx.spawn(async move |this, cx| {
6829 Self::resolve_completion_local(
6830 server.clone(),
6831 completions.clone(),
6832 completion_index,
6833 )
6834 .await
6835 .context("resolving completion")?;
6836 let completion = completions.borrow()[completion_index].clone();
6837 let additional_text_edits = completion
6838 .source
6839 .lsp_completion(true)
6840 .as_ref()
6841 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6842 if let Some(edits) = additional_text_edits {
6843 let edits = this
6844 .update(cx, |this, cx| {
6845 this.as_local_mut().unwrap().edits_from_lsp(
6846 &buffer_handle,
6847 edits,
6848 server.server_id(),
6849 None,
6850 cx,
6851 )
6852 })?
6853 .await?;
6854
6855 buffer_handle.update(cx, |buffer, cx| {
6856 buffer.finalize_last_transaction();
6857 buffer.start_transaction();
6858
6859 for (range, text) in edits {
6860 let primary = &completion.replace_range;
6861
6862 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6863 // and the primary completion is just an insertion (empty range), then this is likely
6864 // an auto-import scenario and should not be considered overlapping
6865 // https://github.com/zed-industries/zed/issues/26136
6866 let is_file_start_auto_import = {
6867 let snapshot = buffer.snapshot();
6868 let primary_start_point = primary.start.to_point(&snapshot);
6869 let range_start_point = range.start.to_point(&snapshot);
6870
6871 let result = primary_start_point.row == 0
6872 && primary_start_point.column == 0
6873 && range_start_point.row == 0
6874 && range_start_point.column == 0;
6875
6876 result
6877 };
6878
6879 let has_overlap = if is_file_start_auto_import {
6880 false
6881 } else {
6882 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6883 && primary.end.cmp(&range.start, buffer).is_ge();
6884 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6885 && range.end.cmp(&primary.end, buffer).is_ge();
6886 let result = start_within || end_within;
6887 result
6888 };
6889
6890 //Skip additional edits which overlap with the primary completion edit
6891 //https://github.com/zed-industries/zed/pull/1871
6892 if !has_overlap {
6893 buffer.edit([(range, text)], None, cx);
6894 }
6895 }
6896
6897 let transaction = if buffer.end_transaction(cx).is_some() {
6898 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6899 if !push_to_history {
6900 buffer.forget_transaction(transaction.id);
6901 }
6902 Some(transaction)
6903 } else {
6904 None
6905 };
6906 Ok(transaction)
6907 })
6908 } else {
6909 Ok(None)
6910 }
6911 })
6912 }
6913 }
6914
6915 pub fn pull_diagnostics(
6916 &mut self,
6917 buffer: Entity<Buffer>,
6918 cx: &mut Context<Self>,
6919 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6920 let buffer_id = buffer.read(cx).remote_id();
6921
6922 if let Some((client, upstream_project_id)) = self.upstream_client() {
6923 let mut suitable_capabilities = None;
6924 // Are we capable for proto request?
6925 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6926 &buffer,
6927 |capabilities| {
6928 if let Some(caps) = &capabilities.diagnostic_provider {
6929 suitable_capabilities = Some(caps.clone());
6930 true
6931 } else {
6932 false
6933 }
6934 },
6935 cx,
6936 );
6937 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6938 let Some(dynamic_caps) = suitable_capabilities else {
6939 return Task::ready(Ok(None));
6940 };
6941 assert!(any_server_has_diagnostics_provider);
6942
6943 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6944 let request = GetDocumentDiagnostics {
6945 previous_result_id: None,
6946 identifier,
6947 registration_id: None,
6948 };
6949 let request_task = client.request_lsp(
6950 upstream_project_id,
6951 None,
6952 LSP_REQUEST_TIMEOUT,
6953 cx.background_executor().clone(),
6954 request.to_proto(upstream_project_id, buffer.read(cx)),
6955 );
6956 cx.background_spawn(async move {
6957 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6958 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6959 // Do not attempt to further process the dummy responses here.
6960 let _response = request_task.await?;
6961 Ok(None)
6962 })
6963 } else {
6964 let servers = buffer.update(cx, |buffer, cx| {
6965 self.running_language_servers_for_local_buffer(buffer, cx)
6966 .map(|(_, server)| server.clone())
6967 .collect::<Vec<_>>()
6968 });
6969
6970 let pull_diagnostics = servers
6971 .into_iter()
6972 .flat_map(|server| {
6973 let result = maybe!({
6974 let local = self.as_local()?;
6975 let server_id = server.server_id();
6976 let providers_with_identifiers = local
6977 .language_server_dynamic_registrations
6978 .get(&server_id)
6979 .into_iter()
6980 .flat_map(|registrations| registrations.diagnostics.clone())
6981 .collect::<Vec<_>>();
6982 Some(
6983 providers_with_identifiers
6984 .into_iter()
6985 .map(|(registration_id, dynamic_caps)| {
6986 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6987 let registration_id = registration_id.map(SharedString::from);
6988 let result_id = self.result_id_for_buffer_pull(
6989 server_id,
6990 buffer_id,
6991 ®istration_id,
6992 cx,
6993 );
6994 self.request_lsp(
6995 buffer.clone(),
6996 LanguageServerToQuery::Other(server_id),
6997 GetDocumentDiagnostics {
6998 previous_result_id: result_id,
6999 registration_id,
7000 identifier,
7001 },
7002 cx,
7003 )
7004 })
7005 .collect::<Vec<_>>(),
7006 )
7007 });
7008
7009 result.unwrap_or_default()
7010 })
7011 .collect::<Vec<_>>();
7012
7013 cx.background_spawn(async move {
7014 let mut responses = Vec::new();
7015 for diagnostics in join_all(pull_diagnostics).await {
7016 responses.extend(diagnostics?);
7017 }
7018 Ok(Some(responses))
7019 })
7020 }
7021 }
7022
7023 pub fn applicable_inlay_chunks(
7024 &mut self,
7025 buffer: &Entity<Buffer>,
7026 ranges: &[Range<text::Anchor>],
7027 cx: &mut Context<Self>,
7028 ) -> Vec<Range<BufferRow>> {
7029 let buffer_snapshot = buffer.read(cx).snapshot();
7030 let ranges = ranges
7031 .iter()
7032 .map(|range| range.to_point(&buffer_snapshot))
7033 .collect::<Vec<_>>();
7034
7035 self.latest_lsp_data(buffer, cx)
7036 .inlay_hints
7037 .applicable_chunks(ranges.as_slice())
7038 .map(|chunk| chunk.row_range())
7039 .collect()
7040 }
7041
7042 pub fn invalidate_inlay_hints<'a>(
7043 &'a mut self,
7044 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7045 ) {
7046 for buffer_id in for_buffers {
7047 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7048 lsp_data.inlay_hints.clear();
7049 }
7050 }
7051 }
7052
7053 pub fn inlay_hints(
7054 &mut self,
7055 invalidate: InvalidationStrategy,
7056 buffer: Entity<Buffer>,
7057 ranges: Vec<Range<text::Anchor>>,
7058 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7059 cx: &mut Context<Self>,
7060 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7061 let next_hint_id = self.next_hint_id.clone();
7062 let lsp_data = self.latest_lsp_data(&buffer, cx);
7063 let query_version = lsp_data.buffer_version.clone();
7064 let mut lsp_refresh_requested = false;
7065 let for_server = if let InvalidationStrategy::RefreshRequested {
7066 server_id,
7067 request_id,
7068 } = invalidate
7069 {
7070 let invalidated = lsp_data
7071 .inlay_hints
7072 .invalidate_for_server_refresh(server_id, request_id);
7073 lsp_refresh_requested = invalidated;
7074 Some(server_id)
7075 } else {
7076 None
7077 };
7078 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7079 let known_chunks = known_chunks
7080 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7081 .map(|(_, known_chunks)| known_chunks)
7082 .unwrap_or_default();
7083
7084 let buffer_snapshot = buffer.read(cx).snapshot();
7085 let ranges = ranges
7086 .iter()
7087 .map(|range| range.to_point(&buffer_snapshot))
7088 .collect::<Vec<_>>();
7089
7090 let mut hint_fetch_tasks = Vec::new();
7091 let mut cached_inlay_hints = None;
7092 let mut ranges_to_query = None;
7093 let applicable_chunks = existing_inlay_hints
7094 .applicable_chunks(ranges.as_slice())
7095 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7096 .collect::<Vec<_>>();
7097 if applicable_chunks.is_empty() {
7098 return HashMap::default();
7099 }
7100
7101 for row_chunk in applicable_chunks {
7102 match (
7103 existing_inlay_hints
7104 .cached_hints(&row_chunk)
7105 .filter(|_| !lsp_refresh_requested)
7106 .cloned(),
7107 existing_inlay_hints
7108 .fetched_hints(&row_chunk)
7109 .as_ref()
7110 .filter(|_| !lsp_refresh_requested)
7111 .cloned(),
7112 ) {
7113 (None, None) => {
7114 let chunk_range = row_chunk.anchor_range();
7115 ranges_to_query
7116 .get_or_insert_with(Vec::new)
7117 .push((row_chunk, chunk_range));
7118 }
7119 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7120 (Some(cached_hints), None) => {
7121 for (server_id, cached_hints) in cached_hints {
7122 if for_server.is_none_or(|for_server| for_server == server_id) {
7123 cached_inlay_hints
7124 .get_or_insert_with(HashMap::default)
7125 .entry(row_chunk.row_range())
7126 .or_insert_with(HashMap::default)
7127 .entry(server_id)
7128 .or_insert_with(Vec::new)
7129 .extend(cached_hints);
7130 }
7131 }
7132 }
7133 (Some(cached_hints), Some(fetched_hints)) => {
7134 hint_fetch_tasks.push((row_chunk, fetched_hints));
7135 for (server_id, cached_hints) in cached_hints {
7136 if for_server.is_none_or(|for_server| for_server == server_id) {
7137 cached_inlay_hints
7138 .get_or_insert_with(HashMap::default)
7139 .entry(row_chunk.row_range())
7140 .or_insert_with(HashMap::default)
7141 .entry(server_id)
7142 .or_insert_with(Vec::new)
7143 .extend(cached_hints);
7144 }
7145 }
7146 }
7147 }
7148 }
7149
7150 if hint_fetch_tasks.is_empty()
7151 && ranges_to_query
7152 .as_ref()
7153 .is_none_or(|ranges| ranges.is_empty())
7154 && let Some(cached_inlay_hints) = cached_inlay_hints
7155 {
7156 cached_inlay_hints
7157 .into_iter()
7158 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7159 .collect()
7160 } else {
7161 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7162 let next_hint_id = next_hint_id.clone();
7163 let buffer = buffer.clone();
7164 let query_version = query_version.clone();
7165 let new_inlay_hints = cx
7166 .spawn(async move |lsp_store, cx| {
7167 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7168 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7169 })?;
7170 new_fetch_task
7171 .await
7172 .and_then(|new_hints_by_server| {
7173 lsp_store.update(cx, |lsp_store, cx| {
7174 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7175 let update_cache = lsp_data.buffer_version == query_version;
7176 if new_hints_by_server.is_empty() {
7177 if update_cache {
7178 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7179 }
7180 HashMap::default()
7181 } else {
7182 new_hints_by_server
7183 .into_iter()
7184 .map(|(server_id, new_hints)| {
7185 let new_hints = new_hints
7186 .into_iter()
7187 .map(|new_hint| {
7188 (
7189 InlayId::Hint(next_hint_id.fetch_add(
7190 1,
7191 atomic::Ordering::AcqRel,
7192 )),
7193 new_hint,
7194 )
7195 })
7196 .collect::<Vec<_>>();
7197 if update_cache {
7198 lsp_data.inlay_hints.insert_new_hints(
7199 chunk,
7200 server_id,
7201 new_hints.clone(),
7202 );
7203 }
7204 (server_id, new_hints)
7205 })
7206 .collect()
7207 }
7208 })
7209 })
7210 .map_err(Arc::new)
7211 })
7212 .shared();
7213
7214 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7215 *fetch_task = Some(new_inlay_hints.clone());
7216 hint_fetch_tasks.push((chunk, new_inlay_hints));
7217 }
7218
7219 cached_inlay_hints
7220 .unwrap_or_default()
7221 .into_iter()
7222 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7223 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7224 (
7225 chunk.row_range(),
7226 cx.spawn(async move |_, _| {
7227 hints_fetch.await.map_err(|e| {
7228 if e.error_code() != ErrorCode::Internal {
7229 anyhow!(e.error_code())
7230 } else {
7231 anyhow!("{e:#}")
7232 }
7233 })
7234 }),
7235 )
7236 }))
7237 .collect()
7238 }
7239 }
7240
7241 fn fetch_inlay_hints(
7242 &mut self,
7243 for_server: Option<LanguageServerId>,
7244 buffer: &Entity<Buffer>,
7245 range: Range<Anchor>,
7246 cx: &mut Context<Self>,
7247 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7248 let request = InlayHints {
7249 range: range.clone(),
7250 };
7251 if let Some((upstream_client, project_id)) = self.upstream_client() {
7252 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7253 return Task::ready(Ok(HashMap::default()));
7254 }
7255 let request_task = upstream_client.request_lsp(
7256 project_id,
7257 for_server.map(|id| id.to_proto()),
7258 LSP_REQUEST_TIMEOUT,
7259 cx.background_executor().clone(),
7260 request.to_proto(project_id, buffer.read(cx)),
7261 );
7262 let buffer = buffer.clone();
7263 cx.spawn(async move |weak_lsp_store, cx| {
7264 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7265 return Ok(HashMap::default());
7266 };
7267 let Some(responses) = request_task.await? else {
7268 return Ok(HashMap::default());
7269 };
7270
7271 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7272 let lsp_store = lsp_store.clone();
7273 let buffer = buffer.clone();
7274 let cx = cx.clone();
7275 let request = request.clone();
7276 async move {
7277 (
7278 LanguageServerId::from_proto(response.server_id),
7279 request
7280 .response_from_proto(response.response, lsp_store, buffer, cx)
7281 .await,
7282 )
7283 }
7284 }))
7285 .await;
7286
7287 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7288 let mut has_errors = false;
7289 let inlay_hints = inlay_hints
7290 .into_iter()
7291 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7292 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7293 Err(e) => {
7294 has_errors = true;
7295 log::error!("{e:#}");
7296 None
7297 }
7298 })
7299 .map(|(server_id, mut new_hints)| {
7300 new_hints.retain(|hint| {
7301 hint.position.is_valid(&buffer_snapshot)
7302 && range.start.is_valid(&buffer_snapshot)
7303 && range.end.is_valid(&buffer_snapshot)
7304 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7305 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7306 });
7307 (server_id, new_hints)
7308 })
7309 .collect::<HashMap<_, _>>();
7310 anyhow::ensure!(
7311 !has_errors || !inlay_hints.is_empty(),
7312 "Failed to fetch inlay hints"
7313 );
7314 Ok(inlay_hints)
7315 })
7316 } else {
7317 let inlay_hints_task = match for_server {
7318 Some(server_id) => {
7319 let server_task = self.request_lsp(
7320 buffer.clone(),
7321 LanguageServerToQuery::Other(server_id),
7322 request,
7323 cx,
7324 );
7325 cx.background_spawn(async move {
7326 let mut responses = Vec::new();
7327 match server_task.await {
7328 Ok(response) => responses.push((server_id, response)),
7329 // rust-analyzer likes to error with this when its still loading up
7330 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7331 Err(e) => log::error!(
7332 "Error handling response for inlay hints request: {e:#}"
7333 ),
7334 }
7335 responses
7336 })
7337 }
7338 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7339 };
7340 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7341 cx.background_spawn(async move {
7342 Ok(inlay_hints_task
7343 .await
7344 .into_iter()
7345 .map(|(server_id, mut new_hints)| {
7346 new_hints.retain(|hint| {
7347 hint.position.is_valid(&buffer_snapshot)
7348 && range.start.is_valid(&buffer_snapshot)
7349 && range.end.is_valid(&buffer_snapshot)
7350 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7351 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7352 });
7353 (server_id, new_hints)
7354 })
7355 .collect())
7356 })
7357 }
7358 }
7359
7360 fn diagnostic_registration_exists(
7361 &self,
7362 server_id: LanguageServerId,
7363 registration_id: &Option<SharedString>,
7364 ) -> bool {
7365 let Some(local) = self.as_local() else {
7366 return false;
7367 };
7368 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7369 else {
7370 return false;
7371 };
7372 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7373 registrations.diagnostics.contains_key(®istration_key)
7374 }
7375
7376 pub fn pull_diagnostics_for_buffer(
7377 &mut self,
7378 buffer: Entity<Buffer>,
7379 cx: &mut Context<Self>,
7380 ) -> Task<anyhow::Result<()>> {
7381 let diagnostics = self.pull_diagnostics(buffer, cx);
7382 cx.spawn(async move |lsp_store, cx| {
7383 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7384 return Ok(());
7385 };
7386 lsp_store.update(cx, |lsp_store, cx| {
7387 if lsp_store.as_local().is_none() {
7388 return;
7389 }
7390
7391 let mut unchanged_buffers = HashMap::default();
7392 let server_diagnostics_updates = diagnostics
7393 .into_iter()
7394 .filter_map(|diagnostics_set| match diagnostics_set {
7395 LspPullDiagnostics::Response {
7396 server_id,
7397 uri,
7398 diagnostics,
7399 registration_id,
7400 } => Some((server_id, uri, diagnostics, registration_id)),
7401 LspPullDiagnostics::Default => None,
7402 })
7403 .filter(|(server_id, _, _, registration_id)| {
7404 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7405 })
7406 .fold(
7407 HashMap::default(),
7408 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7409 let (result_id, diagnostics) = match diagnostics {
7410 PulledDiagnostics::Unchanged { result_id } => {
7411 unchanged_buffers
7412 .entry(new_registration_id.clone())
7413 .or_insert_with(HashSet::default)
7414 .insert(uri.clone());
7415 (Some(result_id), Vec::new())
7416 }
7417 PulledDiagnostics::Changed {
7418 result_id,
7419 diagnostics,
7420 } => (result_id, diagnostics),
7421 };
7422 let disk_based_sources = Cow::Owned(
7423 lsp_store
7424 .language_server_adapter_for_id(server_id)
7425 .as_ref()
7426 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7427 .unwrap_or(&[])
7428 .to_vec(),
7429 );
7430 acc.entry(server_id)
7431 .or_insert_with(HashMap::default)
7432 .entry(new_registration_id.clone())
7433 .or_insert_with(Vec::new)
7434 .push(DocumentDiagnosticsUpdate {
7435 server_id,
7436 diagnostics: lsp::PublishDiagnosticsParams {
7437 uri,
7438 diagnostics,
7439 version: None,
7440 },
7441 result_id,
7442 disk_based_sources,
7443 registration_id: new_registration_id,
7444 });
7445 acc
7446 },
7447 );
7448
7449 for diagnostic_updates in server_diagnostics_updates.into_values() {
7450 for (registration_id, diagnostic_updates) in diagnostic_updates {
7451 lsp_store
7452 .merge_lsp_diagnostics(
7453 DiagnosticSourceKind::Pulled,
7454 diagnostic_updates,
7455 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7456 DiagnosticSourceKind::Pulled => {
7457 old_diagnostic.registration_id != registration_id
7458 || unchanged_buffers
7459 .get(&old_diagnostic.registration_id)
7460 .is_some_and(|unchanged_buffers| {
7461 unchanged_buffers.contains(&document_uri)
7462 })
7463 }
7464 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7465 true
7466 }
7467 },
7468 cx,
7469 )
7470 .log_err();
7471 }
7472 }
7473 })
7474 })
7475 }
7476
7477 pub fn document_colors(
7478 &mut self,
7479 known_cache_version: Option<usize>,
7480 buffer: Entity<Buffer>,
7481 cx: &mut Context<Self>,
7482 ) -> Option<DocumentColorTask> {
7483 let version_queried_for = buffer.read(cx).version();
7484 let buffer_id = buffer.read(cx).remote_id();
7485
7486 let current_language_servers = self.as_local().map(|local| {
7487 local
7488 .buffers_opened_in_servers
7489 .get(&buffer_id)
7490 .cloned()
7491 .unwrap_or_default()
7492 });
7493
7494 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7495 if let Some(cached_colors) = &lsp_data.document_colors {
7496 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7497 let has_different_servers =
7498 current_language_servers.is_some_and(|current_language_servers| {
7499 current_language_servers
7500 != cached_colors.colors.keys().copied().collect()
7501 });
7502 if !has_different_servers {
7503 let cache_version = cached_colors.cache_version;
7504 if Some(cache_version) == known_cache_version {
7505 return None;
7506 } else {
7507 return Some(
7508 Task::ready(Ok(DocumentColors {
7509 colors: cached_colors
7510 .colors
7511 .values()
7512 .flatten()
7513 .cloned()
7514 .collect(),
7515 cache_version: Some(cache_version),
7516 }))
7517 .shared(),
7518 );
7519 }
7520 }
7521 }
7522 }
7523 }
7524
7525 let color_lsp_data = self
7526 .latest_lsp_data(&buffer, cx)
7527 .document_colors
7528 .get_or_insert_default();
7529 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7530 && !version_queried_for.changed_since(updating_for)
7531 {
7532 return Some(running_update.clone());
7533 }
7534 let buffer_version_queried_for = version_queried_for.clone();
7535 let new_task = cx
7536 .spawn(async move |lsp_store, cx| {
7537 cx.background_executor()
7538 .timer(Duration::from_millis(30))
7539 .await;
7540 let fetched_colors = lsp_store
7541 .update(cx, |lsp_store, cx| {
7542 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7543 })?
7544 .await
7545 .context("fetching document colors")
7546 .map_err(Arc::new);
7547 let fetched_colors = match fetched_colors {
7548 Ok(fetched_colors) => {
7549 if buffer.update(cx, |buffer, _| {
7550 buffer.version() != buffer_version_queried_for
7551 }) {
7552 return Ok(DocumentColors::default());
7553 }
7554 fetched_colors
7555 }
7556 Err(e) => {
7557 lsp_store
7558 .update(cx, |lsp_store, _| {
7559 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7560 if let Some(document_colors) = &mut lsp_data.document_colors {
7561 document_colors.colors_update = None;
7562 }
7563 }
7564 })
7565 .ok();
7566 return Err(e);
7567 }
7568 };
7569
7570 lsp_store
7571 .update(cx, |lsp_store, cx| {
7572 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7573 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7574
7575 if let Some(fetched_colors) = fetched_colors {
7576 if lsp_data.buffer_version == buffer_version_queried_for {
7577 lsp_colors.colors.extend(fetched_colors);
7578 lsp_colors.cache_version += 1;
7579 } else if !lsp_data
7580 .buffer_version
7581 .changed_since(&buffer_version_queried_for)
7582 {
7583 lsp_data.buffer_version = buffer_version_queried_for;
7584 lsp_colors.colors = fetched_colors;
7585 lsp_colors.cache_version += 1;
7586 }
7587 }
7588 lsp_colors.colors_update = None;
7589 let colors = lsp_colors
7590 .colors
7591 .values()
7592 .flatten()
7593 .cloned()
7594 .collect::<HashSet<_>>();
7595 DocumentColors {
7596 colors,
7597 cache_version: Some(lsp_colors.cache_version),
7598 }
7599 })
7600 .map_err(Arc::new)
7601 })
7602 .shared();
7603 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7604 Some(new_task)
7605 }
7606
7607 fn fetch_document_colors_for_buffer(
7608 &mut self,
7609 buffer: &Entity<Buffer>,
7610 cx: &mut Context<Self>,
7611 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7612 if let Some((client, project_id)) = self.upstream_client() {
7613 let request = GetDocumentColor {};
7614 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7615 return Task::ready(Ok(None));
7616 }
7617
7618 let request_task = client.request_lsp(
7619 project_id,
7620 None,
7621 LSP_REQUEST_TIMEOUT,
7622 cx.background_executor().clone(),
7623 request.to_proto(project_id, buffer.read(cx)),
7624 );
7625 let buffer = buffer.clone();
7626 cx.spawn(async move |lsp_store, cx| {
7627 let Some(lsp_store) = lsp_store.upgrade() else {
7628 return Ok(None);
7629 };
7630 let colors = join_all(
7631 request_task
7632 .await
7633 .log_err()
7634 .flatten()
7635 .map(|response| response.payload)
7636 .unwrap_or_default()
7637 .into_iter()
7638 .map(|color_response| {
7639 let response = request.response_from_proto(
7640 color_response.response,
7641 lsp_store.clone(),
7642 buffer.clone(),
7643 cx.clone(),
7644 );
7645 async move {
7646 (
7647 LanguageServerId::from_proto(color_response.server_id),
7648 response.await.log_err().unwrap_or_default(),
7649 )
7650 }
7651 }),
7652 )
7653 .await
7654 .into_iter()
7655 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7656 acc.entry(server_id)
7657 .or_insert_with(HashSet::default)
7658 .extend(colors);
7659 acc
7660 });
7661 Ok(Some(colors))
7662 })
7663 } else {
7664 let document_colors_task =
7665 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7666 cx.background_spawn(async move {
7667 Ok(Some(
7668 document_colors_task
7669 .await
7670 .into_iter()
7671 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7672 acc.entry(server_id)
7673 .or_insert_with(HashSet::default)
7674 .extend(colors);
7675 acc
7676 })
7677 .into_iter()
7678 .collect(),
7679 ))
7680 })
7681 }
7682 }
7683
7684 pub fn signature_help<T: ToPointUtf16>(
7685 &mut self,
7686 buffer: &Entity<Buffer>,
7687 position: T,
7688 cx: &mut Context<Self>,
7689 ) -> Task<Option<Vec<SignatureHelp>>> {
7690 let position = position.to_point_utf16(buffer.read(cx));
7691
7692 if let Some((client, upstream_project_id)) = self.upstream_client() {
7693 let request = GetSignatureHelp { position };
7694 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7695 return Task::ready(None);
7696 }
7697 let request_task = client.request_lsp(
7698 upstream_project_id,
7699 None,
7700 LSP_REQUEST_TIMEOUT,
7701 cx.background_executor().clone(),
7702 request.to_proto(upstream_project_id, buffer.read(cx)),
7703 );
7704 let buffer = buffer.clone();
7705 cx.spawn(async move |weak_lsp_store, cx| {
7706 let lsp_store = weak_lsp_store.upgrade()?;
7707 let signatures = join_all(
7708 request_task
7709 .await
7710 .log_err()
7711 .flatten()
7712 .map(|response| response.payload)
7713 .unwrap_or_default()
7714 .into_iter()
7715 .map(|response| {
7716 let response = GetSignatureHelp { position }.response_from_proto(
7717 response.response,
7718 lsp_store.clone(),
7719 buffer.clone(),
7720 cx.clone(),
7721 );
7722 async move { response.await.log_err().flatten() }
7723 }),
7724 )
7725 .await
7726 .into_iter()
7727 .flatten()
7728 .collect();
7729 Some(signatures)
7730 })
7731 } else {
7732 let all_actions_task = self.request_multiple_lsp_locally(
7733 buffer,
7734 Some(position),
7735 GetSignatureHelp { position },
7736 cx,
7737 );
7738 cx.background_spawn(async move {
7739 Some(
7740 all_actions_task
7741 .await
7742 .into_iter()
7743 .flat_map(|(_, actions)| actions)
7744 .collect::<Vec<_>>(),
7745 )
7746 })
7747 }
7748 }
7749
7750 pub fn hover(
7751 &mut self,
7752 buffer: &Entity<Buffer>,
7753 position: PointUtf16,
7754 cx: &mut Context<Self>,
7755 ) -> Task<Option<Vec<Hover>>> {
7756 if let Some((client, upstream_project_id)) = self.upstream_client() {
7757 let request = GetHover { position };
7758 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7759 return Task::ready(None);
7760 }
7761 let request_task = client.request_lsp(
7762 upstream_project_id,
7763 None,
7764 LSP_REQUEST_TIMEOUT,
7765 cx.background_executor().clone(),
7766 request.to_proto(upstream_project_id, buffer.read(cx)),
7767 );
7768 let buffer = buffer.clone();
7769 cx.spawn(async move |weak_lsp_store, cx| {
7770 let lsp_store = weak_lsp_store.upgrade()?;
7771 let hovers = join_all(
7772 request_task
7773 .await
7774 .log_err()
7775 .flatten()
7776 .map(|response| response.payload)
7777 .unwrap_or_default()
7778 .into_iter()
7779 .map(|response| {
7780 let response = GetHover { position }.response_from_proto(
7781 response.response,
7782 lsp_store.clone(),
7783 buffer.clone(),
7784 cx.clone(),
7785 );
7786 async move {
7787 response
7788 .await
7789 .log_err()
7790 .flatten()
7791 .and_then(remove_empty_hover_blocks)
7792 }
7793 }),
7794 )
7795 .await
7796 .into_iter()
7797 .flatten()
7798 .collect();
7799 Some(hovers)
7800 })
7801 } else {
7802 let all_actions_task = self.request_multiple_lsp_locally(
7803 buffer,
7804 Some(position),
7805 GetHover { position },
7806 cx,
7807 );
7808 cx.background_spawn(async move {
7809 Some(
7810 all_actions_task
7811 .await
7812 .into_iter()
7813 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7814 .collect::<Vec<Hover>>(),
7815 )
7816 })
7817 }
7818 }
7819
7820 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7821 let language_registry = self.languages.clone();
7822
7823 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7824 let request = upstream_client.request(proto::GetProjectSymbols {
7825 project_id: *project_id,
7826 query: query.to_string(),
7827 });
7828 cx.foreground_executor().spawn(async move {
7829 let response = request.await?;
7830 let mut symbols = Vec::new();
7831 let core_symbols = response
7832 .symbols
7833 .into_iter()
7834 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7835 .collect::<Vec<_>>();
7836 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7837 .await;
7838 Ok(symbols)
7839 })
7840 } else if let Some(local) = self.as_local() {
7841 struct WorkspaceSymbolsResult {
7842 server_id: LanguageServerId,
7843 lsp_adapter: Arc<CachedLspAdapter>,
7844 worktree: WeakEntity<Worktree>,
7845 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7846 }
7847
7848 let mut requests = Vec::new();
7849 let mut requested_servers = BTreeSet::new();
7850 for (seed, state) in local.language_server_ids.iter() {
7851 let Some(worktree_handle) = self
7852 .worktree_store
7853 .read(cx)
7854 .worktree_for_id(seed.worktree_id, cx)
7855 else {
7856 continue;
7857 };
7858 let worktree = worktree_handle.read(cx);
7859 if !worktree.is_visible() {
7860 continue;
7861 }
7862
7863 if !requested_servers.insert(state.id) {
7864 continue;
7865 }
7866
7867 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7868 Some(LanguageServerState::Running {
7869 adapter, server, ..
7870 }) => (adapter.clone(), server),
7871
7872 _ => continue,
7873 };
7874 let supports_workspace_symbol_request =
7875 match server.capabilities().workspace_symbol_provider {
7876 Some(OneOf::Left(supported)) => supported,
7877 Some(OneOf::Right(_)) => true,
7878 None => false,
7879 };
7880 if !supports_workspace_symbol_request {
7881 continue;
7882 }
7883 let worktree_handle = worktree_handle.clone();
7884 let server_id = server.server_id();
7885 requests.push(
7886 server
7887 .request::<lsp::request::WorkspaceSymbolRequest>(
7888 lsp::WorkspaceSymbolParams {
7889 query: query.to_string(),
7890 ..Default::default()
7891 },
7892 )
7893 .map(move |response| {
7894 let lsp_symbols = response
7895 .into_response()
7896 .context("workspace symbols request")
7897 .log_err()
7898 .flatten()
7899 .map(|symbol_response| match symbol_response {
7900 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7901 flat_responses
7902 .into_iter()
7903 .map(|lsp_symbol| {
7904 (
7905 lsp_symbol.name,
7906 lsp_symbol.kind,
7907 lsp_symbol.location,
7908 )
7909 })
7910 .collect::<Vec<_>>()
7911 }
7912 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7913 nested_responses
7914 .into_iter()
7915 .filter_map(|lsp_symbol| {
7916 let location = match lsp_symbol.location {
7917 OneOf::Left(location) => location,
7918 OneOf::Right(_) => {
7919 log::error!(
7920 "Unexpected: client capabilities \
7921 forbid symbol resolutions in \
7922 workspace.symbol.resolveSupport"
7923 );
7924 return None;
7925 }
7926 };
7927 Some((lsp_symbol.name, lsp_symbol.kind, location))
7928 })
7929 .collect::<Vec<_>>()
7930 }
7931 })
7932 .unwrap_or_default();
7933
7934 WorkspaceSymbolsResult {
7935 server_id,
7936 lsp_adapter,
7937 worktree: worktree_handle.downgrade(),
7938 lsp_symbols,
7939 }
7940 }),
7941 );
7942 }
7943
7944 cx.spawn(async move |this, cx| {
7945 let responses = futures::future::join_all(requests).await;
7946 let this = match this.upgrade() {
7947 Some(this) => this,
7948 None => return Ok(Vec::new()),
7949 };
7950
7951 let mut symbols = Vec::new();
7952 for result in responses {
7953 let core_symbols = this.update(cx, |this, cx| {
7954 result
7955 .lsp_symbols
7956 .into_iter()
7957 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7958 let abs_path = symbol_location.uri.to_file_path().ok()?;
7959 let source_worktree = result.worktree.upgrade()?;
7960 let source_worktree_id = source_worktree.read(cx).id();
7961
7962 let path = if let Some((tree, rel_path)) =
7963 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7964 {
7965 let worktree_id = tree.read(cx).id();
7966 SymbolLocation::InProject(ProjectPath {
7967 worktree_id,
7968 path: rel_path,
7969 })
7970 } else {
7971 SymbolLocation::OutsideProject {
7972 signature: this.symbol_signature(&abs_path),
7973 abs_path: abs_path.into(),
7974 }
7975 };
7976
7977 Some(CoreSymbol {
7978 source_language_server_id: result.server_id,
7979 language_server_name: result.lsp_adapter.name.clone(),
7980 source_worktree_id,
7981 path,
7982 kind: symbol_kind,
7983 name: symbol_name,
7984 range: range_from_lsp(symbol_location.range),
7985 })
7986 })
7987 .collect::<Vec<_>>()
7988 });
7989
7990 populate_labels_for_symbols(
7991 core_symbols,
7992 &language_registry,
7993 Some(result.lsp_adapter),
7994 &mut symbols,
7995 )
7996 .await;
7997 }
7998
7999 Ok(symbols)
8000 })
8001 } else {
8002 Task::ready(Err(anyhow!("No upstream client or local language server")))
8003 }
8004 }
8005
8006 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
8007 let mut summary = DiagnosticSummary::default();
8008 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
8009 summary.error_count += path_summary.error_count;
8010 summary.warning_count += path_summary.warning_count;
8011 }
8012 summary
8013 }
8014
8015 /// Returns the diagnostic summary for a specific project path.
8016 pub fn diagnostic_summary_for_path(
8017 &self,
8018 project_path: &ProjectPath,
8019 _: &App,
8020 ) -> DiagnosticSummary {
8021 if let Some(summaries) = self
8022 .diagnostic_summaries
8023 .get(&project_path.worktree_id)
8024 .and_then(|map| map.get(&project_path.path))
8025 {
8026 let (error_count, warning_count) = summaries.iter().fold(
8027 (0, 0),
8028 |(error_count, warning_count), (_language_server_id, summary)| {
8029 (
8030 error_count + summary.error_count,
8031 warning_count + summary.warning_count,
8032 )
8033 },
8034 );
8035
8036 DiagnosticSummary {
8037 error_count,
8038 warning_count,
8039 }
8040 } else {
8041 DiagnosticSummary::default()
8042 }
8043 }
8044
8045 pub fn diagnostic_summaries<'a>(
8046 &'a self,
8047 include_ignored: bool,
8048 cx: &'a App,
8049 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
8050 self.worktree_store
8051 .read(cx)
8052 .visible_worktrees(cx)
8053 .filter_map(|worktree| {
8054 let worktree = worktree.read(cx);
8055 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
8056 })
8057 .flat_map(move |(worktree, summaries)| {
8058 let worktree_id = worktree.id();
8059 summaries
8060 .iter()
8061 .filter(move |(path, _)| {
8062 include_ignored
8063 || worktree
8064 .entry_for_path(path.as_ref())
8065 .is_some_and(|entry| !entry.is_ignored)
8066 })
8067 .flat_map(move |(path, summaries)| {
8068 summaries.iter().map(move |(server_id, summary)| {
8069 (
8070 ProjectPath {
8071 worktree_id,
8072 path: path.clone(),
8073 },
8074 *server_id,
8075 *summary,
8076 )
8077 })
8078 })
8079 })
8080 }
8081
8082 pub fn on_buffer_edited(
8083 &mut self,
8084 buffer: Entity<Buffer>,
8085 cx: &mut Context<Self>,
8086 ) -> Option<()> {
8087 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8088 Some(
8089 self.as_local()?
8090 .language_servers_for_buffer(buffer, cx)
8091 .map(|i| i.1.clone())
8092 .collect(),
8093 )
8094 })?;
8095
8096 let buffer = buffer.read(cx);
8097 let file = File::from_dyn(buffer.file())?;
8098 let abs_path = file.as_local()?.abs_path(cx);
8099 let uri = lsp::Uri::from_file_path(&abs_path)
8100 .ok()
8101 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8102 .log_err()?;
8103 let next_snapshot = buffer.text_snapshot();
8104 for language_server in language_servers {
8105 let language_server = language_server.clone();
8106
8107 let buffer_snapshots = self
8108 .as_local_mut()?
8109 .buffer_snapshots
8110 .get_mut(&buffer.remote_id())
8111 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8112 let previous_snapshot = buffer_snapshots.last()?;
8113
8114 let build_incremental_change = || {
8115 buffer
8116 .edits_since::<Dimensions<PointUtf16, usize>>(
8117 previous_snapshot.snapshot.version(),
8118 )
8119 .map(|edit| {
8120 let edit_start = edit.new.start.0;
8121 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8122 let new_text = next_snapshot
8123 .text_for_range(edit.new.start.1..edit.new.end.1)
8124 .collect();
8125 lsp::TextDocumentContentChangeEvent {
8126 range: Some(lsp::Range::new(
8127 point_to_lsp(edit_start),
8128 point_to_lsp(edit_end),
8129 )),
8130 range_length: None,
8131 text: new_text,
8132 }
8133 })
8134 .collect()
8135 };
8136
8137 let document_sync_kind = language_server
8138 .capabilities()
8139 .text_document_sync
8140 .as_ref()
8141 .and_then(|sync| match sync {
8142 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8143 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8144 });
8145
8146 let content_changes: Vec<_> = match document_sync_kind {
8147 Some(lsp::TextDocumentSyncKind::FULL) => {
8148 vec![lsp::TextDocumentContentChangeEvent {
8149 range: None,
8150 range_length: None,
8151 text: next_snapshot.text(),
8152 }]
8153 }
8154 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8155 _ => {
8156 #[cfg(any(test, feature = "test-support"))]
8157 {
8158 build_incremental_change()
8159 }
8160
8161 #[cfg(not(any(test, feature = "test-support")))]
8162 {
8163 continue;
8164 }
8165 }
8166 };
8167
8168 let next_version = previous_snapshot.version + 1;
8169 buffer_snapshots.push(LspBufferSnapshot {
8170 version: next_version,
8171 snapshot: next_snapshot.clone(),
8172 });
8173
8174 language_server
8175 .notify::<lsp::notification::DidChangeTextDocument>(
8176 lsp::DidChangeTextDocumentParams {
8177 text_document: lsp::VersionedTextDocumentIdentifier::new(
8178 uri.clone(),
8179 next_version,
8180 ),
8181 content_changes,
8182 },
8183 )
8184 .ok();
8185 self.pull_workspace_diagnostics(language_server.server_id());
8186 }
8187
8188 None
8189 }
8190
8191 pub fn on_buffer_saved(
8192 &mut self,
8193 buffer: Entity<Buffer>,
8194 cx: &mut Context<Self>,
8195 ) -> Option<()> {
8196 let file = File::from_dyn(buffer.read(cx).file())?;
8197 let worktree_id = file.worktree_id(cx);
8198 let abs_path = file.as_local()?.abs_path(cx);
8199 let text_document = lsp::TextDocumentIdentifier {
8200 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8201 };
8202 let local = self.as_local()?;
8203
8204 for server in local.language_servers_for_worktree(worktree_id) {
8205 if let Some(include_text) = include_text(server.as_ref()) {
8206 let text = if include_text {
8207 Some(buffer.read(cx).text())
8208 } else {
8209 None
8210 };
8211 server
8212 .notify::<lsp::notification::DidSaveTextDocument>(
8213 lsp::DidSaveTextDocumentParams {
8214 text_document: text_document.clone(),
8215 text,
8216 },
8217 )
8218 .ok();
8219 }
8220 }
8221
8222 let language_servers = buffer.update(cx, |buffer, cx| {
8223 local.language_server_ids_for_buffer(buffer, cx)
8224 });
8225 for language_server_id in language_servers {
8226 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8227 }
8228
8229 None
8230 }
8231
8232 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8233 maybe!(async move {
8234 let mut refreshed_servers = HashSet::default();
8235 let servers = lsp_store
8236 .update(cx, |lsp_store, cx| {
8237 let local = lsp_store.as_local()?;
8238
8239 let servers = local
8240 .language_server_ids
8241 .iter()
8242 .filter_map(|(seed, state)| {
8243 let worktree = lsp_store
8244 .worktree_store
8245 .read(cx)
8246 .worktree_for_id(seed.worktree_id, cx);
8247 let delegate: Arc<dyn LspAdapterDelegate> =
8248 worktree.map(|worktree| {
8249 LocalLspAdapterDelegate::new(
8250 local.languages.clone(),
8251 &local.environment,
8252 cx.weak_entity(),
8253 &worktree,
8254 local.http_client.clone(),
8255 local.fs.clone(),
8256 cx,
8257 )
8258 })?;
8259 let server_id = state.id;
8260
8261 let states = local.language_servers.get(&server_id)?;
8262
8263 match states {
8264 LanguageServerState::Starting { .. } => None,
8265 LanguageServerState::Running {
8266 adapter, server, ..
8267 } => {
8268 let adapter = adapter.clone();
8269 let server = server.clone();
8270 refreshed_servers.insert(server.name());
8271 let toolchain = seed.toolchain.clone();
8272 Some(cx.spawn(async move |_, cx| {
8273 let settings =
8274 LocalLspStore::workspace_configuration_for_adapter(
8275 adapter.adapter.clone(),
8276 &delegate,
8277 toolchain,
8278 None,
8279 cx,
8280 )
8281 .await
8282 .ok()?;
8283 server
8284 .notify::<lsp::notification::DidChangeConfiguration>(
8285 lsp::DidChangeConfigurationParams { settings },
8286 )
8287 .ok()?;
8288 Some(())
8289 }))
8290 }
8291 }
8292 })
8293 .collect::<Vec<_>>();
8294
8295 Some(servers)
8296 })
8297 .ok()
8298 .flatten()?;
8299
8300 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8301 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8302 // to stop and unregister its language server wrapper.
8303 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8304 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8305 let _: Vec<Option<()>> = join_all(servers).await;
8306
8307 Some(())
8308 })
8309 .await;
8310 }
8311
8312 fn maintain_workspace_config(
8313 external_refresh_requests: watch::Receiver<()>,
8314 cx: &mut Context<Self>,
8315 ) -> Task<Result<()>> {
8316 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8317 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8318
8319 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8320 *settings_changed_tx.borrow_mut() = ();
8321 });
8322
8323 let mut joint_future =
8324 futures::stream::select(settings_changed_rx, external_refresh_requests);
8325 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8326 // - 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).
8327 // - 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.
8328 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8329 // - 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,
8330 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8331 cx.spawn(async move |this, cx| {
8332 while let Some(()) = joint_future.next().await {
8333 this.update(cx, |this, cx| {
8334 this.refresh_server_tree(cx);
8335 })
8336 .ok();
8337
8338 Self::refresh_workspace_configurations(&this, cx).await;
8339 }
8340
8341 drop(settings_observation);
8342 anyhow::Ok(())
8343 })
8344 }
8345
8346 pub fn running_language_servers_for_local_buffer<'a>(
8347 &'a self,
8348 buffer: &Buffer,
8349 cx: &mut App,
8350 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8351 let local = self.as_local();
8352 let language_server_ids = local
8353 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8354 .unwrap_or_default();
8355
8356 language_server_ids
8357 .into_iter()
8358 .filter_map(
8359 move |server_id| match local?.language_servers.get(&server_id)? {
8360 LanguageServerState::Running {
8361 adapter, server, ..
8362 } => Some((adapter, server)),
8363 _ => None,
8364 },
8365 )
8366 }
8367
8368 pub fn language_servers_for_local_buffer(
8369 &self,
8370 buffer: &Buffer,
8371 cx: &mut App,
8372 ) -> Vec<LanguageServerId> {
8373 let local = self.as_local();
8374 local
8375 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8376 .unwrap_or_default()
8377 }
8378
8379 pub fn language_server_for_local_buffer<'a>(
8380 &'a self,
8381 buffer: &'a Buffer,
8382 server_id: LanguageServerId,
8383 cx: &'a mut App,
8384 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8385 self.as_local()?
8386 .language_servers_for_buffer(buffer, cx)
8387 .find(|(_, s)| s.server_id() == server_id)
8388 }
8389
8390 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8391 self.diagnostic_summaries.remove(&id_to_remove);
8392 if let Some(local) = self.as_local_mut() {
8393 let to_remove = local.remove_worktree(id_to_remove, cx);
8394 for server in to_remove {
8395 self.language_server_statuses.remove(&server);
8396 }
8397 }
8398 }
8399
8400 pub fn shared(
8401 &mut self,
8402 project_id: u64,
8403 downstream_client: AnyProtoClient,
8404 _: &mut Context<Self>,
8405 ) {
8406 self.downstream_client = Some((downstream_client.clone(), project_id));
8407
8408 for (server_id, status) in &self.language_server_statuses {
8409 if let Some(server) = self.language_server_for_id(*server_id) {
8410 downstream_client
8411 .send(proto::StartLanguageServer {
8412 project_id,
8413 server: Some(proto::LanguageServer {
8414 id: server_id.to_proto(),
8415 name: status.name.to_string(),
8416 worktree_id: status.worktree.map(|id| id.to_proto()),
8417 }),
8418 capabilities: serde_json::to_string(&server.capabilities())
8419 .expect("serializing server LSP capabilities"),
8420 })
8421 .log_err();
8422 }
8423 }
8424 }
8425
8426 pub fn disconnected_from_host(&mut self) {
8427 self.downstream_client.take();
8428 }
8429
8430 pub fn disconnected_from_ssh_remote(&mut self) {
8431 if let LspStoreMode::Remote(RemoteLspStore {
8432 upstream_client, ..
8433 }) = &mut self.mode
8434 {
8435 upstream_client.take();
8436 }
8437 }
8438
8439 pub(crate) fn set_language_server_statuses_from_proto(
8440 &mut self,
8441 project: WeakEntity<Project>,
8442 language_servers: Vec<proto::LanguageServer>,
8443 server_capabilities: Vec<String>,
8444 cx: &mut Context<Self>,
8445 ) {
8446 let lsp_logs = cx
8447 .try_global::<GlobalLogStore>()
8448 .map(|lsp_store| lsp_store.0.clone());
8449
8450 self.language_server_statuses = language_servers
8451 .into_iter()
8452 .zip(server_capabilities)
8453 .map(|(server, server_capabilities)| {
8454 let server_id = LanguageServerId(server.id as usize);
8455 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8456 self.lsp_server_capabilities
8457 .insert(server_id, server_capabilities);
8458 }
8459
8460 let name = LanguageServerName::from_proto(server.name);
8461 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8462
8463 if let Some(lsp_logs) = &lsp_logs {
8464 lsp_logs.update(cx, |lsp_logs, cx| {
8465 lsp_logs.add_language_server(
8466 // Only remote clients get their language servers set from proto
8467 LanguageServerKind::Remote {
8468 project: project.clone(),
8469 },
8470 server_id,
8471 Some(name.clone()),
8472 worktree,
8473 None,
8474 cx,
8475 );
8476 });
8477 }
8478
8479 (
8480 server_id,
8481 LanguageServerStatus {
8482 name,
8483 server_version: None,
8484 pending_work: Default::default(),
8485 has_pending_diagnostic_updates: false,
8486 progress_tokens: Default::default(),
8487 worktree,
8488 binary: None,
8489 configuration: None,
8490 workspace_folders: BTreeSet::new(),
8491 process_id: None,
8492 },
8493 )
8494 })
8495 .collect();
8496 }
8497
8498 #[cfg(feature = "test-support")]
8499 pub fn update_diagnostic_entries(
8500 &mut self,
8501 server_id: LanguageServerId,
8502 abs_path: PathBuf,
8503 result_id: Option<SharedString>,
8504 version: Option<i32>,
8505 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8506 cx: &mut Context<Self>,
8507 ) -> anyhow::Result<()> {
8508 self.merge_diagnostic_entries(
8509 vec![DocumentDiagnosticsUpdate {
8510 diagnostics: DocumentDiagnostics {
8511 diagnostics,
8512 document_abs_path: abs_path,
8513 version,
8514 },
8515 result_id,
8516 server_id,
8517 disk_based_sources: Cow::Borrowed(&[]),
8518 registration_id: None,
8519 }],
8520 |_, _, _| false,
8521 cx,
8522 )?;
8523 Ok(())
8524 }
8525
8526 pub fn merge_diagnostic_entries<'a>(
8527 &mut self,
8528 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8529 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8530 cx: &mut Context<Self>,
8531 ) -> anyhow::Result<()> {
8532 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8533 let mut updated_diagnostics_paths = HashMap::default();
8534 for mut update in diagnostic_updates {
8535 let abs_path = &update.diagnostics.document_abs_path;
8536 let server_id = update.server_id;
8537 let Some((worktree, relative_path)) =
8538 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8539 else {
8540 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8541 return Ok(());
8542 };
8543
8544 let worktree_id = worktree.read(cx).id();
8545 let project_path = ProjectPath {
8546 worktree_id,
8547 path: relative_path,
8548 };
8549
8550 let document_uri = lsp::Uri::from_file_path(abs_path)
8551 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8552 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8553 let snapshot = buffer_handle.read(cx).snapshot();
8554 let buffer = buffer_handle.read(cx);
8555 let reused_diagnostics = buffer
8556 .buffer_diagnostics(Some(server_id))
8557 .iter()
8558 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8559 .map(|v| {
8560 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8561 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8562 DiagnosticEntry {
8563 range: start..end,
8564 diagnostic: v.diagnostic.clone(),
8565 }
8566 })
8567 .collect::<Vec<_>>();
8568
8569 self.as_local_mut()
8570 .context("cannot merge diagnostics on a remote LspStore")?
8571 .update_buffer_diagnostics(
8572 &buffer_handle,
8573 server_id,
8574 Some(update.registration_id),
8575 update.result_id,
8576 update.diagnostics.version,
8577 update.diagnostics.diagnostics.clone(),
8578 reused_diagnostics.clone(),
8579 cx,
8580 )?;
8581
8582 update.diagnostics.diagnostics.extend(reused_diagnostics);
8583 } else if let Some(local) = self.as_local() {
8584 let reused_diagnostics = local
8585 .diagnostics
8586 .get(&worktree_id)
8587 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8588 .and_then(|diagnostics_by_server_id| {
8589 diagnostics_by_server_id
8590 .binary_search_by_key(&server_id, |e| e.0)
8591 .ok()
8592 .map(|ix| &diagnostics_by_server_id[ix].1)
8593 })
8594 .into_iter()
8595 .flatten()
8596 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8597
8598 update
8599 .diagnostics
8600 .diagnostics
8601 .extend(reused_diagnostics.cloned());
8602 }
8603
8604 let updated = worktree.update(cx, |worktree, cx| {
8605 self.update_worktree_diagnostics(
8606 worktree.id(),
8607 server_id,
8608 project_path.path.clone(),
8609 update.diagnostics.diagnostics,
8610 cx,
8611 )
8612 })?;
8613 match updated {
8614 ControlFlow::Continue(new_summary) => {
8615 if let Some((project_id, new_summary)) = new_summary {
8616 match &mut diagnostics_summary {
8617 Some(diagnostics_summary) => {
8618 diagnostics_summary
8619 .more_summaries
8620 .push(proto::DiagnosticSummary {
8621 path: project_path.path.as_ref().to_proto(),
8622 language_server_id: server_id.0 as u64,
8623 error_count: new_summary.error_count,
8624 warning_count: new_summary.warning_count,
8625 })
8626 }
8627 None => {
8628 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8629 project_id,
8630 worktree_id: worktree_id.to_proto(),
8631 summary: Some(proto::DiagnosticSummary {
8632 path: project_path.path.as_ref().to_proto(),
8633 language_server_id: server_id.0 as u64,
8634 error_count: new_summary.error_count,
8635 warning_count: new_summary.warning_count,
8636 }),
8637 more_summaries: Vec::new(),
8638 })
8639 }
8640 }
8641 }
8642 updated_diagnostics_paths
8643 .entry(server_id)
8644 .or_insert_with(Vec::new)
8645 .push(project_path);
8646 }
8647 ControlFlow::Break(()) => {}
8648 }
8649 }
8650
8651 if let Some((diagnostics_summary, (downstream_client, _))) =
8652 diagnostics_summary.zip(self.downstream_client.as_ref())
8653 {
8654 downstream_client.send(diagnostics_summary).log_err();
8655 }
8656 for (server_id, paths) in updated_diagnostics_paths {
8657 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8658 }
8659 Ok(())
8660 }
8661
8662 fn update_worktree_diagnostics(
8663 &mut self,
8664 worktree_id: WorktreeId,
8665 server_id: LanguageServerId,
8666 path_in_worktree: Arc<RelPath>,
8667 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8668 _: &mut Context<Worktree>,
8669 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8670 let local = match &mut self.mode {
8671 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8672 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8673 };
8674
8675 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8676 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8677 let summaries_by_server_id = summaries_for_tree
8678 .entry(path_in_worktree.clone())
8679 .or_default();
8680
8681 let old_summary = summaries_by_server_id
8682 .remove(&server_id)
8683 .unwrap_or_default();
8684
8685 let new_summary = DiagnosticSummary::new(&diagnostics);
8686 if diagnostics.is_empty() {
8687 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8688 {
8689 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8690 diagnostics_by_server_id.remove(ix);
8691 }
8692 if diagnostics_by_server_id.is_empty() {
8693 diagnostics_for_tree.remove(&path_in_worktree);
8694 }
8695 }
8696 } else {
8697 summaries_by_server_id.insert(server_id, new_summary);
8698 let diagnostics_by_server_id = diagnostics_for_tree
8699 .entry(path_in_worktree.clone())
8700 .or_default();
8701 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8702 Ok(ix) => {
8703 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8704 }
8705 Err(ix) => {
8706 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8707 }
8708 }
8709 }
8710
8711 if !old_summary.is_empty() || !new_summary.is_empty() {
8712 if let Some((_, project_id)) = &self.downstream_client {
8713 Ok(ControlFlow::Continue(Some((
8714 *project_id,
8715 proto::DiagnosticSummary {
8716 path: path_in_worktree.to_proto(),
8717 language_server_id: server_id.0 as u64,
8718 error_count: new_summary.error_count as u32,
8719 warning_count: new_summary.warning_count as u32,
8720 },
8721 ))))
8722 } else {
8723 Ok(ControlFlow::Continue(None))
8724 }
8725 } else {
8726 Ok(ControlFlow::Break(()))
8727 }
8728 }
8729
8730 pub fn open_buffer_for_symbol(
8731 &mut self,
8732 symbol: &Symbol,
8733 cx: &mut Context<Self>,
8734 ) -> Task<Result<Entity<Buffer>>> {
8735 if let Some((client, project_id)) = self.upstream_client() {
8736 let request = client.request(proto::OpenBufferForSymbol {
8737 project_id,
8738 symbol: Some(Self::serialize_symbol(symbol)),
8739 });
8740 cx.spawn(async move |this, cx| {
8741 let response = request.await?;
8742 let buffer_id = BufferId::new(response.buffer_id)?;
8743 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8744 .await
8745 })
8746 } else if let Some(local) = self.as_local() {
8747 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8748 seed.worktree_id == symbol.source_worktree_id
8749 && state.id == symbol.source_language_server_id
8750 && symbol.language_server_name == seed.name
8751 });
8752 if !is_valid {
8753 return Task::ready(Err(anyhow!(
8754 "language server for worktree and language not found"
8755 )));
8756 };
8757
8758 let symbol_abs_path = match &symbol.path {
8759 SymbolLocation::InProject(project_path) => self
8760 .worktree_store
8761 .read(cx)
8762 .absolutize(&project_path, cx)
8763 .context("no such worktree"),
8764 SymbolLocation::OutsideProject {
8765 abs_path,
8766 signature: _,
8767 } => Ok(abs_path.to_path_buf()),
8768 };
8769 let symbol_abs_path = match symbol_abs_path {
8770 Ok(abs_path) => abs_path,
8771 Err(err) => return Task::ready(Err(err)),
8772 };
8773 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8774 uri
8775 } else {
8776 return Task::ready(Err(anyhow!("invalid symbol path")));
8777 };
8778
8779 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8780 } else {
8781 Task::ready(Err(anyhow!("no upstream client or local store")))
8782 }
8783 }
8784
8785 pub(crate) fn open_local_buffer_via_lsp(
8786 &mut self,
8787 abs_path: lsp::Uri,
8788 language_server_id: LanguageServerId,
8789 cx: &mut Context<Self>,
8790 ) -> Task<Result<Entity<Buffer>>> {
8791 let path_style = self.worktree_store.read(cx).path_style();
8792 cx.spawn(async move |lsp_store, cx| {
8793 // Escape percent-encoded string.
8794 let current_scheme = abs_path.scheme().to_owned();
8795 // Uri is immutable, so we can't modify the scheme
8796
8797 let abs_path = abs_path
8798 .to_file_path_ext(path_style)
8799 .map_err(|()| anyhow!("can't convert URI to path"))?;
8800 let p = abs_path.clone();
8801 let yarn_worktree = lsp_store
8802 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8803 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8804 cx.spawn(async move |this, cx| {
8805 let t = this
8806 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8807 .ok()?;
8808 t.await
8809 })
8810 }),
8811 None => Task::ready(None),
8812 })?
8813 .await;
8814 let (worktree_root_target, known_relative_path) =
8815 if let Some((zip_root, relative_path)) = yarn_worktree {
8816 (zip_root, Some(relative_path))
8817 } else {
8818 (Arc::<Path>::from(abs_path.as_path()), None)
8819 };
8820 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8821 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8822 worktree_store.find_worktree(&worktree_root_target, cx)
8823 })
8824 })?;
8825 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8826 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8827 (result.0, relative_path, None)
8828 } else {
8829 let worktree = lsp_store
8830 .update(cx, |lsp_store, cx| {
8831 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8832 worktree_store.create_worktree(&worktree_root_target, false, cx)
8833 })
8834 })?
8835 .await?;
8836 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8837 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8838 lsp_store
8839 .update(cx, |lsp_store, cx| {
8840 if let Some(local) = lsp_store.as_local_mut() {
8841 local.register_language_server_for_invisible_worktree(
8842 &worktree,
8843 language_server_id,
8844 cx,
8845 )
8846 }
8847 match lsp_store.language_server_statuses.get(&language_server_id) {
8848 Some(status) => status.worktree,
8849 None => None,
8850 }
8851 })
8852 .ok()
8853 .flatten()
8854 .zip(Some(worktree_root.clone()))
8855 } else {
8856 None
8857 };
8858 let relative_path = if let Some(known_path) = known_relative_path {
8859 known_path
8860 } else {
8861 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8862 .into_arc()
8863 };
8864 (worktree, relative_path, source_ws)
8865 };
8866 let project_path = ProjectPath {
8867 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8868 path: relative_path,
8869 };
8870 let buffer = lsp_store
8871 .update(cx, |lsp_store, cx| {
8872 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8873 buffer_store.open_buffer(project_path, cx)
8874 })
8875 })?
8876 .await?;
8877 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8878 if let Some((source_ws, worktree_root)) = source_ws {
8879 buffer.update(cx, |buffer, cx| {
8880 let settings = WorktreeSettings::get(
8881 Some(
8882 (&ProjectPath {
8883 worktree_id: source_ws,
8884 path: Arc::from(RelPath::empty()),
8885 })
8886 .into(),
8887 ),
8888 cx,
8889 );
8890 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8891 if is_read_only {
8892 buffer.set_capability(Capability::ReadOnly, cx);
8893 }
8894 });
8895 }
8896 Ok(buffer)
8897 })
8898 }
8899
8900 fn request_multiple_lsp_locally<P, R>(
8901 &mut self,
8902 buffer: &Entity<Buffer>,
8903 position: Option<P>,
8904 request: R,
8905 cx: &mut Context<Self>,
8906 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8907 where
8908 P: ToOffset,
8909 R: LspCommand + Clone,
8910 <R::LspRequest as lsp::request::Request>::Result: Send,
8911 <R::LspRequest as lsp::request::Request>::Params: Send,
8912 {
8913 let Some(local) = self.as_local() else {
8914 return Task::ready(Vec::new());
8915 };
8916
8917 let snapshot = buffer.read(cx).snapshot();
8918 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8919
8920 let server_ids = buffer.update(cx, |buffer, cx| {
8921 local
8922 .language_servers_for_buffer(buffer, cx)
8923 .filter(|(adapter, _)| {
8924 scope
8925 .as_ref()
8926 .map(|scope| scope.language_allowed(&adapter.name))
8927 .unwrap_or(true)
8928 })
8929 .map(|(_, server)| server.server_id())
8930 .filter(|server_id| {
8931 self.as_local().is_none_or(|local| {
8932 local
8933 .buffers_opened_in_servers
8934 .get(&snapshot.remote_id())
8935 .is_some_and(|servers| servers.contains(server_id))
8936 })
8937 })
8938 .collect::<Vec<_>>()
8939 });
8940
8941 let mut response_results = server_ids
8942 .into_iter()
8943 .map(|server_id| {
8944 let task = self.request_lsp(
8945 buffer.clone(),
8946 LanguageServerToQuery::Other(server_id),
8947 request.clone(),
8948 cx,
8949 );
8950 async move { (server_id, task.await) }
8951 })
8952 .collect::<FuturesUnordered<_>>();
8953
8954 cx.background_spawn(async move {
8955 let mut responses = Vec::with_capacity(response_results.len());
8956 while let Some((server_id, response_result)) = response_results.next().await {
8957 match response_result {
8958 Ok(response) => responses.push((server_id, response)),
8959 // rust-analyzer likes to error with this when its still loading up
8960 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8961 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8962 }
8963 }
8964 responses
8965 })
8966 }
8967
8968 async fn handle_lsp_get_completions(
8969 this: Entity<Self>,
8970 envelope: TypedEnvelope<proto::GetCompletions>,
8971 mut cx: AsyncApp,
8972 ) -> Result<proto::GetCompletionsResponse> {
8973 let sender_id = envelope.original_sender_id().unwrap_or_default();
8974
8975 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8976 let buffer_handle = this.update(&mut cx, |this, cx| {
8977 this.buffer_store.read(cx).get_existing(buffer_id)
8978 })?;
8979 let request = GetCompletions::from_proto(
8980 envelope.payload,
8981 this.clone(),
8982 buffer_handle.clone(),
8983 cx.clone(),
8984 )
8985 .await?;
8986
8987 let server_to_query = match request.server_id {
8988 Some(server_id) => LanguageServerToQuery::Other(server_id),
8989 None => LanguageServerToQuery::FirstCapable,
8990 };
8991
8992 let response = this
8993 .update(&mut cx, |this, cx| {
8994 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8995 })
8996 .await?;
8997 this.update(&mut cx, |this, cx| {
8998 Ok(GetCompletions::response_to_proto(
8999 response,
9000 this,
9001 sender_id,
9002 &buffer_handle.read(cx).version(),
9003 cx,
9004 ))
9005 })
9006 }
9007
9008 async fn handle_lsp_command<T: LspCommand>(
9009 this: Entity<Self>,
9010 envelope: TypedEnvelope<T::ProtoRequest>,
9011 mut cx: AsyncApp,
9012 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
9013 where
9014 <T::LspRequest as lsp::request::Request>::Params: Send,
9015 <T::LspRequest as lsp::request::Request>::Result: Send,
9016 {
9017 let sender_id = envelope.original_sender_id().unwrap_or_default();
9018 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
9019 let buffer_handle = this.update(&mut cx, |this, cx| {
9020 this.buffer_store.read(cx).get_existing(buffer_id)
9021 })?;
9022 let request = T::from_proto(
9023 envelope.payload,
9024 this.clone(),
9025 buffer_handle.clone(),
9026 cx.clone(),
9027 )
9028 .await?;
9029 let response = this
9030 .update(&mut cx, |this, cx| {
9031 this.request_lsp(
9032 buffer_handle.clone(),
9033 LanguageServerToQuery::FirstCapable,
9034 request,
9035 cx,
9036 )
9037 })
9038 .await?;
9039 this.update(&mut cx, |this, cx| {
9040 Ok(T::response_to_proto(
9041 response,
9042 this,
9043 sender_id,
9044 &buffer_handle.read(cx).version(),
9045 cx,
9046 ))
9047 })
9048 }
9049
9050 async fn handle_lsp_query(
9051 lsp_store: Entity<Self>,
9052 envelope: TypedEnvelope<proto::LspQuery>,
9053 mut cx: AsyncApp,
9054 ) -> Result<proto::Ack> {
9055 use proto::lsp_query::Request;
9056 let sender_id = envelope.original_sender_id().unwrap_or_default();
9057 let lsp_query = envelope.payload;
9058 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
9059 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
9060 match lsp_query.request.context("invalid LSP query request")? {
9061 Request::GetReferences(get_references) => {
9062 let position = get_references.position.clone().and_then(deserialize_anchor);
9063 Self::query_lsp_locally::<GetReferences>(
9064 lsp_store,
9065 server_id,
9066 sender_id,
9067 lsp_request_id,
9068 get_references,
9069 position,
9070 &mut cx,
9071 )
9072 .await?;
9073 }
9074 Request::GetDocumentColor(get_document_color) => {
9075 Self::query_lsp_locally::<GetDocumentColor>(
9076 lsp_store,
9077 server_id,
9078 sender_id,
9079 lsp_request_id,
9080 get_document_color,
9081 None,
9082 &mut cx,
9083 )
9084 .await?;
9085 }
9086 Request::GetHover(get_hover) => {
9087 let position = get_hover.position.clone().and_then(deserialize_anchor);
9088 Self::query_lsp_locally::<GetHover>(
9089 lsp_store,
9090 server_id,
9091 sender_id,
9092 lsp_request_id,
9093 get_hover,
9094 position,
9095 &mut cx,
9096 )
9097 .await?;
9098 }
9099 Request::GetCodeActions(get_code_actions) => {
9100 Self::query_lsp_locally::<GetCodeActions>(
9101 lsp_store,
9102 server_id,
9103 sender_id,
9104 lsp_request_id,
9105 get_code_actions,
9106 None,
9107 &mut cx,
9108 )
9109 .await?;
9110 }
9111 Request::GetSignatureHelp(get_signature_help) => {
9112 let position = get_signature_help
9113 .position
9114 .clone()
9115 .and_then(deserialize_anchor);
9116 Self::query_lsp_locally::<GetSignatureHelp>(
9117 lsp_store,
9118 server_id,
9119 sender_id,
9120 lsp_request_id,
9121 get_signature_help,
9122 position,
9123 &mut cx,
9124 )
9125 .await?;
9126 }
9127 Request::GetCodeLens(get_code_lens) => {
9128 Self::query_lsp_locally::<GetCodeLens>(
9129 lsp_store,
9130 server_id,
9131 sender_id,
9132 lsp_request_id,
9133 get_code_lens,
9134 None,
9135 &mut cx,
9136 )
9137 .await?;
9138 }
9139 Request::GetDefinition(get_definition) => {
9140 let position = get_definition.position.clone().and_then(deserialize_anchor);
9141 Self::query_lsp_locally::<GetDefinitions>(
9142 lsp_store,
9143 server_id,
9144 sender_id,
9145 lsp_request_id,
9146 get_definition,
9147 position,
9148 &mut cx,
9149 )
9150 .await?;
9151 }
9152 Request::GetDeclaration(get_declaration) => {
9153 let position = get_declaration
9154 .position
9155 .clone()
9156 .and_then(deserialize_anchor);
9157 Self::query_lsp_locally::<GetDeclarations>(
9158 lsp_store,
9159 server_id,
9160 sender_id,
9161 lsp_request_id,
9162 get_declaration,
9163 position,
9164 &mut cx,
9165 )
9166 .await?;
9167 }
9168 Request::GetTypeDefinition(get_type_definition) => {
9169 let position = get_type_definition
9170 .position
9171 .clone()
9172 .and_then(deserialize_anchor);
9173 Self::query_lsp_locally::<GetTypeDefinitions>(
9174 lsp_store,
9175 server_id,
9176 sender_id,
9177 lsp_request_id,
9178 get_type_definition,
9179 position,
9180 &mut cx,
9181 )
9182 .await?;
9183 }
9184 Request::GetImplementation(get_implementation) => {
9185 let position = get_implementation
9186 .position
9187 .clone()
9188 .and_then(deserialize_anchor);
9189 Self::query_lsp_locally::<GetImplementations>(
9190 lsp_store,
9191 server_id,
9192 sender_id,
9193 lsp_request_id,
9194 get_implementation,
9195 position,
9196 &mut cx,
9197 )
9198 .await?;
9199 }
9200 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9201 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9202 let version = deserialize_version(get_document_diagnostics.buffer_version());
9203 let buffer = lsp_store.update(&mut cx, |this, cx| {
9204 this.buffer_store.read(cx).get_existing(buffer_id)
9205 })?;
9206 buffer
9207 .update(&mut cx, |buffer, _| {
9208 buffer.wait_for_version(version.clone())
9209 })
9210 .await?;
9211 lsp_store.update(&mut cx, |lsp_store, cx| {
9212 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9213 let key = LspKey {
9214 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9215 server_queried: server_id,
9216 };
9217 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9218 ) {
9219 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9220 lsp_requests.clear();
9221 };
9222 }
9223
9224 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9225 existing_queries.insert(
9226 lsp_request_id,
9227 cx.spawn(async move |lsp_store, cx| {
9228 let diagnostics_pull = lsp_store.update(cx, |lsp_store, cx| {
9229 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9230 });
9231 if let Ok(diagnostics_pull) = diagnostics_pull {
9232 match diagnostics_pull.await {
9233 Ok(()) => {}
9234 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9235 };
9236 }
9237 }),
9238 );
9239 });
9240 }
9241 Request::InlayHints(inlay_hints) => {
9242 let query_start = inlay_hints
9243 .start
9244 .clone()
9245 .and_then(deserialize_anchor)
9246 .context("invalid inlay hints range start")?;
9247 let query_end = inlay_hints
9248 .end
9249 .clone()
9250 .and_then(deserialize_anchor)
9251 .context("invalid inlay hints range end")?;
9252 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9253 &lsp_store,
9254 server_id,
9255 lsp_request_id,
9256 &inlay_hints,
9257 query_start..query_end,
9258 &mut cx,
9259 )
9260 .await
9261 .context("preparing inlay hints request")?;
9262 Self::query_lsp_locally::<InlayHints>(
9263 lsp_store,
9264 server_id,
9265 sender_id,
9266 lsp_request_id,
9267 inlay_hints,
9268 None,
9269 &mut cx,
9270 )
9271 .await
9272 .context("querying for inlay hints")?
9273 }
9274 }
9275 Ok(proto::Ack {})
9276 }
9277
9278 async fn handle_lsp_query_response(
9279 lsp_store: Entity<Self>,
9280 envelope: TypedEnvelope<proto::LspQueryResponse>,
9281 cx: AsyncApp,
9282 ) -> Result<()> {
9283 lsp_store.read_with(&cx, |lsp_store, _| {
9284 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9285 upstream_client.handle_lsp_response(envelope.clone());
9286 }
9287 });
9288 Ok(())
9289 }
9290
9291 async fn handle_apply_code_action(
9292 this: Entity<Self>,
9293 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9294 mut cx: AsyncApp,
9295 ) -> Result<proto::ApplyCodeActionResponse> {
9296 let sender_id = envelope.original_sender_id().unwrap_or_default();
9297 let action =
9298 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9299 let apply_code_action = this.update(&mut cx, |this, cx| {
9300 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9301 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9302 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9303 })?;
9304
9305 let project_transaction = apply_code_action.await?;
9306 let project_transaction = this.update(&mut cx, |this, cx| {
9307 this.buffer_store.update(cx, |buffer_store, cx| {
9308 buffer_store.serialize_project_transaction_for_peer(
9309 project_transaction,
9310 sender_id,
9311 cx,
9312 )
9313 })
9314 });
9315 Ok(proto::ApplyCodeActionResponse {
9316 transaction: Some(project_transaction),
9317 })
9318 }
9319
9320 async fn handle_register_buffer_with_language_servers(
9321 this: Entity<Self>,
9322 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9323 mut cx: AsyncApp,
9324 ) -> Result<proto::Ack> {
9325 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9326 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9327 this.update(&mut cx, |this, cx| {
9328 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9329 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9330 project_id: upstream_project_id,
9331 buffer_id: buffer_id.to_proto(),
9332 only_servers: envelope.payload.only_servers,
9333 });
9334 }
9335
9336 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9337 anyhow::bail!("buffer is not open");
9338 };
9339
9340 let handle = this.register_buffer_with_language_servers(
9341 &buffer,
9342 envelope
9343 .payload
9344 .only_servers
9345 .into_iter()
9346 .filter_map(|selector| {
9347 Some(match selector.selector? {
9348 proto::language_server_selector::Selector::ServerId(server_id) => {
9349 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9350 }
9351 proto::language_server_selector::Selector::Name(name) => {
9352 LanguageServerSelector::Name(LanguageServerName(
9353 SharedString::from(name),
9354 ))
9355 }
9356 })
9357 })
9358 .collect(),
9359 false,
9360 cx,
9361 );
9362 // Pull diagnostics for the buffer even if it was already registered.
9363 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9364 // but it's unclear if we need it.
9365 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9366 .detach();
9367 this.buffer_store().update(cx, |buffer_store, _| {
9368 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9369 });
9370
9371 Ok(())
9372 })?;
9373 Ok(proto::Ack {})
9374 }
9375
9376 async fn handle_rename_project_entry(
9377 this: Entity<Self>,
9378 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9379 mut cx: AsyncApp,
9380 ) -> Result<proto::ProjectEntryResponse> {
9381 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9382 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9383 let new_path =
9384 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9385
9386 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9387 .update(&mut cx, |this, cx| {
9388 let (worktree, entry) = this
9389 .worktree_store
9390 .read(cx)
9391 .worktree_and_entry_for_id(entry_id, cx)?;
9392 let new_worktree = this
9393 .worktree_store
9394 .read(cx)
9395 .worktree_for_id(new_worktree_id, cx)?;
9396 Some((
9397 this.worktree_store.clone(),
9398 worktree,
9399 new_worktree,
9400 entry.clone(),
9401 ))
9402 })
9403 .context("worktree not found")?;
9404 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9405 (worktree.absolutize(&old_entry.path), worktree.id())
9406 });
9407 let new_abs_path =
9408 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9409
9410 let _transaction = Self::will_rename_entry(
9411 this.downgrade(),
9412 old_worktree_id,
9413 &old_abs_path,
9414 &new_abs_path,
9415 old_entry.is_dir(),
9416 cx.clone(),
9417 )
9418 .await;
9419 let response = WorktreeStore::handle_rename_project_entry(
9420 worktree_store,
9421 envelope.payload,
9422 cx.clone(),
9423 )
9424 .await;
9425 this.read_with(&cx, |this, _| {
9426 this.did_rename_entry(
9427 old_worktree_id,
9428 &old_abs_path,
9429 &new_abs_path,
9430 old_entry.is_dir(),
9431 );
9432 });
9433 response
9434 }
9435
9436 async fn handle_update_diagnostic_summary(
9437 this: Entity<Self>,
9438 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9439 mut cx: AsyncApp,
9440 ) -> Result<()> {
9441 this.update(&mut cx, |lsp_store, cx| {
9442 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9443 let mut updated_diagnostics_paths = HashMap::default();
9444 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9445 for message_summary in envelope
9446 .payload
9447 .summary
9448 .into_iter()
9449 .chain(envelope.payload.more_summaries)
9450 {
9451 let project_path = ProjectPath {
9452 worktree_id,
9453 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9454 };
9455 let path = project_path.path.clone();
9456 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9457 let summary = DiagnosticSummary {
9458 error_count: message_summary.error_count as usize,
9459 warning_count: message_summary.warning_count as usize,
9460 };
9461
9462 if summary.is_empty() {
9463 if let Some(worktree_summaries) =
9464 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9465 && let Some(summaries) = worktree_summaries.get_mut(&path)
9466 {
9467 summaries.remove(&server_id);
9468 if summaries.is_empty() {
9469 worktree_summaries.remove(&path);
9470 }
9471 }
9472 } else {
9473 lsp_store
9474 .diagnostic_summaries
9475 .entry(worktree_id)
9476 .or_default()
9477 .entry(path)
9478 .or_default()
9479 .insert(server_id, summary);
9480 }
9481
9482 if let Some((_, project_id)) = &lsp_store.downstream_client {
9483 match &mut diagnostics_summary {
9484 Some(diagnostics_summary) => {
9485 diagnostics_summary
9486 .more_summaries
9487 .push(proto::DiagnosticSummary {
9488 path: project_path.path.as_ref().to_proto(),
9489 language_server_id: server_id.0 as u64,
9490 error_count: summary.error_count as u32,
9491 warning_count: summary.warning_count as u32,
9492 })
9493 }
9494 None => {
9495 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9496 project_id: *project_id,
9497 worktree_id: worktree_id.to_proto(),
9498 summary: Some(proto::DiagnosticSummary {
9499 path: project_path.path.as_ref().to_proto(),
9500 language_server_id: server_id.0 as u64,
9501 error_count: summary.error_count as u32,
9502 warning_count: summary.warning_count as u32,
9503 }),
9504 more_summaries: Vec::new(),
9505 })
9506 }
9507 }
9508 }
9509 updated_diagnostics_paths
9510 .entry(server_id)
9511 .or_insert_with(Vec::new)
9512 .push(project_path);
9513 }
9514
9515 if let Some((diagnostics_summary, (downstream_client, _))) =
9516 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9517 {
9518 downstream_client.send(diagnostics_summary).log_err();
9519 }
9520 for (server_id, paths) in updated_diagnostics_paths {
9521 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9522 }
9523 Ok(())
9524 })
9525 }
9526
9527 async fn handle_start_language_server(
9528 lsp_store: Entity<Self>,
9529 envelope: TypedEnvelope<proto::StartLanguageServer>,
9530 mut cx: AsyncApp,
9531 ) -> Result<()> {
9532 let server = envelope.payload.server.context("invalid server")?;
9533 let server_capabilities =
9534 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9535 .with_context(|| {
9536 format!(
9537 "incorrect server capabilities {}",
9538 envelope.payload.capabilities
9539 )
9540 })?;
9541 lsp_store.update(&mut cx, |lsp_store, cx| {
9542 let server_id = LanguageServerId(server.id as usize);
9543 let server_name = LanguageServerName::from_proto(server.name.clone());
9544 lsp_store
9545 .lsp_server_capabilities
9546 .insert(server_id, server_capabilities);
9547 lsp_store.language_server_statuses.insert(
9548 server_id,
9549 LanguageServerStatus {
9550 name: server_name.clone(),
9551 server_version: None,
9552 pending_work: Default::default(),
9553 has_pending_diagnostic_updates: false,
9554 progress_tokens: Default::default(),
9555 worktree: server.worktree_id.map(WorktreeId::from_proto),
9556 binary: None,
9557 configuration: None,
9558 workspace_folders: BTreeSet::new(),
9559 process_id: None,
9560 },
9561 );
9562 cx.emit(LspStoreEvent::LanguageServerAdded(
9563 server_id,
9564 server_name,
9565 server.worktree_id.map(WorktreeId::from_proto),
9566 ));
9567 cx.notify();
9568 });
9569 Ok(())
9570 }
9571
9572 async fn handle_update_language_server(
9573 lsp_store: Entity<Self>,
9574 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9575 mut cx: AsyncApp,
9576 ) -> Result<()> {
9577 lsp_store.update(&mut cx, |lsp_store, cx| {
9578 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9579
9580 match envelope.payload.variant.context("invalid variant")? {
9581 proto::update_language_server::Variant::WorkStart(payload) => {
9582 lsp_store.on_lsp_work_start(
9583 language_server_id,
9584 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9585 .context("invalid progress token value")?,
9586 LanguageServerProgress {
9587 title: payload.title,
9588 is_disk_based_diagnostics_progress: false,
9589 is_cancellable: payload.is_cancellable.unwrap_or(false),
9590 message: payload.message,
9591 percentage: payload.percentage.map(|p| p as usize),
9592 last_update_at: cx.background_executor().now(),
9593 },
9594 cx,
9595 );
9596 }
9597 proto::update_language_server::Variant::WorkProgress(payload) => {
9598 lsp_store.on_lsp_work_progress(
9599 language_server_id,
9600 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9601 .context("invalid progress token value")?,
9602 LanguageServerProgress {
9603 title: None,
9604 is_disk_based_diagnostics_progress: false,
9605 is_cancellable: payload.is_cancellable.unwrap_or(false),
9606 message: payload.message,
9607 percentage: payload.percentage.map(|p| p as usize),
9608 last_update_at: cx.background_executor().now(),
9609 },
9610 cx,
9611 );
9612 }
9613
9614 proto::update_language_server::Variant::WorkEnd(payload) => {
9615 lsp_store.on_lsp_work_end(
9616 language_server_id,
9617 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9618 .context("invalid progress token value")?,
9619 cx,
9620 );
9621 }
9622
9623 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9624 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9625 }
9626
9627 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9628 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9629 }
9630
9631 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9632 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9633 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9634 cx.emit(LspStoreEvent::LanguageServerUpdate {
9635 language_server_id,
9636 name: envelope
9637 .payload
9638 .server_name
9639 .map(SharedString::new)
9640 .map(LanguageServerName),
9641 message: non_lsp,
9642 });
9643 }
9644 }
9645
9646 Ok(())
9647 })
9648 }
9649
9650 async fn handle_language_server_log(
9651 this: Entity<Self>,
9652 envelope: TypedEnvelope<proto::LanguageServerLog>,
9653 mut cx: AsyncApp,
9654 ) -> Result<()> {
9655 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9656 let log_type = envelope
9657 .payload
9658 .log_type
9659 .map(LanguageServerLogType::from_proto)
9660 .context("invalid language server log type")?;
9661
9662 let message = envelope.payload.message;
9663
9664 this.update(&mut cx, |_, cx| {
9665 cx.emit(LspStoreEvent::LanguageServerLog(
9666 language_server_id,
9667 log_type,
9668 message,
9669 ));
9670 });
9671 Ok(())
9672 }
9673
9674 async fn handle_lsp_ext_cancel_flycheck(
9675 lsp_store: Entity<Self>,
9676 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9677 cx: AsyncApp,
9678 ) -> Result<proto::Ack> {
9679 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9680 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9681 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9682 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9683 } else {
9684 None
9685 }
9686 });
9687 if let Some(task) = task {
9688 task.context("handling lsp ext cancel flycheck")?;
9689 }
9690
9691 Ok(proto::Ack {})
9692 }
9693
9694 async fn handle_lsp_ext_run_flycheck(
9695 lsp_store: Entity<Self>,
9696 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9697 mut cx: AsyncApp,
9698 ) -> Result<proto::Ack> {
9699 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9700 lsp_store.update(&mut cx, |lsp_store, cx| {
9701 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9702 let text_document = if envelope.payload.current_file_only {
9703 let buffer_id = envelope
9704 .payload
9705 .buffer_id
9706 .map(|id| BufferId::new(id))
9707 .transpose()?;
9708 buffer_id
9709 .and_then(|buffer_id| {
9710 lsp_store
9711 .buffer_store()
9712 .read(cx)
9713 .get(buffer_id)
9714 .and_then(|buffer| {
9715 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9716 })
9717 .map(|path| make_text_document_identifier(&path))
9718 })
9719 .transpose()?
9720 } else {
9721 None
9722 };
9723 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9724 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9725 )?;
9726 }
9727 anyhow::Ok(())
9728 })?;
9729
9730 Ok(proto::Ack {})
9731 }
9732
9733 async fn handle_lsp_ext_clear_flycheck(
9734 lsp_store: Entity<Self>,
9735 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9736 cx: AsyncApp,
9737 ) -> Result<proto::Ack> {
9738 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9739 lsp_store.read_with(&cx, |lsp_store, _| {
9740 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9741 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9742 } else {
9743 None
9744 }
9745 });
9746
9747 Ok(proto::Ack {})
9748 }
9749
9750 pub fn disk_based_diagnostics_started(
9751 &mut self,
9752 language_server_id: LanguageServerId,
9753 cx: &mut Context<Self>,
9754 ) {
9755 if let Some(language_server_status) =
9756 self.language_server_statuses.get_mut(&language_server_id)
9757 {
9758 language_server_status.has_pending_diagnostic_updates = true;
9759 }
9760
9761 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9762 cx.emit(LspStoreEvent::LanguageServerUpdate {
9763 language_server_id,
9764 name: self
9765 .language_server_adapter_for_id(language_server_id)
9766 .map(|adapter| adapter.name()),
9767 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9768 Default::default(),
9769 ),
9770 })
9771 }
9772
9773 pub fn disk_based_diagnostics_finished(
9774 &mut self,
9775 language_server_id: LanguageServerId,
9776 cx: &mut Context<Self>,
9777 ) {
9778 if let Some(language_server_status) =
9779 self.language_server_statuses.get_mut(&language_server_id)
9780 {
9781 language_server_status.has_pending_diagnostic_updates = false;
9782 }
9783
9784 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9785 cx.emit(LspStoreEvent::LanguageServerUpdate {
9786 language_server_id,
9787 name: self
9788 .language_server_adapter_for_id(language_server_id)
9789 .map(|adapter| adapter.name()),
9790 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9791 Default::default(),
9792 ),
9793 })
9794 }
9795
9796 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9797 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9798 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9799 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9800 // the language server might take some time to publish diagnostics.
9801 fn simulate_disk_based_diagnostics_events_if_needed(
9802 &mut self,
9803 language_server_id: LanguageServerId,
9804 cx: &mut Context<Self>,
9805 ) {
9806 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9807
9808 let Some(LanguageServerState::Running {
9809 simulate_disk_based_diagnostics_completion,
9810 adapter,
9811 ..
9812 }) = self
9813 .as_local_mut()
9814 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9815 else {
9816 return;
9817 };
9818
9819 if adapter.disk_based_diagnostics_progress_token.is_some() {
9820 return;
9821 }
9822
9823 let prev_task =
9824 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9825 cx.background_executor()
9826 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9827 .await;
9828
9829 this.update(cx, |this, cx| {
9830 this.disk_based_diagnostics_finished(language_server_id, cx);
9831
9832 if let Some(LanguageServerState::Running {
9833 simulate_disk_based_diagnostics_completion,
9834 ..
9835 }) = this.as_local_mut().and_then(|local_store| {
9836 local_store.language_servers.get_mut(&language_server_id)
9837 }) {
9838 *simulate_disk_based_diagnostics_completion = None;
9839 }
9840 })
9841 .ok();
9842 }));
9843
9844 if prev_task.is_none() {
9845 self.disk_based_diagnostics_started(language_server_id, cx);
9846 }
9847 }
9848
9849 pub fn language_server_statuses(
9850 &self,
9851 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9852 self.language_server_statuses
9853 .iter()
9854 .map(|(key, value)| (*key, value))
9855 }
9856
9857 pub(super) fn did_rename_entry(
9858 &self,
9859 worktree_id: WorktreeId,
9860 old_path: &Path,
9861 new_path: &Path,
9862 is_dir: bool,
9863 ) {
9864 maybe!({
9865 let local_store = self.as_local()?;
9866
9867 let old_uri = lsp::Uri::from_file_path(old_path)
9868 .ok()
9869 .map(|uri| uri.to_string())?;
9870 let new_uri = lsp::Uri::from_file_path(new_path)
9871 .ok()
9872 .map(|uri| uri.to_string())?;
9873
9874 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9875 let Some(filter) = local_store
9876 .language_server_paths_watched_for_rename
9877 .get(&language_server.server_id())
9878 else {
9879 continue;
9880 };
9881
9882 if filter.should_send_did_rename(&old_uri, is_dir) {
9883 language_server
9884 .notify::<DidRenameFiles>(RenameFilesParams {
9885 files: vec![FileRename {
9886 old_uri: old_uri.clone(),
9887 new_uri: new_uri.clone(),
9888 }],
9889 })
9890 .ok();
9891 }
9892 }
9893 Some(())
9894 });
9895 }
9896
9897 pub(super) fn will_rename_entry(
9898 this: WeakEntity<Self>,
9899 worktree_id: WorktreeId,
9900 old_path: &Path,
9901 new_path: &Path,
9902 is_dir: bool,
9903 cx: AsyncApp,
9904 ) -> Task<ProjectTransaction> {
9905 let old_uri = lsp::Uri::from_file_path(old_path)
9906 .ok()
9907 .map(|uri| uri.to_string());
9908 let new_uri = lsp::Uri::from_file_path(new_path)
9909 .ok()
9910 .map(|uri| uri.to_string());
9911 cx.spawn(async move |cx| {
9912 let mut tasks = vec![];
9913 this.update(cx, |this, cx| {
9914 let local_store = this.as_local()?;
9915 let old_uri = old_uri?;
9916 let new_uri = new_uri?;
9917 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9918 let Some(filter) = local_store
9919 .language_server_paths_watched_for_rename
9920 .get(&language_server.server_id())
9921 else {
9922 continue;
9923 };
9924
9925 if filter.should_send_will_rename(&old_uri, is_dir) {
9926 let apply_edit = cx.spawn({
9927 let old_uri = old_uri.clone();
9928 let new_uri = new_uri.clone();
9929 let language_server = language_server.clone();
9930 async move |this, cx| {
9931 let edit = language_server
9932 .request::<WillRenameFiles>(RenameFilesParams {
9933 files: vec![FileRename { old_uri, new_uri }],
9934 })
9935 .await
9936 .into_response()
9937 .context("will rename files")
9938 .log_err()
9939 .flatten()?;
9940
9941 let transaction = LocalLspStore::deserialize_workspace_edit(
9942 this.upgrade()?,
9943 edit,
9944 false,
9945 language_server.clone(),
9946 cx,
9947 )
9948 .await
9949 .ok()?;
9950 Some(transaction)
9951 }
9952 });
9953 tasks.push(apply_edit);
9954 }
9955 }
9956 Some(())
9957 })
9958 .ok()
9959 .flatten();
9960 let mut merged_transaction = ProjectTransaction::default();
9961 for task in tasks {
9962 // Await on tasks sequentially so that the order of application of edits is deterministic
9963 // (at least with regards to the order of registration of language servers)
9964 if let Some(transaction) = task.await {
9965 for (buffer, buffer_transaction) in transaction.0 {
9966 merged_transaction.0.insert(buffer, buffer_transaction);
9967 }
9968 }
9969 }
9970 merged_transaction
9971 })
9972 }
9973
9974 fn lsp_notify_abs_paths_changed(
9975 &mut self,
9976 server_id: LanguageServerId,
9977 changes: Vec<PathEvent>,
9978 ) {
9979 maybe!({
9980 let server = self.language_server_for_id(server_id)?;
9981 let changes = changes
9982 .into_iter()
9983 .filter_map(|event| {
9984 let typ = match event.kind? {
9985 PathEventKind::Created => lsp::FileChangeType::CREATED,
9986 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9987 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9988 };
9989 Some(lsp::FileEvent {
9990 uri: file_path_to_lsp_url(&event.path).log_err()?,
9991 typ,
9992 })
9993 })
9994 .collect::<Vec<_>>();
9995 if !changes.is_empty() {
9996 server
9997 .notify::<lsp::notification::DidChangeWatchedFiles>(
9998 lsp::DidChangeWatchedFilesParams { changes },
9999 )
10000 .ok();
10001 }
10002 Some(())
10003 });
10004 }
10005
10006 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10007 self.as_local()?.language_server_for_id(id)
10008 }
10009
10010 fn on_lsp_progress(
10011 &mut self,
10012 progress_params: lsp::ProgressParams,
10013 language_server_id: LanguageServerId,
10014 disk_based_diagnostics_progress_token: Option<String>,
10015 cx: &mut Context<Self>,
10016 ) {
10017 match progress_params.value {
10018 lsp::ProgressParamsValue::WorkDone(progress) => {
10019 self.handle_work_done_progress(
10020 progress,
10021 language_server_id,
10022 disk_based_diagnostics_progress_token,
10023 ProgressToken::from_lsp(progress_params.token),
10024 cx,
10025 );
10026 }
10027 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10028 let registration_id = match progress_params.token {
10029 lsp::NumberOrString::Number(_) => None,
10030 lsp::NumberOrString::String(token) => token
10031 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10032 .map(|(_, id)| id.to_owned()),
10033 };
10034 if let Some(LanguageServerState::Running {
10035 workspace_diagnostics_refresh_tasks,
10036 ..
10037 }) = self
10038 .as_local_mut()
10039 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10040 && let Some(workspace_diagnostics) =
10041 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10042 {
10043 workspace_diagnostics.progress_tx.try_send(()).ok();
10044 self.apply_workspace_diagnostic_report(
10045 language_server_id,
10046 report,
10047 registration_id.map(SharedString::from),
10048 cx,
10049 )
10050 }
10051 }
10052 }
10053 }
10054
10055 fn handle_work_done_progress(
10056 &mut self,
10057 progress: lsp::WorkDoneProgress,
10058 language_server_id: LanguageServerId,
10059 disk_based_diagnostics_progress_token: Option<String>,
10060 token: ProgressToken,
10061 cx: &mut Context<Self>,
10062 ) {
10063 let language_server_status =
10064 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10065 status
10066 } else {
10067 return;
10068 };
10069
10070 if !language_server_status.progress_tokens.contains(&token) {
10071 return;
10072 }
10073
10074 let is_disk_based_diagnostics_progress =
10075 if let (Some(disk_based_token), ProgressToken::String(token)) =
10076 (&disk_based_diagnostics_progress_token, &token)
10077 {
10078 token.starts_with(disk_based_token)
10079 } else {
10080 false
10081 };
10082
10083 match progress {
10084 lsp::WorkDoneProgress::Begin(report) => {
10085 if is_disk_based_diagnostics_progress {
10086 self.disk_based_diagnostics_started(language_server_id, cx);
10087 }
10088 self.on_lsp_work_start(
10089 language_server_id,
10090 token.clone(),
10091 LanguageServerProgress {
10092 title: Some(report.title),
10093 is_disk_based_diagnostics_progress,
10094 is_cancellable: report.cancellable.unwrap_or(false),
10095 message: report.message.clone(),
10096 percentage: report.percentage.map(|p| p as usize),
10097 last_update_at: cx.background_executor().now(),
10098 },
10099 cx,
10100 );
10101 }
10102 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10103 language_server_id,
10104 token,
10105 LanguageServerProgress {
10106 title: None,
10107 is_disk_based_diagnostics_progress,
10108 is_cancellable: report.cancellable.unwrap_or(false),
10109 message: report.message,
10110 percentage: report.percentage.map(|p| p as usize),
10111 last_update_at: cx.background_executor().now(),
10112 },
10113 cx,
10114 ),
10115 lsp::WorkDoneProgress::End(_) => {
10116 language_server_status.progress_tokens.remove(&token);
10117 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10118 if is_disk_based_diagnostics_progress {
10119 self.disk_based_diagnostics_finished(language_server_id, cx);
10120 }
10121 }
10122 }
10123 }
10124
10125 fn on_lsp_work_start(
10126 &mut self,
10127 language_server_id: LanguageServerId,
10128 token: ProgressToken,
10129 progress: LanguageServerProgress,
10130 cx: &mut Context<Self>,
10131 ) {
10132 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10133 status.pending_work.insert(token.clone(), progress.clone());
10134 cx.notify();
10135 }
10136 cx.emit(LspStoreEvent::LanguageServerUpdate {
10137 language_server_id,
10138 name: self
10139 .language_server_adapter_for_id(language_server_id)
10140 .map(|adapter| adapter.name()),
10141 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10142 token: Some(token.to_proto()),
10143 title: progress.title,
10144 message: progress.message,
10145 percentage: progress.percentage.map(|p| p as u32),
10146 is_cancellable: Some(progress.is_cancellable),
10147 }),
10148 })
10149 }
10150
10151 fn on_lsp_work_progress(
10152 &mut self,
10153 language_server_id: LanguageServerId,
10154 token: ProgressToken,
10155 progress: LanguageServerProgress,
10156 cx: &mut Context<Self>,
10157 ) {
10158 let mut did_update = false;
10159 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10160 match status.pending_work.entry(token.clone()) {
10161 btree_map::Entry::Vacant(entry) => {
10162 entry.insert(progress.clone());
10163 did_update = true;
10164 }
10165 btree_map::Entry::Occupied(mut entry) => {
10166 let entry = entry.get_mut();
10167 if (progress.last_update_at - entry.last_update_at)
10168 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10169 {
10170 entry.last_update_at = progress.last_update_at;
10171 if progress.message.is_some() {
10172 entry.message = progress.message.clone();
10173 }
10174 if progress.percentage.is_some() {
10175 entry.percentage = progress.percentage;
10176 }
10177 if progress.is_cancellable != entry.is_cancellable {
10178 entry.is_cancellable = progress.is_cancellable;
10179 }
10180 did_update = true;
10181 }
10182 }
10183 }
10184 }
10185
10186 if did_update {
10187 cx.emit(LspStoreEvent::LanguageServerUpdate {
10188 language_server_id,
10189 name: self
10190 .language_server_adapter_for_id(language_server_id)
10191 .map(|adapter| adapter.name()),
10192 message: proto::update_language_server::Variant::WorkProgress(
10193 proto::LspWorkProgress {
10194 token: Some(token.to_proto()),
10195 message: progress.message,
10196 percentage: progress.percentage.map(|p| p as u32),
10197 is_cancellable: Some(progress.is_cancellable),
10198 },
10199 ),
10200 })
10201 }
10202 }
10203
10204 fn on_lsp_work_end(
10205 &mut self,
10206 language_server_id: LanguageServerId,
10207 token: ProgressToken,
10208 cx: &mut Context<Self>,
10209 ) {
10210 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10211 if let Some(work) = status.pending_work.remove(&token)
10212 && !work.is_disk_based_diagnostics_progress
10213 {
10214 cx.emit(LspStoreEvent::RefreshInlayHints {
10215 server_id: language_server_id,
10216 request_id: None,
10217 });
10218 }
10219 cx.notify();
10220 }
10221
10222 cx.emit(LspStoreEvent::LanguageServerUpdate {
10223 language_server_id,
10224 name: self
10225 .language_server_adapter_for_id(language_server_id)
10226 .map(|adapter| adapter.name()),
10227 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10228 token: Some(token.to_proto()),
10229 }),
10230 })
10231 }
10232
10233 pub async fn handle_resolve_completion_documentation(
10234 this: Entity<Self>,
10235 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10236 mut cx: AsyncApp,
10237 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10238 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10239
10240 let completion = this
10241 .read_with(&cx, |this, cx| {
10242 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10243 let server = this
10244 .language_server_for_id(id)
10245 .with_context(|| format!("No language server {id}"))?;
10246
10247 anyhow::Ok(cx.background_spawn(async move {
10248 let can_resolve = server
10249 .capabilities()
10250 .completion_provider
10251 .as_ref()
10252 .and_then(|options| options.resolve_provider)
10253 .unwrap_or(false);
10254 if can_resolve {
10255 server
10256 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10257 .await
10258 .into_response()
10259 .context("resolve completion item")
10260 } else {
10261 anyhow::Ok(lsp_completion)
10262 }
10263 }))
10264 })?
10265 .await?;
10266
10267 let mut documentation_is_markdown = false;
10268 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10269 let documentation = match completion.documentation {
10270 Some(lsp::Documentation::String(text)) => text,
10271
10272 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10273 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10274 value
10275 }
10276
10277 _ => String::new(),
10278 };
10279
10280 // If we have a new buffer_id, that means we're talking to a new client
10281 // and want to check for new text_edits in the completion too.
10282 let mut old_replace_start = None;
10283 let mut old_replace_end = None;
10284 let mut old_insert_start = None;
10285 let mut old_insert_end = None;
10286 let mut new_text = String::default();
10287 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10288 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10289 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10290 anyhow::Ok(buffer.read(cx).snapshot())
10291 })?;
10292
10293 if let Some(text_edit) = completion.text_edit.as_ref() {
10294 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10295
10296 if let Some(mut edit) = edit {
10297 LineEnding::normalize(&mut edit.new_text);
10298
10299 new_text = edit.new_text;
10300 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10301 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10302 if let Some(insert_range) = edit.insert_range {
10303 old_insert_start = Some(serialize_anchor(&insert_range.start));
10304 old_insert_end = Some(serialize_anchor(&insert_range.end));
10305 }
10306 }
10307 }
10308 }
10309
10310 Ok(proto::ResolveCompletionDocumentationResponse {
10311 documentation,
10312 documentation_is_markdown,
10313 old_replace_start,
10314 old_replace_end,
10315 new_text,
10316 lsp_completion,
10317 old_insert_start,
10318 old_insert_end,
10319 })
10320 }
10321
10322 async fn handle_on_type_formatting(
10323 this: Entity<Self>,
10324 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10325 mut cx: AsyncApp,
10326 ) -> Result<proto::OnTypeFormattingResponse> {
10327 let on_type_formatting = this.update(&mut cx, |this, cx| {
10328 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10329 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10330 let position = envelope
10331 .payload
10332 .position
10333 .and_then(deserialize_anchor)
10334 .context("invalid position")?;
10335 anyhow::Ok(this.apply_on_type_formatting(
10336 buffer,
10337 position,
10338 envelope.payload.trigger.clone(),
10339 cx,
10340 ))
10341 })?;
10342
10343 let transaction = on_type_formatting
10344 .await?
10345 .as_ref()
10346 .map(language::proto::serialize_transaction);
10347 Ok(proto::OnTypeFormattingResponse { transaction })
10348 }
10349
10350 async fn handle_refresh_inlay_hints(
10351 lsp_store: Entity<Self>,
10352 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10353 mut cx: AsyncApp,
10354 ) -> Result<proto::Ack> {
10355 lsp_store.update(&mut cx, |_, cx| {
10356 cx.emit(LspStoreEvent::RefreshInlayHints {
10357 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10358 request_id: envelope.payload.request_id.map(|id| id as usize),
10359 });
10360 });
10361 Ok(proto::Ack {})
10362 }
10363
10364 async fn handle_pull_workspace_diagnostics(
10365 lsp_store: Entity<Self>,
10366 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10367 mut cx: AsyncApp,
10368 ) -> Result<proto::Ack> {
10369 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10370 lsp_store.update(&mut cx, |lsp_store, _| {
10371 lsp_store.pull_workspace_diagnostics(server_id);
10372 });
10373 Ok(proto::Ack {})
10374 }
10375
10376 async fn handle_get_color_presentation(
10377 lsp_store: Entity<Self>,
10378 envelope: TypedEnvelope<proto::GetColorPresentation>,
10379 mut cx: AsyncApp,
10380 ) -> Result<proto::GetColorPresentationResponse> {
10381 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10382 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10383 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10384 })?;
10385
10386 let color = envelope
10387 .payload
10388 .color
10389 .context("invalid color resolve request")?;
10390 let start = color
10391 .lsp_range_start
10392 .context("invalid color resolve request")?;
10393 let end = color
10394 .lsp_range_end
10395 .context("invalid color resolve request")?;
10396
10397 let color = DocumentColor {
10398 lsp_range: lsp::Range {
10399 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10400 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10401 },
10402 color: lsp::Color {
10403 red: color.red,
10404 green: color.green,
10405 blue: color.blue,
10406 alpha: color.alpha,
10407 },
10408 resolved: false,
10409 color_presentations: Vec::new(),
10410 };
10411 let resolved_color = lsp_store
10412 .update(&mut cx, |lsp_store, cx| {
10413 lsp_store.resolve_color_presentation(
10414 color,
10415 buffer.clone(),
10416 LanguageServerId(envelope.payload.server_id as usize),
10417 cx,
10418 )
10419 })
10420 .await
10421 .context("resolving color presentation")?;
10422
10423 Ok(proto::GetColorPresentationResponse {
10424 presentations: resolved_color
10425 .color_presentations
10426 .into_iter()
10427 .map(|presentation| proto::ColorPresentation {
10428 label: presentation.label.to_string(),
10429 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10430 additional_text_edits: presentation
10431 .additional_text_edits
10432 .into_iter()
10433 .map(serialize_lsp_edit)
10434 .collect(),
10435 })
10436 .collect(),
10437 })
10438 }
10439
10440 async fn handle_resolve_inlay_hint(
10441 lsp_store: Entity<Self>,
10442 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10443 mut cx: AsyncApp,
10444 ) -> Result<proto::ResolveInlayHintResponse> {
10445 let proto_hint = envelope
10446 .payload
10447 .hint
10448 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10449 let hint = InlayHints::proto_to_project_hint(proto_hint)
10450 .context("resolved proto inlay hint conversion")?;
10451 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10452 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10453 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10454 })?;
10455 let response_hint = lsp_store
10456 .update(&mut cx, |lsp_store, cx| {
10457 lsp_store.resolve_inlay_hint(
10458 hint,
10459 buffer,
10460 LanguageServerId(envelope.payload.language_server_id as usize),
10461 cx,
10462 )
10463 })
10464 .await
10465 .context("inlay hints fetch")?;
10466 Ok(proto::ResolveInlayHintResponse {
10467 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10468 })
10469 }
10470
10471 async fn handle_refresh_code_lens(
10472 this: Entity<Self>,
10473 _: TypedEnvelope<proto::RefreshCodeLens>,
10474 mut cx: AsyncApp,
10475 ) -> Result<proto::Ack> {
10476 this.update(&mut cx, |_, cx| {
10477 cx.emit(LspStoreEvent::RefreshCodeLens);
10478 });
10479 Ok(proto::Ack {})
10480 }
10481
10482 async fn handle_open_buffer_for_symbol(
10483 this: Entity<Self>,
10484 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10485 mut cx: AsyncApp,
10486 ) -> Result<proto::OpenBufferForSymbolResponse> {
10487 let peer_id = envelope.original_sender_id().unwrap_or_default();
10488 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10489 let symbol = Self::deserialize_symbol(symbol)?;
10490 this.read_with(&cx, |this, _| {
10491 if let SymbolLocation::OutsideProject {
10492 abs_path,
10493 signature,
10494 } = &symbol.path
10495 {
10496 let new_signature = this.symbol_signature(&abs_path);
10497 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10498 }
10499 Ok(())
10500 })?;
10501 let buffer = this
10502 .update(&mut cx, |this, cx| {
10503 this.open_buffer_for_symbol(
10504 &Symbol {
10505 language_server_name: symbol.language_server_name,
10506 source_worktree_id: symbol.source_worktree_id,
10507 source_language_server_id: symbol.source_language_server_id,
10508 path: symbol.path,
10509 name: symbol.name,
10510 kind: symbol.kind,
10511 range: symbol.range,
10512 label: CodeLabel::default(),
10513 },
10514 cx,
10515 )
10516 })
10517 .await?;
10518
10519 this.update(&mut cx, |this, cx| {
10520 let is_private = buffer
10521 .read(cx)
10522 .file()
10523 .map(|f| f.is_private())
10524 .unwrap_or_default();
10525 if is_private {
10526 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10527 } else {
10528 this.buffer_store
10529 .update(cx, |buffer_store, cx| {
10530 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10531 })
10532 .detach_and_log_err(cx);
10533 let buffer_id = buffer.read(cx).remote_id().to_proto();
10534 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10535 }
10536 })
10537 }
10538
10539 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10540 let mut hasher = Sha256::new();
10541 hasher.update(abs_path.to_string_lossy().as_bytes());
10542 hasher.update(self.nonce.to_be_bytes());
10543 hasher.finalize().as_slice().try_into().unwrap()
10544 }
10545
10546 pub async fn handle_get_project_symbols(
10547 this: Entity<Self>,
10548 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10549 mut cx: AsyncApp,
10550 ) -> Result<proto::GetProjectSymbolsResponse> {
10551 let symbols = this
10552 .update(&mut cx, |this, cx| {
10553 this.symbols(&envelope.payload.query, cx)
10554 })
10555 .await?;
10556
10557 Ok(proto::GetProjectSymbolsResponse {
10558 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10559 })
10560 }
10561
10562 pub async fn handle_restart_language_servers(
10563 this: Entity<Self>,
10564 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10565 mut cx: AsyncApp,
10566 ) -> Result<proto::Ack> {
10567 this.update(&mut cx, |lsp_store, cx| {
10568 let buffers =
10569 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10570 lsp_store.restart_language_servers_for_buffers(
10571 buffers,
10572 envelope
10573 .payload
10574 .only_servers
10575 .into_iter()
10576 .filter_map(|selector| {
10577 Some(match selector.selector? {
10578 proto::language_server_selector::Selector::ServerId(server_id) => {
10579 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10580 }
10581 proto::language_server_selector::Selector::Name(name) => {
10582 LanguageServerSelector::Name(LanguageServerName(
10583 SharedString::from(name),
10584 ))
10585 }
10586 })
10587 })
10588 .collect(),
10589 cx,
10590 );
10591 });
10592
10593 Ok(proto::Ack {})
10594 }
10595
10596 pub async fn handle_stop_language_servers(
10597 lsp_store: Entity<Self>,
10598 envelope: TypedEnvelope<proto::StopLanguageServers>,
10599 mut cx: AsyncApp,
10600 ) -> Result<proto::Ack> {
10601 lsp_store.update(&mut cx, |lsp_store, cx| {
10602 if envelope.payload.all
10603 && envelope.payload.also_servers.is_empty()
10604 && envelope.payload.buffer_ids.is_empty()
10605 {
10606 lsp_store.stop_all_language_servers(cx);
10607 } else {
10608 let buffers =
10609 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10610 lsp_store
10611 .stop_language_servers_for_buffers(
10612 buffers,
10613 envelope
10614 .payload
10615 .also_servers
10616 .into_iter()
10617 .filter_map(|selector| {
10618 Some(match selector.selector? {
10619 proto::language_server_selector::Selector::ServerId(
10620 server_id,
10621 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10622 server_id,
10623 )),
10624 proto::language_server_selector::Selector::Name(name) => {
10625 LanguageServerSelector::Name(LanguageServerName(
10626 SharedString::from(name),
10627 ))
10628 }
10629 })
10630 })
10631 .collect(),
10632 cx,
10633 )
10634 .detach_and_log_err(cx);
10635 }
10636 });
10637
10638 Ok(proto::Ack {})
10639 }
10640
10641 pub async fn handle_cancel_language_server_work(
10642 lsp_store: Entity<Self>,
10643 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10644 mut cx: AsyncApp,
10645 ) -> Result<proto::Ack> {
10646 lsp_store.update(&mut cx, |lsp_store, cx| {
10647 if let Some(work) = envelope.payload.work {
10648 match work {
10649 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10650 let buffers =
10651 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10652 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10653 }
10654 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10655 let server_id = LanguageServerId::from_proto(work.language_server_id);
10656 let token = work
10657 .token
10658 .map(|token| {
10659 ProgressToken::from_proto(token)
10660 .context("invalid work progress token")
10661 })
10662 .transpose()?;
10663 lsp_store.cancel_language_server_work(server_id, token, cx);
10664 }
10665 }
10666 }
10667 anyhow::Ok(())
10668 })?;
10669
10670 Ok(proto::Ack {})
10671 }
10672
10673 fn buffer_ids_to_buffers(
10674 &mut self,
10675 buffer_ids: impl Iterator<Item = u64>,
10676 cx: &mut Context<Self>,
10677 ) -> Vec<Entity<Buffer>> {
10678 buffer_ids
10679 .into_iter()
10680 .flat_map(|buffer_id| {
10681 self.buffer_store
10682 .read(cx)
10683 .get(BufferId::new(buffer_id).log_err()?)
10684 })
10685 .collect::<Vec<_>>()
10686 }
10687
10688 async fn handle_apply_additional_edits_for_completion(
10689 this: Entity<Self>,
10690 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10691 mut cx: AsyncApp,
10692 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10693 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10694 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10695 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10696 let completion = Self::deserialize_completion(
10697 envelope.payload.completion.context("invalid completion")?,
10698 )?;
10699 anyhow::Ok((buffer, completion))
10700 })?;
10701
10702 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10703 this.apply_additional_edits_for_completion(
10704 buffer,
10705 Rc::new(RefCell::new(Box::new([Completion {
10706 replace_range: completion.replace_range,
10707 new_text: completion.new_text,
10708 source: completion.source,
10709 documentation: None,
10710 label: CodeLabel::default(),
10711 match_start: None,
10712 snippet_deduplication_key: None,
10713 insert_text_mode: None,
10714 icon_path: None,
10715 confirm: None,
10716 }]))),
10717 0,
10718 false,
10719 cx,
10720 )
10721 });
10722
10723 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10724 transaction: apply_additional_edits
10725 .await?
10726 .as_ref()
10727 .map(language::proto::serialize_transaction),
10728 })
10729 }
10730
10731 pub fn last_formatting_failure(&self) -> Option<&str> {
10732 self.last_formatting_failure.as_deref()
10733 }
10734
10735 pub fn reset_last_formatting_failure(&mut self) {
10736 self.last_formatting_failure = None;
10737 }
10738
10739 pub fn environment_for_buffer(
10740 &self,
10741 buffer: &Entity<Buffer>,
10742 cx: &mut Context<Self>,
10743 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10744 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10745 environment.update(cx, |env, cx| {
10746 env.buffer_environment(buffer, &self.worktree_store, cx)
10747 })
10748 } else {
10749 Task::ready(None).shared()
10750 }
10751 }
10752
10753 pub fn format(
10754 &mut self,
10755 buffers: HashSet<Entity<Buffer>>,
10756 target: LspFormatTarget,
10757 push_to_history: bool,
10758 trigger: FormatTrigger,
10759 cx: &mut Context<Self>,
10760 ) -> Task<anyhow::Result<ProjectTransaction>> {
10761 let logger = zlog::scoped!("format");
10762 if self.as_local().is_some() {
10763 zlog::trace!(logger => "Formatting locally");
10764 let logger = zlog::scoped!(logger => "local");
10765 let buffers = buffers
10766 .into_iter()
10767 .map(|buffer_handle| {
10768 let buffer = buffer_handle.read(cx);
10769 let buffer_abs_path = File::from_dyn(buffer.file())
10770 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10771
10772 (buffer_handle, buffer_abs_path, buffer.remote_id())
10773 })
10774 .collect::<Vec<_>>();
10775
10776 cx.spawn(async move |lsp_store, cx| {
10777 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10778
10779 for (handle, abs_path, id) in buffers {
10780 let env = lsp_store
10781 .update(cx, |lsp_store, cx| {
10782 lsp_store.environment_for_buffer(&handle, cx)
10783 })?
10784 .await;
10785
10786 let ranges = match &target {
10787 LspFormatTarget::Buffers => None,
10788 LspFormatTarget::Ranges(ranges) => {
10789 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10790 }
10791 };
10792
10793 formattable_buffers.push(FormattableBuffer {
10794 handle,
10795 abs_path,
10796 env,
10797 ranges,
10798 });
10799 }
10800 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10801
10802 let format_timer = zlog::time!(logger => "Formatting buffers");
10803 let result = LocalLspStore::format_locally(
10804 lsp_store.clone(),
10805 formattable_buffers,
10806 push_to_history,
10807 trigger,
10808 logger,
10809 cx,
10810 )
10811 .await;
10812 format_timer.end();
10813
10814 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10815
10816 lsp_store.update(cx, |lsp_store, _| {
10817 lsp_store.update_last_formatting_failure(&result);
10818 })?;
10819
10820 result
10821 })
10822 } else if let Some((client, project_id)) = self.upstream_client() {
10823 zlog::trace!(logger => "Formatting remotely");
10824 let logger = zlog::scoped!(logger => "remote");
10825
10826 let buffer_ranges = match &target {
10827 LspFormatTarget::Buffers => Vec::new(),
10828 LspFormatTarget::Ranges(ranges) => ranges
10829 .iter()
10830 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10831 buffer_id: buffer_id.to_proto(),
10832 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10833 })
10834 .collect(),
10835 };
10836
10837 let buffer_store = self.buffer_store();
10838 cx.spawn(async move |lsp_store, cx| {
10839 zlog::trace!(logger => "Sending remote format request");
10840 let request_timer = zlog::time!(logger => "remote format request");
10841 let result = client
10842 .request(proto::FormatBuffers {
10843 project_id,
10844 trigger: trigger as i32,
10845 buffer_ids: buffers
10846 .iter()
10847 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10848 .collect(),
10849 buffer_ranges,
10850 })
10851 .await
10852 .and_then(|result| result.transaction.context("missing transaction"));
10853 request_timer.end();
10854
10855 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10856
10857 lsp_store.update(cx, |lsp_store, _| {
10858 lsp_store.update_last_formatting_failure(&result);
10859 })?;
10860
10861 let transaction_response = result?;
10862 let _timer = zlog::time!(logger => "deserializing project transaction");
10863 buffer_store
10864 .update(cx, |buffer_store, cx| {
10865 buffer_store.deserialize_project_transaction(
10866 transaction_response,
10867 push_to_history,
10868 cx,
10869 )
10870 })
10871 .await
10872 })
10873 } else {
10874 zlog::trace!(logger => "Not formatting");
10875 Task::ready(Ok(ProjectTransaction::default()))
10876 }
10877 }
10878
10879 async fn handle_format_buffers(
10880 this: Entity<Self>,
10881 envelope: TypedEnvelope<proto::FormatBuffers>,
10882 mut cx: AsyncApp,
10883 ) -> Result<proto::FormatBuffersResponse> {
10884 let sender_id = envelope.original_sender_id().unwrap_or_default();
10885 let format = this.update(&mut cx, |this, cx| {
10886 let mut buffers = HashSet::default();
10887 for buffer_id in &envelope.payload.buffer_ids {
10888 let buffer_id = BufferId::new(*buffer_id)?;
10889 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10890 }
10891
10892 let target = if envelope.payload.buffer_ranges.is_empty() {
10893 LspFormatTarget::Buffers
10894 } else {
10895 let mut ranges_map = BTreeMap::new();
10896 for buffer_range in &envelope.payload.buffer_ranges {
10897 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10898 let ranges: Result<Vec<_>> = buffer_range
10899 .ranges
10900 .iter()
10901 .map(|range| {
10902 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10903 })
10904 .collect();
10905 ranges_map.insert(buffer_id, ranges?);
10906 }
10907 LspFormatTarget::Ranges(ranges_map)
10908 };
10909
10910 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10911 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10912 })?;
10913
10914 let project_transaction = format.await?;
10915 let project_transaction = this.update(&mut cx, |this, cx| {
10916 this.buffer_store.update(cx, |buffer_store, cx| {
10917 buffer_store.serialize_project_transaction_for_peer(
10918 project_transaction,
10919 sender_id,
10920 cx,
10921 )
10922 })
10923 });
10924 Ok(proto::FormatBuffersResponse {
10925 transaction: Some(project_transaction),
10926 })
10927 }
10928
10929 async fn handle_apply_code_action_kind(
10930 this: Entity<Self>,
10931 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10932 mut cx: AsyncApp,
10933 ) -> Result<proto::ApplyCodeActionKindResponse> {
10934 let sender_id = envelope.original_sender_id().unwrap_or_default();
10935 let format = this.update(&mut cx, |this, cx| {
10936 let mut buffers = HashSet::default();
10937 for buffer_id in &envelope.payload.buffer_ids {
10938 let buffer_id = BufferId::new(*buffer_id)?;
10939 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10940 }
10941 let kind = match envelope.payload.kind.as_str() {
10942 "" => CodeActionKind::EMPTY,
10943 "quickfix" => CodeActionKind::QUICKFIX,
10944 "refactor" => CodeActionKind::REFACTOR,
10945 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10946 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10947 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10948 "source" => CodeActionKind::SOURCE,
10949 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10950 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10951 _ => anyhow::bail!(
10952 "Invalid code action kind {}",
10953 envelope.payload.kind.as_str()
10954 ),
10955 };
10956 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10957 })?;
10958
10959 let project_transaction = format.await?;
10960 let project_transaction = this.update(&mut cx, |this, cx| {
10961 this.buffer_store.update(cx, |buffer_store, cx| {
10962 buffer_store.serialize_project_transaction_for_peer(
10963 project_transaction,
10964 sender_id,
10965 cx,
10966 )
10967 })
10968 });
10969 Ok(proto::ApplyCodeActionKindResponse {
10970 transaction: Some(project_transaction),
10971 })
10972 }
10973
10974 async fn shutdown_language_server(
10975 server_state: Option<LanguageServerState>,
10976 name: LanguageServerName,
10977 cx: &mut AsyncApp,
10978 ) {
10979 let server = match server_state {
10980 Some(LanguageServerState::Starting { startup, .. }) => {
10981 let mut timer = cx
10982 .background_executor()
10983 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10984 .fuse();
10985
10986 select! {
10987 server = startup.fuse() => server,
10988 () = timer => {
10989 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10990 None
10991 },
10992 }
10993 }
10994
10995 Some(LanguageServerState::Running { server, .. }) => Some(server),
10996
10997 None => None,
10998 };
10999
11000 if let Some(server) = server
11001 && let Some(shutdown) = server.shutdown()
11002 {
11003 shutdown.await;
11004 }
11005 }
11006
11007 // Returns a list of all of the worktrees which no longer have a language server and the root path
11008 // for the stopped server
11009 fn stop_local_language_server(
11010 &mut self,
11011 server_id: LanguageServerId,
11012 cx: &mut Context<Self>,
11013 ) -> Task<()> {
11014 let local = match &mut self.mode {
11015 LspStoreMode::Local(local) => local,
11016 _ => {
11017 return Task::ready(());
11018 }
11019 };
11020
11021 // Remove this server ID from all entries in the given worktree.
11022 local
11023 .language_server_ids
11024 .retain(|_, state| state.id != server_id);
11025 self.buffer_store.update(cx, |buffer_store, cx| {
11026 for buffer in buffer_store.buffers() {
11027 buffer.update(cx, |buffer, cx| {
11028 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
11029 buffer.set_completion_triggers(server_id, Default::default(), cx);
11030 });
11031 }
11032 });
11033
11034 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
11035 summaries.retain(|path, summaries_by_server_id| {
11036 if summaries_by_server_id.remove(&server_id).is_some() {
11037 if let Some((client, project_id)) = self.downstream_client.clone() {
11038 client
11039 .send(proto::UpdateDiagnosticSummary {
11040 project_id,
11041 worktree_id: worktree_id.to_proto(),
11042 summary: Some(proto::DiagnosticSummary {
11043 path: path.as_ref().to_proto(),
11044 language_server_id: server_id.0 as u64,
11045 error_count: 0,
11046 warning_count: 0,
11047 }),
11048 more_summaries: Vec::new(),
11049 })
11050 .log_err();
11051 }
11052 !summaries_by_server_id.is_empty()
11053 } else {
11054 true
11055 }
11056 });
11057 }
11058
11059 let local = self.as_local_mut().unwrap();
11060 for diagnostics in local.diagnostics.values_mut() {
11061 diagnostics.retain(|_, diagnostics_by_server_id| {
11062 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11063 diagnostics_by_server_id.remove(ix);
11064 !diagnostics_by_server_id.is_empty()
11065 } else {
11066 true
11067 }
11068 });
11069 }
11070 local.language_server_watched_paths.remove(&server_id);
11071
11072 let server_state = local.language_servers.remove(&server_id);
11073 self.cleanup_lsp_data(server_id);
11074 let name = self
11075 .language_server_statuses
11076 .remove(&server_id)
11077 .map(|status| status.name)
11078 .or_else(|| {
11079 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11080 Some(adapter.name())
11081 } else {
11082 None
11083 }
11084 });
11085
11086 if let Some(name) = name {
11087 log::info!("stopping language server {name}");
11088 self.languages
11089 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11090 cx.notify();
11091
11092 return cx.spawn(async move |lsp_store, cx| {
11093 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11094 lsp_store
11095 .update(cx, |lsp_store, cx| {
11096 lsp_store
11097 .languages
11098 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11099 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11100 cx.notify();
11101 })
11102 .ok();
11103 });
11104 }
11105
11106 if server_state.is_some() {
11107 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11108 }
11109 Task::ready(())
11110 }
11111
11112 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11113 self.shutdown_all_language_servers(cx).detach();
11114 }
11115
11116 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11117 if let Some((client, project_id)) = self.upstream_client() {
11118 let request = client.request(proto::StopLanguageServers {
11119 project_id,
11120 buffer_ids: Vec::new(),
11121 also_servers: Vec::new(),
11122 all: true,
11123 });
11124 cx.background_spawn(async move {
11125 request.await.ok();
11126 })
11127 } else {
11128 let Some(local) = self.as_local_mut() else {
11129 return Task::ready(());
11130 };
11131 let language_servers_to_stop = local
11132 .language_server_ids
11133 .values()
11134 .map(|state| state.id)
11135 .collect();
11136 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11137 let tasks = language_servers_to_stop
11138 .into_iter()
11139 .map(|server| self.stop_local_language_server(server, cx))
11140 .collect::<Vec<_>>();
11141 cx.background_spawn(async move {
11142 futures::future::join_all(tasks).await;
11143 })
11144 }
11145 }
11146
11147 pub fn restart_language_servers_for_buffers(
11148 &mut self,
11149 buffers: Vec<Entity<Buffer>>,
11150 only_restart_servers: HashSet<LanguageServerSelector>,
11151 cx: &mut Context<Self>,
11152 ) {
11153 if let Some((client, project_id)) = self.upstream_client() {
11154 let request = client.request(proto::RestartLanguageServers {
11155 project_id,
11156 buffer_ids: buffers
11157 .into_iter()
11158 .map(|b| b.read(cx).remote_id().to_proto())
11159 .collect(),
11160 only_servers: only_restart_servers
11161 .into_iter()
11162 .map(|selector| {
11163 let selector = match selector {
11164 LanguageServerSelector::Id(language_server_id) => {
11165 proto::language_server_selector::Selector::ServerId(
11166 language_server_id.to_proto(),
11167 )
11168 }
11169 LanguageServerSelector::Name(language_server_name) => {
11170 proto::language_server_selector::Selector::Name(
11171 language_server_name.to_string(),
11172 )
11173 }
11174 };
11175 proto::LanguageServerSelector {
11176 selector: Some(selector),
11177 }
11178 })
11179 .collect(),
11180 all: false,
11181 });
11182 cx.background_spawn(request).detach_and_log_err(cx);
11183 } else {
11184 let stop_task = if only_restart_servers.is_empty() {
11185 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11186 } else {
11187 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11188 };
11189 cx.spawn(async move |lsp_store, cx| {
11190 stop_task.await;
11191 lsp_store.update(cx, |lsp_store, cx| {
11192 for buffer in buffers {
11193 lsp_store.register_buffer_with_language_servers(
11194 &buffer,
11195 only_restart_servers.clone(),
11196 true,
11197 cx,
11198 );
11199 }
11200 })
11201 })
11202 .detach();
11203 }
11204 }
11205
11206 pub fn stop_language_servers_for_buffers(
11207 &mut self,
11208 buffers: Vec<Entity<Buffer>>,
11209 also_stop_servers: HashSet<LanguageServerSelector>,
11210 cx: &mut Context<Self>,
11211 ) -> Task<Result<()>> {
11212 if let Some((client, project_id)) = self.upstream_client() {
11213 let request = client.request(proto::StopLanguageServers {
11214 project_id,
11215 buffer_ids: buffers
11216 .into_iter()
11217 .map(|b| b.read(cx).remote_id().to_proto())
11218 .collect(),
11219 also_servers: also_stop_servers
11220 .into_iter()
11221 .map(|selector| {
11222 let selector = match selector {
11223 LanguageServerSelector::Id(language_server_id) => {
11224 proto::language_server_selector::Selector::ServerId(
11225 language_server_id.to_proto(),
11226 )
11227 }
11228 LanguageServerSelector::Name(language_server_name) => {
11229 proto::language_server_selector::Selector::Name(
11230 language_server_name.to_string(),
11231 )
11232 }
11233 };
11234 proto::LanguageServerSelector {
11235 selector: Some(selector),
11236 }
11237 })
11238 .collect(),
11239 all: false,
11240 });
11241 cx.background_spawn(async move {
11242 let _ = request.await?;
11243 Ok(())
11244 })
11245 } else {
11246 let task =
11247 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11248 cx.background_spawn(async move {
11249 task.await;
11250 Ok(())
11251 })
11252 }
11253 }
11254
11255 fn stop_local_language_servers_for_buffers(
11256 &mut self,
11257 buffers: &[Entity<Buffer>],
11258 also_stop_servers: HashSet<LanguageServerSelector>,
11259 cx: &mut Context<Self>,
11260 ) -> Task<()> {
11261 let Some(local) = self.as_local_mut() else {
11262 return Task::ready(());
11263 };
11264 let mut language_server_names_to_stop = BTreeSet::default();
11265 let mut language_servers_to_stop = also_stop_servers
11266 .into_iter()
11267 .flat_map(|selector| match selector {
11268 LanguageServerSelector::Id(id) => Some(id),
11269 LanguageServerSelector::Name(name) => {
11270 language_server_names_to_stop.insert(name);
11271 None
11272 }
11273 })
11274 .collect::<BTreeSet<_>>();
11275
11276 let mut covered_worktrees = HashSet::default();
11277 for buffer in buffers {
11278 buffer.update(cx, |buffer, cx| {
11279 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11280 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11281 && covered_worktrees.insert(worktree_id)
11282 {
11283 language_server_names_to_stop.retain(|name| {
11284 let old_ids_count = language_servers_to_stop.len();
11285 let all_language_servers_with_this_name = local
11286 .language_server_ids
11287 .iter()
11288 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11289 language_servers_to_stop.extend(all_language_servers_with_this_name);
11290 old_ids_count == language_servers_to_stop.len()
11291 });
11292 }
11293 });
11294 }
11295 for name in language_server_names_to_stop {
11296 language_servers_to_stop.extend(
11297 local
11298 .language_server_ids
11299 .iter()
11300 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11301 );
11302 }
11303
11304 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11305 let tasks = language_servers_to_stop
11306 .into_iter()
11307 .map(|server| self.stop_local_language_server(server, cx))
11308 .collect::<Vec<_>>();
11309
11310 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11311 }
11312
11313 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11314 let (worktree, relative_path) =
11315 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11316
11317 let project_path = ProjectPath {
11318 worktree_id: worktree.read(cx).id(),
11319 path: relative_path,
11320 };
11321
11322 Some(
11323 self.buffer_store()
11324 .read(cx)
11325 .get_by_path(&project_path)?
11326 .read(cx),
11327 )
11328 }
11329
11330 #[cfg(any(test, feature = "test-support"))]
11331 pub fn update_diagnostics(
11332 &mut self,
11333 server_id: LanguageServerId,
11334 diagnostics: lsp::PublishDiagnosticsParams,
11335 result_id: Option<SharedString>,
11336 source_kind: DiagnosticSourceKind,
11337 disk_based_sources: &[String],
11338 cx: &mut Context<Self>,
11339 ) -> Result<()> {
11340 self.merge_lsp_diagnostics(
11341 source_kind,
11342 vec![DocumentDiagnosticsUpdate {
11343 diagnostics,
11344 result_id,
11345 server_id,
11346 disk_based_sources: Cow::Borrowed(disk_based_sources),
11347 registration_id: None,
11348 }],
11349 |_, _, _| false,
11350 cx,
11351 )
11352 }
11353
11354 pub fn merge_lsp_diagnostics(
11355 &mut self,
11356 source_kind: DiagnosticSourceKind,
11357 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11358 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11359 cx: &mut Context<Self>,
11360 ) -> Result<()> {
11361 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11362 let updates = lsp_diagnostics
11363 .into_iter()
11364 .filter_map(|update| {
11365 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11366 Some(DocumentDiagnosticsUpdate {
11367 diagnostics: self.lsp_to_document_diagnostics(
11368 abs_path,
11369 source_kind,
11370 update.server_id,
11371 update.diagnostics,
11372 &update.disk_based_sources,
11373 update.registration_id.clone(),
11374 ),
11375 result_id: update.result_id,
11376 server_id: update.server_id,
11377 disk_based_sources: update.disk_based_sources,
11378 registration_id: update.registration_id,
11379 })
11380 })
11381 .collect();
11382 self.merge_diagnostic_entries(updates, merge, cx)?;
11383 Ok(())
11384 }
11385
11386 fn lsp_to_document_diagnostics(
11387 &mut self,
11388 document_abs_path: PathBuf,
11389 source_kind: DiagnosticSourceKind,
11390 server_id: LanguageServerId,
11391 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11392 disk_based_sources: &[String],
11393 registration_id: Option<SharedString>,
11394 ) -> DocumentDiagnostics {
11395 let mut diagnostics = Vec::default();
11396 let mut primary_diagnostic_group_ids = HashMap::default();
11397 let mut sources_by_group_id = HashMap::default();
11398 let mut supporting_diagnostics = HashMap::default();
11399
11400 let adapter = self.language_server_adapter_for_id(server_id);
11401
11402 // Ensure that primary diagnostics are always the most severe
11403 lsp_diagnostics
11404 .diagnostics
11405 .sort_by_key(|item| item.severity);
11406
11407 for diagnostic in &lsp_diagnostics.diagnostics {
11408 let source = diagnostic.source.as_ref();
11409 let range = range_from_lsp(diagnostic.range);
11410 let is_supporting = diagnostic
11411 .related_information
11412 .as_ref()
11413 .is_some_and(|infos| {
11414 infos.iter().any(|info| {
11415 primary_diagnostic_group_ids.contains_key(&(
11416 source,
11417 diagnostic.code.clone(),
11418 range_from_lsp(info.location.range),
11419 ))
11420 })
11421 });
11422
11423 let is_unnecessary = diagnostic
11424 .tags
11425 .as_ref()
11426 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11427
11428 let underline = self
11429 .language_server_adapter_for_id(server_id)
11430 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11431
11432 if is_supporting {
11433 supporting_diagnostics.insert(
11434 (source, diagnostic.code.clone(), range),
11435 (diagnostic.severity, is_unnecessary),
11436 );
11437 } else {
11438 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11439 let is_disk_based =
11440 source.is_some_and(|source| disk_based_sources.contains(source));
11441
11442 sources_by_group_id.insert(group_id, source);
11443 primary_diagnostic_group_ids
11444 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11445
11446 diagnostics.push(DiagnosticEntry {
11447 range,
11448 diagnostic: Diagnostic {
11449 source: diagnostic.source.clone(),
11450 source_kind,
11451 code: diagnostic.code.clone(),
11452 code_description: diagnostic
11453 .code_description
11454 .as_ref()
11455 .and_then(|d| d.href.clone()),
11456 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11457 markdown: adapter.as_ref().and_then(|adapter| {
11458 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11459 }),
11460 message: diagnostic.message.trim().to_string(),
11461 group_id,
11462 is_primary: true,
11463 is_disk_based,
11464 is_unnecessary,
11465 underline,
11466 data: diagnostic.data.clone(),
11467 registration_id: registration_id.clone(),
11468 },
11469 });
11470 if let Some(infos) = &diagnostic.related_information {
11471 for info in infos {
11472 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11473 let range = range_from_lsp(info.location.range);
11474 diagnostics.push(DiagnosticEntry {
11475 range,
11476 diagnostic: Diagnostic {
11477 source: diagnostic.source.clone(),
11478 source_kind,
11479 code: diagnostic.code.clone(),
11480 code_description: diagnostic
11481 .code_description
11482 .as_ref()
11483 .and_then(|d| d.href.clone()),
11484 severity: DiagnosticSeverity::INFORMATION,
11485 markdown: adapter.as_ref().and_then(|adapter| {
11486 adapter.diagnostic_message_to_markdown(&info.message)
11487 }),
11488 message: info.message.trim().to_string(),
11489 group_id,
11490 is_primary: false,
11491 is_disk_based,
11492 is_unnecessary: false,
11493 underline,
11494 data: diagnostic.data.clone(),
11495 registration_id: registration_id.clone(),
11496 },
11497 });
11498 }
11499 }
11500 }
11501 }
11502 }
11503
11504 for entry in &mut diagnostics {
11505 let diagnostic = &mut entry.diagnostic;
11506 if !diagnostic.is_primary {
11507 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11508 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11509 source,
11510 diagnostic.code.clone(),
11511 entry.range.clone(),
11512 )) {
11513 if let Some(severity) = severity {
11514 diagnostic.severity = severity;
11515 }
11516 diagnostic.is_unnecessary = is_unnecessary;
11517 }
11518 }
11519 }
11520
11521 DocumentDiagnostics {
11522 diagnostics,
11523 document_abs_path,
11524 version: lsp_diagnostics.version,
11525 }
11526 }
11527
11528 fn insert_newly_running_language_server(
11529 &mut self,
11530 adapter: Arc<CachedLspAdapter>,
11531 language_server: Arc<LanguageServer>,
11532 server_id: LanguageServerId,
11533 key: LanguageServerSeed,
11534 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11535 cx: &mut Context<Self>,
11536 ) {
11537 let Some(local) = self.as_local_mut() else {
11538 return;
11539 };
11540 // If the language server for this key doesn't match the server id, don't store the
11541 // server. Which will cause it to be dropped, killing the process
11542 if local
11543 .language_server_ids
11544 .get(&key)
11545 .map(|state| state.id != server_id)
11546 .unwrap_or(false)
11547 {
11548 return;
11549 }
11550
11551 // Update language_servers collection with Running variant of LanguageServerState
11552 // indicating that the server is up and running and ready
11553 let workspace_folders = workspace_folders.lock().clone();
11554 language_server.set_workspace_folders(workspace_folders);
11555
11556 let workspace_diagnostics_refresh_tasks = language_server
11557 .capabilities()
11558 .diagnostic_provider
11559 .and_then(|provider| {
11560 local
11561 .language_server_dynamic_registrations
11562 .entry(server_id)
11563 .or_default()
11564 .diagnostics
11565 .entry(None)
11566 .or_insert(provider.clone());
11567 let workspace_refresher =
11568 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11569
11570 Some((None, workspace_refresher))
11571 })
11572 .into_iter()
11573 .collect();
11574 local.language_servers.insert(
11575 server_id,
11576 LanguageServerState::Running {
11577 workspace_diagnostics_refresh_tasks,
11578 adapter: adapter.clone(),
11579 server: language_server.clone(),
11580 simulate_disk_based_diagnostics_completion: None,
11581 },
11582 );
11583 local
11584 .languages
11585 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11586 if let Some(file_ops_caps) = language_server
11587 .capabilities()
11588 .workspace
11589 .as_ref()
11590 .and_then(|ws| ws.file_operations.as_ref())
11591 {
11592 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11593 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11594 if did_rename_caps.or(will_rename_caps).is_some() {
11595 let watcher = RenamePathsWatchedForServer::default()
11596 .with_did_rename_patterns(did_rename_caps)
11597 .with_will_rename_patterns(will_rename_caps);
11598 local
11599 .language_server_paths_watched_for_rename
11600 .insert(server_id, watcher);
11601 }
11602 }
11603
11604 self.language_server_statuses.insert(
11605 server_id,
11606 LanguageServerStatus {
11607 name: language_server.name(),
11608 server_version: language_server.version(),
11609 pending_work: Default::default(),
11610 has_pending_diagnostic_updates: false,
11611 progress_tokens: Default::default(),
11612 worktree: Some(key.worktree_id),
11613 binary: Some(language_server.binary().clone()),
11614 configuration: Some(language_server.configuration().clone()),
11615 workspace_folders: language_server.workspace_folders(),
11616 process_id: language_server.process_id(),
11617 },
11618 );
11619
11620 cx.emit(LspStoreEvent::LanguageServerAdded(
11621 server_id,
11622 language_server.name(),
11623 Some(key.worktree_id),
11624 ));
11625
11626 let server_capabilities = language_server.capabilities();
11627 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11628 downstream_client
11629 .send(proto::StartLanguageServer {
11630 project_id: *project_id,
11631 server: Some(proto::LanguageServer {
11632 id: server_id.to_proto(),
11633 name: language_server.name().to_string(),
11634 worktree_id: Some(key.worktree_id.to_proto()),
11635 }),
11636 capabilities: serde_json::to_string(&server_capabilities)
11637 .expect("serializing server LSP capabilities"),
11638 })
11639 .log_err();
11640 }
11641 self.lsp_server_capabilities
11642 .insert(server_id, server_capabilities);
11643
11644 // Tell the language server about every open buffer in the worktree that matches the language.
11645 // Also check for buffers in worktrees that reused this server
11646 let mut worktrees_using_server = vec![key.worktree_id];
11647 if let Some(local) = self.as_local() {
11648 // Find all worktrees that have this server in their language server tree
11649 for (worktree_id, servers) in &local.lsp_tree.instances {
11650 if *worktree_id != key.worktree_id {
11651 for server_map in servers.roots.values() {
11652 if server_map
11653 .values()
11654 .any(|(node, _)| node.id() == Some(server_id))
11655 {
11656 worktrees_using_server.push(*worktree_id);
11657 }
11658 }
11659 }
11660 }
11661 }
11662
11663 let mut buffer_paths_registered = Vec::new();
11664 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11665 let mut lsp_adapters = HashMap::default();
11666 for buffer_handle in buffer_store.buffers() {
11667 let buffer = buffer_handle.read(cx);
11668 let file = match File::from_dyn(buffer.file()) {
11669 Some(file) => file,
11670 None => continue,
11671 };
11672 let language = match buffer.language() {
11673 Some(language) => language,
11674 None => continue,
11675 };
11676
11677 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11678 || !lsp_adapters
11679 .entry(language.name())
11680 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11681 .iter()
11682 .any(|a| a.name == key.name)
11683 {
11684 continue;
11685 }
11686 // didOpen
11687 let file = match file.as_local() {
11688 Some(file) => file,
11689 None => continue,
11690 };
11691
11692 let local = self.as_local_mut().unwrap();
11693
11694 let buffer_id = buffer.remote_id();
11695 if local.registered_buffers.contains_key(&buffer_id) {
11696 let versions = local
11697 .buffer_snapshots
11698 .entry(buffer_id)
11699 .or_default()
11700 .entry(server_id)
11701 .and_modify(|_| {
11702 assert!(
11703 false,
11704 "There should not be an existing snapshot for a newly inserted buffer"
11705 )
11706 })
11707 .or_insert_with(|| {
11708 vec![LspBufferSnapshot {
11709 version: 0,
11710 snapshot: buffer.text_snapshot(),
11711 }]
11712 });
11713
11714 let snapshot = versions.last().unwrap();
11715 let version = snapshot.version;
11716 let initial_snapshot = &snapshot.snapshot;
11717 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11718 language_server.register_buffer(
11719 uri,
11720 adapter.language_id(&language.name()),
11721 version,
11722 initial_snapshot.text(),
11723 );
11724 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11725 local
11726 .buffers_opened_in_servers
11727 .entry(buffer_id)
11728 .or_default()
11729 .insert(server_id);
11730 }
11731 buffer_handle.update(cx, |buffer, cx| {
11732 buffer.set_completion_triggers(
11733 server_id,
11734 language_server
11735 .capabilities()
11736 .completion_provider
11737 .as_ref()
11738 .and_then(|provider| {
11739 provider
11740 .trigger_characters
11741 .as_ref()
11742 .map(|characters| characters.iter().cloned().collect())
11743 })
11744 .unwrap_or_default(),
11745 cx,
11746 )
11747 });
11748 }
11749 });
11750
11751 for (buffer_id, abs_path) in buffer_paths_registered {
11752 cx.emit(LspStoreEvent::LanguageServerUpdate {
11753 language_server_id: server_id,
11754 name: Some(adapter.name()),
11755 message: proto::update_language_server::Variant::RegisteredForBuffer(
11756 proto::RegisteredForBuffer {
11757 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11758 buffer_id: buffer_id.to_proto(),
11759 },
11760 ),
11761 });
11762 }
11763
11764 cx.notify();
11765 }
11766
11767 pub fn language_servers_running_disk_based_diagnostics(
11768 &self,
11769 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11770 self.language_server_statuses
11771 .iter()
11772 .filter_map(|(id, status)| {
11773 if status.has_pending_diagnostic_updates {
11774 Some(*id)
11775 } else {
11776 None
11777 }
11778 })
11779 }
11780
11781 pub(crate) fn cancel_language_server_work_for_buffers(
11782 &mut self,
11783 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11784 cx: &mut Context<Self>,
11785 ) {
11786 if let Some((client, project_id)) = self.upstream_client() {
11787 let request = client.request(proto::CancelLanguageServerWork {
11788 project_id,
11789 work: Some(proto::cancel_language_server_work::Work::Buffers(
11790 proto::cancel_language_server_work::Buffers {
11791 buffer_ids: buffers
11792 .into_iter()
11793 .map(|b| b.read(cx).remote_id().to_proto())
11794 .collect(),
11795 },
11796 )),
11797 });
11798 cx.background_spawn(request).detach_and_log_err(cx);
11799 } else if let Some(local) = self.as_local() {
11800 let servers = buffers
11801 .into_iter()
11802 .flat_map(|buffer| {
11803 buffer.update(cx, |buffer, cx| {
11804 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11805 })
11806 })
11807 .collect::<HashSet<_>>();
11808 for server_id in servers {
11809 self.cancel_language_server_work(server_id, None, cx);
11810 }
11811 }
11812 }
11813
11814 pub(crate) fn cancel_language_server_work(
11815 &mut self,
11816 server_id: LanguageServerId,
11817 token_to_cancel: Option<ProgressToken>,
11818 cx: &mut Context<Self>,
11819 ) {
11820 if let Some(local) = self.as_local() {
11821 let status = self.language_server_statuses.get(&server_id);
11822 let server = local.language_servers.get(&server_id);
11823 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11824 {
11825 for (token, progress) in &status.pending_work {
11826 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11827 && token != token_to_cancel
11828 {
11829 continue;
11830 }
11831 if progress.is_cancellable {
11832 server
11833 .notify::<lsp::notification::WorkDoneProgressCancel>(
11834 WorkDoneProgressCancelParams {
11835 token: token.to_lsp(),
11836 },
11837 )
11838 .ok();
11839 }
11840 }
11841 }
11842 } else if let Some((client, project_id)) = self.upstream_client() {
11843 let request = client.request(proto::CancelLanguageServerWork {
11844 project_id,
11845 work: Some(
11846 proto::cancel_language_server_work::Work::LanguageServerWork(
11847 proto::cancel_language_server_work::LanguageServerWork {
11848 language_server_id: server_id.to_proto(),
11849 token: token_to_cancel.map(|token| token.to_proto()),
11850 },
11851 ),
11852 ),
11853 });
11854 cx.background_spawn(request).detach_and_log_err(cx);
11855 }
11856 }
11857
11858 fn register_supplementary_language_server(
11859 &mut self,
11860 id: LanguageServerId,
11861 name: LanguageServerName,
11862 server: Arc<LanguageServer>,
11863 cx: &mut Context<Self>,
11864 ) {
11865 if let Some(local) = self.as_local_mut() {
11866 local
11867 .supplementary_language_servers
11868 .insert(id, (name.clone(), server));
11869 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11870 }
11871 }
11872
11873 fn unregister_supplementary_language_server(
11874 &mut self,
11875 id: LanguageServerId,
11876 cx: &mut Context<Self>,
11877 ) {
11878 if let Some(local) = self.as_local_mut() {
11879 local.supplementary_language_servers.remove(&id);
11880 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11881 }
11882 }
11883
11884 pub(crate) fn supplementary_language_servers(
11885 &self,
11886 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11887 self.as_local().into_iter().flat_map(|local| {
11888 local
11889 .supplementary_language_servers
11890 .iter()
11891 .map(|(id, (name, _))| (*id, name.clone()))
11892 })
11893 }
11894
11895 pub fn language_server_adapter_for_id(
11896 &self,
11897 id: LanguageServerId,
11898 ) -> Option<Arc<CachedLspAdapter>> {
11899 self.as_local()
11900 .and_then(|local| local.language_servers.get(&id))
11901 .and_then(|language_server_state| match language_server_state {
11902 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11903 _ => None,
11904 })
11905 }
11906
11907 pub(super) fn update_local_worktree_language_servers(
11908 &mut self,
11909 worktree_handle: &Entity<Worktree>,
11910 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11911 cx: &mut Context<Self>,
11912 ) {
11913 if changes.is_empty() {
11914 return;
11915 }
11916
11917 let Some(local) = self.as_local() else { return };
11918
11919 local.prettier_store.update(cx, |prettier_store, cx| {
11920 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11921 });
11922
11923 let worktree_id = worktree_handle.read(cx).id();
11924 let mut language_server_ids = local
11925 .language_server_ids
11926 .iter()
11927 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11928 .collect::<Vec<_>>();
11929 language_server_ids.sort();
11930 language_server_ids.dedup();
11931
11932 // let abs_path = worktree_handle.read(cx).abs_path();
11933 for server_id in &language_server_ids {
11934 if let Some(LanguageServerState::Running { server, .. }) =
11935 local.language_servers.get(server_id)
11936 && let Some(watched_paths) = local
11937 .language_server_watched_paths
11938 .get(server_id)
11939 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11940 {
11941 let params = lsp::DidChangeWatchedFilesParams {
11942 changes: changes
11943 .iter()
11944 .filter_map(|(path, _, change)| {
11945 if !watched_paths.is_match(path.as_std_path()) {
11946 return None;
11947 }
11948 let typ = match change {
11949 PathChange::Loaded => return None,
11950 PathChange::Added => lsp::FileChangeType::CREATED,
11951 PathChange::Removed => lsp::FileChangeType::DELETED,
11952 PathChange::Updated => lsp::FileChangeType::CHANGED,
11953 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11954 };
11955 let uri = lsp::Uri::from_file_path(
11956 worktree_handle.read(cx).absolutize(&path),
11957 )
11958 .ok()?;
11959 Some(lsp::FileEvent { uri, typ })
11960 })
11961 .collect(),
11962 };
11963 if !params.changes.is_empty() {
11964 server
11965 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11966 .ok();
11967 }
11968 }
11969 }
11970 for (path, _, _) in changes {
11971 if let Some(file_name) = path.file_name()
11972 && local.watched_manifest_filenames.contains(file_name)
11973 {
11974 self.request_workspace_config_refresh();
11975 break;
11976 }
11977 }
11978 }
11979
11980 pub fn wait_for_remote_buffer(
11981 &mut self,
11982 id: BufferId,
11983 cx: &mut Context<Self>,
11984 ) -> Task<Result<Entity<Buffer>>> {
11985 self.buffer_store.update(cx, |buffer_store, cx| {
11986 buffer_store.wait_for_remote_buffer(id, cx)
11987 })
11988 }
11989
11990 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11991 let mut result = proto::Symbol {
11992 language_server_name: symbol.language_server_name.0.to_string(),
11993 source_worktree_id: symbol.source_worktree_id.to_proto(),
11994 language_server_id: symbol.source_language_server_id.to_proto(),
11995 name: symbol.name.clone(),
11996 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11997 start: Some(proto::PointUtf16 {
11998 row: symbol.range.start.0.row,
11999 column: symbol.range.start.0.column,
12000 }),
12001 end: Some(proto::PointUtf16 {
12002 row: symbol.range.end.0.row,
12003 column: symbol.range.end.0.column,
12004 }),
12005 worktree_id: Default::default(),
12006 path: Default::default(),
12007 signature: Default::default(),
12008 };
12009 match &symbol.path {
12010 SymbolLocation::InProject(path) => {
12011 result.worktree_id = path.worktree_id.to_proto();
12012 result.path = path.path.to_proto();
12013 }
12014 SymbolLocation::OutsideProject {
12015 abs_path,
12016 signature,
12017 } => {
12018 result.path = abs_path.to_string_lossy().into_owned();
12019 result.signature = signature.to_vec();
12020 }
12021 }
12022 result
12023 }
12024
12025 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
12026 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
12027 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
12028 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
12029
12030 let path = if serialized_symbol.signature.is_empty() {
12031 SymbolLocation::InProject(ProjectPath {
12032 worktree_id,
12033 path: RelPath::from_proto(&serialized_symbol.path)
12034 .context("invalid symbol path")?,
12035 })
12036 } else {
12037 SymbolLocation::OutsideProject {
12038 abs_path: Path::new(&serialized_symbol.path).into(),
12039 signature: serialized_symbol
12040 .signature
12041 .try_into()
12042 .map_err(|_| anyhow!("invalid signature"))?,
12043 }
12044 };
12045
12046 let start = serialized_symbol.start.context("invalid start")?;
12047 let end = serialized_symbol.end.context("invalid end")?;
12048 Ok(CoreSymbol {
12049 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
12050 source_worktree_id,
12051 source_language_server_id: LanguageServerId::from_proto(
12052 serialized_symbol.language_server_id,
12053 ),
12054 path,
12055 name: serialized_symbol.name,
12056 range: Unclipped(PointUtf16::new(start.row, start.column))
12057 ..Unclipped(PointUtf16::new(end.row, end.column)),
12058 kind,
12059 })
12060 }
12061
12062 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12063 let mut serialized_completion = proto::Completion {
12064 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12065 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12066 new_text: completion.new_text.clone(),
12067 ..proto::Completion::default()
12068 };
12069 match &completion.source {
12070 CompletionSource::Lsp {
12071 insert_range,
12072 server_id,
12073 lsp_completion,
12074 lsp_defaults,
12075 resolved,
12076 } => {
12077 let (old_insert_start, old_insert_end) = insert_range
12078 .as_ref()
12079 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12080 .unzip();
12081
12082 serialized_completion.old_insert_start = old_insert_start;
12083 serialized_completion.old_insert_end = old_insert_end;
12084 serialized_completion.source = proto::completion::Source::Lsp as i32;
12085 serialized_completion.server_id = server_id.0 as u64;
12086 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12087 serialized_completion.lsp_defaults = lsp_defaults
12088 .as_deref()
12089 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12090 serialized_completion.resolved = *resolved;
12091 }
12092 CompletionSource::BufferWord {
12093 word_range,
12094 resolved,
12095 } => {
12096 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12097 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12098 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12099 serialized_completion.resolved = *resolved;
12100 }
12101 CompletionSource::Custom => {
12102 serialized_completion.source = proto::completion::Source::Custom as i32;
12103 serialized_completion.resolved = true;
12104 }
12105 CompletionSource::Dap { sort_text } => {
12106 serialized_completion.source = proto::completion::Source::Dap as i32;
12107 serialized_completion.sort_text = Some(sort_text.clone());
12108 }
12109 }
12110
12111 serialized_completion
12112 }
12113
12114 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12115 let old_replace_start = completion
12116 .old_replace_start
12117 .and_then(deserialize_anchor)
12118 .context("invalid old start")?;
12119 let old_replace_end = completion
12120 .old_replace_end
12121 .and_then(deserialize_anchor)
12122 .context("invalid old end")?;
12123 let insert_range = {
12124 match completion.old_insert_start.zip(completion.old_insert_end) {
12125 Some((start, end)) => {
12126 let start = deserialize_anchor(start).context("invalid insert old start")?;
12127 let end = deserialize_anchor(end).context("invalid insert old end")?;
12128 Some(start..end)
12129 }
12130 None => None,
12131 }
12132 };
12133 Ok(CoreCompletion {
12134 replace_range: old_replace_start..old_replace_end,
12135 new_text: completion.new_text,
12136 source: match proto::completion::Source::from_i32(completion.source) {
12137 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12138 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12139 insert_range,
12140 server_id: LanguageServerId::from_proto(completion.server_id),
12141 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12142 lsp_defaults: completion
12143 .lsp_defaults
12144 .as_deref()
12145 .map(serde_json::from_slice)
12146 .transpose()?,
12147 resolved: completion.resolved,
12148 },
12149 Some(proto::completion::Source::BufferWord) => {
12150 let word_range = completion
12151 .buffer_word_start
12152 .and_then(deserialize_anchor)
12153 .context("invalid buffer word start")?
12154 ..completion
12155 .buffer_word_end
12156 .and_then(deserialize_anchor)
12157 .context("invalid buffer word end")?;
12158 CompletionSource::BufferWord {
12159 word_range,
12160 resolved: completion.resolved,
12161 }
12162 }
12163 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12164 sort_text: completion
12165 .sort_text
12166 .context("expected sort text to exist")?,
12167 },
12168 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12169 },
12170 })
12171 }
12172
12173 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12174 let (kind, lsp_action) = match &action.lsp_action {
12175 LspAction::Action(code_action) => (
12176 proto::code_action::Kind::Action as i32,
12177 serde_json::to_vec(code_action).unwrap(),
12178 ),
12179 LspAction::Command(command) => (
12180 proto::code_action::Kind::Command as i32,
12181 serde_json::to_vec(command).unwrap(),
12182 ),
12183 LspAction::CodeLens(code_lens) => (
12184 proto::code_action::Kind::CodeLens as i32,
12185 serde_json::to_vec(code_lens).unwrap(),
12186 ),
12187 };
12188
12189 proto::CodeAction {
12190 server_id: action.server_id.0 as u64,
12191 start: Some(serialize_anchor(&action.range.start)),
12192 end: Some(serialize_anchor(&action.range.end)),
12193 lsp_action,
12194 kind,
12195 resolved: action.resolved,
12196 }
12197 }
12198
12199 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12200 let start = action
12201 .start
12202 .and_then(deserialize_anchor)
12203 .context("invalid start")?;
12204 let end = action
12205 .end
12206 .and_then(deserialize_anchor)
12207 .context("invalid end")?;
12208 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12209 Some(proto::code_action::Kind::Action) => {
12210 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12211 }
12212 Some(proto::code_action::Kind::Command) => {
12213 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12214 }
12215 Some(proto::code_action::Kind::CodeLens) => {
12216 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12217 }
12218 None => anyhow::bail!("Unknown action kind {}", action.kind),
12219 };
12220 Ok(CodeAction {
12221 server_id: LanguageServerId(action.server_id as usize),
12222 range: start..end,
12223 resolved: action.resolved,
12224 lsp_action,
12225 })
12226 }
12227
12228 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12229 match &formatting_result {
12230 Ok(_) => self.last_formatting_failure = None,
12231 Err(error) => {
12232 let error_string = format!("{error:#}");
12233 log::error!("Formatting failed: {error_string}");
12234 self.last_formatting_failure
12235 .replace(error_string.lines().join(" "));
12236 }
12237 }
12238 }
12239
12240 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12241 self.lsp_server_capabilities.remove(&for_server);
12242 for lsp_data in self.lsp_data.values_mut() {
12243 lsp_data.remove_server_data(for_server);
12244 }
12245 if let Some(local) = self.as_local_mut() {
12246 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12247 local
12248 .workspace_pull_diagnostics_result_ids
12249 .remove(&for_server);
12250 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12251 buffer_servers.remove(&for_server);
12252 }
12253 }
12254 }
12255
12256 pub fn result_id_for_buffer_pull(
12257 &self,
12258 server_id: LanguageServerId,
12259 buffer_id: BufferId,
12260 registration_id: &Option<SharedString>,
12261 cx: &App,
12262 ) -> Option<SharedString> {
12263 let abs_path = self
12264 .buffer_store
12265 .read(cx)
12266 .get(buffer_id)
12267 .and_then(|b| File::from_dyn(b.read(cx).file()))
12268 .map(|f| f.abs_path(cx))?;
12269 self.as_local()?
12270 .buffer_pull_diagnostics_result_ids
12271 .get(&server_id)?
12272 .get(registration_id)?
12273 .get(&abs_path)?
12274 .clone()
12275 }
12276
12277 /// Gets all result_ids for a workspace diagnostics pull request.
12278 /// 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.
12279 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12280 pub fn result_ids_for_workspace_refresh(
12281 &self,
12282 server_id: LanguageServerId,
12283 registration_id: &Option<SharedString>,
12284 ) -> HashMap<PathBuf, SharedString> {
12285 let Some(local) = self.as_local() else {
12286 return HashMap::default();
12287 };
12288 local
12289 .workspace_pull_diagnostics_result_ids
12290 .get(&server_id)
12291 .into_iter()
12292 .filter_map(|diagnostics| diagnostics.get(registration_id))
12293 .flatten()
12294 .filter_map(|(abs_path, result_id)| {
12295 let result_id = local
12296 .buffer_pull_diagnostics_result_ids
12297 .get(&server_id)
12298 .and_then(|buffer_ids_result_ids| {
12299 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12300 })
12301 .cloned()
12302 .flatten()
12303 .or_else(|| result_id.clone())?;
12304 Some((abs_path.clone(), result_id))
12305 })
12306 .collect()
12307 }
12308
12309 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12310 if let Some(LanguageServerState::Running {
12311 workspace_diagnostics_refresh_tasks,
12312 ..
12313 }) = self
12314 .as_local_mut()
12315 .and_then(|local| local.language_servers.get_mut(&server_id))
12316 {
12317 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12318 diagnostics.refresh_tx.try_send(()).ok();
12319 }
12320 }
12321 }
12322
12323 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12324 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12325 /// which requires refreshing both workspace and document diagnostics.
12326 pub fn pull_document_diagnostics_for_server(
12327 &mut self,
12328 server_id: LanguageServerId,
12329 source_buffer_id: Option<BufferId>,
12330 cx: &mut Context<Self>,
12331 ) -> Shared<Task<()>> {
12332 let Some(local) = self.as_local_mut() else {
12333 return Task::ready(()).shared();
12334 };
12335 let mut buffers_to_refresh = HashSet::default();
12336 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12337 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12338 buffers_to_refresh.insert(*buffer_id);
12339 }
12340 }
12341
12342 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12343 }
12344
12345 pub fn pull_document_diagnostics_for_buffer_edit(
12346 &mut self,
12347 buffer_id: BufferId,
12348 cx: &mut Context<Self>,
12349 ) {
12350 let Some(local) = self.as_local_mut() else {
12351 return;
12352 };
12353 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12354 else {
12355 return;
12356 };
12357 for server_id in languages_servers {
12358 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12359 }
12360 }
12361
12362 fn apply_workspace_diagnostic_report(
12363 &mut self,
12364 server_id: LanguageServerId,
12365 report: lsp::WorkspaceDiagnosticReportResult,
12366 registration_id: Option<SharedString>,
12367 cx: &mut Context<Self>,
12368 ) {
12369 let mut workspace_diagnostics =
12370 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12371 report,
12372 server_id,
12373 registration_id,
12374 );
12375 workspace_diagnostics.retain(|d| match &d.diagnostics {
12376 LspPullDiagnostics::Response {
12377 server_id,
12378 registration_id,
12379 ..
12380 } => self.diagnostic_registration_exists(*server_id, registration_id),
12381 LspPullDiagnostics::Default => false,
12382 });
12383 let mut unchanged_buffers = HashMap::default();
12384 let workspace_diagnostics_updates = workspace_diagnostics
12385 .into_iter()
12386 .filter_map(
12387 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12388 LspPullDiagnostics::Response {
12389 server_id,
12390 uri,
12391 diagnostics,
12392 registration_id,
12393 } => Some((
12394 server_id,
12395 uri,
12396 diagnostics,
12397 workspace_diagnostics.version,
12398 registration_id,
12399 )),
12400 LspPullDiagnostics::Default => None,
12401 },
12402 )
12403 .fold(
12404 HashMap::default(),
12405 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12406 let (result_id, diagnostics) = match diagnostics {
12407 PulledDiagnostics::Unchanged { result_id } => {
12408 unchanged_buffers
12409 .entry(new_registration_id.clone())
12410 .or_insert_with(HashSet::default)
12411 .insert(uri.clone());
12412 (Some(result_id), Vec::new())
12413 }
12414 PulledDiagnostics::Changed {
12415 result_id,
12416 diagnostics,
12417 } => (result_id, diagnostics),
12418 };
12419 let disk_based_sources = Cow::Owned(
12420 self.language_server_adapter_for_id(server_id)
12421 .as_ref()
12422 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12423 .unwrap_or(&[])
12424 .to_vec(),
12425 );
12426
12427 let Some(abs_path) = uri.to_file_path().ok() else {
12428 return acc;
12429 };
12430 let Some((worktree, relative_path)) =
12431 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12432 else {
12433 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12434 return acc;
12435 };
12436 let worktree_id = worktree.read(cx).id();
12437 let project_path = ProjectPath {
12438 worktree_id,
12439 path: relative_path,
12440 };
12441 if let Some(local_lsp_store) = self.as_local_mut() {
12442 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12443 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12444 }
12445 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12446 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12447 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12448 acc.entry(server_id)
12449 .or_insert_with(HashMap::default)
12450 .entry(new_registration_id.clone())
12451 .or_insert_with(Vec::new)
12452 .push(DocumentDiagnosticsUpdate {
12453 server_id,
12454 diagnostics: lsp::PublishDiagnosticsParams {
12455 uri,
12456 diagnostics,
12457 version,
12458 },
12459 result_id,
12460 disk_based_sources,
12461 registration_id: new_registration_id,
12462 });
12463 }
12464 acc
12465 },
12466 );
12467
12468 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12469 for (registration_id, diagnostic_updates) in diagnostic_updates {
12470 self.merge_lsp_diagnostics(
12471 DiagnosticSourceKind::Pulled,
12472 diagnostic_updates,
12473 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12474 DiagnosticSourceKind::Pulled => {
12475 old_diagnostic.registration_id != registration_id
12476 || unchanged_buffers
12477 .get(&old_diagnostic.registration_id)
12478 .is_some_and(|unchanged_buffers| {
12479 unchanged_buffers.contains(&document_uri)
12480 })
12481 }
12482 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12483 },
12484 cx,
12485 )
12486 .log_err();
12487 }
12488 }
12489 }
12490
12491 fn register_server_capabilities(
12492 &mut self,
12493 server_id: LanguageServerId,
12494 params: lsp::RegistrationParams,
12495 cx: &mut Context<Self>,
12496 ) -> anyhow::Result<()> {
12497 let server = self
12498 .language_server_for_id(server_id)
12499 .with_context(|| format!("no server {server_id} found"))?;
12500 for reg in params.registrations {
12501 match reg.method.as_str() {
12502 "workspace/didChangeWatchedFiles" => {
12503 if let Some(options) = reg.register_options {
12504 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12505 let caps = serde_json::from_value(options)?;
12506 local_lsp_store
12507 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12508 true
12509 } else {
12510 false
12511 };
12512 if notify {
12513 notify_server_capabilities_updated(&server, cx);
12514 }
12515 }
12516 }
12517 "workspace/didChangeConfiguration" => {
12518 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12519 }
12520 "workspace/didChangeWorkspaceFolders" => {
12521 // In this case register options is an empty object, we can ignore it
12522 let caps = lsp::WorkspaceFoldersServerCapabilities {
12523 supported: Some(true),
12524 change_notifications: Some(OneOf::Right(reg.id)),
12525 };
12526 server.update_capabilities(|capabilities| {
12527 capabilities
12528 .workspace
12529 .get_or_insert_default()
12530 .workspace_folders = Some(caps);
12531 });
12532 notify_server_capabilities_updated(&server, cx);
12533 }
12534 "workspace/symbol" => {
12535 let options = parse_register_capabilities(reg)?;
12536 server.update_capabilities(|capabilities| {
12537 capabilities.workspace_symbol_provider = Some(options);
12538 });
12539 notify_server_capabilities_updated(&server, cx);
12540 }
12541 "workspace/fileOperations" => {
12542 if let Some(options) = reg.register_options {
12543 let caps = serde_json::from_value(options)?;
12544 server.update_capabilities(|capabilities| {
12545 capabilities
12546 .workspace
12547 .get_or_insert_default()
12548 .file_operations = Some(caps);
12549 });
12550 notify_server_capabilities_updated(&server, cx);
12551 }
12552 }
12553 "workspace/executeCommand" => {
12554 if let Some(options) = reg.register_options {
12555 let options = serde_json::from_value(options)?;
12556 server.update_capabilities(|capabilities| {
12557 capabilities.execute_command_provider = Some(options);
12558 });
12559 notify_server_capabilities_updated(&server, cx);
12560 }
12561 }
12562 "textDocument/rangeFormatting" => {
12563 let options = parse_register_capabilities(reg)?;
12564 server.update_capabilities(|capabilities| {
12565 capabilities.document_range_formatting_provider = Some(options);
12566 });
12567 notify_server_capabilities_updated(&server, cx);
12568 }
12569 "textDocument/onTypeFormatting" => {
12570 if let Some(options) = reg
12571 .register_options
12572 .map(serde_json::from_value)
12573 .transpose()?
12574 {
12575 server.update_capabilities(|capabilities| {
12576 capabilities.document_on_type_formatting_provider = Some(options);
12577 });
12578 notify_server_capabilities_updated(&server, cx);
12579 }
12580 }
12581 "textDocument/formatting" => {
12582 let options = parse_register_capabilities(reg)?;
12583 server.update_capabilities(|capabilities| {
12584 capabilities.document_formatting_provider = Some(options);
12585 });
12586 notify_server_capabilities_updated(&server, cx);
12587 }
12588 "textDocument/rename" => {
12589 let options = parse_register_capabilities(reg)?;
12590 server.update_capabilities(|capabilities| {
12591 capabilities.rename_provider = Some(options);
12592 });
12593 notify_server_capabilities_updated(&server, cx);
12594 }
12595 "textDocument/inlayHint" => {
12596 let options = parse_register_capabilities(reg)?;
12597 server.update_capabilities(|capabilities| {
12598 capabilities.inlay_hint_provider = Some(options);
12599 });
12600 notify_server_capabilities_updated(&server, cx);
12601 }
12602 "textDocument/documentSymbol" => {
12603 let options = parse_register_capabilities(reg)?;
12604 server.update_capabilities(|capabilities| {
12605 capabilities.document_symbol_provider = Some(options);
12606 });
12607 notify_server_capabilities_updated(&server, cx);
12608 }
12609 "textDocument/codeAction" => {
12610 let options = parse_register_capabilities(reg)?;
12611 let provider = match options {
12612 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12613 OneOf::Right(caps) => caps,
12614 };
12615 server.update_capabilities(|capabilities| {
12616 capabilities.code_action_provider = Some(provider);
12617 });
12618 notify_server_capabilities_updated(&server, cx);
12619 }
12620 "textDocument/definition" => {
12621 let options = parse_register_capabilities(reg)?;
12622 server.update_capabilities(|capabilities| {
12623 capabilities.definition_provider = Some(options);
12624 });
12625 notify_server_capabilities_updated(&server, cx);
12626 }
12627 "textDocument/completion" => {
12628 if let Some(caps) = reg
12629 .register_options
12630 .map(serde_json::from_value::<CompletionOptions>)
12631 .transpose()?
12632 {
12633 server.update_capabilities(|capabilities| {
12634 capabilities.completion_provider = Some(caps.clone());
12635 });
12636
12637 if let Some(local) = self.as_local() {
12638 let mut buffers_with_language_server = Vec::new();
12639 for handle in self.buffer_store.read(cx).buffers() {
12640 let buffer_id = handle.read(cx).remote_id();
12641 if local
12642 .buffers_opened_in_servers
12643 .get(&buffer_id)
12644 .filter(|s| s.contains(&server_id))
12645 .is_some()
12646 {
12647 buffers_with_language_server.push(handle);
12648 }
12649 }
12650 let triggers = caps
12651 .trigger_characters
12652 .unwrap_or_default()
12653 .into_iter()
12654 .collect::<BTreeSet<_>>();
12655 for handle in buffers_with_language_server {
12656 let triggers = triggers.clone();
12657 let _ = handle.update(cx, move |buffer, cx| {
12658 buffer.set_completion_triggers(server_id, triggers, cx);
12659 });
12660 }
12661 }
12662 notify_server_capabilities_updated(&server, cx);
12663 }
12664 }
12665 "textDocument/hover" => {
12666 let options = parse_register_capabilities(reg)?;
12667 let provider = match options {
12668 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12669 OneOf::Right(caps) => caps,
12670 };
12671 server.update_capabilities(|capabilities| {
12672 capabilities.hover_provider = Some(provider);
12673 });
12674 notify_server_capabilities_updated(&server, cx);
12675 }
12676 "textDocument/signatureHelp" => {
12677 if let Some(caps) = reg
12678 .register_options
12679 .map(serde_json::from_value)
12680 .transpose()?
12681 {
12682 server.update_capabilities(|capabilities| {
12683 capabilities.signature_help_provider = Some(caps);
12684 });
12685 notify_server_capabilities_updated(&server, cx);
12686 }
12687 }
12688 "textDocument/didChange" => {
12689 if let Some(sync_kind) = reg
12690 .register_options
12691 .and_then(|opts| opts.get("syncKind").cloned())
12692 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12693 .transpose()?
12694 {
12695 server.update_capabilities(|capabilities| {
12696 let mut sync_options =
12697 Self::take_text_document_sync_options(capabilities);
12698 sync_options.change = Some(sync_kind);
12699 capabilities.text_document_sync =
12700 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12701 });
12702 notify_server_capabilities_updated(&server, cx);
12703 }
12704 }
12705 "textDocument/didSave" => {
12706 if let Some(include_text) = reg
12707 .register_options
12708 .map(|opts| {
12709 let transpose = opts
12710 .get("includeText")
12711 .cloned()
12712 .map(serde_json::from_value::<Option<bool>>)
12713 .transpose();
12714 match transpose {
12715 Ok(value) => Ok(value.flatten()),
12716 Err(e) => Err(e),
12717 }
12718 })
12719 .transpose()?
12720 {
12721 server.update_capabilities(|capabilities| {
12722 let mut sync_options =
12723 Self::take_text_document_sync_options(capabilities);
12724 sync_options.save =
12725 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12726 include_text,
12727 }));
12728 capabilities.text_document_sync =
12729 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12730 });
12731 notify_server_capabilities_updated(&server, cx);
12732 }
12733 }
12734 "textDocument/codeLens" => {
12735 if let Some(caps) = reg
12736 .register_options
12737 .map(serde_json::from_value)
12738 .transpose()?
12739 {
12740 server.update_capabilities(|capabilities| {
12741 capabilities.code_lens_provider = Some(caps);
12742 });
12743 notify_server_capabilities_updated(&server, cx);
12744 }
12745 }
12746 "textDocument/diagnostic" => {
12747 if let Some(caps) = reg
12748 .register_options
12749 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12750 .transpose()?
12751 {
12752 let local = self
12753 .as_local_mut()
12754 .context("Expected LSP Store to be local")?;
12755 let state = local
12756 .language_servers
12757 .get_mut(&server_id)
12758 .context("Could not obtain Language Servers state")?;
12759 local
12760 .language_server_dynamic_registrations
12761 .entry(server_id)
12762 .or_default()
12763 .diagnostics
12764 .insert(Some(reg.id.clone()), caps.clone());
12765
12766 let supports_workspace_diagnostics =
12767 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12768 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12769 diagnostic_options.workspace_diagnostics
12770 }
12771 DiagnosticServerCapabilities::RegistrationOptions(
12772 diagnostic_registration_options,
12773 ) => {
12774 diagnostic_registration_options
12775 .diagnostic_options
12776 .workspace_diagnostics
12777 }
12778 };
12779
12780 if supports_workspace_diagnostics(&caps) {
12781 if let LanguageServerState::Running {
12782 workspace_diagnostics_refresh_tasks,
12783 ..
12784 } = state
12785 && let Some(task) = lsp_workspace_diagnostics_refresh(
12786 Some(reg.id.clone()),
12787 caps.clone(),
12788 server.clone(),
12789 cx,
12790 )
12791 {
12792 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12793 }
12794 }
12795
12796 server.update_capabilities(|capabilities| {
12797 capabilities.diagnostic_provider = Some(caps);
12798 });
12799
12800 notify_server_capabilities_updated(&server, cx);
12801
12802 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12803 }
12804 }
12805 "textDocument/documentColor" => {
12806 let options = parse_register_capabilities(reg)?;
12807 let provider = match options {
12808 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12809 OneOf::Right(caps) => caps,
12810 };
12811 server.update_capabilities(|capabilities| {
12812 capabilities.color_provider = Some(provider);
12813 });
12814 notify_server_capabilities_updated(&server, cx);
12815 }
12816 _ => log::warn!("unhandled capability registration: {reg:?}"),
12817 }
12818 }
12819
12820 Ok(())
12821 }
12822
12823 fn unregister_server_capabilities(
12824 &mut self,
12825 server_id: LanguageServerId,
12826 params: lsp::UnregistrationParams,
12827 cx: &mut Context<Self>,
12828 ) -> anyhow::Result<()> {
12829 let server = self
12830 .language_server_for_id(server_id)
12831 .with_context(|| format!("no server {server_id} found"))?;
12832 for unreg in params.unregisterations.iter() {
12833 match unreg.method.as_str() {
12834 "workspace/didChangeWatchedFiles" => {
12835 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12836 local_lsp_store
12837 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12838 true
12839 } else {
12840 false
12841 };
12842 if notify {
12843 notify_server_capabilities_updated(&server, cx);
12844 }
12845 }
12846 "workspace/didChangeConfiguration" => {
12847 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12848 }
12849 "workspace/didChangeWorkspaceFolders" => {
12850 server.update_capabilities(|capabilities| {
12851 capabilities
12852 .workspace
12853 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12854 workspace_folders: None,
12855 file_operations: None,
12856 })
12857 .workspace_folders = None;
12858 });
12859 notify_server_capabilities_updated(&server, cx);
12860 }
12861 "workspace/symbol" => {
12862 server.update_capabilities(|capabilities| {
12863 capabilities.workspace_symbol_provider = None
12864 });
12865 notify_server_capabilities_updated(&server, cx);
12866 }
12867 "workspace/fileOperations" => {
12868 server.update_capabilities(|capabilities| {
12869 capabilities
12870 .workspace
12871 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12872 workspace_folders: None,
12873 file_operations: None,
12874 })
12875 .file_operations = None;
12876 });
12877 notify_server_capabilities_updated(&server, cx);
12878 }
12879 "workspace/executeCommand" => {
12880 server.update_capabilities(|capabilities| {
12881 capabilities.execute_command_provider = None;
12882 });
12883 notify_server_capabilities_updated(&server, cx);
12884 }
12885 "textDocument/rangeFormatting" => {
12886 server.update_capabilities(|capabilities| {
12887 capabilities.document_range_formatting_provider = None
12888 });
12889 notify_server_capabilities_updated(&server, cx);
12890 }
12891 "textDocument/onTypeFormatting" => {
12892 server.update_capabilities(|capabilities| {
12893 capabilities.document_on_type_formatting_provider = None;
12894 });
12895 notify_server_capabilities_updated(&server, cx);
12896 }
12897 "textDocument/formatting" => {
12898 server.update_capabilities(|capabilities| {
12899 capabilities.document_formatting_provider = None;
12900 });
12901 notify_server_capabilities_updated(&server, cx);
12902 }
12903 "textDocument/rename" => {
12904 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12905 notify_server_capabilities_updated(&server, cx);
12906 }
12907 "textDocument/codeAction" => {
12908 server.update_capabilities(|capabilities| {
12909 capabilities.code_action_provider = None;
12910 });
12911 notify_server_capabilities_updated(&server, cx);
12912 }
12913 "textDocument/definition" => {
12914 server.update_capabilities(|capabilities| {
12915 capabilities.definition_provider = None;
12916 });
12917 notify_server_capabilities_updated(&server, cx);
12918 }
12919 "textDocument/completion" => {
12920 server.update_capabilities(|capabilities| {
12921 capabilities.completion_provider = None;
12922 });
12923 notify_server_capabilities_updated(&server, cx);
12924 }
12925 "textDocument/hover" => {
12926 server.update_capabilities(|capabilities| {
12927 capabilities.hover_provider = None;
12928 });
12929 notify_server_capabilities_updated(&server, cx);
12930 }
12931 "textDocument/signatureHelp" => {
12932 server.update_capabilities(|capabilities| {
12933 capabilities.signature_help_provider = None;
12934 });
12935 notify_server_capabilities_updated(&server, cx);
12936 }
12937 "textDocument/didChange" => {
12938 server.update_capabilities(|capabilities| {
12939 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12940 sync_options.change = None;
12941 capabilities.text_document_sync =
12942 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12943 });
12944 notify_server_capabilities_updated(&server, cx);
12945 }
12946 "textDocument/didSave" => {
12947 server.update_capabilities(|capabilities| {
12948 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12949 sync_options.save = None;
12950 capabilities.text_document_sync =
12951 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12952 });
12953 notify_server_capabilities_updated(&server, cx);
12954 }
12955 "textDocument/codeLens" => {
12956 server.update_capabilities(|capabilities| {
12957 capabilities.code_lens_provider = None;
12958 });
12959 notify_server_capabilities_updated(&server, cx);
12960 }
12961 "textDocument/diagnostic" => {
12962 let local = self
12963 .as_local_mut()
12964 .context("Expected LSP Store to be local")?;
12965
12966 let state = local
12967 .language_servers
12968 .get_mut(&server_id)
12969 .context("Could not obtain Language Servers state")?;
12970 let registrations = local
12971 .language_server_dynamic_registrations
12972 .get_mut(&server_id)
12973 .with_context(|| {
12974 format!("Expected dynamic registration to exist for server {server_id}")
12975 })?;
12976 registrations.diagnostics
12977 .remove(&Some(unreg.id.clone()))
12978 .with_context(|| format!(
12979 "Attempted to unregister non-existent diagnostic registration with ID {}",
12980 unreg.id)
12981 )?;
12982 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12983
12984 if let LanguageServerState::Running {
12985 workspace_diagnostics_refresh_tasks,
12986 ..
12987 } = state
12988 {
12989 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12990 }
12991
12992 self.clear_unregistered_diagnostics(
12993 server_id,
12994 SharedString::from(unreg.id.clone()),
12995 cx,
12996 )?;
12997
12998 if removed_last_diagnostic_provider {
12999 server.update_capabilities(|capabilities| {
13000 debug_assert!(capabilities.diagnostic_provider.is_some());
13001 capabilities.diagnostic_provider = None;
13002 });
13003 }
13004
13005 notify_server_capabilities_updated(&server, cx);
13006 }
13007 "textDocument/documentColor" => {
13008 server.update_capabilities(|capabilities| {
13009 capabilities.color_provider = None;
13010 });
13011 notify_server_capabilities_updated(&server, cx);
13012 }
13013 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
13014 }
13015 }
13016
13017 Ok(())
13018 }
13019
13020 fn clear_unregistered_diagnostics(
13021 &mut self,
13022 server_id: LanguageServerId,
13023 cleared_registration_id: SharedString,
13024 cx: &mut Context<Self>,
13025 ) -> anyhow::Result<()> {
13026 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
13027
13028 self.buffer_store.update(cx, |buffer_store, cx| {
13029 for buffer_handle in buffer_store.buffers() {
13030 let buffer = buffer_handle.read(cx);
13031 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
13032 let Some(abs_path) = abs_path else {
13033 continue;
13034 };
13035 affected_abs_paths.insert(abs_path);
13036 }
13037 });
13038
13039 let local = self.as_local().context("Expected LSP Store to be local")?;
13040 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13041 let Some(worktree) = self
13042 .worktree_store
13043 .read(cx)
13044 .worktree_for_id(*worktree_id, cx)
13045 else {
13046 continue;
13047 };
13048
13049 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13050 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13051 let has_matching_registration =
13052 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13053 entry.diagnostic.registration_id.as_ref()
13054 == Some(&cleared_registration_id)
13055 });
13056 if has_matching_registration {
13057 let abs_path = worktree.read(cx).absolutize(rel_path);
13058 affected_abs_paths.insert(abs_path);
13059 }
13060 }
13061 }
13062 }
13063
13064 if affected_abs_paths.is_empty() {
13065 return Ok(());
13066 }
13067
13068 // Send a fake diagnostic update which clears the state for the registration ID
13069 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13070 affected_abs_paths
13071 .into_iter()
13072 .map(|abs_path| DocumentDiagnosticsUpdate {
13073 diagnostics: DocumentDiagnostics {
13074 diagnostics: Vec::new(),
13075 document_abs_path: abs_path,
13076 version: None,
13077 },
13078 result_id: None,
13079 registration_id: Some(cleared_registration_id.clone()),
13080 server_id,
13081 disk_based_sources: Cow::Borrowed(&[]),
13082 })
13083 .collect();
13084
13085 let merge_registration_id = cleared_registration_id.clone();
13086 self.merge_diagnostic_entries(
13087 clears,
13088 move |_, diagnostic, _| {
13089 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13090 diagnostic.registration_id != Some(merge_registration_id.clone())
13091 } else {
13092 true
13093 }
13094 },
13095 cx,
13096 )?;
13097
13098 Ok(())
13099 }
13100
13101 async fn deduplicate_range_based_lsp_requests<T>(
13102 lsp_store: &Entity<Self>,
13103 server_id: Option<LanguageServerId>,
13104 lsp_request_id: LspRequestId,
13105 proto_request: &T::ProtoRequest,
13106 range: Range<Anchor>,
13107 cx: &mut AsyncApp,
13108 ) -> Result<()>
13109 where
13110 T: LspCommand,
13111 T::ProtoRequest: proto::LspRequestMessage,
13112 {
13113 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13114 let version = deserialize_version(proto_request.buffer_version());
13115 let buffer = lsp_store.update(cx, |this, cx| {
13116 this.buffer_store.read(cx).get_existing(buffer_id)
13117 })?;
13118 buffer
13119 .update(cx, |buffer, _| buffer.wait_for_version(version))
13120 .await?;
13121 lsp_store.update(cx, |lsp_store, cx| {
13122 let buffer_snapshot = buffer.read(cx).snapshot();
13123 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13124 let chunks_queried_for = lsp_data
13125 .inlay_hints
13126 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13127 .collect::<Vec<_>>();
13128 match chunks_queried_for.as_slice() {
13129 &[chunk] => {
13130 let key = LspKey {
13131 request_type: TypeId::of::<T>(),
13132 server_queried: server_id,
13133 };
13134 let previous_request = lsp_data
13135 .chunk_lsp_requests
13136 .entry(key)
13137 .or_default()
13138 .insert(chunk, lsp_request_id);
13139 if let Some((previous_request, running_requests)) =
13140 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13141 {
13142 running_requests.remove(&previous_request);
13143 }
13144 }
13145 _ambiguous_chunks => {
13146 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13147 // there, a buffer version-based check will be performed and outdated requests discarded.
13148 }
13149 }
13150 anyhow::Ok(())
13151 })?;
13152
13153 Ok(())
13154 }
13155
13156 async fn query_lsp_locally<T>(
13157 lsp_store: Entity<Self>,
13158 for_server_id: Option<LanguageServerId>,
13159 sender_id: proto::PeerId,
13160 lsp_request_id: LspRequestId,
13161 proto_request: T::ProtoRequest,
13162 position: Option<Anchor>,
13163 cx: &mut AsyncApp,
13164 ) -> Result<()>
13165 where
13166 T: LspCommand + Clone,
13167 T::ProtoRequest: proto::LspRequestMessage,
13168 <T::ProtoRequest as proto::RequestMessage>::Response:
13169 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13170 {
13171 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13172 let version = deserialize_version(proto_request.buffer_version());
13173 let buffer = lsp_store.update(cx, |this, cx| {
13174 this.buffer_store.read(cx).get_existing(buffer_id)
13175 })?;
13176 buffer
13177 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13178 .await?;
13179 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13180 let request =
13181 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13182 let key = LspKey {
13183 request_type: TypeId::of::<T>(),
13184 server_queried: for_server_id,
13185 };
13186 lsp_store.update(cx, |lsp_store, cx| {
13187 let request_task = match for_server_id {
13188 Some(server_id) => {
13189 let server_task = lsp_store.request_lsp(
13190 buffer.clone(),
13191 LanguageServerToQuery::Other(server_id),
13192 request.clone(),
13193 cx,
13194 );
13195 cx.background_spawn(async move {
13196 let mut responses = Vec::new();
13197 match server_task.await {
13198 Ok(response) => responses.push((server_id, response)),
13199 // rust-analyzer likes to error with this when its still loading up
13200 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13201 Err(e) => log::error!(
13202 "Error handling response for request {request:?}: {e:#}"
13203 ),
13204 }
13205 responses
13206 })
13207 }
13208 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13209 };
13210 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13211 if T::ProtoRequest::stop_previous_requests() {
13212 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13213 lsp_requests.clear();
13214 }
13215 }
13216 lsp_data.lsp_requests.entry(key).or_default().insert(
13217 lsp_request_id,
13218 cx.spawn(async move |lsp_store, cx| {
13219 let response = request_task.await;
13220 lsp_store
13221 .update(cx, |lsp_store, cx| {
13222 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13223 {
13224 let response = response
13225 .into_iter()
13226 .map(|(server_id, response)| {
13227 (
13228 server_id.to_proto(),
13229 T::response_to_proto(
13230 response,
13231 lsp_store,
13232 sender_id,
13233 &buffer_version,
13234 cx,
13235 )
13236 .into(),
13237 )
13238 })
13239 .collect::<HashMap<_, _>>();
13240 match client.send_lsp_response::<T::ProtoRequest>(
13241 project_id,
13242 lsp_request_id,
13243 response,
13244 ) {
13245 Ok(()) => {}
13246 Err(e) => {
13247 log::error!("Failed to send LSP response: {e:#}",)
13248 }
13249 }
13250 }
13251 })
13252 .ok();
13253 }),
13254 );
13255 });
13256 Ok(())
13257 }
13258
13259 fn take_text_document_sync_options(
13260 capabilities: &mut lsp::ServerCapabilities,
13261 ) -> lsp::TextDocumentSyncOptions {
13262 match capabilities.text_document_sync.take() {
13263 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13264 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13265 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13266 sync_options.change = Some(sync_kind);
13267 sync_options
13268 }
13269 None => lsp::TextDocumentSyncOptions::default(),
13270 }
13271 }
13272
13273 #[cfg(any(test, feature = "test-support"))]
13274 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13275 Some(
13276 self.lsp_data
13277 .get_mut(&buffer_id)?
13278 .code_lens
13279 .take()?
13280 .update
13281 .take()?
13282 .1,
13283 )
13284 }
13285
13286 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13287 self.downstream_client.clone()
13288 }
13289
13290 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13291 self.worktree_store.clone()
13292 }
13293
13294 /// Gets what's stored in the LSP data for the given buffer.
13295 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13296 self.lsp_data.get_mut(&buffer_id)
13297 }
13298
13299 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13300 /// new [`BufferLspData`] will be created to replace the previous state.
13301 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13302 let (buffer_id, buffer_version) =
13303 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13304 let lsp_data = self
13305 .lsp_data
13306 .entry(buffer_id)
13307 .or_insert_with(|| BufferLspData::new(buffer, cx));
13308 if buffer_version.changed_since(&lsp_data.buffer_version) {
13309 *lsp_data = BufferLspData::new(buffer, cx);
13310 }
13311 lsp_data
13312 }
13313}
13314
13315// Registration with registerOptions as null, should fallback to true.
13316// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13317fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13318 reg: lsp::Registration,
13319) -> Result<OneOf<bool, T>> {
13320 Ok(match reg.register_options {
13321 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13322 None => OneOf::Left(true),
13323 })
13324}
13325
13326fn subscribe_to_binary_statuses(
13327 languages: &Arc<LanguageRegistry>,
13328 cx: &mut Context<'_, LspStore>,
13329) -> Task<()> {
13330 let mut server_statuses = languages.language_server_binary_statuses();
13331 cx.spawn(async move |lsp_store, cx| {
13332 while let Some((server_name, binary_status)) = server_statuses.next().await {
13333 if lsp_store
13334 .update(cx, |_, cx| {
13335 let mut message = None;
13336 let binary_status = match binary_status {
13337 BinaryStatus::None => proto::ServerBinaryStatus::None,
13338 BinaryStatus::CheckingForUpdate => {
13339 proto::ServerBinaryStatus::CheckingForUpdate
13340 }
13341 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13342 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13343 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13344 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13345 BinaryStatus::Failed { error } => {
13346 message = Some(error);
13347 proto::ServerBinaryStatus::Failed
13348 }
13349 };
13350 cx.emit(LspStoreEvent::LanguageServerUpdate {
13351 // Binary updates are about the binary that might not have any language server id at that point.
13352 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13353 language_server_id: LanguageServerId(0),
13354 name: Some(server_name),
13355 message: proto::update_language_server::Variant::StatusUpdate(
13356 proto::StatusUpdate {
13357 message,
13358 status: Some(proto::status_update::Status::Binary(
13359 binary_status as i32,
13360 )),
13361 },
13362 ),
13363 });
13364 })
13365 .is_err()
13366 {
13367 break;
13368 }
13369 }
13370 })
13371}
13372
13373fn lsp_workspace_diagnostics_refresh(
13374 registration_id: Option<String>,
13375 options: DiagnosticServerCapabilities,
13376 server: Arc<LanguageServer>,
13377 cx: &mut Context<'_, LspStore>,
13378) -> Option<WorkspaceRefreshTask> {
13379 let identifier = workspace_diagnostic_identifier(&options)?;
13380 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13381
13382 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13383 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13384 refresh_tx.try_send(()).ok();
13385
13386 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13387 let mut attempts = 0;
13388 let max_attempts = 50;
13389 let mut requests = 0;
13390
13391 loop {
13392 let Some(()) = refresh_rx.recv().await else {
13393 return;
13394 };
13395
13396 'request: loop {
13397 requests += 1;
13398 if attempts > max_attempts {
13399 log::error!(
13400 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13401 );
13402 return;
13403 }
13404 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13405 cx.background_executor()
13406 .timer(Duration::from_millis(backoff_millis))
13407 .await;
13408 attempts += 1;
13409
13410 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13411 lsp_store
13412 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13413 .into_iter()
13414 .filter_map(|(abs_path, result_id)| {
13415 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13416 Some(lsp::PreviousResultId {
13417 uri,
13418 value: result_id.to_string(),
13419 })
13420 })
13421 .collect()
13422 }) else {
13423 return;
13424 };
13425
13426 let token = if let Some(registration_id) = ®istration_id {
13427 format!(
13428 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13429 server.server_id(),
13430 )
13431 } else {
13432 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13433 };
13434
13435 progress_rx.try_recv().ok();
13436 let timer =
13437 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13438 let progress = pin!(progress_rx.recv().fuse());
13439 let response_result = server
13440 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13441 lsp::WorkspaceDiagnosticParams {
13442 previous_result_ids,
13443 identifier: identifier.clone(),
13444 work_done_progress_params: Default::default(),
13445 partial_result_params: lsp::PartialResultParams {
13446 partial_result_token: Some(lsp::ProgressToken::String(token)),
13447 },
13448 },
13449 select(timer, progress).then(|either| match either {
13450 Either::Left((message, ..)) => ready(message).left_future(),
13451 Either::Right(..) => pending::<String>().right_future(),
13452 }),
13453 )
13454 .await;
13455
13456 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13457 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13458 match response_result {
13459 ConnectionResult::Timeout => {
13460 log::error!("Timeout during workspace diagnostics pull");
13461 continue 'request;
13462 }
13463 ConnectionResult::ConnectionReset => {
13464 log::error!("Server closed a workspace diagnostics pull request");
13465 continue 'request;
13466 }
13467 ConnectionResult::Result(Err(e)) => {
13468 log::error!("Error during workspace diagnostics pull: {e:#}");
13469 break 'request;
13470 }
13471 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13472 attempts = 0;
13473 if lsp_store
13474 .update(cx, |lsp_store, cx| {
13475 lsp_store.apply_workspace_diagnostic_report(
13476 server.server_id(),
13477 pulled_diagnostics,
13478 registration_id_shared.clone(),
13479 cx,
13480 )
13481 })
13482 .is_err()
13483 {
13484 return;
13485 }
13486 break 'request;
13487 }
13488 }
13489 }
13490 }
13491 });
13492
13493 Some(WorkspaceRefreshTask {
13494 refresh_tx,
13495 progress_tx,
13496 task: workspace_query_language_server,
13497 })
13498}
13499
13500fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13501 match &options {
13502 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13503 diagnostic_options.identifier.clone()
13504 }
13505 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13506 let diagnostic_options = ®istration_options.diagnostic_options;
13507 diagnostic_options.identifier.clone()
13508 }
13509 }
13510}
13511
13512fn workspace_diagnostic_identifier(
13513 options: &DiagnosticServerCapabilities,
13514) -> Option<Option<String>> {
13515 match &options {
13516 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13517 if !diagnostic_options.workspace_diagnostics {
13518 return None;
13519 }
13520 Some(diagnostic_options.identifier.clone())
13521 }
13522 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13523 let diagnostic_options = ®istration_options.diagnostic_options;
13524 if !diagnostic_options.workspace_diagnostics {
13525 return None;
13526 }
13527 Some(diagnostic_options.identifier.clone())
13528 }
13529 }
13530}
13531
13532fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13533 let CompletionSource::BufferWord {
13534 word_range,
13535 resolved,
13536 } = &mut completion.source
13537 else {
13538 return;
13539 };
13540 if *resolved {
13541 return;
13542 }
13543
13544 if completion.new_text
13545 != snapshot
13546 .text_for_range(word_range.clone())
13547 .collect::<String>()
13548 {
13549 return;
13550 }
13551
13552 let mut offset = 0;
13553 for chunk in snapshot.chunks(word_range.clone(), true) {
13554 let end_offset = offset + chunk.text.len();
13555 if let Some(highlight_id) = chunk.syntax_highlight_id {
13556 completion
13557 .label
13558 .runs
13559 .push((offset..end_offset, highlight_id));
13560 }
13561 offset = end_offset;
13562 }
13563 *resolved = true;
13564}
13565
13566impl EventEmitter<LspStoreEvent> for LspStore {}
13567
13568fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13569 hover
13570 .contents
13571 .retain(|hover_block| !hover_block.text.trim().is_empty());
13572 if hover.contents.is_empty() {
13573 None
13574 } else {
13575 Some(hover)
13576 }
13577}
13578
13579async fn populate_labels_for_completions(
13580 new_completions: Vec<CoreCompletion>,
13581 language: Option<Arc<Language>>,
13582 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13583) -> Vec<Completion> {
13584 let lsp_completions = new_completions
13585 .iter()
13586 .filter_map(|new_completion| {
13587 new_completion
13588 .source
13589 .lsp_completion(true)
13590 .map(|lsp_completion| lsp_completion.into_owned())
13591 })
13592 .collect::<Vec<_>>();
13593
13594 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13595 lsp_adapter
13596 .labels_for_completions(&lsp_completions, language)
13597 .await
13598 .log_err()
13599 .unwrap_or_default()
13600 } else {
13601 Vec::new()
13602 }
13603 .into_iter()
13604 .fuse();
13605
13606 let mut completions = Vec::new();
13607 for completion in new_completions {
13608 match completion.source.lsp_completion(true) {
13609 Some(lsp_completion) => {
13610 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13611
13612 let mut label = labels.next().flatten().unwrap_or_else(|| {
13613 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13614 });
13615 ensure_uniform_list_compatible_label(&mut label);
13616 completions.push(Completion {
13617 label,
13618 documentation,
13619 replace_range: completion.replace_range,
13620 new_text: completion.new_text,
13621 insert_text_mode: lsp_completion.insert_text_mode,
13622 source: completion.source,
13623 icon_path: None,
13624 confirm: None,
13625 match_start: None,
13626 snippet_deduplication_key: None,
13627 });
13628 }
13629 None => {
13630 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13631 ensure_uniform_list_compatible_label(&mut label);
13632 completions.push(Completion {
13633 label,
13634 documentation: None,
13635 replace_range: completion.replace_range,
13636 new_text: completion.new_text,
13637 source: completion.source,
13638 insert_text_mode: None,
13639 icon_path: None,
13640 confirm: None,
13641 match_start: None,
13642 snippet_deduplication_key: None,
13643 });
13644 }
13645 }
13646 }
13647 completions
13648}
13649
13650#[derive(Debug)]
13651pub enum LanguageServerToQuery {
13652 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13653 FirstCapable,
13654 /// Query a specific language server.
13655 Other(LanguageServerId),
13656}
13657
13658#[derive(Default)]
13659struct RenamePathsWatchedForServer {
13660 did_rename: Vec<RenameActionPredicate>,
13661 will_rename: Vec<RenameActionPredicate>,
13662}
13663
13664impl RenamePathsWatchedForServer {
13665 fn with_did_rename_patterns(
13666 mut self,
13667 did_rename: Option<&FileOperationRegistrationOptions>,
13668 ) -> Self {
13669 if let Some(did_rename) = did_rename {
13670 self.did_rename = did_rename
13671 .filters
13672 .iter()
13673 .filter_map(|filter| filter.try_into().log_err())
13674 .collect();
13675 }
13676 self
13677 }
13678 fn with_will_rename_patterns(
13679 mut self,
13680 will_rename: Option<&FileOperationRegistrationOptions>,
13681 ) -> Self {
13682 if let Some(will_rename) = will_rename {
13683 self.will_rename = will_rename
13684 .filters
13685 .iter()
13686 .filter_map(|filter| filter.try_into().log_err())
13687 .collect();
13688 }
13689 self
13690 }
13691
13692 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13693 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13694 }
13695 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13696 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13697 }
13698}
13699
13700impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13701 type Error = globset::Error;
13702 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13703 Ok(Self {
13704 kind: ops.pattern.matches.clone(),
13705 glob: GlobBuilder::new(&ops.pattern.glob)
13706 .case_insensitive(
13707 ops.pattern
13708 .options
13709 .as_ref()
13710 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13711 )
13712 .build()?
13713 .compile_matcher(),
13714 })
13715 }
13716}
13717struct RenameActionPredicate {
13718 glob: GlobMatcher,
13719 kind: Option<FileOperationPatternKind>,
13720}
13721
13722impl RenameActionPredicate {
13723 // Returns true if language server should be notified
13724 fn eval(&self, path: &str, is_dir: bool) -> bool {
13725 self.kind.as_ref().is_none_or(|kind| {
13726 let expected_kind = if is_dir {
13727 FileOperationPatternKind::Folder
13728 } else {
13729 FileOperationPatternKind::File
13730 };
13731 kind == &expected_kind
13732 }) && self.glob.is_match(path)
13733 }
13734}
13735
13736#[derive(Default)]
13737struct LanguageServerWatchedPaths {
13738 worktree_paths: HashMap<WorktreeId, GlobSet>,
13739 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13740}
13741
13742#[derive(Default)]
13743struct LanguageServerWatchedPathsBuilder {
13744 worktree_paths: HashMap<WorktreeId, GlobSet>,
13745 abs_paths: HashMap<Arc<Path>, GlobSet>,
13746}
13747
13748impl LanguageServerWatchedPathsBuilder {
13749 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13750 self.worktree_paths.insert(worktree_id, glob_set);
13751 }
13752 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13753 self.abs_paths.insert(path, glob_set);
13754 }
13755 fn build(
13756 self,
13757 fs: Arc<dyn Fs>,
13758 language_server_id: LanguageServerId,
13759 cx: &mut Context<LspStore>,
13760 ) -> LanguageServerWatchedPaths {
13761 let lsp_store = cx.weak_entity();
13762
13763 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13764 let abs_paths = self
13765 .abs_paths
13766 .into_iter()
13767 .map(|(abs_path, globset)| {
13768 let task = cx.spawn({
13769 let abs_path = abs_path.clone();
13770 let fs = fs.clone();
13771
13772 let lsp_store = lsp_store.clone();
13773 async move |_, cx| {
13774 maybe!(async move {
13775 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13776 while let Some(update) = push_updates.0.next().await {
13777 let action = lsp_store
13778 .update(cx, |this, _| {
13779 let Some(local) = this.as_local() else {
13780 return ControlFlow::Break(());
13781 };
13782 let Some(watcher) = local
13783 .language_server_watched_paths
13784 .get(&language_server_id)
13785 else {
13786 return ControlFlow::Break(());
13787 };
13788 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13789 "Watched abs path is not registered with a watcher",
13790 );
13791 let matching_entries = update
13792 .into_iter()
13793 .filter(|event| globs.is_match(&event.path))
13794 .collect::<Vec<_>>();
13795 this.lsp_notify_abs_paths_changed(
13796 language_server_id,
13797 matching_entries,
13798 );
13799 ControlFlow::Continue(())
13800 })
13801 .ok()?;
13802
13803 if action.is_break() {
13804 break;
13805 }
13806 }
13807 Some(())
13808 })
13809 .await;
13810 }
13811 });
13812 (abs_path, (globset, task))
13813 })
13814 .collect();
13815 LanguageServerWatchedPaths {
13816 worktree_paths: self.worktree_paths,
13817 abs_paths,
13818 }
13819 }
13820}
13821
13822struct LspBufferSnapshot {
13823 version: i32,
13824 snapshot: TextBufferSnapshot,
13825}
13826
13827/// A prompt requested by LSP server.
13828#[derive(Clone, Debug)]
13829pub struct LanguageServerPromptRequest {
13830 pub id: usize,
13831 pub level: PromptLevel,
13832 pub message: String,
13833 pub actions: Vec<MessageActionItem>,
13834 pub lsp_name: String,
13835 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13836}
13837
13838impl LanguageServerPromptRequest {
13839 pub fn new(
13840 level: PromptLevel,
13841 message: String,
13842 actions: Vec<MessageActionItem>,
13843 lsp_name: String,
13844 response_channel: smol::channel::Sender<MessageActionItem>,
13845 ) -> Self {
13846 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13847 LanguageServerPromptRequest {
13848 id,
13849 level,
13850 message,
13851 actions,
13852 lsp_name,
13853 response_channel,
13854 }
13855 }
13856 pub async fn respond(self, index: usize) -> Option<()> {
13857 if let Some(response) = self.actions.into_iter().nth(index) {
13858 self.response_channel.send(response).await.ok()
13859 } else {
13860 None
13861 }
13862 }
13863
13864 #[cfg(any(test, feature = "test-support"))]
13865 pub fn test(
13866 level: PromptLevel,
13867 message: String,
13868 actions: Vec<MessageActionItem>,
13869 lsp_name: String,
13870 ) -> Self {
13871 let (tx, _rx) = smol::channel::unbounded();
13872 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13873 }
13874}
13875impl PartialEq for LanguageServerPromptRequest {
13876 fn eq(&self, other: &Self) -> bool {
13877 self.message == other.message && self.actions == other.actions
13878 }
13879}
13880
13881#[derive(Clone, Debug, PartialEq)]
13882pub enum LanguageServerLogType {
13883 Log(MessageType),
13884 Trace { verbose_info: Option<String> },
13885 Rpc { received: bool },
13886}
13887
13888impl LanguageServerLogType {
13889 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13890 match self {
13891 Self::Log(log_type) => {
13892 use proto::log_message::LogLevel;
13893 let level = match *log_type {
13894 MessageType::ERROR => LogLevel::Error,
13895 MessageType::WARNING => LogLevel::Warning,
13896 MessageType::INFO => LogLevel::Info,
13897 MessageType::LOG => LogLevel::Log,
13898 other => {
13899 log::warn!("Unknown lsp log message type: {other:?}");
13900 LogLevel::Log
13901 }
13902 };
13903 proto::language_server_log::LogType::Log(proto::LogMessage {
13904 level: level as i32,
13905 })
13906 }
13907 Self::Trace { verbose_info } => {
13908 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13909 verbose_info: verbose_info.to_owned(),
13910 })
13911 }
13912 Self::Rpc { received } => {
13913 let kind = if *received {
13914 proto::rpc_message::Kind::Received
13915 } else {
13916 proto::rpc_message::Kind::Sent
13917 };
13918 let kind = kind as i32;
13919 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13920 }
13921 }
13922 }
13923
13924 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13925 use proto::log_message::LogLevel;
13926 use proto::rpc_message;
13927 match log_type {
13928 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13929 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13930 LogLevel::Error => MessageType::ERROR,
13931 LogLevel::Warning => MessageType::WARNING,
13932 LogLevel::Info => MessageType::INFO,
13933 LogLevel::Log => MessageType::LOG,
13934 },
13935 ),
13936 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13937 verbose_info: trace_message.verbose_info,
13938 },
13939 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13940 received: match rpc_message::Kind::from_i32(message.kind)
13941 .unwrap_or(rpc_message::Kind::Received)
13942 {
13943 rpc_message::Kind::Received => true,
13944 rpc_message::Kind::Sent => false,
13945 },
13946 },
13947 }
13948 }
13949}
13950
13951pub struct WorkspaceRefreshTask {
13952 refresh_tx: mpsc::Sender<()>,
13953 progress_tx: mpsc::Sender<()>,
13954 #[allow(dead_code)]
13955 task: Task<()>,
13956}
13957
13958pub enum LanguageServerState {
13959 Starting {
13960 startup: Task<Option<Arc<LanguageServer>>>,
13961 /// List of language servers that will be added to the workspace once it's initialization completes.
13962 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13963 },
13964
13965 Running {
13966 adapter: Arc<CachedLspAdapter>,
13967 server: Arc<LanguageServer>,
13968 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13969 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13970 },
13971}
13972
13973impl LanguageServerState {
13974 fn add_workspace_folder(&self, uri: Uri) {
13975 match self {
13976 LanguageServerState::Starting {
13977 pending_workspace_folders,
13978 ..
13979 } => {
13980 pending_workspace_folders.lock().insert(uri);
13981 }
13982 LanguageServerState::Running { server, .. } => {
13983 server.add_workspace_folder(uri);
13984 }
13985 }
13986 }
13987 fn _remove_workspace_folder(&self, uri: Uri) {
13988 match self {
13989 LanguageServerState::Starting {
13990 pending_workspace_folders,
13991 ..
13992 } => {
13993 pending_workspace_folders.lock().remove(&uri);
13994 }
13995 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13996 }
13997 }
13998}
13999
14000impl std::fmt::Debug for LanguageServerState {
14001 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14002 match self {
14003 LanguageServerState::Starting { .. } => {
14004 f.debug_struct("LanguageServerState::Starting").finish()
14005 }
14006 LanguageServerState::Running { .. } => {
14007 f.debug_struct("LanguageServerState::Running").finish()
14008 }
14009 }
14010 }
14011}
14012
14013#[derive(Clone, Debug, Serialize)]
14014pub struct LanguageServerProgress {
14015 pub is_disk_based_diagnostics_progress: bool,
14016 pub is_cancellable: bool,
14017 pub title: Option<String>,
14018 pub message: Option<String>,
14019 pub percentage: Option<usize>,
14020 #[serde(skip_serializing)]
14021 pub last_update_at: Instant,
14022}
14023
14024#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14025pub struct DiagnosticSummary {
14026 pub error_count: usize,
14027 pub warning_count: usize,
14028}
14029
14030impl DiagnosticSummary {
14031 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14032 let mut this = Self {
14033 error_count: 0,
14034 warning_count: 0,
14035 };
14036
14037 for entry in diagnostics {
14038 if entry.diagnostic.is_primary {
14039 match entry.diagnostic.severity {
14040 DiagnosticSeverity::ERROR => this.error_count += 1,
14041 DiagnosticSeverity::WARNING => this.warning_count += 1,
14042 _ => {}
14043 }
14044 }
14045 }
14046
14047 this
14048 }
14049
14050 pub fn is_empty(&self) -> bool {
14051 self.error_count == 0 && self.warning_count == 0
14052 }
14053
14054 pub fn to_proto(
14055 self,
14056 language_server_id: LanguageServerId,
14057 path: &RelPath,
14058 ) -> proto::DiagnosticSummary {
14059 proto::DiagnosticSummary {
14060 path: path.to_proto(),
14061 language_server_id: language_server_id.0 as u64,
14062 error_count: self.error_count as u32,
14063 warning_count: self.warning_count as u32,
14064 }
14065 }
14066}
14067
14068#[derive(Clone, Debug)]
14069pub enum CompletionDocumentation {
14070 /// There is no documentation for this completion.
14071 Undocumented,
14072 /// A single line of documentation.
14073 SingleLine(SharedString),
14074 /// Multiple lines of plain text documentation.
14075 MultiLinePlainText(SharedString),
14076 /// Markdown documentation.
14077 MultiLineMarkdown(SharedString),
14078 /// Both single line and multiple lines of plain text documentation.
14079 SingleLineAndMultiLinePlainText {
14080 single_line: SharedString,
14081 plain_text: Option<SharedString>,
14082 },
14083}
14084
14085impl CompletionDocumentation {
14086 #[cfg(any(test, feature = "test-support"))]
14087 pub fn text(&self) -> SharedString {
14088 match self {
14089 CompletionDocumentation::Undocumented => "".into(),
14090 CompletionDocumentation::SingleLine(s) => s.clone(),
14091 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14092 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14093 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14094 single_line.clone()
14095 }
14096 }
14097 }
14098}
14099
14100impl From<lsp::Documentation> for CompletionDocumentation {
14101 fn from(docs: lsp::Documentation) -> Self {
14102 match docs {
14103 lsp::Documentation::String(text) => {
14104 if text.lines().count() <= 1 {
14105 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14106 } else {
14107 CompletionDocumentation::MultiLinePlainText(text.into())
14108 }
14109 }
14110
14111 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14112 lsp::MarkupKind::PlainText => {
14113 if value.lines().count() <= 1 {
14114 CompletionDocumentation::SingleLine(value.into())
14115 } else {
14116 CompletionDocumentation::MultiLinePlainText(value.into())
14117 }
14118 }
14119
14120 lsp::MarkupKind::Markdown => {
14121 CompletionDocumentation::MultiLineMarkdown(value.into())
14122 }
14123 },
14124 }
14125 }
14126}
14127
14128pub enum ResolvedHint {
14129 Resolved(InlayHint),
14130 Resolving(Shared<Task<()>>),
14131}
14132
14133pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14134 glob.components()
14135 .take_while(|component| match component {
14136 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14137 _ => true,
14138 })
14139 .collect()
14140}
14141
14142pub struct SshLspAdapter {
14143 name: LanguageServerName,
14144 binary: LanguageServerBinary,
14145 initialization_options: Option<String>,
14146 code_action_kinds: Option<Vec<CodeActionKind>>,
14147}
14148
14149impl SshLspAdapter {
14150 pub fn new(
14151 name: LanguageServerName,
14152 binary: LanguageServerBinary,
14153 initialization_options: Option<String>,
14154 code_action_kinds: Option<String>,
14155 ) -> Self {
14156 Self {
14157 name,
14158 binary,
14159 initialization_options,
14160 code_action_kinds: code_action_kinds
14161 .as_ref()
14162 .and_then(|c| serde_json::from_str(c).ok()),
14163 }
14164 }
14165}
14166
14167impl LspInstaller for SshLspAdapter {
14168 type BinaryVersion = ();
14169 async fn check_if_user_installed(
14170 &self,
14171 _: &dyn LspAdapterDelegate,
14172 _: Option<Toolchain>,
14173 _: &AsyncApp,
14174 ) -> Option<LanguageServerBinary> {
14175 Some(self.binary.clone())
14176 }
14177
14178 async fn cached_server_binary(
14179 &self,
14180 _: PathBuf,
14181 _: &dyn LspAdapterDelegate,
14182 ) -> Option<LanguageServerBinary> {
14183 None
14184 }
14185
14186 async fn fetch_latest_server_version(
14187 &self,
14188 _: &dyn LspAdapterDelegate,
14189 _: bool,
14190 _: &mut AsyncApp,
14191 ) -> Result<()> {
14192 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14193 }
14194
14195 async fn fetch_server_binary(
14196 &self,
14197 _: (),
14198 _: PathBuf,
14199 _: &dyn LspAdapterDelegate,
14200 ) -> Result<LanguageServerBinary> {
14201 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14202 }
14203}
14204
14205#[async_trait(?Send)]
14206impl LspAdapter for SshLspAdapter {
14207 fn name(&self) -> LanguageServerName {
14208 self.name.clone()
14209 }
14210
14211 async fn initialization_options(
14212 self: Arc<Self>,
14213 _: &Arc<dyn LspAdapterDelegate>,
14214 ) -> Result<Option<serde_json::Value>> {
14215 let Some(options) = &self.initialization_options else {
14216 return Ok(None);
14217 };
14218 let result = serde_json::from_str(options)?;
14219 Ok(result)
14220 }
14221
14222 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14223 self.code_action_kinds.clone()
14224 }
14225}
14226
14227pub fn language_server_settings<'a>(
14228 delegate: &'a dyn LspAdapterDelegate,
14229 language: &LanguageServerName,
14230 cx: &'a App,
14231) -> Option<&'a LspSettings> {
14232 language_server_settings_for(
14233 SettingsLocation {
14234 worktree_id: delegate.worktree_id(),
14235 path: RelPath::empty(),
14236 },
14237 language,
14238 cx,
14239 )
14240}
14241
14242pub fn language_server_settings_for<'a>(
14243 location: SettingsLocation<'a>,
14244 language: &LanguageServerName,
14245 cx: &'a App,
14246) -> Option<&'a LspSettings> {
14247 ProjectSettings::get(Some(location), cx).lsp.get(language)
14248}
14249
14250pub struct LocalLspAdapterDelegate {
14251 lsp_store: WeakEntity<LspStore>,
14252 worktree: worktree::Snapshot,
14253 fs: Arc<dyn Fs>,
14254 http_client: Arc<dyn HttpClient>,
14255 language_registry: Arc<LanguageRegistry>,
14256 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14257}
14258
14259impl LocalLspAdapterDelegate {
14260 pub fn new(
14261 language_registry: Arc<LanguageRegistry>,
14262 environment: &Entity<ProjectEnvironment>,
14263 lsp_store: WeakEntity<LspStore>,
14264 worktree: &Entity<Worktree>,
14265 http_client: Arc<dyn HttpClient>,
14266 fs: Arc<dyn Fs>,
14267 cx: &mut App,
14268 ) -> Arc<Self> {
14269 let load_shell_env_task =
14270 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14271
14272 Arc::new(Self {
14273 lsp_store,
14274 worktree: worktree.read(cx).snapshot(),
14275 fs,
14276 http_client,
14277 language_registry,
14278 load_shell_env_task,
14279 })
14280 }
14281
14282 pub fn from_local_lsp(
14283 local: &LocalLspStore,
14284 worktree: &Entity<Worktree>,
14285 cx: &mut App,
14286 ) -> Arc<Self> {
14287 Self::new(
14288 local.languages.clone(),
14289 &local.environment,
14290 local.weak.clone(),
14291 worktree,
14292 local.http_client.clone(),
14293 local.fs.clone(),
14294 cx,
14295 )
14296 }
14297}
14298
14299#[async_trait]
14300impl LspAdapterDelegate for LocalLspAdapterDelegate {
14301 fn show_notification(&self, message: &str, cx: &mut App) {
14302 self.lsp_store
14303 .update(cx, |_, cx| {
14304 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14305 })
14306 .ok();
14307 }
14308
14309 fn http_client(&self) -> Arc<dyn HttpClient> {
14310 self.http_client.clone()
14311 }
14312
14313 fn worktree_id(&self) -> WorktreeId {
14314 self.worktree.id()
14315 }
14316
14317 fn worktree_root_path(&self) -> &Path {
14318 self.worktree.abs_path().as_ref()
14319 }
14320
14321 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14322 self.worktree.resolve_executable_path(path)
14323 }
14324
14325 async fn shell_env(&self) -> HashMap<String, String> {
14326 let task = self.load_shell_env_task.clone();
14327 task.await.unwrap_or_default()
14328 }
14329
14330 async fn npm_package_installed_version(
14331 &self,
14332 package_name: &str,
14333 ) -> Result<Option<(PathBuf, Version)>> {
14334 let local_package_directory = self.worktree_root_path();
14335 let node_modules_directory = local_package_directory.join("node_modules");
14336
14337 if let Some(version) =
14338 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14339 {
14340 return Ok(Some((node_modules_directory, version)));
14341 }
14342 let Some(npm) = self.which("npm".as_ref()).await else {
14343 log::warn!(
14344 "Failed to find npm executable for {:?}",
14345 local_package_directory
14346 );
14347 return Ok(None);
14348 };
14349
14350 let env = self.shell_env().await;
14351 let output = util::command::new_smol_command(&npm)
14352 .args(["root", "-g"])
14353 .envs(env)
14354 .current_dir(local_package_directory)
14355 .output()
14356 .await?;
14357 let global_node_modules =
14358 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14359
14360 if let Some(version) =
14361 read_package_installed_version(global_node_modules.clone(), package_name).await?
14362 {
14363 return Ok(Some((global_node_modules, version)));
14364 }
14365 return Ok(None);
14366 }
14367
14368 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14369 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14370 if self.fs.is_file(&worktree_abs_path).await {
14371 worktree_abs_path.pop();
14372 }
14373
14374 let env = self.shell_env().await;
14375
14376 let shell_path = env.get("PATH").cloned();
14377
14378 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14379 }
14380
14381 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14382 let mut working_dir = self.worktree_root_path().to_path_buf();
14383 if self.fs.is_file(&working_dir).await {
14384 working_dir.pop();
14385 }
14386 let output = util::command::new_smol_command(&command.path)
14387 .args(command.arguments)
14388 .envs(command.env.clone().unwrap_or_default())
14389 .current_dir(working_dir)
14390 .output()
14391 .await?;
14392
14393 anyhow::ensure!(
14394 output.status.success(),
14395 "{}, stdout: {:?}, stderr: {:?}",
14396 output.status,
14397 String::from_utf8_lossy(&output.stdout),
14398 String::from_utf8_lossy(&output.stderr)
14399 );
14400 Ok(())
14401 }
14402
14403 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14404 self.language_registry
14405 .update_lsp_binary_status(server_name, status);
14406 }
14407
14408 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14409 self.language_registry
14410 .all_lsp_adapters()
14411 .into_iter()
14412 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14413 .collect()
14414 }
14415
14416 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14417 let dir = self.language_registry.language_server_download_dir(name)?;
14418
14419 if !dir.exists() {
14420 smol::fs::create_dir_all(&dir)
14421 .await
14422 .context("failed to create container directory")
14423 .log_err()?;
14424 }
14425
14426 Some(dir)
14427 }
14428
14429 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14430 let entry = self
14431 .worktree
14432 .entry_for_path(path)
14433 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14434 let abs_path = self.worktree.absolutize(&entry.path);
14435 self.fs.load(&abs_path).await
14436 }
14437}
14438
14439async fn populate_labels_for_symbols(
14440 symbols: Vec<CoreSymbol>,
14441 language_registry: &Arc<LanguageRegistry>,
14442 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14443 output: &mut Vec<Symbol>,
14444) {
14445 #[allow(clippy::mutable_key_type)]
14446 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14447
14448 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14449 for symbol in symbols {
14450 let Some(file_name) = symbol.path.file_name() else {
14451 continue;
14452 };
14453 let language = language_registry
14454 .load_language_for_file_path(Path::new(file_name))
14455 .await
14456 .ok()
14457 .or_else(|| {
14458 unknown_paths.insert(file_name.into());
14459 None
14460 });
14461 symbols_by_language
14462 .entry(language)
14463 .or_default()
14464 .push(symbol);
14465 }
14466
14467 for unknown_path in unknown_paths {
14468 log::info!("no language found for symbol in file {unknown_path:?}");
14469 }
14470
14471 let mut label_params = Vec::new();
14472 for (language, mut symbols) in symbols_by_language {
14473 label_params.clear();
14474 label_params.extend(
14475 symbols
14476 .iter_mut()
14477 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14478 );
14479
14480 let mut labels = Vec::new();
14481 if let Some(language) = language {
14482 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14483 language_registry
14484 .lsp_adapters(&language.name())
14485 .first()
14486 .cloned()
14487 });
14488 if let Some(lsp_adapter) = lsp_adapter {
14489 labels = lsp_adapter
14490 .labels_for_symbols(&label_params, &language)
14491 .await
14492 .log_err()
14493 .unwrap_or_default();
14494 }
14495 }
14496
14497 for ((symbol, (name, _)), label) in symbols
14498 .into_iter()
14499 .zip(label_params.drain(..))
14500 .zip(labels.into_iter().chain(iter::repeat(None)))
14501 {
14502 output.push(Symbol {
14503 language_server_name: symbol.language_server_name,
14504 source_worktree_id: symbol.source_worktree_id,
14505 source_language_server_id: symbol.source_language_server_id,
14506 path: symbol.path,
14507 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14508 name,
14509 kind: symbol.kind,
14510 range: symbol.range,
14511 });
14512 }
14513 }
14514}
14515
14516fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14517 match server.capabilities().text_document_sync.as_ref()? {
14518 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14519 // Server wants didSave but didn't specify includeText.
14520 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14521 // Server doesn't want didSave at all.
14522 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14523 // Server provided SaveOptions.
14524 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14525 Some(save_options.include_text.unwrap_or(false))
14526 }
14527 },
14528 // We do not have any save info. Kind affects didChange only.
14529 lsp::TextDocumentSyncCapability::Kind(_) => None,
14530 }
14531}
14532
14533/// Completion items are displayed in a `UniformList`.
14534/// Usually, those items are single-line strings, but in LSP responses,
14535/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14536/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14537/// 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,
14538/// breaking the completions menu presentation.
14539///
14540/// 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.
14541pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14542 let mut new_text = String::with_capacity(label.text.len());
14543 let mut offset_map = vec![0; label.text.len() + 1];
14544 let mut last_char_was_space = false;
14545 let mut new_idx = 0;
14546 let chars = label.text.char_indices().fuse();
14547 let mut newlines_removed = false;
14548
14549 for (idx, c) in chars {
14550 offset_map[idx] = new_idx;
14551
14552 match c {
14553 '\n' if last_char_was_space => {
14554 newlines_removed = true;
14555 }
14556 '\t' | ' ' if last_char_was_space => {}
14557 '\n' if !last_char_was_space => {
14558 new_text.push(' ');
14559 new_idx += 1;
14560 last_char_was_space = true;
14561 newlines_removed = true;
14562 }
14563 ' ' | '\t' => {
14564 new_text.push(' ');
14565 new_idx += 1;
14566 last_char_was_space = true;
14567 }
14568 _ => {
14569 new_text.push(c);
14570 new_idx += c.len_utf8();
14571 last_char_was_space = false;
14572 }
14573 }
14574 }
14575 offset_map[label.text.len()] = new_idx;
14576
14577 // Only modify the label if newlines were removed.
14578 if !newlines_removed {
14579 return;
14580 }
14581
14582 let last_index = new_idx;
14583 let mut run_ranges_errors = Vec::new();
14584 label.runs.retain_mut(|(range, _)| {
14585 match offset_map.get(range.start) {
14586 Some(&start) => range.start = start,
14587 None => {
14588 run_ranges_errors.push(range.clone());
14589 return false;
14590 }
14591 }
14592
14593 match offset_map.get(range.end) {
14594 Some(&end) => range.end = end,
14595 None => {
14596 run_ranges_errors.push(range.clone());
14597 range.end = last_index;
14598 }
14599 }
14600 true
14601 });
14602 if !run_ranges_errors.is_empty() {
14603 log::error!(
14604 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14605 label.text
14606 );
14607 }
14608
14609 let mut wrong_filter_range = None;
14610 if label.filter_range == (0..label.text.len()) {
14611 label.filter_range = 0..new_text.len();
14612 } else {
14613 let mut original_filter_range = Some(label.filter_range.clone());
14614 match offset_map.get(label.filter_range.start) {
14615 Some(&start) => label.filter_range.start = start,
14616 None => {
14617 wrong_filter_range = original_filter_range.take();
14618 label.filter_range.start = last_index;
14619 }
14620 }
14621
14622 match offset_map.get(label.filter_range.end) {
14623 Some(&end) => label.filter_range.end = end,
14624 None => {
14625 wrong_filter_range = original_filter_range.take();
14626 label.filter_range.end = last_index;
14627 }
14628 }
14629 }
14630 if let Some(wrong_filter_range) = wrong_filter_range {
14631 log::error!(
14632 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14633 label.text
14634 );
14635 }
14636
14637 label.text = new_text;
14638}